Add playground navigation

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
Charles de Dreuille
2024-12-31 12:54:36 +01:00
parent 530412e599
commit 663b2738de
10 changed files with 238 additions and 47 deletions
@@ -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;
+1 -1
View File
@@ -1,3 +1,3 @@
export default function PlaygroundPage() {
return <div>Playground</div>;
return <div></div>;
}
@@ -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;
}
@@ -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 (
<motion.div
className={styles.section}
animate={{
x: isPlayground ? -10 : 0,
opacity: isPlayground ? 0 : 1,
visibility: isPlayground ? 'hidden' : 'visible',
}}
initial={{
x: isPlayground ? -10 : 0,
opacity: isPlayground ? 0 : 1,
visibility: isPlayground ? 'hidden' : 'visible',
}}
transition={{ duration: 0.2 }}
>
<Box marginTop="md" marginBottom="xs">
<Text variant="subtitle" weight="bold">
Core Concepts
</Text>
</Box>
{coreConcepts.map(concept => (
<Link href={`/core-concepts/${concept.slug}`} key={concept.slug}>
<Text variant="body">{concept.title}</Text>
</Link>
))}
<Box marginTop="md" marginBottom="xs">
<Text variant="subtitle" weight="bold">
Layout Components
</Text>
</Box>
{layoutComponents.map(component => (
<Link href={`/components/${component.slug}`} key={component.slug}>
<Text variant="body">{component.title}</Text>
</Link>
))}
<Box marginTop="md" marginBottom="xs">
<Text variant="subtitle" weight="bold">
Components
</Text>
</Box>
{components.map(component => (
<Link href={`/components/${component.slug}`} key={component.slug}>
<Text variant="body">{component.title}</Text>
</Link>
))}
</motion.div>
);
};
+11 -24
View File
@@ -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 (
<div className={styles.sidebar}>
<div className={styles.content}>
@@ -24,26 +29,8 @@ export const Sidebar = () => {
</div>
<TabsPages />
<div className={styles.menu}>
<Box marginTop="md" marginBottom="xs">
<Text variant="subtitle" weight="bold">
Core Concepts
</Text>
</Box>
{coreConcepts.map(concept => (
<Link href={`/core-concepts/${concept.slug}`} key={concept.slug}>
<Text variant="body">{concept.title}</Text>
</Link>
))}
<Box marginTop="md" marginBottom="xs">
<Text variant="subtitle" weight="bold">
Components
</Text>
</Box>
{components.map(component => (
<Link href={`/components/${component.slug}`} key={component.slug}>
<Text variant="body">{component.title}</Text>
</Link>
))}
<Docs />
<Playground />
</div>
</div>
</div>
@@ -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 (
<motion.div
className={styles.section}
animate={{
opacity: isPlayground ? 1 : 0,
x: isPlayground ? 0 : 20,
visibility: isPlayground ? 'visible' : 'hidden',
}}
initial={{
opacity: isPlayground ? 1 : 0,
x: isPlayground ? 0 : 20,
visibility: isPlayground ? 'visible' : 'hidden',
}}
transition={{ duration: 0.2 }}
style={{ position: 'absolute' }}
>
<Box marginTop="md" marginBottom="xs">
<Text variant="subtitle" weight="bold">
Components
</Text>
</Box>
{components.map(({ slug, title }) => (
<div className={styles.line}>
<Text variant="body">{title}</Text>
<Checkbox />
</div>
))}
<Box marginTop="md" marginBottom="xs">
<Text variant="subtitle" weight="bold">
Breakpoints
</Text>
</Box>
{breakpoints.map(({ title }) => (
<div className={styles.line}>
<Text variant="body">{title}</Text>
<Checkbox />
</div>
))}
</motion.div>
);
};
+1
View File
@@ -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",
+20 -17
View File
@@ -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',
+58
View File
@@ -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"