@godxjp/ui 0.2.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BRAND.md +286 -0
- package/CHANGELOG.md +94 -0
- package/README.md +189 -33
- package/dist/components/primitives.d.ts +266 -0
- package/dist/components/primitives.js +252 -0
- package/dist/components/primitives.js.map +1 -0
- package/dist/components/screens.d.ts +51 -0
- package/dist/components/screens.js +806 -0
- package/dist/components/screens.js.map +1 -0
- package/dist/components/shell.d.ts +112 -0
- package/dist/components/shell.js +768 -0
- package/dist/components/shell.js.map +1 -0
- package/dist/data.d.ts +35 -0
- package/dist/data.js +93 -0
- package/dist/data.js.map +1 -0
- package/dist/hooks.d.ts +25 -0
- package/dist/hooks.js +144 -0
- package/dist/hooks.js.map +1 -0
- package/dist/i18n.d.ts +9 -0
- package/dist/i18n.js +409 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +14 -2730
- package/dist/index.js +725 -5683
- package/dist/index.js.map +1 -1
- package/package.json +74 -117
- package/src/tokens/tokens.css +765 -0
- package/src/styles/theme.css +0 -678
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/shell/AppShell.tsx","../../src/components/primitives/cn.ts","../../src/components/shell/Sidebar.tsx","../../src/components/shell/Topbar.tsx","../../src/data/products.ts","../../src/i18n/index.ts","../../src/hooks/useTweaks.ts","../../src/components/shell/TweaksPanel.tsx","../../src/components/shell/ProductSwitcher.tsx","../../src/components/shell/ProjectSwitcher.tsx","../../src/components/shell/CommandPalette.tsx"],"names":["jsxs","jsx","useTranslation","Fragment","ChevronDown","useState","Search","Popover2","Check","useEffect","Dialog2"],"mappings":"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","file":"shell.js","sourcesContent":["import type { ReactNode } from \"react\";\n\n// AppShell — the canonical chrome layout.\n//\n// Grid: sidebar (collapsible) + topbar (header) + main scroll area.\n// All visual rules come from `tokens-ext.css` (`.app-root`,\n// `.app-sidebar`, `.app-topbar`, `.app-main`) so dark mode, density,\n// tenant accent + sidebar-collapsed all swap automatically when the\n// `<html data-*>` attributes change (driven by useTweaks).\n//\n// Per MUST RULE #11, every GoDX service shell renders <AppShell>;\n// services do not hand-roll the grid.\nexport interface AppShellProps {\n sidebar: ReactNode;\n topbar: ReactNode;\n children: ReactNode;\n /**\n * Controls the visual collapsed state. The hook + Tweaks panel\n * mirror this onto `<html data-collapsed>` via useTweaks; pass the\n * same value here so the grid columns shrink in lockstep.\n */\n sidebarCollapsed?: boolean;\n}\n\nexport function AppShell({ sidebar, topbar, children, sidebarCollapsed = false }: AppShellProps) {\n return (\n <div className=\"app-root\" data-collapsed={sidebarCollapsed}>\n <aside className=\"app-sidebar\">{sidebar}</aside>\n <header className=\"app-topbar\">{topbar}</header>\n <main className=\"app-main\">{children}</main>\n </div>\n );\n}\n","// cn — class-name merger. Standard shadcn utility: clsx merges values\n// and tailwind-merge resolves Tailwind class conflicts (e.g. last\n// `bg-*` wins). Every primitive in this package and every consumer\n// service imports cn from this single location to keep the dedupe\n// rules consistent.\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import { ChevronDown } from \"lucide-react\";\nimport type { ComponentType, ReactNode } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { cn } from \"../primitives/cn\";\nimport type { ForgeProduct } from \"../../data/products\";\n\n// Sidebar item shape — what consumers pass to <Sidebar nav={…} />.\n//\n// `icon` is a lucide component (or any React component that accepts a\n// `size` prop). `badge` is a numeric or string count rendered after\n// the label.\nexport interface SidebarItem {\n id: string;\n label: string;\n icon: ComponentType<{ size?: number }>;\n /** Optional numeric badge (e.g. open issue count). */\n badge?: string | number;\n /** Disabled rows are dimmed and unclickable. */\n disabled?: boolean;\n}\n\nexport interface SidebarSection {\n /** Section label shown above the nav items. */\n label?: string;\n items: SidebarItem[];\n}\n\nexport interface SidebarProps {\n /** Currently active route id — must match an item's `id`. */\n activeId: string;\n /** Click handler — called with the item's `id`. */\n onSelect: (id: string) => void;\n sections: SidebarSection[];\n /** Product = the org-shaped tenant shown in the top product chip. */\n product: ForgeProduct;\n /** Click to open the product switcher dropdown (owned by parent). */\n onProductClick?: () => void;\n collapsed?: boolean;\n footer?: ReactNode;\n}\n\nexport function Sidebar({\n activeId,\n onSelect,\n sections,\n product,\n onProductClick,\n collapsed = false,\n footer,\n}: SidebarProps) {\n const { t } = useTranslation();\n void t; // future-proof — tooltips will localize here.\n\n return (\n <>\n {/* Top product chip — opens product switcher. */}\n <button\n type=\"button\"\n className=\"sb-product\"\n onClick={onProductClick}\n aria-label={product.name}\n >\n <span\n className=\"sb-logo-mark\"\n style={{ background: product.color }}\n >\n {product.name[0]?.toUpperCase() ?? \"?\"}\n </span>\n {!collapsed && (\n <span\n className=\"sb-product-meta col flex-1 min-w-0\"\n style={{ display: \"flex\" }}\n >\n <span className=\"sb-product-name\">{product.name}</span>\n <span className=\"sb-product-tenant\">{product.role}</span>\n </span>\n )}\n {!collapsed && (\n <span className=\"sb-product-tenant shrink-0\">\n <ChevronDown size={14} />\n </span>\n )}\n </button>\n\n {/* Nav sections — grouped, separated by a thin divider. */}\n <div className=\"flex-1 overflow-y-auto\">\n {sections.map((section, i) => (\n <div key={section.label ?? i} className=\"sb-section\">\n {section.label && !collapsed && (\n <div className=\"sb-section-label\">{section.label}</div>\n )}\n <div className=\"sb-nav\" role=\"navigation\">\n {section.items.map((item) => {\n const Icon = item.icon;\n const isActive = item.id === activeId;\n return (\n <button\n type=\"button\"\n key={item.id}\n className={cn(\"sb-nav-item\")}\n data-active={isActive}\n aria-current={isActive ? \"page\" : undefined}\n aria-disabled={item.disabled}\n onClick={() => !item.disabled && onSelect(item.id)}\n >\n <span className=\"sb-icon\">\n <Icon size={16} />\n </span>\n <span className=\"sb-label\">{item.label}</span>\n {item.badge !== undefined && item.badge !== \"\" && (\n <span className=\"sb-badge\">{item.badge}</span>\n )}\n </button>\n );\n })}\n </div>\n </div>\n ))}\n </div>\n\n {footer && <div className=\"sb-footer\">{footer}</div>}\n </>\n );\n}\n","import { ChevronDown, PanelLeftClose, PanelLeftOpen, Search, SlidersHorizontal } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { cn } from \"../primitives/cn\";\nimport type { ForgeProduct, ForgeProject } from \"../../data/products\";\n\n// Topbar — sits across the top of every screen. Hosts:\n//\n// • Sidebar collapse toggle (mirror of useTweaks.sidebarCollapsed)\n// • Product chip → opens ProductSwitcher (dropdown — TBD)\n// • Project chip → opens ProjectSwitcher (dropdown — TBD)\n// shown as a dashed empty chip when no\n// active project (fixes the picker-empty\n// bug super-admin used to hit).\n// • Search shortcut → opens CommandPalette (⌘K)\n// • Tweaks button → opens TweaksPanel (right-side drawer)\n//\n// Switcher dropdowns themselves render via callbacks supplied by the\n// host page so the host can manage open state + keyboard nav. This\n// component renders the closed chips + invokes `onProduct/Project\n// Open`.\n\nexport interface TopbarProps {\n product: ForgeProduct;\n project?: ForgeProject | null;\n onProductOpen?: () => void;\n onProjectOpen?: () => void;\n onSearchOpen?: () => void;\n onTweaksOpen?: () => void;\n collapsed?: boolean;\n onToggleCollapsed?: () => void;\n /** Optional breadcrumb / actions slot on the right. */\n rightSlot?: ReactNode;\n}\n\nexport function Topbar({\n product,\n project,\n onProductOpen,\n onProjectOpen,\n onSearchOpen,\n onTweaksOpen,\n collapsed = false,\n onToggleCollapsed,\n rightSlot,\n}: TopbarProps) {\n const { t } = useTranslation();\n\n return (\n <>\n {onToggleCollapsed && (\n <button\n type=\"button\"\n className=\"tb-icon-btn\"\n aria-label={t(\"shell.sidebarCollapse\")}\n aria-pressed={collapsed}\n onClick={onToggleCollapsed}\n >\n {collapsed ? <PanelLeftOpen size={16} /> : <PanelLeftClose size={16} />}\n </button>\n )}\n\n <div className=\"tb-switcher\">\n <button\n type=\"button\"\n className=\"tb-chip\"\n aria-label={product.name}\n onClick={onProductOpen}\n >\n <span\n className=\"tb-chip-icon\"\n style={{ background: product.color }}\n >\n {product.name[0]?.toUpperCase() ?? \"?\"}\n </span>\n <span className=\"tb-chip-label\">{product.name}</span>\n <span className=\"tb-chip-caret\">\n <ChevronDown size={12} />\n </span>\n </button>\n <span className=\"tb-chip-sep\">/</span>\n <button\n type=\"button\"\n className={cn(\"tb-chip\", !project && \"empty\")}\n aria-label={project ? project.name : t(\"shell.pickProject\")}\n onClick={onProjectOpen}\n >\n <span className=\"tb-chip-label\">\n {project ? project.name : t(\"shell.pickProject\")}\n </span>\n <span className=\"tb-chip-caret\">\n <ChevronDown size={12} />\n </span>\n </button>\n </div>\n\n <button\n type=\"button\"\n className=\"tb-search ml-auto\"\n onClick={onSearchOpen}\n >\n <Search size={14} />\n <span>{t(\"common.search\")}…</span>\n <kbd className=\"kbd\">⌘K</kbd>\n </button>\n\n {rightSlot}\n\n {onTweaksOpen && (\n <button\n type=\"button\"\n className=\"tb-icon-btn\"\n aria-label={t(\"tweaks.title\")}\n onClick={onTweaksOpen}\n >\n <SlidersHorizontal size={16} />\n </button>\n )}\n </>\n );\n}\n","// Product / project registry — mock data layer.\n//\n// Mirrors the design prototype's `PRODUCTS` array (shell.jsx). Today\n// this is a static fixture so the UI shell renders end-to-end; a\n// follow-up phase will swap it for `/api/v1/orgs/...` calls against\n// forge-service + identity-service.\n//\n// Vocabulary:\n// Product = Org (GitHub-shaped tenant). Owns projects, members,\n// domains, design tokens (per the OKLCH tenant override\n// in tokens-ext.css).\n// Project = Repo. Has a stack (e.g. \"Vue 3 · Vite\"), kind\n// (service / web / desktop / mobile / library / infra /\n// workstation), branch, lastCommit, openIssues, prs.\n//\n// Tenants must match a `[data-tenant=\"<id>\"]` block in tokens-ext.css.\nexport type ProjectKind =\n | \"service\"\n | \"web\"\n | \"desktop\"\n | \"workstation\"\n | \"mobile\"\n | \"library\"\n | \"infra\";\n\nexport type ProjectStatus = \"active\" | \"review\" | \"planning\" | \"archived\";\n\nexport type ForgeProject = {\n id: string;\n name: string;\n stack: string;\n kind: ProjectKind;\n devs: number;\n status: ProjectStatus;\n branch: string;\n lastCommit: string;\n openIssues: number;\n prs: number;\n sandbox: boolean;\n};\n\nexport type ForgeProduct = {\n id: string;\n name: string;\n tenant: \"godx\" | \"kintai\" | \"tempo\" | \"betoya\" | \"restaurant\";\n role: string;\n desc: string;\n /** Brand color in OKLCH — used as the sidebar logo mark + accent. */\n color: string;\n owner: string;\n devs: number;\n projects: ForgeProject[];\n};\n\nexport const PRODUCTS: ForgeProduct[] = [\n {\n id: \"restaurant\",\n name: \"godx-restaurant\",\n tenant: \"restaurant\",\n role: \"レストラン管理\",\n desc: \"店舗向け統合管理プラットフォーム\",\n color: \"oklch(58% 0.18 25)\",\n owner: \"Satoshi F\",\n devs: 6,\n projects: [\n { id: \"api\", name: \"restaurant-api\", stack: \"NestJS · PostgreSQL\", kind: \"service\", devs: 3, status: \"active\", branch: \"main\", lastCommit: \"12分前\", openIssues: 8, prs: 2, sandbox: true },\n { id: \"admin\", name: \"restaurant-admin\", stack: \"Next.js 14 · React\", kind: \"web\", devs: 2, status: \"active\", branch: \"main\", lastCommit: \"1時間前\", openIssues: 5, prs: 1, sandbox: true },\n { id: \"pos\", name: \"restaurant-pos\", stack: \"Tauri · Vue 3\", kind: \"desktop\", devs: 1, status: \"active\", branch: \"feature/print\", lastCommit: \"30分前\", openIssues: 3, prs: 1, sandbox: true },\n { id: \"kds\", name: \"restaurant-kds\", stack: \"React · Electron\", kind: \"workstation\", devs: 1, status: \"review\", branch: \"main\", lastCommit: \"昨日\", openIssues: 2, prs: 1, sandbox: true },\n { id: \"kintai\", name: \"restaurant-kintai\", stack: \"Vue 3 · Laravel\", kind: \"service\", devs: 2, status: \"active\", branch: \"main\", lastCommit: \"5分前\", openIssues: 4, prs: 0, sandbox: true },\n { id: \"mobile\", name: \"restaurant-mobile\", stack: \"React Native\", kind: \"mobile\", devs: 1, status: \"planning\", branch: \"develop\", lastCommit: \"3日前\", openIssues: 1, prs: 0, sandbox: false },\n ],\n },\n {\n id: \"godx\",\n name: \"godx-admin\",\n tenant: \"godx\",\n role: \"Platform admin\",\n desc: \"GoDX Forge developer workspace\",\n color: \"oklch(60% 0.137 163)\",\n owner: \"Satoshi F\",\n devs: 4,\n projects: [\n { id: \"frontend\", name: \"godx-admin-frontend\", stack: \"React · Vite\", kind: \"web\", devs: 2, status: \"active\", branch: \"master\", lastCommit: \"2時間前\", openIssues: 6, prs: 2, sandbox: true },\n { id: \"api\", name: \"godx-admin-api\", stack: \"Go · Gin\", kind: \"service\", devs: 1, status: \"active\", branch: \"master\", lastCommit: \"4時間前\", openIssues: 3, prs: 1, sandbox: true },\n { id: \"ui\", name: \"@godxjp/ui\", stack: \"TypeScript · React\", kind: \"library\", devs: 2, status: \"active\", branch: \"master\", lastCommit: \"1時間前\", openIssues: 2, prs: 0, sandbox: false },\n ],\n },\n {\n id: \"kintai\",\n name: \"dxs-kintai\",\n tenant: \"kintai\",\n role: \"HR / Attendance\",\n desc: \"勤怠管理プラットフォーム\",\n color: \"oklch(56% 0.15 240)\",\n owner: \"Naoki N\",\n devs: 3,\n projects: [\n { id: \"frontend\", name: \"kintai-web\", stack: \"Vue 3 · Vite\", kind: \"web\", devs: 2, status: \"active\", branch: \"main\", lastCommit: \"20分前\", openIssues: 7, prs: 1, sandbox: true },\n { id: \"backend\", name: \"kintai-api\", stack: \"Laravel 11\", kind: \"service\", devs: 1, status: \"active\", branch: \"main\", lastCommit: \"1日前\", openIssues: 4, prs: 0, sandbox: true },\n ],\n },\n {\n id: \"tempo\",\n name: \"dxs-tempo\",\n tenant: \"tempo\",\n role: \"Shop / Inventory\",\n desc: \"店舗・在庫バックエンド\",\n color: \"oklch(48% 0.16 285)\",\n owner: \"Naoki N\",\n devs: 2,\n projects: [\n { id: \"api\", name: \"tempo-api\", stack: \"Go · Echo\", kind: \"service\", devs: 2, status: \"active\", branch: \"main\", lastCommit: \"5時間前\", openIssues: 9, prs: 1, sandbox: true },\n { id: \"ops\", name: \"tempo-ops\", stack: \"Terraform\", kind: \"infra\", devs: 1, status: \"planning\", branch: \"main\", lastCommit: \"1週間前\", openIssues: 1, prs: 0, sandbox: false },\n ],\n },\n {\n id: \"betoya\",\n name: \"betoya\",\n tenant: \"betoya\",\n role: \"Vietnamese restaurant\",\n desc: \"ベト屋 Tenant\",\n color: \"oklch(58% 0.159 150)\",\n owner: \"Anh K\",\n devs: 1,\n projects: [\n { id: \"site\", name: \"betoya-site\", stack: \"Astro\", kind: \"web\", devs: 1, status: \"active\", branch: \"main\", lastCommit: \"昨日\", openIssues: 2, prs: 0, sandbox: false },\n ],\n },\n];\n\nexport const PROJECT_KIND: Record<ProjectKind, { color: string; label: string }> = {\n service: { color: \"oklch(60% 0.137 163)\", label: \"API\" },\n web: { color: \"oklch(56% 0.15 240)\", label: \"Web\" },\n desktop: { color: \"oklch(48% 0.16 285)\", label: \"Desktop\" },\n workstation: { color: \"oklch(50% 0.16 30)\", label: \"Workstation\" },\n mobile: { color: \"oklch(58% 0.18 25)\", label: \"Mobile\" },\n library: { color: \"oklch(50% 0.05 250)\", label: \"Library\" },\n infra: { color: \"oklch(45% 0.05 260)\", label: \"Infra\" },\n};\n\nexport function findProductByTenant(tenant: string): ForgeProduct | undefined {\n return PRODUCTS.find((p) => p.tenant === tenant);\n}\n","// GoDX Forge i18n bootstrap.\n//\n// Locale resolution order:\n// 1. localStorage[\"forge.locale\"] (user override via Tweaks panel)\n// 2. navigator.language prefix (ja-JP → ja, en-US → en, vi-VN → vi)\n// 3. JA fallback (design's primary locale)\n//\n// Supported locales follow the design prototype (chats + ui-kit.jsx): ja / en / vi.\nimport i18next from \"i18next\";\nimport LanguageDetector from \"i18next-browser-languagedetector\";\nimport { initReactI18next } from \"react-i18next\";\n\nimport ja from \"./locales/ja\";\nimport en from \"./locales/en\";\nimport vi from \"./locales/vi\";\n\nexport const SUPPORTED_LOCALES = [\"ja\", \"en\", \"vi\"] as const;\nexport type ForgeLocale = (typeof SUPPORTED_LOCALES)[number];\n\nexport const FORGE_LOCALE_STORAGE_KEY = \"forge.locale\";\n\nexport function initI18n(): typeof i18next {\n void i18next\n .use(LanguageDetector)\n .use(initReactI18next)\n .init({\n resources: {\n ja: { translation: ja },\n en: { translation: en },\n vi: { translation: vi },\n },\n fallbackLng: \"ja\",\n supportedLngs: SUPPORTED_LOCALES,\n load: \"languageOnly\",\n interpolation: { escapeValue: false },\n detection: {\n order: [\"localStorage\", \"navigator\"],\n lookupLocalStorage: FORGE_LOCALE_STORAGE_KEY,\n caches: [\"localStorage\"],\n },\n });\n return i18next;\n}\n\nexport default i18next;\n","// useTweaks — shared client state for the design system's Tweaks panel.\n//\n// Mirrors the design prototype `useTweaks` hook (tweaks-panel.jsx). Each\n// tweak is persisted to localStorage so reloads keep the user's chosen\n// density / theme / tenant / sidebar-collapsed setting. Locale is owned\n// by i18next (see src/i18n/index.ts) but exposed through this hook so\n// the Tweaks UI has a single dispatcher.\nimport { useCallback, useEffect, useState } from \"react\";\nimport i18n, { FORGE_LOCALE_STORAGE_KEY, type ForgeLocale } from \"../i18n\";\nimport { PRODUCTS, type ForgeProduct } from \"../data/products\";\n\nexport type Density = \"compact\" | \"default\" | \"comfortable\";\nexport type Theme = \"light\" | \"dark\";\n\nexport type Tweaks = {\n density: Density;\n theme: Theme;\n tenant: ForgeProduct[\"tenant\"];\n locale: ForgeLocale;\n sidebarCollapsed: boolean;\n};\n\nconst STORAGE_KEY = \"forge.tweaks\";\n\nconst DEFAULTS: Tweaks = {\n density: \"default\",\n theme: \"light\",\n tenant: \"godx\",\n locale: \"ja\",\n sidebarCollapsed: false,\n};\n\nfunction loadInitial(): Tweaks {\n if (typeof window === \"undefined\") return DEFAULTS;\n try {\n const raw = window.localStorage.getItem(STORAGE_KEY);\n const stored = raw ? (JSON.parse(raw) as Partial<Tweaks>) : {};\n const detected = (i18n.language?.slice(0, 2) || \"ja\") as ForgeLocale;\n return {\n ...DEFAULTS,\n ...stored,\n locale: (stored.locale ?? detected) as ForgeLocale,\n };\n } catch {\n return DEFAULTS;\n }\n}\n\nexport function useTweaks() {\n const [tweaks, setTweaks] = useState<Tweaks>(loadInitial);\n\n // Persist every change to localStorage.\n useEffect(() => {\n try {\n window.localStorage.setItem(STORAGE_KEY, JSON.stringify(tweaks));\n } catch {\n /* Storage may be disabled (private mode). Silently degrade. */\n }\n }, [tweaks]);\n\n // Reflect tweaks onto <html> so the design tokens (CSS custom\n // properties scoped to [data-tenant=…], [data-theme=…], [data-density=…])\n // pick up the change without rerunning React.\n useEffect(() => {\n const html = document.documentElement;\n html.dataset.theme = tweaks.theme;\n html.dataset.density = tweaks.density;\n html.dataset.tenant = tweaks.tenant;\n html.lang = tweaks.locale;\n }, [tweaks.theme, tweaks.density, tweaks.tenant, tweaks.locale]);\n\n // Forward locale changes to i18next so the UI re-renders strings.\n useEffect(() => {\n if (i18n.language?.slice(0, 2) !== tweaks.locale) {\n void i18n.changeLanguage(tweaks.locale);\n try {\n window.localStorage.setItem(FORGE_LOCALE_STORAGE_KEY, tweaks.locale);\n } catch {\n /* ignore */\n }\n }\n }, [tweaks.locale]);\n\n const setTweak = useCallback(<K extends keyof Tweaks>(key: K, value: Tweaks[K]) => {\n setTweaks((prev) => ({ ...prev, [key]: value }));\n }, []);\n\n return { tweaks, setTweak, setTweaks } as const;\n}\n\nexport const PRODUCT_OPTIONS = PRODUCTS.map((p) => ({ value: p.tenant, label: p.name }));\n","import * as Dialog from \"@radix-ui/react-dialog\";\nimport { X } from \"lucide-react\";\nimport { useTranslation } from \"react-i18next\";\nimport { PRODUCTS } from \"../../data/products\";\nimport { useTweaks, type Density, type Theme } from \"../../hooks/useTweaks\";\nimport { SUPPORTED_LOCALES, type ForgeLocale } from \"../../i18n\";\n\n// TweaksPanel — right-side drawer that exposes the four toggles every\n// GoDX surface must honor: density, theme (light/dark), tenant\n// (product brand override), locale (ja/en/vi), sidebar collapsed.\n//\n// Owned state lives in `useTweaks` (localStorage-persisted); this\n// component is the visual face. Per MUST RULE #5 + #8, no service may\n// implement its own theme switcher — every consumer reuses this.\n\nexport interface TweaksPanelProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\nexport function TweaksPanel({ open, onOpenChange }: TweaksPanelProps) {\n const { t } = useTranslation();\n const { tweaks, setTweak } = useTweaks();\n\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Portal>\n <Dialog.Overlay className=\"fixed inset-0 z-40 bg-black/30 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\" />\n <Dialog.Content className=\"fixed right-0 top-0 z-50 h-full w-80 bg-popover text-popover-foreground border-l border-border shadow-2xl data-[state=open]:animate-in data-[state=open]:slide-in-from-right\">\n <div className=\"flex items-center justify-between border-b border-border px-4 h-12\">\n <Dialog.Title className=\"font-medium text-sm\">\n {t(\"tweaks.title\")}\n </Dialog.Title>\n <Dialog.Close asChild>\n <button className=\"tb-icon-btn\" aria-label=\"Close\">\n <X size={14} />\n </button>\n </Dialog.Close>\n </div>\n\n <div className=\"overflow-y-auto h-[calc(100%-3rem)] p-4 flex flex-col gap-6\">\n <Section label={t(\"tweaks.display\")}>\n <Radio\n label={t(\"tweaks.density\")}\n value={tweaks.density}\n onChange={(v) => setTweak(\"density\", v as Density)}\n options={[\n { value: \"compact\", label: t(\"tweaks.densityCompact\") },\n { value: \"default\", label: t(\"tweaks.densityDefault\") },\n { value: \"comfortable\", label: t(\"tweaks.densityComfortable\") },\n ]}\n />\n <Radio\n label={t(\"tweaks.theme\")}\n value={tweaks.theme}\n onChange={(v) => setTweak(\"theme\", v as Theme)}\n options={[\n { value: \"light\", label: t(\"tweaks.themeLight\") },\n { value: \"dark\", label: t(\"tweaks.themeDark\") },\n ]}\n />\n <Toggle\n label={t(\"shell.sidebarCollapse\")}\n value={tweaks.sidebarCollapsed}\n onChange={(v) => setTweak(\"sidebarCollapsed\", v)}\n />\n </Section>\n\n <Section label={t(\"tweaks.product\")}>\n <Select\n label={t(\"tweaks.product\")}\n value={tweaks.tenant}\n onChange={(v) => setTweak(\"tenant\", v as typeof tweaks.tenant)}\n options={PRODUCTS.map((p) => ({ value: p.tenant, label: p.name }))}\n />\n </Section>\n\n <Section label={t(\"tweaks.locale\")}>\n <Radio\n label={t(\"tweaks.language\")}\n value={tweaks.locale}\n onChange={(v) => setTweak(\"locale\", v as ForgeLocale)}\n options={SUPPORTED_LOCALES.map((code) => ({\n value: code,\n label: { ja: \"日本語\", en: \"English\", vi: \"Tiếng Việt\" }[code],\n }))}\n />\n </Section>\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n );\n}\n\nfunction Section({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"flex flex-col gap-2\">\n <div className=\"text-[10px] font-medium uppercase tracking-wider text-muted-foreground\">\n {label}\n </div>\n {children}\n </div>\n );\n}\n\nfunction Radio<T extends string>({\n label,\n value,\n onChange,\n options,\n}: {\n label: string;\n value: T;\n onChange: (v: T) => void;\n options: Array<{ value: T; label: string }>;\n}) {\n return (\n <label className=\"flex flex-col gap-1\">\n <span className=\"text-xs font-medium text-foreground\">{label}</span>\n <div className=\"grid auto-cols-fr grid-flow-col rounded-md border border-border overflow-hidden\">\n {options.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n data-active={opt.value === value}\n onClick={() => onChange(opt.value)}\n className=\"px-2 py-1 text-xs hover:bg-accent/40 data-[active=true]:bg-primary data-[active=true]:text-primary-foreground\"\n >\n {opt.label}\n </button>\n ))}\n </div>\n </label>\n );\n}\n\nfunction Toggle({\n label,\n value,\n onChange,\n}: {\n label: string;\n value: boolean;\n onChange: (v: boolean) => void;\n}) {\n return (\n <label className=\"flex items-center justify-between gap-2 text-xs\">\n <span className=\"font-medium\">{label}</span>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={value}\n onClick={() => onChange(!value)}\n className=\"relative inline-flex h-5 w-9 items-center rounded-full bg-input data-[on=true]:bg-primary transition-colors\"\n data-on={value}\n >\n <span\n className=\"inline-block h-4 w-4 transform rounded-full bg-white shadow-sm transition-transform translate-x-0.5 data-[on=true]:translate-x-4\"\n data-on={value}\n />\n </button>\n </label>\n );\n}\n\nfunction Select<T extends string>({\n label,\n value,\n onChange,\n options,\n}: {\n label: string;\n value: T;\n onChange: (v: T) => void;\n options: Array<{ value: T; label: string }>;\n}) {\n return (\n <label className=\"flex flex-col gap-1\">\n <span className=\"text-xs font-medium text-foreground\">{label}</span>\n <select\n className=\"input\"\n value={value}\n onChange={(e) => onChange(e.target.value as T)}\n >\n {options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n </label>\n );\n}\n","import * as Popover from \"@radix-ui/react-popover\";\nimport { Check, Search } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { PRODUCTS, type ForgeProduct } from \"../../data/products\";\nimport { cn } from \"../primitives/cn\";\n\n// ProductSwitcher — wraps a trigger (the product chip in the topbar)\n// with a Radix Popover that lists every product the user can see.\n// Search filters by name/role; selecting a row fires `onSelect`.\n//\n// Mirrors the design prototype's product dropdown (chats: \"Linear-style\n// quick switcher\"). Active product gets a ✓ marker. Per MUST RULE #12\n// this is the ONLY product switcher in the system — every service\n// reuses it.\nexport interface ProductSwitcherProps {\n trigger: ReactNode;\n activeId: string;\n products?: ForgeProduct[];\n onSelect: (product: ForgeProduct) => void;\n /** Controlled-open API. Omit for uncontrolled. */\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\nexport function ProductSwitcher({\n trigger,\n activeId,\n products = PRODUCTS,\n onSelect,\n open,\n onOpenChange,\n}: ProductSwitcherProps) {\n const { t } = useTranslation();\n const [query, setQuery] = useState(\"\");\n\n const q = query.trim().toLowerCase();\n const filtered = q\n ? products.filter(\n (p) => p.name.toLowerCase().includes(q) || p.role.toLowerCase().includes(q),\n )\n : products;\n\n return (\n <Popover.Root open={open} onOpenChange={onOpenChange}>\n <Popover.Trigger asChild>{trigger}</Popover.Trigger>\n <Popover.Portal>\n <Popover.Content\n align=\"start\"\n sideOffset={4}\n className=\"sw-pop\"\n onOpenAutoFocus={(e) => e.preventDefault()}\n >\n <div className=\"sw-pop-search\">\n <Search size={14} className=\"text-muted-foreground\" />\n <input\n autoFocus\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={t(\"shell.searchProducts\")}\n className=\"flex-1 bg-transparent outline-none\"\n />\n <kbd className=\"kbd\">esc</kbd>\n </div>\n\n <div className=\"sw-pop-list\">\n <div className=\"sw-pop-section\">\n <span>\n {t(\"nav.products\")} · {filtered.length}\n </span>\n </div>\n {filtered.length === 0 ? (\n <div className=\"sw-pop-empty\">—</div>\n ) : (\n filtered.map((p) => {\n const isActive = p.id === activeId;\n return (\n <button\n key={p.id}\n type=\"button\"\n className={cn(\"sw-pop-item w-full text-left\")}\n data-active={isActive}\n onClick={() => {\n onSelect(p);\n setQuery(\"\");\n }}\n >\n <span\n className=\"sb-logo-mark\"\n style={{ background: p.color }}\n >\n {p.name[0]?.toUpperCase() ?? \"?\"}\n </span>\n <div className=\"flex flex-col min-w-0 flex-1\">\n <span className=\"text-sm font-medium truncate\">{p.name}</span>\n <span className=\"text-[10px] text-muted-foreground truncate\">\n {p.role}\n </span>\n </div>\n <span className=\"sw-pop-item-meta\">\n {p.projects.length} · {p.devs}\n </span>\n {isActive && <Check size={12} className=\"text-primary\" />}\n </button>\n );\n })\n )}\n </div>\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n","import * as Popover from \"@radix-ui/react-popover\";\nimport { Check, Clock, Search } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { PRODUCTS, type ForgeProduct, type ForgeProject } from \"../../data/products\";\nimport { cn } from \"../primitives/cn\";\n\nexport interface RecentProject {\n productId: string;\n projectId: string;\n}\n\nexport interface ProjectSwitcherProps {\n trigger: ReactNode;\n /** Currently active product+project, used for the ✓ marker. */\n activeProductId?: string;\n activeProjectId?: string;\n /** Optional list of recent (product, project) tuples — surfaces them first. */\n recent?: RecentProject[];\n products?: ForgeProduct[];\n onSelect: (project: ForgeProject, product: ForgeProduct) => void;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\n// ProjectSwitcher — Linear-style cross-product project picker.\n//\n// Search runs against every product's projects; results are grouped\n// by their owning product so the visual hierarchy stays clear.\n// \"Recent\" surfaces last-N projects the user opened so jumping back\n// is a single click. Selecting a project in a different product auto-\n// changes the active tenant (caller's responsibility — it gets both\n// the project and its product).\n//\n// Per MUST RULE #12 this is THE project switcher across the system.\nexport function ProjectSwitcher({\n trigger,\n activeProductId,\n activeProjectId,\n recent = [],\n products = PRODUCTS,\n onSelect,\n open,\n onOpenChange,\n}: ProjectSwitcherProps) {\n const { t } = useTranslation();\n const [query, setQuery] = useState(\"\");\n\n const productById = new Map(products.map((p) => [p.id, p]));\n const recentResolved = recent\n .map((r) => {\n const product = productById.get(r.productId);\n const project = product?.projects.find((p) => p.id === r.projectId);\n return product && project ? { product, project } : null;\n })\n .filter((x): x is { product: ForgeProduct; project: ForgeProject } => !!x)\n .slice(0, 3);\n\n const q = query.trim().toLowerCase();\n const filteredProducts = products\n .map((product) => ({\n product,\n projects: q\n ? product.projects.filter(\n (p) =>\n p.name.toLowerCase().includes(q) || p.stack.toLowerCase().includes(q),\n )\n : product.projects,\n }))\n .filter((group) => group.projects.length > 0);\n\n return (\n <Popover.Root open={open} onOpenChange={onOpenChange}>\n <Popover.Trigger asChild>{trigger}</Popover.Trigger>\n <Popover.Portal>\n <Popover.Content\n align=\"start\"\n sideOffset={4}\n className=\"sw-pop\"\n style={{ width: 420 }}\n onOpenAutoFocus={(e) => e.preventDefault()}\n >\n <div className=\"sw-pop-search\">\n <Search size={14} className=\"text-muted-foreground\" />\n <input\n autoFocus\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={t(\"shell.searchProjects\")}\n className=\"flex-1 bg-transparent outline-none\"\n />\n <kbd className=\"kbd\">esc</kbd>\n </div>\n\n <div className=\"sw-pop-list\">\n {!q && recentResolved.length > 0 && (\n <>\n <div className=\"sw-pop-section\">\n <span>{t(\"shell.recent\")}</span>\n </div>\n {recentResolved.map(({ product, project }) => (\n <button\n key={`${product.id}:${project.id}`}\n type=\"button\"\n className=\"sw-pop-item w-full text-left\"\n onClick={() => onSelect(project, product)}\n >\n <Clock size={12} className=\"text-muted-foreground\" />\n <span className=\"flex-1 min-w-0 truncate font-mono text-xs\">\n {project.name}\n </span>\n <span className=\"sw-pop-item-meta truncate\">{product.name}</span>\n </button>\n ))}\n </>\n )}\n\n {filteredProducts.length === 0 && (\n <div className=\"sw-pop-empty\">—</div>\n )}\n\n {filteredProducts.map(({ product, projects }) => (\n <div key={product.id}>\n <div className=\"sw-pop-section\">\n <span className=\"flex items-center gap-2\">\n <span\n className=\"sb-logo-mark\"\n style={{ background: product.color, width: 12, height: 12, fontSize: 8 }}\n >\n {product.name[0]?.toUpperCase() ?? \"?\"}\n </span>\n {product.name}\n </span>\n <span>{projects.length}</span>\n </div>\n {projects.map((project) => {\n const isActive =\n product.id === activeProductId && project.id === activeProjectId;\n return (\n <button\n key={project.id}\n type=\"button\"\n className={cn(\"sw-pop-item w-full text-left\")}\n data-active={isActive}\n onClick={() => onSelect(project, product)}\n >\n <span className=\"font-mono text-xs truncate flex-1 min-w-0\">\n {project.name}\n </span>\n <span className=\"sw-kind-chip\">{project.kind}</span>\n <span className=\"sw-pop-item-meta\">\n {project.stack} · {project.devs}d · {project.openIssues}↗ ·{\" \"}\n {project.prs}pr\n </span>\n {isActive && <Check size={12} className=\"text-primary\" />}\n </button>\n );\n })}\n </div>\n ))}\n </div>\n\n <div className=\"sw-pop-foot\">\n <span>{t(\"shell.browseAllProducts\")}</span>\n <span className=\"ml-auto\">\n <kbd className=\"kbd\">↑↓</kbd> <kbd className=\"kbd\">⏎</kbd>\n </span>\n </div>\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n","import * as Dialog from \"@radix-ui/react-dialog\";\nimport * as VisuallyHidden from \"@radix-ui/react-visually-hidden\";\nimport { Command } from \"cmdk\";\nimport { useEffect, useRef } from \"react\";\nimport { useTranslation } from \"react-i18next\";\n\n// CommandPalette — ⌘K shortcut. Opens a centered dialog with a cmdk\n// list of commands. Caller supplies the command set + handlers; this\n// component provides the chrome (overlay, dialog, input, list).\n//\n// Per MUST RULE #11 (shell layout), every GoDX service uses this exact\n// palette — services do not roll their own ⌘K dialogs.\n\nexport interface CommandItem {\n id: string;\n label: string;\n group?: string;\n hint?: string;\n onSelect: () => void;\n}\n\nexport interface CommandPaletteProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n commands: CommandItem[];\n}\n\nexport function CommandPalette({ open, onOpenChange, commands }: CommandPaletteProps) {\n const { t } = useTranslation();\n const inputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n const isModifier = e.metaKey || e.ctrlKey;\n if (isModifier && e.key.toLowerCase() === \"k\") {\n e.preventDefault();\n onOpenChange(!open);\n } else if (e.key === \"Escape\" && open) {\n onOpenChange(false);\n }\n };\n window.addEventListener(\"keydown\", handler);\n return () => window.removeEventListener(\"keydown\", handler);\n }, [open, onOpenChange]);\n\n // Group commands for display.\n const groups = new Map<string, CommandItem[]>();\n for (const cmd of commands) {\n const key = cmd.group ?? \"\";\n const arr = groups.get(key) ?? [];\n arr.push(cmd);\n groups.set(key, arr);\n }\n\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Portal>\n <Dialog.Overlay className=\"fixed inset-0 z-50 bg-black/30 backdrop-blur-sm\" />\n <Dialog.Content\n className=\"fixed left-1/2 top-[20%] z-50 w-[min(560px,calc(100vw-2rem))] -translate-x-1/2 rounded-lg border border-border bg-popover text-popover-foreground shadow-2xl outline-none\"\n aria-describedby={undefined}\n >\n <VisuallyHidden.Root>\n <Dialog.Title>{t(\"common.search\")}</Dialog.Title>\n </VisuallyHidden.Root>\n <Command label=\"Command palette\" className=\"flex flex-col\">\n <Command.Input\n ref={inputRef}\n autoFocus\n placeholder={`${t(\"common.search\")}…`}\n className=\"w-full border-b border-border bg-transparent px-4 py-3 text-sm outline-none placeholder:text-muted-foreground\"\n />\n <Command.List className=\"max-h-80 overflow-y-auto p-1\">\n <Command.Empty className=\"px-3 py-6 text-center text-xs text-muted-foreground\">\n —\n </Command.Empty>\n {[...groups.entries()].map(([groupLabel, items]) => (\n <Command.Group\n key={groupLabel || \"default\"}\n heading={\n groupLabel ? (\n <span className=\"px-2 py-1 text-[10px] uppercase tracking-wider text-muted-foreground\">\n {groupLabel}\n </span>\n ) : undefined\n }\n >\n {items.map((cmd) => (\n <Command.Item\n key={cmd.id}\n value={cmd.label}\n onSelect={() => {\n cmd.onSelect();\n onOpenChange(false);\n }}\n className=\"flex items-center gap-2 rounded-md px-3 py-2 text-sm cursor-pointer data-[selected=true]:bg-accent\"\n >\n <span className=\"flex-1\">{cmd.label}</span>\n {cmd.hint && (\n <span className=\"text-[10px] text-muted-foreground\">\n {cmd.hint}\n </span>\n )}\n </Command.Item>\n ))}\n </Command.Group>\n ))}\n </Command.List>\n <div className=\"border-t border-border px-3 py-2 text-[10px] text-muted-foreground flex items-center gap-3\">\n <span>\n <kbd className=\"kbd\">↑↓</kbd> navigate\n </span>\n <span>\n <kbd className=\"kbd\">⏎</kbd> select\n </span>\n <span className=\"ml-auto\">\n <kbd className=\"kbd\">esc</kbd> close\n </span>\n </div>\n </Command>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n );\n}\n"]}
|
package/dist/data.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
type ProjectKind = "service" | "web" | "desktop" | "workstation" | "mobile" | "library" | "infra";
|
|
2
|
+
type ProjectStatus = "active" | "review" | "planning" | "archived";
|
|
3
|
+
type ForgeProject = {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
stack: string;
|
|
7
|
+
kind: ProjectKind;
|
|
8
|
+
devs: number;
|
|
9
|
+
status: ProjectStatus;
|
|
10
|
+
branch: string;
|
|
11
|
+
lastCommit: string;
|
|
12
|
+
openIssues: number;
|
|
13
|
+
prs: number;
|
|
14
|
+
sandbox: boolean;
|
|
15
|
+
};
|
|
16
|
+
type ForgeProduct = {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
tenant: "godx" | "kintai" | "tempo" | "betoya" | "restaurant";
|
|
20
|
+
role: string;
|
|
21
|
+
desc: string;
|
|
22
|
+
/** Brand color in OKLCH — used as the sidebar logo mark + accent. */
|
|
23
|
+
color: string;
|
|
24
|
+
owner: string;
|
|
25
|
+
devs: number;
|
|
26
|
+
projects: ForgeProject[];
|
|
27
|
+
};
|
|
28
|
+
declare const PRODUCTS: ForgeProduct[];
|
|
29
|
+
declare const PROJECT_KIND: Record<ProjectKind, {
|
|
30
|
+
color: string;
|
|
31
|
+
label: string;
|
|
32
|
+
}>;
|
|
33
|
+
declare function findProductByTenant(tenant: string): ForgeProduct | undefined;
|
|
34
|
+
|
|
35
|
+
export { type ForgeProduct, type ForgeProject, PRODUCTS, PROJECT_KIND, type ProjectKind, type ProjectStatus, findProductByTenant };
|
package/dist/data.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// src/data/products.ts
|
|
2
|
+
var PRODUCTS = [
|
|
3
|
+
{
|
|
4
|
+
id: "restaurant",
|
|
5
|
+
name: "godx-restaurant",
|
|
6
|
+
tenant: "restaurant",
|
|
7
|
+
role: "\u30EC\u30B9\u30C8\u30E9\u30F3\u7BA1\u7406",
|
|
8
|
+
desc: "\u5E97\u8217\u5411\u3051\u7D71\u5408\u7BA1\u7406\u30D7\u30E9\u30C3\u30C8\u30D5\u30A9\u30FC\u30E0",
|
|
9
|
+
color: "oklch(58% 0.18 25)",
|
|
10
|
+
owner: "Satoshi F",
|
|
11
|
+
devs: 6,
|
|
12
|
+
projects: [
|
|
13
|
+
{ id: "api", name: "restaurant-api", stack: "NestJS \xB7 PostgreSQL", kind: "service", devs: 3, status: "active", branch: "main", lastCommit: "12\u5206\u524D", openIssues: 8, prs: 2, sandbox: true },
|
|
14
|
+
{ id: "admin", name: "restaurant-admin", stack: "Next.js 14 \xB7 React", kind: "web", devs: 2, status: "active", branch: "main", lastCommit: "1\u6642\u9593\u524D", openIssues: 5, prs: 1, sandbox: true },
|
|
15
|
+
{ id: "pos", name: "restaurant-pos", stack: "Tauri \xB7 Vue 3", kind: "desktop", devs: 1, status: "active", branch: "feature/print", lastCommit: "30\u5206\u524D", openIssues: 3, prs: 1, sandbox: true },
|
|
16
|
+
{ id: "kds", name: "restaurant-kds", stack: "React \xB7 Electron", kind: "workstation", devs: 1, status: "review", branch: "main", lastCommit: "\u6628\u65E5", openIssues: 2, prs: 1, sandbox: true },
|
|
17
|
+
{ id: "kintai", name: "restaurant-kintai", stack: "Vue 3 \xB7 Laravel", kind: "service", devs: 2, status: "active", branch: "main", lastCommit: "5\u5206\u524D", openIssues: 4, prs: 0, sandbox: true },
|
|
18
|
+
{ id: "mobile", name: "restaurant-mobile", stack: "React Native", kind: "mobile", devs: 1, status: "planning", branch: "develop", lastCommit: "3\u65E5\u524D", openIssues: 1, prs: 0, sandbox: false }
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: "godx",
|
|
23
|
+
name: "godx-admin",
|
|
24
|
+
tenant: "godx",
|
|
25
|
+
role: "Platform admin",
|
|
26
|
+
desc: "GoDX Forge developer workspace",
|
|
27
|
+
color: "oklch(60% 0.137 163)",
|
|
28
|
+
owner: "Satoshi F",
|
|
29
|
+
devs: 4,
|
|
30
|
+
projects: [
|
|
31
|
+
{ id: "frontend", name: "godx-admin-frontend", stack: "React \xB7 Vite", kind: "web", devs: 2, status: "active", branch: "master", lastCommit: "2\u6642\u9593\u524D", openIssues: 6, prs: 2, sandbox: true },
|
|
32
|
+
{ id: "api", name: "godx-admin-api", stack: "Go \xB7 Gin", kind: "service", devs: 1, status: "active", branch: "master", lastCommit: "4\u6642\u9593\u524D", openIssues: 3, prs: 1, sandbox: true },
|
|
33
|
+
{ id: "ui", name: "@godxjp/ui", stack: "TypeScript \xB7 React", kind: "library", devs: 2, status: "active", branch: "master", lastCommit: "1\u6642\u9593\u524D", openIssues: 2, prs: 0, sandbox: false }
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: "kintai",
|
|
38
|
+
name: "dxs-kintai",
|
|
39
|
+
tenant: "kintai",
|
|
40
|
+
role: "HR / Attendance",
|
|
41
|
+
desc: "\u52E4\u6020\u7BA1\u7406\u30D7\u30E9\u30C3\u30C8\u30D5\u30A9\u30FC\u30E0",
|
|
42
|
+
color: "oklch(56% 0.15 240)",
|
|
43
|
+
owner: "Naoki N",
|
|
44
|
+
devs: 3,
|
|
45
|
+
projects: [
|
|
46
|
+
{ id: "frontend", name: "kintai-web", stack: "Vue 3 \xB7 Vite", kind: "web", devs: 2, status: "active", branch: "main", lastCommit: "20\u5206\u524D", openIssues: 7, prs: 1, sandbox: true },
|
|
47
|
+
{ id: "backend", name: "kintai-api", stack: "Laravel 11", kind: "service", devs: 1, status: "active", branch: "main", lastCommit: "1\u65E5\u524D", openIssues: 4, prs: 0, sandbox: true }
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: "tempo",
|
|
52
|
+
name: "dxs-tempo",
|
|
53
|
+
tenant: "tempo",
|
|
54
|
+
role: "Shop / Inventory",
|
|
55
|
+
desc: "\u5E97\u8217\u30FB\u5728\u5EAB\u30D0\u30C3\u30AF\u30A8\u30F3\u30C9",
|
|
56
|
+
color: "oklch(48% 0.16 285)",
|
|
57
|
+
owner: "Naoki N",
|
|
58
|
+
devs: 2,
|
|
59
|
+
projects: [
|
|
60
|
+
{ id: "api", name: "tempo-api", stack: "Go \xB7 Echo", kind: "service", devs: 2, status: "active", branch: "main", lastCommit: "5\u6642\u9593\u524D", openIssues: 9, prs: 1, sandbox: true },
|
|
61
|
+
{ id: "ops", name: "tempo-ops", stack: "Terraform", kind: "infra", devs: 1, status: "planning", branch: "main", lastCommit: "1\u9031\u9593\u524D", openIssues: 1, prs: 0, sandbox: false }
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: "betoya",
|
|
66
|
+
name: "betoya",
|
|
67
|
+
tenant: "betoya",
|
|
68
|
+
role: "Vietnamese restaurant",
|
|
69
|
+
desc: "\u30D9\u30C8\u5C4B Tenant",
|
|
70
|
+
color: "oklch(58% 0.159 150)",
|
|
71
|
+
owner: "Anh K",
|
|
72
|
+
devs: 1,
|
|
73
|
+
projects: [
|
|
74
|
+
{ id: "site", name: "betoya-site", stack: "Astro", kind: "web", devs: 1, status: "active", branch: "main", lastCommit: "\u6628\u65E5", openIssues: 2, prs: 0, sandbox: false }
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
];
|
|
78
|
+
var PROJECT_KIND = {
|
|
79
|
+
service: { color: "oklch(60% 0.137 163)", label: "API" },
|
|
80
|
+
web: { color: "oklch(56% 0.15 240)", label: "Web" },
|
|
81
|
+
desktop: { color: "oklch(48% 0.16 285)", label: "Desktop" },
|
|
82
|
+
workstation: { color: "oklch(50% 0.16 30)", label: "Workstation" },
|
|
83
|
+
mobile: { color: "oklch(58% 0.18 25)", label: "Mobile" },
|
|
84
|
+
library: { color: "oklch(50% 0.05 250)", label: "Library" },
|
|
85
|
+
infra: { color: "oklch(45% 0.05 260)", label: "Infra" }
|
|
86
|
+
};
|
|
87
|
+
function findProductByTenant(tenant) {
|
|
88
|
+
return PRODUCTS.find((p) => p.tenant === tenant);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export { PRODUCTS, PROJECT_KIND, findProductByTenant };
|
|
92
|
+
//# sourceMappingURL=data.js.map
|
|
93
|
+
//# sourceMappingURL=data.js.map
|
package/dist/data.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/data/products.ts"],"names":[],"mappings":"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","file":"data.js","sourcesContent":["// Product / project registry — mock data layer.\n//\n// Mirrors the design prototype's `PRODUCTS` array (shell.jsx). Today\n// this is a static fixture so the UI shell renders end-to-end; a\n// follow-up phase will swap it for `/api/v1/orgs/...` calls against\n// forge-service + identity-service.\n//\n// Vocabulary:\n// Product = Org (GitHub-shaped tenant). Owns projects, members,\n// domains, design tokens (per the OKLCH tenant override\n// in tokens-ext.css).\n// Project = Repo. Has a stack (e.g. \"Vue 3 · Vite\"), kind\n// (service / web / desktop / mobile / library / infra /\n// workstation), branch, lastCommit, openIssues, prs.\n//\n// Tenants must match a `[data-tenant=\"<id>\"]` block in tokens-ext.css.\nexport type ProjectKind =\n | \"service\"\n | \"web\"\n | \"desktop\"\n | \"workstation\"\n | \"mobile\"\n | \"library\"\n | \"infra\";\n\nexport type ProjectStatus = \"active\" | \"review\" | \"planning\" | \"archived\";\n\nexport type ForgeProject = {\n id: string;\n name: string;\n stack: string;\n kind: ProjectKind;\n devs: number;\n status: ProjectStatus;\n branch: string;\n lastCommit: string;\n openIssues: number;\n prs: number;\n sandbox: boolean;\n};\n\nexport type ForgeProduct = {\n id: string;\n name: string;\n tenant: \"godx\" | \"kintai\" | \"tempo\" | \"betoya\" | \"restaurant\";\n role: string;\n desc: string;\n /** Brand color in OKLCH — used as the sidebar logo mark + accent. */\n color: string;\n owner: string;\n devs: number;\n projects: ForgeProject[];\n};\n\nexport const PRODUCTS: ForgeProduct[] = [\n {\n id: \"restaurant\",\n name: \"godx-restaurant\",\n tenant: \"restaurant\",\n role: \"レストラン管理\",\n desc: \"店舗向け統合管理プラットフォーム\",\n color: \"oklch(58% 0.18 25)\",\n owner: \"Satoshi F\",\n devs: 6,\n projects: [\n { id: \"api\", name: \"restaurant-api\", stack: \"NestJS · PostgreSQL\", kind: \"service\", devs: 3, status: \"active\", branch: \"main\", lastCommit: \"12分前\", openIssues: 8, prs: 2, sandbox: true },\n { id: \"admin\", name: \"restaurant-admin\", stack: \"Next.js 14 · React\", kind: \"web\", devs: 2, status: \"active\", branch: \"main\", lastCommit: \"1時間前\", openIssues: 5, prs: 1, sandbox: true },\n { id: \"pos\", name: \"restaurant-pos\", stack: \"Tauri · Vue 3\", kind: \"desktop\", devs: 1, status: \"active\", branch: \"feature/print\", lastCommit: \"30分前\", openIssues: 3, prs: 1, sandbox: true },\n { id: \"kds\", name: \"restaurant-kds\", stack: \"React · Electron\", kind: \"workstation\", devs: 1, status: \"review\", branch: \"main\", lastCommit: \"昨日\", openIssues: 2, prs: 1, sandbox: true },\n { id: \"kintai\", name: \"restaurant-kintai\", stack: \"Vue 3 · Laravel\", kind: \"service\", devs: 2, status: \"active\", branch: \"main\", lastCommit: \"5分前\", openIssues: 4, prs: 0, sandbox: true },\n { id: \"mobile\", name: \"restaurant-mobile\", stack: \"React Native\", kind: \"mobile\", devs: 1, status: \"planning\", branch: \"develop\", lastCommit: \"3日前\", openIssues: 1, prs: 0, sandbox: false },\n ],\n },\n {\n id: \"godx\",\n name: \"godx-admin\",\n tenant: \"godx\",\n role: \"Platform admin\",\n desc: \"GoDX Forge developer workspace\",\n color: \"oklch(60% 0.137 163)\",\n owner: \"Satoshi F\",\n devs: 4,\n projects: [\n { id: \"frontend\", name: \"godx-admin-frontend\", stack: \"React · Vite\", kind: \"web\", devs: 2, status: \"active\", branch: \"master\", lastCommit: \"2時間前\", openIssues: 6, prs: 2, sandbox: true },\n { id: \"api\", name: \"godx-admin-api\", stack: \"Go · Gin\", kind: \"service\", devs: 1, status: \"active\", branch: \"master\", lastCommit: \"4時間前\", openIssues: 3, prs: 1, sandbox: true },\n { id: \"ui\", name: \"@godxjp/ui\", stack: \"TypeScript · React\", kind: \"library\", devs: 2, status: \"active\", branch: \"master\", lastCommit: \"1時間前\", openIssues: 2, prs: 0, sandbox: false },\n ],\n },\n {\n id: \"kintai\",\n name: \"dxs-kintai\",\n tenant: \"kintai\",\n role: \"HR / Attendance\",\n desc: \"勤怠管理プラットフォーム\",\n color: \"oklch(56% 0.15 240)\",\n owner: \"Naoki N\",\n devs: 3,\n projects: [\n { id: \"frontend\", name: \"kintai-web\", stack: \"Vue 3 · Vite\", kind: \"web\", devs: 2, status: \"active\", branch: \"main\", lastCommit: \"20分前\", openIssues: 7, prs: 1, sandbox: true },\n { id: \"backend\", name: \"kintai-api\", stack: \"Laravel 11\", kind: \"service\", devs: 1, status: \"active\", branch: \"main\", lastCommit: \"1日前\", openIssues: 4, prs: 0, sandbox: true },\n ],\n },\n {\n id: \"tempo\",\n name: \"dxs-tempo\",\n tenant: \"tempo\",\n role: \"Shop / Inventory\",\n desc: \"店舗・在庫バックエンド\",\n color: \"oklch(48% 0.16 285)\",\n owner: \"Naoki N\",\n devs: 2,\n projects: [\n { id: \"api\", name: \"tempo-api\", stack: \"Go · Echo\", kind: \"service\", devs: 2, status: \"active\", branch: \"main\", lastCommit: \"5時間前\", openIssues: 9, prs: 1, sandbox: true },\n { id: \"ops\", name: \"tempo-ops\", stack: \"Terraform\", kind: \"infra\", devs: 1, status: \"planning\", branch: \"main\", lastCommit: \"1週間前\", openIssues: 1, prs: 0, sandbox: false },\n ],\n },\n {\n id: \"betoya\",\n name: \"betoya\",\n tenant: \"betoya\",\n role: \"Vietnamese restaurant\",\n desc: \"ベト屋 Tenant\",\n color: \"oklch(58% 0.159 150)\",\n owner: \"Anh K\",\n devs: 1,\n projects: [\n { id: \"site\", name: \"betoya-site\", stack: \"Astro\", kind: \"web\", devs: 1, status: \"active\", branch: \"main\", lastCommit: \"昨日\", openIssues: 2, prs: 0, sandbox: false },\n ],\n },\n];\n\nexport const PROJECT_KIND: Record<ProjectKind, { color: string; label: string }> = {\n service: { color: \"oklch(60% 0.137 163)\", label: \"API\" },\n web: { color: \"oklch(56% 0.15 240)\", label: \"Web\" },\n desktop: { color: \"oklch(48% 0.16 285)\", label: \"Desktop\" },\n workstation: { color: \"oklch(50% 0.16 30)\", label: \"Workstation\" },\n mobile: { color: \"oklch(58% 0.18 25)\", label: \"Mobile\" },\n library: { color: \"oklch(50% 0.05 250)\", label: \"Library\" },\n infra: { color: \"oklch(45% 0.05 260)\", label: \"Infra\" },\n};\n\nexport function findProductByTenant(tenant: string): ForgeProduct | undefined {\n return PRODUCTS.find((p) => p.tenant === tenant);\n}\n"]}
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ForgeLocale } from './i18n.js';
|
|
3
|
+
import { ForgeProduct } from './data.js';
|
|
4
|
+
import 'i18next';
|
|
5
|
+
|
|
6
|
+
type Density = "compact" | "default" | "comfortable";
|
|
7
|
+
type Theme = "light" | "dark";
|
|
8
|
+
type Tweaks = {
|
|
9
|
+
density: Density;
|
|
10
|
+
theme: Theme;
|
|
11
|
+
tenant: ForgeProduct["tenant"];
|
|
12
|
+
locale: ForgeLocale;
|
|
13
|
+
sidebarCollapsed: boolean;
|
|
14
|
+
};
|
|
15
|
+
declare function useTweaks(): {
|
|
16
|
+
readonly tweaks: Tweaks;
|
|
17
|
+
readonly setTweak: <K extends keyof Tweaks>(key: K, value: Tweaks[K]) => void;
|
|
18
|
+
readonly setTweaks: react.Dispatch<react.SetStateAction<Tweaks>>;
|
|
19
|
+
};
|
|
20
|
+
declare const PRODUCT_OPTIONS: {
|
|
21
|
+
value: "godx" | "kintai" | "tempo" | "betoya" | "restaurant";
|
|
22
|
+
label: string;
|
|
23
|
+
}[];
|
|
24
|
+
|
|
25
|
+
export { type Density, PRODUCT_OPTIONS, type Theme, type Tweaks, useTweaks };
|
package/dist/hooks.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
2
|
+
import i18next from 'i18next';
|
|
3
|
+
import 'i18next-browser-languagedetector';
|
|
4
|
+
import 'react-i18next';
|
|
5
|
+
|
|
6
|
+
var FORGE_LOCALE_STORAGE_KEY = "forge.locale";
|
|
7
|
+
var i18n_default = i18next;
|
|
8
|
+
|
|
9
|
+
// src/data/products.ts
|
|
10
|
+
var PRODUCTS = [
|
|
11
|
+
{
|
|
12
|
+
id: "restaurant",
|
|
13
|
+
name: "godx-restaurant",
|
|
14
|
+
tenant: "restaurant",
|
|
15
|
+
role: "\u30EC\u30B9\u30C8\u30E9\u30F3\u7BA1\u7406",
|
|
16
|
+
desc: "\u5E97\u8217\u5411\u3051\u7D71\u5408\u7BA1\u7406\u30D7\u30E9\u30C3\u30C8\u30D5\u30A9\u30FC\u30E0",
|
|
17
|
+
color: "oklch(58% 0.18 25)",
|
|
18
|
+
owner: "Satoshi F",
|
|
19
|
+
devs: 6,
|
|
20
|
+
projects: [
|
|
21
|
+
{ id: "api", name: "restaurant-api", stack: "NestJS \xB7 PostgreSQL", kind: "service", devs: 3, status: "active", branch: "main", lastCommit: "12\u5206\u524D", openIssues: 8, prs: 2, sandbox: true },
|
|
22
|
+
{ id: "admin", name: "restaurant-admin", stack: "Next.js 14 \xB7 React", kind: "web", devs: 2, status: "active", branch: "main", lastCommit: "1\u6642\u9593\u524D", openIssues: 5, prs: 1, sandbox: true },
|
|
23
|
+
{ id: "pos", name: "restaurant-pos", stack: "Tauri \xB7 Vue 3", kind: "desktop", devs: 1, status: "active", branch: "feature/print", lastCommit: "30\u5206\u524D", openIssues: 3, prs: 1, sandbox: true },
|
|
24
|
+
{ id: "kds", name: "restaurant-kds", stack: "React \xB7 Electron", kind: "workstation", devs: 1, status: "review", branch: "main", lastCommit: "\u6628\u65E5", openIssues: 2, prs: 1, sandbox: true },
|
|
25
|
+
{ id: "kintai", name: "restaurant-kintai", stack: "Vue 3 \xB7 Laravel", kind: "service", devs: 2, status: "active", branch: "main", lastCommit: "5\u5206\u524D", openIssues: 4, prs: 0, sandbox: true },
|
|
26
|
+
{ id: "mobile", name: "restaurant-mobile", stack: "React Native", kind: "mobile", devs: 1, status: "planning", branch: "develop", lastCommit: "3\u65E5\u524D", openIssues: 1, prs: 0, sandbox: false }
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: "godx",
|
|
31
|
+
name: "godx-admin",
|
|
32
|
+
tenant: "godx",
|
|
33
|
+
role: "Platform admin",
|
|
34
|
+
desc: "GoDX Forge developer workspace",
|
|
35
|
+
color: "oklch(60% 0.137 163)",
|
|
36
|
+
owner: "Satoshi F",
|
|
37
|
+
devs: 4,
|
|
38
|
+
projects: [
|
|
39
|
+
{ id: "frontend", name: "godx-admin-frontend", stack: "React \xB7 Vite", kind: "web", devs: 2, status: "active", branch: "master", lastCommit: "2\u6642\u9593\u524D", openIssues: 6, prs: 2, sandbox: true },
|
|
40
|
+
{ id: "api", name: "godx-admin-api", stack: "Go \xB7 Gin", kind: "service", devs: 1, status: "active", branch: "master", lastCommit: "4\u6642\u9593\u524D", openIssues: 3, prs: 1, sandbox: true },
|
|
41
|
+
{ id: "ui", name: "@godxjp/ui", stack: "TypeScript \xB7 React", kind: "library", devs: 2, status: "active", branch: "master", lastCommit: "1\u6642\u9593\u524D", openIssues: 2, prs: 0, sandbox: false }
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "kintai",
|
|
46
|
+
name: "dxs-kintai",
|
|
47
|
+
tenant: "kintai",
|
|
48
|
+
role: "HR / Attendance",
|
|
49
|
+
desc: "\u52E4\u6020\u7BA1\u7406\u30D7\u30E9\u30C3\u30C8\u30D5\u30A9\u30FC\u30E0",
|
|
50
|
+
color: "oklch(56% 0.15 240)",
|
|
51
|
+
owner: "Naoki N",
|
|
52
|
+
devs: 3,
|
|
53
|
+
projects: [
|
|
54
|
+
{ id: "frontend", name: "kintai-web", stack: "Vue 3 \xB7 Vite", kind: "web", devs: 2, status: "active", branch: "main", lastCommit: "20\u5206\u524D", openIssues: 7, prs: 1, sandbox: true },
|
|
55
|
+
{ id: "backend", name: "kintai-api", stack: "Laravel 11", kind: "service", devs: 1, status: "active", branch: "main", lastCommit: "1\u65E5\u524D", openIssues: 4, prs: 0, sandbox: true }
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: "tempo",
|
|
60
|
+
name: "dxs-tempo",
|
|
61
|
+
tenant: "tempo",
|
|
62
|
+
role: "Shop / Inventory",
|
|
63
|
+
desc: "\u5E97\u8217\u30FB\u5728\u5EAB\u30D0\u30C3\u30AF\u30A8\u30F3\u30C9",
|
|
64
|
+
color: "oklch(48% 0.16 285)",
|
|
65
|
+
owner: "Naoki N",
|
|
66
|
+
devs: 2,
|
|
67
|
+
projects: [
|
|
68
|
+
{ id: "api", name: "tempo-api", stack: "Go \xB7 Echo", kind: "service", devs: 2, status: "active", branch: "main", lastCommit: "5\u6642\u9593\u524D", openIssues: 9, prs: 1, sandbox: true },
|
|
69
|
+
{ id: "ops", name: "tempo-ops", stack: "Terraform", kind: "infra", devs: 1, status: "planning", branch: "main", lastCommit: "1\u9031\u9593\u524D", openIssues: 1, prs: 0, sandbox: false }
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: "betoya",
|
|
74
|
+
name: "betoya",
|
|
75
|
+
tenant: "betoya",
|
|
76
|
+
role: "Vietnamese restaurant",
|
|
77
|
+
desc: "\u30D9\u30C8\u5C4B Tenant",
|
|
78
|
+
color: "oklch(58% 0.159 150)",
|
|
79
|
+
owner: "Anh K",
|
|
80
|
+
devs: 1,
|
|
81
|
+
projects: [
|
|
82
|
+
{ id: "site", name: "betoya-site", stack: "Astro", kind: "web", devs: 1, status: "active", branch: "main", lastCommit: "\u6628\u65E5", openIssues: 2, prs: 0, sandbox: false }
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
// src/hooks/useTweaks.ts
|
|
88
|
+
var STORAGE_KEY = "forge.tweaks";
|
|
89
|
+
var DEFAULTS = {
|
|
90
|
+
density: "default",
|
|
91
|
+
theme: "light",
|
|
92
|
+
tenant: "godx",
|
|
93
|
+
locale: "ja",
|
|
94
|
+
sidebarCollapsed: false
|
|
95
|
+
};
|
|
96
|
+
function loadInitial() {
|
|
97
|
+
if (typeof window === "undefined") return DEFAULTS;
|
|
98
|
+
try {
|
|
99
|
+
const raw = window.localStorage.getItem(STORAGE_KEY);
|
|
100
|
+
const stored = raw ? JSON.parse(raw) : {};
|
|
101
|
+
const detected = i18n_default.language?.slice(0, 2) || "ja";
|
|
102
|
+
return {
|
|
103
|
+
...DEFAULTS,
|
|
104
|
+
...stored,
|
|
105
|
+
locale: stored.locale ?? detected
|
|
106
|
+
};
|
|
107
|
+
} catch {
|
|
108
|
+
return DEFAULTS;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function useTweaks() {
|
|
112
|
+
const [tweaks, setTweaks] = useState(loadInitial);
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
try {
|
|
115
|
+
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(tweaks));
|
|
116
|
+
} catch {
|
|
117
|
+
}
|
|
118
|
+
}, [tweaks]);
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
const html = document.documentElement;
|
|
121
|
+
html.dataset.theme = tweaks.theme;
|
|
122
|
+
html.dataset.density = tweaks.density;
|
|
123
|
+
html.dataset.tenant = tweaks.tenant;
|
|
124
|
+
html.lang = tweaks.locale;
|
|
125
|
+
}, [tweaks.theme, tweaks.density, tweaks.tenant, tweaks.locale]);
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
if (i18n_default.language?.slice(0, 2) !== tweaks.locale) {
|
|
128
|
+
void i18n_default.changeLanguage(tweaks.locale);
|
|
129
|
+
try {
|
|
130
|
+
window.localStorage.setItem(FORGE_LOCALE_STORAGE_KEY, tweaks.locale);
|
|
131
|
+
} catch {
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}, [tweaks.locale]);
|
|
135
|
+
const setTweak = useCallback((key, value) => {
|
|
136
|
+
setTweaks((prev) => ({ ...prev, [key]: value }));
|
|
137
|
+
}, []);
|
|
138
|
+
return { tweaks, setTweak, setTweaks };
|
|
139
|
+
}
|
|
140
|
+
var PRODUCT_OPTIONS = PRODUCTS.map((p) => ({ value: p.tenant, label: p.name }));
|
|
141
|
+
|
|
142
|
+
export { PRODUCT_OPTIONS, useTweaks };
|
|
143
|
+
//# sourceMappingURL=hooks.js.map
|
|
144
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/i18n/index.ts","../src/data/products.ts","../src/hooks/useTweaks.ts"],"names":[],"mappings":"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","file":"hooks.js","sourcesContent":["// GoDX Forge i18n bootstrap.\n//\n// Locale resolution order:\n// 1. localStorage[\"forge.locale\"] (user override via Tweaks panel)\n// 2. navigator.language prefix (ja-JP → ja, en-US → en, vi-VN → vi)\n// 3. JA fallback (design's primary locale)\n//\n// Supported locales follow the design prototype (chats + ui-kit.jsx): ja / en / vi.\nimport i18next from \"i18next\";\nimport LanguageDetector from \"i18next-browser-languagedetector\";\nimport { initReactI18next } from \"react-i18next\";\n\nimport ja from \"./locales/ja\";\nimport en from \"./locales/en\";\nimport vi from \"./locales/vi\";\n\nexport const SUPPORTED_LOCALES = [\"ja\", \"en\", \"vi\"] as const;\nexport type ForgeLocale = (typeof SUPPORTED_LOCALES)[number];\n\nexport const FORGE_LOCALE_STORAGE_KEY = \"forge.locale\";\n\nexport function initI18n(): typeof i18next {\n void i18next\n .use(LanguageDetector)\n .use(initReactI18next)\n .init({\n resources: {\n ja: { translation: ja },\n en: { translation: en },\n vi: { translation: vi },\n },\n fallbackLng: \"ja\",\n supportedLngs: SUPPORTED_LOCALES,\n load: \"languageOnly\",\n interpolation: { escapeValue: false },\n detection: {\n order: [\"localStorage\", \"navigator\"],\n lookupLocalStorage: FORGE_LOCALE_STORAGE_KEY,\n caches: [\"localStorage\"],\n },\n });\n return i18next;\n}\n\nexport default i18next;\n","// Product / project registry — mock data layer.\n//\n// Mirrors the design prototype's `PRODUCTS` array (shell.jsx). Today\n// this is a static fixture so the UI shell renders end-to-end; a\n// follow-up phase will swap it for `/api/v1/orgs/...` calls against\n// forge-service + identity-service.\n//\n// Vocabulary:\n// Product = Org (GitHub-shaped tenant). Owns projects, members,\n// domains, design tokens (per the OKLCH tenant override\n// in tokens-ext.css).\n// Project = Repo. Has a stack (e.g. \"Vue 3 · Vite\"), kind\n// (service / web / desktop / mobile / library / infra /\n// workstation), branch, lastCommit, openIssues, prs.\n//\n// Tenants must match a `[data-tenant=\"<id>\"]` block in tokens-ext.css.\nexport type ProjectKind =\n | \"service\"\n | \"web\"\n | \"desktop\"\n | \"workstation\"\n | \"mobile\"\n | \"library\"\n | \"infra\";\n\nexport type ProjectStatus = \"active\" | \"review\" | \"planning\" | \"archived\";\n\nexport type ForgeProject = {\n id: string;\n name: string;\n stack: string;\n kind: ProjectKind;\n devs: number;\n status: ProjectStatus;\n branch: string;\n lastCommit: string;\n openIssues: number;\n prs: number;\n sandbox: boolean;\n};\n\nexport type ForgeProduct = {\n id: string;\n name: string;\n tenant: \"godx\" | \"kintai\" | \"tempo\" | \"betoya\" | \"restaurant\";\n role: string;\n desc: string;\n /** Brand color in OKLCH — used as the sidebar logo mark + accent. */\n color: string;\n owner: string;\n devs: number;\n projects: ForgeProject[];\n};\n\nexport const PRODUCTS: ForgeProduct[] = [\n {\n id: \"restaurant\",\n name: \"godx-restaurant\",\n tenant: \"restaurant\",\n role: \"レストラン管理\",\n desc: \"店舗向け統合管理プラットフォーム\",\n color: \"oklch(58% 0.18 25)\",\n owner: \"Satoshi F\",\n devs: 6,\n projects: [\n { id: \"api\", name: \"restaurant-api\", stack: \"NestJS · PostgreSQL\", kind: \"service\", devs: 3, status: \"active\", branch: \"main\", lastCommit: \"12分前\", openIssues: 8, prs: 2, sandbox: true },\n { id: \"admin\", name: \"restaurant-admin\", stack: \"Next.js 14 · React\", kind: \"web\", devs: 2, status: \"active\", branch: \"main\", lastCommit: \"1時間前\", openIssues: 5, prs: 1, sandbox: true },\n { id: \"pos\", name: \"restaurant-pos\", stack: \"Tauri · Vue 3\", kind: \"desktop\", devs: 1, status: \"active\", branch: \"feature/print\", lastCommit: \"30分前\", openIssues: 3, prs: 1, sandbox: true },\n { id: \"kds\", name: \"restaurant-kds\", stack: \"React · Electron\", kind: \"workstation\", devs: 1, status: \"review\", branch: \"main\", lastCommit: \"昨日\", openIssues: 2, prs: 1, sandbox: true },\n { id: \"kintai\", name: \"restaurant-kintai\", stack: \"Vue 3 · Laravel\", kind: \"service\", devs: 2, status: \"active\", branch: \"main\", lastCommit: \"5分前\", openIssues: 4, prs: 0, sandbox: true },\n { id: \"mobile\", name: \"restaurant-mobile\", stack: \"React Native\", kind: \"mobile\", devs: 1, status: \"planning\", branch: \"develop\", lastCommit: \"3日前\", openIssues: 1, prs: 0, sandbox: false },\n ],\n },\n {\n id: \"godx\",\n name: \"godx-admin\",\n tenant: \"godx\",\n role: \"Platform admin\",\n desc: \"GoDX Forge developer workspace\",\n color: \"oklch(60% 0.137 163)\",\n owner: \"Satoshi F\",\n devs: 4,\n projects: [\n { id: \"frontend\", name: \"godx-admin-frontend\", stack: \"React · Vite\", kind: \"web\", devs: 2, status: \"active\", branch: \"master\", lastCommit: \"2時間前\", openIssues: 6, prs: 2, sandbox: true },\n { id: \"api\", name: \"godx-admin-api\", stack: \"Go · Gin\", kind: \"service\", devs: 1, status: \"active\", branch: \"master\", lastCommit: \"4時間前\", openIssues: 3, prs: 1, sandbox: true },\n { id: \"ui\", name: \"@godxjp/ui\", stack: \"TypeScript · React\", kind: \"library\", devs: 2, status: \"active\", branch: \"master\", lastCommit: \"1時間前\", openIssues: 2, prs: 0, sandbox: false },\n ],\n },\n {\n id: \"kintai\",\n name: \"dxs-kintai\",\n tenant: \"kintai\",\n role: \"HR / Attendance\",\n desc: \"勤怠管理プラットフォーム\",\n color: \"oklch(56% 0.15 240)\",\n owner: \"Naoki N\",\n devs: 3,\n projects: [\n { id: \"frontend\", name: \"kintai-web\", stack: \"Vue 3 · Vite\", kind: \"web\", devs: 2, status: \"active\", branch: \"main\", lastCommit: \"20分前\", openIssues: 7, prs: 1, sandbox: true },\n { id: \"backend\", name: \"kintai-api\", stack: \"Laravel 11\", kind: \"service\", devs: 1, status: \"active\", branch: \"main\", lastCommit: \"1日前\", openIssues: 4, prs: 0, sandbox: true },\n ],\n },\n {\n id: \"tempo\",\n name: \"dxs-tempo\",\n tenant: \"tempo\",\n role: \"Shop / Inventory\",\n desc: \"店舗・在庫バックエンド\",\n color: \"oklch(48% 0.16 285)\",\n owner: \"Naoki N\",\n devs: 2,\n projects: [\n { id: \"api\", name: \"tempo-api\", stack: \"Go · Echo\", kind: \"service\", devs: 2, status: \"active\", branch: \"main\", lastCommit: \"5時間前\", openIssues: 9, prs: 1, sandbox: true },\n { id: \"ops\", name: \"tempo-ops\", stack: \"Terraform\", kind: \"infra\", devs: 1, status: \"planning\", branch: \"main\", lastCommit: \"1週間前\", openIssues: 1, prs: 0, sandbox: false },\n ],\n },\n {\n id: \"betoya\",\n name: \"betoya\",\n tenant: \"betoya\",\n role: \"Vietnamese restaurant\",\n desc: \"ベト屋 Tenant\",\n color: \"oklch(58% 0.159 150)\",\n owner: \"Anh K\",\n devs: 1,\n projects: [\n { id: \"site\", name: \"betoya-site\", stack: \"Astro\", kind: \"web\", devs: 1, status: \"active\", branch: \"main\", lastCommit: \"昨日\", openIssues: 2, prs: 0, sandbox: false },\n ],\n },\n];\n\nexport const PROJECT_KIND: Record<ProjectKind, { color: string; label: string }> = {\n service: { color: \"oklch(60% 0.137 163)\", label: \"API\" },\n web: { color: \"oklch(56% 0.15 240)\", label: \"Web\" },\n desktop: { color: \"oklch(48% 0.16 285)\", label: \"Desktop\" },\n workstation: { color: \"oklch(50% 0.16 30)\", label: \"Workstation\" },\n mobile: { color: \"oklch(58% 0.18 25)\", label: \"Mobile\" },\n library: { color: \"oklch(50% 0.05 250)\", label: \"Library\" },\n infra: { color: \"oklch(45% 0.05 260)\", label: \"Infra\" },\n};\n\nexport function findProductByTenant(tenant: string): ForgeProduct | undefined {\n return PRODUCTS.find((p) => p.tenant === tenant);\n}\n","// useTweaks — shared client state for the design system's Tweaks panel.\n//\n// Mirrors the design prototype `useTweaks` hook (tweaks-panel.jsx). Each\n// tweak is persisted to localStorage so reloads keep the user's chosen\n// density / theme / tenant / sidebar-collapsed setting. Locale is owned\n// by i18next (see src/i18n/index.ts) but exposed through this hook so\n// the Tweaks UI has a single dispatcher.\nimport { useCallback, useEffect, useState } from \"react\";\nimport i18n, { FORGE_LOCALE_STORAGE_KEY, type ForgeLocale } from \"../i18n\";\nimport { PRODUCTS, type ForgeProduct } from \"../data/products\";\n\nexport type Density = \"compact\" | \"default\" | \"comfortable\";\nexport type Theme = \"light\" | \"dark\";\n\nexport type Tweaks = {\n density: Density;\n theme: Theme;\n tenant: ForgeProduct[\"tenant\"];\n locale: ForgeLocale;\n sidebarCollapsed: boolean;\n};\n\nconst STORAGE_KEY = \"forge.tweaks\";\n\nconst DEFAULTS: Tweaks = {\n density: \"default\",\n theme: \"light\",\n tenant: \"godx\",\n locale: \"ja\",\n sidebarCollapsed: false,\n};\n\nfunction loadInitial(): Tweaks {\n if (typeof window === \"undefined\") return DEFAULTS;\n try {\n const raw = window.localStorage.getItem(STORAGE_KEY);\n const stored = raw ? (JSON.parse(raw) as Partial<Tweaks>) : {};\n const detected = (i18n.language?.slice(0, 2) || \"ja\") as ForgeLocale;\n return {\n ...DEFAULTS,\n ...stored,\n locale: (stored.locale ?? detected) as ForgeLocale,\n };\n } catch {\n return DEFAULTS;\n }\n}\n\nexport function useTweaks() {\n const [tweaks, setTweaks] = useState<Tweaks>(loadInitial);\n\n // Persist every change to localStorage.\n useEffect(() => {\n try {\n window.localStorage.setItem(STORAGE_KEY, JSON.stringify(tweaks));\n } catch {\n /* Storage may be disabled (private mode). Silently degrade. */\n }\n }, [tweaks]);\n\n // Reflect tweaks onto <html> so the design tokens (CSS custom\n // properties scoped to [data-tenant=…], [data-theme=…], [data-density=…])\n // pick up the change without rerunning React.\n useEffect(() => {\n const html = document.documentElement;\n html.dataset.theme = tweaks.theme;\n html.dataset.density = tweaks.density;\n html.dataset.tenant = tweaks.tenant;\n html.lang = tweaks.locale;\n }, [tweaks.theme, tweaks.density, tweaks.tenant, tweaks.locale]);\n\n // Forward locale changes to i18next so the UI re-renders strings.\n useEffect(() => {\n if (i18n.language?.slice(0, 2) !== tweaks.locale) {\n void i18n.changeLanguage(tweaks.locale);\n try {\n window.localStorage.setItem(FORGE_LOCALE_STORAGE_KEY, tweaks.locale);\n } catch {\n /* ignore */\n }\n }\n }, [tweaks.locale]);\n\n const setTweak = useCallback(<K extends keyof Tweaks>(key: K, value: Tweaks[K]) => {\n setTweaks((prev) => ({ ...prev, [key]: value }));\n }, []);\n\n return { tweaks, setTweak, setTweaks } as const;\n}\n\nexport const PRODUCT_OPTIONS = PRODUCTS.map((p) => ({ value: p.tenant, label: p.name }));\n"]}
|
package/dist/i18n.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import i18next from 'i18next';
|
|
2
|
+
export { default } from 'i18next';
|
|
3
|
+
|
|
4
|
+
declare const SUPPORTED_LOCALES: readonly ["ja", "en", "vi"];
|
|
5
|
+
type ForgeLocale = (typeof SUPPORTED_LOCALES)[number];
|
|
6
|
+
declare const FORGE_LOCALE_STORAGE_KEY = "forge.locale";
|
|
7
|
+
declare function initI18n(): typeof i18next;
|
|
8
|
+
|
|
9
|
+
export { FORGE_LOCALE_STORAGE_KEY, type ForgeLocale, SUPPORTED_LOCALES, initI18n };
|