From da9cdf4b17146428b5adb75e2fcaf29720a2e5dc Mon Sep 17 00:00:00 2001 From: Bram Borggreve Date: Thu, 30 Nov 2023 04:37:53 +0000 Subject: [PATCH] feat: add ui-tab-routes --- apps/web/src/app/app-layout.tsx | 4 +- apps/web/src/app/app-routes.tsx | 7 +- apps/web/src/app/app.tsx | 6 +- .../features/demo/demo-feature-tab-routes.tsx | 42 ++++++ .../src/app/features/demo/demo-feature.tsx | 2 + packages/core/src/lib/index.ts | 1 + packages/core/src/lib/ui-tab-routes/index.ts | 1 + .../src/lib/ui-tab-routes/ui-tab-routes.tsx | 54 +++++++ .../component-generator.spec.ts.snap | 134 ++++++++++++++++++ .../component/component-generator-schema.d.ts | 1 + .../component/component-generator-schema.json | 1 + ...__prefixFileName__-tab-routes.tsx.template | 54 +++++++ .../files/tab-routes/index.ts.template | 1 + .../components-generator.spec.ts.snap | 87 ++++++++++++ .../src/generators/components/components.ts | 1 + .../feature-generator.spec.ts.snap | 49 +++++++ .../demo/demo-feature-tab-routes.tsx.template | 42 ++++++ .../files/demo/demo-feature.tsx.template | 2 + .../features-generator.spec.ts.snap | 49 +++++++ .../theme-generator.spec.ts.snap | 87 ++++++++++++ 20 files changed, 617 insertions(+), 8 deletions(-) create mode 100644 apps/web/src/app/features/demo/demo-feature-tab-routes.tsx create mode 100644 packages/core/src/lib/ui-tab-routes/index.ts create mode 100644 packages/core/src/lib/ui-tab-routes/ui-tab-routes.tsx create mode 100644 packages/generators/src/generators/component/files/tab-routes/__prefixFileName__-tab-routes.tsx.template create mode 100644 packages/generators/src/generators/component/files/tab-routes/index.ts.template create mode 100644 packages/generators/src/generators/feature/files/demo/demo-feature-tab-routes.tsx.template diff --git a/apps/web/src/app/app-layout.tsx b/apps/web/src/app/app-layout.tsx index daf94dc..8eb62c9 100644 --- a/apps/web/src/app/app-layout.tsx +++ b/apps/web/src/app/app-layout.tsx @@ -1,10 +1,10 @@ import { ActionIcon, Anchor, Box, Card, Group, Text } from '@mantine/core' -import { UiContainer, useUiColorScheme } from '@pubkey-ui/core' +import { UiContainer, useUiColorScheme, useUiTheme } from '@pubkey-ui/core' import { IconMoon, IconSun } from '@tabler/icons-react' import { ReactNode } from 'react' -import { Link } from 'react-router-dom' export function AppLayout({ children }: { children: ReactNode }) { + const { Link } = useUiTheme() return ( diff --git a/apps/web/src/app/app-routes.tsx b/apps/web/src/app/app-routes.tsx index bb1a1bd..210de44 100644 --- a/apps/web/src/app/app-routes.tsx +++ b/apps/web/src/app/app-routes.tsx @@ -1,4 +1,5 @@ -import { Navigate, RouteObject, useRoutes } from 'react-router-dom' +import { UiThemeLink } from '@pubkey-ui/core' +import { Link, Navigate, RouteObject, useRoutes } from 'react-router-dom' import { DemoFeature } from './features' import { DashboardFeature } from './features/dashboard/dashboard-feature' import { DevFeature } from './features/dev/dev-feature' @@ -6,10 +7,12 @@ import { DevFeature } from './features/dev/dev-feature' const routes: RouteObject[] = [ { path: '/', element: }, { path: '/dashboard', element: }, - { path: '/demo', element: }, + { path: '/demo/*', element: }, { path: '/dev', element: }, ] export function AppRoutes() { return useRoutes(routes) } + +export const ThemeLink: UiThemeLink = ({ children, ...props }) => {children} diff --git a/apps/web/src/app/app.tsx b/apps/web/src/app/app.tsx index 5b8fbd9..53fa63a 100644 --- a/apps/web/src/app/app.tsx +++ b/apps/web/src/app/app.tsx @@ -1,12 +1,10 @@ import { UiThemeProvider } from '@pubkey-ui/core' -import { Link } from 'react-router-dom' import { AppLayout } from './app-layout' - -import { AppRoutes } from './app-routes' +import { AppRoutes, ThemeLink } from './app-routes' export function App() { return ( - {children}}> + diff --git a/apps/web/src/app/features/demo/demo-feature-tab-routes.tsx b/apps/web/src/app/features/demo/demo-feature-tab-routes.tsx new file mode 100644 index 0000000..55bcc20 --- /dev/null +++ b/apps/web/src/app/features/demo/demo-feature-tab-routes.tsx @@ -0,0 +1,42 @@ +import { SimpleGrid } from '@mantine/core' +import { UiCard, UiTabRoutes } from '@pubkey-ui/core' +import { DemoCard } from './demo-card' + +export function DemoFeatureTabRoutes() { + return ( + + + Overview + + ), + }, + { + value: 'content', + label: 'Content', + component: ( + + Content + + ), + }, + { + value: 'settings', + label: 'Settings', + component: ( + + Settings + + ), + }, + ]} + /> + + ) +} diff --git a/apps/web/src/app/features/demo/demo-feature.tsx b/apps/web/src/app/features/demo/demo-feature.tsx index 0c73701..34add33 100644 --- a/apps/web/src/app/features/demo/demo-feature.tsx +++ b/apps/web/src/app/features/demo/demo-feature.tsx @@ -6,6 +6,7 @@ import { DemoFeatureDebug } from './demo-feature-debug' import { DemoFeatureGroup } from './demo-feature-group' import { DemoFeatureSearchInput } from './demo-feature-search-input' import { DemoFeatureStack } from './demo-feature-stack' +import { DemoFeatureTabRoutes } from './demo-feature-tab-routes' import { DemoFeatureTime } from './demo-feature-time' import { DemoFeatureToast } from './demo-feature-toast' @@ -20,6 +21,7 @@ export function DemoFeature() { + diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts index a9fd0be..2c67538 100644 --- a/packages/core/src/lib/index.ts +++ b/packages/core/src/lib/index.ts @@ -6,6 +6,7 @@ export * from './ui-debug' export * from './ui-group' export * from './ui-search-input' export * from './ui-stack' +export * from './ui-tab-routes' export * from './ui-theme' export * from './ui-time' export * from './ui-toast' diff --git a/packages/core/src/lib/ui-tab-routes/index.ts b/packages/core/src/lib/ui-tab-routes/index.ts new file mode 100644 index 0000000..7c32951 --- /dev/null +++ b/packages/core/src/lib/ui-tab-routes/index.ts @@ -0,0 +1 @@ +export * from './ui-tab-routes' diff --git a/packages/core/src/lib/ui-tab-routes/ui-tab-routes.tsx b/packages/core/src/lib/ui-tab-routes/ui-tab-routes.tsx new file mode 100644 index 0000000..7b7336f --- /dev/null +++ b/packages/core/src/lib/ui-tab-routes/ui-tab-routes.tsx @@ -0,0 +1,54 @@ +import { Box, Tabs, TabsProps, Text } from '@mantine/core' +import { ReactElement, ReactNode } from 'react' +import { Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-dom' + +export interface UiTabRoute { + component: ReactNode + label: ReactElement | string + value: string +} + +export function UiTabRoutes({ + grow = false, + tabs, + baseUrl, + ...props +}: Omit & { + children?: ReactNode + baseUrl?: string + grow?: boolean + tabs: UiTabRoute[] +}) { + const navigate = useNavigate() + const location = useLocation() + // Set the active tab based on matching the location pathname with the tab value + const activeTab = tabs.find((tab) => location.pathname.includes(`/${tab.value}`))?.value + // Set default redirect route to the first tab + const redirect = tabs.length && tabs[0].value !== '' ? tabs[0].value : undefined + + return ( + + navigate(`${baseUrl ? `${baseUrl}/${value}` : value}`)} + mb="md" + {...props} + > + + {tabs.map((tab) => ( + + {tab.label} + + ))} + + + + {redirect ? } /> : null} + {tabs.map((tab) => ( + + ))} + } /> + + + ) +} diff --git a/packages/generators/src/generators/component/__snapshots__/component-generator.spec.ts.snap b/packages/generators/src/generators/component/__snapshots__/component-generator.spec.ts.snap index ecfbe9c..c3f4d73 100644 --- a/packages/generators/src/generators/component/__snapshots__/component-generator.spec.ts.snap +++ b/packages/generators/src/generators/component/__snapshots__/component-generator.spec.ts.snap @@ -815,6 +815,140 @@ exports[`component generator should create files for stack 1`] = ` } `; +exports[`component generator should create files for tab-routes 1`] = ` +{ + ".prettierrc": { + "content": [ + "{ "singleQuote": true }", + ], + "isBinary": false, + "path": "./.prettierrc", + }, + "nx.json": { + "content": [ + "{", + ""affected": { "defaultBase": "main" },", + ""targetDefaults": {", + ""build": { "cache": true },", + ""lint": { "cache": true },", + ""e2e": { "cache": true }", + "}", + "}", + ], + "isBinary": false, + "path": "./nx.json", + }, + "package.json": { + "content": [ + "{", + ""name": "@proj/source",", + ""dependencies": {},", + ""devDependencies": {}", + "}", + ], + "isBinary": false, + "path": "./package.json", + }, + "test": { + "children": { + "index.ts": { + "content": [ + "export * from './ui-tab-routes';", + ], + "isBinary": false, + "path": "./test/index.ts", + }, + "ui-tab-routes.tsx": { + "content": [ + "import { Box, Tabs, TabsProps, Text } from '@mantine/core';", + "import { ReactElement, ReactNode } from 'react';", + "import {", + "Navigate,", + "Route,", + "Routes,", + "useLocation,", + "useNavigate,", + "} from 'react-router-dom';", + "export interface UiTabRoute {", + "component: ReactNode;", + "label: ReactElement | string;", + "value: string;", + "}", + "export function UiTabRoutes({", + "grow = false,", + "tabs,", + "baseUrl,", + "...props", + "}: Omit & {", + "children?: ReactNode;", + "baseUrl?: string;", + "grow?: boolean;", + "tabs: UiTabRoute[];", + "}) {", + "const navigate = useNavigate();", + "const location = useLocation();", + "// Set the active tab based on matching the location pathname with the tab value", + "const activeTab = tabs.find((tab) =>", + "location.pathname.includes(\`/\${tab.value}\`)", + ")?.value;", + "// Set default redirect route to the first tab", + "const redirect =", + "tabs.length && tabs[0].value !== '' ? tabs[0].value : undefined;", + "return (", + "", + "", + "navigate(\`\${baseUrl ? \`\${baseUrl}/\${value}\` : value}\`)", + "}", + "mb="md"", + "{...props}", + ">", + "", + "{tabs.map((tab) => (", + "", + "{tab.label}", + "", + "))}", + "", + "", + "", + "{redirect ? (", + "} />", + ") : null}", + "{tabs.map((tab) => (", + "", + "))}", + "} />", + "", + "", + ");", + "}", + ], + "isBinary": false, + "path": "./test/ui-tab-routes.tsx", + }, + }, + "path": "./test", + }, + "tsconfig.base.json": { + "content": [ + "{", + ""compilerOptions": {", + ""paths": {}", + "}", + "}", + ], + "isBinary": false, + "path": "./tsconfig.base.json", + }, +} +`; + exports[`component generator should create files for theme 1`] = ` { ".prettierrc": { diff --git a/packages/generators/src/generators/component/component-generator-schema.d.ts b/packages/generators/src/generators/component/component-generator-schema.d.ts index 7705fa6..15746d7 100644 --- a/packages/generators/src/generators/component/component-generator-schema.d.ts +++ b/packages/generators/src/generators/component/component-generator-schema.d.ts @@ -22,6 +22,7 @@ export interface ComponentGeneratorSchema { | 'group' | 'search-input' | 'stack' + | 'tab-routes' | 'theme' | 'time' | 'toast' diff --git a/packages/generators/src/generators/component/component-generator-schema.json b/packages/generators/src/generators/component/component-generator-schema.json index f01df2a..d812d36 100644 --- a/packages/generators/src/generators/component/component-generator-schema.json +++ b/packages/generators/src/generators/component/component-generator-schema.json @@ -24,6 +24,7 @@ "group", "search-input", "stack", + "tab-routes", "theme", "time", "toast" diff --git a/packages/generators/src/generators/component/files/tab-routes/__prefixFileName__-tab-routes.tsx.template b/packages/generators/src/generators/component/files/tab-routes/__prefixFileName__-tab-routes.tsx.template new file mode 100644 index 0000000..f99b764 --- /dev/null +++ b/packages/generators/src/generators/component/files/tab-routes/__prefixFileName__-tab-routes.tsx.template @@ -0,0 +1,54 @@ +import { Box, Tabs, TabsProps, Text } from '@mantine/core' +import { ReactElement, ReactNode } from 'react' +import { Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-dom' + +export interface <%= prefix.className %>TabRoute { + component: ReactNode + label: ReactElement | string + value: string +} + +export function <%= prefix.className %>TabRoutes({ + grow = false, + tabs, + baseUrl, + ...props +}: Omit & { + children?: ReactNode + baseUrl?: string + grow?: boolean + tabs: <%= prefix.className %>TabRoute[] +}) { + const navigate = useNavigate() + const location = useLocation() + // Set the active tab based on matching the location pathname with the tab value + const activeTab = tabs.find((tab) => location.pathname.includes(`/${tab.value}`))?.value + // Set default redirect route to the first tab + const redirect = tabs.length && tabs[0].value !== '' ? tabs[0].value : undefined + + return ( + + navigate(`${baseUrl ? `${baseUrl}/${value}` : value}`)} + mb="md" + {...props} + > + + {tabs.map((tab) => ( + + {tab.label} + + ))} + + + + {redirect ? } /> : null} + {tabs.map((tab) => ( + + ))} + } /> + + + ) +} diff --git a/packages/generators/src/generators/component/files/tab-routes/index.ts.template b/packages/generators/src/generators/component/files/tab-routes/index.ts.template new file mode 100644 index 0000000..0a2b841 --- /dev/null +++ b/packages/generators/src/generators/component/files/tab-routes/index.ts.template @@ -0,0 +1 @@ +export * from './<%= prefixFileName %>-tab-routes' diff --git a/packages/generators/src/generators/components/__snapshots__/components-generator.spec.ts.snap b/packages/generators/src/generators/components/__snapshots__/components-generator.spec.ts.snap index 79ece8b..319c852 100644 --- a/packages/generators/src/generators/components/__snapshots__/components-generator.spec.ts.snap +++ b/packages/generators/src/generators/components/__snapshots__/components-generator.spec.ts.snap @@ -46,6 +46,7 @@ exports[`components generator should run successfully 1`] = ` "export * from './ui-group';", "export * from './ui-search-input';", "export * from './ui-stack';", + "export * from './ui-tab-routes';", "export * from './ui-theme';", "export * from './ui-time';", "export * from './ui-toast';", @@ -484,6 +485,92 @@ exports[`components generator should run successfully 1`] = ` }, "path": "./test/ui-stack", }, + "ui-tab-routes": { + "children": { + "index.ts": { + "content": [ + "export * from './ui-tab-routes';", + ], + "isBinary": false, + "path": "./test/ui-tab-routes/index.ts", + }, + "ui-tab-routes.tsx": { + "content": [ + "import { Box, Tabs, TabsProps, Text } from '@mantine/core';", + "import { ReactElement, ReactNode } from 'react';", + "import {", + "Navigate,", + "Route,", + "Routes,", + "useLocation,", + "useNavigate,", + "} from 'react-router-dom';", + "export interface UiTabRoute {", + "component: ReactNode;", + "label: ReactElement | string;", + "value: string;", + "}", + "export function UiTabRoutes({", + "grow = false,", + "tabs,", + "baseUrl,", + "...props", + "}: Omit & {", + "children?: ReactNode;", + "baseUrl?: string;", + "grow?: boolean;", + "tabs: UiTabRoute[];", + "}) {", + "const navigate = useNavigate();", + "const location = useLocation();", + "// Set the active tab based on matching the location pathname with the tab value", + "const activeTab = tabs.find((tab) =>", + "location.pathname.includes(\`/\${tab.value}\`)", + ")?.value;", + "// Set default redirect route to the first tab", + "const redirect =", + "tabs.length && tabs[0].value !== '' ? tabs[0].value : undefined;", + "return (", + "", + "", + "navigate(\`\${baseUrl ? \`\${baseUrl}/\${value}\` : value}\`)", + "}", + "mb="md"", + "{...props}", + ">", + "", + "{tabs.map((tab) => (", + "", + "{tab.label}", + "", + "))}", + "", + "", + "", + "{redirect ? (", + "} />", + ") : null}", + "{tabs.map((tab) => (", + "", + "))}", + "} />", + "", + "", + ");", + "}", + ], + "isBinary": false, + "path": "./test/ui-tab-routes/ui-tab-routes.tsx", + }, + }, + "path": "./test/ui-tab-routes", + }, "ui-theme": { "children": { "index.ts": { diff --git a/packages/generators/src/generators/components/components.ts b/packages/generators/src/generators/components/components.ts index fd842c6..f88f77d 100644 --- a/packages/generators/src/generators/components/components.ts +++ b/packages/generators/src/generators/components/components.ts @@ -9,6 +9,7 @@ export const components: ComponentGeneratorSchema['type'][] = [ 'group', 'search-input', 'stack', + 'tab-routes', 'theme', 'time', 'toast', diff --git a/packages/generators/src/generators/feature/__snapshots__/feature-generator.spec.ts.snap b/packages/generators/src/generators/feature/__snapshots__/feature-generator.spec.ts.snap index 7992f25..b44e86b 100644 --- a/packages/generators/src/generators/feature/__snapshots__/feature-generator.spec.ts.snap +++ b/packages/generators/src/generators/feature/__snapshots__/feature-generator.spec.ts.snap @@ -234,6 +234,53 @@ exports[`feature generator should create files for demo 1`] = ` "isBinary": false, "path": "./test/demo-feature-stack.tsx", }, + "demo-feature-tab-routes.tsx": { + "content": [ + "import { SimpleGrid } from '@mantine/core';", + "import { UiCard, UiTabRoutes } from '@pubkey-ui/core';", + "import { DemoCard } from './demo-card';", + "export function DemoFeatureTabRoutes() {", + "return (", + "", + "", + "Overview", + "", + "),", + "},", + "{", + "value: 'content',", + "label: 'Content',", + "component: (", + "", + "Content", + "", + "),", + "},", + "{", + "value: 'settings',", + "label: 'Settings',", + "component: (", + "", + "Settings", + "", + "),", + "},", + "]}", + "/>", + "", + ");", + "}", + ], + "isBinary": false, + "path": "./test/demo-feature-tab-routes.tsx", + }, "demo-feature-time.tsx": { "content": [ "import { SimpleGrid } from '@mantine/core';", @@ -320,6 +367,7 @@ exports[`feature generator should create files for demo 1`] = ` "import { DemoFeatureGroup } from './demo-feature-group';", "import { DemoFeatureSearchInput } from './demo-feature-search-input';", "import { DemoFeatureStack } from './demo-feature-stack';", + "import { DemoFeatureTabRoutes } from './demo-feature-tab-routes';", "import { DemoFeatureTime } from './demo-feature-time';", "import { DemoFeatureToast } from './demo-feature-toast';", "export function DemoFeature() {", @@ -333,6 +381,7 @@ exports[`feature generator should create files for demo 1`] = ` "", "", "", + "", "", "", "", diff --git a/packages/generators/src/generators/feature/files/demo/demo-feature-tab-routes.tsx.template b/packages/generators/src/generators/feature/files/demo/demo-feature-tab-routes.tsx.template new file mode 100644 index 0000000..404ad85 --- /dev/null +++ b/packages/generators/src/generators/feature/files/demo/demo-feature-tab-routes.tsx.template @@ -0,0 +1,42 @@ +import { SimpleGrid } from '@mantine/core' +import { <%= prefix.className %>Card, <%= prefix.className %>TabRoutes } from '@pubkey-ui/core' +import { DemoCard } from './demo-card' + +export function DemoFeatureTabRoutes() { + return ( + + <<%= prefix.className %>TabRoutes + baseUrl="/demo" + tabs={[ + { + value: 'overview', + label: 'Overview', + component: ( + + <<%= prefix.className %>Card title="Overview">OverviewCard> + + ), + }, + { + value: 'content', + label: 'Content', + component: ( + + <<%= prefix.className %>Card title="Content">ContentCard> + + ), + }, + { + value: 'settings', + label: 'Settings', + component: ( + + <<%= prefix.className %>Card title="Settings">SettingsCard> + + ), + }, + ]} + /> + + ) +} diff --git a/packages/generators/src/generators/feature/files/demo/demo-feature.tsx.template b/packages/generators/src/generators/feature/files/demo/demo-feature.tsx.template index d56d93e..798c7f0 100644 --- a/packages/generators/src/generators/feature/files/demo/demo-feature.tsx.template +++ b/packages/generators/src/generators/feature/files/demo/demo-feature.tsx.template @@ -6,6 +6,7 @@ import { DemoFeatureDebug } from './demo-feature-debug' import { DemoFeatureGroup } from './demo-feature-group' import { DemoFeatureSearchInput } from './demo-feature-search-input' import { DemoFeatureStack } from './demo-feature-stack' +import { DemoFeatureTabRoutes } from './demo-feature-tab-routes' import { DemoFeatureTime } from './demo-feature-time' import { DemoFeatureToast } from './demo-feature-toast' @@ -20,6 +21,7 @@ export function DemoFeature() { + Stack> diff --git a/packages/generators/src/generators/features/__snapshots__/features-generator.spec.ts.snap b/packages/generators/src/generators/features/__snapshots__/features-generator.spec.ts.snap index 13839e9..02ae437 100644 --- a/packages/generators/src/generators/features/__snapshots__/features-generator.spec.ts.snap +++ b/packages/generators/src/generators/features/__snapshots__/features-generator.spec.ts.snap @@ -236,6 +236,53 @@ exports[`features generator should run successfully 1`] = ` "isBinary": false, "path": "./test/demo/demo-feature-stack.tsx", }, + "demo-feature-tab-routes.tsx": { + "content": [ + "import { SimpleGrid } from '@mantine/core';", + "import { UiCard, UiTabRoutes } from '@pubkey-ui/core';", + "import { DemoCard } from './demo-card';", + "export function DemoFeatureTabRoutes() {", + "return (", + "", + "", + "Overview", + "", + "),", + "},", + "{", + "value: 'content',", + "label: 'Content',", + "component: (", + "", + "Content", + "", + "),", + "},", + "{", + "value: 'settings',", + "label: 'Settings',", + "component: (", + "", + "Settings", + "", + "),", + "},", + "]}", + "/>", + "", + ");", + "}", + ], + "isBinary": false, + "path": "./test/demo/demo-feature-tab-routes.tsx", + }, "demo-feature-time.tsx": { "content": [ "import { SimpleGrid } from '@mantine/core';", @@ -322,6 +369,7 @@ exports[`features generator should run successfully 1`] = ` "import { DemoFeatureGroup } from './demo-feature-group';", "import { DemoFeatureSearchInput } from './demo-feature-search-input';", "import { DemoFeatureStack } from './demo-feature-stack';", + "import { DemoFeatureTabRoutes } from './demo-feature-tab-routes';", "import { DemoFeatureTime } from './demo-feature-time';", "import { DemoFeatureToast } from './demo-feature-toast';", "export function DemoFeature() {", @@ -335,6 +383,7 @@ exports[`features generator should run successfully 1`] = ` "", "", "", + "", "", "", "", diff --git a/packages/generators/src/generators/theme/__snapshots__/theme-generator.spec.ts.snap b/packages/generators/src/generators/theme/__snapshots__/theme-generator.spec.ts.snap index 446e39b..56f36e7 100644 --- a/packages/generators/src/generators/theme/__snapshots__/theme-generator.spec.ts.snap +++ b/packages/generators/src/generators/theme/__snapshots__/theme-generator.spec.ts.snap @@ -100,6 +100,7 @@ exports[`theme generator should run successfully 1`] = ` "export * from './ui-group';", "export * from './ui-search-input';", "export * from './ui-stack';", + "export * from './ui-tab-routes';", "export * from './ui-theme';", "export * from './ui-time';", "export * from './ui-toast';", @@ -538,6 +539,92 @@ exports[`theme generator should run successfully 1`] = ` }, "path": "./test-target/src/app/ui/ui-stack", }, + "ui-tab-routes": { + "children": { + "index.ts": { + "content": [ + "export * from './ui-tab-routes';", + ], + "isBinary": false, + "path": "./test-target/src/app/ui/ui-tab-routes/index.ts", + }, + "ui-tab-routes.tsx": { + "content": [ + "import { Box, Tabs, TabsProps, Text } from '@mantine/core';", + "import { ReactElement, ReactNode } from 'react';", + "import {", + "Navigate,", + "Route,", + "Routes,", + "useLocation,", + "useNavigate,", + "} from 'react-router-dom';", + "export interface UiTabRoute {", + "component: ReactNode;", + "label: ReactElement | string;", + "value: string;", + "}", + "export function UiTabRoutes({", + "grow = false,", + "tabs,", + "baseUrl,", + "...props", + "}: Omit & {", + "children?: ReactNode;", + "baseUrl?: string;", + "grow?: boolean;", + "tabs: UiTabRoute[];", + "}) {", + "const navigate = useNavigate();", + "const location = useLocation();", + "// Set the active tab based on matching the location pathname with the tab value", + "const activeTab = tabs.find((tab) =>", + "location.pathname.includes(\`/\${tab.value}\`)", + ")?.value;", + "// Set default redirect route to the first tab", + "const redirect =", + "tabs.length && tabs[0].value !== '' ? tabs[0].value : undefined;", + "return (", + "", + "", + "navigate(\`\${baseUrl ? \`\${baseUrl}/\${value}\` : value}\`)", + "}", + "mb="md"", + "{...props}", + ">", + "", + "{tabs.map((tab) => (", + "", + "{tab.label}", + "", + "))}", + "", + "", + "", + "{redirect ? (", + "} />", + ") : null}", + "{tabs.map((tab) => (", + "", + "))}", + "} />", + "", + "", + ");", + "}", + ], + "isBinary": false, + "path": "./test-target/src/app/ui/ui-tab-routes/ui-tab-routes.tsx", + }, + }, + "path": "./test-target/src/app/ui/ui-tab-routes", + }, "ui-theme": { "children": { "index.ts": {