style: Update CSS classes in Tabs and Callout components
This commit is contained in:
parent
b8608c493c
commit
d0dca7d956
@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -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) => (
|
||||||
|
|||||||
13
app/contexts/ThemeContext.ts
Normal file
13
app/contexts/ThemeContext.ts
Normal 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
11
app/hooks/useTheme.ts
Normal 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;
|
||||||
|
}
|
||||||
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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: {
|
||||||
|
|||||||
22
app/providers/ThemeProvider.tsx
Normal file
22
app/providers/ThemeProvider.tsx
Normal 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>;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user