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 +1 @@
1
- {"version":3,"file":"layouts.mjs","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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"}
1
+ {"version":3,"file":"layouts.mjs","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":";;;;;;;;;AASA,SAAgB,IAAoC;AAClD,SAAO,GAAQ,CAAA;;AAGjB,SAAgB,GAAiB,GAAqB;AACpD,EAAA,EAAQ,GAAoB,CAAA;;AAG9B,SAAgB,KAA4B;AAC1C,EAAA,EAAW,CAAA;;;;;;;;;;;AELb,SAAS,EAAa,GAAiB,GAAc,GAAkC;AACrF,SAAI,MAAY,IAAa,KACzB,GAAC,EAAQ,WAAW,IAAO,GAAA,KAC3B,GAAc,UACO,EAAa,KAAA,CAAM,MAAM,MAAM,MAAS,MAAY,KAAK,EAAQ,WAAW,IAAI,GAAA,EAAI;;AAM/G,SAAS,EAAgB,GAAiB,GAAgC;AACxE,SAAI,EAAa,GAAS,EAAK,MAAM,EAAK,UAAU,IAAA,CAAK,MAAM,EAAE,IAAA,CAAK,IAAU,KAC3E,EAAK,WACH,EAAK,SAAS,KAAA,CAAM,MAAU,EAAa,GAAS,EAAM,MAAM,EAAK,UAAU,IAAA,CAAK,MAAM,EAAE,IAAA,CAAK,KAAK,EAAgB,GAAS,CAAA,CAAM,IADjH;;AAI7B,IAAM,IAAU,EAAA,CACb,EACC,UAAA,GACA,WAAA,IAAY,IACZ,SAAA,IAAU,IACV,iBAAA,GACA,YAAA,IAAa,OACb,WAAA,GACA,OAAA,IAAQ,CAAA,GACR,iBAAA,IAAkB,IAClB,YAAA,GACA,aAAA,IAAc,UACd,cAAA,GACA,oBAAA,EAAA,MACkB;AAClB,QAAM,IAAkB,EAAA,CACrB,MAAiB;AAChB,IAAA,IAAa,CAAA;AAAA,KAEf,CAAC,CAAA,CAAW,GAGR,IAAa,EAAA,CAChB,GAAuB,MAA4B;AAClD,UAAM,IAAS,EAAa,GAAiB,EAAK,MAAM,CAAA;AACxD,QAAI,EAAK,UAAU,QAAQ;AACzB,YAAM,IAAY,EAAgB,GAAiB,CAAA;AACnD,aACE,gBAAA,EAAC,IAAD;AAAA,QAAyB,OAAO,EAAK;AAAA,QAAO,MAAM,EAAK;AAAA,QAAM,QAAQ;AAAA,kBAClE,EAAK,SAAS,IAAA,CAAK,MAAU,EAAW,GAAO,EAAK,SAAU,IAAA,CAAK,MAAM,EAAE,IAAA,CAAK,CAAC;AAAA,SADtE,EAAK,IAAA;AAAA;AAKvB,WACE,gBAAA,EAAC,IAAD;AAAA,MAA0B,MAAM,EAAK;AAAA,MAAM,SAAA,MAAe,EAAgB,EAAK,IAAA;AAAA,MAAe,QAAA;AAAA,gBAC3F,EAAK;AAAA,OADO,EAAK,IAAA;AAAA,KAKxB,CAAC,GAAiB,CAAA,CAAgB,GAG9B,IACJ,EAAM,SAAS,IACb,gBAAA,EAAC,IAAD;AAAA,IAEE,oBAAoB;AAAA,IACpB,cAAA;AAAA,IACA,gBAAgB;AAAA,MACd,QAAQ;AAAA,QACN,OAAO;AAAA,QACP,iBAAiB;AAAA,QACjB,WAAW;AAAA,UACT,iBAAiB;AAAA,UACjB,OAAO;AAAA;QAET,YAAY;AAAA,UACV,iBAAiB;AAAA,UACjB,OAAO;AAAA;;MAGX,MAAM;AAAA,QACJ,OAAO;AAAA,QACP,YAAY,EACV,OAAO,UAAA;AAAA;MAGX,OAAO;AAAA,QACL,OAAO;AAAA,QACP,YAAY,EACV,OAAO,UAAA;AAAA;;cAKZ,EAAM,IAAA,CAAK,MAAS,EAAW,CAAA,CAAK;AAAA,KA9BhC,GAAG,CAAA,IAAa,CAAA,EAAA,IAgCrB,MAEA,IAA4B,GAAA,MAC5B,MACA,KAAgB,OAEhB,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAW,EAAO;AAAA,cACrB,gBAAA,EAAC,UAAD;AAAA,MAAQ,MAAK;AAAA,MAAS,WAAW,EAAO;AAAA,MAAc,SAAS;AAAA,MAAc,OAAO;AAAA,gBAApF,CACE,gBAAA,EAAC,GAAD,EAAQ,MAAM,GAAA,CAAM,GACpB,gBAAA,EAAC,QAAD;AAAA,QAAM,WAAW,IAAY,EAAO,aAAa,EAAO;AAAA,kBAAc;AAAA,OAAmB,CAAA;AAAA;GAEvF,IAGH,OACN;AAAA,IAAC;AAAA,IAAW;AAAA,IAAa;AAAA,IAAc;AAAA,GAAmB;AAE7D,SACE,gBAAA,EAAC,IAAD;AAAA,IACa,WAAA;AAAA,IACF,SAAA;AAAA,IACQ,iBAAA;AAAA,IACL,YAAA;AAAA,IACZ,iBAAgB;AAAA,IAChB,YAAY;AAAA,MACV,QAAQ;AAAA,MACR,aAAa;AAAA;IAEf,WAAW,GAAG,EAAO,OAAA,IAAW,KAAa,EAAA;AAAA,cAE7C,gBAAA,EAAC,OAAD;AAAA,MAAK,WAAW,EAAO;AAAA,MAAgB,SAAA,CAAU,MAAM,EAAE,gBAAA;AAAA,gBAAzD,CACE,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAW,EAAO;AAAA,kBAAc,KAAY;AAAA,OAAkB,GAClE,CAAA;AAAA;GAEQ;;AAKnB,EAAQ,cAAc;;;;;;;GE3IT,IAAuB,EAAA,MAAW;AAC7C,QAAM,KAAc,oBAAI,KAAA,GAAO,YAAA;AAC/B,SACE,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAW,EAAO;AAAA,cAAvB,CACE,gBAAA,EAAC,QAAD;AAAA,MAAM,WAAW,EAAO;AAAA,gBAAxB,CAAmC,MAAG,CAAA;AAAA,QACtC,gBAAA,EAAC,OAAD;AAAA,MAAK,WAAW,EAAO;AAAA,gBAAvB;AAAA,QACE,gBAAA,EAAC,KAAD;AAAA,UAAG,MAAK;AAAA,UAAI,WAAW,EAAO;AAAA,oBAAM;AAAA,SAEhC;AAAA,QACJ,gBAAA,EAAC,KAAD;AAAA,UAAG,MAAK;AAAA,UAAI,WAAW,EAAO;AAAA,oBAAM;AAAA,SAEhC;AAAA,QACJ,gBAAA,EAAC,KAAD;AAAA,UAAG,MAAK;AAAA,UAAI,WAAW,EAAO;AAAA,oBAAM;AAAA,SAEhC;AAAA;;;;AAKZ,EAAqB,cAAc;AAGnC,IAAM,IAAS,EAAA,CAAM,EAAE,UAAA,GAAU,WAAA,EAAA,MACxB,gBAAA,EAAC,OAAD;AAAA,EAAK,WAAW,GAAG,EAAO,MAAA,IAAU,KAAa,EAAA;AAAA,YAAO,KAAY,gBAAA,EAAC,GAAD,CAAA,CAAwB;CAAO;AAG5G,EAAO,cAAc;+DEzBf,IAAS,EAAA,CAAM,EAAE,aAAA,GAAa,cAAA,EAAA,MAEhC,gBAAA,EAAC,OAAD;AAAA,EAAK,WAAW,GAAO;AAAA,YAAvB,CACE,gBAAA,EAAC,OAAD,EAAA,UAAM,EAAA,CAAkB,GACxB,gBAAA,EAAC,OAAD,EAAA,UAAM,EAAA,CAAmB,CAAA;;AAK/B,EAAO,cAAc;;;;;;AERrB,SAAS,IAA0C;AACjD,QAAM,IAAM,EAAiB,IAAA,GACvB,CAAC,GAAQ,CAAA,IAAa,EAAS,CAAA;AAErC,SAAA,EAAA,MAAsB;AACpB,UAAM,IAAO,EAAI;AACjB,QAAI,CAAC,EAAM;AAEX,UAAM,IAAW,IAAI,eAAA,CAAgB,CAAC,CAAA,MAAW;AAC/C,YAAM,IAAa,GAAO,YAAY,UAAU;AAChD,MAAA,EAAA,CAAW,MAAU,MAAS,IAAa,IAAa,CAAA;AAAA;AAG1D,WAAA,EAAS,QAAQ,CAAA,GACjB,MAAa,EAAS,WAAA;AAAA,KACrB,CAAA,CAAE,GAQE,CANa,EAAA,CAAa,MAAuB;AACtD,IAAI,MACF,EAAI,UAAU;AAAA,KAEf,CAAA,CAAE,GAEgB,CAAA;;AAGvB,IAAM,IAAc,EAAA,CAAM,EAAE,UAAA,GAAU,YAAA,GAAY,aAAA,GAAa,eAAA,EAAA,MAAsC;AACnG,QAAM,CAAC,GAAW,CAAA,IAAgB,EAAA,GAC5B,CAAC,GAAW,CAAA,IAAgB,EAAA;AAElC,SACE,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAW,EAAO;AAAA,cAAvB;AAAA,MACE,gBAAA,EAAC,UAAD;AAAA,QAAQ,KAAK;AAAA,QAAW,WAAW,EAAO;AAAA,kBACxC,gBAAA,EAAC,GAAD;AAAA,UAAQ,aAAa;AAAA,UAAY,cAAc;AAAA,SAAe;AAAA,OACvD;AAAA,MAER,EAAS,GAAc,CAAA;AAAA,MAGxB,gBAAA,EAAC,UAAD;AAAA,QAAQ,KAAK;AAAA,QAAW,WAAW,EAAO;AAAA,kBACxC,gBAAA,EAAC,GAAD,EAAA,UAAS,EAAA,CAAuB;AAAA,OACzB;AAAA;;;AAKf,EAAY,cAAc;;;;;GE9CpB,IAAiB,EAAA,CACpB,EACC,UAAA,GACA,cAAA,GACA,cAAA,GACA,cAAA,GACA,wBAAA,GACA,mBAAA,GACA,oBAAA,GACA,iBAAA,EAAA,MACyB;AACzB,QAAM,EAAE,aAAA,GAAa,cAAA,EAAA,IAAiB,EAAA,GAEhC,IAAsB,EAAA,MAAkB;AAC5C,IAAA,EAAA;AAAA,KACC,CAAC,CAAA,CAAa;AAEjB,SACE,gBAAA,EAAC,QAAD;AAAA,IACE,WAAW,EAAO;AAAA,IAClB,OAAO;AAAA,MACL,WAAW,GAAG,CAAA;AAAA,MACd,cAAc,GAAG,CAAA;AAAA;cAJrB,CAOE,gBAAA,EAAC,GAAD;AAAA,MACE,SAAS;AAAA,MACT,iBAAiB;AAAA,MACjB,YAAW;AAAA,MACX,WAAW,EAAO;AAAA,MAClB,OAAO;AAAA,MACP,iBAAiB;AAAA,MACjB,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,cAAc;AAAA,KACd,GACF,gBAAA,EAAC,OAAD;AAAA,MAAK,WAAW,EAAO;AAAA,MAAS,sBAAA;AAAA,MAC7B,UAAA;AAAA,KACG,CAAA;AAAA;;AAMd,EAAe,cAAc;;;;;;;AE5C7B,SAAS,KAAyC;AAChD,QAAM,IAAM,EAAiB,IAAA,GACvB,CAAC,GAAO,CAAA,IAAY,EAAS,CAAA;AAEnC,SAAA,EAAA,MAAsB;AACpB,UAAM,IAAO,EAAI;AACjB,QAAI,CAAC,EAAM;AAEX,UAAM,IAAW,IAAI,eAAA,CAAgB,CAAC,CAAA,MAAW;AAC/C,YAAM,IAAY,GAAO,YAAY,SAAS;AAC9C,MAAA,EAAA,CAAU,MAAU,MAAS,IAAY,IAAY,CAAA;AAAA;AAGvD,WAAA,EAAS,QAAQ,CAAA,GACjB,MAAa,EAAS,WAAA;AAAA,KACrB,CAAA,CAAE,GAQE,CANa,EAAA,CAAa,MAAuB;AACtD,IAAI,MACF,EAAI,UAAU;AAAA,KAEf,CAAA,CAAE,GAEgB,CAAA;;AAGvB,IAAM,IAAiB,EAAA,CACpB,EACC,UAAA,GACA,cAAA,GACA,cAAA,GACA,cAAA,GACA,wBAAA,GACA,mBAAA,GACA,oBAAA,GACA,iBAAA,EAAA,MACyB;AACzB,QAAM,EAAE,aAAA,GAAa,cAAA,EAAA,IAAiB,EAAA,GAChC,CAAC,GAAY,CAAA,IAAgB,GAAA,GAE7B,IAAA,MAA4B;AAChC,IAAA,EAAA;AAAA;AAGF,SACE,gBAAA,EAAA,GAAA,EAAA,UAAA,CACE,gBAAA,EAAC,OAAD;AAAA,IACE,KAAK;AAAA,IACL,WAAW,EAAO;AAAA,IAClB,OAAO;AAAA,MACL,KAAK,GAAG,CAAA;AAAA,MACR,QAAQ,gBAAgB,IAAe,CAAA;AAAA;cAGzC,gBAAA,EAAC,GAAD;AAAA,MACE,WAAW;AAAA,MACX,SAAS;AAAA,MACT,iBAAiB;AAAA,MACjB,YAAW;AAAA,MACX,WAAW,EAAO;AAAA,MAClB,OAAO;AAAA,MACP,iBAAiB;AAAA,MACjB,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,cAAc;AAAA,KACd;AAAA,GACE,GACN,gBAAA,EAAC,QAAD;AAAA,IACE,WAAW,EAAO;AAAA,IAClB,OAAO;AAAA,MACL,WAAW,GAAG,CAAA;AAAA,MACd,cAAc,GAAG,CAAA;AAAA,MACjB,YAAY,GAAG,CAAA;AAAA,MACf,OAAO,eAAe,CAAA;AAAA;cAGxB,gBAAA,EAAC,OAAD;AAAA,MAAK,WAAW,EAAO;AAAA,MAAS,sBAAA;AAAA,MAC7B,UAAA;AAAA,KACG;AAAA,GACD,CAAA,EACN,CAAA;;AAKT,EAAe,cAAc;;;;;;GEpFvB,KAAiB,GAAA,MAAW,OAAO,mBAAA,CAAA,GASnC,KAAa,EAAA,CAAM,EAAE,UAAA,GAAU,YAAA,EAAA,MAoCjC,gBAAA,EAAA,GAAA,EAAA,UAAA,CACG,IApCC,MAAyB;AAC7B,UAAQ,GAAR;AAAA,IACE,KAAK,EAAwB;AAC3B,aACE,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAW,EAAO;AAAA,kBACrB,gBAAA,EAAC,IAAD,CAAA,CAAkB;AAAA,OACd;AAAA,IAEV,KAAK,EAAwB;AAC3B,aACE,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAW,EAAO;AAAA,kBACrB,gBAAA,EAAC,IAAD,CAAA,CAAoB;AAAA,OAChB;AAAA,IAEV,KAAK,EAAwB;AAC3B,aACE,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAW,EAAO;AAAA,kBACrB,gBAAA,EAAC,IAAD,CAAA,CAA0B;AAAA,OACtB;AAAA,IAEV,KAAK,EAAwB;AAC3B,aACE,gBAAA,EAAC,IAAD;AAAA,QAAU,UAAU;AAAA,kBAClB,gBAAA,EAAC,OAAD;AAAA,UAAK,WAAW,EAAO;AAAA,oBACrB,gBAAA,EAAC,IAAD,CAAA,CAAkB;AAAA,SACd;AAAA,OACG;AAAA,IAEf,KAAK,EAAwB;AAAA,IAC7B;AACE,aAAO;AAAA;GAOR,CAAkB,EAClB,CAAA;AAIP,GAAW,cAAc;ACnDzB,IAAa,KAAc,EAAA,CACxB,EACC,UAAA,GACA,YAAA,GACA,aAAA,GACA,eAAA,GACA,cAAA,GACA,wBAAA,GACA,mBAAA,GACA,oBAAA,GACA,iBAAA,GACA,oBAAA,EAAA,MACsB;AACtB,QAAM,EAAE,YAAA,EAAA,IAAe,EAAA;AACvB,SACE,gBAAA,EAAC,GAAD;AAAA,IAAyB,YAAA;AAAA,IAAyB,aAAA;AAAA,IAA4B,eAAA;AAAA,eAC1E,GAAc,MACV,MAAe,EAAe,OAE9B,gBAAA,EAAC,GAAD;AAAA,MACgB,cAAA;AAAA,MACA,cAAA;AAAA,MACA,cAAA;AAAA,MACU,wBAAA;AAAA,MACL,mBAAA;AAAA,MACC,oBAAA;AAAA,MACH,iBAAA;AAAA,MACG,oBAAA;AAAA,MAEnB,UAAA;AAAA,KACc,IAIjB,gBAAA,EAAC,GAAD;AAAA,MACgB,cAAA;AAAA,MACA,cAAA;AAAA,MACA,cAAA;AAAA,MACU,wBAAA;AAAA,MACL,mBAAA;AAAA,MACC,oBAAA;AAAA,MACH,iBAAA;AAAA,MACG,oBAAA;AAAA,MAEnB,UAAA;AAAA,KACc;AAAA,GAIX;;AAKpB,GAAY,cAAc;ACtD1B,IAAM,KAAA,CAAU,EAAE,mBAAA,GAAmB,aAAA,EAAA,MAA+B;AAClE,QAAM,CAAC,GAAY,CAAA,IAAsB,EAAA,MAA+B;AACtE,UAAM,IAAQ,EAAA;AACd,QAAI,EACF,KAAI;AACF,YAAM,IAAS,KAAK,MAAM,CAAA,GACpB,IAAO,EAAO,OAAO,cAAc,EAAO;AAChD,aAAO,MAAS,EAAe,QAAQ,MAAS,EAAe,OAAO,IAAO;AAAA,YACvE;AACN,aAAO;AAAA;AAGX,WAAO;AAAA;AAGT,SAAA,GAAA,MAAgB;AAOd,IAAA,GAAiB,KAAK,UANN,EACd,OAAO;AAAA,MACL,aAAA;AAAA,MACA,YAAA;AAAA,MACD,CACF,CACuC;AAAA,KACvC,CAAC,GAAa,CAAA,CAAW,GAMrB;AAAA,IACL,YAAA;AAAA,IACA,eANoB,EAAA,CAAa,MAAyB;AAC1D,MAAA,EAAmB,CAAA;AAAA,OAClB,CAAA,CAAE;AAAA;GCjCD,KAAA,MAAkB;AACtB,QAAM,CAAC,GAAa,CAAA,IAAuB,EAAA,MAAwB;AACjE,UAAM,IAAQ,EAAA;AACd,QAAI,EACF,KAAI;AACF,YAAM,IAAS,KAAK,MAAM,CAAA;AAC1B,aAAO,EAAO,OAAO,eAAe,EAAO,eAAe;AAAA,YACpD;AACN,aAAO;AAAA;AAGX,WAAO;AAAA;AAeT,SAAO;AAAA,IACL,aAAA;AAAA,IACA,gBAdqB,EAAA,CAAa,MAAkB;AACpD,MAAA,EAAoB,CAAA;AAAA,OACnB,CAAA,CAAE;AAAA,IAaH,eAXoB,EAAA,MAAkB;AACtC,MAAA,EAAA,CAAqB,MAAS,CAAC,CAAA;AAAA,OAC9B,CAAA,CAAE;AAAA,IAUH,cARmB,EAAA,MAAkB;AACrC,MAAA,EAAoB,EAAA;AAAA,OACnB,CAAA,CAAE;AAAA;GCfD,KAAiB,EAAA,CAAM,EAAE,UAAA,GAAU,mBAAA,IAAoB,GAAA,MAA+C;AAC1G,QAAM,EAAE,aAAA,GAAa,gBAAA,GAAgB,eAAA,GAAe,cAAA,EAAA,IAAiB,GAAA,GAC/D,EAAE,YAAA,GAAY,eAAA,EAAA,IAAkB,GAAO;AAAA,IAAE,mBAAA;AAAA,IAAmB,aAAA;AAAA,GAAa;AAE/E,SACE,gBAAA,EAAC,GAAc,UAAf;AAAA,IACE,OAAO;AAAA,MACL,aAAA;AAAA,MACA,YAAA;AAAA,MACA,gBAAA;AAAA,MACA,eAAA;AAAA,MACA,cAAA;AAAA,MACA,eAAA;AAAA;IAGD,UAAA;AAAA,GACsB;;AAI7B,GAAe,cAAc"}
@@ -1,72 +1 @@
1
- /**
2
- * 创建路由对象:仅接受 defineRouter(...) 的返回值,得到只读 ROUTES + matchRoute / isActiveRoute / getRouteByKey
3
- * Create router: accepts only the return value of defineRouter(...); returns ROUTES and typed helpers.
4
- *
5
- * @param routes - 须为 defineRouter(...) 的返回值(DefinedRouter)
6
- */
7
- export declare function createRouter<R extends Record<string, string>>(routes: DefinedRouter<R>): {
8
- ROUTES: Readonly<R>;
9
- matchRoute: (pathname: string, route: R[keyof R]) => boolean;
10
- isActiveRoute: (currentPath: string, targetPath: R[keyof R]) => boolean;
11
- getRouteByKey: (key: keyof R) => R[keyof R];
12
- };
13
-
14
- /**
15
- * 定义品牌类型:用于 defineXxx 的返回值,仅对应的 createXxx/构造函数可接受;Tag 区分不同定义(如 "events" | "router")。
16
- * Define brand type: for defineXxx return value, only the matching createXxx accepts; Tag discriminates (e.g. "events" | "router").
17
- * @example Defined<{ HOME: "/" }, "router"> 仅能传入 createRouter;Defined<{ FOO: "x" }, "events"> 仅能传入 EventEmitter
18
- */
19
- declare type Defined<T, Tag extends string> = T & {
20
- readonly __defineBrand?: Tag;
21
- };
22
-
23
- /**
24
- * 通用路由类型与 defineRouter / createRouter(与 EventEmitter 的 defineEvents 约定一致)
25
- * Generic route types and defineRouter / createRouter; only values from defineRouter are accepted by createRouter.
26
- *
27
- * @example
28
- * ```ts
29
- * import { defineRouter, createRouter } from "@/types/navigation";
30
- * const routeMap = defineRouter({ HOME: "/", LOGIN: "/login", USER: "/user/:id" });
31
- * const router = createRouter(routeMap);
32
- * router.ROUTES.HOME; // "/"
33
- * router.matchRoute(pathname, router.ROUTES.USER);
34
- * ```
35
- */
36
- /** 由 defineRouter 返回的「已规范路由表」类型;createRouter 只接受此类型。 */
37
- export declare type DefinedRouter<R extends Record<string, string>> = Defined<R, "router">;
38
-
39
- /**
40
- * 规范创建路由表:仅允许 defineRouter 返回的值传入 createRouter(类型约束)。
41
- * Define route map: only the return value of defineRouter may be passed to createRouter.
42
- *
43
- * @param routes - 路由 key-value 对象(值可为含 :param 的 path)
44
- * @returns DefinedRouter<R>,仅此类型可传入 createRouter
45
- */
46
- export declare function defineRouter<R extends Record<string, string>>(routes: R): DefinedRouter<R>;
47
-
48
- /**
49
- * 精确匹配:当前路径是否等于目标 path
50
- * Exact match: current path equals target path.
51
- */
52
- export declare function isActiveRoute(currentPath: string, targetPath: string): boolean;
53
-
54
- /**
55
- * 对象 T 的键字面量联合类型,即 keyof T。KeyOf: key type of T.
56
- * @example KeyOf<{ a: 1; b: 2 }> => "a" | "b"
57
- */
58
- declare type KeyOf<T> = keyof T;
59
-
60
- /**
61
- * 模式匹配:pathname 是否匹配带 :param 的 route 模式
62
- * Pattern match: pathname matches route pattern (supports :param segments).
63
- */
64
- export declare function matchRoute(pathname: string, route: string): boolean;
65
-
66
- /** 由路由表 R 推导的 key 类型 */
67
- export declare type RouteKey<R extends Record<string, string>> = KeyOf<R>;
68
-
69
- /** 由路由表 R 推导的 path 联合类型 */
70
- export declare type RoutePath<R extends Record<string, string>> = R[RouteKey<R>];
71
-
72
1
  export { }
@@ -1 +1 @@
1
- {"version":3,"file":"pixel-blast.cjs","names":[],"sources":["../src/designs/animations/PixelBlast/style.module.css","../src/designs/animations/PixelBlast/index.tsx"],"sourcesContent":[".container {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n}\n","// Component inspired by github.com/zavalit/bayer-dithering-webgl-demo\n\nimport React, { memo, useEffect, useMemo, useRef } from \"react\";\nimport { Effect, EffectComposer, EffectPass, RenderPass } from \"postprocessing\";\nimport {\n Clock,\n Color,\n GLSL3,\n LinearFilter,\n Mesh,\n OrthographicCamera,\n PlaneGeometry,\n Scene,\n ShaderMaterial,\n Texture,\n Uniform,\n Vector2,\n WebGLRenderer,\n} from \"three\";\n\nimport { useTheme } from \"@/themes/hooks/useTheme\";\n\nimport styles from \"./style.module.css\";\n\ntype PixelBlastVariant = \"square\" | \"circle\" | \"triangle\" | \"diamond\";\n\ninterface TouchPoint {\n x: number;\n y: number;\n vx: number;\n vy: number;\n force: number;\n age: number;\n}\n\ninterface TouchTexture {\n canvas: HTMLCanvasElement;\n texture: Texture;\n addTouch: (norm: { x: number; y: number }) => void;\n update: () => void;\n radiusScale: number;\n size: number;\n}\n\ninterface ReinitConfig {\n antialias: boolean;\n liquid: boolean;\n noiseAmount: number;\n}\n\ntype PixelBlastProps = {\n variant?: PixelBlastVariant;\n pixelSize?: number;\n color?: string;\n className?: string;\n style?: React.CSSProperties;\n antialias?: boolean;\n patternScale?: number;\n patternDensity?: number;\n liquid?: boolean;\n liquidStrength?: number;\n liquidRadius?: number;\n pixelSizeJitter?: number;\n enableRipples?: boolean;\n rippleIntensityScale?: number;\n rippleThickness?: number;\n rippleSpeed?: number;\n liquidWobbleSpeed?: number;\n autoPauseOffscreen?: boolean;\n speed?: number;\n transparent?: boolean;\n edgeFade?: number;\n noiseAmount?: number;\n};\n\nconst createTouchTexture = (): TouchTexture => {\n const size = 64;\n const canvas = document.createElement(\"canvas\");\n canvas.width = size;\n canvas.height = size;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new Error(\"2D context not available\");\n ctx.fillStyle = \"black\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n const texture = new Texture(canvas);\n texture.minFilter = LinearFilter;\n texture.magFilter = LinearFilter;\n texture.generateMipmaps = false;\n const trail: TouchPoint[] = [];\n let last: { x: number; y: number } | null = null;\n const maxAge = 64;\n let radius = 0.1 * size;\n const speed = 1 / maxAge;\n const clear = () => {\n ctx.fillStyle = \"black\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n };\n const drawPoint = (p: TouchPoint) => {\n const pos = { x: p.x * size, y: (1 - p.y) * size };\n let intensity = 1;\n const easeOutSine = (t: number) => Math.sin((t * Math.PI) / 2);\n const easeOutQuad = (t: number) => -t * (t - 2);\n if (p.age < maxAge * 0.3) intensity = easeOutSine(p.age / (maxAge * 0.3));\n else intensity = easeOutQuad(1 - (p.age - maxAge * 0.3) / (maxAge * 0.7)) || 0;\n intensity *= p.force;\n const color = `${((p.vx + 1) / 2) * 255}, ${((p.vy + 1) / 2) * 255}, ${intensity * 255}`;\n const offset = size * 5;\n ctx.shadowOffsetX = offset;\n ctx.shadowOffsetY = offset;\n ctx.shadowBlur = radius;\n ctx.shadowColor = `rgba(${color},${0.22 * intensity})`;\n ctx.beginPath();\n ctx.fillStyle = \"rgba(255,0,0,1)\";\n ctx.arc(pos.x - offset, pos.y - offset, radius, 0, Math.PI * 2);\n ctx.fill();\n };\n const addTouch = (norm: { x: number; y: number }) => {\n let force = 0;\n let vx = 0;\n let vy = 0;\n if (last) {\n const dx = norm.x - last.x;\n const dy = norm.y - last.y;\n if (dx === 0 && dy === 0) return;\n const dd = dx * dx + dy * dy;\n const d = Math.sqrt(dd);\n vx = dx / (d || 1);\n vy = dy / (d || 1);\n force = Math.min(dd * 10000, 1);\n }\n last = { x: norm.x, y: norm.y };\n trail.push({ x: norm.x, y: norm.y, age: 0, force, vx, vy });\n };\n const update = () => {\n clear();\n for (let i = trail.length - 1; i >= 0; i--) {\n const point = trail[i];\n const f = point.force * speed * (1 - point.age / maxAge);\n point.x += point.vx * f;\n point.y += point.vy * f;\n point.age++;\n if (point.age > maxAge) trail.splice(i, 1);\n }\n for (let i = 0; i < trail.length; i++) drawPoint(trail[i]);\n texture.needsUpdate = true;\n };\n return {\n canvas,\n texture,\n addTouch,\n update,\n set radiusScale(v: number) {\n radius = 0.1 * size * v;\n },\n get radiusScale() {\n return radius / (0.1 * size);\n },\n size,\n };\n};\n\nconst createLiquidEffect = (texture: Texture, opts?: { strength?: number; freq?: number }) => {\n const fragment = `\n uniform sampler2D uTexture;\n uniform float uStrength;\n uniform float uTime;\n uniform float uFreq;\n\n void mainUv(inout vec2 uv) {\n vec4 tex = texture2D(uTexture, uv);\n float vx = tex.r * 2.0 - 1.0;\n float vy = tex.g * 2.0 - 1.0;\n float intensity = tex.b;\n\n float wave = 0.5 + 0.5 * sin(uTime * uFreq + intensity * 6.2831853);\n\n float amt = uStrength * intensity * wave;\n\n uv += vec2(vx, vy) * amt;\n }\n `;\n return new Effect(\"LiquidEffect\", fragment, {\n uniforms: new Map<string, Uniform>([\n [\"uTexture\", new Uniform(texture)],\n [\"uStrength\", new Uniform(opts?.strength ?? 0.025)],\n [\"uTime\", new Uniform(0)],\n [\"uFreq\", new Uniform(opts?.freq ?? 4.5)],\n ]),\n });\n};\n\nconst SHAPE_MAP: Record<PixelBlastVariant, number> = {\n square: 0,\n circle: 1,\n triangle: 2,\n diamond: 3,\n};\n\nconst VERTEX_SRC = `\nvoid main() {\n gl_Position = vec4(position, 1.0);\n}\n`;\n\nconst FRAGMENT_SRC = `\nprecision highp float;\n\nuniform vec3 uColor;\nuniform vec2 uResolution;\nuniform float uTime;\nuniform float uPixelSize;\nuniform float uScale;\nuniform float uDensity;\nuniform float uPixelJitter;\nuniform int uEnableRipples;\nuniform float uRippleSpeed;\nuniform float uRippleThickness;\nuniform float uRippleIntensity;\nuniform float uEdgeFade;\n\nuniform int uShapeType;\nconst int SHAPE_SQUARE = 0;\nconst int SHAPE_CIRCLE = 1;\nconst int SHAPE_TRIANGLE = 2;\nconst int SHAPE_DIAMOND = 3;\n\nconst int MAX_CLICKS = 10;\n\nuniform vec2 uClickPos [MAX_CLICKS];\nuniform float uClickTimes[MAX_CLICKS];\n\nout vec4 fragColor;\n\nfloat Bayer2(vec2 a) {\n a = floor(a);\n return fract(a.x / 2. + a.y * a.y * .75);\n}\n#define Bayer4(a) (Bayer2(.5*(a))*0.25 + Bayer2(a))\n#define Bayer8(a) (Bayer4(.5*(a))*0.25 + Bayer2(a))\n\n#define FBM_OCTAVES 5\n#define FBM_LACUNARITY 1.25\n#define FBM_GAIN 1.0\n\nfloat hash11(float n){ return fract(sin(n)*43758.5453); }\n\nfloat vnoise(vec3 p){\n vec3 ip = floor(p);\n vec3 fp = fract(p);\n float n000 = hash11(dot(ip + vec3(0.0,0.0,0.0), vec3(1.0,57.0,113.0)));\n float n100 = hash11(dot(ip + vec3(1.0,0.0,0.0), vec3(1.0,57.0,113.0)));\n float n010 = hash11(dot(ip + vec3(0.0,1.0,0.0), vec3(1.0,57.0,113.0)));\n float n110 = hash11(dot(ip + vec3(1.0,1.0,0.0), vec3(1.0,57.0,113.0)));\n float n001 = hash11(dot(ip + vec3(0.0,0.0,1.0), vec3(1.0,57.0,113.0)));\n float n101 = hash11(dot(ip + vec3(1.0,0.0,1.0), vec3(1.0,57.0,113.0)));\n float n011 = hash11(dot(ip + vec3(0.0,1.0,1.0), vec3(1.0,57.0,113.0)));\n float n111 = hash11(dot(ip + vec3(1.0,1.0,1.0), vec3(1.0,57.0,113.0)));\n vec3 w = fp*fp*fp*(fp*(fp*6.0-15.0)+10.0);\n float x00 = mix(n000, n100, w.x);\n float x10 = mix(n010, n110, w.x);\n float x01 = mix(n001, n101, w.x);\n float x11 = mix(n011, n111, w.x);\n float y0 = mix(x00, x10, w.y);\n float y1 = mix(x01, x11, w.y);\n return mix(y0, y1, w.z) * 2.0 - 1.0;\n}\n\nfloat fbm2(vec2 uv, float t){\n vec3 p = vec3(uv * uScale, t);\n float amp = 1.0;\n float freq = 1.0;\n float sum = 1.0;\n for (int i = 0; i < FBM_OCTAVES; ++i){\n sum += amp * vnoise(p * freq);\n freq *= FBM_LACUNARITY;\n amp *= FBM_GAIN;\n }\n return sum * 0.5 + 0.5;\n}\n\nfloat maskCircle(vec2 p, float cov){\n float r = sqrt(cov) * .25;\n float d = length(p - 0.5) - r;\n float aa = 0.5 * fwidth(d);\n return cov * (1.0 - smoothstep(-aa, aa, d * 2.0));\n}\n\nfloat maskTriangle(vec2 p, vec2 id, float cov){\n bool flip = mod(id.x + id.y, 2.0) > 0.5;\n if (flip) p.x = 1.0 - p.x;\n float r = sqrt(cov);\n float d = p.y - r*(1.0 - p.x);\n float aa = fwidth(d);\n return cov * clamp(0.5 - d/aa, 0.0, 1.0);\n}\n\nfloat maskDiamond(vec2 p, float cov){\n float r = sqrt(cov) * 0.564;\n return step(abs(p.x - 0.49) + abs(p.y - 0.49), r);\n}\n\nvoid main(){\n float pixelSize = uPixelSize;\n vec2 fragCoord = gl_FragCoord.xy - uResolution * .5;\n float aspectRatio = uResolution.x / uResolution.y;\n\n vec2 pixelId = floor(fragCoord / pixelSize);\n vec2 pixelUV = fract(fragCoord / pixelSize);\n\n float cellPixelSize = 8.0 * pixelSize;\n vec2 cellId = floor(fragCoord / cellPixelSize);\n vec2 cellCoord = cellId * cellPixelSize;\n vec2 uv = cellCoord / uResolution * vec2(aspectRatio, 1.0);\n\n float base = fbm2(uv, uTime * 0.05);\n base = base * 0.5 - 0.65;\n\n float feed = base + (uDensity - 0.5) * 0.3;\n\n float speed = uRippleSpeed;\n float thickness = uRippleThickness;\n const float dampT = 1.0;\n const float dampR = 10.0;\n\n if (uEnableRipples == 1) {\n for (int i = 0; i < MAX_CLICKS; ++i){\n vec2 pos = uClickPos[i];\n if (pos.x < 0.0) continue;\n float cellPixelSize = 8.0 * pixelSize;\n vec2 cuv = (((pos - uResolution * .5 - cellPixelSize * .5) / (uResolution))) * vec2(aspectRatio, 1.0);\n float t = max(uTime - uClickTimes[i], 0.0);\n float r = distance(uv, cuv);\n float waveR = speed * t;\n float ring = exp(-pow((r - waveR) / thickness, 2.0));\n float atten = exp(-dampT * t) * exp(-dampR * r);\n feed = max(feed, ring * atten * uRippleIntensity);\n }\n }\n\n float bayer = Bayer8(fragCoord / uPixelSize) - 0.5;\n float bw = step(0.5, feed + bayer);\n\n float h = fract(sin(dot(floor(fragCoord / uPixelSize), vec2(127.1, 311.7))) * 43758.5453);\n float jitterScale = 1.0 + (h - 0.5) * uPixelJitter;\n float coverage = bw * jitterScale;\n float M;\n if (uShapeType == SHAPE_CIRCLE) M = maskCircle (pixelUV, coverage);\n else if (uShapeType == SHAPE_TRIANGLE) M = maskTriangle(pixelUV, pixelId, coverage);\n else if (uShapeType == SHAPE_DIAMOND) M = maskDiamond(pixelUV, coverage);\n else M = coverage;\n\n if (uEdgeFade > 0.0) {\n vec2 norm = gl_FragCoord.xy / uResolution;\n float edge = min(min(norm.x, norm.y), min(1.0 - norm.x, 1.0 - norm.y));\n float fade = smoothstep(0.0, uEdgeFade, edge);\n M *= fade;\n }\n\n vec3 color = uColor;\n\n // sRGB gamma correction - convert linear to sRGB for accurate color output\n vec3 srgbColor = mix(\n color * 12.92,\n 1.055 * pow(color, vec3(1.0 / 2.4)) - 0.055,\n step(0.0031308, color)\n );\n\n fragColor = vec4(srgbColor, M);\n}\n`;\n\nconst MAX_CLICKS = 10;\n\nconst PixelBlast: React.FC<PixelBlastProps> = memo(\n ({\n variant = \"square\",\n pixelSize = 3,\n color = \"#B19EEF\",\n className,\n style,\n antialias = true,\n patternScale = 2,\n patternDensity = 1,\n liquid = false,\n liquidStrength = 0.1,\n liquidRadius = 1,\n pixelSizeJitter = 0,\n enableRipples = true,\n rippleIntensityScale = 1,\n rippleThickness = 0.1,\n rippleSpeed = 0.3,\n liquidWobbleSpeed = 4.5,\n autoPauseOffscreen = true,\n speed = 0.5,\n transparent = true,\n edgeFade = 0.5,\n noiseAmount = 0,\n }) => {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const visibilityRef = useRef({ visible: true });\n const speedRef = useRef(speed);\n\n const threeRef = useRef<{\n renderer: WebGLRenderer;\n scene: Scene;\n camera: OrthographicCamera;\n material: ShaderMaterial;\n clock: Clock;\n clickIx: number;\n uniforms: {\n uResolution: { value: Vector2 };\n uTime: { value: number };\n uColor: { value: Color };\n uClickPos: { value: Vector2[] };\n uClickTimes: { value: Float32Array };\n uShapeType: { value: number };\n uPixelSize: { value: number };\n uScale: { value: number };\n uDensity: { value: number };\n uPixelJitter: { value: number };\n uEnableRipples: { value: number };\n uRippleSpeed: { value: number };\n uRippleThickness: { value: number };\n uRippleIntensity: { value: number };\n uEdgeFade: { value: number };\n };\n resizeObserver?: ResizeObserver;\n raf?: number;\n quad?: Mesh<PlaneGeometry, ShaderMaterial>;\n timeOffset?: number;\n composer?: EffectComposer;\n touch?: ReturnType<typeof createTouchTexture>;\n liquidEffect?: Effect;\n } | null>(null);\n const prevConfigRef = useRef<ReinitConfig | null>(null);\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n speedRef.current = speed;\n const needsReinitKeys: (keyof ReinitConfig)[] = [\"antialias\", \"liquid\", \"noiseAmount\"];\n const cfg: ReinitConfig = { antialias, liquid, noiseAmount };\n let mustReinit = false;\n if (!threeRef.current) mustReinit = true;\n else if (prevConfigRef.current) {\n for (const k of needsReinitKeys)\n if (prevConfigRef.current[k] !== cfg[k]) {\n mustReinit = true;\n break;\n }\n }\n if (mustReinit) {\n if (threeRef.current) {\n const t = threeRef.current;\n t.resizeObserver?.disconnect();\n cancelAnimationFrame(t.raf!);\n t.quad?.geometry.dispose();\n t.material.dispose();\n t.composer?.dispose();\n t.renderer.dispose();\n if (t.renderer.domElement.parentElement === container) container.removeChild(t.renderer.domElement);\n threeRef.current = null;\n }\n const canvas = document.createElement(\"canvas\");\n const renderer = new WebGLRenderer({\n canvas,\n antialias,\n alpha: true,\n powerPreference: \"high-performance\",\n });\n renderer.domElement.style.width = \"100%\";\n renderer.domElement.style.height = \"100%\";\n // 降低像素比以提高性能\n renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 1.5));\n container.appendChild(renderer.domElement);\n if (transparent) renderer.setClearAlpha(0);\n else renderer.setClearColor(0x000000, 1);\n const uniforms = {\n uResolution: { value: new Vector2(0, 0) },\n uTime: { value: 0 },\n uColor: { value: new Color(color) },\n uClickPos: {\n value: Array.from({ length: MAX_CLICKS }, () => new Vector2(-1, -1)),\n },\n uClickTimes: { value: new Float32Array(MAX_CLICKS) },\n uShapeType: { value: SHAPE_MAP[variant] ?? 0 },\n uPixelSize: { value: pixelSize * renderer.getPixelRatio() },\n uScale: { value: patternScale },\n uDensity: { value: patternDensity },\n uPixelJitter: { value: pixelSizeJitter },\n uEnableRipples: { value: enableRipples ? 1 : 0 },\n uRippleSpeed: { value: rippleSpeed },\n uRippleThickness: { value: rippleThickness },\n uRippleIntensity: { value: rippleIntensityScale },\n uEdgeFade: { value: edgeFade },\n };\n const scene = new Scene();\n const camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1);\n const material = new ShaderMaterial({\n vertexShader: VERTEX_SRC,\n fragmentShader: FRAGMENT_SRC,\n uniforms,\n transparent: true,\n depthTest: false,\n depthWrite: false,\n glslVersion: GLSL3,\n });\n\n const quadGeom = new PlaneGeometry(2, 2);\n const quad = new Mesh(quadGeom, material);\n scene.add(quad);\n const clock = new Clock();\n const setSize = () => {\n const w = container.clientWidth || 1;\n const h = container.clientHeight || 1;\n renderer.setSize(w, h, false);\n uniforms.uResolution.value.set(renderer.domElement.width, renderer.domElement.height);\n if (threeRef.current?.composer) threeRef.current.composer.setSize(renderer.domElement.width, renderer.domElement.height);\n uniforms.uPixelSize.value = pixelSize * renderer.getPixelRatio();\n };\n setSize();\n const ro = new ResizeObserver(setSize);\n ro.observe(container);\n const randomFloat = (): number => {\n if (typeof window !== \"undefined\" && window.crypto?.getRandomValues) {\n const u32 = new Uint32Array(1);\n window.crypto.getRandomValues(u32);\n return u32[0] / 0xffffffff;\n }\n return Math.random();\n };\n const timeOffset = randomFloat() * 1000;\n let composer: EffectComposer | undefined;\n let touch: ReturnType<typeof createTouchTexture> | undefined;\n let liquidEffect: Effect | undefined;\n if (liquid) {\n touch = createTouchTexture();\n touch.radiusScale = liquidRadius;\n composer = new EffectComposer(renderer);\n const renderPass = new RenderPass(scene, camera);\n liquidEffect = createLiquidEffect(touch.texture, {\n strength: liquidStrength,\n freq: liquidWobbleSpeed,\n });\n const effectPass = new EffectPass(camera, liquidEffect);\n effectPass.renderToScreen = true;\n composer.addPass(renderPass);\n composer.addPass(effectPass);\n }\n if (noiseAmount > 0) {\n if (!composer) {\n composer = new EffectComposer(renderer);\n composer.addPass(new RenderPass(scene, camera));\n }\n const noiseEffect = new Effect(\n \"NoiseEffect\",\n `uniform float uTime; uniform float uAmount; float hash(vec2 p){ return fract(sin(dot(p, vec2(127.1,311.7))) * 43758.5453);} void mainUv(inout vec2 uv){} void mainImage(const in vec4 inputColor,const in vec2 uv,out vec4 outputColor){ float n=hash(floor(uv*vec2(1920.0,1080.0))+floor(uTime*60.0)); float g=(n-0.5)*uAmount; outputColor=inputColor+vec4(vec3(g),0.0);} `,\n {\n uniforms: new Map<string, Uniform>([\n [\"uTime\", new Uniform(0)],\n [\"uAmount\", new Uniform(noiseAmount)],\n ]),\n },\n );\n const noisePass = new EffectPass(camera, noiseEffect);\n noisePass.renderToScreen = true;\n if (composer && composer.passes.length > 0) {\n composer.passes.forEach((p: { renderToScreen?: boolean }) => {\n const pass = p as { renderToScreen?: boolean };\n pass.renderToScreen = false;\n });\n }\n composer.addPass(noisePass);\n }\n if (composer) composer.setSize(renderer.domElement.width, renderer.domElement.height);\n const mapToPixels = (e: PointerEvent) => {\n const rect = renderer.domElement.getBoundingClientRect();\n const scaleX = renderer.domElement.width / rect.width;\n const scaleY = renderer.domElement.height / rect.height;\n const fx = (e.clientX - rect.left) * scaleX;\n const fy = (rect.height - (e.clientY - rect.top)) * scaleY;\n return {\n fx,\n fy,\n w: renderer.domElement.width,\n h: renderer.domElement.height,\n };\n };\n const onPointerDown = (e: PointerEvent) => {\n const { fx, fy } = mapToPixels(e);\n const ix = threeRef.current?.clickIx ?? 0;\n uniforms.uClickPos.value[ix].set(fx, fy);\n uniforms.uClickTimes.value[ix] = uniforms.uTime.value;\n if (threeRef.current) threeRef.current.clickIx = (ix + 1) % MAX_CLICKS;\n };\n const onPointerMove = (e: PointerEvent) => {\n if (!touch) return;\n const { fx, fy, w, h } = mapToPixels(e);\n touch.addTouch({ x: fx / w, y: fy / h });\n };\n renderer.domElement.addEventListener(\"pointerdown\", onPointerDown, {\n passive: true,\n });\n renderer.domElement.addEventListener(\"pointermove\", onPointerMove, {\n passive: true,\n });\n let raf = 0;\n let lastFrameTime = 0;\n const targetFPS = 30; // 限制到 30 FPS 以提高性能\n const frameInterval = 1000 / targetFPS;\n\n const animate = (currentTime: number) => {\n if (autoPauseOffscreen && !visibilityRef.current.visible) {\n raf = requestAnimationFrame(animate);\n return;\n }\n\n // 帧率限制\n const elapsed = currentTime - lastFrameTime;\n if (elapsed < frameInterval) {\n raf = requestAnimationFrame(animate);\n return;\n }\n lastFrameTime = currentTime - (elapsed % frameInterval);\n\n uniforms.uTime.value = timeOffset + clock.getElapsedTime() * speedRef.current;\n if (liquidEffect) {\n const liqEffect = liquidEffect as Effect & { uniforms: Map<string, Uniform> };\n const timeUniform = liqEffect.uniforms.get(\"uTime\");\n if (timeUniform) timeUniform.value = uniforms.uTime.value;\n }\n if (composer) {\n if (touch) touch.update();\n composer.passes.forEach((p: any) => {\n const pass = p as { effects?: Array<Effect & { uniforms?: Map<string, Uniform> }> };\n if (pass.effects) {\n pass.effects.forEach((eff: Effect & { uniforms?: Map<string, Uniform> }) => {\n const timeUniform = eff.uniforms?.get(\"uTime\");\n if (timeUniform) timeUniform.value = uniforms.uTime.value;\n });\n }\n });\n composer.render();\n } else renderer.render(scene, camera);\n raf = requestAnimationFrame(animate);\n };\n raf = requestAnimationFrame((time) => {\n lastFrameTime = time;\n animate(time);\n });\n threeRef.current = {\n renderer,\n scene,\n camera,\n material,\n clock,\n clickIx: 0,\n uniforms,\n resizeObserver: ro,\n raf,\n quad,\n timeOffset,\n composer,\n touch,\n liquidEffect,\n };\n } else {\n const t = threeRef.current!;\n t.uniforms.uShapeType.value = SHAPE_MAP[variant] ?? 0;\n t.uniforms.uPixelSize.value = pixelSize * t.renderer.getPixelRatio();\n t.uniforms.uColor.value.set(color);\n t.uniforms.uScale.value = patternScale;\n t.uniforms.uDensity.value = patternDensity;\n t.uniforms.uPixelJitter.value = pixelSizeJitter;\n t.uniforms.uEnableRipples.value = enableRipples ? 1 : 0;\n t.uniforms.uRippleIntensity.value = rippleIntensityScale;\n t.uniforms.uRippleThickness.value = rippleThickness;\n t.uniforms.uRippleSpeed.value = rippleSpeed;\n t.uniforms.uEdgeFade.value = edgeFade;\n if (transparent) t.renderer.setClearAlpha(0);\n else t.renderer.setClearColor(0x000000, 1);\n if (t.liquidEffect) {\n const liqEffect = t.liquidEffect as Effect & { uniforms: Map<string, Uniform> };\n const uStrength = liqEffect.uniforms.get(\"uStrength\");\n if (uStrength) uStrength.value = liquidStrength;\n const uFreq = liqEffect.uniforms.get(\"uFreq\");\n if (uFreq) uFreq.value = liquidWobbleSpeed;\n }\n if (t.touch) t.touch.radiusScale = liquidRadius;\n }\n prevConfigRef.current = cfg;\n return () => {\n if (threeRef.current && mustReinit) return;\n if (!threeRef.current) return;\n const t = threeRef.current;\n t.resizeObserver?.disconnect();\n cancelAnimationFrame(t.raf!);\n t.quad?.geometry.dispose();\n t.material.dispose();\n t.composer?.dispose();\n t.renderer.dispose();\n if (t.renderer.domElement.parentElement === container) container.removeChild(t.renderer.domElement);\n threeRef.current = null;\n };\n }, [\n antialias,\n liquid,\n noiseAmount,\n pixelSize,\n patternScale,\n patternDensity,\n enableRipples,\n rippleIntensityScale,\n rippleThickness,\n rippleSpeed,\n pixelSizeJitter,\n edgeFade,\n transparent,\n liquidStrength,\n liquidRadius,\n liquidWobbleSpeed,\n autoPauseOffscreen,\n variant,\n color,\n speed,\n ]);\n\n return <div ref={containerRef} className={`${styles.container} ${className ?? \"\"}`} style={style} aria-label=\"PixelBlast interactive background\" />;\n },\n);\n\nPixelBlast.displayName = \"PixelBlast\";\n\nconst PixelBlastBackground: React.FC<Omit<PixelBlastProps, \"color\">> = memo((props) => {\n const { currentTheme } = useTheme();\n\n // 从主题中获取颜色\n const color = useMemo(() => {\n const primary = currentTheme.colors.variables.primary || \"#B19EEF\";\n\n const toHex = (color: string): string => {\n if (color.startsWith(\"#\")) {\n return color;\n }\n const match = color.match(/rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)/);\n if (match) {\n const r = parseInt(match[1], 10).toString(16).padStart(2, \"0\");\n const g = parseInt(match[2], 10).toString(16).padStart(2, \"0\");\n const b = parseInt(match[3], 10).toString(16).padStart(2, \"0\");\n return `#${r}${g}${b}`;\n }\n return color;\n };\n\n return toHex(primary);\n }, [currentTheme]);\n\n return (\n <PixelBlast\n color={color}\n variant=\"square\"\n pixelSize={6}\n patternScale={2}\n patternDensity={1}\n pixelSizeJitter={0}\n enableRipples\n rippleSpeed={0.3}\n rippleThickness={0.12}\n rippleIntensityScale={1.2}\n liquid={false}\n liquidStrength={0.12}\n liquidRadius={1.2}\n liquidWobbleSpeed={5}\n speed={0.3}\n edgeFade={0.25}\n transparent\n antialias={false}\n {...props}\n />\n );\n});\n\nPixelBlastBackground.displayName = \"PixelBlastBackground\";\n\nexport default PixelBlastBackground;\n"],"mappings":"gRC2EM,GAAA,IAAyC,CAE7C,MAAM,EAAS,SAAS,cAAc,QAAA,EACtC,EAAO,MAAQ,GACf,EAAO,OAAS,GAChB,MAAM,EAAM,EAAO,WAAW,IAAA,EAC9B,GAAI,CAAC,EAAK,MAAM,IAAI,MAAM,0BAAA,EAC1B,EAAI,UAAY,QAChB,EAAI,SAAS,EAAG,EAAG,EAAO,MAAO,EAAO,MAAA,EACxC,MAAM,EAAU,IAAI,EAAA,QAAQ,CAAA,EAC5B,EAAQ,UAAY,EAAA,aACpB,EAAQ,UAAY,EAAA,aACpB,EAAQ,gBAAkB,GAC1B,MAAM,EAAsB,CAAA,EAC5B,IAAI,EAAwC,KAC5C,MAAM,EAAS,GACf,IAAI,EAAS,GAAM,GACnB,MAAM,EAAQ,EAAI,EACZ,EAAA,IAAc,CAClB,EAAI,UAAY,QAChB,EAAI,SAAS,EAAG,EAAG,EAAO,MAAO,EAAO,MAAA,GAEpC,EAAa,GAAkB,CACnC,MAAM,EAAM,CAAE,EAAG,EAAE,EAAI,GAAM,GAAI,EAAI,EAAE,GAAK,IAC5C,IAAI,EAAY,EAChB,MAAM,EAAe,GAAc,KAAK,IAAK,EAAI,KAAK,GAAM,CAAA,EACtD,EAAe,GAAc,CAAC,GAAK,EAAI,GACzC,EAAE,IAAM,EAAS,GAAK,EAAY,EAAY,EAAE,KAAO,EAAS,GAAA,EAC/D,EAAY,EAAY,GAAK,EAAE,IAAM,EAAS,KAAQ,EAAS,GAAA,GAAS,EAC7E,GAAa,EAAE,MACf,MAAM,EAAQ,IAAK,EAAE,GAAK,GAAK,EAAK,GAAA,MAAU,EAAE,GAAK,GAAK,EAAK,GAAA,KAAQ,EAAY,GAAA,GAC7E,EAAS,IACf,EAAI,cAAgB,EACpB,EAAI,cAAgB,EACpB,EAAI,WAAa,EACjB,EAAI,YAAc,QAAQ,CAAA,IAAS,IAAO,CAAA,IAC1C,EAAI,UAAA,EACJ,EAAI,UAAY,kBAChB,EAAI,IAAI,EAAI,EAAI,EAAQ,EAAI,EAAI,EAAQ,EAAQ,EAAG,KAAK,GAAK,CAAA,EAC7D,EAAI,KAAA,GAgCN,MAAO,CACL,OAAA,EACA,QAAA,EACA,SAjCgB,GAAmC,CACnD,IAAI,EAAQ,EACR,EAAK,EACL,EAAK,EACT,GAAI,EAAM,CACR,MAAM,EAAK,EAAK,EAAI,EAAK,EACnB,EAAK,EAAK,EAAI,EAAK,EACzB,GAAI,IAAO,GAAK,IAAO,EAAG,OAC1B,MAAM,EAAK,EAAK,EAAK,EAAK,EACpB,EAAI,KAAK,KAAK,CAAA,EACpB,EAAK,GAAM,GAAK,GAChB,EAAK,GAAM,GAAK,GAChB,EAAQ,KAAK,IAAI,EAAK,IAAO,CAAA,EAE/B,EAAO,CAAE,EAAG,EAAK,EAAG,EAAG,EAAK,GAC5B,EAAM,KAAK,CAAE,EAAG,EAAK,EAAG,EAAG,EAAK,EAAG,IAAK,EAAG,MAAA,EAAO,GAAA,EAAI,GAAA,EAAI,GAmB1D,OAjBI,IAAe,CACnB,EAAA,EACA,QAAS,EAAI,EAAM,OAAS,EAAG,GAAK,EAAG,IAAK,CAC1C,MAAM,EAAQ,EAAM,CAAA,EACd,EAAI,EAAM,MAAQ,GAAS,EAAI,EAAM,IAAM,GACjD,EAAM,GAAK,EAAM,GAAK,EACtB,EAAM,GAAK,EAAM,GAAK,EACtB,EAAM,MACF,EAAM,IAAM,GAAQ,EAAM,OAAO,EAAG,CAAA,EAE1C,QAAS,EAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,EAAU,EAAM,CAAA,CAAA,EACvD,EAAQ,YAAc,IAOtB,IAAI,YAAY,EAAW,CACzB,EAAS,GAAM,GAAO,GAExB,IAAI,aAAc,CAChB,OAAO,GAAU,GAAM,KAEzB,UAIE,GAAA,CAAsB,EAAkB,IAoBrC,IAAI,EAAA,OAAO,eAnBD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAmB2B,CAC1C,SAAU,IAAI,IAAqB,CACjC,CAAC,WAAY,IAAI,EAAA,QAAQ,CAAA,CAAQ,EACjC,CAAC,YAAa,IAAI,EAAA,QAAQ,GAAM,UAAY,IAAA,CAAM,EAClD,CAAC,QAAS,IAAI,EAAA,QAAQ,CAAA,CAAE,EACxB,CAAC,QAAS,IAAI,EAAA,QAAQ,GAAM,MAAQ,GAAA,CAAI,EACzC,CAAC,CACH,EAGG,GAA+C,CACnD,OAAQ,EACR,OAAQ,EACR,SAAU,EACV,QAAS,GAGL,GAAa;AAAA;AAAA;AAAA;AAAA,EAMb,GAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuKf,EAAa,GAEb,MAAA,EAAA,MAAA,CACH,CACC,QAAA,EAAU,SACV,UAAA,EAAY,EACZ,MAAA,EAAQ,UACR,UAAA,EACA,MAAA,EACA,UAAA,EAAY,GACZ,aAAA,EAAe,EACf,eAAA,EAAiB,EACjB,OAAA,EAAS,GACT,eAAA,EAAiB,GACjB,aAAA,EAAe,EACf,gBAAA,EAAkB,EAClB,cAAA,EAAgB,GAChB,qBAAA,EAAuB,EACvB,gBAAA,EAAkB,GAClB,YAAA,EAAc,GACd,kBAAA,EAAoB,IACpB,mBAAA,EAAqB,GACrB,MAAA,EAAQ,GACR,YAAA,EAAc,GACd,SAAA,EAAW,GACX,YAAA,EAAc,CAAA,IACV,CACJ,MAAM,KAAA,EAAA,QAA6C,IAAA,EAC7C,MAAA,EAAA,QAAuB,CAAE,QAAS,EAAA,CAAM,EACxC,KAAA,EAAA,QAAkB,CAAA,EAElB,KAAA,EAAA,QA+BI,IAAA,EACJ,KAAA,EAAA,QAA4C,IAAA,EAClD,SAAA,EAAA,WAAA,IAAgB,CACd,MAAM,EAAY,EAAa,QAC/B,GAAI,CAAC,EAAW,OAChB,EAAS,QAAU,EACnB,MAAM,GAA0C,CAAC,YAAa,SAAU,eAClE,EAAoB,CAAE,UAAA,EAAW,OAAA,EAAQ,YAAA,GAC/C,IAAI,EAAa,GACjB,GAAI,CAAC,EAAS,QAAS,EAAa,WAC3B,EAAc,mBACV,KAAK,GACd,GAAI,EAAc,QAAQ,CAAA,IAAO,EAAI,CAAA,EAAI,CACvC,EAAa,GACb,OAGN,GAAI,EAAY,CACd,GAAI,EAAS,QAAS,CACpB,MAAM,EAAI,EAAS,QACnB,EAAE,gBAAgB,WAAA,EAClB,qBAAqB,EAAE,GAAA,EACvB,EAAE,MAAM,SAAS,QAAA,EACjB,EAAE,SAAS,QAAA,EACX,EAAE,UAAU,QAAA,EACZ,EAAE,SAAS,QAAA,EACP,EAAE,SAAS,WAAW,gBAAkB,GAAW,EAAU,YAAY,EAAE,SAAS,UAAA,EACxF,EAAS,QAAU,KAGrB,MAAM,EAAW,IAAI,EAAA,cAAc,CACjC,OAFa,SAAS,cAAc,QAAA,EAGpC,UAAA,EACA,MAAO,GACP,gBAAiB,mBAClB,EACD,EAAS,WAAW,MAAM,MAAQ,OAClC,EAAS,WAAW,MAAM,OAAS,OAEnC,EAAS,cAAc,KAAK,IAAI,OAAO,kBAAoB,EAAG,GAAA,CAAI,EAClE,EAAU,YAAY,EAAS,UAAA,EAC3B,EAAa,EAAS,cAAc,CAAA,EACnC,EAAS,cAAc,EAAU,CAAA,EACtC,MAAM,EAAW,CACf,YAAa,CAAE,MAAO,IAAI,EAAA,QAAQ,EAAG,CAAA,CAAE,EACvC,MAAO,CAAE,MAAO,CAAA,EAChB,OAAQ,CAAE,MAAO,IAAI,EAAA,MAAM,CAAA,CAAM,EACjC,UAAW,CACT,MAAO,MAAM,KAAK,CAAE,OAAQ,CAAA,EAAY,IAAQ,IAAI,EAAA,QAAQ,GAAI,EAAA,CAAG,CAAC,EAEtE,YAAa,CAAE,MAAO,IAAI,aAAa,CAAA,CAAW,EAClD,WAAY,CAAE,MAAO,GAAU,CAAA,GAAY,CAAA,EAC3C,WAAY,CAAE,MAAO,EAAY,EAAS,cAAA,CAAe,EACzD,OAAQ,CAAE,MAAO,CAAA,EACjB,SAAU,CAAE,MAAO,CAAA,EACnB,aAAc,CAAE,MAAO,CAAA,EACvB,eAAgB,CAAE,MAAO,EAAgB,EAAI,CAAA,EAC7C,aAAc,CAAE,MAAO,CAAA,EACvB,iBAAkB,CAAE,MAAO,CAAA,EAC3B,iBAAkB,CAAE,MAAO,CAAA,EAC3B,UAAW,CAAE,MAAO,CAAA,GAEhB,EAAQ,IAAI,EAAA,MACZ,EAAS,IAAI,EAAA,mBAAmB,GAAI,EAAG,EAAG,GAAI,EAAG,CAAA,EACjD,EAAW,IAAI,EAAA,eAAe,CAClC,aAAc,GACd,eAAgB,GAChB,SAAA,EACA,YAAa,GACb,UAAW,GACX,WAAY,GACZ,YAAa,EAAA,MACd,EAGK,EAAO,IAAI,EAAA,KADA,IAAI,EAAA,cAAc,EAAG,CAAA,EACN,CAAA,EAChC,EAAM,IAAI,CAAA,EACV,MAAM,EAAQ,IAAI,EAAA,MACZ,EAAA,IAAgB,CACpB,MAAM,EAAI,EAAU,aAAe,EAC7B,EAAI,EAAU,cAAgB,EACpC,EAAS,QAAQ,EAAG,EAAG,EAAA,EACvB,EAAS,YAAY,MAAM,IAAI,EAAS,WAAW,MAAO,EAAS,WAAW,MAAA,EAC1E,EAAS,SAAS,UAAU,EAAS,QAAQ,SAAS,QAAQ,EAAS,WAAW,MAAO,EAAS,WAAW,MAAA,EACjH,EAAS,WAAW,MAAQ,EAAY,EAAS,cAAA,GAEnD,EAAA,EACA,MAAM,EAAK,IAAI,eAAe,CAAA,EAC9B,EAAG,QAAQ,CAAA,EASX,MAAM,GARA,IAA4B,CAChC,GAAI,OAAO,OAAW,KAAe,OAAO,QAAQ,gBAAiB,CACnE,MAAM,EAAM,IAAI,YAAY,CAAA,EAC5B,cAAO,OAAO,gBAAgB,CAAA,EACvB,EAAI,CAAA,EAAK,WAElB,OAAO,KAAK,OAAA,IAEK,EAAgB,IACnC,IAAI,EACA,EACA,EACJ,GAAI,EAAQ,CACV,EAAQ,GAAA,EACR,EAAM,YAAc,EACpB,EAAW,IAAI,EAAA,eAAe,CAAA,EAC9B,MAAM,EAAa,IAAI,EAAA,WAAW,EAAO,CAAA,EACzC,EAAe,GAAmB,EAAM,QAAS,CAC/C,SAAU,EACV,KAAM,EACP,EACD,MAAM,EAAa,IAAI,EAAA,WAAW,EAAQ,CAAA,EAC1C,EAAW,eAAiB,GAC5B,EAAS,QAAQ,CAAA,EACjB,EAAS,QAAQ,CAAA,EAEnB,GAAI,EAAc,EAAG,CACd,IACH,EAAW,IAAI,EAAA,eAAe,CAAA,EAC9B,EAAS,QAAQ,IAAI,EAAA,WAAW,EAAO,CAAA,CAAO,GAYhD,MAAM,EAAY,IAAI,EAAA,WAAW,EAVb,IAAI,EAAA,OACtB,cACA,+WACA,CACE,SAAU,IAAI,IAAqB,CACjC,CAAC,QAAS,IAAI,EAAA,QAAQ,CAAA,CAAE,EACxB,CAAC,UAAW,IAAI,EAAA,QAAQ,CAAA,CAAY,CAAC,CACtC,CAAC,CACH,CACF,EAED,EAAU,eAAiB,GACvB,GAAY,EAAS,OAAO,OAAS,GACvC,EAAS,OAAO,QAAS,GAAoC,CAC3D,MAAM,EAAO,EACb,EAAK,eAAiB,KAG1B,EAAS,QAAQ,CAAA,EAEf,GAAU,EAAS,QAAQ,EAAS,WAAW,MAAO,EAAS,WAAW,MAAA,EAC9E,MAAM,GAAe,GAAoB,CACvC,MAAM,EAAO,EAAS,WAAW,sBAAA,EAC3B,EAAS,EAAS,WAAW,MAAQ,EAAK,MAC1C,EAAS,EAAS,WAAW,OAAS,EAAK,OAGjD,MAAO,CACL,IAHU,EAAE,QAAU,EAAK,MAAQ,EAInC,IAHU,EAAK,QAAU,EAAE,QAAU,EAAK,MAAQ,EAIlD,EAAG,EAAS,WAAW,MACvB,EAAG,EAAS,WAAW,SAGrB,GAAiB,GAAoB,CACzC,KAAM,CAAE,GAAA,EAAI,GAAA,CAAA,EAAO,GAAY,CAAA,EACzB,EAAK,EAAS,SAAS,SAAW,EACxC,EAAS,UAAU,MAAM,CAAA,EAAI,IAAI,EAAI,CAAA,EACrC,EAAS,YAAY,MAAM,CAAA,EAAM,EAAS,MAAM,MAC5C,EAAS,UAAS,EAAS,QAAQ,SAAW,EAAK,GAAK,IAExD,GAAiB,GAAoB,CACzC,GAAI,CAAC,EAAO,OACZ,KAAM,CAAE,GAAA,EAAI,GAAA,EAAI,EAAG,EAAA,CAAA,EAAM,GAAY,CAAA,EACrC,EAAM,SAAS,CAAE,EAAG,EAAK,EAAG,EAAG,EAAK,EAAG,GAEzC,EAAS,WAAW,iBAAiB,cAAe,GAAe,CACjE,QAAS,EAAA,CACV,EACD,EAAS,WAAW,iBAAiB,cAAe,GAAe,CACjE,QAAS,EAAA,CACV,EACD,IAAI,EAAM,EACN,EAAgB,EAEpB,MAAM,GAAgB,IADJ,GAGZ,EAAW,GAAwB,CACvC,GAAI,GAAsB,CAAC,GAAc,QAAQ,QAAS,CACxD,EAAM,sBAAsB,CAAA,EAC5B,OAIF,MAAM,EAAU,EAAc,EAC9B,GAAI,EAAU,GAAe,CAC3B,EAAM,sBAAsB,CAAA,EAC5B,OAKF,GAHA,EAAgB,EAAe,EAAU,GAEzC,EAAS,MAAM,MAAQ,EAAa,EAAM,eAAA,EAAmB,EAAS,QAClE,EAAc,CAEhB,MAAM,EADY,EACY,SAAS,IAAI,OAAA,EACvC,IAAa,EAAY,MAAQ,EAAS,MAAM,OAElD,GACE,GAAO,EAAM,OAAA,EACjB,EAAS,OAAO,QAAS,GAAW,CAClC,MAAM,EAAO,EACT,EAAK,SACP,EAAK,QAAQ,QAAS,GAAsD,CAC1E,MAAM,GAAc,EAAI,UAAU,IAAI,OAAA,EAClC,KAAa,GAAY,MAAQ,EAAS,MAAM,WAI1D,EAAS,OAAA,GACJ,EAAS,OAAO,EAAO,CAAA,EAC9B,EAAM,sBAAsB,CAAA,GAE9B,EAAM,sBAAuB,GAAS,CACpC,EAAgB,EAChB,EAAQ,CAAA,IAEV,EAAS,QAAU,CACjB,SAAA,EACA,MAAA,EACA,OAAA,EACA,SAAA,EACA,MAAA,EACA,QAAS,EACT,SAAA,EACA,eAAgB,EAChB,IAAA,EACA,KAAA,EACA,WAAA,EACA,SAAA,EACA,MAAA,EACA,aAAA,OAEG,CACL,MAAM,EAAI,EAAS,QAcnB,GAbA,EAAE,SAAS,WAAW,MAAQ,GAAU,CAAA,GAAY,EACpD,EAAE,SAAS,WAAW,MAAQ,EAAY,EAAE,SAAS,cAAA,EACrD,EAAE,SAAS,OAAO,MAAM,IAAI,CAAA,EAC5B,EAAE,SAAS,OAAO,MAAQ,EAC1B,EAAE,SAAS,SAAS,MAAQ,EAC5B,EAAE,SAAS,aAAa,MAAQ,EAChC,EAAE,SAAS,eAAe,MAAQ,EAAgB,EAAI,EACtD,EAAE,SAAS,iBAAiB,MAAQ,EACpC,EAAE,SAAS,iBAAiB,MAAQ,EACpC,EAAE,SAAS,aAAa,MAAQ,EAChC,EAAE,SAAS,UAAU,MAAQ,EACzB,EAAa,EAAE,SAAS,cAAc,CAAA,EACrC,EAAE,SAAS,cAAc,EAAU,CAAA,EACpC,EAAE,aAAc,CAClB,MAAM,EAAY,EAAE,aACd,EAAY,EAAU,SAAS,IAAI,WAAA,EACrC,IAAW,EAAU,MAAQ,GACjC,MAAM,EAAQ,EAAU,SAAS,IAAI,OAAA,EACjC,IAAO,EAAM,MAAQ,GAEvB,EAAE,QAAO,EAAE,MAAM,YAAc,GAErC,OAAA,EAAc,QAAU,EACxB,IAAa,CAEX,GADI,EAAS,SAAW,GACpB,CAAC,EAAS,QAAS,OACvB,MAAM,EAAI,EAAS,QACnB,EAAE,gBAAgB,WAAA,EAClB,qBAAqB,EAAE,GAAA,EACvB,EAAE,MAAM,SAAS,QAAA,EACjB,EAAE,SAAS,QAAA,EACX,EAAE,UAAU,QAAA,EACZ,EAAE,SAAS,QAAA,EACP,EAAE,SAAS,WAAW,gBAAkB,GAAW,EAAU,YAAY,EAAE,SAAS,UAAA,EACxF,EAAS,QAAU,OAEpB,CACD,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACD,KAED,GAAA,KAAQ,MAAD,CAAK,IAAK,EAAc,UAAW,GAAG,GAAO,SAAA,IAAa,GAAa,EAAA,GAAa,MAAA,EAAO,aAAW,oCAAsC,IAIvJ,GAAW,YAAc,aAEzB,IAAM,MAAA,EAAA,MAAuE,GAAU,CACrF,KAAM,CAAE,aAAA,CAAA,EAAiB,GAAA,SAAA,EAuBzB,SAAA,GAAA,KACG,GAAD,CACS,SAAA,EAAA,SAAA,IAtBiB,CAC1B,MAAM,EAAU,EAAa,OAAO,UAAU,SAAW,UAgBzD,OAde,GAA0B,CACvC,GAAI,EAAM,WAAW,GAAA,EACnB,OAAO,EAET,MAAM,EAAQ,EAAM,MAAM,gCAAA,EAC1B,OAAI,EAIK,IAHG,SAAS,EAAM,CAAA,EAAI,EAAA,EAAI,SAAS,EAAA,EAAI,SAAS,EAAG,GAAA,CAAI,GACpD,SAAS,EAAM,CAAA,EAAI,EAAA,EAAI,SAAS,EAAA,EAAI,SAAS,EAAG,GAAA,CAAI,GACpD,SAAS,EAAM,CAAA,EAAI,EAAA,EAAI,SAAS,EAAA,EAAI,SAAS,EAAG,GAAA,CAAI,GAGzD,IAGI,CAAA,GACZ,CAAC,CAAA,CAAa,EAKb,QAAQ,SACR,UAAW,EACX,aAAc,EACd,eAAgB,EAChB,gBAAiB,EACjB,cAAA,GACA,YAAa,GACb,gBAAiB,IACjB,qBAAsB,IACtB,OAAQ,GACR,eAAgB,IAChB,aAAc,IACd,kBAAmB,EACnB,MAAO,GACP,SAAU,IACV,YAAA,GACA,UAAW,GACX,GAAI,EACJ,IAIN,GAAqB,YAAc"}
1
+ {"version":3,"file":"pixel-blast.cjs","names":[],"sources":["../src/designs/animations/PixelBlast/style.module.css","../src/designs/animations/PixelBlast/index.tsx"],"sourcesContent":[".container {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n}\n","// Component inspired by github.com/zavalit/bayer-dithering-webgl-demo\n\nimport React, { memo, useEffect, useMemo, useRef } from \"react\";\nimport { Effect, EffectComposer, EffectPass, RenderPass } from \"postprocessing\";\nimport {\n Clock,\n Color,\n GLSL3,\n LinearFilter,\n Mesh,\n OrthographicCamera,\n PlaneGeometry,\n Scene,\n ShaderMaterial,\n Texture,\n Uniform,\n Vector2,\n WebGLRenderer,\n} from \"three\";\n\nimport { useTheme } from \"@/themes/hooks/useTheme\";\n\nimport styles from \"./style.module.css\";\n\ntype PixelBlastVariant = \"square\" | \"circle\" | \"triangle\" | \"diamond\";\n\ninterface TouchPoint {\n x: number;\n y: number;\n vx: number;\n vy: number;\n force: number;\n age: number;\n}\n\ninterface TouchTexture {\n canvas: HTMLCanvasElement;\n texture: Texture;\n addTouch: (norm: { x: number; y: number }) => void;\n update: () => void;\n radiusScale: number;\n size: number;\n}\n\ninterface ReinitConfig {\n antialias: boolean;\n liquid: boolean;\n noiseAmount: number;\n}\n\ntype PixelBlastProps = {\n variant?: PixelBlastVariant;\n pixelSize?: number;\n color?: string;\n className?: string;\n style?: React.CSSProperties;\n antialias?: boolean;\n patternScale?: number;\n patternDensity?: number;\n liquid?: boolean;\n liquidStrength?: number;\n liquidRadius?: number;\n pixelSizeJitter?: number;\n enableRipples?: boolean;\n rippleIntensityScale?: number;\n rippleThickness?: number;\n rippleSpeed?: number;\n liquidWobbleSpeed?: number;\n autoPauseOffscreen?: boolean;\n speed?: number;\n transparent?: boolean;\n edgeFade?: number;\n noiseAmount?: number;\n};\n\nconst createTouchTexture = (): TouchTexture => {\n const size = 64;\n const canvas = document.createElement(\"canvas\");\n canvas.width = size;\n canvas.height = size;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new Error(\"2D context not available\");\n ctx.fillStyle = \"black\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n const texture = new Texture(canvas);\n texture.minFilter = LinearFilter;\n texture.magFilter = LinearFilter;\n texture.generateMipmaps = false;\n const trail: TouchPoint[] = [];\n let last: { x: number; y: number } | null = null;\n const maxAge = 64;\n let radius = 0.1 * size;\n const speed = 1 / maxAge;\n const clear = () => {\n ctx.fillStyle = \"black\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n };\n const drawPoint = (p: TouchPoint) => {\n const pos = { x: p.x * size, y: (1 - p.y) * size };\n let intensity = 1;\n const easeOutSine = (t: number) => Math.sin((t * Math.PI) / 2);\n const easeOutQuad = (t: number) => -t * (t - 2);\n if (p.age < maxAge * 0.3) intensity = easeOutSine(p.age / (maxAge * 0.3));\n else intensity = easeOutQuad(1 - (p.age - maxAge * 0.3) / (maxAge * 0.7)) || 0;\n intensity *= p.force;\n const color = `${((p.vx + 1) / 2) * 255}, ${((p.vy + 1) / 2) * 255}, ${intensity * 255}`;\n const offset = size * 5;\n ctx.shadowOffsetX = offset;\n ctx.shadowOffsetY = offset;\n ctx.shadowBlur = radius;\n ctx.shadowColor = `rgba(${color},${0.22 * intensity})`;\n ctx.beginPath();\n ctx.fillStyle = \"rgba(255,0,0,1)\";\n ctx.arc(pos.x - offset, pos.y - offset, radius, 0, Math.PI * 2);\n ctx.fill();\n };\n const addTouch = (norm: { x: number; y: number }) => {\n let force = 0;\n let vx = 0;\n let vy = 0;\n if (last) {\n const dx = norm.x - last.x;\n const dy = norm.y - last.y;\n if (dx === 0 && dy === 0) return;\n const dd = dx * dx + dy * dy;\n const d = Math.sqrt(dd);\n vx = dx / (d || 1);\n vy = dy / (d || 1);\n force = Math.min(dd * 10000, 1);\n }\n last = { x: norm.x, y: norm.y };\n trail.push({ x: norm.x, y: norm.y, age: 0, force, vx, vy });\n };\n const update = () => {\n clear();\n for (let i = trail.length - 1; i >= 0; i--) {\n const point = trail[i];\n const f = point.force * speed * (1 - point.age / maxAge);\n point.x += point.vx * f;\n point.y += point.vy * f;\n point.age++;\n if (point.age > maxAge) trail.splice(i, 1);\n }\n for (let i = 0; i < trail.length; i++) drawPoint(trail[i]);\n texture.needsUpdate = true;\n };\n return {\n canvas,\n texture,\n addTouch,\n update,\n set radiusScale(v: number) {\n radius = 0.1 * size * v;\n },\n get radiusScale() {\n return radius / (0.1 * size);\n },\n size,\n };\n};\n\nconst createLiquidEffect = (texture: Texture, opts?: { strength?: number; freq?: number }) => {\n const fragment = `\n uniform sampler2D uTexture;\n uniform float uStrength;\n uniform float uTime;\n uniform float uFreq;\n\n void mainUv(inout vec2 uv) {\n vec4 tex = texture2D(uTexture, uv);\n float vx = tex.r * 2.0 - 1.0;\n float vy = tex.g * 2.0 - 1.0;\n float intensity = tex.b;\n\n float wave = 0.5 + 0.5 * sin(uTime * uFreq + intensity * 6.2831853);\n\n float amt = uStrength * intensity * wave;\n\n uv += vec2(vx, vy) * amt;\n }\n `;\n return new Effect(\"LiquidEffect\", fragment, {\n uniforms: new Map<string, Uniform>([\n [\"uTexture\", new Uniform(texture)],\n [\"uStrength\", new Uniform(opts?.strength ?? 0.025)],\n [\"uTime\", new Uniform(0)],\n [\"uFreq\", new Uniform(opts?.freq ?? 4.5)],\n ]),\n });\n};\n\nconst SHAPE_MAP: Record<PixelBlastVariant, number> = {\n square: 0,\n circle: 1,\n triangle: 2,\n diamond: 3,\n};\n\nconst VERTEX_SRC = `\nvoid main() {\n gl_Position = vec4(position, 1.0);\n}\n`;\n\nconst FRAGMENT_SRC = `\nprecision highp float;\n\nuniform vec3 uColor;\nuniform vec2 uResolution;\nuniform float uTime;\nuniform float uPixelSize;\nuniform float uScale;\nuniform float uDensity;\nuniform float uPixelJitter;\nuniform int uEnableRipples;\nuniform float uRippleSpeed;\nuniform float uRippleThickness;\nuniform float uRippleIntensity;\nuniform float uEdgeFade;\n\nuniform int uShapeType;\nconst int SHAPE_SQUARE = 0;\nconst int SHAPE_CIRCLE = 1;\nconst int SHAPE_TRIANGLE = 2;\nconst int SHAPE_DIAMOND = 3;\n\nconst int MAX_CLICKS = 10;\n\nuniform vec2 uClickPos [MAX_CLICKS];\nuniform float uClickTimes[MAX_CLICKS];\n\nout vec4 fragColor;\n\nfloat Bayer2(vec2 a) {\n a = floor(a);\n return fract(a.x / 2. + a.y * a.y * .75);\n}\n#define Bayer4(a) (Bayer2(.5*(a))*0.25 + Bayer2(a))\n#define Bayer8(a) (Bayer4(.5*(a))*0.25 + Bayer2(a))\n\n#define FBM_OCTAVES 5\n#define FBM_LACUNARITY 1.25\n#define FBM_GAIN 1.0\n\nfloat hash11(float n){ return fract(sin(n)*43758.5453); }\n\nfloat vnoise(vec3 p){\n vec3 ip = floor(p);\n vec3 fp = fract(p);\n float n000 = hash11(dot(ip + vec3(0.0,0.0,0.0), vec3(1.0,57.0,113.0)));\n float n100 = hash11(dot(ip + vec3(1.0,0.0,0.0), vec3(1.0,57.0,113.0)));\n float n010 = hash11(dot(ip + vec3(0.0,1.0,0.0), vec3(1.0,57.0,113.0)));\n float n110 = hash11(dot(ip + vec3(1.0,1.0,0.0), vec3(1.0,57.0,113.0)));\n float n001 = hash11(dot(ip + vec3(0.0,0.0,1.0), vec3(1.0,57.0,113.0)));\n float n101 = hash11(dot(ip + vec3(1.0,0.0,1.0), vec3(1.0,57.0,113.0)));\n float n011 = hash11(dot(ip + vec3(0.0,1.0,1.0), vec3(1.0,57.0,113.0)));\n float n111 = hash11(dot(ip + vec3(1.0,1.0,1.0), vec3(1.0,57.0,113.0)));\n vec3 w = fp*fp*fp*(fp*(fp*6.0-15.0)+10.0);\n float x00 = mix(n000, n100, w.x);\n float x10 = mix(n010, n110, w.x);\n float x01 = mix(n001, n101, w.x);\n float x11 = mix(n011, n111, w.x);\n float y0 = mix(x00, x10, w.y);\n float y1 = mix(x01, x11, w.y);\n return mix(y0, y1, w.z) * 2.0 - 1.0;\n}\n\nfloat fbm2(vec2 uv, float t){\n vec3 p = vec3(uv * uScale, t);\n float amp = 1.0;\n float freq = 1.0;\n float sum = 1.0;\n for (int i = 0; i < FBM_OCTAVES; ++i){\n sum += amp * vnoise(p * freq);\n freq *= FBM_LACUNARITY;\n amp *= FBM_GAIN;\n }\n return sum * 0.5 + 0.5;\n}\n\nfloat maskCircle(vec2 p, float cov){\n float r = sqrt(cov) * .25;\n float d = length(p - 0.5) - r;\n float aa = 0.5 * fwidth(d);\n return cov * (1.0 - smoothstep(-aa, aa, d * 2.0));\n}\n\nfloat maskTriangle(vec2 p, vec2 id, float cov){\n bool flip = mod(id.x + id.y, 2.0) > 0.5;\n if (flip) p.x = 1.0 - p.x;\n float r = sqrt(cov);\n float d = p.y - r*(1.0 - p.x);\n float aa = fwidth(d);\n return cov * clamp(0.5 - d/aa, 0.0, 1.0);\n}\n\nfloat maskDiamond(vec2 p, float cov){\n float r = sqrt(cov) * 0.564;\n return step(abs(p.x - 0.49) + abs(p.y - 0.49), r);\n}\n\nvoid main(){\n float pixelSize = uPixelSize;\n vec2 fragCoord = gl_FragCoord.xy - uResolution * .5;\n float aspectRatio = uResolution.x / uResolution.y;\n\n vec2 pixelId = floor(fragCoord / pixelSize);\n vec2 pixelUV = fract(fragCoord / pixelSize);\n\n float cellPixelSize = 8.0 * pixelSize;\n vec2 cellId = floor(fragCoord / cellPixelSize);\n vec2 cellCoord = cellId * cellPixelSize;\n vec2 uv = cellCoord / uResolution * vec2(aspectRatio, 1.0);\n\n float base = fbm2(uv, uTime * 0.05);\n base = base * 0.5 - 0.65;\n\n float feed = base + (uDensity - 0.5) * 0.3;\n\n float speed = uRippleSpeed;\n float thickness = uRippleThickness;\n const float dampT = 1.0;\n const float dampR = 10.0;\n\n if (uEnableRipples == 1) {\n for (int i = 0; i < MAX_CLICKS; ++i){\n vec2 pos = uClickPos[i];\n if (pos.x < 0.0) continue;\n float cellPixelSize = 8.0 * pixelSize;\n vec2 cuv = (((pos - uResolution * .5 - cellPixelSize * .5) / (uResolution))) * vec2(aspectRatio, 1.0);\n float t = max(uTime - uClickTimes[i], 0.0);\n float r = distance(uv, cuv);\n float waveR = speed * t;\n float ring = exp(-pow((r - waveR) / thickness, 2.0));\n float atten = exp(-dampT * t) * exp(-dampR * r);\n feed = max(feed, ring * atten * uRippleIntensity);\n }\n }\n\n float bayer = Bayer8(fragCoord / uPixelSize) - 0.5;\n float bw = step(0.5, feed + bayer);\n\n float h = fract(sin(dot(floor(fragCoord / uPixelSize), vec2(127.1, 311.7))) * 43758.5453);\n float jitterScale = 1.0 + (h - 0.5) * uPixelJitter;\n float coverage = bw * jitterScale;\n float M;\n if (uShapeType == SHAPE_CIRCLE) M = maskCircle (pixelUV, coverage);\n else if (uShapeType == SHAPE_TRIANGLE) M = maskTriangle(pixelUV, pixelId, coverage);\n else if (uShapeType == SHAPE_DIAMOND) M = maskDiamond(pixelUV, coverage);\n else M = coverage;\n\n if (uEdgeFade > 0.0) {\n vec2 norm = gl_FragCoord.xy / uResolution;\n float edge = min(min(norm.x, norm.y), min(1.0 - norm.x, 1.0 - norm.y));\n float fade = smoothstep(0.0, uEdgeFade, edge);\n M *= fade;\n }\n\n vec3 color = uColor;\n\n // sRGB gamma correction - convert linear to sRGB for accurate color output\n vec3 srgbColor = mix(\n color * 12.92,\n 1.055 * pow(color, vec3(1.0 / 2.4)) - 0.055,\n step(0.0031308, color)\n );\n\n fragColor = vec4(srgbColor, M);\n}\n`;\n\nconst MAX_CLICKS = 10;\n\nconst PixelBlast: React.FC<PixelBlastProps> = memo(\n ({\n variant = \"square\",\n pixelSize = 3,\n color = \"#B19EEF\",\n className,\n style,\n antialias = true,\n patternScale = 2,\n patternDensity = 1,\n liquid = false,\n liquidStrength = 0.1,\n liquidRadius = 1,\n pixelSizeJitter = 0,\n enableRipples = true,\n rippleIntensityScale = 1,\n rippleThickness = 0.1,\n rippleSpeed = 0.3,\n liquidWobbleSpeed = 4.5,\n autoPauseOffscreen = true,\n speed = 0.5,\n transparent = true,\n edgeFade = 0.5,\n noiseAmount = 0,\n }) => {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const visibilityRef = useRef({ visible: true });\n const speedRef = useRef(speed);\n\n const threeRef = useRef<{\n renderer: WebGLRenderer;\n scene: Scene;\n camera: OrthographicCamera;\n material: ShaderMaterial;\n clock: Clock;\n clickIx: number;\n uniforms: {\n uResolution: { value: Vector2 };\n uTime: { value: number };\n uColor: { value: Color };\n uClickPos: { value: Vector2[] };\n uClickTimes: { value: Float32Array };\n uShapeType: { value: number };\n uPixelSize: { value: number };\n uScale: { value: number };\n uDensity: { value: number };\n uPixelJitter: { value: number };\n uEnableRipples: { value: number };\n uRippleSpeed: { value: number };\n uRippleThickness: { value: number };\n uRippleIntensity: { value: number };\n uEdgeFade: { value: number };\n };\n resizeObserver?: ResizeObserver;\n raf?: number;\n quad?: Mesh<PlaneGeometry, ShaderMaterial>;\n timeOffset?: number;\n composer?: EffectComposer;\n touch?: ReturnType<typeof createTouchTexture>;\n liquidEffect?: Effect;\n } | null>(null);\n const prevConfigRef = useRef<ReinitConfig | null>(null);\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n speedRef.current = speed;\n const needsReinitKeys: (keyof ReinitConfig)[] = [\"antialias\", \"liquid\", \"noiseAmount\"];\n const cfg: ReinitConfig = { antialias, liquid, noiseAmount };\n let mustReinit = false;\n if (!threeRef.current) mustReinit = true;\n else if (prevConfigRef.current) {\n for (const k of needsReinitKeys)\n if (prevConfigRef.current[k] !== cfg[k]) {\n mustReinit = true;\n break;\n }\n }\n if (mustReinit) {\n if (threeRef.current) {\n const t = threeRef.current;\n t.resizeObserver?.disconnect();\n cancelAnimationFrame(t.raf!);\n t.quad?.geometry.dispose();\n t.material.dispose();\n t.composer?.dispose();\n t.renderer.dispose();\n if (t.renderer.domElement.parentElement === container) container.removeChild(t.renderer.domElement);\n threeRef.current = null;\n }\n const canvas = document.createElement(\"canvas\");\n const renderer = new WebGLRenderer({\n canvas,\n antialias,\n alpha: true,\n powerPreference: \"high-performance\",\n });\n renderer.domElement.style.width = \"100%\";\n renderer.domElement.style.height = \"100%\";\n // 降低像素比以提高性能\n renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 1.5));\n container.appendChild(renderer.domElement);\n if (transparent) renderer.setClearAlpha(0);\n else renderer.setClearColor(0x000000, 1);\n const uniforms = {\n uResolution: { value: new Vector2(0, 0) },\n uTime: { value: 0 },\n uColor: { value: new Color(color) },\n uClickPos: {\n value: Array.from({ length: MAX_CLICKS }, () => new Vector2(-1, -1)),\n },\n uClickTimes: { value: new Float32Array(MAX_CLICKS) },\n uShapeType: { value: SHAPE_MAP[variant] ?? 0 },\n uPixelSize: { value: pixelSize * renderer.getPixelRatio() },\n uScale: { value: patternScale },\n uDensity: { value: patternDensity },\n uPixelJitter: { value: pixelSizeJitter },\n uEnableRipples: { value: enableRipples ? 1 : 0 },\n uRippleSpeed: { value: rippleSpeed },\n uRippleThickness: { value: rippleThickness },\n uRippleIntensity: { value: rippleIntensityScale },\n uEdgeFade: { value: edgeFade },\n };\n const scene = new Scene();\n const camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1);\n const material = new ShaderMaterial({\n vertexShader: VERTEX_SRC,\n fragmentShader: FRAGMENT_SRC,\n uniforms,\n transparent: true,\n depthTest: false,\n depthWrite: false,\n glslVersion: GLSL3,\n });\n\n const quadGeom = new PlaneGeometry(2, 2);\n const quad = new Mesh(quadGeom, material);\n scene.add(quad);\n const clock = new Clock();\n const setSize = () => {\n const w = container.clientWidth || 1;\n const h = container.clientHeight || 1;\n renderer.setSize(w, h, false);\n uniforms.uResolution.value.set(renderer.domElement.width, renderer.domElement.height);\n if (threeRef.current?.composer) threeRef.current.composer.setSize(renderer.domElement.width, renderer.domElement.height);\n uniforms.uPixelSize.value = pixelSize * renderer.getPixelRatio();\n };\n setSize();\n const ro = new ResizeObserver(setSize);\n ro.observe(container);\n const randomFloat = (): number => {\n if (typeof window !== \"undefined\" && window.crypto?.getRandomValues) {\n const u32 = new Uint32Array(1);\n window.crypto.getRandomValues(u32);\n return u32[0] / 0xffffffff;\n }\n return Math.random();\n };\n const timeOffset = randomFloat() * 1000;\n let composer: EffectComposer | undefined;\n let touch: ReturnType<typeof createTouchTexture> | undefined;\n let liquidEffect: Effect | undefined;\n if (liquid) {\n touch = createTouchTexture();\n touch.radiusScale = liquidRadius;\n composer = new EffectComposer(renderer);\n const renderPass = new RenderPass(scene, camera);\n liquidEffect = createLiquidEffect(touch.texture, {\n strength: liquidStrength,\n freq: liquidWobbleSpeed,\n });\n const effectPass = new EffectPass(camera, liquidEffect);\n effectPass.renderToScreen = true;\n composer.addPass(renderPass);\n composer.addPass(effectPass);\n }\n if (noiseAmount > 0) {\n if (!composer) {\n composer = new EffectComposer(renderer);\n composer.addPass(new RenderPass(scene, camera));\n }\n const noiseEffect = new Effect(\n \"NoiseEffect\",\n `uniform float uTime; uniform float uAmount; float hash(vec2 p){ return fract(sin(dot(p, vec2(127.1,311.7))) * 43758.5453);} void mainUv(inout vec2 uv){} void mainImage(const in vec4 inputColor,const in vec2 uv,out vec4 outputColor){ float n=hash(floor(uv*vec2(1920.0,1080.0))+floor(uTime*60.0)); float g=(n-0.5)*uAmount; outputColor=inputColor+vec4(vec3(g),0.0);} `,\n {\n uniforms: new Map<string, Uniform>([\n [\"uTime\", new Uniform(0)],\n [\"uAmount\", new Uniform(noiseAmount)],\n ]),\n },\n );\n const noisePass = new EffectPass(camera, noiseEffect);\n noisePass.renderToScreen = true;\n if (composer && composer.passes.length > 0) {\n composer.passes.forEach((p: { renderToScreen?: boolean }) => {\n const pass = p as { renderToScreen?: boolean };\n pass.renderToScreen = false;\n });\n }\n composer.addPass(noisePass);\n }\n if (composer) composer.setSize(renderer.domElement.width, renderer.domElement.height);\n const mapToPixels = (e: PointerEvent) => {\n const rect = renderer.domElement.getBoundingClientRect();\n const scaleX = renderer.domElement.width / rect.width;\n const scaleY = renderer.domElement.height / rect.height;\n const fx = (e.clientX - rect.left) * scaleX;\n const fy = (rect.height - (e.clientY - rect.top)) * scaleY;\n return {\n fx,\n fy,\n w: renderer.domElement.width,\n h: renderer.domElement.height,\n };\n };\n const onPointerDown = (e: PointerEvent) => {\n const { fx, fy } = mapToPixels(e);\n const ix = threeRef.current?.clickIx ?? 0;\n uniforms.uClickPos.value[ix].set(fx, fy);\n uniforms.uClickTimes.value[ix] = uniforms.uTime.value;\n if (threeRef.current) threeRef.current.clickIx = (ix + 1) % MAX_CLICKS;\n };\n const onPointerMove = (e: PointerEvent) => {\n if (!touch) return;\n const { fx, fy, w, h } = mapToPixels(e);\n touch.addTouch({ x: fx / w, y: fy / h });\n };\n renderer.domElement.addEventListener(\"pointerdown\", onPointerDown, {\n passive: true,\n });\n renderer.domElement.addEventListener(\"pointermove\", onPointerMove, {\n passive: true,\n });\n let raf = 0;\n let lastFrameTime = 0;\n const targetFPS = 30; // 限制到 30 FPS 以提高性能\n const frameInterval = 1000 / targetFPS;\n\n const animate = (currentTime: number) => {\n if (autoPauseOffscreen && !visibilityRef.current.visible) {\n raf = requestAnimationFrame(animate);\n return;\n }\n\n // 帧率限制\n const elapsed = currentTime - lastFrameTime;\n if (elapsed < frameInterval) {\n raf = requestAnimationFrame(animate);\n return;\n }\n lastFrameTime = currentTime - (elapsed % frameInterval);\n\n uniforms.uTime.value = timeOffset + clock.getElapsedTime() * speedRef.current;\n if (liquidEffect) {\n const liqEffect = liquidEffect as Effect & { uniforms: Map<string, Uniform> };\n const timeUniform = liqEffect.uniforms.get(\"uTime\");\n if (timeUniform) timeUniform.value = uniforms.uTime.value;\n }\n if (composer) {\n if (touch) touch.update();\n composer.passes.forEach((p: any) => {\n const pass = p as { effects?: Array<Effect & { uniforms?: Map<string, Uniform> }> };\n if (pass.effects) {\n pass.effects.forEach((eff: Effect & { uniforms?: Map<string, Uniform> }) => {\n const timeUniform = eff.uniforms?.get(\"uTime\");\n if (timeUniform) timeUniform.value = uniforms.uTime.value;\n });\n }\n });\n composer.render();\n } else renderer.render(scene, camera);\n raf = requestAnimationFrame(animate);\n };\n raf = requestAnimationFrame((time) => {\n lastFrameTime = time;\n animate(time);\n });\n threeRef.current = {\n renderer,\n scene,\n camera,\n material,\n clock,\n clickIx: 0,\n uniforms,\n resizeObserver: ro,\n raf,\n quad,\n timeOffset,\n composer,\n touch,\n liquidEffect,\n };\n } else {\n const t = threeRef.current!;\n t.uniforms.uShapeType.value = SHAPE_MAP[variant] ?? 0;\n t.uniforms.uPixelSize.value = pixelSize * t.renderer.getPixelRatio();\n t.uniforms.uColor.value.set(color);\n t.uniforms.uScale.value = patternScale;\n t.uniforms.uDensity.value = patternDensity;\n t.uniforms.uPixelJitter.value = pixelSizeJitter;\n t.uniforms.uEnableRipples.value = enableRipples ? 1 : 0;\n t.uniforms.uRippleIntensity.value = rippleIntensityScale;\n t.uniforms.uRippleThickness.value = rippleThickness;\n t.uniforms.uRippleSpeed.value = rippleSpeed;\n t.uniforms.uEdgeFade.value = edgeFade;\n if (transparent) t.renderer.setClearAlpha(0);\n else t.renderer.setClearColor(0x000000, 1);\n if (t.liquidEffect) {\n const liqEffect = t.liquidEffect as Effect & { uniforms: Map<string, Uniform> };\n const uStrength = liqEffect.uniforms.get(\"uStrength\");\n if (uStrength) uStrength.value = liquidStrength;\n const uFreq = liqEffect.uniforms.get(\"uFreq\");\n if (uFreq) uFreq.value = liquidWobbleSpeed;\n }\n if (t.touch) t.touch.radiusScale = liquidRadius;\n }\n prevConfigRef.current = cfg;\n return () => {\n if (threeRef.current && mustReinit) return;\n if (!threeRef.current) return;\n const t = threeRef.current;\n t.resizeObserver?.disconnect();\n cancelAnimationFrame(t.raf!);\n t.quad?.geometry.dispose();\n t.material.dispose();\n t.composer?.dispose();\n t.renderer.dispose();\n if (t.renderer.domElement.parentElement === container) container.removeChild(t.renderer.domElement);\n threeRef.current = null;\n };\n }, [\n antialias,\n liquid,\n noiseAmount,\n pixelSize,\n patternScale,\n patternDensity,\n enableRipples,\n rippleIntensityScale,\n rippleThickness,\n rippleSpeed,\n pixelSizeJitter,\n edgeFade,\n transparent,\n liquidStrength,\n liquidRadius,\n liquidWobbleSpeed,\n autoPauseOffscreen,\n variant,\n color,\n speed,\n ]);\n\n return <div ref={containerRef} className={`${styles.container} ${className ?? \"\"}`} style={style} aria-label=\"PixelBlast interactive background\" />;\n },\n);\n\nPixelBlast.displayName = \"PixelBlast\";\n\nconst PixelBlastBackground: React.FC<Omit<PixelBlastProps, \"color\">> = memo((props) => {\n const { currentTheme } = useTheme();\n\n // 从主题中获取颜色\n const color = useMemo(() => {\n const primary = currentTheme.colors.variables.primary || \"#B19EEF\";\n\n const toHex = (color: string): string => {\n if (color.startsWith(\"#\")) {\n return color;\n }\n const match = color.match(/rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)/);\n if (match) {\n const r = parseInt(match[1], 10).toString(16).padStart(2, \"0\");\n const g = parseInt(match[2], 10).toString(16).padStart(2, \"0\");\n const b = parseInt(match[3], 10).toString(16).padStart(2, \"0\");\n return `#${r}${g}${b}`;\n }\n return color;\n };\n\n return toHex(primary);\n }, [currentTheme]);\n\n return (\n <PixelBlast\n color={color}\n variant=\"square\"\n pixelSize={6}\n patternScale={2}\n patternDensity={1}\n pixelSizeJitter={0}\n enableRipples\n rippleSpeed={0.3}\n rippleThickness={0.12}\n rippleIntensityScale={1.2}\n liquid={false}\n liquidStrength={0.12}\n liquidRadius={1.2}\n liquidWobbleSpeed={5}\n speed={0.3}\n edgeFade={0.25}\n transparent\n antialias={false}\n {...props}\n />\n );\n});\n\nPixelBlastBackground.displayName = \"PixelBlastBackground\";\n\nexport default PixelBlastBackground;\n"],"mappings":"gRC2EM,GAAA,IAAyC,CAE7C,MAAM,EAAS,SAAS,cAAc,QAAA,EACtC,EAAO,MAAQ,GACf,EAAO,OAAS,GAChB,MAAM,EAAM,EAAO,WAAW,IAAA,EAC9B,GAAI,CAAC,EAAK,MAAM,IAAI,MAAM,0BAAA,EAC1B,EAAI,UAAY,QAChB,EAAI,SAAS,EAAG,EAAG,EAAO,MAAO,EAAO,MAAA,EACxC,MAAM,EAAU,IAAI,EAAA,QAAQ,CAAA,EAC5B,EAAQ,UAAY,EAAA,aACpB,EAAQ,UAAY,EAAA,aACpB,EAAQ,gBAAkB,GAC1B,MAAM,EAAsB,CAAA,EAC5B,IAAI,EAAwC,KAC5C,MAAM,EAAS,GACf,IAAI,EAAS,GAAM,GACnB,MAAM,EAAQ,EAAI,EACZ,EAAA,IAAc,CAClB,EAAI,UAAY,QAChB,EAAI,SAAS,EAAG,EAAG,EAAO,MAAO,EAAO,MAAA,GAEpC,EAAa,GAAkB,CACnC,MAAM,EAAM,CAAE,EAAG,EAAE,EAAI,GAAM,GAAI,EAAI,EAAE,GAAK,IAC5C,IAAI,EAAY,EAChB,MAAM,EAAe,GAAc,KAAK,IAAK,EAAI,KAAK,GAAM,CAAA,EACtD,EAAe,GAAc,CAAC,GAAK,EAAI,GACzC,EAAE,IAAM,EAAS,GAAK,EAAY,EAAY,EAAE,KAAO,EAAS,GAAA,EAC/D,EAAY,EAAY,GAAK,EAAE,IAAM,EAAS,KAAQ,EAAS,GAAA,GAAS,EAC7E,GAAa,EAAE,MACf,MAAM,EAAQ,IAAK,EAAE,GAAK,GAAK,EAAK,GAAA,MAAU,EAAE,GAAK,GAAK,EAAK,GAAA,KAAQ,EAAY,GAAA,GAC7E,EAAS,IACf,EAAI,cAAgB,EACpB,EAAI,cAAgB,EACpB,EAAI,WAAa,EACjB,EAAI,YAAc,QAAQ,CAAA,IAAS,IAAO,CAAA,IAC1C,EAAI,UAAA,EACJ,EAAI,UAAY,kBAChB,EAAI,IAAI,EAAI,EAAI,EAAQ,EAAI,EAAI,EAAQ,EAAQ,EAAG,KAAK,GAAK,CAAA,EAC7D,EAAI,KAAA,GAgCN,MAAO,CACL,OAAA,EACA,QAAA,EACA,SAjCgB,GAAmC,CACnD,IAAI,EAAQ,EACR,EAAK,EACL,EAAK,EACT,GAAI,EAAM,CACR,MAAM,EAAK,EAAK,EAAI,EAAK,EACnB,EAAK,EAAK,EAAI,EAAK,EACzB,GAAI,IAAO,GAAK,IAAO,EAAG,OAC1B,MAAM,EAAK,EAAK,EAAK,EAAK,EACpB,EAAI,KAAK,KAAK,CAAA,EACpB,EAAK,GAAM,GAAK,GAChB,EAAK,GAAM,GAAK,GAChB,EAAQ,KAAK,IAAI,EAAK,IAAO,CAAA,EAE/B,EAAO,CAAE,EAAG,EAAK,EAAG,EAAG,EAAK,GAC5B,EAAM,KAAK,CAAE,EAAG,EAAK,EAAG,EAAG,EAAK,EAAG,IAAK,EAAG,MAAA,EAAO,GAAA,EAAI,GAAA,EAAI,GAmB1D,OAjBI,IAAe,CACnB,EAAA,EACA,QAAS,EAAI,EAAM,OAAS,EAAG,GAAK,EAAG,IAAK,CAC1C,MAAM,EAAQ,EAAM,CAAA,EACd,EAAI,EAAM,MAAQ,GAAS,EAAI,EAAM,IAAM,GACjD,EAAM,GAAK,EAAM,GAAK,EACtB,EAAM,GAAK,EAAM,GAAK,EACtB,EAAM,MACF,EAAM,IAAM,GAAQ,EAAM,OAAO,EAAG,CAAA,EAE1C,QAAS,EAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,EAAU,EAAM,CAAA,CAAA,EACvD,EAAQ,YAAc,IAOtB,IAAI,YAAY,EAAW,CACzB,EAAS,GAAM,GAAO,GAExB,IAAI,aAAc,CAChB,OAAO,GAAU,GAAM,KAEzB,UAIE,GAAA,CAAsB,EAAkB,IAoBrC,IAAI,EAAA,OAAO,eAnBD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAmB2B,CAC1C,SAAU,IAAI,IAAqB,CACjC,CAAC,WAAY,IAAI,EAAA,QAAQ,CAAA,CAAQ,EACjC,CAAC,YAAa,IAAI,EAAA,QAAQ,GAAM,UAAY,IAAA,CAAM,EAClD,CAAC,QAAS,IAAI,EAAA,QAAQ,CAAA,CAAE,EACxB,CAAC,QAAS,IAAI,EAAA,QAAQ,GAAM,MAAQ,GAAA,CAAI,EACzC,CAAC,CACH,EAGG,GAA+C,CACnD,OAAQ,EACR,OAAQ,EACR,SAAU,EACV,QAAS,GAGL,GAAa;AAAA;AAAA;AAAA;AAAA,EAMb,GAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuKf,EAAa,GAEb,MAAA,EAAA,MAAA,CACH,CACC,QAAA,EAAU,SACV,UAAA,EAAY,EACZ,MAAA,EAAQ,UACR,UAAA,EACA,MAAA,EACA,UAAA,EAAY,GACZ,aAAA,EAAe,EACf,eAAA,EAAiB,EACjB,OAAA,EAAS,GACT,eAAA,EAAiB,GACjB,aAAA,EAAe,EACf,gBAAA,EAAkB,EAClB,cAAA,EAAgB,GAChB,qBAAA,EAAuB,EACvB,gBAAA,EAAkB,GAClB,YAAA,EAAc,GACd,kBAAA,EAAoB,IACpB,mBAAA,EAAqB,GACrB,MAAA,EAAQ,GACR,YAAA,EAAc,GACd,SAAA,EAAW,GACX,YAAA,EAAc,CAAA,IACV,CACJ,MAAM,KAAA,EAAA,QAA6C,IAAA,EAC7C,MAAA,EAAA,QAAuB,CAAE,QAAS,EAAA,CAAM,EACxC,KAAA,EAAA,QAAkB,CAAA,EAElB,KAAA,EAAA,QA+BI,IAAA,EACJ,KAAA,EAAA,QAA4C,IAAA,EAClD,SAAA,EAAA,WAAA,IAAgB,CACd,MAAM,EAAY,EAAa,QAC/B,GAAI,CAAC,EAAW,OAChB,EAAS,QAAU,EACnB,MAAM,GAA0C,CAAC,YAAa,SAAU,eAClE,EAAoB,CAAE,UAAA,EAAW,OAAA,EAAQ,YAAA,GAC/C,IAAI,EAAa,GACjB,GAAI,CAAC,EAAS,QAAS,EAAa,WAC3B,EAAc,mBACV,KAAK,GACd,GAAI,EAAc,QAAQ,CAAA,IAAO,EAAI,CAAA,EAAI,CACvC,EAAa,GACb,OAGN,GAAI,EAAY,CACd,GAAI,EAAS,QAAS,CACpB,MAAM,EAAI,EAAS,QACnB,EAAE,gBAAgB,WAAA,EAClB,qBAAqB,EAAE,GAAA,EACvB,EAAE,MAAM,SAAS,QAAA,EACjB,EAAE,SAAS,QAAA,EACX,EAAE,UAAU,QAAA,EACZ,EAAE,SAAS,QAAA,EACP,EAAE,SAAS,WAAW,gBAAkB,GAAW,EAAU,YAAY,EAAE,SAAS,UAAA,EACxF,EAAS,QAAU,KAGrB,MAAM,EAAW,IAAI,EAAA,cAAc,CACjC,OAFa,SAAS,cAAc,QAAA,EAGpC,UAAA,EACA,MAAO,GACP,gBAAiB,mBAClB,EACD,EAAS,WAAW,MAAM,MAAQ,OAClC,EAAS,WAAW,MAAM,OAAS,OAEnC,EAAS,cAAc,KAAK,IAAI,OAAO,kBAAoB,EAAG,GAAA,CAAI,EAClE,EAAU,YAAY,EAAS,UAAA,EAC3B,EAAa,EAAS,cAAc,CAAA,EACnC,EAAS,cAAc,EAAU,CAAA,EACtC,MAAM,EAAW,CACf,YAAa,CAAE,MAAO,IAAI,EAAA,QAAQ,EAAG,CAAA,CAAE,EACvC,MAAO,CAAE,MAAO,CAAA,EAChB,OAAQ,CAAE,MAAO,IAAI,EAAA,MAAM,CAAA,CAAM,EACjC,UAAW,CACT,MAAO,MAAM,KAAK,CAAE,OAAQ,CAAA,EAAY,IAAQ,IAAI,EAAA,QAAQ,GAAI,EAAA,CAAG,CAAC,EAEtE,YAAa,CAAE,MAAO,IAAI,aAAa,CAAA,CAAW,EAClD,WAAY,CAAE,MAAO,GAAU,CAAA,GAAY,CAAA,EAC3C,WAAY,CAAE,MAAO,EAAY,EAAS,cAAA,CAAe,EACzD,OAAQ,CAAE,MAAO,CAAA,EACjB,SAAU,CAAE,MAAO,CAAA,EACnB,aAAc,CAAE,MAAO,CAAA,EACvB,eAAgB,CAAE,MAAO,EAAgB,EAAI,CAAA,EAC7C,aAAc,CAAE,MAAO,CAAA,EACvB,iBAAkB,CAAE,MAAO,CAAA,EAC3B,iBAAkB,CAAE,MAAO,CAAA,EAC3B,UAAW,CAAE,MAAO,CAAA,GAEhB,EAAQ,IAAI,EAAA,MACZ,EAAS,IAAI,EAAA,mBAAmB,GAAI,EAAG,EAAG,GAAI,EAAG,CAAA,EACjD,EAAW,IAAI,EAAA,eAAe,CAClC,aAAc,GACd,eAAgB,GAChB,SAAA,EACA,YAAa,GACb,UAAW,GACX,WAAY,GACZ,YAAa,EAAA,MACd,EAGK,EAAO,IAAI,EAAA,KADA,IAAI,EAAA,cAAc,EAAG,CAAA,EACN,CAAA,EAChC,EAAM,IAAI,CAAA,EACV,MAAM,EAAQ,IAAI,EAAA,MACZ,EAAA,IAAgB,CACpB,MAAM,EAAI,EAAU,aAAe,EAC7B,EAAI,EAAU,cAAgB,EACpC,EAAS,QAAQ,EAAG,EAAG,EAAA,EACvB,EAAS,YAAY,MAAM,IAAI,EAAS,WAAW,MAAO,EAAS,WAAW,MAAA,EAC1E,EAAS,SAAS,UAAU,EAAS,QAAQ,SAAS,QAAQ,EAAS,WAAW,MAAO,EAAS,WAAW,MAAA,EACjH,EAAS,WAAW,MAAQ,EAAY,EAAS,cAAA,GAEnD,EAAA,EACA,MAAM,EAAK,IAAI,eAAe,CAAA,EAC9B,EAAG,QAAQ,CAAA,EASX,MAAM,GARA,IAA4B,CAChC,GAAI,OAAO,OAAW,KAAe,OAAO,QAAQ,gBAAiB,CACnE,MAAM,EAAM,IAAI,YAAY,CAAA,EAC5B,cAAO,OAAO,gBAAgB,CAAA,EACvB,EAAI,CAAA,EAAK,WAElB,OAAO,KAAK,OAAA,IAEK,EAAgB,IACnC,IAAI,EACA,EACA,EACJ,GAAI,EAAQ,CACV,EAAQ,GAAA,EACR,EAAM,YAAc,EACpB,EAAW,IAAI,EAAA,eAAe,CAAA,EAC9B,MAAM,EAAa,IAAI,EAAA,WAAW,EAAO,CAAA,EACzC,EAAe,GAAmB,EAAM,QAAS,CAC/C,SAAU,EACV,KAAM,EACP,EACD,MAAM,EAAa,IAAI,EAAA,WAAW,EAAQ,CAAA,EAC1C,EAAW,eAAiB,GAC5B,EAAS,QAAQ,CAAA,EACjB,EAAS,QAAQ,CAAA,EAEnB,GAAI,EAAc,EAAG,CACd,IACH,EAAW,IAAI,EAAA,eAAe,CAAA,EAC9B,EAAS,QAAQ,IAAI,EAAA,WAAW,EAAO,CAAA,CAAO,GAYhD,MAAM,EAAY,IAAI,EAAA,WAAW,EAVb,IAAI,EAAA,OACtB,cACA,+WACA,CACE,SAAU,IAAI,IAAqB,CACjC,CAAC,QAAS,IAAI,EAAA,QAAQ,CAAA,CAAE,EACxB,CAAC,UAAW,IAAI,EAAA,QAAQ,CAAA,CAAY,CAAC,CACtC,CAAC,CACH,CACF,EAED,EAAU,eAAiB,GACvB,GAAY,EAAS,OAAO,OAAS,GACvC,EAAS,OAAO,QAAS,GAAoC,CAC3D,MAAM,EAAO,EACb,EAAK,eAAiB,KAG1B,EAAS,QAAQ,CAAA,EAEf,GAAU,EAAS,QAAQ,EAAS,WAAW,MAAO,EAAS,WAAW,MAAA,EAC9E,MAAM,GAAe,GAAoB,CACvC,MAAM,EAAO,EAAS,WAAW,sBAAA,EAC3B,EAAS,EAAS,WAAW,MAAQ,EAAK,MAC1C,EAAS,EAAS,WAAW,OAAS,EAAK,OAGjD,MAAO,CACL,IAHU,EAAE,QAAU,EAAK,MAAQ,EAInC,IAHU,EAAK,QAAU,EAAE,QAAU,EAAK,MAAQ,EAIlD,EAAG,EAAS,WAAW,MACvB,EAAG,EAAS,WAAW,SAGrB,GAAiB,GAAoB,CACzC,KAAM,CAAE,GAAA,EAAI,GAAA,CAAA,EAAO,GAAY,CAAA,EACzB,EAAK,EAAS,SAAS,SAAW,EACxC,EAAS,UAAU,MAAM,CAAA,EAAI,IAAI,EAAI,CAAA,EACrC,EAAS,YAAY,MAAM,CAAA,EAAM,EAAS,MAAM,MAC5C,EAAS,UAAS,EAAS,QAAQ,SAAW,EAAK,GAAK,IAExD,GAAiB,GAAoB,CACzC,GAAI,CAAC,EAAO,OACZ,KAAM,CAAE,GAAA,EAAI,GAAA,EAAI,EAAG,EAAA,CAAA,EAAM,GAAY,CAAA,EACrC,EAAM,SAAS,CAAE,EAAG,EAAK,EAAG,EAAG,EAAK,EAAG,GAEzC,EAAS,WAAW,iBAAiB,cAAe,GAAe,CACjE,QAAS,EAAA,CACV,EACD,EAAS,WAAW,iBAAiB,cAAe,GAAe,CACjE,QAAS,EAAA,CACV,EACD,IAAI,EAAM,EACN,EAAgB,EAEpB,MAAM,GAAgB,IADJ,GAGZ,EAAW,GAAwB,CACvC,GAAI,GAAsB,CAAC,GAAc,QAAQ,QAAS,CACxD,EAAM,sBAAsB,CAAA,EAC5B,OAIF,MAAM,EAAU,EAAc,EAC9B,GAAI,EAAU,GAAe,CAC3B,EAAM,sBAAsB,CAAA,EAC5B,OAKF,GAHA,EAAgB,EAAe,EAAU,GAEzC,EAAS,MAAM,MAAQ,EAAa,EAAM,eAAA,EAAmB,EAAS,QAClE,EAAc,CAEhB,MAAM,EADY,EACY,SAAS,IAAI,OAAA,EACvC,IAAa,EAAY,MAAQ,EAAS,MAAM,OAElD,GACE,GAAO,EAAM,OAAA,EACjB,EAAS,OAAO,QAAS,GAAW,CAClC,MAAM,EAAO,EACT,EAAK,SACP,EAAK,QAAQ,QAAS,GAAsD,CAC1E,MAAM,GAAc,EAAI,UAAU,IAAI,OAAA,EAClC,KAAa,GAAY,MAAQ,EAAS,MAAM,WAI1D,EAAS,OAAA,GACJ,EAAS,OAAO,EAAO,CAAA,EAC9B,EAAM,sBAAsB,CAAA,GAE9B,EAAM,sBAAuB,GAAS,CACpC,EAAgB,EAChB,EAAQ,CAAA,IAEV,EAAS,QAAU,CACjB,SAAA,EACA,MAAA,EACA,OAAA,EACA,SAAA,EACA,MAAA,EACA,QAAS,EACT,SAAA,EACA,eAAgB,EAChB,IAAA,EACA,KAAA,EACA,WAAA,EACA,SAAA,EACA,MAAA,EACA,aAAA,OAEG,CACL,MAAM,EAAI,EAAS,QAcnB,GAbA,EAAE,SAAS,WAAW,MAAQ,GAAU,CAAA,GAAY,EACpD,EAAE,SAAS,WAAW,MAAQ,EAAY,EAAE,SAAS,cAAA,EACrD,EAAE,SAAS,OAAO,MAAM,IAAI,CAAA,EAC5B,EAAE,SAAS,OAAO,MAAQ,EAC1B,EAAE,SAAS,SAAS,MAAQ,EAC5B,EAAE,SAAS,aAAa,MAAQ,EAChC,EAAE,SAAS,eAAe,MAAQ,EAAgB,EAAI,EACtD,EAAE,SAAS,iBAAiB,MAAQ,EACpC,EAAE,SAAS,iBAAiB,MAAQ,EACpC,EAAE,SAAS,aAAa,MAAQ,EAChC,EAAE,SAAS,UAAU,MAAQ,EACzB,EAAa,EAAE,SAAS,cAAc,CAAA,EACrC,EAAE,SAAS,cAAc,EAAU,CAAA,EACpC,EAAE,aAAc,CAClB,MAAM,EAAY,EAAE,aACd,EAAY,EAAU,SAAS,IAAI,WAAA,EACrC,IAAW,EAAU,MAAQ,GACjC,MAAM,EAAQ,EAAU,SAAS,IAAI,OAAA,EACjC,IAAO,EAAM,MAAQ,GAEvB,EAAE,QAAO,EAAE,MAAM,YAAc,GAErC,OAAA,EAAc,QAAU,EACxB,IAAa,CAEX,GADI,EAAS,SAAW,GACpB,CAAC,EAAS,QAAS,OACvB,MAAM,EAAI,EAAS,QACnB,EAAE,gBAAgB,WAAA,EAClB,qBAAqB,EAAE,GAAA,EACvB,EAAE,MAAM,SAAS,QAAA,EACjB,EAAE,SAAS,QAAA,EACX,EAAE,UAAU,QAAA,EACZ,EAAE,SAAS,QAAA,EACP,EAAE,SAAS,WAAW,gBAAkB,GAAW,EAAU,YAAY,EAAE,SAAS,UAAA,EACxF,EAAS,QAAU,OAEpB,CACD,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EACD,KAEM,GAAA,KAAC,MAAD,CAAK,IAAK,EAAc,UAAW,GAAG,GAAO,SAAA,IAAa,GAAa,EAAA,GAAa,MAAA,EAAO,aAAW,oCAAsC,IAIvJ,GAAW,YAAc,aAEzB,IAAM,MAAA,EAAA,MAAuE,GAAU,CACrF,KAAM,CAAE,aAAA,CAAA,EAAiB,GAAA,SAAA,EAuBzB,SACE,GAAA,KAAC,GAAD,CACS,SAAA,EAAA,SAAA,IAtBiB,CAC1B,MAAM,EAAU,EAAa,OAAO,UAAU,SAAW,UAgBzD,OAde,GAA0B,CACvC,GAAI,EAAM,WAAW,GAAA,EACnB,OAAO,EAET,MAAM,EAAQ,EAAM,MAAM,gCAAA,EAC1B,OAAI,EAIK,IAHG,SAAS,EAAM,CAAA,EAAI,EAAA,EAAI,SAAS,EAAA,EAAI,SAAS,EAAG,GAAA,CAAI,GACpD,SAAS,EAAM,CAAA,EAAI,EAAA,EAAI,SAAS,EAAA,EAAI,SAAS,EAAG,GAAA,CAAI,GACpD,SAAS,EAAM,CAAA,EAAI,EAAA,EAAI,SAAS,EAAA,EAAI,SAAS,EAAG,GAAA,CAAI,GAGzD,IAGI,CAAA,GACZ,CAAC,CAAA,CAAa,EAKb,QAAQ,SACR,UAAW,EACX,aAAc,EACd,eAAgB,EAChB,gBAAiB,EACjB,cAAA,GACA,YAAa,GACb,gBAAiB,IACjB,qBAAsB,IACtB,OAAQ,GACR,eAAgB,IAChB,aAAc,IACd,kBAAmB,EACnB,MAAO,GACP,SAAU,IACV,YAAA,GACA,UAAW,GACX,GAAI,EACJ,IAIN,GAAqB,YAAc"}
@@ -1,33 +1 @@
1
- import { default as default_2 } from 'react';
2
-
3
- declare const PixelBlastBackground: default_2.FC<Omit<PixelBlastProps, "color">>;
4
- export default PixelBlastBackground;
5
-
6
- declare type PixelBlastProps = {
7
- variant?: PixelBlastVariant;
8
- pixelSize?: number;
9
- color?: string;
10
- className?: string;
11
- style?: default_2.CSSProperties;
12
- antialias?: boolean;
13
- patternScale?: number;
14
- patternDensity?: number;
15
- liquid?: boolean;
16
- liquidStrength?: number;
17
- liquidRadius?: number;
18
- pixelSizeJitter?: number;
19
- enableRipples?: boolean;
20
- rippleIntensityScale?: number;
21
- rippleThickness?: number;
22
- rippleSpeed?: number;
23
- liquidWobbleSpeed?: number;
24
- autoPauseOffscreen?: boolean;
25
- speed?: number;
26
- transparent?: boolean;
27
- edgeFade?: number;
28
- noiseAmount?: number;
29
- };
30
-
31
- declare type PixelBlastVariant = "square" | "circle" | "triangle" | "diamond";
32
-
33
1
  export { }
@@ -1,96 +1 @@
1
- /**
2
- * 数组类型。Array type.
3
- * @example Array<string> => string[]
4
- */
5
- declare type Array_2<T> = T[];
6
-
7
- /** 基础主题枚举(平台/圆角等,如 iOS 24 / Android|Windows 6 / Linux 4) */
8
- declare enum BaseEnum {
9
- DEFAULT = "default",
10
- IOS = "ios",
11
- ANDROID = "android",
12
- WINDOWS = "windows",
13
- LINUX = "linux"
14
- }
15
-
16
- /** 仪表盘背景可选值列表。Dashboard background values list. */
17
- export declare const DASHBOARD_BACKGROUND_VALUES: Array_2<DashboardBackgroundEnum>;
18
-
19
- /** 仪表盘背景枚举。Dashboard background enum. */
20
- export declare enum DashboardBackgroundEnum {
21
- NONE = "none",
22
- WAVES = "waves",
23
- SQUARES = "squares",
24
- LETTER_GLITCH = "letterGlitch",
25
- PIXEL_BLAST = "pixelBlast"
26
- }
27
-
28
- export declare const DEFAULT_DASHBOARD_BACKGROUND = DashboardBackgroundEnum.NONE;
29
-
30
- /**
31
- * 默认偏好(解析不到或同步时兜底):默认中文、default 主题、default base
32
- * Default preference (fallback when parse fails or for initial sync).
33
- * @returns 默认 Preference
34
- */
35
- export declare function getDefaultPreference(): Preference;
36
-
37
- /**
38
- * 语言枚举与常量,不引用任何 JSON,供需要轻量引用的模块使用。
39
- * Language enum and constants; no JSON deps for lightweight usage.
40
- */
41
- declare enum LanguageEnum {
42
- EN = "en",
43
- ZH = "zh",
44
- FR = "fr"
45
- }
46
-
47
- /**
48
- * 布局模式枚举与常量。Layout mode enum and constants.
49
- */
50
- declare enum LayoutModeEnum {
51
- SHOW = "show",
52
- HIDE = "hide"
53
- }
54
-
55
- /**
56
- * 从后端 preference JSON 解析为前端 Preference,解析失败或空返回 null
57
- * Parse backend preference JSON to Preference; returns null on empty or parse error.
58
- * @param json - 后端存的 JSON 字符串
59
- * @returns Preference 或 null
60
- */
61
- export declare function parsePreferenceJson(json: string | null | undefined): Preference | null;
62
-
63
- /** 前端统一的偏好结构;后端存为 JSON:theme, base, language, layoutMode, other.dashboardBackground */
64
- export declare type Preference = {
65
- theme: ThemeEnum;
66
- base: BaseEnum;
67
- language: LanguageEnum;
68
- layoutMode: LayoutModeEnum;
69
- other?: {
70
- dashboardBackground: DashboardBackgroundEnum;
71
- };
72
- };
73
-
74
- /**
75
- * 将前端 Preference 序列化为后端存的完整 JSON 字符串(每次更新都传完整 JSON)
76
- * Serialize Preference to backend JSON string (full payload on each update).
77
- * @param preference - 前端偏好对象
78
- * @returns JSON 字符串
79
- */
80
- export declare function preferenceToJson(preference: Preference): string;
81
-
82
- /** 颜色主题枚举 */
83
- declare enum ThemeEnum {
84
- DEFAULT = "default",
85
- LIGHT = "light",
86
- CORPORATE = "corporate",
87
- FOREST = "forest",
88
- DARK = "dark",
89
- COSMIC = "cosmic",
90
- COFFEE = "coffee",
91
- WINE = "wine",
92
- /** 麦田:default 基础上白红色改为金黄色 */
93
- WHEAT = "wheat"
94
- }
95
-
96
1
  export { }
@@ -1,8 +1 @@
1
- /**
2
- * 压缩头像图片(用于上传)
3
- * @param file - 用户选择的图片文件
4
- * @returns File - 压缩后的文件
5
- */
6
- export declare const compressImage: (file: File) => Promise<File>;
7
-
8
1
  export { }