130 lines
3.1 KiB
Vue
130 lines
3.1 KiB
Vue
<template>
|
||
<!-- 主题卡片外壳:plain / elevated / ornament / canvas-frame,按 effect.card 切换 -->
|
||
<view
|
||
class="theme-card"
|
||
:class="['theme-card--' + mode]"
|
||
:style="cardStyle"
|
||
>
|
||
<view v-if="mode === 'canvas-frame' || mode === 'ornament'" class="theme-card__corners" aria-hidden="true">
|
||
<view class="c c-tl" :style="cornerStyle"></view>
|
||
<view class="c c-tr" :style="cornerStyle"></view>
|
||
<view class="c c-bl" :style="cornerStyle"></view>
|
||
<view class="c c-br" :style="cornerStyle"></view>
|
||
</view>
|
||
<view v-if="mode === 'canvas-frame'" class="theme-card__folio" :style="{ borderColor: accent }"></view>
|
||
<view class="theme-card__body">
|
||
<slot />
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { getActiveLayout, getActiveVars } from '@/utils/theme'
|
||
|
||
export default {
|
||
name: 'ThemeCardFrame',
|
||
props: {
|
||
/** 覆盖 effect.card;默认读当前主题 */
|
||
card: { type: String, default: '' },
|
||
},
|
||
computed: {
|
||
mode() {
|
||
if (this.card) return this.card
|
||
const effect = (getActiveLayout().effect) || {}
|
||
return effect.card || 'elevated'
|
||
},
|
||
vars() {
|
||
return getActiveVars()
|
||
},
|
||
accent() {
|
||
return this.vars['--color-primary'] || '#C9A227'
|
||
},
|
||
cardStyle() {
|
||
const v = this.vars
|
||
const base = {
|
||
background: v['--color-surface'] || '#fff',
|
||
color: v['--color-text'] || '#111',
|
||
borderRadius: v['--radius-md'] || '16rpx',
|
||
}
|
||
if (this.mode === 'plain') {
|
||
return {
|
||
...base,
|
||
border: `1rpx solid ${v['--color-border'] || '#eee'}`,
|
||
boxShadow: 'none',
|
||
}
|
||
}
|
||
if (this.mode === 'elevated') {
|
||
return {
|
||
...base,
|
||
border: `1rpx solid ${v['--color-border'] || '#eee'}`,
|
||
boxShadow: v['--shadow-md'] || '0 8rpx 24rpx rgba(0,0,0,0.06)',
|
||
}
|
||
}
|
||
// ornament / canvas-frame
|
||
return {
|
||
...base,
|
||
border: `1rpx solid ${this.accent}`,
|
||
boxShadow: this.mode === 'canvas-frame' ? 'none' : (v['--shadow-md'] || 'none'),
|
||
}
|
||
},
|
||
cornerStyle() {
|
||
return { borderColor: this.accent }
|
||
},
|
||
},
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.theme-card {
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.theme-card__body {
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
.theme-card__folio {
|
||
pointer-events: none;
|
||
position: absolute;
|
||
inset: 8rpx;
|
||
z-index: 0;
|
||
border: 1rpx solid;
|
||
opacity: 0.55;
|
||
}
|
||
.theme-card__corners .c {
|
||
position: absolute;
|
||
z-index: 2;
|
||
width: 20rpx;
|
||
height: 20rpx;
|
||
border-style: solid;
|
||
border-width: 0;
|
||
}
|
||
.theme-card__corners .c-tl {
|
||
top: 8rpx;
|
||
left: 8rpx;
|
||
border-top-width: 2rpx;
|
||
border-left-width: 2rpx;
|
||
}
|
||
.theme-card__corners .c-tr {
|
||
top: 8rpx;
|
||
right: 8rpx;
|
||
border-top-width: 2rpx;
|
||
border-right-width: 2rpx;
|
||
}
|
||
.theme-card__corners .c-bl {
|
||
bottom: 8rpx;
|
||
left: 8rpx;
|
||
border-bottom-width: 2rpx;
|
||
border-left-width: 2rpx;
|
||
}
|
||
.theme-card__corners .c-br {
|
||
right: 8rpx;
|
||
bottom: 8rpx;
|
||
border-right-width: 2rpx;
|
||
border-bottom-width: 2rpx;
|
||
}
|
||
.theme-card--ornament {
|
||
clip-path: polygon(0 0, calc(100% - 16rpx) 0, 100% 16rpx, 100% 100%, 16rpx 100%, 0 calc(100% - 16rpx));
|
||
}
|
||
</style>
|