diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 4b6ce17..74d4cc8 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -29,8 +29,6 @@ jobs: sudo apt-get install -y libwebkit2gtk-4.1-dev build-essential curl wget file libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev - uses: pnpm/action-setup@v4 - with: - version: 10 - uses: actions/setup-node@v4 with: @@ -40,6 +38,10 @@ jobs: - name: Install Rust stable uses: dtolnay/rust-toolchain@stable + - name: Add x86_64 target (macOS only) + if: matrix.platform == 'macos-latest' + run: rustup target add x86_64-apple-darwin + - uses: Swatinem/rust-cache@v2 with: workspaces: "apps/desktop/src-tauri -> target" diff --git a/.github/workflows/ci-check.yml b/.github/workflows/ci-check.yml index 341ef24..6e7acef 100644 --- a/.github/workflows/ci-check.yml +++ b/.github/workflows/ci-check.yml @@ -11,8 +11,6 @@ jobs: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 - with: - version: 10 - uses: actions/setup-node@v4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f3a0d04..0fe74bf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,8 +33,6 @@ jobs: sudo apt-get install -y libwebkit2gtk-4.1-dev build-essential curl wget file libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev - uses: pnpm/action-setup@v4 - with: - version: 10 - uses: actions/setup-node@v4 with: @@ -44,6 +42,10 @@ jobs: - name: Install Rust stable uses: dtolnay/rust-toolchain@stable + - name: Add x86_64 target (macOS only) + if: matrix.platform == 'macos-latest' + run: rustup target add x86_64-apple-darwin + - uses: Swatinem/rust-cache@v2 with: workspaces: "apps/desktop/src-tauri -> target" diff --git a/apps/desktop/public/backgrounds/settings-bg-dark.png b/apps/desktop/public/backgrounds/settings-bg-dark.png new file mode 100644 index 0000000..eccce0a Binary files /dev/null and b/apps/desktop/public/backgrounds/settings-bg-dark.png differ diff --git a/apps/desktop/public/backgrounds/settings-bg-light.png b/apps/desktop/public/backgrounds/settings-bg-light.png new file mode 100644 index 0000000..514fc03 Binary files /dev/null and b/apps/desktop/public/backgrounds/settings-bg-light.png differ diff --git a/apps/desktop/src-tauri/Cargo.lock b/apps/desktop/src-tauri/Cargo.lock index 4aed1b8..381bc18 100644 --- a/apps/desktop/src-tauri/Cargo.lock +++ b/apps/desktop/src-tauri/Cargo.lock @@ -25,9 +25,9 @@ checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" [[package]] name = "alloc-stdlib" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195" dependencies = [ "alloc-no-stdlib", ] @@ -248,9 +248,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" dependencies = [ "serde_core", ] @@ -288,9 +288,9 @@ dependencies = [ [[package]] name = "brotli" -version = "8.0.2" +version = "8.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -299,9 +299,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "5.0.0" +version = "5.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -349,7 +349,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "cairo-sys-rs", "glib", "libc", @@ -412,9 +412,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.62" +version = "1.2.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +checksum = "dad887fd958be91b5098c0248def011f4523ab786cd411be668777e55063501f" dependencies = [ "find-msvc-tools", "shlex", @@ -455,9 +455,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "iana-time-zone", "num-traits", @@ -516,7 +516,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "core-foundation", "core-graphics-types", "foreign-types", @@ -529,7 +529,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "core-foundation", "libc", ] @@ -667,7 +667,6 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ - "powerfmt", "serde_core", ] @@ -729,7 +728,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block2", "libc", "objc2", @@ -737,9 +736,9 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", @@ -1292,7 +1291,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "futures-channel", "futures-core", "futures-executor", @@ -1459,9 +1458,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" dependencies = [ "bytes", "itoa", @@ -1498,9 +1497,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "hyper" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ "atomic-waker", "bytes", @@ -1820,13 +1819,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.99" +version = "0.3.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" +checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31" dependencies = [ "cfg-if", "futures-util", - "once_cell", "wasm-bindgen", ] @@ -1858,7 +1856,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "serde", "unicode-segmentation", ] @@ -1920,9 +1918,9 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" +checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" dependencies = [ "libc", ] @@ -1950,9 +1948,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" [[package]] name = "markup5ever" @@ -1967,9 +1965,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" [[package]] name = "memoffset" @@ -1998,9 +1996,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "wasi", @@ -2034,7 +2032,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "jni-sys 0.3.1", "log", "ndk-sys", @@ -2124,7 +2122,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block2", "objc2", "objc2-core-foundation", @@ -2137,7 +2135,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "objc2", "objc2-foundation", ] @@ -2158,7 +2156,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "dispatch2", "objc2", ] @@ -2169,7 +2167,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "dispatch2", "objc2", "objc2-core-foundation", @@ -2202,7 +2200,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "objc2", "objc2-core-foundation", "objc2-core-graphics", @@ -2229,7 +2227,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block2", "objc2", "objc2-core-foundation", @@ -2241,7 +2239,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "objc2", "objc2-core-foundation", ] @@ -2252,7 +2250,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "objc2", "objc2-core-foundation", "objc2-foundation", @@ -2264,7 +2262,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block2", "objc2", "objc2-cloud-kit", @@ -2295,7 +2293,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block2", "objc2", "objc2-app-kit", @@ -2511,7 +2509,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "crc32fast", "fdeflate", "flate2", @@ -2589,7 +2587,7 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.25.11+spec-1.1.0", + "toml_edit 0.25.12+spec-1.1.0", ] [[package]] @@ -2667,7 +2665,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", ] [[package]] @@ -2703,9 +2701,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.3" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" dependencies = [ "aho-corasick", "memchr", @@ -2726,15 +2724,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "reqwest" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" dependencies = [ "base64 0.22.1", "bytes", @@ -2785,7 +2783,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "errno", "libc", "linux-raw-sys", @@ -2870,7 +2868,7 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "cssparser", "derive_more", "log", @@ -2990,9 +2988,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.20.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2" +checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" dependencies = [ "base64 0.22.1", "bs58", @@ -3010,9 +3008,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.20.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b90c488738ecb4fb0262f41f43bc40efc5868d9fb744319ddf5f5317f417bfac" +checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" dependencies = [ "darling", "proc-macro2", @@ -3064,9 +3062,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signal-hook-registry" @@ -3098,15 +3096,15 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.1" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "socket2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", "windows-sys 0.61.2", @@ -3267,7 +3265,7 @@ version = "0.35.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1c93047acf68669466a34690ac58cca7010bd1b201e1ec86f1fd0a75d3dd4a9" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "block2", "core-foundation", "core-graphics", @@ -3488,7 +3486,7 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73736611e14142408d15353e21e3cca2f12a3cfb523ad0ce85999b6d2ef1a704" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "log", "serde", "serde_json", @@ -3662,12 +3660,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.47" +version = "0.3.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "711a53c2d47bbd818258c498c8dbfe186a2526c631495cfe7e078567f86b8469" dependencies = [ "deranged", - "itoa", "num-conv", "powerfmt", "serde_core", @@ -3677,15 +3674,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "71c652a3727a9cbb9a02f707f530b618ce00d0ccd762009c8c23bd191df3c17d" dependencies = [ "num-conv", "time-core", @@ -3838,9 +3835,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.11+spec-1.1.0" +version = "0.25.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" dependencies = [ "indexmap 2.14.0", "toml_datetime 1.1.1+spec-1.1.0", @@ -3884,7 +3881,7 @@ version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "bytes", "futures-util", "http", @@ -3975,9 +3972,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "uds_windows" @@ -4039,9 +4036,9 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" -version = "1.13.2" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-xid" @@ -4088,9 +4085,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.23.1" +version = "1.23.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +checksum = "144d6b123cef80b301b8f72a9e2ca4370ddec21950d0a103dd22c437006d2db7" dependencies = [ "getrandom 0.4.2", "js-sys", @@ -4157,9 +4154,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.3+wasi-0.2.9" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ "wit-bindgen 0.57.1", ] @@ -4175,9 +4172,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.122" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" +checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a" dependencies = [ "cfg-if", "once_cell", @@ -4188,9 +4185,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.72" +version = "0.4.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f" +checksum = "503b14d284f2c8dac03b819967e155ea753f573586193b2b2c95990cb5d69280" dependencies = [ "js-sys", "wasm-bindgen", @@ -4198,9 +4195,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.122" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" +checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4208,9 +4205,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.122" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" +checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd" dependencies = [ "bumpalo", "proc-macro2", @@ -4221,9 +4218,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.122" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" +checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f" dependencies = [ "unicode-ident", ] @@ -4269,7 +4266,7 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "hashbrown 0.15.5", "indexmap 2.14.0", "semver", @@ -4277,9 +4274,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.99" +version = "0.3.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" +checksum = "a6430a72df5eb332242960fe84b3002a241163998241eb596d4f739b9757061d" dependencies = [ "js-sys", "wasm-bindgen", @@ -4826,7 +4823,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.1", + "bitflags 2.13.0", "indexmap 2.14.0", "log", "serde", @@ -4929,9 +4926,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -4952,9 +4949,9 @@ dependencies = [ [[package]] name = "zbus" -version = "5.15.0" +version = "5.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bcbf15c8708d7fc1be0c993622e0a5cbd5e8b52bfa40afa4c3e0cd8d724ac1" +checksum = "eee682d202a77e4a9f3b2c2bdf48a7b28af5c08c34ddf66f98c93e5e39464285" dependencies = [ "async-broadcast", "async-executor", @@ -4987,9 +4984,9 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "5.15.0" +version = "5.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51fa5406ad9175a8c825a931f8cf347116b531b3634fcb0b627c290f1f2516ff" +checksum = "adf1bd45a81a103745b1757754762a26e8cd01e4532e4d6c8ec431624b80d1d6" dependencies = [ "proc-macro-crate 3.5.0", "proc-macro2", @@ -5073,9 +5070,9 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "zvariant" -version = "5.11.0" +version = "5.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c1567a6ec68df868cbbfde844cfc6d81649fe5109a62b116b19fabd53e618ee" +checksum = "a192a0bde63360d77a7523c833d4b4ce6070a927e2c53246e4c540b1a3e27be0" dependencies = [ "endi", "enumflags2", @@ -5087,9 +5084,9 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "5.11.0" +version = "5.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d5b780599bbde114e39d9a0799577fad1ced5105d38515745f7b3099d8ceda" +checksum = "90bc6cde9c01c511074be97f7ccb6c19d0da89e3f8662e812e999dcfd4638737" dependencies = [ "proc-macro-crate 3.5.0", "proc-macro2", @@ -5100,9 +5097,9 @@ dependencies = [ [[package]] name = "zvariant_utils" -version = "3.3.1" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d464f5733ffa07a3164d656f18533caace9d0638596721355d73256a410d691" +checksum = "1e8535915cfa75547e559d8c68e8139909a4aeee076831e4ef7fc59d8172c4d6" dependencies = [ "proc-macro2", "quote", diff --git a/apps/desktop/src-tauri/Cargo.toml b/apps/desktop/src-tauri/Cargo.toml index 47b516d..d0e7c53 100644 --- a/apps/desktop/src-tauri/Cargo.toml +++ b/apps/desktop/src-tauri/Cargo.toml @@ -18,4 +18,6 @@ tauri-plugin-opener = "2" tauri-plugin-window-state = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" + +[target.'cfg(target_os = "windows")'.dependencies] tauri-plugin-wallpaper = "3.0.0" diff --git a/apps/desktop/src-tauri/capabilities/default.json b/apps/desktop/src-tauri/capabilities/default.json index 45d03f5..73aced1 100644 --- a/apps/desktop/src-tauri/capabilities/default.json +++ b/apps/desktop/src-tauri/capabilities/default.json @@ -2,11 +2,10 @@ "$schema": "../gen/schemas/desktop-schema.json", "identifier": "default", "description": "Default desktop capability for NeoCompanion v1", - "windows": ["main", "panel", "wallpaper"], + "windows": ["main", "panel", "wallpaper", "settings"], "permissions": [ "core:default", "opener:default", - "wallpaper:default", "window-state:default" ] } diff --git a/apps/desktop/src-tauri/capabilities/windows-wallpaper.json b/apps/desktop/src-tauri/capabilities/windows-wallpaper.json new file mode 100644 index 0000000..ee75dad --- /dev/null +++ b/apps/desktop/src-tauri/capabilities/windows-wallpaper.json @@ -0,0 +1,10 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "windows-wallpaper", + "description": "Wallpaper plugin — Windows only", + "platforms": ["windows"], + "windows": ["wallpaper"], + "permissions": [ + "wallpaper:default" + ] +} diff --git a/apps/desktop/src-tauri/src/lib.rs b/apps/desktop/src-tauri/src/lib.rs index d63c84d..adb99d8 100644 --- a/apps/desktop/src-tauri/src/lib.rs +++ b/apps/desktop/src-tauri/src/lib.rs @@ -66,6 +66,17 @@ pub fn run() { }); } + if let Some(window) = app.get_webview_window("settings") { + let _ = window.hide(); + let settings = window.clone(); + window.on_window_event(move |event| { + if let WindowEvent::CloseRequested { api, .. } = event { + api.prevent_close(); + let _ = settings.hide(); + } + }); + } + Ok(()) }) .run(tauri::generate_context!()) diff --git a/apps/desktop/src-tauri/tauri.conf.json b/apps/desktop/src-tauri/tauri.conf.json index f4cad24..8f8f81a 100644 --- a/apps/desktop/src-tauri/tauri.conf.json +++ b/apps/desktop/src-tauri/tauri.conf.json @@ -30,11 +30,11 @@ "title": "NeoCompanion", "label": "panel", "url": "/?view=panel", - "width": 944, - "height": 744, - "minWidth": 560, - "minHeight": 640, - "transparent": true, + "width": 1400, + "height": 900, + "minWidth": 980, + "minHeight": 700, + "transparent": false, "decorations": false, "alwaysOnTop": false, "resizable": true, @@ -55,6 +55,22 @@ "skipTaskbar": true, "visible": false, "center": false + }, + { + "title": "NeoCompanion 设置", + "label": "settings", + "url": "/?view=settings", + "width": 1080, + "height": 760, + "minWidth": 880, + "minHeight": 640, + "transparent": false, + "decorations": true, + "alwaysOnTop": false, + "resizable": true, + "skipTaskbar": false, + "visible": false, + "center": true } ], "security": { diff --git a/apps/desktop/src/App.vue b/apps/desktop/src/App.vue index 0368e0d..307c312 100644 --- a/apps/desktop/src/App.vue +++ b/apps/desktop/src/App.vue @@ -17,21 +17,41 @@ import SpeechBubble from "./components/pet/SpeechBubble.vue"; import PetStatusBar from "./components/pet/PetStatusBar.vue"; import PermissionBubble from "./components/pet/PermissionBubble.vue"; -import PanelHeader from "./components/panel/PanelHeader.vue"; -import TabNav from "./components/panel/TabNav.vue"; -import FocusPanel from "./components/panel/FocusPanel.vue"; -import TaskPanel from "./components/panel/TaskPanel.vue"; -import ChatPanel from "./components/panel/ChatPanel.vue"; -import StatusBar from "./components/panel/StatusBar.vue"; +import TopNav from "./components/panel/TopNav.vue"; +import CreateFocusCard from "./components/panel/cards/CreateFocusCard.vue"; +import TodayTasksCard from "./components/panel/cards/TodayTasksCard.vue"; +import WeeklyFocusCard from "./components/panel/cards/WeeklyFocusCard.vue"; +import ClawGatewayCard from "./components/panel/cards/ClawGatewayCard.vue"; +import AssistantStatusCard from "./components/panel/cards/AssistantStatusCard.vue"; +import HookNotificationsCard from "./components/panel/cards/HookNotificationsCard.vue"; +import AiChatCard from "./components/panel/cards/AiChatCard.vue"; +import DiaryCard from "./components/panel/cards/DiaryCard.vue"; +import BottomBar from "./components/panel/BottomBar.vue"; +import FloatingControls from "./components/panel/FloatingControls.vue"; +import ComponentsButton from "./components/panel/ComponentsButton.vue"; +import PageDots from "./components/panel/PageDots.vue"; import ErrorToast from "./components/shared/ErrorToast.vue"; import WallpaperView from "./views/WallpaperView.vue"; - -type DrawerTab = "focus" | "tasks" | "chat"; +import SettingsView from "./views/SettingsView.vue"; +import { useSettings } from "./composables/useSettings"; const viewMode = new URLSearchParams(window.location.search).get("view"); const isPetView = viewMode === "pet"; const isWallpaperView = viewMode === "wallpaper"; +const isSettingsView = viewMode === "settings"; const isTauriRuntime = "__TAURI_INTERNALS__" in window; +type PanelPage = "focus" | "tasks" | "weekly" | "claw" | "assistant" | "hooks" | "chat" | "diary"; + +const panelPages: Array<{ id: PanelPage; label: string }> = [ + { id: "focus", label: "专注" }, + { id: "tasks", label: "任务" }, + { id: "weekly", label: "本周" }, + { id: "claw", label: "OpenClaw" }, + { id: "assistant", label: "助手" }, + { id: "hooks", label: "Hook" }, + { id: "chat", label: "AI 对话" }, + { id: "diary", label: "日记" }, +]; const pet = usePetState(); const focus = useFocus(); @@ -39,19 +59,25 @@ const tasks = useTasks(); const chat = useChat(); const permission = usePermission(); const wallpaper = useWallpaperState(); +const settings = useSettings(); const weather = ref(null); const lastWindow = ref(null); const serverReady = ref(false); const errorText = ref(""); -const activeTab = ref("focus"); +const isPanelDark = ref(false); +const activePanelPage = ref("focus"); const wallpaperVisible = ref(true); +const focusStartTime = ref(""); const contextMenu = ref<{ x: number; y: number } | null>(null); let disconnectWs: (() => void) | null = null; onMounted(async () => { + if (isSettingsView) { + return; + } if (isWallpaperView) { wallpaper.startClock(); } @@ -129,9 +155,11 @@ async function openPanel() { await panel?.setFocus(); } -async function hidePanel() { +async function openSettings() { if (!isTauriRuntime) return; - await WebviewWindow.getCurrent().hide(); + const settings = await WebviewWindow.getByLabel("settings"); + await settings?.show(); + await settings?.setFocus(); } async function setWallpaperLayerVisible(visible: boolean) { @@ -184,10 +212,10 @@ function closeContextMenu() { async function quickStartFocus() { closeContextMenu(); - if (tasks.activeTaskId.value) { - await focus.startFocus(tasks.activeTaskId.value); - pet.setState("focus"); - } + if (!tasks.activeTaskId.value) return; + focusStartTime.value = new Date().toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit" }); + await focus.startFocus(tasks.activeTaskId.value); + pet.setState("focus"); } function focusAddTask() { @@ -202,19 +230,38 @@ function onTaskToggle(task: typeof tasks.tasks.value[0]) { } } -async function onSendChat() { - chat.sendChat(); - pet.setState("thinking"); +function togglePanelTheme() { + isPanelDark.value = !isPanelDark.value; } -async function onStartFocus() { +function setActivePanelPage(pageId: string) { + if (panelPages.some((page) => page.id === pageId)) { + activePanelPage.value = pageId as PanelPage; + } +} + +async function onStartFocusFromCard(duration?: number) { + if (!tasks.activeTaskId.value) return; + if (duration) { + focus.focusMinutes.value = duration; + } + focusStartTime.value = new Date().toLocaleTimeString("zh-CN", { hour: "2-digit", minute: "2-digit" }); await focus.startFocus(tasks.activeTaskId.value); pet.setState("focus"); } -async function onCompleteFocus() { - await focus.completeFocus(); - pet.setState("happy"); +function handleSendMessage(text: string) { + chat.chatInput.value = text; + chat.sendChat(); + pet.setState("thinking"); +} + +function toggleTts() { + settings.ttsEnabled.value = !settings.ttsEnabled.value; +} + +function toggleImmersive() { + settings.immersiveMode.value = !settings.immersiveMode.value; } @@ -237,7 +284,7 @@ async function onCompleteFocus() {
- +
@@ -245,48 +292,82 @@ async function onCompleteFocus() { -
-
- - - - - - - + +
+ + + + + + + + + + + + +
+ + + - + + + + + + + + - +
+
+ +
+ + +
+ +
diff --git a/apps/desktop/src/components/panel/BottomBar.vue b/apps/desktop/src/components/panel/BottomBar.vue new file mode 100644 index 0000000..f4ef1bd --- /dev/null +++ b/apps/desktop/src/components/panel/BottomBar.vue @@ -0,0 +1,49 @@ + + + diff --git a/apps/desktop/src/components/panel/ComponentsButton.vue b/apps/desktop/src/components/panel/ComponentsButton.vue new file mode 100644 index 0000000..ea33653 --- /dev/null +++ b/apps/desktop/src/components/panel/ComponentsButton.vue @@ -0,0 +1,8 @@ + diff --git a/apps/desktop/src/components/panel/FloatingControls.vue b/apps/desktop/src/components/panel/FloatingControls.vue new file mode 100644 index 0000000..67ea040 --- /dev/null +++ b/apps/desktop/src/components/panel/FloatingControls.vue @@ -0,0 +1,37 @@ + + + diff --git a/apps/desktop/src/components/panel/PageDots.vue b/apps/desktop/src/components/panel/PageDots.vue new file mode 100644 index 0000000..7bec16d --- /dev/null +++ b/apps/desktop/src/components/panel/PageDots.vue @@ -0,0 +1,27 @@ + + + diff --git a/apps/desktop/src/components/panel/PanelHeader.vue b/apps/desktop/src/components/panel/PanelHeader.vue index 9e98726..026165c 100644 --- a/apps/desktop/src/components/panel/PanelHeader.vue +++ b/apps/desktop/src/components/panel/PanelHeader.vue @@ -9,6 +9,7 @@ defineProps<{ defineEmits<{ hide: []; + openSettings: []; }>(); @@ -21,6 +22,17 @@ defineEmits<{

{{ currentTask?.title ?? "先选一件小事" }}

- +
+ + +
+ + diff --git a/apps/desktop/src/components/panel/TopNav.vue b/apps/desktop/src/components/panel/TopNav.vue new file mode 100644 index 0000000..4b4ef6c --- /dev/null +++ b/apps/desktop/src/components/panel/TopNav.vue @@ -0,0 +1,59 @@ + + + diff --git a/apps/desktop/src/components/panel/cards/AiChatCard.vue b/apps/desktop/src/components/panel/cards/AiChatCard.vue new file mode 100644 index 0000000..92e127c --- /dev/null +++ b/apps/desktop/src/components/panel/cards/AiChatCard.vue @@ -0,0 +1,71 @@ + + + diff --git a/apps/desktop/src/components/panel/cards/AssistantStatusCard.vue b/apps/desktop/src/components/panel/cards/AssistantStatusCard.vue new file mode 100644 index 0000000..55f10cf --- /dev/null +++ b/apps/desktop/src/components/panel/cards/AssistantStatusCard.vue @@ -0,0 +1,41 @@ + + + diff --git a/apps/desktop/src/components/panel/cards/ClawGatewayCard.vue b/apps/desktop/src/components/panel/cards/ClawGatewayCard.vue new file mode 100644 index 0000000..8508fe1 --- /dev/null +++ b/apps/desktop/src/components/panel/cards/ClawGatewayCard.vue @@ -0,0 +1,42 @@ + + + diff --git a/apps/desktop/src/components/panel/cards/CreateFocusCard.vue b/apps/desktop/src/components/panel/cards/CreateFocusCard.vue new file mode 100644 index 0000000..329547c --- /dev/null +++ b/apps/desktop/src/components/panel/cards/CreateFocusCard.vue @@ -0,0 +1,39 @@ + + + diff --git a/apps/desktop/src/components/panel/cards/DiaryCard.vue b/apps/desktop/src/components/panel/cards/DiaryCard.vue new file mode 100644 index 0000000..3eb5096 --- /dev/null +++ b/apps/desktop/src/components/panel/cards/DiaryCard.vue @@ -0,0 +1,37 @@ + + + diff --git a/apps/desktop/src/components/panel/cards/HookNotificationsCard.vue b/apps/desktop/src/components/panel/cards/HookNotificationsCard.vue new file mode 100644 index 0000000..fda9f58 --- /dev/null +++ b/apps/desktop/src/components/panel/cards/HookNotificationsCard.vue @@ -0,0 +1,38 @@ + + + diff --git a/apps/desktop/src/components/panel/cards/TodayTasksCard.vue b/apps/desktop/src/components/panel/cards/TodayTasksCard.vue new file mode 100644 index 0000000..43e182a --- /dev/null +++ b/apps/desktop/src/components/panel/cards/TodayTasksCard.vue @@ -0,0 +1,76 @@ + + + diff --git a/apps/desktop/src/components/panel/cards/WeeklyFocusCard.vue b/apps/desktop/src/components/panel/cards/WeeklyFocusCard.vue new file mode 100644 index 0000000..3bb09b1 --- /dev/null +++ b/apps/desktop/src/components/panel/cards/WeeklyFocusCard.vue @@ -0,0 +1,55 @@ + + + diff --git a/apps/desktop/src/components/settings/BlacklistEditor.vue b/apps/desktop/src/components/settings/BlacklistEditor.vue new file mode 100644 index 0000000..46dfce8 --- /dev/null +++ b/apps/desktop/src/components/settings/BlacklistEditor.vue @@ -0,0 +1,74 @@ + + + diff --git a/apps/desktop/src/components/settings/HookStatusDot.vue b/apps/desktop/src/components/settings/HookStatusDot.vue new file mode 100644 index 0000000..41dd6d1 --- /dev/null +++ b/apps/desktop/src/components/settings/HookStatusDot.vue @@ -0,0 +1,14 @@ + + + diff --git a/apps/desktop/src/components/settings/KeyBadge.vue b/apps/desktop/src/components/settings/KeyBadge.vue new file mode 100644 index 0000000..a951a08 --- /dev/null +++ b/apps/desktop/src/components/settings/KeyBadge.vue @@ -0,0 +1,9 @@ + + + diff --git a/apps/desktop/src/components/settings/ModelGrid.vue b/apps/desktop/src/components/settings/ModelGrid.vue new file mode 100644 index 0000000..b114b99 --- /dev/null +++ b/apps/desktop/src/components/settings/ModelGrid.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/apps/desktop/src/components/settings/MountModeCards.vue b/apps/desktop/src/components/settings/MountModeCards.vue new file mode 100644 index 0000000..39aa132 --- /dev/null +++ b/apps/desktop/src/components/settings/MountModeCards.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/apps/desktop/src/components/settings/SelectField.vue b/apps/desktop/src/components/settings/SelectField.vue new file mode 100644 index 0000000..2a84421 --- /dev/null +++ b/apps/desktop/src/components/settings/SelectField.vue @@ -0,0 +1,30 @@ + + + diff --git a/apps/desktop/src/components/settings/SettingRow.vue b/apps/desktop/src/components/settings/SettingRow.vue new file mode 100644 index 0000000..602ba68 --- /dev/null +++ b/apps/desktop/src/components/settings/SettingRow.vue @@ -0,0 +1,18 @@ + + + diff --git a/apps/desktop/src/components/settings/SettingsSidebar.vue b/apps/desktop/src/components/settings/SettingsSidebar.vue new file mode 100644 index 0000000..24957e3 --- /dev/null +++ b/apps/desktop/src/components/settings/SettingsSidebar.vue @@ -0,0 +1,76 @@ + + + diff --git a/apps/desktop/src/components/settings/SettingsTopbar.vue b/apps/desktop/src/components/settings/SettingsTopbar.vue new file mode 100644 index 0000000..d29ea16 --- /dev/null +++ b/apps/desktop/src/components/settings/SettingsTopbar.vue @@ -0,0 +1,24 @@ + + + diff --git a/apps/desktop/src/components/settings/TextField.vue b/apps/desktop/src/components/settings/TextField.vue new file mode 100644 index 0000000..74092e3 --- /dev/null +++ b/apps/desktop/src/components/settings/TextField.vue @@ -0,0 +1,34 @@ + + + diff --git a/apps/desktop/src/components/settings/ToggleSwitch.vue b/apps/desktop/src/components/settings/ToggleSwitch.vue new file mode 100644 index 0000000..c24dc72 --- /dev/null +++ b/apps/desktop/src/components/settings/ToggleSwitch.vue @@ -0,0 +1,25 @@ + + + diff --git a/apps/desktop/src/components/settings/sections/AssistantSection.vue b/apps/desktop/src/components/settings/sections/AssistantSection.vue new file mode 100644 index 0000000..ed36660 --- /dev/null +++ b/apps/desktop/src/components/settings/sections/AssistantSection.vue @@ -0,0 +1,84 @@ + + + diff --git a/apps/desktop/src/components/settings/sections/GeneralSection.vue b/apps/desktop/src/components/settings/sections/GeneralSection.vue new file mode 100644 index 0000000..195147b --- /dev/null +++ b/apps/desktop/src/components/settings/sections/GeneralSection.vue @@ -0,0 +1,58 @@ + + + diff --git a/apps/desktop/src/components/settings/sections/HookSection.vue b/apps/desktop/src/components/settings/sections/HookSection.vue new file mode 100644 index 0000000..d6d739a --- /dev/null +++ b/apps/desktop/src/components/settings/sections/HookSection.vue @@ -0,0 +1,90 @@ + + + diff --git a/apps/desktop/src/components/settings/sections/ModelSection.vue b/apps/desktop/src/components/settings/sections/ModelSection.vue new file mode 100644 index 0000000..19bdc10 --- /dev/null +++ b/apps/desktop/src/components/settings/sections/ModelSection.vue @@ -0,0 +1,71 @@ + + + diff --git a/apps/desktop/src/components/settings/sections/PersonaSection.vue b/apps/desktop/src/components/settings/sections/PersonaSection.vue new file mode 100644 index 0000000..f6f5f54 --- /dev/null +++ b/apps/desktop/src/components/settings/sections/PersonaSection.vue @@ -0,0 +1,77 @@ + + + diff --git a/apps/desktop/src/components/settings/sections/PrivacySection.vue b/apps/desktop/src/components/settings/sections/PrivacySection.vue new file mode 100644 index 0000000..3acbefc --- /dev/null +++ b/apps/desktop/src/components/settings/sections/PrivacySection.vue @@ -0,0 +1,75 @@ + + + diff --git a/apps/desktop/src/composables/useSettings.ts b/apps/desktop/src/composables/useSettings.ts new file mode 100644 index 0000000..a72c3c5 --- /dev/null +++ b/apps/desktop/src/composables/useSettings.ts @@ -0,0 +1,152 @@ +import { ref } from "vue"; + +/** + * Settings composable — 阶段 1 仅维护本地状态,所有改动留在内存里。 + * 阶段 2 会接 `api.getSettings()` / `api.updateSettings()`,并加 `handleWsMessage`。 + * + * 设计要点:保持与 usePetState / useFocus 一致的 "refs + functions" 形态, + * 类型在文件内定义,等阶段 2 再迁到 @neo-companion/shared。 + */ + +export type SettingsSection = + | "general" + | "assistant" + | "persona" + | "model" + | "privacy" + | "hooks"; + +export type MountMode = "tcp" | "uds" | "remote"; +export type ModelKey = "deepseek" | "claude" | "gpt-4o" | "custom"; +export type LanguageOption = "zh-CN" | "en-US" | "ja-JP"; +export type AssistantSize = "small" | "medium" | "large"; +export type AssistantTheme = "default" | "bongo-cat" | "pixel" | "import"; +export type ToneStyle = "warm" | "concise" | "humor" | "strict"; +export type NudgeFrequency = "once" | "gentle" | "persistent"; +export type TtsEngine = "edge" | "openai" | "system"; +export type CommandFrequency = string; + +export function useSettings() { + const isDark = ref(false); + const activeSection = ref("general"); + + // —— 通用设置 + const language = ref("zh-CN"); + const autoStart = ref(true); + const minimizeToTray = ref(false); + const mountMode = ref("tcp"); + + // —— 助手形象 + const assistantTheme = ref("default"); + const assistantSize = ref("medium"); + const ttsEnabled = ref(true); + const wallpaperStatusEnabled = ref(true); + const wallpaperAmbientTint = ref(true); + const immersiveMode = ref(false); + const focusAutoImmersive = ref(false); + + // —— 人设配置 + const personaLoaded = ref(true); + const toneStyle = ref("warm"); + const nudgeFrequency = ref("gentle"); + + // —— 模型配置 + const selectedModel = ref("deepseek"); + const apiKeyMasked = ref(""); + const customApiEndpoint = ref(""); + const ttsEngine = ref("edge"); + + // —— 隐私安全 + const windowDetection = ref(true); + const appEventLogging = ref(true); + const screenContentCapture = ref(false); + const blacklist = ref(["1Password", "Bitwarden", "银行类应用"]); + + // —— Hook 与连接 + const hookApiEnabled = ref(true); + const hookPort = ref("10103"); + const hookSentinelActive = ref(true); + const autoScanInject = ref(true); + const floatingApproval = ref(true); + const mqttEnabled = ref(false); + const openClawDetected = ref(false); + + function toggleTheme(): void { + isDark.value = !isDark.value; + } + + function setSection(id: SettingsSection): void { + activeSection.value = id; + } + + function selectModel(key: ModelKey): void { + selectedModel.value = key; + } + + function selectMount(mode: MountMode): void { + mountMode.value = mode; + } + + function removeBlacklistItem(name: string): void { + blacklist.value = blacklist.value.filter((item) => item !== name); + } + + function addBlacklistItem(name: string): void { + const trimmed = name.trim(); + if (!trimmed || blacklist.value.includes(trimmed)) return; + blacklist.value = [...blacklist.value, trimmed]; + } + + return { + // state + isDark, + activeSection, + language, + autoStart, + minimizeToTray, + mountMode, + assistantTheme, + assistantSize, + ttsEnabled, + wallpaperStatusEnabled, + wallpaperAmbientTint, + immersiveMode, + focusAutoImmersive, + personaLoaded, + toneStyle, + nudgeFrequency, + selectedModel, + apiKeyMasked, + customApiEndpoint, + ttsEngine, + windowDetection, + appEventLogging, + screenContentCapture, + blacklist, + hookApiEnabled, + hookPort, + hookSentinelActive, + autoScanInject, + floatingApproval, + mqttEnabled, + openClawDetected, + // actions + toggleTheme, + setSection, + selectModel, + selectMount, + removeBlacklistItem, + addBlacklistItem, + }; +} + +export type SettingsState = ReturnType; + +export const SECTION_TITLES: Record = { + general: "通用设置", + assistant: "助手形象", + persona: "人设配置", + model: "模型配置", + privacy: "隐私安全", + hooks: "Hook 与连接", +}; diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index c686b30..c316b8f 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -7,5 +7,6 @@ import "./styles/pet.css"; import "./styles/panel.css"; import "./styles/permission-bubble.css"; import "./styles/wallpaper.css"; +import "./styles/settings.css"; createApp(App).mount("#app"); diff --git a/apps/desktop/src/styles/panel.css b/apps/desktop/src/styles/panel.css index e8f94d5..0d8e62c 100644 --- a/apps/desktop/src/styles/panel.css +++ b/apps/desktop/src/styles/panel.css @@ -1,499 +1,1884 @@ +/* ═══════════════════════════════════════════════════════════════ + Panel — Full-screen Status Dashboard + Light-mode-first design with .dark-mode variant + Background images shared with settings panel + ═══════════════════════════════════════════════════════════════ */ + +/* ───── Panel Shell (Full-screen container) ───── */ .panel-shell { + --glass-bg: rgba(255, 255, 255, 0.55); + --glass-border: rgba(255, 255, 255, 0.6); + --glass-blur: 8px; + --panel-text: #1a1a1a; + --panel-muted: #6b7280; + --panel-accent: #000000; + --card-radius: 34px; + --panel-transition: all 0.4s cubic-bezier(0.22, 1, 0.36, 1); + --blue: #3b82f6; + --alert: #ff4545; + --orange: #e05e36; + --panel-card-bg: rgba(248, 252, 255, 0.72); + --panel-card-border: rgba(255, 255, 255, 0.68); + --panel-card-shadow: 0 18px 44px rgba(58, 78, 112, 0.18), 0 4px 16px rgba(58, 78, 112, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.74); + position: relative; width: 100%; - min-height: 100%; - display: grid; - place-items: center; - padding: var(--space-3); + min-height: 100dvh; + height: 100vh; + display: flex; + flex-direction: column; overflow: hidden; - background: transparent; + background-color: #000; + background-image: url("/backgrounds/settings-bg-light.png"); + background-size: cover; + background-position: center; + background-repeat: no-repeat; + font-family: "Inter", -apple-system, BlinkMacSystemFont, system-ui, sans-serif; + color: var(--panel-text); + padding: 32px 40px 22px; + transition: background-image 0.4s ease; } -.panel-shell::before { +.panel-shell.dark-mode { + --glass-bg: rgba(0, 0, 0, 0.45); + --glass-border: rgba(255, 255, 255, 0.08); + --panel-text: #fff; + --panel-muted: #b0b0b0; + --panel-accent: #fff; + --panel-card-bg: rgba(12, 16, 24, 0.68); + --panel-card-border: rgba(255, 255, 255, 0.12); + --panel-card-shadow: 0 18px 50px rgba(0, 0, 0, 0.32), 0 4px 14px rgba(0, 0, 0, 0.18), inset 0 1px 0 rgba(255, 255, 255, 0.12); + + background-image: url("/backgrounds/settings-bg-dark.png"); +} + +.panel-shell::before, +.panel-shell::after { content: ""; - position: absolute; - inset: -60px; + position: fixed; + inset: 0; + pointer-events: none; z-index: 0; +} + +.panel-shell::before { background: - radial-gradient(ellipse 70% 50% at 50% 30%, var(--glow-amber) 0%, transparent 70%), - radial-gradient(ellipse 50% 40% at 60% 70%, var(--glow-sage) 0%, transparent 60%); - filter: blur(40px); - opacity: 0.6; - animation: ambience-breathe 8s ease-in-out infinite; - pointer-events: none; + linear-gradient(180deg, rgba(104, 166, 230, 0.1) 0%, rgba(255, 255, 255, 0.02) 42%, rgba(220, 185, 108, 0.18) 100%), + radial-gradient(ellipse 80% 42% at 50% 105%, rgba(155, 132, 42, 0.24), transparent 66%); + mix-blend-mode: multiply; +} + +.panel-shell::after { + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, transparent 34%, rgba(70, 98, 36, 0.1) 100%); +} + +.panel-shell.dark-mode::before { + background: + linear-gradient(180deg, rgba(29, 55, 84, 0.18), rgba(8, 12, 22, 0.28)), + radial-gradient(ellipse 80% 42% at 50% 108%, rgba(124, 94, 36, 0.16), transparent 68%); + mix-blend-mode: normal; +} + +.panel-shell.dark-mode::after { + background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), transparent 36%, rgba(0, 0, 0, 0.16)); } -.work-panel { +.panel-shell > :not(svg) { position: relative; z-index: 1; - width: min(520px, calc(100vw - 24px)); - height: min(720px, calc(100vh - 24px)); - min-height: 600px; - display: grid; - grid-template-rows: auto auto minmax(0, 1fr) auto; - gap: var(--space-4); - padding: var(--space-5); - overflow: hidden; - border: 1px solid var(--line-strong); - border-radius: var(--radius-l); - background: - linear-gradient(165deg, rgba(36, 32, 27, 0.88), rgba(28, 24, 20, 0.82)), - radial-gradient(ellipse at 25% 15%, var(--ochre-light), transparent 45%), - radial-gradient(ellipse at 75% 85%, var(--sage-light), transparent 40%); - backdrop-filter: blur(24px) saturate(1.15); - -webkit-backdrop-filter: blur(24px) saturate(1.15); +} + +.panel-shell *, +.panel-shell *::before, +.panel-shell *::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +.panel-shell button { + font: inherit; + cursor: pointer; + border: none; + background: none; + color: inherit; +} + +.panel-shell button.primary { + min-height: 40px; + padding: 0 18px; + border-radius: 999px; + background: var(--blue); + color: #fff; + font-weight: 600; + box-shadow: 0 8px 20px rgba(59, 130, 246, 0.22); +} + +.panel-shell button.primary:disabled { + cursor: not-allowed; + opacity: 0.55; +} + +.panel-shell svg { + display: block; +} + +.panel-shell img { + display: block; +} + +.panel-shell :focus-visible { + outline: 2px solid var(--blue); + outline-offset: 2px; +} + +/* ───── Glass base class ───── */ +.panel-shell .glass { + position: relative; + background: var(--glass-bg); + backdrop-filter: blur(var(--glass-blur)) saturate(1.8); + -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.8); + border-radius: var(--card-radius); box-shadow: - var(--shadow-3), - inset 0 1px 0 var(--glass-highlight); + 0 4px 24px rgba(0, 0, 0, 0.06), + 0 1px 4px rgba(0, 0, 0, 0.04), + inset 0 1px 0 rgba(255, 255, 255, 0.5); } -.panel-header { - display: flex; +.panel-shell .glass::after { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; + pointer-events: none; + filter: url(#panel-noise-filter); + opacity: 0.06; + mix-blend-mode: overlay; +} + +/* ═══════════════════════════════════════════════════════════════ + TOP NAVIGATION + ═══════════════════════════════════════════════════════════════ */ +.panel-topnav { + display: grid; + grid-template-columns: auto auto minmax(0, 1fr) auto; + gap: 16px; align-items: center; - gap: var(--space-3); - user-select: none; + margin-bottom: 22px; + flex: none; +} + +.panel-topnav .icon-btn { + width: 48px; + height: 48px; + border-radius: 50%; + flex: none; + display: grid; + place-items: center; + background: var(--glass-bg); + backdrop-filter: blur(var(--glass-blur)); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); + transition: var(--panel-transition); + color: var(--panel-text); +} + +.panel-topnav .icon-btn:hover { + transform: scale(1.05); +} + +.panel-topnav .avatar { + border-radius: 50%; + object-fit: cover; } -.panel-header-left { +.panel-topnav .toggle-container { display: flex; align-items: center; - gap: var(--space-3); - min-width: 0; - flex: 1; + gap: 8px; + flex: none; + background: var(--glass-bg); + backdrop-filter: blur(var(--glass-blur)); + padding: 6px; + border-radius: 100px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); } -.mini-pet-avatar { +.panel-topnav .mode-switch { + width: 88px; + height: 48px; + border-radius: 100px; position: relative; - width: 40px; - height: 40px; - flex: 0 0 auto; - border-radius: 50%; - border: 2px solid var(--sage); - background: var(--sage-light); + flex: none; + background: #fff; + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); overflow: hidden; - transition: border-color var(--duration-normal) var(--ease-smooth); } -.mini-pet-avatar img { - width: 100%; - height: 100%; - object-fit: cover; +.panel-topnav .mode-track { + position: absolute; + top: 4px; + left: 8px; + width: 76px; + height: 40px; + border-radius: 100px; + background: var(--blue); } -.mini-pet-avatar[data-state="focus"] { - border-color: var(--sage-dark); +.panel-topnav .mode-handle { + position: absolute; + top: 8px; + right: 8px; + width: 32px; + height: 32px; + border-radius: 50%; + background: #fff; + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25); + transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1); + z-index: 2; } -.mini-pet-avatar[data-state="happy"] { - border-color: var(--ochre); +.panel-topnav .mode-icon { + position: absolute; + top: 14px; + left: 12px; + font-size: 16px; + color: #fff; + transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1); + z-index: 1; } -.mini-pet-avatar[data-state="warn"] { - border-color: var(--terra); +.panel-shell.dark-mode .mode-handle { + transform: translateX(-36px); } -.mini-pet-avatar[data-state="thinking"] { - border-color: var(--sage); - animation: breathe 2s ease-in-out infinite; +.panel-shell.dark-mode .mode-icon { + transform: translateX(42px); } -.mini-pet-avatar.bounce { - animation: pet-happy-bounce 0.6s var(--ease-bounce); +.panel-topnav .nav-btn { + height: 40px; + padding: 0 18px; + border-radius: 100px; + color: var(--panel-text); + background: rgba(255, 255, 255, 0.22); + backdrop-filter: blur(var(--glass-blur)); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35); + transition: var(--panel-transition); + white-space: nowrap; + flex: none; + font-size: 0.85rem; + font-weight: 500; } -.panel-header-text { +/* Meeting alert */ +.panel-topnav .meeting-alert { + justify-self: center; + display: flex; + align-items: center; + gap: 10px; + width: min(480px, 100%); min-width: 0; + background: rgba(255, 255, 255, 0.72); + color: #1a1a1a; + backdrop-filter: blur(12px) saturate(1.5); + -webkit-backdrop-filter: blur(12px) saturate(1.5); + padding: 6px 6px 6px 14px; + border-radius: 100px; + box-shadow: + 0 4px 20px rgba(0, 0, 0, 0.08), + inset 0 1px 0 rgba(255, 255, 255, 0.65); + font-size: 0.85rem; + font-weight: 500; } -.eyebrow { - color: var(--ochre); - font-size: 12px; - font-weight: 700; - letter-spacing: 0.04em; - margin-bottom: 2px; +.panel-topnav .meeting-alert .avatar { + flex: none; } -.panel-header h1 { - max-width: 240px; +.panel-topnav .meeting-alert > span:first-of-type { + flex: 1; + min-width: 0; + white-space: nowrap; overflow: hidden; text-overflow: ellipsis; +} + +.panel-topnav .time-tag { + flex: none; + background: rgba(240, 240, 240, 0.9); + color: #6b7280; + padding: 4px 10px; + border-radius: 100px; + font-size: 0.75rem; white-space: nowrap; - font-size: var(--text-h1); - color: var(--ink); } -.tab-nav { +.panel-topnav .ring-close { + flex: none; + width: 32px; + height: 32px; + position: relative; display: grid; - grid-template-columns: repeat(3, 1fr); - gap: var(--space-2); - padding: 4px; - border: 1.5px solid var(--line); - border-radius: var(--radius-m); - background: rgba(255, 255, 255, 0.04); -} - -.tab-nav button { - min-height: 36px; - padding: 0 var(--space-3); - border: 1.5px solid transparent; - border-radius: var(--radius-s); - background: transparent; + place-items: center; + border-radius: 50%; + background: rgba(255, 255, 255, 0.72); + box-shadow: inset 0 0 0 2px rgba(229, 231, 235, 0.95); +} + +.panel-topnav .ring-close::before { + content: ""; + position: absolute; + inset: 3px; + border-radius: 50%; + border: 2px solid transparent; + border-top-color: #1a1a1a; + border-right-color: #1a1a1a; + transform: rotate(24deg); +} + +.panel-topnav .ring-close::after { + content: "\00d7"; + position: relative; + z-index: 1; + font-size: 17px; + line-height: 1; + font-weight: 400; + color: #1a1a1a; + transform: translateY(-0.5px); +} + +/* View switcher */ +/* ═══════════════════════════════════════════════════════════════ + CARD GRID + ═══════════════════════════════════════════════════════════════ */ +.panel-page-stage { + display: grid; + place-items: center; + max-width: 1320px; + width: 100%; + margin: 0 auto; + flex: 1; + min-height: 0; + padding: 0; +} + +.panel-page-stage > .card { + width: min(920px, 100%); + height: 100%; + min-height: 0; + max-height: 100%; + padding: 36px 32px; +} + +.panel-page-stage > .card-create { + min-height: 360px; +} + +/* ═══════════════════════════════════════════════════════════════ + CARD BASE + ═══════════════════════════════════════════════════════════════ */ +.card { + position: relative; + padding: 28px 20px; + display: flex; + flex-direction: column; + border-radius: var(--card-radius); + transition: var(--panel-transition); + overflow: hidden; + color: #1a1a1a; + background: var(--panel-card-bg); + border: 1px solid var(--panel-card-border); + backdrop-filter: blur(18px) saturate(1.55); + -webkit-backdrop-filter: blur(18px) saturate(1.55); + box-shadow: var(--panel-card-shadow); +} + +.card::after { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; + pointer-events: none; + filter: url(#panel-noise-filter); + opacity: 0.045; + mix-blend-mode: overlay; +} + +.card > * { + position: relative; + z-index: 1; +} + +.panel-page-stage .card-title { + font-size: 1.8rem; font-weight: 500; - font-size: var(--text-caption); - color: var(--muted); - transition: - all var(--duration-fast) var(--ease-smooth); + line-height: 1.08; } -.tab-nav button:hover:not(.active):not(:disabled) { - color: var(--ink); - background: rgba(255, 255, 255, 0.06); - border-color: transparent; - box-shadow: none; - transform: none; +.panel-page-stage .card-sub { + font-size: 0.92rem; + margin-top: 8px; } -.tab-nav button.active { - background: rgba(255, 255, 255, 0.09); - color: var(--sage); - border-color: var(--line-strong); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); +.panel-page-stage .card-foot { + flex: none; } -.drawer-panel { +.panel-page-stage .nc-tasks, +.panel-page-stage .nc-hooks, +.panel-page-stage .nc-diary-snippet, +.panel-page-stage .nc-chat-scroll { + flex: 1; min-height: 0; overflow: auto; - animation: slide-up var(--duration-fast) var(--ease-smooth); + padding-right: 4px; + scrollbar-width: thin; } -.panel-line { - display: flex; - align-items: center; - justify-content: space-between; - gap: var(--space-3); +.panel-page-stage .nc-task { + min-height: 44px; + font-size: 0.95rem; + padding: 8px 0; +} + +.panel-page-stage .nc-task .label, +.panel-page-stage .nc-hook .msg { + white-space: normal; + overflow: visible; + text-overflow: clip; +} + +.panel-page-stage .nc-hook { + min-height: 48px; + font-size: 0.9rem; } -.count { - color: var(--muted); - font-size: var(--text-caption); +.panel-page-stage .nc-chat { + overflow: hidden; } -.focus-panel { +.panel-page-stage .nc-chat-scroll { display: grid; align-content: start; - gap: var(--space-3); + gap: 12px; } -.timer-ring-container { - display: grid; - place-items: center; - padding: var(--space-5) 0; +.panel-page-stage .nc-chat .row { + font-size: 0.95rem; } -.timer-ring { - position: relative; - width: 180px; - height: 180px; +.panel-page-stage .nc-chat .msg { + display: block; + overflow: visible; + -webkit-line-clamp: unset; } -.timer-ring svg { - width: 100%; - height: 100%; - transform: rotate(-90deg); +.panel-page-stage .nc-chat .msg.streaming { + -webkit-line-clamp: unset; } -.timer-ring-track { - fill: none; - stroke: var(--line); - stroke-width: 6; +.panel-page-stage .nc-chat .input { + flex: none; } -.timer-ring-progress { - fill: none; - stroke: var(--sage); - stroke-width: 6; - stroke-linecap: round; - transition: stroke-dashoffset var(--duration-normal) var(--ease-smooth); +.panel-page-stage .nc-diary-snippet { + max-height: none; + font-size: 0.95rem; + line-height: 1.7; } -.timer-ring-progress.complete { - stroke: var(--ochre); - filter: drop-shadow(0 0 6px rgba(212, 168, 75, 0.45)); +.card:hover { + transform: translateY(-2px) scale(1.006); + box-shadow: + 0 22px 56px rgba(58, 78, 112, 0.2), + 0 8px 24px rgba(58, 78, 112, 0.1), + inset 0 1px 0 rgba(255, 255, 255, 0.82); } -.timer-text { - position: absolute; - inset: 0; - display: grid; - place-items: center; - font-size: var(--text-timer); - font-weight: 760; - font-variant-numeric: tabular-nums; - color: var(--ink); - letter-spacing: -0.02em; +/* Dark mode card base */ +.panel-shell.dark-mode .card { + color: #fff; + background: var(--panel-card-bg); + border-color: var(--panel-card-border); + box-shadow: var(--panel-card-shadow); } -.timer-ring-progress.complete + .timer-text, -.timer-ring:has(.timer-ring-progress.complete) .timer-text { - text-shadow: 0 0 16px rgba(212, 168, 75, 0.35); +.panel-shell.dark-mode .card:hover { + box-shadow: + 0 24px 64px rgba(0, 0, 0, 0.4), + 0 8px 24px rgba(0, 0, 0, 0.22), + inset 0 1px 0 rgba(255, 255, 255, 0.16); } -.focus-config { - display: flex; - align-items: center; - gap: var(--space-3); - color: var(--muted); - font-size: var(--text-caption); +/* ───── Card variants ───── */ +.card-solid { + background: var(--panel-card-bg); + color: #1a1a1a; } -.focus-config select { - min-height: 32px; - padding: 0 28px 0 var(--space-3); - font-size: var(--text-caption); - border-radius: var(--radius-s); +.panel-shell.dark-mode .card-solid { + background: var(--panel-card-bg); + color: #fff; } -.focus-hint { - color: var(--muted); - font-size: var(--text-caption); - line-height: 1.55; - text-wrap: pretty; +.card-grad { + background: var(--panel-card-bg); + color: #1a1a1a; } -.focus-actions { - display: flex; - gap: var(--space-2); +.card-grad .chip { + background: rgba(255, 255, 255, 0.82); } -.task-panel { - display: grid; - align-content: start; - gap: var(--space-3); +.card-grad .card-foot > span:first-child { + color: var(--panel-muted) !important; } -.task-panel-title { - display: flex; - align-items: baseline; - gap: var(--space-2); +.panel-shell.dark-mode .card-grad { + background: var(--panel-card-bg); + color: #fff; } -.task-panel-title h2 { - font-size: var(--text-h2); +.panel-shell.dark-mode .card-grad .card-foot > span:first-child { + color: rgba(255, 255, 255, 0.62) !important; } -.task-form { - display: flex; - gap: var(--space-2); +.card-glass-dark { + color: #1a1a1a; + background: var(--panel-card-bg); } -.task-form input { - min-width: 0; - flex: 1; +.panel-shell.dark-mode .card-glass-dark { + background: var(--panel-card-bg); + color: #fff; } -.task-list { - display: grid; - gap: var(--space-2); - max-height: 360px; - overflow: auto; - padding-right: 2px; - background-image: repeating-linear-gradient( - transparent, - transparent 43px, - var(--line) 43px, - var(--line) 44px - ); +.card-glass-dark .card-sub { + color: var(--panel-muted); } -.task-item { - display: grid; - grid-template-columns: 22px minmax(0, 1fr) auto; - align-items: center; - gap: var(--space-3); - min-height: 44px; - padding: var(--space-2) var(--space-3); - border: 1.5px solid var(--line); - border-radius: var(--radius-s); - background: rgba(255, 255, 255, 0.04); - transition: - background var(--duration-fast) var(--ease-smooth), - border-color var(--duration-fast) var(--ease-smooth), - opacity var(--duration-normal) var(--ease-smooth); +.card-glass-dark .nc-mood .quote { + color: var(--panel-text); + text-shadow: none; } -.task-item:hover { - background: rgba(255, 255, 255, 0.07); - border-color: var(--line-strong); +.panel-shell.dark-mode .card-glass-dark .card-sub { + color: rgba(255, 255, 255, 0.66); } -.task-item.active { - border-color: var(--sage); - background: var(--sage-light); +.panel-shell.dark-mode .card-glass-dark .nc-mood .quote { + color: #fff; + text-shadow: 0 1px 8px rgba(0, 0, 0, 0.22); } -.task-item.done { - opacity: 0.45; +.card-glass-dark .nc-pill { + background: rgba(255, 255, 255, 0.24); + color: var(--panel-text); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22); } -.task-item.done .task-title { - text-decoration: line-through; - color: var(--muted); +.panel-shell.dark-mode .card-glass-dark .nc-pill { + background: rgba(255, 255, 255, 0.14); + color: rgba(255, 255, 255, 0.86); } -.task-radio { - appearance: none; - width: 18px; - height: 18px; - border: 2px solid var(--line-strong); - border-radius: 50%; - background: var(--paper); - cursor: pointer; - transition: all var(--duration-fast) var(--ease-smooth); +.card-glass-dark .nc-pill.on { + background: var(--blue); + color: #fff; } -.task-radio:checked { - border-color: var(--sage); - background: var(--sage); - box-shadow: inset 0 0 0 3px var(--paper); +/* nc-wrap-glass variant */ +.nc-wrap-glass { + color: #1a1a1a; + background: var(--panel-card-bg); } -.task-title { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - font-size: var(--text-body); - color: var(--ink); +.panel-shell.dark-mode .nc-wrap-glass { + color: #fff; + background: var(--panel-card-bg); } -.task-toggle { - min-height: 28px; - padding: 0 var(--space-2); - border: none; - border-radius: var(--radius-s); - background: transparent; - color: var(--muted); - font-size: 12px; - cursor: pointer; - transition: color var(--duration-fast) var(--ease-smooth); +.nc-wrap-glass .card-sub { + color: var(--panel-muted); } -.task-toggle:hover:not(:disabled) { - color: var(--sage); - background: var(--sage-light); - box-shadow: none; - transform: none; +.nc-wrap-glass .nc-mood .quote { + color: var(--panel-text); + text-shadow: none; } -.chat-panel { - display: grid; - grid-template-rows: auto minmax(0, 1fr) auto; - gap: var(--space-3); +.nc-wrap-glass .nc-pill { + background: rgba(255, 255, 255, 0.24); + color: var(--panel-text); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22); } -.chat-answer { - padding: var(--space-4); - overflow: auto; - border: 1.5px solid var(--line); - border-radius: var(--radius-m); - background: rgba(255, 255, 255, 0.04); - color: var(--ink); - line-height: 1.7; - white-space: pre-wrap; - text-wrap: pretty; - font-size: var(--text-body); +.nc-wrap-glass .nc-pill.on { + background: var(--blue); + color: #fff; } -.chat-answer.empty { - display: grid; - place-items: center; - color: var(--muted); - font-size: var(--text-caption); - text-align: center; - min-height: 120px; +.nc-wrap-glass .nc-hook { + background: rgba(255, 255, 255, 0.24); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.24); } -.chat-answer code { - font-family: var(--font-mono); - font-size: 13px; - background: rgba(125, 168, 130, 0.12); - color: #b8d4bb; - padding: 2px 6px; - border-radius: 4px; +.nc-wrap-glass .nc-hook .src { + opacity: 0.68; +} + +.nc-wrap-glass .nc-hook .msg { + color: var(--panel-text); + opacity: 0.82; +} + +.panel-shell.dark-mode .nc-wrap-glass .nc-hook .msg { + color: var(--panel-text); + opacity: 0.86; } -.chat-form { +/* Create card */ +.panel-shell .card-create { + align-items: center; + justify-content: center; + gap: 12px; + color: #fff; + background: rgba(22, 27, 38, 0.72); + border-color: rgba(255, 255, 255, 0.18); + text-shadow: 0 1px 12px rgba(0, 0, 0, 0.28); +} + +.panel-shell.dark-mode .card-create { + background: rgba(12, 16, 24, 0.72); +} + +/* ───── Card layout helpers ───── */ +.card-head { display: flex; - gap: var(--space-2); + justify-content: space-between; + align-items: flex-start; } -.chat-form input { - min-width: 0; - flex: 1; +.card-title { + font-size: 1.35rem; + font-weight: 400; + letter-spacing: -0.03em; + line-height: 1.15; } -.status-bar { +.card-sub { + font-size: 0.8rem; + color: var(--panel-muted); + margin-top: 4px; +} + +.card-solid .card-sub { + color: #6b7280; +} + +.panel-shell.dark-mode .card-solid .card-sub { + color: rgba(255, 255, 255, 0.66); +} + +.card-foot { + margin-top: auto; display: flex; align-items: center; - justify-content: space-between; - gap: var(--space-3); - padding-top: var(--space-3); - border-top: 1px solid var(--line); - color: var(--muted); - font-size: 12px; + gap: 8px; + padding-top: 20px; +} + +.panel-shell .badge { + width: 38px; + height: 38px; + border-radius: 50%; + display: grid; + place-items: center; + background: rgba(0, 0, 0, 0.08); + font-size: 0.85rem; + font-weight: 600; + margin-left: auto; +} + +.panel-shell .card-glass-dark .badge { + background: rgba(255, 255, 255, 0.16); + color: #fff; +} + +.panel-shell .glass-panel { + width: min(1320px, 100%); + margin: 0 auto; + flex: 1; + min-height: 0; + padding: 28px; + border-radius: var(--card-radius); + background: + linear-gradient(135deg, rgba(248, 252, 255, 0.72), rgba(242, 247, 255, 0.52)); + border: 1px solid rgba(255, 255, 255, 0.7); + backdrop-filter: blur(18px) saturate(1.55); + -webkit-backdrop-filter: blur(18px) saturate(1.55); + box-shadow: var(--panel-card-shadow); +} + +.panel-shell.dark-mode .glass-panel { + background: + linear-gradient(135deg, rgba(18, 24, 38, 0.62), rgba(8, 12, 22, 0.46)); + border-color: rgba(255, 255, 255, 0.12); +} + +.panel-task-board { + display: grid; + grid-template-rows: auto auto minmax(0, 1fr); + gap: 18px; } -.status-bar-section { +.panel-task-board-head { display: flex; align-items: center; - gap: var(--space-2); - min-width: 0; + justify-content: space-between; + gap: 18px; } -.status-bar-text { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; +.panel-task-board-head h2 { + color: var(--panel-text); + font-size: 1.55rem; + font-weight: 600; + letter-spacing: -0.02em; + line-height: 1.15; } -.panel-error { - position: fixed; - left: var(--space-5); - right: var(--space-5); - bottom: var(--space-5); - z-index: 10; - margin: 0; - padding: var(--space-3) var(--space-4); - border: 1.5px solid rgba(201, 123, 107, 0.35); - border-radius: var(--radius-m); - background: rgba(44, 28, 24, 0.92); - color: #e8a89a; - font-size: var(--text-caption); - line-height: 1.5; - box-shadow: var(--shadow-2); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - animation: error-slide-in var(--duration-normal) var(--ease-smooth); +.panel-task-board-head p { + margin-top: 4px; + color: var(--panel-muted); + font-size: 0.88rem; } -@media (max-width: 760px) { - .panel-shell { - padding: var(--space-2); - } +.panel-task-form { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 10px; + max-width: 640px; +} - .work-panel { - width: calc(100vw - 16px); - height: auto; - min-height: calc(100vh - 16px); - } +.panel-task-form input, +.nc-task-add input, +.nc-chat .input input { + min-height: 38px; + border: 1px solid rgba(255, 255, 255, 0.58); + background: rgba(255, 255, 255, 0.46); + color: var(--panel-text); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.36); } -@media (prefers-reduced-motion: reduce) { - .panel-shell::before { - animation: none; - opacity: 0.6; +.panel-shell.dark-mode .panel-task-form input, +.panel-shell.dark-mode .nc-task-add input, +.panel-shell.dark-mode .nc-chat .input input { + border-color: rgba(255, 255, 255, 0.12); + background: rgba(255, 255, 255, 0.07); +} + +.chat-input-native { + flex: 1; + border: none; + background: transparent; + outline: none; + font: inherit; + font-size: 0.78rem; + color: inherit; +} + +.panel-task-list { + display: grid; + align-content: start; + gap: 10px; + overflow: auto; + padding-right: 4px; +} + +.panel-task-row { + display: grid; + grid-template-columns: 18px minmax(0, 1fr) auto; + align-items: center; + gap: 12px; + min-height: 50px; + padding: 10px 14px; + border-radius: 18px; + background: rgba(255, 255, 255, 0.38); + border: 1px solid rgba(255, 255, 255, 0.46); + transition: var(--panel-transition); +} + +.panel-task-row.active { + background: rgba(59, 130, 246, 0.13); + border-color: rgba(59, 130, 246, 0.28); +} + +.panel-task-row.done { + opacity: 0.62; +} + +.panel-task-title { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.panel-task-row.done .panel-task-title { + text-decoration: line-through; +} + +.panel-task-empty { + display: grid; + place-items: center; + align-content: center; + gap: 8px; + min-height: 220px; + color: var(--panel-muted); + text-align: center; +} + +.panel-task-empty strong { + color: var(--panel-text); + font-size: 1.1rem; +} + +/* ═══════════════════════════════════════════════════════════════ + MICRO-MODULES + ═══════════════════════════════════════════════════════════════ */ + +/* ───── Tasks ───── */ +.nc-tasks { + display: flex; + flex-direction: column; + gap: 6px; + margin-top: 14px; + flex: 1; + min-height: 0; +} + +.nc-task { + display: flex; + align-items: center; + gap: 10px; + font-size: 0.85rem; +} + +.nc-task .dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: #cbd5e1; + flex: none; +} + +.nc-task.run .dot { + background: var(--blue); + box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.18); +} + +.nc-task.done .dot { + background: #94a3b8; +} + +.nc-task.done .label { + color: var(--panel-muted); + text-decoration: line-through; +} + +.nc-task .label { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.nc-task .meta { + font-variant-numeric: tabular-nums; + font-size: 0.72rem; + color: var(--panel-muted); + flex: none; +} + +.panel-shell .task-mini-action { + min-height: 26px; + padding: 0 10px; + border-radius: 999px; + background: rgba(255, 255, 255, 0.48); + color: var(--panel-muted); + font-size: 0.7rem; + flex: none; +} + +.panel-shell .task-mini-action:hover { + color: var(--blue); + background: rgba(59, 130, 246, 0.1); + transform: none; +} + +.nc-empty-state { + flex: 1; + min-height: 0; + display: grid; + place-items: center; + align-content: center; + gap: 6px; + color: var(--panel-muted); + text-align: center; +} + +.nc-empty-state span { + color: var(--panel-text); + font-weight: 600; +} + +.nc-empty-state small { + max-width: 220px; + line-height: 1.45; +} + +.nc-task-add { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 8px; + margin-top: 12px; +} + +.nc-task-add input { + min-width: 0; + font-size: 0.78rem; +} + +.panel-shell .nc-task-add button, +.panel-shell .panel-task-form button, +.panel-shell .panel-task-row button { + min-height: 38px; + padding: 0 12px; + border-radius: 999px; + background: var(--blue); + color: #fff; + font-size: 0.78rem; +} + +/* ───── Claw steps ───── */ +.nc-claw { + display: flex; + flex-direction: column; + gap: 10px; + margin-top: 18px; + flex: 1; + min-height: 0; +} + +.nc-claw-step { + display: flex; + align-items: center; + gap: 8px; + font-size: 0.78rem; + opacity: 0.55; +} + +.nc-claw-step.active { + opacity: 1; +} + +.nc-claw-step.done { + opacity: 0.85; +} + +.nc-claw-step .pin { + width: 6px; + height: 6px; + border-radius: 50%; + background: rgba(15, 23, 42, 0.28); +} + +.nc-claw-step.active .pin { + background: var(--blue); + box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.22); +} + +.nc-claw-step.done .pin { + background: rgba(15, 23, 42, 0.56); +} + +.nc-claw .progress { + height: 3px; + border-radius: 2px; + background: rgba(15, 23, 42, 0.12); + overflow: hidden; +} + +.nc-claw .progress > i { + display: block; + height: 100%; + width: 62%; + background: var(--blue); + border-radius: 2px; +} + +.panel-shell.dark-mode .nc-claw-step .pin { + background: rgba(255, 255, 255, 0.35); +} + +.panel-shell.dark-mode .nc-claw-step.done .pin { + background: rgba(255, 255, 255, 0.7); +} + +.panel-shell.dark-mode .nc-claw .progress { + background: rgba(255, 255, 255, 0.12); +} + +/* ───── Mood & State pills ───── */ +.nc-mood { + display: flex; + align-items: center; + gap: 14px; + margin-top: 18px; +} + +.nc-mood .orb { + width: 56px; + height: 56px; + border-radius: 50%; + flex: none; + background: radial-gradient(circle at 30% 30%, #ffd6a3, #ffb347 55%, #d97706 100%); + box-shadow: + 0 8px 22px rgba(255, 153, 51, 0.35), + inset 0 1px 0 rgba(255, 255, 255, 0.6); +} + +.card-glass-dark .nc-mood .orb { + box-shadow: + 0 8px 24px rgba(255, 153, 51, 0.28), + inset 0 1px 0 rgba(255, 255, 255, 0.72), + 0 0 0 1px rgba(255, 255, 255, 0.24); +} + +.nc-mood .quote { + font-size: 0.92rem; + line-height: 1.45; + color: #1a1a1a; +} + +.panel-shell.dark-mode .nc-mood .quote { + color: #fff; +} + +.nc-mood .quote em { + font-style: normal; + color: var(--blue); + font-weight: 500; +} + +.nc-state-row { + display: flex; + gap: 6px; + margin-top: 14px; + flex-wrap: wrap; +} + +.nc-pill { + font-size: 0.7rem; + padding: 4px 10px; + border-radius: 100px; + background: rgba(0, 0, 0, 0.06); + color: #1a1a1a; +} + +.panel-shell.dark-mode .nc-pill { + background: rgba(255, 255, 255, 0.1); + color: #fff; +} + +.nc-pill.on { + background: var(--blue); + color: #fff; +} + +/* Status card overrides */ +.nc-status-card .nc-mood { + align-items: stretch; + gap: 12px; + margin-top: 14px; + padding: 12px; + border-radius: 24px; + background: rgba(255, 255, 255, 0.22); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.26); +} + +.nc-status-card .nc-mood .orb { + width: 48px; + height: 48px; + align-self: center; +} + +.nc-status-card .nc-mood .quote { + flex: 1; + min-width: 0; + font-size: 0.82rem; + line-height: 1.5; + text-wrap: pretty; + display: flex; + align-items: center; +} + +.nc-status-card .nc-state-row { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 8px; + margin-top: auto; + padding-top: 12px; +} + +.nc-status-card .nc-pill { + min-width: 0; + text-align: center; + padding: 6px 8px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + background: rgba(255, 255, 255, 0.24); +} + +.panel-shell.dark-mode .nc-status-card .nc-mood { + background: rgba(255, 255, 255, 0.08); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12); +} + +.panel-shell.dark-mode .nc-status-card .nc-pill { + background: rgba(255, 255, 255, 0.1); +} + +/* ───── Hooks ───── */ +.nc-hooks { + display: flex; + flex-direction: column; + gap: 8px; + margin-top: 14px; + flex: 1; + min-height: 0; +} + +.nc-hook { + display: flex; + align-items: center; + gap: 10px; + font-size: 0.78rem; + padding: 8px 10px; + border-radius: 14px; + background: rgba(255, 255, 255, 0.16); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18); +} + +.nc-hook .src { + font-family: ui-monospace, Menlo, monospace; + font-size: 0.68rem; + opacity: 0.72; + flex: none; +} + +.nc-hook .msg { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.nc-hook .pend { + background: var(--alert); + color: #fff; + font-size: 0.6rem; + padding: 2px 7px; + border-radius: 100px; + flex: none; +} + +.nc-hook .ok { + color: var(--blue); + font-size: 0.7rem; + flex: none; +} + +/* ───── Chat ───── */ +.nc-chat { + display: flex; + flex-direction: column; + gap: 8px; + margin-top: 14px; + flex: 1; + min-height: 0; +} + +.nc-chat .row { + display: flex; + gap: 8px; + align-items: flex-start; + font-size: 0.8rem; + line-height: 1.45; +} + +.nc-chat .who { + font-weight: 500; + color: var(--blue); + flex: none; + min-width: 46px; +} + +.nc-chat .msg { + color: #1a1a1a; + opacity: 0.78; + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + white-space: normal; +} + +.panel-shell.dark-mode .nc-chat .msg { + color: #fff; + opacity: 0.75; +} + +.nc-chat .msg.streaming { + opacity: 0.88; + -webkit-line-clamp: 6; +} + +.nc-chat-empty { + display: grid; + gap: 8px; +} + +.nc-chat-empty small { + color: var(--panel-muted); + font-size: 0.68rem; +} + +.nc-chat .input { + margin-top: auto; + display: flex; + gap: 8px; + align-items: center; + padding: 8px 10px 8px 14px; + background: rgba(0, 0, 0, 0.04); + border-radius: 100px; + font-size: 0.78rem; + color: var(--panel-muted); +} + +.panel-shell.dark-mode .nc-chat .input { + background: rgba(255, 255, 255, 0.06); +} + +.nc-chat .input .send { + width: 28px; + height: 28px; + border-radius: 50%; + background: var(--blue); + color: #fff; + display: grid; + place-items: center; + flex: none; +} + +/* ───── Diary ───── */ +.nc-diary { + padding: 6px 0 0; + flex: 1; + display: flex; + flex-direction: column; + gap: 10px; + min-height: 0; +} + +.nc-diary-snippet { + font-size: 0.8rem; + line-height: 1.55; + color: #1a1a1a; + opacity: 0.78; + max-height: 7.7em; + overflow: hidden; +} + +.panel-shell.dark-mode .nc-diary-snippet { + color: #e8e8e8; +} + +.nc-diary-meta { + display: flex; + gap: 8px; + font-size: 0.68rem; + color: var(--panel-muted); + font-variant-numeric: tabular-nums; + letter-spacing: 0.04em; + text-transform: uppercase; +} + +/* ───── Bar chart (weekly focus) ───── */ +.bars { + display: flex; + align-items: flex-end; + gap: 2px; + height: 60px; + margin-top: 14px; +} + +.bars span { + flex: 1; + border-radius: 2px; +} + +.markers { + display: flex; + justify-content: space-between; + padding: 0 8px; + margin: 16px 0 4px; +} + +.markers img, +.markers .mg img { + border: 1.5px solid #fff; +} + +.mg { + display: flex; +} + +.mg img + img { + margin-left: -8px; +} + +.panel-shell .play-btn { + width: 54px; + height: 54px; + border-radius: 50%; + margin-left: auto; + background: rgba(245, 245, 245, 0.85); + display: grid; + place-items: center; + color: #000; +} + +/* ───── Chips (diary card) ───── */ +.chips { + display: flex; + gap: 8px; +} + +.chip { + background: #fff; + padding: 6px 14px; + border-radius: 100px; + font-size: 0.75rem; + font-weight: 600; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); +} + +.chip.blue { + color: var(--blue); +} + +.chip.black { + color: #000; +} + +/* ═══════════════════════════════════════════════════════════════ + BOTTOM BAR & COMPANION + ═══════════════════════════════════════════════════════════════ */ +.panel-lower { + width: min(1100px, 100%); + margin: 16px auto 0; + display: grid; + grid-template-columns: 54px minmax(0, 1fr) auto; + align-items: end; + gap: 14px; + flex: none; +} + +.panel-status-stack { + display: grid; + justify-items: center; + gap: 10px; + min-width: 0; + overflow: hidden; +} + +.panel-bottom-bar { + position: static; + transform: none; + display: grid; + grid-template-columns: minmax(250px, 320px) minmax(180px, 240px); + align-items: center; + gap: 10px; + width: min(580px, 100%); + min-height: 64px; + padding: 0; + border-radius: 0; + z-index: 1; + background: transparent; + backdrop-filter: none; + -webkit-backdrop-filter: none; + box-shadow: none; +} + +.nc-companion { + display: grid; + grid-template-columns: 40px minmax(0, 1fr) 22px; + align-items: center; + gap: 12px; + min-height: 64px; + padding: 10px 16px 10px 12px; + background: rgba(255, 255, 255, 0.2); + backdrop-filter: blur(12px) saturate(1.5); + -webkit-backdrop-filter: blur(12px) saturate(1.5); + border: 1px solid rgba(255, 255, 255, 0.22); + border-radius: 28px; + color: #fff; + font-size: 0.78rem; + box-shadow: + 0 8px 28px rgba(0, 0, 0, 0.12), + inset 0 1px 0 rgba(255, 255, 255, 0.22); +} + +.nc-companion .face { + width: 40px; + height: 40px; + border-radius: 50%; + background: radial-gradient(circle at 32% 32%, #ffe0a3, #ffb347 60%, #d97706 100%); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.65); + position: relative; +} + +.nc-companion .face::before, +.nc-companion .face::after { + content: ""; + position: absolute; + top: 14px; + width: 3px; + height: 5px; + background: #3b1f0a; + border-radius: 2px; +} + +.nc-companion .face::before { + left: 12px; +} + +.nc-companion .face::after { + right: 12px; +} + +.nc-companion .text { + min-width: 0; + line-height: 1.18; +} + +.nc-companion .text b { + display: block; + font-weight: 650; + font-size: 0.9rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.nc-companion .text span { + display: block; + margin-top: 3px; + opacity: 0.72; + font-size: 0.7rem; + letter-spacing: 0.04em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +/* Voice indicator */ +.voice-ind { + position: absolute; + top: -2px; + right: -2px; + width: 18px; + height: 18px; + border-radius: 50%; + background: #fff; + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); + display: flex; + align-items: center; + justify-content: center; + gap: 1.5px; +} + +.voice-ind i { + width: 2px; + background: #4b5563; + border-radius: 2px; + animation: panel-voice-wave 1s ease-in-out infinite; +} + +.voice-ind i:nth-child(1) { + animation-delay: 0s; +} + +.voice-ind i:nth-child(2) { + animation-delay: 0.2s; +} + +.voice-ind i:nth-child(3) { + animation-delay: 0.4s; +} + +@keyframes panel-voice-wave { + 0%, + 100% { + height: 4px; + } + 50% { + height: 10px; + } +} + +.nc-companion > .voice-ind { + position: static; + width: 22px !important; + height: 22px !important; + justify-self: end; + background: rgba(255, 255, 255, 0.92) !important; +} + +/* Context stack */ +.nc-ctx-stack { + display: grid; + gap: 8px; + min-width: 0; +} + +.nc-ctx { + display: grid; + grid-template-columns: 28px minmax(0, 1fr); + align-items: center; + gap: 10px; + min-height: 34px; + padding: 6px 12px; + border-radius: 18px; + background: rgba(255, 255, 255, 0.14); + color: #fff; + font-size: 0.75rem; + border: 1px solid rgba(255, 255, 255, 0.14); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12); +} + +.nc-ctx .ico { + width: 28px; + height: 28px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.18); + display: grid; + place-items: center; +} + +.nc-ctx-label { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* Speaker wrap (voice indicator positioning) */ +.speaker-wrap { + position: relative; +} + +/* ═══════════════════════════════════════════════════════════════ + PAGE DOTS + ═══════════════════════════════════════════════════════════════ */ +.page-dots { + display: flex; + justify-content: flex-start; + gap: 8px; + width: min(720px, 100%); + max-width: 100%; + margin: 0; + padding: 6px; + overflow-x: auto; + overscroll-behavior-x: contain; + scroll-snap-type: x proximity; + border-radius: 999px; + background: rgba(255, 255, 255, 0.28); + border: 1px solid rgba(255, 255, 255, 0.28); + backdrop-filter: blur(14px) saturate(1.4); + -webkit-backdrop-filter: blur(14px) saturate(1.4); + box-shadow: + 0 8px 28px rgba(58, 78, 112, 0.12), + inset 0 1px 0 rgba(255, 255, 255, 0.38); + scrollbar-width: none; +} + +.page-dots::-webkit-scrollbar { + display: none; +} + +.page-dots button { + flex: 0 0 auto; + min-width: 82px; + height: 34px; + padding: 0 16px; + border-radius: 999px; + color: rgba(15, 23, 42, 0.72); + background: transparent; + font-size: 0.78rem; + font-weight: 600; + white-space: nowrap; + scroll-snap-align: center; + transition: var(--panel-transition); +} + +.page-dots button:hover { + color: var(--panel-text); + background: rgba(255, 255, 255, 0.34); +} + +.page-dots button.active { + color: #fff; + background: var(--blue); + box-shadow: 0 8px 18px rgba(59, 130, 246, 0.22); +} + +.panel-shell.dark-mode .page-dots { + background: rgba(8, 12, 22, 0.38); + border-color: rgba(255, 255, 255, 0.16); + box-shadow: 0 12px 32px rgba(0, 0, 0, 0.28); +} + +.panel-shell.dark-mode .page-dots button { + color: rgba(255, 255, 255, 0.68); +} + +.panel-shell.dark-mode .page-dots button:hover { + color: #fff; + background: rgba(255, 255, 255, 0.1); +} + +.panel-shell.dark-mode .page-dots button.active { + color: #fff; +} + +/* ═══════════════════════════════════════════════════════════════ + FLOATING CONTROLS + ═══════════════════════════════════════════════════════════════ */ +.panel-float-controls { + position: static; + display: flex; + gap: 12px; + background: rgba(0, 0, 0, 0.04); + backdrop-filter: blur(var(--glass-blur)); + padding: 10px 14px; + border-radius: 100px; + z-index: 1; + justify-self: end; +} + +.panel-shell .ctrl-btn { + width: 44px; + height: 44px; + border-radius: 50%; + display: grid; + place-items: center; + background: rgba(255, 255, 255, 0.9); + color: #1a1a1a; + transition: var(--panel-transition); +} + +.panel-shell .ctrl-btn:hover { + transform: scale(1.08); +} + +.panel-shell .ctrl-btn.off { + background: var(--alert); + color: #fff; +} + +/* ═══════════════════════════════════════════════════════════════ + COMPONENTS BUTTON + ═══════════════════════════════════════════════════════════════ */ +.panel-components-btn { + position: static; + width: 44px; + height: 44px; + border-radius: 14px; + background: rgba(0, 0, 0, 0.04); + backdrop-filter: blur(var(--glass-blur)); + display: grid; + grid-template-columns: 1fr 1fr; + gap: 3px; + padding: 7px; + z-index: 1; + align-self: end; +} + +.panel-components-btn span { + border-radius: 4px; + display: grid; + place-items: center; + font-size: 9px; + font-weight: 600; +} + +/* ═══════════════════════════════════════════════════════════════ + PLUS CHIP + ═══════════════════════════════════════════════════════════════ */ +.plus-chip { + width: 40px; + height: 40px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.25); + color: #fff; + font-weight: 700; + font-size: 0.8rem; + display: grid; + place-items: center; +} + +/* ═══════════════════════════════════════════════════════════════ + RESPONSIVE + ═══════════════════════════════════════════════════════════════ */ +@media (prefers-reduced-motion: reduce) { + .panel-shell *, + .panel-shell *::before, + .panel-shell *::after { + animation-duration: 0.001ms !important; + transition-duration: 0.001ms !important; + } +} + +@media (max-width: 1200px) { + .panel-shell { + overflow: hidden; + height: 100vh; + min-height: 100dvh; + padding: 28px 28px 18px; + } + + .panel-page-stage > .card { + width: min(860px, 100%); + padding: 32px 28px; + } + + .panel-lower { + grid-template-columns: 44px minmax(0, 1fr) auto; + align-items: center; + margin-top: 14px; + } + + .panel-bottom-bar { + grid-template-columns: minmax(240px, 320px) minmax(200px, 260px); + } + + .page-dots { + width: min(600px, 100%); + } +} + +@media (max-width: 980px) { + .panel-topnav { + grid-template-columns: auto minmax(0, 1fr) auto; + grid-template-areas: + "profile toggle search" + "alert alert alert"; + row-gap: 12px; + } + + .panel-topnav > .icon-btn:first-child { + grid-area: profile; + } + + .panel-topnav .toggle-container { + grid-area: toggle; + justify-self: start; + } + + .panel-topnav .meeting-alert { + grid-area: alert; + justify-self: start; + width: min(520px, 100%); + } + + .panel-topnav > .icon-btn:last-child { + grid-area: search; + justify-self: end; + } + + .panel-lower { + grid-template-columns: minmax(0, 1fr) auto; + align-items: end; + gap: 12px; + } + + .panel-components-btn { + display: none; + } + + .panel-status-stack { + justify-items: start; + } + + .panel-bottom-bar { + grid-template-columns: minmax(240px, 1fr); + width: min(520px, 100%); + } + + .page-dots { + width: min(520px, 100%); + } + + .nc-ctx-stack { + display: none; + } +} + +@media (max-width: 768px) { + .panel-shell { + padding: 16px; + } + + .panel-page-stage > .card { + width: 100%; + padding: 26px 22px; + } + + .panel-topnav { + grid-template-columns: auto 1fr auto; + grid-template-areas: "profile toggle search"; + } + + .panel-topnav .meeting-alert { + display: none; + } + + .panel-lower { + grid-template-columns: 1fr; + justify-items: stretch; + } + + .panel-status-stack { + justify-items: stretch; + } + + .panel-bottom-bar, + .panel-float-controls { + width: 100%; + } + + .page-dots { + width: 100%; } - .drawer-panel { - animation: none; + .panel-float-controls { + justify-content: center; + justify-self: stretch; } } diff --git a/apps/desktop/src/styles/settings.css b/apps/desktop/src/styles/settings.css new file mode 100644 index 0000000..05b69f7 --- /dev/null +++ b/apps/desktop/src/styles/settings.css @@ -0,0 +1,840 @@ +/* + * Settings Window Styles + * + * 来源:原型 D:\character_design\settings.html 的