From 52dd2f9429f41fd5e012173911a97ec54d97b469 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Wed, 1 Jan 2025 15:30:02 +0100 Subject: [PATCH] Improve tabs to work with cookies Signed-off-by: Charles de Dreuille --- microsite-canon/app/actions.ts | 21 ++++++++++ microsite-canon/app/layout.tsx | 16 +++++++- microsite-canon/app/providers.tsx | 5 +-- microsite-canon/components/Global/index.tsx | 2 - microsite-canon/components/Sidebar/index.tsx | 13 +++++-- .../components/Sidebar/playground.tsx | 2 - microsite-canon/components/Story/frame.tsx | 23 +++++++++++ microsite-canon/components/Story/index.tsx | 27 ++++--------- microsite-canon/components/Tabs/actions.ts | 25 ++++++++++++ microsite-canon/components/Tabs/index.tsx | 39 +++++++++---------- microsite-canon/package.json | 1 - microsite-canon/public/components.css | 2 +- yarn.lock | 11 ------ 13 files changed, 120 insertions(+), 67 deletions(-) create mode 100644 microsite-canon/app/actions.ts create mode 100644 microsite-canon/components/Story/frame.tsx create mode 100644 microsite-canon/components/Tabs/actions.ts diff --git a/microsite-canon/app/actions.ts b/microsite-canon/app/actions.ts new file mode 100644 index 0000000000..59d995ed68 --- /dev/null +++ b/microsite-canon/app/actions.ts @@ -0,0 +1,21 @@ +'use server'; + +import { cookies } from 'next/headers'; + +export async function setDefaultThemeCookie() { + const cookieStore = await cookies(); + const theme = cookieStore.get('theme'); + + if (theme === undefined) { + cookieStore.set('theme', 'light'); + } +} + +export async function setDefaultVersionCookie() { + const cookieStore = await cookies(); + const version = cookieStore.get('version'); + + if (version === undefined) { + cookieStore.set('version', 'v2'); + } +} diff --git a/microsite-canon/app/layout.tsx b/microsite-canon/app/layout.tsx index 4694e187dc..5f85b6a2d0 100644 --- a/microsite-canon/app/layout.tsx +++ b/microsite-canon/app/layout.tsx @@ -7,19 +7,31 @@ import '../../packages/canon/src/css/components.css'; import styles from './page.module.css'; import { Global } from '@/components/Global'; import { Providers } from './providers'; +import { cookies } from 'next/headers'; +import { setDefaultThemeCookie, setDefaultVersionCookie } from './actions'; export const metadata: Metadata = { title: 'Canon', description: 'UI library for Backstage', }; -export default function RootLayout({ +export default async function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { + const cookieStore = await cookies(); + const theme = cookieStore.get('theme')?.value || 'light'; + const version = cookieStore.get('version')?.value || 'v1'; + + let dataTheme = 'light'; + if (version === 'v1' && theme === 'light') dataTheme = 'backstage-light'; + if (version === 'v1' && theme === 'dark') dataTheme = 'backstage-dark'; + if (version === 'v2' && theme === 'light') dataTheme = 'light'; + if (version === 'v2' && theme === 'dark') dataTheme = 'dark'; + return ( - + diff --git a/microsite-canon/app/providers.tsx b/microsite-canon/app/providers.tsx index 9f999602f6..508d40b7df 100644 --- a/microsite-canon/app/providers.tsx +++ b/microsite-canon/app/providers.tsx @@ -2,15 +2,12 @@ import { ReactNode } from 'react'; import { CanonProvider } from '@backstage/canon'; -import { ThemeProvider } from 'next-themes'; import { PlaygroundProvider } from '@/utils/playground-context'; export const Providers = ({ children }: { children: ReactNode }) => { return ( - - {children} - + {children} ); }; diff --git a/microsite-canon/components/Global/index.tsx b/microsite-canon/components/Global/index.tsx index ab089eca25..e872b6b7d1 100644 --- a/microsite-canon/components/Global/index.tsx +++ b/microsite-canon/components/Global/index.tsx @@ -1,7 +1,5 @@ 'use client'; -import { useEffect } from 'react'; -import { useSearchParams } from 'next/navigation'; import styles from './styles.module.css'; export const Global = ({ children }: { children: React.ReactNode }) => { diff --git a/microsite-canon/components/Sidebar/index.tsx b/microsite-canon/components/Sidebar/index.tsx index 5778efaba0..2f73013264 100644 --- a/microsite-canon/components/Sidebar/index.tsx +++ b/microsite-canon/components/Sidebar/index.tsx @@ -1,9 +1,14 @@ import styles from './Sidebar.module.css'; -import { TabsVersion, TabsTheme, TabsPages } from '../Tabs'; +import { TabsVersion, TabsPages, TabsTheme } from '../Tabs'; import { Docs } from './docs'; import { Playground } from './playground'; +import { cookies } from 'next/headers'; + +export const Sidebar = async () => { + const cookieStore = await cookies(); + const theme = cookieStore.get('theme'); + const version = cookieStore.get('version'); -export const Sidebar = () => { return (
@@ -18,8 +23,8 @@ export const Sidebar = () => {
- - + +
diff --git a/microsite-canon/components/Sidebar/playground.tsx b/microsite-canon/components/Sidebar/playground.tsx index da772ee3f9..e20aa2e137 100644 --- a/microsite-canon/components/Sidebar/playground.tsx +++ b/microsite-canon/components/Sidebar/playground.tsx @@ -36,8 +36,6 @@ export const Playground = () => { } }; - console.log(selectedComponents); - return ( { + return ( + + ); +}; diff --git a/microsite-canon/components/Story/index.tsx b/microsite-canon/components/Story/index.tsx index 3b7a9430f8..339b300710 100644 --- a/microsite-canon/components/Story/index.tsx +++ b/microsite-canon/components/Story/index.tsx @@ -1,33 +1,20 @@ -'use client'; - -import { useTheme } from 'next-themes'; -import styles from './styles.module.css'; -import IframeResizer from '@iframe-resizer/react'; +import { cookies } from 'next/headers'; +import { Frame } from './frame'; interface StoryProps { id: string; border?: boolean; } -export const Story = ({ id, border = true }: StoryProps) => { - const { theme } = useTheme(); - - const localTheme = theme === 'dark' ? 'Dark' : 'Light'; +export const Story = async ({ id, border = true }: StoryProps) => { + const cookieStore = await cookies(); + const theme = cookieStore.get('theme'); + const localTheme = theme?.value === 'dark' ? 'Dark' : 'Light'; const chromaticId = '67584b7e8c2eb09c0422c27e-dmfbzicnkw'; const chromaticUrl = `https://${chromaticId}.chromatic.com/iframe.html`; const localUrl = 'http://localhost:6006/iframe.html'; const url = process.env.NODE_ENV === 'development' ? localUrl : chromaticUrl; const iframeUrl = `${url}?globals=theme%3A${localTheme}&args=&id=${id}`; - return ( - - ); + return ; }; diff --git a/microsite-canon/components/Tabs/actions.ts b/microsite-canon/components/Tabs/actions.ts new file mode 100644 index 0000000000..41812fbab1 --- /dev/null +++ b/microsite-canon/components/Tabs/actions.ts @@ -0,0 +1,25 @@ +'use server'; + +import { cookies } from 'next/headers'; + +export async function setThemeCookie() { + const cookieStore = await cookies(); + const theme = cookieStore.get('theme'); + + if (theme?.value === 'dark') { + cookieStore.set('theme', 'light'); + } else { + cookieStore.set('theme', 'dark'); + } +} + +export async function setVersionCookie() { + const cookieStore = await cookies(); + const version = cookieStore.get('version'); + + if (version?.value === 'v1') { + cookieStore.set('version', 'v2'); + } else { + cookieStore.set('version', 'v1'); + } +} diff --git a/microsite-canon/components/Tabs/index.tsx b/microsite-canon/components/Tabs/index.tsx index 566f6beb41..6293dabb34 100644 --- a/microsite-canon/components/Tabs/index.tsx +++ b/microsite-canon/components/Tabs/index.tsx @@ -3,14 +3,21 @@ import styles from './Tabs.module.css'; import { Tabs } from '@base-ui-components/react/tabs'; import { Icon, Text } from '@backstage/canon'; -import { usePathname, useSearchParams } from 'next/navigation'; +import { usePathname } from 'next/navigation'; import { useRouter } from 'next/navigation'; -import { useTheme } from 'next-themes'; -import { useEffect, useState } from 'react'; +import { setThemeCookie, setVersionCookie } from './actions'; -export const TabsVersion = () => { +export const TabsVersion = ({ + version, +}: { + version?: { value: string; name: string }; +}) => { return ( - + @@ -28,24 +35,16 @@ export const TabsVersion = () => { ); }; -export const TabsTheme = () => { - const { theme, setTheme } = useTheme(); - - const onValueChange = (value: string) => { - setTheme(value); - }; - - const [isClient, setIsClient] = useState(false); - - useEffect(() => { - setIsClient(true); - }, []); - +export const TabsTheme = ({ + theme, +}: { + theme?: { value: string; name: string }; +}) => { return ( diff --git a/microsite-canon/package.json b/microsite-canon/package.json index c8f5c71bdd..e65face1a1 100644 --- a/microsite-canon/package.json +++ b/microsite-canon/package.json @@ -20,7 +20,6 @@ "@types/mdx": "^2.0.13", "motion": "^11.15.0", "next": "15.1.3", - "next-themes": "^0.4.4", "react": "^19.0.0", "react-dom": "^19.0.0", "react-frame-component": "^5.2.7" diff --git a/microsite-canon/public/components.css b/microsite-canon/public/components.css index 2af88526e0..07f65ac0be 100644 --- a/microsite-canon/public/components.css +++ b/microsite-canon/public/components.css @@ -1 +1 @@ -.cn-button{all:unset;user-select:none;font-family:var(--canon-font-regular);font-weight:var(--canon-font-weight-bold);font-size:var(--canon-font-size-body);cursor:pointer;border-radius:8px;justify-content:center;align-items:center;padding:0;transition:all .15s;display:inline-flex}.cn-button-primary{background-color:var(--canon-accent);color:var(--canon-text-primary-on-accent);&:hover{box-shadow:inset 0 0 0 1px var(--canon-outline-focus);color:var(--canon-text-primary);background-color:#0000}}.cn-button-secondary{box-shadow:inset 0 0 0 1px var(--canon-outline);color:var(--canon-text-primary);background-color:#0000;&:hover{box-shadow:inset 0 0 0 1px var(--canon-outline-hover)}}.cn-button-tertiary{color:var(--canon-text-primary);background-color:#0000;&:hover{color:var(--canon-text-secondary)}}.cn-button-small{height:32px;padding-left:6px;padding-right:6px}.cn-button-medium{height:40px;padding-left:8px;padding-right:8px}.cn-button-content{align-items:center;gap:var(--canon-spacing-xs);font-weight:var(--canon-font-weight-bold);display:flex}.cn-button-content-icon-both{flex:1}.canon-stack{flex-direction:column;display:flex}.canon-inline{flex-wrap:wrap;display:flex}.canon-grid{display:grid}.canon-container{max-width:var(--canon-container-max-width);padding:0 var(--canon-container-padding);margin:0 auto}.icon-12{width:12px;height:12px}.icon-16{width:16px;height:16px}.icon-24{width:24px;height:24px}.checkbox-label{justify-content:center;align-items:center;gap:var(--canon-spacing-xs);font-size:var(--canon-font-size-xs);font-family:var(--canon-font-regular);color:var(--canon-text-primary);user-select:none;flex-direction:row;display:flex;&:hover{& .checkbox{box-shadow:inset 0 0 0 1px var(--canon-border-hover)}}}.checkbox{all:unset;width:1rem;height:1rem;box-shadow:inset 0 0 0 1px var(--canon-border-base);cursor:pointer;border-radius:2px;justify-content:center;align-items:center;transition:all .2s ease-in-out;display:flex;&[data-checked]{background-color:var(--canon-accent)}}.checkbox-indicator{color:var(--canon-text-primary-on-accent);justify-content:center;align-items:center;display:flex}.table{background-color:var(--canon-surface-1);border-radius:var(--canon-border-radius-xs);width:100%;padding-bottom:var(--canon-spacing-5xs);padding-top:var(--canon-spacing-5xs);font-size:var(--canon-font-size-body);position:relative;overflow:auto;& table{caption-side:bottom;width:100%;font-size:var(--canon-font-size-sm);border-collapse:collapse}}.table-head{text-align:left;padding:var(--canon-spacing-xs)}.table-body{& tr:last-child{border-bottom:none}}.table-row{transition:color .2s ease-in-out;&:hover td{background-color:var(--canon-surface-3)}& .table-cell:first-child{border-top-left-radius:var(--canon-border-radius-xs);border-bottom-left-radius:var(--canon-border-radius-xs);box-shadow:inset 4px 2px 0 0 var(--canon-surface-1),inset 4px -2px 0 0 var(--canon-surface-1);padding-left:var(--canon-spacing-xs)}& .table-cell:last-child{border-top-right-radius:var(--canon-border-radius-xs);border-bottom-right-radius:var(--canon-border-radius-xs);box-shadow:inset -4px 2px 0 0 var(--canon-surface-1),inset -4px -2px 0 0 var(--canon-surface-1);padding-right:var(--canon-spacing-xs)}}.table-cell{padding:var(--canon-spacing-xs);background-color:var(--canon-surface-2);box-shadow:inset 0px 2px 0 0 var(--canon-surface-1),inset 0px -2px 0 0 var(--canon-surface-1)}.text{font-family:var(--canon-font-regular);color:var(--canon-text-primary);margin:0;padding:0;&.text-body{font-size:var(--canon-font-size-body);line-height:140%}&.text-subtitle{font-size:var(--canon-font-size-subtitle);line-height:140%}&.text-caption{font-size:var(--canon-font-size-caption);line-height:140%}&.text-label{font-size:var(--canon-font-size-label);line-height:140%}&.text-regular{font-weight:var(--canon-font-weight-regular)}&.text-bold{font-weight:var(--canon-font-weight-bold)}}.text{font-family:var(--canon-font-regular);color:var(--canon-text-primary);margin:0;padding:0;&.text-display{font-size:var(--canon-font-size-display);line-height:100%;font-weight:var(--canon-font-weight-bold)}&.text-title1{font-size:var(--canon-font-size-title1);line-height:100%;font-weight:var(--canon-font-weight-bold)}&.text-title2{font-size:var(--canon-font-size-title2);line-height:100%;font-weight:var(--canon-font-weight-bold)}&.text-title3{font-size:var(--canon-font-size-title3);line-height:100%;font-weight:var(--canon-font-weight-bold)}&.text-title4{font-size:var(--canon-font-size-title4);line-height:100%;font-weight:var(--canon-font-weight-bold)}&.text-title5{font-size:var(--canon-font-size-title5);line-height:100%;font-weight:var(--canon-font-weight-bold)}} \ No newline at end of file +.cn-button{all:unset;user-select:none;font-family:var(--canon-font-regular);font-weight:var(--canon-font-weight-bold);font-size:var(--canon-font-size-body);cursor:pointer;border-radius:8px;justify-content:center;align-items:center;padding:0;transition:all .15s;display:inline-flex}.cn-button-primary{background-color:var(--canon-accent);color:var(--canon-text-primary-on-accent);&:hover{box-shadow:inset 0 0 0 1px var(--canon-border-focus);color:var(--canon-text-primary);background-color:#0000}}.cn-button-secondary{box-shadow:inset 0 0 0 1px var(--canon-border-base);color:var(--canon-text-primary);background-color:#0000;&:hover{box-shadow:inset 0 0 0 1px var(--canon-border-hover)}}.cn-button-tertiary{color:var(--canon-text-primary);background-color:#0000;&:hover{color:var(--canon-text-secondary)}}.cn-button-small{height:32px;padding-left:6px;padding-right:6px}.cn-button-medium{height:40px;padding-left:8px;padding-right:8px}.cn-button-content{align-items:center;gap:var(--canon-spacing-xs);font-weight:var(--canon-font-weight-bold);display:flex}.cn-button-content-icon-both{flex:1}.canon-stack{flex-direction:column;display:flex}.canon-inline{flex-wrap:wrap;display:flex}.canon-grid{display:grid}.canon-container{max-width:var(--canon-container-max-width);padding:0 var(--canon-container-padding);margin:0 auto}.icon-12{width:12px;height:12px}.icon-16{width:16px;height:16px}.icon-24{width:24px;height:24px}.checkbox-label{justify-content:center;align-items:center;gap:var(--canon-spacing-xs);font-size:var(--canon-font-size-xs);font-family:var(--canon-font-regular);color:var(--canon-text-primary);user-select:none;flex-direction:row;display:flex;&:hover{& .checkbox{box-shadow:inset 0 0 0 1px var(--canon-border-hover)}}}.checkbox{all:unset;width:1rem;height:1rem;box-shadow:inset 0 0 0 1px var(--canon-border-base);cursor:pointer;border-radius:2px;justify-content:center;align-items:center;transition:all .2s ease-in-out;display:flex;&[data-checked]{background-color:var(--canon-accent)}}.checkbox-indicator{color:var(--canon-text-primary-on-accent);justify-content:center;align-items:center;display:flex}.table{background-color:var(--canon-surface-1);border-radius:var(--canon-border-radius-xs);width:100%;padding-bottom:var(--canon-spacing-5xs);padding-top:var(--canon-spacing-5xs);font-size:var(--canon-font-size-body);position:relative;overflow:auto;& table{caption-side:bottom;width:100%;font-size:var(--canon-font-size-sm);border-collapse:collapse}}.table-head{text-align:left;padding:var(--canon-spacing-xs)}.table-body{& tr:last-child{border-bottom:none}}.table-row{transition:color .2s ease-in-out;&:hover td{background-color:var(--canon-surface-3)}& .table-cell:first-child{border-top-left-radius:var(--canon-border-radius-xs);border-bottom-left-radius:var(--canon-border-radius-xs);box-shadow:inset 4px 2px 0 0 var(--canon-surface-1),inset 4px -2px 0 0 var(--canon-surface-1);padding-left:var(--canon-spacing-xs)}& .table-cell:last-child{border-top-right-radius:var(--canon-border-radius-xs);border-bottom-right-radius:var(--canon-border-radius-xs);box-shadow:inset -4px 2px 0 0 var(--canon-surface-1),inset -4px -2px 0 0 var(--canon-surface-1);padding-right:var(--canon-spacing-xs)}}.table-cell{padding:var(--canon-spacing-xs);background-color:var(--canon-surface-2);box-shadow:inset 0px 2px 0 0 var(--canon-surface-1),inset 0px -2px 0 0 var(--canon-surface-1)}.text{font-family:var(--canon-font-regular);color:var(--canon-text-primary);margin:0;padding:0;&.text-body{font-size:var(--canon-font-size-body);line-height:140%}&.text-subtitle{font-size:var(--canon-font-size-subtitle);line-height:140%}&.text-caption{font-size:var(--canon-font-size-caption);line-height:140%}&.text-label{font-size:var(--canon-font-size-label);line-height:140%}&.text-regular{font-weight:var(--canon-font-weight-regular)}&.text-bold{font-weight:var(--canon-font-weight-bold)}}.text{font-family:var(--canon-font-regular);color:var(--canon-text-primary);margin:0;padding:0;&.text-display{font-size:var(--canon-font-size-display);line-height:100%;font-weight:var(--canon-font-weight-bold)}&.text-title1{font-size:var(--canon-font-size-title1);line-height:100%;font-weight:var(--canon-font-weight-bold)}&.text-title2{font-size:var(--canon-font-size-title2);line-height:100%;font-weight:var(--canon-font-weight-bold)}&.text-title3{font-size:var(--canon-font-size-title3);line-height:100%;font-weight:var(--canon-font-weight-bold)}&.text-title4{font-size:var(--canon-font-size-title4);line-height:100%;font-weight:var(--canon-font-weight-bold)}&.text-title5{font-size:var(--canon-font-size-title5);line-height:100%;font-weight:var(--canon-font-weight-bold)}} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index ac7596a89f..7474874865 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24570,7 +24570,6 @@ __metadata: lightningcss: ^1.28.2 motion: ^11.15.0 next: 15.1.3 - next-themes: ^0.4.4 react: ^19.0.0 react-dom: ^19.0.0 react-frame-component: ^5.2.7 @@ -38282,16 +38281,6 @@ __metadata: languageName: node linkType: hard -"next-themes@npm:^0.4.4": - version: 0.4.4 - resolution: "next-themes@npm:0.4.4" - peerDependencies: - react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - checksum: 9107fd68152eec5e4681e18c7ddbf17f8d4d65abc0ff3b17f6f5d8ee61d2b2106ee5f26d93942da52799214354eed3bb5d4a76a8bf2c7274e73ac09467441390 - languageName: node - linkType: hard - "next-tick@npm:1, next-tick@npm:^1.1.0": version: 1.1.0 resolution: "next-tick@npm:1.1.0"