Merge pull request #28442 from backstage/canon-docs-updates
Canon docs updates
This commit is contained in:
@@ -4,6 +4,10 @@ body {
|
||||
background-color: var(--canon-background);
|
||||
color: var(--canon-text-primary);
|
||||
transition: background-color 0.2s ease-in-out;
|
||||
|
||||
--docs-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
||||
'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
||||
'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
}
|
||||
|
||||
iframe {
|
||||
|
||||
@@ -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>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 350 KiB |
@@ -3,10 +3,15 @@
|
||||
}
|
||||
|
||||
.container {
|
||||
padding-left: 300px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.container {
|
||||
padding-left: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
.page {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 300px;
|
||||
height: 100vh;
|
||||
color: var(--canon-text-primary);
|
||||
background-color: var(--canon-surface-1);
|
||||
border-right: 1px solid var(--canon-border-base);
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
|
||||
overflow: hidden;
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.sidebar {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 300px;
|
||||
height: 100vh;
|
||||
color: var(--canon-text-primary);
|
||||
background-color: var(--canon-surface-1);
|
||||
border-right: 1px solid var(--canon-border-base);
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
|
||||
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;
|
||||
@@ -46,6 +46,13 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
font-family: var(--docs-font);
|
||||
font-size: var(--canon-font-size-body);
|
||||
font-weight: var(--canon-font-weight-bold);
|
||||
padding: 12px 0;
|
||||
}
|
||||
|
||||
.line {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
@@ -65,3 +72,16 @@
|
||||
.line.active {
|
||||
background-color: var(--canon-surface-2);
|
||||
}
|
||||
|
||||
.lineTitle {
|
||||
font-family: var(--docs-font);
|
||||
font-size: var(--canon-font-size-body);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
color: var(--canon-text-primary);
|
||||
}
|
||||
|
||||
.lineStatus {
|
||||
font-family: var(--docs-font);
|
||||
font-size: var(--canon-font-size-body);
|
||||
color: var(--canon-text-secondary);
|
||||
}
|
||||
|
||||
@@ -55,9 +55,7 @@ export const Docs = () => {
|
||||
return (
|
||||
<Fragment key={section.title}>
|
||||
<Box marginTop="lg" marginBottom="2xs">
|
||||
<Text variant="body" weight="bold">
|
||||
{section.title}
|
||||
</Text>
|
||||
<div className={styles.sectionTitle}>{section.title}</div>
|
||||
</Box>
|
||||
{section.content.map(item => {
|
||||
const isActive = pathname === `${section.url}/${item.slug}`;
|
||||
@@ -68,17 +66,14 @@ export const Docs = () => {
|
||||
key={item.slug}
|
||||
className={`${styles.line} ${isActive ? styles.active : ''}`}
|
||||
>
|
||||
<Text variant="body">{item.title}</Text>
|
||||
<Text
|
||||
variant="body"
|
||||
style={{ color: 'var(--canon-text-secondary)' }}
|
||||
>
|
||||
<div className={styles.lineTitle}>{item.title}</div>
|
||||
<div className={styles.lineStatus}>
|
||||
{item.status === 'alpha' && 'Alpha'}
|
||||
{item.status === 'beta' && 'Beta'}
|
||||
{item.status === 'inProgress' && 'In Progress'}
|
||||
{item.status === 'stable' && 'Stable'}
|
||||
{item.status === 'deprecated' && 'Deprecated'}
|
||||
</Text>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
'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 { usePlayground } from '@/utils/playground-context';
|
||||
|
||||
export const TabsVersion = () => {
|
||||
const { selectedThemeName, setSelectedThemeName } = usePlayground();
|
||||
return (
|
||||
<Tabs.Root
|
||||
className={styles.tabs}
|
||||
onValueChange={setSelectedThemeName}
|
||||
value={selectedThemeName}
|
||||
>
|
||||
<Tabs.List className={styles.list}>
|
||||
<Tabs.Tab className={styles.tab} value="legacy">
|
||||
<Text variant="caption" weight="bold">
|
||||
Theme 1
|
||||
</Text>
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab className={styles.tab} value="default">
|
||||
<Text variant="caption" weight="bold">
|
||||
Theme 2
|
||||
</Text>
|
||||
</Tabs.Tab>
|
||||
<Tabs.Indicator className={styles.indicator} />
|
||||
</Tabs.List>
|
||||
</Tabs.Root>
|
||||
);
|
||||
};
|
||||
|
||||
export const TabsTheme = () => {
|
||||
const { selectedTheme, setSelectedTheme } = usePlayground();
|
||||
|
||||
return (
|
||||
<Tabs.Root
|
||||
className={styles.tabsTheme}
|
||||
onValueChange={setSelectedTheme}
|
||||
value={selectedTheme}
|
||||
>
|
||||
<Tabs.List className={styles.list}>
|
||||
<Tabs.Tab className={styles.tab} value="light">
|
||||
<Icon name="sun" />
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab className={styles.tab} value="dark">
|
||||
<Icon name="moon" />
|
||||
</Tabs.Tab>
|
||||
<Tabs.Indicator className={styles.indicator} />
|
||||
</Tabs.List>
|
||||
</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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
import { ThemeSelector } from './theme';
|
||||
import { ThemeNameSelector } from './theme-name';
|
||||
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}>
|
||||
<ThemeNameSelector />
|
||||
<ThemeSelector />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
.tabs {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.tabs {
|
||||
display: block;
|
||||
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: var(--canon-spacing-lg);
|
||||
}
|
||||
|
||||
.tab {
|
||||
all: unset;
|
||||
height: 60px;
|
||||
font-family: var(--docs-font);
|
||||
color: var(--canon-text-secondary);
|
||||
font-size: var(--canon-font-size-body);
|
||||
font-weight: var(--canon-font-weight-bold);
|
||||
cursor: pointer;
|
||||
transition: color 0.2s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
color: var(--canon-text-primary);
|
||||
}
|
||||
|
||||
&[data-selected] {
|
||||
color: var(--canon-text-primary);
|
||||
|
||||
& p {
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
'use client';
|
||||
|
||||
import { Tabs } from '@base-ui-components/react/tabs';
|
||||
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('/');
|
||||
}}
|
||||
>
|
||||
Documentation
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab
|
||||
className={styles.tab}
|
||||
value="playground"
|
||||
onClick={() => {
|
||||
router.push('/playground');
|
||||
}}
|
||||
>
|
||||
Playground
|
||||
</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: 10;
|
||||
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-sm);
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
.Select {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
height: 2rem;
|
||||
padding-left: 0.875rem;
|
||||
padding-right: 0.75rem;
|
||||
margin: 0;
|
||||
outline: 0;
|
||||
border: 1px solid var(--color-gray-200);
|
||||
border-radius: 0.375rem;
|
||||
font-family: inherit;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5rem;
|
||||
color: var(--color-gray-900);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
background-color: var(--canon-surface-2);
|
||||
transition: background-color 0.2s ease-in-out;
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--color-blue);
|
||||
outline-offset: -1px;
|
||||
}
|
||||
}
|
||||
|
||||
.SelectIcon {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.SelectValue {
|
||||
font-size: var(--canon-font-size-body);
|
||||
font-weight: var(--canon-font-weight-regular);
|
||||
}
|
||||
|
||||
.Positioner {
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.Popup {
|
||||
box-sizing: border-box;
|
||||
padding-block: 0.25rem;
|
||||
border-radius: 0.375rem;
|
||||
background-color: canvas;
|
||||
color: var(--color-gray-900);
|
||||
border: 1px solid var(--canon-border-base);
|
||||
padding-inline: 0.25rem;
|
||||
transform-origin: var(--transform-origin);
|
||||
transition: transform 150ms, opacity 150ms;
|
||||
|
||||
&[data-starting-style],
|
||||
&[data-ending-style] {
|
||||
opacity: 0;
|
||||
transform: scale(0.9);
|
||||
}
|
||||
|
||||
&[data-side='none'] {
|
||||
transition: none;
|
||||
transform: none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
outline: 1px solid var(--color-gray-200);
|
||||
box-shadow: 0px 10px 15px -3px var(--color-gray-200),
|
||||
0px 4px 6px -4px var(--color-gray-200);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
outline: 1px solid var(--color-gray-300);
|
||||
outline-offset: -1px;
|
||||
}
|
||||
}
|
||||
|
||||
.Item {
|
||||
box-sizing: border-box;
|
||||
outline: 0;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1rem;
|
||||
padding-block: 0.5rem;
|
||||
padding-left: 0.625rem;
|
||||
padding-right: 1rem;
|
||||
font-size: var(--canon-font-size-body);
|
||||
font-weight: var(--canon-font-weight-bold);
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
grid-template-columns: 0.75rem 1fr;
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
border-radius: 0.25rem;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease-in-out;
|
||||
|
||||
[data-side='none'] & {
|
||||
font-size: 1rem;
|
||||
padding-right: 3rem;
|
||||
min-width: calc(var(--anchor-width) + 1rem);
|
||||
}
|
||||
|
||||
&[data-highlighted] {
|
||||
z-index: 0;
|
||||
position: relative;
|
||||
color: var(--color-gray-50);
|
||||
background-color: var(--canon-surface-2);
|
||||
}
|
||||
|
||||
&[data-highlighted]::before {
|
||||
content: '';
|
||||
z-index: -1;
|
||||
position: absolute;
|
||||
inset-block: 0;
|
||||
inset-inline: 0.25rem;
|
||||
border-radius: 0.25rem;
|
||||
background-color: var(--color-gray-900);
|
||||
}
|
||||
}
|
||||
|
||||
.ItemIndicator {
|
||||
grid-column-start: 1;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ItemIndicatorIcon {
|
||||
display: block;
|
||||
width: 0.75rem;
|
||||
height: 0.75rem;
|
||||
}
|
||||
|
||||
.ItemText {
|
||||
grid-column-start: 2;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
'use client';
|
||||
|
||||
import { Select } from '@base-ui-components/react/select';
|
||||
import styles from './theme-name.module.css';
|
||||
import { Icon } from '@backstage/canon';
|
||||
import { usePlayground } from '@/utils/playground-context';
|
||||
|
||||
const themes = [
|
||||
{ name: 'Backstage Legacy', value: 'legacy' },
|
||||
{ name: 'Backstage Default', value: 'default' },
|
||||
];
|
||||
|
||||
export const ThemeNameSelector = () => {
|
||||
const { selectedThemeName, setSelectedThemeName } = usePlayground();
|
||||
|
||||
return (
|
||||
<Select.Root
|
||||
value={selectedThemeName || 'default'}
|
||||
onValueChange={setSelectedThemeName}
|
||||
>
|
||||
<Select.Trigger className={styles.Select}>
|
||||
<Select.Value
|
||||
className={styles.SelectValue}
|
||||
placeholder="Select a theme"
|
||||
/>
|
||||
<Select.Icon className={styles.SelectIcon}>
|
||||
<Icon name="chevronDown" />
|
||||
</Select.Icon>
|
||||
</Select.Trigger>
|
||||
<Select.Portal>
|
||||
<Select.Positioner className={styles.Positioner} sideOffset={8}>
|
||||
<Select.Popup className={styles.Popup}>
|
||||
{themes.map(({ name, value }) => (
|
||||
<Select.Item className={styles.Item} value={value}>
|
||||
<Select.ItemIndicator className={styles.ItemIndicator}>
|
||||
<Icon name="check" />
|
||||
</Select.ItemIndicator>
|
||||
<Select.ItemText className={styles.ItemText}>
|
||||
{name}
|
||||
</Select.ItemText>
|
||||
</Select.Item>
|
||||
))}
|
||||
</Select.Popup>
|
||||
</Select.Positioner>
|
||||
</Select.Portal>
|
||||
</Select.Root>
|
||||
);
|
||||
};
|
||||
+6
-10
@@ -6,7 +6,7 @@
|
||||
}
|
||||
|
||||
.tabsTheme {
|
||||
width: 142px;
|
||||
width: 100px;
|
||||
border-radius: 0.375rem;
|
||||
background-color: var(--canon-surface-2);
|
||||
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
|
||||
@@ -29,21 +29,17 @@
|
||||
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;
|
||||
color: var(--canon-text-secondary);
|
||||
user-select: none;
|
||||
height: 2.25rem;
|
||||
height: 2rem;
|
||||
flex: 1;
|
||||
cursor: pointer;
|
||||
|
||||
&[data-selected] {
|
||||
color: var(--canon-text-primary) !important;
|
||||
color: var(--canon-text-primary);
|
||||
|
||||
& p {
|
||||
color: var(--canon-text-primary) !important;
|
||||
color: var(--canon-text-primary);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +74,7 @@
|
||||
top: 50%;
|
||||
translate: var(--active-tab-left) -50%;
|
||||
width: var(--active-tab-width);
|
||||
height: 1.8rem;
|
||||
height: 1.5rem;
|
||||
border-radius: 0.25rem;
|
||||
background-color: var(--canon-surface-1);
|
||||
transition-property: translate, width, background-color;
|
||||
@@ -0,0 +1,28 @@
|
||||
'use client';
|
||||
|
||||
import { Tabs } from '@base-ui-components/react/tabs';
|
||||
import { Icon } from '@backstage/canon';
|
||||
import { usePlayground } from '@/utils/playground-context';
|
||||
import styles from './theme.module.css';
|
||||
|
||||
export const ThemeSelector = () => {
|
||||
const { selectedTheme, setSelectedTheme } = usePlayground();
|
||||
|
||||
return (
|
||||
<Tabs.Root
|
||||
className={styles.tabsTheme}
|
||||
onValueChange={setSelectedTheme}
|
||||
value={selectedTheme}
|
||||
>
|
||||
<Tabs.List className={styles.list}>
|
||||
<Tabs.Tab className={styles.tab} value="light">
|
||||
<Icon name="sun" />
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab className={styles.tab} value="dark">
|
||||
<Icon name="moon" />
|
||||
</Tabs.Tab>
|
||||
<Tabs.Indicator className={styles.indicator} />
|
||||
</Tabs.List>
|
||||
</Tabs.Root>
|
||||
);
|
||||
};
|
||||
@@ -1,33 +1,64 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
import type { MDXComponents } from 'mdx/types';
|
||||
import Image, { ImageProps } from 'next/image';
|
||||
import { ReactNode } from 'react';
|
||||
import React from 'react';
|
||||
import { CodeBlock } from '@/components/CodeBlock';
|
||||
import { Heading } from '../../packages/canon/src/components/Heading';
|
||||
import { Text } from '../../packages/canon/src/components/Text';
|
||||
import { Box } from '../../packages/canon/src/components/Box';
|
||||
|
||||
export function useMDXComponents(components: MDXComponents): MDXComponents {
|
||||
return {
|
||||
// Allows customizing built-in components, e.g. to add styling.
|
||||
h1: ({ children }) => (
|
||||
<Box marginBottom="md" style={{ marginTop: '4rem' }}>
|
||||
<Heading variant="title2">{children as ReactNode}</Heading>
|
||||
<Box style={{ marginTop: '4rem' }}>
|
||||
<h1
|
||||
style={{
|
||||
fontFamily: 'var(--docs-font)',
|
||||
fontSize: '3rem',
|
||||
fontWeight: 'var(--canon-font-weight-bold)',
|
||||
margin: 0,
|
||||
}}
|
||||
>
|
||||
{children as ReactNode}
|
||||
</h1>
|
||||
</Box>
|
||||
),
|
||||
h2: ({ children }) => (
|
||||
<Box marginTop="2xl" marginBottom="md">
|
||||
<Heading variant="title4">{children as ReactNode}</Heading>
|
||||
<h2
|
||||
style={{
|
||||
fontFamily: 'var(--docs-font)',
|
||||
fontSize: '1.5rem',
|
||||
fontWeight: 'var(--canon-font-weight-bold)',
|
||||
}}
|
||||
>
|
||||
{children as ReactNode}
|
||||
</h2>
|
||||
</Box>
|
||||
),
|
||||
h3: ({ children }) => (
|
||||
<Box marginTop="xl" marginBottom="xs">
|
||||
<Heading variant="title5">{children as ReactNode}</Heading>
|
||||
<h3
|
||||
style={{
|
||||
fontFamily: 'var(--docs-font)',
|
||||
fontSize: '1.25rem',
|
||||
fontWeight: 'var(--canon-font-weight-bold)',
|
||||
}}
|
||||
>
|
||||
{children as ReactNode}
|
||||
</h3>
|
||||
</Box>
|
||||
),
|
||||
p: ({ children }) => (
|
||||
<Box marginBottom="sm">
|
||||
<Text variant="subtitle">{children as ReactNode}</Text>
|
||||
<p
|
||||
style={{
|
||||
fontFamily: 'var(--docs-font)',
|
||||
fontSize: '1rem',
|
||||
lineHeight: '1.5',
|
||||
}}
|
||||
>
|
||||
{children as ReactNode}
|
||||
</p>
|
||||
</Box>
|
||||
),
|
||||
a: ({ children, href }) => (
|
||||
@@ -42,6 +73,21 @@ export function useMDXComponents(components: MDXComponents): MDXComponents {
|
||||
|
||||
return <CodeBlock lang="tsx" code={codeContent} />;
|
||||
},
|
||||
code: ({ children }) => (
|
||||
<code
|
||||
style={{
|
||||
fontFamily: 'var(--canon-font-monospace)',
|
||||
backgroundColor: 'var(--canon-surface-1)',
|
||||
padding: '0.2rem 0.375rem',
|
||||
borderRadius: '0.25rem',
|
||||
color: 'var(--canon-text-secondary)',
|
||||
border: '1px solid var(--canon-border-base)',
|
||||
fontSize: '0.875rem',
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</code>
|
||||
),
|
||||
img: props => (
|
||||
<Image
|
||||
sizes="100vw"
|
||||
|
||||
Reference in New Issue
Block a user