feat: add task-manager workspace layout

This commit is contained in:
2026-07-21 00:54:46 +09:00
parent 4a54977341
commit f1fe65ebe4
7 changed files with 859 additions and 72 deletions

View File

@@ -0,0 +1,107 @@
(function () {
"use strict";
const region = document.getElementById("workspace-region");
const navigation = document.getElementById("workspace-navigation");
const navigationItems = document.getElementById("workspace-nav-items");
const toggle = document.getElementById("workspace-nav-toggle");
const toggleLabel = toggle && toggle.querySelector(".workspace-nav-toggle-label");
const stockTab = document.getElementById("workspace-stock-tab");
const catalogTab = document.getElementById("workspace-catalog-tab");
const stockWorkspace = document.getElementById("stock-workspace");
const catalogWorkspace = document.getElementById("catalog-workspace");
const marketTabs = document.getElementById("market-tabs");
const title = document.getElementById("workspace-title");
if (!region || !navigation || !navigationItems || !toggle || !toggleLabel ||
!stockTab || !catalogTab || !stockWorkspace || !catalogWorkspace ||
!marketTabs || !title) {
return;
}
const views = Object.freeze({
stock: Object.freeze({ tab: stockTab, view: stockWorkspace, title: "종목·컷" }),
catalog: Object.freeze({ tab: catalogTab, view: catalogWorkspace, title: "기타 그래픽" })
});
function setNavigationExpanded(expanded) {
const isExpanded = expanded === true;
region.classList.toggle("nav-collapsed", !isExpanded);
toggle.setAttribute("aria-expanded", isExpanded ? "true" : "false");
toggle.setAttribute("aria-label", isExpanded ? "작업 메뉴 접기" : "작업 메뉴 펼치기");
toggle.title = isExpanded ? "메뉴 접기" : "메뉴 펼치기";
toggleLabel.textContent = isExpanded ? "메뉴 접기" : "메뉴 펼치기";
}
function setWorkspace(name) {
const selected = views[name];
if (!selected) return false;
const currentFocus = document.activeElement;
const focusWillBeHidden = Object.keys(views).some(function (key) {
return key !== name && views[key].view.contains(currentFocus);
});
if (focusWillBeHidden) selected.tab.focus();
Object.keys(views).forEach(function (key) {
const entry = views[key];
const isCurrent = key === name;
entry.tab.classList.toggle("workspace-current", isCurrent);
entry.tab.setAttribute("aria-current", isCurrent ? "page" : "false");
entry.view.hidden = !isCurrent;
entry.view.toggleAttribute("inert", !isCurrent);
entry.view.setAttribute("aria-hidden", isCurrent ? "false" : "true");
});
region.dataset.activeWorkspace = name;
title.textContent = selected.title;
return true;
}
function focusAdjacentItem(direction) {
const items = [stockTab, catalogTab].filter(function (button) {
return button.disabled !== true;
});
const currentIndex = items.indexOf(document.activeElement);
const nextIndex = currentIndex < 0
? 0
: (currentIndex + direction + items.length) % items.length;
items[nextIndex].focus();
}
toggle.addEventListener("click", function () {
setNavigationExpanded(toggle.getAttribute("aria-expanded") !== "true");
});
stockTab.addEventListener("click", function () { setWorkspace("stock"); });
catalogTab.addEventListener("click", function () { setWorkspace("catalog"); });
navigationItems.addEventListener("keydown", function (event) {
const menuButton = event.target.closest && event.target.closest(".workspace-nav-item");
if ((event.key === "Enter" || event.key === " ") && menuButton) {
event.preventDefault();
event.stopPropagation();
setWorkspace(menuButton === stockTab ? "stock" : "catalog");
return;
}
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
event.preventDefault();
event.stopPropagation();
focusAdjacentItem(event.key === "ArrowUp" ? -1 : 1);
});
// A market tab can also be activated by automation or accessibility tools.
// Reveal its owning workspace before app.js dispatches the native select-tab intent.
marketTabs.addEventListener("click", function (event) {
if (event.target.closest("button[data-tab-id]")) setWorkspace("catalog");
}, true);
setNavigationExpanded(true);
setWorkspace("stock");
window.LegacyWorkspaceNavigation = Object.freeze({
select: setWorkspace,
setExpanded: setNavigationExpanded,
active: function () { return region.dataset.activeWorkspace; },
expanded: function () { return toggle.getAttribute("aria-expanded") === "true"; }
});
}());