Add playground navigation
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
@@ -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,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>
|
||||
);
|
||||
};
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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",
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user