nfx-ui 0.6.3 → 0.7.2

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.
@@ -1,179 +1 @@
1
- import { default as i18n } from 'i18next';
2
- import { JSX } from 'react/jsx-runtime';
3
- import { MemoExoticComponent } from 'react';
4
- import { ReactNode } from 'react';
5
-
6
- /** 基础主题枚举(平台/圆角等,如 iOS 24 / Android|Windows 6 / Linux 4) */
7
- declare enum BaseEnum {
8
- DEFAULT = "default",
9
- IOS = "ios",
10
- ANDROID = "android",
11
- WINDOWS = "windows",
12
- LINUX = "linux"
13
- }
14
-
15
- /** 切换当前语言。Switch current language. */
16
- export declare function changeLanguage(lng: LanguageEnum): void;
17
-
18
- /**
19
- * 由调用方传入 resources 和 nameSpacesMap,生成 i18n 所需的 RESOURCES、NAME_SPACES_MAP、NAME_SPACES。
20
- * Caller provides resources and nameSpacesMap; returns RESOURCES, NAME_SPACES_MAP, NAME_SPACES for i18n.
21
- *
22
- * @param resources - 各语言下的命名空间文案。Bundles per language.
23
- * @param nameSpacesMap - 命名空间 key → 命名空间字符串。Namespace key to string.
24
- */
25
- export declare function createI18nResources(resources: Resources, nameSpacesMap: NameSpacesMap): CreateI18nResourcesResult;
26
-
27
- /** createI18nResources 返回值,含 RESOURCES / NAME_SPACES_MAP / NAME_SPACES。Return type of createI18nResources. */
28
- export declare interface CreateI18nResourcesResult {
29
- RESOURCES: Resources;
30
- NAME_SPACES_MAP: NameSpacesMap;
31
- NAME_SPACES: string[];
32
- }
33
-
34
- export declare const DEFAULT_LANGUAGE = LanguageEnum.ZH;
35
-
36
- /** 单条额外 bundle:命名空间 + 文案对象,由 initI18n 注入到 i18n。 */
37
- export declare interface ExtraBundleItem {
38
- namespace: string;
39
- bundle: Record<string, unknown>;
40
- }
41
-
42
- /**
43
- * 返回 NFX-UI 默认文案包,可与使用方自建 resources 合并后传入 createI18nResources。
44
- * Returns default NFX bundles; merge with your resources and pass to createI18nResources.
45
- */
46
- export declare function getDefaultNfxBundles(): CreateI18nResourcesResult;
47
-
48
- export declare function getLanguageDisplayName(lang: LanguageEnum): string;
49
-
50
- export declare function getLanguageStorage(): Nilable<LanguageEnum>;
51
-
52
- export declare function getLayoutDisplayName(mode: LayoutModeEnum): string;
53
-
54
- export declare function getLocalLanguage(): LanguageEnum;
55
-
56
- export declare function getPreferenceDisplayName(base: BaseEnum): string;
57
-
58
- export declare function getThemeDisplayName(theme: ThemeEnum): string;
59
-
60
- export { i18n }
61
-
62
- /**
63
- * 初始化 i18n。会先合并 NFX-UI 自带的四类 JSON(theme/language/layout/preference),再与用户传入的 bundles 合并(用户可覆盖)。
64
- * Init i18n. Merges built-in NFX bundles (theme, language, layout, preference) with user bundles (user overrides).
65
- */
66
- export declare function initI18n(options: InitI18nOptions): void;
67
-
68
- /** initI18n 的选项。Options for initI18n. */
69
- export declare interface InitI18nOptions {
70
- /** 由 createI18nResources(resources, nameSpacesMap) 得到;用户自建 JSON 后组装传入。From createI18nResources; user builds from their JSON. */
71
- bundles: CreateI18nResourcesResult;
72
- /** 回退语言。Fallback language. */
73
- fallbackLng?: LanguageEnum;
74
- /** 语言切换后由调用方拉取额外文案(如错误码);返回 { namespace, bundle } 或数组,由 initI18n 负责 addResourceBundle。 */
75
- onLoadExtraBundles?: onLoadExtraBundles;
76
- }
77
-
78
- export declare const LANGUAGE_STORAGE_KEY = "language-storage";
79
-
80
- export declare const LANGUAGE_VALUES: LanguageEnum[];
81
-
82
- /**
83
- * 语言枚举与常量,不引用任何 JSON,供需要轻量引用的模块使用。
84
- * Language enum and constants; no JSON deps for lightweight usage.
85
- */
86
- export declare enum LanguageEnum {
87
- EN = "en",
88
- ZH = "zh",
89
- FR = "fr"
90
- }
91
-
92
- export declare const LanguageProvider: MemoExoticComponent<({ children, bundles, fallbackLng, onLoadExtraBundles }: LanguageProviderProps) => JSX.Element>;
93
-
94
- /** 语言 Provider 的 props。LanguageProvider props. */
95
- export declare interface LanguageProviderProps {
96
- /** 子节点。Children. */
97
- children: ReactNode;
98
- /** 用户自建 JSON 后调用 createI18nResources 得到的结果。Result of createI18nResources(resources, nameSpacesMap). */
99
- bundles: CreateI18nResourcesResult;
100
- /** 回退语言。Fallback language. */
101
- fallbackLng?: LanguageEnum;
102
- /** 语言切换后拉取额外文案(如错误码);返回 { namespace, bundle },由 Provider 内部 addResourceBundle。Caller only fetches; Provider injects. */
103
- onLoadExtraBundles?: onLoadExtraBundles;
104
- }
105
-
106
- /** 语言切换器 props。LanguageSwitcher props. */
107
- export declare interface LanguageSwitcherProps {
108
- /** 样式状态。Visual status. */
109
- status?: "primary" | "default";
110
- /** 根据 lang 返回显示名称;未传则使用 lang 原值。Display name for language; default is lang value. */
111
- getLanguageDisplayName?: (lang: LanguageEnum) => string;
112
- /** 处理语言改变。Handle language change. */
113
- handleChangeLanguage?: (language: LanguageEnum) => void;
114
- }
115
-
116
- /**
117
- * 布局模式枚举与常量。Layout mode enum and constants.
118
- */
119
- declare enum LayoutModeEnum {
120
- SHOW = "show",
121
- HIDE = "hide"
122
- }
123
-
124
- /** 单语言下的命名空间 → 文案对象。One language: namespace -> key-value bundle. */
125
- export declare type NamespaceBundle = Record<string, unknown>;
126
-
127
- /** 命名空间映射:命名空间 key → 命名空间字符串(用于 ns 列表)。Name space key -> string. */
128
- export declare type NameSpacesMap = Record<string, string>;
129
-
130
- export declare const NFX_NAMESPACES: readonly ["theme", "language", "layout", "preference"];
131
-
132
- export declare const NFX_NAMESPACES_MAP: NameSpacesMap;
133
-
134
- /**
135
- * 可为 null 或 undefined。Nilable: T | null | undefined.
136
- * @example Nilable<boolean> => boolean | null | undefined
137
- */
138
- declare type Nilable<T> = T | null | undefined;
139
-
140
- export declare type onLoadExtraBundles = (lng: LanguageEnum) => Promise<ExtraBundleItem | ExtraBundleItem[] | null | undefined>;
141
-
142
- export declare function removeLanguageStorage(): void;
143
-
144
- /** 所有语言的资源:语言码 → 命名空间 → 文案。Resources: lng -> ns -> bundle. */
145
- export declare type Resources = Record<string, Record<string, NamespaceBundle>>;
146
-
147
- export declare function setLanguageStorage(value: LanguageEnum): void;
148
-
149
- /** 颜色主题枚举 */
150
- declare enum ThemeEnum {
151
- DEFAULT = "default",
152
- LIGHT = "light",
153
- CORPORATE = "corporate",
154
- FOREST = "forest",
155
- DARK = "dark",
156
- COSMIC = "cosmic",
157
- COFFEE = "coffee",
158
- WINE = "wine",
159
- /** 麦田:default 基础上白红色改为金黄色 */
160
- WHEAT = "wheat"
161
- }
162
-
163
- export declare function useLanguageLabel(): {
164
- getLanguageDisplayName: (lang: LanguageEnum) => string;
165
- };
166
-
167
- export declare function useLayoutLabel(): {
168
- getLayoutDisplayName: (mode: LayoutModeEnum) => string;
169
- };
170
-
171
- export declare function usePreferenceLabel(): {
172
- getPreferenceDisplayName: (base: BaseEnum) => string;
173
- };
174
-
175
- export declare function useThemeLabel(): {
176
- getThemeDisplayName: (theme: ThemeEnum) => string;
177
- };
178
-
179
1
  export { }
@@ -1 +1 @@
1
- {"version":3,"file":"layouts.cjs","names":[],"sources":["../src/designs/layouts/utils/layoutStorage.ts","../src/designs/layouts/components/Sidebar/styles.module.css","../src/designs/layouts/components/Sidebar/index.tsx","../src/designs/layouts/components/Footer/styles.module.css","../src/designs/layouts/components/Footer/index.tsx","../src/designs/layouts/components/Header/styles.module.css","../src/designs/layouts/components/Header/index.tsx","../src/designs/layouts/components/MainWrapper/styles.module.css","../src/designs/layouts/components/MainWrapper/index.tsx","../src/designs/layouts/components/SideHideLayout/styles.module.css","../src/designs/layouts/components/SideHideLayout/index.tsx","../src/designs/layouts/components/SideShowLayout/styles.module.css","../src/designs/layouts/components/SideShowLayout/index.tsx","../src/designs/layouts/components/Background/styles.module.css","../src/designs/layouts/components/Background/index.tsx","../src/designs/layouts/components/LayoutFrame/index.tsx","../src/designs/layouts/hooks/useSet.ts","../src/designs/layouts/hooks/useAction.ts","../src/designs/layouts/providers/index.tsx"],"sourcesContent":["/**\n * 布局相关 localStorage 读写与移除,统一走 utils/lstorage。\n * Layout localStorage get/set/remove via utils/lstorage.\n */\nimport type { Nilable } from \"@/types/utils\";\nimport { getItem, removeItem, setItem } from \"@/utils/lstorage\";\n\nimport { LAYOUT_STORAGE_KEY } from \"../types\";\n\nexport function getLayoutStorage(): Nilable<string> {\n return getItem(LAYOUT_STORAGE_KEY);\n}\n\nexport function setLayoutStorage(value: string): void {\n setItem(LAYOUT_STORAGE_KEY, value);\n}\n\nexport function removeLayoutStorage(): void {\n removeItem(LAYOUT_STORAGE_KEY);\n}\n","/* ===== Sidebar Component ===== */\r\n\r\n.sidebar {\r\n height: 100%;\r\n min-height: 0;\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n}\r\n\r\n.sidebarContent {\r\n padding-top: 1rem;\r\n height: 100%;\r\n min-height: 0;\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n}\r\n\r\n.menuWrapper {\r\n flex: 1;\r\n min-height: 0;\r\n overflow-y: auto;\r\n overflow-x: hidden;\r\n}\r\n\r\n/* 自定义滚动条样式 - 隐藏但保持滚动功能 */\r\n.sidebarContent::-webkit-scrollbar {\r\n width: 0px;\r\n}\r\n\r\n.sidebarContent::-webkit-scrollbar-track {\r\n background: transparent;\r\n}\r\n\r\n.sidebarContent::-webkit-scrollbar-thumb {\r\n background: transparent;\r\n}\r\n\r\n.sidebarContent::-webkit-scrollbar-thumb:hover {\r\n background: transparent;\r\n}\r\n\r\n/* 内部 a 元素左边距为 0 */\r\n.sidebar :global(a) {\r\n margin-left: 0;\r\n}\r\n\r\n/* 覆盖 react-pro-sidebar 默认样式 */\r\n.sidebar :global(.ps-sidebar-root) {\r\n height: 100% !important;\r\n min-height: 0 !important;\r\n overflow: hidden !important;\r\n display: flex !important;\r\n flex-direction: column !important;\r\n background-color: var(--color-bg-2) !important;\r\n border-right: 1px solid var(--color-separator) !important;\r\n}\r\n\r\n.sidebar :global(.ps-sidebar-container) {\r\n height: 100% !important;\r\n min-height: 0 !important;\r\n display: flex !important;\r\n flex-direction: column !important;\r\n flex: 1 !important;\r\n overflow: hidden !important;\r\n background-color: var(--color-bg-2) !important;\r\n color: var(--color-fg-text) !important;\r\n}\r\n\r\n.sidebar :global(.ps-menu-button) {\r\n padding: 0.5rem 0.75rem !important;\r\n margin: 0.125rem 0.5rem !important;\r\n border-radius: 0.375rem !important;\r\n transition: all 0.2s ease !important;\r\n color: var(--color-fg-text) !important;\r\n font-size: 0.875rem !important;\r\n}\r\n\r\n.sidebar :global(.ps-menu-button:hover) {\r\n background-color: var(--color-bg-3) !important;\r\n color: var(--color-fg-text) !important;\r\n}\r\n\r\n.sidebar :global(.ps-menu-button.ps-active) {\r\n background-color: var(--color-primary) !important;\r\n color: #ffffff !important;\r\n}\r\n\r\n.sidebar :global(.ps-menu-button.ps-active *) {\r\n color: #ffffff !important;\r\n}\r\n\r\n.sidebar :global(.ps-menu-button.ps-active .ps-menu-icon) {\r\n color: #ffffff !important;\r\n}\r\n\r\n.sidebar :global(.ps-menu-button.ps-active .ps-menu-label) {\r\n color: #ffffff !important;\r\n}\r\n\r\n/* 菜单图标样式 */\r\n.sidebar :global(.ps-menu-icon) {\r\n margin-right: 0.5rem !important;\r\n width: 1.25rem !important;\r\n height: 1.25rem !important;\r\n color: var(--color-fg-text) !important;\r\n}\r\n\r\n/* 子菜单样式 */\r\n.sidebar :global(.ps-submenu-content) {\r\n background-color: var(--color-bg-3) !important;\r\n padding-left: 0.5rem !important;\r\n overflow: hidden !important;\r\n}\r\n\r\n.sidebar :global(.ps-submenu-content .ps-menu-button) {\r\n padding: 0.375rem 0.5rem !important;\r\n margin: 0.125rem 0.25rem !important;\r\n font-size: 0.8125rem !important;\r\n transition: all 0.2s ease !important;\r\n}\r\n\r\n/* 子菜单标题样式 */\r\n.sidebar :global(.ps-menu-label) {\r\n color: var(--color-fg-text) !important;\r\n font-weight: 500 !important;\r\n}\r\n\r\n/* 强制选中状态的所有子元素为白色 */\r\n.sidebar :global(.ps-menu-button.ps-active),\r\n.sidebar :global(.ps-menu-button.ps-active span),\r\n.sidebar :global(.ps-menu-button.ps-active div),\r\n.sidebar :global(.ps-menu-button.ps-active .ps-menu-icon),\r\n.sidebar :global(.ps-menu-button.ps-active .ps-menu-label) {\r\n color: #ffffff !important;\r\n}\r\n\r\n/* 退出登录按钮容器 */\r\n.logoutContainer {\r\n margin-top: auto;\r\n padding: 0.5rem;\r\n border-top: 1px solid var(--color-separator);\r\n flex-shrink: 0;\r\n writing-mode: horizontal-tb;\r\n text-orientation: mixed;\r\n}\r\n\r\n.logoutButton {\r\n width: 100%;\r\n display: flex;\r\n align-items: center;\r\n justify-content: flex-start;\r\n gap: 0.5rem;\r\n padding: 0.5rem 0.75rem;\r\n background: transparent;\r\n border: none;\r\n border-radius: 0.375rem;\r\n color: var(--color-fg-text);\r\n font-size: 0.875rem;\r\n cursor: pointer;\r\n transition:\r\n background-color 0.2s ease,\r\n color 0.2s ease;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n writing-mode: horizontal-tb;\r\n text-orientation: mixed;\r\n direction: ltr;\r\n}\r\n\r\n.logoutButton span {\r\n display: inline-block;\r\n writing-mode: horizontal-tb !important;\r\n text-orientation: mixed !important;\r\n direction: ltr !important;\r\n transform: none !important;\r\n transition:\r\n opacity 0.3s ease,\r\n max-width 0.3s ease;\r\n max-width: 200px;\r\n opacity: 1;\r\n}\r\n\r\n.logoutButton .hiddenText {\r\n opacity: 0;\r\n max-width: 0;\r\n width: 0;\r\n overflow: hidden;\r\n}\r\n\r\n.logoutButton .visibleText {\r\n opacity: 1;\r\n max-width: 200px;\r\n width: auto;\r\n}\r\n\r\n.logoutButton:hover {\r\n background-color: var(--color-bg-3);\r\n}\r\n\r\n.logoutButton:active {\r\n transform: scale(0.98);\r\n}\r\n\r\n.logoutButton svg {\r\n flex-shrink: 0;\r\n color: inherit;\r\n}\r\n","import type { SidebarMenuItem, SidebarProps } from \"../../types\";\n\nimport { memo, useCallback, useMemo } from \"react\";\nimport { Menu, MenuItem, Sidebar as ProSidebar, SubMenu } from \"react-pro-sidebar\";\n\nimport { LogOut } from \"@/icons/lucide\";\n\nimport styles from \"./styles.module.css\";\n\n/**\n * 当前路径是否命中该菜单项。\n * 若有 siblingPaths(同组子项路径),则只有当前路径精确等于 path 或匹配 path 下的详情(非其它子项)时才命中,避免 /categories 与 /categories/add 同时高亮。\n */\nfunction isPathActive(current: string, path: string, siblingPaths?: string[]): boolean {\n if (current === path) return true;\n if (!current.startsWith(path + \"/\")) return false;\n if (siblingPaths?.length) {\n const matchedSibling = siblingPaths.some((s) => s !== path && (current === s || current.startsWith(s + \"/\")));\n if (matchedSibling) return false;\n }\n return true;\n}\n\nfunction isSubMenuActive(current: string, item: SidebarMenuItem): boolean {\n if (isPathActive(current, item.path, item.children?.map((c) => c.path))) return true;\n if (!item.children) return false;\n return item.children.some((child) => isPathActive(current, child.path, item.children?.map((c) => c.path)) || isSubMenuActive(current, child));\n}\n\nconst Sidebar = memo(\n ({\n children,\n collapsed = false,\n toggled = false,\n onBackdropClick,\n breakPoint = \"all\",\n className,\n items = [],\n currentPathname = \"\",\n onNavigate,\n logoutLabel = \"Logout\",\n handleLogout,\n bottomLogoutButton,\n }: SidebarProps) => {\n const handleItemClick = useCallback(\n (path: string) => {\n onNavigate?.(path);\n },\n [onNavigate],\n );\n\n const renderItem = useCallback(\n (item: SidebarMenuItem, siblingPaths?: string[]) => {\n const active = isPathActive(currentPathname, item.path, siblingPaths);\n if (item.children?.length) {\n const subActive = isSubMenuActive(currentPathname, item);\n return (\n <SubMenu key={item.path} label={item.label} icon={item.icon} active={subActive}>\n {item.children.map((child) => renderItem(child, item.children!.map((c) => c.path)))}\n </SubMenu>\n );\n }\n return (\n <MenuItem key={item.path} icon={item.icon} onClick={() => handleItemClick(item.path)} active={active}>\n {item.label}\n </MenuItem>\n );\n },\n [currentPathname, handleItemClick],\n );\n\n const menuContent =\n items.length > 0 ? (\n <Menu\n key={`${collapsed}-${toggled}`}\n transitionDuration={300}\n closeOnClick\n menuItemStyles={{\n button: {\n color: \"var(--color-fg-text)\",\n backgroundColor: \"transparent\",\n \"&:hover\": {\n backgroundColor: \"var(--color-bg-3)\",\n color: \"var(--color-fg-text)\",\n },\n \"&.active\": {\n backgroundColor: \"var(--color-primary)\",\n color: \"#ffffff\",\n },\n },\n icon: {\n color: \"var(--color-fg-text)\",\n \"&.active\": {\n color: \"#ffffff\",\n },\n },\n label: {\n color: \"var(--color-fg-text)\",\n \"&.active\": {\n color: \"#ffffff\",\n },\n },\n }}\n >\n {items.map((item) => renderItem(item))}\n </Menu>\n ) : null;\n\n const bottomLogoutButtonContent = useMemo(() => {\n if (bottomLogoutButton != null) return bottomLogoutButton;\n if (handleLogout != null) {\n return (\n <div className={styles.logoutContainer}>\n <button type=\"button\" className={styles.logoutButton} onClick={handleLogout} title={logoutLabel}>\n <LogOut size={20} />\n <span className={collapsed ? styles.hiddenText : styles.visibleText}>{logoutLabel}</span>\n </button>\n </div>\n );\n }\n return null;\n }, [collapsed, logoutLabel, handleLogout, bottomLogoutButton]);\n\n return (\n <ProSidebar\n collapsed={collapsed}\n toggled={toggled}\n onBackdropClick={onBackdropClick}\n breakPoint={breakPoint}\n backgroundColor=\"var(--color-bg-2)\"\n rootStyles={{\n border: \"none\",\n borderRight: \"1px solid var(--color-separator)\",\n }}\n className={`${styles.sidebar} ${className || \"\"}`}\n >\n <div className={styles.sidebarContent} onWheel={(e) => e.stopPropagation()}>\n <div className={styles.menuWrapper}>{children ?? menuContent}</div>\n {bottomLogoutButtonContent}\n </div>\n </ProSidebar>\n );\n },\n);\n\nSidebar.displayName = \"Sidebar\";\nexport default Sidebar;\n","/* ===== Footer Component ===== */\r\n\r\n.footer {\r\n background: var(--color-bg-2);\r\n padding: 0 2rem;\r\n width: 100%;\r\n}\r\n\r\n.footerContent {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n max-width: 100%;\r\n margin: 0 auto;\r\n}\r\n\r\n.copyright {\r\n color: var(--color-fg-text);\r\n font-size: 0.875rem;\r\n}\r\n\r\n.links {\r\n display: flex;\r\n gap: 1.5rem;\r\n}\r\n\r\n.link {\r\n color: var(--color-fg-text);\r\n font-size: 0.875rem;\r\n text-decoration: none;\r\n transition: color 0.3s ease;\r\n}\r\n\r\n.link:hover {\r\n color: var(--color-primary);\r\n}\r\n\r\n/* ===== 响应式 ===== */\r\n@media (max-width: 768px) {\r\n .footerContent {\r\n flex-direction: column;\r\n gap: 1rem;\r\n }\r\n\r\n .links {\r\n gap: 1rem;\r\n }\r\n}\r\n","import type { FooterProps } from \"../../types\";\n\nimport { memo } from \"react\";\n\nimport styles from \"./styles.module.css\";\n\nexport const DefaultFooterContent = memo(() => {\n const currentYear = new Date().getFullYear();\n return (\n <div className={styles.footerContent}>\n <span className={styles.copyright}>© {currentYear}</span>\n <div className={styles.links}>\n <a href=\"#\" className={styles.link}>\n About Us\n </a>\n <a href=\"#\" className={styles.link}>\n Privacy Policy\n </a>\n <a href=\"#\" className={styles.link}>\n Terms of Service\n </a>\n </div>\n </div>\n );\n});\nDefaultFooterContent.displayName = \"DefaultFooterContent\";\n\n/** 通用 Footer:只负责布局与样式,内容由外部传入。 */\nconst Footer = memo(({ children, className }: FooterProps) => {\n return <div className={`${styles.footer} ${className || \"\"}`}>{children ?? <DefaultFooterContent />}</div>;\n});\n\nFooter.displayName = \"Footer\";\n\nexport default Footer;\n","/* ===== Header - 主容器样式 ===== */\r\n\r\n.header {\r\n display: flex;\r\n width: 100%;\r\n padding: 0.5rem 2rem;\r\n}\r\n\r\n/* 左侧容器:占一半,左对齐 */\r\n.header> :first-child {\r\n flex: 1;\r\n display: flex;\r\n justify-content: flex-start;\r\n align-items: center;\r\n}\r\n\r\n/* 右侧容器:占一半,右对齐 */\r\n.header> :last-child {\r\n flex: 1;\r\n display: flex;\r\n justify-content: flex-end;\r\n align-items: center;\r\n}","import type { HeaderProps } from \"../../types\";\n\nimport { memo } from \"react\";\n\nimport styles from \"./styles.module.css\";\n\n/** 通用 Header:只负责布局左右两栏,内容全部由外部传入,内部不获取数据。Generic header: layout only; all content from props. */\nconst Header = memo(({ leftContent, rightContent }: HeaderProps) => {\n return (\n <div className={styles.header}>\n <div>{leftContent}</div>\n <div>{rightContent}</div>\n </div>\n );\n});\n\nHeader.displayName = \"Header\";\nexport default Header;\n","/* ===== One Column Layout ===== */\r\n\r\n.layout {\r\n display: flex;\r\n flex-direction: column;\r\n height: 100vh;\r\n width: 100%;\r\n background: var(--color-bg);\r\n position: relative;\r\n}\r\n\r\n/* ===== Header ===== */\r\n.header {\r\n position: fixed;\r\n top: 0;\r\n z-index: 100;\r\n background: var(--color-bg);\r\n width: 100%;\r\n box-shadow: 0 0.125rem 0.25rem 0 rgba(44, 51, 73, 0.1);\r\n}\r\n\r\n\r\n/* ===== Footer ===== */\r\n.footer {\r\n position: fixed;\r\n bottom: 0;\r\n width: 100%;\r\n z-index: 100;\r\n}\r\n","import type { MainWrapperProps } from \"../../types\";\n\nimport { memo, useCallback, useLayoutEffect, useRef, useState } from \"react\";\n\nimport Footer from \"../Footer\";\nimport Header from \"../Header\";\nimport styles from \"./styles.module.css\";\n\nfunction useElementHeight<T extends HTMLElement>() {\n const ref = useRef<T | null>(null);\n const [height, setHeight] = useState(0);\n\n useLayoutEffect(() => {\n const node = ref.current;\n if (!node) return;\n\n const observer = new ResizeObserver(([entry]) => {\n const nextHeight = entry?.contentRect.height ?? 0;\n setHeight((prev) => (prev !== nextHeight ? nextHeight : prev));\n });\n\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n const callbackRef = useCallback((instance: T | null) => {\n if (instance) {\n ref.current = instance;\n }\n }, []);\n\n return [callbackRef, height] as const;\n}\n\nconst MainWrapper = memo(({ children, headerLeft, headerRight, footerContent }: MainWrapperProps) => {\n const [headerRef, headerHeight] = useElementHeight<HTMLDivElement>();\n const [footerRef, footerHeight] = useElementHeight<HTMLDivElement>();\n\n return (\n <div className={styles.layout}>\n <header ref={headerRef} className={styles.header}>\n <Header leftContent={headerLeft} rightContent={headerRight} />\n </header>\n\n {children(headerHeight, footerHeight)}\n\n {/* Footer */}\n <footer ref={footerRef} className={styles.footer}>\n <Footer>{footerContent}</Footer>\n </footer>\n </div>\n );\n});\n\nMainWrapper.displayName = \"MainWrapper\";\nexport default MainWrapper;\n",".mainWrapper {\n display: flex;\n flex: 1;\n position: relative;\n}\n\n.sidebar {\n position: fixed;\n top: 0;\n}\n\n.content {\n flex: 1;\n background: var(--color-bg);\n overflow-y: auto;\n overflow-x: hidden;\n min-height: calc(100vh - 10rem);\n padding-top: 0;\n padding-bottom: 0;\n margin: 0;\n}\n\n@media (max-width: 768px) {\n .content {\n width: 100%;\n }\n .sidebar {\n position: fixed;\n top: 0;\n left: 0;\n height: 100vh;\n z-index: 999;\n }\n}\n","import type { SideHideLayoutProps } from \"../../types\";\n\nimport { memo, useCallback } from \"react\";\n\nimport useLayout from \"../../hooks/useLayout\";\nimport Sidebar from \"../Sidebar\";\nimport styles from \"./styles.module.css\";\n\nconst SideHideLayout = memo(\n ({\n children,\n headerHeight,\n footerHeight,\n sidebarItems,\n sidebarCurrentPathname,\n onSidebarNavigate,\n sidebarLogoutLabel,\n onSidebarLogout,\n }: SideHideLayoutProps) => {\n const { sidebarOpen, closeSidebar } = useLayout();\n\n const handleBackdropClick = useCallback(() => {\n closeSidebar();\n }, [closeSidebar]);\n\n return (\n <main\n className={styles.mainWrapper}\n style={{\n marginTop: `${headerHeight}px`,\n marginBottom: `${footerHeight}px`,\n }}\n >\n <Sidebar\n toggled={sidebarOpen}\n onBackdropClick={handleBackdropClick}\n breakPoint=\"all\"\n className={styles.sidebar}\n items={sidebarItems}\n currentPathname={sidebarCurrentPathname}\n onNavigate={onSidebarNavigate}\n logoutLabel={sidebarLogoutLabel}\n handleLogout={onSidebarLogout}\n />\n <div className={styles.content} data-lenis-prevent>\n {children}\n </div>\n </main>\n );\n },\n);\n\nSideHideLayout.displayName = \"SideHideLayout\";\n\nexport default SideHideLayout;\n","/* ===== Main Wrapper (Sidebar + Content) ===== */\n.mainWrapper {\n display: flex;\n flex: 1;\n position: relative;\n flex-direction: row;\n}\n\n.sidebarContainer {\n position: fixed;\n left: 0;\n z-index: 99;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.sidebar {\n top: 0;\n left: 0;\n flex-shrink: 0;\n}\n\n.content {\n flex: 1;\n background: var(--color-bg);\n overflow-y: auto;\n overflow-x: hidden;\n padding-top: 0;\n padding-bottom: 0;\n margin: 0;\n}\n\n@media (max-width: 1024px) {\n .content {\n padding: 1.5rem;\n }\n}\n\n@media (max-width: 768px) {\n .content {\n width: 100%;\n }\n .sidebar {\n position: fixed;\n top: 0;\n left: 0;\n height: 100vh;\n z-index: 999;\n }\n}\n","import type { SideShowLayoutProps } from \"../../types\";\n\nimport { memo, useCallback, useLayoutEffect, useRef, useState } from \"react\";\n\nimport useLayout from \"../../hooks/useLayout\";\nimport Sidebar from \"../Sidebar\";\nimport styles from \"./styles.module.css\";\n\nfunction useElementWidth<T extends HTMLElement>() {\n const ref = useRef<T | null>(null);\n const [width, setWidth] = useState(0);\n\n useLayoutEffect(() => {\n const node = ref.current;\n if (!node) return;\n\n const observer = new ResizeObserver(([entry]) => {\n const nextWidth = entry?.contentRect.width ?? 0;\n setWidth((prev) => (prev !== nextWidth ? nextWidth : prev));\n });\n\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n const callbackRef = useCallback((instance: T | null) => {\n if (instance) {\n ref.current = instance;\n }\n }, []);\n\n return [callbackRef, width] as const;\n}\n\nconst SideShowLayout = memo(\n ({\n children,\n headerHeight,\n footerHeight,\n sidebarItems,\n sidebarCurrentPathname,\n onSidebarNavigate,\n sidebarLogoutLabel,\n onSidebarLogout,\n }: SideShowLayoutProps) => {\n const { sidebarOpen, closeSidebar } = useLayout();\n const [sidebarRef, sidebarWidth] = useElementWidth<HTMLDivElement>();\n\n const handleBackdropClick = () => {\n closeSidebar();\n };\n\n return (\n <>\n <div\n ref={sidebarRef}\n className={styles.sidebarContainer}\n style={{\n top: `${headerHeight}px`,\n height: `calc(100vh - ${headerHeight + footerHeight}px)`,\n }}\n >\n <Sidebar\n collapsed={sidebarOpen}\n toggled={sidebarOpen}\n onBackdropClick={handleBackdropClick}\n breakPoint=\"xs\"\n className={styles.sidebar}\n items={sidebarItems}\n currentPathname={sidebarCurrentPathname}\n onNavigate={onSidebarNavigate}\n logoutLabel={sidebarLogoutLabel}\n handleLogout={onSidebarLogout}\n />\n </div>\n <main\n className={styles.mainWrapper}\n style={{\n marginTop: `${headerHeight}px`,\n marginBottom: `${footerHeight}px`,\n marginLeft: `${sidebarWidth}px`,\n width: `calc(100% - ${sidebarWidth}px)`,\n }}\n >\n <div className={styles.content} data-lenis-prevent>\n {children}\n </div>\n </main>\n </>\n );\n },\n);\n\nSideShowLayout.displayName = \"SideShowLayout\";\nexport default SideShowLayout;\n",".wavesWrapper {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n width: 100vw;\n height: 100vh;\n pointer-events: none;\n z-index: 0;\n overflow: hidden;\n}\n\n.wavesWrapper > * {\n pointer-events: auto;\n}\n\n.squaresWrapper {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n width: 100vw;\n height: 100vh;\n pointer-events: none;\n z-index: 0;\n overflow: hidden;\n}\n\n.squaresWrapper > * {\n pointer-events: auto;\n}\n\n.letterGlitchWrapper {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n width: 100vw;\n height: 100vh;\n pointer-events: none;\n z-index: 0;\n overflow: hidden;\n}\n\n.letterGlitchWrapper > * {\n pointer-events: auto;\n}\n\n.pixelBlastWrapper {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n width: 100vw;\n height: 100vh;\n pointer-events: none;\n z-index: 0;\n overflow: hidden;\n}\n\n.pixelBlastWrapper > * {\n pointer-events: auto;\n}\n","import type { ReactNode } from \"react\";\n\nimport { Suspense, lazy, memo } from \"react\";\n\nimport { LetterGlitchBackground, SquareBackground, WaveBackground } from \"@/designs/animations\";\nimport { DashboardBackgroundEnum } from \"@/preference\";\n\nimport styles from \"./styles.module.css\";\n\nconst LazyPixelBlast = lazy(() => import(\"@/designs/animations/PixelBlast\"));\n\ninterface BackgroundProps {\n children: ReactNode;\n /** 可选:外部传入的偏好,有则优先使用;否则从 profile.preference 解析。Optional: preference from parent; otherwise parsed from profile. */\n background?: DashboardBackgroundEnum | null;\n}\n\n/** 与 NFX-Identity/console 一致:仪表盘背景由用户偏好(可外部传入或从 profile 解析) */\nconst Background = memo(({ children, background }: BackgroundProps) => {\n const renderBackground = () => {\n switch (background) {\n case DashboardBackgroundEnum.WAVES:\n return (\n <div className={styles.wavesWrapper}>\n <WaveBackground />\n </div>\n );\n case DashboardBackgroundEnum.SQUARES:\n return (\n <div className={styles.squaresWrapper}>\n <SquareBackground />\n </div>\n );\n case DashboardBackgroundEnum.LETTER_GLITCH:\n return (\n <div className={styles.letterGlitchWrapper}>\n <LetterGlitchBackground />\n </div>\n );\n case DashboardBackgroundEnum.PIXEL_BLAST:\n return (\n <Suspense fallback={null}>\n <div className={styles.pixelBlastWrapper}>\n <LazyPixelBlast />\n </div>\n </Suspense>\n );\n case DashboardBackgroundEnum.NONE:\n default:\n return null;\n }\n };\n\n return (\n <>\n {children}\n {renderBackground()}\n </>\n );\n});\n\nBackground.displayName = \"Background\";\nexport default Background;\nexport type { BackgroundProps };\n","import type { LayoutFrameProps } from \"../../types\";\n\nimport { memo } from \"react\";\n\nimport useLayout from \"../../hooks/useLayout\";\nimport { LayoutModeEnum } from \"../../types\";\nimport MainWrapper from \"../MainWrapper\";\nimport SideHideLayout from \"../SideHideLayout\";\nimport SideShowLayout from \"../SideShowLayout\";\n\nexport const LayoutFrame = memo(\n ({\n children,\n headerLeft,\n headerRight,\n footerContent,\n sidebarItems,\n sidebarCurrentPathname,\n onSidebarNavigate,\n sidebarLogoutLabel,\n onSidebarLogout,\n bottomLogoutButton,\n }: LayoutFrameProps) => {\n const { layoutMode } = useLayout();\n return (\n <MainWrapper headerLeft={headerLeft} headerRight={headerRight} footerContent={footerContent}>\n {(headerHeight, footerHeight) => {\n if (layoutMode === LayoutModeEnum.HIDE) {\n return (\n <SideHideLayout\n headerHeight={headerHeight}\n footerHeight={footerHeight}\n sidebarItems={sidebarItems}\n sidebarCurrentPathname={sidebarCurrentPathname}\n onSidebarNavigate={onSidebarNavigate}\n sidebarLogoutLabel={sidebarLogoutLabel}\n onSidebarLogout={onSidebarLogout}\n bottomLogoutButton={bottomLogoutButton}\n >\n {children}\n </SideHideLayout>\n );\n } else {\n return (\n <SideShowLayout\n headerHeight={headerHeight}\n footerHeight={footerHeight}\n sidebarItems={sidebarItems}\n sidebarCurrentPathname={sidebarCurrentPathname}\n onSidebarNavigate={onSidebarNavigate}\n sidebarLogoutLabel={sidebarLogoutLabel}\n onSidebarLogout={onSidebarLogout}\n bottomLogoutButton={bottomLogoutButton}\n >\n {children}\n </SideShowLayout>\n );\n }\n }}\n </MainWrapper>\n );\n },\n);\n\nLayoutFrame.displayName = \"LayoutFrame\";\nexport default LayoutFrame;\n","import { useCallback, useEffect, useState } from \"react\";\n\nimport { getLayoutStorage, setLayoutStorage } from \"../utils\";\nimport { LayoutModeEnum } from \"../types\";\n\ninterface UseSetProps {\n defaultLayoutMode: LayoutModeEnum;\n sidebarOpen: boolean;\n}\n\nconst useSet = ({ defaultLayoutMode, sidebarOpen }: UseSetProps) => {\n const [layoutMode, setLayoutModeState] = useState<LayoutModeEnum>(() => {\n const saved = getLayoutStorage();\n if (saved) {\n try {\n const parsed = JSON.parse(saved);\n const mode = parsed.state?.layoutMode ?? parsed.layoutMode;\n return mode === LayoutModeEnum.SHOW || mode === LayoutModeEnum.HIDE ? mode : defaultLayoutMode;\n } catch {\n return defaultLayoutMode;\n }\n }\n return defaultLayoutMode;\n });\n\n useEffect(() => {\n const storage = {\n state: {\n sidebarOpen,\n layoutMode,\n },\n };\n setLayoutStorage(JSON.stringify(storage));\n }, [sidebarOpen, layoutMode]);\n\n const setLayoutMode = useCallback((mode: LayoutModeEnum) => {\n setLayoutModeState(mode);\n }, []);\n\n return {\n layoutMode,\n setLayoutMode,\n };\n};\n\nexport default useSet;\n","import { useCallback, useState } from \"react\";\n\nimport { getLayoutStorage } from \"../utils\";\n\nconst useAction = () => {\n const [sidebarOpen, setSidebarOpenState] = useState<boolean>(() => {\n const saved = getLayoutStorage();\n if (saved) {\n try {\n const parsed = JSON.parse(saved);\n return parsed.state?.sidebarOpen ?? parsed.sidebarOpen ?? false;\n } catch {\n return false;\n }\n }\n return false;\n });\n\n const setSidebarOpen = useCallback((open: boolean) => {\n setSidebarOpenState(open);\n }, []);\n\n const toggleSidebar = useCallback(() => {\n setSidebarOpenState((prev) => !prev);\n }, []);\n\n const closeSidebar = useCallback(() => {\n setSidebarOpenState(false);\n }, []);\n\n return {\n sidebarOpen,\n setSidebarOpen,\n toggleSidebar,\n closeSidebar,\n };\n};\n\nexport default useAction;\n","/**\n * 布局提供者:提供侧栏开关与显示/隐藏模式上下文。\n * Layout provider: provides sidebar state and show/hide layout mode context.\n */\nimport type { LayoutProviderProps } from \"../types\";\n\nimport { memo } from \"react\";\n\nimport useAction from \"../hooks/useAction\";\nimport { LayoutContext } from \"../hooks/useLayout\";\nimport useSet from \"../hooks/useSet\";\nimport { DEFAULT_LAYOUT_MODE } from \"../types\";\n\nconst LayoutProvider = memo(({ children, defaultLayoutMode = DEFAULT_LAYOUT_MODE }: LayoutProviderProps) => {\n const { sidebarOpen, setSidebarOpen, toggleSidebar, closeSidebar } = useAction();\n const { layoutMode, setLayoutMode } = useSet({ defaultLayoutMode, sidebarOpen });\n\n return (\n <LayoutContext.Provider\n value={{\n sidebarOpen,\n layoutMode,\n setSidebarOpen,\n toggleSidebar,\n closeSidebar,\n setLayoutMode,\n }}\n >\n {children}\n </LayoutContext.Provider>\n );\n});\n\nLayoutProvider.displayName = \"LayoutProvider\";\nexport default LayoutProvider;\n"],"mappings":"2bASA,SAAgB,GAAoC,CAClD,OAAO,EAAA,QAAQ,EAAA,kBAAA,EAGjB,SAAgB,EAAiB,EAAqB,CACpD,EAAA,QAAQ,EAAA,mBAAoB,CAAA,EAG9B,SAAgB,GAA4B,CAC1C,EAAA,WAAW,EAAA,kBAAA,+YELb,SAAS,EAAa,EAAiB,EAAc,EAAkC,CACrF,OAAI,IAAY,EAAa,GACzB,GAAC,EAAQ,WAAW,EAAO,GAAA,GAC3B,GAAc,QACO,EAAa,KAAM,GAAM,IAAM,IAAS,IAAY,GAAK,EAAQ,WAAW,EAAI,GAAA,EAAI,GAM/G,SAAS,EAAgB,EAAiB,EAAgC,CACxE,OAAI,EAAa,EAAS,EAAK,KAAM,EAAK,UAAU,IAAK,GAAM,EAAE,IAAA,CAAK,EAAU,GAC3E,EAAK,SACH,EAAK,SAAS,KAAM,GAAU,EAAa,EAAS,EAAM,KAAM,EAAK,UAAU,IAAK,GAAM,EAAE,IAAA,CAAK,GAAK,EAAgB,EAAS,CAAA,CAAM,EADjH,GAI7B,IAAM,KAAA,EAAA,MAAA,CACH,CACC,SAAA,EACA,UAAA,EAAY,GACZ,QAAA,EAAU,GACV,gBAAA,EACA,WAAA,EAAa,MACb,UAAA,EACA,MAAA,EAAQ,CAAA,EACR,gBAAA,EAAkB,GAClB,WAAA,EACA,YAAA,EAAc,SACd,aAAA,EACA,mBAAA,CAAA,IACkB,CAClB,MAAM,KAAA,EAAA,aACH,GAAiB,CAChB,IAAa,CAAA,GAEf,CAAC,CAAA,CAAW,EAGR,KAAA,EAAA,aAAA,CACH,EAAuB,IAA4B,CAClD,MAAM,EAAS,EAAa,EAAiB,EAAK,KAAM,CAAA,EACxD,GAAI,EAAK,UAAU,OAAQ,CACzB,MAAM,EAAY,EAAgB,EAAiB,CAAA,EACnD,SAAA,EAAA,KACG,EAAA,QAAD,CAAyB,MAAO,EAAK,MAAO,KAAM,EAAK,KAAM,OAAQ,WAClE,EAAK,SAAS,IAAK,GAAU,EAAW,EAAO,EAAK,SAAU,IAAK,GAAM,EAAE,IAAA,CAAK,CAAC,GADtE,EAAK,IAAA,EAKvB,SAAA,EAAA,KACG,EAAA,SAAD,CAA0B,KAAM,EAAK,KAAM,QAAA,IAAe,EAAgB,EAAK,IAAA,EAAe,OAAA,WAC3F,EAAK,OADO,EAAK,IAAA,GAKxB,CAAC,EAAiB,CAAA,CAAgB,EAG9B,EACJ,EAAM,OAAS,KAAA,EAAA,KACZ,EAAA,KAAD,CAEE,mBAAoB,IACpB,aAAA,GACA,eAAgB,CACd,OAAQ,CACN,MAAO,uBACP,gBAAiB,cACjB,UAAW,CACT,gBAAiB,oBACjB,MAAO,wBAET,WAAY,CACV,gBAAiB,uBACjB,MAAO,YAGX,KAAM,CACJ,MAAO,uBACP,WAAY,CACV,MAAO,SAAA,GAGX,MAAO,CACL,MAAO,uBACP,WAAY,CACV,MAAO,SAAA,aAKZ,EAAM,IAAK,GAAS,EAAW,CAAA,CAAK,GA9BhC,GAAG,CAAA,IAAa,CAAA,EAAA,EAgCrB,KAEA,KAAA,EAAA,SAAA,IACA,IACA,GAAgB,QAClB,EAAA,KACG,MAAD,CAAK,UAAW,EAAO,oCACpB,SAAD,CAAQ,KAAK,SAAS,UAAW,EAAO,aAAc,QAAS,EAAc,MAAO,WAApF,IAAA,EAAA,KACG,EAAA,OAAD,CAAQ,KAAM,EAAA,CAAM,KAAA,EAAA,KACnB,OAAD,CAAM,UAAW,EAAY,EAAO,WAAa,EAAO,qBAAc,EAAmB,CAAA,IAEvF,EAGH,MACN,CAAC,EAAW,EAAa,EAAc,EAAmB,EAE7D,SAAA,EAAA,KACG,EAAA,QAAD,CACa,UAAA,EACF,QAAA,EACQ,gBAAA,EACL,WAAA,EACZ,gBAAgB,oBAChB,WAAY,CACV,OAAQ,OACR,YAAa,oCAEf,UAAW,GAAG,EAAO,OAAA,IAAW,GAAa,EAAA,uBAE5C,MAAD,CAAK,UAAW,EAAO,eAAgB,QAAU,GAAM,EAAE,gBAAA,WAAzD,IAAA,EAAA,KACG,MAAD,CAAK,UAAW,EAAO,qBAAc,GAAY,EAAkB,EAClE,CAAA,IAEQ,IAKnB,EAAQ,YAAc,iQE3IT,KAAA,EAAA,MAAA,IAAkC,CAC7C,MAAM,EAAc,IAAI,KAAA,EAAO,YAAA,EAC/B,SAAA,EAAA,MACG,MAAD,CAAK,UAAW,EAAO,uBAAvB,IAAA,EAAA,MACG,OAAD,CAAM,UAAW,EAAO,mBAAxB,CAAmC,KAAG,CAAA,eACrC,MAAD,CAAK,UAAW,EAAO,eAAvB,WACG,IAAD,CAAG,KAAK,IAAI,UAAW,EAAO,cAAM,WAEhC,YACH,IAAD,CAAG,KAAK,IAAI,UAAW,EAAO,cAAM,iBAEhC,YACH,IAAD,CAAG,KAAK,IAAI,UAAW,EAAO,cAAM,mBAEhC,UAKZ,EAAqB,YAAc,uBAGnC,IAAM,KAAA,EAAA,MAAA,CAAe,CAAE,SAAA,EAAU,UAAA,CAAA,OAC/B,EAAA,KAAQ,MAAD,CAAK,UAAW,GAAG,EAAO,MAAA,IAAU,GAAa,EAAA,YAAO,MAAA,EAAA,KAAa,EAAD,CAAA,CAAwB,EAAO,GAG5G,EAAO,YAAc,+DEzBf,KAAA,EAAA,MAAA,CAAe,CAAE,YAAA,EAAa,aAAA,CAAA,OAClC,EAAA,MACG,MAAD,CAAK,UAAW,GAAO,gBAAvB,IAAA,EAAA,KACG,MAAD,CAAA,SAAM,CAAA,CAAkB,KAAA,EAAA,KACvB,MAAD,CAAA,SAAM,CAAA,CAAmB,CAAA,KAK/B,EAAO,YAAc,wJERrB,SAAS,GAA0C,CACjD,MAAM,KAAA,EAAA,QAAuB,IAAA,EACvB,CAAC,EAAQ,CAAA,KAAA,EAAA,UAAsB,CAAA,EAErC,SAAA,EAAA,iBAAA,IAAsB,CACpB,MAAM,EAAO,EAAI,QACjB,GAAI,CAAC,EAAM,OAEX,MAAM,EAAW,IAAI,eAAA,CAAgB,CAAC,CAAA,IAAW,CAC/C,MAAM,EAAa,GAAO,YAAY,QAAU,EAChD,EAAW,GAAU,IAAS,EAAa,EAAa,CAAA,IAG1D,OAAA,EAAS,QAAQ,CAAA,EACjB,IAAa,EAAS,WAAA,GACrB,CAAA,CAAE,EAQE,IAAA,EAAA,aAN0B,GAAuB,CAClD,IACF,EAAI,QAAU,IAEf,CAAA,CAAE,EAEgB,CAAA,EAGvB,IAAM,KAAA,EAAA,MAAA,CAAoB,CAAE,SAAA,EAAU,WAAA,EAAY,YAAA,EAAa,cAAA,CAAA,IAAsC,CACnG,KAAM,CAAC,EAAW,CAAA,EAAgB,EAAA,EAC5B,CAAC,EAAW,CAAA,EAAgB,EAAA,EAElC,SAAA,EAAA,MACG,MAAD,CAAK,UAAW,EAAO,gBAAvB,WACG,SAAD,CAAQ,IAAK,EAAW,UAAW,EAAO,0BACvC,EAAD,CAAQ,YAAa,EAAY,aAAc,EAAe,EACvD,EAER,EAAS,EAAc,CAAA,YAGvB,SAAD,CAAQ,IAAK,EAAW,UAAW,EAAO,0BACvC,EAAD,CAAA,SAAS,CAAA,CAAuB,EACzB,OAKf,EAAY,YAAc,2KE9CpB,KAAA,EAAA,MAAA,CACH,CACC,SAAA,EACA,aAAA,EACA,aAAA,EACA,aAAA,EACA,uBAAA,EACA,kBAAA,EACA,mBAAA,EACA,gBAAA,CAAA,IACyB,CACzB,KAAM,CAAE,YAAA,EAAa,aAAA,CAAA,EAAiB,EAAA,UAAA,EAEhC,KAAA,EAAA,aAAA,IAAwC,CAC5C,EAAA,GACC,CAAC,CAAA,CAAa,EAEjB,SAAA,EAAA,MACG,OAAD,CACE,UAAW,EAAO,YAClB,MAAO,CACL,UAAW,GAAG,CAAA,KACd,aAAc,GAAG,CAAA,eAJrB,IAAA,EAAA,KAOG,EAAD,CACE,QAAS,EACT,gBAAiB,EACjB,WAAW,MACX,UAAW,EAAO,QAClB,MAAO,EACP,gBAAiB,EACjB,WAAY,EACZ,YAAa,EACb,aAAc,EACd,KAAA,EAAA,KACD,MAAD,CAAK,UAAW,EAAO,QAAS,qBAAA,GAC7B,SAAA,EACG,CAAA,MAMd,EAAe,YAAc,+OE5C7B,SAAS,IAAyC,CAChD,MAAM,KAAA,EAAA,QAAuB,IAAA,EACvB,CAAC,EAAO,CAAA,KAAA,EAAA,UAAqB,CAAA,EAEnC,SAAA,EAAA,iBAAA,IAAsB,CACpB,MAAM,EAAO,EAAI,QACjB,GAAI,CAAC,EAAM,OAEX,MAAM,EAAW,IAAI,eAAA,CAAgB,CAAC,CAAA,IAAW,CAC/C,MAAM,EAAY,GAAO,YAAY,OAAS,EAC9C,EAAU,GAAU,IAAS,EAAY,EAAY,CAAA,IAGvD,OAAA,EAAS,QAAQ,CAAA,EACjB,IAAa,EAAS,WAAA,GACrB,CAAA,CAAE,EAQE,IAAA,EAAA,aAN0B,GAAuB,CAClD,IACF,EAAI,QAAU,IAEf,CAAA,CAAE,EAEgB,CAAA,EAGvB,IAAM,KAAA,EAAA,MAAA,CACH,CACC,SAAA,EACA,aAAA,EACA,aAAA,EACA,aAAA,EACA,uBAAA,EACA,kBAAA,EACA,mBAAA,EACA,gBAAA,CAAA,IACyB,CACzB,KAAM,CAAE,YAAA,EAAa,aAAA,CAAA,EAAiB,EAAA,UAAA,EAChC,CAAC,EAAY,CAAA,EAAgB,GAAA,EAE7B,EAAA,IAA4B,CAChC,EAAA,GAGF,SAAA,EAAA,MACE,EAAA,SAAA,CAAA,SAAA,IAAA,EAAA,KACG,MAAD,CACE,IAAK,EACL,UAAW,EAAO,iBAClB,MAAO,CACL,IAAK,GAAG,CAAA,KACR,OAAQ,gBAAgB,EAAe,CAAA,0BAGxC,EAAD,CACE,UAAW,EACX,QAAS,EACT,gBAAiB,EACjB,WAAW,KACX,UAAW,EAAO,QAClB,MAAO,EACP,gBAAiB,EACjB,WAAY,EACZ,YAAa,EACb,aAAc,EACd,EACE,KAAA,EAAA,KACL,OAAD,CACE,UAAW,EAAO,YAClB,MAAO,CACL,UAAW,GAAG,CAAA,KACd,aAAc,GAAG,CAAA,KACjB,WAAY,GAAG,CAAA,KACf,MAAO,eAAe,CAAA,0BAGvB,MAAD,CAAK,UAAW,EAAO,QAAS,qBAAA,GAC7B,SAAA,EACG,EACD,CAAA,CACN,CAAA,IAKT,EAAe,YAAc,yREpFvB,MAAA,EAAA,MAAA,IAAA,QAAA,QAAA,EAAA,KAAA,IAAA,QAA4B,mBAAA,CAAA,CAAA,EAS5B,KAAA,EAAA,MAAA,CAAmB,CAAE,SAAA,EAAU,WAAA,CAAA,IAAkC,CACrE,MAAM,EAAA,IAAyB,CAC7B,OAAQ,EAAR,CACE,KAAK,EAAA,wBAAwB,MAC3B,SAAA,EAAA,KACG,MAAD,CAAK,UAAW,EAAO,gCACpB,EAAA,eAAD,CAAA,CAAkB,EACd,EAEV,KAAK,EAAA,wBAAwB,QAC3B,SAAA,EAAA,KACG,MAAD,CAAK,UAAW,EAAO,kCACpB,EAAA,iBAAD,CAAA,CAAoB,EAChB,EAEV,KAAK,EAAA,wBAAwB,cAC3B,SAAA,EAAA,KACG,MAAD,CAAK,UAAW,EAAO,uCACpB,EAAA,uBAAD,CAAA,CAA0B,EACtB,EAEV,KAAK,EAAA,wBAAwB,YAC3B,SAAA,EAAA,KACG,EAAA,SAAD,CAAU,SAAU,wBACjB,MAAD,CAAK,UAAW,EAAO,qCACpB,GAAD,CAAA,CAAkB,EACd,EACG,EAEf,KAAK,EAAA,wBAAwB,KAC7B,QACE,OAAO,OAIb,SAAA,EAAA,MACE,EAAA,SAAA,CAAA,SAAA,CACG,EACA,EAAA,CAAkB,CAClB,CAAA,IAIP,EAAW,YAAc,aCnDzB,IAAa,KAAA,EAAA,MAAA,CACV,CACC,SAAA,EACA,WAAA,EACA,YAAA,EACA,cAAA,EACA,aAAA,EACA,uBAAA,EACA,kBAAA,EACA,mBAAA,EACA,gBAAA,EACA,mBAAA,CAAA,IACsB,CACtB,KAAM,CAAE,WAAA,CAAA,EAAe,EAAA,UAAA,EACvB,SAAA,EAAA,KACG,EAAD,CAAyB,WAAA,EAAyB,YAAA,EAA4B,cAAA,YAC1E,EAAc,IACV,IAAe,EAAA,eAAe,QAChC,EAAA,KACG,EAAD,CACgB,aAAA,EACA,aAAA,EACA,aAAA,EACU,uBAAA,EACL,kBAAA,EACC,mBAAA,EACH,gBAAA,EACG,mBAAA,EAEnB,SAAA,EACc,KAGnB,EAAA,KACG,EAAD,CACgB,aAAA,EACA,aAAA,EACA,aAAA,EACU,uBAAA,EACL,kBAAA,EACC,mBAAA,EACH,gBAAA,EACG,mBAAA,EAEnB,SAAA,EACc,EAIX,IAKpB,EAAY,YAAc,cCtD1B,IAAM,GAAA,CAAU,CAAE,kBAAA,EAAmB,YAAA,CAAA,IAA+B,CAClE,KAAM,CAAC,EAAY,CAAA,KAAA,EAAA,UAAA,IAAqD,CACtE,MAAM,EAAQ,EAAA,EACd,GAAI,EACF,GAAI,CACF,MAAM,EAAS,KAAK,MAAM,CAAA,EACpB,EAAO,EAAO,OAAO,YAAc,EAAO,WAChD,OAAO,IAAS,EAAA,eAAe,MAAQ,IAAS,EAAA,eAAe,KAAO,EAAO,OACvE,CACN,OAAO,EAGX,OAAO,IAGT,SAAA,EAAA,WAAA,IAAgB,CAOd,EAAiB,KAAK,UANN,CACd,MAAO,CACL,YAAA,EACA,WAAA,EACD,CAE6B,CAAQ,GACvC,CAAC,EAAa,CAAA,CAAW,EAMrB,CACL,WAAA,EACA,iBAAA,EAAA,aANiC,GAAyB,CAC1D,EAAmB,CAAA,GAClB,CAAA,CAAE,ICjCD,GAAA,IAAkB,CACtB,KAAM,CAAC,EAAa,CAAA,KAAA,EAAA,UAAA,IAA+C,CACjE,MAAM,EAAQ,EAAA,EACd,GAAI,EACF,GAAI,CACF,MAAM,EAAS,KAAK,MAAM,CAAA,EAC1B,OAAO,EAAO,OAAO,aAAe,EAAO,aAAe,QACpD,CACN,MAAO,GAGX,MAAO,KAeT,MAAO,CACL,YAAA,EACA,kBAAA,EAAA,aAdkC,GAAkB,CACpD,EAAoB,CAAA,GACnB,CAAA,CAAE,EAaH,iBAAA,EAAA,aAAA,IAXsC,CACtC,EAAqB,GAAS,CAAC,CAAA,GAC9B,CAAA,CAAE,EAUH,gBAAA,EAAA,aAAA,IARqC,CACrC,EAAoB,EAAA,GACnB,CAAA,CAAE,ICfD,KAAA,EAAA,MAAA,CAAuB,CAAE,SAAA,EAAU,kBAAA,EAAoB,EAAA,mBAAA,IAA+C,CAC1G,KAAM,CAAE,YAAA,EAAa,eAAA,EAAgB,cAAA,EAAe,aAAA,CAAA,EAAiB,GAAA,EAC/D,CAAE,WAAA,EAAY,cAAA,CAAA,EAAkB,GAAO,CAAE,kBAAA,EAAmB,YAAA,EAAa,EAE/E,SAAA,EAAA,KACG,EAAA,cAAc,SAAf,CACE,MAAO,CACL,YAAA,EACA,WAAA,EACA,eAAA,EACA,cAAA,EACA,aAAA,EACA,cAAA,GAGD,SAAA,EACsB,IAI7B,EAAe,YAAc"}
1
+ {"version":3,"file":"layouts.cjs","names":[],"sources":["../src/designs/layouts/utils/layoutStorage.ts","../src/designs/layouts/components/Sidebar/styles.module.css","../src/designs/layouts/components/Sidebar/index.tsx","../src/designs/layouts/components/Footer/styles.module.css","../src/designs/layouts/components/Footer/index.tsx","../src/designs/layouts/components/Header/styles.module.css","../src/designs/layouts/components/Header/index.tsx","../src/designs/layouts/components/MainWrapper/styles.module.css","../src/designs/layouts/components/MainWrapper/index.tsx","../src/designs/layouts/components/SideHideLayout/styles.module.css","../src/designs/layouts/components/SideHideLayout/index.tsx","../src/designs/layouts/components/SideShowLayout/styles.module.css","../src/designs/layouts/components/SideShowLayout/index.tsx","../src/designs/layouts/components/Background/styles.module.css","../src/designs/layouts/components/Background/index.tsx","../src/designs/layouts/components/LayoutFrame/index.tsx","../src/designs/layouts/hooks/useSet.ts","../src/designs/layouts/hooks/useAction.ts","../src/designs/layouts/providers/index.tsx"],"sourcesContent":["/**\n * 布局相关 localStorage 读写与移除,统一走 utils/lstorage。\n * Layout localStorage get/set/remove via utils/lstorage.\n */\nimport type { Nilable } from \"@/types/utils\";\nimport { getItem, removeItem, setItem } from \"@/utils/lstorage\";\n\nimport { LAYOUT_STORAGE_KEY } from \"../types\";\n\nexport function getLayoutStorage(): Nilable<string> {\n return getItem(LAYOUT_STORAGE_KEY);\n}\n\nexport function setLayoutStorage(value: string): void {\n setItem(LAYOUT_STORAGE_KEY, value);\n}\n\nexport function removeLayoutStorage(): void {\n removeItem(LAYOUT_STORAGE_KEY);\n}\n","/* ===== Sidebar Component ===== */\r\n\r\n.sidebar {\r\n height: 100%;\r\n min-height: 0;\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n}\r\n\r\n.sidebarContent {\r\n padding-top: 1rem;\r\n height: 100%;\r\n min-height: 0;\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n}\r\n\r\n.menuWrapper {\r\n flex: 1;\r\n min-height: 0;\r\n overflow-y: auto;\r\n overflow-x: hidden;\r\n}\r\n\r\n/* 自定义滚动条样式 - 隐藏但保持滚动功能 */\r\n.sidebarContent::-webkit-scrollbar {\r\n width: 0px;\r\n}\r\n\r\n.sidebarContent::-webkit-scrollbar-track {\r\n background: transparent;\r\n}\r\n\r\n.sidebarContent::-webkit-scrollbar-thumb {\r\n background: transparent;\r\n}\r\n\r\n.sidebarContent::-webkit-scrollbar-thumb:hover {\r\n background: transparent;\r\n}\r\n\r\n/* 内部 a 元素左边距为 0 */\r\n.sidebar :global(a) {\r\n margin-left: 0;\r\n}\r\n\r\n/* 覆盖 react-pro-sidebar 默认样式 */\r\n.sidebar :global(.ps-sidebar-root) {\r\n height: 100% !important;\r\n min-height: 0 !important;\r\n overflow: hidden !important;\r\n display: flex !important;\r\n flex-direction: column !important;\r\n background-color: var(--color-bg-2) !important;\r\n border-right: 1px solid var(--color-separator) !important;\r\n}\r\n\r\n.sidebar :global(.ps-sidebar-container) {\r\n height: 100% !important;\r\n min-height: 0 !important;\r\n display: flex !important;\r\n flex-direction: column !important;\r\n flex: 1 !important;\r\n overflow: hidden !important;\r\n background-color: var(--color-bg-2) !important;\r\n color: var(--color-fg-text) !important;\r\n}\r\n\r\n.sidebar :global(.ps-menu-button) {\r\n padding: 0.5rem 0.75rem !important;\r\n margin: 0.125rem 0.5rem !important;\r\n border-radius: 0.375rem !important;\r\n transition: all 0.2s ease !important;\r\n color: var(--color-fg-text) !important;\r\n font-size: 0.875rem !important;\r\n}\r\n\r\n.sidebar :global(.ps-menu-button:hover) {\r\n background-color: var(--color-bg-3) !important;\r\n color: var(--color-fg-text) !important;\r\n}\r\n\r\n.sidebar :global(.ps-menu-button.ps-active) {\r\n background-color: var(--color-primary) !important;\r\n color: #ffffff !important;\r\n}\r\n\r\n.sidebar :global(.ps-menu-button.ps-active *) {\r\n color: #ffffff !important;\r\n}\r\n\r\n.sidebar :global(.ps-menu-button.ps-active .ps-menu-icon) {\r\n color: #ffffff !important;\r\n}\r\n\r\n.sidebar :global(.ps-menu-button.ps-active .ps-menu-label) {\r\n color: #ffffff !important;\r\n}\r\n\r\n/* 菜单图标样式 */\r\n.sidebar :global(.ps-menu-icon) {\r\n margin-right: 0.5rem !important;\r\n width: 1.25rem !important;\r\n height: 1.25rem !important;\r\n color: var(--color-fg-text) !important;\r\n}\r\n\r\n/* 子菜单样式 */\r\n.sidebar :global(.ps-submenu-content) {\r\n background-color: var(--color-bg-3) !important;\r\n padding-left: 0.5rem !important;\r\n overflow: hidden !important;\r\n}\r\n\r\n.sidebar :global(.ps-submenu-content .ps-menu-button) {\r\n padding: 0.375rem 0.5rem !important;\r\n margin: 0.125rem 0.25rem !important;\r\n font-size: 0.8125rem !important;\r\n transition: all 0.2s ease !important;\r\n}\r\n\r\n/* 子菜单标题样式 */\r\n.sidebar :global(.ps-menu-label) {\r\n color: var(--color-fg-text) !important;\r\n font-weight: 500 !important;\r\n}\r\n\r\n/* 强制选中状态的所有子元素为白色 */\r\n.sidebar :global(.ps-menu-button.ps-active),\r\n.sidebar :global(.ps-menu-button.ps-active span),\r\n.sidebar :global(.ps-menu-button.ps-active div),\r\n.sidebar :global(.ps-menu-button.ps-active .ps-menu-icon),\r\n.sidebar :global(.ps-menu-button.ps-active .ps-menu-label) {\r\n color: #ffffff !important;\r\n}\r\n\r\n/* 退出登录按钮容器 */\r\n.logoutContainer {\r\n margin-top: auto;\r\n padding: 0.5rem;\r\n border-top: 1px solid var(--color-separator);\r\n flex-shrink: 0;\r\n writing-mode: horizontal-tb;\r\n text-orientation: mixed;\r\n}\r\n\r\n.logoutButton {\r\n width: 100%;\r\n display: flex;\r\n align-items: center;\r\n justify-content: flex-start;\r\n gap: 0.5rem;\r\n padding: 0.5rem 0.75rem;\r\n background: transparent;\r\n border: none;\r\n border-radius: 0.375rem;\r\n color: var(--color-fg-text);\r\n font-size: 0.875rem;\r\n cursor: pointer;\r\n transition:\r\n background-color 0.2s ease,\r\n color 0.2s ease;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n writing-mode: horizontal-tb;\r\n text-orientation: mixed;\r\n direction: ltr;\r\n}\r\n\r\n.logoutButton span {\r\n display: inline-block;\r\n writing-mode: horizontal-tb !important;\r\n text-orientation: mixed !important;\r\n direction: ltr !important;\r\n transform: none !important;\r\n transition:\r\n opacity 0.3s ease,\r\n max-width 0.3s ease;\r\n max-width: 200px;\r\n opacity: 1;\r\n}\r\n\r\n.logoutButton .hiddenText {\r\n opacity: 0;\r\n max-width: 0;\r\n width: 0;\r\n overflow: hidden;\r\n}\r\n\r\n.logoutButton .visibleText {\r\n opacity: 1;\r\n max-width: 200px;\r\n width: auto;\r\n}\r\n\r\n.logoutButton:hover {\r\n background-color: var(--color-bg-3);\r\n}\r\n\r\n.logoutButton:active {\r\n transform: scale(0.98);\r\n}\r\n\r\n.logoutButton svg {\r\n flex-shrink: 0;\r\n color: inherit;\r\n}\r\n","import type { SidebarMenuItem, SidebarProps } from \"../../types\";\n\nimport { memo, useCallback, useMemo } from \"react\";\nimport { Menu, MenuItem, Sidebar as ProSidebar, SubMenu } from \"react-pro-sidebar\";\n\nimport { LogOut } from \"@/icons/lucide\";\n\nimport styles from \"./styles.module.css\";\n\n/**\n * 当前路径是否命中该菜单项。\n * 若有 siblingPaths(同组子项路径),则只有当前路径精确等于 path 或匹配 path 下的详情(非其它子项)时才命中,避免 /categories 与 /categories/add 同时高亮。\n */\nfunction isPathActive(current: string, path: string, siblingPaths?: string[]): boolean {\n if (current === path) return true;\n if (!current.startsWith(path + \"/\")) return false;\n if (siblingPaths?.length) {\n const matchedSibling = siblingPaths.some((s) => s !== path && (current === s || current.startsWith(s + \"/\")));\n if (matchedSibling) return false;\n }\n return true;\n}\n\nfunction isSubMenuActive(current: string, item: SidebarMenuItem): boolean {\n if (isPathActive(current, item.path, item.children?.map((c) => c.path))) return true;\n if (!item.children) return false;\n return item.children.some((child) => isPathActive(current, child.path, item.children?.map((c) => c.path)) || isSubMenuActive(current, child));\n}\n\nconst Sidebar = memo(\n ({\n children,\n collapsed = false,\n toggled = false,\n onBackdropClick,\n breakPoint = \"all\",\n className,\n items = [],\n currentPathname = \"\",\n onNavigate,\n logoutLabel = \"Logout\",\n handleLogout,\n bottomLogoutButton,\n }: SidebarProps) => {\n const handleItemClick = useCallback(\n (path: string) => {\n onNavigate?.(path);\n },\n [onNavigate],\n );\n\n const renderItem = useCallback(\n (item: SidebarMenuItem, siblingPaths?: string[]) => {\n const active = isPathActive(currentPathname, item.path, siblingPaths);\n if (item.children?.length) {\n const subActive = isSubMenuActive(currentPathname, item);\n return (\n <SubMenu key={item.path} label={item.label} icon={item.icon} active={subActive}>\n {item.children.map((child) => renderItem(child, item.children!.map((c) => c.path)))}\n </SubMenu>\n );\n }\n return (\n <MenuItem key={item.path} icon={item.icon} onClick={() => handleItemClick(item.path)} active={active}>\n {item.label}\n </MenuItem>\n );\n },\n [currentPathname, handleItemClick],\n );\n\n const menuContent =\n items.length > 0 ? (\n <Menu\n key={`${collapsed}-${toggled}`}\n transitionDuration={300}\n closeOnClick\n menuItemStyles={{\n button: {\n color: \"var(--color-fg-text)\",\n backgroundColor: \"transparent\",\n \"&:hover\": {\n backgroundColor: \"var(--color-bg-3)\",\n color: \"var(--color-fg-text)\",\n },\n \"&.active\": {\n backgroundColor: \"var(--color-primary)\",\n color: \"#ffffff\",\n },\n },\n icon: {\n color: \"var(--color-fg-text)\",\n \"&.active\": {\n color: \"#ffffff\",\n },\n },\n label: {\n color: \"var(--color-fg-text)\",\n \"&.active\": {\n color: \"#ffffff\",\n },\n },\n }}\n >\n {items.map((item) => renderItem(item))}\n </Menu>\n ) : null;\n\n const bottomLogoutButtonContent = useMemo(() => {\n if (bottomLogoutButton != null) return bottomLogoutButton;\n if (handleLogout != null) {\n return (\n <div className={styles.logoutContainer}>\n <button type=\"button\" className={styles.logoutButton} onClick={handleLogout} title={logoutLabel}>\n <LogOut size={20} />\n <span className={collapsed ? styles.hiddenText : styles.visibleText}>{logoutLabel}</span>\n </button>\n </div>\n );\n }\n return null;\n }, [collapsed, logoutLabel, handleLogout, bottomLogoutButton]);\n\n return (\n <ProSidebar\n collapsed={collapsed}\n toggled={toggled}\n onBackdropClick={onBackdropClick}\n breakPoint={breakPoint}\n backgroundColor=\"var(--color-bg-2)\"\n rootStyles={{\n border: \"none\",\n borderRight: \"1px solid var(--color-separator)\",\n }}\n className={`${styles.sidebar} ${className || \"\"}`}\n >\n <div className={styles.sidebarContent} onWheel={(e) => e.stopPropagation()}>\n <div className={styles.menuWrapper}>{children ?? menuContent}</div>\n {bottomLogoutButtonContent}\n </div>\n </ProSidebar>\n );\n },\n);\n\nSidebar.displayName = \"Sidebar\";\nexport default Sidebar;\n","/* ===== Footer Component ===== */\r\n\r\n.footer {\r\n background: var(--color-bg-2);\r\n padding: 0 2rem;\r\n width: 100%;\r\n}\r\n\r\n.footerContent {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n max-width: 100%;\r\n margin: 0 auto;\r\n}\r\n\r\n.copyright {\r\n color: var(--color-fg-text);\r\n font-size: 0.875rem;\r\n}\r\n\r\n.links {\r\n display: flex;\r\n gap: 1.5rem;\r\n}\r\n\r\n.link {\r\n color: var(--color-fg-text);\r\n font-size: 0.875rem;\r\n text-decoration: none;\r\n transition: color 0.3s ease;\r\n}\r\n\r\n.link:hover {\r\n color: var(--color-primary);\r\n}\r\n\r\n/* ===== 响应式 ===== */\r\n@media (max-width: 768px) {\r\n .footerContent {\r\n flex-direction: column;\r\n gap: 1rem;\r\n }\r\n\r\n .links {\r\n gap: 1rem;\r\n }\r\n}\r\n","import type { FooterProps } from \"../../types\";\n\nimport { memo } from \"react\";\n\nimport styles from \"./styles.module.css\";\n\nexport const DefaultFooterContent = memo(() => {\n const currentYear = new Date().getFullYear();\n return (\n <div className={styles.footerContent}>\n <span className={styles.copyright}>© {currentYear}</span>\n <div className={styles.links}>\n <a href=\"#\" className={styles.link}>\n About Us\n </a>\n <a href=\"#\" className={styles.link}>\n Privacy Policy\n </a>\n <a href=\"#\" className={styles.link}>\n Terms of Service\n </a>\n </div>\n </div>\n );\n});\nDefaultFooterContent.displayName = \"DefaultFooterContent\";\n\n/** 通用 Footer:只负责布局与样式,内容由外部传入。 */\nconst Footer = memo(({ children, className }: FooterProps) => {\n return <div className={`${styles.footer} ${className || \"\"}`}>{children ?? <DefaultFooterContent />}</div>;\n});\n\nFooter.displayName = \"Footer\";\n\nexport default Footer;\n","/* ===== Header - 主容器样式 ===== */\r\n\r\n.header {\r\n display: flex;\r\n width: 100%;\r\n padding: 0.5rem 2rem;\r\n}\r\n\r\n/* 左侧容器:占一半,左对齐 */\r\n.header> :first-child {\r\n flex: 1;\r\n display: flex;\r\n justify-content: flex-start;\r\n align-items: center;\r\n}\r\n\r\n/* 右侧容器:占一半,右对齐 */\r\n.header> :last-child {\r\n flex: 1;\r\n display: flex;\r\n justify-content: flex-end;\r\n align-items: center;\r\n}","import type { HeaderProps } from \"../../types\";\n\nimport { memo } from \"react\";\n\nimport styles from \"./styles.module.css\";\n\n/** 通用 Header:只负责布局左右两栏,内容全部由外部传入,内部不获取数据。Generic header: layout only; all content from props. */\nconst Header = memo(({ leftContent, rightContent }: HeaderProps) => {\n return (\n <div className={styles.header}>\n <div>{leftContent}</div>\n <div>{rightContent}</div>\n </div>\n );\n});\n\nHeader.displayName = \"Header\";\nexport default Header;\n","/* ===== One Column Layout ===== */\r\n\r\n.layout {\r\n display: flex;\r\n flex-direction: column;\r\n height: 100vh;\r\n width: 100%;\r\n background: var(--color-bg);\r\n position: relative;\r\n}\r\n\r\n/* ===== Header ===== */\r\n.header {\r\n position: fixed;\r\n top: 0;\r\n z-index: 100;\r\n background: var(--color-bg);\r\n width: 100%;\r\n box-shadow: 0 0.125rem 0.25rem 0 rgba(44, 51, 73, 0.1);\r\n}\r\n\r\n\r\n/* ===== Footer ===== */\r\n.footer {\r\n position: fixed;\r\n bottom: 0;\r\n width: 100%;\r\n z-index: 100;\r\n}\r\n","import type { MainWrapperProps } from \"../../types\";\n\nimport { memo, useCallback, useLayoutEffect, useRef, useState } from \"react\";\n\nimport Footer from \"../Footer\";\nimport Header from \"../Header\";\nimport styles from \"./styles.module.css\";\n\nfunction useElementHeight<T extends HTMLElement>() {\n const ref = useRef<T | null>(null);\n const [height, setHeight] = useState(0);\n\n useLayoutEffect(() => {\n const node = ref.current;\n if (!node) return;\n\n const observer = new ResizeObserver(([entry]) => {\n const nextHeight = entry?.contentRect.height ?? 0;\n setHeight((prev) => (prev !== nextHeight ? nextHeight : prev));\n });\n\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n const callbackRef = useCallback((instance: T | null) => {\n if (instance) {\n ref.current = instance;\n }\n }, []);\n\n return [callbackRef, height] as const;\n}\n\nconst MainWrapper = memo(({ children, headerLeft, headerRight, footerContent }: MainWrapperProps) => {\n const [headerRef, headerHeight] = useElementHeight<HTMLDivElement>();\n const [footerRef, footerHeight] = useElementHeight<HTMLDivElement>();\n\n return (\n <div className={styles.layout}>\n <header ref={headerRef} className={styles.header}>\n <Header leftContent={headerLeft} rightContent={headerRight} />\n </header>\n\n {children(headerHeight, footerHeight)}\n\n {/* Footer */}\n <footer ref={footerRef} className={styles.footer}>\n <Footer>{footerContent}</Footer>\n </footer>\n </div>\n );\n});\n\nMainWrapper.displayName = \"MainWrapper\";\nexport default MainWrapper;\n",".mainWrapper {\n display: flex;\n flex: 1;\n position: relative;\n}\n\n.sidebar {\n position: fixed;\n top: 0;\n}\n\n.content {\n flex: 1;\n background: var(--color-bg);\n overflow-y: auto;\n overflow-x: hidden;\n min-height: calc(100vh - 10rem);\n padding-top: 0;\n padding-bottom: 0;\n margin: 0;\n}\n\n@media (max-width: 768px) {\n .content {\n width: 100%;\n }\n .sidebar {\n position: fixed;\n top: 0;\n left: 0;\n height: 100vh;\n z-index: 999;\n }\n}\n","import type { SideHideLayoutProps } from \"../../types\";\n\nimport { memo, useCallback } from \"react\";\n\nimport useLayout from \"../../hooks/useLayout\";\nimport Sidebar from \"../Sidebar\";\nimport styles from \"./styles.module.css\";\n\nconst SideHideLayout = memo(\n ({\n children,\n headerHeight,\n footerHeight,\n sidebarItems,\n sidebarCurrentPathname,\n onSidebarNavigate,\n sidebarLogoutLabel,\n onSidebarLogout,\n }: SideHideLayoutProps) => {\n const { sidebarOpen, closeSidebar } = useLayout();\n\n const handleBackdropClick = useCallback(() => {\n closeSidebar();\n }, [closeSidebar]);\n\n return (\n <main\n className={styles.mainWrapper}\n style={{\n marginTop: `${headerHeight}px`,\n marginBottom: `${footerHeight}px`,\n }}\n >\n <Sidebar\n toggled={sidebarOpen}\n onBackdropClick={handleBackdropClick}\n breakPoint=\"all\"\n className={styles.sidebar}\n items={sidebarItems}\n currentPathname={sidebarCurrentPathname}\n onNavigate={onSidebarNavigate}\n logoutLabel={sidebarLogoutLabel}\n handleLogout={onSidebarLogout}\n />\n <div className={styles.content} data-lenis-prevent>\n {children}\n </div>\n </main>\n );\n },\n);\n\nSideHideLayout.displayName = \"SideHideLayout\";\n\nexport default SideHideLayout;\n","/* ===== Main Wrapper (Sidebar + Content) ===== */\n.mainWrapper {\n display: flex;\n flex: 1;\n position: relative;\n flex-direction: row;\n}\n\n.sidebarContainer {\n position: fixed;\n left: 0;\n z-index: 99;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.sidebar {\n top: 0;\n left: 0;\n flex-shrink: 0;\n}\n\n.content {\n flex: 1;\n background: var(--color-bg);\n overflow-y: auto;\n overflow-x: hidden;\n padding-top: 0;\n padding-bottom: 0;\n margin: 0;\n}\n\n@media (max-width: 1024px) {\n .content {\n padding: 1.5rem;\n }\n}\n\n@media (max-width: 768px) {\n .content {\n width: 100%;\n }\n .sidebar {\n position: fixed;\n top: 0;\n left: 0;\n height: 100vh;\n z-index: 999;\n }\n}\n","import type { SideShowLayoutProps } from \"../../types\";\n\nimport { memo, useCallback, useLayoutEffect, useRef, useState } from \"react\";\n\nimport useLayout from \"../../hooks/useLayout\";\nimport Sidebar from \"../Sidebar\";\nimport styles from \"./styles.module.css\";\n\nfunction useElementWidth<T extends HTMLElement>() {\n const ref = useRef<T | null>(null);\n const [width, setWidth] = useState(0);\n\n useLayoutEffect(() => {\n const node = ref.current;\n if (!node) return;\n\n const observer = new ResizeObserver(([entry]) => {\n const nextWidth = entry?.contentRect.width ?? 0;\n setWidth((prev) => (prev !== nextWidth ? nextWidth : prev));\n });\n\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n const callbackRef = useCallback((instance: T | null) => {\n if (instance) {\n ref.current = instance;\n }\n }, []);\n\n return [callbackRef, width] as const;\n}\n\nconst SideShowLayout = memo(\n ({\n children,\n headerHeight,\n footerHeight,\n sidebarItems,\n sidebarCurrentPathname,\n onSidebarNavigate,\n sidebarLogoutLabel,\n onSidebarLogout,\n }: SideShowLayoutProps) => {\n const { sidebarOpen, closeSidebar } = useLayout();\n const [sidebarRef, sidebarWidth] = useElementWidth<HTMLDivElement>();\n\n const handleBackdropClick = () => {\n closeSidebar();\n };\n\n return (\n <>\n <div\n ref={sidebarRef}\n className={styles.sidebarContainer}\n style={{\n top: `${headerHeight}px`,\n height: `calc(100vh - ${headerHeight + footerHeight}px)`,\n }}\n >\n <Sidebar\n collapsed={sidebarOpen}\n toggled={sidebarOpen}\n onBackdropClick={handleBackdropClick}\n breakPoint=\"xs\"\n className={styles.sidebar}\n items={sidebarItems}\n currentPathname={sidebarCurrentPathname}\n onNavigate={onSidebarNavigate}\n logoutLabel={sidebarLogoutLabel}\n handleLogout={onSidebarLogout}\n />\n </div>\n <main\n className={styles.mainWrapper}\n style={{\n marginTop: `${headerHeight}px`,\n marginBottom: `${footerHeight}px`,\n marginLeft: `${sidebarWidth}px`,\n width: `calc(100% - ${sidebarWidth}px)`,\n }}\n >\n <div className={styles.content} data-lenis-prevent>\n {children}\n </div>\n </main>\n </>\n );\n },\n);\n\nSideShowLayout.displayName = \"SideShowLayout\";\nexport default SideShowLayout;\n",".wavesWrapper {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n width: 100vw;\n height: 100vh;\n pointer-events: none;\n z-index: 0;\n overflow: hidden;\n}\n\n.wavesWrapper > * {\n pointer-events: auto;\n}\n\n.squaresWrapper {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n width: 100vw;\n height: 100vh;\n pointer-events: none;\n z-index: 0;\n overflow: hidden;\n}\n\n.squaresWrapper > * {\n pointer-events: auto;\n}\n\n.letterGlitchWrapper {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n width: 100vw;\n height: 100vh;\n pointer-events: none;\n z-index: 0;\n overflow: hidden;\n}\n\n.letterGlitchWrapper > * {\n pointer-events: auto;\n}\n\n.pixelBlastWrapper {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n width: 100vw;\n height: 100vh;\n pointer-events: none;\n z-index: 0;\n overflow: hidden;\n}\n\n.pixelBlastWrapper > * {\n pointer-events: auto;\n}\n","import type { ReactNode } from \"react\";\n\nimport { Suspense, lazy, memo } from \"react\";\n\nimport { LetterGlitchBackground, SquareBackground, WaveBackground } from \"@/designs/animations\";\nimport { DashboardBackgroundEnum } from \"@/preference\";\n\nimport styles from \"./styles.module.css\";\n\nconst LazyPixelBlast = lazy(() => import(\"@/designs/animations/PixelBlast\"));\n\ninterface BackgroundProps {\n children: ReactNode;\n /** 可选:外部传入的偏好,有则优先使用;否则从 profile.preference 解析。Optional: preference from parent; otherwise parsed from profile. */\n background?: DashboardBackgroundEnum | null;\n}\n\n/** 与 NFX-Identity/console 一致:仪表盘背景由用户偏好(可外部传入或从 profile 解析) */\nconst Background = memo(({ children, background }: BackgroundProps) => {\n const renderBackground = () => {\n switch (background) {\n case DashboardBackgroundEnum.WAVES:\n return (\n <div className={styles.wavesWrapper}>\n <WaveBackground />\n </div>\n );\n case DashboardBackgroundEnum.SQUARES:\n return (\n <div className={styles.squaresWrapper}>\n <SquareBackground />\n </div>\n );\n case DashboardBackgroundEnum.LETTER_GLITCH:\n return (\n <div className={styles.letterGlitchWrapper}>\n <LetterGlitchBackground />\n </div>\n );\n case DashboardBackgroundEnum.PIXEL_BLAST:\n return (\n <Suspense fallback={null}>\n <div className={styles.pixelBlastWrapper}>\n <LazyPixelBlast />\n </div>\n </Suspense>\n );\n case DashboardBackgroundEnum.NONE:\n default:\n return null;\n }\n };\n\n return (\n <>\n {children}\n {renderBackground()}\n </>\n );\n});\n\nBackground.displayName = \"Background\";\nexport default Background;\nexport type { BackgroundProps };\n","import type { LayoutFrameProps } from \"../../types\";\n\nimport { memo } from \"react\";\n\nimport useLayout from \"../../hooks/useLayout\";\nimport { LayoutModeEnum } from \"../../types\";\nimport MainWrapper from \"../MainWrapper\";\nimport SideHideLayout from \"../SideHideLayout\";\nimport SideShowLayout from \"../SideShowLayout\";\n\nexport const LayoutFrame = memo(\n ({\n children,\n headerLeft,\n headerRight,\n footerContent,\n sidebarItems,\n sidebarCurrentPathname,\n onSidebarNavigate,\n sidebarLogoutLabel,\n onSidebarLogout,\n bottomLogoutButton,\n }: LayoutFrameProps) => {\n const { layoutMode } = useLayout();\n return (\n <MainWrapper headerLeft={headerLeft} headerRight={headerRight} footerContent={footerContent}>\n {(headerHeight, footerHeight) => {\n if (layoutMode === LayoutModeEnum.HIDE) {\n return (\n <SideHideLayout\n headerHeight={headerHeight}\n footerHeight={footerHeight}\n sidebarItems={sidebarItems}\n sidebarCurrentPathname={sidebarCurrentPathname}\n onSidebarNavigate={onSidebarNavigate}\n sidebarLogoutLabel={sidebarLogoutLabel}\n onSidebarLogout={onSidebarLogout}\n bottomLogoutButton={bottomLogoutButton}\n >\n {children}\n </SideHideLayout>\n );\n } else {\n return (\n <SideShowLayout\n headerHeight={headerHeight}\n footerHeight={footerHeight}\n sidebarItems={sidebarItems}\n sidebarCurrentPathname={sidebarCurrentPathname}\n onSidebarNavigate={onSidebarNavigate}\n sidebarLogoutLabel={sidebarLogoutLabel}\n onSidebarLogout={onSidebarLogout}\n bottomLogoutButton={bottomLogoutButton}\n >\n {children}\n </SideShowLayout>\n );\n }\n }}\n </MainWrapper>\n );\n },\n);\n\nLayoutFrame.displayName = \"LayoutFrame\";\nexport default LayoutFrame;\n","import { useCallback, useEffect, useState } from \"react\";\n\nimport { getLayoutStorage, setLayoutStorage } from \"../utils\";\nimport { LayoutModeEnum } from \"../types\";\n\ninterface UseSetProps {\n defaultLayoutMode: LayoutModeEnum;\n sidebarOpen: boolean;\n}\n\nconst useSet = ({ defaultLayoutMode, sidebarOpen }: UseSetProps) => {\n const [layoutMode, setLayoutModeState] = useState<LayoutModeEnum>(() => {\n const saved = getLayoutStorage();\n if (saved) {\n try {\n const parsed = JSON.parse(saved);\n const mode = parsed.state?.layoutMode ?? parsed.layoutMode;\n return mode === LayoutModeEnum.SHOW || mode === LayoutModeEnum.HIDE ? mode : defaultLayoutMode;\n } catch {\n return defaultLayoutMode;\n }\n }\n return defaultLayoutMode;\n });\n\n useEffect(() => {\n const storage = {\n state: {\n sidebarOpen,\n layoutMode,\n },\n };\n setLayoutStorage(JSON.stringify(storage));\n }, [sidebarOpen, layoutMode]);\n\n const setLayoutMode = useCallback((mode: LayoutModeEnum) => {\n setLayoutModeState(mode);\n }, []);\n\n return {\n layoutMode,\n setLayoutMode,\n };\n};\n\nexport default useSet;\n","import { useCallback, useState } from \"react\";\n\nimport { getLayoutStorage } from \"../utils\";\n\nconst useAction = () => {\n const [sidebarOpen, setSidebarOpenState] = useState<boolean>(() => {\n const saved = getLayoutStorage();\n if (saved) {\n try {\n const parsed = JSON.parse(saved);\n return parsed.state?.sidebarOpen ?? parsed.sidebarOpen ?? false;\n } catch {\n return false;\n }\n }\n return false;\n });\n\n const setSidebarOpen = useCallback((open: boolean) => {\n setSidebarOpenState(open);\n }, []);\n\n const toggleSidebar = useCallback(() => {\n setSidebarOpenState((prev) => !prev);\n }, []);\n\n const closeSidebar = useCallback(() => {\n setSidebarOpenState(false);\n }, []);\n\n return {\n sidebarOpen,\n setSidebarOpen,\n toggleSidebar,\n closeSidebar,\n };\n};\n\nexport default useAction;\n","/**\n * 布局提供者:提供侧栏开关与显示/隐藏模式上下文。\n * Layout provider: provides sidebar state and show/hide layout mode context.\n */\nimport type { LayoutProviderProps } from \"../types\";\n\nimport { memo } from \"react\";\n\nimport useAction from \"../hooks/useAction\";\nimport { LayoutContext } from \"../hooks/useLayout\";\nimport useSet from \"../hooks/useSet\";\nimport { DEFAULT_LAYOUT_MODE } from \"../types\";\n\nconst LayoutProvider = memo(({ children, defaultLayoutMode = DEFAULT_LAYOUT_MODE }: LayoutProviderProps) => {\n const { sidebarOpen, setSidebarOpen, toggleSidebar, closeSidebar } = useAction();\n const { layoutMode, setLayoutMode } = useSet({ defaultLayoutMode, sidebarOpen });\n\n return (\n <LayoutContext.Provider\n value={{\n sidebarOpen,\n layoutMode,\n setSidebarOpen,\n toggleSidebar,\n closeSidebar,\n setLayoutMode,\n }}\n >\n {children}\n </LayoutContext.Provider>\n );\n});\n\nLayoutProvider.displayName = \"LayoutProvider\";\nexport default LayoutProvider;\n"],"mappings":"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"}
package/dist/layouts.d.ts CHANGED
@@ -1,209 +1 @@
1
- import { Context } from 'react';
2
- import { JSX } from 'react/jsx-runtime';
3
- import { MemoExoticComponent } from 'react';
4
- import { ReactNode } from 'react';
5
- import { SidebarProps as SidebarProps_2 } from 'react-pro-sidebar';
6
-
7
- /** 与 NFX-Identity/console 一致:仪表盘背景由用户偏好(可外部传入或从 profile 解析) */
8
- export declare const Background: MemoExoticComponent<({ children, background }: BackgroundProps) => JSX.Element>;
9
-
10
- declare interface BackgroundProps {
11
- children: ReactNode;
12
- /** 可选:外部传入的偏好,有则优先使用;否则从 profile.preference 解析。Optional: preference from parent; otherwise parsed from profile. */
13
- background?: DashboardBackgroundEnum | null;
14
- }
15
-
16
- /** 仪表盘背景枚举。Dashboard background enum. */
17
- declare enum DashboardBackgroundEnum {
18
- NONE = "none",
19
- WAVES = "waves",
20
- SQUARES = "squares",
21
- LETTER_GLITCH = "letterGlitch",
22
- PIXEL_BLAST = "pixelBlast"
23
- }
24
-
25
- export declare const DEFAULT_LAYOUT_MODE = LayoutModeEnum.SHOW;
26
-
27
- /** 通用 Footer:只负责布局与样式,内容由外部传入。 */
28
- export declare const Footer: MemoExoticComponent<({ children, className }: FooterProps) => JSX.Element>;
29
-
30
- /** Footer props. */
31
- export declare interface FooterProps {
32
- /** 页脚内容由使用方传入。Footer content passed from parent. */
33
- children?: ReactNode;
34
- className?: string;
35
- }
36
-
37
- export declare function getLayoutStorage(): Nilable<string>;
38
-
39
- /** 通用 Header:只负责布局左右两栏,内容全部由外部传入,内部不获取数据。Generic header: layout only; all content from props. */
40
- export declare const Header: MemoExoticComponent<({ leftContent, rightContent }: HeaderProps) => JSX.Element>;
41
-
42
- /** Header props. */
43
- export declare interface HeaderProps {
44
- /** 左侧内容(如 Logo、SlideDownSwitcher 等),由使用方传入。Left slot; passed from parent. */
45
- leftContent?: ReactNode;
46
- /** 右侧内容(如语言切换、用户菜单等),由使用方传入。Right slot; passed from parent. */
47
- rightContent?: ReactNode;
48
- }
49
-
50
- export declare const LAYOUT_MODE_VALUES: LayoutModeEnum[];
51
-
52
- export declare const LAYOUT_STORAGE_KEY = "layout-storage";
53
-
54
- export declare const LayoutContext: Context<LayoutContextType | undefined>;
55
-
56
- /** useLayout 返回值类型。Return type of useLayout. */
57
- export declare interface LayoutContextType {
58
- /** 侧栏是否展开。Whether sidebar is open. */
59
- sidebarOpen: boolean;
60
- /** 当前布局模式(显示/隐藏)。Current layout mode (show/hide). */
61
- layoutMode: LayoutModeEnum;
62
- setSidebarOpen: (open: boolean) => void;
63
- toggleSidebar: () => void;
64
- closeSidebar: () => void;
65
- setLayoutMode: (mode: LayoutModeEnum) => void;
66
- }
67
-
68
- export declare const LayoutFrame: MemoExoticComponent<({ children, headerLeft, headerRight, footerContent, sidebarItems, sidebarCurrentPathname, onSidebarNavigate, sidebarLogoutLabel, onSidebarLogout, bottomLogoutButton, }: LayoutFrameProps) => JSX.Element>;
69
-
70
- /** LayoutFrame props. */
71
- export declare interface LayoutFrameProps {
72
- children: ReactNode;
73
- /** 可选:Header 左侧内容(如 Logo、SlideDownSwitcher),使用方传入。Optional: header left slot. */
74
- headerLeft?: ReactNode;
75
- /** 可选:Header 右侧内容(如语言、用户菜单),使用方传入。Optional: header right slot. */
76
- headerRight?: ReactNode;
77
- /** 可选:Footer 内容(children),使用方传入。Optional: footer content. */
78
- footerContent?: ReactNode;
79
- /** 可选:侧栏菜单项。Optional: sidebar menu items. */
80
- sidebarItems?: SidebarMenuItem[];
81
- /** 可选:当前路径,用于高亮。传 useLocation().pathname。Optional: current pathname for active state. */
82
- sidebarCurrentPathname?: string;
83
- /** 可选:点击菜单项时调用。Optional: called when a sidebar item is clicked. */
84
- onSidebarNavigate?: (path: string) => void;
85
- /** 可选:侧栏底部登出按钮文案。Optional: logout button label. */
86
- sidebarLogoutLabel?: string;
87
- /** 可选:侧栏登出回调。Optional: logout handler. */
88
- onSidebarLogout?: () => void;
89
- /** 可选:侧栏底部登出按钮。Optional: bottom logout button. */
90
- bottomLogoutButton?: ReactNode;
91
- }
92
-
93
- /**
94
- * 布局模式枚举与常量。Layout mode enum and constants.
95
- */
96
- export declare enum LayoutModeEnum {
97
- SHOW = "show",
98
- HIDE = "hide"
99
- }
100
-
101
- export declare const LayoutProvider: MemoExoticComponent<({ children, defaultLayoutMode }: LayoutProviderProps) => JSX.Element>;
102
-
103
- /** 布局 Provider 的 props。LayoutProvider props. */
104
- export declare interface LayoutProviderProps {
105
- /** 子节点。Children. */
106
- children: ReactNode;
107
- /** 默认布局模式(显示/隐藏侧栏)。Default layout mode (show/hide sidebar). */
108
- defaultLayoutMode?: LayoutModeEnum;
109
- }
110
-
111
- /** 布局切换器 props。LayoutSwitcher props. */
112
- export declare interface LayoutSwitcherProps {
113
- /** 样式状态。Visual status. */
114
- status?: "primary" | "default";
115
- /** 显示模式标签(未传 getLayoutDisplayName 且无内置翻译时使用)。Show mode label. */
116
- showLabel?: string;
117
- /** 隐藏模式标签(未传 getLayoutDisplayName 且无内置翻译时使用)。Hide mode label. */
118
- hideLabel?: string;
119
- /** 根据布局模式返回展示名;未传则使用 showLabel / hideLabel。Display name for layout mode; default uses showLabel/hideLabel. */
120
- getLayoutDisplayName?: (mode: LayoutModeEnum) => string;
121
- /** 处理布局模式改变。Handle layout mode change. */
122
- handleChangeLayoutMode?: (mode: LayoutModeEnum) => void;
123
- }
124
-
125
- export declare const MainWrapper: MemoExoticComponent<({ children, headerLeft, headerRight, footerContent }: MainWrapperProps) => JSX.Element>;
126
-
127
- /** MainWrapper props. */
128
- export declare interface MainWrapperProps {
129
- children: (headerHeight: number, footerHeight: number) => ReactNode;
130
- headerLeft?: ReactNode;
131
- headerRight?: ReactNode;
132
- footerContent?: ReactNode;
133
- }
134
-
135
- /**
136
- * 可为 null 或 undefined。Nilable: T | null | undefined.
137
- * @example Nilable<boolean> => boolean | null | undefined
138
- */
139
- declare type Nilable<T> = T | null | undefined;
140
-
141
- export declare function removeLayoutStorage(): void;
142
-
143
- export declare function setLayoutStorage(value: string): void;
144
-
145
- export declare const Sidebar: MemoExoticComponent<({ children, collapsed, toggled, onBackdropClick, breakPoint, className, items, currentPathname, onNavigate, logoutLabel, handleLogout, bottomLogoutButton, }: SidebarProps) => JSX.Element>;
146
-
147
- /** 侧栏菜单项。Sidebar menu item. */
148
- export declare interface SidebarMenuItem {
149
- label: string;
150
- path: string;
151
- icon: ReactNode;
152
- /** Sub-items for SubMenu. Omit for a leaf item. */
153
- children?: SidebarMenuItem[];
154
- }
155
-
156
- /** Sidebar props(扩展 react-pro-sidebar). */
157
- export declare interface SidebarProps extends SidebarProps_2 {
158
- children?: ReactNode;
159
- collapsed?: boolean;
160
- toggled?: boolean;
161
- onBackdropClick?: () => void;
162
- className?: string;
163
- /** Menu items. Rendered when no children. */
164
- items?: SidebarMenuItem[];
165
- /** Current pathname for active state. Pass from useLocation().pathname. */
166
- currentPathname?: string;
167
- /** Called when a menu item is clicked. Parent should navigate to path. */
168
- onNavigate?: (path: string) => void;
169
- /** Logout label. */
170
- logoutLabel?: string;
171
- /** Handle logout. */
172
- handleLogout?: () => void;
173
- /** Bottom Logout Button. */
174
- bottomLogoutButton?: ReactNode;
175
- }
176
-
177
- export declare const SideHideLayout: MemoExoticComponent<({ children, headerHeight, footerHeight, sidebarItems, sidebarCurrentPathname, onSidebarNavigate, sidebarLogoutLabel, onSidebarLogout, }: SideHideLayoutProps) => JSX.Element>;
178
-
179
- /** SideHideLayout props. */
180
- export declare interface SideHideLayoutProps {
181
- children: ReactNode;
182
- headerHeight: number;
183
- footerHeight: number;
184
- sidebarItems?: SidebarMenuItem[];
185
- sidebarCurrentPathname?: string;
186
- onSidebarNavigate?: (path: string) => void;
187
- sidebarLogoutLabel?: string;
188
- onSidebarLogout?: () => void;
189
- bottomLogoutButton?: ReactNode;
190
- }
191
-
192
- export declare const SideShowLayout: MemoExoticComponent<({ children, headerHeight, footerHeight, sidebarItems, sidebarCurrentPathname, onSidebarNavigate, sidebarLogoutLabel, onSidebarLogout, }: SideShowLayoutProps) => JSX.Element>;
193
-
194
- /** SideShowLayout props. */
195
- export declare interface SideShowLayoutProps {
196
- children: ReactNode;
197
- headerHeight: number;
198
- footerHeight: number;
199
- sidebarItems?: SidebarMenuItem[];
200
- sidebarCurrentPathname?: string;
201
- onSidebarNavigate?: (path: string) => void;
202
- sidebarLogoutLabel?: string;
203
- onSidebarLogout?: () => void;
204
- bottomLogoutButton?: ReactNode;
205
- }
206
-
207
- export declare const useLayout: () => LayoutContextType;
208
-
209
1
  export { }