Files
lgp-wx-plus/components/theme/ThemeCardFrame.vue

130 lines
3.1 KiB
Vue
Raw Permalink Normal View History

2026-08-19 08:17:18 +08:00
<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>