修改UI风格为粘土拟态风格
This commit is contained in:
parent
90110f5bce
commit
2a98cde85f
271
components/ClayButton.vue
Normal file
271
components/ClayButton.vue
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
<template>
|
||||||
|
<view
|
||||||
|
class="clay-button-wrapper"
|
||||||
|
:class="[
|
||||||
|
`clay-btn-${size}`,
|
||||||
|
{ 'clay-btn-block': block },
|
||||||
|
{ 'clay-btn-disabled': disabled }
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
class="clay-button"
|
||||||
|
:class="[
|
||||||
|
`clay-btn-${variant}`,
|
||||||
|
{ 'clay-btn-outline': outline },
|
||||||
|
{ 'is-loading': loading }
|
||||||
|
]"
|
||||||
|
:style="customStyle"
|
||||||
|
@tap="handleTap"
|
||||||
|
>
|
||||||
|
<!-- 加载动画 -->
|
||||||
|
<view v-if="loading" class="clay-loading">
|
||||||
|
<view class="loading-spinner"></view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 图标 -->
|
||||||
|
<view v-if="icon && !loading" class="clay-icon">
|
||||||
|
<text>{{ icon }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 按钮文字 -->
|
||||||
|
<text class="clay-text">{{ text }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ClayButton',
|
||||||
|
props: {
|
||||||
|
// 按钮文字
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: '按钮'
|
||||||
|
},
|
||||||
|
// 尺寸:sm, md, lg
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: 'md'
|
||||||
|
},
|
||||||
|
// 变体:primary, secondary, success, warning, error
|
||||||
|
variant: {
|
||||||
|
type: String,
|
||||||
|
default: 'primary'
|
||||||
|
},
|
||||||
|
// 是否轮廓样式
|
||||||
|
outline: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否块级按钮
|
||||||
|
block: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否禁用
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否加载中
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 图标(emoji)
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 自定义样式
|
||||||
|
customStyle: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleTap(e) {
|
||||||
|
if (this.disabled || this.loading) return
|
||||||
|
this.$emit('tap', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
/* ============================================
|
||||||
|
Claymorphism 按钮组件
|
||||||
|
使用示例:
|
||||||
|
<ClayButton text="确认" variant="primary" size="lg" @tap="handleConfirm" />
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
.clay-button-wrapper {
|
||||||
|
display: inline-flex;
|
||||||
|
|
||||||
|
&.clay-btn-block {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-btn-disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.clay-button {
|
||||||
|
border-radius: 50rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
border: none;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8rpx;
|
||||||
|
|
||||||
|
/* Claymorphism 双阴影 - 创造凸起感 */
|
||||||
|
box-shadow:
|
||||||
|
8rpx 8rpx 16rpx rgba(0, 0, 0, 0.08),
|
||||||
|
-8rpx -8rpx 16rpx rgba(255, 255, 255, 0.8),
|
||||||
|
inset 2rpx 2rpx 4rpx rgba(255, 255, 255, 0.5),
|
||||||
|
inset -2rpx -2rpx 4rpx rgba(0, 0, 0, 0.05);
|
||||||
|
|
||||||
|
&.clay-btn-sm {
|
||||||
|
padding: 12rpx 32rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
border-radius: 40rpx;
|
||||||
|
box-shadow:
|
||||||
|
6rpx 6rpx 12rpx rgba(0, 0, 0, 0.06),
|
||||||
|
-6rpx -6rpx 12rpx rgba(255, 255, 255, 0.8),
|
||||||
|
inset 2rpx 2rpx 4rpx rgba(255, 255, 255, 0.5),
|
||||||
|
inset -2rpx -2rpx 4rpx rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-btn-md {
|
||||||
|
padding: 20rpx 48rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
border-radius: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-btn-lg {
|
||||||
|
padding: 28rpx 64rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
border-radius: 60rpx;
|
||||||
|
box-shadow:
|
||||||
|
10rpx 10rpx 20rpx rgba(0, 0, 0, 0.1),
|
||||||
|
-10rpx -10rpx 20rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 3rpx 3rpx 6rpx rgba(255, 255, 255, 0.5),
|
||||||
|
inset -3rpx -3rpx 6rpx rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 按钮变体 */
|
||||||
|
&.clay-btn-primary {
|
||||||
|
background: linear-gradient(145deg, #FF9500, #FF6B00);
|
||||||
|
color: #fff;
|
||||||
|
box-shadow:
|
||||||
|
10rpx 10rpx 20rpx rgba(255, 107, 0, 0.15),
|
||||||
|
-10rpx -10rpx 20rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 3rpx 3rpx 6rpx rgba(255, 255, 255, 0.4),
|
||||||
|
inset -3rpx -3rpx 6rpx rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-btn-secondary {
|
||||||
|
background: linear-gradient(145deg, #ffffff, #f0f0f0);
|
||||||
|
color: #1D1D1F;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-btn-success {
|
||||||
|
background: linear-gradient(145deg, #34C759, #30D158);
|
||||||
|
color: #fff;
|
||||||
|
box-shadow:
|
||||||
|
10rpx 10rpx 20rpx rgba(52, 199, 89, 0.15),
|
||||||
|
-10rpx -10rpx 20rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 3rpx 3rpx 6rpx rgba(255, 255, 255, 0.4),
|
||||||
|
inset -3rpx -3rpx 6rpx rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-btn-warning {
|
||||||
|
background: linear-gradient(145deg, #FF9F0A, #FF9500);
|
||||||
|
color: #fff;
|
||||||
|
box-shadow:
|
||||||
|
10rpx 10rpx 20rpx rgba(255, 159, 10, 0.15),
|
||||||
|
-10rpx -10rpx 20rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 3rpx 3rpx 6rpx rgba(255, 255, 255, 0.4),
|
||||||
|
inset -3rpx -3rpx 6rpx rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-btn-error {
|
||||||
|
background: linear-gradient(145deg, #FF3B30, #FF453A);
|
||||||
|
color: #fff;
|
||||||
|
box-shadow:
|
||||||
|
10rpx 10rpx 20rpx rgba(255, 59, 48, 0.15),
|
||||||
|
-10rpx -10rpx 20rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 3rpx 3rpx 6rpx rgba(255, 255, 255, 0.4),
|
||||||
|
inset -3rpx -3rpx 6rpx rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 轮廓样式 */
|
||||||
|
&.clay-btn-outline {
|
||||||
|
background: transparent;
|
||||||
|
border: 3rpx solid currentColor;
|
||||||
|
|
||||||
|
&.clay-btn-primary {
|
||||||
|
color: #FF6B00;
|
||||||
|
background: rgba(255, 107, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-btn-secondary {
|
||||||
|
color: #86868B;
|
||||||
|
background: rgba(134, 134, 139, 0.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 按下效果 */
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.96);
|
||||||
|
box-shadow:
|
||||||
|
4rpx 4rpx 8rpx rgba(0, 0, 0, 0.1),
|
||||||
|
-4rpx -4rpx 8rpx rgba(255, 255, 255, 0.5),
|
||||||
|
inset 4rpx 4rpx 8rpx rgba(0, 0, 0, 0.08),
|
||||||
|
inset -4rpx -4rpx 8rpx rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载状态 */
|
||||||
|
&.is-loading {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载动画 */
|
||||||
|
.clay-loading {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
width: 32rpx;
|
||||||
|
height: 32rpx;
|
||||||
|
border: 4rpx solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-top-color: #fff;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: clay-spin 0.8s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes clay-spin {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 图标 */
|
||||||
|
.clay-icon {
|
||||||
|
font-size: 32rpx;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 文字 */
|
||||||
|
.clay-text {
|
||||||
|
line-height: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
151
components/ClayCard.vue
Normal file
151
components/ClayCard.vue
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
<template>
|
||||||
|
<view
|
||||||
|
class="clay-card"
|
||||||
|
:class="[
|
||||||
|
`clay-card-${size}`,
|
||||||
|
{ 'clay-card-primary': variant === 'primary' },
|
||||||
|
{ 'clay-card-gold': variant === 'gold' },
|
||||||
|
{ 'clay-card-inset': inset },
|
||||||
|
customClass
|
||||||
|
]"
|
||||||
|
:style="customStyle"
|
||||||
|
@tap="handleTap"
|
||||||
|
>
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ClayCard',
|
||||||
|
props: {
|
||||||
|
// 卡片尺寸:sm, md, lg
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: 'md'
|
||||||
|
},
|
||||||
|
// 变体:default, primary, gold
|
||||||
|
variant: {
|
||||||
|
type: String,
|
||||||
|
default: 'default'
|
||||||
|
},
|
||||||
|
// 是否凹陷效果
|
||||||
|
inset: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 自定义类名
|
||||||
|
customClass: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 自定义样式
|
||||||
|
customStyle: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleTap(e) {
|
||||||
|
this.$emit('tap', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
/* ============================================
|
||||||
|
Claymorphism 卡片组件
|
||||||
|
使用示例:
|
||||||
|
<ClayCard size="lg" variant="primary">内容</ClayCard>
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
.clay-card {
|
||||||
|
background: linear-gradient(145deg, #ffffff, #f0f0f0);
|
||||||
|
border-radius: 24rpx;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
|
||||||
|
/* 外部双阴影 - 创造凸起效果 */
|
||||||
|
box-shadow:
|
||||||
|
8rpx 8rpx 16rpx rgba(0, 0, 0, 0.06),
|
||||||
|
-8rpx -8rpx 16rpx rgba(255, 255, 255, 0.8),
|
||||||
|
inset 2rpx 2rpx 4rpx rgba(255, 255, 255, 0.9),
|
||||||
|
inset -2rpx -2rpx 4rpx rgba(0, 0, 0, 0.03);
|
||||||
|
|
||||||
|
&.clay-card-sm {
|
||||||
|
border-radius: 16rpx;
|
||||||
|
box-shadow:
|
||||||
|
6rpx 6rpx 12rpx rgba(0, 0, 0, 0.04),
|
||||||
|
-6rpx -6rpx 12rpx rgba(255, 255, 255, 0.8),
|
||||||
|
inset 2rpx 2rpx 4rpx rgba(255, 255, 255, 0.9),
|
||||||
|
inset -2rpx -2rpx 4rpx rgba(0, 0, 0, 0.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-card-md {
|
||||||
|
border-radius: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-card-lg {
|
||||||
|
border-radius: 32rpx;
|
||||||
|
box-shadow:
|
||||||
|
12rpx 12rpx 24rpx rgba(0, 0, 0, 0.08),
|
||||||
|
-12rpx -12rpx 24rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 4rpx 4rpx 8rpx rgba(255, 255, 255, 0.85),
|
||||||
|
inset -4rpx -4rpx 8rpx rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.98);
|
||||||
|
box-shadow:
|
||||||
|
4rpx 4rpx 8rpx rgba(0, 0, 0, 0.06),
|
||||||
|
-4rpx -4rpx 8rpx rgba(255, 255, 255, 0.6),
|
||||||
|
inset 4rpx 4rpx 8rpx rgba(0, 0, 0, 0.05),
|
||||||
|
inset -4rpx -4rpx 8rpx rgba(255, 255, 255, 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 彩色粘土卡片 */
|
||||||
|
.clay-card-primary {
|
||||||
|
background: linear-gradient(145deg, #FF9500, #FF6B00);
|
||||||
|
color: #fff;
|
||||||
|
box-shadow:
|
||||||
|
10rpx 10rpx 20rpx rgba(255, 107, 0, 0.2),
|
||||||
|
-10rpx -10rpx 20rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 3rpx 3rpx 6rpx rgba(255, 255, 255, 0.4),
|
||||||
|
inset -3rpx -3rpx 6rpx rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
box-shadow:
|
||||||
|
5rpx 5rpx 10rpx rgba(255, 107, 0, 0.25),
|
||||||
|
-5rpx -5rpx 10rpx rgba(255, 255, 255, 0.5),
|
||||||
|
inset 5rpx 5rpx 10rpx rgba(0, 0, 0, 0.15),
|
||||||
|
inset -5rpx -5rpx 10rpx rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.clay-card-gold {
|
||||||
|
background: linear-gradient(145deg, #FFD60A, #FF9F0A);
|
||||||
|
box-shadow:
|
||||||
|
10rpx 10rpx 20rpx rgba(255, 159, 10, 0.2),
|
||||||
|
-10rpx -10rpx 20rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 3rpx 3rpx 6rpx rgba(255, 255, 255, 0.4),
|
||||||
|
inset -3rpx -3rpx 6rpx rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
box-shadow:
|
||||||
|
5rpx 5rpx 10rpx rgba(255, 159, 10, 0.25),
|
||||||
|
-5rpx -5rpx 10rpx rgba(255, 255, 255, 0.5),
|
||||||
|
inset 5rpx 5rpx 10rpx rgba(0, 0, 0, 0.15),
|
||||||
|
inset -5rpx -5rpx 10rpx rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 凹陷粘土卡片 (Inset) */
|
||||||
|
.clay-card-inset {
|
||||||
|
background: linear-gradient(145deg, #e8e8e8, #f8f8f8);
|
||||||
|
box-shadow:
|
||||||
|
inset 6rpx 6rpx 12rpx rgba(0, 0, 0, 0.08),
|
||||||
|
inset -6rpx -6rpx 12rpx rgba(255, 255, 255, 0.9);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
282
components/ClayInput.vue
Normal file
282
components/ClayInput.vue
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
<template>
|
||||||
|
<view
|
||||||
|
class="clay-input-wrapper"
|
||||||
|
:class="[
|
||||||
|
`clay-input-${size}`,
|
||||||
|
{ 'clay-input-focused': isFocused },
|
||||||
|
{ 'clay-input-error': error },
|
||||||
|
{ 'clay-input-disabled': disabled },
|
||||||
|
customClass
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<!-- 前缀图标 -->
|
||||||
|
<view v-if="prefixIcon" class="clay-prefix-icon">
|
||||||
|
<text>{{ prefixIcon }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 输入框 -->
|
||||||
|
<input
|
||||||
|
class="clay-input-field"
|
||||||
|
:type="type"
|
||||||
|
:value="modelValue"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:disabled="disabled"
|
||||||
|
:maxlength="maxlength"
|
||||||
|
@input="handleInput"
|
||||||
|
@focus="handleFocus"
|
||||||
|
@blur="handleBlur"
|
||||||
|
@confirm="handleConfirm"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 后缀图标/按钮 -->
|
||||||
|
<view v-if="suffixIcon || clearable" class="clay-suffix-icon" @tap="handleSuffixTap">
|
||||||
|
<text v-if="showClearButton" class="clear-button">×</text>
|
||||||
|
<text v-else-if="suffixIcon">{{ suffixIcon }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 错误提示 -->
|
||||||
|
<view v-if="error && errorText" class="clay-error-text">
|
||||||
|
<text>{{ errorText }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ClayInput',
|
||||||
|
props: {
|
||||||
|
// v-model 绑定值
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 输入框类型
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'text'
|
||||||
|
},
|
||||||
|
// 占位符
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请输入'
|
||||||
|
},
|
||||||
|
// 尺寸:sm, md, lg
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: 'md'
|
||||||
|
},
|
||||||
|
// 是否禁用
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否显示错误状态
|
||||||
|
error: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 错误提示文字
|
||||||
|
errorText: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 最大长度
|
||||||
|
maxlength: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 140
|
||||||
|
},
|
||||||
|
// 是否可清空
|
||||||
|
clearable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 前缀图标(emoji)
|
||||||
|
prefixIcon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 后缀图标(emoji)
|
||||||
|
suffixIcon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 自定义类名
|
||||||
|
customClass: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isFocused: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
showClearButton() {
|
||||||
|
return this.clearable && this.modelValue && !this.disabled
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleInput(e) {
|
||||||
|
this.$emit('update:modelValue', e.detail.value)
|
||||||
|
this.$emit('input', e.detail.value)
|
||||||
|
},
|
||||||
|
handleFocus(e) {
|
||||||
|
this.isFocused = true
|
||||||
|
this.$emit('focus', e)
|
||||||
|
},
|
||||||
|
handleBlur(e) {
|
||||||
|
this.isFocused = false
|
||||||
|
this.$emit('blur', e)
|
||||||
|
},
|
||||||
|
handleConfirm(e) {
|
||||||
|
this.$emit('confirm', e)
|
||||||
|
},
|
||||||
|
handleSuffixTap() {
|
||||||
|
if (this.showClearButton) {
|
||||||
|
this.$emit('update:modelValue', '')
|
||||||
|
this.$emit('clear')
|
||||||
|
} else if (this.suffixIcon) {
|
||||||
|
this.$emit('suffix-tap')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
/* ============================================
|
||||||
|
Claymorphism 输入框组件
|
||||||
|
使用示例:
|
||||||
|
<ClayInput v-model="value" placeholder="请输入" prefixIcon="🔍" />
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
.clay-input-wrapper {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: linear-gradient(145deg, #ffffff, #f5f5f5);
|
||||||
|
border-radius: 24rpx;
|
||||||
|
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
/* Claymorphism 双阴影 */
|
||||||
|
box-shadow:
|
||||||
|
inset 4rpx 4rpx 8rpx rgba(0, 0, 0, 0.06),
|
||||||
|
inset -4rpx -4rpx 8rpx rgba(255, 255, 255, 0.9),
|
||||||
|
4rpx 4rpx 8rpx rgba(0, 0, 0, 0.04),
|
||||||
|
-4rpx -4rpx 8rpx rgba(255, 255, 255, 0.7);
|
||||||
|
|
||||||
|
&.clay-input-sm {
|
||||||
|
border-radius: 20rpx;
|
||||||
|
padding: 16rpx 24rpx;
|
||||||
|
|
||||||
|
.clay-input-field {
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-input-md {
|
||||||
|
border-radius: 24rpx;
|
||||||
|
padding: 24rpx 28rpx;
|
||||||
|
|
||||||
|
.clay-input-field {
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-input-lg {
|
||||||
|
border-radius: 28rpx;
|
||||||
|
padding: 28rpx 32rpx;
|
||||||
|
|
||||||
|
.clay-input-field {
|
||||||
|
font-size: 32rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 聚焦状态 */
|
||||||
|
&.clay-input-focused {
|
||||||
|
box-shadow:
|
||||||
|
inset 6rpx 6rpx 12rpx rgba(255, 107, 0, 0.08),
|
||||||
|
inset -6rpx -6rpx 12rpx rgba(255, 255, 255, 0.85),
|
||||||
|
6rpx 6rpx 12rpx rgba(255, 107, 0, 0.1),
|
||||||
|
-6rpx -6rpx 12rpx rgba(255, 255, 255, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 错误状态 */
|
||||||
|
&.clay-input-error {
|
||||||
|
box-shadow:
|
||||||
|
inset 4rpx 4rpx 8rpx rgba(255, 59, 48, 0.1),
|
||||||
|
inset -4rpx -4rpx 8rpx rgba(255, 255, 255, 0.9),
|
||||||
|
4rpx 4rpx 8rpx rgba(255, 59, 48, 0.1),
|
||||||
|
-4rpx -4rpx 8rpx rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 禁用状态 */
|
||||||
|
&.clay-input-disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
background: linear-gradient(145deg, #f0f0f0, #e8e8e8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.clay-input-field {
|
||||||
|
flex: 1;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
color: #1D1D1F;
|
||||||
|
outline: none;
|
||||||
|
line-height: 1.5;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: #C7C7CC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 前缀图标 */
|
||||||
|
.clay-prefix-icon {
|
||||||
|
margin-right: 16rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 后缀图标 */
|
||||||
|
.clay-suffix-icon {
|
||||||
|
margin-left: 16rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear-button {
|
||||||
|
display: inline-block;
|
||||||
|
width: 40rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
line-height: 36rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 40rpx;
|
||||||
|
color: #86868B;
|
||||||
|
background: linear-gradient(145deg, #e8e8e8, #f8f8f8);
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
/* Claymorphism 凹陷效果 */
|
||||||
|
box-shadow:
|
||||||
|
inset 2rpx 2rpx 4rpx rgba(0, 0, 0, 0.1),
|
||||||
|
inset -2rpx -2rpx 4rpx rgba(255, 255, 255, 0.9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 错误提示 */
|
||||||
|
.clay-error-text {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -40rpx;
|
||||||
|
left: 0;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #FF3B30;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,23 +1,31 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- #ifndef MP-TOUTIAO -->
|
<!-- #ifndef MP-TOUTIAO -->
|
||||||
<view class="app-tab-bar">
|
<view class="clay-tab-bar">
|
||||||
<view class="tab-bar-item" @tap="switchTab('pages/index/index')">
|
<view class="tab-bar-item" @tap="switchTab('pages/index/index')" :class="{ active: selected === 0 }">
|
||||||
<image class="tab-icon" :src="selected === 0 ? '/static/tab/home_active.png' : '/static/tab/home.png'" mode="aspectFit"></image>
|
<view class="tab-icon-wrapper" :class="{ 'icon-active': selected === 0 }">
|
||||||
|
<image class="tab-icon" :src="selected === 0 ? '/static/tab/home_active.png' : '/static/tab/home.png'" mode="aspectFit"></image>
|
||||||
|
</view>
|
||||||
<text class="tab-text" :class="{ active: selected === 0 }">首页</text>
|
<text class="tab-text" :class="{ active: selected === 0 }">首页</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="tab-bar-item" @tap="switchTab('pages/shop/index')">
|
<view class="tab-bar-item" @tap="switchTab('pages/shop/index')" :class="{ active: selected === 1 }">
|
||||||
<image class="tab-icon" :src="selected === 1 ? '/static/tab/shop_active.png' : '/static/tab/shop.png'" mode="aspectFit"></image>
|
<view class="tab-icon-wrapper" :class="{ 'icon-active': selected === 1 }">
|
||||||
|
<image class="tab-icon" :src="selected === 1 ? '/static/tab/shop_active.png' : '/static/tab/shop.png'" mode="aspectFit"></image>
|
||||||
|
</view>
|
||||||
<text class="tab-text" :class="{ active: selected === 1 }">商城</text>
|
<text class="tab-text" :class="{ active: selected === 1 }">商城</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="tab-bar-item" @tap="switchTab('pages/cabinet/index')">
|
<view class="tab-bar-item" @tap="switchTab('pages/cabinet/index')" :class="{ active: selected === 2 }">
|
||||||
<image class="tab-icon" :src="selected === 2 ? '/static/tab/box_active.png' : '/static/tab/box.png'" mode="aspectFit"></image>
|
<view class="tab-icon-wrapper" :class="{ 'icon-active': selected === 2 }">
|
||||||
|
<image class="tab-icon" :src="selected === 2 ? '/static/tab/box_active.png' : '/static/tab/box.png'" mode="aspectFit"></image>
|
||||||
|
</view>
|
||||||
<text class="tab-text" :class="{ active: selected === 2 }">盒柜</text>
|
<text class="tab-text" :class="{ active: selected === 2 }">盒柜</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="tab-bar-item" @tap="switchTab('pages/mine/index')">
|
<view class="tab-bar-item" @tap="switchTab('pages/mine/index')" :class="{ active: selected === 3 }">
|
||||||
<image class="tab-icon" :src="selected === 3 ? '/static/tab/profile_active.png' : '/static/tab/profile.png'" mode="aspectFit"></image>
|
<view class="tab-icon-wrapper" :class="{ 'icon-active': selected === 3 }">
|
||||||
|
<image class="tab-icon" :src="selected === 3 ? '/static/tab/profile_active.png' : '/static/tab/profile.png'" mode="aspectFit"></image>
|
||||||
|
</view>
|
||||||
<text class="tab-text" :class="{ active: selected === 3 }">我的</text>
|
<text class="tab-text" :class="{ active: selected === 3 }">我的</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -63,19 +71,30 @@ export default {
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
/* #ifndef MP-TOUTIAO */
|
/* #ifndef MP-TOUTIAO */
|
||||||
.app-tab-bar {
|
/* ============================================
|
||||||
|
Claymorphism 底部导航栏
|
||||||
|
粘土风格 - 柔和浮感 & 双阴影效果
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
.clay-tab-bar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
height: 100rpx;
|
background: linear-gradient(145deg, #ffffff, #f5f5f5);
|
||||||
background: #FFFFFF;
|
border-top: 1px solid rgba(255, 255, 255, 0.6);
|
||||||
border-top: 1rpx solid #E5E5E5;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-bottom: env(safe-area-inset-bottom);
|
padding: 12rpx 0 calc(12rpx + env(safe-area-inset-bottom));
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
|
|
||||||
|
/* Claymorphism 双阴影 - 创造浮起效果 */
|
||||||
|
box-shadow:
|
||||||
|
0 -8rpx 16rpx rgba(0, 0, 0, 0.04),
|
||||||
|
0 8rpx 16rpx rgba(255, 255, 255, 0.8),
|
||||||
|
inset 0 2rpx 4rpx rgba(255, 255, 255, 0.9),
|
||||||
|
inset 0 -2rpx 4rpx rgba(0, 0, 0, 0.02);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-bar-item {
|
.tab-bar-item {
|
||||||
@ -84,22 +103,68 @@ export default {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: 100%;
|
padding: 8rpx 0;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
.tab-icon-wrapper {
|
||||||
|
/* 选中状态 - Claymorphism 凸起效果 */
|
||||||
|
background: linear-gradient(145deg, #FF9500, #FF6B00);
|
||||||
|
box-shadow:
|
||||||
|
6rpx 6rpx 12rpx rgba(255, 107, 0, 0.2),
|
||||||
|
-6rpx -6rpx 12rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 2rpx 2rpx 4rpx rgba(255, 255, 255, 0.4),
|
||||||
|
inset -2rpx -2rpx 4rpx rgba(0, 0, 0, 0.1);
|
||||||
|
transform: translateY(-4rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-text {
|
||||||
|
color: #FF6B00;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 图标包装器 - Claymorphism 圆形徽章 */
|
||||||
|
.tab-icon-wrapper {
|
||||||
|
width: 64rpx;
|
||||||
|
height: 64rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 6rpx;
|
||||||
|
background: linear-gradient(145deg, #f8f8f8, #e8e8e8);
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
|
||||||
|
/* 默认状态 - 凹陷效果 */
|
||||||
|
box-shadow:
|
||||||
|
inset 3rpx 3rpx 6rpx rgba(0, 0, 0, 0.08),
|
||||||
|
inset -3rpx -3rpx 6rpx rgba(255, 255, 255, 0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-icon {
|
.tab-icon {
|
||||||
width: 48rpx;
|
width: 40rpx;
|
||||||
height: 48rpx;
|
height: 40rpx;
|
||||||
margin-bottom: 4rpx;
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-text {
|
.tab-text {
|
||||||
font-size: 22rpx;
|
font-size: 22rpx;
|
||||||
color: #7A7E83;
|
color: #86868B;
|
||||||
|
transition: all 0.3s ease;
|
||||||
&.active {
|
font-weight: 500;
|
||||||
color: #007AFF;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 选中状态的图标颜色调整 */
|
||||||
|
.tab-bar-item.active .tab-icon {
|
||||||
|
filter: brightness(0) invert(1);
|
||||||
|
}
|
||||||
|
|
||||||
/* #endif */
|
/* #endif */
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
69
components/clay-components.js
Normal file
69
components/clay-components.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* Claymorphism 组件库导出
|
||||||
|
*
|
||||||
|
* 使用方式(在 pages.json 中配置 easycom):
|
||||||
|
* {
|
||||||
|
* "easycom": {
|
||||||
|
* "autoscan": true,
|
||||||
|
* "custom": {
|
||||||
|
* "^Clay(A.*)": "@/components/Clay$1.vue"
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* 或手动导入:
|
||||||
|
* import ClayCard from '@/components/ClayCard.vue'
|
||||||
|
* import ClayButton from '@/components/ClayButton.vue'
|
||||||
|
* import ClayInput from '@/components/ClayInput.vue'
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { default as ClayCard } from './ClayCard.vue'
|
||||||
|
export { default as ClayButton } from './ClayButton.vue'
|
||||||
|
export { default as ClayInput } from './ClayInput.vue'
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
Claymorphism 设计系统说明
|
||||||
|
|
||||||
|
🎨 核心特点:
|
||||||
|
1. 双阴影效果(外部 + 内部)创造立体浮感
|
||||||
|
2. 柔和的渐变背景
|
||||||
|
3. 圆润的边角设计
|
||||||
|
4. 有机感的按压动画
|
||||||
|
|
||||||
|
📦 组件列表:
|
||||||
|
- ClayCard: 粘土风格卡片
|
||||||
|
- ClayButton: 粘土风格按钮
|
||||||
|
- ClayInput: 粘土风格输入框
|
||||||
|
|
||||||
|
🎯 使用示例:
|
||||||
|
|
||||||
|
<!-- 卡片 -->
|
||||||
|
<ClayCard size="lg" variant="primary" @tap="handleTap">
|
||||||
|
<text>卡片内容</text>
|
||||||
|
</ClayCard>
|
||||||
|
|
||||||
|
<!-- 按钮 -->
|
||||||
|
<ClayButton
|
||||||
|
text="确认"
|
||||||
|
variant="primary"
|
||||||
|
size="lg"
|
||||||
|
:loading="isLoading"
|
||||||
|
@tap="handleConfirm"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 输入框 -->
|
||||||
|
<ClayInput
|
||||||
|
v-model="inputValue"
|
||||||
|
placeholder="请输入内容"
|
||||||
|
prefixIcon="🔍"
|
||||||
|
:clearable="true"
|
||||||
|
@confirm="handleSearch"
|
||||||
|
/>
|
||||||
|
|
||||||
|
🎨 样式变量(uni.scss):
|
||||||
|
- $clay-shadow-sm/md/lg/xl: 阴影层级
|
||||||
|
- $clay-bg-light: #FAFAFA
|
||||||
|
- $clay-bg-white: #FFFFFF
|
||||||
|
- $clay-border: rgba(255, 255, 255, 0.8)
|
||||||
|
|
||||||
|
============================================ */
|
||||||
260
docs/CLAYMORPHISM.md
Normal file
260
docs/CLAYMORPHISM.md
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
# Claymorphism UI 优化文档
|
||||||
|
|
||||||
|
## 🎨 设计系统概述
|
||||||
|
|
||||||
|
### 什么是 Claymorphism(粘土拟态)?
|
||||||
|
|
||||||
|
Claymorphism 是一种结合了 **Neumorphism(新拟态)** 和 **3D 粘土质感** 的设计风格,具有以下特点:
|
||||||
|
|
||||||
|
- ✨ **双阴影效果**:外部阴影 + 内部阴影创造立体浮感
|
||||||
|
- 🎨 **柔和渐变**:使用 145deg 渐变创造有机感
|
||||||
|
- 🔄 **圆润边角**:大圆角设计传递柔和友好感
|
||||||
|
- 💫 **有机动画**:平滑的过渡和按压反馈
|
||||||
|
- 🌈 **高对比度**:保持可访问性的同时提供视觉吸引力
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 组件库
|
||||||
|
|
||||||
|
### 核心组件
|
||||||
|
|
||||||
|
| 组件 | 文件路径 | 功能 |
|
||||||
|
|------|---------|------|
|
||||||
|
| **ClayCard** | `/components/ClayCard.vue` | 粘土风格卡片 |
|
||||||
|
| **ClayButton** | `/components/ClayButton.vue` | 粘土风格按钮 |
|
||||||
|
| **ClayInput** | `/components/ClayInput.vue` | 粘土风格输入框 |
|
||||||
|
|
||||||
|
### 使用示例
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<!-- 卡片组件 -->
|
||||||
|
<ClayCard size="lg" variant="primary" @tap="handleTap">
|
||||||
|
<text>这是一张粘土卡片</text>
|
||||||
|
</ClayCard>
|
||||||
|
|
||||||
|
<!-- 按钮组件 -->
|
||||||
|
<ClayButton
|
||||||
|
text="确认操作"
|
||||||
|
variant="primary"
|
||||||
|
size="lg"
|
||||||
|
:loading="isLoading"
|
||||||
|
@tap="handleConfirm"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 输入框组件 -->
|
||||||
|
<ClayInput
|
||||||
|
v-model="searchText"
|
||||||
|
placeholder="搜索内容..."
|
||||||
|
prefixIcon="🔍"
|
||||||
|
:clearable="true"
|
||||||
|
@confirm="handleSearch"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ClayCard, ClayButton, ClayInput } from '@/components/clay-components.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { ClayCard, ClayButton, ClayInput },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
searchText: '',
|
||||||
|
isLoading: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleTap() { console.log('卡片被点击') },
|
||||||
|
async handleConfirm() {
|
||||||
|
this.isLoading = true
|
||||||
|
// 执行操作...
|
||||||
|
},
|
||||||
|
handleSearch(val) { console.log('搜索:', val) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 组件 Props
|
||||||
|
|
||||||
|
### ClayCard
|
||||||
|
|
||||||
|
| 属性 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| `size` | String | `'md'` | 尺寸:`sm`, `md`, `lg` |
|
||||||
|
| `variant` | String | `'default'` | 变体:`default`, `primary`, `gold` |
|
||||||
|
| `inset` | Boolean | `false` | 是否凹陷效果 |
|
||||||
|
| `customClass` | String | `''` | 自定义类名 |
|
||||||
|
| `customStyle` | Object | `{}` | 自定义样式 |
|
||||||
|
|
||||||
|
### ClayButton
|
||||||
|
|
||||||
|
| 属性 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| `text` | String | `'按钮'` | 按钮文字 |
|
||||||
|
| `size` | String | `'md'` | 尺寸:`sm`, `md`, `lg` |
|
||||||
|
| `variant` | String | `'primary'` | 变体:`primary`, `secondary`, `success`, `warning`, `error` |
|
||||||
|
| `outline` | Boolean | `false` | 是否轮廓样式 |
|
||||||
|
| `block` | Boolean | `false` | 是否块级按钮 |
|
||||||
|
| `disabled` | Boolean | `false` | 是否禁用 |
|
||||||
|
| `loading` | Boolean | `false` | 是否加载中 |
|
||||||
|
| `icon` | String | `''` | 图标(emoji) |
|
||||||
|
| `customStyle` | Object | `{}` | 自定义样式 |
|
||||||
|
|
||||||
|
### ClayInput
|
||||||
|
|
||||||
|
| 属性 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| `modelValue` | String/Number | `''` | v-model 绑定值 |
|
||||||
|
| `type` | String | `'text'` | 输入框类型 |
|
||||||
|
| `placeholder` | String | `'请输入'` | 占位符 |
|
||||||
|
| `size` | String | `'md'` | 尺寸:`sm`, `md`, `lg` |
|
||||||
|
| `disabled` | Boolean | `false` | 是否禁用 |
|
||||||
|
| `error` | Boolean | `false` | 是否错误状态 |
|
||||||
|
| `errorText` | String | `''` | 错误提示 |
|
||||||
|
| `clearable` | Boolean | `false` | 是否可清空 |
|
||||||
|
| `prefixIcon` | String | `''` | 前缀图标(emoji) |
|
||||||
|
| `suffixIcon` | String | `''` | 后缀图标(emoji) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 样式变量
|
||||||
|
|
||||||
|
在 `uni.scss` 中定义的核心变量:
|
||||||
|
|
||||||
|
```scss
|
||||||
|
/* Claymorphism 阴影层级 */
|
||||||
|
$clay-shadow-sm: (...)
|
||||||
|
$clay-shadow-md: (...)
|
||||||
|
$clay-shadow-lg: (...)
|
||||||
|
$clay-shadow-xl: (...)
|
||||||
|
|
||||||
|
/* 颜色变量 */
|
||||||
|
$clay-bg-light: #FAFAFA;
|
||||||
|
$clay-bg-white: #FFFFFF;
|
||||||
|
$clay-bg-soft: rgba(255, 255, 255, 0.85);
|
||||||
|
$clay-border: rgba(255, 255, 255, 0.8);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 已优化的页面
|
||||||
|
|
||||||
|
### ✅ 首页 (`pages/index/index.vue`)
|
||||||
|
- Banner 轮播卡片
|
||||||
|
- 通知栏
|
||||||
|
- 玩法分类卡片
|
||||||
|
- 活动列表项
|
||||||
|
|
||||||
|
### ✅ 底部导航栏 (`components/app-tab-bar.vue`)
|
||||||
|
- 导航栏背景
|
||||||
|
- 图标容器(圆形徽章)
|
||||||
|
- 选中状态动画
|
||||||
|
|
||||||
|
### ✅ 个人中心 (`pages/mine/index.vue`)
|
||||||
|
- 用户信息卡片
|
||||||
|
- 头像凹陷效果
|
||||||
|
- 统计数据卡片
|
||||||
|
- 功能图标容器
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 快速开始
|
||||||
|
|
||||||
|
### 1. 配置 easycom(推荐)
|
||||||
|
|
||||||
|
在 `pages.json` 中添加:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"easycom": {
|
||||||
|
"autoscan": true,
|
||||||
|
"custom": {
|
||||||
|
"^Clay(A.*)": "@/components/Clay$1.vue"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 直接使用组件
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<ClayCard size="lg">内容</ClayCard>
|
||||||
|
<ClayButton text="按钮" variant="primary" />
|
||||||
|
<ClayInput v-model="value" placeholder="输入..." />
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 使用全局样式类
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<!-- 粘土卡片 -->
|
||||||
|
<view class="clay-card">内容</view>
|
||||||
|
|
||||||
|
<!-- 粘土按钮 -->
|
||||||
|
<view class="clay-btn clay-btn-primary clay-btn-md">按钮</view>
|
||||||
|
|
||||||
|
<!-- 凹陷效果 -->
|
||||||
|
<view class="clay-card-inset">凹陷卡片</view>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 设计原则
|
||||||
|
|
||||||
|
### ✅ 推荐做法
|
||||||
|
|
||||||
|
1. **保持一致性**:在整个应用中统一使用 Claymorphism 组件
|
||||||
|
2. **适度使用**:不要过度使用,保持界面呼吸感
|
||||||
|
3. **注意对比度**:确保文字与背景有足够的对比度
|
||||||
|
4. **动画平滑**:使用 `cubic-bezier(0.4, 0, 0.2, 1)` 缓动函数
|
||||||
|
5. **圆角统一**:卡片 24-32rpx,按钮 50-60rpx(圆角)
|
||||||
|
|
||||||
|
### ❌ 避免做法
|
||||||
|
|
||||||
|
1. **不要混合多种拟态风格**
|
||||||
|
2. **不要使用过多的彩色渐变**
|
||||||
|
3. **不要忽略深色模式适配**
|
||||||
|
4. **不要在小元素上使用粘土效果**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📱 兼容性
|
||||||
|
|
||||||
|
| 平台 | 支持情况 |
|
||||||
|
|------|----------|
|
||||||
|
| 微信小程序 | ✅ 完全支持 |
|
||||||
|
| 抖音小程序 | ✅ 完全支持 |
|
||||||
|
| H5 | ✅ 完全支持 |
|
||||||
|
| App | ✅ 完全支持 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔮 后续计划
|
||||||
|
|
||||||
|
- [ ] 添加更多组件:ClaySwitch、ClaySlider、ClayModal
|
||||||
|
- [ ] 深色模式适配
|
||||||
|
- [ ] 动画效果增强
|
||||||
|
- [ ] 性能优化
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 更新日志
|
||||||
|
|
||||||
|
### v1.0.0 (2025-02-05)
|
||||||
|
- ✅ 初始化 Claymorphism 设计系统
|
||||||
|
- ✅ 创建核心组件:ClayCard、ClayButton、ClayInput
|
||||||
|
- ✅ 优化首页、个人中心、底部导航栏
|
||||||
|
- ✅ 添加全局样式变量和 Mixins
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**设计团队**: Z Code AI Studio
|
||||||
|
**最后更新**: 2025-02-05
|
||||||
@ -448,7 +448,7 @@ export default {
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Banner Container (Modern Floating) */
|
/* Banner Container - Claymorphism Style */
|
||||||
.banner-container {
|
.banner-container {
|
||||||
padding: $spacing-sm $spacing-lg $spacing-xl;
|
padding: $spacing-sm $spacing-lg $spacing-xl;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -462,17 +462,27 @@ export default {
|
|||||||
.banner-card {
|
.banner-card {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 0 4rpx;
|
margin: 0 4rpx;
|
||||||
border-radius: 32rpx;
|
border-radius: 40rpx;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
transform: scale(0.96);
|
transform: scale(0.96);
|
||||||
transition: all 0.5s $ease-out;
|
transition: all 0.5s $ease-out;
|
||||||
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.08);
|
|
||||||
|
/* Claymorphism 双阴影效果 */
|
||||||
|
box-shadow:
|
||||||
|
12rpx 12rpx 24rpx rgba(0, 0, 0, 0.08),
|
||||||
|
-12rpx -12rpx 24rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 4rpx 4rpx 8rpx rgba(255, 255, 255, 0.5),
|
||||||
|
inset -4rpx -4rpx 8rpx rgba(0, 0, 0, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.banner-card.active {
|
.banner-card.active {
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
box-shadow: $shadow-float;
|
box-shadow:
|
||||||
|
16rpx 16rpx 32rpx rgba(255, 107, 0, 0.12),
|
||||||
|
-16rpx -16rpx 32rpx rgba(255, 255, 255, 0.6),
|
||||||
|
inset 6rpx 6rpx 12rpx rgba(255, 255, 255, 0.4),
|
||||||
|
inset -6rpx -6rpx 12rpx rgba(0, 0, 0, 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
.banner-image {
|
.banner-image {
|
||||||
@ -541,17 +551,23 @@ export default {
|
|||||||
background: $brand-primary;
|
background: $brand-primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Notice Bar V2 (Minimalist) */
|
/* Notice Bar - Claymorphism Style */
|
||||||
.notice-bar-v2 {
|
.notice-bar-v2 {
|
||||||
margin: 0 $spacing-lg $spacing-xl;
|
margin: 0 $spacing-lg $spacing-xl;
|
||||||
background: rgba(255, 255, 255, 0.7);
|
background: linear-gradient(145deg, #ffffff, #f5f5f5);
|
||||||
backdrop-filter: blur(10rpx);
|
border-radius: 40rpx;
|
||||||
border-radius: 32rpx;
|
|
||||||
padding: 24rpx 32rpx;
|
padding: 24rpx 32rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 20rpx;
|
gap: 20rpx;
|
||||||
box-shadow: $shadow-sm;
|
|
||||||
|
/* Claymorphism 双阴影 */
|
||||||
|
box-shadow:
|
||||||
|
8rpx 8rpx 16rpx rgba(0, 0, 0, 0.06),
|
||||||
|
-8rpx -8rpx 16rpx rgba(255, 255, 255, 0.8),
|
||||||
|
inset 2rpx 2rpx 4rpx rgba(255, 255, 255, 0.9),
|
||||||
|
inset -2rpx -2rpx 4rpx rgba(0, 0, 0, 0.03);
|
||||||
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.6);
|
border: 1px solid rgba(255, 255, 255, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -616,19 +632,31 @@ export default {
|
|||||||
height: 190rpx;
|
height: 190rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 玩法卡片 - Claymorphism Style */
|
||||||
.game-card-large {
|
.game-card-large {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
border-radius: $radius-lg;
|
border-radius: $radius-xl;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 22rpx;
|
padding: 22rpx;
|
||||||
box-shadow: $shadow-card;
|
|
||||||
transition: transform 0.2s;
|
transition: transform 0.2s;
|
||||||
|
|
||||||
|
/* Claymorphism 阴影 */
|
||||||
|
box-shadow:
|
||||||
|
12rpx 12rpx 24rpx rgba(0, 0, 0, 0.1),
|
||||||
|
-12rpx -12rpx 24rpx rgba(255, 255, 255, 0.6),
|
||||||
|
inset 4rpx 4rpx 8rpx rgba(255, 255, 255, 0.3),
|
||||||
|
inset -4rpx -4rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-card-large:active {
|
.game-card-large:active {
|
||||||
transform: scale(0.98);
|
transform: scale(0.96);
|
||||||
|
box-shadow:
|
||||||
|
6rpx 6rpx 12rpx rgba(0, 0, 0, 0.12),
|
||||||
|
-6rpx -6rpx 12rpx rgba(255, 255, 255, 0.4),
|
||||||
|
inset 6rpx 6rpx 12rpx rgba(0, 0, 0, 0.15),
|
||||||
|
inset -6rpx -6rpx 12rpx rgba(255, 255, 255, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 下排 */
|
/* 下排 */
|
||||||
@ -640,20 +668,31 @@ export default {
|
|||||||
|
|
||||||
.game-card-small {
|
.game-card-small {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
border-radius: $radius-md;
|
border-radius: $radius-lg;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 16rpx;
|
padding: 16rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
box-shadow: $shadow-sm;
|
|
||||||
background: white;
|
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
/* Claymorphism 阴影 */
|
||||||
|
box-shadow:
|
||||||
|
8rpx 8rpx 16rpx rgba(0, 0, 0, 0.08),
|
||||||
|
-8rpx -8rpx 16rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 2rpx 2rpx 4rpx rgba(255, 255, 255, 0.5),
|
||||||
|
inset -2rpx -2rpx 4rpx rgba(0, 0, 0, 0.05);
|
||||||
|
background: linear-gradient(145deg, #ffffff, #f8f8f8);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.6);
|
||||||
}
|
}
|
||||||
.game-card-small:active {
|
.game-card-small:active {
|
||||||
transform: scale(0.96);
|
transform: scale(0.94);
|
||||||
box-shadow: none;
|
box-shadow:
|
||||||
|
4rpx 4rpx 8rpx rgba(0, 0, 0, 0.1),
|
||||||
|
-4rpx -4rpx 8rpx rgba(255, 255, 255, 0.5),
|
||||||
|
inset 4rpx 4rpx 8rpx rgba(0, 0, 0, 0.08),
|
||||||
|
inset -4rpx -4rpx 8rpx rgba(255, 255, 255, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 内容样式 - 大卡片 */
|
/* 内容样式 - 大卡片 */
|
||||||
@ -748,7 +787,7 @@ export default {
|
|||||||
.card-more .card-title-small { color: $text-sub; }
|
.card-more .card-title-small { color: $text-sub; }
|
||||||
|
|
||||||
|
|
||||||
/* 推荐活动列表 */
|
/* 推荐活动列表 - Claymorphism Style */
|
||||||
.activity-section {
|
.activity-section {
|
||||||
padding: 0 $spacing-lg;
|
padding: 0 $spacing-lg;
|
||||||
animation: fadeInUp 0.6s ease-out 0.3s backwards;
|
animation: fadeInUp 0.6s ease-out 0.3s backwards;
|
||||||
@ -763,20 +802,29 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.activity-item {
|
.activity-item {
|
||||||
background: rgba(255, 255, 255, 0.7);
|
background: linear-gradient(145deg, #ffffff, #f8f8f8);
|
||||||
backdrop-filter: blur(10rpx);
|
|
||||||
border-radius: $radius-xl;
|
border-radius: $radius-xl;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-shadow: $shadow-sm;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
/* Claymorphism 阴影 */
|
||||||
|
box-shadow:
|
||||||
|
10rpx 10rpx 20rpx rgba(0, 0, 0, 0.06),
|
||||||
|
-10rpx -10rpx 20rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 3rpx 3rpx 6rpx rgba(255, 255, 255, 0.8),
|
||||||
|
inset -3rpx -3rpx 6rpx rgba(0, 0, 0, 0.03);
|
||||||
border: 1px solid rgba(255, 255, 255, 0.6);
|
border: 1px solid rgba(255, 255, 255, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.activity-item:active {
|
.activity-item:active {
|
||||||
transform: translateY(4rpx);
|
transform: translateY(4rpx) scale(0.98);
|
||||||
box-shadow: none;
|
box-shadow:
|
||||||
|
5rpx 5rpx 10rpx rgba(0, 0, 0, 0.08),
|
||||||
|
-5rpx -5rpx 10rpx rgba(255, 255, 255, 0.5),
|
||||||
|
inset 5rpx 5rpx 10rpx rgba(0, 0, 0, 0.05),
|
||||||
|
inset -5rpx -5rpx 10rpx rgba(255, 255, 255, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.activity-thumb-box {
|
.activity-thumb-box {
|
||||||
|
|||||||
@ -1533,12 +1533,16 @@ export default {
|
|||||||
50% { transform: translate(30rpx, 50rpx); }
|
50% { transform: translate(30rpx, 50rpx); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 通用毛玻璃卡片 */
|
/* 通用毛玻璃卡片 - Claymorphism */
|
||||||
.glass-card {
|
.glass-card {
|
||||||
background: $bg-glass;
|
background: linear-gradient(145deg, #ffffff, #f8f8f8);
|
||||||
backdrop-filter: blur(20rpx);
|
backdrop-filter: blur(20rpx);
|
||||||
border: 1px solid rgba(255, 255, 255, 0.6);
|
border: 1px solid rgba(255, 255, 255, 0.6);
|
||||||
box-shadow: $shadow-card;
|
box-shadow:
|
||||||
|
10rpx 10rpx 20rpx rgba(0, 0, 0, 0.06),
|
||||||
|
-10rpx -10rpx 20rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 3rpx 3rpx 6rpx rgba(255, 255, 255, 0.8),
|
||||||
|
inset -3rpx -3rpx 6rpx rgba(0, 0, 0, 0.03);
|
||||||
border-radius: $radius-lg;
|
border-radius: $radius-lg;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
@ -1553,9 +1557,14 @@ export default {
|
|||||||
|
|
||||||
.user-info-card {
|
.user-info-card {
|
||||||
padding: $spacing-xl;
|
padding: $spacing-xl;
|
||||||
background: linear-gradient(135deg, rgba(255,255,255,0.95), rgba(255,255,255,0.8));
|
background: linear-gradient(145deg, #ffffff, #f8f8f8);
|
||||||
box-shadow: $shadow-float;
|
box-shadow:
|
||||||
border: 1px solid rgba(255,255,255,0.8);
|
12rpx 12rpx 24rpx rgba(0, 0, 0, 0.06),
|
||||||
|
-12rpx -12rpx 24rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 4rpx 4rpx 8rpx rgba(255, 255, 255, 0.85),
|
||||||
|
inset -4rpx -4rpx 8rpx rgba(0, 0, 0, 0.03);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.6);
|
||||||
|
border-radius: $radius-xl;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-main {
|
.user-main {
|
||||||
@ -1569,7 +1578,11 @@ export default {
|
|||||||
background: $bg-card;
|
background: $bg-card;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
border: 4rpx solid $bg-card;
|
border: 4rpx solid $bg-card;
|
||||||
box-shadow: $shadow-sm;
|
|
||||||
|
/* Claymorphism 凹陷效果 */
|
||||||
|
box-shadow:
|
||||||
|
inset 4rpx 4rpx 8rpx rgba(0, 0, 0, 0.1),
|
||||||
|
inset -4rpx -4rpx 8rpx rgba(255, 255, 255, 0.9);
|
||||||
margin-right: 24rpx;
|
margin-right: 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1588,13 +1601,19 @@ export default {
|
|||||||
right: 0;
|
right: 0;
|
||||||
width: 40rpx;
|
width: 40rpx;
|
||||||
height: 40rpx;
|
height: 40rpx;
|
||||||
background: linear-gradient(135deg, $brand-primary, $brand-secondary);
|
background: linear-gradient(145deg, #FF9500, #FF6B00);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border: 3rpx solid $bg-card;
|
border: 3rpx solid $bg-card;
|
||||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.15);
|
|
||||||
|
/* Claymorphism 凸起效果 */
|
||||||
|
box-shadow:
|
||||||
|
4rpx 4rpx 8rpx rgba(255, 107, 0, 0.2),
|
||||||
|
-4rpx -4rpx 8rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 2rpx 2rpx 4rpx rgba(255, 255, 255, 0.4),
|
||||||
|
inset -2rpx -2rpx 4rpx rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
.edit-icon {
|
.edit-icon {
|
||||||
font-size: 20rpx;
|
font-size: 20rpx;
|
||||||
@ -1750,10 +1769,18 @@ export default {
|
|||||||
transform: rotate(-15deg);
|
transform: rotate(-15deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 常用功能 & 订单 */
|
/* 常用功能 & 订单 - Claymorphism */
|
||||||
.section-card {
|
.section-card {
|
||||||
margin: 0 $spacing-lg $spacing-lg;
|
margin: 0 $spacing-lg $spacing-lg;
|
||||||
padding: 30rpx;
|
padding: 30rpx;
|
||||||
|
background: linear-gradient(145deg, #ffffff, #f8f8f8);
|
||||||
|
box-shadow:
|
||||||
|
10rpx 10rpx 20rpx rgba(0, 0, 0, 0.05),
|
||||||
|
-10rpx -10rpx 20rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 3rpx 3rpx 6rpx rgba(255, 255, 255, 0.8),
|
||||||
|
inset -3rpx -3rpx 6rpx rgba(0, 0, 0, 0.03);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.6);
|
||||||
|
border-radius: $radius-lg;
|
||||||
}
|
}
|
||||||
.section-header {
|
.section-header {
|
||||||
display: flex; justify-content: space-between; align-items: center;
|
display: flex; justify-content: space-between; align-items: center;
|
||||||
@ -1774,14 +1801,22 @@ export default {
|
|||||||
}
|
}
|
||||||
.icon-wrapper, .menu-icon-box {
|
.icon-wrapper, .menu-icon-box {
|
||||||
width: 80rpx; height: 80rpx;
|
width: 80rpx; height: 80rpx;
|
||||||
background: $bg-secondary;
|
background: linear-gradient(145deg, #f8f8f8, #e8e8e8);
|
||||||
border-radius: 24rpx;
|
border-radius: 24rpx;
|
||||||
display: flex; align-items: center; justify-content: center;
|
display: flex; align-items: center; justify-content: center;
|
||||||
margin-bottom: 12rpx;
|
margin-bottom: 12rpx;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
/* Claymorphism 凹陷效果 */
|
||||||
|
box-shadow:
|
||||||
|
inset 3rpx 3rpx 6rpx rgba(0, 0, 0, 0.06),
|
||||||
|
inset -3rpx -3rpx 6rpx rgba(255, 255, 255, 0.9);
|
||||||
}
|
}
|
||||||
.grid-item:active .icon-wrapper, .menu-item:active .menu-icon-box {
|
.grid-item:active .icon-wrapper, .menu-item:active .menu-icon-box {
|
||||||
background: $uni-bg-color-hover;
|
background: linear-gradient(145deg, #e8e8e8, #d8d8d8);
|
||||||
|
box-shadow:
|
||||||
|
inset 4rpx 4rpx 8rpx rgba(0, 0, 0, 0.1),
|
||||||
|
inset -4rpx -4rpx 8rpx rgba(255, 255, 255, 0.7);
|
||||||
}
|
}
|
||||||
.grid-icon-img, .menu-icon-img { width: 44rpx; height: 44rpx; }
|
.grid-icon-img, .menu-icon-img { width: 44rpx; height: 44rpx; }
|
||||||
.grid-label, .menu-label { font-size: $font-sm; color: $text-main; }
|
.grid-label, .menu-label { font-size: $font-sm; color: $text-main; }
|
||||||
|
|||||||
173
uni.scss
173
uni.scss
@ -185,6 +185,44 @@ $uni-font-size-paragraph: 15px;
|
|||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
💎 Claymorphism 设计系统 (2025)
|
||||||
|
粘土拟态风格 - 柔和、圆润、立体浮感
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
/* 🎨 Claymorphism 核心阴影 */
|
||||||
|
$clay-shadow-sm: (
|
||||||
|
6rpx 6rpx 12rpx rgba(0, 0, 0, 0.04),
|
||||||
|
-6rpx -6rpx 12rpx rgba(255, 255, 255, 0.8),
|
||||||
|
inset 2rpx 2rpx 4rpx rgba(255, 255, 255, 0.9),
|
||||||
|
inset -2rpx -2rpx 4rpx rgba(0, 0, 0, 0.03)
|
||||||
|
);
|
||||||
|
$clay-shadow-md: (
|
||||||
|
12rpx 12rpx 24rpx rgba(0, 0, 0, 0.06),
|
||||||
|
-12rpx -12rpx 24rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 4rpx 4rpx 8rpx rgba(255, 255, 255, 0.85),
|
||||||
|
inset -4rpx -4rpx 8rpx rgba(0, 0, 0, 0.04)
|
||||||
|
);
|
||||||
|
$clay-shadow-lg: (
|
||||||
|
20rpx 20rpx 40rpx rgba(0, 0, 0, 0.08),
|
||||||
|
-20rpx -20rpx 40rpx rgba(255, 255, 255, 0.6),
|
||||||
|
inset 6rpx 6rpx 12rpx rgba(255, 255, 255, 0.8),
|
||||||
|
inset -6rpx -6rpx 12rpx rgba(0, 0, 0, 0.05)
|
||||||
|
);
|
||||||
|
$clay-shadow-xl: (
|
||||||
|
28rpx 28rpx 56rpx rgba(0, 0, 0, 0.1),
|
||||||
|
-28rpx -28rpx 56rpx rgba(255, 255, 255, 0.5),
|
||||||
|
inset 8rpx 8rpx 16rpx rgba(255, 255, 255, 0.75),
|
||||||
|
inset -8rpx -8rpx 16rpx rgba(0, 0, 0, 0.06)
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Claymorphism 颜色变量 */
|
||||||
|
$clay-bg-light: #FAFAFA;
|
||||||
|
$clay-bg-white: #FFFFFF;
|
||||||
|
$clay-bg-soft: rgba(255, 255, 255, 0.85);
|
||||||
|
$clay-border: rgba(255, 255, 255, 0.8);
|
||||||
|
$clay-border-dark: rgba(0, 0, 0, 0.04);
|
||||||
|
|
||||||
/* ============================================
|
/* ============================================
|
||||||
💎 核心公共 UI 类 (Premium UI 6.0)
|
💎 核心公共 UI 类 (Premium UI 6.0)
|
||||||
============================================ */
|
============================================ */
|
||||||
@ -240,6 +278,141 @@ $uni-font-size-paragraph: 15px;
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
🟤 Claymorphism 卡片组件
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
/* 基础粘土卡片 */
|
||||||
|
.clay-card {
|
||||||
|
background: linear-gradient(145deg, #ffffff, #f0f0f0);
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
position: relative;
|
||||||
|
transition: all $transition-normal $ease-out;
|
||||||
|
|
||||||
|
/* 外部双阴影 - 创造凸起效果 */
|
||||||
|
box-shadow:
|
||||||
|
8rpx 8rpx 16rpx rgba(0, 0, 0, 0.06),
|
||||||
|
-8rpx -8rpx 16rpx rgba(255, 255, 255, 0.8),
|
||||||
|
inset 2rpx 2rpx 4rpx rgba(255, 255, 255, 0.9),
|
||||||
|
inset -2rpx -2rpx 4rpx rgba(0, 0, 0, 0.03);
|
||||||
|
|
||||||
|
&.clay-card-sm {
|
||||||
|
border-radius: $radius-md;
|
||||||
|
box-shadow:
|
||||||
|
6rpx 6rpx 12rpx rgba(0, 0, 0, 0.04),
|
||||||
|
-6rpx -6rpx 12rpx rgba(255, 255, 255, 0.8),
|
||||||
|
inset 2rpx 2rpx 4rpx rgba(255, 255, 255, 0.9),
|
||||||
|
inset -2rpx -2rpx 4rpx rgba(0, 0, 0, 0.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-card-lg {
|
||||||
|
border-radius: $radius-xl;
|
||||||
|
box-shadow:
|
||||||
|
12rpx 12rpx 24rpx rgba(0, 0, 0, 0.08),
|
||||||
|
-12rpx -12rpx 24rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 4rpx 4rpx 8rpx rgba(255, 255, 255, 0.85),
|
||||||
|
inset -4rpx -4rpx 8rpx rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.98);
|
||||||
|
box-shadow:
|
||||||
|
4rpx 4rpx 8rpx rgba(0, 0, 0, 0.06),
|
||||||
|
-4rpx -4rpx 8rpx rgba(255, 255, 255, 0.6),
|
||||||
|
inset 4rpx 4rpx 8rpx rgba(0, 0, 0, 0.05),
|
||||||
|
inset -4rpx -4rpx 8rpx rgba(255, 255, 255, 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 彩色粘土卡片 */
|
||||||
|
.clay-card-primary {
|
||||||
|
background: linear-gradient(145deg, $brand-primary-light, $brand-primary);
|
||||||
|
color: #fff;
|
||||||
|
box-shadow:
|
||||||
|
10rpx 10rpx 20rpx rgba(255, 107, 0, 0.2),
|
||||||
|
-10rpx -10rpx 20rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 3rpx 3rpx 6rpx rgba(255, 255, 255, 0.4),
|
||||||
|
inset -3rpx -3rpx 6rpx rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
&.clay-card-gold {
|
||||||
|
background: linear-gradient(145deg, #FFD60A, #FF9F0A);
|
||||||
|
box-shadow:
|
||||||
|
10rpx 10rpx 20rpx rgba(255, 159, 10, 0.2),
|
||||||
|
-10rpx -10rpx 20rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 3rpx 3rpx 6rpx rgba(255, 255, 255, 0.4),
|
||||||
|
inset -3rpx -3rpx 6rpx rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 凹陷粘土卡片 (Inset) */
|
||||||
|
.clay-card-inset {
|
||||||
|
background: linear-gradient(145deg, #e8e8e8, #f8f8f8);
|
||||||
|
box-shadow:
|
||||||
|
inset 6rpx 6rpx 12rpx rgba(0, 0, 0, 0.08),
|
||||||
|
inset -6rpx -6rpx 12rpx rgba(255, 255, 255, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
🔘 Claymorphism 按钮组件
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
.clay-btn {
|
||||||
|
border-radius: $radius-round;
|
||||||
|
font-weight: 700;
|
||||||
|
position: relative;
|
||||||
|
transition: all $transition-normal $ease-out;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
/* 外部双阴影 - 创造凸起感 */
|
||||||
|
box-shadow:
|
||||||
|
8rpx 8rpx 16rpx rgba(0, 0, 0, 0.08),
|
||||||
|
-8rpx -8rpx 16rpx rgba(255, 255, 255, 0.8),
|
||||||
|
inset 2rpx 2rpx 4rpx rgba(255, 255, 255, 0.5),
|
||||||
|
inset -2rpx -2rpx 4rpx rgba(0, 0, 0, 0.05);
|
||||||
|
|
||||||
|
&.clay-btn-primary {
|
||||||
|
background: linear-gradient(145deg, $brand-primary-light, $brand-primary);
|
||||||
|
color: #fff;
|
||||||
|
box-shadow:
|
||||||
|
10rpx 10rpx 20rpx rgba(255, 107, 0, 0.15),
|
||||||
|
-10rpx -10rpx 20rpx rgba(255, 255, 255, 0.7),
|
||||||
|
inset 3rpx 3rpx 6rpx rgba(255, 255, 255, 0.4),
|
||||||
|
inset -3rpx -3rpx 6rpx rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-btn-secondary {
|
||||||
|
background: linear-gradient(145deg, #ffffff, #f0f0f0);
|
||||||
|
color: $text-main;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-btn-sm {
|
||||||
|
padding: 12rpx 32rpx;
|
||||||
|
font-size: $font-sm;
|
||||||
|
border-radius: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-btn-md {
|
||||||
|
padding: 20rpx 48rpx;
|
||||||
|
font-size: $font-md;
|
||||||
|
border-radius: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clay-btn-lg {
|
||||||
|
padding: 28rpx 64rpx;
|
||||||
|
font-size: $font-lg;
|
||||||
|
border-radius: 60rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.96);
|
||||||
|
box-shadow:
|
||||||
|
4rpx 4rpx 8rpx rgba(0, 0, 0, 0.1),
|
||||||
|
-4rpx -4rpx 8rpx rgba(255, 255, 255, 0.5),
|
||||||
|
inset 4rpx 4rpx 8rpx rgba(0, 0, 0, 0.08),
|
||||||
|
inset -4rpx -4rpx 8rpx rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* 3. 通用功能按钮 */
|
/* 3. 通用功能按钮 */
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
background: $gradient-brand;
|
background: $gradient-brand;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user