refactor(all): shadcn rewrite
This commit is contained in:
parent
a3c7945750
commit
e111bdffb4
34 changed files with 1003 additions and 173 deletions
|
@ -8,15 +8,40 @@
|
|||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="logo.svg"
|
||||
inkscape:export-filename="/home/odin/dev/websites/z0x.ca_shadcn/src/assets/logo.svg"
|
||||
inkscape:export-xdpi="192"
|
||||
inkscape:export-ydpi="192"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.3934784"
|
||||
inkscape:cx="80.733221"
|
||||
inkscape:cy="164.33696"
|
||||
inkscape:window-width="1402"
|
||||
inkscape:window-height="892"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" /><defs
|
||||
id="defs1"><linearGradient
|
||||
id="linearGradient10"><stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
style="stop-color:#f5f5f5;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop10" /><stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
style="stop-color:#0a0a0a;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop11" /></linearGradient><radialGradient
|
||||
xlink:href="#linearGradient10"
|
||||
|
@ -31,7 +56,7 @@
|
|||
d="M 55.824663,125.40476 125.21246,55.832186 a 3.9865567,3.9865567 0.02025256 0 1 5.64732,0.002 l 69.31756,69.600498 a 4.0005896,4.0005896 90.112473 0 1 -0.0111,5.65726 l -69.34652,69.08498 a 4.0135339,4.0135339 0.01148544 0 1 -5.6664,-0.001 L 55.832634,131.06116 a 3.9993654,3.9993654 89.919265 0 1 -0.008,-5.6564 z M 125.77344,89.300192 89.179269,125.4342 a 3.9542778,3.9542778 90.033181 0 0 -0.0033,5.62424 l 36.551738,36.17581 a 4.0462516,4.0462516 0.03318674 0 0 5.68928,0.003 l 36.59418,-36.13401 a 3.9542766,3.9542766 90.033183 0 0 0.003,-5.62424 L 131.46272,89.303486 a 4.0462513,4.0462513 0.03317792 0 0 -5.68928,-0.0033 z"
|
||||
id="blur"
|
||||
transform="matrix(1.6906828,0,0,1.6906828,-85.407698,-89.414059)" /><path
|
||||
style="display:inline;fill:#0a0a0a;fill-opacity:1;stroke:none;stroke-width:1.18365;stroke-opacity:1"
|
||||
style="display:inline;fill:#171717;fill-opacity:1;stroke:none;stroke-width:1.18365;stroke-opacity:1"
|
||||
d="M 55.824663,125.40476 125.21246,55.832186 a 3.9865567,3.9865567 0.02025256 0 1 5.64732,0.002 l 69.31756,69.600498 a 4.0005896,4.0005896 90.112473 0 1 -0.0111,5.65726 l -69.34652,69.08498 a 4.0135339,4.0135339 0.01148544 0 1 -5.6664,-0.001 L 55.832634,131.06116 a 3.9993654,3.9993654 89.919265 0 1 -0.008,-5.6564 z M 125.77344,89.300192 89.179269,125.4342 a 3.9542778,3.9542778 90.033181 0 0 -0.0033,5.62424 l 36.551738,36.17581 a 4.0462516,4.0462516 0.03318674 0 0 5.68928,0.003 l 36.59418,-36.13401 a 3.9542766,3.9542766 90.033183 0 0 0.003,-5.62424 L 131.46272,89.303486 a 4.0462513,4.0462513 0.03317792 0 0 -5.68928,-0.0033 z"
|
||||
id="diamond"
|
||||
transform="matrix(1.6906828,0,0,1.6906828,-92.40771,-92.414083)" /></svg>
|
||||
|
|
Before (image error) Size: 2.5 KiB After (image error) Size: 3.4 KiB |
|
@ -1,10 +1,10 @@
|
|||
<footer
|
||||
class="sticky bottom-4 motion-footer opacity-0 text-xs text-center text-white/60 sm:text-sm"
|
||||
class="sticky bottom-4 motion-footer opacity-0 text-xs text-center text-muted-foreground sm:text-sm"
|
||||
>
|
||||
<p>
|
||||
© {new Date().getFullYear()} • <a
|
||||
href="https://z0x.ca?utm_source=z0x.ca"
|
||||
class="transition hover:text-white/80">z0x</a
|
||||
class="transition hover:text-foreground">z0x</a
|
||||
>
|
||||
</p>
|
||||
<p>All rights reserved.</p>
|
||||
|
|
|
@ -1,30 +1,58 @@
|
|||
---
|
||||
import "/src/css/app.css";
|
||||
import "/src/styles/globals.css";
|
||||
---
|
||||
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<link rel="icon" type="image/svg+xml" href="/assets/favicon.svg" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon-16x16.png" />
|
||||
|
||||
<link rel="canonical" href="https://z0x.ca" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
|
||||
<title>z0x</title>
|
||||
|
||||
<meta name="title" content="z0x" />
|
||||
<meta name="description" content="z0x" />
|
||||
<meta name="description" content="z0x's webpage" />
|
||||
<meta name="keywords" content="z0x" />
|
||||
<meta name="referrer" content="no-referrer" />
|
||||
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://z0x.ca" />
|
||||
<meta property="og:site_name" content="z0x" />
|
||||
<meta property="og:title" content="z0x" />
|
||||
<meta property="og:description" content="z0x" />
|
||||
<meta property="og:description" content="z0x's webpage" />
|
||||
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
<meta property="twitter:url" content="https://z0x.ca" />
|
||||
<meta property="twitter:title" content="z0x" />
|
||||
<meta property="twitter:description" content="z0x" />
|
||||
<meta property="twitter:description" content="z0x's webpage" />
|
||||
|
||||
<meta name="darkreader-lock" />
|
||||
|
||||
<link rel="canonical" href="https://z0x.ca" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||
|
||||
<script src="/src/js/index.ts"></script>
|
||||
|
||||
<script is:inline>
|
||||
const getThemePreference = () => {
|
||||
if (typeof localStorage !== "undefined" && localStorage.getItem("theme")) {
|
||||
return localStorage.getItem("theme");
|
||||
}
|
||||
return window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
? "dark"
|
||||
: "light";
|
||||
};
|
||||
const isDark = getThemePreference() === "dark";
|
||||
document.documentElement.classList[isDark ? "add" : "remove"]("dark");
|
||||
|
||||
if (typeof localStorage !== "undefined") {
|
||||
const observer = new MutationObserver(() => {
|
||||
const isDark = document.documentElement.classList.contains("dark");
|
||||
localStorage.setItem("theme", isDark ? "dark" : "light");
|
||||
});
|
||||
observer.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ["class"],
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
aria-label="blog"
|
||||
href="https://blog.z0x.ca"
|
||||
target="_blank"
|
||||
class="flex relative justify-center items-center w-12 text-white transition aspect-square hover:text-white/60"
|
||||
class="flex relative justify-center items-center w-12 transition aspect-square hover:text-muted-foreground"
|
||||
>
|
||||
<div class="absolute inset-0 aspect-square h-12 bg-white/10 rounded-md">
|
||||
<div
|
||||
class="absolute inset-0 aspect-square h-12 bg-foreground/10 rounded-md"
|
||||
>
|
||||
</div>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -31,9 +33,11 @@
|
|||
aria-label="matrix"
|
||||
href="https://matrix.to/#/@z0x:z0x.ca"
|
||||
target="_blank"
|
||||
class="flex relative justify-center items-center w-12 text-white transition aspect-square hover:text-white/60"
|
||||
class="flex relative justify-center items-center w-12 transition aspect-square hover:text-muted-foreground"
|
||||
>
|
||||
<div class="absolute inset-0 aspect-square h-12 bg-white/10 rounded-md">
|
||||
<div
|
||||
class="absolute inset-0 aspect-square h-12 bg-foreground/10 rounded-md"
|
||||
>
|
||||
</div>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<p class="relative text-4xl font-semibold text-white">
|
||||
<span class="absolute inset-0 opacity-0 blur-md motion-text bg-white/50"
|
||||
<p class="relative text-4xl font-semibold text-foreground">
|
||||
<span
|
||||
class="absolute inset-0 opacity-0 blur-md motion-text bg-muted-foreground"
|
||||
></span>
|
||||
<span class="relative opacity-0 motion-text">404</span>
|
||||
</p>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<p class="relative text-4xl font-semibold text-white">
|
||||
<span class="absolute inset-0 opacity-0 blur-md motion-text bg-white/50"
|
||||
<p class="relative text-4xl font-semibold text-foreground">
|
||||
<span
|
||||
class="absolute inset-0 opacity-0 blur-md motion-text bg-muted-foreground"
|
||||
></span>
|
||||
<span class="relative opacity-0 motion-text">z0x</span>
|
||||
</p>
|
||||
|
|
7
src/components/ThemeToggle.astro
Normal file
7
src/components/ThemeToggle.astro
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
import { ModeToggle } from "@/components/ui/ModeToggle";
|
||||
---
|
||||
|
||||
<div class="fixed top-4 right-4">
|
||||
<ModeToggle client:load />
|
||||
</div>
|
52
src/components/ui/ModeToggle.tsx
Normal file
52
src/components/ui/ModeToggle.tsx
Normal file
|
@ -0,0 +1,52 @@
|
|||
import * as React from "react";
|
||||
import { Moon, Sun } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
|
||||
export function ModeToggle() {
|
||||
const [theme, setThemeState] = React.useState<
|
||||
"theme-light" | "dark" | "system"
|
||||
>("theme-light");
|
||||
|
||||
React.useEffect(() => {
|
||||
const isDarkMode = document.documentElement.classList.contains("dark");
|
||||
setThemeState(isDarkMode ? "dark" : "theme-light");
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
const isDark =
|
||||
theme === "dark" ||
|
||||
(theme === "system" &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches);
|
||||
document.documentElement.classList[isDark ? "add" : "remove"]("dark");
|
||||
}, [theme]);
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" size="icon">
|
||||
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
||||
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
||||
<span className="sr-only">Toggle theme</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem onClick={() => setThemeState("theme-light")}>
|
||||
Light
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setThemeState("dark")}>
|
||||
Dark
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setThemeState("system")}>
|
||||
System
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
57
src/components/ui/button.tsx
Normal file
57
src/components/ui/button.tsx
Normal file
|
@ -0,0 +1,57 @@
|
|||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-9 px-4 py-2",
|
||||
sm: "h-8 rounded-md px-3 text-xs",
|
||||
lg: "h-10 rounded-md px-8",
|
||||
icon: "h-9 w-9",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : "button"
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
Button.displayName = "Button"
|
||||
|
||||
export { Button, buttonVariants }
|
199
src/components/ui/dropdown-menu.tsx
Normal file
199
src/components/ui/dropdown-menu.tsx
Normal file
|
@ -0,0 +1,199 @@
|
|||
import * as React from "react"
|
||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
||||
import { Check, ChevronRight, Circle } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const DropdownMenu = DropdownMenuPrimitive.Root
|
||||
|
||||
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
|
||||
|
||||
const DropdownMenuGroup = DropdownMenuPrimitive.Group
|
||||
|
||||
const DropdownMenuPortal = DropdownMenuPrimitive.Portal
|
||||
|
||||
const DropdownMenuSub = DropdownMenuPrimitive.Sub
|
||||
|
||||
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
|
||||
|
||||
const DropdownMenuSubTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, children, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRight className="ml-auto" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
))
|
||||
DropdownMenuSubTrigger.displayName =
|
||||
DropdownMenuPrimitive.SubTrigger.displayName
|
||||
|
||||
const DropdownMenuSubContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuSubContent.displayName =
|
||||
DropdownMenuPrimitive.SubContent.displayName
|
||||
|
||||
const DropdownMenuContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
|
||||
>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Portal>
|
||||
<DropdownMenuPrimitive.Content
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
|
||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</DropdownMenuPrimitive.Portal>
|
||||
))
|
||||
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
|
||||
|
||||
const DropdownMenuItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
|
||||
|
||||
const DropdownMenuCheckboxItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
|
||||
>(({ className, children, checked, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.CheckboxItem>
|
||||
))
|
||||
DropdownMenuCheckboxItem.displayName =
|
||||
DropdownMenuPrimitive.CheckboxItem.displayName
|
||||
|
||||
const DropdownMenuRadioItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Circle className="h-2 w-2 fill-current" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.RadioItem>
|
||||
))
|
||||
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
|
||||
|
||||
const DropdownMenuLabel = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({ className, inset, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-semibold",
|
||||
inset && "pl-8",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
|
||||
|
||||
const DropdownMenuSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DropdownMenuPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
|
||||
|
||||
const DropdownMenuShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
|
||||
|
||||
export {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuRadioGroup,
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
@import "tailwindcss";
|
||||
|
||||
body {
|
||||
cursor: url("/assets/cursor.svg") 28 32, auto;
|
||||
@apply flex overflow-hidden flex-col items-center min-h-screen bg-black;
|
||||
}
|
||||
|
||||
main {
|
||||
@apply flex flex-col flex-auto gap-4 justify-center items-center;
|
||||
}
|
1
src/env.d.ts
vendored
1
src/env.d.ts
vendored
|
@ -1 +0,0 @@
|
|||
/// <reference path="../.astro/types.d.ts" />
|
|
@ -1,16 +1,16 @@
|
|||
---
|
||||
import Footer from "@components/Footer.astro";
|
||||
import Head from "@components/Head.astro";
|
||||
import Footer from "@/components/Footer.astro";
|
||||
import Head from "@/components/Head.astro";
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<Head />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<slot />
|
||||
</main>
|
||||
<Footer />
|
||||
</body>
|
||||
<head>
|
||||
<Head />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<slot />
|
||||
</main>
|
||||
<Footer />
|
||||
</body>
|
||||
</html>
|
||||
|
|
6
src/lib/utils.ts
Normal file
6
src/lib/utils.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { clsx, type ClassValue } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
---
|
||||
import NotFound from "@components/NotFound.astro";
|
||||
import Logo from "@components/Logo.astro";
|
||||
import Layout from "@layouts/Layout.astro";
|
||||
import Layout from "@/layouts/Layout.astro";
|
||||
import ThemeToggle from "@/components/ThemeToggle.astro";
|
||||
import NotFound from "@/components/NotFound.astro";
|
||||
import Logo from "@/components/Logo.astro";
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<ThemeToggle />
|
||||
<NotFound />
|
||||
<Logo />
|
||||
</Layout>
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
---
|
||||
import Text from "@components/Text.astro";
|
||||
import Logo from "@components/Logo.astro";
|
||||
import Links from "@components/Links.astro";
|
||||
import Layout from "@layouts/Layout.astro";
|
||||
import Layout from "@/layouts/Layout.astro";
|
||||
import ThemeToggle from "@/components/ThemeToggle.astro";
|
||||
import Text from "@/components/Text.astro";
|
||||
import Logo from "@/components/Logo.astro";
|
||||
import Links from "@/components/Links.astro";
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<Text />
|
||||
<Logo />
|
||||
<Links />
|
||||
<ThemeToggle />
|
||||
<Text />
|
||||
<Logo />
|
||||
<Links />
|
||||
</Layout>
|
||||
|
|
108
src/styles/globals.css
Normal file
108
src/styles/globals.css
Normal file
|
@ -0,0 +1,108 @@
|
|||
@import "tailwindcss";
|
||||
@plugin "tailwindcss-animate";
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
cursor: var(--cursor-url) 28 32, auto;
|
||||
@apply flex overflow-hidden flex-col items-center min-h-screen;
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
main {
|
||||
@apply flex flex-col flex-auto gap-4 justify-center items-center;
|
||||
}
|
||||
}
|
||||
|
||||
:root {
|
||||
--cursor-light: url("/cursor-light.svg");
|
||||
--cursor-dark: url("/cursor-dark.svg");
|
||||
--cursor-url: var(--cursor-light);
|
||||
--background: hsl(0 0% 100%);
|
||||
--foreground: hsl(240 10% 3.9%);
|
||||
--card: hsl(0 0% 100%);
|
||||
--card-foreground: hsl(240 10% 3.9%);
|
||||
--popover: hsl(0 0% 100%);
|
||||
--popover-foreground: hsl(240 10% 3.9%);
|
||||
--primary: hsl(240 5.9% 10%);
|
||||
--primary-foreground: hsl(0 0% 98%);
|
||||
--secondary: hsl(240 4.8% 95.9%);
|
||||
--secondary-foreground: hsl(240 5.9% 10%);
|
||||
--muted: hsl(240 4.8% 95.9%);
|
||||
--muted-foreground: hsl(240 3.8% 46.1%);
|
||||
--accent: hsl(240 4.8% 95.9%);
|
||||
--accent-foreground: hsl(240 5.9% 10%);
|
||||
--destructive: hsl(0 84.2% 60.2%);
|
||||
--destructive-foreground: hsl(0 0% 98%);
|
||||
--border: hsl(240 5.9% 90%);
|
||||
--input: hsl(240 5.9% 90%);
|
||||
--ring: hsl(240 10% 3.9%);
|
||||
--chart-1: hsl(12 76% 61%);
|
||||
--chart-2: hsl(173 58% 39%);
|
||||
--chart-3: hsl(197 37% 24%);
|
||||
--chart-4: hsl(43 74% 66%);
|
||||
--chart-5: hsl(27 87% 67%);
|
||||
--radius: 0.6rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--cursor-url: var(--cursor-dark);
|
||||
--background: hsl(240 10% 3.9%);
|
||||
--foreground: hsl(0 0% 98%);
|
||||
--card: hsl(240 10% 3.9%);
|
||||
--card-foreground: hsl(0 0% 98%);
|
||||
--popover: hsl(240 10% 3.9%);
|
||||
--popover-foreground: hsl(0 0% 98%);
|
||||
--primary: hsl(0 0% 98%);
|
||||
--primary-foreground: hsl(240 5.9% 10%);
|
||||
--secondary: hsl(240 3.7% 15.9%);
|
||||
--secondary-foreground: hsl(0 0% 98%);
|
||||
--muted: hsl(240 3.7% 15.9%);
|
||||
--muted-foreground: hsl(240 5% 64.9%);
|
||||
--accent: hsl(240 3.7% 15.9%);
|
||||
--accent-foreground: hsl(0 0% 98%);
|
||||
--destructive: hsl(0 62.8% 30.6%);
|
||||
--destructive-foreground: hsl(0 0% 98%);
|
||||
--border: hsl(240 3.7% 15.9%);
|
||||
--input: hsl(240 3.7% 15.9%);
|
||||
--ring: hsl(240 4.9% 83.9%);
|
||||
--chart-1: hsl(220 70% 50%);
|
||||
--chart-2: hsl(160 60% 45%);
|
||||
--chart-3: hsl(30 80% 55%);
|
||||
--chart-4: hsl(280 65% 60%);
|
||||
--chart-5: hsl(340 75% 55%);
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue