Compare commits

..
32 changed files with 151 additions and 612 deletions

View file

@ -4,6 +4,7 @@ on:
pull_request:
env:
NIX_CONFIG: experimental-features = nix-command flakes
FORGEJO_TOKEN: ""
GITHUB_TOKEN: ""
@ -13,6 +14,7 @@ jobs:
name: Build & Lint
runs-on: nixos
steps:
- run: nix profile add nixpkgs#nodejs_24
- uses: https://data.forgejo.org/actions/checkout@v4
with:
persist-credentials: false

View file

@ -2,10 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#111827" />
<title>Methanium UI Showcase</title>
</head>

View file

@ -17,7 +17,6 @@ import {
SelectValue,
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupContent,
SidebarInset,
@ -206,15 +205,6 @@ export default function App() {
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
<SidebarFooter>
<a
href="https://legal.methanium.net/methanium/privacy-policy"
target="_blank"
className="hover:underline"
>
Privacy Policy
</a>
</SidebarFooter>
</Sidebar>
<SidebarInset>

View file

@ -1,6 +1,6 @@
{
"name": "@methanium/ui",
"version": "0.0.32",
"version": "0.0.28",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@ -66,8 +66,8 @@
"emojibase-data": "^17.0.0",
"hast-util-to-jsx-runtime": "^2.3.6",
"input-otp": "^1.4.2",
"katex": "^0.18.3",
"lucide-react": "^1.31.0",
"katex": "^0.18.2",
"lucide-react": "^1.30.0",
"next-themes": "^0.4.6",
"react-markdown": "^10.1.0",
"react-resizable-panels": "^4.12.2",
@ -80,7 +80,7 @@
"remark-math": "^6.0.0",
"shadcn": "^4.16.2",
"shiki": "^4.4.2",
"sonner": "^2.0.8",
"sonner": "^2.0.7",
"tailwind-merge": "^3.6.0",
"tw-animate-css": "^1.4.0",
"unist-util-visit": "^5.1.0",

44
pnpm-lock.yaml generated
View file

@ -57,11 +57,11 @@ importers:
specifier: ^1.4.2
version: 1.4.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
katex:
specifier: ^0.18.3
version: 0.18.3
specifier: ^0.18.2
version: 0.18.2
lucide-react:
specifier: ^1.31.0
version: 1.31.0(react@19.2.8)
specifier: ^1.30.0
version: 1.30.0(react@19.2.8)
next-themes:
specifier: ^0.4.6
version: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
@ -105,8 +105,8 @@ importers:
specifier: ^4.4.2
version: 4.4.2
sonner:
specifier: ^2.0.8
version: 2.0.8(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
specifier: ^2.0.7
version: 2.0.7(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
tailwind-merge:
specifier: ^3.6.0
version: 3.6.0
@ -1689,8 +1689,8 @@ packages:
ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
electron-to-chromium@1.5.403:
resolution: {integrity: sha512-MQsYmdaLzvaCX5j+ZZBr5Fm6uCCnPQcRtlvmvRlWqrXy+BH2O4ffXIAScF+JQznQWB9brWp4lSD9Z4yNmaf2BA==}
electron-to-chromium@1.5.402:
resolution: {integrity: sha512-/oOpMaPT6Yg+6/1XQhyIPlzgj7Ye9zf+nNM2Uh6OcE2G2oNptWazFa+qB2Pdqqbsc9KnIDzgAntoYN0dbwOXwA==}
embla-carousel-react@8.6.0:
resolution: {integrity: sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA==}
@ -2277,8 +2277,8 @@ packages:
resolution: {integrity: sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==}
hasBin: true
katex@0.18.3:
resolution: {integrity: sha512-6kbPr8KiYZpRfNNIw+8Td33njnFzK/ELcw6bI9FzIHysYPatAUdepQimfCX1vG2VCD/5Lv+Gu6P5YA58k8HHmw==}
katex@0.18.2:
resolution: {integrity: sha512-3snve4y0SXTMequLim1FMiPvLGElySam0blN5xQZBqEY3lOJz1TnuaaiugnBZBqHzlSAGmFTYL7MCQkORuLKCA==}
hasBin: true
keyv@4.5.4:
@ -2465,8 +2465,8 @@ packages:
lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
lucide-react@1.31.0:
resolution: {integrity: sha512-G8u2eEtoHUnUa9f8lbvqDhCiORMnYLdUEo06EEG9MQvHQrInKcX3Pa2TH39MM5qyzRcWETxB0+aOwAPI1g1kEg==}
lucide-react@1.30.0:
resolution: {integrity: sha512-tUIr2jXLbWpCkdtH8XP7P7YppM9ueWgTky99lpWDY6z5REs6B+O6ZQ3U5tHkUUY59ANyOv/PBcs8E4Fe3KO3eA==}
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
@ -3112,15 +3112,11 @@ packages:
sisteransi@1.0.5:
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
sonner@2.0.8:
resolution: {integrity: sha512-UM/ByIoFra8yzV75n1o0Puu0bw5U/9UNnDacrJNspekBewIfsQ3D6ez1nvlWpt7aTsO6rujQtifBpycwIivqlg==}
sonner@2.0.7:
resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==}
peerDependencies:
'@types/react': ^18.0.0 || ^19.0.0
react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
@ -4650,7 +4646,7 @@ snapshots:
dependencies:
baseline-browser-mapping: 2.11.13
caniuse-lite: 1.0.30001809
electron-to-chromium: 1.5.403
electron-to-chromium: 1.5.402
node-releases: 2.0.53
update-browserslist-db: 1.3.0(browserslist@4.28.8)
@ -4870,7 +4866,7 @@ snapshots:
ee-first@1.1.1: {}
electron-to-chromium@1.5.403: {}
electron-to-chromium@1.5.402: {}
embla-carousel-react@8.6.0(react@19.2.8):
dependencies:
@ -5489,7 +5485,7 @@ snapshots:
dependencies:
commander: 8.3.0
katex@0.18.3:
katex@0.18.2:
dependencies:
commander: 8.3.0
@ -5626,7 +5622,7 @@ snapshots:
dependencies:
yallist: 3.1.1
lucide-react@1.31.0(react@19.2.8):
lucide-react@1.30.0(react@19.2.8):
dependencies:
react: 19.2.8
@ -6617,12 +6613,10 @@ snapshots:
sisteransi@1.0.5: {}
sonner@2.0.8(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8):
sonner@2.0.7(react-dom@19.2.8(react@19.2.8))(react@19.2.8):
dependencies:
react: 19.2.8
react-dom: 19.2.8(react@19.2.8)
optionalDependencies:
'@types/react': 19.2.18
source-map-js@1.2.1: {}

View file

@ -52,7 +52,7 @@ function AlertDialogContent({
data-slot="alert-dialog-content"
data-size={size}
className={cn(
"group/alert-dialog-content fixed top-[calc((100dvh+max(1rem,var(--ui-safe-area-top))-max(1rem,var(--ui-safe-area-bottom)))/2)] left-[calc((100%+max(1rem,var(--ui-safe-area-left))-max(1rem,var(--ui-safe-area-right)))/2)] z-50 grid w-[calc(100%-max(1rem,var(--ui-safe-area-left))-max(1rem,var(--ui-safe-area-right)))] max-h-[calc(100dvh-max(1rem,var(--ui-safe-area-top))-max(1rem,var(--ui-safe-area-bottom)))] -translate-x-1/2 -translate-y-1/2 gap-4 overflow-y-auto rounded-xl bg-popover p-4 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
"group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
className,
)}
{...props}

View file

@ -2,7 +2,6 @@ import * as React from "react";
import { Combobox as ComboboxPrimitive } from "@base-ui/react";
import { cn } from "../lib/utils";
import { useSafeAreaCollisionPadding } from "../hooks/use-safe-area";
import { Button } from "./button";
import {
InputGroup,
@ -90,20 +89,12 @@ function ComboboxContent({
align = "start",
alignOffset = 0,
anchor,
collisionPadding,
...props
}: ComboboxPrimitive.Popup.Props &
Pick<
ComboboxPrimitive.Positioner.Props,
| "side"
| "align"
| "sideOffset"
| "alignOffset"
| "anchor"
| "collisionPadding"
"side" | "align" | "sideOffset" | "alignOffset" | "anchor"
>) {
const safeAreaCollisionPadding = useSafeAreaCollisionPadding();
return (
<ComboboxPrimitive.Portal>
<ComboboxPrimitive.Positioner
@ -112,7 +103,6 @@ function ComboboxContent({
align={align}
alignOffset={alignOffset}
anchor={anchor}
collisionPadding={collisionPadding ?? safeAreaCollisionPadding}
className="isolate z-50"
>
<ComboboxPrimitive.Popup

View file

@ -52,7 +52,7 @@ function CommandDialog({
</DialogHeader>
<DialogContent
className={cn(
"top-[calc(var(--ui-safe-area-top)+(100dvh-var(--ui-safe-area-top)-var(--ui-safe-area-bottom))/3)] max-h-[calc((100dvh-var(--ui-safe-area-top)-var(--ui-safe-area-bottom))*2/3-1rem)] translate-y-0 overflow-hidden rounded-xl! p-0",
"top-1/3 translate-y-0 overflow-hidden rounded-xl! p-0",
className,
)}
showCloseButton={showCloseButton}

View file

@ -4,7 +4,6 @@ import * as React from "react";
import { ContextMenu as ContextMenuPrimitive } from "@base-ui/react/context-menu";
import { cn } from "../lib/utils";
import { useSafeAreaCollisionPadding } from "../hooks/use-safe-area";
import { ChevronRightIcon, CheckIcon } from "lucide-react";
function ContextMenu({ ...props }: ContextMenuPrimitive.Root.Props) {
@ -36,15 +35,12 @@ function ContextMenuContent({
alignOffset = 4,
side = "right",
sideOffset = 0,
collisionPadding,
...props
}: ContextMenuPrimitive.Popup.Props &
Pick<
ContextMenuPrimitive.Positioner.Props,
"align" | "alignOffset" | "side" | "sideOffset" | "collisionPadding"
"align" | "alignOffset" | "side" | "sideOffset"
>) {
const safeAreaCollisionPadding = useSafeAreaCollisionPadding();
return (
<ContextMenuPrimitive.Portal>
<ContextMenuPrimitive.Positioner
@ -53,7 +49,6 @@ function ContextMenuContent({
alignOffset={alignOffset}
side={side}
sideOffset={sideOffset}
collisionPadding={collisionPadding ?? safeAreaCollisionPadding}
>
<ContextMenuPrimitive.Popup
data-slot="context-menu-content"

View file

@ -53,7 +53,7 @@ function DialogContent({
<DialogPrimitive.Popup
data-slot="dialog-content"
className={cn(
"fixed top-[calc((100dvh+max(1rem,var(--ui-safe-area-top))-max(1rem,var(--ui-safe-area-bottom)))/2)] left-[calc((100%+max(1rem,var(--ui-safe-area-left))-max(1rem,var(--ui-safe-area-right)))/2)] z-50 grid w-[calc(100%-max(1rem,var(--ui-safe-area-left))-max(1rem,var(--ui-safe-area-right)))] max-h-[calc(100dvh-max(1rem,var(--ui-safe-area-top))-max(1rem,var(--ui-safe-area-bottom)))] -translate-x-1/2 -translate-y-1/2 gap-4 overflow-y-auto rounded-xl bg-popover p-4 text-sm text-popover-foreground border duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
"fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-sm text-popover-foreground border duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
className,
)}
{...props}

View file

@ -56,7 +56,7 @@ function DrawerContent({
<DrawerPrimitive.Content
data-slot="drawer-content"
className={cn(
"group/drawer-content fixed z-50 flex h-auto flex-col bg-popover text-sm text-popover-foreground data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80dvh] data-[vaul-drawer-direction=bottom]:rounded-t-xl data-[vaul-drawer-direction=bottom]:border-t data-[vaul-drawer-direction=bottom]:pr-[var(--ui-safe-area-right)] data-[vaul-drawer-direction=bottom]:pb-[var(--ui-safe-area-bottom)] data-[vaul-drawer-direction=bottom]:pl-[var(--ui-safe-area-left)] data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:rounded-r-xl data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=left]:pt-[var(--ui-safe-area-top)] data-[vaul-drawer-direction=left]:pb-[var(--ui-safe-area-bottom)] data-[vaul-drawer-direction=left]:pl-[var(--ui-safe-area-left)] data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:rounded-l-xl data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=right]:pt-[var(--ui-safe-area-top)] data-[vaul-drawer-direction=right]:pr-[var(--ui-safe-area-right)] data-[vaul-drawer-direction=right]:pb-[var(--ui-safe-area-bottom)] data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80dvh] data-[vaul-drawer-direction=top]:rounded-b-xl data-[vaul-drawer-direction=top]:border-b data-[vaul-drawer-direction=top]:pt-[var(--ui-safe-area-top)] data-[vaul-drawer-direction=top]:pr-[var(--ui-safe-area-right)] data-[vaul-drawer-direction=top]:pl-[var(--ui-safe-area-left)] data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm",
"group/drawer-content fixed z-50 flex h-auto flex-col bg-popover text-sm text-popover-foreground data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-xl data-[vaul-drawer-direction=bottom]:border-t data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:rounded-r-xl data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:rounded-l-xl data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-xl data-[vaul-drawer-direction=top]:border-b data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm",
className,
)}
{...props}

View file

@ -2,7 +2,6 @@ import * as React from "react";
import { Menu as MenuPrimitive } from "@base-ui/react/menu";
import { cn } from "../lib/utils";
import { useSafeAreaCollisionPadding } from "../hooks/use-safe-area";
import { ChevronRightIcon, CheckIcon } from "lucide-react";
function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
@ -22,16 +21,13 @@ function DropdownMenuContent({
alignOffset = 0,
side = "bottom",
sideOffset = 4,
collisionPadding,
className,
...props
}: MenuPrimitive.Popup.Props &
Pick<
MenuPrimitive.Positioner.Props,
"align" | "alignOffset" | "side" | "sideOffset" | "collisionPadding"
"align" | "alignOffset" | "side" | "sideOffset"
>) {
const safeAreaCollisionPadding = useSafeAreaCollisionPadding();
return (
<MenuPrimitive.Portal>
<MenuPrimitive.Positioner
@ -40,7 +36,6 @@ function DropdownMenuContent({
alignOffset={alignOffset}
side={side}
sideOffset={sideOffset}
collisionPadding={collisionPadding ?? safeAreaCollisionPadding}
>
<MenuPrimitive.Popup
data-slot="dropdown-menu-content"

View file

@ -3,7 +3,6 @@
import { PreviewCard as PreviewCardPrimitive } from "@base-ui/react/preview-card";
import { cn } from "../lib/utils";
import { useSafeAreaCollisionPadding } from "../hooks/use-safe-area";
function HoverCard({ ...props }: PreviewCardPrimitive.Root.Props) {
return <PreviewCardPrimitive.Root data-slot="hover-card" {...props} />;
@ -21,15 +20,12 @@ function HoverCardContent({
sideOffset = 4,
align = "center",
alignOffset = 4,
collisionPadding,
...props
}: PreviewCardPrimitive.Popup.Props &
Pick<
PreviewCardPrimitive.Positioner.Props,
"align" | "alignOffset" | "side" | "sideOffset" | "collisionPadding"
"align" | "alignOffset" | "side" | "sideOffset"
>) {
const safeAreaCollisionPadding = useSafeAreaCollisionPadding();
return (
<PreviewCardPrimitive.Portal data-slot="hover-card-portal">
<PreviewCardPrimitive.Positioner
@ -37,7 +33,6 @@ function HoverCardContent({
alignOffset={alignOffset}
side={side}
sideOffset={sideOffset}
collisionPadding={collisionPadding ?? safeAreaCollisionPadding}
className="isolate z-50"
>
<PreviewCardPrimitive.Popup

View file

@ -2,7 +2,6 @@ import { NavigationMenu as NavigationMenuPrimitive } from "@base-ui/react/naviga
import { cva } from "class-variance-authority";
import { cn } from "../lib/utils";
import { useSafeAreaCollisionPadding } from "../hooks/use-safe-area";
import { ChevronDownIcon } from "lucide-react";
function NavigationMenu({
@ -102,11 +101,8 @@ function NavigationMenuPositioner({
sideOffset = 8,
align = "start",
alignOffset = 0,
collisionPadding,
...props
}: NavigationMenuPrimitive.Positioner.Props) {
const safeAreaCollisionPadding = useSafeAreaCollisionPadding();
return (
<NavigationMenuPrimitive.Portal>
<NavigationMenuPrimitive.Positioner
@ -114,7 +110,6 @@ function NavigationMenuPositioner({
sideOffset={sideOffset}
align={align}
alignOffset={alignOffset}
collisionPadding={collisionPadding ?? safeAreaCollisionPadding}
className={cn(
"isolate z-50 h-(--positioner-height) w-(--positioner-width) max-w-(--available-width) transition-[top,left,right,bottom] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] data-instant:transition-none data-[side=bottom]:before:top-[-10px] data-[side=bottom]:before:right-0 data-[side=bottom]:before:left-0",
className,

View file

@ -123,7 +123,7 @@ function OnboardingFlow({
</ConfigureStepContext.Provider>
</main>
<footer className="shrink-0 px-6 pt-4 pb-6 md:px-10">
<footer className="shrink-0 px-6 pt-4 pb-[max(1.5rem,env(safe-area-inset-bottom))] md:px-10">
<div className="flex justify-center md:justify-end">
<Button
size="lg"

View file

@ -2,7 +2,6 @@ import * as React from "react";
import { Popover as PopoverPrimitive } from "@base-ui/react/popover";
import { cn } from "../lib/utils";
import { useSafeAreaCollisionPadding } from "../hooks/use-safe-area";
function Popover({ ...props }: PopoverPrimitive.Root.Props) {
return <PopoverPrimitive.Root data-slot="popover" {...props} />;
@ -18,18 +17,15 @@ function PopoverContent({
alignOffset = 0,
side = "bottom",
sideOffset = 4,
collisionPadding,
portalProps,
...props
}: PopoverPrimitive.Popup.Props &
Pick<
PopoverPrimitive.Positioner.Props,
"align" | "alignOffset" | "side" | "sideOffset" | "collisionPadding"
"align" | "alignOffset" | "side" | "sideOffset"
> & {
portalProps?: PopoverPrimitive.Portal.Props;
}) {
const safeAreaCollisionPadding = useSafeAreaCollisionPadding();
return (
<PopoverPrimitive.Portal {...portalProps}>
<PopoverPrimitive.Positioner
@ -37,7 +33,6 @@ function PopoverContent({
alignOffset={alignOffset}
side={side}
sideOffset={sideOffset}
collisionPadding={collisionPadding ?? safeAreaCollisionPadding}
className="isolate z-50"
>
<PopoverPrimitive.Popup

View file

@ -4,7 +4,6 @@ import * as React from "react";
import { Select as SelectPrimitive } from "@base-ui/react/select";
import { cn } from "../lib/utils";
import { useSafeAreaCollisionPadding } from "../hooks/use-safe-area";
import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react";
const Select = SelectPrimitive.Root;
@ -65,20 +64,12 @@ function SelectContent({
align = "center",
alignOffset = 0,
alignItemWithTrigger = true,
collisionPadding,
...props
}: SelectPrimitive.Popup.Props &
Pick<
SelectPrimitive.Positioner.Props,
| "align"
| "alignOffset"
| "side"
| "sideOffset"
| "alignItemWithTrigger"
| "collisionPadding"
"align" | "alignOffset" | "side" | "sideOffset" | "alignItemWithTrigger"
>) {
const safeAreaCollisionPadding = useSafeAreaCollisionPadding();
return (
<SelectPrimitive.Portal>
<SelectPrimitive.Positioner
@ -87,7 +78,6 @@ function SelectContent({
align={align}
alignOffset={alignOffset}
alignItemWithTrigger={alignItemWithTrigger}
collisionPadding={collisionPadding ?? safeAreaCollisionPadding}
className="isolate z-50"
>
<SelectPrimitive.Popup

View file

@ -53,7 +53,7 @@ function SheetContent({
data-slot="sheet-content"
data-side={side}
className={cn(
"group/sheet-content fixed z-50 flex flex-col gap-4 bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition duration-200 ease-in-out data-ending-style:opacity-0 data-starting-style:opacity-0 data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=bottom]:pr-[var(--ui-safe-area-right)] data-[side=bottom]:pb-[var(--ui-safe-area-bottom)] data-[side=bottom]:pl-[var(--ui-safe-area-left)] data-[side=bottom]:data-ending-style:translate-y-[2.5rem] data-[side=bottom]:data-starting-style:translate-y-[2.5rem] data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=left]:pt-[var(--ui-safe-area-top)] data-[side=left]:pb-[var(--ui-safe-area-bottom)] data-[side=left]:pl-[var(--ui-safe-area-left)] data-[side=left]:data-ending-style:translate-x-[-2.5rem] data-[side=left]:data-starting-style:translate-x-[-2.5rem] data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=right]:pt-[var(--ui-safe-area-top)] data-[side=right]:pr-[var(--ui-safe-area-right)] data-[side=right]:pb-[var(--ui-safe-area-bottom)] data-[side=right]:data-ending-style:translate-x-[2.5rem] data-[side=right]:data-starting-style:translate-x-[2.5rem] data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=top]:pt-[var(--ui-safe-area-top)] data-[side=top]:pr-[var(--ui-safe-area-right)] data-[side=top]:pl-[var(--ui-safe-area-left)] data-[side=top]:data-ending-style:translate-y-[-2.5rem] data-[side=top]:data-starting-style:translate-y-[-2.5rem] data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm",
"fixed z-50 flex flex-col gap-4 bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition duration-200 ease-in-out data-ending-style:opacity-0 data-starting-style:opacity-0 data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=bottom]:data-ending-style:translate-y-[2.5rem] data-[side=bottom]:data-starting-style:translate-y-[2.5rem] data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=left]:data-ending-style:translate-x-[-2.5rem] data-[side=left]:data-starting-style:translate-x-[-2.5rem] data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=right]:data-ending-style:translate-x-[2.5rem] data-[side=right]:data-starting-style:translate-x-[2.5rem] data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=top]:data-ending-style:translate-y-[-2.5rem] data-[side=top]:data-starting-style:translate-y-[-2.5rem] data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm",
className,
)}
{...props}
@ -65,7 +65,7 @@ function SheetContent({
render={
<Button
variant="ghost"
className="absolute top-3 right-3 group-data-[side=bottom]/sheet-content:right-[max(0.75rem,var(--ui-safe-area-right))] group-data-[side=left]/sheet-content:top-[max(0.75rem,var(--ui-safe-area-top))] group-data-[side=right]/sheet-content:top-[max(0.75rem,var(--ui-safe-area-top))] group-data-[side=right]/sheet-content:right-[max(0.75rem,var(--ui-safe-area-right))] group-data-[side=top]/sheet-content:top-[max(0.75rem,var(--ui-safe-area-top))] group-data-[side=top]/sheet-content:right-[max(0.75rem,var(--ui-safe-area-right))]"
className="absolute top-3 right-3"
size="icon-sm"
/>
}

View file

@ -215,10 +215,10 @@ function Sidebar({
data-side={side}
style={{ width: SIDEBAR_WIDTH }}
className={cn(
"fixed inset-y-0 z-10 hidden h-svh pt-[var(--ui-safe-area-top)] pb-[var(--ui-safe-area-bottom)] transition-[left,right,width,transform] duration-200 ease-linear data-[side=left]:left-0 data-[side=left]:pl-[var(--ui-safe-area-left)] data-[side=left]:group-data-[collapsible=offcanvas]:-translate-x-full data-[side=right]:right-0 data-[side=right]:pr-[var(--ui-safe-area-right)] data-[side=right]:group-data-[collapsible=offcanvas]:translate-x-full md:flex",
"fixed inset-y-0 z-10 hidden h-svh transition-[left,right,width,transform] duration-200 ease-linear data-[side=left]:left-0 data-[side=left]:group-data-[collapsible=offcanvas]:-translate-x-full data-[side=right]:right-0 data-[side=right]:group-data-[collapsible=offcanvas]:translate-x-full md:flex",
// Adjust the padding for floating and inset variants.
variant === "floating" || variant === "inset"
? "pt-[max(0.5rem,var(--ui-safe-area-top))] pr-2 pb-[max(0.5rem,var(--ui-safe-area-bottom))] pl-2 data-[side=left]:pl-[max(0.5rem,var(--ui-safe-area-left))] data-[side=right]:pr-[max(0.5rem,var(--ui-safe-area-right))] group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]"
? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]"
: "group-data-[collapsible=icon]:w-(--sidebar-width-icon)",
className,
)}

View file

@ -17,18 +17,6 @@ const Toaster = ({ ...props }: ToasterProps) => {
<Sonner
theme={theme as ToasterProps["theme"]}
className="toaster group"
offset={{
top: "max(1rem, var(--ui-safe-area-top))",
right: "max(1rem, var(--ui-safe-area-right))",
bottom: "max(1rem, var(--ui-safe-area-bottom))",
left: "max(1rem, var(--ui-safe-area-left))",
}}
mobileOffset={{
top: "max(1rem, var(--ui-safe-area-top))",
right: "max(1rem, var(--ui-safe-area-right), var(--ui-safe-area-left))",
bottom: "max(1rem, var(--ui-safe-area-bottom))",
left: "max(1rem, var(--ui-safe-area-right), var(--ui-safe-area-left))",
}}
icons={{
success: <CircleCheckIcon className="size-4" />,
info: <InfoIcon className="size-4" />,

View file

@ -6,7 +6,7 @@ function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
<Loader2Icon
role="status"
aria-label="Loading"
className={cn("size-4 animate-spin!", className)}
className={cn("size-4 animate-spin", className)}
{...props}
/>
);

View file

@ -2,7 +2,6 @@ import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip";
import type { ReactElement, ReactNode } from "react";
import { cn } from "../lib/utils";
import { useSafeAreaCollisionPadding } from "../hooks/use-safe-area";
function TooltipProvider({
delay = 0,
@ -32,18 +31,15 @@ function TooltipContent({
align = "center",
alignOffset = 0,
children,
collisionPadding,
portalProps,
...props
}: TooltipPrimitive.Popup.Props &
Pick<
TooltipPrimitive.Positioner.Props,
"align" | "alignOffset" | "side" | "sideOffset" | "collisionPadding"
"align" | "alignOffset" | "side" | "sideOffset"
> & {
portalProps?: TooltipPrimitive.Portal.Props;
}) {
const safeAreaCollisionPadding = useSafeAreaCollisionPadding();
return (
<TooltipPrimitive.Portal {...portalProps}>
<TooltipPrimitive.Positioner
@ -51,7 +47,6 @@ function TooltipContent({
alignOffset={alignOffset}
side={side}
sideOffset={sideOffset}
collisionPadding={collisionPadding ?? safeAreaCollisionPadding}
className="isolate z-50"
>
<TooltipPrimitive.Popup

View file

@ -1,40 +0,0 @@
import * as React from "react";
const properties = [
"--ui-safe-area-top",
"--ui-safe-area-right",
"--ui-safe-area-bottom",
"--ui-safe-area-left",
] as const;
function getSnapshot() {
const styles = getComputedStyle(document.documentElement);
return properties
.map((property) => styles.getPropertyValue(property))
.join(",");
}
function subscribe(onChange: () => void) {
window.addEventListener("resize", onChange);
window.addEventListener("orientationchange", onChange);
window.visualViewport?.addEventListener("resize", onChange);
return () => {
window.removeEventListener("resize", onChange);
window.removeEventListener("orientationchange", onChange);
window.visualViewport?.removeEventListener("resize", onChange);
};
}
export function useSafeAreaCollisionPadding() {
const snapshot = React.useSyncExternalStore(
subscribe,
getSnapshot,
() => "0,0,0,0",
);
const [top, right, bottom, left] = snapshot
.split(",")
.map((value) => Math.max(5, Number.parseFloat(value) || 0));
return { top, right, bottom, left };
}

View file

@ -88,10 +88,6 @@
}
:root {
--ui-safe-area-top: env(safe-area-inset-top, 0px);
--ui-safe-area-right: env(safe-area-inset-right, 0px);
--ui-safe-area-bottom: env(safe-area-inset-bottom, 0px);
--ui-safe-area-left: env(safe-area-inset-left, 0px);
--ui-density: 1;
--ui-border-width: 1px;
--ui-shadow-strength: 0;

View file

@ -8,7 +8,6 @@ export { toast } from "sonner";
export * from "./theme";
export * from "./screens/util";
export * from "./hooks/use-mobile";
export * from "./hooks/use-safe-area";
export * from "./lib/utils";
export * from "./cmp/accordion";

View file

@ -71,7 +71,7 @@ function CodeBlock({
data-slot="code-block"
data-line-numbers={showLineNumbers || undefined}
data-language={language || undefined}
className="group/code-block overflow-hidden rounded-lg border-[length:var(--ui-border-width)] border-border bg-[var(--markdown-code-background,var(--markdown-code-background-default))] my-2!"
className="group/code-block overflow-hidden rounded-lg border-[length:var(--ui-border-width)] border-border bg-[var(--markdown-code-background)] my-2!"
>
<figcaption
data-slot="code-block-header"

View file

@ -3,7 +3,7 @@
@layer components {
[data-slot="markdown"],
.tm-md-root {
--markdown-code-background-default: color-mix(
--markdown-code-background: color-mix(
in oklch,
var(--muted) 72%,
var(--background)
@ -35,7 +35,7 @@
.dark [data-slot="markdown"]:not([data-code-theme="light"]),
[data-slot="markdown"][data-code-theme="dark"],
.dark .tm-md-root {
--markdown-code-background-default: color-mix(
--markdown-code-background: color-mix(
in oklch,
var(--muted) 76%,
black 24%
@ -102,10 +102,7 @@
border-right: var(--ui-border-width) solid var(--border);
border-left: var(--ui-border-width) solid var(--border);
border-radius: 0;
background: var(
--markdown-code-background,
var(--markdown-code-background-default)
);
background: var(--markdown-code-background);
color: var(--markdown-code-foreground);
font-family: "JetBrains Mono", ui-monospace, monospace;
font-size: 0.82rem;

View file

@ -18,7 +18,7 @@ export type HighlightedCodeToken = {
};
export const shikiPreClassName =
"shiki m-0 w-max min-w-full bg-[var(--markdown-code-background,var(--markdown-code-background-default))]! font-mono text-[0.82rem]/[1.7] text-[var(--markdown-code-foreground)]! [tab-size:2]";
"shiki m-0 w-max min-w-full bg-[var(--markdown-code-background)]! font-mono text-[0.82rem]/[1.7] text-[var(--markdown-code-foreground)]! [tab-size:2]";
export const shikiLineClassNames =
"line -mx-4 inline-block min-w-full px-4 group-data-[line-numbers]/code-block:before:inline-block group-data-[line-numbers]/code-block:before:w-10 group-data-[line-numbers]/code-block:before:pe-4 group-data-[line-numbers]/code-block:before:text-end group-data-[line-numbers]/code-block:before:text-muted-foreground group-data-[line-numbers]/code-block:before:select-none group-data-[line-numbers]/code-block:before:content-[attr(data-line)]";
export const highlightedLineClassNames =

View file

@ -1,5 +1,6 @@
import { cn } from "../lib/utils";
import Controls from "../windowControls";
import { isTauri } from "@tauri-apps/api/core";
export default function CreateScreen({
children,
@ -11,13 +12,13 @@ export default function CreateScreen({
return (
<div
className={cn(
"bg-background flex h-dvh w-screen flex-col items-center justify-center pt-[var(--ui-safe-area-top)] pr-[var(--ui-safe-area-right)] pb-[var(--ui-safe-area-bottom)] pl-[var(--ui-safe-area-left)]",
"bg-background w-screen h-screen flex flex-col justify-center items-center",
className,
)}
data-tauri-drag-region
>
<>
<Controls className="fixed top-[max(0.4375rem,var(--ui-safe-area-top))] right-[max(0.475rem,var(--ui-safe-area-right))] ring-foreground/15" />
<Controls className="fixed top-0 right-0 m-1.75 mr-[7.6px]! ring-foreground/15" />
{children}
</>
</div>
@ -86,8 +87,9 @@ export function StorageDestoryer() {
return (
<div
className={cn(
"fixed bottom-0 p-5 pr-[max(1.25rem,var(--ui-safe-area-right))] pb-[max(1.25rem,var(--ui-safe-area-bottom))] pl-[max(1.25rem,var(--ui-safe-area-left))]",
"fixed p-5 bottom-0",
isMobile ? "w-full" : "right-0",
isTauri() ? "py-10" : "",
)}
>
<ClearStorageButton />

View file

@ -140,7 +140,6 @@ export function ThemeProvider({
customCssStorageKey = "theme_custom_css",
parentThemeStorageKey = "theme_parent",
designStorageKey = "theme_design",
notCustomizedStorageKey = "theme_not_customized",
disableTransitionOnChange = true,
...props
}: ThemeProviderProps) {
@ -191,20 +190,6 @@ export function ThemeProvider({
const [themeDesign, setThemeDesignState] = useState(() =>
storedDesign(designStorageKey, initialDesign),
);
const [notCustomized, setNotCustomizedState] = useState(() => {
const stored = storageValue(notCustomizedStorageKey);
if (stored !== null) return stored === "true";
return Boolean(
initialParent &&
themeColor === "" &&
themePalette === null &&
themePrimaryColor === "" &&
themeTint === "soft" &&
themeBorderRadius === initialBorderRadius &&
designsEqual(themeDesign, initialDesign) &&
themeCustomCss === initialParent.css,
);
});
const [systemPolarity, setSystemPolarity] = useState<ResolvedThemePolarity>(
() => getSystemTheme(),
);
@ -213,22 +198,13 @@ export function ThemeProvider({
const resolvedPolarity =
themePolarity === "system" ? systemPolarity : themePolarity;
const setNotCustomized = useCallback(
(next: boolean) => {
saveStoredValue(notCustomizedStorageKey, String(next));
setNotCustomizedState(next);
},
[notCustomizedStorageKey],
);
const setParentThemeId = useCallback(
(id: string | null) => {
const next = findTheme(themes, id)?.id ?? null;
saveStoredValue(parentThemeStorageKey, next ?? "");
setParentThemeIdState(next);
setNotCustomized(false);
},
[parentThemeStorageKey, setNotCustomized, themes],
[parentThemeStorageKey, themes],
);
const setThemePolarity = useCallback(
@ -243,34 +219,30 @@ export function ThemeProvider({
if (!isThemeColor(next)) return;
saveStoredValue(colorStorageKey, next);
setThemeColorState(next);
setNotCustomized(false);
},
[colorStorageKey, setNotCustomized],
[colorStorageKey],
);
const setThemePalette = useCallback(
(next: Base16Palette | null) => {
saveStoredValue(paletteStorageKey, serializeBase16Palette(next));
setThemePaletteState(next);
setNotCustomized(false);
},
[paletteStorageKey, setNotCustomized],
[paletteStorageKey],
);
const setThemePrimaryColor = useCallback(
(next: string) => {
if (!isThemeColor(next)) return;
saveStoredValue(primaryColorStorageKey, next);
setThemePrimaryColorState(next);
setNotCustomized(false);
},
[primaryColorStorageKey, setNotCustomized],
[primaryColorStorageKey],
);
const setThemeTint = useCallback(
(next: ThemeTint) => {
saveStoredValue(tintStorageKey, next);
setThemeTintState(next);
setNotCustomized(false);
},
[setNotCustomized, tintStorageKey],
[tintStorageKey],
);
const setThemeBorderRadius = useCallback(
(next: number) => {
@ -278,28 +250,25 @@ export function ThemeProvider({
if (radius === null) return;
saveStoredValue(borderRadiusStorageKey, String(radius));
setThemeBorderRadiusState(radius);
setNotCustomized(false);
},
[borderRadiusStorageKey, setNotCustomized],
[borderRadiusStorageKey],
);
const setThemeCustomCss = useCallback(
(next: string) => {
saveStoredValue(customCssStorageKey, next);
setThemeCustomCssState(next);
setNotCustomized(false);
},
[customCssStorageKey, setNotCustomized],
[customCssStorageKey],
);
const setThemeDesign = useCallback(
(next: ThemeDesign | ((current: ThemeDesign) => ThemeDesign)) => {
setNotCustomized(false);
setThemeDesignState((current) => {
const value = typeof next === "function" ? next(current) : next;
saveStoredValue(designStorageKey, JSON.stringify(value));
return value;
});
},
[designStorageKey, setNotCustomized],
[designStorageKey],
);
const applyThemePreset = useCallback(
@ -314,7 +283,6 @@ export function ThemeProvider({
setThemeBorderRadius(presetBorderRadius(preset, defaultBorderRadius));
setThemeDesign(presetDesign(preset, defaultDesign));
setThemeCustomCss(preset.css);
setNotCustomized(true);
},
[
defaultDesign,
@ -327,7 +295,6 @@ export function ThemeProvider({
setThemePalette,
setThemePrimaryColor,
setThemeTint,
setNotCustomized,
themes,
],
);
@ -335,13 +302,6 @@ export function ThemeProvider({
if (parentTheme) applyThemePreset(parentTheme.id);
}, [applyThemePreset, parentTheme]);
useEffect(() => {
if (typeof window === "undefined") return;
if (storageValue(notCustomizedStorageKey) === null) {
saveStoredValue(notCustomizedStorageKey, String(notCustomized));
}
}, [notCustomized, notCustomizedStorageKey]);
useEffect(() => {
if (typeof window === "undefined") return;
const mediaQuery = window.matchMedia(COLOR_SCHEME_QUERY);
@ -350,14 +310,6 @@ export function ThemeProvider({
return () => mediaQuery.removeEventListener("change", handleChange);
}, []);
useIsomorphicLayoutEffect(() => {
if (!notCustomized || !parentTheme || themeCustomCss === parentTheme.css) {
return;
}
saveStoredValue(customCssStorageKey, parentTheme.css);
setThemeCustomCssState(parentTheme.css);
}, [customCssStorageKey, notCustomized, parentTheme, themeCustomCss]);
useIsomorphicLayoutEffect(() => {
if (typeof document === "undefined") return;
const root = document.documentElement;
@ -470,9 +422,6 @@ export function ThemeProvider({
parseDesign(stored, presetDesign(parentTheme, defaultDesign)),
),
);
register(notCustomizedStorageKey, (stored) =>
setNotCustomizedState(stored === "true"),
);
const handleStorageChange = (event: StorageEvent) => {
if (event.storageArea !== localStorage) return;
if (event.key) handlers.get(event.key)?.(event.newValue);
@ -491,7 +440,6 @@ export function ThemeProvider({
defaultTheme,
defaultTint,
designStorageKey,
notCustomizedStorageKey,
paletteStorageKey,
parentThemeStorageKey,
parentTheme,
@ -501,7 +449,22 @@ export function ThemeProvider({
tintStorageKey,
]);
const isThemeCustomized = Boolean(parentTheme && !notCustomized);
const parentDesign = presetDesign(parentTheme, defaultDesign);
const parentBorderRadius = presetBorderRadius(
parentTheme,
defaultBorderRadius,
);
const isThemeCustomized = Boolean(
parentTheme &&
(themeCustomCss !== parentTheme.css ||
themeColor !== "" ||
themePalette !== null ||
themePrimaryColor !== "" ||
themeTint !== "soft" ||
themeBorderRadius !== parentBorderRadius ||
!designsEqual(themeDesign, parentDesign)),
);
const value = useMemo<ThemeProviderState>(
() => ({
@ -529,14 +492,12 @@ export function ThemeProvider({
applyThemePreset,
resetThemePreset,
isThemeCustomized,
notCustomized,
themeDesign,
setThemeDesign,
}),
[
applyThemePreset,
isThemeCustomized,
notCustomized,
parentTheme,
parentThemeId,
resetThemePreset,

View file

@ -51,7 +51,6 @@ export const BUILT_IN_THEMES = defineThemes([
--ring: oklch(0.62 0.12 185);
--sidebar: color-mix(in oklch, var(--background) 97%, black);
--sidebar-primary: oklch(0.58 0.12 185);
--markdown-code-background: color-mix(in oklch, var(--muted) 72%, var(--background));
--tensamin-outline-background: #fff;
--tensamin-outline-hover: #0000000a;
--tensamin-outline-pressed: #00000014;
@ -74,7 +73,6 @@ export const BUILT_IN_THEMES = defineThemes([
--primary: oklch(0.69 0.12 184);
--primary-foreground: oklch(0.16 0.025 190);
--primary-foreground-alt: oklch(0.73 0.13 183);
--markdown-code-background: color-mix(in oklch, var(--card) 76%, black 24%);
--tensamin-outline-background: #ffffff0f;
--tensamin-outline-hover: #ffffff0f;
--tensamin-outline-pressed: #ffffff1a;
@ -249,7 +247,6 @@ export const BUILT_IN_THEMES = defineThemes([
--chart-3: #aca1cf;
--chart-4: #e29eca;
--chart-5: #e5c890;
--markdown-code-background: color-mix(in srgb, var(--muted) 78%, var(--background));
}
:root.dark[data-theme="og-tensamin"] {
--background: #0f1014;
@ -284,7 +281,6 @@ export const BUILT_IN_THEMES = defineThemes([
--chart-3: #aca1cf;
--chart-4: #e29eca;
--chart-5: #e5c890;
--markdown-code-background: color-mix(in srgb, var(--muted) 72%, black 28%);
}
:root[data-theme="og-tensamin"] :where([data-slot="select-content"], [data-slot="dropdown-menu-content"], [data-slot="dropdown-menu-sub-content"], [data-slot="context-menu-content"], [data-slot="context-menu-sub-content"], [data-slot="menubar-content"], [data-slot="menubar-sub-content"], [data-slot="combobox-content"], [data-slot="popover-content"], [data-slot="hover-card-content"]) {
background-color: var(--popover);
@ -327,7 +323,7 @@ export const BUILT_IN_THEMES = defineThemes([
--accent: #cf8fe633;
--accent-foreground: #642f79;
--destructive: #b91c1c;
--border: #b7c2cc;
--border: #242D38;
--input: #b7c2cc;
--ring: #9d53bc;
--chart-1: #8c47ad;
@ -341,9 +337,8 @@ export const BUILT_IN_THEMES = defineThemes([
--sidebar-primary-foreground: #ffffff;
--sidebar-accent: #cf8fe633;
--sidebar-accent-foreground: #642f79;
--sidebar-border: #b7c2cc;
--sidebar-border: #242D38;
--sidebar-ring: #9d53bc;
--markdown-code-background: color-mix(in srgb, var(--input) 55%, var(--background));
}
:root.dark[data-theme="methanium"] {
--background: #171E26;
@ -378,7 +373,6 @@ export const BUILT_IN_THEMES = defineThemes([
--sidebar-accent-foreground: #d2e0f0;
--sidebar-border: #242D38;
--sidebar-ring: #cf8fe6;
--markdown-code-background: color-mix(in srgb, var(--input) 55%, var(--background));
}
:root[data-theme="methanium"] body {
background-color: var(--background);
@ -441,8 +435,8 @@ export const BUILT_IN_THEMES = defineThemes([
}
:root[data-theme="methanium"] [data-slot="card"] {
padding-block: calc(1rem * var(--ui-density));
border: 1px solid var(--input);
background-color: color-mix(in srgb, var(--input) 55%, var(--background));
border: none;
background-color: #242D38;
}
:root[data-theme="methanium"] [data-slot="button"][data-variant="default"] {
background-color: var(--primary);
@ -512,464 +506,175 @@ export const BUILT_IN_THEMES = defineThemes([
},
css: `:root[data-theme="secret"] {
--secret-border: color-mix(in srgb, #2f1b13 22%, #fffaf2 78%);
--secret-purple: #d7a8c9;
--secret-control: var(--secret-purple);
--secret-control: #5e244e;
--secret-gold: color-mix(in srgb, #f9b637 75%, #2f1b13 25%);
--secret-gold-dark: color-mix(in srgb, var(--secret-gold) 60%, #2f1b13 40%);
--secret-gold-light: color-mix(in srgb, var(--secret-gold) 45%, #ffe8b4 55%);
--background: oklch(0.98 0 0);
--foreground: #2f1b13;
--card: var(--background);
--card-foreground: var(--foreground);
--popover: var(--secret-purple);
--popover-foreground: #2f1b13;
--popover: #5e244e;
--popover-foreground: #fffaf2;
--primary: var(--secret-gold);
--primary-foreground: #24120c;
--primary-foreground-alt: #c04b00;
--secondary: var(--secret-purple);
--secondary-foreground: #2f1b13;
--muted: #c89ab9;
--muted-foreground: #49333f;
--primary-foreground-alt: #fb6c00;
--secondary: #5e244e;
--secondary-foreground: #fffaf2;
--muted: #24120c;
--muted-foreground: #6b7280;
--accent: #fb6c00;
--accent-foreground: #24120c;
--destructive: #d93618;
--destructive-foreground: #fffaf2;
--destructive: #e73f1e;
--border: var(--secret-border);
--input: var(--secret-border);
--ring: #4a2110;
--ring: #fb6c00;
--sidebar: color-mix(in oklch, var(--background) 97%, black);
--sidebar-foreground: #2f1b13;
--sidebar-primary: var(--secret-gold);
--sidebar-primary-foreground: #24120c;
--sidebar-accent: #d7a8c9;
--sidebar-accent-foreground: #2f1b13;
--sidebar-accent: #aa1c41;
--sidebar-accent-foreground: #fffaf2;
--sidebar-border: var(--secret-border);
--markdown-code-background: color-mix(
in srgb,
var(--secret-gold) 9%,
var(--background)
);
}
:root.dark[data-theme="secret"] {
--secret-border: color-mix(in srgb, #ffe8b4 8%, #24120c 35%);
--secret-purple: #5e244e;
--secret-control: var(--secret-purple);
--background: #0a0a0a;
--secret-border: color-mix(in srgb, #ffe8b4 15%, #24120c 85%);
--secret-control: #5e244e;
--background: #0A0A0A;
--foreground: #ffe8b4;
--card: var(--background);
--card-foreground: var(--foreground);
--popover: #2f1b13;
--popover-foreground: #ffe8b4;
--primary: var(--secret-gold);
--primary-foreground: #24120c;
--primary-foreground-alt: #fb6c00;
--secondary: var(--secret-purple);
--secondary: #5e244e;
--secondary-foreground: #fffaf2;
--muted: #2f1b13;
--muted-foreground: #e68457;
--accent: #d93618;
--accent: #e73f1e;
--accent-foreground: #fffaf2;
--destructive: #d93618;
--destructive-foreground: #fffaf2;
--destructive: #e73f1e;
--border: var(--secret-border);
--input: var(--secret-border);
--ring: #f9b637;
--sidebar: #0f0f0f;
--ring: #fb6c00;
--sidebar: #0F0F0F;
--sidebar-foreground: #ffe8b4;
--sidebar-primary: var(--secret-gold);
--sidebar-primary-foreground: #24120c;
--sidebar-accent: #aa1c41;
--sidebar-accent-foreground: #fffaf2;
--sidebar-border: var(--secret-border);
--markdown-code-background: color-mix(
in srgb,
var(--muted) 72%,
black 28%
);
}
:root[data-theme="secret"] :where(
[data-slot="button"],
[data-slot="toggle"],
[data-slot="input"],
[data-slot="textarea"],
[data-slot="native-select"],
[data-slot="select-trigger"],
[data-slot="input-group"],
[data-slot="checkbox"],
[data-slot="radio-group-item"],
[data-slot="switch"]
) {
background-image: linear-gradient(
to top,
rgb(255 255 255 / 12%),
rgb(255 255 255 / 2%)
);
:root[data-theme="secret"] :where([data-slot="button"], [data-slot="toggle"], [data-slot="input"], [data-slot="textarea"], [data-slot="native-select"], [data-slot="select-trigger"], [data-slot="input-group"], [data-slot="checkbox"], [data-slot="radio-group-item"], [data-slot="switch"]) {
background-image: linear-gradient(to top, rgb(255 255 255 / 12%), rgb(255 255 255 / 2%));
background-repeat: no-repeat;
}
:root[data-theme="secret"] [data-slot="button"][data-variant="ghost"] {
background-image: none;
}
:root[data-theme="secret"] [data-slot="button"][data-variant="ghost"]:hover {
background-image: linear-gradient(
to top,
rgb(255 255 255 / 12%),
rgb(255 255 255 / 2%)
);
background-image: linear-gradient(to top, rgb(255 255 255 / 12%), rgb(255 255 255 / 2%));
}
:root[data-theme="secret"] [data-slot="button"][data-variant="subtleDefault"] {
background-image: linear-gradient(
to top,
rgb(255 232 180 / 12%),
rgb(255 232 180 / 2%)
);
background-image: linear-gradient(to top, rgb(255 232 180 / 12%), rgb(255 232 180 / 2%));
color: var(--foreground);
}
:root:not(.dark)[data-theme="secret"]
[data-slot="button"][data-variant="subtleDefault"] {
background-color: color-mix(
in srgb,
var(--primary-foreground-alt) 6%,
transparent
);
background-image: linear-gradient(
to top,
rgb(255 232 180 / 30%),
rgb(255 232 180 / 80%)
);
:root:not(.dark)[data-theme="secret"] [data-slot="button"][data-variant="subtleDefault"] {
background-color: color-mix(in srgb, var(--primary-foreground-alt) 6%, transparent);
background-image: linear-gradient(to top, rgb(255 232 180 / 30%), rgb(255 232 180 / 80%));
}
:root[data-theme="secret"] :where(
[data-slot="input"],
[data-slot="textarea"],
[data-slot="native-select"],
[data-slot="select-trigger"],
[data-slot="input-group"]
) {
:root[data-theme="secret"] :where([data-slot="input"], [data-slot="textarea"], [data-slot="native-select"], [data-slot="select-trigger"], [data-slot="input-group"]) {
background-color: var(--secret-control);
border-color: transparent;
color: var(--foreground);
}
:root:not(.dark)[data-theme="secret"] :where(
[data-slot="input"],
[data-slot="textarea"],
[data-slot="native-select"],
[data-slot="select-trigger"],
[data-slot="input-group"]
) {
color: #2f1b13;
:root:not(.dark)[data-theme="secret"] :where([data-slot="input"], [data-slot="textarea"], [data-slot="native-select"], [data-slot="select-trigger"], [data-slot="input-group"]) {
color: #fffaf2;
}
:root.dark[data-theme="secret"] :where(
[data-slot="input"],
[data-slot="textarea"],
[data-slot="native-select"],
[data-slot="select-trigger"],
[data-slot="input-group"]
) {
color: #ffe8b4;
}
:root:not(.dark)[data-theme="secret"] :where(
[data-slot="input"],
[data-slot="textarea"]
)::placeholder {
color: #5f4558;
opacity: 1;
}
:root.dark[data-theme="secret"] :where(
[data-slot="input"],
[data-slot="textarea"]
)::placeholder {
color: #d9b99c;
opacity: 1;
}
:root:not(.dark)[data-theme="secret"] :where(
[data-slot="input"],
[data-slot="textarea"],
[data-slot="native-select"],
[data-slot="select-trigger"],
[data-slot="input-group"]
):hover {
background-color: color-mix(
in srgb,
var(--secret-control) 88%,
#622a53 12%
);
:root[data-theme="secret"] :where([data-slot="input"], [data-slot="textarea"], [data-slot="native-select"], [data-slot="select-trigger"], [data-slot="input-group"]):hover {
background-color: color-mix(in srgb, var(--secret-control) 84%, #24120c 16%);
border-color: transparent;
}
:root.dark[data-theme="secret"] :where(
[data-slot="input"],
[data-slot="textarea"],
[data-slot="native-select"],
[data-slot="select-trigger"],
[data-slot="input-group"]
):hover {
background-color: color-mix(
in srgb,
var(--secret-control) 84%,
#24120c 16%
);
:root[data-theme="secret"] :where([data-slot="input"], [data-slot="textarea"], [data-slot="native-select"], [data-slot="select-trigger"], [data-slot="input-group"]):is(:focus-visible, :focus-within) {
background-color: color-mix(in srgb, var(--secret-control) 84%, #24120c 16%);
border-color: transparent;
}
:root:not(.dark)[data-theme="secret"] :where(
[data-slot="input"],
[data-slot="textarea"],
[data-slot="native-select"],
[data-slot="select-trigger"],
[data-slot="input-group"]
):is(:focus-visible, :focus-within) {
background-color: color-mix(
in srgb,
var(--secret-control) 88%,
#622a53 12%
);
:root[data-theme="secret"] [data-slot="select-trigger"]:is([data-popup-open], [data-open], [aria-expanded="true"]) {
background-color: color-mix(in srgb, var(--secret-control) 84%, #24120c 16%);
border-color: transparent;
}
:root.dark[data-theme="secret"] :where(
[data-slot="input"],
[data-slot="textarea"],
[data-slot="native-select"],
[data-slot="select-trigger"],
[data-slot="input-group"]
):is(:focus-visible, :focus-within) {
background-color: color-mix(
in srgb,
var(--secret-control) 84%,
#24120c 16%
);
border-color: transparent;
}
:root:not(.dark)[data-theme="secret"]
[data-slot="select-trigger"]:is(
[data-popup-open],
[data-open],
[aria-expanded="true"]
) {
background-color: color-mix(
in srgb,
var(--secret-control) 88%,
#622a53 12%
);
border-color: transparent;
}
:root.dark[data-theme="secret"]
[data-slot="select-trigger"]:is(
[data-popup-open],
[data-open],
[aria-expanded="true"]
) {
background-color: color-mix(
in srgb,
var(--secret-control) 84%,
#24120c 16%
);
border-color: transparent;
}
:root[data-theme="secret"] [data-slot="select-content"] {
background-color: var(--popover);
border-color: var(--secret-border);
color: var(--popover-foreground);
}
:root:not(.dark)[data-theme="secret"] :where(
[data-slot="select-item"],
[data-slot="context-menu-item"],
[data-slot="context-menu-sub-trigger"]
):is(
:hover,
:focus,
[data-highlighted],
[data-selected],
[data-open]
) {
background-color: color-mix(
in srgb,
var(--popover) 82%,
#622a53 18%
);
color: #2f1b13;
:root.dark[data-theme="secret"] [data-slot="select-content"] {
border-color: var(--secret-border);
}
:root.dark[data-theme="secret"] :where(
[data-slot="select-item"],
[data-slot="context-menu-item"],
[data-slot="context-menu-sub-trigger"]
):is(
:hover,
:focus,
[data-highlighted],
[data-selected],
[data-open]
) {
background-color: color-mix(
in srgb,
var(--popover) 72%,
#0a0a0a 28%
);
:root[data-theme="secret"] :where([data-slot="select-item"], [data-slot="context-menu-item"], [data-slot="context-menu-sub-trigger"]):is(:hover, :focus, [data-highlighted], [data-selected], [data-open]) {
background-color: color-mix(in srgb, var(--popover) 72%, #0a0a0a 28%);
color: #ffe8b4;
}
:root[data-theme="secret"] [data-slot="button"][data-variant="default"] {
background-color: var(--primary);
background-image:
linear-gradient(
to top,
rgb(255 255 255 / 12%),
rgb(255 255 255 / 2%)
),
linear-gradient(
115deg,
var(--secret-gold-dark) 0%,
var(--secret-gold) 30%,
var(--secret-gold-light) 47%,
var(--secret-gold) 62%,
var(--secret-gold-dark) 100%
);
background-image: linear-gradient(to top, rgb(255 255 255 / 12%), rgb(255 255 255 / 2%)), linear-gradient(115deg, var(--secret-gold-dark) 0%, var(--secret-gold) 30%, var(--secret-gold-light) 47%, var(--secret-gold) 62%, var(--secret-gold-dark) 100%);
border-color: var(--secret-border);
color: var(--primary-foreground);
text-shadow: 0 1px rgb(255 255 255 / 35%);
box-shadow:
inset 0 1px rgb(255 255 255 / 45%),
0 0.45rem 1.2rem rgb(36 18 12 / 28%);
box-shadow: inset 0 1px rgb(255 255 255 / 45%), 0 0.45rem 1.2rem rgb(36 18 12 / 28%);
}
:root[data-theme="secret"] :where(
[data-slot="card"],
[data-slot="dialog-content"],
[data-slot="alert-dialog-content"]
) {
:root[data-theme="secret"] :where([data-slot="card"], [data-slot="dialog-content"], [data-slot="alert-dialog-content"]) {
border-color: var(--secret-border);
box-shadow:
inset 0 1px color-mix(in oklch, white 8%, transparent),
0 1rem 3rem rgb(97 37 82 / 12%);
box-shadow: inset 0 1px color-mix(in oklch, white 8%, transparent), 0 1rem 3rem rgb(97 37 82 / 12%);
}
:root[data-theme="secret"] [data-slot="card"] {
background: var(--card);
}
:root[data-theme="secret"] :where(
[data-slot="button"][data-variant="outline"],
[data-slot="button"][data-variant="link"],
[data-slot="badge"][data-variant="outline"],
[data-slot="toggle"][data-variant="outline"]
) {
:root[data-theme="secret"] :where([data-slot="button"][data-variant="outline"], [data-slot="button"][data-variant="link"], [data-slot="badge"][data-variant="outline"], [data-slot="toggle"][data-variant="outline"]) {
background-color: var(--secondary);
border-color: transparent;
color: var(--secondary-foreground);
}
:root[data-theme="secret"] [data-slot="button"][data-variant="link"] {
background-image: none;
}
:root[data-theme="secret"] [data-slot="button"][data-variant="link"]:hover {
background-color: var(--secondary);
background-image: none;
}
:root:not(.dark)[data-theme="secret"] :where(
[data-slot="button"],
[data-slot="badge"],
[data-slot="toggle"]
)[data-variant="outline"]:is(
:hover,
:focus-visible,
[aria-expanded="true"],
[data-popup-open],
[data-open]
) {
background-color: color-mix(
in srgb,
var(--secondary) 82%,
#622a53 18%
);
:root[data-theme="secret"] [data-slot="button"][data-variant="outline"]:hover {
background-color: color-mix(in srgb, #5e244e 82%, #24120c 18%);
border-color: transparent;
color: var(--secondary-foreground);
}
:root.dark[data-theme="secret"] :where(
[data-slot="button"],
[data-slot="badge"],
[data-slot="toggle"]
)[data-variant="outline"]:is(
:hover,
:focus-visible,
[aria-expanded="true"],
[data-popup-open],
[data-open]
) {
background-color: color-mix(
in srgb,
var(--secondary) 82%,
#24120c 18%
);
:root[data-theme="secret"] :where([data-slot="badge"], [data-slot="toggle"])[data-variant="outline"]:hover {
background-color: color-mix(in srgb, #5e244e 82%, #24120c 18%);
border-color: transparent;
color: var(--secondary-foreground);
}
:root[data-theme="secret"] :where(
[data-slot="card-title"],
[data-slot="item-media"][data-variant="icon"],
[data-slot="badge"][data-variant="outline"]
) svg {
:root[data-theme="secret"] :where([data-slot="button"], [data-slot="badge"], [data-slot="toggle"])[data-variant="outline"]:is(:focus-visible, [aria-expanded="true"], [data-popup-open], [data-open]) {
background-color: color-mix(in srgb, #5e244e 82%, #24120c 18%);
border-color: transparent;
}
:root:not(.dark)[data-theme="secret"] [data-slot="button"][data-variant="outline"]:hover,
:root:not(.dark)[data-theme="secret"] :where([data-slot="badge"], [data-slot="toggle"])[data-variant="outline"]:hover,
:root:not(.dark)[data-theme="secret"] :where([data-slot="button"], [data-slot="badge"], [data-slot="toggle"])[data-variant="outline"]:is(:focus-visible, [aria-expanded="true"], [data-popup-open], [data-open]) {
background-color: color-mix(in srgb, var(--secondary) 82%, #fffaf2 18%);
border-color: transparent;
}
:root.dark[data-theme="secret"] :where([data-slot="button"][data-variant="outline"], [data-slot="button"][data-variant="link"], [data-slot="badge"][data-variant="outline"], [data-slot="toggle"][data-variant="outline"]) {
background-color: #5e244e;
border-color: transparent;
color: #ffe8b4;
}
:root.dark[data-theme="secret"] [data-slot="button"][data-variant="outline"]:hover {
background-color: color-mix(in srgb, #5e244e 82%, #24120c 18%);
}
:root[data-theme="secret"] :where([data-slot="card-title"], [data-slot="item-media"][data-variant="icon"], [data-slot="badge"][data-variant="outline"]) svg {
color: var(--primary);
}
:root:not(.dark)[data-theme="secret"] :where(
[data-slot="card-title"],
[data-slot="item-media"][data-variant="icon"],
[data-slot="badge"][data-variant="outline"]
) svg {
color: var(--secret-gold-dark);
}
:root[data-theme="secret"] [data-slot="separator"] {
background: linear-gradient(
90deg,
transparent,
color-mix(in oklch, var(--primary) 42%, var(--border)),
transparent
);
background: linear-gradient(90deg, transparent, color-mix(in oklch, var(--primary) 42%, var(--border)), transparent);
}`,
},
] as const);

View file

@ -74,7 +74,6 @@ export type ThemeProviderProps = {
customCssStorageKey?: string | null;
parentThemeStorageKey?: string | null;
designStorageKey?: string | null;
notCustomizedStorageKey?: string | null;
disableTransitionOnChange?: boolean;
};
@ -103,7 +102,6 @@ export type ThemeProviderState = {
applyThemePreset: (id: string) => void;
resetThemePreset: () => void;
isThemeCustomized: boolean;
notCustomized: boolean;
themeDesign: ThemeDesign;
setThemeDesign: (
design: ThemeDesign | ((current: ThemeDesign) => ThemeDesign),