diff --git a/package.json b/package.json index a9fed0e..f782315 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "prettier": "^3.7.4", "react": "^19.2.1", "react-dom": "^19.2.1", + "sass": "^1.102.0", "typescript": "^5.9.3", "vite": "^7.2.6" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2d61088..ff6b9e7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,6 +33,7 @@ specifiers: prettier: ^3.7.4 react: ^19.2.1 react-dom: ^19.2.1 + sass: ^1.102.0 silk-wasm: ^3.7.1 typescript: ^5.9.3 vite: ^7.2.6 @@ -71,8 +72,9 @@ devDependencies: prettier: 3.7.4 react: 19.2.1 react-dom: 19.2.1_react@19.2.1 + sass: 1.102.0 typescript: 5.9.3 - vite: 7.2.7_@types+node@22.19.2 + vite: 7.2.7_kx7yyowhop237vgn7dp2p54shq packages: @@ -930,6 +932,132 @@ packages: rimraf: 3.0.2 dev: true + /@parcel/watcher-android-arm64/2.6.0: + resolution: {integrity: sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + dev: true + optional: true + + /@parcel/watcher-darwin-arm64/2.6.0: + resolution: {integrity: sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + dev: true + optional: true + + /@parcel/watcher-darwin-x64/2.6.0: + resolution: {integrity: sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + dev: true + optional: true + + /@parcel/watcher-freebsd-x64/2.6.0: + resolution: {integrity: sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + dev: true + optional: true + + /@parcel/watcher-linux-arm-glibc/2.6.0: + resolution: {integrity: sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + dev: true + optional: true + + /@parcel/watcher-linux-arm-musl/2.6.0: + resolution: {integrity: sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [musl] + dev: true + optional: true + + /@parcel/watcher-linux-arm64-glibc/2.6.0: + resolution: {integrity: sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + dev: true + optional: true + + /@parcel/watcher-linux-arm64-musl/2.6.0: + resolution: {integrity: sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + dev: true + optional: true + + /@parcel/watcher-linux-x64-glibc/2.6.0: + resolution: {integrity: sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + dev: true + optional: true + + /@parcel/watcher-linux-x64-musl/2.6.0: + resolution: {integrity: sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + dev: true + optional: true + + /@parcel/watcher-win32-arm64/2.6.0: + resolution: {integrity: sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + dev: true + optional: true + + /@parcel/watcher-win32-x64/2.6.0: + resolution: {integrity: sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + dev: true + optional: true + + /@parcel/watcher/2.6.0: + resolution: {integrity: sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==} + engines: {node: '>= 10.0.0'} + dependencies: + detect-libc: 2.1.2 + is-glob: 4.0.3 + node-addon-api: 7.1.1 + picomatch: 4.0.5 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.6.0 + '@parcel/watcher-darwin-arm64': 2.6.0 + '@parcel/watcher-darwin-x64': 2.6.0 + '@parcel/watcher-freebsd-x64': 2.6.0 + '@parcel/watcher-linux-arm-glibc': 2.6.0 + '@parcel/watcher-linux-arm-musl': 2.6.0 + '@parcel/watcher-linux-arm64-glibc': 2.6.0 + '@parcel/watcher-linux-arm64-musl': 2.6.0 + '@parcel/watcher-linux-x64-glibc': 2.6.0 + '@parcel/watcher-linux-x64-musl': 2.6.0 + '@parcel/watcher-win32-arm64': 2.6.0 + '@parcel/watcher-win32-x64': 2.6.0 + dev: true + optional: true + /@pkgjs/parseargs/0.11.0: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -1429,7 +1557,7 @@ packages: '@rolldown/pluginutils': 1.0.0-beta.53 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 7.2.7_@types+node@22.19.2 + vite: 7.2.7_kx7yyowhop237vgn7dp2p54shq transitivePeerDependencies: - supports-color dev: true @@ -1882,6 +2010,13 @@ packages: supports-color: 7.2.0 dev: true + /chokidar/5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + dependencies: + readdirp: 5.0.0 + dev: true + /chownr/2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} @@ -2236,7 +2371,7 @@ packages: esbuild: 0.25.12 magic-string: 0.30.21 picocolors: 1.1.1 - vite: 7.2.7_@types+node@22.19.2 + vite: 7.2.7_kx7yyowhop237vgn7dp2p54shq transitivePeerDependencies: - supports-color dev: true @@ -3091,6 +3226,10 @@ packages: engines: {node: '>= 4'} dev: true + /immutable/5.1.9: + resolution: {integrity: sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==} + dev: true + /import-fresh/3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -3742,6 +3881,11 @@ packages: dev: true optional: true + /node-addon-api/7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + dev: true + optional: true + /node-api-version/0.2.1: resolution: {integrity: sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==} dependencies: @@ -3962,6 +4106,12 @@ packages: engines: {node: '>=12'} dev: true + /picomatch/4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + engines: {node: '>=12'} + dev: true + optional: true + /plist/3.1.0: resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} engines: {node: '>=10.4.0'} @@ -4093,6 +4243,11 @@ packages: util-deprecate: 1.0.2 dev: true + /readdirp/5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} + dev: true + /reflect.getprototypeof/1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -4250,6 +4405,18 @@ packages: truncate-utf8-bytes: 1.0.2 dev: true + /sass/1.102.0: + resolution: {integrity: sha512-NSOyTnaQF7rTAEOtI2fwb386vL+akyiQLBZu8Na7hXCb+umJy0GAqlcMIaqACZ6Z1VgTBS4K9PG6B3IdjHGJsw==} + engines: {node: '>=20.19.0'} + hasBin: true + dependencies: + chokidar: 5.0.0 + immutable: 5.1.9 + source-map-js: 1.2.1 + optionalDependencies: + '@parcel/watcher': 2.6.0 + dev: true + /sax/1.4.3: resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==} dev: true @@ -4784,7 +4951,7 @@ packages: dev: true optional: true - /vite/7.2.7_@types+node@22.19.2: + /vite/7.2.7_kx7yyowhop237vgn7dp2p54shq: resolution: {integrity: sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -4830,6 +4997,7 @@ packages: picomatch: 4.0.3 postcss: 8.5.6 rollup: 4.53.3 + sass: 1.102.0 tinyglobby: 0.2.15 optionalDependencies: fsevents: 2.3.3 diff --git a/src/renderer/src/assets/main.css b/src/renderer/src/assets/main.css deleted file mode 100644 index 9556804..0000000 --- a/src/renderer/src/assets/main.css +++ /dev/null @@ -1,8955 +0,0 @@ -:root { - --bg-color: #f5f5f5; - --sidebar-bg: #e7e7e7; - --sidebar-hover: #d6d6d6; - --sidebar-active: #c6c6c6; - --chat-bg: #f5f5f5; - --message-bg-user: #95ec69; - --message-bg-other: #ffffff; - --text-color: #000000; - --border-color: #dcdcdc; -} - -body { - margin: 0; - padding: 0; - font-family: var(--wxex-font); - background-color: var(--wxex-bg-app); - color: var(--wxex-text-primary); - height: 100vh; - overflow: hidden; -} - -#root { - height: 100%; - display: flex; -} - -.app-shell { - box-sizing: border-box; - display: flex; - width: 100%; - height: 100%; - min-height: 0; - min-width: 0; - overflow: hidden; - background: var(--wxex-bg-app); -} - -.app-primary-rail { - box-sizing: border-box; - width: var(--wxex-nav-width); - flex: 0 0 var(--wxex-nav-width); - height: 100%; - min-height: 0; - display: flex; - flex-direction: column; - align-items: center; - border-right: 1px solid var(--wxex-border); - background: var(--wxex-bg-sidebar); - padding: 12px 8px; - overflow: hidden; - -webkit-app-region: drag; -} - -.app-brand { - box-sizing: border-box; - width: 42px; - height: 42px; - display: grid; - place-items: center; - border: 0; - border-radius: 12px; - background: transparent; - -webkit-app-region: no-drag; -} - -.app-brand img { - display: block; - width: 42px; - height: 42px; - border-radius: 12px; -} - -.primary-navigation { - box-sizing: border-box; - display: flex; - flex: 1; - flex-direction: column; - gap: 6px; - width: 100%; - margin-top: 18px; - -webkit-app-region: no-drag; -} - -.primary-nav-item { - width: 100%; - height: 58px; - flex: 0 0 58px; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 4px; - border: 0; - border-radius: var(--wxex-radius-md); - background: transparent; - color: var(--wxex-text-secondary); - cursor: pointer; - font-family: var(--wxex-font); -} - -.primary-nav-item:hover { - background: rgba(255, 255, 255, 0.46); - color: var(--wxex-text-primary); -} - -.primary-nav-item.active { - background: var(--wxex-brand-soft); - color: var(--wxex-brand); -} - -.primary-nav-mark { - width: 24px; - height: 24px; - display: grid; - place-items: center; -} - -.primary-nav-mark svg { - width: 22px; - height: 22px; -} - -.primary-nav-mark path, -.primary-nav-mark circle { - fill: none; - stroke: currentColor; - stroke-width: 1.7; - stroke-linecap: round; - stroke-linejoin: round; -} - -.primary-nav-label { - font-size: 12px; - line-height: 16px; - font-weight: 600; - white-space: nowrap; -} - -.app-rail-account { - box-sizing: border-box; - width: 100%; - flex: 0 0 auto; - -webkit-app-region: no-drag; -} - -.account-summary { - box-sizing: border-box; - width: 100%; - display: flex; - align-items: center; - gap: 10px; - border: 0; - border-radius: var(--wxex-radius-md); - background: transparent; - color: var(--wxex-text-primary); - font-family: var(--wxex-font); - text-align: left; -} - -.account-summary:hover { - background: rgba(255, 255, 255, 0.72); -} - -.account-summary.compact { - justify-content: center; - cursor: pointer; - padding: 8px 0; -} - -.account-summary-avatar { - box-sizing: border-box; - position: relative; - width: 38px; - height: 38px; - display: grid; - place-items: center; - flex: 0 0 auto; - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); - color: var(--wxex-brand); - font-size: 14px; - font-weight: 700; - overflow: hidden; -} - -.account-summary-avatar img { - width: 100%; - height: 100%; - object-fit: cover; -} - -.account-summary-status { - position: absolute; - right: 2px; - bottom: 2px; - width: 9px; - height: 9px; - border: 2px solid var(--wxex-bg-elevated); - border-radius: 999px; - background: var(--wxex-text-muted); -} - -.account-summary-status.ready { - background: var(--wxex-success); -} - -.account-summary:not(.compact) .account-summary-avatar .account-summary-status { - display: none; -} - -.account-summary-text { - min-width: 0; - display: flex; - flex-direction: column; -} - -.account-summary-name { - overflow: hidden; - color: var(--wxex-text-primary); - font-size: 13px; - font-weight: 600; - line-height: 18px; - text-overflow: ellipsis; - white-space: nowrap; -} - -.account-summary-meta { - overflow: hidden; - color: var(--wxex-text-muted); - font-size: 12px; - line-height: 16px; - text-overflow: ellipsis; - white-space: nowrap; -} - -.account-summary-state { - overflow: hidden; - display: flex; - align-items: center; - gap: 5px; - color: var(--wxex-text-secondary); - font-size: 12px; - line-height: 16px; - text-overflow: ellipsis; - white-space: nowrap; -} - -.account-summary-state-dot { - width: 7px; - height: 7px; - flex: 0 0 auto; - border-radius: 999px; - background: var(--wxex-text-muted); -} - -.account-summary-state-dot.ready { - background: var(--wxex-success); -} - -.account-summary-settings { - box-sizing: border-box; - width: 28px; - height: 28px; - display: grid; - place-items: center; - flex: 0 0 auto; - border: 0; - border-radius: var(--wxex-radius-sm); - background: transparent; - color: var(--wxex-text-muted); - cursor: pointer; -} - -.account-summary-settings:hover { - background: var(--wxex-brand-soft); - color: var(--wxex-brand); -} - -.account-summary-settings svg { - width: 17px; - height: 17px; -} - -.account-summary-settings path { - fill: none; - stroke: currentColor; - stroke-width: 1.7; - stroke-linecap: round; - stroke-linejoin: round; -} - -.app-shell-main { - box-sizing: border-box; - flex: 1; - min-width: 0; - min-height: 0; - height: 100%; - display: flex; - align-items: stretch; - overflow: hidden; - padding-top: var(--wxex-shell-content-top); - background: var(--wxex-bg-main); -} - -.app-page-placeholder { - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 24px; - color: var(--wxex-text-secondary); - text-align: center; -} - -.app-page-placeholder-eyebrow { - margin-bottom: 8px; - color: var(--wxex-brand); - font-size: 11px; - font-weight: 700; - letter-spacing: 0; -} - -.app-page-placeholder h2 { - margin: 0 0 8px; - color: var(--wxex-text-primary); - font-size: 20px; - font-weight: 600; - line-height: 28px; -} - -.app-page-placeholder p { - margin: 0; - font-size: 13px; - line-height: 20px; -} - -.app-container { - display: flex; - width: 100%; - height: 100%; - min-height: 0; - min-width: 0; - align-items: stretch; - overflow: hidden; -} - -.conversation-sidebar { - box-sizing: border-box; - display: flex; - height: 100%; - min-height: 0; - flex: 0 0 auto; - flex-direction: column; - overflow: hidden; - border-right: 1px solid var(--wxex-border); - background: var(--wxex-bg-sidebar); - color: var(--wxex-text-primary); -} - -.conversation-sidebar-header { - box-sizing: border-box; - flex: 0 0 auto; - padding: 16px 14px 12px; - border-bottom: 1px solid var(--wxex-border); - -webkit-app-region: drag; -} - -.conversation-sidebar-title-row { - display: flex; - align-items: baseline; - justify-content: space-between; - gap: 12px; - margin-bottom: 12px; -} - -.conversation-sidebar-title-row h2 { - margin: 0; - color: var(--wxex-text-primary); - font-size: 18px; - font-weight: 700; - line-height: 24px; -} - -.conversation-sidebar-title-row span { - color: var(--wxex-text-muted); - font-size: 12px; - line-height: 18px; - white-space: nowrap; -} - -.conversation-search { - box-sizing: border-box; - display: flex; - height: 34px; - align-items: center; - gap: 8px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); - padding: 0 10px; - color: var(--wxex-text-muted); - -webkit-app-region: no-drag; -} - -.conversation-search:focus-within { - border-color: rgba(36, 122, 99, 0.58); - color: var(--wxex-brand); -} - -.conversation-search-icon { - width: 17px; - height: 17px; - display: grid; - place-items: center; - flex: 0 0 auto; -} - -.conversation-search-icon svg { - width: 17px; - height: 17px; -} - -.conversation-search-icon circle, -.conversation-search-icon path { - fill: none; - stroke: currentColor; - stroke-width: 1.8; - stroke-linecap: round; - stroke-linejoin: round; -} - -.conversation-search input { - width: 100%; - min-width: 0; - border: 0; - outline: 0; - background: transparent; - color: var(--wxex-text-primary); - font: 13px/18px var(--wxex-font); -} - -.conversation-search input::placeholder { - color: var(--wxex-text-muted); -} - -.conversation-date-range { - display: grid; - grid-template-columns: repeat(5, minmax(0, 1fr)); - gap: 6px; - margin-top: 10px; - -webkit-app-region: no-drag; -} - -.conversation-date-range-button { - box-sizing: border-box; - height: 30px; - min-width: 0; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); - color: var(--wxex-text-secondary); - cursor: pointer; - font: 12px/16px var(--wxex-font); - white-space: nowrap; -} - -.conversation-date-range-button:hover { - border-color: rgba(36, 122, 99, 0.28); - color: var(--wxex-text-primary); -} - -.conversation-date-range-button.active { - border-color: var(--wxex-brand); - background: var(--wxex-brand); - color: #ffffff; - font-weight: 600; -} - -.conversation-list { - flex: 1; - min-height: 0; - overflow: auto; - padding: 8px 8px 12px; -} - -.conversation-virtual-content { - position: relative; - width: 100%; -} - -.conversation-virtual-row { - position: absolute; - top: 0; - right: 0; - left: 0; -} - -.conversation-section + .conversation-section { - margin-top: 6px; -} - -.conversation-section-header { - box-sizing: border-box; - width: 100%; - height: 32px; - display: flex; - align-items: center; - gap: 4px; - border: 0; - border-radius: var(--wxex-radius-sm); - background: transparent; - color: var(--wxex-text-secondary); - cursor: pointer; - font: 600 12px/16px var(--wxex-font); - padding: 0 8px; - text-align: left; -} - -.conversation-section-header:hover { - background: rgba(255, 255, 255, 0.48); - color: var(--wxex-text-primary); -} - -.conversation-section-chevron { - width: 16px; - height: 16px; - display: grid; - place-items: center; - flex: 0 0 auto; -} - -.conversation-section-chevron svg { - width: 14px; - height: 14px; -} - -.conversation-section-chevron path { - fill: none; - stroke: currentColor; - stroke-width: 1.8; - stroke-linecap: round; - stroke-linejoin: round; -} - -.conversation-section-title { - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.conversation-section-list { - position: relative; - overflow: visible; -} - -.export-config-scroll > .export-section:not(.export-format-top):has(.export-format-grid) { - display: none; -} - -.conversation-section-virtual-content { - position: relative; - width: 100%; -} - -.conversation-section-virtual-row { - position: absolute; - top: 0; - right: 0; - left: 0; - height: 58px; -} - -.conversation-section-empty { - padding: 10px 12px 12px 28px; - color: var(--wxex-text-muted); - font-size: 12px; - line-height: 18px; -} - -.conversation-item { - box-sizing: border-box; - position: relative; - width: 100%; - min-height: 58px; - display: flex; - align-items: center; - gap: 10px; - border: 0; - border-radius: var(--wxex-radius-md); - background: transparent; - color: var(--wxex-text-primary); - cursor: pointer; - font-family: var(--wxex-font); - padding: 8px 10px 8px 13px; - text-align: left; -} - -.conversation-item:hover { - background: rgba(255, 255, 255, 0.56); -} - -.conversation-item.active { - background: var(--wxex-brand-soft); -} - -.conversation-item-active-mark { - position: absolute; - top: 10px; - bottom: 10px; - left: 0; - width: 3px; - border-radius: 0 999px 999px 0; - background: transparent; -} - -.conversation-item.active .conversation-item-active-mark { - background: var(--wxex-brand); -} - -.conversation-item-avatar { - box-sizing: border-box; - width: 40px; - height: 40px; - display: grid; - place-items: center; - flex: 0 0 auto; - overflow: hidden; - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); - color: var(--wxex-brand); - font-size: 14px; - font-weight: 700; -} - -.conversation-item-avatar img { - width: 100%; - height: 100%; - display: block; - object-fit: cover; -} - -.conversation-item-body { - min-width: 0; - display: flex; - flex: 1; - flex-direction: column; - justify-content: center; -} - -.conversation-item-name { - overflow: hidden; - color: var(--wxex-text-primary); - font-size: 13px; - font-weight: 600; - line-height: 18px; - text-overflow: ellipsis; - white-space: nowrap; -} - -.conversation-item-meta { - overflow: hidden; - color: var(--wxex-text-muted); - font-size: 12px; - line-height: 16px; - text-overflow: ellipsis; - white-space: nowrap; -} - -.conversation-sidebar-account { - box-sizing: border-box; - flex: 0 0 auto; - border-top: 1px solid var(--wxex-border); - padding: 10px; -} - -.conversation-sidebar-account .account-summary { - min-height: 58px; - padding: 8px; -} - -.conversation-sidebar-account .account-summary-text { - flex: 1; -} - -.sidebar { - background-color: var(--sidebar-bg); - border-right: 1px solid var(--border-color); - display: flex; - flex-direction: column; - height: 100%; - min-height: 0; - flex-shrink: 0; - /* Prevent shrinking */ -} - -.sidebar-header { - flex: 0 0 auto; - padding: 10px; - border-bottom: 1px solid var(--border-color); - -webkit-app-region: drag; -} - -.sidebar-footer { - padding: 10px; - border-top: 1px solid var(--border-color); - display: flex; - justify-content: space-between; - align-items: center; - font-size: 14px; -} - -.sidebar-btn { - cursor: pointer; - display: flex; - align-items: center; - gap: 5px; - color: #666; -} - -.sidebar-btn:hover { - color: #333; -} - -.sidebar-status { - color: #07c160; - font-size: 12px; -} - -.search-input { - width: 100%; - padding: 5px; - border-radius: 4px; - border: 1px solid #ccc; - -webkit-app-region: no-drag; -} - -.date-range-selector { - display: flex; - gap: 5px; - margin-top: 8px; - justify-content: space-between; -} - -.range-btn { - padding: 2px 6px; - font-size: 10px; - border: 1px solid #ccc; - border-radius: 10px; - background: #fff; - cursor: pointer; - color: #666; - flex: 1; - text-align: center; -} - -.range-btn.active { - background: #07c160; - color: #fff; - border-color: #07c160; -} - -.contact-list { - flex: 1; - overflow-y: auto; -} - -.section-header { - padding: 8px 10px; - background-color: #f0f0f0; - font-size: 12px; - color: #666; - font-weight: bold; - cursor: pointer; - display: flex; - align-items: center; - user-select: none; -} - -.section-header:hover { - background-color: #e0e0e0; -} - -.section-header .arrow { - margin-right: 5px; - font-size: 10px; - width: 12px; -} - -.section-empty { - padding: 10px 14px 12px 27px; - color: #888; - font-size: 12px; -} - -.contact-item { - padding: 10px; - display: flex; - align-items: center; - cursor: pointer; -} - -.contact-item:hover { - background-color: var(--sidebar-hover); -} - -.contact-item.active { - background-color: var(--sidebar-active); -} - -.contact-avatar { - width: 40px; - height: 40px; - border-radius: 4px; - background-color: #ccc; - margin-right: 10px; - display: flex; - align-items: center; - justify-content: center; - font-size: 12px; - color: #fff; - overflow: hidden; - flex-shrink: 0; -} - -.contact-avatar img, -.message-avatar img { - width: 100%; - height: 100%; - object-fit: cover; - display: block; -} - -.contact-info { - flex: 1; - overflow: hidden; -} - -.contact-name { - font-weight: 500; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.resizer { - width: 4px; - cursor: col-resize; - background-color: transparent; - border-right: 1px solid transparent; - transition: - background-color 0.2s, - border-color 0.2s; - z-index: 10; -} - -.resizer:hover, -.resizer:active { - border-color: rgba(36, 122, 99, 0.22); - background-color: rgba(36, 122, 99, 0.06); -} - -.chat-window { - flex: 1; - display: flex; - flex-direction: column; - background-color: var(--wxex-bg-main); - height: 100%; - min-height: 0; - min-width: 0; - color: var(--wxex-text-primary); - overflow: hidden; -} - -.chat-window.empty { - align-items: center; - justify-content: center; -} - -.chat-archive-header { - box-sizing: border-box; - min-height: 70px; - flex: 0 0 auto; - display: flex; - align-items: center; - justify-content: space-between; - gap: 16px; - border-bottom: 1px solid var(--wxex-border); - background: var(--wxex-bg-main); - padding: 12px 18px; - -webkit-app-region: drag; -} - -.chat-title-block { - min-width: 0; - display: flex; - align-items: center; - gap: 12px; -} - -.chat-title-avatar { - width: 42px; - height: 42px; - display: grid; - place-items: center; - flex: 0 0 auto; - overflow: hidden; - border-radius: var(--wxex-radius-md); - background: var(--wxex-brand-soft); - color: var(--wxex-brand); - font-size: 15px; - font-weight: 700; -} - -.chat-title-avatar img { - width: 100%; - height: 100%; - display: block; - object-fit: cover; -} - -.chat-title-text { - min-width: 0; -} - -.chat-title-text h2 { - overflow: hidden; - margin: 0; - color: var(--wxex-text-primary); - font-size: 19px; - font-weight: 700; - line-height: 26px; - text-overflow: ellipsis; - white-space: nowrap; -} - -.chat-title-meta { - display: flex; - align-items: center; - gap: 8px; - color: var(--wxex-text-secondary); - font-size: 12px; - line-height: 18px; -} - -.chat-title-meta span + span::before { - content: ''; - display: inline-block; - width: 3px; - height: 3px; - margin-right: 8px; - border-radius: 999px; - background: var(--wxex-text-muted); - vertical-align: middle; -} - -.chat-header-actions { - display: flex; - align-items: center; - justify-content: flex-end; - gap: 8px; - flex: 0 0 auto; - -webkit-app-region: no-drag; -} - -.chat-icon-button, -.chat-tool-button, -.chat-ai-button { - box-sizing: border-box; - height: 32px; - display: inline-flex; - align-items: center; - justify-content: center; - gap: 6px; - border: 1px solid transparent; - border-radius: var(--wxex-radius-md); - background: transparent; - color: var(--wxex-text-secondary); - cursor: pointer; - font: 13px/18px var(--wxex-font); -} - -.chat-icon-button { - width: 32px; - padding: 0; -} - -.chat-tool-button { - padding: 0 9px; - border-color: var(--wxex-border); - background: var(--wxex-bg-elevated); -} - -.chat-icon-button:hover, -.chat-tool-button:hover { - background: var(--wxex-brand-soft); - color: var(--wxex-brand); -} - -.chat-tool-button:disabled, -.chat-ai-button:disabled { - cursor: not-allowed; - opacity: 0.55; -} - -.chat-ai-button { - padding: 0 12px; - border-color: var(--wxex-ai); - background: var(--wxex-ai); - color: #ffffff; - font-weight: 600; -} - -.chat-ai-button:hover:not(:disabled) { - background: #5a60c6; -} - -.chat-icon-button svg, -.chat-tool-button svg, -.chat-ai-button svg, -.chat-content-search svg, -.data-trust-bar svg { - width: 17px; - height: 17px; -} - -.chat-icon-button path, -.chat-tool-button path, -.chat-ai-button path, -.chat-content-search path, -.data-trust-bar path, -.chat-icon-button circle, -.chat-tool-button circle, -.chat-ai-button circle, -.chat-content-search circle, -.data-trust-bar circle { - fill: none; - stroke: currentColor; - stroke-width: 1.8; - stroke-linecap: round; - stroke-linejoin: round; -} - -.chat-menu { - position: relative; -} - -.chat-dropdown-menu { - position: absolute; - top: calc(100% + 6px); - left: 0; - z-index: 40; - min-width: 150px; - overflow: hidden; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); - box-shadow: var(--wxex-shadow-popover); - padding: 4px; -} - -.chat-dropdown-menu.right { - right: 0; - left: auto; -} - -.chat-dropdown-menu button { - box-sizing: border-box; - width: 100%; - display: block; - border: 0; - border-radius: var(--wxex-radius-sm); - background: transparent; - color: var(--wxex-text-primary); - cursor: pointer; - font: 13px/18px var(--wxex-font); - padding: 7px 9px; - text-align: left; - white-space: nowrap; -} - -.chat-dropdown-menu button:hover { - background: var(--wxex-brand-soft); - color: var(--wxex-brand); -} - -.chat-content-search { - box-sizing: border-box; - width: 280px; - height: 34px; - display: flex; - align-items: center; - gap: 7px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); - padding: 0 5px 0 10px; - color: var(--wxex-text-muted); -} - -.chat-content-search input { - min-width: 0; - flex: 1; - border: 0; - outline: 0; - background: transparent; - color: var(--wxex-text-primary); - font: 13px/18px var(--wxex-font); -} - -.chat-content-search-count { - color: var(--wxex-text-muted); - font-size: 12px; - white-space: nowrap; -} - -.data-trust-bar { - box-sizing: border-box; - min-height: 34px; - flex: 0 0 auto; - display: flex; - align-items: center; - justify-content: space-between; - gap: 16px; - border-bottom: 1px solid var(--wxex-border); - background: #f3f6f4; - color: var(--wxex-text-secondary); - padding: 0 18px; - font-size: 12px; - line-height: 18px; -} - -.data-trust-left, -.data-trust-right, -.data-trust-item { - display: flex; - align-items: center; - gap: 6px; -} - -.data-trust-right { - flex-wrap: wrap; - justify-content: flex-end; -} - -.data-trust-item { - color: var(--wxex-success); -} - -.data-trust-dot { - width: 3px; - height: 3px; - border-radius: 999px; - background: var(--wxex-text-muted); -} - -.message-list { - flex: 1; - overflow-y: auto; - padding: 0; - display: flex; - flex-direction: column; -} - -.wechat-message-list { - min-height: 0; - padding: 18px 28px 24px; - background: #f0f2ef; -} - -.virtual-message-list { - position: relative; - flex: 0 0 auto; - width: 100%; -} - -.virtual-message-group { - position: absolute; - top: 0; - left: 0; - display: flow-root; - width: 100%; -} - -.wechat-message-row { - margin-bottom: 14px; -} - -.message-loading-pill { - align-self: center; - margin: 0 0 12px; - padding: 5px 12px; - border-radius: var(--wxex-radius-md); - background: rgba(255, 255, 255, 0.78); - color: var(--wxex-text-secondary); - font-size: 12px; - line-height: 1.4; -} - -.wechat-message-row { - display: flex; - align-items: flex-start; - gap: 10px; - width: 100%; -} - -.wechat-message-row.mine { - justify-content: flex-end; -} - -.wechat-system-message-row { - display: flex; - flex-direction: column; - align-items: center; - gap: 4px; - margin: 2px 0 6px; -} - -.wechat-system-message { - max-width: min(78%, 760px); - padding: 6px 12px; - border-radius: var(--wxex-radius-md); - background: rgba(255, 255, 255, 0.72); - color: var(--wxex-text-muted); - font-size: 12px; - line-height: 1.5; - text-align: center; - word-break: break-word; -} - -.wechat-system-message-meta { - color: #a0a7ab; - font-size: 11px; -} - -.message-avatar { - width: 38px; - height: 38px; - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); - color: var(--wxex-brand); - display: flex; - align-items: center; - justify-content: center; - overflow: hidden; - flex: 0 0 38px; - font-size: 13px; -} - -.mine-avatar { - background: var(--wxex-brand-soft); -} - -.message-avatar-spacer { - width: 38px; - flex: 0 0 38px; -} - -.message-stack { - max-width: min(70%, 760px); - display: flex; - flex-direction: column; - align-items: flex-start; -} - -.wechat-message-row.mine .message-stack { - align-items: flex-end; -} - -.message-sender-name { - color: var(--wxex-text-secondary); - font-size: 12px; - margin: 0 0 4px 2px; -} - -.message-bubble-wrap { - position: relative; - display: flex; - flex-direction: column; - align-items: flex-start; - margin-top: 4px; -} - -.wechat-message-row.mine .message-bubble-wrap { - align-items: flex-end; -} - -.message-bubble-wrap.is-followup { - margin-top: 2px; -} - -.message-bubble { - position: relative; - padding: 9px 13px; - border: 1px solid rgba(221, 227, 224, 0.74); - border-radius: var(--wxex-radius-md); - background: #ffffff; - color: var(--wxex-text-primary); - font-size: 14px; - line-height: 1.55; - word-break: break-word; -} - -.wechat-message-row.mine .message-bubble { - border-color: rgba(36, 122, 99, 0.16); - background: #e7f2ee; - color: var(--wxex-text-primary); -} - -.message-bubble::before { - display: none; -} - -.message-meta { - display: none; -} - -.message-hover-time, -.message-accessible-sender { - color: var(--wxex-text-muted); - font-size: 12px; -} - -.message-recalled-status { - align-self: flex-end; - margin-top: 3px; - color: #c63c32; - font-size: 11px; - font-weight: 600; - line-height: 16px; -} - -.message-hover-time { - position: absolute; - top: 50%; - left: calc(100% + 8px); - z-index: 1; - visibility: hidden; - opacity: 0; - pointer-events: none; - transform: translateY(-50%); - transition: opacity 0.12s ease; - white-space: nowrap; -} - -.message-bubble-wrap:hover .message-hover-time { - visibility: visible; - opacity: 1; -} - -.wechat-message-row.mine .message-hover-time { - right: calc(100% + 8px); - left: auto; -} - -.message-accessible-sender { - position: absolute; - width: 1px; - height: 1px; - overflow: hidden; - clip: rect(0 0 0 0); -} - -.chat-time-separator { - align-self: center; - margin: 8px 0 12px; - color: var(--wxex-text-muted); - font-size: 12px; - line-height: 18px; -} - -.message-text { - min-width: 0; -} - -.inline-wechat-emoji { - display: inline-block; - margin: 0 1px; - vertical-align: -5px; - object-fit: contain; -} - -.voice-bubble { - min-width: 138px; -} - -.image-message-bubble { - padding: 0; - overflow: hidden; - background: transparent; - box-shadow: none; - white-space: normal; -} - -.wechat-message-row.mine .image-message-bubble { - background: transparent; -} - -.image-message-bubble::before { - display: none; -} - -.video-message-bubble { - padding: 0; - overflow: hidden; - background: #101412; - border-color: rgba(0, 0, 0, 0.12); -} - -.wechat-message-row.mine .video-message-bubble { - background: #101412; -} - -.video-message { - position: relative; - width: min(320px, 48vw); - min-height: 140px; - background: #101412; -} - -.video-content { - display: block; - width: 100%; - max-height: 360px; - object-fit: contain; - background: #101412; -} - -.video-duration { - position: absolute; - right: 8px; - top: 8px; - padding: 2px 6px; - border-radius: 8px; - color: #fff; - background: rgba(0, 0, 0, 0.55); - font-size: 11px; - pointer-events: none; -} - -.video-placeholder { - display: grid; - place-items: center; - width: min(260px, 44vw); - min-height: 120px; - padding: 16px; - color: rgba(255, 255, 255, 0.78); - text-align: center; -} - -.image-bubble { - position: relative; - max-width: min(260px, 46vw); - max-height: 220px; - min-width: 96px; - min-height: 72px; - border-radius: var(--wxex-radius-md); - overflow: hidden; - background: #fff; - cursor: zoom-in; - border: 1px solid var(--wxex-border); -} - -.image-content { - display: block; - max-width: min(260px, 46vw); - max-height: 220px; - width: auto; - height: auto; - object-fit: contain; - background: #f7f7f7; -} - -.image-loading, -.image-placeholder, -.image-error { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 6px; - padding: 14px 18px; - color: var(--wxex-text-secondary); - font-size: 13px; -} - -.image-loading-skeleton { - width: 110px; - height: 72px; - border-radius: var(--wxex-radius-md); - background: linear-gradient(90deg, #edf1ef 0%, #f7f8f7 50%, #edf1ef 100%); - background-size: 200% 100%; - animation: image-skeleton-shimmer 1.2s linear infinite; -} - -.image-actions { - position: absolute; - right: 6px; - bottom: 6px; - opacity: 0; - transition: opacity 0.15s ease; -} - -.image-bubble:hover .image-actions { - opacity: 1; -} - -.image-quality-badge { - position: absolute; - right: 6px; - bottom: 6px; - max-width: calc(100% - 12px); - padding: 3px 6px; - border-radius: 5px; - background: rgba(0, 0, 0, 0.5); - color: #fff; - font-size: 11px; - line-height: 1.3; - pointer-events: none; -} - -@keyframes image-skeleton-shimmer { - 0% { - background-position: 200% 0; - } - 100% { - background-position: -200% 0; - } -} - -.image-action-btn { - border: 0; - border-radius: 5px; - background: rgba(0, 0, 0, 0.48); - color: #fff; - cursor: pointer; - padding: 4px 6px; -} - -.voice-message { - display: flex; - align-items: center; - gap: 8px; - white-space: nowrap; -} - -.voice-icon { - width: 20px; - height: 20px; - border-radius: 50%; - display: inline-flex; - align-items: center; - justify-content: center; - background: rgba(36, 122, 99, 0.12); - color: var(--wxex-brand); - font-size: 10px; - line-height: 1; -} - -.wechat-message-row.mine .voice-icon { - background: rgba(36, 122, 99, 0.14); -} - -.voice-error { - color: var(--wxex-text-secondary); -} - -.voice-error-text { - color: var(--wxex-text-secondary); -} - -.voice-bars { - display: inline-flex; - align-items: center; - gap: 3px; - height: 16px; -} - -.voice-bars i { - width: 3px; - border-radius: 3px; - background: currentColor; - opacity: 0.75; -} - -.voice-bars i:nth-child(1) { - height: 7px; -} - -.voice-bars i:nth-child(2) { - height: 13px; -} - -.voice-bars i:nth-child(3) { - height: 9px; -} - -.sticker-message { - display: flex; - flex-direction: column; - gap: 6px; - align-items: flex-start; -} - -.sticker-image { - display: block; - max-width: 140px; - max-height: 140px; - border-radius: 6px; - object-fit: contain; -} - -.sticker-placeholder { - color: #666; - font-size: 14px; -} - -.sticker-md5 { - max-width: 180px; - color: #999; - font-size: 11px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.quote-message { - min-width: 160px; - max-width: 320px; -} - -.quoted-message { - display: flex; - gap: 4px; - max-width: 100%; - margin-bottom: 8px; - padding: 6px 8px; - border-radius: 4px; - background: rgba(255, 255, 255, 0.18); - color: rgba(255, 255, 255, 0.82); - font-size: 12px; - line-height: 1.4; -} - -.wechat-message-row.other .quoted-message { - background: #f0f0f0; - color: #666; -} - -.quoted-sender { - flex: 0 1 auto; - min-width: 0; - font-weight: 600; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.quoted-sender::after { - content: ':'; -} - -.quoted-text { - flex: 0 0 auto; -} - -.quote-reply { - font-size: 14px; - line-height: 1.5; - white-space: pre-wrap; - word-break: break-word; -} - -.chat-table { - width: 100%; - border-collapse: collapse; - font-size: 13px; -} - -.chat-table th { - text-align: left; - padding: 8px; - border-bottom: 1px solid var(--border-color); - background-color: #f9f9f9; - color: #666; - font-weight: normal; - position: sticky; - top: 0; - z-index: 1; - position: relative; - /* For resizer positioning */ -} - -.column-resizer { - position: absolute; - right: 0; - top: 0; - bottom: 0; - width: 5px; - cursor: col-resize; - z-index: 2; -} - -.column-resizer:hover { - background-color: #ccc; -} - -.chat-table td { - padding: 8px; - border-bottom: 1px solid #eee; - vertical-align: top; - color: #333; -} - -.chat-table tr:hover { - background-color: #f0f0f0; -} - -.col-sender { - width: 80px; -} - -.col-type { - width: 80px; -} - -.col-time { - width: 150px; -} - -.col-content { -} - -.chat-toolbar { - padding: 10px; - border-top: 1px solid var(--border-color); - display: flex; - gap: 10px; - background-color: #fff; - flex-wrap: wrap; -} - -.toolbar-btn { - padding: 4px 12px; - border: 1px solid #dcdcdc; - border-radius: 4px; - background-color: #fff; - font-size: 12px; - cursor: pointer; - display: flex; - align-items: center; - gap: 4px; -} - -.toolbar-btn:hover { - background-color: #f5f5f5; -} - -.empty-state { - display: flex; - align-items: center; - justify-content: center; - height: 100%; - color: #999; -} - -.chat-status-bar { - box-sizing: border-box; - min-height: 38px; - flex: 0 0 auto; - display: flex; - align-items: center; - justify-content: space-between; - gap: 16px; - border-top: 1px solid var(--wxex-border); - background: var(--wxex-bg-main); - color: var(--wxex-text-secondary); - padding: 0 18px; - font-size: 12px; - line-height: 18px; -} - -.chat-status-actions { - display: flex; - align-items: center; - justify-content: flex-end; - gap: 10px; -} - -.chat-avatar-toggle { - display: inline-flex; - align-items: center; - gap: 6px; - cursor: pointer; - white-space: nowrap; -} - -.chat-avatar-toggle input { - margin: 0; - accent-color: var(--wxex-brand); -} - -.chat-avatar-note { - max-width: 320px; - color: var(--wxex-text-muted); - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.chat-avatar-reload { - display: inline-flex; - align-items: center; - gap: 4px; - white-space: nowrap; -} - -.chat-avatar-reload svg { - width: 14px; - height: 14px; - fill: none; - stroke: currentColor; - stroke-linecap: round; - stroke-linejoin: round; - stroke-width: 1.8; -} - -.chat-avatar-reload svg.is-spinning { - animation: chat-avatar-spin 0.8s linear infinite; -} - -@keyframes chat-avatar-spin { - to { - transform: rotate(360deg); - } -} - -.chat-status-separator { - width: 1px; - height: 14px; - background: var(--wxex-border); -} - -.chat-status-actions button { - border: 0; - background: transparent; - color: var(--wxex-brand); - cursor: pointer; - font: 12px/18px var(--wxex-font); - padding: 0; -} - -.chat-status-actions button:hover { - color: var(--wxex-brand-hover); -} - -.chat-status-actions button:disabled { - color: var(--wxex-text-muted); - cursor: default; -} - -@media (max-width: 1120px) { - .chat-avatar-note { - display: none; - } -} - -.empty-conversation-state { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 6px; - color: var(--wxex-text-secondary); - text-align: center; -} - -.empty-conversation-state h2 { - margin: 0; - color: var(--wxex-text-primary); - font-size: 20px; - line-height: 28px; -} - -.empty-conversation-state p { - margin: 0; - color: var(--wxex-text-muted); - font-size: 13px; - line-height: 20px; -} - -.database-login-page { - --login-primary: #247a63; - --login-primary-dark: #00604c; - --login-border: #d7dfda; - --login-surface: #f7faf6; - --login-surface-low: #f1f4f1; - --login-text: #181c1b; - --login-muted: #5f6965; - width: 100vw; - min-width: 760px; - height: 100vh; - min-height: 560px; - display: grid; - grid-template-columns: minmax(300px, 40%) 1fr; - overflow: hidden; - color: var(--login-text); - background: #fff; -} - -.database-login-brand { - position: relative; - display: flex; - flex-direction: column; - padding: clamp(36px, 6vh, 72px) clamp(36px, 5vw, 72px) 28px; - background: var(--login-surface-low); - border-right: 1px solid var(--login-border); -} - -.database-login-brand-content { - width: min(360px, 100%); - margin: auto 0; -} - -.database-login-logo { - width: 56px; - height: 56px; - display: grid; - place-items: center; - margin-bottom: 24px; - border-radius: 10px; - color: #fff; - background: var(--login-primary-dark); - box-shadow: 0 4px 12px rgba(0, 96, 76, 0.12); -} - -.database-login-logo svg { - width: 29px; - height: 29px; -} - -.database-login-brand h1 { - margin: 0; - font-size: 25px; - line-height: 32px; - font-weight: 650; - letter-spacing: -0.02em; - color: var(--login-primary-dark); -} - -.database-login-tagline { - margin: 4px 0 26px; - color: var(--login-primary); - font-size: 14px; - line-height: 22px; - font-weight: 600; -} - -.database-login-description { - max-width: 320px; - margin: 0 0 30px; - color: var(--login-muted); - font-size: 13px; - line-height: 21px; -} - -.database-login-promises { - display: grid; - gap: 10px; -} - -.database-login-promises > div { - min-height: 44px; - display: flex; - align-items: center; - gap: 12px; - padding: 0 14px; - border: 1px solid rgba(190, 201, 195, 0.62); - border-radius: 7px; - color: #35423d; - background: rgba(255, 255, 255, 0.42); - font-size: 13px; - font-weight: 550; -} - -.database-login-promises svg { - width: 18px; - height: 18px; - color: var(--login-primary); -} - -.database-login-brand-footer { - margin-top: auto; - padding-top: 24px; - color: #78827e; - font-family: 'Work Sans', Inter, sans-serif; - font-size: 10px; - font-weight: 650; - letter-spacing: 0.11em; -} - -.database-login-workspace { - display: grid; - place-items: center; - min-width: 0; - padding: 48px clamp(40px, 7vw, 96px); - background: #fff; -} - -.database-login-panel { - width: min(520px, 100%); -} - -.database-login-tabs { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 4px; - padding: 4px; - margin-bottom: 28px; - border: 1px solid var(--login-border); - border-radius: 8px; - background: #e9eeeb; -} - -.database-login-tabs button { - min-height: 38px; - border: 0; - border-radius: 5px; - color: #66716c; - background: transparent; - cursor: pointer; - font-size: 13px; - font-weight: 550; -} - -.database-login-tabs button.active { - color: var(--login-primary-dark); - background: #fff; - box-shadow: 0 1px 3px rgba(24, 28, 27, 0.08); -} - -.database-login-state-card { - padding: 18px; - border: 1px solid var(--login-border); - border-radius: 9px; - background: var(--login-surface); -} - -.database-login-state-card.error { - border-color: #efc4be; - border-left: 3px solid #ba1a1a; - background: #fff9f8; -} - -.database-login-state-heading { - display: flex; - gap: 12px; - margin-bottom: 18px; -} - -.database-login-state-icon { - flex: 0 0 auto; - width: 30px; - height: 30px; - display: grid; - place-items: center; - border-radius: 50%; - color: var(--login-primary); - background: #e2f0eb; -} - -.database-login-state-card.error .database-login-state-icon { - color: #ba1a1a; - background: #ffebe8; -} - -.database-login-state-icon svg { - width: 17px; - height: 17px; -} - -.database-login-state-heading strong { - display: block; - margin: 1px 0 4px; - font-size: 14px; - line-height: 20px; -} - -.database-login-state-heading p { - margin: 0; - color: var(--login-muted); - font-size: 12px; - line-height: 18px; - white-space: pre-wrap; - word-break: break-word; -} - -.database-login-diagnostics { - margin: 0; - border-top: 1px solid #e2e7e4; -} - -.database-login-diagnostics > div { - min-height: 43px; - display: grid; - grid-template-columns: 112px 1fr; - align-items: center; - border-bottom: 1px solid #e2e7e4; -} - -.database-login-diagnostics > div:last-child { - border-bottom: 0; -} - -.database-login-diagnostics dt { - display: flex; - align-items: center; - gap: 6px; - color: #6e7874; - font-family: 'Work Sans', Inter, sans-serif; - font-size: 10px; - font-weight: 650; - letter-spacing: 0.04em; -} - -.database-login-diagnostics dd { - min-width: 0; - margin: 0; - color: #35423d; - font-size: 12px; - text-align: right; -} - -.database-login-path-input-wrap { - position: relative; - display: block; - width: 100%; -} - -.database-login-diagnostics input { - width: 100%; - height: 36px; - padding: 7px 0; - border: 0; - outline: 0; - color: #4c5752; - background: transparent; - font: inherit; - text-align: right; - text-overflow: ellipsis; -} - -.database-login-path-value { - position: absolute; - right: 0; - bottom: calc(100% + 7px); - z-index: 25; - width: min(520px, calc(100vw - 48px)); - padding: 9px 11px; - border: 1px solid #d7dfda; - border-radius: 7px; - color: #35423d; - background: #fff; - box-shadow: 0 6px 18px rgba(24, 28, 27, 0.13); - font-size: 11px; - line-height: 17px; - text-align: left; - overflow-wrap: anywhere; - opacity: 0; - pointer-events: none; - transform: translateY(4px); - transition: - opacity 120ms ease, - transform 120ms ease; -} - -.database-login-path-input-wrap:hover .database-login-path-value, -.database-login-path-input-wrap:focus-within .database-login-path-value { - opacity: 1; - transform: translateY(0); -} - -.database-login-primary, -.database-login-secondary { - width: 100%; - min-height: 44px; - margin-top: 22px; - border-radius: 7px; - cursor: pointer; - font-size: 13px; - font-weight: 600; -} - -.database-login-primary { - border: 1px solid var(--login-primary); - color: #fff; - background: var(--login-primary); - box-shadow: 0 2px 5px rgba(0, 96, 76, 0.16); -} - -.database-login-primary:hover:not(:disabled) { - border-color: var(--login-primary-dark); - background: var(--login-primary-dark); -} - -.database-login-primary:disabled { - cursor: not-allowed; - opacity: 0.52; - box-shadow: none; -} - -.database-login-auto > a { - display: block; - margin-top: 16px; - color: var(--login-primary); - font-size: 12px; - text-align: center; - text-decoration: none; -} - -.database-login-manual { - padding-top: 2px; -} - -.database-login-field { - margin-bottom: 20px; -} - -.database-login-field > label { - display: flex; - align-items: center; - gap: 7px; - margin-bottom: 8px; - color: #35423d; - font-size: 12px; - font-weight: 600; -} - -.database-login-path-help { - position: relative; - display: inline-flex; - align-items: center; -} - -.database-login-path-help-icon { - width: 15px; - height: 15px; - display: inline-grid; - place-items: center; - border: 1px solid #9a6b18; - border-radius: 50%; - color: #8a5d0b; - background: #fff8e6; - cursor: help; - font-family: Inter, sans-serif; - font-size: 10px; - font-weight: 700; - line-height: 1; -} - -.database-login-path-tooltip { - position: absolute; - left: 50%; - bottom: calc(100% + 9px); - z-index: 20; - width: 260px; - padding: 9px 11px; - border: 1px solid #d7dfda; - border-radius: 7px; - color: #35423d; - background: #fff; - box-shadow: 0 6px 18px rgba(24, 28, 27, 0.12); - font-family: Inter, sans-serif; - font-size: 11px; - font-weight: 400; - line-height: 17px; - letter-spacing: 0; - opacity: 0; - pointer-events: none; - transform: translate(-50%, 4px); - transition: - opacity 120ms ease, - transform 120ms ease; -} - -.database-login-path-help:hover .database-login-path-tooltip, -.database-login-path-help:focus-within .database-login-path-tooltip { - opacity: 1; - transform: translate(-50%, 0); -} - -.database-login-field > input, -.database-login-key-input { - width: 100%; - min-height: 42px; - border: 1px solid var(--login-border); - border-radius: 7px; - background: #fff; -} - -.database-login-field > input { - padding: 0 12px; - color: var(--login-text); - font-size: 13px; - outline: none; -} - -.database-login-key-input { - display: flex; - align-items: center; -} - -.database-login-key-input:focus-within, -.database-login-field > input:focus { - border-color: var(--login-primary); - box-shadow: 0 0 0 3px rgba(36, 122, 99, 0.1); -} - -.database-login-key-input input { - flex: 1; - min-width: 0; - height: 40px; - padding: 0 4px 0 12px; - border: 0; - outline: 0; - color: var(--login-text); - background: transparent; - font-size: 13px; -} - -.database-login-key-input button { - width: 38px; - height: 38px; - display: grid; - place-items: center; - border: 0; - color: #65706b; - background: transparent; - cursor: pointer; -} - -.database-login-key-input svg { - width: 18px; - height: 18px; - fill: none; - stroke: currentColor; - stroke-width: 1.7; - stroke-linecap: round; - stroke-linejoin: round; -} - -.database-login-field small { - display: block; - margin-top: 7px; - color: #77817d; - font-size: 11px; -} - -.database-login-message { - padding: 10px 12px; - border-radius: 7px; - color: #57625d; - background: var(--login-surface-low); - font-size: 12px; - line-height: 18px; - white-space: pre-wrap; -} - -.database-login-message.success { - color: var(--login-primary-dark); - background: #edf7f3; -} - -.database-login-message.error { - color: #93000a; - background: #fff0ee; -} - -.database-login-secondary { - margin-top: 10px; - border: 1px solid var(--login-border); - color: #3f4945; - background: #fff; -} - -.database-login-secondary:hover { - border-color: var(--login-primary); - color: var(--login-primary-dark); - background: var(--login-surface); -} - -.database-login-footer-actions { - display: flex; - align-items: center; - justify-content: space-between; - margin-top: 42px; - padding-top: 16px; - border-top: 1px solid #e5e9e6; - color: #8a938f; - font-size: 11px; -} - -.database-login-footer-actions button { - padding: 0; - border: 0; - color: #78827e; - background: transparent; - cursor: pointer; - font-size: 11px; -} - -.database-login-footer-actions button:hover { - color: #93000a; -} - -@media (max-width: 900px), (max-height: 620px) { - .database-login-brand { - padding: 30px; - } - - .database-login-description { - margin-bottom: 20px; - } - - .database-login-workspace { - padding: 30px; - } -} - -.modal-overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0.5); - display: flex; - justify-content: center; - align-items: center; - z-index: 1000; -} - -.modal-content { - background: white; - padding: 20px; - border-radius: 8px; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); - min-width: 400px; - max-width: 90vw; - max-height: 90vh; - overflow: auto; -} - -.ai-settings-modal { - width: min(460px, 90vw); -} - -.ai-settings-modal h3 { - margin: 0 0 18px; -} - -.ai-filter-section { - margin-bottom: 16px; -} - -.ai-filter-label { - margin-bottom: 7px; - color: #333; - font-size: 14px; - font-weight: 600; -} - -.ai-date-options { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 6px; -} - -.ai-date-options label { - display: flex; - min-width: 0; - align-items: center; - justify-content: center; - gap: 5px; - padding: 8px 6px; - border: 1px solid #d8dcdf; - border-radius: 6px; - background: #fff; - color: #4a5257; - cursor: pointer; - font-size: 13px; -} - -.ai-date-options label.selected { - border-color: #07c160; - background: #eefaf3; - color: #078f49; -} - -.ai-date-options input, -.ai-type-options input { - margin: 0; - accent-color: #07c160; -} - -.ai-type-options { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 8px 10px; - padding: 11px; - border: 1px solid #e1e4e6; - border-radius: 6px; - background: #f8f9fa; -} - -.ai-type-options label { - display: flex; - min-width: 0; - align-items: center; - gap: 6px; - color: #3f474c; - cursor: pointer; - font-size: 13px; - white-space: nowrap; -} - -.image-preview-modal { - width: min(520px, 92vw); - max-height: 88vh; - background: #f7f8fa; - box-shadow: 0 18px 48px rgba(0, 0, 0, 0.18); - padding: 16px; - overflow: hidden; -} - -.report-preview-frame { - border: 1px solid #d8dde3; - border-radius: 10px; - background: #eef1f4; - padding: 12px; -} - -.report-preview-scroller { - max-height: calc(88vh - 120px); - overflow-y: auto; - overflow-x: hidden; - padding-right: 4px; -} - -.report-preview-image { - display: block; - width: min(430px, 100%); - height: auto; - margin: 0 auto; - border-radius: 8px; - border: 1px solid #ccd3d9; - background: #fff; -} - -.report-preview-actions { - margin-top: 12px; - display: flex; - gap: 10px; - flex-wrap: wrap; -} - -.image-viewer-overlay { - position: fixed; - inset: 0; - z-index: 1200; - display: flex; - align-items: center; - justify-content: center; - background: rgba(16, 24, 28, 0.28); - backdrop-filter: blur(1px); - overscroll-behavior: contain; -} - -.image-viewer-window { - width: min(1280px, 96vw); - height: min(900px, 92vh); - display: flex; - flex-direction: column; - overflow: hidden; - border: 1px solid rgba(0, 0, 0, 0.14); - border-radius: 8px; - background: #eaf0f1; - box-shadow: 0 18px 48px rgba(0, 0, 0, 0.22); -} - -.image-viewer-titlebar { - height: 40px; - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 12px 0 16px; - border-bottom: 1px solid rgba(0, 0, 0, 0.08); - background: rgba(255, 255, 255, 0.78); - color: #333; - font-size: 14px; -} - -.image-viewer-tools { - display: flex; - align-items: center; - gap: 12px; -} - -.image-viewer-title { - margin-right: 8px; - font-weight: 500; -} - -.image-viewer-zoom { - min-width: 44px; - color: #666; - text-align: center; -} - -.image-viewer-divider { - width: 1px; - height: 18px; - background: rgba(0, 0, 0, 0.12); -} - -.image-viewer-titlebar button { - width: 28px; - height: 28px; - border: 0; - border-radius: 50%; - background: transparent; - color: #555; - cursor: pointer; - font-size: 18px; - line-height: 1; -} - -.image-viewer-titlebar button:hover { - background: rgba(0, 0, 0, 0.08); -} - -.image-viewer-stage { - flex: 1; - display: flex; - align-items: center; - justify-content: center; - padding: 28px; - overflow: hidden; - overscroll-behavior: contain; - cursor: grab; - user-select: none; -} - -.image-viewer-stage img { - max-width: none; - max-height: none; - width: auto; - height: auto; - object-fit: contain; - box-shadow: 0 3px 16px rgba(0, 0, 0, 0.12); - transform-origin: center center; - transition: transform 0.08s ease-out; - user-select: none; - pointer-events: none; -} - -/* Voice Player */ -.voice-message { - cursor: pointer; - user-select: none; -} - -.voice-loading { - opacity: 0.6; -} - -.voice-error { - opacity: 1; -} - -.voice-loading-text { - font-size: 12px; - color: var(--wxex-text-muted); -} - -.voice-error-text { - color: var(--wxex-text-secondary); -} - -.voice-duration { - font-size: 12px; - margin-left: 4px; - min-width: 32px; -} - -.voice-icon.playing { - background: rgba(36, 122, 99, 0.18); -} - -/* Rich Message Bubbles */ -.location-message { - display: flex; - align-items: center; - gap: 10px; - cursor: pointer; - min-width: 180px; - max-width: 280px; -} - -.location-icon { - box-sizing: border-box; - min-width: 34px; - padding: 4px 6px; - border-radius: var(--wxex-radius-sm); - background: var(--wxex-brand-soft); - color: var(--wxex-brand); - font-size: 12px; - font-weight: 600; - flex-shrink: 0; -} - -.location-info { - flex: 1; - overflow: hidden; -} - -.location-name { - font-weight: 500; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.location-label { - font-size: 12px; - color: var(--wxex-text-secondary); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.location-coords { - font-size: 11px; - color: var(--wxex-text-muted); - margin-top: 2px; -} - -.wechat-message-row.mine .location-message { - flex-direction: row-reverse; -} - -.card-message { - display: flex; - align-items: center; - gap: 10px; - min-width: 160px; - max-width: 240px; -} - -.card-avatar { - width: 40px; - height: 40px; - border-radius: 6px; - background: #07c160; - color: #fff; - display: flex; - align-items: center; - justify-content: center; - font-size: 18px; - font-weight: 500; - flex-shrink: 0; -} - -.card-info { - flex: 1; - overflow: hidden; -} - -.card-nickname { - font-weight: 500; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.card-username { - font-size: 12px; - color: #666; - cursor: pointer; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.card-username:hover { - color: #07c160; -} - -.share-message { - display: flex; - flex-direction: column; - gap: 4px; - cursor: pointer; - min-width: 180px; - max-width: 280px; -} - -.share-appname { - font-size: 11px; - color: #999; -} - -.share-title { - font-weight: 500; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.share-desc { - font-size: 12px; - color: #666; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; -} - -.share-url { - font-size: 11px; - color: #999; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.mini-program-message { - width: min(280px, 48vw); - overflow: hidden; - color: var(--wxex-text-primary); -} - -.mini-program-title { - margin-bottom: 8px; - font-size: 14px; - line-height: 20px; - word-break: break-word; -} - -.mini-program-description { - margin: -4px 0 8px; - color: var(--wxex-text-secondary); - font-size: 12px; - line-height: 18px; -} - -.mini-program-preview .image-bubble, -.mini-program-preview .image-content { - width: 100%; - max-width: 100%; - max-height: 220px; - border-radius: 4px; -} - -.mini-program-preview .image-content { - object-fit: cover; -} - -.mini-program-inline-image { - display: block; - width: 100%; - max-height: 220px; - border-radius: 4px; - object-fit: cover; - cursor: zoom-in; -} - -.mini-program-preview .image-content.image-fallback { - width: 64px; - height: 64px; - margin: 28px auto; - border-radius: 8px; - object-fit: cover; -} - -.mini-program-preview .image-actions { - display: none; -} - -.mini-program-icon { - display: block; - width: 52px; - height: 52px; - margin: 8px 0; - border-radius: 6px; - object-fit: cover; -} - -.mini-program-footer { - display: flex; - align-items: center; - gap: 5px; - margin-top: 8px; - padding-top: 7px; - border-top: 1px solid var(--wxex-border); - color: var(--wxex-text-muted); - font-size: 11px; - line-height: 16px; -} - -.red-packet-message { - width: min(280px, 48vw); - overflow: hidden; - border-radius: 6px; - background: #fa9d3b; - color: #fff; -} - -.red-packet-message.is-clickable { - cursor: pointer; -} - -.red-packet-main { - display: flex; - align-items: center; - gap: 12px; - min-height: 72px; - padding: 12px 14px; -} - -.red-packet-icon { - display: grid; - width: 36px; - height: 36px; - flex: 0 0 36px; - place-items: center; - border: 2px solid rgba(255, 239, 170, 0.92); - border-radius: 50%; - color: #fff1a8; - font-size: 18px; - font-weight: 700; -} - -.red-packet-copy { - display: flex; - min-width: 0; - flex-direction: column; - gap: 2px; -} - -.red-packet-copy strong { - overflow: hidden; - font-size: 15px; - font-weight: 500; - line-height: 21px; - text-overflow: ellipsis; - white-space: nowrap; -} - -.red-packet-copy small { - color: rgba(255, 255, 255, 0.82); - font-size: 12px; - line-height: 18px; -} - -.red-packet-footer { - padding: 5px 14px; - background: #fff; - color: var(--wxex-text-muted); - font-size: 11px; - line-height: 16px; -} - -.voip-message { - display: flex; - align-items: center; - gap: 8px; - white-space: nowrap; -} - -.voip-icon { - box-sizing: border-box; - padding: 3px 6px; - border-radius: var(--wxex-radius-sm); - background: var(--wxex-brand-soft); - color: var(--wxex-brand); - font-size: 12px; - font-weight: 600; -} - -.voip-status { - font-size: 13px; -} - -/* Sidebar 自助卡片 + 入口 */ -.sidebar-footer { - padding: 10px 12px; - border-top: 1px solid var(--border-color); - display: flex; - align-items: center; - gap: 10px; - cursor: pointer; - background-color: #f3f4f5; - transition: background-color 0.15s ease; - user-select: none; -} - -.sidebar-footer:hover { - background-color: #e6e9eb; -} - -.sidebar-self-avatar { - width: 36px; - height: 36px; - border-radius: 6px; - background-color: #07c160; - color: #fff; - display: flex; - align-items: center; - justify-content: center; - font-size: 14px; - font-weight: 500; - overflow: hidden; - flex-shrink: 0; -} - -.sidebar-self-avatar img { - width: 100%; - height: 100%; - object-fit: cover; -} - -.sidebar-self-info { - flex: 1; - min-width: 0; - overflow: hidden; -} - -.sidebar-self-nickname { - font-size: 13px; - font-weight: 500; - color: #1f2429; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.sidebar-self-wxid { - font-size: 11px; - color: #8a9298; - margin-top: 2px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.sidebar-self-arrow { - color: #8a9298; - font-size: 18px; - flex-shrink: 0; -} - -/* 启动自动连接 Splash */ -.boot-splash { - position: fixed; - inset: 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 14px; - background: linear-gradient(180deg, #f5f7f8 0%, #eceff1 100%); - z-index: 2000; - animation: boot-splash-fade-in 0.2s ease-out; -} - -@keyframes boot-splash-fade-in { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -.boot-splash-spinner { - width: 36px; - height: 36px; - border-radius: 50%; - border: 3px solid rgba(7, 193, 96, 0.18); - border-top-color: #07c160; - animation: boot-splash-spin 0.9s linear infinite; -} - -@keyframes boot-splash-spin { - to { - transform: rotate(360deg); - } -} - -.boot-splash-title { - font-size: 15px; - font-weight: 500; - color: #1f2429; -} - -.boot-splash-subtitle { - font-size: 12px; - color: #6f767c; -} - -.boot-splash-detail { - min-height: 18px; - font-size: 12px; - color: #8a9298; -} - -.boot-splash-progress { - width: min(320px, 72vw); - height: 6px; - margin-top: 2px; - overflow: hidden; - border-radius: 999px; - background: rgba(7, 193, 96, 0.12); -} - -.boot-splash-progress-bar { - height: 100%; - border-radius: inherit; - background: #07c160; - transition: width 0.18s ease-out; -} - -/* 设置面板 */ -.settings-overlay { - position: fixed; - inset: 0; - background: rgba(15, 21, 26, 0.45); - backdrop-filter: blur(2px); - z-index: 1100; - display: flex; - align-items: center; - justify-content: center; - animation: settings-fade-in 0.16s ease-out; -} - -@keyframes settings-fade-in { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -.settings-modal { - width: min(560px, 92vw); - max-height: 84vh; - background: #fff; - border-radius: 12px; - box-shadow: 0 24px 60px rgba(15, 21, 26, 0.28); - display: flex; - flex-direction: column; - overflow: hidden; - animation: settings-pop-in 0.18s ease-out; -} - -@keyframes settings-pop-in { - from { - transform: translateY(8px) scale(0.98); - opacity: 0; - } - to { - transform: translateY(0) scale(1); - opacity: 1; - } -} - -.settings-header { - display: flex; - align-items: center; - justify-content: space-between; - padding: 16px 22px; - border-bottom: 1px solid #ececec; -} - -.settings-header h2 { - margin: 0; - font-size: 17px; - font-weight: 600; - color: #1f2429; -} - -.settings-close { - background: transparent; - border: 0; - color: #7d858a; - font-size: 26px; - line-height: 1; - width: 32px; - height: 32px; - border-radius: 50%; - cursor: pointer; - transition: background-color 0.15s ease; -} - -.settings-close:hover { - background: #f0f2f4; - color: #1f2429; -} - -.settings-body { - padding: 12px 22px 22px; - overflow-y: auto; -} - -.settings-section { - margin-top: 14px; - padding: 14px 16px; - border-radius: 10px; - background: #fafbfc; - border: 1px solid #ececec; -} - -.settings-section:first-child { - margin-top: 6px; -} - -.settings-section-title { - font-size: 12px; - font-weight: 600; - color: #6f767c; - letter-spacing: 0.5px; - text-transform: uppercase; - margin-bottom: 10px; -} - -.settings-row { - display: flex; - align-items: center; - gap: 10px; - flex-wrap: wrap; - margin-top: 8px; -} - -.settings-row:first-child { - margin-top: 0; -} - -.settings-input { - flex: 1; - min-width: 0; - padding: 8px 11px; - border: 1px solid #d4d9dc; - border-radius: 6px; - background: #fff; - font-size: 13px; - color: #1f2429; - font-family: 'SF Mono', Menlo, Consolas, monospace; - outline: none; - transition: - border-color 0.15s ease, - box-shadow 0.15s ease; -} - -.settings-input:focus { - border-color: #07c160; - box-shadow: 0 0 0 3px rgba(7, 193, 96, 0.12); -} - -.settings-input-half { - flex: 0 1 140px; -} - -.settings-input-quarter { - flex: 0 1 90px; -} - -.settings-btn { - padding: 7px 14px; - border: 1px solid #d4d9dc; - border-radius: 6px; - background: #fff; - color: #30383d; - cursor: pointer; - font-size: 13px; - transition: - border-color 0.15s ease, - background-color 0.15s ease, - color 0.15s ease; -} - -.settings-btn:hover:not(:disabled) { - border-color: #07c160; - color: #078f49; -} - -.settings-btn:disabled { - opacity: 0.55; - cursor: not-allowed; -} - -.settings-btn-primary { - background: #07c160; - color: #fff; - border-color: #07c160; -} - -.settings-btn-primary:hover:not(:disabled) { - background: #06ad56; - color: #fff; - border-color: #06ad56; -} - -.settings-hint { - margin-top: 10px; - font-size: 11px; - color: #8a9298; - line-height: 1.6; -} - -.settings-hint code { - background: #eef0f2; - padding: 1px 5px; - border-radius: 3px; - font-size: 10.5px; -} - -.settings-status { - font-size: 12px; - color: #59636a; -} - -.settings-status.ok { - color: #078f49; -} - -.settings-status.fail { - color: #c73737; -} - -.settings-toggle { - display: inline-flex; - align-items: center; - gap: 8px; - cursor: pointer; - font-size: 13px; - color: #30383d; -} - -.settings-toggle input { - width: 16px; - height: 16px; - accent-color: #07c160; - cursor: pointer; -} - -.settings-self { - display: flex; - align-items: center; - gap: 12px; -} - -.settings-self-avatar { - width: 56px; - height: 56px; - border-radius: 10px; - background: #07c160; - color: #fff; - display: flex; - align-items: center; - justify-content: center; - font-size: 22px; - font-weight: 500; - overflow: hidden; - flex-shrink: 0; -} - -.settings-self-avatar img { - width: 100%; - height: 100%; - object-fit: cover; -} - -.settings-self-info { - flex: 1; - min-width: 0; -} - -.settings-self-nickname { - font-size: 15px; - font-weight: 600; - color: #1f2429; -} - -.settings-self-wxid { - font-size: 12px; - color: #6f767c; - margin-top: 2px; - font-family: 'SF Mono', Menlo, Consolas, monospace; -} - -.settings-self-account { - font-size: 11px; - color: #8a9298; - margin-top: 2px; - word-break: break-all; -} - -.settings-self-empty { - font-size: 13px; - color: #8a9298; -} - -.settings-path { - display: inline-block; - font-family: 'SF Mono', Menlo, Consolas, monospace; - font-size: 11px; - background: #eef0f2; - padding: 3px 7px; - border-radius: 4px; - color: #30383d; - word-break: break-all; - max-width: 100%; -} - -.app-toast { - position: fixed; - top: 18px; - left: calc(var(--wxex-nav-width) + 50%); - z-index: 40; - transform: translateX(-50%); - padding: 9px 14px; - border: 1px solid rgba(198, 134, 53, 0.35); - border-radius: var(--wxex-radius-md); - background: #fff9ef; - color: #7b4b14; - font: 13px/18px var(--wxex-font); - box-shadow: var(--wxex-shadow-popover); -} - -.report-page { - display: grid; - grid-template-columns: 292px minmax(420px, 1fr) 304px; - width: 100%; - height: 100%; - min-height: 0; - min-width: 0; - overflow: hidden; - background: var(--wxex-bg-main); -} - -.report-center-page { - display: grid; - grid-template-columns: 292px minmax(420px, 1fr) 304px; - width: 100%; - height: 100%; - min-height: 0; - min-width: 0; - overflow: hidden; - background: var(--wxex-bg-main); -} - -.report-page > *, -.report-center-page > * { - min-height: 0; - min-width: 0; -} - -.report-source-sidebar { - display: flex; - min-width: 0; - min-height: 0; - height: 100%; - flex-direction: column; - overflow: hidden; - border-right: 1px solid var(--wxex-border); - background: var(--wxex-bg-sidebar); -} - -.report-source-header { - display: flex; - flex: 0 0 auto; - align-items: flex-start; - justify-content: space-between; - gap: 12px; - padding: 18px 16px 12px; - border-bottom: 1px solid var(--wxex-border); -} - -.report-source-header h2, -.ai-report-header h1, -.report-task-header h2 { - margin: 0; - color: var(--wxex-text-primary); -} - -.report-source-header h2 { - font: 700 18px/24px var(--wxex-font); -} - -.report-source-header p, -.ai-report-header p, -.report-task-header p { - margin: 4px 0 0; - color: var(--wxex-text-secondary); - font: 12px/18px var(--wxex-font); -} - -.report-source-header > span { - flex: 0 0 auto; - margin-top: 3px; - color: var(--wxex-text-muted); - font: 12px/18px var(--wxex-font); -} - -.report-source-search { - display: flex; - flex: 0 0 auto; - align-items: center; - gap: 8px; - margin: 12px 14px; - padding: 0 10px; - height: 36px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); - color: var(--wxex-text-muted); -} - -.report-source-search svg { - width: 16px; - height: 16px; -} - -.report-source-search path, -.report-source-search circle { - fill: none; - stroke: currentColor; - stroke-width: 1.8; - stroke-linecap: round; - stroke-linejoin: round; -} - -.report-source-search input { - min-width: 0; - flex: 1; - border: 0; - outline: 0; - background: transparent; - color: var(--wxex-text-primary); - font: 13px/18px var(--wxex-font); -} - -.report-source-list { - flex: 1 1 auto; - min-height: 0; - overflow-y: auto; - padding: 0 10px 12px; -} - -.report-source-item { - position: relative; - display: flex; - width: 100%; - min-width: 0; - align-items: center; - gap: 10px; - padding: 10px 10px 10px 12px; - border: 0; - border-radius: var(--wxex-radius-md); - background: transparent; - color: var(--wxex-text-primary); - text-align: left; - cursor: pointer; - font-family: var(--wxex-font); -} - -.report-source-item:hover { - background: rgba(255, 255, 255, 0.62); -} - -.report-source-item.active { - background: var(--wxex-brand-soft); - color: var(--wxex-brand); -} - -.report-source-item.active::before { - position: absolute; - left: 0; - top: 8px; - bottom: 8px; - width: 3px; - border-radius: 4px; - background: var(--wxex-brand); - content: ''; -} - -.report-source-avatar { - display: grid; - width: 36px; - height: 36px; - flex: 0 0 auto; - place-items: center; - overflow: hidden; - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); - color: var(--wxex-brand); - font: 700 14px/1 var(--wxex-font); -} - -.report-source-avatar img { - width: 100%; - height: 100%; - object-fit: cover; -} - -.report-source-text { - display: grid; - min-width: 0; -} - -.report-source-text span { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.report-source-text span { - color: inherit; - font: 600 13px/18px var(--wxex-font); -} - -.report-source-empty { - padding: 18px 8px; - color: var(--wxex-text-muted); - font: 13px/18px var(--wxex-font); -} - -.report-source-account { - flex: 0 0 auto; - padding: 12px; - border-top: 1px solid var(--wxex-border); -} - -.ai-report-workspace { - display: flex; - min-width: 0; - min-height: 0; - height: 100%; - flex-direction: column; - overflow: hidden; - background: var(--wxex-bg-main); -} - -.ai-report-header { - display: flex; - flex: 0 0 auto; - align-items: flex-start; - justify-content: space-between; - gap: 18px; - padding: 22px 28px 16px; - border-bottom: 1px solid var(--wxex-border); -} - -.ai-report-header h1 { - font: 700 21px/28px var(--wxex-font); -} - -.ai-report-header p { - font-size: 13px; -} - -.report-inline-error { - max-width: 320px; - padding: 8px 10px; - border: 1px solid rgba(200, 90, 90, 0.35); - border-radius: var(--wxex-radius-md); - background: #fff4f4; - color: var(--wxex-danger); - font: 12px/17px var(--wxex-font); -} - -.ai-report-body { - flex: 1 1 auto; - min-height: 0; - overflow-y: auto; - overflow-x: hidden; - padding: 18px 28px 20px; -} - -.ai-report-body > * { - max-width: 720px; -} - -.ai-report-body > .report-section + .report-section { - margin-top: 28px; -} - -.report-empty-state, -.report-config-section, -.report-privacy-note, -.report-result-panel { - margin-bottom: 16px; - padding: 16px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-lg); - background: var(--wxex-bg-elevated); -} - -.report-empty-state h2, -.report-privacy-note h3, -.report-config-section h3, -.report-result-panel h3 { - margin: 0; - color: var(--wxex-text-primary); - font: 700 15px/20px var(--wxex-font); -} - -.report-timeout-section { - display: flex; - align-items: center; - justify-content: space-between; - gap: 20px; -} - -.report-timeout-section p { - margin: 6px 0 0; - color: var(--wxex-text-secondary); - font-size: 12px; -} - -.report-timeout-section label { - display: flex; - flex: 0 0 auto; - align-items: center; - gap: 8px; - color: var(--wxex-text-secondary); - font-size: 13px; -} - -.report-timeout-section input { - width: 96px; - height: 36px; - padding: 0 10px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: #fff; - color: var(--wxex-text-primary); - font: 500 13px var(--wxex-font); -} - -.report-empty-state p, -.report-privacy-note p { - margin: 6px 0 0; - color: var(--wxex-text-secondary); - font: 13px/19px var(--wxex-font); -} - -.report-section-heading { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; - margin-bottom: 12px; -} - -.report-section-heading span { - color: var(--wxex-text-muted); - font: 12px/18px var(--wxex-font); -} - -.report-section-heading span.danger { - color: var(--wxex-danger); -} - -.report-range-options, -.report-density-options { - display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); - gap: 8px; -} - -.report-density-options { - grid-template-columns: repeat(3, minmax(0, 1fr)); -} - -.report-range-options button, -.report-density-options button, -.report-model-summary button, -.report-result-actions button, -.report-task-error button, -.ai-report-footer button { - min-height: 34px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); - color: var(--wxex-text-primary); - cursor: pointer; - font: 600 13px/18px var(--wxex-font); -} - -.report-range-options button.active, -.report-density-options button.active { - border-color: var(--wxex-brand); - background: var(--wxex-brand-soft); - color: var(--wxex-brand); -} - -.report-range-options button:disabled, -.report-density-options button:disabled { - color: var(--wxex-text-muted); - cursor: not-allowed; - opacity: 0.75; -} - -.report-range-options button span, -.report-density-options button span { - display: block; - margin-top: 2px; - font: 11px/14px var(--wxex-font); -} - -.report-type-grid { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 8px; -} - -.report-check-row { - display: grid; - grid-template-columns: auto minmax(0, 1fr) auto; - align-items: start; - gap: 8px; - padding: 10px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: #fbfcfb; - color: var(--wxex-text-primary); -} - -.report-check-row input { - margin-top: 2px; - accent-color: var(--wxex-brand); -} - -.report-check-row span { - display: grid; - min-width: 0; - gap: 2px; -} - -.report-check-row b { - font: 600 13px/18px var(--wxex-font); -} - -.report-check-row small { - color: var(--wxex-text-muted); - font: 12px/16px var(--wxex-font); -} - -.report-check-row em { - color: var(--wxex-text-secondary); - font: normal 12px/18px var(--wxex-font); -} - -.report-readonly-modules { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 8px; - cursor: default; -} - -.report-readonly-modules span { - display: flex; - min-width: 0; - align-items: center; - gap: 8px; - padding: 8px 10px; - border: 1px solid #e9eeeb; - border-radius: var(--wxex-radius-md); - background: #f7f9f8; - color: var(--wxex-text-secondary); - font: 12px/17px var(--wxex-font); - cursor: default; -} - -.report-readonly-modules svg { - width: 14px; - height: 14px; - flex: 0 0 auto; - color: var(--wxex-text-muted); -} - -.report-readonly-modules rect, -.report-readonly-modules path { - fill: none; - stroke: currentColor; - stroke-width: 1.7; - stroke-linecap: round; - stroke-linejoin: round; -} - -.report-model-summary { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; -} - -.report-model-summary p { - margin: 4px 0 0; - color: var(--wxex-text-secondary); - font: 13px/18px var(--wxex-font); -} - -.report-model-summary button, -.report-result-actions button, -.report-task-error button { - padding: 0 12px; -} - -.report-result-preview { - max-height: 460px; - overflow: auto; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: #f6f4f0; - text-align: center; -} - -.report-result-preview img { - display: inline-block; - width: min(100%, 430px); - height: auto; -} - -.report-result-actions { - display: flex; - gap: 8px; - margin-top: 10px; -} - -.report-action-status { - margin: 8px 0 0; - color: var(--wxex-text-secondary); - font: 12px/16px var(--wxex-font); -} - -.ai-report-footer { - display: flex; - flex: 0 0 auto; - min-height: 66px; - align-items: center; - justify-content: space-between; - gap: 16px; - padding: 12px 28px; - border-top: 1px solid var(--wxex-border); - background: var(--wxex-bg-main); -} - -.report-footer-note, -.report-footer-actions span { - min-width: 0; - color: var(--wxex-text-secondary); - font: 12px/18px var(--wxex-font); -} - -.report-footer-note { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.report-footer-actions { - display: flex; - min-width: 0; - flex: 0 0 auto; - align-items: center; - gap: 12px; -} - -.report-footer-actions span { - max-width: 280px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.ai-report-footer button { - min-width: 132px; - padding: 0 16px; - border-color: var(--wxex-ai); - background: var(--wxex-ai); - color: #fff; -} - -.ai-report-footer button.secondary { - min-width: 92px; - border-color: var(--wxex-border); - background: var(--wxex-bg-elevated); - color: var(--wxex-text-primary); -} - -.ai-report-footer button:disabled { - border-color: var(--wxex-border); - background: #e8ebe9; - color: var(--wxex-text-muted); - cursor: not-allowed; -} - -.report-task-panel { - display: flex; - min-width: 0; - min-height: 0; - height: 100%; - flex-direction: column; - overflow: hidden; - border-left: 1px solid var(--wxex-border); - background: #f7f9f8; -} - -.report-task-header { - flex: 0 0 auto; - padding: 20px 18px 14px; - border-bottom: 1px solid var(--wxex-border); -} - -.report-task-header h2 { - font: 700 16px/22px var(--wxex-font); -} - -.report-task-steps { - flex: 0 0 auto; - padding: 16px 18px; -} - -.report-task-step { - display: grid; - grid-template-columns: 18px minmax(0, 1fr); - gap: 10px; - padding: 0 0 18px; - color: var(--wxex-text-muted); -} - -.report-task-step b { - display: block; - color: inherit; - font: 600 13px/18px var(--wxex-font); -} - -.report-task-step small { - color: var(--wxex-text-muted); - font: 12px/16px var(--wxex-font); -} - -.report-task-dot { - width: 12px; - height: 12px; - margin-top: 3px; - border: 2px solid var(--wxex-border); - border-radius: 50%; - background: transparent; -} - -.report-task-step.done { - color: var(--wxex-success); -} - -.report-task-step.done .report-task-dot { - border-color: var(--wxex-success); - background: var(--wxex-success); -} - -.report-task-step.active { - color: var(--wxex-ai); -} - -.report-task-step.active .report-task-dot { - border-color: var(--wxex-ai); - background: var(--wxex-ai-soft); -} - -.report-task-error, -.report-task-success, -.report-task-note { - margin: 0 18px 14px; - padding: 12px; - border-radius: var(--wxex-radius-md); - font: 12px/18px var(--wxex-font); -} - -.report-task-error { - border: 1px solid rgba(200, 90, 90, 0.35); - background: #fff4f4; - color: var(--wxex-danger); -} - -.report-task-success { - border: 1px solid rgba(46, 139, 104, 0.28); - background: var(--wxex-brand-soft); - color: var(--wxex-success); -} - -.report-task-note { - margin-top: auto; - flex: 0 0 auto; - color: var(--wxex-text-secondary); - background: var(--wxex-ai-soft); -} - -.report-task-error p, -.report-task-success p { - margin: 4px 0 10px; -} - -.report-task-error button + button { - margin-left: 8px; -} - -.report-task-log-path { - display: block; - margin-top: 8px; - overflow-wrap: anywhere; - color: var(--wxex-text-secondary); - font: 11px/16px var(--wxex-font); -} - -@media (max-width: 1120px) { - .report-page { - grid-template-columns: 268px minmax(360px, 1fr) 280px; - } - - .report-type-grid { - grid-template-columns: 1fr; - } - - .report-readonly-modules { - grid-template-columns: 1fr; - } -} - -.agent-hub-workspace { - box-sizing: border-box; - width: 100%; - height: 100%; - min-width: 0; - overflow: auto; - padding: 34px 40px 48px; - background: #fafbfa; -} -.agent-hub-header { - display: flex; - align-items: flex-start; - justify-content: space-between; - gap: 24px; - max-width: 1080px; - margin: 0 auto 28px; -} -.agent-hub-eyebrow, -.agent-hub-card-kicker { - color: var(--wxex-brand); - font: 700 11px/16px var(--wxex-font); - letter-spacing: 0.08em; - text-transform: uppercase; -} -.agent-hub-header h1 { - margin: 4px 0 6px; - color: var(--wxex-text-primary); - font: 750 28px/36px var(--wxex-font); -} -.agent-hub-header p, -.agent-hub-card p { - margin: 0; - color: var(--wxex-text-secondary); - font: 13px/20px var(--wxex-font); -} -.agent-hub-runtime { - display: inline-flex; - align-items: center; - padding: 6px 10px; - border-radius: 999px; - background: #f0f2f0; - color: var(--wxex-text-muted); - font: 700 12px/18px var(--wxex-font); -} -.agent-hub-runtime.online { - background: #e8f6ed; - color: #24864b; -} -.agent-hub-runtime.error { - background: #fff0ef; - color: var(--wxex-danger); -} -.agent-hub-grid { - display: grid; - grid-template-columns: minmax(0, 1.55fr) minmax(280px, 0.75fr); - gap: 20px; - max-width: 1080px; - margin: 0 auto; -} -.agent-hub-card { - box-sizing: border-box; - min-width: 0; - border: 1px solid var(--wxex-border); - border-radius: 18px; - background: var(--wxex-bg-elevated); - box-shadow: 0 8px 28px rgba(28, 38, 31, 0.045); -} -.agent-hub-login-card { - min-height: 520px; - padding: 26px; - display: flex; - flex-direction: column; -} -.agent-hub-capability-card { - padding: 26px; - align-self: start; -} -.agent-hub-card-heading { - display: flex; - align-items: flex-start; - justify-content: space-between; - gap: 16px; - padding-bottom: 20px; - border-bottom: 1px solid var(--wxex-border); -} -.agent-hub-card h2 { - margin: 4px 0 0; - color: var(--wxex-text-primary); - font: 700 19px/27px var(--wxex-font); -} -.agent-hub-status { - display: inline-flex; - align-items: center; - gap: 7px; - padding: 5px 9px; - border-radius: 999px; - background: #f2f3f2; - color: var(--wxex-text-secondary); - font: 650 12px/18px var(--wxex-font); - white-space: nowrap; -} -.agent-hub-status i { - width: 7px; - height: 7px; - border-radius: 50%; - background: #9aa39d; -} -.agent-hub-status.online { - background: #e8f6ed; - color: #24864b; -} -.agent-hub-status.online i { - background: #35a663; -} -.agent-hub-status.waiting_scan, -.agent-hub-status.scanned, -.agent-hub-status.starting { - background: #fff5de; - color: #9b6a12; -} -.agent-hub-status.waiting_scan i, -.agent-hub-status.scanned i, -.agent-hub-status.starting i { - background: #d89b2b; -} -.agent-hub-status.error { - background: #fff0ef; - color: var(--wxex-danger); -} -.agent-hub-status.error i { - background: var(--wxex-danger); -} -.agent-hub-empty-login { - flex: 1; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - min-height: 280px; - text-align: center; -} -.agent-hub-empty-login h3, -.agent-hub-connected h3, -.agent-hub-qr-copy h3 { - margin: 18px 0 6px; - color: var(--wxex-text-primary); - font: 700 16px/24px var(--wxex-font); -} -.agent-hub-empty-login p { - max-width: 360px; -} -.agent-hub-phone { - width: 64px; - height: 88px; - position: relative; - border: 2px solid #9eb3a5; - border-radius: 13px; - background: linear-gradient(145deg, #f6fbf7, #eaf4ed); -} -.agent-hub-phone::before { - content: ''; - position: absolute; - top: 8px; - left: 22px; - width: 18px; - height: 3px; - border-radius: 3px; - background: #b8c8bd; -} -.agent-hub-phone span { - position: absolute; - left: 23px; - bottom: 8px; - width: 16px; - height: 16px; - border: 1.5px solid var(--wxex-brand); - border-radius: 50%; -} -.agent-hub-actions { - display: flex; - justify-content: center; - gap: 10px; - min-height: 38px; - padding-top: 18px; -} -.agent-hub-button { - height: 38px; - padding: 0 16px; - border: 1px solid transparent; - border-radius: 9px; - font: 650 13px/20px var(--wxex-font); - cursor: pointer; -} -.agent-hub-button:disabled { - opacity: 0.55; - cursor: default; -} -.agent-hub-button.primary { - background: var(--wxex-brand); - color: #fff; -} -.agent-hub-button.secondary { - border-color: var(--wxex-border-strong); - background: #fff; - color: var(--wxex-text-primary); -} -.agent-hub-button.danger { - border-color: #f0c6c2; - background: #fff8f7; - color: var(--wxex-danger); -} -.agent-hub-qr-panel { - flex: 1; - display: flex; - align-items: center; - justify-content: center; - gap: 32px; - min-height: 320px; - padding: 22px 0; -} -.agent-hub-qr-frame { - box-sizing: border-box; - width: 220px; - height: 220px; - flex: 0 0 220px; - display: grid; - place-items: center; - padding: 12px; - border: 1px solid var(--wxex-border); - border-radius: 16px; - background: #fff; - box-shadow: 0 10px 30px rgba(23, 44, 30, 0.08); -} -.agent-hub-qr-frame img { - width: 100%; - height: 100%; - display: block; - image-rendering: pixelated; -} -.agent-hub-qr-copy { - max-width: 260px; -} -.agent-hub-qr-copy h3 { - margin-top: 0; -} -.agent-hub-qr-copy .agent-hub-button { - margin-top: 18px; -} -.agent-hub-connected { - flex: 1; - min-height: 300px; - display: flex; - align-items: center; - justify-content: center; - gap: 16px; -} -.agent-hub-connected h3 { - margin: 0 0 4px; -} -.agent-hub-connected-icon { - width: 48px; - height: 48px; - display: grid; - place-items: center; - border-radius: 50%; - background: #e4f5ea; - color: #23834a; - font: 800 22px/1 var(--wxex-font); -} -.agent-hub-capability-card > p { - margin-top: 8px; -} -.agent-hub-example { - margin: 24px 0 20px; - padding: 16px; - border-radius: 12px; - background: var(--wxex-brand-soft); -} -.agent-hub-example span { - display: block; - color: var(--wxex-text-muted); - font: 600 11px/16px var(--wxex-font); -} -.agent-hub-example strong { - display: block; - margin-top: 4px; - color: var(--wxex-brand); - font: 700 14px/21px var(--wxex-font); -} -.agent-hub-capability-card ul { - margin: 0; - padding: 0; - list-style: none; -} -.agent-hub-capability-card li { - display: flex; - align-items: center; - gap: 9px; - padding: 9px 0; - border-bottom: 1px solid var(--wxex-border); - color: var(--wxex-text-secondary); - font: 13px/19px var(--wxex-font); -} -.agent-hub-capability-card li:last-child { - border-bottom: 0; -} -.agent-hub-capability-card li i { - width: 7px; - height: 7px; - border-radius: 50%; - background: var(--wxex-brand); -} -.agent-hub-example strong + strong { - margin-top: 9px; - padding-top: 9px; - border-top: 1px solid rgba(36, 122, 99, 0.15); -} -.agent-hub-capability-card li i.offline { - background: var(--wxex-danger); -} -.agent-hub-log-card { - max-width: 1080px; - margin: 20px auto 0; - padding: 22px; -} -.agent-hub-log-heading { - display: flex; - align-items: center; - justify-content: space-between; - gap: 16px; - margin-bottom: 14px; -} -.agent-hub-log-heading h2 { - margin-top: 3px; -} -.agent-hub-log-actions { - display: flex; - align-items: center; - gap: 8px; -} -.agent-hub-log-actions select, -.agent-hub-log-actions button { - height: 32px; - border: 1px solid var(--wxex-border-strong); - border-radius: 8px; - background: #fff; - color: var(--wxex-text-secondary); - font: 600 12px/18px var(--wxex-font); -} -.agent-hub-log-actions select { - padding: 0 28px 0 10px; -} -.agent-hub-log-actions button { - padding: 0 11px; - cursor: pointer; -} -.agent-hub-log-actions button:disabled { - opacity: 0.45; - cursor: default; -} -.agent-hub-log-body { - height: 250px; - overflow: auto; - padding: 12px 14px; - border: 1px solid #26312a; - border-radius: 11px; - background: #18201b; - color: #dfe9e2; -} -.agent-hub-log-line { - display: grid; - grid-template-columns: 78px 94px minmax(0, 1fr); - gap: 9px; - align-items: baseline; - min-height: 24px; - font: - 12px/19px ui-monospace, - SFMono-Regular, - Menlo, - monospace; -} -.agent-hub-log-line time { - color: #84938a; -} -.agent-hub-log-line .source { - color: #76d49a; -} -.agent-hub-log-line .source.wechat-connector { - color: #7dbcf1; -} -.agent-hub-log-line .source.system { - color: #d8bd6b; -} -.agent-hub-log-line code { - min-width: 0; - color: inherit; - white-space: pre-wrap; - overflow-wrap: anywhere; -} -.agent-hub-log-line.warn code { - color: #f1cf77; -} -.agent-hub-log-line.error code { - color: #ff9690; -} -.agent-hub-log-empty { - height: 100%; - display: grid; - place-items: center; - color: #84938a; - font: 12px/20px var(--wxex-font); -} -.agent-hub-log-note { - margin-top: 9px !important; - color: var(--wxex-text-muted) !important; - font-size: 11px !important; -} -@media (max-width: 900px) { - .agent-hub-workspace { - padding: 24px; - } - .agent-hub-grid { - grid-template-columns: 1fr; - } - .agent-hub-qr-panel { - flex-direction: column; - text-align: center; - } - .agent-hub-capability-card { - width: 100%; - } -} - -.ai-vision-test { - display: grid; - gap: 16px; -} - -.ai-vision-test > header, -.ai-vision-test > footer, -.ai-vision-model { - display: flex; - align-items: center; - justify-content: space-between; - gap: 16px; -} - -.ai-vision-test h2, -.ai-vision-test h3, -.ai-vision-test p { - margin: 0; -} - -.ai-vision-test h2 { - color: #202724; - font-size: 15px; -} - -.ai-vision-test header h3 { - margin-top: 12px; - color: #35403b; - font-size: 13px; -} - -.ai-vision-test header p, -.ai-vision-model, -.ai-vision-upload small { - margin-top: 4px; - color: #66706b; - font-size: 12px; -} - -.ai-vision-capability { - border-radius: 999px; - padding: 5px 9px; - background: #f1f3f2; - color: #66706b; - white-space: nowrap; - font-size: 12px; -} - -.ai-vision-capability.supported { - background: #eaf5f1; - color: #2e8b68; -} - -.ai-vision-model { - justify-content: flex-start; - margin: 0; -} - -.ai-vision-upload { - display: flex; - min-height: 112px; - align-items: center; - justify-content: center; - gap: 14px; - border: 1px dashed #bfc9c4; - border-radius: 10px; - padding: 14px; - background: #f7f9f8; - color: #35403b; - text-align: center; - cursor: pointer; -} - -.ai-vision-upload:hover { - border-color: #247a63; - background: #f2f8f5; -} - -.ai-vision-upload input { - display: none; -} - -.ai-vision-upload.has-image { - justify-content: flex-start; - text-align: left; -} - -.ai-vision-upload img { - width: 112px; - height: 82px; - flex: 0 0 auto; - border-radius: 8px; - object-fit: cover; -} - -.ai-vision-upload strong, -.ai-vision-upload small { - display: block; -} - -.ai-vision-prompt { - display: grid; - gap: 7px; - color: #46514c; - font-size: 12px; - font-weight: 600; -} - -.ai-vision-prompt textarea { - width: 100%; - border: 1px solid #d5ddda; - border-radius: 8px; - outline: none; - padding: 10px; - resize: vertical; - background: #f4f7f5; - color: #202724; - font: 13px/1.6 var(--wxex-font); -} - -.ai-vision-prompt textarea:focus { - border-color: #247a63; - box-shadow: 0 0 0 2px rgba(36, 122, 99, 0.08); -} - -.ai-vision-privacy { - color: #66706b; - font-size: 12px; - line-height: 1.6; -} - -.ai-vision-error { - border-left: 3px solid #c85a5a; - padding: 9px 11px; - background: #fff2f2; - color: #a84444; - font-size: 12px; -} - -.ai-vision-result { - display: grid; - gap: 12px; - border: 1px solid #dce7e2; - border-radius: 9px; - padding: 14px; - background: #f7faf9; -} - -.ai-vision-result dl { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 12px; - margin: 0; -} - -.ai-vision-result dt { - color: #929a96; - font-size: 11px; -} - -.ai-vision-result dd { - margin: 4px 0 0; - color: #35403b; - font-size: 12px; - font-weight: 600; -} - -.ai-vision-result > p { - white-space: pre-wrap; - color: #3d4742; - font-size: 13px; - line-height: 1.7; -} - -.ai-vision-test > footer { - justify-content: flex-end; -} - -.ai-vision-test > footer button { - min-height: 34px; - border: 1px solid #d5ddda; - border-radius: 7px; - padding: 0 13px; - background: #fff; - color: #46514c; - cursor: pointer; -} - -.ai-vision-test > footer button:disabled { - cursor: not-allowed; - opacity: 0.5; -} - -.report-density-options button:disabled:hover { - border-color: var(--wxex-border); - background: var(--wxex-bg-elevated); - color: var(--wxex-text-muted); -} - -.report-density-options button.active:disabled { - border-color: var(--wxex-brand); - background: var(--wxex-brand-soft); - color: var(--wxex-brand); - opacity: 1; - cursor: default; -} - -.report-history-sidebar { - display: flex; - min-width: 0; - min-height: 0; - height: 100%; - flex-direction: column; - overflow: hidden; - border-right: 1px solid var(--wxex-border); - background: var(--wxex-bg-sidebar); -} - -.report-history-header { - display: flex; - flex: 0 0 auto; - align-items: flex-start; - justify-content: space-between; - gap: 12px; - padding: 18px 16px 12px; - border-bottom: 1px solid var(--wxex-border); -} - -.report-history-header h2, -.report-settings-panel header h2, -.report-viewer-header h1 { - margin: 0; - color: var(--wxex-text-primary); -} - -.report-history-header h2 { - font: 700 18px/24px var(--wxex-font); -} - -.report-history-header p, -.report-settings-panel header p, -.report-viewer-header p { - margin: 4px 0 0; - color: var(--wxex-text-secondary); - font: 12px/18px var(--wxex-font); -} - -.report-history-header > span { - color: var(--wxex-text-muted); - font: 12px/18px var(--wxex-font); -} - -.report-history-search { - display: flex; - flex: 0 0 auto; - align-items: center; - gap: 8px; - margin: 12px 14px 8px; - padding: 0 10px; - height: 36px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); - color: var(--wxex-text-muted); -} - -.report-history-search svg { - width: 16px; - height: 16px; -} - -.report-history-search path, -.report-history-search circle { - fill: none; - stroke: currentColor; - stroke-width: 1.8; - stroke-linecap: round; - stroke-linejoin: round; -} - -.report-history-search input { - min-width: 0; - flex: 1; - border: 0; - outline: 0; - background: transparent; - color: var(--wxex-text-primary); - font: 13px/18px var(--wxex-font); -} - -.report-history-create { - flex: 0 0 auto; - height: 36px; - margin: 0 14px 12px; - border: 1px solid var(--wxex-brand); - border-radius: var(--wxex-radius-md); - background: var(--wxex-brand); - color: #fff; - cursor: pointer; - font: 700 13px/18px var(--wxex-font); -} - -.report-history-list { - flex: 1 1 auto; - min-height: 0; - overflow-x: hidden; - overflow-y: auto; - padding: 0 10px 12px; -} - -/* API-01 本地 API 中心 */ -.api-center-layout { - display: grid; - grid-template-columns: minmax(0, 1fr) 320px; - width: 100%; - height: 100%; - min-width: 0; - min-height: 0; - overflow: hidden; - background: var(--wxex-bg-main); -} - -/* SETTINGS-01: formal settings workspace. The legacy SettingsPanel remains only as a fallback source. */ -.settings-workspace { - display: flex; - width: 100%; - height: 100%; - min-width: 0; - min-height: 0; - overflow: hidden; - background: #fafbfa; -} - -.settings-page-panel { - display: none; - min-width: 0; - min-height: 0; - flex: 1 1 auto; -} - -.settings-page-panel.active { - display: flex; -} -.settings-sidebar { - width: 294px; - flex: 0 0 294px; - min-width: 0; - min-height: 0; - display: flex; - flex-direction: column; - background: #eef2f0; - border-right: 1px solid #dde3e0; -} -.settings-sidebar header { - padding: 22px 20px 16px; - border-bottom: 1px solid #dde3e0; -} -.settings-sidebar h1 { - margin: 0; - color: #202724; - font-size: 20px; -} -.settings-sidebar header p { - margin: 5px 0 16px; - color: #66706b; - font-size: 12px; -} -.settings-search { - height: 34px; - display: flex; - align-items: center; - gap: 8px; - padding: 0 10px; - border: 1px solid #dde3e0; - border-radius: 8px; - background: #fff; - color: #66706b; -} -.settings-search input { - min-width: 0; - width: 100%; - border: 0; - outline: 0; - color: #202724; - background: transparent; - font: inherit; - font-size: 12px; -} -.settings-sidebar-list { - flex: 1; - min-height: 0; - overflow: auto; - padding: 12px 8px; -} -.settings-sidebar-list section { - margin: 0 0 18px; -} -.settings-sidebar-list h2 { - margin: 0 12px 6px; - color: #929a96; - font-size: 12px; - font-weight: 500; -} -.settings-sidebar-list button { - position: relative; - display: block; - width: 100%; - border: 0; - padding: 9px 12px; - background: transparent; - color: #39433e; - text-align: left; - font: 600 13px inherit; - cursor: pointer; - border-radius: 8px; -} -.settings-sidebar-list button.active { - background: #fff; - color: #202724; -} -.settings-sidebar-list button.active::before { - content: ''; - position: absolute; - left: 0; - top: 7px; - bottom: 7px; - width: 3px; - border-radius: 0 3px 3px 0; - background: #247a63; -} -.settings-sidebar-account { - flex: 0 0 auto; - padding: 10px; - border-top: 1px solid #dde3e0; -} -.settings-page { - position: relative; - display: flex; - flex: 1; - min-width: 0; - min-height: 0; - flex-direction: column; -} -.settings-page-header { - flex: 0 0 auto; - display: flex; - justify-content: space-between; - align-items: flex-start; - gap: 18px; - padding: 24px 34px; - border-bottom: 1px solid #eef1ef; - background: #fafbfa; -} -.settings-page-header h1 { - margin: 0; - color: #202724; - font-size: 21px; -} -.settings-page-header p { - margin: 6px 0 0; - color: #66706b; - font-size: 13px; -} -.settings-status-badge { - margin-top: 5px; - flex: 0 0 auto; - border-radius: 16px; - padding: 7px 12px; - background: #edf5f1; - color: #2e8b68; - font-size: 12px; -} -.settings-status-badge::before { - content: '●'; - margin-right: 6px; - font-size: 9px; -} -.settings-status-badge.checking { - background: #eef4f8; - color: #4f7188; -} -.settings-status-badge.warning { - background: #fff6e8; - color: #a56a24; -} -.settings-status-badge.error { - background: #f9eeee; - color: #c85a5a; -} -.settings-status-badge.unavailable { - background: #f1f3f2; - color: #66706b; -} -.settings-page-scroll { - flex: 1; - min-height: 0; - overflow-y: auto; - overflow-x: hidden; -} -.settings-page-content { - box-sizing: border-box; - width: min(100%, 860px); - padding: 34px 34px 64px; -} -.settings-privacy-notice { - display: flex; - gap: 14px; - align-items: flex-start; - padding: 17px; - border: 1px solid #bfded3; - border-radius: 10px; - background: #f0f7f4; - color: #36564d; -} -.settings-privacy-notice svg { - flex: 0 0 24px; - width: 24px; - stroke: #247a63; - fill: none; - stroke-width: 1.8; -} -.settings-privacy-notice strong { - color: #294b41; - font-size: 14px; -} -.settings-privacy-notice p { - margin: 5px 0 0; - color: #66706b; - font-size: 13px; - line-height: 1.6; -} -.settings-section-heading { - margin: 30px 0 14px; - color: #3d4742; - font-size: 16px; -} -.settings-card { - border: 1px solid #dde3e0; - border-radius: 10px; - background: #fff; - padding: 24px 26px; -} -.settings-account-overview { - display: grid; - grid-template-columns: minmax(190px, 1fr) minmax(220px, 1fr) auto; - gap: 24px; - align-items: center; -} -.settings-account-primary { - display: flex; - min-width: 0; - align-items: center; - gap: 15px; -} -.settings-avatar { - width: 66px; - height: 66px; - flex: 0 0 auto; - overflow: hidden; - display: grid; - place-items: center; - border-radius: 9px; - background: #dcede6; - color: #247a63; - font-size: 23px; -} -.settings-avatar img { - width: 100%; - height: 100%; - object-fit: cover; -} -.settings-account-identity { - display: grid; - min-width: 0; - gap: 3px; -} -.settings-account-identity span, -.settings-account-root > span, -.settings-account-facts dt { - color: #929a96; - font-size: 12px; -} -.settings-account-identity strong, -.settings-account-identity small { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.settings-account-identity strong { - color: #35403b; - font-size: 14px; -} -.settings-account-identity small { - color: #66706b; - font: - 12px/18px ui-monospace, - SFMono-Regular, - Consolas, - monospace; -} -.settings-account-facts { - display: grid; - min-width: 0; - gap: 12px; - margin: 0; -} -.settings-account-facts div { - min-width: 0; -} -.settings-account-facts dd { - overflow: hidden; - margin: 3px 0 0; - color: #35403b; - font-size: 13px; - text-overflow: ellipsis; - white-space: nowrap; -} -.settings-connection-text.success { - color: #2e8b68; -} -.settings-connection-text.warning { - color: #a56a24; -} -.settings-connection-text.error { - color: #c85a5a; -} -.settings-account-actions { - display: grid; - gap: 8px; -} -.settings-account-actions button { - min-height: 34px; - white-space: nowrap; -} -.settings-account-root { - grid-column: 1/-1; - display: grid; - min-width: 0; - gap: 7px; - padding-top: 19px; - border-top: 1px solid #edf0ee; -} -.settings-account-root > div { - display: flex; - min-width: 0; - align-items: center; - gap: 8px; -} -.settings-account-root code { - min-width: 0; - flex: 1; - overflow: hidden; - padding: 10px 12px; - border: 1px solid #dde3e0; - border-radius: 8px; - background: #f2f5f3; - color: #46514c; - text-overflow: ellipsis; - white-space: nowrap; - font: - 12px/18px ui-monospace, - SFMono-Regular, - Consolas, - monospace; -} -.settings-icon-button { - display: grid; - width: 36px; - height: 36px; - flex: 0 0 auto; - place-items: center; - border: 1px solid #dde3e0; - border-radius: 8px; - background: #fff; - color: #66706b; - cursor: pointer; -} -.settings-icon-button:hover:not(:disabled) { - border-color: #247a63; - color: #247a63; -} -.settings-icon-button:disabled { - cursor: not-allowed; - opacity: 0.45; -} -.settings-icon-button svg { - width: 17px; - fill: none; - stroke: currentColor; - stroke-linecap: round; - stroke-linejoin: round; - stroke-width: 1.8; -} -.settings-health-card { - padding: 12px; -} -.settings-diagnostic-summary { - margin: 0 0 10px; - padding: 9px 11px; - border-left: 3px solid #c68635; - border-radius: 6px; - background: #fff8ec; - color: #79501f; - font-size: 12px; - line-height: 1.55; -} -.settings-diagnostics { - display: grid; - gap: 8px; -} -.settings-diagnostic { - display: flex; - align-items: center; - gap: 12px; - min-width: 0; - padding: 13px; - border: 1px solid #edf0ee; - border-radius: 8px; -} -.settings-diagnostic-icon { - display: grid; - width: 18px; - height: 18px; - flex: 0 0 auto; - place-items: center; - border: 1px solid #929a96; - border-radius: 50%; - color: #929a96; - font-size: 11px; - font-weight: 700; -} -.settings-diagnostic-icon.success { - border-color: #2e8b68; - color: #2e8b68; -} -.settings-diagnostic-icon.warning { - border-color: #c68635; - color: #c68635; -} -.settings-diagnostic-icon.error { - border-color: #c85a5a; - color: #c85a5a; -} -.settings-diagnostic-icon.checking { - border-color: #cbd7d2; - border-top-color: #247a63; - animation: settings-spin 0.8s linear infinite; -} -.settings-diagnostic span { - color: #3d4742; - font-size: 13px; -} -.settings-diagnostic small { - margin-left: auto; - overflow: hidden; - color: #66706b; - text-overflow: ellipsis; - white-space: nowrap; -} -.settings-empty-state { - display: grid; - flex: 1; - place-content: center; - color: #66706b; - text-align: center; -} -.settings-empty-state h2 { - color: #202724; -} -/* SETTINGS-02: database key */ -.database-key-content { - padding-bottom: 48px; -} -.database-key-badge.unconfigured { - background: #f1f3f2; - color: #66706b; -} -.database-key-badge.validating { - background: #eef4f8; - color: #4f7188; -} -.database-key-badge.invalid { - background: #f9eeee; - color: #c85a5a; -} -.database-key-status-card dl { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 18px 36px; - margin: 0 0 20px; -} -.database-key-status-card dl div { - min-width: 0; -} -.database-key-status-card dt, -.database-key-diagnostics dt { - color: #929a96; - font-size: 12px; -} -.database-key-status-card dd, -.database-key-diagnostics dd { - overflow: hidden; - margin: 5px 0 0; - color: #35403b; - font-size: 13px; - text-overflow: ellipsis; - white-space: nowrap; -} -.database-key-mono { - font-family: ui-monospace, SFMono-Regular, Consolas, monospace; -} -.database-key-success { - color: #2e8b68 !important; -} -.database-key-muted { - color: #66706b !important; -} -.database-key-primary, -.database-key-secondary { - min-height: 36px; - padding: 0 15px; - border: 1px solid #247a63; - border-radius: 8px; - cursor: pointer; - font: 600 13px/1 inherit; -} -.database-key-primary { - background: #247a63; - color: #fff; -} -.database-key-secondary { - background: #fff; - color: #247a63; -} -.database-key-primary:hover:not(:disabled) { - background: #1d6754; -} -.database-key-secondary:hover:not(:disabled) { - background: #f0f7f4; -} -.database-key-primary:disabled, -.database-key-secondary:disabled { - cursor: not-allowed; - opacity: 0.45; -} -.database-key-editor label { - display: block; - margin-bottom: 9px; - color: #46514c; - font-size: 12px; - font-weight: 700; - letter-spacing: 0.04em; - text-transform: uppercase; -} -.database-key-input-row { - display: flex; - min-width: 0; - height: 42px; - border: 1px solid #d5ddda; - border-radius: 8px; - background: #f4f7f5; -} -.database-key-input-row:focus-within { - border-color: #247a63; - box-shadow: 0 0 0 2px rgba(36, 122, 99, 0.09); -} -.database-key-input-row input { - min-width: 0; - flex: 1; - border: 0; - outline: 0; - padding: 0 14px; - background: transparent; - color: #202724; - font: - 13px/1.4 ui-monospace, - SFMono-Regular, - Consolas, - monospace; -} -.database-key-input-row button { - display: grid; - width: 38px; - flex: 0 0 38px; - place-items: center; - border: 0; - background: transparent; - color: #66706b; - cursor: pointer; -} -.database-key-input-row button:hover:not(:disabled) { - color: #247a63; -} -.database-key-input-row button:disabled { - cursor: not-allowed; - opacity: 0.4; -} -.database-key-input-row svg { - width: 17px; - fill: none; - stroke: currentColor; - stroke-linecap: round; - stroke-linejoin: round; - stroke-width: 1.8; -} -.database-key-editor > p { - margin: 9px 0 0; - color: #66706b; - font-size: 12px; - line-height: 1.6; -} -.database-key-actions { - display: flex; - gap: 9px; - margin-top: 18px; -} -.database-key-feedback { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 8px 18px; - margin-top: 12px; - padding: 12px 15px; - border-radius: 8px; - font-size: 12px; - line-height: 1.5; -} -.database-key-feedback.checking { - background: #f1f4f3; - color: #66706b; -} -.database-key-feedback.checking i { - width: 14px; - height: 14px; - border: 2px solid #c8d5d0; - border-top-color: #247a63; - border-radius: 50%; - animation: settings-spin 0.8s linear infinite; -} -.database-key-feedback.success { - border: 1px solid #bfded3; - background: #eaf5f1; - color: #2e765d; -} -.database-key-feedback.success strong { - width: 100%; -} -.database-key-feedback.error { - border: 1px solid #efcaca; - background: #fff2f2; - color: #a84444; -} -.database-key-auto-heading { - display: flex; - align-items: flex-start; - justify-content: space-between; - gap: 24px; -} -.database-key-auto strong { - color: #35403b; - font-size: 14px; -} -.database-key-auto p { - margin: 6px 0 0; - color: #66706b; - font-size: 12px; - line-height: 1.6; -} -.database-key-prerequisites { - display: flex; - flex-wrap: wrap; - gap: 8px 20px; - margin: 18px 0 0; - padding: 14px 0 0; - border-top: 1px solid #edf0ee; - list-style: none; - color: #8b5c25; - font-size: 12px; -} -.database-key-prerequisites li::before { - content: '○'; - margin-right: 6px; -} -.database-key-prerequisites li.ok { - color: #2e8b68; -} -.database-key-prerequisites li.ok::before { - content: '✓'; -} -.database-key-phases { - display: grid; - grid-template-columns: repeat(5, minmax(0, 1fr)); - gap: 8px; - margin: 18px 0 0; - padding: 0; - counter-reset: key-phase; - list-style: none; -} -.database-key-phases li { - position: relative; - padding-top: 24px; - color: #929a96; - text-align: center; - font-size: 11px; -} -.database-key-phases li::before { - position: absolute; - top: 0; - left: 50%; - display: grid; - width: 18px; - height: 18px; - place-items: center; - border: 1px solid #d5ddda; - border-radius: 50%; - background: #fff; - content: counter(key-phase); - counter-increment: key-phase; - transform: translateX(-50%); -} -.database-key-phases li.active { - color: #247a63; -} -.database-key-phases li.active::before { - border-color: #247a63; - background: #247a63; - color: #fff; -} -.database-key-auto-error { - display: grid; - gap: 4px; - margin-top: 16px; - padding: 12px 14px; - border-left: 3px solid #c68635; - background: #fff8ec; - color: #79501f; - font-size: 12px; -} -.database-key-auto-error span { - overflow-wrap: anywhere; -} -.database-key-auto-error p { - color: #79501f; -} -.database-key-auto-error button { - justify-self: start; - border: 0; - padding: 4px 0; - background: transparent; - color: #247a63; - cursor: pointer; - font: 600 12px inherit; -} -.database-key-security-info { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 1px; - overflow: hidden; - border: 1px solid #e3e8e5; - border-radius: 9px; - background: #e3e8e5; -} -.database-key-security-info span { - display: grid; - gap: 6px; - padding: 15px; - background: #f5f7f6; - color: #66706b; - font-size: 12px; - line-height: 1.5; -} -.database-key-security-info strong { - color: #35403b; - font-size: 13px; -} -.database-key-diagnostics { - margin-top: 22px; - border: 1px solid #dde3e0; - border-radius: 9px; - background: #fff; -} -.database-key-diagnostics summary { - padding: 14px 16px; - color: #46514c; - cursor: pointer; - font-size: 13px; - font-weight: 600; -} -.database-key-diagnostics dl { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 14px 28px; - margin: 0; - padding: 2px 16px 16px; -} -.database-key-diagnostics button { - margin: 0 16px 16px; - border: 0; - padding: 0; - background: transparent; - color: #247a63; - cursor: pointer; - font: 600 12px inherit; -} -.database-key-connection-actions { - margin-top: 30px; -} -.database-key-connection-actions > h2 { - margin: 0 0 14px; - color: #3d4742; - font-size: 15px; -} -.database-key-connection-actions > div { - display: flex; - align-items: center; - justify-content: space-between; - gap: 20px; - padding: 16px 20px; - border: 1px solid #dde3e0; - border-radius: 9px; - background: #fff; -} -.database-key-connection-actions span { - display: grid; - gap: 4px; -} -.database-key-connection-actions strong { - color: #35403b; - font-size: 13px; -} -.database-key-connection-actions small { - color: #66706b; - font-size: 12px; -} -.database-key-connection-actions button { - min-height: 34px; - flex: 0 0 auto; - border: 1px solid #247a63; - border-radius: 8px; - padding: 0 13px; - background: #fff; - color: #247a63; - cursor: pointer; -} -.database-key-connection-actions button:hover:not(:disabled) { - background: #f0f7f4; -} -.database-key-danger { - margin-top: 30px; - padding-bottom: 1px; -} -.database-key-danger > h2 { - margin: 0 0 14px; - color: #c85a5a; - font-size: 15px; -} -.database-key-danger > div { - display: flex; - align-items: center; - justify-content: space-between; - gap: 20px; - padding: 16px 20px; - border: 1px solid #efcdcd; - background: #fff7f7; -} -.database-key-danger > div:first-of-type { - border-radius: 9px 9px 0 0; -} -.database-key-danger > div:last-of-type { - border-top: 0; - border-radius: 0 0 9px 9px; -} -.database-key-danger span { - display: grid; - gap: 4px; -} -.database-key-danger strong { - color: #4a3c3c; - font-size: 13px; -} -.database-key-danger small { - color: #786868; - font-size: 12px; -} -.database-key-danger button { - min-height: 34px; - flex: 0 0 auto; - border: 1px solid #e8baba; - border-radius: 8px; - padding: 0 13px; - background: #fff; - color: #c85a5a; - cursor: pointer; -} -.database-key-danger button:disabled { - cursor: not-allowed; - opacity: 0.45; -} -.database-key-confirm-backdrop { - position: fixed; - z-index: 30; - inset: 0; - display: grid; - place-items: center; - padding: 24px; - background: rgba(25, 32, 29, 0.34); -} -.database-key-confirm { - width: min(100%, 430px); - padding: 22px; - border-radius: 12px; - background: #fff; - box-shadow: 0 18px 50px rgba(24, 35, 30, 0.2); -} -.database-key-confirm h2 { - margin: 0; - color: #202724; - font-size: 17px; -} -.database-key-confirm p { - margin: 12px 0 22px; - color: #66706b; - font-size: 13px; - line-height: 1.7; -} -.database-key-confirm > div { - display: flex; - justify-content: flex-end; - gap: 8px; -} -.database-key-confirm button { - min-height: 34px; - border: 1px solid #dde3e0; - border-radius: 8px; - padding: 0 14px; - background: #fff; - color: #46514c; - cursor: pointer; -} -.database-key-confirm button.danger { - border-color: #c85a5a; - background: #c85a5a; - color: #fff; -} -/* SETTINGS-03: image decryption */ -.image-decryption-content { - padding-bottom: 48px; -} -.image-decrypt-badge.unconfigured { - background: #f1f3f2; - color: #66706b; -} -.image-decrypt-badge.partial { - background: #fff6e8; - color: #a56a24; -} -.image-decrypt-status dl { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 18px 30px; - margin: 0 0 20px; -} -.image-decrypt-status dl div { - min-width: 0; -} -.image-decrypt-status dt { - color: #929a96; - font-size: 12px; -} -.image-decrypt-status dd { - overflow: hidden; - margin: 5px 0 0; - color: #35403b; - font-size: 13px; - text-overflow: ellipsis; - white-space: nowrap; -} -.image-decrypt-status .image-decrypt-wide { - grid-column: span 2; -} -.image-decrypt-mono { - font-family: ui-monospace, SFMono-Regular, Consolas, monospace; -} -.image-state-success { - color: #2e8b68 !important; -} -.image-state-muted { - color: #66706b !important; -} -.image-state-error { - color: #c85a5a !important; -} -.image-resource-checks { - padding: 10px 18px; -} -.image-resource-checks > div { - display: flex; - min-width: 0; - align-items: center; - gap: 11px; - padding: 13px 2px; - border-bottom: 1px solid #edf0ee; -} -.image-resource-checks > div:last-child { - border-bottom: 0; -} -.image-resource-checks strong { - color: #3d4742; - font-size: 13px; -} -.image-resource-checks small { - margin-left: auto; - overflow: hidden; - color: #66706b; - text-overflow: ellipsis; - white-space: nowrap; - font-size: 12px; -} -.image-resource-icon { - display: grid; - width: 18px; - height: 18px; - flex: 0 0 auto; - place-items: center; - border-radius: 50%; - background: #f1f3f2; - color: #66706b; - font-size: 11px; - font-weight: 700; -} -.image-resource-icon.available { - background: #e6f2ed; - color: #2e8b68; -} -.image-resource-icon.unavailable { - background: #f9eaea; - color: #c85a5a; -} -.image-key-editor { - display: grid; - gap: 17px; -} -.image-key-editor label { - display: grid; - min-width: 0; - gap: 8px; - color: #46514c; - font-size: 12px; - font-weight: 600; -} -.image-key-editor input, -.image-test-section select { - box-sizing: border-box; - width: 100%; - height: 40px; - border: 1px solid #d5ddda; - border-radius: 8px; - outline: 0; - padding: 0 12px; - background: #f4f7f5; - color: #202724; - font: - 12px/1.4 ui-monospace, - SFMono-Regular, - Consolas, - monospace; -} -.image-key-editor input:focus, -.image-test-section select:focus { - border-color: #247a63; - box-shadow: 0 0 0 2px rgba(36, 122, 99, 0.09); -} -.image-key-grid { - display: grid; - grid-template-columns: 180px minmax(0, 1fr); - gap: 14px; -} -.image-key-editor > p { - margin: 0; - color: #66706b; - font-size: 12px; - line-height: 1.6; -} -.image-test-section > div:first-child strong, -.image-auto-detect strong, -.image-auto-unavailable strong { - color: #35403b; - font-size: 14px; -} -.image-test-section > div:first-child p, -.image-auto-detect p, -.image-auto-unavailable p { - margin: 6px 0 0; - color: #66706b; - font-size: 12px; - line-height: 1.6; -} -.image-test-section > label { - display: block; - margin: 18px 0 8px; - color: #46514c; - font-size: 12px; - font-weight: 600; -} -.image-test-actions { - display: flex; - gap: 9px; - margin-top: 14px; -} -.image-test-result { - display: flex; - flex-wrap: wrap; - gap: 8px 18px; - margin-top: 14px; - padding: 12px 14px; - border-radius: 8px; - color: #2e765d; - font-size: 12px; -} -.image-test-result.success { - border: 1px solid #bfded3; - background: #eaf5f1; -} -.image-test-result.error { - border: 1px solid #efcaca; - background: #fff2f2; - color: #a84444; -} -.image-test-result p { - width: 100%; - margin: 2px 0 0; -} -.image-step-list { - list-style: none; - margin: 14px 0 0; - padding: 12px 14px; - border-radius: 8px; - border: 1px solid #e5ecea; - background: #f7faf9; - display: flex; - flex-direction: column; - gap: 8px; - font-size: 12px; -} -.image-step { - display: flex; - align-items: center; - gap: 8px; -} -.image-step-icon { - width: 18px; - height: 18px; - display: inline-flex; - align-items: center; - justify-content: center; - border-radius: 50%; - font-size: 12px; - font-weight: 600; -} -.image-step-ok .image-step-icon { - background: #2e765d; - color: #fff; -} -.image-step-fail .image-step-icon { - background: #a84444; - color: #fff; -} -.image-step-fail span:last-child { - color: #a84444; -} -.image-step-pending .image-step-icon { - background: #d6dde0; - color: #6a7378; -} -.image-step-pending span:last-child { - color: #98a1a4; -} -.image-step-skipped .image-step-icon { - background: transparent; - color: #b8c0c4; -} -.image-step-skipped span:last-child { - color: #b8c0c4; - text-decoration: line-through; -} -.image-inline-error { - margin: 14px 0 0; - color: #a84444; - font-size: 12px; -} -.image-auto-heading { - display: flex; - align-items: flex-start; - justify-content: space-between; - gap: 24px; -} -.image-auto-detect ul { - display: flex; - flex-wrap: wrap; - gap: 10px 22px; - margin: 17px 0 0; - padding: 14px 0 0; - border-top: 1px solid #edf0ee; - list-style: none; - color: #8b5c25; - font-size: 12px; -} -.image-auto-detect li::before { - content: '○'; - margin-right: 6px; -} -.image-auto-detect li.ok { - color: #2e8b68; -} -.image-auto-detect li.ok::before { - content: '✓'; -} -.image-auto-progress { - margin-top: 12px !important; - padding: 9px 12px; - border-radius: 7px; - background: #f1f4f3; -} -.image-auto-scope-hint { - display: inline-block; - margin-top: 4px; - color: #7d8c8a; - font-size: 11px; -} -.image-auto-unavailable { - padding-top: 20px; - padding-bottom: 20px; -} -.image-key-danger > div { - border-radius: 9px !important; -} -.image-key-danger { - margin-top: 30px; -} -.image-auto-phases { - display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); - gap: 8px; - margin: 18px 0 0; - padding: 0; - counter-reset: image-auto-phase; - list-style: none; -} -.image-auto-phases li { - position: relative; - padding-top: 24px; - color: #929a96; - text-align: center; - font-size: 11px; -} -.image-auto-phases li::before { - position: absolute; - top: 0; - left: 50%; - display: grid; - width: 18px; - height: 18px; - place-items: center; - border: 1px solid #d5ddda; - border-radius: 50%; - background: #fff; - content: counter(image-auto-phase); - counter-increment: image-auto-phase; - transform: translateX(-50%); -} -.image-auto-phases li.active { - color: #247a63; -} -.image-auto-phases li.active::before { - border-color: #247a63; - background: #247a63; - color: #fff; -} -.image-auto-error { - margin: 12px 0 0 !important; - padding: 10px 12px; - border-left: 3px solid #c85a5a; - background: #fff2f2; - color: #a84444 !important; -} -.image-auto-success { - display: grid; - grid-template-columns: minmax(0, 1fr) auto; - gap: 7px 20px; - align-items: center; - margin-top: 14px; - padding: 14px 16px; - border: 1px solid #bfded3; - border-radius: 8px; - background: #eaf5f1; - color: #2e765d; - font-size: 12px; -} -.image-auto-success strong { - grid-column: 1; - color: #2e765d; -} -.image-auto-success span { - grid-column: 1; -} -.image-auto-success button { - grid-column: 2; - grid-row: 1/4; -} -/* SETTINGS-04: AI provider center */ -.ai-model-content { - padding-bottom: 48px; -} -.ai-model-default { - display: flex; - align-items: center; - justify-content: space-between; - gap: 20px; -} -.ai-model-default > div { - display: grid; - gap: 5px; -} -.ai-model-default > div > span, -.ai-model-default small { - color: #66706b; - font-size: 12px; -} -.ai-model-default strong { - color: #202724; - font-size: 18px; -} -.ai-model-page-error { - padding: 11px 14px; - border-left: 3px solid #c85a5a; - background: #fff2f2; - color: #a84444; - font-size: 12px; -} -.ai-provider-list { - display: grid; - gap: 12px; -} -.ai-provider-card { - border: 1px solid #dde3e0; - border-radius: 10px; - background: #fff; - padding: 19px 20px; -} -.ai-provider-card header { - display: flex; - align-items: flex-start; - justify-content: space-between; - gap: 18px; -} -.ai-provider-card h3 { - margin: 0 0 5px; - color: #202724; - font-size: 15px; -} -.ai-provider-card header span { - color: #66706b; - font-size: 12px; -} -.ai-provider-status { - border-radius: 12px; - padding: 4px 8px; - background: #f1f3f2; -} -.ai-provider-status.connected { - background: #eaf5f1; - color: #2e8b68 !important; -} -.ai-provider-status.error { - background: #fff2f2; - color: #c85a5a !important; -} -.ai-provider-card dl { - display: grid; - grid-template-columns: 2fr 1fr 1fr; - gap: 18px; - margin: 18px 0; -} -.ai-provider-card dt { - color: #929a96; - font-size: 11px; -} -.ai-provider-card dd { - overflow: hidden; - margin: 5px 0 0; - color: #3d4742; - text-overflow: ellipsis; - white-space: nowrap; - font-size: 12px; -} -.ai-provider-card footer { - display: flex; - flex-wrap: wrap; - gap: 8px; - padding-top: 14px; - border-top: 1px solid #edf0ee; -} -.ai-provider-card button, -.ai-provider-editor button { - min-height: 32px; - border: 1px solid #d5ddda; - border-radius: 7px; - padding: 0 11px; - background: #fff; - color: #46514c; - cursor: pointer; - font: 600 12px inherit; -} -.ai-provider-card button:hover, -.ai-provider-editor button:hover { - border-color: #247a63; - color: #247a63; -} -.ai-provider-card button:disabled, -.ai-provider-editor button:disabled { - cursor: not-allowed; - opacity: 0.45; -} -.ai-provider-card button.danger, -.ai-provider-editor button.danger { - color: #c85a5a; -} -.ai-provider-error { - margin: 0 0 12px; - color: #a84444; - font-size: 12px; -} -.ai-provider-empty { - color: #66706b; - text-align: center; -} -.ai-provider-empty p { - margin: 6px 0 0; - font-size: 12px; -} -.ai-provider-editor { - display: grid; - gap: 18px; - margin-top: 22px; -} -.ai-provider-editor > header { - display: flex; - align-items: flex-start; - justify-content: space-between; - gap: 18px; -} -.ai-provider-editor h2, -.ai-provider-editor h3 { - margin: 0; - color: #35403b; - font-size: 15px; -} -.ai-provider-editor header p { - margin: 5px 0 0; - color: #66706b; - font-size: 12px; -} -.ai-provider-editor label { - display: grid; - gap: 7px; - color: #46514c; - font-size: 12px; - font-weight: 600; -} -.ai-provider-editor input:not([type='checkbox']):not([type='radio']), -.ai-provider-editor select, -.ai-provider-editor textarea { - box-sizing: border-box; - width: 100%; - border: 1px solid #d5ddda; - border-radius: 7px; - outline: 0; - padding: 9px 10px; - background: #f4f7f5; - color: #202724; - font: - 12px/1.4 ui-monospace, - SFMono-Regular, - Consolas, - monospace; -} -.ai-provider-editor input:focus, -.ai-provider-editor select:focus, -.ai-provider-editor textarea:focus { - border-color: #247a63; - box-shadow: 0 0 0 2px rgba(36, 122, 99, 0.08); -} -.ai-provider-form-grid, -.ai-provider-advanced > div { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 14px; -} -.ai-provider-form-grid .wide, -.ai-provider-advanced .wide { - grid-column: 1/-1; -} -.ai-model-table-heading { - display: flex; - align-items: center; - justify-content: space-between; -} -.ai-model-table { - display: grid; - gap: 9px; -} -.ai-model-row { - display: grid; - grid-template-columns: 1fr 1fr repeat(3, auto) 110px auto auto; - gap: 8px; - align-items: center; - padding: 11px; - border: 1px solid #e3e8e5; - border-radius: 8px; -} -.ai-model-row label { - display: flex; - align-items: center; - gap: 4px; - white-space: nowrap; - font-weight: 400; -} -.ai-provider-advanced, -.ai-provider-preview { - border: 1px solid #e3e8e5; - border-radius: 8px; -} -.ai-provider-advanced summary, -.ai-provider-preview summary { - padding: 12px 14px; - cursor: pointer; - color: #46514c; - font-size: 13px; - font-weight: 600; -} -.ai-provider-advanced > div { - padding: 2px 14px 14px; -} -.ai-provider-advanced textarea { - min-height: 90px; - resize: vertical; -} -.ai-provider-preview pre { - overflow: auto; - max-height: 280px; - margin: 0; - padding: 0 14px 14px; - color: #46514c; - font: - 11px/1.6 ui-monospace, - SFMono-Regular, - Consolas, - monospace; -} -.ai-provider-editor > footer { - display: flex; - justify-content: flex-end; - gap: 8px; -} -@keyframes settings-spin { - to { - transform: rotate(360deg); - } -} -@media (max-width: 900px) { - .settings-sidebar { - width: 248px; - flex-basis: 248px; - } - .settings-page-content { - padding: 24px; - } - .settings-page-header { - padding: 20px 24px; - } - .settings-recall-grid { - grid-template-columns: 1fr; - } - .settings-recall-notice { - padding-top: 10px; - padding-left: 0; - border-top: 2px solid #e5b45f; - border-left: 0; - } - .settings-account-overview { - grid-template-columns: minmax(0, 1fr) auto; - gap: 18px; - } - .settings-account-facts { - grid-column: 1/-1; - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - .settings-account-actions { - grid-row: 1; - grid-column: 2; - } - .database-key-security-info { - grid-template-columns: 1fr; - } - .image-decrypt-status dl { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - .image-decrypt-status .image-decrypt-wide { - grid-column: span 2; - } - .ai-model-row { - grid-template-columns: 1fr 1fr; - } - .ai-model-row label, - .ai-model-row button { - justify-self: start; - } -} -@media (max-width: 700px) { - .settings-account-overview { - grid-template-columns: minmax(0, 1fr); - } - .settings-account-actions { - grid-row: auto; - grid-column: 1; - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - .settings-account-root { - grid-column: 1; - } - .database-key-status-card dl, - .database-key-diagnostics dl { - grid-template-columns: 1fr; - } - .database-key-auto-heading { - flex-direction: column; - } - .database-key-phases { - grid-template-columns: 1fr; - } - .database-key-phases li { - padding: 0 0 0 28px; - text-align: left; - } - .database-key-phases li::before { - top: -2px; - left: 0; - transform: none; - } - .image-decrypt-status dl, - .image-key-grid { - grid-template-columns: 1fr; - } - .image-decrypt-status .image-decrypt-wide { - grid-column: 1; - } - .image-auto-heading { - flex-direction: column; - } - .image-auto-phases { - grid-template-columns: 1fr; - } - .image-auto-phases li { - padding: 0 0 0 28px; - text-align: left; - } - .image-auto-phases li::before { - top: -2px; - left: 0; - transform: none; - } - .image-auto-success { - grid-template-columns: 1fr; - } - .image-auto-success button { - grid-column: 1; - grid-row: auto; - justify-self: start; - } - .image-resource-checks > div { - align-items: flex-start; - } - .image-resource-checks small { - white-space: normal; - text-align: right; - } - .ai-provider-card dl, - .ai-provider-form-grid, - .ai-provider-advanced > div { - grid-template-columns: 1fr; - } - .ai-provider-form-grid .wide, - .ai-provider-advanced .wide { - grid-column: 1; - } - .ai-model-row { - grid-template-columns: 1fr; - } -} -.api-center-layout > * { - min-width: 0; - min-height: 0; - box-sizing: border-box; -} -.api-section-heading h2, -.api-introduction h2, -.api-integrations h2, -.api-runtime-title h2 { - margin: 0; - color: var(--wxex-text-primary); - font: 700 17px/24px var(--wxex-font); -} -.ready-text { - color: var(--wxex-success); -} -.api-main { - position: relative; - display: flex; - min-width: 0; - min-height: 0; - overflow: hidden; - background: var(--wxex-bg-main); -} -.api-main-scroll { - flex: 1; - min-width: 0; - min-height: 0; - overflow-y: auto; - padding: 22px 28px 36px; -} -.api-workspace-heading { - display: flex; - align-items: flex-start; - justify-content: space-between; - gap: 16px; - padding-bottom: 16px; - border-bottom: 1px solid var(--wxex-border); -} -.api-title-line { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 8px; -} -.api-title-line h1 { - margin: 0; - color: var(--wxex-text-primary); - font: 700 22px/30px var(--wxex-font); -} -.api-workspace-heading p { - margin: 4px 0 0; - color: var(--wxex-text-secondary); - font: 13px/19px var(--wxex-font); -} -.api-skill-status, -.api-version { - padding: 2px 7px; - border-radius: 5px; - font: 700 11px/17px var(--wxex-font); -} -.api-skill-status.ready { - color: var(--wxex-brand); - background: var(--wxex-brand-soft); -} -.api-skill-status.error { - color: var(--wxex-danger); - background: #fff1f1; -} -.api-version { - color: var(--wxex-text-muted); - background: var(--wxex-bg-app); -} -.api-header-actions, -.api-tester-actions, -.api-runtime-actions, -.api-skill-file-actions { - display: flex; - flex-wrap: wrap; - gap: 8px; -} -.api-header-actions button, -.api-tester-actions button, -.api-runtime-actions button, -.api-endpoint-row button, -.api-response-summary + pre + p + button, -.api-skill-file-actions button { - min-height: 32px; - padding: 0 11px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-sm); - background: var(--wxex-bg-elevated); - color: var(--wxex-text-primary); - cursor: pointer; - font: 600 12px/18px var(--wxex-font); -} -.api-header-actions button:hover, -.api-tester-actions button:hover, -.api-runtime-actions button:hover, -.api-endpoint-row button:hover, -.api-skill-file-actions button:hover { - border-color: var(--wxex-brand); - color: var(--wxex-brand); -} -.api-primary-button { - border-color: var(--wxex-brand) !important; - background: var(--wxex-brand) !important; - color: #fff !important; -} -.api-primary-button:hover:not(:disabled), -.api-primary-button:focus-visible, -.api-primary-button:active { - background: var(--wxex-brand-hover) !important; - color: #fff !important; -} -.api-primary-button:disabled { - cursor: not-allowed; - opacity: 0.55; -} -.api-trust-bar { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 10px; - margin-top: 16px; - padding: 10px 12px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: #f5f8f6; - color: var(--wxex-text-secondary); - font: 12px/18px var(--wxex-font); -} -.api-trust-bar i { - width: 3px; - height: 3px; - border-radius: 50%; - background: var(--wxex-text-muted); -} -.api-introduction { - margin-top: 24px; - padding: 18px 20px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-lg); - background: var(--wxex-bg-elevated); -} -.api-introduction p { - margin: 10px 0 16px; - color: var(--wxex-text-secondary); - font: 13px/20px var(--wxex-font); -} -.api-flow { - display: flex; - align-items: center; - justify-content: space-between; - gap: 10px; - padding: 12px; - border: 1px dashed var(--wxex-border); - border-radius: var(--wxex-radius-md); - color: var(--wxex-text-secondary); - font: 12px/18px var(--wxex-font); -} -.api-flow span, -.api-flow strong { - padding: 7px 10px; - border: 1px solid var(--wxex-border); - border-radius: 5px; - background: #fff; - white-space: nowrap; -} -.api-flow strong { - color: var(--wxex-brand); - background: var(--wxex-brand-soft); -} -.api-flow b { - color: var(--wxex-text-muted); - font-size: 17px; -} -.api-endpoint-catalog, -.api-request-tester { - margin-top: 26px; -} -.skill-install-flow { - margin-top: 26px; - padding: 18px 20px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-lg); - background: var(--wxex-bg-elevated); -} -.skill-flow-steps { - display: grid; - gap: 16px; - margin-top: 16px; -} -.skill-flow-steps > section { - position: relative; - display: grid; - grid-template-columns: 26px minmax(0, 1fr); - gap: 10px; - color: var(--wxex-text-muted); -} -.skill-flow-steps > section:not(:last-child)::after { - position: absolute; - top: 28px; - left: 12px; - bottom: -16px; - width: 1px; - background: var(--wxex-border); - content: ''; -} -.skill-flow-steps > section > b { - position: relative; - z-index: 1; - display: grid; - width: 24px; - height: 24px; - place-items: center; - border: 1px solid var(--wxex-border); - border-radius: 50%; - background: var(--wxex-bg-elevated); - font: 700 12px/1 var(--wxex-font); -} -.skill-flow-steps > section.active > b, -.skill-flow-steps > section.done > b { - border-color: var(--wxex-brand); - background: var(--wxex-brand); - color: #fff; -} -.skill-flow-steps h3 { - margin: 1px 0 5px; - color: var(--wxex-text-primary); - font: 700 14px/20px var(--wxex-font); -} -.skill-flow-steps p { - margin: 3px 0; - color: var(--wxex-text-secondary); - font: 12px/18px var(--wxex-font); -} -.skill-flow-actions { - display: flex; - flex-wrap: wrap; - gap: 8px; - margin-top: 10px; -} -.skill-flow-actions button, -.api-skill-details button { - min-height: 30px; - padding: 0 10px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-sm); - background: #fff; - color: var(--wxex-text-primary); - cursor: pointer; - font: 600 12px/18px var(--wxex-font); -} -.skill-flow-actions button:disabled, -.api-skill-details button:disabled { - cursor: not-allowed; - opacity: 0.55; -} -.skill-target-selector { - display: flex; - flex-wrap: wrap; - gap: 6px; - margin-top: 8px; -} -.skill-target-selector button { - min-height: 30px; - padding: 0 10px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-sm); - background: #fff; - color: var(--wxex-text-secondary); - cursor: pointer; - font: 600 12px/18px var(--wxex-font); -} -.skill-target-selector button.active { - border-color: var(--wxex-brand); - background: var(--wxex-brand-soft); - color: var(--wxex-brand); -} -.api-skill-details { - margin-top: 16px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); -} -.api-skill-details summary { - padding: 12px 14px; - color: var(--wxex-text-primary); - cursor: pointer; - font: 700 13px/18px var(--wxex-font); -} -.api-skill-details > dl, -.api-skill-details > div { - margin: 0; - padding: 0 14px 14px; -} -.api-skill-details dl div { - display: grid; - grid-template-columns: 72px minmax(0, 1fr); - gap: 8px; - padding: 4px 0; - color: var(--wxex-text-secondary); - font: 12px/18px var(--wxex-font); -} -.api-skill-details dd { - margin: 0; - color: var(--wxex-text-primary); -} -.api-skill-more { - position: relative; -} -.api-skill-more summary { - display: grid; - min-height: 32px; - place-items: center; - padding: 0 11px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-sm); - background: var(--wxex-bg-elevated); - color: var(--wxex-text-primary); - cursor: pointer; - font: 600 12px/18px var(--wxex-font); - list-style: none; -} -.api-skill-more[open] > button { - position: absolute; - z-index: 2; - top: 36px; - right: 0; - width: 170px; - padding: 9px 10px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-sm); - background: #fff; - color: var(--wxex-text-primary); - box-shadow: var(--wxex-shadow-popover); - font: 12px/18px var(--wxex-font); - text-align: left; -} -.api-section-heading { - display: flex; - align-items: baseline; - justify-content: space-between; - gap: 12px; -} -.api-section-heading > span { - color: var(--wxex-text-muted); - font: 12px/18px var(--wxex-font); -} -.api-endpoint-table { - margin-top: 12px; - overflow: hidden; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); -} -.api-endpoint-head, -.api-endpoint-row { - display: grid; - grid-template-columns: 72px minmax(128px, 1.1fr) minmax(150px, 1.2fr) 90px; - align-items: center; - gap: 12px; - padding: 11px 14px; -} -.api-endpoint-head { - background: #f1f4f2; - color: var(--wxex-text-secondary); - font: 700 12px/18px var(--wxex-font); -} -.api-endpoint-row { - min-height: 54px; - border-top: 1px solid var(--wxex-border); - color: var(--wxex-text-secondary); - font: 12px/18px var(--wxex-font); -} -.api-endpoint-row.active { - background: #f7faf8; -} -.api-endpoint-row code { - color: var(--wxex-text-primary); - font: - 12px/18px ui-monospace, - monospace; -} -.api-endpoint-row small { - display: block; - color: var(--wxex-text-muted); -} -.api-endpoint-row > span:last-child { - display: flex; - gap: 4px; -} -.api-endpoint-row button { - min-height: 26px; - padding: 0 7px; - font-size: 11px; -} -.api-method { - display: inline-block; - color: var(--wxex-brand); - font: - 700 11px/18px ui-monospace, - monospace; -} -.api-method.post { - color: var(--wxex-ai); -} -.api-request-meta { - display: flex; - align-items: center; - gap: 10px; - margin: 12px 0; - padding: 10px 12px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: #f5f8f6; - overflow: hidden; -} -.api-request-meta code { - overflow: hidden; - color: var(--wxex-text-primary); - font: - 12px/18px ui-monospace, - monospace; - text-overflow: ellipsis; - white-space: nowrap; -} -.api-param-grid { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 10px; -} -.api-param-grid label, -.api-json-input { - display: grid; - gap: 5px; - color: var(--wxex-text-secondary); - font: 12px/18px var(--wxex-font); -} -.api-param-grid label span b { - margin-left: 5px; - color: var(--wxex-danger); - font-size: 11px; -} -.api-param-grid input, -.api-json-input textarea { - box-sizing: border-box; - width: 100%; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-sm); - outline: none; - background: #fff; - color: var(--wxex-text-primary); - font: 12px/18px var(--wxex-font); -} -.api-param-grid input { - height: 34px; - padding: 0 9px; -} -.api-json-input { - margin-top: 10px; -} -.api-json-input textarea { - min-height: 180px; - padding: 10px; - resize: vertical; - font-family: ui-monospace, monospace; -} -.api-tester-actions { - justify-content: flex-end; - margin-top: 12px; -} -.api-inline-error { - margin: 10px 0 0; - padding: 8px 10px; - border: 1px solid rgba(200, 90, 90, 0.35); - border-radius: var(--wxex-radius-sm); - background: #fff4f4; - color: var(--wxex-danger); - font: 12px/18px var(--wxex-font); -} -.api-runtime-panel { - border-left: 1px solid var(--wxex-border); - background: var(--wxex-bg-main); - overflow: hidden; -} -.api-runtime-scroll { - height: 100%; - overflow-y: auto; -} -.api-runtime-scroll section { - padding: 18px 16px; - border-bottom: 1px solid var(--wxex-border); -} -.api-runtime-title { - display: flex; - align-items: center; - justify-content: space-between; - gap: 8px; -} -.api-runtime-title > span { - font: 700 12px/18px var(--wxex-font); -} -.api-runtime-title .ready { - color: var(--wxex-success); -} -.api-runtime-title .stopped { - color: var(--wxex-text-muted); -} -.api-runtime-scroll h3 { - margin: 0 0 12px; - color: var(--wxex-text-primary); - font: 700 14px/20px var(--wxex-font); -} -.api-runtime-scroll dl { - margin: 14px 0; -} -.api-runtime-scroll dl div { - display: flex; - justify-content: space-between; - gap: 12px; - padding: 5px 0; - font: 12px/18px var(--wxex-font); -} -.api-runtime-scroll dt { - color: var(--wxex-text-secondary); -} -.api-runtime-scroll dd { - margin: 0; - color: var(--wxex-text-primary); - text-align: right; -} -.warning-text { - color: var(--wxex-warning); -} -.api-runtime-actions { - display: grid; - grid-template-columns: 1fr 1fr; -} -.api-runtime-actions button { - min-height: 30px; - padding: 0 6px; -} -.api-security-warning { - margin: 12px 16px; - padding: 9px 10px; - border-left: 3px solid var(--wxex-warning); - background: #fff8ec; - color: #915d1e; - font: 12px/18px var(--wxex-font); -} -.api-response-summary { - display: flex; - align-items: center; - justify-content: space-between; - gap: 8px; - color: var(--wxex-text-primary); - font: - 12px/18px ui-monospace, - monospace; -} -.api-runtime-scroll pre { - max-height: 180px; - overflow: auto; - margin: 10px 0 8px; - padding: 10px; - border-radius: var(--wxex-radius-sm); - background: #1f2824; - color: #cde7dc; - font: - 11px/16px ui-monospace, - monospace; - white-space: pre-wrap; - word-break: break-word; -} -.api-response-meta, -.api-empty-text { - margin: 0 0 9px; - color: var(--wxex-text-muted); - font: 11px/17px var(--wxex-font); -} -.api-history { - display: grid; - gap: 8px; - margin: 0; - padding: 0; - list-style: none; -} -.api-history li { - display: grid; - grid-template-columns: minmax(0, 1fr) auto; - gap: 2px 8px; - padding-bottom: 8px; - border-bottom: 1px solid var(--wxex-border); -} -.api-history span { - overflow: hidden; - color: var(--wxex-text-primary); - font: - 11px/17px ui-monospace, - monospace; - text-overflow: ellipsis; - white-space: nowrap; -} -.api-history b { - font: 700 11px/17px var(--wxex-font); -} -.api-history small { - grid-column: 1 / -1; - color: var(--wxex-text-muted); - font: 11px/16px var(--wxex-font); -} -.api-privacy { - background: #f5f8f6; -} -.api-privacy p { - margin: 0; - color: var(--wxex-text-secondary); - font: 12px/18px var(--wxex-font); -} -.api-markdown-overlay { - position: absolute; - inset: 0; - z-index: 4; - display: flex; - align-items: stretch; - justify-content: center; - padding: 20px; - background: rgba(32, 39, 36, 0.24); -} -.api-markdown-overlay > div { - display: flex; - width: min(820px, 100%); - flex-direction: column; - min-height: 0; - padding: 14px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-lg); - background: #fff; - box-shadow: 0 12px 40px rgba(0, 0, 0, 0.16); -} -.api-markdown-overlay header { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; -} -.api-markdown-overlay header > div { - display: flex; - align-items: center; - gap: 8px; -} -.api-markdown-overlay header span { - color: var(--wxex-text-muted); - font: 12px/18px var(--wxex-font); -} -.api-markdown-overlay button { - min-height: 30px; - padding: 0 10px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-sm); - background: #fff; - color: var(--wxex-text-primary); - cursor: pointer; -} -.api-markdown-overlay pre, -.skill-markdown-preview { - min-height: 0; - overflow: auto; - margin: 14px 0 0; - white-space: pre-wrap; - color: var(--wxex-text-primary); - font: 12px/19px var(--wxex-font); -} -.skill-markdown-preview h1 { - font-size: 20px; -} -.skill-markdown-preview h2 { - margin-top: 18px; - font-size: 16px; -} -.skill-markdown-preview p { - margin: 6px 0; -} -.skill-markdown-preview li { - margin-left: 18px; -} -@media (max-width: 1100px) { - .api-center-layout { - grid-template-columns: minmax(0, 1fr) 280px; - } - .api-main-scroll { - padding: 18px; - } - .api-header-actions { - max-width: 260px; - justify-content: flex-end; - } - .api-endpoint-head, - .api-endpoint-row { - grid-template-columns: 56px minmax(110px, 1fr) minmax(100px, 1fr) 78px; - gap: 7px; - padding: 10px; - } - .api-flow { - overflow-x: auto; - justify-content: flex-start; - } -} - -.report-history-list-title { - padding: 4px 4px 8px; - color: var(--wxex-text-secondary); - font: 700 13px/18px var(--wxex-font); -} - -.report-history-group { - margin: 0 0 10px; -} - -.report-history-group h3 { - margin: 0; - padding: 6px 4px; - color: var(--wxex-text-muted); - font: 700 12px/16px var(--wxex-font); -} - -.report-history-item { - position: relative; - display: flex; - width: 100%; - min-width: 0; - box-sizing: border-box; - gap: 10px; - padding: 10px 54px 10px 12px; - border: 0; - border-radius: var(--wxex-radius-md); - background: transparent; - color: var(--wxex-text-primary); - text-align: left; - cursor: pointer; - font-family: var(--wxex-font); -} - -.report-history-item:hover { - background: rgba(255, 255, 255, 0.62); -} - -.report-history-item.active { - background: var(--wxex-brand-soft); - color: var(--wxex-brand); -} - -.report-history-item.active::before { - position: absolute; - left: 0; - top: 8px; - bottom: 8px; - width: 3px; - border-radius: 4px; - background: var(--wxex-brand); - content: ''; -} - -.report-history-avatar { - display: grid; - width: 36px; - height: 36px; - flex: 0 0 auto; - place-items: center; - overflow: hidden; - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); - color: var(--wxex-brand); - font: 700 14px/1 var(--wxex-font); -} - -.report-history-avatar img { - width: 100%; - height: 100%; - object-fit: cover; -} - -.report-history-text { - display: grid; - flex: 1 1 auto; - min-width: 0; - gap: 2px; -} - -.report-history-text b, -.report-history-text small, -.report-history-text em { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.report-history-text b { - color: inherit; - font: 600 13px/18px var(--wxex-font); -} - -.report-history-text small, -.report-history-text em { - color: var(--wxex-text-muted); - font: normal 12px/16px var(--wxex-font); -} - -.report-history-delete { - position: absolute; - right: 10px; - top: 50%; - display: grid; - width: 38px; - height: 26px; - place-items: center; - border: 1px solid rgba(198, 72, 72, 0.22); - border-radius: var(--wxex-radius-sm); - background: rgba(198, 72, 72, 0.06); - color: #a64242; - cursor: pointer; - font: 600 12px/16px var(--wxex-font); - opacity: 0; - transform: translateY(-50%); - transition: opacity 0.12s ease; -} - -.report-history-item:hover .report-history-delete, -.report-history-delete:focus { - opacity: 1; -} - -.report-history-empty { - display: grid; - gap: 10px; - padding: 18px 8px; - color: var(--wxex-text-muted); - font: 13px/18px var(--wxex-font); -} - -.report-history-empty button, -.report-center-empty button { - justify-self: start; - min-height: 32px; - padding: 0 12px; - border: 1px solid var(--wxex-brand); - border-radius: var(--wxex-radius-md); - background: var(--wxex-brand); - color: #fff; - cursor: pointer; - font: 600 13px/18px var(--wxex-font); -} - -.report-history-account { - flex: 0 0 auto; - padding: 12px; - border-top: 1px solid var(--wxex-border); -} - -.report-delete-confirm { - position: fixed; - inset: 0; - z-index: 30; - display: grid; - place-items: center; - background: rgba(32, 39, 36, 0.28); -} - -.report-delete-confirm-card { - display: grid; - width: min(360px, calc(100vw - 48px)); - gap: 12px; - padding: 18px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-lg); - background: var(--wxex-bg-main); - box-shadow: var(--wxex-shadow-popover); -} - -.report-delete-confirm-card h2 { - margin: 0; - color: var(--wxex-text-primary); - font: 700 18px/24px var(--wxex-font); -} - -.report-delete-confirm-card p { - margin: 0; - color: var(--wxex-text-secondary); - font: 13px/20px var(--wxex-font); -} - -.report-delete-confirm-card > div { - display: flex; - justify-content: flex-end; - gap: 8px; -} - -.report-delete-confirm-card button { - min-height: 32px; - padding: 0 14px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); - color: var(--wxex-text-primary); - cursor: pointer; - font: 600 13px/18px var(--wxex-font); -} - -.report-delete-confirm-card button.danger { - border-color: #a64242; - background: #a64242; - color: #fff; -} - -.report-delete-error { - color: #a64242 !important; -} - -.report-viewer { - display: flex; - min-width: 0; - min-height: 0; - height: 100%; - flex-direction: column; - overflow: hidden; - background: #f2f1ee; -} - -.report-viewer-header { - display: flex; - flex: 0 0 auto; - align-items: flex-start; - justify-content: space-between; - gap: 16px; - padding: 18px 22px 12px; - border-bottom: 1px solid var(--wxex-border); - background: var(--wxex-bg-main); -} - -.report-viewer-header h1 { - font: 700 20px/27px var(--wxex-font); -} - -.report-viewer-toolbar { - display: flex; - flex: 0 0 auto; - align-items: center; - gap: 8px; -} - -.report-viewer-toolbar button, -.report-zoom-bar button, -.report-more-popover button, -.report-settings-section button { - min-height: 32px; - padding: 0 12px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); - color: var(--wxex-text-primary); - cursor: pointer; - font: 600 13px/18px var(--wxex-font); -} - -.report-viewer-toolbar button.primary { - border-color: var(--wxex-ai); - background: var(--wxex-ai); - color: #fff; -} - -.report-viewer-toolbar button:disabled { - color: var(--wxex-text-muted); - cursor: not-allowed; - opacity: 0.72; -} - -.report-more-menu { - position: relative; -} - -.report-more-popover { - position: absolute; - top: 38px; - right: 0; - z-index: 8; - min-width: 128px; - padding: 6px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-md); - background: var(--wxex-bg-elevated); - box-shadow: var(--wxex-shadow-popover); -} - -.report-more-popover button { - width: 100%; - border: 0; - text-align: left; -} - -.report-viewer-status { - flex: 0 0 auto; - padding: 8px 22px; - border-bottom: 1px solid var(--wxex-border); - background: var(--wxex-ai-soft); - color: var(--wxex-ai); - font: 12px/18px var(--wxex-font); -} - -.report-viewer-stage { - display: block; - flex: 1 1 auto; - min-height: 0; - min-width: 0; - overflow: auto; - padding: 22px; -} - -.report-canvas { - width: max-content; - margin: 0 auto; - padding: 0; - background: #fff; - box-shadow: 0 8px 24px rgba(32, 39, 36, 0.14); -} - -.report-canvas img { - display: block; - max-width: none; - height: auto; -} - -.report-zoom-bar { - display: flex; - flex: 0 0 auto; - align-items: center; - justify-content: center; - gap: 8px; - min-height: 48px; - border-top: 1px solid var(--wxex-border); - background: var(--wxex-bg-main); -} - -.report-zoom-bar span { - min-width: 48px; - color: var(--wxex-text-secondary); - text-align: center; - font: 12px/18px var(--wxex-font); -} - -.report-center-empty { - display: grid; - align-self: center; - justify-self: center; - max-width: 360px; - gap: 12px; - margin: auto; - color: var(--wxex-text-secondary); - text-align: center; -} - -.report-center-empty-icon { - display: grid; - width: 54px; - height: 54px; - place-items: center; - justify-self: center; - border: 1px solid rgba(104, 110, 220, 0.18); - border-radius: 18px; - background: var(--wxex-ai-soft); - color: var(--wxex-ai); -} - -.report-center-empty-icon svg { - width: 28px; - height: 28px; -} - -.report-center-empty-icon path { - fill: currentColor; -} - -.report-center-empty h2 { - margin: 0; - color: var(--wxex-text-primary); - font: 700 18px/24px var(--wxex-font); -} - -.report-center-empty p { - margin: 0; - font: 13px/20px var(--wxex-font); -} - -.report-center-empty button { - justify-self: center; -} - -.report-settings-panel { - display: flex; - min-width: 0; - min-height: 0; - height: 100%; - flex-direction: column; - overflow-y: auto; - border-left: 1px solid var(--wxex-border); - background: #f7f9f8; -} - -.report-settings-panel header { - flex: 0 0 auto; - padding: 20px 18px 14px; - border-bottom: 1px solid var(--wxex-border); -} - -.report-settings-panel header h2 { - font: 700 16px/22px var(--wxex-font); -} - -.report-settings-section { - margin: 0; - padding: 16px 18px; - border-bottom: 1px solid var(--wxex-border); -} - -.report-settings-section h3 { - margin: 0 0 8px; - color: var(--wxex-text-primary); - font: 700 14px/20px var(--wxex-font); -} - -.report-settings-section p, -.report-settings-section code { - margin: 0 0 10px; - color: var(--wxex-text-secondary); - font: 12px/18px var(--wxex-font); -} - -.report-settings-section code { - display: block; - max-width: 100%; - overflow-wrap: anywhere; - padding: 8px; - border-radius: var(--wxex-radius-sm); - background: var(--wxex-bg-elevated); -} - -.report-settings-section.muted { - color: var(--wxex-text-muted); -} - -.report-export-list { - display: grid; - gap: 8px; - margin-bottom: 10px; -} - -.report-export-list div { - display: flex; - justify-content: space-between; - gap: 12px; - color: var(--wxex-text-secondary); - font: 12px/18px var(--wxex-font); -} - -.report-export-list b { - min-width: 0; - color: var(--wxex-text-primary); - font-weight: 600; - overflow-wrap: anywhere; - text-align: right; -} - -.report-generation-log { - display: grid; - gap: 10px; - margin: 0; - padding: 0; - list-style: none; -} - -.report-generation-log li { - display: grid; - grid-template-columns: 18px minmax(0, 1fr); - gap: 8px; - color: var(--wxex-text-secondary); - font: 12px/18px var(--wxex-font); -} - -.report-generation-log li > span { - color: var(--wxex-brand); - font-weight: 700; -} - -.report-generation-log b, -.report-generation-log time, -.report-generation-log small { - display: block; -} - -.report-generation-log b { - color: var(--wxex-text-primary); - font-weight: 600; -} - -.report-generation-log time { - color: var(--wxex-text-muted); - font-size: 11px; -} - -.report-generation-log small { - color: var(--wxex-text-secondary); - font: 600 11px/16px var(--wxex-font); -} - -@media (max-width: 1120px) { - .report-center-page { - grid-template-columns: 268px minmax(360px, 1fr) 280px; - } - - .report-viewer-header { - flex-direction: column; - } -} - -/* ============================================================ */ -/* 日报模板选择器 + 预览器 */ -/* ============================================================ */ -.report-section-desc { - margin: 0 0 12px; - color: var(--wxex-text-secondary); - font-size: 12px; - line-height: 1.6; -} - -.report-template-list { - display: grid; - gap: 10px; -} - -.report-template-item { - display: flex; - align-items: center; - gap: 12px; - padding: 12px 14px; - border: 1.5px solid var(--wxex-border); - border-radius: 12px; - background: #fff; - transition: - border-color 0.2s, - background 0.2s; -} - -.report-template-item.active { - border-color: var(--wxex-primary, #07c160); - background: #f0fbf3; -} - -.report-template-item.disabled { - opacity: 0.6; - cursor: not-allowed; -} - -.report-template-item > label { - flex: 1; - display: flex; - align-items: center; - gap: 10px; - cursor: pointer; - min-width: 0; -} - -.report-template-item input[type='radio'] { - accent-color: var(--wxex-primary, #07c160); -} - -.report-template-body { - flex: 1; - min-width: 0; -} - -.report-template-title { - font-size: 14px; - font-weight: 700; - color: var(--wxex-text-primary, #1f2933); -} - -.report-template-tagline { - margin-top: 4px; - font-size: 12px; - color: var(--wxex-text-secondary, #485465); - line-height: 1.5; -} - -.report-template-preview-btn { - padding: 6px 12px; - font-size: 12px; - font-weight: 600; - border-radius: 8px; - border: 1px solid var(--wxex-border); - background: #fff; - color: var(--wxex-text-primary, #1f2933); - cursor: pointer; - transition: - background 0.2s, - color 0.2s, - border-color 0.2s; -} - -.report-template-preview-btn:hover { - background: var(--wxex-primary, #07c160); - color: #fff; - border-color: var(--wxex-primary, #07c160); -} - -/* 预览遮罩 */ -.report-template-preview-mask { - position: fixed; - inset: 0; - background: rgba(15, 23, 42, 0.5); - display: flex; - align-items: center; - justify-content: center; - z-index: 999; - padding: 20px; -} - -.report-template-preview-card { - background: #f3f5f7; - border-radius: 18px; - padding: 18px; - width: min(380px, 100%); - max-height: 90vh; - overflow-y: auto; - box-shadow: 0 16px 60px rgba(15, 23, 42, 0.25); -} - -.report-template-preview-card h4 { - margin: 0 0 6px; - font-size: 17px; - font-weight: 800; -} - -.report-template-preview-card p.muted { - margin: 0 0 14px; - font-size: 12px; - color: var(--wxex-text-secondary, #485465); - line-height: 1.5; -} - -.report-template-preview-frame { - display: grid; - gap: 8px; - background: #fff; - border-radius: 14px; - padding: 12px; - border: 1px solid var(--wxex-border); -} - -.fake-card { - background: #f7faf9; - border-radius: 10px; - padding: 10px 12px; -} - -.fake-hero { - background: linear-gradient(135deg, #edf9f1 0%, #f7fbf8 100%); -} - -.fake-title { - font-size: 14px; - font-weight: 800; - color: #076c39; -} - -.fake-sub { - margin-top: 2px; - font-size: 11px; - color: #485465; -} - -.fake-section { - display: flex; - align-items: center; - gap: 8px; -} - -.fake-bar { - width: 4px; - height: 14px; - border-radius: 2px; - background: var(--wxex-primary, #07c160); -} - -.fake-section-title { - font-size: 12px; - font-weight: 700; - color: #1f2933; -} - -.report-template-preview-close { - margin-top: 14px; - width: 100%; - padding: 10px; - border-radius: 10px; - border: none; - background: var(--wxex-primary, #07c160); - color: #fff; - font-weight: 700; - cursor: pointer; -} - -.settings-auto-login-card { - padding: 18px 20px; -} -.settings-auto-login-card label { - display: flex; - align-items: center; - justify-content: space-between; - gap: 20px; - cursor: pointer; -} -.settings-auto-login-card label > span { - display: grid; - gap: 4px; -} -.settings-auto-login-card b { - color: var(--wxex-text-primary); - font: 700 13px/19px var(--wxex-font); -} -.settings-auto-login-card small { - color: var(--wxex-text-secondary); - font: 12px/18px var(--wxex-font); -} -.settings-auto-login-card input { - width: 18px; - height: 18px; - accent-color: var(--wxex-brand); -} -.settings-recall-card { - padding: 18px 20px; -} -.settings-recall-grid { - display: grid; - grid-template-columns: minmax(0, 1fr) minmax(220px, 0.8fr); - gap: 18px; - align-items: center; -} -.settings-recall-option { - display: flex; - align-items: center; - justify-content: space-between; - gap: 20px; - min-width: 0; - cursor: pointer; -} -.settings-recall-option span { - display: grid; - gap: 4px; -} -.settings-recall-option b { - color: var(--wxex-text-primary); - font: 700 13px/19px var(--wxex-font); -} -.settings-recall-option small { - color: var(--wxex-text-secondary); - font: 12px/18px var(--wxex-font); -} -.settings-recall-option input { - width: 18px; - height: 18px; - flex: 0 0 auto; - accent-color: var(--wxex-brand); -} -.settings-recall-notice { - display: grid; - gap: 3px; - padding-left: 14px; - border-left: 2px solid #e5b45f; - color: #765326; - font: 12px/18px var(--wxex-font); -} -.settings-recall-notice strong { - font-weight: 700; -} -.settings-recall-notice span { - color: #8a6a3e; -} -.api-upload-test-row { - display: flex; - align-items: center; - gap: 10px; - margin: 10px 0; -} -.api-upload-test-row button { - min-height: 32px; - padding: 0 12px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-sm); - background: var(--wxex-bg-elevated); - color: var(--wxex-text-primary); - cursor: pointer; - font: 600 12px/18px var(--wxex-font); -} -.api-upload-test-row span { - color: var(--wxex-text-muted); - font: 11px/17px var(--wxex-font); -} - -/* Export workspace */ -.export-workspace { - display: grid; - grid-template-columns: 292px minmax(520px, 1fr) 360px; - width: 100%; - height: 100%; - min-width: 0; - min-height: 0; - background: var(--wxex-bg-main); -} - -.export-contact-panel, -.export-config-panel, -.export-preview-panel { - min-width: 0; - min-height: 0; - background: var(--wxex-bg-elevated); -} - -.export-contact-panel { - display: flex; - flex-direction: column; - border-right: 1px solid var(--wxex-border); - background: var(--wxex-bg-sidebar); -} - -.export-panel-header { - padding: 20px 16px 12px; - border-bottom: 1px solid var(--wxex-border); -} - -.export-panel-title-row, -.export-section-heading, -.export-preview-heading, -.export-action-bar, -.export-target-path, -.export-media-master, -.export-account-summary { - display: flex; - align-items: center; -} - -.export-panel-title-row { - justify-content: space-between; - gap: 8px; - margin-bottom: 14px; -} - -.export-panel-title-row h2, -.export-config-header h1, -.export-job-state h2 { - margin: 0; - color: var(--wxex-text-primary); - font-weight: 700; -} - -.export-panel-title-row h2 { - font-size: 17px; -} - -.export-count-badge { - padding: 3px 8px; - border-radius: 5px; - background: var(--wxex-bg-elevated); - color: var(--wxex-text-secondary); - font-size: 11px; - white-space: nowrap; -} - -.export-search-field { - display: flex; - align-items: center; - gap: 8px; - height: 38px; - padding: 0 10px; - border: 1px solid var(--wxex-border); - border-radius: 7px; - background: var(--wxex-bg-elevated); - color: var(--wxex-text-muted); -} - -.export-search-field input, -.export-save-section input, -.export-date-fields input { - min-width: 0; - border: 0; - outline: 0; - background: transparent; - color: var(--wxex-text-primary); - font: 13px/20px var(--wxex-font); -} - -.export-search-field input { - width: 100%; -} - -.export-filter-tabs { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 3px; - margin-top: 12px; - padding: 3px; - border-radius: 7px; - background: #e3e9e5; -} - -.export-filter-tabs button, -.export-range-toggle button { - border: 0; - border-radius: 5px; - background: transparent; - color: var(--wxex-text-secondary); - cursor: pointer; - font: 600 12px/30px var(--wxex-font); -} - -.export-filter-tabs button.active, -.export-range-toggle button.active { - background: var(--wxex-bg-elevated); - color: var(--wxex-brand); - box-shadow: 0 1px 2px rgba(32, 39, 36, 0.06); -} - -.export-contact-list { - flex: 1; - min-height: 0; - overflow: auto; - padding: 8px 0; -} - -.export-contact-item { - display: flex; - align-items: center; - width: 100%; - gap: 10px; - padding: 11px 16px; - border: 0; - border-left: 3px solid transparent; - background: transparent; - color: var(--wxex-text-primary); - cursor: pointer; - text-align: left; -} - -.export-contact-item:hover { - background: rgba(255, 255, 255, 0.58); -} -.export-contact-item.active { - border-left-color: var(--wxex-brand); - background: var(--wxex-brand-soft); -} - -.export-contact-avatar, -.export-account-avatar, -.export-chat-avatar, -.export-preview-avatar { - display: grid; - place-items: center; - flex: 0 0 auto; - overflow: hidden; - background: var(--wxex-brand-soft); - color: var(--wxex-brand); - font-weight: 700; -} - -.export-contact-avatar { - width: 38px; - height: 38px; - border-radius: 8px; -} -.export-contact-avatar img, -.export-account-avatar img { - width: 100%; - height: 100%; - object-fit: cover; -} - -.export-contact-copy, -.export-account-summary > span:last-child { - display: grid; - min-width: 0; - gap: 2px; -} - -.export-contact-copy strong, -.export-account-summary strong { - overflow: hidden; - color: var(--wxex-text-primary); - font-size: 13px; - text-overflow: ellipsis; - white-space: nowrap; -} - -.export-contact-copy small, -.export-account-summary small { - color: var(--wxex-text-muted); - font-size: 11px; -} -.export-account-summary small.ready { - color: var(--wxex-success); -} - -.export-account-summary { - gap: 9px; - padding: 14px 16px; - border: 0; - border-top: 1px solid var(--wxex-border); - background: transparent; - text-align: left; - cursor: pointer; -} - -.export-account-avatar { - width: 34px; - height: 34px; - border-radius: 50%; -} - -.export-config-panel { - display: flex; - flex-direction: column; - overflow: hidden; - background: var(--wxex-bg-main); -} - -.export-config-scroll { - flex: 1; - min-height: 0; - overflow: auto; - padding: 24px 28px 28px; -} - -.export-config-header { - display: flex; - align-items: center; - gap: 14px; - margin-bottom: 26px; -} -.export-chat-avatar { - width: 52px; - height: 52px; - border-radius: 10px; - font-size: 22px; -} -.export-chat-avatar img, -.export-preview-avatar img { - width: 100%; - height: 100%; - object-fit: cover; -} -.export-config-header h1 { - font-size: 20px; - line-height: 28px; -} -.export-config-header p { - margin: 2px 0 0; - color: var(--wxex-text-secondary); - font-size: 13px; -} - -.export-section { - margin-bottom: 25px; -} -.export-section h3 { - margin: 0 0 12px; - color: var(--wxex-text-primary); - font-size: 12px; - font-weight: 700; -} -.export-section-heading { - justify-content: space-between; - gap: 12px; -} -.export-section-heading span { - color: var(--wxex-brand); - font-size: 12px; -} - -.export-range-toggle { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 8px; -} -.export-range-toggle button { - border: 1px solid var(--wxex-border); - background: var(--wxex-bg-elevated); - line-height: 36px; -} -.export-range-toggle button.active { - border-color: var(--wxex-brand); - background: var(--wxex-brand); - color: #fff; - box-shadow: none; -} - -.export-date-fields { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 10px; - margin-top: 10px; - padding: 12px; - border-radius: 8px; - background: #f0f3f0; -} -.export-date-fields label, -.export-save-section > label { - display: grid; - gap: 5px; - color: var(--wxex-text-secondary); - font-size: 11px; -} -.export-date-fields input, -.export-save-section input { - width: 100%; - padding: 8px 9px; - border: 1px solid var(--wxex-border); - border-radius: 6px; - background: #fff; -} - -.export-kind-grid { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 4px 20px; - padding: 14px; - border-radius: 8px; - background: #f0f3f0; -} -.export-check-row { - display: flex; - align-items: center; - gap: 8px; - min-height: 28px; - color: var(--wxex-text-primary); - font-size: 12px; - cursor: pointer; -} -.export-check-row input { - width: 16px; - height: 16px; - accent-color: var(--wxex-brand); -} -.export-check-row.unsupported { - color: var(--wxex-text-muted); - cursor: not-allowed; -} -.export-check-row.unsupported input { - cursor: not-allowed; -} -.export-unsupported-hint { - display: inline-grid; - width: 16px; - height: 16px; - place-items: center; - border: 1px solid #c57923; - border-radius: 50%; - color: #a85e13; - font-size: 11px; - font-weight: 700; - line-height: 1; -} -.export-name-mode-grid { - display: flex; - gap: 8px; - padding: 10px; - border-radius: 8px; - background: #f0f3f0; -} -.export-name-mode-option { - display: flex; - align-items: center; - gap: 7px; - flex: 1; - min-height: 32px; - padding: 0 8px; - border: 1px solid var(--wxex-border); - border-radius: 6px; - background: #fff; - color: var(--wxex-text-primary); - font-size: 12px; - cursor: pointer; -} -.export-name-mode-option input { - accent-color: var(--wxex-brand); -} - -.export-media-master { - justify-content: space-between; - gap: 12px; - padding: 13px 14px; - border: 1px solid var(--wxex-border); - border-radius: 7px; - background: #fff; - color: var(--wxex-text-primary); - font-size: 12px; -} -.export-media-master input { - width: 17px; - height: 17px; - accent-color: var(--wxex-brand); -} -.export-media-options { - display: grid; - gap: 2px; - margin-top: 8px; - padding: 9px 13px; - border-radius: 8px; - background: #f0f3f0; -} -.export-media-options.disabled { - opacity: 0.52; -} -.export-resource-statuses { - display: flex; - flex-wrap: wrap; - gap: 6px; - margin-top: 9px; -} -.export-resource-statuses span { - padding: 3px 7px; - border-radius: 4px; - background: var(--wxex-brand-soft); - color: var(--wxex-success); - font-size: 10px; -} -.export-helper-text { - margin: 9px 0 0; - color: var(--wxex-text-muted); - font-size: 11px; -} - -.export-format-grid { - display: grid; - grid-template-columns: repeat(4, 1fr); - gap: 8px; -} -.export-format-grid button { - min-height: 78px; - border: 1px solid var(--wxex-border); - border-radius: 8px; - background: #fff; - color: var(--wxex-text-primary); - cursor: pointer; -} -.export-format-grid button.active { - border: 2px solid var(--wxex-brand); - background: #f2f8f5; -} -.export-format-grid strong { - display: block; - font-size: 13px; -} -.export-format-grid small { - display: block; - margin-top: 6px; - color: var(--wxex-success); - font-size: 10px; -} -.export-html-options { - display: grid; - gap: 8px; - margin-top: 10px; - padding: 11px 13px; - border: 1px solid var(--wxex-border); - border-radius: 8px; - background: #f0f3f0; - color: var(--wxex-text-primary); - font-size: 12px; -} -.export-html-options input { - accent-color: var(--wxex-brand); -} - -.export-save-section { - display: grid; - gap: 12px; -} -.export-target-path { - gap: 10px; - padding: 9px 10px; - border: 1px solid var(--wxex-border); - border-radius: 7px; - background: #fff; - color: var(--wxex-text-secondary); - font-size: 11px; -} -.export-target-path strong { - flex: 1; - min-width: 0; - overflow: hidden; - color: var(--wxex-text-primary); - font-weight: 500; - text-overflow: ellipsis; - white-space: nowrap; -} -.export-target-path button { - padding: 5px 8px; - border: 1px solid var(--wxex-border); - border-radius: 5px; - background: #fff; - color: var(--wxex-text-primary); - cursor: pointer; - font: 11px var(--wxex-font); -} - -.export-action-bar { - flex: 0 0 58px; - gap: 8px; - padding: 0 22px; - border-top: 1px solid var(--wxex-border); - background: #fff; - color: var(--wxex-text-secondary); - font-size: 12px; -} -.export-ready-dot { - width: 8px; - height: 8px; - border-radius: 50%; - background: var(--wxex-success); -} -.export-ready-dot.completed { - background: var(--wxex-brand); -} -.export-target-summary { - flex: 1; - min-width: 0; - margin-left: 14px; - overflow: hidden; - color: var(--wxex-text-muted); - text-overflow: ellipsis; - white-space: nowrap; -} -.export-reset-button { - border: 0; - background: transparent; - color: var(--wxex-text-primary); - cursor: pointer; - font: 600 12px var(--wxex-font); -} -.export-primary-button { - min-width: 132px; - padding: 10px 16px; - border: 0; - border-radius: 7px; - background: var(--wxex-brand); - color: #fff; - cursor: pointer; - font: 700 12px var(--wxex-font); -} -.export-primary-button:disabled { - cursor: default; - opacity: 0.55; -} - -.export-preview-panel { - display: flex; - flex-direction: column; - overflow: hidden; - border-left: 1px solid var(--wxex-border); - background: #fbfcfb; -} -.export-preview-heading { - justify-content: space-between; - flex: 0 0 52px; - padding: 0 18px; - border-bottom: 1px solid var(--wxex-border); - color: var(--wxex-text-primary); - font-size: 12px; -} -.export-preview-heading span { - color: var(--wxex-text-muted); - font-size: 11px; -} -.export-message-preview { - flex: 1; - min-height: 0; - overflow: auto; - padding: 16px 14px; -} -.export-preview-date { - width: fit-content; - margin: 0 auto 18px; - padding: 4px 9px; - border-radius: 10px; - background: #e9eeeb; - color: var(--wxex-text-secondary); - font-size: 10px; -} -.export-preview-message { - display: flex; - align-items: flex-start; - gap: 8px; - width: min(100%, 620px); - margin: 0 auto 15px; -} -.export-preview-message.mine { - flex-direction: row-reverse; -} -.export-preview-message.system { - justify-content: center; - flex-direction: row; -} -.export-preview-avatar { - width: 30px; - height: 30px; - border-radius: 7px; - font-size: 11px; -} -.export-preview-bubble { - max-width: 78%; - padding: 9px 10px; - border-radius: 8px; - background: #fff; - color: var(--wxex-text-primary); - font-size: 12px; - line-height: 18px; - box-shadow: 0 1px 2px rgba(32, 39, 36, 0.05); -} -.export-preview-message.mine .export-preview-bubble { - background: #95ec69; -} -.export-preview-message.system .export-preview-avatar { - display: none; -} -.export-preview-message.system .export-preview-bubble { - max-width: 92%; - padding: 5px 10px; - border: 0; - border-radius: 5px; - background: #e9eeeb; - color: var(--wxex-text-muted); - font-size: 11px; - text-align: center; - box-shadow: none; -} -.export-preview-message.system .export-preview-bubble small { - display: none; -} -.export-preview-bubble small { - display: block; - margin-bottom: 3px; - color: var(--wxex-text-muted); - font-size: 10px; -} -.export-preview-stats { - flex: 0 0 auto; - display: grid; - gap: 12px; - padding: 18px; - border-top: 1px solid var(--wxex-border); -} - -.export-task-center-button { - align-self: flex-start; - margin: 0 0 12px; - border: 1px solid var(--wxex-border); - border-radius: 6px; - background: var(--wxex-bg-elevated); - color: var(--wxex-brand); - cursor: pointer; - padding: 7px 11px; - font: 600 12px/18px var(--wxex-font); -} - -.export-task-center { - margin: 0 0 18px; - padding: 12px; - border: 1px solid var(--wxex-border); - border-radius: 8px; - background: var(--wxex-bg-elevated); -} - -.export-task-row { - display: grid; - grid-template-columns: minmax(0, 1fr) auto auto; - align-items: center; - gap: 12px; - padding: 9px 0; - border-top: 1px solid var(--wxex-border); - color: var(--wxex-text-secondary); - font-size: 12px; -} - -.export-task-row:first-of-type { - margin-top: 8px; -} - -.export-task-row span:first-child { - display: grid; - gap: 2px; - min-width: 0; -} - -.export-task-row strong, -.export-task-row small { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.export-task-row strong { - color: var(--wxex-text-primary); -} - -.export-task-progress { - position: relative; - width: 110px; - height: 6px; - overflow: hidden; - border-radius: 999px; - background: var(--wxex-border); -} - -.export-task-progress i { - display: block; - height: 100%; - border-radius: inherit; - background: var(--wxex-brand); -} - -.export-task-progress b { - position: absolute; - top: 10px; - right: 0; - color: var(--wxex-text-muted); - font-size: 10px; - font-weight: 500; -} - -.export-task-row button { - border: 1px solid var(--wxex-border); - border-radius: 5px; - background: transparent; - color: var(--wxex-text-secondary); - cursor: pointer; - padding: 4px 8px; -} -.export-preview-panel .export-preview-stats:not(.export-preview-real-stats) { - display: none; -} -.export-preview-stats span, -.export-complete-summary span { - display: flex; - justify-content: space-between; - color: var(--wxex-text-secondary); - font-size: 12px; -} -.export-preview-stats strong, -.export-complete-summary strong { - color: var(--wxex-text-primary); - font-weight: 600; -} - -.export-job-state { - display: grid; - align-content: center; - gap: 12px; - height: 100%; - padding: 28px; - text-align: center; -} -.export-job-state h2 { - font-size: 18px; -} -.export-job-state p { - margin: 0; - color: var(--wxex-text-secondary); - font-size: 12px; - line-height: 18px; -} -.export-job-state ol { - display: grid; - gap: 10px; - margin: 8px 0; - padding: 0; - list-style: none; - text-align: left; -} -.export-job-state li { - color: var(--wxex-text-muted); - font-size: 12px; -} -.export-job-state li::before { - display: inline-grid; - width: 16px; - height: 16px; - margin-right: 8px; - place-items: center; - border: 1px solid var(--wxex-border); - border-radius: 50%; - content: ''; - vertical-align: -3px; -} -.export-job-state li.done { - color: var(--wxex-success); -} -.export-job-state li.done::before { - border-color: var(--wxex-success); - background: var(--wxex-success); - content: '✓'; - color: #fff; - font-size: 10px; -} -.export-job-state li.current { - color: var(--wxex-text-primary); - font-weight: 600; -} -.export-job-state li.current::before { - border-color: var(--wxex-brand); - background: var(--wxex-brand); - box-shadow: inset 0 0 0 4px #fff; -} -.export-progress-bar { - height: 6px; - overflow: hidden; - border-radius: 4px; - background: #e2e9e4; -} -.export-progress-bar span { - display: block; - height: 100%; - border-radius: 4px; - background: var(--wxex-brand); - transition: width 0.2s ease; -} -.export-job-state > strong { - color: var(--wxex-text-secondary); - font-size: 12px; - font-weight: 500; -} -.export-cancel-button, -.export-open-folder-button { - padding: 10px 14px; - border: 1px solid var(--wxex-border); - border-radius: 7px; - background: #fff; - color: var(--wxex-text-primary); - cursor: pointer; - font: 600 12px var(--wxex-font); -} -.export-success-icon { - width: 58px; - height: 58px; - margin: 0 auto 4px; - border: 5px solid var(--wxex-brand-soft); - border-radius: 50%; - background: #fff; - color: var(--wxex-brand); - font-size: 30px; - line-height: 48px; -} -.export-complete-summary { - display: grid; - gap: 12px; - margin: 12px 0; - padding: 14px; - border-radius: 8px; - background: #eef3ef; - text-align: left; -} - -@media (max-width: 1100px) { - .export-workspace { - grid-template-columns: 248px minmax(460px, 1fr); - } - .export-preview-panel { - display: none; - } -} diff --git a/src/renderer/src/components/export/ExportContactPanel.tsx b/src/renderer/src/components/export/ExportContactPanel.tsx new file mode 100644 index 0000000..893360c --- /dev/null +++ b/src/renderer/src/components/export/ExportContactPanel.tsx @@ -0,0 +1,107 @@ +import React from 'react' +import type { Contact, SelfInfo } from './exportTypes' +import { displayName } from './exportUtils' + +interface ExportContactPanelProps { + contacts: Contact[] + filteredContacts: Contact[] + activeContact: Contact | null + selfInfo: SelfInfo | null + dbReady: boolean + contactFilter: string + contactType: 'all' | 'group' | 'user' + onContactFilterChange: (value: string) => void + onContactTypeChange: (value: 'all' | 'group' | 'user') => void + onSelectContact: (contact: Contact) => void + onOpenSettings: () => void +} + +export function ExportContactPanel({ + contacts, + filteredContacts, + activeContact, + selfInfo, + dbReady, + contactFilter, + contactType, + onContactFilterChange, + onContactTypeChange, + onSelectContact, + onOpenSettings +}: ExportContactPanelProps): React.ReactElement { + return ( + + ) +} diff --git a/src/renderer/src/components/export/ExportPreviewPanel.tsx b/src/renderer/src/components/export/ExportPreviewPanel.tsx new file mode 100644 index 0000000..91d4be4 --- /dev/null +++ b/src/renderer/src/components/export/ExportPreviewPanel.tsx @@ -0,0 +1,164 @@ +import React from 'react' +import type { Message } from './exportTypes' +import type { ExportJobProgress, ExportStatus, SelfInfo } from './exportTypes' +import { formatPreviewTime } from './exportUtils' + +interface ExportPreviewPanelProps { + status: ExportStatus + previewItems: Message[] + previewMediaCount: number + previewBytes: number + selfInfo: SelfInfo | null + progress: ExportJobProgress | null + jobId: string + onCancel: (jobId: string) => void + onReveal: (path: string) => void +} + +export function ExportPreviewPanel({ + status, + previewItems, + previewMediaCount, + previewBytes, + selfInfo, + progress, + jobId, + onCancel, + onReveal +}: ExportPreviewPanelProps): React.ReactElement { + return ( + + ) +} diff --git a/src/renderer/src/components/export/ExportTaskCenter.tsx b/src/renderer/src/components/export/ExportTaskCenter.tsx new file mode 100644 index 0000000..f8e21c0 --- /dev/null +++ b/src/renderer/src/components/export/ExportTaskCenter.tsx @@ -0,0 +1,57 @@ +import React from 'react' +import type { ExportTaskRecord } from './exportTypes' + +interface ExportTaskCenterProps { + open: boolean + taskCount: number + tasks: ExportTaskRecord[] + onToggle: () => void + onCancel: (jobId: string) => void +} + +export function ExportTaskCenter({ + open, + taskCount, + tasks, + onToggle, + onCancel +}: ExportTaskCenterProps): React.ReactElement { + return ( + <> + + {open && ( +
+
+

导出任务

+ {tasks.length} 条记录 +
+ {tasks.length === 0 ? ( +

暂无导出记录

+ ) : ( + tasks.map((task) => ( +
+ + {task.contactName} + + {task.format.toUpperCase()} · {task.progress.phase} + + + + + {task.progress.percent ?? 0}% + + {task.status === 'running' && ( + + )} +
+ )) + )} +
+ )} + + ) +} diff --git a/src/renderer/src/components/export/ExportWorkspace.tsx b/src/renderer/src/components/export/ExportWorkspace.tsx index 3ef21c8..4c0bdc5 100644 --- a/src/renderer/src/components/export/ExportWorkspace.tsx +++ b/src/renderer/src/components/export/ExportWorkspace.tsx @@ -1,75 +1,21 @@ import React, { useMemo, useState } from 'react' -import type { Contact, Message } from '../../../../shared/types' +import type { Message } from '../../../../shared/types' import type { ExportJobProgress, ExportMessageKind, ExportNameMode } from '../../../../shared/export' -import type { ExportRequest, ExportResult, ExportTaskRecord } from '../../../../shared/export' - -type ExportRange = 'today' | 'threeDays' | 'sevenDays' | 'custom' -type ExportFormat = 'html' | 'csv' | 'json' | 'markdown' -type ExportStatus = 'idle' | 'running' | 'completed' - -interface GroupMemberName { - wxid: string - nickname: string - groupNickname: string - wechatNickname: string - remark: string - avatar: string -} - -interface SelfInfo { - wxid: string - nickname: string - avatar?: string - accountRoot: string -} - -interface ExportWorkspaceProps { - contacts: Contact[] - selectedContact: Contact | null - previewMessages: Message[] - selfInfo: SelfInfo | null - dbReady: boolean - onSelectContact: (contact: Contact) => void - onOpenSettings: () => void - exportTasks: ExportTaskRecord[] - onStartExport: (request: ExportRequest) => Promise - onCancelExport: (jobId: string) => Promise -} - -const messageKinds = [ - ['text', '文字'], - ['image', '图片'], - ['video', '视频'], - ['voice', '语音'], - ['sticker', '表情包'], - ['share', '链接与分享'], - ['location', '位置'], - ['system', '系统消息'] -] as const - -const formatLabels: Record = { - html: { label: 'HTML', hint: '推荐' }, - csv: { label: 'CSV' }, - json: { label: 'JSON' }, - markdown: { label: 'Markdown' } -} -const formatOrder: ExportFormat[] = ['csv', 'html', 'json', 'markdown'] - -function displayName(contact: Contact | null): string { - return contact?.m_nsNickName || contact?.m_nsUsrName || '未选择会话' -} - -function formatPreviewTime(message: Message): string { - if (!message.createTime) return message.datetime || '' - return new Date(message.createTime * 1000).toLocaleTimeString('zh-CN', { - hour: '2-digit', - minute: '2-digit' - }) -} +import { ExportContactPanel } from './ExportContactPanel' +import { ExportPreviewPanel } from './ExportPreviewPanel' +import { ExportTaskCenter } from './ExportTaskCenter' +import type { + ExportFormat, + ExportRange, + ExportStatus, + ExportWorkspaceProps, + GroupMemberName +} from './exportTypes' +import { displayName, formatLabels, formatOrder, messageKinds } from './exportUtils' export function ExportWorkspace({ contacts, @@ -313,97 +259,29 @@ export function ExportWorkspace({ return (
- +
- - {taskCenterOpen && ( -
-

导出任务

{exportTasks.length} 条记录
- {exportTasks.length === 0 ?

暂无导出记录

: exportTasks.map((task) => ( -
- {task.contactName}{task.format.toUpperCase()} · {task.progress.phase} - {task.progress.percent ?? 0}% - {task.status === 'running' && } -
- ))} -
- )} + setTaskCenterOpen((open) => !open)} + onCancel={(taskJobId) => void onCancelExport(taskJobId)} + />
{activeContact?.avatar ? ( @@ -678,145 +556,20 @@ export function ExportWorkspace({
- + { + void window.api.cancelExport(exportJobId) + setStatus('idle') + }} + onReveal={(path) => void window.api.revealExport(path)} + />
) } diff --git a/src/renderer/src/components/export/exportTypes.ts b/src/renderer/src/components/export/exportTypes.ts new file mode 100644 index 0000000..aa60f90 --- /dev/null +++ b/src/renderer/src/components/export/exportTypes.ts @@ -0,0 +1,44 @@ +import type { Contact, Message } from '../../../../shared/types' +import type { + ExportJobProgress, + ExportMessageKind, + ExportNameMode, + ExportRequest, + ExportResult, + ExportTaskRecord +} from '../../../../shared/export' + +export type ExportRange = 'today' | 'threeDays' | 'sevenDays' | 'custom' +export type ExportFormat = 'html' | 'csv' | 'json' | 'markdown' +export type ExportStatus = 'idle' | 'running' | 'completed' + +export interface GroupMemberName { + wxid: string + nickname: string + groupNickname: string + wechatNickname: string + remark: string + avatar: string +} + +export interface SelfInfo { + wxid: string + nickname: string + avatar?: string + accountRoot: string +} + +export interface ExportWorkspaceProps { + contacts: Contact[] + selectedContact: Contact | null + previewMessages: Message[] + selfInfo: SelfInfo | null + dbReady: boolean + onSelectContact: (contact: Contact) => void + onOpenSettings: () => void + exportTasks: ExportTaskRecord[] + onStartExport: (request: ExportRequest) => Promise + onCancelExport: (jobId: string) => Promise +} + +export type { Contact, ExportJobProgress, ExportMessageKind, Message, ExportNameMode, ExportTaskRecord } diff --git a/src/renderer/src/components/export/exportUtils.ts b/src/renderer/src/components/export/exportUtils.ts new file mode 100644 index 0000000..e4245d9 --- /dev/null +++ b/src/renderer/src/components/export/exportUtils.ts @@ -0,0 +1,77 @@ +import type { Contact, Message } from '../../../../shared/types' +import type { ExportFormat, GroupMemberName } from './exportTypes' + +export const messageKinds = [ + ['text', '文字'], + ['image', '图片'], + ['video', '视频'], + ['voice', '语音'], + ['sticker', '表情包'], + ['share', '链接与分享'], + ['location', '位置'], + ['system', '系统消息'] +] as const + +export const formatLabels: Record = { + html: { label: 'HTML', hint: '推荐' }, + csv: { label: 'CSV' }, + json: { label: 'JSON' }, + markdown: { label: 'Markdown' } +} + +export const formatOrder: ExportFormat[] = ['csv', 'html', 'json', 'markdown'] + +export function displayName(contact: Contact | null): string { + return contact?.m_nsNickName || contact?.m_nsUsrName || '未选择会话' +} + +export function formatPreviewTime(message: Message): string { + if (!message.createTime) return message.datetime || '' + return new Date(message.createTime * 1000).toLocaleTimeString('zh-CN', { + hour: '2-digit', + minute: '2-digit' + }) +} + +export function buildNameMap( + activeContact: Contact | null, + groupMembers: GroupMemberName[], + nameMode: string, + selfInfo: { wxid: string; nickname: string } | null +): Record { + const map: Record = {} + if (activeContact?.type === 'group') { + for (const member of groupMembers) { + const value = + nameMode === 'groupNickname' + ? member.groupNickname || member.nickname || member.wxid + : nameMode === 'remark' + ? member.remark || member.wechatNickname || member.wxid + : member.wechatNickname || member.wxid + map[member.wxid] = value + } + } else if (activeContact) { + map[activeContact.m_nsUsrName] = + nameMode === 'remark' + ? activeContact.remark || activeContact.m_nsNickName || activeContact.m_nsUsrName + : activeContact.wechatNickname || activeContact.m_nsUsrName + } + if (selfInfo?.wxid) map[selfInfo.wxid] = selfInfo.nickname || selfInfo.wxid + return map +} + +export function buildAvatarUrls( + activeContact: Contact | null, + groupMembers: GroupMemberName[], + selfInfo: { wxid: string; avatar?: string } | null +): Record { + const map: Record = {} + if (activeContact?.m_nsUsrName && activeContact.avatar) { + map[activeContact.m_nsUsrName] = activeContact.avatar + } + for (const member of groupMembers) { + if (member.avatar) map[member.wxid] = member.avatar + } + if (selfInfo?.wxid && selfInfo.avatar) map[selfInfo.wxid] = selfInfo.avatar + return map +} diff --git a/src/renderer/src/components/search/AISearchWorkspace.tsx b/src/renderer/src/components/search/AISearchWorkspace.tsx index 4c60155..e17e534 100644 --- a/src/renderer/src/components/search/AISearchWorkspace.tsx +++ b/src/renderer/src/components/search/AISearchWorkspace.tsx @@ -1,479 +1,47 @@ import React, { useMemo, useRef, useState } from 'react' -import type { AIRuntimeModelConfig } from '../../../../shared/ai-provider' import type { Contact, Message } from '../../../../shared/types' import { SearchIcon } from '../chat/icons' -type SearchStage = 'idle' | 'loading' | 'result' | 'insufficient' -type SearchScope = 'global' | 'conversation' -type SearchRange = 'today' | '7d' | '30d' | 'all' -type SearchIntent = 'general' | 'topic' | 'participants' | 'mixed' - -interface EvidenceItem { - contact: Contact - message: Message -} - -interface AISearchCacheRecord { - version: 1 - key: string - createdAt: number - answer: string - evidence: EvidenceItem[] - senderNames: Record - messageCount: number -} - -interface GroupMemberName { - wxid: string - nickname?: string - groupNickname?: string - remark?: string - wechatNickname?: string -} - -interface SenderDirectory { - displayNames: Record - aliases: Record -} - -interface SearchQueryPlan { - intent: SearchIntent - keywords: string[] - variants: string[] - source: 'local' | 'ai' | 'hybrid' -} - -interface SearchPassSummary { - label: string - keywords: string[] - messageCount: number -} - -interface AISearchWorkspaceProps { - contacts: Contact[] - selectedContact: Contact | null - dbReady: boolean - aiModelConfig: AIRuntimeModelConfig - onSelectContact: (contact: Contact) => void - onOpenEvidence: (contact: Contact, createTime?: number) => void - onOpenAISettings: () => void - onNotice: (message: string) => void -} - -const RANGE_LABELS: Record = { - today: '今天', - '7d': '近 7 天', - '30d': '近 30 天', - all: '全部历史' -} - -const SEARCH_CACHE_KEY = 'wxe_ai_search_cache_v8' -const SEARCH_HISTORY_KEY = 'wxe_ai_search_history_v1' -const SEARCH_CACHE_LIMIT = 20 -const currentTimestamp = (): number => Date.now() - -const SEARCH_INTENT_PHRASES = [ - '全局搜一下', - '全局搜索', - '搜索一下', - '搜一下', - '查询一下', - '查一下', - '找一下', - '我和谁聊过', - '谁和我聊过', - '哪些人和我聊过', - '最近讨论了什么', - '最近聊了什么', - '最近说了什么', - '讨论了什么', - '讨论什么', - '聊了什么', - '聊些什么', - '说了什么', - '说些什么', - '最近讨论', - '最近聊天', - '这个话题', - '相关话题', - '的聊天', - '的内容', - '的记录', - '关于', - '聊天', - '记录', - '聊天记录', - '帮我', - '请问' -].sort((left, right) => right.length - left.length) - -const SEARCH_STOP_WORDS = new Set([ - '我', - '谁', - '什么', - '哪些', - '哪个', - '人', - '和', - '聊过', - '说过', - '提到', - '讨论', - '聊天', - '记录', - '说', - '聊', - '话题', - '内容', - '相关', - '最近', - '一下' -]) - -const messageText = (message: Message): string => - String(message.content || '').trim() || `[${message.type || '消息'}]` - -const normalizeSearchText = (value: string): string => value.toLowerCase().replace(/\s+/g, '') - -const includesSearchAlias = (query: string, alias: string): boolean => { - const normalizedAlias = normalizeSearchText(alias.trim()) - return Boolean(normalizedAlias) && normalizeSearchText(query).includes(normalizedAlias) -} - -const extractSearchKeywords = (query: string): string[] => { - const cleanedQuery = SEARCH_INTENT_PHRASES.reduce( - (value, phrase) => value.split(phrase).join(' '), - query.toLowerCase() - ) - const tokens = cleanedQuery - .split(/[\s,,。!?!?、::;;"“”‘’()()[\]【】]+/) - .map((token) => token.trim()) - .filter((token) => token.length >= 2 && !SEARCH_STOP_WORDS.has(token)) - return Array.from(new Set(tokens)) -} - -const getFuzzySearchKeywords = (keywords: string[]): string[] => - Array.from( - new Set( - keywords.flatMap((keyword) => { - const variants = [keyword] - if (/^[\u4e00-\u9fff]+$/.test(keyword) && keyword.length > 2) { - variants.push(keyword.slice(-2)) - } - return variants - }) - ) - ) - -const normalizeSearchTerms = (terms: unknown): string[] => { - if (!Array.isArray(terms)) return [] - return Array.from( - new Set( - terms - .filter((term): term is string => typeof term === 'string') - .map((term) => term.trim()) - .filter((term) => term.length >= 2 && term.length <= 32) - ) - ).slice(0, 16) -} - -const buildLocalSearchPlan = (query: string): SearchQueryPlan => { - const keywords = extractSearchKeywords(query) - const asksParticipants = /我和谁|谁和我|哪些人|哪个人|哪些联系人/.test(query) - const intent: SearchIntent = asksParticipants - ? keywords.length - ? 'mixed' - : 'participants' - : keywords.length - ? 'topic' - : 'general' - return { - intent, - keywords, - variants: getFuzzySearchKeywords(keywords), - source: 'local' - } -} - -const parseSearchPlanResponse = (value: string): Partial | null => { - const jsonMatch = value.match(/\{[\s\S]*\}/) - if (!jsonMatch) return null - try { - const parsed = JSON.parse(jsonMatch[0]) as Record - const intent = ['general', 'topic', 'participants', 'mixed'].includes(String(parsed.intent)) - ? (parsed.intent as SearchIntent) - : undefined - return { - intent, - keywords: normalizeSearchTerms(parsed.keywords), - variants: normalizeSearchTerms(parsed.variants) - } - } catch { - return null - } -} - -const mergeSearchPlans = ( - localPlan: SearchQueryPlan, - aiPlan: Partial | null -): SearchQueryPlan => { - if (!aiPlan) return localPlan - const keywords = normalizeSearchTerms([...(localPlan.keywords || []), ...(aiPlan.keywords || [])]) - const variants = normalizeSearchTerms([ - ...getFuzzySearchKeywords(keywords), - ...(localPlan.variants || []), - ...(aiPlan.variants || []) - ]) - return { - intent: aiPlan.intent || localPlan.intent, - keywords, - variants, - source: 'hybrid' - } -} - -const messageIdentity = (message: Message): string => - message.localId - ? `local:${message.localId}` - : message.id || `${message.createTime}:${message.content}` - -const evidenceIdentity = ({ contact, message }: EvidenceItem): string => - `${contact.md5}:${messageIdentity(message)}` - -const formatMessageTime = (message: Message): string => { - if (message.datetime) return message.datetime - if (message.createTime) return new Date(message.createTime * 1000).toLocaleString('zh-CN') - return '未知时间' -} - -const getRangeStart = (range: SearchRange): number | undefined => { - if (range === 'all') return undefined - if (range === 'today') { - const now = new Date() - return Math.floor(new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime() / 1000) - } - const days = range === '7d' ? 7 : 30 - return Math.floor(Date.now() / 1000) - days * 86400 -} - -const messageDateKey = (message: Message): string => { - if (!message.createTime) return 'unknown' - const date = new Date(message.createTime * 1000) - const year = date.getFullYear() - const month = String(date.getMonth() + 1).padStart(2, '0') - const day = String(date.getDate()).padStart(2, '0') - return `${year}-${month}-${day}` -} - -const formatMessageDate = (dateKey: string): string => { - if (dateKey === 'unknown') return '--/--' - const [, month, day] = dateKey.split('-') - return `${month}/${day}` -} - -const selectEvenly = (items: T[], count: number): T[] => { - if (count >= items.length) return items - if (count <= 0) return [] - if (count === 1) return [items[items.length - 1]] - return Array.from({ length: count }, (_item, index) => { - const itemIndex = Math.round((index * (items.length - 1)) / (count - 1)) - return items[itemIndex] - }) -} - -const selectEvidenceByDate = (items: EvidenceItem[], maxItems: number): EvidenceItem[] => { - const buckets = new Map() - items.forEach((item) => { - const key = messageDateKey(item.message) - const bucket = buckets.get(key) || [] - bucket.push(item) - buckets.set(key, bucket) - }) - const entries = Array.from(buckets.entries()).sort(([left], [right]) => left.localeCompare(right)) - const targetCount = Math.min(maxItems, items.length) - const counts = entries.map(() => 0) - let remaining = targetCount - while (remaining > 0) { - let bestIndex = -1 - let bestRemaining = 0 - entries.forEach(([, bucket], index) => { - const available = bucket.length - counts[index] - if (available > bestRemaining) { - bestIndex = index - bestRemaining = available - } - }) - if (bestIndex < 0) break - counts[bestIndex] += 1 - remaining -= 1 - } - return entries - .flatMap((entry, index) => selectEvenly(entry[1], counts[index])) - .sort((left, right) => (left.message.createTime || 0) - (right.message.createTime || 0)) -} - -const looksLikeUserId = (value: string): boolean => - value.startsWith('wxid_') || value.includes('@chatroom') || /^\d{6,}$/.test(value) - -const formatMemberName = (member: GroupMemberName): string => - member.groupNickname || member.wechatNickname || member.nickname || member.remark || member.wxid - -const senderName = (message: Message, contact: Contact, names: Record): string => { - const identifiers = [message.senderId, message.from, message.name].filter( - (value): value is string => Boolean(value?.trim()) - ) - const mappedName = identifiers.map((value) => names[value]).find(Boolean) - if (mappedName) return mappedName - if (message.name && !looksLikeUserId(message.name)) return message.name - if (message.isSender) return '我' - return contact.type === 'user' ? contact.m_nsNickName || '联系人' : '群成员' -} - -const compactCacheItem = ({ contact, message }: EvidenceItem): EvidenceItem => ({ - contact: { - md5: contact.md5, - m_nsUsrName: contact.m_nsUsrName, - m_nsNickName: contact.m_nsNickName, - type: contact.type, - avatar: contact.avatar - }, - message: { - id: message.id, - from: message.from, - type: message.type, - datetime: message.datetime, - content: message.content, - isSender: message.isSender, - name: message.name, - senderId: message.senderId, - localId: message.localId, - serverId: message.serverId, - createTime: message.createTime - } -}) - -const buildSearchCacheKey = ( - scope: SearchScope, - contactMd5: string, - range: SearchRange, - query: string -): string => JSON.stringify([scope, contactMd5, range, query.trim().toLowerCase()]) - -const parseSearchCacheKey = ( - key: string -): { scope: SearchScope; contactMd5: string; range: SearchRange; query: string } | null => { - try { - const parts = JSON.parse(key) as unknown - if ( - !Array.isArray(parts) || - !['global', 'conversation'].includes(String(parts[0])) || - !['today', '7d', '30d', 'all'].includes(String(parts[2])) || - typeof parts[3] !== 'string' - ) { - return null - } - return { - scope: parts[0] as SearchScope, - contactMd5: typeof parts[1] === 'string' ? parts[1] : '', - range: parts[2] as SearchRange, - query: parts[3] - } - } catch { - return null - } -} - -const readSearchCache = (key: string): AISearchCacheRecord | null => { - try { - const records = JSON.parse( - localStorage.getItem(SEARCH_CACHE_KEY) || '[]' - ) as AISearchCacheRecord[] - const record = records.find((item) => item.version === 1 && item.key === key) - return record || null - } catch { - return null - } -} - -const readSearchCacheByQuery = ( - query: string -): { record: AISearchCacheRecord; location: ReturnType } | null => { - try { - const records = JSON.parse( - localStorage.getItem(SEARCH_CACHE_KEY) || '[]' - ) as AISearchCacheRecord[] - const normalizedQuery = query.trim().toLowerCase() - for (const record of records) { - const location = parseSearchCacheKey(record.key) - if (record.version === 1 && location?.query === normalizedQuery) { - return { record, location } - } - } - return null - } catch { - return null - } -} - -const writeSearchCache = (record: AISearchCacheRecord): void => { - try { - const records = JSON.parse( - localStorage.getItem(SEARCH_CACHE_KEY) || '[]' - ) as AISearchCacheRecord[] - const nextRecords = [record, ...records.filter((item) => item.key !== record.key)].slice( - 0, - SEARCH_CACHE_LIMIT - ) - localStorage.setItem(SEARCH_CACHE_KEY, JSON.stringify(nextRecords)) - } catch { - // A large message result must not break the search itself. - } -} - -const inlineMarkdown = (value: string, keyPrefix: string): React.ReactNode[] => - value.split(/(\*\*.*?\*\*|`.*?`|\*.*?\*)/g).map((part, index) => { - const key = `${keyPrefix}-${index}` - if (part.startsWith('**') && part.endsWith('**')) { - return {part.slice(2, -2)} - } - if (part.startsWith('`') && part.endsWith('`')) { - return {part.slice(1, -1)} - } - if (part.startsWith('*') && part.endsWith('*')) { - return {part.slice(1, -1)} - } - return {part} - }) - -const renderMarkdown = (value: string): React.ReactNode => - value.split(/\r?\n/).map((line, index) => { - const key = `markdown-${index}` - if (!line.trim()) return
- const heading = /^(#{1,3})\s+(.+)$/.exec(line) - if (heading) { - const Heading = `h${heading[1].length}` as 'h1' | 'h2' | 'h3' - return {inlineMarkdown(heading[2], key)} - } - const bullet = /^\s*[-*]\s+(.+)$/.exec(line) - if (bullet) { - return ( -
- - {inlineMarkdown(bullet[1], key)} -
- ) - } - const numbered = /^\s*\d+[.)]\s+(.+)$/.exec(line) - if (numbered) { - return ( -
- {line.trim().match(/^\d+/)?.[0]}. - {inlineMarkdown(numbered[1], key)} -
- ) - } - return

{inlineMarkdown(line, key)}

- }) +import type { + AISearchCacheRecord, + AISearchWorkspaceProps, + EvidenceItem, + GroupMemberName, + SearchPassSummary, + SearchRange, + SearchScope, + SearchStage, + SenderDirectory +} from './searchTypes' +import { + RANGE_LABELS, + SEARCH_CACHE_KEY, + SEARCH_HISTORY_KEY, + buildLocalSearchPlan, + buildSearchCacheKey, + compactCacheItem, + currentTimestamp, + evidenceIdentity, + formatMemberName, + formatMessageDate, + formatMessageTime, + getRangeStart, + includesSearchAlias, + messageDateKey, + messageIdentity, + messageText, + mergeSearchPlans, + normalizeSearchText, + parseSearchCacheKey, + parseSearchPlanResponse, + readSearchCache, + readSearchCacheByQuery, + selectEvenly, + selectEvidenceByDate, + senderName, + writeSearchCache +} from './searchUtils' +import { renderMarkdown } from './searchMarkdown' export function AISearchWorkspace({ contacts, diff --git a/src/renderer/src/components/search/searchMarkdown.tsx b/src/renderer/src/components/search/searchMarkdown.tsx new file mode 100644 index 0000000..b6e5a2b --- /dev/null +++ b/src/renderer/src/components/search/searchMarkdown.tsx @@ -0,0 +1,46 @@ +import React from 'react' + +const inlineMarkdown = (value: string, keyPrefix: string): React.ReactNode[] => + value.split(/(\*\*.*?\*\*|`.*?`|\*.*?\*)/g).map((part, index) => { + const key = `${keyPrefix}-${index}` + if (part.startsWith('**') && part.endsWith('**')) { + return {part.slice(2, -2)} + } + if (part.startsWith('`') && part.endsWith('`')) { + return {part.slice(1, -1)} + } + if (part.startsWith('*') && part.endsWith('*')) { + return {part.slice(1, -1)} + } + return {part} + }) + +export const renderMarkdown = (value: string): React.ReactNode => + value.split(/\r?\n/).map((line, index) => { + const key = `markdown-${index}` + if (!line.trim()) return
+ const heading = /^(#{1,3})\s+(.+)$/.exec(line) + if (heading) { + const Heading = `h${heading[1].length}` as 'h1' | 'h2' | 'h3' + return {inlineMarkdown(heading[2], key)} + } + const bullet = /^\s*[-*]\s+(.+)$/.exec(line) + if (bullet) { + return ( +
+ + {inlineMarkdown(bullet[1], key)} +
+ ) + } + const numbered = /^\s*\d+[.)]\s+(.+)$/.exec(line) + if (numbered) { + return ( +
+ {line.trim().match(/^\d+/)?.[0]}. + {inlineMarkdown(numbered[1], key)} +
+ ) + } + return

{inlineMarkdown(line, key)}

+ }) diff --git a/src/renderer/src/components/search/searchTypes.ts b/src/renderer/src/components/search/searchTypes.ts new file mode 100644 index 0000000..e796cf4 --- /dev/null +++ b/src/renderer/src/components/search/searchTypes.ts @@ -0,0 +1,59 @@ +import type { AIRuntimeModelConfig } from '../../../../shared/ai-provider' +import type { Contact, Message } from '../../../../shared/types' + +export type SearchStage = 'idle' | 'loading' | 'result' | 'insufficient' +export type SearchScope = 'global' | 'conversation' +export type SearchRange = 'today' | '7d' | '30d' | 'all' +export type SearchIntent = 'general' | 'topic' | 'participants' | 'mixed' + +export interface EvidenceItem { + contact: Contact + message: Message +} + +export interface AISearchCacheRecord { + version: 1 + key: string + createdAt: number + answer: string + evidence: EvidenceItem[] + senderNames: Record + messageCount: number +} + +export interface GroupMemberName { + wxid: string + nickname?: string + groupNickname?: string + remark?: string + wechatNickname?: string +} + +export interface SenderDirectory { + displayNames: Record + aliases: Record +} + +export interface SearchQueryPlan { + intent: SearchIntent + keywords: string[] + variants: string[] + source: 'local' | 'ai' | 'hybrid' +} + +export interface SearchPassSummary { + label: string + keywords: string[] + messageCount: number +} + +export interface AISearchWorkspaceProps { + contacts: Contact[] + selectedContact: Contact | null + dbReady: boolean + aiModelConfig: AIRuntimeModelConfig + onSelectContact: (contact: Contact) => void + onOpenEvidence: (contact: Contact, createTime?: number) => void + onOpenAISettings: () => void + onNotice: (message: string) => void +} diff --git a/src/renderer/src/components/search/searchUtils.ts b/src/renderer/src/components/search/searchUtils.ts new file mode 100644 index 0000000..0f7ea07 --- /dev/null +++ b/src/renderer/src/components/search/searchUtils.ts @@ -0,0 +1,372 @@ +import type { Contact, Message } from '../../../../shared/types' +import type { AISearchCacheRecord, EvidenceItem, GroupMemberName, SearchIntent, SearchQueryPlan, SearchRange, SearchScope } from './searchTypes' + +export const RANGE_LABELS: Record = { + today: '今天', + '7d': '近 7 天', + '30d': '近 30 天', + all: '全部历史' +} + +export const SEARCH_CACHE_KEY = 'wxe_ai_search_cache_v8' +export const SEARCH_HISTORY_KEY = 'wxe_ai_search_history_v1' +export const SEARCH_CACHE_LIMIT = 20 +export const currentTimestamp = (): number => Date.now() + +const SEARCH_INTENT_PHRASES = [ + '全局搜一下', + '全局搜索', + '搜索一下', + '搜一下', + '查询一下', + '查一下', + '找一下', + '我和谁聊过', + '谁和我聊过', + '哪些人和我聊过', + '最近讨论了什么', + '最近聊了什么', + '最近说了什么', + '讨论了什么', + '讨论什么', + '聊了什么', + '聊些什么', + '说了什么', + '说些什么', + '最近讨论', + '最近聊天', + '这个话题', + '相关话题', + '的聊天', + '的内容', + '的记录', + '关于', + '聊天', + '记录', + '聊天记录', + '帮我', + '请问' +].sort((left, right) => right.length - left.length) + +const SEARCH_STOP_WORDS = new Set([ + '我', + '谁', + '什么', + '哪些', + '哪个', + '人', + '和', + '聊过', + '说过', + '提到', + '讨论', + '聊天', + '记录', + '说', + '聊', + '话题', + '内容', + '相关', + '最近', + '一下' +]) + +export const messageText = (message: Message): string => + String(message.content || '').trim() || `[${message.type || '消息'}]` + +export const normalizeSearchText = (value: string): string => value.toLowerCase().replace(/\s+/g, '') + +export const includesSearchAlias = (query: string, alias: string): boolean => { + const normalizedAlias = normalizeSearchText(alias.trim()) + return Boolean(normalizedAlias) && normalizeSearchText(query).includes(normalizedAlias) +} + +const extractSearchKeywords = (query: string): string[] => { + const cleanedQuery = SEARCH_INTENT_PHRASES.reduce( + (value, phrase) => value.split(phrase).join(' '), + query.toLowerCase() + ) + const tokens = cleanedQuery + .split(/[\s,,。!?!?、::;;"“”‘’()()[\]【】]+/) + .map((token) => token.trim()) + .filter((token) => token.length >= 2 && !SEARCH_STOP_WORDS.has(token)) + return Array.from(new Set(tokens)) +} + +const getFuzzySearchKeywords = (keywords: string[]): string[] => + Array.from( + new Set( + keywords.flatMap((keyword) => { + const variants = [keyword] + if (/^[\u4e00-\u9fff]+$/.test(keyword) && keyword.length > 2) { + variants.push(keyword.slice(-2)) + } + return variants + }) + ) + ) + +const normalizeSearchTerms = (terms: unknown): string[] => { + if (!Array.isArray(terms)) return [] + return Array.from( + new Set( + terms + .filter((term): term is string => typeof term === 'string') + .map((term) => term.trim()) + .filter((term) => term.length >= 2 && term.length <= 32) + ) + ).slice(0, 16) +} + +export const buildLocalSearchPlan = (query: string): SearchQueryPlan => { + const keywords = extractSearchKeywords(query) + const asksParticipants = /我和谁|谁和我|哪些人|哪个人|哪些联系人/.test(query) + const intent: SearchIntent = asksParticipants + ? keywords.length + ? 'mixed' + : 'participants' + : keywords.length + ? 'topic' + : 'general' + return { + intent, + keywords, + variants: getFuzzySearchKeywords(keywords), + source: 'local' + } +} + +export const parseSearchPlanResponse = (value: string): Partial | null => { + const jsonMatch = value.match(/\{[\s\S]*\}/) + if (!jsonMatch) return null + try { + const parsed = JSON.parse(jsonMatch[0]) as Record + const intent = ['general', 'topic', 'participants', 'mixed'].includes(String(parsed.intent)) + ? (parsed.intent as SearchIntent) + : undefined + return { + intent, + keywords: normalizeSearchTerms(parsed.keywords), + variants: normalizeSearchTerms(parsed.variants) + } + } catch { + return null + } +} + +export const mergeSearchPlans = ( + localPlan: SearchQueryPlan, + aiPlan: Partial | null +): SearchQueryPlan => { + if (!aiPlan) return localPlan + const keywords = normalizeSearchTerms([...(localPlan.keywords || []), ...(aiPlan.keywords || [])]) + const variants = normalizeSearchTerms([ + ...getFuzzySearchKeywords(keywords), + ...(localPlan.variants || []), + ...(aiPlan.variants || []) + ]) + return { + intent: aiPlan.intent || localPlan.intent, + keywords, + variants, + source: 'hybrid' + } +} + +export const messageIdentity = (message: Message): string => + message.localId + ? `local:${message.localId}` + : message.id || `${message.createTime}:${message.content}` + +export const evidenceIdentity = ({ contact, message }: EvidenceItem): string => + `${contact.md5}:${messageIdentity(message)}` + +export const formatMessageTime = (message: Message): string => { + if (message.datetime) return message.datetime + if (message.createTime) return new Date(message.createTime * 1000).toLocaleString('zh-CN') + return '未知时间' +} + +export const getRangeStart = (range: SearchRange): number | undefined => { + if (range === 'all') return undefined + if (range === 'today') { + const now = new Date() + return Math.floor(new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime() / 1000) + } + const days = range === '7d' ? 7 : 30 + return Math.floor(Date.now() / 1000) - days * 86400 +} + +export const messageDateKey = (message: Message): string => { + if (!message.createTime) return 'unknown' + const date = new Date(message.createTime * 1000) + const year = date.getFullYear() + const month = String(date.getMonth() + 1).padStart(2, '0') + const day = String(date.getDate()).padStart(2, '0') + return `${year}-${month}-${day}` +} + +export const formatMessageDate = (dateKey: string): string => { + if (dateKey === 'unknown') return '--/--' + const [, month, day] = dateKey.split('-') + return `${month}/${day}` +} + +export const selectEvenly = (items: T[], count: number): T[] => { + if (count >= items.length) return items + if (count <= 0) return [] + if (count === 1) return [items[items.length - 1]] + return Array.from({ length: count }, (_item, index) => { + const itemIndex = Math.round((index * (items.length - 1)) / (count - 1)) + return items[itemIndex] + }) +} + +export const selectEvidenceByDate = (items: EvidenceItem[], maxItems: number): EvidenceItem[] => { + const buckets = new Map() + items.forEach((item) => { + const key = messageDateKey(item.message) + const bucket = buckets.get(key) || [] + bucket.push(item) + buckets.set(key, bucket) + }) + const entries = Array.from(buckets.entries()).sort(([left], [right]) => left.localeCompare(right)) + const targetCount = Math.min(maxItems, items.length) + const counts = entries.map(() => 0) + let remaining = targetCount + while (remaining > 0) { + let bestIndex = -1 + let bestRemaining = 0 + entries.forEach(([, bucket], index) => { + const available = bucket.length - counts[index] + if (available > bestRemaining) { + bestIndex = index + bestRemaining = available + } + }) + if (bestIndex < 0) break + counts[bestIndex] += 1 + remaining -= 1 + } + return entries + .flatMap((entry, index) => selectEvenly(entry[1], counts[index])) + .sort((left, right) => (left.message.createTime || 0) - (right.message.createTime || 0)) +} + +const looksLikeUserId = (value: string): boolean => + value.startsWith('wxid_') || value.includes('@chatroom') || /^\d{6,}$/.test(value) + +export const formatMemberName = (member: GroupMemberName): string => + member.groupNickname || member.wechatNickname || member.nickname || member.remark || member.wxid + +export const senderName = (message: Message, contact: Contact, names: Record): string => { + const identifiers = [message.senderId, message.from, message.name].filter( + (value): value is string => Boolean(value?.trim()) + ) + const mappedName = identifiers.map((value) => names[value]).find(Boolean) + if (mappedName) return mappedName + if (message.name && !looksLikeUserId(message.name)) return message.name + if (message.isSender) return '我' + return contact.type === 'user' ? contact.m_nsNickName || '联系人' : '群成员' +} + +export const compactCacheItem = ({ contact, message }: EvidenceItem): EvidenceItem => ({ + contact: { + md5: contact.md5, + m_nsUsrName: contact.m_nsUsrName, + m_nsNickName: contact.m_nsNickName, + type: contact.type, + avatar: contact.avatar + }, + message: { + id: message.id, + from: message.from, + type: message.type, + datetime: message.datetime, + content: message.content, + isSender: message.isSender, + name: message.name, + senderId: message.senderId, + localId: message.localId, + serverId: message.serverId, + createTime: message.createTime + } +}) + +export const buildSearchCacheKey = ( + scope: SearchScope, + contactMd5: string, + range: SearchRange, + query: string +): string => JSON.stringify([scope, contactMd5, range, query.trim().toLowerCase()]) + +export const parseSearchCacheKey = ( + key: string +): { scope: SearchScope; contactMd5: string; range: SearchRange; query: string } | null => { + try { + const parts = JSON.parse(key) as unknown + if ( + !Array.isArray(parts) || + !['global', 'conversation'].includes(String(parts[0])) || + !['today', '7d', '30d', 'all'].includes(String(parts[2])) || + typeof parts[3] !== 'string' + ) { + return null + } + return { + scope: parts[0] as SearchScope, + contactMd5: typeof parts[1] === 'string' ? parts[1] : '', + range: parts[2] as SearchRange, + query: parts[3] + } + } catch { + return null + } +} + +export const readSearchCache = (key: string): AISearchCacheRecord | null => { + try { + const records = JSON.parse( + localStorage.getItem(SEARCH_CACHE_KEY) || '[]' + ) as AISearchCacheRecord[] + const record = records.find((item) => item.version === 1 && item.key === key) + return record || null + } catch { + return null + } +} + +export const readSearchCacheByQuery = ( + query: string +): { record: AISearchCacheRecord; location: ReturnType } | null => { + try { + const records = JSON.parse( + localStorage.getItem(SEARCH_CACHE_KEY) || '[]' + ) as AISearchCacheRecord[] + const normalizedQuery = query.trim().toLowerCase() + for (const record of records) { + const location = parseSearchCacheKey(record.key) + if (record.version === 1 && location?.query === normalizedQuery) { + return { record, location } + } + } + return null + } catch { + return null + } +} + +export const writeSearchCache = (record: AISearchCacheRecord): void => { + try { + const records = JSON.parse( + localStorage.getItem(SEARCH_CACHE_KEY) || '[]' + ) as AISearchCacheRecord[] + const nextRecords = [record, ...records.filter((item) => item.key !== record.key)].slice( + 0, + SEARCH_CACHE_LIMIT + ) + localStorage.setItem(SEARCH_CACHE_KEY, JSON.stringify(nextRecords)) + } catch { + // A large message result must not break the search itself. + } +} diff --git a/src/renderer/src/main.tsx b/src/renderer/src/main.tsx index b54070d..0654178 100644 --- a/src/renderer/src/main.tsx +++ b/src/renderer/src/main.tsx @@ -1,11 +1,7 @@ import React from 'react' import ReactDOM from 'react-dom/client' import App from './App' -import './styles/tokens.css' -import './assets/main.css' -import './styles/search.css' -import './styles/archive.css' -import './styles/settings-advanced.css' +import './styles/index.scss' window.addEventListener('error', (event) => { void window.api diff --git a/src/renderer/src/assets/base.css b/src/renderer/src/styles/_base.scss similarity index 100% rename from src/renderer/src/assets/base.css rename to src/renderer/src/styles/_base.scss diff --git a/src/renderer/src/styles/tokens.css b/src/renderer/src/styles/_tokens.scss similarity index 100% rename from src/renderer/src/styles/tokens.css rename to src/renderer/src/styles/_tokens.scss diff --git a/src/renderer/src/styles/api.scss b/src/renderer/src/styles/api.scss new file mode 100644 index 0000000..7fe1c81 --- /dev/null +++ b/src/renderer/src/styles/api.scss @@ -0,0 +1,769 @@ +@media (max-width: 700px) { + .settings-account-overview { + grid-template-columns: minmax(0, 1fr); + } + .settings-account-actions { + grid-row: auto; + grid-column: 1; + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .settings-account-root { + grid-column: 1; + } + .database-key-status-card dl, + .database-key-diagnostics dl { + grid-template-columns: 1fr; + } + .database-key-auto-heading { + flex-direction: column; + } + .database-key-phases { + grid-template-columns: 1fr; + } + .database-key-phases li { + padding: 0 0 0 28px; + text-align: left; + } + .database-key-phases li::before { + top: -2px; + left: 0; + transform: none; + } + .image-decrypt-status dl, + .image-key-grid { + grid-template-columns: 1fr; + } + .image-decrypt-status .image-decrypt-wide { + grid-column: 1; + } + .image-auto-heading { + flex-direction: column; + } + .image-auto-phases { + grid-template-columns: 1fr; + } + .image-auto-phases li { + padding: 0 0 0 28px; + text-align: left; + } + .image-auto-phases li::before { + top: -2px; + left: 0; + transform: none; + } + .image-auto-success { + grid-template-columns: 1fr; + } + .image-auto-success button { + grid-column: 1; + grid-row: auto; + justify-self: start; + } + .image-resource-checks > div { + align-items: flex-start; + } + .image-resource-checks small { + white-space: normal; + text-align: right; + } + .ai-provider-card dl, + .ai-provider-form-grid, + .ai-provider-advanced > div { + grid-template-columns: 1fr; + } + .ai-provider-form-grid .wide, + .ai-provider-advanced .wide { + grid-column: 1; + } + .ai-model-row { + grid-template-columns: 1fr; + } +} +.api-center-layout > * { + min-width: 0; + min-height: 0; + box-sizing: border-box; +} +.api-section-heading h2, +.api-introduction h2, +.api-integrations h2, +.api-runtime-title h2 { + margin: 0; + color: var(--wxex-text-primary); + font: 700 17px/24px var(--wxex-font); +} +.ready-text { + color: var(--wxex-success); +} +.api-main { + position: relative; + display: flex; + min-width: 0; + min-height: 0; + overflow: hidden; + background: var(--wxex-bg-main); +} +.api-main-scroll { + flex: 1; + min-width: 0; + min-height: 0; + overflow-y: auto; + padding: 22px 28px 36px; +} +.api-workspace-heading { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 16px; + padding-bottom: 16px; + border-bottom: 1px solid var(--wxex-border); +} +.api-title-line { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; +} +.api-title-line h1 { + margin: 0; + color: var(--wxex-text-primary); + font: 700 22px/30px var(--wxex-font); +} +.api-workspace-heading p { + margin: 4px 0 0; + color: var(--wxex-text-secondary); + font: 13px/19px var(--wxex-font); +} +.api-skill-status, +.api-version { + padding: 2px 7px; + border-radius: 5px; + font: 700 11px/17px var(--wxex-font); +} +.api-skill-status.ready { + color: var(--wxex-brand); + background: var(--wxex-brand-soft); +} +.api-skill-status.error { + color: var(--wxex-danger); + background: #fff1f1; +} +.api-version { + color: var(--wxex-text-muted); + background: var(--wxex-bg-app); +} +.api-header-actions, +.api-tester-actions, +.api-runtime-actions, +.api-skill-file-actions { + display: flex; + flex-wrap: wrap; + gap: 8px; +} +.api-header-actions button, +.api-tester-actions button, +.api-runtime-actions button, +.api-endpoint-row button, +.api-response-summary + pre + p + button, +.api-skill-file-actions button { + min-height: 32px; + padding: 0 11px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-sm); + background: var(--wxex-bg-elevated); + color: var(--wxex-text-primary); + cursor: pointer; + font: 600 12px/18px var(--wxex-font); +} +.api-header-actions button:hover, +.api-tester-actions button:hover, +.api-runtime-actions button:hover, +.api-endpoint-row button:hover, +.api-skill-file-actions button:hover { + border-color: var(--wxex-brand); + color: var(--wxex-brand); +} +.api-primary-button { + border-color: var(--wxex-brand) !important; + background: var(--wxex-brand) !important; + color: #fff !important; +} +.api-primary-button:hover:not(:disabled), +.api-primary-button:focus-visible, +.api-primary-button:active { + background: var(--wxex-brand-hover) !important; + color: #fff !important; +} +.api-primary-button:disabled { + cursor: not-allowed; + opacity: 0.55; +} +.api-trust-bar { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 10px; + margin-top: 16px; + padding: 10px 12px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: #f5f8f6; + color: var(--wxex-text-secondary); + font: 12px/18px var(--wxex-font); +} +.api-trust-bar i { + width: 3px; + height: 3px; + border-radius: 50%; + background: var(--wxex-text-muted); +} +.api-introduction { + margin-top: 24px; + padding: 18px 20px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-lg); + background: var(--wxex-bg-elevated); +} +.api-introduction p { + margin: 10px 0 16px; + color: var(--wxex-text-secondary); + font: 13px/20px var(--wxex-font); +} +.api-flow { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + padding: 12px; + border: 1px dashed var(--wxex-border); + border-radius: var(--wxex-radius-md); + color: var(--wxex-text-secondary); + font: 12px/18px var(--wxex-font); +} +.api-flow span, +.api-flow strong { + padding: 7px 10px; + border: 1px solid var(--wxex-border); + border-radius: 5px; + background: #fff; + white-space: nowrap; +} +.api-flow strong { + color: var(--wxex-brand); + background: var(--wxex-brand-soft); +} +.api-flow b { + color: var(--wxex-text-muted); + font-size: 17px; +} +.api-endpoint-catalog, +.api-request-tester { + margin-top: 26px; +} +.skill-install-flow { + margin-top: 26px; + padding: 18px 20px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-lg); + background: var(--wxex-bg-elevated); +} +.skill-flow-steps { + display: grid; + gap: 16px; + margin-top: 16px; +} +.skill-flow-steps > section { + position: relative; + display: grid; + grid-template-columns: 26px minmax(0, 1fr); + gap: 10px; + color: var(--wxex-text-muted); +} +.skill-flow-steps > section:not(:last-child)::after { + position: absolute; + top: 28px; + left: 12px; + bottom: -16px; + width: 1px; + background: var(--wxex-border); + content: ''; +} +.skill-flow-steps > section > b { + position: relative; + z-index: 1; + display: grid; + width: 24px; + height: 24px; + place-items: center; + border: 1px solid var(--wxex-border); + border-radius: 50%; + background: var(--wxex-bg-elevated); + font: 700 12px/1 var(--wxex-font); +} +.skill-flow-steps > section.active > b, +.skill-flow-steps > section.done > b { + border-color: var(--wxex-brand); + background: var(--wxex-brand); + color: #fff; +} +.skill-flow-steps h3 { + margin: 1px 0 5px; + color: var(--wxex-text-primary); + font: 700 14px/20px var(--wxex-font); +} +.skill-flow-steps p { + margin: 3px 0; + color: var(--wxex-text-secondary); + font: 12px/18px var(--wxex-font); +} +.skill-flow-actions { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-top: 10px; +} +.skill-flow-actions button, +.api-skill-details button { + min-height: 30px; + padding: 0 10px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-sm); + background: #fff; + color: var(--wxex-text-primary); + cursor: pointer; + font: 600 12px/18px var(--wxex-font); +} +.skill-flow-actions button:disabled, +.api-skill-details button:disabled { + cursor: not-allowed; + opacity: 0.55; +} +.skill-target-selector { + display: flex; + flex-wrap: wrap; + gap: 6px; + margin-top: 8px; +} +.skill-target-selector button { + min-height: 30px; + padding: 0 10px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-sm); + background: #fff; + color: var(--wxex-text-secondary); + cursor: pointer; + font: 600 12px/18px var(--wxex-font); +} +.skill-target-selector button.active { + border-color: var(--wxex-brand); + background: var(--wxex-brand-soft); + color: var(--wxex-brand); +} +.api-skill-details { + margin-top: 16px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); +} +.api-skill-details summary { + padding: 12px 14px; + color: var(--wxex-text-primary); + cursor: pointer; + font: 700 13px/18px var(--wxex-font); +} +.api-skill-details > dl, +.api-skill-details > div { + margin: 0; + padding: 0 14px 14px; +} +.api-skill-details dl div { + display: grid; + grid-template-columns: 72px minmax(0, 1fr); + gap: 8px; + padding: 4px 0; + color: var(--wxex-text-secondary); + font: 12px/18px var(--wxex-font); +} +.api-skill-details dd { + margin: 0; + color: var(--wxex-text-primary); +} +.api-skill-more { + position: relative; +} +.api-skill-more summary { + display: grid; + min-height: 32px; + place-items: center; + padding: 0 11px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-sm); + background: var(--wxex-bg-elevated); + color: var(--wxex-text-primary); + cursor: pointer; + font: 600 12px/18px var(--wxex-font); + list-style: none; +} +.api-skill-more[open] > button { + position: absolute; + z-index: 2; + top: 36px; + right: 0; + width: 170px; + padding: 9px 10px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-sm); + background: #fff; + color: var(--wxex-text-primary); + box-shadow: var(--wxex-shadow-popover); + font: 12px/18px var(--wxex-font); + text-align: left; +} +.api-section-heading { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 12px; +} +.api-section-heading > span { + color: var(--wxex-text-muted); + font: 12px/18px var(--wxex-font); +} +.api-endpoint-table { + margin-top: 12px; + overflow: hidden; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); +} +.api-endpoint-head, +.api-endpoint-row { + display: grid; + grid-template-columns: 72px minmax(128px, 1.1fr) minmax(150px, 1.2fr) 90px; + align-items: center; + gap: 12px; + padding: 11px 14px; +} +.api-endpoint-head { + background: #f1f4f2; + color: var(--wxex-text-secondary); + font: 700 12px/18px var(--wxex-font); +} +.api-endpoint-row { + min-height: 54px; + border-top: 1px solid var(--wxex-border); + color: var(--wxex-text-secondary); + font: 12px/18px var(--wxex-font); +} +.api-endpoint-row.active { + background: #f7faf8; +} +.api-endpoint-row code { + color: var(--wxex-text-primary); + font: + 12px/18px ui-monospace, + monospace; +} +.api-endpoint-row small { + display: block; + color: var(--wxex-text-muted); +} +.api-endpoint-row > span:last-child { + display: flex; + gap: 4px; +} +.api-endpoint-row button { + min-height: 26px; + padding: 0 7px; + font-size: 11px; +} +.api-method { + display: inline-block; + color: var(--wxex-brand); + font: + 700 11px/18px ui-monospace, + monospace; +} +.api-method.post { + color: var(--wxex-ai); +} +.api-request-meta { + display: flex; + align-items: center; + gap: 10px; + margin: 12px 0; + padding: 10px 12px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: #f5f8f6; + overflow: hidden; +} +.api-request-meta code { + overflow: hidden; + color: var(--wxex-text-primary); + font: + 12px/18px ui-monospace, + monospace; + text-overflow: ellipsis; + white-space: nowrap; +} +.api-param-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px; +} +.api-param-grid label, +.api-json-input { + display: grid; + gap: 5px; + color: var(--wxex-text-secondary); + font: 12px/18px var(--wxex-font); +} +.api-param-grid label span b { + margin-left: 5px; + color: var(--wxex-danger); + font-size: 11px; +} +.api-param-grid input, +.api-json-input textarea { + box-sizing: border-box; + width: 100%; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-sm); + outline: none; + background: #fff; + color: var(--wxex-text-primary); + font: 12px/18px var(--wxex-font); +} +.api-param-grid input { + height: 34px; + padding: 0 9px; +} +.api-json-input { + margin-top: 10px; +} +.api-json-input textarea { + min-height: 180px; + padding: 10px; + resize: vertical; + font-family: ui-monospace, monospace; +} +.api-tester-actions { + justify-content: flex-end; + margin-top: 12px; +} +.api-inline-error { + margin: 10px 0 0; + padding: 8px 10px; + border: 1px solid rgba(200, 90, 90, 0.35); + border-radius: var(--wxex-radius-sm); + background: #fff4f4; + color: var(--wxex-danger); + font: 12px/18px var(--wxex-font); +} +.api-runtime-panel { + border-left: 1px solid var(--wxex-border); + background: var(--wxex-bg-main); + overflow: hidden; +} +.api-runtime-scroll { + height: 100%; + overflow-y: auto; +} +.api-runtime-scroll section { + padding: 18px 16px; + border-bottom: 1px solid var(--wxex-border); +} +.api-runtime-title { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; +} +.api-runtime-title > span { + font: 700 12px/18px var(--wxex-font); +} +.api-runtime-title .ready { + color: var(--wxex-success); +} +.api-runtime-title .stopped { + color: var(--wxex-text-muted); +} +.api-runtime-scroll h3 { + margin: 0 0 12px; + color: var(--wxex-text-primary); + font: 700 14px/20px var(--wxex-font); +} +.api-runtime-scroll dl { + margin: 14px 0; +} +.api-runtime-scroll dl div { + display: flex; + justify-content: space-between; + gap: 12px; + padding: 5px 0; + font: 12px/18px var(--wxex-font); +} +.api-runtime-scroll dt { + color: var(--wxex-text-secondary); +} +.api-runtime-scroll dd { + margin: 0; + color: var(--wxex-text-primary); + text-align: right; +} +.warning-text { + color: var(--wxex-warning); +} +.api-runtime-actions { + display: grid; + grid-template-columns: 1fr 1fr; +} +.api-runtime-actions button { + min-height: 30px; + padding: 0 6px; +} +.api-security-warning { + margin: 12px 16px; + padding: 9px 10px; + border-left: 3px solid var(--wxex-warning); + background: #fff8ec; + color: #915d1e; + font: 12px/18px var(--wxex-font); +} +.api-response-summary { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + color: var(--wxex-text-primary); + font: + 12px/18px ui-monospace, + monospace; +} +.api-runtime-scroll pre { + max-height: 180px; + overflow: auto; + margin: 10px 0 8px; + padding: 10px; + border-radius: var(--wxex-radius-sm); + background: #1f2824; + color: #cde7dc; + font: + 11px/16px ui-monospace, + monospace; + white-space: pre-wrap; + word-break: break-word; +} +.api-response-meta, +.api-empty-text { + margin: 0 0 9px; + color: var(--wxex-text-muted); + font: 11px/17px var(--wxex-font); +} +.api-history { + display: grid; + gap: 8px; + margin: 0; + padding: 0; + list-style: none; +} +.api-history li { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 2px 8px; + padding-bottom: 8px; + border-bottom: 1px solid var(--wxex-border); +} +.api-history span { + overflow: hidden; + color: var(--wxex-text-primary); + font: + 11px/17px ui-monospace, + monospace; + text-overflow: ellipsis; + white-space: nowrap; +} +.api-history b { + font: 700 11px/17px var(--wxex-font); +} +.api-history small { + grid-column: 1 / -1; + color: var(--wxex-text-muted); + font: 11px/16px var(--wxex-font); +} +.api-privacy { + background: #f5f8f6; +} +.api-privacy p { + margin: 0; + color: var(--wxex-text-secondary); + font: 12px/18px var(--wxex-font); +} +.api-markdown-overlay { + position: absolute; + inset: 0; + z-index: 4; + display: flex; + align-items: stretch; + justify-content: center; + padding: 20px; + background: rgba(32, 39, 36, 0.24); +} +.api-markdown-overlay > div { + display: flex; + width: min(820px, 100%); + flex-direction: column; + min-height: 0; + padding: 14px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-lg); + background: #fff; + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.16); +} +.api-markdown-overlay header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} +.api-markdown-overlay header > div { + display: flex; + align-items: center; + gap: 8px; +} +.api-markdown-overlay header span { + color: var(--wxex-text-muted); + font: 12px/18px var(--wxex-font); +} +.api-markdown-overlay button { + min-height: 30px; + padding: 0 10px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-sm); + background: #fff; + color: var(--wxex-text-primary); + cursor: pointer; +} +.api-markdown-overlay pre, +.skill-markdown-preview { + min-height: 0; + overflow: auto; + margin: 14px 0 0; + white-space: pre-wrap; + color: var(--wxex-text-primary); + font: 12px/19px var(--wxex-font); +} +.skill-markdown-preview h1 { + font-size: 20px; +} +.skill-markdown-preview h2 { + margin-top: 18px; + font-size: 16px; +} +.skill-markdown-preview p { + margin: 6px 0; +} +.skill-markdown-preview li { + margin-left: 18px; +} diff --git a/src/renderer/src/styles/archive.css b/src/renderer/src/styles/archive.scss similarity index 53% rename from src/renderer/src/styles/archive.css rename to src/renderer/src/styles/archive.scss index dbb84fb..91c0d6f 100644 --- a/src/renderer/src/styles/archive.css +++ b/src/renderer/src/styles/archive.scss @@ -1,10 +1,10 @@ .archive-jump-target-group { z-index: 2; -} -.archive-jump-message { - z-index: 1; - animation: archive-jump-flash 0.72s ease-in-out 2; + .archive-jump-message { + z-index: 1; + animation: archive-jump-flash 0.72s ease-in-out 2; + } } @keyframes archive-jump-flash { @@ -20,9 +20,11 @@ } @media (prefers-reduced-motion: reduce) { - .archive-jump-message { - outline: 3px solid rgba(38, 128, 103, 0.58); - outline-offset: 5px; - animation: none; + .archive-jump-target-group { + .archive-jump-message { + outline: 3px solid rgba(38, 128, 103, 0.58); + outline-offset: 5px; + animation: none; + } } } diff --git a/src/renderer/src/styles/chat.scss b/src/renderer/src/styles/chat.scss new file mode 100644 index 0000000..6914cb7 --- /dev/null +++ b/src/renderer/src/styles/chat.scss @@ -0,0 +1,1843 @@ +.chat-window { + flex: 1; + display: flex; + flex-direction: column; + background-color: var(--wxex-bg-main); + height: 100%; + min-height: 0; + min-width: 0; + color: var(--wxex-text-primary); + overflow: hidden; + + &.empty { + align-items: center; + justify-content: center; + } +} + +.chat-archive-header { + box-sizing: border-box; + min-height: 70px; + flex: 0 0 auto; + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + border-bottom: 1px solid var(--wxex-border); + background: var(--wxex-bg-main); + padding: 12px 18px; + -webkit-app-region: drag; +} + +.chat-title-block { + min-width: 0; + display: flex; + align-items: center; + gap: 12px; +} + +.chat-title-avatar { + width: 42px; + height: 42px; + display: grid; + place-items: center; + flex: 0 0 auto; + overflow: hidden; + border-radius: var(--wxex-radius-md); + background: var(--wxex-brand-soft); + color: var(--wxex-brand); + font-size: 15px; + font-weight: 700; + + img { + width: 100%; + height: 100%; + display: block; + object-fit: cover; + } +} + +.chat-title-text { + min-width: 0; + + h2 { + overflow: hidden; + margin: 0; + color: var(--wxex-text-primary); + font-size: 19px; + font-weight: 700; + line-height: 26px; + text-overflow: ellipsis; + white-space: nowrap; + } +} + +.chat-title-meta { + display: flex; + align-items: center; + gap: 8px; + color: var(--wxex-text-secondary); + font-size: 12px; + line-height: 18px; + + span + span::before { + content: ''; + display: inline-block; + width: 3px; + height: 3px; + margin-right: 8px; + border-radius: 999px; + background: var(--wxex-text-muted); + vertical-align: middle; + } +} + +.chat-header-actions { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 8px; + flex: 0 0 auto; + -webkit-app-region: no-drag; +} + +.chat-icon-button, +.chat-tool-button, +.chat-ai-button { + box-sizing: border-box; + height: 32px; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 6px; + border: 1px solid transparent; + border-radius: var(--wxex-radius-md); + background: transparent; + color: var(--wxex-text-secondary); + cursor: pointer; + font: 13px/18px var(--wxex-font); +} + +.chat-icon-button { + width: 32px; + padding: 0; +} + +.chat-tool-button { + padding: 0 9px; + border-color: var(--wxex-border); + background: var(--wxex-bg-elevated); +} + +.chat-icon-button:hover, +.chat-tool-button:hover { + background: var(--wxex-brand-soft); + color: var(--wxex-brand); +} + +.chat-tool-button:disabled, +.chat-ai-button:disabled { + cursor: not-allowed; + opacity: 0.55; +} + +.chat-ai-button { + padding: 0 12px; + border-color: var(--wxex-ai); + background: var(--wxex-ai); + color: #ffffff; + font-weight: 600; +} + +.chat-ai-button:hover:not(:disabled) { + background: #5a60c6; +} + +.chat-icon-button svg, +.chat-tool-button svg, +.chat-ai-button svg, +.chat-content-search svg, +.data-trust-bar svg { + width: 17px; + height: 17px; +} + +.chat-icon-button path, +.chat-tool-button path, +.chat-ai-button path, +.chat-content-search path, +.data-trust-bar path, +.chat-icon-button circle, +.chat-tool-button circle, +.chat-ai-button circle, +.chat-content-search circle, +.data-trust-bar circle { + fill: none; + stroke: currentColor; + stroke-width: 1.8; + stroke-linecap: round; + stroke-linejoin: round; +} + +.chat-menu { + position: relative; +} + +.chat-dropdown-menu { + position: absolute; + top: calc(100% + 6px); + left: 0; + z-index: 40; + min-width: 150px; + overflow: hidden; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); + box-shadow: var(--wxex-shadow-popover); + padding: 4px; + + &.right { + right: 0; + left: auto; + } + + button { + box-sizing: border-box; + width: 100%; + display: block; + border: 0; + border-radius: var(--wxex-radius-sm); + background: transparent; + color: var(--wxex-text-primary); + cursor: pointer; + font: 13px/18px var(--wxex-font); + padding: 7px 9px; + text-align: left; + white-space: nowrap; + + &:hover { + background: var(--wxex-brand-soft); + color: var(--wxex-brand); + } + } +} + +.chat-content-search { + box-sizing: border-box; + width: 280px; + height: 34px; + display: flex; + align-items: center; + gap: 7px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); + padding: 0 5px 0 10px; + color: var(--wxex-text-muted); + + input { + min-width: 0; + flex: 1; + border: 0; + outline: 0; + background: transparent; + color: var(--wxex-text-primary); + font: 13px/18px var(--wxex-font); + } + + svg { + width: 17px; + height: 17px; + } + + path, + circle { + fill: none; + stroke: currentColor; + stroke-width: 1.8; + stroke-linecap: round; + stroke-linejoin: round; + } +} + +.chat-content-search-count { + color: var(--wxex-text-muted); + font-size: 12px; + white-space: nowrap; +} + +.data-trust-bar { + box-sizing: border-box; + min-height: 34px; + flex: 0 0 auto; + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + border-bottom: 1px solid var(--wxex-border); + background: #f3f6f4; + color: var(--wxex-text-secondary); + padding: 0 18px; + font-size: 12px; + line-height: 18px; +} + +.data-trust-left, +.data-trust-right, +.data-trust-item { + display: flex; + align-items: center; + gap: 6px; +} + +.data-trust-right { + flex-wrap: wrap; + justify-content: flex-end; +} + +.data-trust-item { + color: var(--wxex-success); +} + +.data-trust-dot { + width: 3px; + height: 3px; + border-radius: 999px; + background: var(--wxex-text-muted); +} + +.message-list { + flex: 1; + overflow-y: auto; + padding: 0; + display: flex; + flex-direction: column; +} + +.wechat-message-list { + min-height: 0; + padding: 18px 28px 24px; + background: #f0f2ef; +} + +.virtual-message-list { + position: relative; + flex: 0 0 auto; + width: 100%; +} + +.virtual-message-group { + position: absolute; + top: 0; + left: 0; + display: flow-root; + width: 100%; +} + +.wechat-message-row { + margin-bottom: 14px; +} + +.message-loading-pill { + align-self: center; + margin: 0 0 12px; + padding: 5px 12px; + border-radius: var(--wxex-radius-md); + background: rgba(255, 255, 255, 0.78); + color: var(--wxex-text-secondary); + font-size: 12px; + line-height: 1.4; +} + +.wechat-message-row { + display: flex; + align-items: flex-start; + gap: 10px; + width: 100%; + + &.mine { + justify-content: flex-end; + + .message-stack { + align-items: flex-end; + } + + .message-bubble-wrap { + align-items: flex-end; + } + + .message-bubble { + border-color: rgba(36, 122, 99, 0.16); + background: #e7f2ee; + color: var(--wxex-text-primary); + } + + .message-hover-time { + right: calc(100% + 8px); + left: auto; + } + + .image-message-bubble { + background: transparent; + } + + .video-message-bubble { + background: #101412; + } + + .voice-icon { + background: rgba(36, 122, 99, 0.14); + } + + .quoted-message { + background: rgba(255, 255, 255, 0.18); + color: rgba(255, 255, 255, 0.82); + } + } + + &.other { + .quoted-message { + background: #f0f0f0; + color: #666; + } + } +} + +.wechat-system-message-row { + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; + margin: 2px 0 6px; +} + +.wechat-system-message { + max-width: min(78%, 760px); + padding: 6px 12px; + border-radius: var(--wxex-radius-md); + background: rgba(255, 255, 255, 0.72); + color: var(--wxex-text-muted); + font-size: 12px; + line-height: 1.5; + text-align: center; + word-break: break-word; +} + +.wechat-system-message-meta { + color: #a0a7ab; + font-size: 11px; +} + +.message-avatar { + width: 38px; + height: 38px; + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); + color: var(--wxex-brand); + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + flex: 0 0 38px; + font-size: 13px; +} + +.mine-avatar { + background: var(--wxex-brand-soft); +} + +.message-avatar-spacer { + width: 38px; + flex: 0 0 38px; +} + +.message-stack { + max-width: min(70%, 760px); + display: flex; + flex-direction: column; + align-items: flex-start; +} + +.message-sender-name { + color: var(--wxex-text-secondary); + font-size: 12px; + margin: 0 0 4px 2px; +} + +.message-bubble-wrap { + position: relative; + display: flex; + flex-direction: column; + align-items: flex-start; + margin-top: 4px; + + &.is-followup { + margin-top: 2px; + } + + &:hover { + .message-hover-time { + visibility: visible; + opacity: 1; + } + } +} + +.message-bubble { + position: relative; + padding: 9px 13px; + border: 1px solid rgba(221, 227, 224, 0.74); + border-radius: var(--wxex-radius-md); + background: #ffffff; + color: var(--wxex-text-primary); + font-size: 14px; + line-height: 1.55; + word-break: break-word; + + &::before { + display: none; + } +} + +.message-meta { + display: none; +} + +.message-hover-time, +.message-accessible-sender { + color: var(--wxex-text-muted); + font-size: 12px; +} + +.message-recalled-status { + align-self: flex-end; + margin-top: 3px; + color: #c63c32; + font-size: 11px; + font-weight: 600; + line-height: 16px; +} + +.message-hover-time { + position: absolute; + top: 50%; + left: calc(100% + 8px); + z-index: 1; + visibility: hidden; + opacity: 0; + pointer-events: none; + transform: translateY(-50%); + transition: opacity 0.12s ease; + white-space: nowrap; +} + +.message-accessible-sender { + position: absolute; + width: 1px; + height: 1px; + overflow: hidden; + clip: rect(0 0 0 0); +} + +.chat-time-separator { + align-self: center; + margin: 8px 0 12px; + color: var(--wxex-text-muted); + font-size: 12px; + line-height: 18px; +} + +.message-text { + min-width: 0; +} + +.inline-wechat-emoji { + display: inline-block; + margin: 0 1px; + vertical-align: -5px; + object-fit: contain; +} + +.voice-bubble { + min-width: 138px; +} + +.image-message-bubble { + padding: 0; + overflow: hidden; + background: transparent; + box-shadow: none; + white-space: normal; +} + +.wechat-message-row.mine .image-message-bubble { + background: transparent; +} + +.image-message-bubble::before { + display: none; +} + +.video-message-bubble { + padding: 0; + overflow: hidden; + background: #101412; + border-color: rgba(0, 0, 0, 0.12); +} + +.wechat-message-row.mine .video-message-bubble { + background: #101412; +} + +.video-message { + position: relative; + width: min(320px, 48vw); + min-height: 140px; + background: #101412; +} + +.video-content { + display: block; + width: 100%; + max-height: 360px; + object-fit: contain; + background: #101412; +} + +.video-duration { + position: absolute; + right: 8px; + top: 8px; + padding: 2px 6px; + border-radius: 8px; + color: #fff; + background: rgba(0, 0, 0, 0.55); + font-size: 11px; + pointer-events: none; +} + +.video-placeholder { + display: grid; + place-items: center; + width: min(260px, 44vw); + min-height: 120px; + padding: 16px; + color: rgba(255, 255, 255, 0.78); + text-align: center; +} + +.image-bubble { + position: relative; + max-width: min(260px, 46vw); + max-height: 220px; + min-width: 96px; + min-height: 72px; + border-radius: var(--wxex-radius-md); + overflow: hidden; + background: #fff; + cursor: zoom-in; + border: 1px solid var(--wxex-border); + + &:hover { + .image-actions { + opacity: 1; + } + } +} +.image-bubble .image-content { + display: block; + max-width: min(260px, 46vw); + max-height: 220px; + width: auto; + height: auto; + object-fit: contain; + background: #f7f7f7; +} + +.image-loading, +.image-placeholder, +.image-error { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 6px; + padding: 14px 18px; + color: var(--wxex-text-secondary); + font-size: 13px; +} + +.image-loading-skeleton { + width: 110px; + height: 72px; + border-radius: var(--wxex-radius-md); + background: linear-gradient(90deg, #edf1ef 0%, #f7f8f7 50%, #edf1ef 100%); + background-size: 200% 100%; + animation: image-skeleton-shimmer 1.2s linear infinite; +} + +.image-actions { + position: absolute; + right: 6px; + bottom: 6px; + opacity: 0; + transition: opacity 0.15s ease; +} + +.image-quality-badge { + position: absolute; + right: 6px; + bottom: 6px; + max-width: calc(100% - 12px); + padding: 3px 6px; + border-radius: 5px; + background: rgba(0, 0, 0, 0.5); + color: #fff; + font-size: 11px; + line-height: 1.3; + pointer-events: none; +} + +@keyframes image-skeleton-shimmer { + 0% { + background-position: 200% 0; + } + 100% { + background-position: -200% 0; + } +} + +.image-action-btn { + border: 0; + border-radius: 5px; + background: rgba(0, 0, 0, 0.48); + color: #fff; + cursor: pointer; + padding: 4px 6px; +} + +.voice-message { + display: flex; + align-items: center; + gap: 8px; + white-space: nowrap; +} + +.voice-icon { + width: 20px; + height: 20px; + border-radius: 50%; + display: inline-flex; + align-items: center; + justify-content: center; + background: rgba(36, 122, 99, 0.12); + color: var(--wxex-brand); + font-size: 10px; + line-height: 1; +} + +.wechat-message-row.mine .voice-icon { + background: rgba(36, 122, 99, 0.14); +} + +.voice-error { + color: var(--wxex-text-secondary); +} + +.voice-error-text { + color: var(--wxex-text-secondary); +} + +.voice-bars { + display: inline-flex; + align-items: center; + gap: 3px; + height: 16px; + + i { + width: 3px; + border-radius: 3px; + background: currentColor; + opacity: 0.75; + + &:nth-child(1) { + height: 7px; + } + + &:nth-child(2) { + height: 13px; + } + + &:nth-child(3) { + height: 9px; + } + } +} + +.sticker-message { + display: flex; + flex-direction: column; + gap: 6px; + align-items: flex-start; +} + +.sticker-image { + display: block; + max-width: 140px; + max-height: 140px; + border-radius: 6px; + object-fit: contain; +} + +.sticker-placeholder { + color: #666; + font-size: 14px; +} + +.sticker-md5 { + max-width: 180px; + color: #999; + font-size: 11px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.quote-message { + min-width: 160px; + max-width: 320px; +} + +.quoted-message { + display: flex; + gap: 4px; + max-width: 100%; + margin-bottom: 8px; + padding: 6px 8px; + border-radius: 4px; + background: rgba(255, 255, 255, 0.18); + color: rgba(255, 255, 255, 0.82); + font-size: 12px; + line-height: 1.4; +} + +.wechat-message-row.other .quoted-message { + background: #f0f0f0; + color: #666; +} + +.quoted-sender { + flex: 0 1 auto; + min-width: 0; + font-weight: 600; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + &::after { + content: ':'; + } +} + +.quoted-text { + flex: 0 0 auto; +} + +.quote-reply { + font-size: 14px; + line-height: 1.5; + white-space: pre-wrap; + word-break: break-word; +} + +.chat-table { + width: 100%; + border-collapse: collapse; + font-size: 13px; + + th { + text-align: left; + padding: 8px; + border-bottom: 1px solid var(--border-color); + background-color: #f9f9f9; + color: #666; + font-weight: normal; + position: sticky; + top: 0; + z-index: 1; + position: relative; + } + + td { + padding: 8px; + border-bottom: 1px solid #eee; + vertical-align: top; + color: #333; + } + + tr:hover { + background-color: #f0f0f0; + } +} + +.column-resizer { + position: absolute; + right: 0; + top: 0; + bottom: 0; + width: 5px; + cursor: col-resize; + z-index: 2; +} + +.column-resizer:hover { + background-color: #ccc; +} + +.col-sender { + width: 80px; +} + +.col-type { + width: 80px; +} + +.col-time { + width: 150px; +} + +.col-content { +} + +.chat-toolbar { + padding: 10px; + border-top: 1px solid var(--border-color); + display: flex; + gap: 10px; + background-color: #fff; + flex-wrap: wrap; + + .toolbar-btn { + padding: 4px 12px; + border: 1px solid #dcdcdc; + border-radius: 4px; + background-color: #fff; + font-size: 12px; + cursor: pointer; + display: flex; + align-items: center; + gap: 4px; + + &:hover { + background-color: #f5f5f5; + } + } +} + +.empty-state { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + color: #999; +} + +.chat-status-bar { + box-sizing: border-box; + min-height: 38px; + flex: 0 0 auto; + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + border-top: 1px solid var(--wxex-border); + background: var(--wxex-bg-main); + color: var(--wxex-text-secondary); + padding: 0 18px; + font-size: 12px; + line-height: 18px; +} + +.chat-status-actions { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 10px; + + button { + border: 0; + background: transparent; + color: var(--wxex-brand); + cursor: pointer; + font: 12px/18px var(--wxex-font); + padding: 0; + + &:hover { + color: var(--wxex-brand-hover); + } + + &:disabled { + color: var(--wxex-text-muted); + cursor: default; + } + } +} + +.chat-avatar-toggle { + display: inline-flex; + align-items: center; + gap: 6px; + cursor: pointer; + white-space: nowrap; +} + +.chat-avatar-toggle input { + margin: 0; + accent-color: var(--wxex-brand); +} + +.chat-avatar-note { + max-width: 320px; + color: var(--wxex-text-muted); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.chat-avatar-reload { + display: inline-flex; + align-items: center; + gap: 4px; + white-space: nowrap; +} + +.chat-avatar-reload svg { + width: 14px; + height: 14px; + fill: none; + stroke: currentColor; + stroke-linecap: round; + stroke-linejoin: round; + stroke-width: 1.8; +} + +.chat-avatar-reload svg.is-spinning { + animation: chat-avatar-spin 0.8s linear infinite; +} + +@keyframes chat-avatar-spin { + to { + transform: rotate(360deg); + } +} + +.chat-status-separator { + width: 1px; + height: 14px; + background: var(--wxex-border); +} + +@media (max-width: 1120px) { + .chat-avatar-note { + display: none; + } +} + +.empty-conversation-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 6px; + color: var(--wxex-text-secondary); + text-align: center; + + h2 { + margin: 0; + color: var(--wxex-text-primary); + font-size: 20px; + line-height: 28px; + } + + p { + margin: 0; + color: var(--wxex-text-muted); + font-size: 13px; + line-height: 20px; + } +} + +.database-login-page { + --login-primary: #247a63; + --login-primary-dark: #00604c; + --login-border: #d7dfda; + --login-surface: #f7faf6; + --login-surface-low: #f1f4f1; + --login-text: #181c1b; + --login-muted: #5f6965; + width: 100vw; + min-width: 760px; + height: 100vh; + min-height: 560px; + display: grid; + grid-template-columns: minmax(300px, 40%) 1fr; + overflow: hidden; + color: var(--login-text); + background: #fff; +} + +.database-login-brand { + position: relative; + display: flex; + flex-direction: column; + padding: clamp(36px, 6vh, 72px) clamp(36px, 5vw, 72px) 28px; + background: var(--login-surface-low); + border-right: 1px solid var(--login-border); +} + +.database-login-brand-content { + width: min(360px, 100%); + margin: auto 0; +} + +.database-login-logo { + width: 56px; + height: 56px; + display: grid; + place-items: center; + margin-bottom: 24px; + border-radius: 10px; + color: #fff; + background: var(--login-primary-dark); + box-shadow: 0 4px 12px rgba(0, 96, 76, 0.12); +} + +.database-login-logo svg { + width: 29px; + height: 29px; +} + +.database-login-brand h1 { + margin: 0; + font-size: 25px; + line-height: 32px; + font-weight: 650; + letter-spacing: -0.02em; + color: var(--login-primary-dark); +} + +.database-login-tagline { + margin: 4px 0 26px; + color: var(--login-primary); + font-size: 14px; + line-height: 22px; + font-weight: 600; +} + +.database-login-description { + max-width: 320px; + margin: 0 0 30px; + color: var(--login-muted); + font-size: 13px; + line-height: 21px; +} + +.database-login-promises { + display: grid; + gap: 10px; +} + +.database-login-promises > div { + min-height: 44px; + display: flex; + align-items: center; + gap: 12px; + padding: 0 14px; + border: 1px solid rgba(190, 201, 195, 0.62); + border-radius: 7px; + color: #35423d; + background: rgba(255, 255, 255, 0.42); + font-size: 13px; + font-weight: 550; +} + +.database-login-promises svg { + width: 18px; + height: 18px; + color: var(--login-primary); +} + +.database-login-brand-footer { + margin-top: auto; + padding-top: 24px; + color: #78827e; + font-family: 'Work Sans', Inter, sans-serif; + font-size: 10px; + font-weight: 650; + letter-spacing: 0.11em; +} + +.database-login-workspace { + display: grid; + place-items: center; + min-width: 0; + padding: 48px clamp(40px, 7vw, 96px); + background: #fff; +} + +.database-login-panel { + width: min(520px, 100%); +} + +.database-login-tabs { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 4px; + padding: 4px; + margin-bottom: 28px; + border: 1px solid var(--login-border); + border-radius: 8px; + background: #e9eeeb; +} + +.database-login-tabs button { + min-height: 38px; + border: 0; + border-radius: 5px; + color: #66716c; + background: transparent; + cursor: pointer; + font-size: 13px; + font-weight: 550; +} + +.database-login-tabs button.active { + color: var(--login-primary-dark); + background: #fff; + box-shadow: 0 1px 3px rgba(24, 28, 27, 0.08); +} + +.database-login-state-card { + padding: 18px; + border: 1px solid var(--login-border); + border-radius: 9px; + background: var(--login-surface); +} + +.database-login-state-card.error { + border-color: #efc4be; + border-left: 3px solid #ba1a1a; + background: #fff9f8; +} + +.database-login-state-heading { + display: flex; + gap: 12px; + margin-bottom: 18px; +} + +.database-login-state-icon { + flex: 0 0 auto; + width: 30px; + height: 30px; + display: grid; + place-items: center; + border-radius: 50%; + color: var(--login-primary); + background: #e2f0eb; +} + +.database-login-state-card.error .database-login-state-icon { + color: #ba1a1a; + background: #ffebe8; +} + +.database-login-state-icon svg { + width: 17px; + height: 17px; +} + +.database-login-state-heading strong { + display: block; + margin: 1px 0 4px; + font-size: 14px; + line-height: 20px; +} + +.database-login-state-heading p { + margin: 0; + color: var(--login-muted); + font-size: 12px; + line-height: 18px; + white-space: pre-wrap; + word-break: break-word; +} + +.database-login-diagnostics { + margin: 0; + border-top: 1px solid #e2e7e4; +} + +.database-login-diagnostics > div { + min-height: 43px; + display: grid; + grid-template-columns: 112px 1fr; + align-items: center; + border-bottom: 1px solid #e2e7e4; +} + +.database-login-diagnostics > div:last-child { + border-bottom: 0; +} + +.database-login-diagnostics dt { + display: flex; + align-items: center; + gap: 6px; + color: #6e7874; + font-family: 'Work Sans', Inter, sans-serif; + font-size: 10px; + font-weight: 650; + letter-spacing: 0.04em; +} + +.database-login-diagnostics dd { + min-width: 0; + margin: 0; + color: #35423d; + font-size: 12px; + text-align: right; +} + +.database-login-path-input-wrap { + position: relative; + display: block; + width: 100%; +} + +.database-login-diagnostics input { + width: 100%; + height: 36px; + padding: 7px 0; + border: 0; + outline: 0; + color: #4c5752; + background: transparent; + font: inherit; + text-align: right; + text-overflow: ellipsis; +} + +.database-login-path-value { + position: absolute; + right: 0; + bottom: calc(100% + 7px); + z-index: 25; + width: min(520px, calc(100vw - 48px)); + padding: 9px 11px; + border: 1px solid #d7dfda; + border-radius: 7px; + color: #35423d; + background: #fff; + box-shadow: 0 6px 18px rgba(24, 28, 27, 0.13); + font-size: 11px; + line-height: 17px; + text-align: left; + overflow-wrap: anywhere; + opacity: 0; + pointer-events: none; + transform: translateY(4px); + transition: + opacity 120ms ease, + transform 120ms ease; +} + +.database-login-path-input-wrap:hover .database-login-path-value, +.database-login-path-input-wrap:focus-within .database-login-path-value { + opacity: 1; + transform: translateY(0); +} + +.database-login-primary, +.database-login-secondary { + width: 100%; + min-height: 44px; + margin-top: 22px; + border-radius: 7px; + cursor: pointer; + font-size: 13px; + font-weight: 600; +} + +.database-login-primary { + border: 1px solid var(--login-primary); + color: #fff; + background: var(--login-primary); + box-shadow: 0 2px 5px rgba(0, 96, 76, 0.16); +} + +.database-login-primary:hover:not(:disabled) { + border-color: var(--login-primary-dark); + background: var(--login-primary-dark); +} + +.database-login-primary:disabled { + cursor: not-allowed; + opacity: 0.52; + box-shadow: none; +} + +.database-login-auto > a { + display: block; + margin-top: 16px; + color: var(--login-primary); + font-size: 12px; + text-align: center; + text-decoration: none; +} + +.database-login-manual { + padding-top: 2px; +} + +.database-login-field { + margin-bottom: 20px; +} + +.database-login-field > label { + display: flex; + align-items: center; + gap: 7px; + margin-bottom: 8px; + color: #35423d; + font-size: 12px; + font-weight: 600; +} + +.database-login-path-help { + position: relative; + display: inline-flex; + align-items: center; +} + +.database-login-path-help-icon { + width: 15px; + height: 15px; + display: inline-grid; + place-items: center; + border: 1px solid #9a6b18; + border-radius: 50%; + color: #8a5d0b; + background: #fff8e6; + cursor: help; + font-family: Inter, sans-serif; + font-size: 10px; + font-weight: 700; + line-height: 1; +} + +.database-login-path-tooltip { + position: absolute; + left: 50%; + bottom: calc(100% + 9px); + z-index: 20; + width: 260px; + padding: 9px 11px; + border: 1px solid #d7dfda; + border-radius: 7px; + color: #35423d; + background: #fff; + box-shadow: 0 6px 18px rgba(24, 28, 27, 0.12); + font-family: Inter, sans-serif; + font-size: 11px; + font-weight: 400; + line-height: 17px; + letter-spacing: 0; + opacity: 0; + pointer-events: none; + transform: translate(-50%, 4px); + transition: + opacity 120ms ease, + transform 120ms ease; +} + +.database-login-path-help:hover .database-login-path-tooltip, +.database-login-path-help:focus-within .database-login-path-tooltip { + opacity: 1; + transform: translate(-50%, 0); +} + +.database-login-field > input, +.database-login-key-input { + width: 100%; + min-height: 42px; + border: 1px solid var(--login-border); + border-radius: 7px; + background: #fff; +} + +.database-login-field > input { + padding: 0 12px; + color: var(--login-text); + font-size: 13px; + outline: none; +} + +.database-login-key-input { + display: flex; + align-items: center; +} + +.database-login-key-input:focus-within, +.database-login-field > input:focus { + border-color: var(--login-primary); + box-shadow: 0 0 0 3px rgba(36, 122, 99, 0.1); +} + +.database-login-key-input input { + flex: 1; + min-width: 0; + height: 40px; + padding: 0 4px 0 12px; + border: 0; + outline: 0; + color: var(--login-text); + background: transparent; + font-size: 13px; +} + +.database-login-key-input button { + width: 38px; + height: 38px; + display: grid; + place-items: center; + border: 0; + color: #65706b; + background: transparent; + cursor: pointer; +} + +.database-login-key-input svg { + width: 18px; + height: 18px; + fill: none; + stroke: currentColor; + stroke-width: 1.7; + stroke-linecap: round; + stroke-linejoin: round; +} + +.database-login-field small { + display: block; + margin-top: 7px; + color: #77817d; + font-size: 11px; +} + +.database-login-message { + padding: 10px 12px; + border-radius: 7px; + color: #57625d; + background: var(--login-surface-low); + font-size: 12px; + line-height: 18px; + white-space: pre-wrap; +} + +.database-login-message.success { + color: var(--login-primary-dark); + background: #edf7f3; +} + +.database-login-message.error { + color: #93000a; + background: #fff0ee; +} + +.database-login-secondary { + margin-top: 10px; + border: 1px solid var(--login-border); + color: #3f4945; + background: #fff; +} + +.database-login-secondary:hover { + border-color: var(--login-primary); + color: var(--login-primary-dark); + background: var(--login-surface); +} + +.database-login-footer-actions { + display: flex; + align-items: center; + justify-content: space-between; + margin-top: 42px; + padding-top: 16px; + border-top: 1px solid #e5e9e6; + color: #8a938f; + font-size: 11px; +} + +.database-login-footer-actions button { + padding: 0; + border: 0; + color: #78827e; + background: transparent; + cursor: pointer; + font-size: 11px; +} + +.database-login-footer-actions button:hover { + color: #93000a; +} + +@media (max-width: 900px), (max-height: 620px) { + .database-login-brand { + padding: 30px; + } + + .database-login-description { + margin-bottom: 20px; + } + + .database-login-workspace { + padding: 30px; + } +} + +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.modal-content { + background: white; + padding: 20px; + border-radius: 8px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + min-width: 400px; + max-width: 90vw; + max-height: 90vh; + overflow: auto; +} + +.ai-settings-modal { + width: min(460px, 90vw); +} + +.ai-settings-modal h3 { + margin: 0 0 18px; +} + +.ai-filter-section { + margin-bottom: 16px; +} + +.ai-filter-label { + margin-bottom: 7px; + color: #333; + font-size: 14px; + font-weight: 600; +} + +.ai-date-options { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 6px; +} + +.ai-date-options label { + display: flex; + min-width: 0; + align-items: center; + justify-content: center; + gap: 5px; + padding: 8px 6px; + border: 1px solid #d8dcdf; + border-radius: 6px; + background: #fff; + color: #4a5257; + cursor: pointer; + font-size: 13px; +} + +.ai-date-options label.selected { + border-color: #07c160; + background: #eefaf3; + color: #078f49; +} + +.ai-date-options input, +.ai-type-options input { + margin: 0; + accent-color: #07c160; +} + +.ai-type-options { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 8px 10px; + padding: 11px; + border: 1px solid #e1e4e6; + border-radius: 6px; + background: #f8f9fa; +} + +.ai-type-options label { + display: flex; + min-width: 0; + align-items: center; + gap: 6px; + color: #3f474c; + cursor: pointer; + font-size: 13px; + white-space: nowrap; +} + +.image-preview-modal { + width: min(520px, 92vw); + max-height: 88vh; + background: #f7f8fa; + box-shadow: 0 18px 48px rgba(0, 0, 0, 0.18); + padding: 16px; + overflow: hidden; +} + +.report-preview-frame { + border: 1px solid #d8dde3; + border-radius: 10px; + background: #eef1f4; + padding: 12px; +} + +.report-preview-scroller { + max-height: calc(88vh - 120px); + overflow-y: auto; + overflow-x: hidden; + padding-right: 4px; +} + +.report-preview-image { + display: block; + width: min(430px, 100%); + height: auto; + margin: 0 auto; + border-radius: 8px; + border: 1px solid #ccd3d9; + background: #fff; +} + +.report-preview-actions { + margin-top: 12px; + display: flex; + gap: 10px; + flex-wrap: wrap; +} + +.image-viewer-overlay { + position: fixed; + inset: 0; + z-index: 1200; + display: flex; + align-items: center; + justify-content: center; + background: rgba(16, 24, 28, 0.28); + backdrop-filter: blur(1px); + overscroll-behavior: contain; +} + +.image-viewer-window { + width: min(1280px, 96vw); + height: min(900px, 92vh); + display: flex; + flex-direction: column; + overflow: hidden; + border: 1px solid rgba(0, 0, 0, 0.14); + border-radius: 8px; + background: #eaf0f1; + box-shadow: 0 18px 48px rgba(0, 0, 0, 0.22); +} + +.image-viewer-titlebar { + height: 40px; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 12px 0 16px; + border-bottom: 1px solid rgba(0, 0, 0, 0.08); + background: rgba(255, 255, 255, 0.78); + color: #333; + font-size: 14px; + + button { + width: 28px; + height: 28px; + border: 0; + border-radius: 50%; + background: transparent; + color: #555; + cursor: pointer; + font-size: 18px; + line-height: 1; + + &:hover { + background: rgba(0, 0, 0, 0.08); + } + } +} + +.image-viewer-tools { + display: flex; + align-items: center; + gap: 12px; +} + +.image-viewer-title { + margin-right: 8px; + font-weight: 500; +} + +.image-viewer-zoom { + min-width: 44px; + color: #666; + text-align: center; +} + +.image-viewer-divider { + width: 1px; + height: 18px; + background: rgba(0, 0, 0, 0.12); +} + +.image-viewer-stage { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + padding: 28px; + overflow: hidden; + overscroll-behavior: contain; + cursor: grab; + user-select: none; + + img { + max-width: none; + max-height: none; + width: auto; + height: auto; + object-fit: contain; + box-shadow: 0 3px 16px rgba(0, 0, 0, 0.12); + transform-origin: center center; + transition: transform 0.08s ease-out; + user-select: none; + pointer-events: none; + } +} diff --git a/src/renderer/src/styles/conversation.scss b/src/renderer/src/styles/conversation.scss new file mode 100644 index 0000000..a5be2fb --- /dev/null +++ b/src/renderer/src/styles/conversation.scss @@ -0,0 +1,523 @@ +.conversation-sidebar { + box-sizing: border-box; + display: flex; + height: 100%; + min-height: 0; + flex: 0 0 auto; + flex-direction: column; + overflow: hidden; + border-right: 1px solid var(--wxex-border); + background: var(--wxex-bg-sidebar); + color: var(--wxex-text-primary); +} + +.conversation-sidebar-header { + box-sizing: border-box; + flex: 0 0 auto; + padding: 16px 14px 12px; + border-bottom: 1px solid var(--wxex-border); + -webkit-app-region: drag; +} + +.conversation-sidebar-title-row { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 12px; + margin-bottom: 12px; + + h2 { + margin: 0; + color: var(--wxex-text-primary); + font-size: 18px; + font-weight: 700; + line-height: 24px; + } + + span { + color: var(--wxex-text-muted); + font-size: 12px; + line-height: 18px; + white-space: nowrap; + } +} + +.conversation-search { + box-sizing: border-box; + display: flex; + height: 34px; + align-items: center; + gap: 8px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); + padding: 0 10px; + color: var(--wxex-text-muted); + -webkit-app-region: no-drag; + + &:focus-within { + border-color: rgba(36, 122, 99, 0.58); + color: var(--wxex-brand); + } + + input { + width: 100%; + min-width: 0; + border: 0; + outline: 0; + background: transparent; + color: var(--wxex-text-primary); + font: 13px/18px var(--wxex-font); + + &::placeholder { + color: var(--wxex-text-muted); + } + } +} + +.conversation-search-icon { + width: 17px; + height: 17px; + display: grid; + place-items: center; + flex: 0 0 auto; +} + +.conversation-search-icon svg { + width: 17px; + height: 17px; +} + +.conversation-search-icon circle, +.conversation-search-icon path { + fill: none; + stroke: currentColor; + stroke-width: 1.8; + stroke-linecap: round; + stroke-linejoin: round; +} + +.conversation-date-range { + display: grid; + grid-template-columns: repeat(5, minmax(0, 1fr)); + gap: 6px; + margin-top: 10px; + -webkit-app-region: no-drag; +} + +.conversation-date-range-button { + box-sizing: border-box; + height: 30px; + min-width: 0; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); + color: var(--wxex-text-secondary); + cursor: pointer; + font: 12px/16px var(--wxex-font); + white-space: nowrap; + + &:hover { + border-color: rgba(36, 122, 99, 0.28); + color: var(--wxex-text-primary); + } + + &.active { + border-color: var(--wxex-brand); + background: var(--wxex-brand); + color: #ffffff; + font-weight: 600; + } +} + +.conversation-list { + flex: 1; + min-height: 0; + overflow: auto; + padding: 8px 8px 12px; +} + +.conversation-virtual-content { + position: relative; + width: 100%; +} + +.conversation-virtual-row { + position: absolute; + top: 0; + right: 0; + left: 0; +} + +.conversation-section + .conversation-section { + margin-top: 6px; +} + +.conversation-section-header { + box-sizing: border-box; + width: 100%; + height: 32px; + display: flex; + align-items: center; + gap: 4px; + border: 0; + border-radius: var(--wxex-radius-sm); + background: transparent; + color: var(--wxex-text-secondary); + cursor: pointer; + font: 600 12px/16px var(--wxex-font); + padding: 0 8px; + text-align: left; + + &:hover { + background: rgba(255, 255, 255, 0.48); + color: var(--wxex-text-primary); + } +} + +.conversation-section-chevron { + width: 16px; + height: 16px; + display: grid; + place-items: center; + flex: 0 0 auto; + + svg { + width: 14px; + height: 14px; + } + + path { + fill: none; + stroke: currentColor; + stroke-width: 1.8; + stroke-linecap: round; + stroke-linejoin: round; + } +} + +.conversation-section-title { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.conversation-section-list { + position: relative; + overflow: visible; +} + +.export-config-scroll > .export-section:not(.export-format-top):has(.export-format-grid) { + display: none; +} + +.conversation-section-virtual-content { + position: relative; + width: 100%; +} + +.conversation-section-virtual-row { + position: absolute; + top: 0; + right: 0; + left: 0; + height: 58px; +} + +.conversation-section-empty { + padding: 10px 12px 12px 28px; + color: var(--wxex-text-muted); + font-size: 12px; + line-height: 18px; +} + +.conversation-item { + box-sizing: border-box; + position: relative; + width: 100%; + min-height: 58px; + display: flex; + align-items: center; + gap: 10px; + border: 0; + border-radius: var(--wxex-radius-md); + background: transparent; + color: var(--wxex-text-primary); + cursor: pointer; + font-family: var(--wxex-font); + padding: 8px 10px 8px 13px; + text-align: left; + + &:hover { + background: rgba(255, 255, 255, 0.56); + } + + &.active { + background: var(--wxex-brand-soft); + + .conversation-item-active-mark { + background: var(--wxex-brand); + } + } +} + +.conversation-item-active-mark { + position: absolute; + top: 10px; + bottom: 10px; + left: 0; + width: 3px; + border-radius: 0 999px 999px 0; + background: transparent; +} + +.conversation-item-avatar { + box-sizing: border-box; + width: 40px; + height: 40px; + display: grid; + place-items: center; + flex: 0 0 auto; + overflow: hidden; + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); + color: var(--wxex-brand); + font-size: 14px; + font-weight: 700; + + img { + width: 100%; + height: 100%; + display: block; + object-fit: cover; + } +} + +.conversation-item-body { + min-width: 0; + display: flex; + flex: 1; + flex-direction: column; + justify-content: center; +} + +.conversation-item-name { + overflow: hidden; + color: var(--wxex-text-primary); + font-size: 13px; + font-weight: 600; + line-height: 18px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.conversation-item-meta { + overflow: hidden; + color: var(--wxex-text-muted); + font-size: 12px; + line-height: 16px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.conversation-sidebar-account { + box-sizing: border-box; + flex: 0 0 auto; + border-top: 1px solid var(--wxex-border); + padding: 10px; +} + +.conversation-sidebar-account .account-summary { + min-height: 58px; + padding: 8px; +} + +.conversation-sidebar-account .account-summary-text { + flex: 1; +} + +.sidebar { + background-color: var(--sidebar-bg); + border-right: 1px solid var(--border-color); + display: flex; + flex-direction: column; + height: 100%; + min-height: 0; + flex-shrink: 0; + /* Prevent shrinking */ +} + +.sidebar-header { + flex: 0 0 auto; + padding: 10px; + border-bottom: 1px solid var(--border-color); + -webkit-app-region: drag; +} + +.sidebar-footer { + padding: 10px; + border-top: 1px solid var(--border-color); + display: flex; + justify-content: space-between; + align-items: center; + font-size: 14px; +} + +.sidebar-btn { + cursor: pointer; + display: flex; + align-items: center; + gap: 5px; + color: #666; + + &:hover { + color: #333; + } +} + +.sidebar-status { + color: #07c160; + font-size: 12px; +} + +.search-input { + width: 100%; + padding: 5px; + border-radius: 4px; + border: 1px solid #ccc; + -webkit-app-region: no-drag; +} + +.date-range-selector { + display: flex; + gap: 5px; + margin-top: 8px; + justify-content: space-between; +} + +.range-btn { + padding: 2px 6px; + font-size: 10px; + border: 1px solid #ccc; + border-radius: 10px; + background: #fff; + cursor: pointer; + color: #666; + flex: 1; + text-align: center; + + &.active { + background: #07c160; + color: #fff; + border-color: #07c160; + } +} + +.contact-list { + flex: 1; + overflow-y: auto; +} + +.section-header { + padding: 8px 10px; + background-color: #f0f0f0; + font-size: 12px; + color: #666; + font-weight: bold; + cursor: pointer; + display: flex; + align-items: center; + user-select: none; + + &:hover { + background-color: #e0e0e0; + } + + .arrow { + margin-right: 5px; + font-size: 10px; + width: 12px; + } +} + +.section-empty { + padding: 10px 14px 12px 27px; + color: #888; + font-size: 12px; +} + +.contact-item { + padding: 10px; + display: flex; + align-items: center; + cursor: pointer; + + &:hover { + background-color: var(--sidebar-hover); + } + + &.active { + background-color: var(--sidebar-active); + } +} + +.contact-avatar { + width: 40px; + height: 40px; + border-radius: 4px; + background-color: #ccc; + margin-right: 10px; + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + color: #fff; + overflow: hidden; + flex-shrink: 0; + + img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; + } +} + +.message-avatar { + img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; + } +} + +.contact-info { + flex: 1; + overflow: hidden; +} + +.contact-name { + font-weight: 500; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.resizer { + width: 4px; + cursor: col-resize; + background-color: transparent; + border-right: 1px solid transparent; + transition: + background-color 0.2s, + border-color 0.2s; + z-index: 10; +} + +.resizer:hover, +.resizer:active { + border-color: rgba(36, 122, 99, 0.22); + background-color: rgba(36, 122, 99, 0.06); +} diff --git a/src/renderer/src/styles/export.scss b/src/renderer/src/styles/export.scss new file mode 100644 index 0000000..42fc60e --- /dev/null +++ b/src/renderer/src/styles/export.scss @@ -0,0 +1,951 @@ +/* Export workspace */ +.export-workspace { + display: grid; + grid-template-columns: 292px minmax(520px, 1fr) 360px; + width: 100%; + height: 100%; + min-width: 0; + min-height: 0; + background: var(--wxex-bg-main); +} + +.export-contact-panel, +.export-config-panel, +.export-preview-panel { + min-width: 0; + min-height: 0; + background: var(--wxex-bg-elevated); +} + +.export-contact-panel { + display: flex; + flex-direction: column; + border-right: 1px solid var(--wxex-border); + background: var(--wxex-bg-sidebar); +} + +.export-panel-header { + padding: 20px 16px 12px; + border-bottom: 1px solid var(--wxex-border); +} + +.export-panel-title-row, +.export-section-heading, +.export-preview-heading, +.export-action-bar, +.export-target-path, +.export-media-master, +.export-account-summary { + display: flex; + align-items: center; +} + +.export-panel-title-row { + justify-content: space-between; + gap: 8px; + margin-bottom: 14px; + + h2 { + margin: 0; + color: var(--wxex-text-primary); + font-size: 17px; + font-weight: 700; + } +} + +.export-count-badge { + padding: 3px 8px; + border-radius: 5px; + background: var(--wxex-bg-elevated); + color: var(--wxex-text-secondary); + font-size: 11px; + white-space: nowrap; +} + +.export-search-field { + display: flex; + align-items: center; + gap: 8px; + height: 38px; + padding: 0 10px; + border: 1px solid var(--wxex-border); + border-radius: 7px; + background: var(--wxex-bg-elevated); + color: var(--wxex-text-muted); + + input { + width: 100%; + min-width: 0; + border: 0; + outline: 0; + background: transparent; + color: var(--wxex-text-primary); + font: 13px/20px var(--wxex-font); + } +} + +.export-filter-tabs { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 3px; + margin-top: 12px; + padding: 3px; + border-radius: 7px; + background: #e3e9e5; + + button { + border: 0; + border-radius: 5px; + background: transparent; + color: var(--wxex-text-secondary); + cursor: pointer; + font: 600 12px/30px var(--wxex-font); + + &.active { + background: var(--wxex-bg-elevated); + color: var(--wxex-brand); + box-shadow: 0 1px 2px rgba(32, 39, 36, 0.06); + } + } +} + +.export-contact-list { + flex: 1; + min-height: 0; + overflow: auto; + padding: 8px 0; +} + +.export-contact-item { + display: flex; + align-items: center; + width: 100%; + gap: 10px; + padding: 11px 16px; + border: 0; + border-left: 3px solid transparent; + background: transparent; + color: var(--wxex-text-primary); + cursor: pointer; + text-align: left; + + &:hover { + background: rgba(255, 255, 255, 0.58); + } + + &.active { + border-left-color: var(--wxex-brand); + background: var(--wxex-brand-soft); + } +} + +.export-contact-avatar, +.export-account-avatar, +.export-chat-avatar, +.export-preview-avatar { + display: grid; + place-items: center; + flex: 0 0 auto; + overflow: hidden; + background: var(--wxex-brand-soft); + color: var(--wxex-brand); + font-weight: 700; +} + +.export-contact-avatar { + width: 38px; + height: 38px; + border-radius: 8px; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } +} + +.export-contact-copy, +.export-account-summary > span:last-child { + display: grid; + min-width: 0; + gap: 2px; + + strong { + overflow: hidden; + color: var(--wxex-text-primary); + font-size: 13px; + text-overflow: ellipsis; + white-space: nowrap; + } + + small { + color: var(--wxex-text-muted); + font-size: 11px; + } +} + +.export-account-summary { + small.ready { + color: var(--wxex-success); + } +} + +.export-account-summary { + gap: 9px; + padding: 14px 16px; + border: 0; + border-top: 1px solid var(--wxex-border); + background: transparent; + text-align: left; + cursor: pointer; +} + +.export-account-avatar { + width: 34px; + height: 34px; + border-radius: 50%; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } +} + +.export-config-panel { + display: flex; + flex-direction: column; + overflow: hidden; + background: var(--wxex-bg-main); +} + +.export-config-scroll { + flex: 1; + min-height: 0; + overflow: auto; + padding: 24px 28px 28px; +} + +.export-config-header { + display: flex; + align-items: center; + gap: 14px; + margin-bottom: 26px; + + h1 { + margin: 0; + color: var(--wxex-text-primary); + font-size: 20px; + font-weight: 700; + line-height: 28px; + } + + p { + margin: 2px 0 0; + color: var(--wxex-text-secondary); + font-size: 13px; + } +} +.export-chat-avatar { + width: 52px; + height: 52px; + border-radius: 10px; + font-size: 22px; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } +} + +.export-section { + margin-bottom: 25px; + + h3 { + margin: 0 0 12px; + color: var(--wxex-text-primary); + font-size: 12px; + font-weight: 700; + } +} +.export-section-heading { + justify-content: space-between; + gap: 12px; + + span { + color: var(--wxex-brand); + font-size: 12px; + } +} + +.export-range-toggle { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 8px; + + button { + border: 0; + border-radius: 5px; + background: transparent; + color: var(--wxex-text-secondary); + cursor: pointer; + font: 600 12px/30px var(--wxex-font); + border: 1px solid var(--wxex-border); + background: var(--wxex-bg-elevated); + line-height: 36px; + + &.active { + border-color: var(--wxex-brand); + background: var(--wxex-brand); + color: #fff; + box-shadow: none; + } + } +} + +.export-date-fields { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; + margin-top: 10px; + padding: 12px; + border-radius: 8px; + background: #f0f3f0; + + label { + display: grid; + gap: 5px; + color: var(--wxex-text-secondary); + font-size: 11px; + } + + input { + width: 100%; + min-width: 0; + padding: 8px 9px; + border: 1px solid var(--wxex-border); + border-radius: 6px; + background: #fff; + color: var(--wxex-text-primary); + font: 13px/20px var(--wxex-font); + } +} + +.export-kind-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 4px 20px; + padding: 14px; + border-radius: 8px; + background: #f0f3f0; +} +.export-check-row { + display: flex; + align-items: center; + gap: 8px; + min-height: 28px; + color: var(--wxex-text-primary); + font-size: 12px; + cursor: pointer; + + input { + width: 16px; + height: 16px; + accent-color: var(--wxex-brand); + } + + &.unsupported { + color: var(--wxex-text-muted); + cursor: not-allowed; + + input { + cursor: not-allowed; + } + } +} +.export-unsupported-hint { + display: inline-grid; + width: 16px; + height: 16px; + place-items: center; + border: 1px solid #c57923; + border-radius: 50%; + color: #a85e13; + font-size: 11px; + font-weight: 700; + line-height: 1; +} +.export-name-mode-grid { + display: flex; + gap: 8px; + padding: 10px; + border-radius: 8px; + background: #f0f3f0; +} +.export-name-mode-option { + display: flex; + align-items: center; + gap: 7px; + flex: 1; + min-height: 32px; + padding: 0 8px; + border: 1px solid var(--wxex-border); + border-radius: 6px; + background: #fff; + color: var(--wxex-text-primary); + font-size: 12px; + cursor: pointer; + + input { + accent-color: var(--wxex-brand); + } +} + +.export-media-master { + justify-content: space-between; + gap: 12px; + padding: 13px 14px; + border: 1px solid var(--wxex-border); + border-radius: 7px; + background: #fff; + color: var(--wxex-text-primary); + font-size: 12px; + + input { + width: 17px; + height: 17px; + accent-color: var(--wxex-brand); + } +} +.export-media-options { + display: grid; + gap: 2px; + margin-top: 8px; + padding: 9px 13px; + border-radius: 8px; + background: #f0f3f0; + + &.disabled { + opacity: 0.52; + } +} +.export-resource-statuses { + display: flex; + flex-wrap: wrap; + gap: 6px; + margin-top: 9px; + + span { + padding: 3px 7px; + border-radius: 4px; + background: var(--wxex-brand-soft); + color: var(--wxex-success); + font-size: 10px; + } +} +.export-helper-text { + margin: 9px 0 0; + color: var(--wxex-text-muted); + font-size: 11px; +} + +.export-format-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 8px; + + button { + min-height: 78px; + border: 1px solid var(--wxex-border); + border-radius: 8px; + background: #fff; + color: var(--wxex-text-primary); + cursor: pointer; + + &.active { + border: 2px solid var(--wxex-brand); + background: #f2f8f5; + } + } + + strong { + display: block; + font-size: 13px; + } + + small { + display: block; + margin-top: 6px; + color: var(--wxex-success); + font-size: 10px; + } +} +.export-html-options { + display: grid; + gap: 8px; + margin-top: 10px; + padding: 11px 13px; + border: 1px solid var(--wxex-border); + border-radius: 8px; + background: #f0f3f0; + color: var(--wxex-text-primary); + font-size: 12px; + + input { + accent-color: var(--wxex-brand); + } +} + +.export-save-section { + display: grid; + gap: 12px; + + > label { + display: grid; + gap: 5px; + color: var(--wxex-text-secondary); + font-size: 11px; + + input { + width: 100%; + min-width: 0; + padding: 8px 9px; + border: 1px solid var(--wxex-border); + border-radius: 6px; + outline: 0; + background: #fff; + color: var(--wxex-text-primary); + font: 13px/20px var(--wxex-font); + } + } +} +.export-target-path { + gap: 10px; + padding: 9px 10px; + border: 1px solid var(--wxex-border); + border-radius: 7px; + background: #fff; + color: var(--wxex-text-secondary); + font-size: 11px; + + strong { + flex: 1; + min-width: 0; + overflow: hidden; + color: var(--wxex-text-primary); + font-weight: 500; + text-overflow: ellipsis; + white-space: nowrap; + } + + button { + padding: 5px 8px; + border: 1px solid var(--wxex-border); + border-radius: 5px; + background: #fff; + color: var(--wxex-text-primary); + cursor: pointer; + font: 11px var(--wxex-font); + } +} + +.export-action-bar { + flex: 0 0 58px; + gap: 8px; + padding: 0 22px; + border-top: 1px solid var(--wxex-border); + background: #fff; + color: var(--wxex-text-secondary); + font-size: 12px; +} +.export-ready-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--wxex-success); + + &.completed { + background: var(--wxex-brand); + } +} +.export-target-summary { + flex: 1; + min-width: 0; + margin-left: 14px; + overflow: hidden; + color: var(--wxex-text-muted); + text-overflow: ellipsis; + white-space: nowrap; +} +.export-reset-button { + border: 0; + background: transparent; + color: var(--wxex-text-primary); + cursor: pointer; + font: 600 12px var(--wxex-font); +} +.export-primary-button { + min-width: 132px; + padding: 10px 16px; + border: 0; + border-radius: 7px; + background: var(--wxex-brand); + color: #fff; + cursor: pointer; + font: 700 12px var(--wxex-font); + + &:disabled { + cursor: default; + opacity: 0.55; + } +} + +.export-preview-panel { + display: flex; + flex-direction: column; + overflow: hidden; + border-left: 1px solid var(--wxex-border); + background: #fbfcfb; +} +.export-preview-heading { + justify-content: space-between; + flex: 0 0 52px; + padding: 0 18px; + border-bottom: 1px solid var(--wxex-border); + color: var(--wxex-text-primary); + font-size: 12px; + + span { + color: var(--wxex-text-muted); + font-size: 11px; + } +} +.export-message-preview { + flex: 1; + min-height: 0; + overflow: auto; + padding: 16px 14px; +} +.export-preview-date { + width: fit-content; + margin: 0 auto 18px; + padding: 4px 9px; + border-radius: 10px; + background: #e9eeeb; + color: var(--wxex-text-secondary); + font-size: 10px; +} +.export-preview-message { + display: flex; + align-items: flex-start; + gap: 8px; + width: min(100%, 620px); + margin: 0 auto 15px; + + &.mine { + flex-direction: row-reverse; + + .export-preview-bubble { + background: #95ec69; + } + } + + &.system { + justify-content: center; + flex-direction: row; + + .export-preview-avatar { + display: none; + } + + .export-preview-bubble { + max-width: 92%; + padding: 5px 10px; + border: 0; + border-radius: 5px; + background: #e9eeeb; + color: var(--wxex-text-muted); + font-size: 11px; + text-align: center; + box-shadow: none; + + small { + display: none; + } + } + } +} +.export-preview-avatar { + width: 30px; + height: 30px; + border-radius: 7px; + font-size: 11px; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } +} +.export-preview-bubble { + max-width: 78%; + padding: 9px 10px; + border-radius: 8px; + background: #fff; + color: var(--wxex-text-primary); + font-size: 12px; + line-height: 18px; + box-shadow: 0 1px 2px rgba(32, 39, 36, 0.05); + + small { + display: block; + margin-bottom: 3px; + color: var(--wxex-text-muted); + font-size: 10px; + } +} +.export-preview-stats { + flex: 0 0 auto; + display: grid; + gap: 12px; + padding: 18px; + border-top: 1px solid var(--wxex-border); +} + +.export-task-center-button { + align-self: flex-start; + margin: 0 0 12px; + border: 1px solid var(--wxex-border); + border-radius: 6px; + background: var(--wxex-bg-elevated); + color: var(--wxex-brand); + cursor: pointer; + padding: 7px 11px; + font: 600 12px/18px var(--wxex-font); +} + +.export-task-center { + margin: 0 0 18px; + padding: 12px; + border: 1px solid var(--wxex-border); + border-radius: 8px; + background: var(--wxex-bg-elevated); +} + +.export-task-row { + display: grid; + grid-template-columns: minmax(0, 1fr) auto auto; + align-items: center; + gap: 12px; + padding: 9px 0; + border-top: 1px solid var(--wxex-border); + color: var(--wxex-text-secondary); + font-size: 12px; + + &:first-of-type { + margin-top: 8px; + } + + > span:first-child { + display: grid; + gap: 2px; + min-width: 0; + } + + strong, + small { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + strong { + color: var(--wxex-text-primary); + } + + button { + border: 1px solid var(--wxex-border); + border-radius: 5px; + background: transparent; + color: var(--wxex-text-secondary); + cursor: pointer; + padding: 4px 8px; + } +} + +.export-task-progress { + position: relative; + width: 110px; + height: 6px; + overflow: hidden; + border-radius: 999px; + background: var(--wxex-border); + + i { + display: block; + height: 100%; + border-radius: inherit; + background: var(--wxex-brand); + } + + b { + position: absolute; + top: 10px; + right: 0; + color: var(--wxex-text-muted); + font-size: 10px; + font-weight: 500; + } +} +.export-preview-panel .export-preview-stats:not(.export-preview-real-stats) { + display: none; +} +.export-preview-stats span, +.export-complete-summary span { + display: flex; + justify-content: space-between; + color: var(--wxex-text-secondary); + font-size: 12px; +} +.export-preview-stats strong, +.export-complete-summary strong { + color: var(--wxex-text-primary); + font-weight: 600; +} + +.export-job-state { + display: grid; + align-content: center; + gap: 12px; + height: 100%; + padding: 28px; + text-align: center; + + h2 { + margin: 0; + color: var(--wxex-text-primary); + font-size: 18px; + font-weight: 700; + } + + p { + margin: 0; + color: var(--wxex-text-secondary); + font-size: 12px; + line-height: 18px; + } + + ol { + display: grid; + gap: 10px; + margin: 8px 0; + padding: 0; + list-style: none; + text-align: left; + } + + li { + color: var(--wxex-text-muted); + font-size: 12px; + + &::before { + display: inline-grid; + width: 16px; + height: 16px; + margin-right: 8px; + place-items: center; + border: 1px solid var(--wxex-border); + border-radius: 50%; + content: ''; + vertical-align: -3px; + } + + &.done { + color: var(--wxex-success); + + &::before { + border-color: var(--wxex-success); + background: var(--wxex-success); + content: '✓'; + color: #fff; + font-size: 10px; + } + } + + &.current { + color: var(--wxex-text-primary); + font-weight: 600; + + &::before { + border-color: var(--wxex-brand); + background: var(--wxex-brand); + box-shadow: inset 0 0 0 4px #fff; + } + } + } + + > strong { + color: var(--wxex-text-secondary); + font-size: 12px; + font-weight: 500; + } +} +.export-progress-bar { + height: 6px; + overflow: hidden; + border-radius: 4px; + background: #e2e9e4; + + span { + display: block; + height: 100%; + border-radius: 4px; + background: var(--wxex-brand); + transition: width 0.2s ease; + } +} +.export-job-state > strong { + color: var(--wxex-text-secondary); + font-size: 12px; + font-weight: 500; +} +.export-cancel-button, +.export-open-folder-button { + padding: 10px 14px; + border: 1px solid var(--wxex-border); + border-radius: 7px; + background: #fff; + color: var(--wxex-text-primary); + cursor: pointer; + font: 600 12px var(--wxex-font); +} +.export-success-icon { + width: 58px; + height: 58px; + margin: 0 auto 4px; + border: 5px solid var(--wxex-brand-soft); + border-radius: 50%; + background: #fff; + color: var(--wxex-brand); + font-size: 30px; + line-height: 48px; +} +.export-complete-summary { + display: grid; + gap: 12px; + margin: 12px 0; + padding: 14px; + border-radius: 8px; + background: #eef3ef; + text-align: left; +} + +@media (max-width: 1100px) { + .export-workspace { + grid-template-columns: 248px minmax(460px, 1fr); + } + .export-preview-panel { + display: none; + } +} diff --git a/src/renderer/src/styles/foundation.scss b/src/renderer/src/styles/foundation.scss new file mode 100644 index 0000000..84eead1 --- /dev/null +++ b/src/renderer/src/styles/foundation.scss @@ -0,0 +1,348 @@ +:root { + --bg-color: #f5f5f5; + --sidebar-bg: #e7e7e7; + --sidebar-hover: #d6d6d6; + --sidebar-active: #c6c6c6; + --chat-bg: #f5f5f5; + --message-bg-user: #95ec69; + --message-bg-other: #ffffff; + --text-color: #000000; + --border-color: #dcdcdc; +} + +body { + margin: 0; + padding: 0; + font-family: var(--wxex-font); + background-color: var(--wxex-bg-app); + color: var(--wxex-text-primary); + height: 100vh; + overflow: hidden; +} + +#root { + height: 100%; + display: flex; +} + +.app-shell { + box-sizing: border-box; + display: flex; + width: 100%; + height: 100%; + min-height: 0; + min-width: 0; + overflow: hidden; + background: var(--wxex-bg-app); +} + +.app-primary-rail { + box-sizing: border-box; + width: var(--wxex-nav-width); + flex: 0 0 var(--wxex-nav-width); + height: 100%; + min-height: 0; + display: flex; + flex-direction: column; + align-items: center; + border-right: 1px solid var(--wxex-border); + background: var(--wxex-bg-sidebar); + padding: 12px 8px; + overflow: hidden; + -webkit-app-region: drag; +} + +.app-brand { + box-sizing: border-box; + width: 42px; + height: 42px; + display: grid; + place-items: center; + border: 0; + border-radius: 12px; + background: transparent; + -webkit-app-region: no-drag; + + img { + display: block; + width: 42px; + height: 42px; + border-radius: 12px; + } +} + +.primary-navigation { + box-sizing: border-box; + display: flex; + flex: 1; + flex-direction: column; + gap: 6px; + width: 100%; + margin-top: 18px; + -webkit-app-region: no-drag; +} + +.primary-nav-item { + width: 100%; + height: 58px; + flex: 0 0 58px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 4px; + border: 0; + border-radius: var(--wxex-radius-md); + background: transparent; + color: var(--wxex-text-secondary); + cursor: pointer; + font-family: var(--wxex-font); + + &:hover { + background: rgba(255, 255, 255, 0.46); + color: var(--wxex-text-primary); + } + + &.active { + background: var(--wxex-brand-soft); + color: var(--wxex-brand); + } +} + +.primary-nav-mark { + width: 24px; + height: 24px; + display: grid; + place-items: center; + + svg { + width: 22px; + height: 22px; + } + + path, + circle { + fill: none; + stroke: currentColor; + stroke-width: 1.7; + stroke-linecap: round; + stroke-linejoin: round; + } +} + +.primary-nav-label { + font-size: 12px; + line-height: 16px; + font-weight: 600; + white-space: nowrap; +} + +.app-rail-account { + box-sizing: border-box; + width: 100%; + flex: 0 0 auto; + -webkit-app-region: no-drag; +} + +.account-summary { + box-sizing: border-box; + width: 100%; + display: flex; + align-items: center; + gap: 10px; + border: 0; + border-radius: var(--wxex-radius-md); + background: transparent; + color: var(--wxex-text-primary); + font-family: var(--wxex-font); + text-align: left; + + &:hover { + background: rgba(255, 255, 255, 0.72); + } +} + +.account-summary.compact { + justify-content: center; + cursor: pointer; + padding: 8px 0; +} + +.account-summary-avatar { + box-sizing: border-box; + position: relative; + width: 38px; + height: 38px; + display: grid; + place-items: center; + flex: 0 0 auto; + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); + color: var(--wxex-brand); + font-size: 14px; + font-weight: 700; + overflow: hidden; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } +} + +.account-summary-status { + position: absolute; + right: 2px; + bottom: 2px; + width: 9px; + height: 9px; + border: 2px solid var(--wxex-bg-elevated); + border-radius: 999px; + background: var(--wxex-text-muted); + + &.ready { + background: var(--wxex-success); + } +} + +.account-summary:not(.compact) .account-summary-avatar .account-summary-status { + display: none; +} + +.account-summary-text { + min-width: 0; + display: flex; + flex-direction: column; +} + +.account-summary-name { + overflow: hidden; + color: var(--wxex-text-primary); + font-size: 13px; + font-weight: 600; + line-height: 18px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.account-summary-meta { + overflow: hidden; + color: var(--wxex-text-muted); + font-size: 12px; + line-height: 16px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.account-summary-state { + overflow: hidden; + display: flex; + align-items: center; + gap: 5px; + color: var(--wxex-text-secondary); + font-size: 12px; + line-height: 16px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.account-summary-state-dot { + width: 7px; + height: 7px; + flex: 0 0 auto; + border-radius: 999px; + background: var(--wxex-text-muted); + + &.ready { + background: var(--wxex-success); + } +} + +.account-summary-settings { + box-sizing: border-box; + width: 28px; + height: 28px; + display: grid; + place-items: center; + flex: 0 0 auto; + border: 0; + border-radius: var(--wxex-radius-sm); + background: transparent; + color: var(--wxex-text-muted); + cursor: pointer; + + &:hover { + background: var(--wxex-brand-soft); + color: var(--wxex-brand); + } + + svg { + width: 17px; + height: 17px; + } + + path { + fill: none; + stroke: currentColor; + stroke-width: 1.7; + stroke-linecap: round; + stroke-linejoin: round; + } +} + +.app-shell-main { + box-sizing: border-box; + flex: 1; + min-width: 0; + min-height: 0; + height: 100%; + display: flex; + align-items: stretch; + overflow: hidden; + padding-top: var(--wxex-shell-content-top); + background: var(--wxex-bg-main); +} + +.app-page-placeholder { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 24px; + color: var(--wxex-text-secondary); + text-align: center; + + h2 { + margin: 0 0 8px; + color: var(--wxex-text-primary); + font-size: 20px; + font-weight: 600; + line-height: 28px; + } + + p { + margin: 0; + font-size: 13px; + line-height: 20px; + } +} +.app-page-placeholder-eyebrow { + margin-bottom: 8px; + color: var(--wxex-brand); + font-size: 11px; + font-weight: 700; + letter-spacing: 0; +} + + +.app-container { + display: flex; + width: 100%; + height: 100%; + min-height: 0; + min-width: 0; + align-items: stretch; + overflow: hidden; +} diff --git a/src/renderer/src/styles/index.scss b/src/renderer/src/styles/index.scss new file mode 100644 index 0000000..46df485 --- /dev/null +++ b/src/renderer/src/styles/index.scss @@ -0,0 +1,16 @@ +@use './_tokens'; +@use './_base'; + +@use './foundation'; +@use './conversation'; +@use './chat'; +@use './rich-message'; +@use './shell-overlays'; +@use './reports-core'; +@use './settings'; +@use './api'; +@use './reports-templates'; +@use './export'; +@use './search'; +@use './archive'; +@use './settings-advanced'; diff --git a/src/renderer/src/styles/reports-core.scss b/src/renderer/src/styles/reports-core.scss new file mode 100644 index 0000000..20261c7 --- /dev/null +++ b/src/renderer/src/styles/reports-core.scss @@ -0,0 +1,1444 @@ +.report-page { + display: grid; + grid-template-columns: 292px minmax(420px, 1fr) 304px; + width: 100%; + height: 100%; + min-height: 0; + min-width: 0; + overflow: hidden; + background: var(--wxex-bg-main); +} + +.report-center-page { + display: grid; + grid-template-columns: 292px minmax(420px, 1fr) 304px; + width: 100%; + height: 100%; + min-height: 0; + min-width: 0; + overflow: hidden; + background: var(--wxex-bg-main); +} + +.report-page > *, +.report-center-page > * { + min-height: 0; + min-width: 0; +} + +.report-source-sidebar { + display: flex; + min-width: 0; + min-height: 0; + height: 100%; + flex-direction: column; + overflow: hidden; + border-right: 1px solid var(--wxex-border); + background: var(--wxex-bg-sidebar); +} + +.report-source-header { + display: flex; + flex: 0 0 auto; + align-items: flex-start; + justify-content: space-between; + gap: 12px; + padding: 18px 16px 12px; + border-bottom: 1px solid var(--wxex-border); +} + +.report-source-header h2, +.ai-report-header h1, +.report-task-header h2 { + margin: 0; + color: var(--wxex-text-primary); +} + +.report-source-header h2 { + font: 700 18px/24px var(--wxex-font); +} + +.report-source-header p, +.ai-report-header p, +.report-task-header p { + margin: 4px 0 0; + color: var(--wxex-text-secondary); + font: 12px/18px var(--wxex-font); +} + +.report-source-header > span { + flex: 0 0 auto; + margin-top: 3px; + color: var(--wxex-text-muted); + font: 12px/18px var(--wxex-font); +} + +.report-source-search { + display: flex; + flex: 0 0 auto; + align-items: center; + gap: 8px; + margin: 12px 14px; + padding: 0 10px; + height: 36px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); + color: var(--wxex-text-muted); +} + +.report-source-search svg { + width: 16px; + height: 16px; +} + +.report-source-search path, +.report-source-search circle { + fill: none; + stroke: currentColor; + stroke-width: 1.8; + stroke-linecap: round; + stroke-linejoin: round; +} + +.report-source-search input { + min-width: 0; + flex: 1; + border: 0; + outline: 0; + background: transparent; + color: var(--wxex-text-primary); + font: 13px/18px var(--wxex-font); +} + +.report-source-list { + flex: 1 1 auto; + min-height: 0; + overflow-y: auto; + padding: 0 10px 12px; +} + +.report-source-item { + position: relative; + display: flex; + width: 100%; + min-width: 0; + align-items: center; + gap: 10px; + padding: 10px 10px 10px 12px; + border: 0; + border-radius: var(--wxex-radius-md); + background: transparent; + color: var(--wxex-text-primary); + text-align: left; + cursor: pointer; + font-family: var(--wxex-font); +} + +.report-source-item:hover { + background: rgba(255, 255, 255, 0.62); +} + +.report-source-item.active { + background: var(--wxex-brand-soft); + color: var(--wxex-brand); +} + +.report-source-item.active::before { + position: absolute; + left: 0; + top: 8px; + bottom: 8px; + width: 3px; + border-radius: 4px; + background: var(--wxex-brand); + content: ''; +} + +.report-source-avatar { + display: grid; + width: 36px; + height: 36px; + flex: 0 0 auto; + place-items: center; + overflow: hidden; + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); + color: var(--wxex-brand); + font: 700 14px/1 var(--wxex-font); +} + +.report-source-avatar img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.report-source-text { + display: grid; + min-width: 0; +} + +.report-source-text span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.report-source-text span { + color: inherit; + font: 600 13px/18px var(--wxex-font); +} + +.report-source-empty { + padding: 18px 8px; + color: var(--wxex-text-muted); + font: 13px/18px var(--wxex-font); +} + +.report-source-account { + flex: 0 0 auto; + padding: 12px; + border-top: 1px solid var(--wxex-border); +} + +.ai-report-workspace { + display: flex; + min-width: 0; + min-height: 0; + height: 100%; + flex-direction: column; + overflow: hidden; + background: var(--wxex-bg-main); +} + +.ai-report-header { + display: flex; + flex: 0 0 auto; + align-items: flex-start; + justify-content: space-between; + gap: 18px; + padding: 22px 28px 16px; + border-bottom: 1px solid var(--wxex-border); +} + +.ai-report-header h1 { + font: 700 21px/28px var(--wxex-font); +} + +.ai-report-header p { + font-size: 13px; +} + +.report-inline-error { + max-width: 320px; + padding: 8px 10px; + border: 1px solid rgba(200, 90, 90, 0.35); + border-radius: var(--wxex-radius-md); + background: #fff4f4; + color: var(--wxex-danger); + font: 12px/17px var(--wxex-font); +} + +.ai-report-body { + flex: 1 1 auto; + min-height: 0; + overflow-y: auto; + overflow-x: hidden; + padding: 18px 28px 20px; +} + +.ai-report-body > * { + max-width: 720px; +} + +.ai-report-body > .report-section + .report-section { + margin-top: 28px; +} + +.report-empty-state, +.report-config-section, +.report-privacy-note, +.report-result-panel { + margin-bottom: 16px; + padding: 16px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-lg); + background: var(--wxex-bg-elevated); +} + +.report-empty-state h2, +.report-privacy-note h3, +.report-config-section h3, +.report-result-panel h3 { + margin: 0; + color: var(--wxex-text-primary); + font: 700 15px/20px var(--wxex-font); +} + +.report-timeout-section { + display: flex; + align-items: center; + justify-content: space-between; + gap: 20px; +} + +.report-timeout-section p { + margin: 6px 0 0; + color: var(--wxex-text-secondary); + font-size: 12px; +} + +.report-timeout-section label { + display: flex; + flex: 0 0 auto; + align-items: center; + gap: 8px; + color: var(--wxex-text-secondary); + font-size: 13px; +} + +.report-timeout-section input { + width: 96px; + height: 36px; + padding: 0 10px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: #fff; + color: var(--wxex-text-primary); + font: 500 13px var(--wxex-font); +} + +.report-empty-state p, +.report-privacy-note p { + margin: 6px 0 0; + color: var(--wxex-text-secondary); + font: 13px/19px var(--wxex-font); +} + +.report-section-heading { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-bottom: 12px; +} + +.report-section-heading span { + color: var(--wxex-text-muted); + font: 12px/18px var(--wxex-font); +} + +.report-section-heading span.danger { + color: var(--wxex-danger); +} + +.report-range-options, +.report-density-options { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 8px; +} + +.report-density-options { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.report-range-options button, +.report-density-options button, +.report-model-summary button, +.report-result-actions button, +.report-task-error button, +.ai-report-footer button { + min-height: 34px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); + color: var(--wxex-text-primary); + cursor: pointer; + font: 600 13px/18px var(--wxex-font); +} + +.report-range-options button.active, +.report-density-options button.active { + border-color: var(--wxex-brand); + background: var(--wxex-brand-soft); + color: var(--wxex-brand); +} + +.report-range-options button:disabled, +.report-density-options button:disabled { + color: var(--wxex-text-muted); + cursor: not-allowed; + opacity: 0.75; +} + +.report-range-options button span, +.report-density-options button span { + display: block; + margin-top: 2px; + font: 11px/14px var(--wxex-font); +} + +.report-type-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 8px; +} + +.report-check-row { + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto; + align-items: start; + gap: 8px; + padding: 10px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: #fbfcfb; + color: var(--wxex-text-primary); +} + +.report-check-row input { + margin-top: 2px; + accent-color: var(--wxex-brand); +} + +.report-check-row span { + display: grid; + min-width: 0; + gap: 2px; +} + +.report-check-row b { + font: 600 13px/18px var(--wxex-font); +} + +.report-check-row small { + color: var(--wxex-text-muted); + font: 12px/16px var(--wxex-font); +} + +.report-check-row em { + color: var(--wxex-text-secondary); + font: normal 12px/18px var(--wxex-font); +} + +.report-readonly-modules { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 8px; + cursor: default; +} + +.report-readonly-modules span { + display: flex; + min-width: 0; + align-items: center; + gap: 8px; + padding: 8px 10px; + border: 1px solid #e9eeeb; + border-radius: var(--wxex-radius-md); + background: #f7f9f8; + color: var(--wxex-text-secondary); + font: 12px/17px var(--wxex-font); + cursor: default; +} + +.report-readonly-modules svg { + width: 14px; + height: 14px; + flex: 0 0 auto; + color: var(--wxex-text-muted); +} + +.report-readonly-modules rect, +.report-readonly-modules path { + fill: none; + stroke: currentColor; + stroke-width: 1.7; + stroke-linecap: round; + stroke-linejoin: round; +} + +.report-model-summary { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} + +.report-model-summary p { + margin: 4px 0 0; + color: var(--wxex-text-secondary); + font: 13px/18px var(--wxex-font); +} + +.report-model-summary button, +.report-result-actions button, +.report-task-error button { + padding: 0 12px; +} + +.report-result-preview { + max-height: 460px; + overflow: auto; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: #f6f4f0; + text-align: center; +} + +.report-result-preview img { + display: inline-block; + width: min(100%, 430px); + height: auto; +} + +.report-result-actions { + display: flex; + gap: 8px; + margin-top: 10px; +} + +.report-action-status { + margin: 8px 0 0; + color: var(--wxex-text-secondary); + font: 12px/16px var(--wxex-font); +} + +.ai-report-footer { + display: flex; + flex: 0 0 auto; + min-height: 66px; + align-items: center; + justify-content: space-between; + gap: 16px; + padding: 12px 28px; + border-top: 1px solid var(--wxex-border); + background: var(--wxex-bg-main); +} + +.report-footer-note, +.report-footer-actions span { + min-width: 0; + color: var(--wxex-text-secondary); + font: 12px/18px var(--wxex-font); +} + +.report-footer-note { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.report-footer-actions { + display: flex; + min-width: 0; + flex: 0 0 auto; + align-items: center; + gap: 12px; +} + +.report-footer-actions span { + max-width: 280px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.ai-report-footer button { + min-width: 132px; + padding: 0 16px; + border-color: var(--wxex-ai); + background: var(--wxex-ai); + color: #fff; +} + +.ai-report-footer button.secondary { + min-width: 92px; + border-color: var(--wxex-border); + background: var(--wxex-bg-elevated); + color: var(--wxex-text-primary); +} + +.ai-report-footer button:disabled { + border-color: var(--wxex-border); + background: #e8ebe9; + color: var(--wxex-text-muted); + cursor: not-allowed; +} + +.report-task-panel { + display: flex; + min-width: 0; + min-height: 0; + height: 100%; + flex-direction: column; + overflow: hidden; + border-left: 1px solid var(--wxex-border); + background: #f7f9f8; +} + +.report-task-header { + flex: 0 0 auto; + padding: 20px 18px 14px; + border-bottom: 1px solid var(--wxex-border); +} + +.report-task-header h2 { + font: 700 16px/22px var(--wxex-font); +} + +.report-task-steps { + flex: 0 0 auto; + padding: 16px 18px; +} + +.report-task-step { + display: grid; + grid-template-columns: 18px minmax(0, 1fr); + gap: 10px; + padding: 0 0 18px; + color: var(--wxex-text-muted); +} + +.report-task-step b { + display: block; + color: inherit; + font: 600 13px/18px var(--wxex-font); +} + +.report-task-step small { + color: var(--wxex-text-muted); + font: 12px/16px var(--wxex-font); +} + +.report-task-dot { + width: 12px; + height: 12px; + margin-top: 3px; + border: 2px solid var(--wxex-border); + border-radius: 50%; + background: transparent; +} + +.report-task-step.done { + color: var(--wxex-success); +} + +.report-task-step.done .report-task-dot { + border-color: var(--wxex-success); + background: var(--wxex-success); +} + +.report-task-step.active { + color: var(--wxex-ai); +} + +.report-task-step.active .report-task-dot { + border-color: var(--wxex-ai); + background: var(--wxex-ai-soft); +} + +.report-task-error, +.report-task-success, +.report-task-note { + margin: 0 18px 14px; + padding: 12px; + border-radius: var(--wxex-radius-md); + font: 12px/18px var(--wxex-font); +} + +.report-task-error { + border: 1px solid rgba(200, 90, 90, 0.35); + background: #fff4f4; + color: var(--wxex-danger); +} + +.report-task-success { + border: 1px solid rgba(46, 139, 104, 0.28); + background: var(--wxex-brand-soft); + color: var(--wxex-success); +} + +.report-task-note { + margin-top: auto; + flex: 0 0 auto; + color: var(--wxex-text-secondary); + background: var(--wxex-ai-soft); +} + +.report-task-error p, +.report-task-success p { + margin: 4px 0 10px; +} + +.report-task-error button + button { + margin-left: 8px; +} + +.report-task-log-path { + display: block; + margin-top: 8px; + overflow-wrap: anywhere; + color: var(--wxex-text-secondary); + font: 11px/16px var(--wxex-font); +} + +@media (max-width: 1120px) { + .report-page { + grid-template-columns: 268px minmax(360px, 1fr) 280px; + } + + .report-type-grid { + grid-template-columns: 1fr; + } + + .report-readonly-modules { + grid-template-columns: 1fr; + } +} + +.agent-hub-workspace { + box-sizing: border-box; + width: 100%; + height: 100%; + min-width: 0; + overflow: auto; + padding: 34px 40px 48px; + background: #fafbfa; +} +.agent-hub-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 24px; + max-width: 1080px; + margin: 0 auto 28px; +} +.agent-hub-eyebrow, +.agent-hub-card-kicker { + color: var(--wxex-brand); + font: 700 11px/16px var(--wxex-font); + letter-spacing: 0.08em; + text-transform: uppercase; +} +.agent-hub-header h1 { + margin: 4px 0 6px; + color: var(--wxex-text-primary); + font: 750 28px/36px var(--wxex-font); +} +.agent-hub-header p, +.agent-hub-card p { + margin: 0; + color: var(--wxex-text-secondary); + font: 13px/20px var(--wxex-font); +} +.agent-hub-runtime { + display: inline-flex; + align-items: center; + padding: 6px 10px; + border-radius: 999px; + background: #f0f2f0; + color: var(--wxex-text-muted); + font: 700 12px/18px var(--wxex-font); +} +.agent-hub-runtime.online { + background: #e8f6ed; + color: #24864b; +} +.agent-hub-runtime.error { + background: #fff0ef; + color: var(--wxex-danger); +} +.agent-hub-grid { + display: grid; + grid-template-columns: minmax(0, 1.55fr) minmax(280px, 0.75fr); + gap: 20px; + max-width: 1080px; + margin: 0 auto; +} +.agent-hub-card { + box-sizing: border-box; + min-width: 0; + border: 1px solid var(--wxex-border); + border-radius: 18px; + background: var(--wxex-bg-elevated); + box-shadow: 0 8px 28px rgba(28, 38, 31, 0.045); +} +.agent-hub-login-card { + min-height: 520px; + padding: 26px; + display: flex; + flex-direction: column; +} +.agent-hub-capability-card { + padding: 26px; + align-self: start; +} +.agent-hub-card-heading { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 16px; + padding-bottom: 20px; + border-bottom: 1px solid var(--wxex-border); +} +.agent-hub-card h2 { + margin: 4px 0 0; + color: var(--wxex-text-primary); + font: 700 19px/27px var(--wxex-font); +} +.agent-hub-status { + display: inline-flex; + align-items: center; + gap: 7px; + padding: 5px 9px; + border-radius: 999px; + background: #f2f3f2; + color: var(--wxex-text-secondary); + font: 650 12px/18px var(--wxex-font); + white-space: nowrap; +} +.agent-hub-status i { + width: 7px; + height: 7px; + border-radius: 50%; + background: #9aa39d; +} +.agent-hub-status.online { + background: #e8f6ed; + color: #24864b; +} +.agent-hub-status.online i { + background: #35a663; +} +.agent-hub-status.waiting_scan, +.agent-hub-status.scanned, +.agent-hub-status.starting { + background: #fff5de; + color: #9b6a12; +} +.agent-hub-status.waiting_scan i, +.agent-hub-status.scanned i, +.agent-hub-status.starting i { + background: #d89b2b; +} +.agent-hub-status.error { + background: #fff0ef; + color: var(--wxex-danger); +} +.agent-hub-status.error i { + background: var(--wxex-danger); +} +.agent-hub-empty-login { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 280px; + text-align: center; +} +.agent-hub-empty-login h3, +.agent-hub-connected h3, +.agent-hub-qr-copy h3 { + margin: 18px 0 6px; + color: var(--wxex-text-primary); + font: 700 16px/24px var(--wxex-font); +} +.agent-hub-empty-login p { + max-width: 360px; +} +.agent-hub-phone { + width: 64px; + height: 88px; + position: relative; + border: 2px solid #9eb3a5; + border-radius: 13px; + background: linear-gradient(145deg, #f6fbf7, #eaf4ed); +} +.agent-hub-phone::before { + content: ''; + position: absolute; + top: 8px; + left: 22px; + width: 18px; + height: 3px; + border-radius: 3px; + background: #b8c8bd; +} +.agent-hub-phone span { + position: absolute; + left: 23px; + bottom: 8px; + width: 16px; + height: 16px; + border: 1.5px solid var(--wxex-brand); + border-radius: 50%; +} +.agent-hub-actions { + display: flex; + justify-content: center; + gap: 10px; + min-height: 38px; + padding-top: 18px; +} +.agent-hub-button { + height: 38px; + padding: 0 16px; + border: 1px solid transparent; + border-radius: 9px; + font: 650 13px/20px var(--wxex-font); + cursor: pointer; +} +.agent-hub-button:disabled { + opacity: 0.55; + cursor: default; +} +.agent-hub-button.primary { + background: var(--wxex-brand); + color: #fff; +} +.agent-hub-button.secondary { + border-color: var(--wxex-border-strong); + background: #fff; + color: var(--wxex-text-primary); +} +.agent-hub-button.danger { + border-color: #f0c6c2; + background: #fff8f7; + color: var(--wxex-danger); +} +.agent-hub-qr-panel { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + gap: 32px; + min-height: 320px; + padding: 22px 0; +} +.agent-hub-qr-frame { + box-sizing: border-box; + width: 220px; + height: 220px; + flex: 0 0 220px; + display: grid; + place-items: center; + padding: 12px; + border: 1px solid var(--wxex-border); + border-radius: 16px; + background: #fff; + box-shadow: 0 10px 30px rgba(23, 44, 30, 0.08); +} +.agent-hub-qr-frame img { + width: 100%; + height: 100%; + display: block; + image-rendering: pixelated; +} +.agent-hub-qr-copy { + max-width: 260px; +} +.agent-hub-qr-copy h3 { + margin-top: 0; +} +.agent-hub-qr-copy .agent-hub-button { + margin-top: 18px; +} +.agent-hub-connected { + flex: 1; + min-height: 300px; + display: flex; + align-items: center; + justify-content: center; + gap: 16px; +} +.agent-hub-connected h3 { + margin: 0 0 4px; +} +.agent-hub-connected-icon { + width: 48px; + height: 48px; + display: grid; + place-items: center; + border-radius: 50%; + background: #e4f5ea; + color: #23834a; + font: 800 22px/1 var(--wxex-font); +} +.agent-hub-capability-card > p { + margin-top: 8px; +} +.agent-hub-example { + margin: 24px 0 20px; + padding: 16px; + border-radius: 12px; + background: var(--wxex-brand-soft); +} +.agent-hub-example span { + display: block; + color: var(--wxex-text-muted); + font: 600 11px/16px var(--wxex-font); +} +.agent-hub-example strong { + display: block; + margin-top: 4px; + color: var(--wxex-brand); + font: 700 14px/21px var(--wxex-font); +} +.agent-hub-capability-card ul { + margin: 0; + padding: 0; + list-style: none; +} +.agent-hub-capability-card li { + display: flex; + align-items: center; + gap: 9px; + padding: 9px 0; + border-bottom: 1px solid var(--wxex-border); + color: var(--wxex-text-secondary); + font: 13px/19px var(--wxex-font); +} +.agent-hub-capability-card li:last-child { + border-bottom: 0; +} +.agent-hub-capability-card li i { + width: 7px; + height: 7px; + border-radius: 50%; + background: var(--wxex-brand); +} +.agent-hub-example strong + strong { + margin-top: 9px; + padding-top: 9px; + border-top: 1px solid rgba(36, 122, 99, 0.15); +} +.agent-hub-capability-card li i.offline { + background: var(--wxex-danger); +} +.agent-hub-log-card { + max-width: 1080px; + margin: 20px auto 0; + padding: 22px; +} +.agent-hub-log-heading { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + margin-bottom: 14px; +} +.agent-hub-log-heading h2 { + margin-top: 3px; +} +.agent-hub-log-actions { + display: flex; + align-items: center; + gap: 8px; +} +.agent-hub-log-actions select, +.agent-hub-log-actions button { + height: 32px; + border: 1px solid var(--wxex-border-strong); + border-radius: 8px; + background: #fff; + color: var(--wxex-text-secondary); + font: 600 12px/18px var(--wxex-font); +} +.agent-hub-log-actions select { + padding: 0 28px 0 10px; +} +.agent-hub-log-actions button { + padding: 0 11px; + cursor: pointer; +} +.agent-hub-log-actions button:disabled { + opacity: 0.45; + cursor: default; +} +.agent-hub-log-body { + height: 250px; + overflow: auto; + padding: 12px 14px; + border: 1px solid #26312a; + border-radius: 11px; + background: #18201b; + color: #dfe9e2; +} +.agent-hub-log-line { + display: grid; + grid-template-columns: 78px 94px minmax(0, 1fr); + gap: 9px; + align-items: baseline; + min-height: 24px; + font: + 12px/19px ui-monospace, + SFMono-Regular, + Menlo, + monospace; +} +.agent-hub-log-line time { + color: #84938a; +} +.agent-hub-log-line .source { + color: #76d49a; +} +.agent-hub-log-line .source.wechat-connector { + color: #7dbcf1; +} +.agent-hub-log-line .source.system { + color: #d8bd6b; +} +.agent-hub-log-line code { + min-width: 0; + color: inherit; + white-space: pre-wrap; + overflow-wrap: anywhere; +} +.agent-hub-log-line.warn code { + color: #f1cf77; +} +.agent-hub-log-line.error code { + color: #ff9690; +} +.agent-hub-log-empty { + height: 100%; + display: grid; + place-items: center; + color: #84938a; + font: 12px/20px var(--wxex-font); +} +.agent-hub-log-note { + margin-top: 9px !important; + color: var(--wxex-text-muted) !important; + font-size: 11px !important; +} +@media (max-width: 900px) { + .agent-hub-workspace { + padding: 24px; + } + .agent-hub-grid { + grid-template-columns: 1fr; + } + .agent-hub-qr-panel { + flex-direction: column; + text-align: center; + } + .agent-hub-capability-card { + width: 100%; + } +} + +.ai-vision-test { + display: grid; + gap: 16px; +} + +.ai-vision-test > header, +.ai-vision-test > footer, +.ai-vision-model { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; +} + +.ai-vision-test h2, +.ai-vision-test h3, +.ai-vision-test p { + margin: 0; +} + +.ai-vision-test h2 { + color: #202724; + font-size: 15px; +} + +.ai-vision-test header h3 { + margin-top: 12px; + color: #35403b; + font-size: 13px; +} + +.ai-vision-test header p, +.ai-vision-model, +.ai-vision-upload small { + margin-top: 4px; + color: #66706b; + font-size: 12px; +} + +.ai-vision-capability { + border-radius: 999px; + padding: 5px 9px; + background: #f1f3f2; + color: #66706b; + white-space: nowrap; + font-size: 12px; +} + +.ai-vision-capability.supported { + background: #eaf5f1; + color: #2e8b68; +} + +.ai-vision-model { + justify-content: flex-start; + margin: 0; +} + +.ai-vision-upload { + display: flex; + min-height: 112px; + align-items: center; + justify-content: center; + gap: 14px; + border: 1px dashed #bfc9c4; + border-radius: 10px; + padding: 14px; + background: #f7f9f8; + color: #35403b; + text-align: center; + cursor: pointer; +} + +.ai-vision-upload:hover { + border-color: #247a63; + background: #f2f8f5; +} + +.ai-vision-upload input { + display: none; +} + +.ai-vision-upload.has-image { + justify-content: flex-start; + text-align: left; +} + +.ai-vision-upload img { + width: 112px; + height: 82px; + flex: 0 0 auto; + border-radius: 8px; + object-fit: cover; +} + +.ai-vision-upload strong, +.ai-vision-upload small { + display: block; +} + +.ai-vision-prompt { + display: grid; + gap: 7px; + color: #46514c; + font-size: 12px; + font-weight: 600; +} + +.ai-vision-prompt textarea { + width: 100%; + border: 1px solid #d5ddda; + border-radius: 8px; + outline: none; + padding: 10px; + resize: vertical; + background: #f4f7f5; + color: #202724; + font: 13px/1.6 var(--wxex-font); +} + +.ai-vision-prompt textarea:focus { + border-color: #247a63; + box-shadow: 0 0 0 2px rgba(36, 122, 99, 0.08); +} + +.ai-vision-privacy { + color: #66706b; + font-size: 12px; + line-height: 1.6; +} + +.ai-vision-error { + border-left: 3px solid #c85a5a; + padding: 9px 11px; + background: #fff2f2; + color: #a84444; + font-size: 12px; +} + +.ai-vision-result { + display: grid; + gap: 12px; + border: 1px solid #dce7e2; + border-radius: 9px; + padding: 14px; + background: #f7faf9; +} + +.ai-vision-result dl { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 12px; + margin: 0; +} + +.ai-vision-result dt { + color: #929a96; + font-size: 11px; +} + +.ai-vision-result dd { + margin: 4px 0 0; + color: #35403b; + font-size: 12px; + font-weight: 600; +} + +.ai-vision-result > p { + white-space: pre-wrap; + color: #3d4742; + font-size: 13px; + line-height: 1.7; +} + +.ai-vision-test > footer { + justify-content: flex-end; +} + +.ai-vision-test > footer button { + min-height: 34px; + border: 1px solid #d5ddda; + border-radius: 7px; + padding: 0 13px; + background: #fff; + color: #46514c; + cursor: pointer; +} + +.ai-vision-test > footer button:disabled { + cursor: not-allowed; + opacity: 0.5; +} + +.report-density-options button:disabled:hover { + border-color: var(--wxex-border); + background: var(--wxex-bg-elevated); + color: var(--wxex-text-muted); +} + +.report-density-options button.active:disabled { + border-color: var(--wxex-brand); + background: var(--wxex-brand-soft); + color: var(--wxex-brand); + opacity: 1; + cursor: default; +} + +.report-history-sidebar { + display: flex; + min-width: 0; + min-height: 0; + height: 100%; + flex-direction: column; + overflow: hidden; + border-right: 1px solid var(--wxex-border); + background: var(--wxex-bg-sidebar); +} + +.report-history-header { + display: flex; + flex: 0 0 auto; + align-items: flex-start; + justify-content: space-between; + gap: 12px; + padding: 18px 16px 12px; + border-bottom: 1px solid var(--wxex-border); +} + +.report-history-header h2, +.report-settings-panel header h2, +.report-viewer-header h1 { + margin: 0; + color: var(--wxex-text-primary); +} + +.report-history-header h2 { + font: 700 18px/24px var(--wxex-font); +} + +.report-history-header p, +.report-settings-panel header p, +.report-viewer-header p { + margin: 4px 0 0; + color: var(--wxex-text-secondary); + font: 12px/18px var(--wxex-font); +} + +.report-history-header > span { + color: var(--wxex-text-muted); + font: 12px/18px var(--wxex-font); +} + +.report-history-search { + display: flex; + flex: 0 0 auto; + align-items: center; + gap: 8px; + margin: 12px 14px 8px; + padding: 0 10px; + height: 36px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); + color: var(--wxex-text-muted); +} + +.report-history-search svg { + width: 16px; + height: 16px; +} + +.report-history-search path, +.report-history-search circle { + fill: none; + stroke: currentColor; + stroke-width: 1.8; + stroke-linecap: round; + stroke-linejoin: round; +} + +.report-history-search input { + min-width: 0; + flex: 1; + border: 0; + outline: 0; + background: transparent; + color: var(--wxex-text-primary); + font: 13px/18px var(--wxex-font); +} + +.report-history-create { + flex: 0 0 auto; + height: 36px; + margin: 0 14px 12px; + border: 1px solid var(--wxex-brand); + border-radius: var(--wxex-radius-md); + background: var(--wxex-brand); + color: #fff; + cursor: pointer; + font: 700 13px/18px var(--wxex-font); +} + +.report-history-list { + flex: 1 1 auto; + min-height: 0; + overflow-x: hidden; + overflow-y: auto; + padding: 0 10px 12px; +} + diff --git a/src/renderer/src/styles/reports-templates.scss b/src/renderer/src/styles/reports-templates.scss new file mode 100644 index 0000000..1aca12a --- /dev/null +++ b/src/renderer/src/styles/reports-templates.scss @@ -0,0 +1,821 @@ +@media (max-width: 1100px) { + .api-center-layout { + grid-template-columns: minmax(0, 1fr) 280px; + } + .api-main-scroll { + padding: 18px; + } + .api-header-actions { + max-width: 260px; + justify-content: flex-end; + } + .api-endpoint-head, + .api-endpoint-row { + grid-template-columns: 56px minmax(110px, 1fr) minmax(100px, 1fr) 78px; + gap: 7px; + padding: 10px; + } + .api-flow { + overflow-x: auto; + justify-content: flex-start; + } +} + +.report-history-list-title { + padding: 4px 4px 8px; + color: var(--wxex-text-secondary); + font: 700 13px/18px var(--wxex-font); +} + +.report-history-group { + margin: 0 0 10px; +} + +.report-history-group h3 { + margin: 0; + padding: 6px 4px; + color: var(--wxex-text-muted); + font: 700 12px/16px var(--wxex-font); +} + +.report-history-item { + position: relative; + display: flex; + width: 100%; + min-width: 0; + box-sizing: border-box; + gap: 10px; + padding: 10px 54px 10px 12px; + border: 0; + border-radius: var(--wxex-radius-md); + background: transparent; + color: var(--wxex-text-primary); + text-align: left; + cursor: pointer; + font-family: var(--wxex-font); +} + +.report-history-item:hover { + background: rgba(255, 255, 255, 0.62); +} + +.report-history-item.active { + background: var(--wxex-brand-soft); + color: var(--wxex-brand); +} + +.report-history-item.active::before { + position: absolute; + left: 0; + top: 8px; + bottom: 8px; + width: 3px; + border-radius: 4px; + background: var(--wxex-brand); + content: ''; +} + +.report-history-avatar { + display: grid; + width: 36px; + height: 36px; + flex: 0 0 auto; + place-items: center; + overflow: hidden; + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); + color: var(--wxex-brand); + font: 700 14px/1 var(--wxex-font); +} + +.report-history-avatar img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.report-history-text { + display: grid; + flex: 1 1 auto; + min-width: 0; + gap: 2px; +} + +.report-history-text b, +.report-history-text small, +.report-history-text em { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.report-history-text b { + color: inherit; + font: 600 13px/18px var(--wxex-font); +} + +.report-history-text small, +.report-history-text em { + color: var(--wxex-text-muted); + font: normal 12px/16px var(--wxex-font); +} + +.report-history-delete { + position: absolute; + right: 10px; + top: 50%; + display: grid; + width: 38px; + height: 26px; + place-items: center; + border: 1px solid rgba(198, 72, 72, 0.22); + border-radius: var(--wxex-radius-sm); + background: rgba(198, 72, 72, 0.06); + color: #a64242; + cursor: pointer; + font: 600 12px/16px var(--wxex-font); + opacity: 0; + transform: translateY(-50%); + transition: opacity 0.12s ease; +} + +.report-history-item:hover .report-history-delete, +.report-history-delete:focus { + opacity: 1; +} + +.report-history-empty { + display: grid; + gap: 10px; + padding: 18px 8px; + color: var(--wxex-text-muted); + font: 13px/18px var(--wxex-font); +} + +.report-history-empty button, +.report-center-empty button { + justify-self: start; + min-height: 32px; + padding: 0 12px; + border: 1px solid var(--wxex-brand); + border-radius: var(--wxex-radius-md); + background: var(--wxex-brand); + color: #fff; + cursor: pointer; + font: 600 13px/18px var(--wxex-font); +} + +.report-history-account { + flex: 0 0 auto; + padding: 12px; + border-top: 1px solid var(--wxex-border); +} + +.report-delete-confirm { + position: fixed; + inset: 0; + z-index: 30; + display: grid; + place-items: center; + background: rgba(32, 39, 36, 0.28); +} + +.report-delete-confirm-card { + display: grid; + width: min(360px, calc(100vw - 48px)); + gap: 12px; + padding: 18px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-lg); + background: var(--wxex-bg-main); + box-shadow: var(--wxex-shadow-popover); +} + +.report-delete-confirm-card h2 { + margin: 0; + color: var(--wxex-text-primary); + font: 700 18px/24px var(--wxex-font); +} + +.report-delete-confirm-card p { + margin: 0; + color: var(--wxex-text-secondary); + font: 13px/20px var(--wxex-font); +} + +.report-delete-confirm-card > div { + display: flex; + justify-content: flex-end; + gap: 8px; +} + +.report-delete-confirm-card button { + min-height: 32px; + padding: 0 14px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); + color: var(--wxex-text-primary); + cursor: pointer; + font: 600 13px/18px var(--wxex-font); +} + +.report-delete-confirm-card button.danger { + border-color: #a64242; + background: #a64242; + color: #fff; +} + +.report-delete-error { + color: #a64242 !important; +} + +.report-viewer { + display: flex; + min-width: 0; + min-height: 0; + height: 100%; + flex-direction: column; + overflow: hidden; + background: #f2f1ee; +} + +.report-viewer-header { + display: flex; + flex: 0 0 auto; + align-items: flex-start; + justify-content: space-between; + gap: 16px; + padding: 18px 22px 12px; + border-bottom: 1px solid var(--wxex-border); + background: var(--wxex-bg-main); +} + +.report-viewer-header h1 { + font: 700 20px/27px var(--wxex-font); +} + +.report-viewer-toolbar { + display: flex; + flex: 0 0 auto; + align-items: center; + gap: 8px; +} + +.report-viewer-toolbar button, +.report-zoom-bar button, +.report-more-popover button, +.report-settings-section button { + min-height: 32px; + padding: 0 12px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); + color: var(--wxex-text-primary); + cursor: pointer; + font: 600 13px/18px var(--wxex-font); +} + +.report-viewer-toolbar button.primary { + border-color: var(--wxex-ai); + background: var(--wxex-ai); + color: #fff; +} + +.report-viewer-toolbar button:disabled { + color: var(--wxex-text-muted); + cursor: not-allowed; + opacity: 0.72; +} + +.report-more-menu { + position: relative; +} + +.report-more-popover { + position: absolute; + top: 38px; + right: 0; + z-index: 8; + min-width: 128px; + padding: 6px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-md); + background: var(--wxex-bg-elevated); + box-shadow: var(--wxex-shadow-popover); +} + +.report-more-popover button { + width: 100%; + border: 0; + text-align: left; +} + +.report-viewer-status { + flex: 0 0 auto; + padding: 8px 22px; + border-bottom: 1px solid var(--wxex-border); + background: var(--wxex-ai-soft); + color: var(--wxex-ai); + font: 12px/18px var(--wxex-font); +} + +.report-viewer-stage { + display: block; + flex: 1 1 auto; + min-height: 0; + min-width: 0; + overflow: auto; + padding: 22px; +} + +.report-canvas { + width: max-content; + margin: 0 auto; + padding: 0; + background: #fff; + box-shadow: 0 8px 24px rgba(32, 39, 36, 0.14); +} + +.report-canvas img { + display: block; + max-width: none; + height: auto; +} + +.report-zoom-bar { + display: flex; + flex: 0 0 auto; + align-items: center; + justify-content: center; + gap: 8px; + min-height: 48px; + border-top: 1px solid var(--wxex-border); + background: var(--wxex-bg-main); +} + +.report-zoom-bar span { + min-width: 48px; + color: var(--wxex-text-secondary); + text-align: center; + font: 12px/18px var(--wxex-font); +} + +.report-center-empty { + display: grid; + align-self: center; + justify-self: center; + max-width: 360px; + gap: 12px; + margin: auto; + color: var(--wxex-text-secondary); + text-align: center; +} + +.report-center-empty-icon { + display: grid; + width: 54px; + height: 54px; + place-items: center; + justify-self: center; + border: 1px solid rgba(104, 110, 220, 0.18); + border-radius: 18px; + background: var(--wxex-ai-soft); + color: var(--wxex-ai); +} + +.report-center-empty-icon svg { + width: 28px; + height: 28px; +} + +.report-center-empty-icon path { + fill: currentColor; +} + +.report-center-empty h2 { + margin: 0; + color: var(--wxex-text-primary); + font: 700 18px/24px var(--wxex-font); +} + +.report-center-empty p { + margin: 0; + font: 13px/20px var(--wxex-font); +} + +.report-center-empty button { + justify-self: center; +} + +.report-settings-panel { + display: flex; + min-width: 0; + min-height: 0; + height: 100%; + flex-direction: column; + overflow-y: auto; + border-left: 1px solid var(--wxex-border); + background: #f7f9f8; +} + +.report-settings-panel header { + flex: 0 0 auto; + padding: 20px 18px 14px; + border-bottom: 1px solid var(--wxex-border); +} + +.report-settings-panel header h2 { + font: 700 16px/22px var(--wxex-font); +} + +.report-settings-section { + margin: 0; + padding: 16px 18px; + border-bottom: 1px solid var(--wxex-border); +} + +.report-settings-section h3 { + margin: 0 0 8px; + color: var(--wxex-text-primary); + font: 700 14px/20px var(--wxex-font); +} + +.report-settings-section p, +.report-settings-section code { + margin: 0 0 10px; + color: var(--wxex-text-secondary); + font: 12px/18px var(--wxex-font); +} + +.report-settings-section code { + display: block; + max-width: 100%; + overflow-wrap: anywhere; + padding: 8px; + border-radius: var(--wxex-radius-sm); + background: var(--wxex-bg-elevated); +} + +.report-settings-section.muted { + color: var(--wxex-text-muted); +} + +.report-export-list { + display: grid; + gap: 8px; + margin-bottom: 10px; +} + +.report-export-list div { + display: flex; + justify-content: space-between; + gap: 12px; + color: var(--wxex-text-secondary); + font: 12px/18px var(--wxex-font); +} + +.report-export-list b { + min-width: 0; + color: var(--wxex-text-primary); + font-weight: 600; + overflow-wrap: anywhere; + text-align: right; +} + +.report-generation-log { + display: grid; + gap: 10px; + margin: 0; + padding: 0; + list-style: none; +} + +.report-generation-log li { + display: grid; + grid-template-columns: 18px minmax(0, 1fr); + gap: 8px; + color: var(--wxex-text-secondary); + font: 12px/18px var(--wxex-font); +} + +.report-generation-log li > span { + color: var(--wxex-brand); + font-weight: 700; +} + +.report-generation-log b, +.report-generation-log time, +.report-generation-log small { + display: block; +} + +.report-generation-log b { + color: var(--wxex-text-primary); + font-weight: 600; +} + +.report-generation-log time { + color: var(--wxex-text-muted); + font-size: 11px; +} + +.report-generation-log small { + color: var(--wxex-text-secondary); + font: 600 11px/16px var(--wxex-font); +} + +@media (max-width: 1120px) { + .report-center-page { + grid-template-columns: 268px minmax(360px, 1fr) 280px; + } + + .report-viewer-header { + flex-direction: column; + } +} + +/* ============================================================ */ +/* 日报模板选择器 + 预览器 */ +/* ============================================================ */ +.report-section-desc { + margin: 0 0 12px; + color: var(--wxex-text-secondary); + font-size: 12px; + line-height: 1.6; +} + +.report-template-list { + display: grid; + gap: 10px; +} + +.report-template-item { + display: flex; + align-items: center; + gap: 12px; + padding: 12px 14px; + border: 1.5px solid var(--wxex-border); + border-radius: 12px; + background: #fff; + transition: + border-color 0.2s, + background 0.2s; +} + +.report-template-item.active { + border-color: var(--wxex-primary, #07c160); + background: #f0fbf3; +} + +.report-template-item.disabled { + opacity: 0.6; + cursor: not-allowed; +} + +.report-template-item > label { + flex: 1; + display: flex; + align-items: center; + gap: 10px; + cursor: pointer; + min-width: 0; +} + +.report-template-item input[type='radio'] { + accent-color: var(--wxex-primary, #07c160); +} + +.report-template-body { + flex: 1; + min-width: 0; +} + +.report-template-title { + font-size: 14px; + font-weight: 700; + color: var(--wxex-text-primary, #1f2933); +} + +.report-template-tagline { + margin-top: 4px; + font-size: 12px; + color: var(--wxex-text-secondary, #485465); + line-height: 1.5; +} + +.report-template-preview-btn { + padding: 6px 12px; + font-size: 12px; + font-weight: 600; + border-radius: 8px; + border: 1px solid var(--wxex-border); + background: #fff; + color: var(--wxex-text-primary, #1f2933); + cursor: pointer; + transition: + background 0.2s, + color 0.2s, + border-color 0.2s; +} + +.report-template-preview-btn:hover { + background: var(--wxex-primary, #07c160); + color: #fff; + border-color: var(--wxex-primary, #07c160); +} + +/* 预览遮罩 */ +.report-template-preview-mask { + position: fixed; + inset: 0; + background: rgba(15, 23, 42, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 999; + padding: 20px; +} + +.report-template-preview-card { + background: #f3f5f7; + border-radius: 18px; + padding: 18px; + width: min(380px, 100%); + max-height: 90vh; + overflow-y: auto; + box-shadow: 0 16px 60px rgba(15, 23, 42, 0.25); +} + +.report-template-preview-card h4 { + margin: 0 0 6px; + font-size: 17px; + font-weight: 800; +} + +.report-template-preview-card p.muted { + margin: 0 0 14px; + font-size: 12px; + color: var(--wxex-text-secondary, #485465); + line-height: 1.5; +} + +.report-template-preview-frame { + display: grid; + gap: 8px; + background: #fff; + border-radius: 14px; + padding: 12px; + border: 1px solid var(--wxex-border); +} + +.fake-card { + background: #f7faf9; + border-radius: 10px; + padding: 10px 12px; +} + +.fake-hero { + background: linear-gradient(135deg, #edf9f1 0%, #f7fbf8 100%); +} + +.fake-title { + font-size: 14px; + font-weight: 800; + color: #076c39; +} + +.fake-sub { + margin-top: 2px; + font-size: 11px; + color: #485465; +} + +.fake-section { + display: flex; + align-items: center; + gap: 8px; +} + +.fake-bar { + width: 4px; + height: 14px; + border-radius: 2px; + background: var(--wxex-primary, #07c160); +} + +.fake-section-title { + font-size: 12px; + font-weight: 700; + color: #1f2933; +} + +.report-template-preview-close { + margin-top: 14px; + width: 100%; + padding: 10px; + border-radius: 10px; + border: none; + background: var(--wxex-primary, #07c160); + color: #fff; + font-weight: 700; + cursor: pointer; +} + +.settings-auto-login-card { + padding: 18px 20px; +} +.settings-auto-login-card label { + display: flex; + align-items: center; + justify-content: space-between; + gap: 20px; + cursor: pointer; +} +.settings-auto-login-card label > span { + display: grid; + gap: 4px; +} +.settings-auto-login-card b { + color: var(--wxex-text-primary); + font: 700 13px/19px var(--wxex-font); +} +.settings-auto-login-card small { + color: var(--wxex-text-secondary); + font: 12px/18px var(--wxex-font); +} +.settings-auto-login-card input { + width: 18px; + height: 18px; + accent-color: var(--wxex-brand); +} +.settings-recall-card { + padding: 18px 20px; +} +.settings-recall-grid { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(220px, 0.8fr); + gap: 18px; + align-items: center; +} +.settings-recall-option { + display: flex; + align-items: center; + justify-content: space-between; + gap: 20px; + min-width: 0; + cursor: pointer; +} +.settings-recall-option span { + display: grid; + gap: 4px; +} +.settings-recall-option b { + color: var(--wxex-text-primary); + font: 700 13px/19px var(--wxex-font); +} +.settings-recall-option small { + color: var(--wxex-text-secondary); + font: 12px/18px var(--wxex-font); +} +.settings-recall-option input { + width: 18px; + height: 18px; + flex: 0 0 auto; + accent-color: var(--wxex-brand); +} +.settings-recall-notice { + display: grid; + gap: 3px; + padding-left: 14px; + border-left: 2px solid #e5b45f; + color: #765326; + font: 12px/18px var(--wxex-font); +} +.settings-recall-notice strong { + font-weight: 700; +} +.settings-recall-notice span { + color: #8a6a3e; +} +.api-upload-test-row { + display: flex; + align-items: center; + gap: 10px; + margin: 10px 0; +} +.api-upload-test-row button { + min-height: 32px; + padding: 0 12px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-sm); + background: var(--wxex-bg-elevated); + color: var(--wxex-text-primary); + cursor: pointer; + font: 600 12px/18px var(--wxex-font); +} +.api-upload-test-row span { + color: var(--wxex-text-muted); + font: 11px/17px var(--wxex-font); +} + diff --git a/src/renderer/src/styles/rich-message.scss b/src/renderer/src/styles/rich-message.scss new file mode 100644 index 0000000..ec96e2f --- /dev/null +++ b/src/renderer/src/styles/rich-message.scss @@ -0,0 +1,331 @@ +/* Voice Player */ +.voice-message { + cursor: pointer; + user-select: none; +} + +.voice-loading { + opacity: 0.6; +} + +.voice-error { + opacity: 1; +} + +.voice-loading-text { + font-size: 12px; + color: var(--wxex-text-muted); +} + +.voice-error-text { + color: var(--wxex-text-secondary); +} + +.voice-duration { + font-size: 12px; + margin-left: 4px; + min-width: 32px; +} + +.voice-icon.playing { + background: rgba(36, 122, 99, 0.18); +} + +/* Rich Message Bubbles */ +.location-message { + display: flex; + align-items: center; + gap: 10px; + cursor: pointer; + min-width: 180px; + max-width: 280px; + + .location-icon { + box-sizing: border-box; + min-width: 34px; + padding: 4px 6px; + border-radius: var(--wxex-radius-sm); + background: var(--wxex-brand-soft); + color: var(--wxex-brand); + font-size: 12px; + font-weight: 600; + flex-shrink: 0; + } + + .location-info { + flex: 1; + overflow: hidden; + } + + .location-name { + font-weight: 500; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .location-label { + font-size: 12px; + color: var(--wxex-text-secondary); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .location-coords { + font-size: 11px; + color: var(--wxex-text-muted); + margin-top: 2px; + } +} + +.wechat-message-row.mine { + .location-message { + flex-direction: row-reverse; + } +} + +.card-message { + display: flex; + align-items: center; + gap: 10px; + min-width: 160px; + max-width: 240px; +} + +.card-avatar { + width: 40px; + height: 40px; + border-radius: 6px; + background: #07c160; + color: #fff; + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; + font-weight: 500; + flex-shrink: 0; +} + +.card-info { + flex: 1; + overflow: hidden; +} + +.card-nickname { + font-weight: 500; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.card-username { + font-size: 12px; + color: #666; + cursor: pointer; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + &:hover { + color: #07c160; + } +} + +.share-message { + display: flex; + flex-direction: column; + gap: 4px; + cursor: pointer; + min-width: 180px; + max-width: 280px; +} + +.share-appname { + font-size: 11px; + color: #999; +} + +.share-title { + font-weight: 500; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.share-desc { + font-size: 12px; + color: #666; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.share-url { + font-size: 11px; + color: #999; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.mini-program-message { + width: min(280px, 48vw); + overflow: hidden; + color: var(--wxex-text-primary); +} + +.mini-program-title { + margin-bottom: 8px; + font-size: 14px; + line-height: 20px; + word-break: break-word; +} + +.mini-program-description { + margin: -4px 0 8px; + color: var(--wxex-text-secondary); + font-size: 12px; + line-height: 18px; +} + +.mini-program-preview { + .image-bubble, + .image-content { + width: 100%; + max-width: 100%; + max-height: 220px; + border-radius: 4px; + } + + .image-content { + object-fit: cover; + } + + .image-actions { + display: none; + } + + .image-content.image-fallback { + width: 64px; + height: 64px; + margin: 28px auto; + border-radius: 8px; + object-fit: cover; + } +} + +.mini-program-inline-image { + display: block; + width: 100%; + max-height: 220px; + border-radius: 4px; + object-fit: cover; + cursor: zoom-in; +} + +.mini-program-icon { + display: block; + width: 52px; + height: 52px; + margin: 8px 0; + border-radius: 6px; + object-fit: cover; +} + +.mini-program-footer { + display: flex; + align-items: center; + gap: 5px; + margin-top: 8px; + padding-top: 7px; + border-top: 1px solid var(--wxex-border); + color: var(--wxex-text-muted); + font-size: 11px; + line-height: 16px; +} + +.red-packet-message { + width: min(280px, 48vw); + overflow: hidden; + border-radius: 6px; + background: #fa9d3b; + color: #fff; + + &.is-clickable { + cursor: pointer; + } +} + +.red-packet-main { + display: flex; + align-items: center; + gap: 12px; + min-height: 72px; + padding: 12px 14px; +} + +.red-packet-icon { + display: grid; + width: 36px; + height: 36px; + flex: 0 0 36px; + place-items: center; + border: 2px solid rgba(255, 239, 170, 0.92); + border-radius: 50%; + color: #fff1a8; + font-size: 18px; + font-weight: 700; +} + +.red-packet-copy { + display: flex; + min-width: 0; + flex-direction: column; + gap: 2px; +} + +.red-packet-copy strong { + overflow: hidden; + font-size: 15px; + font-weight: 500; + line-height: 21px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.red-packet-copy small { + color: rgba(255, 255, 255, 0.82); + font-size: 12px; + line-height: 18px; +} + +.red-packet-footer { + padding: 5px 14px; + background: #fff; + color: var(--wxex-text-muted); + font-size: 11px; + line-height: 16px; +} + +.voip-message { + display: flex; + align-items: center; + gap: 8px; + white-space: nowrap; +} + +.voip-icon { + box-sizing: border-box; + padding: 3px 6px; + border-radius: var(--wxex-radius-sm); + background: var(--wxex-brand-soft); + color: var(--wxex-brand); + font-size: 12px; + font-weight: 600; +} + +.voip-status { + font-size: 13px; +} diff --git a/src/renderer/src/styles/search.css b/src/renderer/src/styles/search.scss similarity index 75% rename from src/renderer/src/styles/search.css rename to src/renderer/src/styles/search.scss index 17e5a90..8ca88bf 100644 --- a/src/renderer/src/styles/search.css +++ b/src/renderer/src/styles/search.scss @@ -21,24 +21,21 @@ padding: 14px 22px 12px; border-bottom: 1px solid var(--wxex-border); background: rgba(250, 251, 250, 0.94); -} -.ai-search-header h1, -.ai-search-header p { - margin: 0; -} + h1 { + margin: 0; + color: var(--wxex-text-primary); + font-size: 20px; + font-weight: 700; + line-height: 28px; + } -.ai-search-header h1 { - color: var(--wxex-text-primary); - font-size: 20px; - font-weight: 700; - line-height: 28px; -} - -.ai-search-header p { - color: var(--wxex-text-secondary); - font-size: 12px; - line-height: 18px; + p { + margin: 0; + color: var(--wxex-text-secondary); + font-size: 12px; + line-height: 18px; + } } .ai-search-kicker { @@ -57,28 +54,36 @@ color: var(--wxex-text-secondary); font-size: 12px; line-height: 18px; -} -.ai-search-model-status > span:first-child { - width: 8px; - height: 8px; - flex: 0 0 auto; - border-radius: 50%; - background: var(--wxex-text-muted); -} + > span:first-child { + width: 8px; + height: 8px; + flex: 0 0 auto; + border-radius: 50%; + background: var(--wxex-text-muted); + } -.ai-search-model-status > span.ready { - background: var(--wxex-success); -} + > span { + &.ready { + background: var(--wxex-success); + } -.ai-search-model-status > span.warning { - background: var(--wxex-warning); -} + &.warning { + background: var(--wxex-warning); + } + } -.ai-search-model-status > span:nth-child(2) { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + > span:nth-child(2) { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + button { + padding: 5px 8px; + color: var(--wxex-brand); + white-space: nowrap; + } } .ai-search-model-status button, @@ -93,12 +98,6 @@ font: inherit; } -.ai-search-model-status button { - padding: 5px 8px; - color: var(--wxex-brand); - white-space: nowrap; -} - .ai-search-grid { display: grid; flex: 1; @@ -134,25 +133,26 @@ justify-content: space-between; gap: 10px; margin-bottom: 14px; -} -.ai-search-panel-heading div { - display: flex; - flex-direction: column; - gap: 2px; -} + div { + display: flex; + flex-direction: column; + gap: 2px; + } -.ai-search-panel-heading span:first-child { - color: var(--wxex-text-muted); - font-size: 10px; - line-height: 15px; -} + span:first-child { + color: var(--wxex-text-muted); + font-size: 10px; + line-height: 15px; + } + + strong { + color: var(--wxex-text-primary); + font-size: 14px; + font-weight: 700; + line-height: 20px; + } -.ai-search-panel-heading strong { - color: var(--wxex-text-primary); - font-size: 14px; - font-weight: 700; - line-height: 20px; } .ai-search-local-badge, @@ -179,33 +179,17 @@ padding: 3px; border-radius: var(--wxex-radius-sm); background: var(--wxex-bg-elevated); -} -.ai-search-scope-toggle button, -.ai-search-range-grid button, -.ai-search-history button { - border: 0; - border-radius: var(--wxex-radius-sm); - background: transparent; - color: var(--wxex-text-secondary); - cursor: pointer; - font: inherit; -} + button { + padding: 7px 4px; + font-size: 11px; -.ai-search-scope-toggle button { - padding: 7px 4px; - font-size: 11px; -} - -.ai-search-scope-toggle button.active, -.ai-search-range-grid button.active { - background: var(--wxex-brand); - color: var(--wxex-brand); - font-weight: 700; -} - -.ai-search-scope-toggle button.active { - color: #fff; + &.active { + background: var(--wxex-brand); + color: #fff; + font-weight: 700; + } + } } .ai-search-scope-help { @@ -235,24 +219,24 @@ border: 1px solid var(--wxex-border); border-radius: var(--wxex-radius-sm); background: var(--wxex-bg-elevated); -} -.ai-search-filter-input svg { - width: 15px; - height: 15px; - flex: 0 0 auto; - color: var(--wxex-text-muted); -} + svg { + width: 15px; + height: 15px; + flex: 0 0 auto; + color: var(--wxex-text-muted); + } -.ai-search-filter-input input { - width: 100%; - min-width: 0; - border: 0; - outline: 0; - background: transparent; - color: var(--wxex-text-primary); - font: inherit; - font-size: 11px; + input { + width: 100%; + min-width: 0; + border: 0; + outline: 0; + background: transparent; + color: var(--wxex-text-primary); + font: inherit; + font-size: 11px; + } } .ai-search-contact-list { @@ -277,11 +261,11 @@ cursor: pointer; font: inherit; text-align: left; -} -.ai-search-contact:hover, -.ai-search-contact.active { - background: var(--wxex-brand-soft); + &:hover, + &.active { + background: var(--wxex-brand-soft); + } } .ai-search-contact-avatar { @@ -296,12 +280,12 @@ color: var(--wxex-brand); font-size: 12px; font-weight: 700; -} -.ai-search-contact-avatar img { - width: 100%; - height: 100%; - object-fit: cover; + img { + width: 100%; + height: 100%; + object-fit: cover; + } } .ai-search-contact > span:last-child { @@ -337,6 +321,31 @@ background: var(--wxex-bg-elevated); grid-template-columns: 1fr 1fr; margin-bottom: 16px; + + button { + border: 0; + border-radius: var(--wxex-radius-sm); + background: transparent; + color: var(--wxex-text-secondary); + cursor: pointer; + font: inherit; + min-height: 34px; + padding: 7px 4px; + border: 1px solid transparent; + font-size: 11px; + + &:hover { + border-color: var(--wxex-brand); + color: var(--wxex-brand); + } + + &.active { + border-color: var(--wxex-brand); + background: var(--wxex-brand); + color: #fff; + box-shadow: 0 1px 3px rgba(34, 89, 74, 0.2); + } + } } .ai-search-field-heading { @@ -356,26 +365,6 @@ font-weight: 700; } -.ai-search-range-grid button { - min-height: 34px; - padding: 7px 4px; - border: 1px solid transparent; - font-size: 11px; -} - -.ai-search-range-grid button:hover { - border-color: var(--wxex-brand); - color: var(--wxex-brand); -} - -.ai-search-range-grid button.active, -.ai-search-range-grid button.active:hover { - border-color: var(--wxex-brand); - background: var(--wxex-brand); - color: #fff; - box-shadow: 0 1px 3px rgba(34, 89, 74, 0.2); -} - .ai-search-filter-note { display: flex; gap: 6px; @@ -386,28 +375,34 @@ color: var(--wxex-text-secondary); font-size: 10px; line-height: 16px; -} -.ai-search-filter-note span { - color: var(--wxex-success); + span { + color: var(--wxex-success); + } } .ai-search-history { margin-top: 18px; -} -.ai-search-history button { - min-width: 0; - padding: 5px 0; - overflow: hidden; - text-align: left; - text-overflow: ellipsis; - white-space: nowrap; - font-size: 10px; -} + button { + min-width: 0; + padding: 5px 0; + overflow: hidden; + border: 0; + border-radius: var(--wxex-radius-sm); + background: transparent; + color: var(--wxex-text-secondary); + cursor: pointer; + font: inherit; + text-align: left; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 10px; -.ai-search-history button:hover { - color: var(--wxex-brand); + &:hover { + color: var(--wxex-brand); + } + } } .ai-search-history-item { @@ -415,10 +410,10 @@ align-items: center; gap: 5px; min-width: 0; -} -.ai-search-history-item > button:first-child { - flex: 1; + > button:first-child { + flex: 1; + } } .ai-search-history-delete { @@ -434,11 +429,11 @@ font-size: 16px !important; line-height: 18px; text-align: center !important; -} -.ai-search-history-delete:hover { - background: var(--wxex-brand-soft); - color: var(--wxex-danger, #b34d46) !important; + &:hover { + background: var(--wxex-brand-soft); + color: var(--wxex-danger, #b34d46) !important; + } } .ai-search-main { @@ -468,6 +463,22 @@ padding: 48px 24px; flex-direction: column; text-align: center; + + h2 { + margin: 7px 0 8px; + color: var(--wxex-text-primary); + font-size: 18px; + font-weight: 700; + line-height: 26px; + } + + p { + max-width: 440px; + margin: 0; + color: var(--wxex-text-secondary); + font-size: 12px; + line-height: 20px; + } } .ai-search-empty-mark { @@ -482,24 +493,18 @@ font-size: 28px; } -.ai-search-empty h2, -.ai-search-loading h2, -.ai-search-insufficient h2 { - margin: 7px 0 8px; - color: var(--wxex-text-primary); - font-size: 18px; - font-weight: 700; - line-height: 26px; -} +.ai-search-insufficient { + button { + margin-top: 20px; + padding: 8px 12px; + font-size: 11px; -.ai-search-empty p, -.ai-search-loading p, -.ai-search-insufficient p { - max-width: 440px; - margin: 0; - color: var(--wxex-text-secondary); - font-size: 12px; - line-height: 20px; + &.primary { + border-color: var(--wxex-brand); + background: var(--wxex-brand); + color: #fff; + } + } } .ai-search-prompts { @@ -508,22 +513,22 @@ justify-content: center; gap: 7px; margin-top: 22px; -} -.ai-search-prompts button { - padding: 7px 10px; - border: 1px solid var(--wxex-border); - border-radius: 999px; - background: var(--wxex-bg-elevated); - color: var(--wxex-text-secondary); - cursor: pointer; - font: inherit; - font-size: 11px; -} + button { + padding: 7px 10px; + border: 1px solid var(--wxex-border); + border-radius: 999px; + background: var(--wxex-bg-elevated); + color: var(--wxex-text-secondary); + cursor: pointer; + font: inherit; + font-size: 11px; -.ai-search-prompts button:hover { - border-color: var(--wxex-brand); - color: var(--wxex-brand); + &:hover { + border-color: var(--wxex-brand); + color: var(--wxex-brand); + } + } } .ai-search-spinner { @@ -550,14 +555,15 @@ color: var(--wxex-text-muted); font-size: 11px; text-align: left; -} -.ai-search-loading-steps .done { - color: var(--wxex-success); -} -.ai-search-loading-steps .active { - color: var(--wxex-brand); - font-weight: 700; + .done { + color: var(--wxex-success); + } + + .active { + color: var(--wxex-brand); + font-weight: 700; + } } .ai-search-result { @@ -573,21 +579,21 @@ gap: 18px; padding-bottom: 20px; border-bottom: 1px solid var(--wxex-border); -} -.ai-search-result-header h2 { - margin: 6px 0 5px; - color: var(--wxex-text-primary); - font-size: 18px; - font-weight: 700; - line-height: 26px; -} + h2 { + margin: 6px 0 5px; + color: var(--wxex-text-primary); + font-size: 18px; + font-weight: 700; + line-height: 26px; + } -.ai-search-result-header p { - margin: 0; - color: var(--wxex-text-muted); - font-size: 11px; - line-height: 16px; + p { + margin: 0; + color: var(--wxex-text-muted); + font-size: 11px; + line-height: 16px; + } } .ai-search-result-actions { @@ -596,19 +602,17 @@ flex-wrap: wrap; justify-content: flex-end; gap: 6px; -} -.ai-search-result-actions button { - padding: 7px 9px; - font-size: 11px; -} + button { + padding: 7px 9px; + font-size: 11px; -.ai-search-result-actions button.primary, -.ai-search-composer button.primary, -.ai-search-insufficient button.primary { - border-color: var(--wxex-brand); - background: var(--wxex-brand); - color: #fff; + &.primary { + border-color: var(--wxex-brand); + background: var(--wxex-brand); + color: #fff; + } + } } .ai-search-summary-block { @@ -656,12 +660,6 @@ font-weight: 700; } -.ai-search-insufficient button { - margin-top: 20px; - padding: 8px 12px; - font-size: 11px; -} - .ai-search-composer { padding: 12px 18px 14px; border-top: 1px solid var(--wxex-border); @@ -678,13 +676,16 @@ line-height: 15px; } -.ai-search-composer-meta strong { - color: var(--wxex-brand); - font-weight: 700; -} -.ai-search-composer-meta em { - font-style: normal; - color: var(--wxex-text-secondary); +.ai-search-composer-meta { + strong { + color: var(--wxex-brand); + font-weight: 700; + } + + em { + font-style: normal; + color: var(--wxex-text-secondary); + } } .ai-search-composer-row { @@ -692,41 +693,50 @@ align-items: flex-end; gap: 8px; margin-top: 7px; -} -.ai-search-composer textarea { - width: 100%; - min-width: 0; - resize: none; - padding: 9px 10px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-sm); - outline: 0; - background: var(--wxex-bg-main); - color: var(--wxex-text-primary); - font: inherit; - font-size: 12px; - line-height: 18px; -} + textarea { + width: 100%; + min-width: 0; + resize: none; + padding: 9px 10px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-sm); + outline: 0; + background: var(--wxex-bg-main); + color: var(--wxex-text-primary); + font: inherit; + font-size: 12px; + line-height: 18px; -.ai-search-composer textarea:focus { - border-color: var(--wxex-brand); -} -.ai-search-composer button { - display: flex; - align-items: center; - gap: 8px; - padding: 9px 13px; - white-space: nowrap; - font-size: 11px; -} -.ai-search-composer button span { - font-size: 16px; - line-height: 12px; -} -.ai-search-composer button:disabled { - opacity: 0.6; - cursor: wait; + &:focus { + border-color: var(--wxex-brand); + } + } + + button { + display: flex; + align-items: center; + gap: 8px; + padding: 9px 13px; + white-space: nowrap; + font-size: 11px; + + span { + font-size: 16px; + line-height: 12px; + } + + &.primary { + border-color: var(--wxex-brand); + background: var(--wxex-brand); + color: #fff; + } + + &:disabled { + opacity: 0.6; + cursor: wait; + } + } } .ai-search-composer-foot { justify-content: space-between; diff --git a/src/renderer/src/styles/settings-advanced.css b/src/renderer/src/styles/settings-advanced.css deleted file mode 100644 index 4663c07..0000000 --- a/src/renderer/src/styles/settings-advanced.css +++ /dev/null @@ -1,46 +0,0 @@ -.settings-debug-card { - display: grid; - gap: 14px; -} - -.settings-debug-card > label { - display: flex; - align-items: center; - justify-content: space-between; - gap: 18px; -} - -.settings-debug-card > label > span { - display: grid; - gap: 5px; -} - -.settings-debug-card b { - color: var(--wxex-text-primary); - font-size: 13px; -} - -.settings-debug-card small { - color: var(--wxex-text-secondary); - font-size: 11px; - line-height: 18px; -} - -.settings-debug-actions { - display: flex; - align-items: center; - gap: 10px; - padding-top: 12px; - border-top: 1px solid var(--wxex-border); -} - -.settings-debug-actions button { - padding: 7px 10px; - border: 1px solid var(--wxex-border); - border-radius: var(--wxex-radius-sm); - background: var(--wxex-bg-elevated); - color: var(--wxex-brand); - cursor: pointer; - font: inherit; - font-size: 11px; -} diff --git a/src/renderer/src/styles/settings-advanced.scss b/src/renderer/src/styles/settings-advanced.scss new file mode 100644 index 0000000..ad28dc7 --- /dev/null +++ b/src/renderer/src/styles/settings-advanced.scss @@ -0,0 +1,46 @@ +.settings-debug-card { + display: grid; + gap: 14px; + + > label { + display: flex; + align-items: center; + justify-content: space-between; + gap: 18px; + + > span { + display: grid; + gap: 5px; + } + } + + b { + color: var(--wxex-text-primary); + font-size: 13px; + } + + small { + color: var(--wxex-text-secondary); + font-size: 11px; + line-height: 18px; + } +} + +.settings-debug-actions { + display: flex; + align-items: center; + gap: 10px; + padding-top: 12px; + border-top: 1px solid var(--wxex-border); + + button { + padding: 7px 10px; + border: 1px solid var(--wxex-border); + border-radius: var(--wxex-radius-sm); + background: var(--wxex-bg-elevated); + color: var(--wxex-brand); + cursor: pointer; + font: inherit; + font-size: 11px; + } +} diff --git a/src/renderer/src/styles/settings.scss b/src/renderer/src/styles/settings.scss new file mode 100644 index 0000000..ea4695b --- /dev/null +++ b/src/renderer/src/styles/settings.scss @@ -0,0 +1,1628 @@ +/* API-01 本地 API 中心 */ +.api-center-layout { + display: grid; + grid-template-columns: minmax(0, 1fr) 320px; + width: 100%; + height: 100%; + min-width: 0; + min-height: 0; + overflow: hidden; + background: var(--wxex-bg-main); +} + +/* SETTINGS-01: formal settings workspace. The legacy SettingsPanel remains only as a fallback source. */ +.settings-workspace { + display: flex; + width: 100%; + height: 100%; + min-width: 0; + min-height: 0; + overflow: hidden; + background: #fafbfa; +} + +.settings-page-panel { + display: none; + min-width: 0; + min-height: 0; + flex: 1 1 auto; + + &.active { + display: flex; + } +} +.settings-sidebar { + width: 294px; + flex: 0 0 294px; + min-width: 0; + min-height: 0; + display: flex; + flex-direction: column; + background: #eef2f0; + border-right: 1px solid #dde3e0; + + header { + padding: 22px 20px 16px; + border-bottom: 1px solid #dde3e0; + + h1 { + margin: 0; + color: #202724; + font-size: 20px; + } + + p { + margin: 5px 0 16px; + color: #66706b; + font-size: 12px; + } + } +} +.settings-search { + height: 34px; + display: flex; + align-items: center; + gap: 8px; + padding: 0 10px; + border: 1px solid #dde3e0; + border-radius: 8px; + background: #fff; + color: #66706b; + + input { + min-width: 0; + width: 100%; + border: 0; + outline: 0; + color: #202724; + background: transparent; + font: inherit; + font-size: 12px; + } +} +.settings-sidebar-list { + flex: 1; + min-height: 0; + overflow: auto; + padding: 12px 8px; + + section { + margin: 0 0 18px; + } + + h2 { + margin: 0 12px 6px; + color: #929a96; + font-size: 12px; + font-weight: 500; + } + + button { + position: relative; + display: block; + width: 100%; + border: 0; + padding: 9px 12px; + background: transparent; + color: #39433e; + text-align: left; + font: 600 13px inherit; + cursor: pointer; + border-radius: 8px; + + &.active { + background: #fff; + color: #202724; + + &::before { + content: ''; + position: absolute; + left: 0; + top: 7px; + bottom: 7px; + width: 3px; + border-radius: 0 3px 3px 0; + background: #247a63; + } + } + } +} +.settings-sidebar-account { + flex: 0 0 auto; + padding: 10px; + border-top: 1px solid #dde3e0; +} +.settings-page { + position: relative; + display: flex; + flex: 1; + min-width: 0; + min-height: 0; + flex-direction: column; +} +.settings-page-header { + flex: 0 0 auto; + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: 18px; + padding: 24px 34px; + border-bottom: 1px solid #eef1ef; + background: #fafbfa; + + h1 { + margin: 0; + color: #202724; + font-size: 21px; + } + + p { + margin: 6px 0 0; + color: #66706b; + font-size: 13px; + } +} +.settings-status-badge { + margin-top: 5px; + flex: 0 0 auto; + border-radius: 16px; + padding: 7px 12px; + background: #edf5f1; + color: #2e8b68; + font-size: 12px; + + &::before { + content: '●'; + margin-right: 6px; + font-size: 9px; + } + + &.checking { + background: #eef4f8; + color: #4f7188; + } + + &.warning { + background: #fff6e8; + color: #a56a24; + } + + &.error { + background: #f9eeee; + color: #c85a5a; + } + + &.unavailable { + background: #f1f3f2; + color: #66706b; + } +} +.settings-page-scroll { + flex: 1; + min-height: 0; + overflow-y: auto; + overflow-x: hidden; +} +.settings-page-content { + box-sizing: border-box; + width: min(100%, 860px); + padding: 34px 34px 64px; +} +.settings-privacy-notice { + display: flex; + gap: 14px; + align-items: flex-start; + padding: 17px; + border: 1px solid #bfded3; + border-radius: 10px; + background: #f0f7f4; + color: #36564d; + + svg { + flex: 0 0 24px; + width: 24px; + stroke: #247a63; + fill: none; + stroke-width: 1.8; + } + + strong { + color: #294b41; + font-size: 14px; + } + + p { + margin: 5px 0 0; + color: #66706b; + font-size: 13px; + line-height: 1.6; + } +} +.settings-section-heading { + margin: 30px 0 14px; + color: #3d4742; + font-size: 16px; +} +.settings-card { + border: 1px solid #dde3e0; + border-radius: 10px; + background: #fff; + padding: 24px 26px; +} +.settings-account-overview { + display: grid; + grid-template-columns: minmax(190px, 1fr) minmax(220px, 1fr) auto; + gap: 24px; + align-items: center; +} +.settings-account-primary { + display: flex; + min-width: 0; + align-items: center; + gap: 15px; +} +.settings-avatar { + width: 66px; + height: 66px; + flex: 0 0 auto; + overflow: hidden; + display: grid; + place-items: center; + border-radius: 9px; + background: #dcede6; + color: #247a63; + font-size: 23px; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } +} +.settings-account-identity { + display: grid; + min-width: 0; + gap: 3px; +} +.settings-account-identity span, +.settings-account-root > span, +.settings-account-facts dt { + color: #929a96; + font-size: 12px; +} +.settings-account-identity strong, +.settings-account-identity small { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.settings-account-identity strong { + color: #35403b; + font-size: 14px; +} +.settings-account-identity small { + color: #66706b; + font: + 12px/18px ui-monospace, + SFMono-Regular, + Consolas, + monospace; +} +.settings-account-facts { + display: grid; + min-width: 0; + gap: 12px; + margin: 0; +} +.settings-account-facts div { + min-width: 0; +} +.settings-account-facts dd { + overflow: hidden; + margin: 3px 0 0; + color: #35403b; + font-size: 13px; + text-overflow: ellipsis; + white-space: nowrap; +} +.settings-connection-text.success { + color: #2e8b68; +} +.settings-connection-text.warning { + color: #a56a24; +} +.settings-connection-text.error { + color: #c85a5a; +} +.settings-account-actions { + display: grid; + gap: 8px; +} +.settings-account-actions button { + min-height: 34px; + white-space: nowrap; +} +.settings-account-root { + grid-column: 1/-1; + display: grid; + min-width: 0; + gap: 7px; + padding-top: 19px; + border-top: 1px solid #edf0ee; +} +.settings-account-root > div { + display: flex; + min-width: 0; + align-items: center; + gap: 8px; +} +.settings-account-root code { + min-width: 0; + flex: 1; + overflow: hidden; + padding: 10px 12px; + border: 1px solid #dde3e0; + border-radius: 8px; + background: #f2f5f3; + color: #46514c; + text-overflow: ellipsis; + white-space: nowrap; + font: + 12px/18px ui-monospace, + SFMono-Regular, + Consolas, + monospace; +} +.settings-icon-button { + display: grid; + width: 36px; + height: 36px; + flex: 0 0 auto; + place-items: center; + border: 1px solid #dde3e0; + border-radius: 8px; + background: #fff; + color: #66706b; + cursor: pointer; +} +.settings-icon-button:hover:not(:disabled) { + border-color: #247a63; + color: #247a63; +} +.settings-icon-button:disabled { + cursor: not-allowed; + opacity: 0.45; +} +.settings-icon-button svg { + width: 17px; + fill: none; + stroke: currentColor; + stroke-linecap: round; + stroke-linejoin: round; + stroke-width: 1.8; +} +.settings-health-card { + padding: 12px; +} +.settings-diagnostic-summary { + margin: 0 0 10px; + padding: 9px 11px; + border-left: 3px solid #c68635; + border-radius: 6px; + background: #fff8ec; + color: #79501f; + font-size: 12px; + line-height: 1.55; +} +.settings-diagnostics { + display: grid; + gap: 8px; +} +.settings-diagnostic { + display: flex; + align-items: center; + gap: 12px; + min-width: 0; + padding: 13px; + border: 1px solid #edf0ee; + border-radius: 8px; +} +.settings-diagnostic-icon { + display: grid; + width: 18px; + height: 18px; + flex: 0 0 auto; + place-items: center; + border: 1px solid #929a96; + border-radius: 50%; + color: #929a96; + font-size: 11px; + font-weight: 700; +} +.settings-diagnostic-icon.success { + border-color: #2e8b68; + color: #2e8b68; +} +.settings-diagnostic-icon.warning { + border-color: #c68635; + color: #c68635; +} +.settings-diagnostic-icon.error { + border-color: #c85a5a; + color: #c85a5a; +} +.settings-diagnostic-icon.checking { + border-color: #cbd7d2; + border-top-color: #247a63; + animation: settings-spin 0.8s linear infinite; +} +.settings-diagnostic span { + color: #3d4742; + font-size: 13px; +} +.settings-diagnostic small { + margin-left: auto; + overflow: hidden; + color: #66706b; + text-overflow: ellipsis; + white-space: nowrap; +} +.settings-empty-state { + display: grid; + flex: 1; + place-content: center; + color: #66706b; + text-align: center; +} +.settings-empty-state h2 { + color: #202724; +} +/* SETTINGS-02: database key */ +.database-key-content { + padding-bottom: 48px; +} +.database-key-badge.unconfigured { + background: #f1f3f2; + color: #66706b; +} +.database-key-badge.validating { + background: #eef4f8; + color: #4f7188; +} +.database-key-badge.invalid { + background: #f9eeee; + color: #c85a5a; +} +.database-key-status-card dl { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 18px 36px; + margin: 0 0 20px; +} +.database-key-status-card dl div { + min-width: 0; +} +.database-key-status-card dt, +.database-key-diagnostics dt { + color: #929a96; + font-size: 12px; +} +.database-key-status-card dd, +.database-key-diagnostics dd { + overflow: hidden; + margin: 5px 0 0; + color: #35403b; + font-size: 13px; + text-overflow: ellipsis; + white-space: nowrap; +} +.database-key-mono { + font-family: ui-monospace, SFMono-Regular, Consolas, monospace; +} +.database-key-success { + color: #2e8b68 !important; +} +.database-key-muted { + color: #66706b !important; +} +.database-key-primary, +.database-key-secondary { + min-height: 36px; + padding: 0 15px; + border: 1px solid #247a63; + border-radius: 8px; + cursor: pointer; + font: 600 13px/1 inherit; +} +.database-key-primary { + background: #247a63; + color: #fff; +} +.database-key-secondary { + background: #fff; + color: #247a63; +} +.database-key-primary:hover:not(:disabled) { + background: #1d6754; +} +.database-key-secondary:hover:not(:disabled) { + background: #f0f7f4; +} +.database-key-primary:disabled, +.database-key-secondary:disabled { + cursor: not-allowed; + opacity: 0.45; +} +.database-key-editor label { + display: block; + margin-bottom: 9px; + color: #46514c; + font-size: 12px; + font-weight: 700; + letter-spacing: 0.04em; + text-transform: uppercase; +} +.database-key-input-row { + display: flex; + min-width: 0; + height: 42px; + border: 1px solid #d5ddda; + border-radius: 8px; + background: #f4f7f5; +} +.database-key-input-row:focus-within { + border-color: #247a63; + box-shadow: 0 0 0 2px rgba(36, 122, 99, 0.09); +} +.database-key-input-row input { + min-width: 0; + flex: 1; + border: 0; + outline: 0; + padding: 0 14px; + background: transparent; + color: #202724; + font: + 13px/1.4 ui-monospace, + SFMono-Regular, + Consolas, + monospace; +} +.database-key-input-row button { + display: grid; + width: 38px; + flex: 0 0 38px; + place-items: center; + border: 0; + background: transparent; + color: #66706b; + cursor: pointer; +} +.database-key-input-row button:hover:not(:disabled) { + color: #247a63; +} +.database-key-input-row button:disabled { + cursor: not-allowed; + opacity: 0.4; +} +.database-key-input-row svg { + width: 17px; + fill: none; + stroke: currentColor; + stroke-linecap: round; + stroke-linejoin: round; + stroke-width: 1.8; +} +.database-key-editor > p { + margin: 9px 0 0; + color: #66706b; + font-size: 12px; + line-height: 1.6; +} +.database-key-actions { + display: flex; + gap: 9px; + margin-top: 18px; +} +.database-key-feedback { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px 18px; + margin-top: 12px; + padding: 12px 15px; + border-radius: 8px; + font-size: 12px; + line-height: 1.5; +} +.database-key-feedback.checking { + background: #f1f4f3; + color: #66706b; +} +.database-key-feedback.checking i { + width: 14px; + height: 14px; + border: 2px solid #c8d5d0; + border-top-color: #247a63; + border-radius: 50%; + animation: settings-spin 0.8s linear infinite; +} +.database-key-feedback.success { + border: 1px solid #bfded3; + background: #eaf5f1; + color: #2e765d; +} +.database-key-feedback.success strong { + width: 100%; +} +.database-key-feedback.error { + border: 1px solid #efcaca; + background: #fff2f2; + color: #a84444; +} +.database-key-auto-heading { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 24px; +} +.database-key-auto strong { + color: #35403b; + font-size: 14px; +} +.database-key-auto p { + margin: 6px 0 0; + color: #66706b; + font-size: 12px; + line-height: 1.6; +} +.database-key-prerequisites { + display: flex; + flex-wrap: wrap; + gap: 8px 20px; + margin: 18px 0 0; + padding: 14px 0 0; + border-top: 1px solid #edf0ee; + list-style: none; + color: #8b5c25; + font-size: 12px; +} +.database-key-prerequisites li::before { + content: '○'; + margin-right: 6px; +} +.database-key-prerequisites li.ok { + color: #2e8b68; +} +.database-key-prerequisites li.ok::before { + content: '✓'; +} +.database-key-phases { + display: grid; + grid-template-columns: repeat(5, minmax(0, 1fr)); + gap: 8px; + margin: 18px 0 0; + padding: 0; + counter-reset: key-phase; + list-style: none; +} +.database-key-phases li { + position: relative; + padding-top: 24px; + color: #929a96; + text-align: center; + font-size: 11px; +} +.database-key-phases li::before { + position: absolute; + top: 0; + left: 50%; + display: grid; + width: 18px; + height: 18px; + place-items: center; + border: 1px solid #d5ddda; + border-radius: 50%; + background: #fff; + content: counter(key-phase); + counter-increment: key-phase; + transform: translateX(-50%); +} +.database-key-phases li.active { + color: #247a63; +} +.database-key-phases li.active::before { + border-color: #247a63; + background: #247a63; + color: #fff; +} +.database-key-auto-error { + display: grid; + gap: 4px; + margin-top: 16px; + padding: 12px 14px; + border-left: 3px solid #c68635; + background: #fff8ec; + color: #79501f; + font-size: 12px; +} +.database-key-auto-error span { + overflow-wrap: anywhere; +} +.database-key-auto-error p { + color: #79501f; +} +.database-key-auto-error button { + justify-self: start; + border: 0; + padding: 4px 0; + background: transparent; + color: #247a63; + cursor: pointer; + font: 600 12px inherit; +} +.database-key-security-info { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 1px; + overflow: hidden; + border: 1px solid #e3e8e5; + border-radius: 9px; + background: #e3e8e5; +} +.database-key-security-info span { + display: grid; + gap: 6px; + padding: 15px; + background: #f5f7f6; + color: #66706b; + font-size: 12px; + line-height: 1.5; +} +.database-key-security-info strong { + color: #35403b; + font-size: 13px; +} +.database-key-diagnostics { + margin-top: 22px; + border: 1px solid #dde3e0; + border-radius: 9px; + background: #fff; +} +.database-key-diagnostics summary { + padding: 14px 16px; + color: #46514c; + cursor: pointer; + font-size: 13px; + font-weight: 600; +} +.database-key-diagnostics dl { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 14px 28px; + margin: 0; + padding: 2px 16px 16px; +} +.database-key-diagnostics button { + margin: 0 16px 16px; + border: 0; + padding: 0; + background: transparent; + color: #247a63; + cursor: pointer; + font: 600 12px inherit; +} +.database-key-connection-actions { + margin-top: 30px; +} +.database-key-connection-actions > h2 { + margin: 0 0 14px; + color: #3d4742; + font-size: 15px; +} +.database-key-connection-actions > div { + display: flex; + align-items: center; + justify-content: space-between; + gap: 20px; + padding: 16px 20px; + border: 1px solid #dde3e0; + border-radius: 9px; + background: #fff; +} +.database-key-connection-actions span { + display: grid; + gap: 4px; +} +.database-key-connection-actions strong { + color: #35403b; + font-size: 13px; +} +.database-key-connection-actions small { + color: #66706b; + font-size: 12px; +} +.database-key-connection-actions button { + min-height: 34px; + flex: 0 0 auto; + border: 1px solid #247a63; + border-radius: 8px; + padding: 0 13px; + background: #fff; + color: #247a63; + cursor: pointer; +} +.database-key-connection-actions button:hover:not(:disabled) { + background: #f0f7f4; +} +.database-key-danger { + margin-top: 30px; + padding-bottom: 1px; +} +.database-key-danger > h2 { + margin: 0 0 14px; + color: #c85a5a; + font-size: 15px; +} +.database-key-danger > div { + display: flex; + align-items: center; + justify-content: space-between; + gap: 20px; + padding: 16px 20px; + border: 1px solid #efcdcd; + background: #fff7f7; +} +.database-key-danger > div:first-of-type { + border-radius: 9px 9px 0 0; +} +.database-key-danger > div:last-of-type { + border-top: 0; + border-radius: 0 0 9px 9px; +} +.database-key-danger span { + display: grid; + gap: 4px; +} +.database-key-danger strong { + color: #4a3c3c; + font-size: 13px; +} +.database-key-danger small { + color: #786868; + font-size: 12px; +} +.database-key-danger button { + min-height: 34px; + flex: 0 0 auto; + border: 1px solid #e8baba; + border-radius: 8px; + padding: 0 13px; + background: #fff; + color: #c85a5a; + cursor: pointer; +} +.database-key-danger button:disabled { + cursor: not-allowed; + opacity: 0.45; +} +.database-key-confirm-backdrop { + position: fixed; + z-index: 30; + inset: 0; + display: grid; + place-items: center; + padding: 24px; + background: rgba(25, 32, 29, 0.34); +} +.database-key-confirm { + width: min(100%, 430px); + padding: 22px; + border-radius: 12px; + background: #fff; + box-shadow: 0 18px 50px rgba(24, 35, 30, 0.2); +} +.database-key-confirm h2 { + margin: 0; + color: #202724; + font-size: 17px; +} +.database-key-confirm p { + margin: 12px 0 22px; + color: #66706b; + font-size: 13px; + line-height: 1.7; +} +.database-key-confirm > div { + display: flex; + justify-content: flex-end; + gap: 8px; +} +.database-key-confirm button { + min-height: 34px; + border: 1px solid #dde3e0; + border-radius: 8px; + padding: 0 14px; + background: #fff; + color: #46514c; + cursor: pointer; +} +.database-key-confirm button.danger { + border-color: #c85a5a; + background: #c85a5a; + color: #fff; +} +/* SETTINGS-03: image decryption */ +.image-decryption-content { + padding-bottom: 48px; +} +.image-decrypt-badge.unconfigured { + background: #f1f3f2; + color: #66706b; +} +.image-decrypt-badge.partial { + background: #fff6e8; + color: #a56a24; +} +.image-decrypt-status dl { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 18px 30px; + margin: 0 0 20px; +} +.image-decrypt-status dl div { + min-width: 0; +} +.image-decrypt-status dt { + color: #929a96; + font-size: 12px; +} +.image-decrypt-status dd { + overflow: hidden; + margin: 5px 0 0; + color: #35403b; + font-size: 13px; + text-overflow: ellipsis; + white-space: nowrap; +} +.image-decrypt-status .image-decrypt-wide { + grid-column: span 2; +} +.image-decrypt-mono { + font-family: ui-monospace, SFMono-Regular, Consolas, monospace; +} +.image-state-success { + color: #2e8b68 !important; +} +.image-state-muted { + color: #66706b !important; +} +.image-state-error { + color: #c85a5a !important; +} +.image-resource-checks { + padding: 10px 18px; +} +.image-resource-checks > div { + display: flex; + min-width: 0; + align-items: center; + gap: 11px; + padding: 13px 2px; + border-bottom: 1px solid #edf0ee; +} +.image-resource-checks > div:last-child { + border-bottom: 0; +} +.image-resource-checks strong { + color: #3d4742; + font-size: 13px; +} +.image-resource-checks small { + margin-left: auto; + overflow: hidden; + color: #66706b; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 12px; +} +.image-resource-icon { + display: grid; + width: 18px; + height: 18px; + flex: 0 0 auto; + place-items: center; + border-radius: 50%; + background: #f1f3f2; + color: #66706b; + font-size: 11px; + font-weight: 700; +} +.image-resource-icon.available { + background: #e6f2ed; + color: #2e8b68; +} +.image-resource-icon.unavailable { + background: #f9eaea; + color: #c85a5a; +} +.image-key-editor { + display: grid; + gap: 17px; +} +.image-key-editor label { + display: grid; + min-width: 0; + gap: 8px; + color: #46514c; + font-size: 12px; + font-weight: 600; +} +.image-key-editor input, +.image-test-section select { + box-sizing: border-box; + width: 100%; + height: 40px; + border: 1px solid #d5ddda; + border-radius: 8px; + outline: 0; + padding: 0 12px; + background: #f4f7f5; + color: #202724; + font: + 12px/1.4 ui-monospace, + SFMono-Regular, + Consolas, + monospace; +} +.image-key-editor input:focus, +.image-test-section select:focus { + border-color: #247a63; + box-shadow: 0 0 0 2px rgba(36, 122, 99, 0.09); +} +.image-key-grid { + display: grid; + grid-template-columns: 180px minmax(0, 1fr); + gap: 14px; +} +.image-key-editor > p { + margin: 0; + color: #66706b; + font-size: 12px; + line-height: 1.6; +} +.image-test-section > div:first-child strong, +.image-auto-detect strong, +.image-auto-unavailable strong { + color: #35403b; + font-size: 14px; +} +.image-test-section > div:first-child p, +.image-auto-detect p, +.image-auto-unavailable p { + margin: 6px 0 0; + color: #66706b; + font-size: 12px; + line-height: 1.6; +} +.image-test-section > label { + display: block; + margin: 18px 0 8px; + color: #46514c; + font-size: 12px; + font-weight: 600; +} +.image-test-actions { + display: flex; + gap: 9px; + margin-top: 14px; +} +.image-test-result { + display: flex; + flex-wrap: wrap; + gap: 8px 18px; + margin-top: 14px; + padding: 12px 14px; + border-radius: 8px; + color: #2e765d; + font-size: 12px; +} +.image-test-result.success { + border: 1px solid #bfded3; + background: #eaf5f1; +} +.image-test-result.error { + border: 1px solid #efcaca; + background: #fff2f2; + color: #a84444; +} +.image-test-result p { + width: 100%; + margin: 2px 0 0; +} +.image-step-list { + list-style: none; + margin: 14px 0 0; + padding: 12px 14px; + border-radius: 8px; + border: 1px solid #e5ecea; + background: #f7faf9; + display: flex; + flex-direction: column; + gap: 8px; + font-size: 12px; +} +.image-step { + display: flex; + align-items: center; + gap: 8px; +} +.image-step-icon { + width: 18px; + height: 18px; + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: 50%; + font-size: 12px; + font-weight: 600; +} +.image-step-ok .image-step-icon { + background: #2e765d; + color: #fff; +} +.image-step-fail .image-step-icon { + background: #a84444; + color: #fff; +} +.image-step-fail span:last-child { + color: #a84444; +} +.image-step-pending .image-step-icon { + background: #d6dde0; + color: #6a7378; +} +.image-step-pending span:last-child { + color: #98a1a4; +} +.image-step-skipped .image-step-icon { + background: transparent; + color: #b8c0c4; +} +.image-step-skipped span:last-child { + color: #b8c0c4; + text-decoration: line-through; +} +.image-inline-error { + margin: 14px 0 0; + color: #a84444; + font-size: 12px; +} +.image-auto-heading { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 24px; +} +.image-auto-detect ul { + display: flex; + flex-wrap: wrap; + gap: 10px 22px; + margin: 17px 0 0; + padding: 14px 0 0; + border-top: 1px solid #edf0ee; + list-style: none; + color: #8b5c25; + font-size: 12px; +} +.image-auto-detect li::before { + content: '○'; + margin-right: 6px; +} +.image-auto-detect li.ok { + color: #2e8b68; +} +.image-auto-detect li.ok::before { + content: '✓'; +} +.image-auto-progress { + margin-top: 12px !important; + padding: 9px 12px; + border-radius: 7px; + background: #f1f4f3; +} +.image-auto-scope-hint { + display: inline-block; + margin-top: 4px; + color: #7d8c8a; + font-size: 11px; +} +.image-auto-unavailable { + padding-top: 20px; + padding-bottom: 20px; +} +.image-key-danger > div { + border-radius: 9px !important; +} +.image-key-danger { + margin-top: 30px; +} +.image-auto-phases { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 8px; + margin: 18px 0 0; + padding: 0; + counter-reset: image-auto-phase; + list-style: none; +} +.image-auto-phases li { + position: relative; + padding-top: 24px; + color: #929a96; + text-align: center; + font-size: 11px; +} +.image-auto-phases li::before { + position: absolute; + top: 0; + left: 50%; + display: grid; + width: 18px; + height: 18px; + place-items: center; + border: 1px solid #d5ddda; + border-radius: 50%; + background: #fff; + content: counter(image-auto-phase); + counter-increment: image-auto-phase; + transform: translateX(-50%); +} +.image-auto-phases li.active { + color: #247a63; +} +.image-auto-phases li.active::before { + border-color: #247a63; + background: #247a63; + color: #fff; +} +.image-auto-error { + margin: 12px 0 0 !important; + padding: 10px 12px; + border-left: 3px solid #c85a5a; + background: #fff2f2; + color: #a84444 !important; +} +.image-auto-success { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 7px 20px; + align-items: center; + margin-top: 14px; + padding: 14px 16px; + border: 1px solid #bfded3; + border-radius: 8px; + background: #eaf5f1; + color: #2e765d; + font-size: 12px; +} +.image-auto-success strong { + grid-column: 1; + color: #2e765d; +} +.image-auto-success span { + grid-column: 1; +} +.image-auto-success button { + grid-column: 2; + grid-row: 1/4; +} +/* SETTINGS-04: AI provider center */ +.ai-model-content { + padding-bottom: 48px; +} +.ai-model-default { + display: flex; + align-items: center; + justify-content: space-between; + gap: 20px; +} +.ai-model-default > div { + display: grid; + gap: 5px; +} +.ai-model-default > div > span, +.ai-model-default small { + color: #66706b; + font-size: 12px; +} +.ai-model-default strong { + color: #202724; + font-size: 18px; +} +.ai-model-page-error { + padding: 11px 14px; + border-left: 3px solid #c85a5a; + background: #fff2f2; + color: #a84444; + font-size: 12px; +} +.ai-provider-list { + display: grid; + gap: 12px; +} +.ai-provider-card { + border: 1px solid #dde3e0; + border-radius: 10px; + background: #fff; + padding: 19px 20px; +} +.ai-provider-card header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 18px; +} +.ai-provider-card h3 { + margin: 0 0 5px; + color: #202724; + font-size: 15px; +} +.ai-provider-card header span { + color: #66706b; + font-size: 12px; +} +.ai-provider-status { + border-radius: 12px; + padding: 4px 8px; + background: #f1f3f2; +} +.ai-provider-status.connected { + background: #eaf5f1; + color: #2e8b68 !important; +} +.ai-provider-status.error { + background: #fff2f2; + color: #c85a5a !important; +} +.ai-provider-card dl { + display: grid; + grid-template-columns: 2fr 1fr 1fr; + gap: 18px; + margin: 18px 0; +} +.ai-provider-card dt { + color: #929a96; + font-size: 11px; +} +.ai-provider-card dd { + overflow: hidden; + margin: 5px 0 0; + color: #3d4742; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 12px; +} +.ai-provider-card footer { + display: flex; + flex-wrap: wrap; + gap: 8px; + padding-top: 14px; + border-top: 1px solid #edf0ee; +} +.ai-provider-card button, +.ai-provider-editor button { + min-height: 32px; + border: 1px solid #d5ddda; + border-radius: 7px; + padding: 0 11px; + background: #fff; + color: #46514c; + cursor: pointer; + font: 600 12px inherit; +} +.ai-provider-card button:hover, +.ai-provider-editor button:hover { + border-color: #247a63; + color: #247a63; +} +.ai-provider-card button:disabled, +.ai-provider-editor button:disabled { + cursor: not-allowed; + opacity: 0.45; +} +.ai-provider-card button.danger, +.ai-provider-editor button.danger { + color: #c85a5a; +} +.ai-provider-error { + margin: 0 0 12px; + color: #a84444; + font-size: 12px; +} +.ai-provider-empty { + color: #66706b; + text-align: center; +} +.ai-provider-empty p { + margin: 6px 0 0; + font-size: 12px; +} +.ai-provider-editor { + display: grid; + gap: 18px; + margin-top: 22px; +} +.ai-provider-editor > header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 18px; +} +.ai-provider-editor h2, +.ai-provider-editor h3 { + margin: 0; + color: #35403b; + font-size: 15px; +} +.ai-provider-editor header p { + margin: 5px 0 0; + color: #66706b; + font-size: 12px; +} +.ai-provider-editor label { + display: grid; + gap: 7px; + color: #46514c; + font-size: 12px; + font-weight: 600; +} +.ai-provider-editor input:not([type='checkbox']):not([type='radio']), +.ai-provider-editor select, +.ai-provider-editor textarea { + box-sizing: border-box; + width: 100%; + border: 1px solid #d5ddda; + border-radius: 7px; + outline: 0; + padding: 9px 10px; + background: #f4f7f5; + color: #202724; + font: + 12px/1.4 ui-monospace, + SFMono-Regular, + Consolas, + monospace; +} +.ai-provider-editor input:focus, +.ai-provider-editor select:focus, +.ai-provider-editor textarea:focus { + border-color: #247a63; + box-shadow: 0 0 0 2px rgba(36, 122, 99, 0.08); +} +.ai-provider-form-grid, +.ai-provider-advanced > div { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 14px; +} +.ai-provider-form-grid .wide, +.ai-provider-advanced .wide { + grid-column: 1/-1; +} +.ai-model-table-heading { + display: flex; + align-items: center; + justify-content: space-between; +} +.ai-model-table { + display: grid; + gap: 9px; +} +.ai-model-row { + display: grid; + grid-template-columns: 1fr 1fr repeat(3, auto) 110px auto auto; + gap: 8px; + align-items: center; + padding: 11px; + border: 1px solid #e3e8e5; + border-radius: 8px; +} +.ai-model-row label { + display: flex; + align-items: center; + gap: 4px; + white-space: nowrap; + font-weight: 400; +} +.ai-provider-advanced, +.ai-provider-preview { + border: 1px solid #e3e8e5; + border-radius: 8px; +} +.ai-provider-advanced summary, +.ai-provider-preview summary { + padding: 12px 14px; + cursor: pointer; + color: #46514c; + font-size: 13px; + font-weight: 600; +} +.ai-provider-advanced > div { + padding: 2px 14px 14px; +} +.ai-provider-advanced textarea { + min-height: 90px; + resize: vertical; +} +.ai-provider-preview pre { + overflow: auto; + max-height: 280px; + margin: 0; + padding: 0 14px 14px; + color: #46514c; + font: + 11px/1.6 ui-monospace, + SFMono-Regular, + Consolas, + monospace; +} +.ai-provider-editor > footer { + display: flex; + justify-content: flex-end; + gap: 8px; +} +@keyframes settings-spin { + to { + transform: rotate(360deg); + } +} +@media (max-width: 900px) { + .settings-sidebar { + width: 248px; + flex-basis: 248px; + } + .settings-page-content { + padding: 24px; + } + .settings-page-header { + padding: 20px 24px; + } + .settings-recall-grid { + grid-template-columns: 1fr; + } + .settings-recall-notice { + padding-top: 10px; + padding-left: 0; + border-top: 2px solid #e5b45f; + border-left: 0; + } + .settings-account-overview { + grid-template-columns: minmax(0, 1fr) auto; + gap: 18px; + } + .settings-account-facts { + grid-column: 1/-1; + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .settings-account-actions { + grid-row: 1; + grid-column: 2; + } + .database-key-security-info { + grid-template-columns: 1fr; + } + .image-decrypt-status dl { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .image-decrypt-status .image-decrypt-wide { + grid-column: span 2; + } + .ai-model-row { + grid-template-columns: 1fr 1fr; + } + .ai-model-row label, + .ai-model-row button { + justify-self: start; + } +} diff --git a/src/renderer/src/styles/shell-overlays.scss b/src/renderer/src/styles/shell-overlays.scss new file mode 100644 index 0000000..43719c9 --- /dev/null +++ b/src/renderer/src/styles/shell-overlays.scss @@ -0,0 +1,446 @@ +/* Sidebar 自助卡片 + 入口 */ +.sidebar-footer { + padding: 10px 12px; + border-top: 1px solid var(--border-color); + display: flex; + align-items: center; + gap: 10px; + cursor: pointer; + background-color: #f3f4f5; + transition: background-color 0.15s ease; + user-select: none; + + &:hover { + background-color: #e6e9eb; + } +} + +.sidebar-self-avatar { + width: 36px; + height: 36px; + border-radius: 6px; + background-color: #07c160; + color: #fff; + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; + font-weight: 500; + overflow: hidden; + flex-shrink: 0; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } +} + +.sidebar-self-info { + flex: 1; + min-width: 0; + overflow: hidden; +} + +.sidebar-self-nickname { + font-size: 13px; + font-weight: 500; + color: #1f2429; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.sidebar-self-wxid { + font-size: 11px; + color: #8a9298; + margin-top: 2px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.sidebar-self-arrow { + color: #8a9298; + font-size: 18px; + flex-shrink: 0; +} + +/* 启动自动连接 Splash */ +.boot-splash { + position: fixed; + inset: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 14px; + background: linear-gradient(180deg, #f5f7f8 0%, #eceff1 100%); + z-index: 2000; + animation: boot-splash-fade-in 0.2s ease-out; +} + +@keyframes boot-splash-fade-in { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +.boot-splash-spinner { + width: 36px; + height: 36px; + border-radius: 50%; + border: 3px solid rgba(7, 193, 96, 0.18); + border-top-color: #07c160; + animation: boot-splash-spin 0.9s linear infinite; +} + +@keyframes boot-splash-spin { + to { + transform: rotate(360deg); + } +} + +.boot-splash-title { + font-size: 15px; + font-weight: 500; + color: #1f2429; +} + +.boot-splash-subtitle { + font-size: 12px; + color: #6f767c; +} + +.boot-splash-detail { + min-height: 18px; + font-size: 12px; + color: #8a9298; +} + +.boot-splash-progress { + width: min(320px, 72vw); + height: 6px; + margin-top: 2px; + overflow: hidden; + border-radius: 999px; + background: rgba(7, 193, 96, 0.12); +} + +.boot-splash-progress-bar { + height: 100%; + border-radius: inherit; + background: #07c160; + transition: width 0.18s ease-out; +} + +/* 设置面板 */ +.settings-overlay { + position: fixed; + inset: 0; + background: rgba(15, 21, 26, 0.45); + backdrop-filter: blur(2px); + z-index: 1100; + display: flex; + align-items: center; + justify-content: center; + animation: settings-fade-in 0.16s ease-out; +} + +@keyframes settings-fade-in { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +.settings-modal { + width: min(560px, 92vw); + max-height: 84vh; + background: #fff; + border-radius: 12px; + box-shadow: 0 24px 60px rgba(15, 21, 26, 0.28); + display: flex; + flex-direction: column; + overflow: hidden; + animation: settings-pop-in 0.18s ease-out; +} + +@keyframes settings-pop-in { + from { + transform: translateY(8px) scale(0.98); + opacity: 0; + } + to { + transform: translateY(0) scale(1); + opacity: 1; + } +} + +.settings-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px 22px; + border-bottom: 1px solid #ececec; + + h2 { + margin: 0; + font-size: 17px; + font-weight: 600; + color: #1f2429; + } +} + +.settings-close { + background: transparent; + border: 0; + color: #7d858a; + font-size: 26px; + line-height: 1; + width: 32px; + height: 32px; + border-radius: 50%; + cursor: pointer; + transition: background-color 0.15s ease; + + &:hover { + background: #f0f2f4; + color: #1f2429; + } +} + +.settings-body { + padding: 12px 22px 22px; + overflow-y: auto; +} + +.settings-section { + margin-top: 14px; + padding: 14px 16px; + border-radius: 10px; + background: #fafbfc; + border: 1px solid #ececec; +} + +.settings-section:first-child { + margin-top: 6px; +} + +.settings-section-title { + font-size: 12px; + font-weight: 600; + color: #6f767c; + letter-spacing: 0.5px; + text-transform: uppercase; + margin-bottom: 10px; +} + +.settings-row { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; + margin-top: 8px; +} + +.settings-row:first-child { + margin-top: 0; +} + +.settings-input { + flex: 1; + min-width: 0; + padding: 8px 11px; + border: 1px solid #d4d9dc; + border-radius: 6px; + background: #fff; + font-size: 13px; + color: #1f2429; + font-family: 'SF Mono', Menlo, Consolas, monospace; + outline: none; + transition: + border-color 0.15s ease, + box-shadow 0.15s ease; +} + +.settings-input:focus { + border-color: #07c160; + box-shadow: 0 0 0 3px rgba(7, 193, 96, 0.12); +} + +.settings-input-half { + flex: 0 1 140px; +} + +.settings-input-quarter { + flex: 0 1 90px; +} + +.settings-btn { + padding: 7px 14px; + border: 1px solid #d4d9dc; + border-radius: 6px; + background: #fff; + color: #30383d; + cursor: pointer; + font-size: 13px; + transition: + border-color 0.15s ease, + background-color 0.15s ease, + color 0.15s ease; + + &:hover:not(:disabled) { + border-color: #07c160; + color: #078f49; + } + + &:disabled { + opacity: 0.55; + cursor: not-allowed; + } +} + +.settings-btn-primary { + background: #07c160; + color: #fff; + border-color: #07c160; + + &:hover:not(:disabled) { + background: #06ad56; + color: #fff; + border-color: #06ad56; + } +} + +.settings-hint { + margin-top: 10px; + font-size: 11px; + color: #8a9298; + line-height: 1.6; +} + +.settings-hint code { + background: #eef0f2; + padding: 1px 5px; + border-radius: 3px; + font-size: 10.5px; +} + +.settings-status { + font-size: 12px; + color: #59636a; +} + +.settings-status.ok { + color: #078f49; +} + +.settings-status.fail { + color: #c73737; +} + +.settings-toggle { + display: inline-flex; + align-items: center; + gap: 8px; + cursor: pointer; + font-size: 13px; + color: #30383d; + + input { + width: 16px; + height: 16px; + accent-color: #07c160; + cursor: pointer; + } +} + +.settings-self { + display: flex; + align-items: center; + gap: 12px; +} + +.settings-self-avatar { + width: 56px; + height: 56px; + border-radius: 10px; + background: #07c160; + color: #fff; + display: flex; + align-items: center; + justify-content: center; + font-size: 22px; + font-weight: 500; + overflow: hidden; + flex-shrink: 0; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } +} + +.settings-self-info { + flex: 1; + min-width: 0; +} + +.settings-self-nickname { + font-size: 15px; + font-weight: 600; + color: #1f2429; +} + +.settings-self-wxid { + font-size: 12px; + color: #6f767c; + margin-top: 2px; + font-family: 'SF Mono', Menlo, Consolas, monospace; +} + +.settings-self-account { + font-size: 11px; + color: #8a9298; + margin-top: 2px; + word-break: break-all; +} + +.settings-self-empty { + font-size: 13px; + color: #8a9298; +} + +.settings-path { + display: inline-block; + font-family: 'SF Mono', Menlo, Consolas, monospace; + font-size: 11px; + background: #eef0f2; + padding: 3px 7px; + border-radius: 4px; + color: #30383d; + word-break: break-all; + max-width: 100%; +} + +.app-toast { + position: fixed; + top: 18px; + left: calc(var(--wxex-nav-width) + 50%); + z-index: 40; + transform: translateX(-50%); + padding: 9px 14px; + border: 1px solid rgba(198, 134, 53, 0.35); + border-radius: var(--wxex-radius-md); + background: #fff9ef; + color: #7b4b14; + font: 13px/18px var(--wxex-font); + box-shadow: var(--wxex-shadow-popover); +}