Add top nav bar

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
Charles de Dreuille
2025-01-11 09:14:11 +00:00
parent 9f04ad87e0
commit f0f89c1baa
9 changed files with 195 additions and 81 deletions
+6 -6
View File
@@ -1,8 +1,9 @@
import type { Metadata } from 'next';
import { Sidebar } from '../components/Sidebar';
import { Toolbar } from '@/components/Toolbar';
import { Providers } from './providers';
import styles from './page.module.css';
import { Providers } from './providers';
import './globals.css';
import '/public/core.css';
@@ -19,10 +20,6 @@ export default function RootLayout({
}: Readonly<{
children: React.ReactNode;
}>) {
// const cookieStore = await cookies();
// const theme = cookieStore.get('theme')?.value || 'light';
// const themeName = cookieStore.get('theme-name')?.value || 'default';
return (
<html
lang="en"
@@ -34,7 +31,10 @@ export default function RootLayout({
<Providers>
<div className={styles.global}>
<Sidebar />
<div className={styles.container}>{children}</div>
<div className={styles.container}>
<Toolbar />
{children}
</div>
</div>
</Providers>
</body>
@@ -13,22 +13,15 @@
overflow: hidden;
}
.logoContainer {
padding-left: 6px;
padding-top: 32px;
}
.logo path {
fill: var(--canon-text-primary);
}
.content {
padding-top: 20px;
}
.actions {
display: flex;
flex-direction: row;
gap: 12px;
margin-top: 20px;
margin-bottom: 12px;
}
.menu {
display: flex;
flex-direction: row;
+5 -11
View File
@@ -1,5 +1,4 @@
import styles from './Sidebar.module.css';
import { TabsVersion, TabsPages, TabsTheme } from './tabs';
import { Docs } from './docs';
import { Playground } from './playground';
import Link from 'next/link';
@@ -7,7 +6,7 @@ import Link from 'next/link';
export const Sidebar = () => {
return (
<div className={styles.sidebar}>
<div className={styles.content}>
<div className={styles.logoContainer}>
<Link href="/">
<svg
width="89"
@@ -20,15 +19,10 @@ export const Sidebar = () => {
<path d="M14.037 16.729a4.237 4.237 0 0 0 4.234-4.24 4.237 4.237 0 0 0-4.234-4.242 4.237 4.237 0 0 0-4.234 4.241 4.237 4.237 0 0 0 4.234 4.24Z" />
</svg>
</Link>
<div className={styles.actions}>
<TabsVersion />
<TabsTheme />
</div>
<TabsPages />
<div className={styles.menu}>
<Docs />
<Playground />
</div>
</div>
<div className={styles.menu}>
<Docs />
<Playground />
</div>
</div>
);
@@ -0,0 +1,18 @@
import Link from 'next/link';
import { TabsVersion, TabsTheme } from './tabs';
import styles from './styles.module.css';
import { Nav } from './nav';
export const Toolbar = () => {
return (
<div className={styles.toolbar}>
<div>
<Nav />
</div>
<div className={styles.actions}>
<TabsVersion />
<TabsTheme />
</div>
</div>
);
};
@@ -0,0 +1,84 @@
.tabs {
height: 60px;
}
.tabsTheme {
width: 142px;
border-radius: 0.375rem;
background-color: var(--canon-surface-2);
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
}
.list {
display: flex;
position: relative;
z-index: 0;
gap: 1.5rem;
}
.tab {
height: 60px;
display: flex;
align-items: center;
justify-content: center;
border: 0;
margin: 0;
outline: 0;
background: none;
appearance: none;
color: var(--canon-text-secondary) !important;
font-family: inherit;
font-size: 0.75rem;
line-height: 1.25rem;
font-weight: 500;
user-select: none;
flex: 1;
cursor: pointer;
padding: 0;
&[data-selected] {
color: var(--canon-text-primary) !important;
& p {
color: var(--canon-text-primary) !important;
}
}
@media (hover: hover) {
&:hover {
color: var(--canon-text-primary);
}
}
&:focus-visible {
position: relative;
&::before {
content: '';
position: absolute;
inset: 0.25rem 0;
border-radius: 0.25rem;
outline: 2px solid var(--canon-surface-1);
outline-offset: -1px;
}
}
}
.tab p {
color: var(--canon-text-secondary) !important;
}
.indicator {
position: absolute;
z-index: -1;
left: 0;
bottom: -1px;
translate: var(--active-tab-left) -50%;
width: var(--active-tab-width);
height: 1px;
border-radius: 0.25rem;
background-color: var(--canon-text-primary);
transition-property: translate, width, background-color;
transition-duration: 200ms;
transition-timing-function: ease-in-out;
}
+54
View File
@@ -0,0 +1,54 @@
'use client';
import { Tabs } from '@base-ui-components/react/tabs';
import { Text } from '../../../../packages/canon';
import { usePathname } from 'next/navigation';
import { useRouter } from 'next/navigation';
import styles from './nav.module.css';
export const Nav = () => {
const pathname = usePathname();
const router = useRouter();
const onValueChange = (value: string) => {
if (value === 'docs') {
router.push('/');
} else {
router.push('/playground');
}
};
return (
<Tabs.Root
className={styles.tabs}
value={pathname.includes('playground') ? 'playground' : 'docs'}
onValueChange={onValueChange}
>
<Tabs.List className={styles.list}>
<Tabs.Tab
className={styles.tab}
value="docs"
onClick={() => {
router.push('/');
}}
>
<Text variant="caption" weight="bold">
Documentation
</Text>
</Tabs.Tab>
<Tabs.Tab
className={styles.tab}
value="playground"
onClick={() => {
router.push('/playground');
}}
>
<Text variant="caption" weight="bold">
Playground
</Text>
</Tabs.Tab>
<Tabs.Indicator className={styles.indicator} />
</Tabs.List>
</Tabs.Root>
);
};
@@ -0,0 +1,21 @@
.toolbar {
position: sticky;
top: 0;
left: 0;
right: 0;
z-index: 1000;
background-color: var(--canon-surface-1);
border-bottom: 1px solid var(--canon-border-base);
height: 60px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 var(--canon-spacing-md);
transition: background-color 0.2s ease-in-out;
}
.actions {
display: flex;
align-items: center;
gap: var(--canon-spacing-md);
}
@@ -1,12 +1,9 @@
'use client';
import styles from './Tabs.module.css';
import { Tabs } from '@base-ui-components/react/tabs';
import { Icon } from '../../../../packages/canon/src/components/Icon';
import { Text } from '../../../../packages/canon/src/components/Text';
import { usePathname } from 'next/navigation';
import { useRouter } from 'next/navigation';
import { Icon, Text } from '../../../../packages/canon';
import { usePlayground } from '@/utils/playground-context';
import styles from './tabs.module.css';
export const TabsVersion = () => {
const { selectedThemeName, setSelectedThemeName } = usePlayground();
@@ -54,50 +51,3 @@ export const TabsTheme = () => {
</Tabs.Root>
);
};
export const TabsPages = () => {
const pathname = usePathname();
const router = useRouter();
const onValueChange = (value: string) => {
if (value === 'docs') {
router.push('/');
} else {
router.push('/playground');
}
};
return (
<Tabs.Root
className={styles.tabs}
value={pathname.includes('playground') ? 'playground' : 'docs'}
onValueChange={onValueChange}
>
<Tabs.List className={styles.list}>
<Tabs.Tab
className={styles.tab}
value="docs"
onClick={() => {
router.push('/');
}}
>
<Text variant="caption" weight="bold">
Documentation
</Text>
</Tabs.Tab>
<Tabs.Tab
className={styles.tab}
value="playground"
onClick={() => {
router.push('/playground');
}}
>
<Text variant="caption" weight="bold">
Playground
</Text>
</Tabs.Tab>
<Tabs.Indicator className={styles.indicator} />
</Tabs.List>
</Tabs.Root>
);
};