diff --git a/docs/app/[...slug]/page.tsx b/docs/app/[...slug]/page.tsx index 37b3d47485..3330f8c628 100644 --- a/docs/app/[...slug]/page.tsx +++ b/docs/app/[...slug]/page.tsx @@ -2,6 +2,7 @@ import { notFound } from 'next/navigation'; import { Metadata } from 'next'; import { allContentPages } from 'contentlayer/generated'; +import { Headline } from '@/ui'; import { Mdx } from '@/ui/mdx'; interface ContentPageProps { @@ -51,8 +52,8 @@ export default async function ContentPage({ params }: ContentPageProps) { } return ( -
-

{page.title}

+
+ {page.title}
); diff --git a/docs/app/components/[...slug]/page.tsx b/docs/app/components/[...slug]/page.tsx index 8202178175..66a87a39c0 100644 --- a/docs/app/components/[...slug]/page.tsx +++ b/docs/app/components/[...slug]/page.tsx @@ -2,11 +2,12 @@ import { notFound } from 'next/navigation'; import { Metadata } from 'next'; import { allComponentPages } from 'contentlayer/generated'; +import { Headline } from '@/ui'; import { Mdx } from '@/ui/mdx'; -import { MarigoldThemeSwitch, ThemeMenu } from './_components'; - import { b2bTheme, coreTheme } from '@/theme'; +import { MarigoldThemeSwitch, ThemeMenu } from './_components'; + interface ComponentPageProps { params: { slug: string[]; @@ -59,8 +60,8 @@ export default async function ComponentPage({ params }: ComponentPageProps) { } return ( -
-

{page.title}

+
+ {page.title} diff --git a/docs/app/layout.tsx b/docs/app/layout.tsx index 780da13f5e..ceb9af679d 100644 --- a/docs/app/layout.tsx +++ b/docs/app/layout.tsx @@ -28,7 +28,7 @@ const Layout = ({ children }: { children: React.ReactNode }) => { -
+
{children}
diff --git a/docs/content/components/accordion/basic-accordion.demo.tsx b/docs/content/components/accordion/basic-accordion.demo.tsx new file mode 100644 index 0000000000..f1c4a08e3c --- /dev/null +++ b/docs/content/components/accordion/basic-accordion.demo.tsx @@ -0,0 +1,46 @@ +import { Accordion, Text } from '@marigold/components'; + +export default () => { + return ( + + + + Harry Potter and the Philosopher's Stone is a 1997 fantasy novel + written by British author J. K. Rowling. The first novel in the Harry + Potter series and Rowling's debut novel, it follows Harry Potter, a + young wizard who discovers his magical heritage on his eleventh + birthday, when he receives a letter of acceptance to Hogwarts School + of Witchcraft and Wizardry. Harry makes close friends and a few + enemies during his first year at the school and with the help of his + friends, Ron Weasley and Hermione Granger, he faces an attempted + comeback by the dark wizard Lord Voldemort, who killed Harry's + parents, but failed to kill Harry when he was just 15 months old. + + + + + Harry Potter and the Chamber of Secrets is a fantasy novel written by + British author J. K. Rowling and the second novel in the Harry Potter + series. The plot follows Harry's second year at Hogwarts School of + Witchcraft and Wizardry, during which a series of messages on the + walls of the school's corridors warn that the "Chamber of Secrets" has + been opened and that the "heir of Slytherin" would kill all pupils who + do not come from all-magical families. These threats are found after + attacks that leave residents of the school petrified. Throughout the + year, Harry and his friends Ron and Hermione investigate the attacks. + + + + + Harry Potter and the Prisoner of Azkaban is a fantasy novel written by + British author J. K. Rowling and is the third in the Harry Potter + series. The book follows Harry Potter, a young wizard, in his third + year at Hogwarts School of Witchcraft and Wizardry. Along with friends + Ronald Weasley and Hermione Granger, Harry investigates Sirius Black, + an escaped prisoner from Azkaban, the wizard prison, believed to be + one of Lord Voldemort's old allies. + + + + ); +}; diff --git a/docs/contentlayer.config.ts b/docs/contentlayer.config.ts index b82a22e636..2db77d950a 100644 --- a/docs/contentlayer.config.ts +++ b/docs/contentlayer.config.ts @@ -88,7 +88,26 @@ export default makeSource({ rehypePlugins: [ [rehypeComponentDemo, { contentDirPath }], rehypeSlug, - [rehypeAutolinkHeadings, { behavior: 'wrap' }], + [ + rehypeAutolinkHeadings, + { + behavior: 'wrap', + properties: { + class: [ + 'relative', + 'no-underline', + 'before:absolute', + 'before:-left-6', + 'before:inset-y-0', + 'before:flex', + 'before:items-center', + 'before:text-secondary-400', + 'before:text-2xl', + `hover:before:content-['#']`, + ].join(' '), + }, + }, + ], ], }, documentTypes: [ContentPage, ComponentPage], diff --git a/docs/lib/registry.ts b/docs/lib/registry.ts deleted file mode 100644 index 0e226a15e0..0000000000 --- a/docs/lib/registry.ts +++ /dev/null @@ -1,7 +0,0 @@ -import dynamic from 'next/dynamic'; - -export const registry: any = { - 'button-variant': dynamic( - () => import('@/content/components/button/button-variant.demo') - ), -}; diff --git a/docs/next.config.js b/docs/next.config.js index 7c2b165e6f..fb450e3b6f 100644 --- a/docs/next.config.js +++ b/docs/next.config.js @@ -13,9 +13,18 @@ const nextConfig = { }, transpilePackages: [ '@marigold/components', - '@marigold/theme-preset', '@marigold/system', + '@marigold/theme-preset', ], + async redirects() { + return [ + { + source: '/', + destination: '/introduction/getting-started', + permanent: true, + }, + ]; + }, }; module.exports = withContentlayer(nextConfig); diff --git a/docs/package.json b/docs/package.json index 0aa59ce000..ec21171fd6 100644 --- a/docs/package.json +++ b/docs/package.json @@ -3,15 +3,17 @@ "version": "5.6.0", "private": true, "scripts": { - "dev": "next dev", + "dev": "pnpm registry && next dev", "build": "next build", - "start": "next start" + "start": "next start", + "registry": "zx ./scripts/build-registry.mjs" }, "dependencies": { "@marigold/components": "workspace:*", "@marigold/eslint-config": "workspace:*", "@marigold/icons": "workspace:*", "@marigold/theme-preset": "workspace:*", + "@tailwindcss/typography": "0.5.9", "@vercel/analytics": "1.0.1", "autoprefixer": "10.4.14", "contentlayer": "0.3.4", @@ -26,7 +28,8 @@ "rehype-autolink-headings": "6.1.1", "rehype-slug": "5.1.0", "remark-gfm": "3.0.1", - "tailwindcss": "3.3.2" + "tailwindcss": "3.3.2", + "zx": "7.2.2" }, "devDependencies": { "@types/node": "18.16.19", diff --git a/docs/registry/index.tsx b/docs/registry/index.tsx new file mode 100644 index 0000000000..4928c33480 --- /dev/null +++ b/docs/registry/index.tsx @@ -0,0 +1,21 @@ +// @ts-nocheck +// This file is autogenerated by scripts/build-registry.ts +// Do not edit this file directly. +import dynamic from 'next/dynamic'; + +export const registry = { + 'basic-accordion': { + name: 'basic-accordion', + demo: dynamic( + () => import('@/content/components/accordion/basic-accordion.demo') + ), + file: 'content/components/accordion/basic-accordion.demo.tsx', + }, + 'button-variant': { + name: 'button-variant', + demo: dynamic( + () => import('@/content/components/button/button-variant.demo') + ), + file: 'content/components/button/button-variant.demo.tsx', + }, +} as const; diff --git a/docs/scripts/build-registry.mjs b/docs/scripts/build-registry.mjs new file mode 100644 index 0000000000..3344674131 --- /dev/null +++ b/docs/scripts/build-registry.mjs @@ -0,0 +1,34 @@ +#!/usr/bin/env zx +// Registry of demos ideas is based on https://github.com/shadcn/ui ! + +import fs from 'fs'; +import path, { basename } from 'path'; +import { glob } from 'zx'; + +let demoPath = await glob([`content/components/**/**.demo.tsx`]); + +console.log('📑 Building registry...'); + +let index = `// @ts-nocheck +// This file is autogenerated by scripts/build-registry.ts +// Do not edit this file directly. +import dynamic from 'next/dynamic'; + +export const registry = {`; + +for (const item of demoPath) { + const name = basename(item, '.demo.tsx'); + index += ` + '${name}': { + name: '${name}', + demo: dynamic( + () => import('@/${item.replace('.tsx', '')}') + ), + file: '${item}', + },`; +} +index += ` +} as const;`; + +fs.writeFileSync(path.join(process.cwd(), 'registry/index.tsx'), index); +console.log('✅ Registry build successfully!'); diff --git a/docs/tailwind.config.ts b/docs/tailwind.config.ts index d3abdd93e7..11004475e1 100644 --- a/docs/tailwind.config.ts +++ b/docs/tailwind.config.ts @@ -12,11 +12,15 @@ const config: Config = { './ui/**/*.{js,ts,jsx,tsx,mdx}', './app/**/*.{js,ts,jsx,tsx,mdx}', + // Used for the anchor links + './contentlayer.config.ts', + // Marigold components '../packages/{components,system}/**/*.{tsx,ts}', '!../packages/{components,system}/**/*.{stories,test}.{tsx,ts}', ], presets: [preset], + plugins: [require('@tailwindcss/typography')], }; export default config; diff --git a/docs/theme/components/Headline.styles.tsx b/docs/theme/components/Headline.styles.tsx deleted file mode 100644 index c32f5f140f..0000000000 --- a/docs/theme/components/Headline.styles.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { ThemeComponent, cva } from '@marigold/system'; - -export const Headline: ThemeComponent<'Headline'> = cva(); diff --git a/docs/tsconfig.json b/docs/tsconfig.json index 0c1c5d3613..84950d9389 100644 --- a/docs/tsconfig.json +++ b/docs/tsconfig.json @@ -4,8 +4,15 @@ "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, - "strict": true, + "strictNullChecks": true, + "strictBindCallApply": true, + "strictFunctionTypes": false, + "strictPropertyInitialization": true, + "noImplicitAny": true, + "noImplicitThis": true, + "useUnknownInCatchVariables": true, "forceConsistentCasingInFileNames": true, + "noUnusedLocals": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", @@ -24,7 +31,8 @@ "@/*": ["./*"], "@marigold/*": ["../packages/*/src", "../themes/*/src"], "contentlayer/generated": ["./.contentlayer/generated"] - } + }, + "strict": false }, "include": [ "**/*.ts", @@ -34,7 +42,8 @@ "../packages/**/*.ts", "../packages/**/*.tsx", "../.next/types/**/*.ts", - "contentlayer.config.ts" + "contentlayer.config.ts", + "scripts/build-registry.mjs" ], "exclude": ["node_modules"] } diff --git a/docs/ui/ComponentDemo.tsx b/docs/ui/ComponentDemo.tsx index 0676eeeb02..f177d7bee8 100644 --- a/docs/ui/ComponentDemo.tsx +++ b/docs/ui/ComponentDemo.tsx @@ -1,8 +1,8 @@ import { ReactNode } from 'react'; -import { registry } from '@/lib/registry'; +import { registry } from '../registry'; export interface ComponentDemoProps { - name: string; + name: keyof typeof registry; source: string; children?: ReactNode; } @@ -12,7 +12,7 @@ export const ComponentDemo = ({ source, children, }: ComponentDemoProps) => { - const Demo = registry[name]; + const Demo = registry[name].demo; return (
@@ -20,7 +20,6 @@ export const ComponentDemo = ({ {source}
-
{children}
diff --git a/docs/ui/mdx.tsx b/docs/ui/mdx.tsx index 5011549c75..5e79311cb2 100644 --- a/docs/ui/mdx.tsx +++ b/docs/ui/mdx.tsx @@ -48,14 +48,14 @@ const typography = { // MDX Components // --------------- const components = { + ...DocComponents, + ...typography, // TODO: wrap Marigold's Image/Link with next's image/link component ComponentDemo, Headline, Message, Text, IconList, - ...DocComponents, - ...typography, }; // Props diff --git a/package.json b/package.json index 4298602d30..0fd83b75d4 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "private": true, "license": "MIT", "engines": { - "node": ">=16.x" + "node": "18.x" }, "packageManager": "pnpm@8.6.6", "dependencies": { @@ -44,6 +44,7 @@ "build:docs": "pnpm --filter @marigold/docs... build", "build:storybook": "pnpm --filter @marigold/storybook-config... build", "build:themes": "pnpm --filter \"@marigold/theme*...\" build", + "registry": "pnpm --filter @marigold/docs registry", "test": "jest --config jest.config.js", "test:coverage": "jest --config jest.config.js --coverage --coverageReporters html", "test:ci": "jest --config jest.config.js --coverage --ci --no-cache", diff --git a/packages/components/src/Menu/Menu.test.tsx b/packages/components/src/Menu/Menu.test.tsx index 05aa147f75..940fab1b96 100644 --- a/packages/components/src/Menu/Menu.test.tsx +++ b/packages/components/src/Menu/Menu.test.tsx @@ -9,12 +9,7 @@ import { } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { OverlayProvider } from '@react-aria/overlays'; -import { - Theme, - ThemeProvider, - useResponsiveValue, - cva, -} from '@marigold/system'; +import { Theme, ThemeProvider, cva, useSmallScreen } from '@marigold/system'; import { Button } from '../Button'; import { Menu } from './Menu'; @@ -72,11 +67,7 @@ const mockMatchMedia = (matches: string[]) => matches: matches.includes(query), })); -window.matchMedia = mockMatchMedia([ - 'screen and (min-width: 40em)', - 'screen and (min-width: 52em)', - 'screen and (min-width: 64em)', -]); +window.matchMedia = mockMatchMedia(['(max-width: 600px)']); afterEach(cleanup); @@ -342,13 +333,10 @@ test('renders as tray', () => { if (event === 'resize') resize = cb; }); - const { result } = renderHook(() => - useResponsiveValue(['one', 'two', 'three', 'four']) - ); - window.matchMedia = mockMatchMedia([]); + const { result } = renderHook(() => useSmallScreen()); + window.matchMedia = mockMatchMedia(['(max-width: 600px)']); act(() => resize()); - - expect(result.current).toEqual('one'); + expect(result.current).toBeTruthy(); render( diff --git a/packages/components/src/Menu/MenuTrigger.tsx b/packages/components/src/Menu/MenuTrigger.tsx index d40f32c18f..321cb428dd 100644 --- a/packages/components/src/Menu/MenuTrigger.tsx +++ b/packages/components/src/Menu/MenuTrigger.tsx @@ -3,7 +3,7 @@ import { useMenuTriggerState } from '@react-stately/menu'; import { PressResponder } from '@react-aria/interactions'; import { useMenuTrigger } from '@react-aria/menu'; import { useObjectRef } from '@react-aria/utils'; -import { useResponsiveValue } from '@marigold/system'; +import { useSmallScreen } from '@marigold/system'; import { MenuContext, MenuContextProps } from './Context'; import { Popover, Tray } from '../Overlay'; @@ -44,8 +44,7 @@ export const MenuTrigger = ({ autoFocus: state.focusStrategy, }; - const isSmallScreen = useResponsiveValue([true, false, false], 2); - + const isSmallScreen = useSmallScreen(); return ( { }); test('supports to select an option and closes listbox afterwards', () => { - window.matchMedia = mockMatchMedia([ - 'screen and (min-width: 40em)', - 'screen and (min-width: 52em)', - 'screen and (min-width: 64em)', - ]); + window.matchMedia = mockMatchMedia(['screen and (min-width: 600px)']); render(