diff --git a/microsite-canon/app/components/[slug]/page.tsx b/microsite-canon/app/components/[slug]/page.tsx index 53d2030504..499c28685c 100644 --- a/microsite-canon/app/components/[slug]/page.tsx +++ b/microsite-canon/app/components/[slug]/page.tsx @@ -1,4 +1,4 @@ -import { components } from '@/utils/data'; +import { components, layoutComponents } from '@/utils/data'; import { notFound } from 'next/navigation'; import fs from 'fs'; import path from 'path'; @@ -24,7 +24,9 @@ export default async function Page({ } export function generateStaticParams() { - return components.map(component => ({ slug: component.slug })); + return [...components, ...layoutComponents].map(component => ({ + slug: component.slug, + })); } export const dynamicParams = false; diff --git a/microsite-canon/app/playground/page.tsx b/microsite-canon/app/playground/page.tsx index beeb015e65..4bb59426ce 100644 --- a/microsite-canon/app/playground/page.tsx +++ b/microsite-canon/app/playground/page.tsx @@ -1,3 +1,3 @@ export default function PlaygroundPage() { - return
Playground
; + return
; } diff --git a/microsite-canon/app/playground/styles.module.css b/microsite-canon/app/playground/styles.module.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/microsite-canon/components/Sidebar/Sidebar.module.css b/microsite-canon/components/Sidebar/Sidebar.module.css index a38ce6daf4..91dc8e03cc 100644 --- a/microsite-canon/components/Sidebar/Sidebar.module.css +++ b/microsite-canon/components/Sidebar/Sidebar.module.css @@ -10,6 +10,7 @@ padding-left: 20px; padding-right: 20px; transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out; + overflow: hidden; } .sidebar svg path { @@ -29,11 +30,28 @@ } .menu { - margin-top: 48px; + margin-top: 20px; + display: flex; + flex-direction: row; + position: relative; } .menu a { - display: block; + display: flex; text-decoration: none; - height: 1.75rem; + height: 28px; + align-items: center; +} + +.section { + width: 100%; +} + +.line { + width: 100%; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + height: 28px; } diff --git a/microsite-canon/components/Sidebar/docs.tsx b/microsite-canon/components/Sidebar/docs.tsx new file mode 100644 index 0000000000..8d1e079768 --- /dev/null +++ b/microsite-canon/components/Sidebar/docs.tsx @@ -0,0 +1,61 @@ +'use client'; + +import Link from 'next/link'; +import { components, coreConcepts, layoutComponents } from '@/utils/data'; +import { Box, Text } from '@backstage/canon'; +import { motion } from 'framer-motion'; +import styles from './Sidebar.module.css'; +import { usePathname } from 'next/navigation'; + +export const Docs = () => { + const pathname = usePathname(); + const isPlayground = pathname.includes('/playground'); + + return ( + + + + Core Concepts + + + {coreConcepts.map(concept => ( + + {concept.title} + + ))} + + + Layout Components + + + {layoutComponents.map(component => ( + + {component.title} + + ))} + + + Components + + + {components.map(component => ( + + {component.title} + + ))} + + ); +}; diff --git a/microsite-canon/components/Sidebar/index.tsx b/microsite-canon/components/Sidebar/index.tsx index 126570619c..f4136886ae 100644 --- a/microsite-canon/components/Sidebar/index.tsx +++ b/microsite-canon/components/Sidebar/index.tsx @@ -1,11 +1,16 @@ +'use client'; + import styles from './Sidebar.module.css'; -import Image from 'next/image'; import { TabsVersion, TabsTheme, TabsPages } from '../Tabs'; -import Link from 'next/link'; -import { components, coreConcepts } from '@/utils/data'; -import { Box, Text } from '@backstage/canon'; +import { usePathname } from 'next/navigation'; +import { AnimatePresence } from 'framer-motion'; +import { Docs } from './docs'; +import { Playground } from './playground'; export const Sidebar = () => { + const pathname = usePathname(); + const isPlayground = pathname.includes('/playground'); + return (
@@ -24,26 +29,8 @@ export const Sidebar = () => {
- - - Core Concepts - - - {coreConcepts.map(concept => ( - - {concept.title} - - ))} - - - Components - - - {components.map(component => ( - - {component.title} - - ))} + +
diff --git a/microsite-canon/components/Sidebar/playground.tsx b/microsite-canon/components/Sidebar/playground.tsx new file mode 100644 index 0000000000..ce4ffabcb2 --- /dev/null +++ b/microsite-canon/components/Sidebar/playground.tsx @@ -0,0 +1,61 @@ +import Link from 'next/link'; +import { components } from '@/utils/data'; +import { Box, Checkbox, Text } from '@backstage/canon'; +import { motion } from 'framer-motion'; +import styles from './Sidebar.module.css'; +import { usePathname } from 'next/navigation'; + +const breakpoints = [ + { title: 'XSmall', slug: 'xs' }, + { title: 'Small', slug: 'sm' }, + { title: 'Medium', slug: 'md' }, + { title: 'Large', slug: 'lg' }, + { title: 'XLarge', slug: 'xl' }, + { title: 'XXLarge', slug: '2xl' }, +]; + +export const Playground = () => { + const pathname = usePathname(); + const isPlayground = pathname.includes('/playground'); + + return ( + + + + Components + + + {components.map(({ slug, title }) => ( +
+ {title} + +
+ ))} + + + Breakpoints + + + {breakpoints.map(({ title }) => ( +
+ {title} + +
+ ))} +
+ ); +}; diff --git a/microsite-canon/package.json b/microsite-canon/package.json index 1b942b48fd..d90e4524da 100644 --- a/microsite-canon/package.json +++ b/microsite-canon/package.json @@ -19,6 +19,7 @@ "@mdx-js/react": "^3.1.0", "@next/mdx": "^15.1.3", "@types/mdx": "^2.0.13", + "motion": "^11.15.0", "next": "15.1.3", "next-themes": "^0.4.4", "react": "^19.0.0", diff --git a/microsite-canon/utils/data.ts b/microsite-canon/utils/data.ts index 12dbb1432c..bb4d52dec1 100644 --- a/microsite-canon/utils/data.ts +++ b/microsite-canon/utils/data.ts @@ -21,19 +21,11 @@ export const coreConcepts = [ }, ]; -export const components = [ +export const layoutComponents = [ { title: 'Box', slug: 'box', }, - { - title: 'Button', - slug: 'button', - }, - { - title: 'Checkbox', - slug: 'checkbox', - }, { title: 'Container', slug: 'container', @@ -42,14 +34,6 @@ export const components = [ title: 'Grid', slug: 'grid', }, - { - title: 'Heading', - slug: 'heading', - }, - { - title: 'Icon', - slug: 'icon', - }, { title: 'Inline', slug: 'inline', @@ -58,6 +42,25 @@ export const components = [ title: 'Stack', slug: 'stack', }, +]; + +export const components = [ + { + title: 'Button', + slug: 'button', + }, + { + title: 'Checkbox', + slug: 'checkbox', + }, + { + title: 'Heading', + slug: 'heading', + }, + { + title: 'Icon', + slug: 'icon', + }, { title: 'Table', slug: 'table', diff --git a/yarn.lock b/yarn.lock index 0d9c715db8..f7b2dbb2fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24544,6 +24544,7 @@ __metadata: "@types/react-dom": ^19 eslint: ^9 eslint-config-next: 15.1.3 + motion: ^11.15.0 next: 15.1.3 next-themes: ^0.4.4 react: ^19.0.0 @@ -30228,6 +30229,28 @@ __metadata: languageName: node linkType: hard +"framer-motion@npm:^11.15.0": + version: 11.15.0 + resolution: "framer-motion@npm:11.15.0" + dependencies: + motion-dom: ^11.14.3 + motion-utils: ^11.14.3 + tslib: ^2.4.0 + peerDependencies: + "@emotion/is-prop-valid": "*" + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/is-prop-valid": + optional: true + react: + optional: true + react-dom: + optional: true + checksum: 94ad254ca4874a9aa8eb64a721ad40e76a926489206d817ad4512b65d4506c65803714f9393309d352aa828b2272bbff8700878c92ab4d1202eab16a6efc45d7 + languageName: node + linkType: hard + "framer-motion@npm:^6.5.1": version: 6.5.1 resolution: "framer-motion@npm:6.5.1" @@ -37728,6 +37751,41 @@ __metadata: languageName: node linkType: hard +"motion-dom@npm:^11.14.3": + version: 11.14.3 + resolution: "motion-dom@npm:11.14.3" + checksum: af9e6f6bfd1ff5c08ccd1138d10fb08a2f4b86e968a3eaf180cdcb80e9c8f7ed34dcedffc18c4bf99cf5b64d8938b5ba5e6b88e7f46ffe5ed7b1d4c23150cae2 + languageName: node + linkType: hard + +"motion-utils@npm:^11.14.3": + version: 11.14.3 + resolution: "motion-utils@npm:11.14.3" + checksum: 49ca9cd5731ce50a53b35f9d3f0b1858bcd24c6e602bfd6d64c9ec0006a1f87ee57be3872d55503233555c1fcfaf358fc4e18c6e2771d31a676f1243833352c4 + languageName: node + linkType: hard + +"motion@npm:^11.15.0": + version: 11.15.0 + resolution: "motion@npm:11.15.0" + dependencies: + framer-motion: ^11.15.0 + tslib: ^2.4.0 + peerDependencies: + "@emotion/is-prop-valid": "*" + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@emotion/is-prop-valid": + optional: true + react: + optional: true + react-dom: + optional: true + checksum: fd8e07ce7552dfbc8bc845623b459c7d7742f2ae6d4cfe63717794a3016b6aa31687fe63da5e25d8bdb24f8894c83a1c5585e2bf8f6fdc7eb73c01d76070f590 + languageName: node + linkType: hard + "mri@npm:1.1.4": version: 1.1.4 resolution: "mri@npm:1.1.4"