@godxjp/ui 2.1.0 → 5.0.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 +39 -29
- package/CHANGELOG.md +554 -10
- package/README.md +143 -168
- package/config/eslint.js +54 -0
- package/config/prettier.cjs +20 -0
- package/config/tsconfig.base.json +22 -0
- package/config/vitest.base.ts +26 -0
- package/dist/MiniMonth-YAmPGEpC.d.ts +143 -0
- package/dist/Table.types-BbsxoIYE.d.ts +352 -0
- package/dist/color-DO0qqUAb.d.ts +38 -0
- package/dist/components/composites.d.ts +963 -0
- package/dist/components/composites.js +7340 -0
- package/dist/components/composites.js.map +1 -0
- package/dist/components/primitives.d.ts +2633 -163
- package/dist/components/primitives.js +7264 -165
- package/dist/components/primitives.js.map +1 -1
- package/dist/components/shell.d.ts +82 -12
- package/dist/components/shell.js +168 -162
- package/dist/components/shell.js.map +1 -1
- package/dist/hooks.d.ts +83 -8
- package/dist/hooks.js +497 -83
- package/dist/hooks.js.map +1 -1
- package/dist/i18n.d.ts +55 -3
- package/dist/i18n.js +456 -5
- package/dist/i18n.js.map +1 -1
- package/dist/index.d.ts +24 -5
- package/dist/index.js +12522 -267
- package/dist/index.js.map +1 -1
- package/dist/padding-DY0JV5Ja.d.ts +16 -0
- package/dist/preferences.d.ts +132 -0
- package/dist/preferences.js +262 -0
- package/dist/preferences.js.map +1 -0
- package/dist/props.d.ts +86 -0
- package/dist/props.js +16 -0
- package/dist/props.js.map +1 -0
- package/dist/size-CQwNvOWd.d.ts +19 -0
- package/dist/{data.d.ts → types-LTj-2bl-.d.ts} +7 -12
- package/dist/useTableViews-D5NIAJ7h.d.ts +154 -0
- package/package.json +92 -34
- package/src/tokens/tailwind.css +158 -0
- package/dist/components/screens.d.ts +0 -51
- package/dist/components/screens.js +0 -806
- package/dist/components/screens.js.map +0 -1
- package/dist/data.js +0 -93
- package/dist/data.js.map +0 -1
- package/src/tokens/tokens.css +0 -765
|
@@ -1,19 +1,34 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode, ComponentType } from 'react';
|
|
3
|
-
import { ForgeProduct, ForgeProject } from '../
|
|
3
|
+
import { F as ForgeProduct, a as ForgeProject } from '../types-LTj-2bl-.js';
|
|
4
|
+
export { P as ProjectKind, b as ProjectStatus } from '../types-LTj-2bl-.js';
|
|
5
|
+
import { P as PaddingProp } from '../padding-DY0JV5Ja.js';
|
|
4
6
|
|
|
5
7
|
interface AppShellProps {
|
|
8
|
+
/** Sidebar content — usually `<Sidebar … />` from this package. */
|
|
6
9
|
sidebar: ReactNode;
|
|
7
|
-
|
|
10
|
+
/** Main content — page or `<Outlet />`. */
|
|
8
11
|
children: ReactNode;
|
|
9
12
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
+
* Topbar slot. Provide EITHER `topbar` for a single composed header
|
|
14
|
+
* (e.g. `<Topbar … />` from this package) OR `topbarLeft` +
|
|
15
|
+
* `topbarRight` to lay out two slot groups within the canonical
|
|
16
|
+
* header rail. Mixing `topbar` with the split slots is allowed —
|
|
17
|
+
* the single `topbar` wins.
|
|
13
18
|
*/
|
|
19
|
+
topbar?: ReactNode;
|
|
20
|
+
topbarLeft?: ReactNode;
|
|
21
|
+
topbarRight?: ReactNode;
|
|
22
|
+
/** Optional logo / brand mark — rendered at the top-left of the topbar. */
|
|
23
|
+
logo?: ReactNode;
|
|
24
|
+
/** Optional breadcrumb rail — sits just above main content. */
|
|
25
|
+
breadcrumb?: ReactNode;
|
|
26
|
+
/** Optional footer band under main content. */
|
|
27
|
+
footer?: ReactNode;
|
|
28
|
+
/** Sidebar collapsed state — mirror onto `<html data-collapsed>` via useTweaks. */
|
|
14
29
|
sidebarCollapsed?: boolean;
|
|
15
30
|
}
|
|
16
|
-
declare function AppShell({ sidebar, topbar, children, sidebarCollapsed }: AppShellProps): react_jsx_runtime.JSX.Element;
|
|
31
|
+
declare function AppShell({ sidebar, topbar, topbarLeft, topbarRight, logo, breadcrumb, footer, children, sidebarCollapsed, }: AppShellProps): react_jsx_runtime.JSX.Element;
|
|
17
32
|
|
|
18
33
|
interface SidebarItem {
|
|
19
34
|
id: string;
|
|
@@ -37,14 +52,23 @@ interface SidebarProps {
|
|
|
37
52
|
/** Click handler — called with the item's `id`. */
|
|
38
53
|
onSelect: (id: string) => void;
|
|
39
54
|
sections: SidebarSection[];
|
|
40
|
-
/**
|
|
41
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Product = the org-shaped tenant shown in the top product chip.
|
|
57
|
+
* Required unless `brand` is provided (custom top slot wins).
|
|
58
|
+
*/
|
|
59
|
+
product?: ForgeProduct;
|
|
42
60
|
/** Click to open the product switcher dropdown (owned by parent). */
|
|
43
61
|
onProductClick?: () => void;
|
|
62
|
+
/**
|
|
63
|
+
* Custom top-of-sidebar slot — when present, replaces the product
|
|
64
|
+
* chip entirely. Use for service-specific brands (e.g. me-service
|
|
65
|
+
* renders the signed-in user's avatar + name + email here).
|
|
66
|
+
*/
|
|
67
|
+
brand?: ReactNode;
|
|
44
68
|
collapsed?: boolean;
|
|
45
69
|
footer?: ReactNode;
|
|
46
70
|
}
|
|
47
|
-
declare function Sidebar({ activeId, onSelect, sections, product, onProductClick, collapsed, footer, }: SidebarProps): react_jsx_runtime.JSX.Element;
|
|
71
|
+
declare function Sidebar({ activeId, onSelect, sections, product, onProductClick, brand, collapsed, footer, }: SidebarProps): react_jsx_runtime.JSX.Element;
|
|
48
72
|
|
|
49
73
|
interface TopbarProps {
|
|
50
74
|
product: ForgeProduct;
|
|
@@ -57,14 +81,30 @@ interface TopbarProps {
|
|
|
57
81
|
onToggleCollapsed?: () => void;
|
|
58
82
|
/** Optional breadcrumb / actions slot on the right. */
|
|
59
83
|
rightSlot?: ReactNode;
|
|
84
|
+
/**
|
|
85
|
+
* Notification bell. When `unread` is true a 6×6 attention-colored
|
|
86
|
+
* dot renders in the top-right corner. Click handler invokes
|
|
87
|
+
* `onNotificationsOpen`. Hidden when both are unset.
|
|
88
|
+
*/
|
|
89
|
+
unread?: boolean;
|
|
90
|
+
onNotificationsOpen?: () => void;
|
|
91
|
+
/**
|
|
92
|
+
* Right-edge user chip. Rendered as the trailing element (after
|
|
93
|
+
* notifications, before tweaks) to match the design-handoff topbar
|
|
94
|
+
* shape (shell.jsx:366). Pass any node — typically a `<Avatar>` or
|
|
95
|
+
* a `<DropdownMenu>` wrapping one.
|
|
96
|
+
*/
|
|
97
|
+
user?: ReactNode;
|
|
60
98
|
}
|
|
61
|
-
declare function Topbar({ product, project, onProductOpen, onProjectOpen, onSearchOpen, onTweaksOpen, collapsed, onToggleCollapsed, rightSlot, }: TopbarProps): react_jsx_runtime.JSX.Element;
|
|
99
|
+
declare function Topbar({ product, project, onProductOpen, onProjectOpen, onSearchOpen, onTweaksOpen, collapsed, onToggleCollapsed, rightSlot, unread, onNotificationsOpen, user, }: TopbarProps): react_jsx_runtime.JSX.Element;
|
|
62
100
|
|
|
63
101
|
interface TweaksPanelProps {
|
|
64
102
|
open: boolean;
|
|
65
103
|
onOpenChange: (open: boolean) => void;
|
|
104
|
+
/** Product catalogue for the tenant selector. Pass `[]` to hide. */
|
|
105
|
+
products?: ForgeProduct[];
|
|
66
106
|
}
|
|
67
|
-
declare function TweaksPanel({ open, onOpenChange }: TweaksPanelProps): react_jsx_runtime.JSX.Element;
|
|
107
|
+
declare function TweaksPanel({ open, onOpenChange, products }: TweaksPanelProps): react_jsx_runtime.JSX.Element;
|
|
68
108
|
|
|
69
109
|
interface ProductSwitcherProps {
|
|
70
110
|
trigger: ReactNode;
|
|
@@ -109,4 +149,34 @@ interface CommandPaletteProps {
|
|
|
109
149
|
}
|
|
110
150
|
declare function CommandPalette({ open, onOpenChange, commands }: CommandPaletteProps): react_jsx_runtime.JSX.Element;
|
|
111
151
|
|
|
112
|
-
|
|
152
|
+
type PageContentPadding = PaddingProp;
|
|
153
|
+
interface PageContentProps {
|
|
154
|
+
/** Page title — usually rendered as <h1>. */
|
|
155
|
+
title?: ReactNode;
|
|
156
|
+
/** Short page description under the title. */
|
|
157
|
+
subtitle?: ReactNode;
|
|
158
|
+
/**
|
|
159
|
+
* Right-aligned slot in the header — typically primary actions
|
|
160
|
+
* (Save, Cancel, New, etc.) or settings buttons.
|
|
161
|
+
*/
|
|
162
|
+
extra?: ReactNode;
|
|
163
|
+
/** Optional breadcrumb rendered above the title. */
|
|
164
|
+
breadcrumb?: ReactNode;
|
|
165
|
+
/** Optional tabs row rendered under the title block, above content. */
|
|
166
|
+
tabs?: ReactNode;
|
|
167
|
+
/** Main content. */
|
|
168
|
+
children?: ReactNode;
|
|
169
|
+
/** Page-level footer (sticky-feeling band under content). */
|
|
170
|
+
footer?: ReactNode;
|
|
171
|
+
/** Padding step — default = system-wide standard. */
|
|
172
|
+
padding?: PageContentPadding;
|
|
173
|
+
/**
|
|
174
|
+
* Header behaviour. `default` shows the title block; `none` skips it
|
|
175
|
+
* entirely (when the page itself renders its own custom header).
|
|
176
|
+
*/
|
|
177
|
+
header?: "default" | "none";
|
|
178
|
+
className?: string;
|
|
179
|
+
}
|
|
180
|
+
declare function PageContent({ title, subtitle, extra, breadcrumb, tabs, children, footer, padding, header, className, }: PageContentProps): react_jsx_runtime.JSX.Element;
|
|
181
|
+
|
|
182
|
+
export { AppShell, type AppShellProps, type CommandItem, CommandPalette, type CommandPaletteProps, ForgeProduct, ForgeProject, PageContent, type PageContentPadding, type PageContentProps, ProductSwitcher, type ProductSwitcherProps, ProjectSwitcher, type ProjectSwitcherProps, type RecentProject, Sidebar, type SidebarItem, type SidebarProps, type SidebarSection, Topbar, type TopbarProps, TweaksPanel, type TweaksPanelProps };
|
package/dist/components/shell.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { ChevronDown, PanelLeftOpen, PanelLeftClose, Search, SlidersHorizontal, X, Check, Clock } from 'lucide-react';
|
|
2
|
+
import { ChevronDown, PanelLeftOpen, PanelLeftClose, Search, Bell, SlidersHorizontal, X, Check, Clock } from 'lucide-react';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
import { clsx } from 'clsx';
|
|
5
5
|
import { twMerge } from 'tailwind-merge';
|
|
@@ -11,11 +11,32 @@ import * as Popover from '@radix-ui/react-popover';
|
|
|
11
11
|
import * as VisuallyHidden from '@radix-ui/react-visually-hidden';
|
|
12
12
|
import { Command } from 'cmdk';
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
// src/components/shell/AppShell.tsx
|
|
15
|
+
function AppShell({
|
|
16
|
+
sidebar,
|
|
17
|
+
topbar,
|
|
18
|
+
topbarLeft,
|
|
19
|
+
topbarRight,
|
|
20
|
+
logo,
|
|
21
|
+
breadcrumb,
|
|
22
|
+
footer,
|
|
23
|
+
children,
|
|
24
|
+
sidebarCollapsed = false
|
|
25
|
+
}) {
|
|
26
|
+
const resolvedTopbar = topbar !== void 0 ? topbar : /* @__PURE__ */ jsxs("div", { className: "app-topbar-rail", children: [
|
|
27
|
+
logo !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-logo", children: logo }),
|
|
28
|
+
topbarLeft !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-left", children: topbarLeft }),
|
|
29
|
+
/* @__PURE__ */ jsx("div", { className: "app-topbar-spacer" }),
|
|
30
|
+
topbarRight !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-right", children: topbarRight })
|
|
31
|
+
] });
|
|
15
32
|
return /* @__PURE__ */ jsxs("div", { className: "app-root", "data-collapsed": sidebarCollapsed, children: [
|
|
16
33
|
/* @__PURE__ */ jsx("aside", { className: "app-sidebar", children: sidebar }),
|
|
17
|
-
/* @__PURE__ */ jsx("header", { className: "app-topbar", children:
|
|
18
|
-
/* @__PURE__ */
|
|
34
|
+
/* @__PURE__ */ jsx("header", { className: "app-topbar", children: resolvedTopbar }),
|
|
35
|
+
/* @__PURE__ */ jsxs("main", { className: "app-main", children: [
|
|
36
|
+
breadcrumb !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-breadcrumb", children: breadcrumb }),
|
|
37
|
+
children
|
|
38
|
+
] }),
|
|
39
|
+
footer !== void 0 && /* @__PURE__ */ jsx("footer", { className: "app-footer", children: footer })
|
|
19
40
|
] });
|
|
20
41
|
}
|
|
21
42
|
function cn(...inputs) {
|
|
@@ -27,12 +48,13 @@ function Sidebar({
|
|
|
27
48
|
sections,
|
|
28
49
|
product,
|
|
29
50
|
onProductClick,
|
|
51
|
+
brand,
|
|
30
52
|
collapsed = false,
|
|
31
53
|
footer
|
|
32
54
|
}) {
|
|
33
55
|
const { t } = useTranslation();
|
|
34
|
-
return /* @__PURE__ */ jsxs(
|
|
35
|
-
/* @__PURE__ */ jsxs(
|
|
56
|
+
return /* @__PURE__ */ jsxs("div", { className: "sb-root", "data-collapsed": collapsed ? "true" : void 0, style: { display: "contents" }, children: [
|
|
57
|
+
brand !== void 0 ? /* @__PURE__ */ jsx("div", { className: "sb-brand", children: brand }) : product ? /* @__PURE__ */ jsxs(
|
|
36
58
|
"button",
|
|
37
59
|
{
|
|
38
60
|
type: "button",
|
|
@@ -62,7 +84,7 @@ function Sidebar({
|
|
|
62
84
|
!collapsed && /* @__PURE__ */ jsx("span", { className: "sb-product-tenant shrink-0", children: /* @__PURE__ */ jsx(ChevronDown, { size: 14 }) })
|
|
63
85
|
]
|
|
64
86
|
}
|
|
65
|
-
),
|
|
87
|
+
) : null,
|
|
66
88
|
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: sections.map((section, i) => /* @__PURE__ */ jsxs("div", { className: "sb-section", children: [
|
|
67
89
|
section.label && !collapsed && /* @__PURE__ */ jsx("div", { className: "sb-section-label", children: section.label }),
|
|
68
90
|
/* @__PURE__ */ jsx("div", { className: "sb-nav", role: "navigation", children: section.items.map((item) => {
|
|
@@ -74,13 +96,15 @@ function Sidebar({
|
|
|
74
96
|
type: "button",
|
|
75
97
|
className: cn("sb-nav-item"),
|
|
76
98
|
"data-active": isActive,
|
|
99
|
+
"aria-label": collapsed ? item.label : void 0,
|
|
77
100
|
"aria-current": isActive ? "page" : void 0,
|
|
78
101
|
"aria-disabled": item.disabled,
|
|
102
|
+
title: collapsed ? item.label : void 0,
|
|
79
103
|
onClick: () => !item.disabled && onSelect(item.id),
|
|
80
104
|
children: [
|
|
81
105
|
/* @__PURE__ */ jsx("span", { className: "sb-icon", children: /* @__PURE__ */ jsx(Icon, { size: 16 }) }),
|
|
82
|
-
/* @__PURE__ */ jsx("span", { className: "sb-label", children: item.label }),
|
|
83
|
-
item.badge !== void 0 && item.badge !== "" && /* @__PURE__ */ jsx("span", { className: "sb-badge", children: item.badge })
|
|
106
|
+
!collapsed && /* @__PURE__ */ jsx("span", { className: "sb-label", children: item.label }),
|
|
107
|
+
!collapsed && item.badge !== void 0 && item.badge !== "" && /* @__PURE__ */ jsx("span", { className: "sb-badge", children: item.badge })
|
|
84
108
|
]
|
|
85
109
|
},
|
|
86
110
|
item.id
|
|
@@ -99,7 +123,10 @@ function Topbar({
|
|
|
99
123
|
onTweaksOpen,
|
|
100
124
|
collapsed = false,
|
|
101
125
|
onToggleCollapsed,
|
|
102
|
-
rightSlot
|
|
126
|
+
rightSlot,
|
|
127
|
+
unread = false,
|
|
128
|
+
onNotificationsOpen,
|
|
129
|
+
user
|
|
103
130
|
}) {
|
|
104
131
|
const { t } = useTranslation();
|
|
105
132
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -141,7 +168,7 @@ function Topbar({
|
|
|
141
168
|
"button",
|
|
142
169
|
{
|
|
143
170
|
type: "button",
|
|
144
|
-
className: cn("tb-chip", !project && "empty"),
|
|
171
|
+
className: cn("tb-chip", !project && "tb-chip-empty"),
|
|
145
172
|
"aria-label": project ? project.name : t("shell.pickProject"),
|
|
146
173
|
onClick: onProjectOpen,
|
|
147
174
|
children: [
|
|
@@ -168,6 +195,20 @@ function Topbar({
|
|
|
168
195
|
}
|
|
169
196
|
),
|
|
170
197
|
rightSlot,
|
|
198
|
+
onNotificationsOpen && /* @__PURE__ */ jsxs(
|
|
199
|
+
"button",
|
|
200
|
+
{
|
|
201
|
+
type: "button",
|
|
202
|
+
className: "tb-icon-btn tb-bell",
|
|
203
|
+
"aria-label": t("topbar.notifications", { defaultValue: "Notifications" }),
|
|
204
|
+
onClick: onNotificationsOpen,
|
|
205
|
+
children: [
|
|
206
|
+
/* @__PURE__ */ jsx(Bell, { size: 16 }),
|
|
207
|
+
unread && /* @__PURE__ */ jsx("span", { className: "tb-bell-dot", "aria-hidden": true })
|
|
208
|
+
]
|
|
209
|
+
}
|
|
210
|
+
),
|
|
211
|
+
user,
|
|
171
212
|
onTweaksOpen && /* @__PURE__ */ jsx(
|
|
172
213
|
"button",
|
|
173
214
|
{
|
|
@@ -180,90 +221,12 @@ function Topbar({
|
|
|
180
221
|
)
|
|
181
222
|
] });
|
|
182
223
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
var PRODUCTS = [
|
|
186
|
-
{
|
|
187
|
-
id: "restaurant",
|
|
188
|
-
name: "godx-restaurant",
|
|
189
|
-
tenant: "restaurant",
|
|
190
|
-
role: "\u30EC\u30B9\u30C8\u30E9\u30F3\u7BA1\u7406",
|
|
191
|
-
desc: "\u5E97\u8217\u5411\u3051\u7D71\u5408\u7BA1\u7406\u30D7\u30E9\u30C3\u30C8\u30D5\u30A9\u30FC\u30E0",
|
|
192
|
-
color: "oklch(58% 0.18 25)",
|
|
193
|
-
owner: "Satoshi F",
|
|
194
|
-
devs: 6,
|
|
195
|
-
projects: [
|
|
196
|
-
{ 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 },
|
|
197
|
-
{ 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 },
|
|
198
|
-
{ 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 },
|
|
199
|
-
{ 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 },
|
|
200
|
-
{ 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 },
|
|
201
|
-
{ 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 }
|
|
202
|
-
]
|
|
203
|
-
},
|
|
204
|
-
{
|
|
205
|
-
id: "godx",
|
|
206
|
-
name: "godx-admin",
|
|
207
|
-
tenant: "godx",
|
|
208
|
-
role: "Platform admin",
|
|
209
|
-
desc: "GoDX Forge developer workspace",
|
|
210
|
-
color: "oklch(60% 0.137 163)",
|
|
211
|
-
owner: "Satoshi F",
|
|
212
|
-
devs: 4,
|
|
213
|
-
projects: [
|
|
214
|
-
{ 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 },
|
|
215
|
-
{ 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 },
|
|
216
|
-
{ 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 }
|
|
217
|
-
]
|
|
218
|
-
},
|
|
219
|
-
{
|
|
220
|
-
id: "kintai",
|
|
221
|
-
name: "dxs-kintai",
|
|
222
|
-
tenant: "kintai",
|
|
223
|
-
role: "HR / Attendance",
|
|
224
|
-
desc: "\u52E4\u6020\u7BA1\u7406\u30D7\u30E9\u30C3\u30C8\u30D5\u30A9\u30FC\u30E0",
|
|
225
|
-
color: "oklch(56% 0.15 240)",
|
|
226
|
-
owner: "Naoki N",
|
|
227
|
-
devs: 3,
|
|
228
|
-
projects: [
|
|
229
|
-
{ 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 },
|
|
230
|
-
{ 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 }
|
|
231
|
-
]
|
|
232
|
-
},
|
|
233
|
-
{
|
|
234
|
-
id: "tempo",
|
|
235
|
-
name: "dxs-tempo",
|
|
236
|
-
tenant: "tempo",
|
|
237
|
-
role: "Shop / Inventory",
|
|
238
|
-
desc: "\u5E97\u8217\u30FB\u5728\u5EAB\u30D0\u30C3\u30AF\u30A8\u30F3\u30C9",
|
|
239
|
-
color: "oklch(48% 0.16 285)",
|
|
240
|
-
owner: "Naoki N",
|
|
241
|
-
devs: 2,
|
|
242
|
-
projects: [
|
|
243
|
-
{ 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 },
|
|
244
|
-
{ 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 }
|
|
245
|
-
]
|
|
246
|
-
},
|
|
247
|
-
{
|
|
248
|
-
id: "betoya",
|
|
249
|
-
name: "betoya",
|
|
250
|
-
tenant: "betoya",
|
|
251
|
-
role: "Vietnamese restaurant",
|
|
252
|
-
desc: "\u30D9\u30C8\u5C4B Tenant",
|
|
253
|
-
color: "oklch(58% 0.159 150)",
|
|
254
|
-
owner: "Anh K",
|
|
255
|
-
devs: 1,
|
|
256
|
-
projects: [
|
|
257
|
-
{ id: "site", name: "betoya-site", stack: "Astro", kind: "web", devs: 1, status: "active", branch: "main", lastCommit: "\u6628\u65E5", openIssues: 2, prs: 0, sandbox: false }
|
|
258
|
-
]
|
|
259
|
-
}
|
|
260
|
-
];
|
|
261
|
-
var SUPPORTED_LOCALES = ["ja", "en", "vi"];
|
|
262
|
-
var FORGE_LOCALE_STORAGE_KEY = "forge.locale";
|
|
224
|
+
var SUPPORTED_LOCALES = ["ja", "en", "vi", "fil"];
|
|
225
|
+
var GODX_LOCALE_STORAGE_KEY = "godx.locale";
|
|
263
226
|
var i18n_default = i18next;
|
|
264
227
|
|
|
265
228
|
// src/hooks/useTweaks.ts
|
|
266
|
-
var STORAGE_KEY = "
|
|
229
|
+
var STORAGE_KEY = "godx.tweaks";
|
|
267
230
|
var DEFAULTS = {
|
|
268
231
|
density: "default",
|
|
269
232
|
theme: "light",
|
|
@@ -302,10 +265,11 @@ function useTweaks() {
|
|
|
302
265
|
html.lang = tweaks.locale;
|
|
303
266
|
}, [tweaks.theme, tweaks.density, tweaks.tenant, tweaks.locale]);
|
|
304
267
|
useEffect(() => {
|
|
268
|
+
if (!i18n_default.isInitialized) return;
|
|
305
269
|
if (i18n_default.language?.slice(0, 2) !== tweaks.locale) {
|
|
306
270
|
void i18n_default.changeLanguage(tweaks.locale);
|
|
307
271
|
try {
|
|
308
|
-
window.localStorage.setItem(
|
|
272
|
+
window.localStorage.setItem(GODX_LOCALE_STORAGE_KEY, tweaks.locale);
|
|
309
273
|
} catch {
|
|
310
274
|
}
|
|
311
275
|
}
|
|
@@ -315,76 +279,82 @@ function useTweaks() {
|
|
|
315
279
|
}, []);
|
|
316
280
|
return { tweaks, setTweak, setTweaks };
|
|
317
281
|
}
|
|
318
|
-
|
|
319
|
-
function TweaksPanel({ open, onOpenChange }) {
|
|
282
|
+
function TweaksPanel({ open, onOpenChange, products = [] }) {
|
|
320
283
|
const { t } = useTranslation();
|
|
321
284
|
const { tweaks, setTweak } = useTweaks();
|
|
322
285
|
return /* @__PURE__ */ jsx(Dialog.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxs(Dialog.Portal, { children: [
|
|
323
286
|
/* @__PURE__ */ jsx(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" }),
|
|
324
|
-
/* @__PURE__ */ jsxs(
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
{
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
{
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
287
|
+
/* @__PURE__ */ jsxs(
|
|
288
|
+
Dialog.Content,
|
|
289
|
+
{
|
|
290
|
+
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",
|
|
291
|
+
"aria-describedby": void 0,
|
|
292
|
+
children: [
|
|
293
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-border px-4 h-12", children: [
|
|
294
|
+
/* @__PURE__ */ jsx(Dialog.Title, { className: "font-medium text-sm", children: t("tweaks.title") }),
|
|
295
|
+
/* @__PURE__ */ jsx(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsx("button", { className: "tb-icon-btn", "aria-label": "Close", children: /* @__PURE__ */ jsx(X, { size: 14 }) }) })
|
|
296
|
+
] }),
|
|
297
|
+
/* @__PURE__ */ jsxs("div", { className: "overflow-y-auto h-[calc(100%-3rem)] p-4 flex flex-col gap-6", children: [
|
|
298
|
+
/* @__PURE__ */ jsxs(Section, { label: t("tweaks.display"), children: [
|
|
299
|
+
/* @__PURE__ */ jsx(
|
|
300
|
+
Radio,
|
|
301
|
+
{
|
|
302
|
+
label: t("tweaks.density"),
|
|
303
|
+
value: tweaks.density,
|
|
304
|
+
onChange: (v) => setTweak("density", v),
|
|
305
|
+
options: [
|
|
306
|
+
{ value: "compact", label: t("tweaks.densityCompact") },
|
|
307
|
+
{ value: "default", label: t("tweaks.densityDefault") },
|
|
308
|
+
{ value: "comfortable", label: t("tweaks.densityComfortable") }
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
),
|
|
312
|
+
/* @__PURE__ */ jsx(
|
|
313
|
+
Radio,
|
|
314
|
+
{
|
|
315
|
+
label: t("tweaks.theme"),
|
|
316
|
+
value: tweaks.theme,
|
|
317
|
+
onChange: (v) => setTweak("theme", v),
|
|
318
|
+
options: [
|
|
319
|
+
{ value: "light", label: t("tweaks.themeLight") },
|
|
320
|
+
{ value: "dark", label: t("tweaks.themeDark") }
|
|
321
|
+
]
|
|
322
|
+
}
|
|
323
|
+
),
|
|
324
|
+
/* @__PURE__ */ jsx(
|
|
325
|
+
Toggle,
|
|
326
|
+
{
|
|
327
|
+
label: t("shell.sidebarCollapse"),
|
|
328
|
+
value: tweaks.sidebarCollapsed,
|
|
329
|
+
onChange: (v) => setTweak("sidebarCollapsed", v)
|
|
330
|
+
}
|
|
331
|
+
)
|
|
332
|
+
] }),
|
|
333
|
+
products.length > 0 && /* @__PURE__ */ jsx(Section, { label: t("tweaks.product"), children: /* @__PURE__ */ jsx(
|
|
334
|
+
Select,
|
|
335
|
+
{
|
|
336
|
+
label: t("tweaks.product"),
|
|
337
|
+
value: tweaks.tenant,
|
|
338
|
+
onChange: (v) => setTweak("tenant", v),
|
|
339
|
+
options: products.map((p) => ({ value: p.tenant, label: p.name }))
|
|
340
|
+
}
|
|
341
|
+
) }),
|
|
342
|
+
/* @__PURE__ */ jsx(Section, { label: t("tweaks.locale"), children: /* @__PURE__ */ jsx(
|
|
343
|
+
Radio,
|
|
344
|
+
{
|
|
345
|
+
label: t("tweaks.language"),
|
|
346
|
+
value: tweaks.locale,
|
|
347
|
+
onChange: (v) => setTweak("locale", v),
|
|
348
|
+
options: SUPPORTED_LOCALES.map((code) => ({
|
|
349
|
+
value: code,
|
|
350
|
+
label: { ja: "\u65E5\u672C\u8A9E", en: "English", vi: "Ti\u1EBFng Vi\u1EC7t", fil: "Filipino" }[code] ?? code
|
|
351
|
+
}))
|
|
352
|
+
}
|
|
353
|
+
) })
|
|
354
|
+
] })
|
|
355
|
+
]
|
|
356
|
+
}
|
|
357
|
+
)
|
|
388
358
|
] }) });
|
|
389
359
|
}
|
|
390
360
|
function Section({ label, children }) {
|
|
@@ -463,7 +433,7 @@ function Select({
|
|
|
463
433
|
function ProductSwitcher({
|
|
464
434
|
trigger,
|
|
465
435
|
activeId,
|
|
466
|
-
products =
|
|
436
|
+
products = [],
|
|
467
437
|
onSelect,
|
|
468
438
|
open,
|
|
469
439
|
onOpenChange
|
|
@@ -551,7 +521,7 @@ function ProjectSwitcher({
|
|
|
551
521
|
activeProductId,
|
|
552
522
|
activeProjectId,
|
|
553
523
|
recent = [],
|
|
554
|
-
products =
|
|
524
|
+
products = [],
|
|
555
525
|
onSelect,
|
|
556
526
|
open,
|
|
557
527
|
onOpenChange
|
|
@@ -762,7 +732,43 @@ function CommandPalette({ open, onOpenChange, commands }) {
|
|
|
762
732
|
)
|
|
763
733
|
] }) });
|
|
764
734
|
}
|
|
735
|
+
function PageContent({
|
|
736
|
+
title,
|
|
737
|
+
subtitle,
|
|
738
|
+
extra,
|
|
739
|
+
breadcrumb,
|
|
740
|
+
tabs,
|
|
741
|
+
children,
|
|
742
|
+
footer,
|
|
743
|
+
padding = "default",
|
|
744
|
+
header = "default",
|
|
745
|
+
className
|
|
746
|
+
}) {
|
|
747
|
+
const showHeader = header !== "none" && (breadcrumb || title || subtitle || extra);
|
|
748
|
+
return /* @__PURE__ */ jsxs(
|
|
749
|
+
"section",
|
|
750
|
+
{
|
|
751
|
+
className: cn("page-content", className),
|
|
752
|
+
"data-padding": padding,
|
|
753
|
+
children: [
|
|
754
|
+
showHeader && /* @__PURE__ */ jsxs("header", { className: "page-content-header", children: [
|
|
755
|
+
breadcrumb && /* @__PURE__ */ jsx("div", { className: "page-content-breadcrumb", children: breadcrumb }),
|
|
756
|
+
/* @__PURE__ */ jsxs("div", { className: "page-content-titlebar", children: [
|
|
757
|
+
/* @__PURE__ */ jsxs("div", { className: "page-content-titlegroup", children: [
|
|
758
|
+
title && /* @__PURE__ */ jsx("h1", { className: "page-content-title", children: title }),
|
|
759
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "page-content-subtitle", children: subtitle })
|
|
760
|
+
] }),
|
|
761
|
+
extra && /* @__PURE__ */ jsx("div", { className: "page-content-extra", children: extra })
|
|
762
|
+
] }),
|
|
763
|
+
tabs && /* @__PURE__ */ jsx("div", { className: "page-content-tabs", children: tabs })
|
|
764
|
+
] }),
|
|
765
|
+
children !== void 0 && /* @__PURE__ */ jsx("div", { className: "page-content-body", children }),
|
|
766
|
+
footer && /* @__PURE__ */ jsx("footer", { className: "page-content-footer", children: footer })
|
|
767
|
+
]
|
|
768
|
+
}
|
|
769
|
+
);
|
|
770
|
+
}
|
|
765
771
|
|
|
766
|
-
export { AppShell, CommandPalette, ProductSwitcher, ProjectSwitcher, Sidebar, Topbar, TweaksPanel };
|
|
772
|
+
export { AppShell, CommandPalette, PageContent, ProductSwitcher, ProjectSwitcher, Sidebar, Topbar, TweaksPanel };
|
|
767
773
|
//# sourceMappingURL=shell.js.map
|
|
768
774
|
//# sourceMappingURL=shell.js.map
|