diff --git a/README.ja.md b/README.ja.md index 58b5ea9e..a2812442 100644 --- a/README.ja.md +++ b/README.ja.md @@ -137,7 +137,7 @@ Codex の **セッション管理 → コンテキスト編集(実験的)** ## カスタムテーマ -カスタムテーマは、アプリデータディレクトリの `themes` フォルダ内のサブフォルダ 1 つにつき 1 つです。Windows と Linux では実行ファイルと同じディレクトリ、macOS アプリでは `~/Library/Application Support/com.cpa.gui/themes` です(`.app` 以外から実行した場合は実行ファイルと同じディレクトリ)。テーマメニュー下部の **テーマフォルダを開く** でフォルダを作成して開き、**再読み込み** で再起動せずに変更を反映できます。カスタムテーマはフォルダ名順に組み込みテーマの後へ並びます。 +カスタムテーマは、アプリデータディレクトリの `themes` フォルダ内のサブフォルダ 1 つにつき 1 つです。Windows と Linux では実行ファイルと同じディレクトリ、macOS アプリでは `~/Library/Application Support/com.cpa.gui/themes` です(`.app` 以外から実行した場合は実行ファイルと同じディレクトリ)。テーマメニュー下部の **テーマフォルダを開く** でフォルダを作成して開き、**再読み込み** で再起動せずに変更を反映できます。カスタムテーマはフォルダ名順に組み込みテーマの後へ並びます。テーマセレクターはダイアログで開き、名前・説明・テーマ ID での検索、提供元(すべて・組み込み・カスタム)での絞り込み、自動モードでのライトとダークの個別選択に対応しています。 ``` themes/ diff --git a/README.md b/README.md index 24d52c69..30b96ba9 100644 --- a/README.md +++ b/README.md @@ -155,7 +155,7 @@ Manually renamed files without a session ID in their filename or a database path ## Custom Themes -Each custom theme is a folder inside the `themes` folder of the application data directory: next to the executable on Windows and Linux, and `~/Library/Application Support/com.cpa.gui/themes` for the macOS app (next to the executable when run outside the `.app` bundle). The **Open themes folder** button at the bottom of the theme picker creates and opens it; **Reload** applies changes without restarting. Custom themes appear after the built-in themes in folder-name order. +Each custom theme is a folder inside the `themes` folder of the application data directory: next to the executable on Windows and Linux, and `~/Library/Application Support/com.cpa.gui/themes` for the macOS app (next to the executable when run outside the `.app` bundle). The **Open themes folder** button at the bottom of the theme picker creates and opens it; **Reload** applies changes without restarting. Custom themes appear after the built-in themes in folder-name order. The theme picker opens in a dialog where you can search by name, description or theme ID, filter by source (all, built-in or custom), and pick separate light and dark themes while the mode is set to Auto. ``` themes/ diff --git a/README.zh-CN.md b/README.zh-CN.md index 50d78825..e1712243 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -149,7 +149,7 @@ Codex 的 **会话管理 → 编辑上下文(实验性)** 仅在点击某个 ## 自定义主题 -每个自定义主题是应用数据目录 `themes` 文件夹下的一个子文件夹:Windows 和 Linux 为程序所在目录,macOS 应用为 `~/Library/Application Support/com.cpa.gui/themes`(不以 `.app` 方式运行时为程序所在目录)。主题菜单底部的 **打开主题目录** 会创建并打开该目录,**重新加载** 无需重启即可应用改动。自定义主题按文件夹名顺序排在内置主题之后。 +每个自定义主题是应用数据目录 `themes` 文件夹下的一个子文件夹:Windows 和 Linux 为程序所在目录,macOS 应用为 `~/Library/Application Support/com.cpa.gui/themes`(不以 `.app` 方式运行时为程序所在目录)。主题菜单底部的 **打开主题目录** 会创建并打开该目录,**重新加载** 无需重启即可应用改动。自定义主题按文件夹名顺序排在内置主题之后。主题选择器以弹窗形式打开,可按名称、描述或主题 ID 搜索,按来源(全部、内置、自定义)筛选,自动模式下还可分别选择浅色与深色主题。 ``` themes/ diff --git a/bun.lock b/bun.lock index 4ce77297..03e58b2b 100644 --- a/bun.lock +++ b/bun.lock @@ -8,15 +8,15 @@ "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@tauri-apps/api": "^2.12.3", - "@tauri-apps/plugin-dialog": "^2.7.1", + "@tauri-apps/api": "2.12.4", + "@tauri-apps/plugin-dialog": "2.8.3", "lucide-react": "^1.24.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-markdown": "^10.1.0", }, "devDependencies": { - "@tauri-apps/cli": "^2.12.2", + "@tauri-apps/cli": "2.12.3", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "@vitejs/plugin-react": "^5.0.0", @@ -186,33 +186,33 @@ "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.62.2", "", { "os": "win32", "cpu": "x64" }, "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA=="], - "@tauri-apps/api": ["@tauri-apps/api@2.12.3", "", {}, "sha512-9s0PKw0p4r3kFq92jhpivYSp+cSht15o0gXpZxuQd0+dV9KCexEVkNaLELVoLdJWyoH4KlfQo5h3W2LIM8siJg=="], + "@tauri-apps/api": ["@tauri-apps/api@2.12.4", "", {}, "sha512-pVmfis+4zT8H0Qhp3xPZx9Ju7kpzvA6rr/PSJPyuwfvucTQ8sVt61NYU9KMkK703UFlYadFmjKA4HhybOtN0gg=="], - "@tauri-apps/cli": ["@tauri-apps/cli@2.12.2", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.12.2", "@tauri-apps/cli-darwin-x64": "2.12.2", "@tauri-apps/cli-linux-arm-gnueabihf": "2.12.2", "@tauri-apps/cli-linux-arm64-gnu": "2.12.2", "@tauri-apps/cli-linux-arm64-musl": "2.12.2", "@tauri-apps/cli-linux-riscv64-gnu": "2.12.2", "@tauri-apps/cli-linux-x64-gnu": "2.12.2", "@tauri-apps/cli-linux-x64-musl": "2.12.2", "@tauri-apps/cli-win32-arm64-msvc": "2.12.2", "@tauri-apps/cli-win32-ia32-msvc": "2.12.2", "@tauri-apps/cli-win32-x64-msvc": "2.12.2" }, "bin": { "tauri": "tauri.js" } }, "sha512-PMSppzAnlT+BvZtRKuidxjRSm2r5t8kDpJ/czmmQUa0AtDNTwrjLE8vApK3phCWGg7isfnYL46Dl1jB4ArI0hA=="], + "@tauri-apps/cli": ["@tauri-apps/cli@2.12.3", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.12.3", "@tauri-apps/cli-darwin-x64": "2.12.3", "@tauri-apps/cli-linux-arm-gnueabihf": "2.12.3", "@tauri-apps/cli-linux-arm64-gnu": "2.12.3", "@tauri-apps/cli-linux-arm64-musl": "2.12.3", "@tauri-apps/cli-linux-riscv64-gnu": "2.12.3", "@tauri-apps/cli-linux-x64-gnu": "2.12.3", "@tauri-apps/cli-linux-x64-musl": "2.12.3", "@tauri-apps/cli-win32-arm64-msvc": "2.12.3", "@tauri-apps/cli-win32-ia32-msvc": "2.12.3", "@tauri-apps/cli-win32-x64-msvc": "2.12.3" }, "bin": { "tauri": "tauri.js" } }, "sha512-f7/LsY74SVb1ChmOPw1ajOpxii0GSzDAgmWHRci8JUYuuai04rXsSbFobpmB0sP2DdlvMD/B5ZotEn8GOGMRUg=="], - "@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.12.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Lk3zaBTfzNvA7670Al5PNgo2M/95uaDPe1yp+ILJeDOmol87XiYuK5E5+FUbK5e6U6OORx9qpZdOo2U+5tETtQ=="], + "@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.12.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-xmVNoJOOKzKLj7GLHXmXLimRby9M42aBIJa0sB80N7o24eKV5JiVmToKTRLVH9yhL05GZ/B6rSSOmbzNFJwBAA=="], - "@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.12.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-2CyYjJ833JB3sKRz4B0W/Tv4oOVC16ws1bxdSCWj1XvrmanWwvZi99e5tNIoCHwHhcOm0jh+sh0PCGQyls6Z+w=="], + "@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.12.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-URd+0usfmUQQyb5kNPiKt2OT8gp7oGU7QR+qOppB6e35mpVBFFVNhWc9oWb3p0u71fDJ09DpF4T6m9xYxoIB8g=="], - "@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.12.2", "", { "os": "linux", "cpu": "arm" }, "sha512-uvt2xbone4JftKarelssi86Kqnl7JiG1Smh5+Ae+nZmtM+JUhTGmqkcqfUPXRW8Ygwog92POZvd4oGDN9j8eXQ=="], + "@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.12.3", "", { "os": "linux", "cpu": "arm" }, "sha512-0kwUVx2LbmOoTRlwF1oDww7th4/NSluv4ZBQ6KRZsFKg4g0TlTcIiJ0VehqkQYUeC9xIT1Mk6XtF52mI155VSQ=="], - "@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.12.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-DZlDJ24u3tlocKOYqzR+b2M+Qr+5WFcoMBZ7EfdhHN5j3ZXwBBpms4G4gyNvPCrak5vMzmdZ65ecBXPJcC+5sA=="], + "@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.12.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-gKSGDx6fx+HBLQmG6guChFdisbrCSdx9Yli+j5teOa64gm1CeM+C6NLru5Pj3ZkkEep05BmCFjxvX+cjqAycZQ=="], - "@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.12.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-pb+RTZUYH/p0gR4j4ecCCq+FNfz3W3eKuUQvVEBn7MQZx6DzfLO7FaYzt2NyDKWpdNN3lP10mdzOvw3R5P5aAQ=="], + "@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.12.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-Yr59qMy/gcvAfBuFdCGlAmGiLsYWMFDbsP4bAI6iNBzcJTGrYWZGeiQhGDo29MQwfF/NUBqyM2qljXu5tZ6wjQ=="], - "@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.12.2", "", { "os": "linux", "cpu": "none" }, "sha512-nidEvDUJyHYNbIv9MUk6KiEix8IXfRh4Wj2G2SA5g8nFmgbBCwazUNWYiG/LhNeNbfZpBMLerRBUtoQ5K0GidA=="], + "@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.12.3", "", { "os": "linux", "cpu": "none" }, "sha512-jKr0/REBMnLKC0OwPQZkyge0mKDaNZ0b/AbfGwVyCgFfwS730EVLfVDo3nt7MUu6jJaytRq08+xSj5qfy+U1+Q=="], - "@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.12.2", "", { "os": "linux", "cpu": "x64" }, "sha512-gkXyYn3w+Xfc8nz/DleEbkm1M7bBuU2cejqUXNmI98cA2P5kp+oPmS4ALTorb1FaNWjpsKoYZBWsbS9BXxYFkQ=="], + "@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.12.3", "", { "os": "linux", "cpu": "x64" }, "sha512-gTkEqJAGCMROGanxHnzaJzQ+/rXl39HWVg0/hDODS1wDWBGqoceqGC6Qm1+mQbyT11xnsB8mKu/gyVID/YpFIw=="], - "@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.12.2", "", { "os": "linux", "cpu": "x64" }, "sha512-MrjgoZ09s8Hsn99XvxSNvK8NQTZxi7XiyK3FxxytzfHgz2jb3qUT69CZtsokRkN/zdi9rCgrMtq+w9XNICjcfQ=="], + "@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.12.3", "", { "os": "linux", "cpu": "x64" }, "sha512-T2dTxL1svRym71fZtaW4pZYXbthbfFsEJr1NeOUg/p7laWXZbUt/8DMSZf8recu9f7+1F/Lv00HtzsEu6vDO9w=="], - "@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.12.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-BR+CYM7iF3lkfyTtVkwMQU/s9hwegLpj3UqDjaxKCPmixQCa1csBBPy3C75V+FhLtOjIXNna4Gt6Vm9oxbV+qA=="], + "@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.12.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-eoiQwpEZWbpsVHcM9BAzqqe4TCHszvr3rsM7pUQ4ofLK0lF1i1d/jX0Qo5DYMqcrUtwQuDdDuOCbcT0Izf1VwQ=="], - "@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.12.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-zODJo9l3TbNBM+GrO/yPqGeELNMK5cjIc+QHh1WQc3l8tD+jDZGTQyYuAxViCsM6Uh5uWJ//RnCZG9LXrvsXww=="], + "@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.12.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-kE+KUg6Dbbkgvcw0m99wJVIToFQzJqpMBAXah74WqxaLzssNwSTUccrHp6+QVzMhjQP330tvekFmnQF+0NbE6Q=="], - "@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.12.2", "", { "os": "win32", "cpu": "x64" }, "sha512-cQXI2ZaZmwBDt0XATCqASVanYizxkEE3ceQVlVHXaQ51HzsQUWA04c9Nz7LrrY2lgAu3jFMyat+8Yz3Z2R2qBA=="], + "@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.12.3", "", { "os": "win32", "cpu": "x64" }, "sha512-L7wndWAgX2mLW7alswpL3d1R0P9FN2WYBgHaQkAYEBxHHGkY4vFX9CjcRQ1LAxDAMIJxrY7/aDziFJeChS84NQ=="], - "@tauri-apps/plugin-dialog": ["@tauri-apps/plugin-dialog@2.7.2", "", { "dependencies": { "@tauri-apps/api": "^2.11.0" } }, "sha512-pX0IGm1I3I6wc+zeKYcq1GSqogK6okCNX5fOdaNU5ab1AjGS6l1E5wFNjEb7meg7ZFSp0JUs+0jQGQNyOvLrsg=="], + "@tauri-apps/plugin-dialog": ["@tauri-apps/plugin-dialog@2.8.3", "", { "dependencies": { "@tauri-apps/api": "^2.12.0" } }, "sha512-Hd/yBfk2R5v2MFrz/0VArSXeh8xKLLXGunqSiTtcHKn1zNZwaKujuA0VSwUvNfwC4hDoF1PveS+gBDNe3nHspw=="], "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], @@ -458,8 +458,6 @@ "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], - "@tauri-apps/plugin-dialog/@tauri-apps/api": ["@tauri-apps/api@2.11.1", "", {}, "sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA=="], - "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], } } diff --git a/package.json b/package.json index f28ee08f..1dacc27b 100644 --- a/package.json +++ b/package.json @@ -23,15 +23,15 @@ "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", - "@tauri-apps/api": "^2.12.3", - "@tauri-apps/plugin-dialog": "^2.7.1", + "@tauri-apps/api": "2.12.4", + "@tauri-apps/plugin-dialog": "2.8.3", "lucide-react": "^1.24.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-markdown": "^10.1.0" }, "devDependencies": { - "@tauri-apps/cli": "^2.12.2", + "@tauri-apps/cli": "2.12.3", "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "@vitejs/plugin-react": "^5.0.0", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 815df237..c664d24f 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -242,13 +242,16 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "auto-launch" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f012b8cc0c850f34117ec8252a44418f2e34a2cf501de89e29b241ae5f79471" +checksum = "17918dba7ecf78b9a14507ec9f984e7977d13fad87dc86d61038980a45d128cf" dependencies = [ - "dirs 4.0.0", - "thiserror 1.0.69", - "winreg 0.10.1", + "dirs 6.0.0", + "os_info", + "smappservice-rs", + "thiserror 2.0.18", + "windows-registry", + "windows-result", ] [[package]] @@ -848,11 +851,11 @@ dependencies = [ [[package]] name = "dirs" -version = "4.0.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" dependencies = [ - "dirs-sys 0.3.7", + "dirs-sys", ] [[package]] @@ -861,18 +864,7 @@ version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d57d423b3c82e89b9a24ca3091fee61f456a26edbd28d26c65906f4bc1dcd8f" dependencies = [ - "dirs-sys 0.5.0", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users 0.4.6", - "winapi", + "dirs-sys", ] [[package]] @@ -883,8 +875,8 @@ checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", - "redox_users 0.5.3", - "windows-sys 0.60.2", + "redox_users", + "windows-sys 0.61.2", ] [[package]] @@ -995,7 +987,7 @@ dependencies = [ "rustc_version", "toml 1.1.3+spec-1.1.0", "vswhom", - "winreg 0.55.0", + "winreg", ] [[package]] @@ -1055,7 +1047,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2300,7 +2292,7 @@ dependencies = [ "png 0.18.1", "serde", "thiserror 2.0.18", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2339,6 +2331,18 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nix" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" +dependencies = [ + "bitflags 2.13.0", + "cfg-if", + "cfg_aliases", + "libc", +] + [[package]] name = "notify" version = "7.0.0" @@ -2577,6 +2581,30 @@ dependencies = [ "objc2-foundation", ] +[[package]] +name = "objc2-security" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a" +dependencies = [ + "bitflags 2.13.0", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-service-management" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b213642d6959cc6023ceb1217aa595eaaf09b8094ce95127c103cab611fe65e8" +dependencies = [ + "block2", + "objc2", + "objc2-core-foundation", + "objc2-foundation", + "objc2-security", +] + [[package]] name = "objc2-ui-kit" version = "0.3.2" @@ -2655,6 +2683,21 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "os_info" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf20a545b305cf1da722b236b5155c9bb35f1d5ceb28c048bd96ca842f41b5b" +dependencies = [ + "android_system_properties", + "log", + "nix", + "objc2", + "objc2-foundation", + "objc2-ui-kit", + "windows-sys 0.61.2", +] + [[package]] name = "pango" version = "0.18.3" @@ -3031,7 +3074,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -3096,17 +3139,6 @@ dependencies = [ "bitflags 2.13.0", ] -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom 0.2.17", - "libredox", - "thiserror 1.0.69", -] - [[package]] name = "redox_users" version = "0.5.3" @@ -3337,7 +3369,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -3729,6 +3761,18 @@ version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" +[[package]] +name = "smappservice-rs" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52703b97a53101cf5d4580e0737aaa634ce1fdcfc123c16b2a9658e358013488" +dependencies = [ + "objc2", + "objc2-foundation", + "objc2-service-management", + "thiserror 2.0.18", +] + [[package]] name = "socket2" version = "0.6.5" @@ -3736,7 +3780,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4112,9 +4156,9 @@ dependencies = [ [[package]] name = "tauri-plugin-autostart" -version = "2.5.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459383cebc193cdd03d1ba4acc40f2c408a7abce419d64bdcd2d745bc2886f70" +checksum = "bce56ceb0a99b8ab5eebc977ba9ffc62391b862648cb9ab76fc8bc7231b8f7e2" dependencies = [ "auto-launch", "serde", @@ -4126,9 +4170,9 @@ dependencies = [ [[package]] name = "tauri-plugin-dialog" -version = "2.7.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2d3c1dbe38037e7f590cdf2492594d5ceebe031e7bc7e827509b22a999d2940" +checksum = "b7461aaacf1901915ea7b9f5cd74f8224a351ed96af0a62c07fce934003cb34b" dependencies = [ "log", "raw-window-handle", @@ -4144,9 +4188,9 @@ dependencies = [ [[package]] name = "tauri-plugin-fs" -version = "2.5.1" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ecc274121aca0c036a2b42d1cbe83d368d348f54e0bb8a735c2b1548e8f371" +checksum = "5d58eb1d4984e535f47a642ffec09a2da6f5c18a12b5902d12126cb7626d628b" dependencies = [ "anyhow", "dunce", @@ -4168,9 +4212,9 @@ dependencies = [ [[package]] name = "tauri-plugin-opener" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85dead674ee41937d042ee855d785f07ee67206f19402200c12b9255964d5ac8" +checksum = "53810be1b4fed22bb6ac3f4cab5a2b80d9391d1af436bda145607532bc0bb219" dependencies = [ "dunce", "glob", @@ -4298,7 +4342,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4656,7 +4700,7 @@ dependencies = [ "png 0.18.1", "serde", "thiserror 2.0.18", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4691,7 +4735,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ "memoffset", "tempfile", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -5068,7 +5112,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -5089,7 +5133,7 @@ dependencies = [ "objc2-foundation", "objc2-quartz-core", "raw-window-handle", - "windows-sys 0.60.2", + "windows-sys 0.61.2", "windows-version", ] @@ -5176,6 +5220,17 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + [[package]] name = "windows-result" version = "0.4.1" @@ -5461,15 +5516,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - [[package]] name = "winreg" version = "0.55.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 49120a26..28dccfe2 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -28,9 +28,9 @@ serde_yaml = "0.9" sha2 = "0.10" tar = "0.4" tauri = { version = "~2.12.4", features = ["macos-private-api", "tray-icon", "unstable"] } -tauri-plugin-autostart = "2" -tauri-plugin-dialog = "2.7.1" -tauri-plugin-opener = "2" +tauri-plugin-autostart = "2.7.0" +tauri-plugin-dialog = "2.8.3" +tauri-plugin-opener = "2.7.2" tokio = { version = "1", features = ["io-util", "macros", "net", "sync", "time"] } tokio-util = "0.7" toml = "0.8" diff --git a/src/components/ThemeSelector.css b/src/components/ThemeSelector.css index 719f55cf..0a852f07 100644 --- a/src/components/ThemeSelector.css +++ b/src/components/ThemeSelector.css @@ -32,54 +32,72 @@ .theme-selector-warning { position: absolute; top: 2px; right: 2px; width: 5px; height: 5px; border-radius: var(--radius-full); background: var(--amber-color); } .theme-selector-menu { - position: fixed; - z-index: 150; display: flex; flex-direction: column; - gap: 4px; + gap: 12px; box-sizing: border-box; - padding: 10px; - overflow-y: auto; - overscroll-behavior: contain; - border: 1px solid var(--sidebar-popover-edge); - border-radius: var(--radius-lg); - background: var(--sidebar-popover-bg); - color: var(--sidebar-text); - box-shadow: var(--sidebar-popover-shadow); - font-size: var(--font-size-meta); + width: min(840px, 100%); + height: 740px; + max-height: calc(100dvh - 40px); + min-height: 0; + padding: 22px; + overflow: hidden; + color: var(--color-text-primary); } -.theme-selector-notice { flex: none; padding: 2px 4px 6px; font-size: 11px; line-height: 1.5; color: var(--sidebar-text-subtle); overflow-wrap: anywhere; } -.theme-selector-notice button { display: block; margin-top: 4px; padding: 0; border: 0; background: transparent; color: var(--ui-accent); font: inherit; cursor: pointer; } - -.theme-selector-modes { display: grid; flex: none; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2px; padding: 2px; margin-bottom: 6px; border-radius: var(--radius-md); background: var(--sidebar-hover-bg); } -.theme-selector-mode { display: inline-flex; align-items: center; justify-content: center; gap: 5px; min-width: 0; height: 28px; padding: 0 4px; border: 1px solid transparent; border-radius: var(--radius-md); background: transparent; color: var(--sidebar-text); font: inherit; white-space: nowrap; overflow: hidden; cursor: pointer; } +.theme-selector-menu > :not(.theme-selector-results) { flex: none; } +.theme-selector-notice { margin: 0; } +.theme-selector-preferences { display: grid; gap: 6px; } +.theme-selector-modes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; padding: 3px; border-radius: var(--radius-md); background: var(--color-surface-subtle); } +.theme-selector-mode { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-width: 0; height: 34px; padding: 0 8px; border: var(--border-width) solid transparent; border-radius: var(--radius-md); background: transparent; color: var(--color-text-secondary); font: inherit; white-space: nowrap; cursor: pointer; } .theme-selector-mode svg { flex: none; } -.theme-selector-mode:hover { color: var(--sidebar-text-strong); } -.theme-selector-mode.selected { border-color: var(--sidebar-popover-edge); background: var(--sidebar-popover-bg); color: var(--sidebar-text-strong); box-shadow: var(--shadow-sm); font-weight: 500; } +.theme-selector-mode:hover { color: var(--color-text-primary); } +.theme-selector-mode.selected { border-color: var(--color-border-default); background: var(--color-surface); color: var(--color-text-primary); box-shadow: var(--shadow-sm); } +.theme-selector-current, .theme-selector-system-hint, .theme-selector-count, .theme-selector-hint { margin: 0; color: var(--color-text-secondary); font-size: var(--font-size-meta); line-height: 1.5; overflow-wrap: anywhere; } +.theme-selector-current { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.theme-selector-filters { display: grid; grid-template-columns: minmax(0, 1fr) 170px; gap: 12px; } +.theme-selector-search { position: relative; min-width: 0; } +.theme-selector-search > svg { position: absolute; top: 50%; left: 12px; transform: translateY(-50%); color: var(--color-text-tertiary); pointer-events: none; } +.theme-selector-search input { box-sizing: border-box; width: 100%; height: 42px; padding-left: 36px; } +.theme-selector-filters .select-control { width: 100%; min-width: 0; } +.theme-selector-results { flex: 1 1 0; min-height: 0; overflow-y: auto; overscroll-behavior: contain; scrollbar-gutter: stable; padding: 2px 4px 4px 2px; } +.theme-selector-group + .theme-selector-group { margin-top: 18px; } +.theme-selector-heading { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; font-weight: 600; } +.theme-selector-heading > span { color: var(--color-text-tertiary); font-size: var(--font-size-meta); font-weight: 400; } +.theme-selector-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; } +.theme-selector-card { position: relative; display: flex; flex-direction: column; align-items: stretch; gap: 6px; min-width: 0; height: auto; padding: 12px; color: var(--color-text-primary); font: inherit; text-align: start; white-space: normal; font-weight: 400; } +.theme-selector-card:hover { background: var(--color-surface-hover); } +.theme-selector-card.selected { border-color: var(--ui-accent); background: color-mix(in srgb, var(--ui-accent) 8%, var(--color-surface)); } +.theme-selector-card .theme-thumbnail { width: 100%; height: 76px; margin-bottom: 4px; } +.theme-selector-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; } +.theme-selector-description { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; min-height: 2.8em; overflow: hidden; overflow-wrap: anywhere; color: var(--color-text-secondary); font-size: var(--font-size-meta); line-height: 1.4; } +.theme-selector-id { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--color-text-tertiary); font-size: var(--font-size-meta); } +.theme-selector-meta { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px 8px; margin-top: auto; color: var(--color-text-secondary); font-size: var(--font-size-meta); } +.theme-selector-active { color: var(--ui-accent-strong); } +.theme-selector-check { position: absolute; top: 16px; right: 16px; padding: 3px; border-radius: var(--radius-full); background: var(--ui-accent); color: var(--primary-contrast); } +.theme-selector-footer { display: grid; gap: 8px; padding-top: 12px; border-top: var(--border-width) solid var(--color-border-subtle); } +.theme-selector-actions { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px; } +.theme-selector-actions button { min-width: 0; } +.theme-selector-problems { margin-bottom: 12px; font-size: var(--font-size-meta); } +.theme-selector-problems summary { cursor: pointer; color: var(--color-text-secondary); } +.theme-selector-custom-problems { max-height: 100px; overflow-y: auto; overflow-wrap: anywhere; margin-top: 8px; } +.theme-selector-mode:focus-visible, .theme-selector-card:focus-visible { outline: 2px solid var(--ui-focus-ring); outline-offset: 1px; } -.theme-selector-group { flex: none; transition: opacity 0.15s; } -.theme-selector-group.inactive { opacity: 0.6; } -.theme-selector-group.inactive:hover, .theme-selector-group.inactive:focus-within { opacity: 1; } -.theme-selector-heading { padding: 5px 4px 6px; color: var(--sidebar-text-strong); font-weight: 600; } -.theme-selector-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; } -.theme-selector-card { position: relative; display: flex; flex-direction: column; align-items: center; gap: 5px; min-width: 0; padding: 7px 4px 6px; border: 1px solid transparent; border-radius: var(--radius-md); background: transparent; color: var(--sidebar-text); font: inherit; font-size: 11px; cursor: pointer; } -.theme-selector-card:hover { background: var(--sidebar-hover-bg); } -.theme-selector-card.selected { border-color: var(--ui-accent); color: var(--sidebar-text-strong); background: color-mix(in srgb, var(--ui-accent) 8%, var(--sidebar-popover-bg)); } -.theme-selector-card .theme-thumbnail { width: 100%; height: 36px; } -.theme-selector-name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.theme-selector-check { position: absolute; top: 3px; right: 3px; padding: 1px; border-radius: var(--radius-full); background: var(--ui-accent); color: var(--primary-contrast); } -.theme-selector-custom-notice { padding: 6px 4px 0; } -.theme-selector-custom-problems { padding: 6px 4px 0; } -.theme-selector-hint { flex: none; margin: 0; padding: 6px 4px 0; color: var(--sidebar-text-subtle); font-size: 11px; line-height: 1.5; overflow-wrap: anywhere; } -.theme-selector-actions { display: flex; flex: none; justify-content: space-between; gap: 6px; margin-top: 6px; padding-top: 8px; border-top: 1px solid var(--sidebar-popover-edge); } -.theme-selector-actions button { display: inline-flex; flex: 0 1 auto; align-items: center; justify-content: center; gap: 5px; min-width: 0; height: 28px; padding: 0 6px; border: 1px solid transparent; border-radius: var(--radius-md); background: transparent; color: var(--sidebar-text); font: inherit; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; } -.theme-selector-actions button svg { flex: none; } -.theme-selector-actions button:hover:not(:disabled) { background: var(--sidebar-hover-bg); color: var(--sidebar-text-strong); } -.theme-selector-actions button:disabled { opacity: 0.55; cursor: default; } -.theme-selector-mode:focus-visible, .theme-selector-card:focus-visible, .theme-selector-notice button:focus-visible , .theme-selector-actions button:focus-visible { outline: 2px solid var(--sidebar-focus); outline-offset: 1px; } +@media (max-width: 700px) { + .theme-selector-menu { padding: 16px; } + .theme-selector-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .theme-selector-filters { grid-template-columns: minmax(0, 1fr) 145px; gap: 8px; } +} + +@media (max-height: 540px) { + .theme-selector-menu { gap: 6px; padding: 12px; } + .theme-selector-preferences { gap: 4px; } + .theme-selector-current, .theme-selector-hint { display: none; } + .theme-selector-footer { padding-top: 6px; gap: 4px; } + .theme-selector-custom-problems { max-height: 48px; } +} -.theme-thumbnail { display: flex; flex: none; width: 42px; height: 30px; overflow: hidden; border: 1px solid var(--sidebar-edge); border-radius: var(--radius-md); background: var(--preview-bg); box-shadow: var(--shadow-xs); box-sizing: border-box; } +.theme-thumbnail { display: flex; flex: none; width: 42px; height: 30px; overflow: hidden; border: 1px solid var(--color-border-default); border-radius: var(--radius-md); background: var(--preview-bg); box-shadow: var(--shadow-xs); box-sizing: border-box; } .theme-thumbnail-sidebar { display: grid; align-content: start; gap: 3px; width: 10px; padding: 5px 2px; background: var(--preview-sidebar); } .theme-thumbnail-sidebar i { height: 3px; border-radius: var(--radius-sm); background: var(--preview-accent); opacity: 0.35; } .theme-thumbnail-sidebar i:first-child { opacity: 1; } diff --git a/src/components/ThemeSelector.tsx b/src/components/ThemeSelector.tsx index 1a15a0c0..c2c301a1 100644 --- a/src/components/ThemeSelector.tsx +++ b/src/components/ThemeSelector.tsx @@ -1,16 +1,19 @@ import { SegmentedControl } from './SegmentedControl'; -import { useEffect, useLayoutEffect, useRef, useState, type CSSProperties } from 'react'; -import { createPortal } from 'react-dom'; -import { Check, FolderOpen, Monitor, Moon, RefreshCw, Sun, SunMoon } from 'lucide-react'; +import { useEffect, useRef, useState, type CSSProperties } from 'react'; +import { Check, FolderOpen, Monitor, Moon, RefreshCw, Search, Sun, SunMoon } from 'lucide-react'; import { useI18n } from '../i18n'; import { openCustomThemesDirectory, reloadCustomThemes, retryThemeSave, setSystemTheme, useCustomThemeStatus, useResolvedThemeId, useSystemThemes, useThemePreferenceIssue, useThemeRegistry, } from '../theme'; -import { themePreview, type ThemeRegistry } from '../themes/registry'; +import { builtinThemes, themePreview, type ThemeRegistry } from '../themes/registry'; import { localizeThemeLabel, type ThemeAppearance, type ThemeDefinition, type ThemeIssueCode } from '../themes/types'; import type { CustomThemeSkipReason } from '../themes/customThemes'; import type { MessageKey } from '../i18n/resources'; +import { Dialog } from './Dialog'; +import { EmptyState } from './EmptyState'; +import { Notice } from './Notice'; +import { Select } from './Select'; import './ThemeSelector.css'; const skipReasonKeys: Record = { @@ -41,6 +44,8 @@ function ThemeThumbnail({ theme }: { theme: ThemeDefinition }) { } type Mode = ThemeAppearance | 'system'; +type Source = 'all' | 'builtin' | 'custom'; +const builtinIds = new Set(builtinThemes.map(theme => theme.id)); export function ThemeSelector({ value, onChange, open, onOpenChange, registry: override }: { value: string; @@ -57,9 +62,9 @@ export function ThemeSelector({ value, onChange, open, onOpenChange, registry: o const resolvedId = useResolvedThemeId(); const custom = useCustomThemeStatus(); const [openFailed, setOpenFailed] = useState(false); - const trigger = useRef(null); - const menu = useRef(null); - const [layout, setLayout] = useState(); + const search = useRef(null); + const [query, setQuery] = useState(''); + const [source, setSource] = useState('all'); const fixed = value === 'system' ? undefined : registry.get(value); const unavailable = value !== 'system' && !fixed; const mode: Mode = value === 'system' ? 'system' : fixed?.appearance ?? 'light'; @@ -67,11 +72,15 @@ export function ThemeSelector({ value, onChange, open, onOpenChange, registry: o fixed?.appearance === appearance ? fixed.id : registry.resolveSystem(appearance, systemThemes).id; const current = registry.get(resolvedId) ?? registry.get('light')!; const themeName = (theme: ThemeDefinition) => theme.name ? localizeThemeLabel(theme.name, locale) : t(theme.nameKey!); - const themeTitle = (theme: ThemeDefinition) => { - const description = theme.description ? localizeThemeLabel(theme.description, locale) - : theme.descriptionKey ? t(theme.descriptionKey) : ''; - return description ? `${themeName(theme)}\n${description}` : themeName(theme); - }; + const themeDescription = (theme: ThemeDefinition) => theme.description ? localizeThemeLabel(theme.description, locale) + : theme.descriptionKey ? t(theme.descriptionKey) : ''; + const themeTitle = (theme: ThemeDefinition) => [themeName(theme), themeDescription(theme)].filter(Boolean).join('\n'); + const normalizedQuery = query.trim().normalize('NFKC').toLocaleLowerCase(locale); + const matches = registry.themes.filter(theme => + (source === 'all' || builtinIds.has(theme.id) === (source === 'builtin')) + && [themeName(theme), themeDescription(theme), theme.id].some(text => + text.normalize('NFKC').toLocaleLowerCase(locale).includes(normalizedQuery))); + const resetFilters = () => { setQuery(''); setSource('all'); search.current?.focus(); }; const name = unavailable ? t('app.theme.unavailable') : themeName(current); const issueText = issue === 'read' ? t('app.theme.readFailed') : issue === 'save' ? t('app.theme.saveFailed') : unavailable ? t('app.theme.unavailableHint') : ''; @@ -94,46 +103,10 @@ export function ThemeSelector({ value, onChange, open, onOpenChange, registry: o openCustomThemesDirectory().catch(() => setOpenFailed(true)); }; - useLayoutEffect(() => { - if (!open) { setLayout(undefined); return; } - const position = () => { - if (!trigger.current) return; - const rect = trigger.current.getBoundingClientRect(); - const edge = 12; - const width = Math.min(300, window.innerWidth - edge * 2); - const above = rect.top - edge - 8; - const below = window.innerHeight - rect.bottom - edge - 8; - const up = above >= below; - setLayout({ - width, maxHeight: Math.max(0, up ? above : below), - left: Math.max(edge, Math.min(rect.left, window.innerWidth - width - edge)), - ...(up ? { bottom: window.innerHeight - rect.top + 8 } : { top: rect.bottom + 8 }), - }); - }; - position(); - window.addEventListener('resize', position); - return () => window.removeEventListener('resize', position); - }, [open]); - useEffect(() => { - if (open && layout) menu.current?.querySelector('.theme-selector-mode[aria-checked="true"]')?.focus({ preventScroll: true }); - }, [open, layout === undefined]); - - useEffect(() => { - if (!open) return; - const close = (event: Event) => { - const target = event.target as Node; - if (!trigger.current?.contains(target) && !menu.current?.contains(target)) onOpenChange(false); - }; - document.addEventListener('pointerdown', close); - document.addEventListener('focusin', close); - return () => { - document.removeEventListener('pointerdown', close); - document.removeEventListener('focusin', close); - }; - }, [open, onOpenChange]); + if (!open) { setQuery(''); setSource('all'); } + }, [open]); - const closeToTrigger = () => { onOpenChange(false); trigger.current?.focus(); }; const chooseMode = (next: Mode) => { if (fixed) setSystemTheme(fixed.id); onChange(next === 'system' ? 'system' : slot(next)); @@ -150,68 +123,99 @@ export function ThemeSelector({ value, onChange, open, onOpenChange, registry: o return (
-