this.gui 1.3.40 → 1.3.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/init/index.html +27 -0
- package/dist/init/package-lock.json +5779 -0
- package/dist/init/package.json +24 -0
- package/dist/init/src/App.tsx +40 -0
- package/dist/init/src/index.css +16 -0
- package/dist/init/src/main.tsx +13 -0
- package/dist/init/src/router/DerivableRouter.tsx +36 -0
- package/dist/init/tsconfig.json +17 -0
- package/dist/init/vite.config.ts +11 -0
- package/package.json +5 -3
- package/src/GUI.tsx +46 -0
- package/src/QRouter/QRegistry.tsx +53 -0
- package/src/QRouter/QRouter.stories.tsx +31 -0
- package/src/QRouter/QRouter.tsx +57 -0
- package/src/gui/Theme/GuiProvider.tsx +111 -0
- package/src/gui/Theme/Icon/Icon.resolver.tsx +29 -0
- package/src/gui/Theme/Icon/Icon.tsx +43 -0
- package/src/gui/Theme/Layout/Content/Content.resolver.tsx +0 -0
- package/src/gui/Theme/Layout/Content/Content.stories.tsx +88 -0
- package/src/gui/Theme/Layout/Content/Content.tsx +53 -0
- package/src/gui/Theme/Layout/Content/Content.types.tsx +40 -0
- package/src/gui/Theme/Layout/Footer/Footer.resolver.tsx +45 -0
- package/src/gui/Theme/Layout/Footer/Footer.stories.tsx +205 -0
- package/src/gui/Theme/Layout/Footer/Footer.tsx +337 -0
- package/src/gui/Theme/Layout/Footer/Footer.types.ts +40 -0
- package/src/gui/Theme/Layout/Layout/Layout.resolver.tsx +37 -0
- package/src/gui/Theme/Layout/Layout/Layout.stories.tsx +289 -0
- package/src/gui/Theme/Layout/Layout/Layout.tsx +117 -0
- package/src/gui/Theme/Layout/Layout/Layout.types.ts +57 -0
- package/src/gui/Theme/Layout/Layout/useLayoutBreakpoints.ts +9 -0
- package/src/gui/Theme/Layout/Namespace/Namespace.stories.tsx +105 -0
- package/src/gui/Theme/Layout/Namespace/Namespace.tsx +26 -0
- package/src/gui/Theme/Layout/Sidebars/LeftSidebar/LeftSidebar.resolver.tsx +87 -0
- package/src/gui/Theme/Layout/Sidebars/LeftSidebar/LeftSidebar.stories.tsx +199 -0
- package/src/gui/Theme/Layout/Sidebars/LeftSidebar/LeftSidebar.tsx +311 -0
- package/src/gui/Theme/Layout/Sidebars/LeftSidebar/LeftSidebar.types.ts +41 -0
- package/src/gui/Theme/Layout/Sidebars/LeftSidebar/SidebarToggleButton.tsx +53 -0
- package/src/gui/Theme/Layout/Sidebars/LeftSidebar/components/LeftSidebarAction/LeftSidebarAction.resolver.tsx +19 -0
- package/src/gui/Theme/Layout/Sidebars/LeftSidebar/components/LeftSidebarAction/LeftSidebarAction.tsx +107 -0
- package/src/gui/Theme/Layout/Sidebars/LeftSidebar/components/LeftSidebarLink/LeftSidebarLink.resolver.tsx +0 -0
- package/src/gui/Theme/Layout/Sidebars/LeftSidebar/components/LeftSidebarLink/LeftSidebarLink.tsx +134 -0
- package/src/gui/Theme/Layout/Sidebars/LeftSidebar/components/LeftSidebarLink/LeftSidebarLink.types.ts +15 -0
- package/src/gui/Theme/Layout/Sidebars/LeftSidebar/components/LeftSidebarMenu/LeftSidebarMenu.tsx +142 -0
- package/src/gui/Theme/Layout/Sidebars/LeftSidebar/components/LeftSidebarToggleButton/LeftSidebarToggleButton.tsx +23 -0
- package/src/gui/Theme/Layout/Sidebars/RightSidebar/RightSidebar.resolver.tsx +35 -0
- package/src/gui/Theme/Layout/Sidebars/RightSidebar/RightSidebar.stories.tsx +239 -0
- package/src/gui/Theme/Layout/Sidebars/RightSidebar/RightSidebar.tsx +319 -0
- package/src/gui/Theme/Layout/Sidebars/RightSidebar/RightSidebar.types.ts +17 -0
- package/src/gui/Theme/Layout/Sidebars/RightSidebar/components/RightSidebarAction/RightSidebarAction.tsx +102 -0
- package/src/gui/Theme/Layout/Sidebars/RightSidebar/components/RightSidebarLink/RightSidebarLink.tsx +132 -0
- package/src/gui/Theme/Layout/Sidebars/RightSidebar/components/RightSidebarMenu/RightSidebarMenu.tsx +140 -0
- package/src/gui/Theme/Layout/Sidebars/RightSidebar/components/RightSidebarToggleButton/RightSidebarToggleButton.tsx +22 -0
- package/src/gui/Theme/Layout/StickyOptions/StickyOptionsTop.stories.tsx +469 -0
- package/src/gui/Theme/Layout/StickyOptions/StickyOptionsTop.tsx +489 -0
- package/src/gui/Theme/Layout/TopBar/TopBar.resolver.tsx +86 -0
- package/src/gui/Theme/Layout/TopBar/TopBar.stories.tsx +350 -0
- package/src/gui/Theme/Layout/TopBar/TopBar.tsx +292 -0
- package/src/gui/Theme/Layout/TopBar/TopBar.types.ts +39 -0
- package/src/gui/Theme/Layout/TopBar/components/TopBarAction/TopBarAction.stories.tsx +83 -0
- package/src/gui/Theme/Layout/TopBar/components/TopBarAction/TopBarAction.tsx +18 -0
- package/src/gui/Theme/Layout/TopBar/components/TopBarAction/TopBarAction.types.ts +4 -0
- package/src/gui/Theme/Layout/TopBar/components/TopBarLink/TopBarLink.stories.tsx +189 -0
- package/src/gui/Theme/Layout/TopBar/components/TopBarLink/TopBarLink.tsx +30 -0
- package/src/gui/Theme/Layout/TopBar/components/TopBarLink/TopBarLink.types.ts +9 -0
- package/src/gui/Theme/Layout/TopBar/components/TopBarMenu/TopBarMenu.resolver.tsx +14 -0
- package/src/gui/Theme/Layout/TopBar/components/TopBarMenu/TopBarMenu.stories.tsx +56 -0
- package/src/gui/Theme/Layout/TopBar/components/TopBarMenu/TopBarMenu.tsx +123 -0
- package/src/gui/Theme/Layout/TopBar/components/TopBarMenu/TopBarMenu.types.ts +44 -0
- package/src/gui/Theme/catalog/CherryByte/CherryByte.png +0 -0
- package/src/gui/Theme/catalog/CherryByte/dark.tokens.ts +47 -0
- package/src/gui/Theme/catalog/CherryByte/light.tokens.ts +47 -0
- package/src/gui/Theme/catalog/CherryByte/manifest.ts +24 -0
- package/src/gui/Theme/catalog/GhostShell/dark.tokens.ts +43 -0
- package/src/gui/Theme/catalog/GhostShell/ghost.png +0 -0
- package/src/gui/Theme/catalog/GhostShell/light.tokens.ts +39 -0
- package/src/gui/Theme/catalog/GhostShell/manifest.ts +24 -0
- package/src/gui/Theme/catalog/LunaHex/LunaHex.png +0 -0
- package/src/gui/Theme/catalog/LunaHex/dark.tokens.ts +34 -0
- package/src/gui/Theme/catalog/LunaHex/light.tokens.ts +74 -0
- package/src/gui/Theme/catalog/LunaHex/manifest.ts +24 -0
- package/src/gui/Theme/catalog/MUI/MUI.png +0 -0
- package/src/gui/Theme/catalog/MUI/dark.tokens.ts +58 -0
- package/src/gui/Theme/catalog/MUI/light.tokens.ts +74 -0
- package/src/gui/Theme/catalog/MUI/manifest.ts +24 -0
- package/src/gui/Theme/catalog/PrinceOfDarkness/dark.tokens.ts +48 -0
- package/src/gui/Theme/catalog/PrinceOfDarkness/light.tokens.ts +47 -0
- package/src/gui/Theme/catalog/PrinceOfDarkness/manifest.ts +24 -0
- package/src/gui/Theme/catalog/PrinceOfDarkness/prince.png +0 -0
- package/src/gui/Theme/catalog/PrinceOfDarkness/princeOfDarkness.png +0 -0
- package/src/gui/Theme/catalog/Seafoam/dark.tokens.ts +49 -0
- package/src/gui/Theme/catalog/Seafoam/light.tokens.ts +47 -0
- package/src/gui/Theme/catalog/Seafoam/manifest.ts +24 -0
- package/src/gui/Theme/catalog/Seafoam/seaFoam.png +0 -0
- package/src/gui/Theme/catalog/neurons/dark.tokens.ts +58 -0
- package/src/gui/Theme/catalog/neurons/light.tokens.ts +74 -0
- package/src/gui/Theme/catalog/neurons/manifest.ts +24 -0
- package/src/gui/Theme/catalog/neurons/neurons.me.png +0 -0
- package/src/gui/Theme/fromTokens.ts +272 -0
- package/src/gui/Theme/gui.css +31 -0
- package/src/gui/Theme/index.ts +17 -0
- package/src/gui/Theme/styles/buildShadows.ts +83 -0
- package/src/gui/Theme/styles/theme.tokens.ts +108 -0
- package/src/gui/Theme/utils/catalog.ts +61 -0
- package/src/gui/Theme/utils/persistence.ts +66 -0
- package/src/gui/Theme/utils/themeUtils.ts +34 -0
- package/src/gui/components/atoms/AppBar/AppBar.resolver.tsx +46 -0
- package/src/gui/components/atoms/AppBar/AppBar.stories.tsx +251 -0
- package/src/gui/components/atoms/AppBar/AppBar.tsx +107 -0
- package/src/gui/components/atoms/AppBar/AppBar.types.ts +28 -0
- package/src/gui/components/atoms/Avatar/Avatar.resolver.tsx +61 -0
- package/src/gui/components/atoms/Avatar/Avatar.stories.tsx +36 -0
- package/src/gui/components/atoms/Avatar/Avatar.tsx +14 -0
- package/src/gui/components/atoms/Box/Box.resolver.tsx +171 -0
- package/src/gui/components/atoms/Box/Box.stories.tsx +263 -0
- package/src/gui/components/atoms/Box/Box.tsx +15 -0
- package/src/gui/components/atoms/Button/Button.resolver.tsx +103 -0
- package/src/gui/components/atoms/Button/Button.stories.tsx +219 -0
- package/src/gui/components/atoms/Button/Button.tsx +40 -0
- package/src/gui/components/atoms/Card/Card.resolver.tsx +63 -0
- package/src/gui/components/atoms/Card/Card.stories.tsx +54 -0
- package/src/gui/components/atoms/Card/Card.tsx +13 -0
- package/src/gui/components/atoms/CardActions/CardActions.resolver.tsx +59 -0
- package/src/gui/components/atoms/CardActions/CardActions.stories.tsx +32 -0
- package/src/gui/components/atoms/CardActions/CardActions.tsx +14 -0
- package/src/gui/components/atoms/CardContent/CardContent.resolver.tsx +60 -0
- package/src/gui/components/atoms/CardContent/CardContent.stories.tsx +34 -0
- package/src/gui/components/atoms/CardContent/CardContent.tsx +13 -0
- package/src/gui/components/atoms/CardHeader/CardHeader.resolver.tsx +68 -0
- package/src/gui/components/atoms/CardHeader/CardHeader.stories.tsx +40 -0
- package/src/gui/components/atoms/CardHeader/CardHeader.tsx +12 -0
- package/src/gui/components/atoms/Collapse/Collapse.resolver.tsx +85 -0
- package/src/gui/components/atoms/Collapse/Collapse.stories.tsx +130 -0
- package/src/gui/components/atoms/Collapse/Collapse.tsx +17 -0
- package/src/gui/components/atoms/Divider/Divider.resolver.tsx +95 -0
- package/src/gui/components/atoms/Divider/Divider.stories.tsx +108 -0
- package/src/gui/components/atoms/Divider/Divider.tsx +14 -0
- package/src/gui/components/atoms/Drawer/Drawer.resolver.tsx +116 -0
- package/src/gui/components/atoms/Drawer/Drawer.stories.tsx +223 -0
- package/src/gui/components/atoms/Drawer/Drawer.tsx +25 -0
- package/src/gui/components/atoms/Grid/Grid.resolver.tsx +33 -0
- package/src/gui/components/atoms/Grid/Grid.stories.tsx +136 -0
- package/src/gui/components/atoms/Grid/Grid.tsx +15 -0
- package/src/gui/components/atoms/Grid/Grid.types.ts +9 -0
- package/src/gui/components/atoms/IconButton/IconButton.resolver.tsx +137 -0
- package/src/gui/components/atoms/IconButton/IconButton.stories.tsx +134 -0
- package/src/gui/components/atoms/IconButton/IconButton.tsx +22 -0
- package/src/gui/components/atoms/Link/Link.resolver.tsx +74 -0
- package/src/gui/components/atoms/Link/Link.stories.tsx +157 -0
- package/src/gui/components/atoms/Link/Link.tsx +36 -0
- package/src/gui/components/atoms/List/List.resolver.tsx +94 -0
- package/src/gui/components/atoms/List/List.stories.tsx +137 -0
- package/src/gui/components/atoms/List/List.tsx +20 -0
- package/src/gui/components/atoms/ListItem/ListItem.resolver.tsx +88 -0
- package/src/gui/components/atoms/ListItem/ListItem.stories.tsx +151 -0
- package/src/gui/components/atoms/ListItem/ListItem.tsx +19 -0
- package/src/gui/components/atoms/ListItemButton/ListItemButton.resolver.tsx +214 -0
- package/src/gui/components/atoms/ListItemButton/ListItemButton.stories.tsx +155 -0
- package/src/gui/components/atoms/ListItemButton/ListItemButton.tsx +15 -0
- package/src/gui/components/atoms/ListItemIcon/ListItemIcon.resolver.tsx +102 -0
- package/src/gui/components/atoms/ListItemIcon/ListItemIcon.stories.tsx +132 -0
- package/src/gui/components/atoms/ListItemIcon/ListItemIcon.tsx +11 -0
- package/src/gui/components/atoms/ListItemText/ListItemText.resolver.tsx +112 -0
- package/src/gui/components/atoms/ListItemText/ListItemText.stories.tsx +156 -0
- package/src/gui/components/atoms/ListItemText/ListItemText.tsx +15 -0
- package/src/gui/components/atoms/Menu/Menu.resolver.tsx +112 -0
- package/src/gui/components/atoms/Menu/Menu.stories.tsx +162 -0
- package/src/gui/components/atoms/Menu/Menu.tsx +17 -0
- package/src/gui/components/atoms/MenuItem/MenuItem.resolver.tsx +183 -0
- package/src/gui/components/atoms/MenuItem/MenuItem.stories.tsx +134 -0
- package/src/gui/components/atoms/MenuItem/MenuItem.tsx +14 -0
- package/src/gui/components/atoms/Paper/Paper.resolver.tsx +98 -0
- package/src/gui/components/atoms/Paper/Paper.stories.tsx +184 -0
- package/src/gui/components/atoms/Paper/Paper.tsx +15 -0
- package/src/gui/components/atoms/Section/Section.resolver.tsx +10 -0
- package/src/gui/components/atoms/Section/Section.stories.tsx +189 -0
- package/src/gui/components/atoms/Section/Section.tsx +76 -0
- package/src/gui/components/atoms/Section/Section.types.tsx +24 -0
- package/src/gui/components/atoms/Stack/Stack.resolver.tsx +94 -0
- package/src/gui/components/atoms/Stack/Stack.stories.tsx +160 -0
- package/src/gui/components/atoms/Stack/Stack.tsx +15 -0
- package/src/gui/components/atoms/Surface/Surface.resolver.tsx +37 -0
- package/src/gui/components/atoms/Surface/Surface.tsx +49 -0
- package/src/gui/components/atoms/Surface/Surface.types.ts +20 -0
- package/src/gui/components/atoms/Switch/Switch.resolver.tsx +53 -0
- package/src/gui/components/atoms/Switch/Switch.stories.tsx +236 -0
- package/src/gui/components/atoms/Switch/Switch.tsx +22 -0
- package/src/gui/components/atoms/Table/Body/TableBody.tsx +7 -0
- package/src/gui/components/atoms/Table/Cell/TableCell.tsx +18 -0
- package/src/gui/components/atoms/Table/Head/TableHead.tsx +9 -0
- package/src/gui/components/atoms/Table/Row/TableRow.tsx +20 -0
- package/src/gui/components/atoms/Table/Table.resolver.tsx +77 -0
- package/src/gui/components/atoms/Table/Table.stories.tsx +173 -0
- package/src/gui/components/atoms/Table/Table.tsx +20 -0
- package/src/gui/components/atoms/TextField/TextField.stories.tsx +25 -0
- package/src/gui/components/atoms/TextField/TextField.tsx +15 -0
- package/src/gui/components/atoms/Toolbar/Toolbar.resolver.tsx +60 -0
- package/src/gui/components/atoms/Toolbar/Toolbar.stories.tsx +155 -0
- package/src/gui/components/atoms/Toolbar/Toolbar.tsx +16 -0
- package/src/gui/components/atoms/Tooltip/Tooltip.resolver.tsx +142 -0
- package/src/gui/components/atoms/Tooltip/Tooltip.stories.tsx +117 -0
- package/src/gui/components/atoms/Tooltip/Tooltip.tsx +70 -0
- package/src/gui/components/atoms/Typography/Typography.resolver.tsx +158 -0
- package/src/gui/components/atoms/Typography/Typography.stories.tsx +222 -0
- package/src/gui/components/atoms/Typography/Typography.tsx +27 -0
- package/src/gui/components/atoms/Window/Nodes/node.ts +0 -0
- package/src/gui/components/atoms/Window/code/block/node.tsx +0 -0
- package/src/gui/components/atoms/Window/code/hugging.face.api.ts +11 -0
- package/src/gui/components/atoms/Window/connectors/index.ts +19 -0
- package/src/gui/components/atoms/Window/window.stories.tsx +20 -0
- package/src/gui/components/atoms/Window/window.tsx +636 -0
- package/src/gui/components/atoms/atoms.tsx +151 -0
- package/src/gui/components/atoms/index.ts +2 -0
- package/src/gui/components/generics/Cards/Gridme.jsx +52 -0
- package/src/gui/components/generics/Cards/LilBox.jsx +65 -0
- package/src/gui/components/generics/Cards/ModuleCard.jsx +106 -0
- package/src/gui/components/generics/Chats/FullChatBot.jsx +223 -0
- package/src/gui/components/generics/Code/CodeBlock.jsx +33 -0
- package/src/gui/components/generics/EmojiCursor/EmojiCursor.stories.tsx +153 -0
- package/src/gui/components/generics/EmojiCursor/EmojiCursor.tsx +23 -0
- package/src/gui/components/generics/Feedback/Callout.jsx +92 -0
- package/src/gui/components/generics/Layout/GridX.jsx +29 -0
- package/src/gui/components/generics/Layout/Hero2.jsx +132 -0
- package/src/gui/components/generics/Layout/PageContainer.jsx +29 -0
- package/src/gui/components/generics/Layout/PageDivider.jsx +20 -0
- package/src/gui/components/generics/Layout/Section.jsx +43 -0
- package/src/gui/components/generics/Layout/SectionHeader.jsx +21 -0
- package/src/gui/components/generics/Media/Img.jsx +58 -0
- package/src/gui/components/generics/Media/VideoEmbed.jsx +51 -0
- package/src/gui/components/generics/Organization/TableOfContents.jsx +51 -0
- package/src/gui/components/generics/Organization/Tabs.jsx +45 -0
- package/src/gui/components/generics/Text/TextList.jsx +41 -0
- package/src/gui/components/generics/Text/TextParagraph.jsx +28 -0
- package/src/gui/components/generics/Text/TextQuote.jsx +23 -0
- package/src/gui/components/generics/Text/TextTitle.jsx +44 -0
- package/src/gui/components/molecules/Dialog/Dialog.stories.tsx +18 -0
- package/src/gui/components/molecules/Dialog/Dialog.tsx +5 -0
- package/src/gui/components/molecules/Hero/Hero.stories.tsx +140 -0
- package/src/gui/components/molecules/Hero/Hero.tsx +152 -0
- package/src/gui/components/molecules/Hero/Hero.types.tsx +18 -0
- package/src/gui/components/molecules/Modal/Modal.resolver.tsx +38 -0
- package/src/gui/components/molecules/Modal/Modal.stories.tsx +82 -0
- package/src/gui/components/molecules/Modal/Modal.tsx +110 -0
- package/src/gui/components/molecules/Modal/Modal.types.ts +29 -0
- package/src/gui/components/molecules/Page/Page.stories.tsx +135 -0
- package/src/gui/components/molecules/Page/Page.tsx +94 -0
- package/src/gui/components/molecules/Theme/ThemeModeToggle/ThemeModeToggle.resolver.tsx +58 -0
- package/src/gui/components/molecules/Theme/ThemeModeToggle/ThemeModeToggle.stories.tsx +133 -0
- package/src/gui/components/molecules/Theme/ThemeModeToggle/ThemeModeToggle.tsx +101 -0
- package/src/gui/components/molecules/Theme/ThemeModeToggle/ThemeModeToggle.types.ts +29 -0
- package/src/gui/components/molecules/Theme/ThemesCatalog/ThemesCatalog.resolver.tsx +15 -0
- package/src/gui/components/molecules/Theme/ThemesCatalog/ThemesCatalog.stories.tsx +88 -0
- package/src/gui/components/molecules/Theme/ThemesCatalog/ThemesCatalog.tsx +167 -0
- package/src/gui/components/molecules/Theme/ThemesCatalog/ThemesCatalog.types.ts +34 -0
- package/src/gui/components/molecules/molecules.ts +49 -0
- package/src/gui/components/organisms/Blockchain/Blocks/BlocksTable.tsx +119 -0
- package/src/gui/components/organisms/Blockchain/Usernames/Identities.stories.tsx +20 -0
- package/src/gui/components/organisms/Blockchain/Usernames/QR.tsx +566 -0
- package/src/gui/components/organisms/Blockchain/Usernames/Usernames.tsx +448 -0
- package/src/gui/components/organisms/Blockchain/Usernames/identities.tsx +710 -0
- package/src/gui/components/organisms/Blockchain/blockchain.stories.tsx +17 -0
- package/src/gui/components/organisms/Blockchain/blockchain.tsx +368 -0
- package/src/gui/components/organisms/Blockchain/scripts/connection.ts +82 -0
- package/src/gui/components/organisms/Blockchain/scripts/match_face.ts +143 -0
- package/src/gui/components/organisms/HighLighter/HighLighter.stories.tsx +168 -0
- package/src/gui/components/organisms/HighLighter/HighLighter.tsx +420 -0
- package/src/gui/components/organisms/HighLighter/HighLightsDrawer.tsx +197 -0
- package/src/gui/components/organisms/IdentityNoise/FaceRecognition/FaceRecognition.stories.tsx +312 -0
- package/src/gui/components/organisms/IdentityNoise/FaceRecognition/FaceRecognition.tsx +765 -0
- package/src/gui/components/organisms/IdentityNoise/FaceRecognition/modules/useFaceCameraPermission.ts +70 -0
- package/src/gui/components/organisms/IdentityNoise/FaceRecognition/modules/useFaceLandmarker.ts +106 -0
- package/src/gui/components/organisms/IdentityNoise/FaceRecognition/modules/useFaceOverlay.ts +489 -0
- package/src/gui/components/organisms/IdentityNoise/FaceRecognition/modules/useFaceTemplate.ts +32 -0
- package/src/gui/components/organisms/IdentityNoise/FaceRecognition/modules/useFaceTemplateBurst.ts +178 -0
- package/src/gui/components/organisms/IdentityNoise/FaceRecognition/modules/verifyTemplate.ts +136 -0
- package/src/gui/components/organisms/IdentityNoise/IdentityNoise.tsx +403 -0
- package/src/gui/components/organisms/IdentityNoise/IndentityNoise.stories.tsx +15 -0
- package/src/gui/components/organisms/IdentityNoise/Noise/Noise.stories.tsx +206 -0
- package/src/gui/components/organisms/IdentityNoise/Noise/Noise.tsx +394 -0
- package/src/gui/components/organisms/IdentityNoise/Triad/QR.tsx +566 -0
- package/src/gui/components/organisms/IdentityNoise/Triad/Tiad.stories.tsx +6 -0
- package/src/gui/components/organisms/IdentityNoise/Triad/Triad.tsx +917 -0
- package/src/gui/components/organisms/IdentityNoise/Triad/handleCleak.ts +0 -0
- package/src/gui/components/organisms/IdentityNoise/Triad/identity.ts +31 -0
- package/src/gui/components/organisms/IdentityNoise/Triad/me/fundamentals/vectors/vectors.tsx +252 -0
- package/src/gui/components/organisms/IdentityNoise/Triad/me/me.stories.tsx +314 -0
- package/src/gui/components/organisms/IdentityNoise/Triad/me/me.tsx +0 -0
- package/src/gui/components/organisms/organisms.ts +15 -0
- package/src/gui/contexts/InsetsContext.tsx +40 -0
- package/src/gui/contexts/LeftSidebarContext.tsx +20 -0
- package/src/gui/contexts/RightSidebarContext.tsx +25 -0
- package/src/gui/contexts/ThemeContext.ts +34 -0
- package/src/gui/contexts/index.ts +4 -0
- package/src/gui/hooks/index.ts +11 -0
- package/src/gui/hooks/resolveColorToken.ts +39 -0
- package/src/gui/hooks/useCodeGen.ts +12 -0
- package/src/gui/hooks/useGuiMediaQuery.ts +18 -0
- package/src/gui/hooks/useGuiTheme.ts +18 -0
- package/src/gui/hooks/useInsets.ts +26 -0
- package/src/gui/hooks/useIsMobile.ts +13 -0
- package/src/gui/hooks/useIsTouchDevice.ts +25 -0
- package/src/gui/hooks/useLeftSidebar.ts +10 -0
- package/src/gui/hooks/useRightSidebar.ts +12 -0
- package/src/gui/hooks/useViewportKey.ts +19 -0
- package/src/gui/hooks/useViewportProp.ts +17 -0
- package/src/gui/registry/GuiRegistry.ts +19 -0
- package/src/gui/registry/factory.ts +12 -0
- package/src/gui/registry/index.ts +3 -0
- package/src/gui/registry/types.ts +6 -0
- package/src/gui/utils/nodeID.ts +11 -0
- package/src/registry/GuiRegistry.ts +19 -0
- package/src/stories/01.Home.mdx +22 -0
- package/src/stories/02.Understanding.This.GUI.mdx +149 -0
- package/src/stories/Theme/Palette.stories.tsx +86 -0
- package/src/stories/Theme/ThemeViewer.stories.tsx +91 -0
- package/src/stories/Theme/Typography.stories.jsx +211 -0
- package/src/stories/assets/this.GUI.png +0 -0
- package/src/types/gui.d.ts +67 -0
- package/src/types/theme.d.ts +191 -0
- package/src/types/viewport.ts +132 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Box } from '@/gui/components/atoms';
|
|
3
|
+
import { useInsets } from '@/gui/hooks';
|
|
4
|
+
import type { ContentProps } from './Content.types';
|
|
5
|
+
|
|
6
|
+
const Content: React.FC<ContentProps> = ({ children }) => {
|
|
7
|
+
const insets = useInsets();
|
|
8
|
+
const safeTop = Math.max(0, Number(insets?.top ?? 0));
|
|
9
|
+
const navHeight = Math.max(0, Number(insets?.nav ?? 0));
|
|
10
|
+
const topInset = safeTop + navHeight;
|
|
11
|
+
const bottomInset = Math.max(0, Number(insets?.bottom ?? 0));
|
|
12
|
+
const leftInset = Math.max(0, Number(insets?.left ?? 0));
|
|
13
|
+
const rightInset = Math.max(0, Number(insets?.right ?? 0));
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Box
|
|
17
|
+
id="content"
|
|
18
|
+
component="main"
|
|
19
|
+
sx={{
|
|
20
|
+
position: 'relative',
|
|
21
|
+
flex: 1,
|
|
22
|
+
display: 'flex',
|
|
23
|
+
flexDirection: 'column',
|
|
24
|
+
minHeight: 0,
|
|
25
|
+
width: '100%',
|
|
26
|
+
overflow: 'hidden',
|
|
27
|
+
paddingTop: `${topInset}px`,
|
|
28
|
+
paddingBottom: `${bottomInset}px`,
|
|
29
|
+
paddingLeft: `${leftInset}px`,
|
|
30
|
+
paddingRight: `${rightInset}px`,
|
|
31
|
+
boxSizing: 'border-box',
|
|
32
|
+
backgroundColor: 'background.default',
|
|
33
|
+
transition: 'padding 0.3s ease',
|
|
34
|
+
}}
|
|
35
|
+
>
|
|
36
|
+
<Box
|
|
37
|
+
sx={{
|
|
38
|
+
flex: 1,
|
|
39
|
+
minHeight: 0,
|
|
40
|
+
width: '100%',
|
|
41
|
+
display: 'flex',
|
|
42
|
+
flexDirection: 'column',
|
|
43
|
+
overflowY: 'auto',
|
|
44
|
+
overflowX: 'hidden',
|
|
45
|
+
}}
|
|
46
|
+
>
|
|
47
|
+
{children}
|
|
48
|
+
</Box>
|
|
49
|
+
</Box>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default Content;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type { SxProps, Theme } from '@mui/material/styles';
|
|
3
|
+
|
|
4
|
+
export type ContentSection = {
|
|
5
|
+
type: string;
|
|
6
|
+
props?: Record<string, any>;
|
|
7
|
+
children?: ContentSection[];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export interface ContentProps {
|
|
11
|
+
/**
|
|
12
|
+
* Array of layout sections or components to render within the Content area.
|
|
13
|
+
*/
|
|
14
|
+
sections?: ContentSection[];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Optional unique identifier.
|
|
18
|
+
*/
|
|
19
|
+
id?: string;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Custom CSS class name for additional styling.
|
|
23
|
+
*/
|
|
24
|
+
className?: string;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Optional style overrides for the main container.
|
|
28
|
+
*/
|
|
29
|
+
sx?: SxProps<Theme>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Optional data-testid for testing purposes.
|
|
33
|
+
*/
|
|
34
|
+
'data-testid'?: string;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Optional React children that can be rendered directly.
|
|
38
|
+
*/
|
|
39
|
+
children?: React.ReactNode;
|
|
40
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { RegistryEntry } from '@/gui/registry/types';
|
|
3
|
+
import Footer from './Footer';
|
|
4
|
+
import type { FooterElement } from './Footer.types';
|
|
5
|
+
|
|
6
|
+
type FooterSpec = {
|
|
7
|
+
type: 'Footer';
|
|
8
|
+
props?: {
|
|
9
|
+
brandLabel?: string;
|
|
10
|
+
brandLogo?: string;
|
|
11
|
+
brandHref?: string;
|
|
12
|
+
leftElements?: FooterElement[];
|
|
13
|
+
centerElements?: FooterElement[];
|
|
14
|
+
rightElements?: FooterElement[];
|
|
15
|
+
position?: 'static' | 'fixed' | 'sticky';
|
|
16
|
+
elevation?: number;
|
|
17
|
+
className?: string;
|
|
18
|
+
id?: string;
|
|
19
|
+
'data-testid'?: string;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const FooterResolver: RegistryEntry = {
|
|
24
|
+
type: 'Footer',
|
|
25
|
+
resolve(spec: FooterSpec) {
|
|
26
|
+
const props = spec.props ?? {};
|
|
27
|
+
return (
|
|
28
|
+
<Footer
|
|
29
|
+
brandLabel={props.brandLabel}
|
|
30
|
+
brandLogo={props.brandLogo}
|
|
31
|
+
brandHref={props.brandHref}
|
|
32
|
+
leftElements={props.leftElements}
|
|
33
|
+
centerElements={props.centerElements}
|
|
34
|
+
rightElements={props.rightElements}
|
|
35
|
+
position={props.position}
|
|
36
|
+
elevation={props.elevation}
|
|
37
|
+
className={props.className}
|
|
38
|
+
id={props.id}
|
|
39
|
+
data-testid={props['data-testid']}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default FooterResolver;
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import Footer from "./Footer";
|
|
3
|
+
import Layout from "@/gui/Theme/Layout/Layout/Layout";
|
|
4
|
+
import ThemeModeToggle from "@/gui/components/molecules/Theme/ThemeModeToggle/ThemeModeToggle";
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof Footer> = {
|
|
7
|
+
title: "Layout/Footer/Footer",
|
|
8
|
+
component: Footer,
|
|
9
|
+
tags: ['autodocs'],
|
|
10
|
+
parameters: {
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component:
|
|
14
|
+
`The **Footer** component serves as a foundational UI element that anchors actions and secondary navigation at the bottom of the viewport, while seamlessly integrating with responsive layouts and respecting insets caused by sidebars and other layout elements.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
## Declarative Usage
|
|
18
|
+
You can declare the Footer directly in JSX by passing branding information and arrays of elements for the left, center, and right zones. Each element can be a link or an action, allowing flexible customization of navigation and controls.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
## Responsive React Layout Integration
|
|
22
|
+
The Footer automatically adjusts its width and position based on the presence of left and right sidebars, ensuring it does not overlap with other UI components. It also adapts to different screen sizes by hiding labels on tablet and mobile views, showing only icons with tooltips for accessibility.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
## Props Overview
|
|
26
|
+
- \`brandLabel\`: Text label representing the brand, used as fallback or alongside the logo.
|
|
27
|
+
- \`brandLogo\`: URL or path to the brand logo image.
|
|
28
|
+
- \`brandHref\`: Link URL for the brand element, typically the home page.
|
|
29
|
+
- \`leftElements\`, \`centerElements\`, \`rightElements\`: Arrays of elements defining the content for each segment of the footer. Each element is an object with a \`type\` ('link' or 'action') and \`props\` defining its properties such as label, icon, href, and event handlers.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
## Features
|
|
33
|
+
- **Inset-aware:** Automatically offsets its width to accommodate left and right sidebars, avoiding overlap.
|
|
34
|
+
- **Responsive Design:** Collapses labels to icons only on smaller screens, maintaining usability and accessibility with tooltips.
|
|
35
|
+
- **Segmented Layout:** Divides the footer into three distinct zones (left, center, right) for organized content placement.
|
|
36
|
+
- **Flexible Positioning:** Supports \`static\`, \`fixed\`, and \`sticky\` positioning modes to suit various layout needs.
|
|
37
|
+
- **Customizable Styling:** Allows style overrides via \`sx\`, \`appBarSx\`, and \`sectionSx\` for fine-grained control.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
## Layout Zones
|
|
41
|
+
- **Left Zone:** Typically contains branding and primary links.
|
|
42
|
+
- **Center Zone:** Ideal for documentation links, community resources, or other central navigation.
|
|
43
|
+
- **Right Zone:** Often used for actions such as theme toggles or contact buttons.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
## Responsiveness
|
|
47
|
+
Below the \`md\` breakpoint, the Footer hides text labels and displays only icons, preserving space and clarity on smaller devices. Tooltips are provided to maintain accessibility despite the reduced label visibility.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
## Integration Tips
|
|
51
|
+
- Combine the Footer with responsive layout shells that include TopBar and Sidebars to maintain consistent insets and layout harmony.
|
|
52
|
+
- Use the \`position="fixed"\` prop to create persistent footers that remain visible and update the global bottom inset dynamically.
|
|
53
|
+
- Leverage the segmented layout to organize navigation and actions intuitively.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
## Example: Declarative Usage
|
|
57
|
+
~~~tsx
|
|
58
|
+
<Footer
|
|
59
|
+
brandLabel="Neuroverse"
|
|
60
|
+
brandLogo="/logo.svg"
|
|
61
|
+
leftElements={[
|
|
62
|
+
{ type: 'link', props: { label: 'Changelog', icon: 'history', href: '/changelog' } },
|
|
63
|
+
]}
|
|
64
|
+
centerElements={[
|
|
65
|
+
{ type: 'link', props: { label: 'Docs', icon: 'menu_book', href: '/docs' } },
|
|
66
|
+
{ type: 'link', props: { label: 'Community', icon: 'forum', href: '/community', external: true } },
|
|
67
|
+
]}
|
|
68
|
+
rightElements={[
|
|
69
|
+
{ type: 'action', props: { label: 'Toggle Theme', icon: 'dark_mode', onClick: toggleMode } },
|
|
70
|
+
]}
|
|
71
|
+
/>
|
|
72
|
+
~~~
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
## Example: React Integration with Layout
|
|
76
|
+
~~~tsx
|
|
77
|
+
<Layout
|
|
78
|
+
topBarConfig={{
|
|
79
|
+
title: "Responsive Shell",
|
|
80
|
+
elementsRight: [
|
|
81
|
+
{
|
|
82
|
+
type: "action",
|
|
83
|
+
props: {
|
|
84
|
+
element: <ThemeModeToggle variant="minimal" show="icons" iconSize="small" />,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
}}
|
|
89
|
+
leftSidebarConfig={{
|
|
90
|
+
elements: [
|
|
91
|
+
{ type: "link", props: { label: "Overview", icon: "dashboard", iconColor: "var(--gui-primary)" } },
|
|
92
|
+
{ type: "link", props: { label: "Reports", icon: "insights", iconColor: "var(--gui-secondary)" } },
|
|
93
|
+
],
|
|
94
|
+
}}
|
|
95
|
+
rightSidebarConfig={{
|
|
96
|
+
elements: [
|
|
97
|
+
{ type: "link", props: { label: "Alerts", icon: "notifications", iconColor: "var(--gui-warning)" } },
|
|
98
|
+
{ type: "action", props: { label: "Export", icon: "download", iconColor: "var(--gui-success)" } },
|
|
99
|
+
],
|
|
100
|
+
}}
|
|
101
|
+
footerConfig={{
|
|
102
|
+
title: "Neuroverse",
|
|
103
|
+
logoSrc: "/logo.svg",
|
|
104
|
+
links: [
|
|
105
|
+
{ name: "Docs", url: "/docs", icon: "menu_book" },
|
|
106
|
+
{ name: "API", url: "/api", icon: "code" },
|
|
107
|
+
],
|
|
108
|
+
socialLinks: [
|
|
109
|
+
{ name: "GitHub", url: "https://github.com", icon: "code" },
|
|
110
|
+
{ name: "Community", url: "https://community.neuroverse.ai", icon: "forum" },
|
|
111
|
+
],
|
|
112
|
+
position: "fixed",
|
|
113
|
+
}}
|
|
114
|
+
>
|
|
115
|
+
{/* Main content goes here */}
|
|
116
|
+
</Layout>
|
|
117
|
+
~~~
|
|
118
|
+
`,
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export default meta;
|
|
125
|
+
type Story = StoryObj<typeof Footer>;
|
|
126
|
+
|
|
127
|
+
export const Default: Story = {
|
|
128
|
+
args: {
|
|
129
|
+
brandLabel: "Neuroverse",
|
|
130
|
+
brandLogo: "https://neurons.me/neurons.me.png",
|
|
131
|
+
brandHref: "/",
|
|
132
|
+
leftElements: [
|
|
133
|
+
{ type: "link", props: { label: "Status", icon: "monitor_heart", href: "/status", iconColor: "var(--gui-info)" } },
|
|
134
|
+
{ type: "link", props: { label: "Changelog", icon: "history", href: "/changelog", iconColor: "var(--gui-warning)" } },
|
|
135
|
+
],
|
|
136
|
+
centerElements: [
|
|
137
|
+
{ type: "link", props: { label: "Docs", icon: "menu_book", href: "/docs", iconColor: "var(--gui-primary)" } },
|
|
138
|
+
{ type: "link", props: { label: "Community", icon: "forum", href: "https://community.neuroverse.ai", external: true, iconColor: "var(--gui-secondary)" } },
|
|
139
|
+
],
|
|
140
|
+
rightElements: [
|
|
141
|
+
{ type: "action", props: { label: "Contact", icon: "support_agent", iconColor: "var(--gui-success)" } },
|
|
142
|
+
{ type: "action", props: { label: "Theme", icon: "dark_mode", iconColor: "var(--gui-primary)" } },
|
|
143
|
+
],
|
|
144
|
+
position: "static",
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export const FixedFooter: Story = {
|
|
149
|
+
args: {
|
|
150
|
+
...Default.args,
|
|
151
|
+
position: "fixed",
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
export const WithLayout: Story = {
|
|
156
|
+
render: () => (
|
|
157
|
+
<Layout
|
|
158
|
+
topBarConfig={{
|
|
159
|
+
title: "Responsive Shell",
|
|
160
|
+
elementsRight: [
|
|
161
|
+
{
|
|
162
|
+
type: "action",
|
|
163
|
+
props: {
|
|
164
|
+
element: <ThemeModeToggle variant="minimal" show="icons" iconSize="small" />,
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
}}
|
|
169
|
+
leftSidebarConfig={{
|
|
170
|
+
elements: [
|
|
171
|
+
{ type: "link", props: { label: "Overview", icon: "dashboard", iconColor: "var(--gui-primary)" } },
|
|
172
|
+
{ type: "link", props: { label: "Reports", icon: "insights", iconColor: "var(--gui-secondary)" } },
|
|
173
|
+
],
|
|
174
|
+
}}
|
|
175
|
+
rightSidebarConfig={{
|
|
176
|
+
elements: [
|
|
177
|
+
{ type: "link", props: { label: "Alerts", icon: "notifications", iconColor: "var(--gui-warning)" } },
|
|
178
|
+
{ type: "action", props: { label: "Export", icon: "download", iconColor: "var(--gui-success)" } },
|
|
179
|
+
],
|
|
180
|
+
}}
|
|
181
|
+
footerConfig={ {
|
|
182
|
+
title: "Neuroverse",
|
|
183
|
+
logoSrc: "https://neurons.me/neurons.me.png",
|
|
184
|
+
links: [
|
|
185
|
+
{ name: "Docs", url: "/docs", icon: "menu_book" },
|
|
186
|
+
{ name: "API", url: "/api", icon: "code" },
|
|
187
|
+
],
|
|
188
|
+
socialLinks: [
|
|
189
|
+
{ name: "GitHub", url: "https://github.com", icon: "code" },
|
|
190
|
+
{ name: "Community", url: "https://community.neuroverse.ai", icon: "forum" },
|
|
191
|
+
],
|
|
192
|
+
position: "fixed",
|
|
193
|
+
} as any}
|
|
194
|
+
>
|
|
195
|
+
<div style={{ minHeight: '120vh', padding: '72px 24px 120px' }}>
|
|
196
|
+
<h2 style={{ marginBottom: 16 }}>Dashboard Content</h2>
|
|
197
|
+
<p>
|
|
198
|
+
Resize the viewport to see how the TopBar, LeftSidebar, RightSidebar, and Footer coordinate
|
|
199
|
+
their insets. The footer collapses labels below the medium breakpoint while keeping icons and
|
|
200
|
+
tooltips.
|
|
201
|
+
</p>
|
|
202
|
+
</div>
|
|
203
|
+
</Layout>
|
|
204
|
+
),
|
|
205
|
+
};
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import { AppBar, Box, Toolbar, Typography, Avatar, Tooltip } from '@/gui/components/atoms';
|
|
3
|
+
import { Link as RouterLink } from 'react-router-dom';
|
|
4
|
+
import Icon from '@/gui/Theme/Icon/Icon';
|
|
5
|
+
import { useGuiTheme, useGuiMediaQuery, useInsets, useUpdateInsets } from '@/gui/hooks';
|
|
6
|
+
import type { FooterProps, FooterElement } from './Footer.types';
|
|
7
|
+
import type { FooterLinkProps, FooterActionProps } from './Footer.types';
|
|
8
|
+
import type { SxProps, Theme } from '@mui/material/styles';
|
|
9
|
+
|
|
10
|
+
const sxN = (...parts: Array<SxProps<Theme> | undefined>): SxProps<Theme> =>
|
|
11
|
+
(parts.filter(Boolean) as unknown) as SxProps<Theme>;
|
|
12
|
+
|
|
13
|
+
type FooterLinkRenderProps = FooterLinkProps & {
|
|
14
|
+
showLabel: boolean;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type FooterActionRenderProps = FooterActionProps & {
|
|
18
|
+
showLabel: boolean;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const FooterLink = ({
|
|
22
|
+
label,
|
|
23
|
+
icon,
|
|
24
|
+
iconColor,
|
|
25
|
+
href,
|
|
26
|
+
external,
|
|
27
|
+
onClick,
|
|
28
|
+
showLabel,
|
|
29
|
+
}: FooterLinkRenderProps) => {
|
|
30
|
+
const content = (
|
|
31
|
+
<Box
|
|
32
|
+
sx={{
|
|
33
|
+
display: 'flex',
|
|
34
|
+
alignItems: 'center',
|
|
35
|
+
gap: showLabel ? 1 : 0,
|
|
36
|
+
color: 'inherit',
|
|
37
|
+
textDecoration: 'none',
|
|
38
|
+
px: showLabel ? 1.5 : 0.75,
|
|
39
|
+
py: 0.75,
|
|
40
|
+
borderRadius: 1,
|
|
41
|
+
transition: 'background-color 0.2s ease, color 0.2s ease',
|
|
42
|
+
'&:hover': {
|
|
43
|
+
backgroundColor: 'action.hover',
|
|
44
|
+
},
|
|
45
|
+
}}
|
|
46
|
+
>
|
|
47
|
+
{icon && <Icon name={icon} iconColor={iconColor} />}
|
|
48
|
+
{showLabel && label && (
|
|
49
|
+
<Typography variant="body2" sx={{ fontWeight: 500 }}>
|
|
50
|
+
{label}
|
|
51
|
+
</Typography>
|
|
52
|
+
)}
|
|
53
|
+
</Box>
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const wrappedContent =
|
|
57
|
+
!showLabel && label ? (
|
|
58
|
+
<Tooltip title={label} placement="top">
|
|
59
|
+
<span style={{ display: 'inline-flex' }}>{content}</span>
|
|
60
|
+
</Tooltip>
|
|
61
|
+
) : (
|
|
62
|
+
content
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const commonProps = {
|
|
66
|
+
onClick,
|
|
67
|
+
style: { color: 'inherit' },
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
if (href) {
|
|
71
|
+
const component = href.startsWith('http')
|
|
72
|
+
? 'a'
|
|
73
|
+
: RouterLink;
|
|
74
|
+
return (
|
|
75
|
+
<Box
|
|
76
|
+
component={component as any}
|
|
77
|
+
to={!href.startsWith('http') ? href : undefined}
|
|
78
|
+
href={href.startsWith('http') ? href : undefined}
|
|
79
|
+
target={external ? '_blank' : undefined}
|
|
80
|
+
rel={external ? 'noopener noreferrer' : undefined}
|
|
81
|
+
sx={{ display: 'inline-flex' }}
|
|
82
|
+
{...commonProps}
|
|
83
|
+
>
|
|
84
|
+
{wrappedContent}
|
|
85
|
+
</Box>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<Box component="button" type="button" sx={{ display: 'inline-flex', background: 'none', border: 'none', p: 0 }} {...commonProps}>
|
|
91
|
+
{wrappedContent}
|
|
92
|
+
</Box>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const FooterAction = ({
|
|
97
|
+
label,
|
|
98
|
+
icon,
|
|
99
|
+
iconColor,
|
|
100
|
+
onClick,
|
|
101
|
+
element,
|
|
102
|
+
showLabel,
|
|
103
|
+
}: FooterActionRenderProps) => {
|
|
104
|
+
if (element) {
|
|
105
|
+
return <Box sx={{ display: 'inline-flex', alignItems: 'center' }}>{element}</Box>;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const content = (
|
|
109
|
+
<Box
|
|
110
|
+
sx={{
|
|
111
|
+
display: 'flex',
|
|
112
|
+
alignItems: 'center',
|
|
113
|
+
gap: showLabel ? 1 : 0,
|
|
114
|
+
px: showLabel ? 1.5 : 0.75,
|
|
115
|
+
py: 0.75,
|
|
116
|
+
borderRadius: 1,
|
|
117
|
+
transition: 'background-color 0.2s ease',
|
|
118
|
+
'&:hover': { backgroundColor: 'action.hover' },
|
|
119
|
+
color: 'inherit',
|
|
120
|
+
}}
|
|
121
|
+
onClick={onClick}
|
|
122
|
+
role="button"
|
|
123
|
+
>
|
|
124
|
+
{icon && <Icon name={icon} iconColor={iconColor} />}
|
|
125
|
+
{showLabel && label && (
|
|
126
|
+
<Typography variant="body2" sx={{ fontWeight: 500 }}>
|
|
127
|
+
{label}
|
|
128
|
+
</Typography>
|
|
129
|
+
)}
|
|
130
|
+
</Box>
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
if (!showLabel && label) {
|
|
134
|
+
return (
|
|
135
|
+
<Tooltip title={label} placement="top">
|
|
136
|
+
<span style={{ display: 'inline-flex' }}>{content}</span>
|
|
137
|
+
</Tooltip>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return content;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
function renderFooterElement(el: FooterElement, showLabel: boolean, key: string | number) {
|
|
145
|
+
if (el.type === 'link') return <FooterLink key={key} {...el.props} showLabel={showLabel} />;
|
|
146
|
+
if (el.type === 'action') return <FooterAction key={key} {...el.props} showLabel={showLabel} />;
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export default function Footer(props: FooterProps) {
|
|
151
|
+
const {
|
|
152
|
+
brandLabel = '',
|
|
153
|
+
brandLogo = '',
|
|
154
|
+
brandHref = '/',
|
|
155
|
+
brandAvatarFallback,
|
|
156
|
+
leftElements = [],
|
|
157
|
+
centerElements = [],
|
|
158
|
+
rightElements = [],
|
|
159
|
+
position = 'static',
|
|
160
|
+
elevation = 0,
|
|
161
|
+
className,
|
|
162
|
+
id,
|
|
163
|
+
sx,
|
|
164
|
+
appBarSx,
|
|
165
|
+
sectionSx,
|
|
166
|
+
'data-testid': dataTestId,
|
|
167
|
+
} = props;
|
|
168
|
+
|
|
169
|
+
const theme = useGuiTheme();
|
|
170
|
+
const isMobile = useGuiMediaQuery(theme.breakpoints.down('sm'));
|
|
171
|
+
const isTablet = useGuiMediaQuery(theme.breakpoints.between('sm', 'md'));
|
|
172
|
+
const isDesktop = useGuiMediaQuery(theme.breakpoints.up('md'));
|
|
173
|
+
const showLabels = isDesktop;
|
|
174
|
+
const showBrandLabel = !isMobile;
|
|
175
|
+
|
|
176
|
+
const insets = useInsets();
|
|
177
|
+
const updateInsets = useUpdateInsets();
|
|
178
|
+
const toolbarRef = useRef<HTMLDivElement | null>(null);
|
|
179
|
+
const appBarRef = useRef<HTMLDivElement | null>(null);
|
|
180
|
+
|
|
181
|
+
const insetLeft = Math.max(0, Number(insets?.left ?? 0));
|
|
182
|
+
const insetRight = Math.max(0, Number(insets?.right ?? 0));
|
|
183
|
+
const horizontalInset = insetLeft + insetRight;
|
|
184
|
+
|
|
185
|
+
const brandVisual = useMemo(() => {
|
|
186
|
+
if (brandLogo) {
|
|
187
|
+
return <Box component="img" src={brandLogo} alt={brandLabel ? `${brandLabel} logo` : 'Footer logo'} sx={{ height: 24 }} />;
|
|
188
|
+
}
|
|
189
|
+
const fallback = brandAvatarFallback || brandLabel?.trim().charAt(0)?.toUpperCase() || '?';
|
|
190
|
+
return <Avatar sx={{ width: 28, height: 28, fontSize: '0.875rem' }}>{fallback}</Avatar>;
|
|
191
|
+
}, [brandAvatarFallback, brandLabel, brandLogo]);
|
|
192
|
+
|
|
193
|
+
useEffect(() => {
|
|
194
|
+
if (typeof updateInsets !== 'function') return;
|
|
195
|
+
const measure = () => {
|
|
196
|
+
const target = appBarRef.current ?? toolbarRef.current;
|
|
197
|
+
const h = target?.offsetHeight ?? 56;
|
|
198
|
+
updateInsets({ bottom: position === 'fixed' || position === 'sticky' ? h : 0 });
|
|
199
|
+
};
|
|
200
|
+
measure();
|
|
201
|
+
|
|
202
|
+
let ro: ResizeObserver | undefined;
|
|
203
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
204
|
+
const target = appBarRef.current ?? toolbarRef.current;
|
|
205
|
+
if (target) {
|
|
206
|
+
ro = new ResizeObserver(() => measure());
|
|
207
|
+
ro.observe(target);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return () => {
|
|
212
|
+
if (ro) ro.disconnect();
|
|
213
|
+
updateInsets({ bottom: 0 });
|
|
214
|
+
};
|
|
215
|
+
}, [position, updateInsets, isMobile, isTablet]);
|
|
216
|
+
|
|
217
|
+
const isFixed = position === 'fixed' || position === 'sticky';
|
|
218
|
+
const baseAppBarSx = {
|
|
219
|
+
top: 'auto',
|
|
220
|
+
bottom: 0,
|
|
221
|
+
backgroundColor: theme.palette.background.paper ?? theme.palette.grey[900],
|
|
222
|
+
borderTop: '1px solid',
|
|
223
|
+
borderColor: theme.palette.divider,
|
|
224
|
+
minHeight: 56,
|
|
225
|
+
zIndex: (theme.zIndex?.appBar ?? 1100) - 1,
|
|
226
|
+
boxShadow: 'none',
|
|
227
|
+
...(isFixed
|
|
228
|
+
? {
|
|
229
|
+
position: 'fixed',
|
|
230
|
+
left: `${insetLeft}px`,
|
|
231
|
+
right: `${insetRight}px`,
|
|
232
|
+
width: `calc(100% - ${horizontalInset}px)`,
|
|
233
|
+
transition: 'left 0.3s ease, right 0.3s ease, width 0.3s ease',
|
|
234
|
+
}
|
|
235
|
+
: {
|
|
236
|
+
position: 'static',
|
|
237
|
+
left: `${insetLeft}px`,
|
|
238
|
+
right: `${insetRight}px`,
|
|
239
|
+
width: `calc(100% - ${horizontalInset}px)`,
|
|
240
|
+
transition: 'margin-left 0.3s ease, margin-right 0.3s ease, width 0.3s ease',
|
|
241
|
+
}),
|
|
242
|
+
} as const;
|
|
243
|
+
|
|
244
|
+
const flowAppBarSx = !isFixed
|
|
245
|
+
? ({
|
|
246
|
+
ml: `${insetLeft}px`,
|
|
247
|
+
mr: `${insetRight}px`,
|
|
248
|
+
width: `calc(100% - ${horizontalInset}px)`,
|
|
249
|
+
transition: 'margin-left 0.3s ease, margin-right 0.3s ease, width 0.3s ease',
|
|
250
|
+
} as SxProps<Theme>)
|
|
251
|
+
: undefined;
|
|
252
|
+
|
|
253
|
+
return (
|
|
254
|
+
<AppBar
|
|
255
|
+
ref={appBarRef}
|
|
256
|
+
id={id}
|
|
257
|
+
className={className}
|
|
258
|
+
data-testid={dataTestId}
|
|
259
|
+
position={position}
|
|
260
|
+
elevation={elevation}
|
|
261
|
+
sx={sxN(baseAppBarSx as SxProps<Theme>, flowAppBarSx, sx, appBarSx)}
|
|
262
|
+
>
|
|
263
|
+
<Toolbar
|
|
264
|
+
ref={toolbarRef}
|
|
265
|
+
variant="dense"
|
|
266
|
+
disableGutters
|
|
267
|
+
sx={sxN(
|
|
268
|
+
{
|
|
269
|
+
minHeight: 56,
|
|
270
|
+
px: 1.5,
|
|
271
|
+
py: 1,
|
|
272
|
+
display: 'flex',
|
|
273
|
+
alignItems: 'center',
|
|
274
|
+
justifyContent: 'space-between',
|
|
275
|
+
gap: 1.5,
|
|
276
|
+
},
|
|
277
|
+
sectionSx
|
|
278
|
+
)}
|
|
279
|
+
>
|
|
280
|
+
<Box
|
|
281
|
+
sx={{
|
|
282
|
+
display: 'flex',
|
|
283
|
+
alignItems: 'center',
|
|
284
|
+
gap: showLabels ? 1 : 0.5,
|
|
285
|
+
color: 'text.secondary',
|
|
286
|
+
flexShrink: 0,
|
|
287
|
+
}}
|
|
288
|
+
>
|
|
289
|
+
{leftElements.map((el, idx) => renderFooterElement(el, showLabels, `left-${idx}`))}
|
|
290
|
+
</Box>
|
|
291
|
+
|
|
292
|
+
<Box
|
|
293
|
+
sx={{
|
|
294
|
+
display: 'flex',
|
|
295
|
+
alignItems: 'center',
|
|
296
|
+
gap: showLabels ? 1 : 0.5,
|
|
297
|
+
flex: 1,
|
|
298
|
+
justifyContent: 'center',
|
|
299
|
+
color: 'text.secondary',
|
|
300
|
+
}}
|
|
301
|
+
>
|
|
302
|
+
{centerElements.map((el, idx) => renderFooterElement(el, showLabels, `center-${idx}`))}
|
|
303
|
+
</Box>
|
|
304
|
+
|
|
305
|
+
<Box
|
|
306
|
+
sx={{
|
|
307
|
+
display: 'flex',
|
|
308
|
+
alignItems: 'center',
|
|
309
|
+
gap: showLabels ? 1 : 0.75,
|
|
310
|
+
color: 'text.secondary',
|
|
311
|
+
flexShrink: 0,
|
|
312
|
+
}}
|
|
313
|
+
>
|
|
314
|
+
{rightElements.map((el, idx) => renderFooterElement(el, showLabels, `right-${idx}`))}
|
|
315
|
+
<Box
|
|
316
|
+
sx={{
|
|
317
|
+
display: 'flex',
|
|
318
|
+
alignItems: 'center',
|
|
319
|
+
gap: showBrandLabel ? 1 : 0.75,
|
|
320
|
+
textDecoration: 'none',
|
|
321
|
+
color: 'inherit',
|
|
322
|
+
}}
|
|
323
|
+
component={brandHref ? RouterLink : 'div'}
|
|
324
|
+
to={brandHref ? brandHref : undefined}
|
|
325
|
+
>
|
|
326
|
+
{brandVisual}
|
|
327
|
+
{showBrandLabel && brandLabel && (
|
|
328
|
+
<Typography variant="body2" sx={{ fontWeight: 600 }}>
|
|
329
|
+
{brandLabel}
|
|
330
|
+
</Typography>
|
|
331
|
+
)}
|
|
332
|
+
</Box>
|
|
333
|
+
</Box>
|
|
334
|
+
</Toolbar>
|
|
335
|
+
</AppBar>
|
|
336
|
+
);
|
|
337
|
+
}
|