diff --git a/apps/web/src/app/app-routes.tsx b/apps/web/src/app/app-routes.tsx index 9830f93..a810ba6 100644 --- a/apps/web/src/app/app-routes.tsx +++ b/apps/web/src/app/app-routes.tsx @@ -1,4 +1,4 @@ -import { UiThemeLink } from '@pubkey-ui/core' +import { UiNotFound, UiThemeLink } from '@pubkey-ui/core' import { lazy } from 'react' import { Link, Navigate, RouteObject, useRoutes } from 'react-router-dom' import { DemoFeature } from './features' @@ -17,6 +17,7 @@ const routes: RouteObject[] = [ { path: '/dashboard', element: }, { path: '/demo/*', element: }, { path: '/dev', element: }, + { path: '*', element: }, ] export function AppRoutes() { diff --git a/apps/web/src/app/features/demo/demo-feature-not-found.tsx b/apps/web/src/app/features/demo/demo-feature-not-found.tsx new file mode 100644 index 0000000..8b88733 --- /dev/null +++ b/apps/web/src/app/features/demo/demo-feature-not-found.tsx @@ -0,0 +1,10 @@ +import { UiCardTitle, UiNotFound, UiStack } from '@pubkey-ui/core' + +export function DemoFeatureNotFound() { + return ( + + NotFound + + + ) +} diff --git a/apps/web/src/app/features/demo/demo-feature.tsx b/apps/web/src/app/features/demo/demo-feature.tsx index 31e15fe..60dd0a6 100644 --- a/apps/web/src/app/features/demo/demo-feature.tsx +++ b/apps/web/src/app/features/demo/demo-feature.tsx @@ -1,5 +1,5 @@ import { Grid, NavLink } from '@mantine/core' -import { UiContainer, UiStack } from '@pubkey-ui/core' +import { UiContainer, UiNotFound, UiStack } from '@pubkey-ui/core' import { ReactNode } from 'react' import { Link, Navigate, useLocation, useRoutes } from 'react-router-dom' import { DemoFeatureAlerts } from './demo-feature-alerts' @@ -11,6 +11,7 @@ import { DemoFeatureGroup } from './demo-feature-group' import { DemoFeatureHeader } from './demo-feature-header' import { DemoFeatureLogo } from './demo-feature-logo' import { DemoFeatureMenu } from './demo-feature-menu' +import { DemoFeatureNotFound } from './demo-feature-not-found' import { DemoFeatureSearchInput } from './demo-feature-search-input' import { DemoFeatureStack } from './demo-feature-stack' import { DemoFeatureTabRoutes } from './demo-feature-tab-routes' @@ -33,6 +34,7 @@ export function DemoFeature() { { path: 'header', label: 'Header', element: }, { path: 'logo', label: 'Logo', element: }, { path: 'menu', label: 'Menu', element: }, + { path: 'not-found', label: 'Not Found', element: }, { path: 'search-input', label: 'Search Input', element: }, { path: 'stack', label: 'Stack', element: }, { path: 'tab-routes', label: 'Tab Routes', element: }, @@ -43,6 +45,7 @@ export function DemoFeature() { const routes = useRoutes([ { index: true, element: }, ...demos.map((demo) => ({ path: `${demo.path}/*`, element: demo.element })), + { path: '*', element: }, ]) return ( diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts index be93fe0..349b5bb 100644 --- a/packages/core/src/lib/index.ts +++ b/packages/core/src/lib/index.ts @@ -9,6 +9,7 @@ export * from './ui-header' export * from './ui-layout' export * from './ui-logo' export * from './ui-menu' +export * from './ui-not-found' export * from './ui-search-input' export * from './ui-stack' export * from './ui-tab-routes' diff --git a/packages/core/src/lib/ui-card/index.ts b/packages/core/src/lib/ui-card/index.ts index 56f9779..2be55a7 100644 --- a/packages/core/src/lib/ui-card/index.ts +++ b/packages/core/src/lib/ui-card/index.ts @@ -1 +1,2 @@ export * from './ui-card' +export * from './ui-card-title' diff --git a/packages/core/src/lib/ui-not-found/index.ts b/packages/core/src/lib/ui-not-found/index.ts new file mode 100644 index 0000000..0160703 --- /dev/null +++ b/packages/core/src/lib/ui-not-found/index.ts @@ -0,0 +1 @@ +export * from './ui-not-found' diff --git a/packages/core/src/lib/ui-not-found/ui-not-found.module.css b/packages/core/src/lib/ui-not-found/ui-not-found.module.css new file mode 100644 index 0000000..fc981eb --- /dev/null +++ b/packages/core/src/lib/ui-not-found/ui-not-found.module.css @@ -0,0 +1,34 @@ +.root { + padding-top: rem(80px); + padding-bottom: rem(80px); +} + +.label { + text-align: center; + font-weight: 900; + font-size: rem(38px); + line-height: 1; + margin-bottom: calc(1.5 * var(--mantine-spacing-xl)); + color: var(--mantine-color-gray-2); + + @media (max-width: $mantine-breakpoint-sm) { + font-size: rem(32px); + } +} + +.description { + max-width: rem(500px); + margin: auto; + margin-top: var(--mantine-spacing-xl); + margin-bottom: calc(1.5 * var(--mantine-spacing-xl)); +} + +.title { + text-align: center; + font-weight: 900; + font-size: rem(38px); + + @media (max-width: $mantine-breakpoint-sm) { + font-size: rem(32px); + } +} diff --git a/packages/core/src/lib/ui-not-found/ui-not-found.tsx b/packages/core/src/lib/ui-not-found/ui-not-found.tsx new file mode 100644 index 0000000..720bf70 --- /dev/null +++ b/packages/core/src/lib/ui-not-found/ui-not-found.tsx @@ -0,0 +1,22 @@ +import { Button, Container, Group, Text, Title } from '@mantine/core' +import { useUiTheme } from '../ui-theme' +import classes from './ui-not-found.module.css' + +export function UiNotFound({ to = '/' }: { to?: string }) { + const { Link } = useUiTheme() + return ( + +
404
+ You have found a secret place. + + Unfortunately, this is only a 404 page. You may have mistyped the address, or the page has been moved to another + URL. + + + + +
+ ) +} 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 939530a..d053f4d 100644 --- a/packages/generators/src/generators/component/component-generator-schema.d.ts +++ b/packages/generators/src/generators/component/component-generator-schema.d.ts @@ -25,6 +25,7 @@ export interface ComponentGeneratorSchema { | 'layout' | 'logo' | 'menu' + | 'not-found' | 'search-input' | 'stack' | 'tab-routes' diff --git a/packages/generators/src/generators/component/component-generator-schema.json b/packages/generators/src/generators/component/component-generator-schema.json index ae8ac70..513999b 100644 --- a/packages/generators/src/generators/component/component-generator-schema.json +++ b/packages/generators/src/generators/component/component-generator-schema.json @@ -27,6 +27,7 @@ "layout", "logo", "menu", + "not-found", "search-input", "stack", "tab-routes", diff --git a/packages/generators/src/generators/component/files/card/index.ts.template b/packages/generators/src/generators/component/files/card/index.ts.template index 82720b8..015bf41 100644 --- a/packages/generators/src/generators/component/files/card/index.ts.template +++ b/packages/generators/src/generators/component/files/card/index.ts.template @@ -1 +1,2 @@ export * from './<%= prefixFileName %>-card' +export * from './<%= prefixFileName %>-card-title' diff --git a/packages/generators/src/generators/component/files/not-found/__prefixFileName__-not-found.module.css.template b/packages/generators/src/generators/component/files/not-found/__prefixFileName__-not-found.module.css.template new file mode 100644 index 0000000..fc981eb --- /dev/null +++ b/packages/generators/src/generators/component/files/not-found/__prefixFileName__-not-found.module.css.template @@ -0,0 +1,34 @@ +.root { + padding-top: rem(80px); + padding-bottom: rem(80px); +} + +.label { + text-align: center; + font-weight: 900; + font-size: rem(38px); + line-height: 1; + margin-bottom: calc(1.5 * var(--mantine-spacing-xl)); + color: var(--mantine-color-gray-2); + + @media (max-width: $mantine-breakpoint-sm) { + font-size: rem(32px); + } +} + +.description { + max-width: rem(500px); + margin: auto; + margin-top: var(--mantine-spacing-xl); + margin-bottom: calc(1.5 * var(--mantine-spacing-xl)); +} + +.title { + text-align: center; + font-weight: 900; + font-size: rem(38px); + + @media (max-width: $mantine-breakpoint-sm) { + font-size: rem(32px); + } +} diff --git a/packages/generators/src/generators/component/files/not-found/__prefixFileName__-not-found.tsx.template b/packages/generators/src/generators/component/files/not-found/__prefixFileName__-not-found.tsx.template new file mode 100644 index 0000000..660ab6a --- /dev/null +++ b/packages/generators/src/generators/component/files/not-found/__prefixFileName__-not-found.tsx.template @@ -0,0 +1,22 @@ +import { Button, Container, Group, Text, Title } from '@mantine/core' +import { use<%= prefix.className %>Theme } from '../<%= prefix.fileName %>-theme' +import classes from './<%= prefix.fileName %>-not-found.module.css' + +export function <%= prefix.className %>NotFound({ to = '/' }: { to?: string }) { + const { Link } = use<%= prefix.className %>Theme() + return ( + +
404
+ You have found a secret place. + + Unfortunately, this is only a 404 page. You may have mistyped the address, or the page has been moved to another + URL. + + + + +
+ ) +} diff --git a/packages/generators/src/generators/component/files/not-found/index.ts.template b/packages/generators/src/generators/component/files/not-found/index.ts.template new file mode 100644 index 0000000..091cfdd --- /dev/null +++ b/packages/generators/src/generators/component/files/not-found/index.ts.template @@ -0,0 +1 @@ +export * from './<%= prefix.fileName %>-not-found' diff --git a/packages/generators/src/generators/components/components.ts b/packages/generators/src/generators/components/components.ts index 49abb0c..ff5c9af 100644 --- a/packages/generators/src/generators/components/components.ts +++ b/packages/generators/src/generators/components/components.ts @@ -12,6 +12,7 @@ export const components: ComponentGeneratorSchema['type'][] = [ 'layout', 'logo', 'menu', + 'not-found', 'search-input', 'stack', 'tab-routes', diff --git a/packages/generators/src/generators/feature/files/demo/demo-feature-not-found.tsx.template b/packages/generators/src/generators/feature/files/demo/demo-feature-not-found.tsx.template new file mode 100644 index 0000000..8b88733 --- /dev/null +++ b/packages/generators/src/generators/feature/files/demo/demo-feature-not-found.tsx.template @@ -0,0 +1,10 @@ +import { UiCardTitle, UiNotFound, UiStack } from '@pubkey-ui/core' + +export function DemoFeatureNotFound() { + return ( + + NotFound + + + ) +} 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 018c5c6..1376cf1 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 @@ -1,5 +1,5 @@ import { Grid, NavLink } from '@mantine/core' -import { <%= prefix.className %>Container, <%= prefix.className %>Stack } from '<%= uiImport %>' +import { <%= prefix.className %>Container, <%= prefix.className %>NotFound, <%= prefix.className %>Stack } from '<%= uiImport %>' import { ReactNode } from 'react' import { Link, Navigate, useLocation, useRoutes } from 'react-router-dom' import { DemoFeatureAlerts } from './demo-feature-alerts' @@ -11,6 +11,7 @@ import { DemoFeatureGroup } from './demo-feature-group' import { DemoFeatureHeader } from './demo-feature-header' import { DemoFeatureLogo } from './demo-feature-logo' import { DemoFeatureMenu } from './demo-feature-menu' +import { DemoFeatureNotFound } from './demo-feature-not-found' import { DemoFeatureSearchInput } from './demo-feature-search-input' import { DemoFeatureStack } from './demo-feature-stack' import { DemoFeatureTabRoutes } from './demo-feature-tab-routes' @@ -33,6 +34,7 @@ element: ReactNode { path: 'header', label: 'Header', element: }, { path: 'logo', label: 'Logo', element: }, { path: 'menu', label: 'Menu', element: }, +{ path: 'not-found', label: 'Not Found', element: }, { path: 'search-input', label: 'Search Input', element: }, { path: 'stack', label: 'Stack', element: }, { path: 'tab-routes', label: 'Tab Routes', element: }, @@ -43,6 +45,7 @@ element: ReactNode const routes = useRoutes([ { index: true, element: }, ...demos.map((demo) => ({ path: `${demo.path}/*`, element: demo.element })), +{ path: '*', element: <<%= prefix.className %>NotFound to="/demo" /> }, ]) return (