From 58e2d0603bc8ac907fbc0c2c686cd1d92f96b6f5 Mon Sep 17 00:00:00 2001 From: nepiedg Date: Sat, 18 Apr 2026 11:12:59 +0800 Subject: [PATCH] refactor(styles): centralize global theme tokens and mixins --- src/App.vue | 257 ++++++++++++++++++------------------- src/styles/_mixins.scss | 250 ++++++++++++++++++++++++++++++++++++ src/styles/_variables.scss | 112 ++++++++++++++++ src/uni.scss | 87 +++++-------- 4 files changed, 521 insertions(+), 185 deletions(-) create mode 100644 src/styles/_mixins.scss create mode 100644 src/styles/_variables.scss diff --git a/src/App.vue b/src/App.vue index db505f6..75ab31c 100644 --- a/src/App.vue +++ b/src/App.vue @@ -49,177 +49,174 @@ export default { } - diff --git a/src/styles/_mixins.scss b/src/styles/_mixins.scss new file mode 100644 index 0000000..48f30aa --- /dev/null +++ b/src/styles/_mixins.scss @@ -0,0 +1,250 @@ +// ========================================== +// 统一 SCSS Mixins +// ========================================== + +// ---- 卡片 ---- +@mixin card-base { + background: $bg-card-glass; + border-radius: $radius-xl; + padding: $spacing-lg; + border: 1.5rpx solid $border-card; + box-shadow: $shadow-card; +} + +@mixin card-solid { + background: $bg-card; + border-radius: $radius-2xl; + padding: $spacing-xl; + box-shadow: $shadow-sm; +} + +@mixin card-glass { + background: $bg-card-glass; + border-radius: $radius-xl; + padding: $spacing-lg; + border: 1.5rpx solid $border-card; + box-shadow: $shadow-card; + -webkit-backdrop-filter: blur(12px); + backdrop-filter: blur(12px); +} + +@mixin card-elevated { + @include card-base; + box-shadow: $shadow-md; + border-color: $border-light; +} + +@mixin card-subtle { + background: $gradient-card-subtle; + border-radius: $radius-md; + padding: $spacing-lg; + border: 1rpx solid $border-light; + box-shadow: inset 0 1rpx 0 rgba(255, 255, 255, 0.9); +} + +// ---- 按钮 ---- +@mixin btn-base { + display: flex; + align-items: center; + justify-content: center; + border-radius: $radius-full; + font-weight: $font-weight-bold; + transition: all $transition-fast; +} + +@mixin btn-primary { + @include btn-base; + height: 96rpx; + background: $gradient-primary; + color: $text-inverse; + font-size: $font-lg; + box-shadow: $shadow-btn; +} + +@mixin btn-secondary { + @include btn-base; + height: 96rpx; + background: $bg-card; + color: $text-primary; + font-size: $font-lg; + border: 2rpx solid $border-light; + box-shadow: $shadow-sm; +} + +@mixin btn-outline { + @include btn-base; + height: 96rpx; + background: transparent; + color: $color-primary-dark; + font-size: $font-lg; + border: 2rpx solid rgba($color-primary, 0.32); +} + +@mixin btn-pill { + @include btn-base; + padding: $spacing-xs $spacing-lg; + font-size: $font-sm; + font-weight: $font-weight-semibold; +} + +// ---- 标签/徽章 ---- +@mixin chip { + display: inline-flex; + align-items: center; + justify-content: center; + padding: $spacing-xs $spacing-md; + border-radius: $radius-full; + font-size: $font-sm; + font-weight: $font-weight-semibold; +} + +@mixin chip-primary { + @include chip; + background: $color-primary-bg; + color: $color-primary-dark; + border: 1rpx solid $color-primary-border; +} + +@mixin chip-muted { + @include chip; + background: $bg-muted; + color: $text-muted; +} + +@mixin badge { + @include chip; + font-size: $font-xs; + padding: 6rpx 14rpx; + background: $color-primary-bg; + color: $color-primary-dark; +} + +// ---- 进度条 ---- +@mixin progress-bar($height: 10rpx) { + height: $height; + background: rgba($color-primary, 0.1); + border-radius: $radius-full; + overflow: hidden; +} + +@mixin progress-fill { + height: 100%; + border-radius: $radius-full; + background: linear-gradient(90deg, $color-primary, $color-primary-light); + transition: width $transition-slow; +} + +// ---- 圆环 ---- +@mixin ring($size: 110rpx) { + width: $size; + height: $size; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +@mixin ring-inner { + border-radius: 50%; + background: $bg-card; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + box-shadow: 0 4rpx 12rpx $color-primary-shadow; +} + +// ---- 布局 ---- +@mixin flex-center { + display: flex; + align-items: center; + justify-content: center; +} + +@mixin flex-between { + display: flex; + align-items: center; + justify-content: space-between; +} + +@mixin flex-col { + display: flex; + flex-direction: column; +} + +// ---- 文字 ---- +@mixin text-number { + font-family: $font-family-number; + font-weight: $font-weight-heavy; +} + +@mixin text-heading { + font-weight: $font-weight-bold; + color: $text-primary; +} + +@mixin text-label { + font-size: $font-sm; + color: $text-tertiary; +} + +@mixin text-kicker { + font-size: $font-xs; + font-weight: $font-weight-semibold; + color: $text-muted; +} + +// ---- 动画骨架 ---- +@mixin skeleton-shimmer { + background: linear-gradient(90deg, #E5E7EB 25%, #F3F4F6 50%, #E5E7EB 75%); + background-size: 200% 100%; + animation: shimmer 1.5s infinite; +} + +// ---- 安全区域 ---- +@mixin safe-area-bottom { + padding-bottom: constant(safe-area-inset-bottom); + padding-bottom: env(safe-area-inset-bottom); +} + +// ---- 悬浮按钮 ---- +@mixin fab { + position: fixed; + z-index: 100; + border-radius: $radius-full; + background: $gradient-primary; + box-shadow: $shadow-fab; + display: flex; + align-items: center; + justify-content: center; + animation: fabFloat 3.6s ease-in-out infinite; +} + +// ---- 空状态 ---- +@mixin empty-state { + @include flex-col; + align-items: center; + padding: 80rpx $spacing-xl; + border-radius: $radius-2xl; + background: $gradient-card; + box-shadow: $shadow-md; +} + +// ---- 菜单项 ---- +@mixin menu-item { + display: flex; + align-items: center; + gap: $spacing-lg; + padding: $spacing-lg 0; + background: transparent; +} + +@mixin menu-icon($bg: $color-primary-soft) { + width: 72rpx; + height: 72rpx; + border-radius: 50%; + @include flex-center; + flex-shrink: 0; + background: $bg; +} diff --git a/src/styles/_variables.scss b/src/styles/_variables.scss new file mode 100644 index 0000000..7b174d4 --- /dev/null +++ b/src/styles/_variables.scss @@ -0,0 +1,112 @@ +// ========================================== +// 薄荷绿浅色系主题 - 统一设计变量 +// ========================================== + +// ---- 主色调 (薄荷绿) ---- +$color-primary: #34C8A0; +$color-primary-dark: #1AA37A; +$color-primary-deeper: #14936d; +$color-primary-light: #6ee7be; +$color-primary-soft: #E6F7F1; +$color-primary-softer: #F0FDF9; +$color-primary-bg: rgba(52, 200, 160, 0.08); +$color-primary-border: rgba(52, 200, 160, 0.14); +$color-primary-shadow: rgba(52, 200, 160, 0.12); + +// ---- 功能色 ---- +$color-success: #10B981; +$color-warning: #F59E0B; +$color-warning-bg: #FEF3C7; +$color-warning-text: #D97706; +$color-danger: #EF4444; +$color-danger-bg: rgba(239, 68, 68, 0.06); +$color-info: #3B82F6; +$color-info-bg: rgba(59, 130, 246, 0.08); + +// ---- 文字色 ---- +$text-primary: #111827; +$text-secondary: #4b5563; +$text-tertiary: #6b7280; +$text-muted: #9ca3af; +$text-disabled: #d1d5db; +$text-inverse: #ffffff; +$text-accent: $color-primary-dark; + +// ---- 背景色 ---- +$bg-page: #F5F8F6; +$bg-page-gradient: linear-gradient(180deg, $color-primary-soft 0%, $color-primary-softer 40%, #FAFFFE 100%); +$bg-card: #ffffff; +$bg-card-glass: rgba(255, 255, 255, 0.88); +$bg-card-hover: #f7faf8; +$bg-subtle: #fbfcfc; +$bg-muted: #f3f4f6; + +// ---- 边框 ---- +$border-light: rgba(15, 23, 42, 0.06); +$border-card: $color-primary-border; +$border-divider: #f0f0f0; + +// ---- 圆角 ---- +$radius-xs: 8rpx; +$radius-sm: 12rpx; +$radius-md: 16rpx; +$radius-lg: 20rpx; +$radius-xl: 24rpx; +$radius-2xl: 32rpx; +$radius-full: 999rpx; + +// ---- 间距 ---- +$spacing-xs: 8rpx; +$spacing-sm: 12rpx; +$spacing-md: 16rpx; +$spacing-lg: 24rpx; +$spacing-xl: 32rpx; +$spacing-2xl: 40rpx; +$spacing-page: 28rpx; + +// ---- 阴影 ---- +$shadow-sm: 0 4rpx 12rpx rgba(52, 200, 160, 0.06); +$shadow-card: 0 4rpx 18rpx rgba(52, 200, 160, 0.07); +$shadow-md: 0 8rpx 24rpx rgba(15, 23, 42, 0.06); +$shadow-lg: 0 18rpx 36rpx rgba(15, 23, 42, 0.08); +$shadow-btn: 0 12rpx 28rpx rgba(52, 200, 160, 0.22); +$shadow-fab: 0 18rpx 36rpx rgba(52, 200, 160, 0.3); + +// ---- 字号 ---- +$font-xs: 20rpx; +$font-sm: 22rpx; +$font-base: 24rpx; +$font-md: 26rpx; +$font-lg: 28rpx; +$font-xl: 30rpx; +$font-2xl: 34rpx; +$font-3xl: 40rpx; +$font-4xl: 52rpx; +$font-display: 74rpx; + +// ---- 字重 ---- +$font-weight-normal: 400; +$font-weight-medium: 500; +$font-weight-semibold: 600; +$font-weight-bold: 700; +$font-weight-heavy: 800; + +// ---- 行高 ---- +$line-height-tight: 1.2; +$line-height-normal: 1.5; +$line-height-relaxed: 1.7; + +// ---- 字体 ---- +$font-family-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; +$font-family-number: 'DIN Alternate', $font-family-base; + +// ---- 渐变 ---- +$gradient-primary: linear-gradient(180deg, $color-primary 0%, $color-primary-dark 100%); +$gradient-primary-soft: linear-gradient(180deg, $color-primary-soft 0%, $color-primary-softer 100%); +$gradient-card: linear-gradient(180deg, rgba(255, 255, 255, 0.98) 0%, rgba(248, 251, 249, 0.94) 100%); +$gradient-card-subtle: linear-gradient(180deg, $bg-subtle 0%, $bg-card-hover 100%); + +// ---- 动画 ---- +$transition-fast: 0.2s ease; +$transition-normal: 0.3s ease; +$transition-slow: 0.5s ease; diff --git a/src/uni.scss b/src/uni.scss index b9249e9..83311fc 100644 --- a/src/uni.scss +++ b/src/uni.scss @@ -1,76 +1,53 @@ /** - * 这里是uni-app内置的常用样式变量 - * - * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 - * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App - * + * 薄荷绿浅色系主题 - uni-app 全局 SCSS 变量 + * 所有页面自动注入,无需手动 import */ -/** - * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 - * - * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 - */ +@import './styles/variables'; +@import './styles/mixins'; -/* 颜色变量 */ - -/* 行为相关颜色 */ -$uni-color-primary: #007aff; -$uni-color-success: #4cd964; -$uni-color-warning: #f0ad4e; -$uni-color-error: #dd524d; +/* 覆盖 uni-app 默认颜色变量 */ +$uni-color-primary: $color-primary-dark; +$uni-color-success: $color-success; +$uni-color-warning: $color-warning; +$uni-color-error: $color-danger; /* 文字基本颜色 */ -$uni-text-color:#333;//基本色 -$uni-text-color-inverse:#fff;//反色 -$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 -$uni-text-color-placeholder: #808080; -$uni-text-color-disable:#c0c0c0; +$uni-text-color: $text-primary; +$uni-text-color-inverse: $text-inverse; +$uni-text-color-grey: $text-tertiary; +$uni-text-color-placeholder: $text-muted; +$uni-text-color-disable: $text-disabled; /* 背景颜色 */ -$uni-bg-color:#ffffff; -$uni-bg-color-grey:#f8f8f8; -$uni-bg-color-hover:#f1f1f1;//点击状态颜色 -$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 +$uni-bg-color: $bg-card; +$uni-bg-color-grey: $bg-page; +$uni-bg-color-hover: $bg-card-hover; +$uni-bg-color-mask: rgba(0, 0, 0, 0.4); /* 边框颜色 */ -$uni-border-color:#c8c7cc; - -/* 尺寸变量 */ +$uni-border-color: $border-divider; /* 文字尺寸 */ -$uni-font-size-sm:12px; -$uni-font-size-base:14px; -$uni-font-size-lg:16px; - -/* 图片尺寸 */ -$uni-img-size-sm:20px; -$uni-img-size-base:26px; -$uni-img-size-lg:40px; +$uni-font-size-sm: $font-sm; +$uni-font-size-base: $font-base; +$uni-font-size-lg: $font-md; /* Border Radius */ -$uni-border-radius-sm: 2px; -$uni-border-radius-base: 3px; -$uni-border-radius-lg: 6px; +$uni-border-radius-sm: $radius-xs; +$uni-border-radius-base: $radius-sm; +$uni-border-radius-lg: $radius-md; $uni-border-radius-circle: 50%; /* 水平间距 */ -$uni-spacing-row-sm: 5px; -$uni-spacing-row-base: 10px; -$uni-spacing-row-lg: 15px; +$uni-spacing-row-sm: $spacing-xs; +$uni-spacing-row-base: $spacing-md; +$uni-spacing-row-lg: $spacing-lg; /* 垂直间距 */ -$uni-spacing-col-sm: 4px; -$uni-spacing-col-base: 8px; -$uni-spacing-col-lg: 12px; +$uni-spacing-col-sm: $spacing-xs; +$uni-spacing-col-base: $spacing-sm; +$uni-spacing-col-lg: $spacing-md; /* 透明度 */ -$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 - -/* 文章场景相关 */ -$uni-color-title: #2C405A; // 文章标题颜色 -$uni-font-size-title:20px; -$uni-color-subtitle: #555555; // 二级标题颜色 -$uni-font-size-subtitle:26px; -$uni-color-paragraph: #3F536E; // 文章段落颜色 -$uni-font-size-paragraph:15px; +$uni-opacity-disabled: 0.3;