style: Update CSS classes in Tabs and Callout components

This commit is contained in:
Gauthier Daniels 2025-04-11 12:19:56 +02:00
parent b8608c493c
commit d0dca7d956
9 changed files with 87 additions and 50 deletions

View File

@ -53,8 +53,8 @@ export function Tabs({
}} }}
> >
<div className="relative"> <div className="relative">
<div className="max-w-full overflow-auto"> <div className="max-w-full overflow-x-auto overflow-y-hidden">
<ul className="-mb-4 !p-0 w-max flex items-stretch gap-2" aria-orientation="horizontal" role="tablist"> <ul className="!p-0 w-max flex items-stretch gap-2" aria-orientation="horizontal" role="tablist">
{tabs.map((tab) => ( {tabs.map((tab) => (
<li key={tab.value} className="overflow-hidden" role="tab" aria-selected={selectedTab === tab.value}> <li key={tab.value} className="overflow-hidden" role="tab" aria-selected={selectedTab === tab.value}>
<TabItem tab={tab} isSelected={selectedTab === tab.value} select={() => selectTab(tab.value)} /> <TabItem tab={tab} isSelected={selectedTab === tab.value} select={() => selectTab(tab.value)} />
@ -62,7 +62,7 @@ export function Tabs({
))} ))}
</ul> </ul>
</div> </div>
<div className={clsx("p-2")}>{children}</div> <div className="-mt-6 p-2">{children}</div>
</div> </div>
</TabsContext.Provider> </TabsContext.Provider>
); );

View File

@ -3,14 +3,14 @@ import clsx from "clsx";
const styles = { const styles = {
note: { note: {
container: "bg-violet-50 dark:bg-slate-800/60 dark:ring-1 dark:ring-slate-300/10", container: "bg-violet-50 dark:bg-violet-800/60 dark:ring-1 dark:ring-violet-300/10",
title: "text-violet-900 dark:text-violet-400", title: "text-violet-900 dark:text-violet-400",
body: "text-violet-800 [--tw-prose-background:var(--color-violet-50)] prose-a:text-violet-900 prose-code:text-violet-900 dark:text-slate-300 dark:prose-code:text-slate-300", body: "text-slate-800 [--tw-prose-background:var(--color-slate-50)] prose-a:text-slate-900 prose-code:text-slate-900 dark:text-slate-300 dark:prose-code:text-slate-300",
}, },
warning: { warning: {
container: "bg-amber-50 dark:bg-slate-800/60 dark:ring-1 dark:ring-slate-300/10", container: "bg-amber-50 dark:bg-amber-800/60 dark:ring-1 dark:ring-amber-300/10",
title: "text-amber-900 dark:text-amber-500", title: "text-amber-900 dark:text-amber-500",
body: "text-amber-800 [--tw-prose-underline:var(--color-amber-400)] [--tw-prose-background:var(--color-amber-50)] prose-a:text-amber-900 prose-code:text-amber-900 dark:text-slate-300 dark:[--tw-prose-underline:var(--color-violet-700)] dark:prose-code:text-slate-300", body: "text-slate-800 [--tw-prose-underline:var(--color-slate-400)] [--tw-prose-background:var(--color-slate-50)] prose-a:text-slate-900 prose-code:text-slate-900 dark:text-slate-300 dark:[--tw-prose-underline:var(--color-slate-700)] dark:prose-code:text-slate-300",
}, },
}; };

View File

@ -38,8 +38,7 @@ export function Logo(props: React.ComponentPropsWithoutRef<"svg">) {
<svg viewBox="0 0 231 38" {...props}> <svg viewBox="0 0 231 38" {...props}>
<LogomarkPaths /> <LogomarkPaths />
<text <text
className="hidden lg:block" className="hidden lg:block fill-zinc-900 dark:fill-zinc-100"
fill="#1A202C"
fontFamily="Inter Variable, sans-serif" fontFamily="Inter Variable, sans-serif"
fontSize={24} fontSize={24}
fontWeight="bold" fontWeight="bold"

View File

@ -1,12 +1,11 @@
import { useEffect, useState } from "react";
// import { useTheme } from 'next-themes'
import { Label, Listbox, ListboxButton, ListboxOption, ListboxOptions } from "@headlessui/react"; import { Label, Listbox, ListboxButton, ListboxOption, ListboxOptions } from "@headlessui/react";
import { useEffect, useState } from "react";
import { useTheme } from "@/hooks/useTheme";
import clsx from "clsx"; import clsx from "clsx";
const themes = [ const themes = [
{ name: "Light", value: "light", icon: LightIcon }, { name: "Clair", value: "light", icon: LightIcon },
{ name: "Dark", value: "dark", icon: DarkIcon }, { name: "Sombre", value: "dark", icon: DarkIcon },
{ name: "System", value: "system", icon: SystemIcon },
]; ];
function LightIcon(props: React.ComponentPropsWithoutRef<"svg">) { function LightIcon(props: React.ComponentPropsWithoutRef<"svg">) {
@ -33,27 +32,9 @@ function DarkIcon(props: React.ComponentPropsWithoutRef<"svg">) {
); );
} }
function SystemIcon(props: React.ComponentPropsWithoutRef<"svg">) {
return (
<svg aria-hidden="true" viewBox="0 0 16 16" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M1 4a3 3 0 0 1 3-3h8a3 3 0 0 1 3 3v4a3 3 0 0 1-3 3h-1.5l.31 1.242c.084.333.36.573.63.808.091.08.182.158.264.24A1 1 0 0 1 11 15H5a1 1 0 0 1-.704-1.71c.082-.082.173-.16.264-.24.27-.235.546-.475.63-.808L5.5 11H4a3 3 0 0 1-3-3V4Zm3-1a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H4Z"
/>
</svg>
);
}
export function ThemeSelector(props: React.ComponentPropsWithoutRef<typeof Listbox<"div">>) { export function ThemeSelector(props: React.ComponentPropsWithoutRef<typeof Listbox<"div">>) {
const useTheme = () => {
return {
theme: "light",
setTheme: (theme: string) => {},
};
};
let { theme, setTheme } = useTheme();
let [mounted, setMounted] = useState(false); let [mounted, setMounted] = useState(false);
let { theme, setTheme } = useTheme();
useEffect(() => { useEffect(() => {
setMounted(true); setMounted(true);
@ -70,10 +51,8 @@ export function ThemeSelector(props: React.ComponentPropsWithoutRef<typeof Listb
className="flex h-6 w-6 items-center justify-center rounded-lg ring-1 shadow-md shadow-black/5 ring-black/5 dark:bg-slate-700 dark:ring-white/5 dark:ring-inset" className="flex h-6 w-6 items-center justify-center rounded-lg ring-1 shadow-md shadow-black/5 ring-black/5 dark:bg-slate-700 dark:ring-white/5 dark:ring-inset"
aria-label="Theme" aria-label="Theme"
> >
<LightIcon className={clsx("h-4 w-4 dark:hidden", theme === "system" ? "fill-slate-400" : "fill-violet-400")} /> <LightIcon className={clsx("h-4 w-4 dark:hidden", "fill-violet-400")} />
<DarkIcon <DarkIcon className={clsx("hidden h-4 w-4 dark:block", "fill-violet-400")} />
className={clsx("hidden h-4 w-4 dark:block", theme === "system" ? "fill-slate-400" : "fill-violet-400")}
/>
</ListboxButton> </ListboxButton>
<ListboxOptions className="absolute top-full left-1/2 mt-3 w-36 -translate-x-1/2 space-y-1 rounded-xl bg-white p-3 text-sm font-medium ring-1 shadow-md shadow-black/5 ring-black/5 dark:bg-slate-800 dark:ring-white/5"> <ListboxOptions className="absolute top-full left-1/2 mt-3 w-36 -translate-x-1/2 space-y-1 rounded-xl bg-white p-3 text-sm font-medium ring-1 shadow-md shadow-black/5 ring-black/5 dark:bg-slate-800 dark:ring-white/5">
{themes.map((theme) => ( {themes.map((theme) => (

View File

@ -0,0 +1,13 @@
import { createContext } from "react";
export type Theme = "light" | "dark";
export type ThemeContextType = {
theme: Theme;
setTheme: (theme: Theme) => void;
};
export const ThemeContext = createContext<ThemeContextType>({
theme: "light",
setTheme: () => {},
});

11
app/hooks/useTheme.ts Normal file
View File

@ -0,0 +1,11 @@
import { ThemeContext } from "@/contexts/ThemeContext";
import { useContext } from "react";
export function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error("useTheme must be used within a ThemeProvider");
}
return context;
}

View File

@ -1,8 +1,9 @@
import { MobileNavigation } from "@syntax/MobileNavigation"; import { MobileNavigation } from "@syntax/MobileNavigation";
import { usePageContext } from "vike-react/usePageContext"; import { usePageContext } from "vike-react/usePageContext";
import { ThemeProvider } from "@/providers/ThemeProvider";
import { ThemeSelector } from "@syntax/ThemeSelector"; import { ThemeSelector } from "@syntax/ThemeSelector";
import { Link } from "@/components/common/Link";
import { Navigation } from "@syntax/Navigation"; import { Navigation } from "@syntax/Navigation";
import { Link } from "@/components/common/Link";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Search } from "@syntax/Search"; import { Search } from "@syntax/Search";
import { Hero } from "@syntax/Hero"; import { Hero } from "@syntax/Hero";
@ -74,22 +75,24 @@ export default function DefaultLayout({ children }: { children: React.ReactNode
const isHomePage = urlPathname === "/"; const isHomePage = urlPathname === "/";
return ( return (
<div className="flex w-full flex-col"> <ThemeProvider>
<Header /> <div className="flex w-full flex-col">
<Header />
{isHomePage && <Hero />} {isHomePage && <Hero />}
<div className="relative mx-auto w-full flex max-w-8xl flex-auto justify-center sm:px-2 lg:px-8 xl:px-12"> <div className="relative mx-auto w-full flex max-w-8xl flex-auto justify-center sm:px-2 lg:px-8 xl:px-12">
<div className="hidden lg:relative lg:block lg:flex-none"> <div className="hidden lg:relative lg:block lg:flex-none">
<div className="absolute inset-y-0 right-0 w-[50vw] bg-slate-50 dark:hidden" /> <div className="absolute inset-y-0 right-0 w-[50vw] bg-slate-50 dark:hidden" />
<div className="absolute top-16 right-0 bottom-0 hidden h-12 w-px bg-linear-to-t from-slate-800 dark:block" /> <div className="absolute top-16 right-0 bottom-0 hidden h-12 w-px bg-linear-to-t from-slate-800 dark:block" />
<div className="absolute top-28 right-0 bottom-0 hidden w-px bg-slate-800 dark:block" /> <div className="absolute top-28 right-0 bottom-0 hidden w-px bg-slate-800 dark:block" />
<div className="sticky top-[4.75rem] -ml-0.5 h-[calc(100vh-4.75rem)] w-64 overflow-x-hidden overflow-y-auto py-16 pr-8 pl-0.5 xl:w-72 xl:pr-16"> <div className="sticky top-[4.75rem] -ml-0.5 h-[calc(100vh-4.75rem)] w-64 overflow-x-hidden overflow-y-auto py-16 pr-8 pl-0.5 xl:w-72 xl:pr-16">
<Navigation /> <Navigation />
</div>
</div> </div>
{children}
</div> </div>
{children}
</div> </div>
</div> </ThemeProvider>
); );
} }

View File

@ -36,6 +36,16 @@ const nodes = {
return new Tag(`h${node.attributes.level}`, { ...attributes, id }, children); return new Tag(`h${node.attributes.level}`, { ...attributes, id }, children);
}, },
}, },
strong: {
...defaultNodes.strong,
attributes: {
...defaultNodes.strong.attributes,
class: {
type: String,
default: "font-semibold text-slate-800 dark:text-slate-200",
},
},
},
th: { th: {
...defaultNodes.th, ...defaultNodes.th,
attributes: { attributes: {

View File

@ -0,0 +1,22 @@
import { ThemeContext, type Theme } from "@/contexts/ThemeContext";
import { useEffect, useState } from "react";
type ThemeProviderProps = {
children: React.ReactNode;
defaultTheme?: Theme;
};
export function ThemeProvider(props: ThemeProviderProps) {
const [theme, setTheme] = useState<Theme>(props.defaultTheme || "light");
useEffect(() => {
const rootElement = document.documentElement;
rootElement.classList.toggle("dark", theme === "dark");
rootElement.classList.toggle("light", theme === "light");
console.log("changed theme to", theme);
}, [theme]);
return <ThemeContext.Provider value={{ theme, setTheme }}>{props.children}</ThemeContext.Provider>;
}