diff --git a/apps/web/src/app/features/demo/demo-feature-dashboard-grid.tsx b/apps/web/src/app/features/demo/demo-feature-dashboard-grid.tsx
new file mode 100644
index 0000000..a86458c
--- /dev/null
+++ b/apps/web/src/app/features/demo/demo-feature-dashboard-grid.tsx
@@ -0,0 +1,57 @@
+import { UiCard, UiDashboardGrid, UiDashboardItem, UiStack } from '@pubkey-ui/core'
+import {
+ IconBuildingBank,
+ IconCashBanknote,
+ IconCoin,
+ IconCreditCard,
+ IconReceipt,
+ IconReceiptRefund,
+ IconReceiptTax,
+ IconRepeat,
+ IconReport,
+} from '@tabler/icons-react'
+import { ReactNode } from 'react'
+import { useRoutes } from 'react-router-dom'
+
+export function useDashboardItems(): {
+ links: UiDashboardItem[]
+ routes: ReactNode
+} {
+ const links: UiDashboardItem[] = [
+ { to: 'credit-cards', label: 'Credit cards', icon: IconCreditCard },
+ { to: 'banks-nearby', label: 'Banks nearby', icon: IconBuildingBank },
+ { to: 'transfers', label: 'Transfers', icon: IconRepeat },
+ { to: 'refunds', label: 'Refunds', icon: IconReceiptRefund },
+ { to: 'receipts', label: 'Receipts', icon: IconReceipt },
+ { to: 'taxes', label: 'Taxes', icon: IconReceiptTax },
+ { to: 'reports', label: 'Reports', icon: IconReport },
+ { to: 'payments', label: 'Payments', icon: IconCoin },
+ { to: 'cashback', label: 'Cashback', icon: IconCashBanknote },
+ ]
+ const routes = useRoutes([
+ { index: true, element:
Dashboard Grid
},
+ ...links.map((link) => ({ path: link.to, element: {link.label}
})),
+ ])
+
+ return {
+ links,
+ routes,
+ }
+}
+
+export function DemoFeatureDashboardGrid() {
+ const base = '/demo/dashboard-grid'
+ const { links, routes } = useDashboardItems()
+ return (
+
+ ({
+ to: `${base}/${to}`,
+ label,
+ icon,
+ }))}
+ />
+ {routes}
+
+ )
+}
diff --git a/apps/web/src/app/features/demo/demo-feature.tsx b/apps/web/src/app/features/demo/demo-feature.tsx
index 399388c..31e15fe 100644
--- a/apps/web/src/app/features/demo/demo-feature.tsx
+++ b/apps/web/src/app/features/demo/demo-feature.tsx
@@ -5,6 +5,7 @@ import { Link, Navigate, useLocation, useRoutes } from 'react-router-dom'
import { DemoFeatureAlerts } from './demo-feature-alerts'
import { DemoFeatureCard } from './demo-feature-card'
import { DemoFeatureCopy } from './demo-feature-copy'
+import { DemoFeatureDashboardGrid } from './demo-feature-dashboard-grid'
import { DemoFeatureDebug } from './demo-feature-debug'
import { DemoFeatureGroup } from './demo-feature-group'
import { DemoFeatureHeader } from './demo-feature-header'
@@ -26,6 +27,7 @@ export function DemoFeature() {
{ path: 'alerts', label: 'Alerts', element: },
{ path: 'card', label: 'Card', element: },
{ path: 'copy', label: 'Copy', element: },
+ { path: 'dashboard-grid', label: 'Dashboard Grid', element: },
{ path: 'debug', label: 'Debug', element: },
{ path: 'group', label: 'Group', element: },
{ path: 'header', label: 'Header', element: },
diff --git a/apps/web/src/app/features/dev/dev-feature-action-grid.tsx b/apps/web/src/app/features/dev/dev-feature-action-grid.tsx
new file mode 100644
index 0000000..a230fb7
--- /dev/null
+++ b/apps/web/src/app/features/dev/dev-feature-action-grid.tsx
@@ -0,0 +1,34 @@
+import { UiCard, UiContainer, UiDashboardGrid } from '@pubkey-ui/core'
+import {
+ IconBuildingBank,
+ IconCashBanknote,
+ IconCoin,
+ IconCreditCard,
+ IconReceipt,
+ IconReceiptRefund,
+ IconReceiptTax,
+ IconRepeat,
+ IconReport,
+} from '@tabler/icons-react'
+
+export function DevFeatureActionGrid() {
+ return (
+
+
+
+
+
+ )
+}
diff --git a/apps/web/src/app/features/dev/dev-feature-logo.tsx b/apps/web/src/app/features/dev/dev-feature-logo.tsx
deleted file mode 100644
index 30548e7..0000000
--- a/apps/web/src/app/features/dev/dev-feature-logo.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-import {
- UiCard,
- UiContainer,
- UiGroup,
- UiLogo,
- UiLogoType,
- UiLogoTypeBlack,
- UiLogoTypeWhite,
- UiStack,
-} from '@pubkey-ui/core'
-
-export function DevFeatureLogo() {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
diff --git a/apps/web/src/app/features/dev/dev-feature.tsx b/apps/web/src/app/features/dev/dev-feature.tsx
index 666f05c..f34e2e9 100644
--- a/apps/web/src/app/features/dev/dev-feature.tsx
+++ b/apps/web/src/app/features/dev/dev-feature.tsx
@@ -1,11 +1,11 @@
import { UiContainer } from '@pubkey-ui/core'
import { DevFeatureLink } from './dev-feature-link'
-import { DevFeatureLogo } from './dev-feature-logo'
+import { DevFeatureActionGrid } from './dev-feature-action-grid'
export function DevFeature() {
return (
-
+
)
diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts
index 650b073..be93fe0 100644
--- a/packages/core/src/lib/index.ts
+++ b/packages/core/src/lib/index.ts
@@ -2,6 +2,7 @@ export * from './ui-alert'
export * from './ui-card'
export * from './ui-container'
export * from './ui-copy'
+export * from './ui-dashboard-grid'
export * from './ui-debug'
export * from './ui-group'
export * from './ui-header'
diff --git a/packages/core/src/lib/ui-dashboard-grid/index.ts b/packages/core/src/lib/ui-dashboard-grid/index.ts
new file mode 100644
index 0000000..f98e359
--- /dev/null
+++ b/packages/core/src/lib/ui-dashboard-grid/index.ts
@@ -0,0 +1 @@
+export * from './ui-dashboard-grid'
diff --git a/packages/core/src/lib/ui-dashboard-grid/ui-dashboard-grid.module.css b/packages/core/src/lib/ui-dashboard-grid/ui-dashboard-grid.module.css
new file mode 100644
index 0000000..e727aa1
--- /dev/null
+++ b/packages/core/src/lib/ui-dashboard-grid/ui-dashboard-grid.module.css
@@ -0,0 +1,16 @@
+.item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ border-radius: var(--mantine-radius-md);
+ height: rem(180px);
+ background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-7));
+ transition: box-shadow 150ms ease, transform 100ms ease;
+
+ @mixin hover {
+ box-shadow: var(--mantine-shadow-md);
+ transform: scale(1.05);
+ }
+}
diff --git a/packages/core/src/lib/ui-dashboard-grid/ui-dashboard-grid.tsx b/packages/core/src/lib/ui-dashboard-grid/ui-dashboard-grid.tsx
new file mode 100644
index 0000000..40a999f
--- /dev/null
+++ b/packages/core/src/lib/ui-dashboard-grid/ui-dashboard-grid.tsx
@@ -0,0 +1,42 @@
+import { SimpleGrid, Text, UnstyledButton, useMantineTheme } from '@mantine/core'
+import { useUiTheme } from '../ui-theme'
+import { ComponentType } from 'react'
+
+import classes from './ui-dashboard-grid.module.css'
+
+const linkColors = ['violet', 'indigo', 'blue', 'green', 'teal', 'cyan', 'pink', 'red', 'orange']
+
+export function getColorByIndex(index: number) {
+ return linkColors[index % linkColors.length]
+}
+
+export interface UiDashboardItem {
+ icon: ComponentType<{ color?: string; size: number | string }>
+ label: string
+ to: string
+ color?: string
+}
+
+export interface UiDashboardGridProps {
+ links: UiDashboardItem[]
+}
+
+export function UiDashboardGrid({ links }: UiDashboardGridProps) {
+ const { Link } = useUiTheme()
+ const theme = useMantineTheme()
+
+ const items = links.map((item, index) => (
+
+
+
+ {item.label}
+
+
+ ))
+
+ return (
+
+ {items}
+
+ )
+}
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 23533e1..43cf4f0 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
@@ -397,6 +397,156 @@ exports[`component generator should create files for copy 1`] = `
}
`;
+exports[`component generator should create files for dashboard-grid 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-dashboard-grid';",
+ ],
+ "isBinary": false,
+ "path": "./test/index.ts",
+ },
+ "ui-dashboard-grid.module.css": {
+ "content": [
+ ".item {",
+ "display: flex;",
+ "flex-direction: column;",
+ "align-items: center;",
+ "justify-content: center;",
+ "text-align: center;",
+ "border-radius: var(--mantine-radius-md);",
+ "height: rem(180px);",
+ "background-color: light-dark(",
+ "var(--mantine-color-white),",
+ "var(--mantine-color-dark-7)",
+ ");",
+ "transition: box-shadow 150ms ease, transform 100ms ease;",
+ "@mixin hover {",
+ "box-shadow: var(--mantine-shadow-md) !important;",
+ "transform: scale(1.05);",
+ "}",
+ "}",
+ ],
+ "isBinary": false,
+ "path": "./test/ui-dashboard-grid.module.css",
+ },
+ "ui-dashboard-grid.tsx": {
+ "content": [
+ "import {",
+ "SimpleGrid,",
+ "Text,",
+ "UnstyledButton,",
+ "useMantineTheme,",
+ "} from '@mantine/core';",
+ "import { useUiTheme } from '../ui-theme';",
+ "import { ComponentType } from 'react';",
+ "import classes from './ui-dashboard-grid.module.css';",
+ "const linkColors = [",
+ "'violet',",
+ "'indigo',",
+ "'blue',",
+ "'green',",
+ "'teal',",
+ "'cyan',",
+ "'pink',",
+ "'red',",
+ "'orange',",
+ "];",
+ "export function getColorByIndex(index: number) {",
+ "return linkColors[index % linkColors.length];",
+ "}",
+ "export interface UiDashboardItem {",
+ "icon: ComponentType<{ color?: string; size: number | string }>;",
+ "label: string;",
+ "to: string;",
+ "color?: string;",
+ "}",
+ "export interface UiDashboardGridProps {",
+ "links: UiDashboardItem[];",
+ "}",
+ "export function UiDashboardGrid({ links }: UiDashboardGridProps) {",
+ "const { Link } = useUiTheme();",
+ "const theme = useMantineTheme();",
+ "const items = links.map((item, index) => (",
+ "",
+ "",
+ "",
+ "{item.label}",
+ "",
+ "",
+ "));",
+ "return (",
+ "",
+ "{items}",
+ "",
+ ");",
+ "}",
+ ],
+ "isBinary": false,
+ "path": "./test/ui-dashboard-grid.tsx",
+ },
+ },
+ "path": "./test",
+ },
+ "tsconfig.base.json": {
+ "content": [
+ "{",
+ ""compilerOptions": {",
+ ""paths": {}",
+ "}",
+ "}",
+ ],
+ "isBinary": false,
+ "path": "./tsconfig.base.json",
+ },
+}
+`;
+
exports[`component generator should create files for debug 1`] = `
{
".prettierrc": {
@@ -673,7 +823,10 @@ exports[`component generator should create files for header 1`] = `
"content": [
".header {",
"height: rem(56px);",
- "background-color: var(--mantine-color-body);",
+ "background-color: light-dark(",
+ "var(--mantine-color-white),",
+ "var(--mantine-color-dark-9)",
+ ");",
"padding-left: var(--mantine-spacing-md);",
"padding-right: var(--mantine-spacing-md);",
"}",
@@ -699,6 +852,13 @@ exports[`component generator should create files for header 1`] = `
");",
"}",
"}",
+ ".linkActive {",
+ "background-color: light-dark(",
+ "var(--mantine-color-gray-0),",
+ "var(--mantine-color-dark-6)",
+ ");",
+ "color: light-dark(var(--mantine-color-brand-6), var(--mantine-color-brand-4));",
+ "}",
],
"isBinary": false,
"path": "./test/ui-header.module.css",
@@ -707,7 +867,8 @@ exports[`component generator should create files for header 1`] = `
"content": [
"import { Anchor, Burger, Group } from '@mantine/core';",
"import { ReactNode } from 'react';",
- "import { Link } from 'react-router-dom';",
+ "import cx from 'clsx';",
+ "import { Link, useLocation } from 'react-router-dom';",
"import { UiLogo, UiLogoType } from '../ui-logo';",
"import classes from './ui-header.module.css';",
"export interface UiHeaderProps {",
@@ -732,12 +893,15 @@ exports[`component generator should create files for header 1`] = `
"profile,",
"toggle,",
"}: UiHeaderProps) {",
+ "const { pathname } = useLocation();",
"const items = links.map((link) => (",
"",
"{link.label}",
"",
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 424ff14..939530a 100644
--- a/packages/generators/src/generators/component/component-generator-schema.d.ts
+++ b/packages/generators/src/generators/component/component-generator-schema.d.ts
@@ -19,6 +19,7 @@ export interface ComponentGeneratorSchema {
| 'container'
| 'copy'
| 'debug'
+ | 'dashboard-grid'
| 'group'
| 'header'
| 'layout'
diff --git a/packages/generators/src/generators/component/component-generator-schema.json b/packages/generators/src/generators/component/component-generator-schema.json
index 072b6b1..ae8ac70 100644
--- a/packages/generators/src/generators/component/component-generator-schema.json
+++ b/packages/generators/src/generators/component/component-generator-schema.json
@@ -21,6 +21,7 @@
"container",
"copy",
"debug",
+ "dashboard-grid",
"group",
"header",
"layout",
diff --git a/packages/generators/src/generators/component/files/dashboard-grid/__prefixFileName__-dashboard-grid.module.css.template b/packages/generators/src/generators/component/files/dashboard-grid/__prefixFileName__-dashboard-grid.module.css.template
new file mode 100644
index 0000000..e727aa1
--- /dev/null
+++ b/packages/generators/src/generators/component/files/dashboard-grid/__prefixFileName__-dashboard-grid.module.css.template
@@ -0,0 +1,16 @@
+.item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ border-radius: var(--mantine-radius-md);
+ height: rem(180px);
+ background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-7));
+ transition: box-shadow 150ms ease, transform 100ms ease;
+
+ @mixin hover {
+ box-shadow: var(--mantine-shadow-md);
+ transform: scale(1.05);
+ }
+}
diff --git a/packages/generators/src/generators/component/files/dashboard-grid/__prefixFileName__-dashboard-grid.tsx.template b/packages/generators/src/generators/component/files/dashboard-grid/__prefixFileName__-dashboard-grid.tsx.template
new file mode 100644
index 0000000..9b4e9cb
--- /dev/null
+++ b/packages/generators/src/generators/component/files/dashboard-grid/__prefixFileName__-dashboard-grid.tsx.template
@@ -0,0 +1,42 @@
+import { SimpleGrid, Text, UnstyledButton, useMantineTheme } from '@mantine/core'
+import { use<%= prefix.className %>Theme } from '../<%= prefix.fileName %>-theme'
+import { ComponentType } from 'react'
+
+import classes from './<%= prefix.fileName %>-dashboard-grid.module.css'
+
+const linkColors = ['violet', 'indigo', 'blue', 'green', 'teal', 'cyan', 'pink', 'red', 'orange']
+
+export function getColorByIndex(index: number) {
+ return linkColors[index % linkColors.length]
+}
+
+export interface <%= prefix.className %>DashboardItem {
+ icon: ComponentType<{ color?: string; size: number | string }>
+ label: string
+ to: string
+ color?: string
+}
+
+export interface <%= prefix.className %>DashboardGridProps {
+ links: <%= prefix.className %>DashboardItem[]
+}
+
+export function <%= prefix.className %>DashboardGrid({ links }: <%= prefix.className %>DashboardGridProps) {
+ const { Link } = use<%= prefix.className %>Theme()
+ const theme = useMantineTheme()
+
+ const items = links.map((item, index) => (
+
+
+
+ {item.label}
+
+
+ ))
+
+ return (
+
+ {items}
+
+ )
+}
diff --git a/packages/generators/src/generators/component/files/dashboard-grid/index.ts.template b/packages/generators/src/generators/component/files/dashboard-grid/index.ts.template
new file mode 100644
index 0000000..f8cd7b0
--- /dev/null
+++ b/packages/generators/src/generators/component/files/dashboard-grid/index.ts.template
@@ -0,0 +1 @@
+export * from './<%= prefixFileName %>-dashboard-grid'
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 649739c..5740bf9 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
@@ -42,6 +42,7 @@ exports[`components generator should run successfully 1`] = `
"export * from './ui-card';",
"export * from './ui-container';",
"export * from './ui-copy';",
+ "export * from './ui-dashboard-grid';",
"export * from './ui-debug';",
"export * from './ui-group';",
"export * from './ui-header';",
@@ -264,6 +265,108 @@ exports[`components generator should run successfully 1`] = `
},
"path": "./test/ui-copy",
},
+ "ui-dashboard-grid": {
+ "children": {
+ "index.ts": {
+ "content": [
+ "export * from './ui-dashboard-grid';",
+ ],
+ "isBinary": false,
+ "path": "./test/ui-dashboard-grid/index.ts",
+ },
+ "ui-dashboard-grid.module.css": {
+ "content": [
+ ".item {",
+ "display: flex;",
+ "flex-direction: column;",
+ "align-items: center;",
+ "justify-content: center;",
+ "text-align: center;",
+ "border-radius: var(--mantine-radius-md);",
+ "height: rem(180px);",
+ "background-color: light-dark(",
+ "var(--mantine-color-white),",
+ "var(--mantine-color-dark-7)",
+ ");",
+ "transition: box-shadow 150ms ease, transform 100ms ease;",
+ "@mixin hover {",
+ "box-shadow: var(--mantine-shadow-md) !important;",
+ "transform: scale(1.05);",
+ "}",
+ "}",
+ ],
+ "isBinary": false,
+ "path": "./test/ui-dashboard-grid/ui-dashboard-grid.module.css",
+ },
+ "ui-dashboard-grid.tsx": {
+ "content": [
+ "import {",
+ "SimpleGrid,",
+ "Text,",
+ "UnstyledButton,",
+ "useMantineTheme,",
+ "} from '@mantine/core';",
+ "import { useUiTheme } from '../ui-theme';",
+ "import { ComponentType } from 'react';",
+ "import classes from './ui-dashboard-grid.module.css';",
+ "const linkColors = [",
+ "'violet',",
+ "'indigo',",
+ "'blue',",
+ "'green',",
+ "'teal',",
+ "'cyan',",
+ "'pink',",
+ "'red',",
+ "'orange',",
+ "];",
+ "export function getColorByIndex(index: number) {",
+ "return linkColors[index % linkColors.length];",
+ "}",
+ "export interface UiDashboardItem {",
+ "icon: ComponentType<{ color?: string; size: number | string }>;",
+ "label: string;",
+ "to: string;",
+ "color?: string;",
+ "}",
+ "export interface UiDashboardGridProps {",
+ "links: UiDashboardItem[];",
+ "}",
+ "export function UiDashboardGrid({ links }: UiDashboardGridProps) {",
+ "const { Link } = useUiTheme();",
+ "const theme = useMantineTheme();",
+ "const items = links.map((item, index) => (",
+ "",
+ "",
+ "",
+ "{item.label}",
+ "",
+ "",
+ "));",
+ "return (",
+ "",
+ "{items}",
+ "",
+ ");",
+ "}",
+ ],
+ "isBinary": false,
+ "path": "./test/ui-dashboard-grid/ui-dashboard-grid.tsx",
+ },
+ },
+ "path": "./test/ui-dashboard-grid",
+ },
"ui-debug": {
"children": {
"index.ts": {
@@ -410,7 +513,10 @@ exports[`components generator should run successfully 1`] = `
"content": [
".header {",
"height: rem(56px);",
- "background-color: var(--mantine-color-body);",
+ "background-color: light-dark(",
+ "var(--mantine-color-white),",
+ "var(--mantine-color-dark-9)",
+ ");",
"padding-left: var(--mantine-spacing-md);",
"padding-right: var(--mantine-spacing-md);",
"}",
@@ -436,6 +542,13 @@ exports[`components generator should run successfully 1`] = `
");",
"}",
"}",
+ ".linkActive {",
+ "background-color: light-dark(",
+ "var(--mantine-color-gray-0),",
+ "var(--mantine-color-dark-6)",
+ ");",
+ "color: light-dark(var(--mantine-color-brand-6), var(--mantine-color-brand-4));",
+ "}",
],
"isBinary": false,
"path": "./test/ui-header/ui-header.module.css",
@@ -444,7 +557,8 @@ exports[`components generator should run successfully 1`] = `
"content": [
"import { Anchor, Burger, Group } from '@mantine/core';",
"import { ReactNode } from 'react';",
- "import { Link } from 'react-router-dom';",
+ "import cx from 'clsx';",
+ "import { Link, useLocation } from 'react-router-dom';",
"import { UiLogo, UiLogoType } from '../ui-logo';",
"import classes from './ui-header.module.css';",
"export interface UiHeaderProps {",
@@ -469,12 +583,15 @@ exports[`components generator should run successfully 1`] = `
"profile,",
"toggle,",
"}: UiHeaderProps) {",
+ "const { pathname } = useLocation();",
"const items = links.map((link) => (",
"",
"{link.label}",
"",
diff --git a/packages/generators/src/generators/components/components.ts b/packages/generators/src/generators/components/components.ts
index 5fd1021..49abb0c 100644
--- a/packages/generators/src/generators/components/components.ts
+++ b/packages/generators/src/generators/components/components.ts
@@ -5,6 +5,7 @@ export const components: ComponentGeneratorSchema['type'][] = [
'card',
'container',
'copy',
+ 'dashboard-grid',
'debug',
'group',
'header',
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 e2f5910..990058b 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
@@ -97,6 +97,74 @@ exports[`feature generator should create files for demo 1`] = `
"isBinary": false,
"path": "./test/demo-feature-copy.tsx",
},
+ "demo-feature-dashboard-grid.tsx": {
+ "content": [
+ "import {",
+ "UiCard,",
+ "UiDashboardGrid,",
+ "UiDashboardItem,",
+ "UiStack,",
+ "} from '@pubkey-ui/core';",
+ "import {",
+ "IconBuildingBank,",
+ "IconCashBanknote,",
+ "IconCoin,",
+ "IconCreditCard,",
+ "IconReceipt,",
+ "IconReceiptRefund,",
+ "IconReceiptTax,",
+ "IconRepeat,",
+ "IconReport,",
+ "} from '@tabler/icons-react';",
+ "import { ReactNode } from 'react';",
+ "import { useRoutes } from 'react-router-dom';",
+ "export function useDashboardItems(): {",
+ "links: UiDashboardItem[];",
+ "routes: ReactNode;",
+ "} {",
+ "const links: UiDashboardItem[] = [",
+ "{ to: 'credit-cards', label: 'Credit cards', icon: IconCreditCard },",
+ "{ to: 'banks-nearby', label: 'Banks nearby', icon: IconBuildingBank },",
+ "{ to: 'transfers', label: 'Transfers', icon: IconRepeat },",
+ "{ to: 'refunds', label: 'Refunds', icon: IconReceiptRefund },",
+ "{ to: 'receipts', label: 'Receipts', icon: IconReceipt },",
+ "{ to: 'taxes', label: 'Taxes', icon: IconReceiptTax },",
+ "{ to: 'reports', label: 'Reports', icon: IconReport },",
+ "{ to: 'payments', label: 'Payments', icon: IconCoin },",
+ "{ to: 'cashback', label: 'Cashback', icon: IconCashBanknote },",
+ "];",
+ "const routes = useRoutes([",
+ "{ index: true, element: Dashboard Grid
},",
+ "...links.map((link) => ({",
+ "path: link.to,",
+ "element: {link.label}
,",
+ "})),",
+ "]);",
+ "return {",
+ "links,",
+ "routes,",
+ "};",
+ "}",
+ "export function DemoFeatureDashboardGrid() {",
+ "const base = '/demo/dashboard-grid';",
+ "const { links, routes } = useDashboardItems();",
+ "return (",
+ "",
+ " ({",
+ "to: \`\${base}/\${to}\`,",
+ "label,",
+ "icon,",
+ "}))}",
+ "/>",
+ "{routes}",
+ "",
+ ");",
+ "}",
+ ],
+ "isBinary": false,
+ "path": "./test/demo-feature-dashboard-grid.tsx",
+ },
"demo-feature-debug.tsx": {
"content": [
"import { SimpleGrid } from '@mantine/core';",
@@ -665,6 +733,7 @@ exports[`feature generator should create files for demo 1`] = `
"import { DemoFeatureAlerts } from './demo-feature-alerts';",
"import { DemoFeatureCard } from './demo-feature-card';",
"import { DemoFeatureCopy } from './demo-feature-copy';",
+ "import { DemoFeatureDashboardGrid } from './demo-feature-dashboard-grid';",
"import { DemoFeatureDebug } from './demo-feature-debug';",
"import { DemoFeatureGroup } from './demo-feature-group';",
"import { DemoFeatureHeader } from './demo-feature-header';",
@@ -685,6 +754,11 @@ exports[`feature generator should create files for demo 1`] = `
"{ path: 'alerts', label: 'Alerts', element: },",
"{ path: 'card', label: 'Card', element: },",
"{ path: 'copy', label: 'Copy', element: },",
+ "{",
+ "path: 'dashboard-grid',",
+ "label: 'Dashboard Grid',",
+ "element: ,",
+ "},",
"{ path: 'debug', label: 'Debug', element: },",
"{ path: 'group', label: 'Group', element: },",
"{ path: 'header', label: 'Header', element: },",
diff --git a/packages/generators/src/generators/feature/files/demo/demo-feature-dashboard-grid.tsx.template b/packages/generators/src/generators/feature/files/demo/demo-feature-dashboard-grid.tsx.template
new file mode 100644
index 0000000..8a909a8
--- /dev/null
+++ b/packages/generators/src/generators/feature/files/demo/demo-feature-dashboard-grid.tsx.template
@@ -0,0 +1,57 @@
+import { <%= prefix.className %>Card, <%= prefix.className %>DashboardGrid, <%= prefix.className %>DashboardItem, <%= prefix.className %>Stack } from '<%= uiImport %>'
+import {
+ IconBuildingBank,
+ IconCashBanknote,
+ IconCoin,
+ IconCreditCard,
+ IconReceipt,
+ IconReceiptRefund,
+ IconReceiptTax,
+ IconRepeat,
+ IconReport,
+} from '@tabler/icons-react'
+import { ReactNode } from 'react'
+import { useRoutes } from 'react-router-dom'
+
+export function useDashboardItems(): {
+ links: <%= prefix.className %>DashboardItem[]
+ routes: ReactNode
+} {
+ const links: <%= prefix.className %>DashboardItem[] = [
+ { to: 'credit-cards', label: 'Credit cards', icon: IconCreditCard },
+ { to: 'banks-nearby', label: 'Banks nearby', icon: IconBuildingBank },
+ { to: 'transfers', label: 'Transfers', icon: IconRepeat },
+ { to: 'refunds', label: 'Refunds', icon: IconReceiptRefund },
+ { to: 'receipts', label: 'Receipts', icon: IconReceipt },
+ { to: 'taxes', label: 'Taxes', icon: IconReceiptTax },
+ { to: 'reports', label: 'Reports', icon: IconReport },
+ { to: 'payments', label: 'Payments', icon: IconCoin },
+ { to: 'cashback', label: 'Cashback', icon: IconCashBanknote },
+ ]
+ const routes = useRoutes([
+ { index: true, element: Dashboard Grid
},
+ ...links.map((link) => ({ path: link.to, element: {link.label}
})),
+ ])
+
+ return {
+ links,
+ routes,
+ }
+}
+
+export function DemoFeatureDashboardGrid() {
+ const base = '/demo/dashboard-grid'
+ const { links, routes } = useDashboardItems()
+ return (
+ <<%= prefix.className %>Stack>
+ <<%= prefix.className %>DashboardGrid
+ links={links.map(({ to, label, icon }) => ({
+ to: `${base}/${to}`,
+ label,
+ icon,
+ }))}
+ />
+ <<%= prefix.className %>Card>{routes}<%= prefix.className %>Card>
+ <%= prefix.className %>Stack>
+ )
+}
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 fda97c6..018c5c6 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
@@ -5,6 +5,7 @@ import { Link, Navigate, useLocation, useRoutes } from 'react-router-dom'
import { DemoFeatureAlerts } from './demo-feature-alerts'
import { DemoFeatureCard } from './demo-feature-card'
import { DemoFeatureCopy } from './demo-feature-copy'
+import { DemoFeatureDashboardGrid } from './demo-feature-dashboard-grid'
import { DemoFeatureDebug } from './demo-feature-debug'
import { DemoFeatureGroup } from './demo-feature-group'
import { DemoFeatureHeader } from './demo-feature-header'
@@ -26,6 +27,7 @@ element: ReactNode
{ path: 'alerts', label: 'Alerts', element: },
{ path: 'card', label: 'Card', element: },
{ path: 'copy', label: 'Copy', element: },
+{ path: 'dashboard-grid', label: 'Dashboard Grid', element: },
{ path: 'debug', label: 'Debug', element: },
{ path: 'group', label: 'Group', element: },
{ path: 'header', label: 'Header', element: },
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 b65bf8d..6964d15 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
@@ -99,6 +99,74 @@ exports[`features generator should run successfully 1`] = `
"isBinary": false,
"path": "./test/demo/demo-feature-copy.tsx",
},
+ "demo-feature-dashboard-grid.tsx": {
+ "content": [
+ "import {",
+ "UiCard,",
+ "UiDashboardGrid,",
+ "UiDashboardItem,",
+ "UiStack,",
+ "} from '@pubkey-ui/core';",
+ "import {",
+ "IconBuildingBank,",
+ "IconCashBanknote,",
+ "IconCoin,",
+ "IconCreditCard,",
+ "IconReceipt,",
+ "IconReceiptRefund,",
+ "IconReceiptTax,",
+ "IconRepeat,",
+ "IconReport,",
+ "} from '@tabler/icons-react';",
+ "import { ReactNode } from 'react';",
+ "import { useRoutes } from 'react-router-dom';",
+ "export function useDashboardItems(): {",
+ "links: UiDashboardItem[];",
+ "routes: ReactNode;",
+ "} {",
+ "const links: UiDashboardItem[] = [",
+ "{ to: 'credit-cards', label: 'Credit cards', icon: IconCreditCard },",
+ "{ to: 'banks-nearby', label: 'Banks nearby', icon: IconBuildingBank },",
+ "{ to: 'transfers', label: 'Transfers', icon: IconRepeat },",
+ "{ to: 'refunds', label: 'Refunds', icon: IconReceiptRefund },",
+ "{ to: 'receipts', label: 'Receipts', icon: IconReceipt },",
+ "{ to: 'taxes', label: 'Taxes', icon: IconReceiptTax },",
+ "{ to: 'reports', label: 'Reports', icon: IconReport },",
+ "{ to: 'payments', label: 'Payments', icon: IconCoin },",
+ "{ to: 'cashback', label: 'Cashback', icon: IconCashBanknote },",
+ "];",
+ "const routes = useRoutes([",
+ "{ index: true, element: Dashboard Grid
},",
+ "...links.map((link) => ({",
+ "path: link.to,",
+ "element: {link.label}
,",
+ "})),",
+ "]);",
+ "return {",
+ "links,",
+ "routes,",
+ "};",
+ "}",
+ "export function DemoFeatureDashboardGrid() {",
+ "const base = '/demo/dashboard-grid';",
+ "const { links, routes } = useDashboardItems();",
+ "return (",
+ "",
+ " ({",
+ "to: \`\${base}/\${to}\`,",
+ "label,",
+ "icon,",
+ "}))}",
+ "/>",
+ "{routes}",
+ "",
+ ");",
+ "}",
+ ],
+ "isBinary": false,
+ "path": "./test/demo/demo-feature-dashboard-grid.tsx",
+ },
"demo-feature-debug.tsx": {
"content": [
"import { SimpleGrid } from '@mantine/core';",
@@ -667,6 +735,7 @@ exports[`features generator should run successfully 1`] = `
"import { DemoFeatureAlerts } from './demo-feature-alerts';",
"import { DemoFeatureCard } from './demo-feature-card';",
"import { DemoFeatureCopy } from './demo-feature-copy';",
+ "import { DemoFeatureDashboardGrid } from './demo-feature-dashboard-grid';",
"import { DemoFeatureDebug } from './demo-feature-debug';",
"import { DemoFeatureGroup } from './demo-feature-group';",
"import { DemoFeatureHeader } from './demo-feature-header';",
@@ -687,6 +756,11 @@ exports[`features generator should run successfully 1`] = `
"{ path: 'alerts', label: 'Alerts', element: },",
"{ path: 'card', label: 'Card', element: },",
"{ path: 'copy', label: 'Copy', element: },",
+ "{",
+ "path: 'dashboard-grid',",
+ "label: 'Dashboard Grid',",
+ "element: ,",
+ "},",
"{ path: 'debug', label: 'Debug', element: },",
"{ path: 'group', label: 'Group', element: },",
"{ path: 'header', label: 'Header', element: },",
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 cf52784..e0591b8 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
@@ -244,6 +244,7 @@ exports[`theme generator should run successfully 1`] = `
"export * from './ui-card';",
"export * from './ui-container';",
"export * from './ui-copy';",
+ "export * from './ui-dashboard-grid';",
"export * from './ui-debug';",
"export * from './ui-group';",
"export * from './ui-header';",
@@ -466,6 +467,108 @@ exports[`theme generator should run successfully 1`] = `
},
"path": "./test-target/src/app/ui/ui-copy",
},
+ "ui-dashboard-grid": {
+ "children": {
+ "index.ts": {
+ "content": [
+ "export * from './ui-dashboard-grid';",
+ ],
+ "isBinary": false,
+ "path": "./test-target/src/app/ui/ui-dashboard-grid/index.ts",
+ },
+ "ui-dashboard-grid.module.css": {
+ "content": [
+ ".item {",
+ "display: flex;",
+ "flex-direction: column;",
+ "align-items: center;",
+ "justify-content: center;",
+ "text-align: center;",
+ "border-radius: var(--mantine-radius-md);",
+ "height: rem(180px);",
+ "background-color: light-dark(",
+ "var(--mantine-color-white),",
+ "var(--mantine-color-dark-7)",
+ ");",
+ "transition: box-shadow 150ms ease, transform 100ms ease;",
+ "@mixin hover {",
+ "box-shadow: var(--mantine-shadow-md) !important;",
+ "transform: scale(1.05);",
+ "}",
+ "}",
+ ],
+ "isBinary": false,
+ "path": "./test-target/src/app/ui/ui-dashboard-grid/ui-dashboard-grid.module.css",
+ },
+ "ui-dashboard-grid.tsx": {
+ "content": [
+ "import {",
+ "SimpleGrid,",
+ "Text,",
+ "UnstyledButton,",
+ "useMantineTheme,",
+ "} from '@mantine/core';",
+ "import { useUiTheme } from '../ui-theme';",
+ "import { ComponentType } from 'react';",
+ "import classes from './ui-dashboard-grid.module.css';",
+ "const linkColors = [",
+ "'violet',",
+ "'indigo',",
+ "'blue',",
+ "'green',",
+ "'teal',",
+ "'cyan',",
+ "'pink',",
+ "'red',",
+ "'orange',",
+ "];",
+ "export function getColorByIndex(index: number) {",
+ "return linkColors[index % linkColors.length];",
+ "}",
+ "export interface UiDashboardItem {",
+ "icon: ComponentType<{ color?: string; size: number | string }>;",
+ "label: string;",
+ "to: string;",
+ "color?: string;",
+ "}",
+ "export interface UiDashboardGridProps {",
+ "links: UiDashboardItem[];",
+ "}",
+ "export function UiDashboardGrid({ links }: UiDashboardGridProps) {",
+ "const { Link } = useUiTheme();",
+ "const theme = useMantineTheme();",
+ "const items = links.map((item, index) => (",
+ "",
+ "",
+ "",
+ "{item.label}",
+ "",
+ "",
+ "));",
+ "return (",
+ "",
+ "{items}",
+ "",
+ ");",
+ "}",
+ ],
+ "isBinary": false,
+ "path": "./test-target/src/app/ui/ui-dashboard-grid/ui-dashboard-grid.tsx",
+ },
+ },
+ "path": "./test-target/src/app/ui/ui-dashboard-grid",
+ },
"ui-debug": {
"children": {
"index.ts": {
@@ -612,7 +715,10 @@ exports[`theme generator should run successfully 1`] = `
"content": [
".header {",
"height: rem(56px);",
- "background-color: var(--mantine-color-body);",
+ "background-color: light-dark(",
+ "var(--mantine-color-white),",
+ "var(--mantine-color-dark-9)",
+ ");",
"padding-left: var(--mantine-spacing-md);",
"padding-right: var(--mantine-spacing-md);",
"}",