Compare commits

..
Author SHA1 Message Date
586eb5f277
feat(methanium-theme): add a border to cards
All checks were successful
/ deploy-and-package (push) Successful in 45s
2026-08-30 12:52:27 +02:00
13580277b4
feat(methanium-theme): improve card backgrounds
All checks were successful
/ deploy-and-package (push) Successful in 37s
2026-08-30 12:47:45 +02:00
99a087db3d
chore(version): bump to 0.0.30
All checks were successful
/ deploy-and-package (push) Successful in 43s
2026-08-30 12:43:25 +02:00
76a26a0af9
fix(spinner): loading animation not playing unless forced to
Some checks failed
/ deploy-and-package (push) Has been cancelled
fix(methanium-theme): missing light mode values for border and card
fix(secret-theme): contrast issues
feat(secret-theme): use lighter colors in light mode
feat(themes): make markdown code box backgrounds fit better to each theme
feat(qol): add flag to auto-reset themes if they're not customised
2026-08-30 12:42:53 +02:00
98a6dde805
Update workflows
All checks were successful
/ deploy-and-package (push) Successful in 17s
2026-08-20 20:58:40 +02:00
e4c2d705e8
feat(mobile): add safe area padding
All checks were successful
/ deploy-and-package (push) Successful in 1m16s
2026-08-11 20:36:07 +02:00
56891acfe2
chore(deps): update codebase
All checks were successful
/ deploy-and-package (push) Successful in 1m22s
2026-08-10 22:33:54 +02:00
2f93b682eb
Merge remote-tracking branch 'refs/remotes/origin/main' 2026-08-10 22:33:33 +02:00
25fd556c3d
feat(legal): add privacy policy notice 2026-08-10 22:33:27 +02:00
5a2fd1b3ec Merge pull request 'chore(deps): lock file maintenance' (#17) from renovate/lock-file-maintenance into main
All checks were successful
/ deploy-and-package (push) Successful in 1m16s
2026-08-10 00:07:28 +02:00
03325797bf
fix(markdown): replace annotation with edited indicator
Some checks failed
/ deploy-and-package (push) Has been cancelled
2026-08-10 00:07:22 +02:00
5b52e1ae29 chore(deps): lock file maintenance
Some checks failed
renovate/stability-days Updates have not met minimum release age requirement
Dependency builds / Build & Lint (pull_request) Failing after 49s
2026-08-10 00:02:40 +02:00
5e2120906e
feat(markdown): add code fencing for ??++
All checks were successful
/ deploy-and-package (push) Successful in 1m17s
2026-08-09 23:56:58 +02:00
f50e7e9b71
feat(markdown): add ??++
All checks were successful
/ deploy-and-package (push) Successful in 1m17s
2026-08-09 23:41:51 +02:00
b48e346001
feat(code-block): last-minute styling
All checks were successful
/ deploy-and-package (push) Successful in 1m18s
2026-08-09 23:22:24 +02:00
358d2a26a0
feat(code-block): last-minute styling
All checks were successful
/ deploy-and-package (push) Successful in 1m18s
2026-08-09 23:20:12 +02:00
dcebbd0943
fix(markdown): respect emoji tooltip option
All checks were successful
/ deploy-and-package (push) Successful in 1m18s
2026-08-09 23:02:49 +02:00
7194ba72fd
feat(deps): add dep build workflow
All checks were successful
/ deploy-and-package (push) Successful in 1m19s
2026-08-09 22:34:19 +02:00
39 changed files with 764 additions and 578 deletions

View file

@ -0,0 +1,21 @@
name: Dependency builds
on:
pull_request:
env:
FORGEJO_TOKEN: ""
GITHUB_TOKEN: ""
jobs:
check:
if: ${{ github.actor == 'rasensprenger' }}
name: Build & Lint
runs-on: nixos
steps:
- uses: https://data.forgejo.org/actions/checkout@v4
with:
persist-credentials: false
- run: nix develop .#electron --command pnpm install --frozen-lockfile
- run: nix develop .#electron --command pnpm run lint
- run: nix develop .#electron --command pnpm run build

View file

@ -3,37 +3,3 @@
```sh ```sh
pnpm install https://git.methanium.net/methanium/ui/releases/download/latest/methanium-ui.tgz pnpm install https://git.methanium.net/methanium/ui/releases/download/latest/methanium-ui.tgz
``` ```
## Markdown
The renderer is available from the package root. The live editor, compact text
renderer, and emoji APIs use the `@methanium/ui/markdown` entry point.
```tsx
import { Markdown } from "@methanium/ui";
import {
EmojiProvider,
Input,
createEmojiRegistry,
} from "@methanium/ui/markdown";
const registry = createEmojiRegistry({
customEmojis: [
{
shortcode: ":party_parrot:",
aliases: [":parrot_party:"],
src: "/emoji/party-parrot.webp",
},
],
});
<EmojiProvider registry={registry}>
<Input value={value} setValue={setValue} />
<Markdown content={value} />
</EmojiProvider>;
```
Custom shortcodes and aliases must be unique and may not collide with built-in
Twemoji names. Twemoji graphics are bundled locally and do not use a CDN. The
graphics are provided by the [Twemoji project](https://github.com/jdecked/twemoji)
under CC-BY 4.0; code is licensed under MIT.

View file

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

View file

@ -17,6 +17,7 @@
"devDependencies": { "devDependencies": {
"@eslint/js": "^10.0.1", "@eslint/js": "^10.0.1",
"@tailwindcss/vite": "^4.3.3", "@tailwindcss/vite": "^4.3.3",
"@typescript/native": "npm:typescript@^7.0.2",
"@types/node": "^26.2.0", "@types/node": "^26.2.0",
"@types/react": "^19.2.18", "@types/react": "^19.2.18",
"@types/react-dom": "^19.2.4", "@types/react-dom": "^19.2.4",
@ -25,7 +26,7 @@
"eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.3", "eslint-plugin-react-refresh": "^0.5.3",
"globals": "^17.9.0", "globals": "^17.9.0",
"typescript": "^7.0.2", "typescript": "npm:@typescript/typescript6@^6.0.2",
"typescript-eslint": "^8.66.0", "typescript-eslint": "^8.66.0",
"vite": "^8.2.1" "vite": "^8.2.1"
} }

View file

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

View file

@ -1,15 +1,6 @@
import { import { Markdown } from "@methanium/ui";
Button,
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
Markdown,
} from "@methanium/ui";
import { import {
createEmojiRegistry, createEmojiRegistry,
Emoji,
EmojiProvider, EmojiProvider,
Input, Input,
Text, Text,
@ -37,7 +28,7 @@ const markdownContent = [
"", "",
"Shortcodes use local Twemoji assets :fire: :white_check_mark:, while applications can register their own images :methanium:.", "Shortcodes use local Twemoji assets :fire: :white_check_mark:, while applications can register their own images :methanium:.",
"", "",
"Visit the [Methanium repository](https://github.com/methanium) or jump to the [code examples](#code-examples). Bare URLs are supported too: https://example.com.", "Visit the [Methanium](https://methanium.net) or jump to the [code examples](#code-examples). Bare URLs are supported too: https://example.com.",
"", "",
"![Methanium logo](" + methaniumLogo + ")", "![Methanium logo](" + methaniumLogo + ")",
"", "",
@ -136,7 +127,6 @@ function MarkdownShowcase() {
const [inputValue, setInputValue] = useState( const [inputValue, setInputValue] = useState(
'Hello **Markdown** :fire:\n\nTry the custom :methanium: emoji or type another `:shortcode:`. \n```ts\nconst stuff = "stuff";\n```', 'Hello **Markdown** :fire:\n\nTry the custom :methanium: emoji or type another `:shortcode:`. \n```ts\nconst stuff = "stuff";\n```',
); );
const [submissions, setSubmissions] = useState(0);
const controllerRef = useRef<InputController | null>(null); const controllerRef = useRef<InputController | null>(null);
return ( return (
@ -149,7 +139,6 @@ function MarkdownShowcase() {
setValue={setInputValue} setValue={setInputValue}
placeholder="Write Markdown or type :fire:" placeholder="Write Markdown or type :fire:"
emojiFrequencies={{ ":methanium:": 20, ":fire:": 10 }} emojiFrequencies={{ ":methanium:": 20, ":fire:": 10 }}
onSubmit={() => setSubmissions((count) => count + 1)}
onControllerChange={(controller) => { onControllerChange={(controller) => {
controllerRef.current = controller; controllerRef.current = controller;
}} }}

27
flake.nix Normal file
View file

@ -0,0 +1,27 @@
{
description = "Methanium UI development environment";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs = { nixpkgs, ... }:
let
forAllSystems = nixpkgs.lib.genAttrs [
"x86_64-linux"
"aarch64-linux"
];
in
{
devShells = forAllSystems (system:
let
pkgs = import nixpkgs { inherit system; };
in
{
electron = pkgs.mkShell {
packages = with pkgs; [
nodejs_24
pnpm
];
};
});
};
}

View file

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

495
pnpm-lock.yaml generated
View file

@ -10,7 +10,7 @@ importers:
dependencies: dependencies:
'@base-ui/react': '@base-ui/react':
specifier: ^1.7.0 specifier: ^1.7.0
version: 1.7.0(@date-fns/tz@1.5.0)(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) version: 1.7.0(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
'@codemirror/autocomplete': '@codemirror/autocomplete':
specifier: ^6.20.3 specifier: ^6.20.3
version: 6.20.3 version: 6.20.3
@ -57,11 +57,11 @@ importers:
specifier: ^1.4.2 specifier: ^1.4.2
version: 1.4.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) version: 1.4.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
katex: katex:
specifier: ^0.18.2 specifier: ^0.18.3
version: 0.18.2 version: 0.18.3
lucide-react: lucide-react:
specifier: ^1.30.0 specifier: ^1.31.0
version: 1.30.0(react@19.2.8) version: 1.31.0(react@19.2.8)
next-themes: next-themes:
specifier: ^0.4.6 specifier: ^0.4.6
version: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8) version: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
@ -79,7 +79,7 @@ importers:
version: 4.12.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8) version: 4.12.2(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
recharts: recharts:
specifier: 3.10.1 specifier: 3.10.1
version: 3.10.1(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.7)(react@19.2.8)(redux@5.0.1) version: 3.10.1(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1)
rehype-autolink-headings: rehype-autolink-headings:
specifier: ^7.1.0 specifier: ^7.1.0
version: 7.1.0 version: 7.1.0
@ -105,8 +105,8 @@ importers:
specifier: ^4.4.2 specifier: ^4.4.2
version: 4.4.2 version: 4.4.2
sonner: sonner:
specifier: ^2.0.7 specifier: ^2.0.8
version: 2.0.7(react-dom@19.2.8(react@19.2.8))(react@19.2.8) version: 2.0.8(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
tailwind-merge: tailwind-merge:
specifier: ^3.6.0 specifier: ^3.6.0
version: 3.6.0 version: 3.6.0
@ -146,7 +146,7 @@ importers:
version: 7.0.2 version: 7.0.2
vite: vite:
specifier: ^8.2.1 specifier: ^8.2.1
version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0) version: 8.2.1(@types/node@26.2.0)(jiti@2.7.0)
apps/showcase: apps/showcase:
dependencies: dependencies:
@ -165,7 +165,7 @@ importers:
version: 10.0.1(eslint@10.8.1(jiti@2.7.0)) version: 10.0.1(eslint@10.8.1(jiti@2.7.0))
'@tailwindcss/vite': '@tailwindcss/vite':
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)) version: 4.3.3(vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0))
'@types/node': '@types/node':
specifier: ^26.2.0 specifier: ^26.2.0
version: 26.2.0 version: 26.2.0
@ -175,9 +175,12 @@ importers:
'@types/react-dom': '@types/react-dom':
specifier: ^19.2.4 specifier: ^19.2.4
version: 19.2.4(@types/react@19.2.18) version: 19.2.4(@types/react@19.2.18)
'@typescript/native':
specifier: npm:typescript@^7.0.2
version: typescript@7.0.2
'@vitejs/plugin-react': '@vitejs/plugin-react':
specifier: ^6.0.5 specifier: ^6.0.5
version: 6.0.5(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0)) version: 6.0.5(vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0))
eslint: eslint:
specifier: ^10.8.1 specifier: ^10.8.1
version: 10.8.1(jiti@2.7.0) version: 10.8.1(jiti@2.7.0)
@ -191,14 +194,14 @@ importers:
specifier: ^17.9.0 specifier: ^17.9.0
version: 17.9.0 version: 17.9.0
typescript: typescript:
specifier: ^7.0.2 specifier: npm:@typescript/typescript6@^6.0.2
version: 7.0.2 version: '@typescript/typescript6@6.0.2'
typescript-eslint: typescript-eslint:
specifier: ^8.66.0 specifier: ^8.66.0
version: 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@7.0.2) version: 8.66.0(@typescript/typescript6@6.0.2)(eslint@10.8.1(jiti@2.7.0))
vite: vite:
specifier: ^8.2.1 specifier: ^8.2.1
version: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0) version: 8.2.1(@types/node@26.2.0)(jiti@2.7.0)
packages: packages:
@ -392,9 +395,6 @@ packages:
'@codemirror/view@6.43.8': '@codemirror/view@6.43.8':
resolution: {integrity: sha512-qtItTDssZ/5GFfi94hrILu9j/VUeFPDPkhovEfmWFj2ipTxnzPB8DdHgfbb8HYTzLTYhrndKmyQxXUz/PDLenw==} resolution: {integrity: sha512-qtItTDssZ/5GFfi94hrILu9j/VUeFPDPkhovEfmWFj2ipTxnzPB8DdHgfbb8HYTzLTYhrndKmyQxXUz/PDLenw==}
'@date-fns/tz@1.5.0':
resolution: {integrity: sha512-lwYN/vDPeNRULcepoE/LO2Pgx+7/RV+S9ARfbc9lr2DtGkOD7pAiruHvbR1RX3Qyf6ja47EWJDMsNK5vK08DJg==}
'@dotenvx/dotenvx@1.75.1': '@dotenvx/dotenvx@1.75.1':
resolution: {integrity: sha512-/BITOC9dmS/edY2zQwZNicQ059O6RKabtQfyEafV0nGtfYRNHYy1DIPiYVcov40+tob9hfmBnbR963dS+EQ1DQ==} resolution: {integrity: sha512-/BITOC9dmS/edY2zQwZNicQ059O6RKabtQfyEafV0nGtfYRNHYy1DIPiYVcov40+tob9hfmBnbR963dS+EQ1DQ==}
hasBin: true hasBin: true
@ -402,162 +402,6 @@ packages:
'@dotenvx/primitives@0.8.0': '@dotenvx/primitives@0.8.0':
resolution: {integrity: sha512-VYJy0uhFm9zTJ1TxBaW/pA8bjbOM/OttaNMwZ1RHG4JKyRG7DhSdiqD1ipQoAyoD22olUtxbP78W9xY3Wd11bg==} resolution: {integrity: sha512-VYJy0uhFm9zTJ1TxBaW/pA8bjbOM/OttaNMwZ1RHG4JKyRG7DhSdiqD1ipQoAyoD22olUtxbP78W9xY3Wd11bg==}
'@esbuild/aix-ppc64@0.28.1':
resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
'@esbuild/android-arm64@0.28.1':
resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm@0.28.1':
resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
'@esbuild/android-x64@0.28.1':
resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
'@esbuild/darwin-arm64@0.28.1':
resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-x64@0.28.1':
resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
'@esbuild/freebsd-arm64@0.28.1':
resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-x64@0.28.1':
resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
'@esbuild/linux-arm64@0.28.1':
resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm@0.28.1':
resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
'@esbuild/linux-ia32@0.28.1':
resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-loong64@0.28.1':
resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-mips64el@0.28.1':
resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-ppc64@0.28.1':
resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-riscv64@0.28.1':
resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-s390x@0.28.1':
resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-x64@0.28.1':
resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
'@esbuild/netbsd-arm64@0.28.1':
resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
'@esbuild/netbsd-x64@0.28.1':
resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
'@esbuild/openbsd-arm64@0.28.1':
resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
'@esbuild/openbsd-x64@0.28.1':
resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
'@esbuild/openharmony-arm64@0.28.1':
resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
'@esbuild/sunos-x64@0.28.1':
resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
'@esbuild/win32-arm64@0.28.1':
resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-ia32@0.28.1':
resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-x64@0.28.1':
resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
'@eslint-community/eslint-utils@4.10.1': '@eslint-community/eslint-utils@4.10.1':
resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -1461,6 +1305,10 @@ packages:
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@typescript/typescript6@6.0.2':
resolution: {integrity: sha512-mbCddXd+jm7hfx7w2YU64/Av4/NqqeG3GoRZgxPcgoTxYjhrcfJRw9ULch71SS4G+Q3bOXFhRvPqjguN0Hyp5w==}
hasBin: true
'@ungap/structured-clone@1.3.3': '@ungap/structured-clone@1.3.3':
resolution: {integrity: sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==} resolution: {integrity: sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==}
@ -1547,11 +1395,6 @@ packages:
resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
engines: {node: 18 || 20 || >=22} engines: {node: 18 || 20 || >=22}
baseline-browser-mapping@2.11.12:
resolution: {integrity: sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA==}
engines: {node: '>=6.0.0'}
hasBin: true
baseline-browser-mapping@2.11.13: baseline-browser-mapping@2.11.13:
resolution: {integrity: sha512-k9HNuUVMlqVjQ9UHzfPjIqiDbWw7WqT1AoT7GL8VwvF3r0ZfArtgiSPAlmupyNquNgOJHTuH4CKYf8ttMTWBTQ==} resolution: {integrity: sha512-k9HNuUVMlqVjQ9UHzfPjIqiDbWw7WqT1AoT7GL8VwvF3r0ZfArtgiSPAlmupyNquNgOJHTuH4CKYf8ttMTWBTQ==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
@ -1569,11 +1412,6 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'} engines: {node: '>=8'}
browserslist@4.28.7:
resolution: {integrity: sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
browserslist@4.28.8: browserslist@4.28.8:
resolution: {integrity: sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==} resolution: {integrity: sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
@ -1599,9 +1437,6 @@ packages:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'} engines: {node: '>=6'}
caniuse-lite@1.0.30001807:
resolution: {integrity: sha512-daRXJ9EB/rdRgu7kV+TTl1YUKtlsMWblPl2sLnpg9DZae16QCegol6A1SmCE31Lm9mXC1sRWGt/krouH+/dl7Q==}
caniuse-lite@1.0.30001809: caniuse-lite@1.0.30001809:
resolution: {integrity: sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==} resolution: {integrity: sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==}
@ -1762,9 +1597,6 @@ packages:
resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
engines: {node: '>=12'} engines: {node: '>=12'}
date-fns@4.4.0:
resolution: {integrity: sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==}
debounce-fn@4.0.0: debounce-fn@4.0.0:
resolution: {integrity: sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==} resolution: {integrity: sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -1857,8 +1689,8 @@ packages:
ee-first@1.1.1: ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
electron-to-chromium@1.5.402: electron-to-chromium@1.5.403:
resolution: {integrity: sha512-/oOpMaPT6Yg+6/1XQhyIPlzgj7Ye9zf+nNM2Uh6OcE2G2oNptWazFa+qB2Pdqqbsc9KnIDzgAntoYN0dbwOXwA==} resolution: {integrity: sha512-MQsYmdaLzvaCX5j+ZZBr5Fm6uCCnPQcRtlvmvRlWqrXy+BH2O4ffXIAScF+JQznQWB9brWp4lSD9Z4yNmaf2BA==}
embla-carousel-react@8.6.0: embla-carousel-react@8.6.0:
resolution: {integrity: sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA==} resolution: {integrity: sha512-0/PjqU7geVmo6F734pmPqpyHqiM99olvyecY7zdweCw+6tKEXnrE90pBiBbMMU8s5tICemzpQ3hi5EpxzGW+JA==}
@ -1923,11 +1755,6 @@ packages:
es-toolkit@1.50.0: es-toolkit@1.50.0:
resolution: {integrity: sha512-OyZKhUVvEep9ITEiwHn8GKnMRQIVqoSIX7WnRbkWgJkllCujilqP2rD0u979tkl8wqyc8ICwlc1UBVv/Sl1G6w==} resolution: {integrity: sha512-OyZKhUVvEep9ITEiwHn8GKnMRQIVqoSIX7WnRbkWgJkllCujilqP2rD0u979tkl8wqyc8ICwlc1UBVv/Sl1G6w==}
esbuild@0.28.1:
resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==}
engines: {node: '>=18'}
hasBin: true
escalade@3.2.0: escalade@3.2.0:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -2450,8 +2277,8 @@ packages:
resolution: {integrity: sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==} resolution: {integrity: sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==}
hasBin: true hasBin: true
katex@0.18.2: katex@0.18.3:
resolution: {integrity: sha512-3snve4y0SXTMequLim1FMiPvLGElySam0blN5xQZBqEY3lOJz1TnuaaiugnBZBqHzlSAGmFTYL7MCQkORuLKCA==} resolution: {integrity: sha512-6kbPr8KiYZpRfNNIw+8Td33njnFzK/ELcw6bI9FzIHysYPatAUdepQimfCX1vG2VCD/5Lv+Gu6P5YA58k8HHmw==}
hasBin: true hasBin: true
keyv@4.5.4: keyv@4.5.4:
@ -2638,8 +2465,8 @@ packages:
lru-cache@5.1.1: lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
lucide-react@1.30.0: lucide-react@1.31.0:
resolution: {integrity: sha512-tUIr2jXLbWpCkdtH8XP7P7YppM9ueWgTky99lpWDY6z5REs6B+O6ZQ3U5tHkUUY59ANyOv/PBcs8E4Fe3KO3eA==} resolution: {integrity: sha512-G8u2eEtoHUnUa9f8lbvqDhCiORMnYLdUEo06EEG9MQvHQrInKcX3Pa2TH39MM5qyzRcWETxB0+aOwAPI1g1kEg==}
peerDependencies: peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
@ -3064,8 +2891,8 @@ packages:
peerDependencies: peerDependencies:
react: ^19.2.8 react: ^19.2.8
react-is@19.2.7: react-is@19.2.8:
resolution: {integrity: sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==} resolution: {integrity: sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==}
react-markdown@10.1.0: react-markdown@10.1.0:
resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==}
@ -3285,11 +3112,15 @@ packages:
sisteransi@1.0.5: sisteransi@1.0.5:
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
sonner@2.0.7: sonner@2.0.8:
resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} resolution: {integrity: sha512-UM/ByIoFra8yzV75n1o0Puu0bw5U/9UNnDacrJNspekBewIfsQ3D6ez1nvlWpt7aTsO6rujQtifBpycwIivqlg==}
peerDependencies: peerDependencies:
'@types/react': ^18.0.0 || ^19.0.0
react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
react-dom: ^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: source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
@ -3421,6 +3252,11 @@ packages:
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
typescript: '>=4.8.4 <6.1.0' typescript: '>=4.8.4 <6.1.0'
typescript@6.0.3:
resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==}
engines: {node: '>=14.17'}
hasBin: true
typescript@7.0.2: typescript@7.0.2:
resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==}
engines: {node: '>=16.20.0'} engines: {node: '>=16.20.0'}
@ -3469,12 +3305,6 @@ packages:
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
update-browserslist-db@1.2.3:
resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
hasBin: true
peerDependencies:
browserslist: '>= 4.21.0'
update-browserslist-db@1.3.0: update-browserslist-db@1.3.0:
resolution: {integrity: sha512-x/M6q3w4Ybp91CNaS4S69UnliqR3BzRpOT6LWbksjth0S/+jhfaPJsWjt/TewpT8j9eLIojUf5jr29WextHroA==} resolution: {integrity: sha512-x/M6q3w4Ybp91CNaS4S69UnliqR3BzRpOT6LWbksjth0S/+jhfaPJsWjt/TewpT8j9eLIojUf5jr29WextHroA==}
hasBin: true hasBin: true
@ -3689,7 +3519,7 @@ snapshots:
dependencies: dependencies:
'@babel/compat-data': 7.29.7 '@babel/compat-data': 7.29.7
'@babel/helper-validator-option': 7.29.7 '@babel/helper-validator-option': 7.29.7
browserslist: 4.28.7 browserslist: 4.28.8
lru-cache: 5.1.1 lru-cache: 5.1.1
semver: 6.3.1 semver: 6.3.1
@ -3833,7 +3663,7 @@ snapshots:
'@babel/helper-string-parser': 7.29.7 '@babel/helper-string-parser': 7.29.7
'@babel/helper-validator-identifier': 7.29.7 '@babel/helper-validator-identifier': 7.29.7
'@base-ui/react@1.7.0(@date-fns/tz@1.5.0)(@types/react@19.2.18)(date-fns@4.4.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': '@base-ui/react@1.7.0(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)':
dependencies: dependencies:
'@babel/runtime': 7.29.7 '@babel/runtime': 7.29.7
'@base-ui/utils': 0.3.2(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@base-ui/utils': 0.3.2(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
@ -3843,9 +3673,7 @@ snapshots:
react-dom: 19.2.8(react@19.2.8) react-dom: 19.2.8(react@19.2.8)
use-sync-external-store: 1.6.0(react@19.2.8) use-sync-external-store: 1.6.0(react@19.2.8)
optionalDependencies: optionalDependencies:
'@date-fns/tz': 1.5.0
'@types/react': 19.2.18 '@types/react': 19.2.18
date-fns: 4.4.0
'@base-ui/utils@0.3.2(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': '@base-ui/utils@0.3.2(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)':
dependencies: dependencies:
@ -3938,9 +3766,6 @@ snapshots:
style-mod: 4.1.3 style-mod: 4.1.3
w3c-keyname: 2.2.8 w3c-keyname: 2.2.8
'@date-fns/tz@1.5.0':
optional: true
'@dotenvx/dotenvx@1.75.1': '@dotenvx/dotenvx@1.75.1':
dependencies: dependencies:
'@dotenvx/primitives': 0.8.0 '@dotenvx/primitives': 0.8.0
@ -3962,84 +3787,6 @@ snapshots:
'@dotenvx/primitives@0.8.0': {} '@dotenvx/primitives@0.8.0': {}
'@esbuild/aix-ppc64@0.28.1':
optional: true
'@esbuild/android-arm64@0.28.1':
optional: true
'@esbuild/android-arm@0.28.1':
optional: true
'@esbuild/android-x64@0.28.1':
optional: true
'@esbuild/darwin-arm64@0.28.1':
optional: true
'@esbuild/darwin-x64@0.28.1':
optional: true
'@esbuild/freebsd-arm64@0.28.1':
optional: true
'@esbuild/freebsd-x64@0.28.1':
optional: true
'@esbuild/linux-arm64@0.28.1':
optional: true
'@esbuild/linux-arm@0.28.1':
optional: true
'@esbuild/linux-ia32@0.28.1':
optional: true
'@esbuild/linux-loong64@0.28.1':
optional: true
'@esbuild/linux-mips64el@0.28.1':
optional: true
'@esbuild/linux-ppc64@0.28.1':
optional: true
'@esbuild/linux-riscv64@0.28.1':
optional: true
'@esbuild/linux-s390x@0.28.1':
optional: true
'@esbuild/linux-x64@0.28.1':
optional: true
'@esbuild/netbsd-arm64@0.28.1':
optional: true
'@esbuild/netbsd-x64@0.28.1':
optional: true
'@esbuild/openbsd-arm64@0.28.1':
optional: true
'@esbuild/openbsd-x64@0.28.1':
optional: true
'@esbuild/openharmony-arm64@0.28.1':
optional: true
'@esbuild/sunos-x64@0.28.1':
optional: true
'@esbuild/win32-arm64@0.28.1':
optional: true
'@esbuild/win32-ia32@0.28.1':
optional: true
'@esbuild/win32-x64@0.28.1':
optional: true
'@eslint-community/eslint-utils@4.10.1(eslint@10.8.1(jiti@2.7.0))': '@eslint-community/eslint-utils@4.10.1(eslint@10.8.1(jiti@2.7.0))':
dependencies: dependencies:
eslint: 10.8.1(jiti@2.7.0) eslint: 10.8.1(jiti@2.7.0)
@ -4573,12 +4320,12 @@ snapshots:
'@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3
'@tailwindcss/oxide-win32-x64-msvc': 4.3.3 '@tailwindcss/oxide-win32-x64-msvc': 4.3.3
'@tailwindcss/vite@4.3.3(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0))': '@tailwindcss/vite@4.3.3(vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0))':
dependencies: dependencies:
'@tailwindcss/node': 4.3.3 '@tailwindcss/node': 4.3.3
'@tailwindcss/oxide': 4.3.3 '@tailwindcss/oxide': 4.3.3
tailwindcss: 4.3.3 tailwindcss: 4.3.3
vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0) vite: 8.2.1(@types/node@26.2.0)(jiti@2.7.0)
'@tauri-apps/api@2.11.1': {} '@tauri-apps/api@2.11.1': {}
@ -4658,40 +4405,40 @@ snapshots:
'@types/validate-npm-package-name@4.0.2': {} '@types/validate-npm-package-name@4.0.2': {}
'@typescript-eslint/eslint-plugin@8.66.0(@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@7.0.2))(eslint@10.8.1(jiti@2.7.0))(typescript@7.0.2)': '@typescript-eslint/eslint-plugin@8.66.0(@typescript-eslint/parser@8.66.0(@typescript/typescript6@6.0.2)(eslint@10.8.1(jiti@2.7.0)))(@typescript/typescript6@6.0.2)(eslint@10.8.1(jiti@2.7.0))':
dependencies: dependencies:
'@eslint-community/regexpp': 4.12.2 '@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@7.0.2) '@typescript-eslint/parser': 8.66.0(@typescript/typescript6@6.0.2)(eslint@10.8.1(jiti@2.7.0))
'@typescript-eslint/scope-manager': 8.66.0 '@typescript-eslint/scope-manager': 8.66.0
'@typescript-eslint/type-utils': 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@7.0.2) '@typescript-eslint/type-utils': 8.66.0(@typescript/typescript6@6.0.2)(eslint@10.8.1(jiti@2.7.0))
'@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@7.0.2) '@typescript-eslint/utils': 8.66.0(@typescript/typescript6@6.0.2)(eslint@10.8.1(jiti@2.7.0))
'@typescript-eslint/visitor-keys': 8.66.0 '@typescript-eslint/visitor-keys': 8.66.0
eslint: 10.8.1(jiti@2.7.0) eslint: 10.8.1(jiti@2.7.0)
ignore: 7.0.6 ignore: 7.0.6
natural-compare: 1.4.0 natural-compare: 1.4.0
ts-api-utils: 2.5.0(typescript@7.0.2) ts-api-utils: 2.5.0(@typescript/typescript6@6.0.2)
typescript: 7.0.2 typescript: '@typescript/typescript6@6.0.2'
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@7.0.2)': '@typescript-eslint/parser@8.66.0(@typescript/typescript6@6.0.2)(eslint@10.8.1(jiti@2.7.0))':
dependencies: dependencies:
'@typescript-eslint/scope-manager': 8.66.0 '@typescript-eslint/scope-manager': 8.66.0
'@typescript-eslint/types': 8.66.0 '@typescript-eslint/types': 8.66.0
'@typescript-eslint/typescript-estree': 8.66.0(typescript@7.0.2) '@typescript-eslint/typescript-estree': 8.66.0(@typescript/typescript6@6.0.2)
'@typescript-eslint/visitor-keys': 8.66.0 '@typescript-eslint/visitor-keys': 8.66.0
debug: 4.4.3 debug: 4.4.3
eslint: 10.8.1(jiti@2.7.0) eslint: 10.8.1(jiti@2.7.0)
typescript: 7.0.2 typescript: '@typescript/typescript6@6.0.2'
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/project-service@8.66.0(typescript@7.0.2)': '@typescript-eslint/project-service@8.66.0(@typescript/typescript6@6.0.2)':
dependencies: dependencies:
'@typescript-eslint/tsconfig-utils': 8.66.0(typescript@7.0.2) '@typescript-eslint/tsconfig-utils': 8.66.0(@typescript/typescript6@6.0.2)
'@typescript-eslint/types': 8.66.0 '@typescript-eslint/types': 8.66.0
debug: 4.4.3 debug: 4.4.3
typescript: 7.0.2 typescript: '@typescript/typescript6@6.0.2'
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -4700,47 +4447,47 @@ snapshots:
'@typescript-eslint/types': 8.66.0 '@typescript-eslint/types': 8.66.0
'@typescript-eslint/visitor-keys': 8.66.0 '@typescript-eslint/visitor-keys': 8.66.0
'@typescript-eslint/tsconfig-utils@8.66.0(typescript@7.0.2)': '@typescript-eslint/tsconfig-utils@8.66.0(@typescript/typescript6@6.0.2)':
dependencies: dependencies:
typescript: 7.0.2 typescript: '@typescript/typescript6@6.0.2'
'@typescript-eslint/type-utils@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@7.0.2)': '@typescript-eslint/type-utils@8.66.0(@typescript/typescript6@6.0.2)(eslint@10.8.1(jiti@2.7.0))':
dependencies: dependencies:
'@typescript-eslint/types': 8.66.0 '@typescript-eslint/types': 8.66.0
'@typescript-eslint/typescript-estree': 8.66.0(typescript@7.0.2) '@typescript-eslint/typescript-estree': 8.66.0(@typescript/typescript6@6.0.2)
'@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@7.0.2) '@typescript-eslint/utils': 8.66.0(@typescript/typescript6@6.0.2)(eslint@10.8.1(jiti@2.7.0))
debug: 4.4.3 debug: 4.4.3
eslint: 10.8.1(jiti@2.7.0) eslint: 10.8.1(jiti@2.7.0)
ts-api-utils: 2.5.0(typescript@7.0.2) ts-api-utils: 2.5.0(@typescript/typescript6@6.0.2)
typescript: 7.0.2 typescript: '@typescript/typescript6@6.0.2'
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/types@8.66.0': {} '@typescript-eslint/types@8.66.0': {}
'@typescript-eslint/typescript-estree@8.66.0(typescript@7.0.2)': '@typescript-eslint/typescript-estree@8.66.0(@typescript/typescript6@6.0.2)':
dependencies: dependencies:
'@typescript-eslint/project-service': 8.66.0(typescript@7.0.2) '@typescript-eslint/project-service': 8.66.0(@typescript/typescript6@6.0.2)
'@typescript-eslint/tsconfig-utils': 8.66.0(typescript@7.0.2) '@typescript-eslint/tsconfig-utils': 8.66.0(@typescript/typescript6@6.0.2)
'@typescript-eslint/types': 8.66.0 '@typescript-eslint/types': 8.66.0
'@typescript-eslint/visitor-keys': 8.66.0 '@typescript-eslint/visitor-keys': 8.66.0
debug: 4.4.3 debug: 4.4.3
minimatch: 10.2.6 minimatch: 10.2.6
semver: 7.8.5 semver: 7.8.5
tinyglobby: 0.2.17 tinyglobby: 0.2.17
ts-api-utils: 2.5.0(typescript@7.0.2) ts-api-utils: 2.5.0(@typescript/typescript6@6.0.2)
typescript: 7.0.2 typescript: '@typescript/typescript6@6.0.2'
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/utils@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@7.0.2)': '@typescript-eslint/utils@8.66.0(@typescript/typescript6@6.0.2)(eslint@10.8.1(jiti@2.7.0))':
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0)) '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0))
'@typescript-eslint/scope-manager': 8.66.0 '@typescript-eslint/scope-manager': 8.66.0
'@typescript-eslint/types': 8.66.0 '@typescript-eslint/types': 8.66.0
'@typescript-eslint/typescript-estree': 8.66.0(typescript@7.0.2) '@typescript-eslint/typescript-estree': 8.66.0(@typescript/typescript6@6.0.2)
eslint: 10.8.1(jiti@2.7.0) eslint: 10.8.1(jiti@2.7.0)
typescript: 7.0.2 typescript: '@typescript/typescript6@6.0.2'
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -4809,12 +4556,16 @@ snapshots:
'@typescript/typescript-win32-x64@7.0.2': '@typescript/typescript-win32-x64@7.0.2':
optional: true optional: true
'@typescript/typescript6@6.0.2':
dependencies:
'@typescript/old': typescript@6.0.3
'@ungap/structured-clone@1.3.3': {} '@ungap/structured-clone@1.3.3': {}
'@vitejs/plugin-react@6.0.5(vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0))': '@vitejs/plugin-react@6.0.5(vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0))':
dependencies: dependencies:
'@rolldown/pluginutils': 1.0.1 '@rolldown/pluginutils': 1.0.1
vite: 8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0) vite: 8.2.1(@types/node@26.2.0)(jiti@2.7.0)
accepts@2.0.0: accepts@2.0.0:
dependencies: dependencies:
@ -4871,8 +4622,6 @@ snapshots:
balanced-match@4.0.4: {} balanced-match@4.0.4: {}
baseline-browser-mapping@2.11.12: {}
baseline-browser-mapping@2.11.13: {} baseline-browser-mapping@2.11.13: {}
body-parser@2.3.0: body-parser@2.3.0:
@ -4897,19 +4646,11 @@ snapshots:
dependencies: dependencies:
fill-range: 7.1.1 fill-range: 7.1.1
browserslist@4.28.7:
dependencies:
baseline-browser-mapping: 2.11.12
caniuse-lite: 1.0.30001807
electron-to-chromium: 1.5.402
node-releases: 2.0.53
update-browserslist-db: 1.2.3(browserslist@4.28.7)
browserslist@4.28.8: browserslist@4.28.8:
dependencies: dependencies:
baseline-browser-mapping: 2.11.13 baseline-browser-mapping: 2.11.13
caniuse-lite: 1.0.30001809 caniuse-lite: 1.0.30001809
electron-to-chromium: 1.5.402 electron-to-chromium: 1.5.403
node-releases: 2.0.53 node-releases: 2.0.53
update-browserslist-db: 1.3.0(browserslist@4.28.8) update-browserslist-db: 1.3.0(browserslist@4.28.8)
@ -4931,8 +4672,6 @@ snapshots:
callsites@3.1.0: {} callsites@3.1.0: {}
caniuse-lite@1.0.30001807: {}
caniuse-lite@1.0.30001809: {} caniuse-lite@1.0.30001809: {}
ccount@2.0.1: {} ccount@2.0.1: {}
@ -5070,9 +4809,6 @@ snapshots:
d3-timer@3.0.1: {} d3-timer@3.0.1: {}
date-fns@4.4.0:
optional: true
debounce-fn@4.0.0: debounce-fn@4.0.0:
dependencies: dependencies:
mimic-fn: 3.1.0 mimic-fn: 3.1.0
@ -5134,7 +4870,7 @@ snapshots:
ee-first@1.1.1: {} ee-first@1.1.1: {}
electron-to-chromium@1.5.402: {} electron-to-chromium@1.5.403: {}
embla-carousel-react@8.6.0(react@19.2.8): embla-carousel-react@8.6.0(react@19.2.8):
dependencies: dependencies:
@ -5186,36 +4922,6 @@ snapshots:
es-toolkit@1.50.0: {} es-toolkit@1.50.0: {}
esbuild@0.28.1:
optionalDependencies:
'@esbuild/aix-ppc64': 0.28.1
'@esbuild/android-arm': 0.28.1
'@esbuild/android-arm64': 0.28.1
'@esbuild/android-x64': 0.28.1
'@esbuild/darwin-arm64': 0.28.1
'@esbuild/darwin-x64': 0.28.1
'@esbuild/freebsd-arm64': 0.28.1
'@esbuild/freebsd-x64': 0.28.1
'@esbuild/linux-arm': 0.28.1
'@esbuild/linux-arm64': 0.28.1
'@esbuild/linux-ia32': 0.28.1
'@esbuild/linux-loong64': 0.28.1
'@esbuild/linux-mips64el': 0.28.1
'@esbuild/linux-ppc64': 0.28.1
'@esbuild/linux-riscv64': 0.28.1
'@esbuild/linux-s390x': 0.28.1
'@esbuild/linux-x64': 0.28.1
'@esbuild/netbsd-arm64': 0.28.1
'@esbuild/netbsd-x64': 0.28.1
'@esbuild/openbsd-arm64': 0.28.1
'@esbuild/openbsd-x64': 0.28.1
'@esbuild/openharmony-arm64': 0.28.1
'@esbuild/sunos-x64': 0.28.1
'@esbuild/win32-arm64': 0.28.1
'@esbuild/win32-ia32': 0.28.1
'@esbuild/win32-x64': 0.28.1
optional: true
escalade@3.2.0: {} escalade@3.2.0: {}
escape-html@1.0.3: {} escape-html@1.0.3: {}
@ -5783,7 +5489,7 @@ snapshots:
dependencies: dependencies:
commander: 8.3.0 commander: 8.3.0
katex@0.18.2: katex@0.18.3:
dependencies: dependencies:
commander: 8.3.0 commander: 8.3.0
@ -5920,7 +5626,7 @@ snapshots:
dependencies: dependencies:
yallist: 3.1.1 yallist: 3.1.1
lucide-react@1.30.0(react@19.2.8): lucide-react@1.31.0(react@19.2.8):
dependencies: dependencies:
react: 19.2.8 react: 19.2.8
@ -6553,7 +6259,7 @@ snapshots:
react: 19.2.8 react: 19.2.8
scheduler: 0.27.0 scheduler: 0.27.0
react-is@19.2.7: {} react-is@19.2.8: {}
react-markdown@10.1.0(@types/react@19.2.18)(react@19.2.8): react-markdown@10.1.0(@types/react@19.2.18)(react@19.2.8):
dependencies: dependencies:
@ -6624,7 +6330,7 @@ snapshots:
tiny-invariant: 1.3.3 tiny-invariant: 1.3.3
tslib: 2.8.1 tslib: 2.8.1
recharts@3.10.1(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.7)(react@19.2.8)(redux@5.0.1): recharts@3.10.1(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react-is@19.2.8)(react@19.2.8)(redux@5.0.1):
dependencies: dependencies:
'@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.18)(react@19.2.8)(redux@5.0.1))(react@19.2.8) '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.18)(react@19.2.8)(redux@5.0.1))(react@19.2.8)
clsx: 2.1.1 clsx: 2.1.1
@ -6634,7 +6340,7 @@ snapshots:
immer: 11.1.16 immer: 11.1.16
react: 19.2.8 react: 19.2.8
react-dom: 19.2.8(react@19.2.8) react-dom: 19.2.8(react@19.2.8)
react-is: 19.2.7 react-is: 19.2.8
react-redux: 9.3.0(@types/react@19.2.18)(react@19.2.8)(redux@5.0.1) react-redux: 9.3.0(@types/react@19.2.18)(react@19.2.8)(redux@5.0.1)
reselect: 5.2.0 reselect: 5.2.0
tiny-invariant: 1.3.3 tiny-invariant: 1.3.3
@ -6911,10 +6617,12 @@ snapshots:
sisteransi@1.0.5: {} sisteransi@1.0.5: {}
sonner@2.0.7(react-dom@19.2.8(react@19.2.8))(react@19.2.8): sonner@2.0.8(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8):
dependencies: dependencies:
react: 19.2.8 react: 19.2.8
react-dom: 19.2.8(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: {} source-map-js@1.2.1: {}
@ -6992,9 +6700,9 @@ snapshots:
trough@2.2.0: {} trough@2.2.0: {}
ts-api-utils@2.5.0(typescript@7.0.2): ts-api-utils@2.5.0(@typescript/typescript6@6.0.2):
dependencies: dependencies:
typescript: 7.0.2 typescript: '@typescript/typescript6@6.0.2'
ts-morph@26.0.0: ts-morph@26.0.0:
dependencies: dependencies:
@ -7021,17 +6729,19 @@ snapshots:
media-typer: 1.1.1 media-typer: 1.1.1
mime-types: 3.0.2 mime-types: 3.0.2
typescript-eslint@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@7.0.2): typescript-eslint@8.66.0(@typescript/typescript6@6.0.2)(eslint@10.8.1(jiti@2.7.0)):
dependencies: dependencies:
'@typescript-eslint/eslint-plugin': 8.66.0(@typescript-eslint/parser@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@7.0.2))(eslint@10.8.1(jiti@2.7.0))(typescript@7.0.2) '@typescript-eslint/eslint-plugin': 8.66.0(@typescript-eslint/parser@8.66.0(@typescript/typescript6@6.0.2)(eslint@10.8.1(jiti@2.7.0)))(@typescript/typescript6@6.0.2)(eslint@10.8.1(jiti@2.7.0))
'@typescript-eslint/parser': 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@7.0.2) '@typescript-eslint/parser': 8.66.0(@typescript/typescript6@6.0.2)(eslint@10.8.1(jiti@2.7.0))
'@typescript-eslint/typescript-estree': 8.66.0(typescript@7.0.2) '@typescript-eslint/typescript-estree': 8.66.0(@typescript/typescript6@6.0.2)
'@typescript-eslint/utils': 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@7.0.2) '@typescript-eslint/utils': 8.66.0(@typescript/typescript6@6.0.2)(eslint@10.8.1(jiti@2.7.0))
eslint: 10.8.1(jiti@2.7.0) eslint: 10.8.1(jiti@2.7.0)
typescript: 7.0.2 typescript: '@typescript/typescript6@6.0.2'
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
typescript@6.0.3: {}
typescript@7.0.2: typescript@7.0.2:
optionalDependencies: optionalDependencies:
'@typescript/typescript-aix-ppc64': 7.0.2 '@typescript/typescript-aix-ppc64': 7.0.2
@ -7108,12 +6818,6 @@ snapshots:
unpipe@1.0.0: {} unpipe@1.0.0: {}
update-browserslist-db@1.2.3(browserslist@4.28.7):
dependencies:
browserslist: 4.28.7
escalade: 3.2.0
picocolors: 1.1.1
update-browserslist-db@1.3.0(browserslist@4.28.8): update-browserslist-db@1.3.0(browserslist@4.28.8):
dependencies: dependencies:
browserslist: 4.28.8 browserslist: 4.28.8
@ -7190,7 +6894,7 @@ snapshots:
d3-time: 3.1.0 d3-time: 3.1.0
d3-timer: 3.0.1 d3-timer: 3.0.1
vite@8.2.1(@types/node@26.2.0)(esbuild@0.28.1)(jiti@2.7.0): vite@8.2.1(@types/node@26.2.0)(jiti@2.7.0):
dependencies: dependencies:
lightningcss: 1.33.0 lightningcss: 1.33.0
picomatch: 4.0.5 picomatch: 4.0.5
@ -7199,7 +6903,6 @@ snapshots:
tinyglobby: 0.2.17 tinyglobby: 0.2.17
optionalDependencies: optionalDependencies:
'@types/node': 26.2.0 '@types/node': 26.2.0
esbuild: 0.28.1
fsevents: 2.3.3 fsevents: 2.3.3
jiti: 2.7.0 jiti: 2.7.0

View file

@ -52,7 +52,7 @@ function AlertDialogContent({
data-slot="alert-dialog-content" data-slot="alert-dialog-content"
data-size={size} data-size={size}
className={cn( className={cn(
"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", "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",
className, className,
)} )}
{...props} {...props}

View file

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

View file

@ -52,7 +52,7 @@ function CommandDialog({
</DialogHeader> </DialogHeader>
<DialogContent <DialogContent
className={cn( className={cn(
"top-1/3 translate-y-0 overflow-hidden rounded-xl! p-0", "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",
className, className,
)} )}
showCloseButton={showCloseButton} showCloseButton={showCloseButton}

View file

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

View file

@ -53,7 +53,7 @@ function DialogContent({
<DialogPrimitive.Popup <DialogPrimitive.Popup
data-slot="dialog-content" data-slot="dialog-content"
className={cn( className={cn(
"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", "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",
className, className,
)} )}
{...props} {...props}

View file

@ -56,7 +56,7 @@ function DrawerContent({
<DrawerPrimitive.Content <DrawerPrimitive.Content
data-slot="drawer-content" data-slot="drawer-content"
className={cn( 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-[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", "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",
className, className,
)} )}
{...props} {...props}

View file

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

View file

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

View file

@ -2,6 +2,7 @@ import { NavigationMenu as NavigationMenuPrimitive } from "@base-ui/react/naviga
import { cva } from "class-variance-authority"; import { cva } from "class-variance-authority";
import { cn } from "../lib/utils"; import { cn } from "../lib/utils";
import { useSafeAreaCollisionPadding } from "../hooks/use-safe-area";
import { ChevronDownIcon } from "lucide-react"; import { ChevronDownIcon } from "lucide-react";
function NavigationMenu({ function NavigationMenu({
@ -101,8 +102,11 @@ function NavigationMenuPositioner({
sideOffset = 8, sideOffset = 8,
align = "start", align = "start",
alignOffset = 0, alignOffset = 0,
collisionPadding,
...props ...props
}: NavigationMenuPrimitive.Positioner.Props) { }: NavigationMenuPrimitive.Positioner.Props) {
const safeAreaCollisionPadding = useSafeAreaCollisionPadding();
return ( return (
<NavigationMenuPrimitive.Portal> <NavigationMenuPrimitive.Portal>
<NavigationMenuPrimitive.Positioner <NavigationMenuPrimitive.Positioner
@ -110,6 +114,7 @@ function NavigationMenuPositioner({
sideOffset={sideOffset} sideOffset={sideOffset}
align={align} align={align}
alignOffset={alignOffset} alignOffset={alignOffset}
collisionPadding={collisionPadding ?? safeAreaCollisionPadding}
className={cn( 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", "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, className,

View file

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

View file

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

View file

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

View file

@ -53,7 +53,7 @@ function SheetContent({
data-slot="sheet-content" data-slot="sheet-content"
data-side={side} data-side={side}
className={cn( className={cn(
"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", "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",
className, className,
)} )}
{...props} {...props}
@ -65,7 +65,7 @@ function SheetContent({
render={ render={
<Button <Button
variant="ghost" variant="ghost"
className="absolute top-3 right-3" 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))]"
size="icon-sm" size="icon-sm"
/> />
} }

View file

@ -215,10 +215,10 @@ function Sidebar({
data-side={side} data-side={side}
style={{ width: SIDEBAR_WIDTH }} style={{ width: SIDEBAR_WIDTH }}
className={cn( className={cn(
"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", "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",
// Adjust the padding for floating and inset variants. // Adjust the padding for floating and inset variants.
variant === "floating" || variant === "inset" variant === "floating" || variant === "inset"
? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]" ? "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)]"
: "group-data-[collapsible=icon]:w-(--sidebar-width-icon)", : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)",
className, className,
)} )}

View file

@ -17,6 +17,18 @@ const Toaster = ({ ...props }: ToasterProps) => {
<Sonner <Sonner
theme={theme as ToasterProps["theme"]} theme={theme as ToasterProps["theme"]}
className="toaster group" 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={{ icons={{
success: <CircleCheckIcon className="size-4" />, success: <CircleCheckIcon className="size-4" />,
info: <InfoIcon className="size-4" />, info: <InfoIcon className="size-4" />,

View file

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

View file

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

View file

@ -0,0 +1,40 @@
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,6 +88,10 @@
} }
:root { :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-density: 1;
--ui-border-width: 1px; --ui-border-width: 1px;
--ui-shadow-strength: 0; --ui-shadow-strength: 0;

View file

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

View file

@ -71,7 +71,7 @@ function CodeBlock({
data-slot="code-block" data-slot="code-block"
data-line-numbers={showLineNumbers || undefined} data-line-numbers={showLineNumbers || undefined}
data-language={language || 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)] group-data-[variant=compact]/markdown:my-[0.45rem]" 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!"
> >
<figcaption <figcaption
data-slot="code-block-header" data-slot="code-block-header"
@ -109,7 +109,7 @@ function CodeBlock({
</figcaption> </figcaption>
<div <div
data-slot="code-block-content" data-slot="code-block-content"
className="max-w-full overflow-x-auto" className="max-w-full overflow-x-auto pb-2"
> >
{highlighted ?? ( {highlighted ?? (
<pre <pre

View file

@ -15,6 +15,7 @@ export default function Emoji({
className = "size-6", className = "size-6",
registry: registryOverride, registry: registryOverride,
shortcode, shortcode,
tooltip = true,
}: EmojiProps) { }: EmojiProps) {
const registry = useEmojiRegistry(registryOverride); const registry = useEmojiRegistry(registryOverride);
const emoji = registry.resolve(shortcode); const emoji = registry.resolve(shortcode);
@ -37,6 +38,8 @@ export default function Emoji({
<span>{shortcode}</span> <span>{shortcode}</span>
); );
if (!tooltip) return content;
return ( return (
<Tooltip> <Tooltip>
<TooltipTrigger render={content} /> <TooltipTrigger render={content} />

View file

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

View file

@ -6,7 +6,7 @@ import rehypeSlug from "rehype-slug";
import remarkBreaks from "remark-breaks"; import remarkBreaks from "remark-breaks";
import remarkGfm from "remark-gfm"; import remarkGfm from "remark-gfm";
import remarkMath from "remark-math"; import remarkMath from "remark-math";
import type { ComponentProps } from "react"; import type { ComponentProps, ReactNode } from "react";
import { cn } from "../lib/utils"; import { cn } from "../lib/utils";
import { CodeBlock } from "./code-block"; import { CodeBlock } from "./code-block";
@ -47,6 +47,7 @@ export type MarkdownProps = Omit<ComponentProps<"div">, "children"> & {
components?: Partial<MarkdownComponents>; components?: Partial<MarkdownComponents>;
registry?: EmojiRegistry; registry?: EmojiRegistry;
theme?: MarkdownTheme; theme?: MarkdownTheme;
trailingContent?: ReactNode;
variant?: MarkdownVariant; variant?: MarkdownVariant;
}; };
@ -136,6 +137,7 @@ function Markdown({
components, components,
registry: registryOverride, registry: registryOverride,
theme, theme,
trailingContent,
variant = "article", variant = "article",
...props ...props
}: MarkdownProps) { }: MarkdownProps) {
@ -171,6 +173,7 @@ function Markdown({
> >
{content} {content}
</ReactMarkdown> </ReactMarkdown>
{trailingContent}
</div> </div>
</EmojiProvider> </EmojiProvider>
); );

View file

@ -18,7 +18,7 @@ export type HighlightedCodeToken = {
}; };
export const shikiPreClassName = export const shikiPreClassName =
"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]"; "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]";
export const shikiLineClassNames = 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)]"; "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 = export const highlightedLineClassNames =

View file

@ -6,14 +6,30 @@ import { Markdown } from "./markdown";
export type TextProps = { export type TextProps = {
fontSize?: CSSProperties["fontSize"]; fontSize?: CSSProperties["fontSize"];
registry?: EmojiRegistry; registry?: EmojiRegistry;
showEditedIndicator?: boolean;
value: string; value: string;
}; };
export default function Text({ fontSize, registry, value }: TextProps) { export default function Text({
fontSize,
registry,
showEditedIndicator = false,
value,
}: TextProps) {
return ( return (
<Markdown <Markdown
className={
showEditedIndicator
? "[&>p:nth-last-child(2)]:my-0 [&>p:nth-last-child(2)]:inline"
: undefined
}
content={value} content={value}
registry={registry} registry={registry}
trailingContent={
showEditedIndicator ? (
<span className="ms-1 text-xs text-muted-foreground">(edited)</span>
) : undefined
}
variant="compact" variant="compact"
style={{ fontSize: fontSize ?? "1rem" }} style={{ fontSize: fontSize ?? "1rem" }}
/> />

View file

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

View file

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

View file

@ -51,6 +51,7 @@ export const BUILT_IN_THEMES = defineThemes([
--ring: oklch(0.62 0.12 185); --ring: oklch(0.62 0.12 185);
--sidebar: color-mix(in oklch, var(--background) 97%, black); --sidebar: color-mix(in oklch, var(--background) 97%, black);
--sidebar-primary: oklch(0.58 0.12 185); --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-background: #fff;
--tensamin-outline-hover: #0000000a; --tensamin-outline-hover: #0000000a;
--tensamin-outline-pressed: #00000014; --tensamin-outline-pressed: #00000014;
@ -73,6 +74,7 @@ export const BUILT_IN_THEMES = defineThemes([
--primary: oklch(0.69 0.12 184); --primary: oklch(0.69 0.12 184);
--primary-foreground: oklch(0.16 0.025 190); --primary-foreground: oklch(0.16 0.025 190);
--primary-foreground-alt: oklch(0.73 0.13 183); --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-background: #ffffff0f;
--tensamin-outline-hover: #ffffff0f; --tensamin-outline-hover: #ffffff0f;
--tensamin-outline-pressed: #ffffff1a; --tensamin-outline-pressed: #ffffff1a;
@ -247,6 +249,7 @@ export const BUILT_IN_THEMES = defineThemes([
--chart-3: #aca1cf; --chart-3: #aca1cf;
--chart-4: #e29eca; --chart-4: #e29eca;
--chart-5: #e5c890; --chart-5: #e5c890;
--markdown-code-background: color-mix(in srgb, var(--muted) 78%, var(--background));
} }
:root.dark[data-theme="og-tensamin"] { :root.dark[data-theme="og-tensamin"] {
--background: #0f1014; --background: #0f1014;
@ -281,6 +284,7 @@ export const BUILT_IN_THEMES = defineThemes([
--chart-3: #aca1cf; --chart-3: #aca1cf;
--chart-4: #e29eca; --chart-4: #e29eca;
--chart-5: #e5c890; --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"]) { :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); background-color: var(--popover);
@ -323,7 +327,7 @@ export const BUILT_IN_THEMES = defineThemes([
--accent: #cf8fe633; --accent: #cf8fe633;
--accent-foreground: #642f79; --accent-foreground: #642f79;
--destructive: #b91c1c; --destructive: #b91c1c;
--border: #242D38; --border: #b7c2cc;
--input: #b7c2cc; --input: #b7c2cc;
--ring: #9d53bc; --ring: #9d53bc;
--chart-1: #8c47ad; --chart-1: #8c47ad;
@ -337,8 +341,9 @@ export const BUILT_IN_THEMES = defineThemes([
--sidebar-primary-foreground: #ffffff; --sidebar-primary-foreground: #ffffff;
--sidebar-accent: #cf8fe633; --sidebar-accent: #cf8fe633;
--sidebar-accent-foreground: #642f79; --sidebar-accent-foreground: #642f79;
--sidebar-border: #242D38; --sidebar-border: #b7c2cc;
--sidebar-ring: #9d53bc; --sidebar-ring: #9d53bc;
--markdown-code-background: color-mix(in srgb, var(--input) 55%, var(--background));
} }
:root.dark[data-theme="methanium"] { :root.dark[data-theme="methanium"] {
--background: #171E26; --background: #171E26;
@ -373,6 +378,7 @@ export const BUILT_IN_THEMES = defineThemes([
--sidebar-accent-foreground: #d2e0f0; --sidebar-accent-foreground: #d2e0f0;
--sidebar-border: #242D38; --sidebar-border: #242D38;
--sidebar-ring: #cf8fe6; --sidebar-ring: #cf8fe6;
--markdown-code-background: color-mix(in srgb, var(--input) 55%, var(--background));
} }
:root[data-theme="methanium"] body { :root[data-theme="methanium"] body {
background-color: var(--background); background-color: var(--background);
@ -435,8 +441,8 @@ export const BUILT_IN_THEMES = defineThemes([
} }
:root[data-theme="methanium"] [data-slot="card"] { :root[data-theme="methanium"] [data-slot="card"] {
padding-block: calc(1rem * var(--ui-density)); padding-block: calc(1rem * var(--ui-density));
border: none; border: 1px solid var(--input);
background-color: #242D38; background-color: color-mix(in srgb, var(--input) 55%, var(--background));
} }
:root[data-theme="methanium"] [data-slot="button"][data-variant="default"] { :root[data-theme="methanium"] [data-slot="button"][data-variant="default"] {
background-color: var(--primary); background-color: var(--primary);
@ -506,175 +512,464 @@ export const BUILT_IN_THEMES = defineThemes([
}, },
css: `:root[data-theme="secret"] { css: `:root[data-theme="secret"] {
--secret-border: color-mix(in srgb, #2f1b13 22%, #fffaf2 78%); --secret-border: color-mix(in srgb, #2f1b13 22%, #fffaf2 78%);
--secret-control: #5e244e;
--secret-purple: #d7a8c9;
--secret-control: var(--secret-purple);
--secret-gold: color-mix(in srgb, #f9b637 75%, #2f1b13 25%); --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-dark: color-mix(in srgb, var(--secret-gold) 60%, #2f1b13 40%);
--secret-gold-light: color-mix(in srgb, var(--secret-gold) 45%, #ffe8b4 55%); --secret-gold-light: color-mix(in srgb, var(--secret-gold) 45%, #ffe8b4 55%);
--background: oklch(0.98 0 0); --background: oklch(0.98 0 0);
--foreground: #2f1b13; --foreground: #2f1b13;
--card: var(--background); --card: var(--background);
--card-foreground: var(--foreground); --card-foreground: var(--foreground);
--popover: #5e244e;
--popover-foreground: #fffaf2; --popover: var(--secret-purple);
--popover-foreground: #2f1b13;
--primary: var(--secret-gold); --primary: var(--secret-gold);
--primary-foreground: #24120c; --primary-foreground: #24120c;
--primary-foreground-alt: #fb6c00; --primary-foreground-alt: #c04b00;
--secondary: #5e244e;
--secondary-foreground: #fffaf2; --secondary: var(--secret-purple);
--muted: #24120c; --secondary-foreground: #2f1b13;
--muted-foreground: #6b7280;
--muted: #c89ab9;
--muted-foreground: #49333f;
--accent: #fb6c00; --accent: #fb6c00;
--accent-foreground: #24120c; --accent-foreground: #24120c;
--destructive: #e73f1e;
--destructive: #d93618;
--destructive-foreground: #fffaf2;
--border: var(--secret-border); --border: var(--secret-border);
--input: var(--secret-border); --input: var(--secret-border);
--ring: #fb6c00; --ring: #4a2110;
--sidebar: color-mix(in oklch, var(--background) 97%, black); --sidebar: color-mix(in oklch, var(--background) 97%, black);
--sidebar-foreground: #2f1b13; --sidebar-foreground: #2f1b13;
--sidebar-primary: var(--secret-gold); --sidebar-primary: var(--secret-gold);
--sidebar-primary-foreground: #24120c; --sidebar-primary-foreground: #24120c;
--sidebar-accent: #aa1c41; --sidebar-accent: #d7a8c9;
--sidebar-accent-foreground: #fffaf2; --sidebar-accent-foreground: #2f1b13;
--sidebar-border: var(--secret-border); --sidebar-border: var(--secret-border);
--markdown-code-background: color-mix(
in srgb,
var(--secret-gold) 9%,
var(--background)
);
} }
:root.dark[data-theme="secret"] { :root.dark[data-theme="secret"] {
--secret-border: color-mix(in srgb, #ffe8b4 15%, #24120c 85%); --secret-border: color-mix(in srgb, #ffe8b4 8%, #24120c 35%);
--secret-control: #5e244e;
--background: #0A0A0A; --secret-purple: #5e244e;
--secret-control: var(--secret-purple);
--background: #0a0a0a;
--foreground: #ffe8b4; --foreground: #ffe8b4;
--card: var(--background); --card: var(--background);
--card-foreground: var(--foreground); --card-foreground: var(--foreground);
--popover: #2f1b13; --popover: #2f1b13;
--popover-foreground: #ffe8b4; --popover-foreground: #ffe8b4;
--primary: var(--secret-gold); --primary: var(--secret-gold);
--primary-foreground: #24120c; --primary-foreground: #24120c;
--primary-foreground-alt: #fb6c00; --primary-foreground-alt: #fb6c00;
--secondary: #5e244e;
--secondary: var(--secret-purple);
--secondary-foreground: #fffaf2; --secondary-foreground: #fffaf2;
--muted: #2f1b13; --muted: #2f1b13;
--muted-foreground: #e68457; --muted-foreground: #e68457;
--accent: #e73f1e;
--accent: #d93618;
--accent-foreground: #fffaf2; --accent-foreground: #fffaf2;
--destructive: #e73f1e;
--destructive: #d93618;
--destructive-foreground: #fffaf2;
--border: var(--secret-border); --border: var(--secret-border);
--input: var(--secret-border); --input: var(--secret-border);
--ring: #fb6c00; --ring: #f9b637;
--sidebar: #0F0F0F;
--sidebar: #0f0f0f;
--sidebar-foreground: #ffe8b4; --sidebar-foreground: #ffe8b4;
--sidebar-primary: var(--secret-gold); --sidebar-primary: var(--secret-gold);
--sidebar-primary-foreground: #24120c; --sidebar-primary-foreground: #24120c;
--sidebar-accent: #aa1c41; --sidebar-accent: #aa1c41;
--sidebar-accent-foreground: #fffaf2; --sidebar-accent-foreground: #fffaf2;
--sidebar-border: var(--secret-border); --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; background-repeat: no-repeat;
} }
:root[data-theme="secret"] [data-slot="button"][data-variant="ghost"] { :root[data-theme="secret"] [data-slot="button"][data-variant="ghost"] {
background-image: none; background-image: none;
} }
:root[data-theme="secret"] [data-slot="button"][data-variant="ghost"]:hover { :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"] { :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); 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); :root:not(.dark)[data-theme="secret"]
background-image: linear-gradient(to top, rgb(255 232 180 / 30%), rgb(255 232 180 / 80%)); [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); background-color: var(--secret-control);
border-color: transparent; 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: #fffaf2; :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[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.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%
);
border-color: transparent; border-color: transparent;
} }
: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%); :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%
);
border-color: transparent; border-color: transparent;
} }
: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%); :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%
);
border-color: transparent; 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"] { :root[data-theme="secret"] [data-slot="select-content"] {
background-color: var(--popover); background-color: var(--popover);
border-color: var(--secret-border); border-color: var(--secret-border);
color: var(--popover-foreground); color: var(--popover-foreground);
} }
:root.dark[data-theme="secret"] [data-slot="select-content"] {
border-color: var(--secret-border); :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[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.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%
);
color: #ffe8b4; color: #ffe8b4;
} }
:root[data-theme="secret"] [data-slot="button"][data-variant="default"] { :root[data-theme="secret"] [data-slot="button"][data-variant="default"] {
background-color: var(--primary); 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); border-color: var(--secret-border);
color: var(--primary-foreground); color: var(--primary-foreground);
text-shadow: 0 1px rgb(255 255 255 / 35%); 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); 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"] { :root[data-theme="secret"] [data-slot="card"] {
background: var(--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); background-color: var(--secondary);
border-color: transparent; border-color: transparent;
color: var(--secondary-foreground); color: var(--secondary-foreground);
} }
:root[data-theme="secret"] [data-slot="button"][data-variant="link"] { :root[data-theme="secret"] [data-slot="button"][data-variant="link"] {
background-image: none; background-image: none;
} }
:root[data-theme="secret"] [data-slot="button"][data-variant="link"]:hover { :root[data-theme="secret"] [data-slot="button"][data-variant="link"]:hover {
background-color: var(--secondary); background-color: var(--secondary);
background-image: none; background-image: none;
} }
:root[data-theme="secret"] [data-slot="button"][data-variant="outline"]:hover {
background-color: color-mix(in srgb, #5e244e 82%, #24120c 18%); :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%
);
border-color: transparent; border-color: transparent;
color: var(--secondary-foreground);
} }
: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%); :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%
);
border-color: transparent; border-color: transparent;
color: var(--secondary-foreground);
} }
: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%); :root[data-theme="secret"] :where(
border-color: transparent; [data-slot="card-title"],
} [data-slot="item-media"][data-variant="icon"],
:root:not(.dark)[data-theme="secret"] [data-slot="button"][data-variant="outline"]:hover, [data-slot="badge"][data-variant="outline"]
:root:not(.dark)[data-theme="secret"] :where([data-slot="badge"], [data-slot="toggle"])[data-variant="outline"]:hover, ) svg {
: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); 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"] { :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); ] as const);

View file

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