Files
WechatOnCloud/panel/web/src/styles.css
Gloridust 5c5e9c8540 update
2026-05-29 22:00:23 +08:00

738 lines
15 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* WechatOnCloud 面板 —— 牛奶布艺soft neumorphism+ 微信绿 + iOS26 圆角极简
* 比喻:整个界面是盖在桌面上的一整块白布,组件是被布顶起的物体。
* - 高光在物体顶面radial中心偏上
* - 阴影是布料折痕(小半径、紧贴边缘、冷灰蓝),不是悬浮投影
* - 组件亮度 ≥ 背景;层级靠明度,不靠边框/分割线 */
:root {
--base: #ebedf1; /* 整块布底色立体档91% 区间) */
--surface: #ffffff; /* 浮起表面:纯白 */
--trough: #e0e3ea; /* 凹槽:比 base 更暗(输入框/进度槽) */
--shadow: 51 66 102; /* 冷灰蓝阴影 RGB配合 rgba() */
--wx-green: #07c160;
--wx-green-dark: #06ad56;
--green-rgb: 7 193 96;
--text: #1a1d24;
--muted: #8a9099;
--danger: #fa5151;
--danger-rgb: 250 81 81;
--r-card: 28px;
--r-blob: 22px;
--r-small: 16px;
/* 布料折痕:两层,紧贴边缘 */
--crease: 0 1px 3px rgba(var(--shadow) / 0.4), 0 2px 8px rgba(var(--shadow) / 0.22);
--crease-press: 0 1px 2px rgba(var(--shadow) / 0.28), 0 1px 3px rgba(var(--shadow) / 0.16);
--crease-accent: 0 1px 3px rgba(var(--green-rgb) / 0.45), 0 4px 14px rgba(var(--green-rgb) / 0.32);
/* 顶面高光(中心偏上的 radial所有浮起组件共用 */
--sheen: radial-gradient(
ellipse at 50% 28%,
rgba(255, 255, 255, 0.55) 0%,
rgba(255, 255, 255, 0.16) 38%,
transparent 74%
);
}
* {
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
html,
body,
#root {
height: 100%;
margin: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', 'Segoe UI', Roboto, sans-serif;
background: var(--base);
color: var(--text);
-webkit-font-smoothing: antialiased;
}
input,
button {
font-family: inherit;
}
.center-screen {
min-height: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
padding-top: max(24px, env(safe-area-inset-top));
padding-bottom: max(24px, env(safe-area-inset-bottom));
}
/* ── 浮起原子surface + 折痕 + 顶面高光 ──────────────────── */
.mf-raised,
.card,
.enter-card,
.list,
.wx-state {
position: relative;
background: var(--surface);
box-shadow: var(--crease);
}
.mf-raised::before,
.card::before,
.enter-card::before,
.list::before,
.wx-state::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
background: var(--sheen);
pointer-events: none;
}
.card > *,
.enter-card > *,
.list > *,
.wx-state > * {
position: relative;
z-index: 1;
}
.card {
border-radius: var(--r-card);
padding: 24px;
width: 100%;
max-width: 360px;
}
/* 登录 */
.login-card {
display: flex;
flex-direction: column;
gap: 14px;
}
.brand {
text-align: center;
margin-bottom: 8px;
}
.brand-logo {
position: relative;
width: 60px;
height: 60px;
border-radius: 18px;
background: var(--wx-green);
color: #fff;
font-size: 32px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 14px;
box-shadow: var(--crease-accent);
overflow: hidden;
}
.brand-logo::before {
content: '';
position: absolute;
inset: 0;
background: var(--sheen);
pointer-events: none;
}
.brand h1 {
font-size: 22px;
font-weight: 700;
margin: 0 0 4px;
}
.muted {
color: var(--muted);
}
.small {
font-size: 12px;
}
/* 输入框凹陷trough fill + 顶部内阴影),聚焦叠绿色半透环 */
.input {
width: 100%;
height: 48px;
padding: 0 16px;
border: none;
border-radius: var(--r-small);
font-size: 16px;
outline: none;
color: var(--text);
background: var(--trough);
box-shadow: inset 0 1px 2px rgba(var(--shadow) / 0.18), inset 0 2px 6px rgba(var(--shadow) / 0.1);
transition: box-shadow 0.2s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.input::placeholder {
color: var(--muted);
}
.input:focus {
box-shadow: inset 0 1px 2px rgba(var(--shadow) / 0.16), 0 0 0 3px rgba(var(--green-rgb) / 0.22);
}
/* 按钮:浮起 blob按下缩小 + 折痕收紧 */
.btn {
position: relative;
height: 48px;
border: none;
border-radius: var(--r-small);
font-size: 16px;
font-weight: 500;
background: var(--surface);
color: var(--text);
cursor: pointer;
box-shadow: var(--crease);
overflow: hidden;
transition: transform 0.18s cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 0.18s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.btn::before {
content: '';
position: absolute;
inset: 0;
background: var(--sheen);
pointer-events: none;
}
.btn:active:not(:disabled) {
transform: scale(0.97);
box-shadow: var(--crease-press);
}
.btn-primary {
background: var(--wx-green);
color: #fff;
box-shadow: var(--crease-accent);
}
/* 绿底上用更克制的顶面高光,避免白色 sheen 把绿冲淡 */
.btn-primary::before,
.wx-btn.btn-primary::before {
background: radial-gradient(
ellipse at 50% 22%,
rgba(255, 255, 255, 0.28) 0%,
rgba(255, 255, 255, 0.08) 42%,
transparent 72%
);
}
.btn-primary:active:not(:disabled) {
background: var(--wx-green-dark);
}
.btn:disabled {
opacity: 0.6;
cursor: default;
}
/* 文本按钮:无浮起,绿字,按下淡绿底 */
.btn-text {
background: none;
border: none;
color: var(--wx-green);
font-size: 15px;
cursor: pointer;
padding: 6px 10px;
border-radius: 10px;
transition: background 0.18s;
}
.btn-text:active {
background: rgba(var(--green-rgb) / 0.12);
}
.btn-text.danger {
color: var(--danger);
}
.btn-text.danger:active {
background: rgba(var(--danger-rgb) / 0.12);
}
.error {
color: var(--danger);
font-size: 14px;
}
.ok {
color: var(--wx-green);
font-size: 14px;
}
/* ── 页面骨架 ──────────────────────────────────────────── */
.page {
min-height: 100%;
display: flex;
flex-direction: column;
}
/* 顶栏走浅色布面(不再整条绿),标题深色、操作绿字 —— iOS26 + 牛奶布艺 */
.topbar {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 8px;
padding-top: env(safe-area-inset-top);
height: calc(52px + env(safe-area-inset-top));
background: var(--base);
}
.topbar-title {
font-size: 17px;
font-weight: 600;
color: var(--text);
position: absolute;
left: 50%;
transform: translateX(-50%);
}
.content {
flex: 1;
padding: 16px;
max-width: 560px;
width: 100%;
margin: 0 auto;
}
.hello {
font-size: 22px;
font-weight: 700;
margin: 8px 4px 18px;
}
.tag {
display: inline-block;
font-size: 11px;
background: rgba(var(--green-rgb) / 0.14);
color: var(--wx-green-dark);
border-radius: 999px;
padding: 2px 9px;
margin-left: 8px;
vertical-align: middle;
font-weight: 600;
}
.tag-off {
background: rgba(var(--danger-rgb) / 0.14);
color: var(--danger);
}
/* 进入微信入口卡 */
.enter-card {
width: 100%;
border: none;
border-radius: var(--r-card);
padding: 20px;
display: flex;
align-items: center;
gap: 14px;
cursor: pointer;
text-align: left;
transition: transform 0.18s cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 0.18s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.enter-card:active {
transform: scale(0.985);
box-shadow: var(--crease-press);
}
.enter-icon {
position: relative;
width: 46px;
height: 46px;
flex: none;
border-radius: 14px;
background: var(--wx-green);
color: #fff;
font-size: 24px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: var(--crease-accent);
overflow: hidden;
}
.enter-icon::after {
content: '';
position: absolute;
inset: 0;
background: var(--sheen);
pointer-events: none;
}
.enter-text {
flex: 1;
}
.enter-title {
font-size: 17px;
font-weight: 600;
}
.enter-sub {
font-size: 13px;
color: var(--muted);
margin-top: 3px;
}
.enter-arrow {
color: #c2c7d0;
font-size: 22px;
}
/* 列表卡:行间用折痕细缝分隔,不用 border */
.list {
margin-top: 16px;
border-radius: var(--r-card);
overflow: hidden;
}
.list-item {
position: relative;
z-index: 1;
width: 100%;
background: none;
border: none;
box-shadow: inset 0 -1px 0 rgba(var(--shadow) / 0.08);
padding: 16px 18px;
font-size: 16px;
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
transition: background 0.18s;
}
.list-item:active {
background: rgba(var(--shadow) / 0.04);
}
.list-item:last-child {
box-shadow: none;
}
/* 子账号列表 */
.user-row {
position: relative;
z-index: 1;
padding: 14px 18px;
box-shadow: inset 0 -1px 0 rgba(var(--shadow) / 0.08);
}
.user-row:last-child {
box-shadow: none;
}
.user-main {
display: flex;
justify-content: space-between;
align-items: center;
}
.user-name {
font-size: 16px;
font-weight: 500;
}
.user-actions {
display: flex;
gap: 4px;
margin-top: 6px;
}
/* ── 微信安装/更新状态卡(启动下载 + 更新到最新版) ──────── */
.wx-state {
margin-top: 16px;
border-radius: var(--r-card);
padding: 20px;
}
.wx-state-row {
position: relative;
z-index: 1;
display: flex;
align-items: center;
gap: 14px;
}
.wx-state-text {
flex: 1;
min-width: 0;
}
.wx-state-title {
font-size: 16px;
font-weight: 600;
}
.wx-state-sub {
font-size: 13px;
color: var(--muted);
margin-top: 3px;
}
.wx-btn {
height: 40px;
flex: none;
padding: 0 18px;
border-radius: 999px;
font-size: 14px;
font-weight: 600;
}
/* 进度条:凹槽轨 + 绿色带光晕填充 */
.wx-progress {
position: relative;
z-index: 1;
margin-top: 16px;
height: 8px;
border-radius: 999px;
background: var(--trough);
box-shadow: inset 0 1px 2px rgba(var(--shadow) / 0.2);
overflow: hidden;
}
.wx-progress-bar {
height: 100%;
border-radius: 999px;
background: linear-gradient(90deg, var(--wx-green-dark), var(--wx-green));
box-shadow: 0 0 8px rgba(var(--green-rgb) / 0.5);
transition: width 0.4s cubic-bezier(0.2, 0.8, 0.2, 1);
}
/* 进度不确定(拿不到总大小)时来回滑动 */
.wx-progress-bar.indeterminate {
width: 40%;
transition: none;
animation: wx-slide 1.1s ease-in-out infinite;
}
@keyframes wx-slide {
0% {
margin-left: -40%;
}
100% {
margin-left: 100%;
}
}
.wx-progress-text {
position: relative;
z-index: 1;
margin-top: 8px;
font-size: 12px;
color: var(--muted);
text-align: right;
}
/* ── 弹窗 ──────────────────────────────────────────────── */
.modal-mask {
position: fixed;
inset: 0;
background: rgba(26, 29, 36, 0.4);
-webkit-backdrop-filter: blur(6px);
backdrop-filter: blur(6px);
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
z-index: 20;
}
.modal {
display: flex;
flex-direction: column;
gap: 12px;
border-radius: var(--r-card);
}
.modal h2 {
margin: 0 0 4px;
font-size: 18px;
font-weight: 700;
}
.modal-actions {
display: flex;
gap: 10px;
}
.modal-actions .btn {
flex: 1;
}
/* ── 桌面 ──────────────────────────────────────────────── */
.desktop-wrap {
position: fixed;
inset: 0;
background: #000;
}
.desktop-frame {
width: 100%;
height: 100%;
border: none;
display: block;
}
/* 返回钮:浮起白色圆 blob */
.desktop-back {
position: fixed;
top: max(12px, env(safe-area-inset-top));
left: 12px;
width: 42px;
height: 42px;
border-radius: 50%;
border: none;
background: var(--surface);
color: var(--text);
font-size: 24px;
line-height: 1;
cursor: pointer;
z-index: 10;
box-shadow: var(--crease);
transition: transform 0.18s cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 0.18s;
}
.desktop-back:active {
transform: scale(0.94);
box-shadow: var(--crease-press);
}
/* ── loading ───────────────────────────────────────────── */
.spinner {
width: 32px;
height: 32px;
border: 3px solid rgba(var(--green-rgb) / 0.2);
border-top-color: var(--wx-green);
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* ---------- 多实例:分区标题 ---------- */
.section-row {
display: flex;
align-items: center;
justify-content: space-between;
margin: 6px 6px 12px;
}
.section-title {
font-size: 15px;
font-weight: 700;
color: var(--text);
}
/* ---------- 实例网格 ---------- */
.inst-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 14px;
margin-bottom: 22px;
}
.inst-card {
position: relative;
background: var(--surface);
border-radius: var(--r-card);
box-shadow: var(--crease);
padding: 18px;
overflow: hidden;
}
.inst-card::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
background: var(--sheen);
pointer-events: none;
}
.inst-card > * {
position: relative;
}
.inst-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.inst-name {
font-size: 16px;
font-weight: 700;
color: var(--text);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.inst-sub {
margin-top: 6px;
font-size: 13px;
color: var(--muted);
min-height: 18px;
}
.inst-actions {
display: flex;
gap: 8px;
margin-top: 14px;
}
.inst-enter {
flex: 1;
}
.inst-act {
flex: none;
}
/* 状态徽章配色 */
.tag-on {
background: rgba(var(--green-rgb) / 0.16);
color: var(--wx-green-dark);
}
.tag-busy {
background: rgba(51 102 204 / 0.16);
color: #2f5fd0;
}
.tag-warn {
background: rgba(245 158 11 / 0.18);
color: #b9770a;
}
/* ---------- chip 多选 / 展示 ---------- */
.field-label {
font-size: 13px;
font-weight: 600;
color: var(--muted);
margin: 14px 2px 8px;
}
.chip-row {
display: inline-flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 4px;
}
.chip-row-pick {
display: flex;
}
.chip {
font-size: 12px;
border-radius: 999px;
padding: 5px 12px;
font-weight: 600;
line-height: 1.4;
}
.chip-static {
background: rgba(var(--green-rgb) / 0.12);
color: var(--wx-green-dark);
}
.chip-toggle {
border: none;
cursor: pointer;
background: var(--trough);
color: var(--muted);
box-shadow: inset 0 1px 2px rgba(var(--shadow) / 0.16);
transition: transform 0.15s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.chip-toggle:active {
transform: scale(0.95);
}
.chip-toggle.on {
background: var(--wx-green);
color: #fff;
box-shadow: var(--crease-accent);
}
/* ---------- 空状态 ---------- */
.empty-state {
text-align: center;
padding: 30px 16px 36px;
}
.empty-blob {
width: 96px;
height: 96px;
margin: 0 auto 16px;
border-radius: 50%;
background: var(--surface);
box-shadow: var(--crease);
display: flex;
align-items: center;
justify-content: center;
font-size: 40px;
position: relative;
overflow: hidden;
}
.empty-blob::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
background: var(--sheen);
}
.empty-title {
font-size: 16px;
font-weight: 700;
color: var(--text);
}
.empty-sub {
margin-top: 6px;
font-size: 13px;
color: var(--muted);
}