修改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>
|
||||
<!-- #ifndef MP-TOUTIAO -->
|
||||
<view class="app-tab-bar">
|
||||
<view class="tab-bar-item" @tap="switchTab('pages/index/index')">
|
||||
<view class="clay-tab-bar">
|
||||
<view class="tab-bar-item" @tap="switchTab('pages/index/index')" :class="{ active: selected === 0 }">
|
||||
<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>
|
||||
</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 }">
|
||||
<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>
|
||||
</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 }">
|
||||
<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>
|
||||
</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 }">
|
||||
<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>
|
||||
</view>
|
||||
</view>
|
||||
@ -63,19 +71,30 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* #ifndef MP-TOUTIAO */
|
||||
.app-tab-bar {
|
||||
/* ============================================
|
||||
Claymorphism 底部导航栏
|
||||
粘土风格 - 柔和浮感 & 双阴影效果
|
||||
============================================ */
|
||||
|
||||
.clay-tab-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100rpx;
|
||||
background: #FFFFFF;
|
||||
border-top: 1rpx solid #E5E5E5;
|
||||
background: linear-gradient(145deg, #ffffff, #f5f5f5);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.6);
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
padding: 12rpx 0 calc(12rpx + env(safe-area-inset-bottom));
|
||||
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 {
|
||||
@ -84,22 +103,68 @@ export default {
|
||||
flex-direction: column;
|
||||
align-items: 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 {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
margin-bottom: 4rpx;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.tab-text {
|
||||
font-size: 22rpx;
|
||||
color: #7A7E83;
|
||||
color: #86868B;
|
||||
transition: all 0.3s ease;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #007AFF;
|
||||
}
|
||||
/* 选中状态的图标颜色调整 */
|
||||
.tab-bar-item.active .tab-icon {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
</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;
|
||||
}
|
||||
|
||||
/* Banner Container (Modern Floating) */
|
||||
/* Banner Container - Claymorphism Style */
|
||||
.banner-container {
|
||||
padding: $spacing-sm $spacing-lg $spacing-xl;
|
||||
position: relative;
|
||||
@ -462,17 +462,27 @@ export default {
|
||||
.banner-card {
|
||||
height: 100%;
|
||||
margin: 0 4rpx;
|
||||
border-radius: 32rpx;
|
||||
border-radius: 40rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
transform: scale(0.96);
|
||||
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 {
|
||||
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 {
|
||||
@ -541,17 +551,23 @@ export default {
|
||||
background: $brand-primary;
|
||||
}
|
||||
|
||||
/* Notice Bar V2 (Minimalist) */
|
||||
/* Notice Bar - Claymorphism Style */
|
||||
.notice-bar-v2 {
|
||||
margin: 0 $spacing-lg $spacing-xl;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
backdrop-filter: blur(10rpx);
|
||||
border-radius: 32rpx;
|
||||
background: linear-gradient(145deg, #ffffff, #f5f5f5);
|
||||
border-radius: 40rpx;
|
||||
padding: 24rpx 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
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);
|
||||
}
|
||||
|
||||
@ -616,19 +632,31 @@ export default {
|
||||
height: 190rpx;
|
||||
}
|
||||
|
||||
/* 玩法卡片 - Claymorphism Style */
|
||||
.game-card-large {
|
||||
flex: 1;
|
||||
border-radius: $radius-lg;
|
||||
border-radius: $radius-xl;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
padding: 22rpx;
|
||||
box-shadow: $shadow-card;
|
||||
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);
|
||||
}
|
||||
|
||||
.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 {
|
||||
flex: 1;
|
||||
border-radius: $radius-md;
|
||||
border-radius: $radius-lg;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
padding: 16rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
box-shadow: $shadow-sm;
|
||||
background: white;
|
||||
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 {
|
||||
transform: scale(0.96);
|
||||
box-shadow: none;
|
||||
transform: scale(0.94);
|
||||
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; }
|
||||
|
||||
|
||||
/* 推荐活动列表 */
|
||||
/* 推荐活动列表 - Claymorphism Style */
|
||||
.activity-section {
|
||||
padding: 0 $spacing-lg;
|
||||
animation: fadeInUp 0.6s ease-out 0.3s backwards;
|
||||
@ -763,20 +802,29 @@ export default {
|
||||
}
|
||||
|
||||
.activity-item {
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
backdrop-filter: blur(10rpx);
|
||||
background: linear-gradient(145deg, #ffffff, #f8f8f8);
|
||||
border-radius: $radius-xl;
|
||||
overflow: hidden;
|
||||
box-shadow: $shadow-sm;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
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);
|
||||
}
|
||||
|
||||
.activity-item:active {
|
||||
transform: translateY(4rpx);
|
||||
box-shadow: none;
|
||||
transform: translateY(4rpx) scale(0.98);
|
||||
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 {
|
||||
|
||||
@ -1533,12 +1533,16 @@ export default {
|
||||
50% { transform: translate(30rpx, 50rpx); }
|
||||
}
|
||||
|
||||
/* 通用毛玻璃卡片 */
|
||||
/* 通用毛玻璃卡片 - Claymorphism */
|
||||
.glass-card {
|
||||
background: $bg-glass;
|
||||
background: linear-gradient(145deg, #ffffff, #f8f8f8);
|
||||
backdrop-filter: blur(20rpx);
|
||||
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;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
@ -1553,9 +1557,14 @@ export default {
|
||||
|
||||
.user-info-card {
|
||||
padding: $spacing-xl;
|
||||
background: linear-gradient(135deg, rgba(255,255,255,0.95), rgba(255,255,255,0.8));
|
||||
box-shadow: $shadow-float;
|
||||
border: 1px solid rgba(255,255,255,0.8);
|
||||
background: linear-gradient(145deg, #ffffff, #f8f8f8);
|
||||
box-shadow:
|
||||
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 {
|
||||
@ -1569,7 +1578,11 @@ export default {
|
||||
background: $bg-card;
|
||||
border-radius: 50%;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1588,13 +1601,19 @@ export default {
|
||||
right: 0;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
background: linear-gradient(135deg, $brand-primary, $brand-secondary);
|
||||
background: linear-gradient(145deg, #FF9500, #FF6B00);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
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 {
|
||||
font-size: 20rpx;
|
||||
@ -1750,10 +1769,18 @@ export default {
|
||||
transform: rotate(-15deg);
|
||||
}
|
||||
|
||||
/* 常用功能 & 订单 */
|
||||
/* 常用功能 & 订单 - Claymorphism */
|
||||
.section-card {
|
||||
margin: 0 $spacing-lg $spacing-lg;
|
||||
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 {
|
||||
display: flex; justify-content: space-between; align-items: center;
|
||||
@ -1774,14 +1801,22 @@ export default {
|
||||
}
|
||||
.icon-wrapper, .menu-icon-box {
|
||||
width: 80rpx; height: 80rpx;
|
||||
background: $bg-secondary;
|
||||
background: linear-gradient(145deg, #f8f8f8, #e8e8e8);
|
||||
border-radius: 24rpx;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
margin-bottom: 12rpx;
|
||||
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 {
|
||||
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-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;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
💎 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)
|
||||
============================================ */
|
||||
@ -240,6 +278,141 @@ $uni-font-size-paragraph: 15px;
|
||||
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. 通用功能按钮 */
|
||||
.btn-primary {
|
||||
background: $gradient-brand;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user