Files
hermes-web/packages/client/src/styles/global.scss
T
toor 836d0228d2 Phase 007: migrate every remaining view from naive-ui to Arco Design Vue
The project now has exactly one UI library. Every naive-ui component in
packages/client/src is replaced by its Arco equivalent across 24 views and
roughly 80 components, and naive-ui is dropped from package.json along with
its transitive vueuc / @css-render / vdirs / seemly dependencies.

The migration is rendering-layer only. No store logic, no API contract, and
no /chat-run payload was touched.

Three classes of leftover were invisible to `grep naive-ui` and are now
covered by tests/client/no-naive-ui.test.ts, which asserts all three:
  - dead .n-* class names in style blocks
  - dead --n-* custom properties
  - naive-ui in package.json

Notable behavioural traps handled along the way, recorded in
docs/arco-migration-rules.md:
  - a-input-password defaults to masked; passing default-visibility="false"
    would have exposed API keys in clear text
  - a-upload fires a real XHR unless auto-upload is false
  - nested Trigger components fight over the first element child, so the
    group-chat settings dropdown was flattened
  - Arco renders tooltip default-slot text inline, which was silently
    collapsing the chat and group-chat toolbars
2026-10-18 22:57:25 +08:00

273 lines
5.0 KiB
SCSS

@use 'variables' as *;
@use 'code-block';
@font-face {
font-family: 'Comic Neue';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/ComicNeue-Bold.ttf') format('truetype');
}
@font-face {
font-family: 'ZCOOL KuaiLe';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/ZCOOLKuaiLe-Regular.ttf') format('truetype');
}
@font-face {
font-family: 'Zen Maru Gothic';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/ZenMaruGothic-Regular.ttf') format('truetype');
}
@font-face {
font-family: 'Zen Maru Gothic';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/fonts/ZenMaruGothic-Bold.ttf') format('truetype');
}
@font-face {
font-family: 'Gaegu';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/Gaegu-Regular.ttf') format('truetype');
}
@font-face {
font-family: 'Gaegu';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/fonts/Gaegu-Bold.ttf') format('truetype');
}
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
button,
input,
select,
textarea {
font-family: inherit;
}
:root {
--vh: 1vh;
}
// Fix mobile viewport height (address bar)
@supports (height: 100dvh) {
:root {
--vh: 1dvh;
}
}
// Theme transition (applied programmatically on toggle, not on load)
html.theme-transitioning,
html.theme-transitioning *,
html.theme-transitioning *::before,
html.theme-transitioning *::after {
transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease,
box-shadow 0.3s ease, fill 0.3s ease, stroke 0.3s ease !important;
}
html, body {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
#app {
height: 100%;
width: 100%;
overflow: hidden;
}
body {
font-family: $font-ui;
background-color: $bg-primary;
color: $text-primary;
font-size: 14px;
line-height: 1.6;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
// Chat input route CSS is code-split; keep the footer color stable before the
// component-scoped chunk arrives so entering chat does not flash the page bg.
.chat-input-area,
.chat-input-area .input-wrapper {
background-color: $bg-card;
}
.settings-check {
display: inline-flex;
align-items: center;
justify-content: center;
width: 16px;
min-width: 16px;
height: 16px;
color: transparent;
font-size: 13px;
line-height: 16px;
}
.settings-check.active {
color: $accent-primary;
}
code, pre, .mono {
font-family: $font-code;
}
a {
color: $accent-primary;
text-decoration: none;
&:hover {
color: $accent-hover;
}
}
::-webkit-scrollbar {
width: 6px;
height: 6px;
background: transparent;
}
::-webkit-scrollbar-track,
::-webkit-scrollbar-track-piece {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: $border-color;
border-radius: 3px;
&:hover {
background: $text-muted;
}
}
::-webkit-scrollbar-corner {
background: transparent;
}
* {
scrollbar-width: thin;
scrollbar-color: $border-color transparent;
}
::selection {
background: rgba(var(--accent-primary-rgb), 0.3);
}
// Shared page header
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
min-height: 64px;
padding: 14px 20px;
border-bottom: 1px solid $border-color;
flex-shrink: 0;
}
.header-title {
margin: 0;
font-size: 16px;
font-weight: 600;
line-height: 1.4;
color: $text-primary;
}
.page-header > .header-actions {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 8px;
}
// Responsive utility classes for inline width replacement
.input-sm { width: 90px; }
.input-md { width: 200px; }
.input-lg { width: 300px; }
// Mobile drawer backdrop
.mobile-backdrop {
display: none;
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.4);
z-index: 999;
}
// Hamburger button (mobile only)
.hamburger-btn {
display: none;
position: fixed;
top: calc(10px + env(safe-area-inset-top, 0px));
left: 12px;
z-index: 99;
width: 36px;
height: 36px;
border: none;
background: $bg-card;
border-radius: $radius-sm;
cursor: pointer;
align-items: center;
justify-content: center;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
}
// Mobile responsive
@media (max-width: $breakpoint-mobile) {
.mobile-backdrop {
display: block;
}
.hamburger-btn {
display: flex;
}
.page-header {
padding: calc(16px + env(safe-area-inset-top, 0px)) 12px 16px 52px !important;
}
.input-sm,
.input-md,
.input-lg {
width: 100%;
}
}
// Prevent iOS Safari auto-zoom on input focus by ensuring font-size is at least 16px
// Arco 的 a-input 渲染原生 <input>,已被上面的元素选择器覆盖;
// 需要额外兜住的是 a-textarea(渲染 textarea,字体继承自容器)与 Arco 包装层。
@media (max-width: 768px) {
input,
textarea,
select,
.arco-input,
.arco-textarea {
font-size: 16px !important;
}
}