756 lines
14 KiB
Plaintext
756 lines
14 KiB
Plaintext
/**
|
||
* ============================================
|
||
* 🎨 企业级通用组件样式库
|
||
* ============================================
|
||
* 参考:Ant Design、Material Design、iOS HIG
|
||
*/
|
||
|
||
@import './design-tokens.wxss';
|
||
|
||
/* ==================== 按钮组件 ==================== */
|
||
|
||
.btn {
|
||
position: relative;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: var(--space-2);
|
||
padding: var(--space-4) var(--space-8);
|
||
border-radius: var(--radius-xl);
|
||
font-size: var(--font-size-base);
|
||
font-weight: var(--font-weight-medium);
|
||
line-height: var(--line-height-tight);
|
||
transition: var(--transition-base);
|
||
border: none;
|
||
outline: none;
|
||
overflow: hidden;
|
||
user-select: none;
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
|
||
.btn::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
width: 0;
|
||
height: 0;
|
||
border-radius: 50%;
|
||
background: rgba(255, 255, 255, 0.3);
|
||
transform: translate(-50%, -50%);
|
||
transition: width var(--duration-moderate) var(--ease-out),
|
||
height var(--duration-moderate) var(--ease-out);
|
||
}
|
||
|
||
.btn:active::before {
|
||
width: 200%;
|
||
height: 200%;
|
||
}
|
||
|
||
/* 主要按钮 */
|
||
.btn-primary {
|
||
background: var(--gradient-purple-dream);
|
||
color: var(--text-inverse);
|
||
box-shadow: var(--shadow-primary);
|
||
}
|
||
|
||
.btn-primary:active {
|
||
transform: translateY(2rpx);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
/* 次要按钮 */
|
||
.btn-secondary {
|
||
background: var(--bg-secondary);
|
||
color: var(--text-primary);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
/* 幽灵按钮 */
|
||
.btn-ghost {
|
||
background: transparent;
|
||
border: 2rpx solid var(--border-base);
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
/* 文本按钮 */
|
||
.btn-text {
|
||
background: transparent;
|
||
color: var(--brand-primary);
|
||
padding: var(--space-2) var(--space-4);
|
||
}
|
||
|
||
/* 危险按钮 */
|
||
.btn-danger {
|
||
background: linear-gradient(135deg, #FF6B6B 0%, #FF4757 100%);
|
||
color: var(--text-inverse);
|
||
box-shadow: var(--shadow-error);
|
||
}
|
||
|
||
/* 按钮尺寸 */
|
||
.btn-large {
|
||
padding: var(--space-6) var(--space-12);
|
||
font-size: var(--font-size-lg);
|
||
border-radius: var(--radius-2xl);
|
||
}
|
||
|
||
.btn-small {
|
||
padding: var(--space-2) var(--space-6);
|
||
font-size: var(--font-size-sm);
|
||
border-radius: var(--radius-md);
|
||
}
|
||
|
||
.btn-mini {
|
||
padding: var(--space-1) var(--space-4);
|
||
font-size: var(--font-size-xs);
|
||
border-radius: var(--radius-sm);
|
||
}
|
||
|
||
/* 块级按钮 */
|
||
.btn-block {
|
||
width: 100%;
|
||
}
|
||
|
||
/* 禁用状态 */
|
||
.btn-disabled {
|
||
opacity: 0.4;
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* 加载状态 */
|
||
.btn-loading {
|
||
pointer-events: none;
|
||
}
|
||
|
||
.btn-loading::after {
|
||
content: '';
|
||
display: inline-block;
|
||
width: 28rpx;
|
||
height: 28rpx;
|
||
margin-left: var(--space-2);
|
||
border: 3rpx solid currentColor;
|
||
border-right-color: transparent;
|
||
border-radius: 50%;
|
||
animation: btn-spin 0.6s linear infinite;
|
||
}
|
||
|
||
@keyframes btn-spin {
|
||
to { transform: rotate(360deg); }
|
||
}
|
||
|
||
/* ==================== 卡片组件 ==================== */
|
||
|
||
.card {
|
||
background: var(--bg-primary);
|
||
border-radius: var(--radius-2xl);
|
||
box-shadow: var(--shadow-sm);
|
||
overflow: hidden;
|
||
transition: var(--transition-base);
|
||
}
|
||
|
||
.card-hover {
|
||
cursor: pointer;
|
||
}
|
||
|
||
.card-hover:active {
|
||
transform: scale(0.98);
|
||
box-shadow: var(--shadow-md);
|
||
}
|
||
|
||
/* 卡片头部 */
|
||
.card-header {
|
||
padding: var(--space-6);
|
||
border-bottom: 1rpx solid var(--divider);
|
||
}
|
||
|
||
.card-title {
|
||
font-size: var(--font-size-lg);
|
||
font-weight: var(--font-weight-semibold);
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.card-subtitle {
|
||
margin-top: var(--space-1);
|
||
font-size: var(--font-size-sm);
|
||
color: var(--text-tertiary);
|
||
}
|
||
|
||
/* 卡片内容 */
|
||
.card-body {
|
||
padding: var(--space-6);
|
||
}
|
||
|
||
/* 卡片底部 */
|
||
.card-footer {
|
||
padding: var(--space-6);
|
||
border-top: 1rpx solid var(--divider);
|
||
background: var(--bg-secondary);
|
||
}
|
||
|
||
/* 渐变卡片 */
|
||
.card-gradient {
|
||
background: var(--gradient-purple-dream);
|
||
color: var(--text-inverse);
|
||
box-shadow: var(--shadow-primary);
|
||
}
|
||
|
||
/* 毛玻璃卡片 */
|
||
.card-glass {
|
||
background: var(--glass-white);
|
||
backdrop-filter: blur(var(--blur-lg));
|
||
border: 1rpx solid var(--glass-border);
|
||
box-shadow: var(--glass-shadow);
|
||
}
|
||
|
||
/* 边框卡片 */
|
||
.card-bordered {
|
||
border: 1rpx solid var(--border-base);
|
||
box-shadow: none;
|
||
}
|
||
|
||
/* 无阴影卡片 */
|
||
.card-flat {
|
||
box-shadow: none;
|
||
}
|
||
|
||
/* ==================== 头像组件 ==================== */
|
||
|
||
.avatar {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: var(--radius-full);
|
||
overflow: hidden;
|
||
background: var(--bg-tertiary);
|
||
color: var(--text-tertiary);
|
||
font-weight: var(--font-weight-medium);
|
||
}
|
||
|
||
.avatar-sm {
|
||
width: 48rpx;
|
||
height: 48rpx;
|
||
font-size: var(--font-size-xs);
|
||
}
|
||
|
||
.avatar-base {
|
||
width: 64rpx;
|
||
height: 64rpx;
|
||
font-size: var(--font-size-sm);
|
||
}
|
||
|
||
.avatar-lg {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
font-size: var(--font-size-base);
|
||
}
|
||
|
||
.avatar-xl {
|
||
width: 120rpx;
|
||
height: 120rpx;
|
||
font-size: var(--font-size-lg);
|
||
}
|
||
|
||
.avatar-2xl {
|
||
width: 160rpx;
|
||
height: 160rpx;
|
||
font-size: var(--font-size-xl);
|
||
}
|
||
|
||
.avatar-img {
|
||
width: 100%;
|
||
height: 100%;
|
||
object-fit: cover;
|
||
}
|
||
|
||
/* 头像组 */
|
||
.avatar-group {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.avatar-group .avatar {
|
||
margin-left: calc(var(--space-2) * -1);
|
||
border: 3rpx solid var(--bg-primary);
|
||
}
|
||
|
||
.avatar-group .avatar:first-child {
|
||
margin-left: 0;
|
||
}
|
||
|
||
/* ==================== 徽标组件 ==================== */
|
||
|
||
.badge {
|
||
position: relative;
|
||
display: inline-flex;
|
||
}
|
||
|
||
.badge-dot {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
width: 16rpx;
|
||
height: 16rpx;
|
||
border-radius: 50%;
|
||
background: var(--color-error);
|
||
border: 3rpx solid var(--bg-primary);
|
||
}
|
||
|
||
.badge-count {
|
||
position: absolute;
|
||
top: -8rpx;
|
||
right: -8rpx;
|
||
min-width: 32rpx;
|
||
height: 32rpx;
|
||
padding: 0 8rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: var(--radius-full);
|
||
background: var(--color-error);
|
||
color: var(--text-inverse);
|
||
font-size: var(--font-size-xs);
|
||
font-weight: var(--font-weight-medium);
|
||
line-height: 1;
|
||
white-space: nowrap;
|
||
border: 2rpx solid var(--bg-primary);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
/* 标签徽标 */
|
||
.tag {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: var(--space-1);
|
||
padding: var(--space-1) var(--space-3);
|
||
border-radius: var(--radius-base);
|
||
font-size: var(--font-size-xs);
|
||
font-weight: var(--font-weight-medium);
|
||
line-height: var(--line-height-tight);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.tag-primary {
|
||
background: rgba(102, 126, 234, 0.1);
|
||
color: var(--brand-primary);
|
||
}
|
||
|
||
.tag-success {
|
||
background: var(--color-success-bg);
|
||
color: var(--color-success);
|
||
}
|
||
|
||
.tag-warning {
|
||
background: var(--color-warning-bg);
|
||
color: var(--color-warning);
|
||
}
|
||
|
||
.tag-error {
|
||
background: var(--color-error-bg);
|
||
color: var(--color-error);
|
||
}
|
||
|
||
.tag-info {
|
||
background: var(--color-info-bg);
|
||
color: var(--color-info);
|
||
}
|
||
|
||
/* ==================== 分割线组件 ==================== */
|
||
|
||
.divider {
|
||
height: 1rpx;
|
||
background: var(--divider);
|
||
border: none;
|
||
margin: var(--space-6) 0;
|
||
}
|
||
|
||
.divider-vertical {
|
||
width: 1rpx;
|
||
height: auto;
|
||
margin: 0 var(--space-4);
|
||
display: inline-block;
|
||
}
|
||
|
||
.divider-text {
|
||
position: relative;
|
||
text-align: center;
|
||
margin: var(--space-6) 0;
|
||
}
|
||
|
||
.divider-text::before,
|
||
.divider-text::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: 50%;
|
||
width: calc(50% - 60rpx);
|
||
height: 1rpx;
|
||
background: var(--divider);
|
||
}
|
||
|
||
.divider-text::before {
|
||
left: 0;
|
||
}
|
||
|
||
.divider-text::after {
|
||
right: 0;
|
||
}
|
||
|
||
.divider-text-content {
|
||
position: relative;
|
||
padding: 0 var(--space-4);
|
||
color: var(--text-tertiary);
|
||
font-size: var(--font-size-sm);
|
||
background: var(--bg-primary);
|
||
}
|
||
|
||
/* ==================== 空状态组件 ==================== */
|
||
|
||
.empty-state {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: var(--space-20) var(--space-6);
|
||
text-align: center;
|
||
}
|
||
|
||
.empty-icon {
|
||
font-size: 120rpx;
|
||
margin-bottom: var(--space-6);
|
||
opacity: 0.5;
|
||
}
|
||
|
||
.empty-title {
|
||
font-size: var(--font-size-lg);
|
||
font-weight: var(--font-weight-medium);
|
||
color: var(--text-secondary);
|
||
margin-bottom: var(--space-2);
|
||
}
|
||
|
||
.empty-description {
|
||
font-size: var(--font-size-sm);
|
||
color: var(--text-tertiary);
|
||
line-height: var(--line-height-relaxed);
|
||
max-width: 400rpx;
|
||
}
|
||
|
||
.empty-action {
|
||
margin-top: var(--space-8);
|
||
}
|
||
|
||
/* ==================== 骨架屏组件 ==================== */
|
||
|
||
.skeleton {
|
||
background: linear-gradient(90deg,
|
||
var(--bg-tertiary) 25%,
|
||
var(--bg-secondary) 50%,
|
||
var(--bg-tertiary) 75%
|
||
);
|
||
background-size: 200% 100%;
|
||
animation: skeleton-loading 1.5s ease-in-out infinite;
|
||
border-radius: var(--radius-base);
|
||
}
|
||
|
||
@keyframes skeleton-loading {
|
||
0% {
|
||
background-position: 200% 0;
|
||
}
|
||
100% {
|
||
background-position: -200% 0;
|
||
}
|
||
}
|
||
|
||
.skeleton-text {
|
||
height: 28rpx;
|
||
margin-bottom: var(--space-3);
|
||
}
|
||
|
||
.skeleton-title {
|
||
height: 40rpx;
|
||
width: 60%;
|
||
margin-bottom: var(--space-4);
|
||
}
|
||
|
||
.skeleton-avatar {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
border-radius: var(--radius-full);
|
||
}
|
||
|
||
.skeleton-image {
|
||
width: 100%;
|
||
height: 400rpx;
|
||
border-radius: var(--radius-xl);
|
||
}
|
||
|
||
.skeleton-button {
|
||
height: 72rpx;
|
||
width: 160rpx;
|
||
border-radius: var(--radius-xl);
|
||
}
|
||
|
||
/* ==================== 加载组件 ==================== */
|
||
|
||
.loading-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: var(--space-12);
|
||
}
|
||
|
||
.loading-spinner {
|
||
width: 64rpx;
|
||
height: 64rpx;
|
||
border: 6rpx solid var(--border-light);
|
||
border-top-color: var(--brand-primary);
|
||
border-radius: 50%;
|
||
animation: spinner-rotate 0.8s linear infinite;
|
||
}
|
||
|
||
@keyframes spinner-rotate {
|
||
to { transform: rotate(360deg); }
|
||
}
|
||
|
||
.loading-dots {
|
||
display: flex;
|
||
gap: var(--space-3);
|
||
}
|
||
|
||
.loading-dot {
|
||
width: 16rpx;
|
||
height: 16rpx;
|
||
border-radius: 50%;
|
||
background: var(--brand-primary);
|
||
animation: dot-bounce 1.4s ease-in-out infinite;
|
||
}
|
||
|
||
.loading-dot:nth-child(1) {
|
||
animation-delay: -0.32s;
|
||
}
|
||
|
||
.loading-dot:nth-child(2) {
|
||
animation-delay: -0.16s;
|
||
}
|
||
|
||
@keyframes dot-bounce {
|
||
0%, 80%, 100% {
|
||
transform: scale(0);
|
||
opacity: 0.5;
|
||
}
|
||
40% {
|
||
transform: scale(1);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
.loading-text {
|
||
margin-top: var(--space-4);
|
||
font-size: var(--font-size-sm);
|
||
color: var(--text-tertiary);
|
||
}
|
||
|
||
/* ==================== 遮罩组件 ==================== */
|
||
|
||
.overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: var(--bg-mask);
|
||
z-index: var(--z-index-modal-backdrop);
|
||
animation: overlay-fadein var(--duration-normal) var(--ease-out);
|
||
}
|
||
|
||
@keyframes overlay-fadein {
|
||
from { opacity: 0; }
|
||
to { opacity: 1; }
|
||
}
|
||
|
||
/* ==================== 模态框组件 ==================== */
|
||
|
||
.modal {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: var(--space-8);
|
||
z-index: var(--z-index-modal);
|
||
animation: modal-fadein var(--duration-normal) var(--ease-out);
|
||
}
|
||
|
||
@keyframes modal-fadein {
|
||
from {
|
||
opacity: 0;
|
||
transform: scale(0.9);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: scale(1);
|
||
}
|
||
}
|
||
|
||
.modal-content {
|
||
width: 100%;
|
||
max-width: 600rpx;
|
||
background: var(--bg-primary);
|
||
border-radius: var(--radius-2xl);
|
||
box-shadow: var(--shadow-2xl);
|
||
overflow: hidden;
|
||
animation: modal-slideup var(--duration-moderate) var(--ease-out);
|
||
}
|
||
|
||
@keyframes modal-slideup {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(40rpx);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
.modal-header {
|
||
position: relative;
|
||
padding: var(--space-8);
|
||
border-bottom: 1rpx solid var(--divider);
|
||
}
|
||
|
||
.modal-title {
|
||
font-size: var(--font-size-xl);
|
||
font-weight: var(--font-weight-semibold);
|
||
color: var(--text-primary);
|
||
text-align: center;
|
||
}
|
||
|
||
.modal-close {
|
||
position: absolute;
|
||
top: var(--space-6);
|
||
right: var(--space-6);
|
||
width: 56rpx;
|
||
height: 56rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: var(--radius-full);
|
||
background: var(--bg-hover);
|
||
color: var(--text-tertiary);
|
||
font-size: var(--font-size-lg);
|
||
transition: var(--transition-fast);
|
||
}
|
||
|
||
.modal-close:active {
|
||
background: var(--bg-active);
|
||
transform: scale(0.9);
|
||
}
|
||
|
||
.modal-body {
|
||
padding: var(--space-8);
|
||
max-height: 800rpx;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.modal-footer {
|
||
padding: var(--space-6) var(--space-8);
|
||
border-top: 1rpx solid var(--divider);
|
||
display: flex;
|
||
gap: var(--space-4);
|
||
}
|
||
|
||
.modal-footer .btn {
|
||
flex: 1;
|
||
}
|
||
|
||
/* ==================== Toast 组件 ==================== */
|
||
|
||
.toast {
|
||
position: fixed;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
padding: var(--space-6) var(--space-8);
|
||
background: rgba(0, 0, 0, 0.8);
|
||
backdrop-filter: blur(var(--blur-md));
|
||
color: var(--text-inverse);
|
||
border-radius: var(--radius-xl);
|
||
font-size: var(--font-size-base);
|
||
text-align: center;
|
||
z-index: var(--z-index-notification);
|
||
animation: toast-show var(--duration-normal) var(--ease-out);
|
||
max-width: 500rpx;
|
||
box-shadow: var(--shadow-lg);
|
||
}
|
||
|
||
@keyframes toast-show {
|
||
from {
|
||
opacity: 0;
|
||
transform: translate(-50%, -50%) scale(0.8);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translate(-50%, -50%) scale(1);
|
||
}
|
||
}
|
||
|
||
.toast-icon {
|
||
font-size: 64rpx;
|
||
margin-bottom: var(--space-3);
|
||
}
|
||
|
||
/* ==================== 输入框组件 ==================== */
|
||
|
||
.input-group {
|
||
margin-bottom: var(--space-6);
|
||
}
|
||
|
||
.input-label {
|
||
display: block;
|
||
margin-bottom: var(--space-2);
|
||
font-size: var(--font-size-sm);
|
||
font-weight: var(--font-weight-medium);
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.input-field {
|
||
width: 100%;
|
||
padding: var(--space-4) var(--space-6);
|
||
border: 2rpx solid var(--border-base);
|
||
border-radius: var(--radius-xl);
|
||
font-size: var(--font-size-base);
|
||
color: var(--text-primary);
|
||
background: var(--bg-primary);
|
||
transition: var(--transition-fast);
|
||
}
|
||
|
||
.input-field:focus {
|
||
border-color: var(--brand-primary);
|
||
box-shadow: 0 0 0 6rpx rgba(102, 126, 234, 0.1);
|
||
}
|
||
|
||
.input-field::placeholder {
|
||
color: var(--text-quaternary);
|
||
}
|
||
|
||
.input-error {
|
||
border-color: var(--color-error);
|
||
}
|
||
|
||
.input-error:focus {
|
||
box-shadow: 0 0 0 6rpx var(--color-error-bg);
|
||
}
|
||
|
||
.input-helper {
|
||
margin-top: var(--space-2);
|
||
font-size: var(--font-size-xs);
|
||
color: var(--text-tertiary);
|
||
}
|
||
|
||
.input-error-text {
|
||
color: var(--color-error);
|
||
}
|