3 changed files with 166 additions and 0 deletions
@ -0,0 +1,42 @@ |
|||
<script setup> |
|||
defineProps({ |
|||
title: { type: String, default: '' }, |
|||
hover: { type: Boolean, default: false } |
|||
}) |
|||
defineOptions({ name: 'SongCard' }) |
|||
</script> |
|||
|
|||
<template> |
|||
<div class="song-card" :class="{ 'song-card--hover': hover }"> |
|||
<div v-if="title || $slots.header" class="song-card__head"> |
|||
<slot name="header"> |
|||
<span class="h3">{{ title }}</span> |
|||
</slot> |
|||
</div> |
|||
<div class="song-card__body"> |
|||
<slot /> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
.song-card { |
|||
background: var(--song-bg-elevated); |
|||
border: 1px solid var(--song-border); |
|||
border-radius: var(--song-radius-l); |
|||
box-shadow: var(--song-shadow-1); |
|||
transition: transform var(--song-dur-1) var(--song-ease), |
|||
box-shadow var(--song-dur-1) var(--song-ease); |
|||
} |
|||
.song-card--hover:hover { |
|||
transform: translateY(-2px); |
|||
box-shadow: var(--song-shadow-2); |
|||
} |
|||
.song-card__head { |
|||
padding: var(--song-space-4) var(--song-space-5); |
|||
border-bottom: 1px solid var(--song-border); |
|||
} |
|||
.song-card__body { |
|||
padding: var(--song-space-5); |
|||
} |
|||
</style> |
|||
@ -0,0 +1,92 @@ |
|||
<script setup> |
|||
import { inject } from 'vue' |
|||
defineProps({ |
|||
items: { type: Array, default: () => [] }, |
|||
labelField: { type: String, default: 'label' } |
|||
}) |
|||
defineOptions({ name: 'SongNav' }) |
|||
|
|||
const theme = inject('songTheme') |
|||
</script> |
|||
|
|||
<template> |
|||
<nav class="song-nav"> |
|||
<a |
|||
v-for="(item, i) in items" |
|||
:key="i" |
|||
class="song-nav__item" |
|||
:class="{ 'song-nav__item--active': item.active }" |
|||
href="javascript:void 0" |
|||
@click="$emit('select', item)" |
|||
> |
|||
{{ item[labelField] }} |
|||
</a> |
|||
<button class="song-nav__theme" @click="theme?.toggle()" type="button"> |
|||
{{ theme?.isDark ? '砚夜' : '天青' }} |
|||
</button> |
|||
</nav> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
.song-nav { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: var(--song-space-6); |
|||
padding: 0 var(--song-space-5); |
|||
height: 56px; |
|||
border-bottom: 1px solid var(--song-border); |
|||
} |
|||
/* 直棂窗意象 §1.1:竖条分隔 */ |
|||
.song-nav__item { |
|||
position: relative; |
|||
color: var(--song-text-secondary); |
|||
font-size: 14px; |
|||
letter-spacing: 0.04em; |
|||
padding: 0 2px; |
|||
text-decoration: none; |
|||
transition: color var(--song-dur-1) var(--song-ease); |
|||
} |
|||
.song-nav__item + .song-nav__item::before { |
|||
content: ''; |
|||
position: absolute; |
|||
left: calc(-1 * var(--song-space-3)); |
|||
top: 25%; |
|||
height: 50%; |
|||
width: 1px; |
|||
background: var(--song-border); |
|||
} |
|||
.song-nav__item:hover { |
|||
color: var(--song-text); |
|||
text-decoration: none; |
|||
} |
|||
.song-nav__item--active { |
|||
color: var(--song-primary); |
|||
} |
|||
/* 主色墨线右滑 §7 */ |
|||
.song-nav__item--active::after { |
|||
content: ''; |
|||
position: absolute; |
|||
left: 0; |
|||
bottom: -8px; |
|||
width: 100%; |
|||
height: 2px; |
|||
background: var(--song-primary); |
|||
} |
|||
.song-nav__theme { |
|||
margin-left: auto; |
|||
height: 28px; |
|||
padding: 0 12px; |
|||
font-family: var(--song-font-serif); |
|||
font-size: 12px; |
|||
color: var(--song-text-secondary); |
|||
background: transparent; |
|||
border: 1px solid var(--song-border); |
|||
border-radius: var(--song-radius-s); |
|||
cursor: pointer; |
|||
transition: color var(--song-dur-1), border-color var(--song-dur-1); |
|||
} |
|||
.song-nav__theme:hover { |
|||
color: var(--song-primary); |
|||
border-color: var(--song-primary); |
|||
} |
|||
</style> |
|||
@ -0,0 +1,32 @@ |
|||
<script setup> |
|||
defineProps({ |
|||
type: { type: String, default: 'default' }, |
|||
closable: { type: Boolean, default: false } |
|||
}) |
|||
defineOptions({ name: 'SongTag' }) |
|||
</script> |
|||
|
|||
<template> |
|||
<span class="song-tag" :class="`song-tag--${type}`"> |
|||
<slot /> |
|||
</span> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
.song-tag { |
|||
display: inline-flex; |
|||
align-items: center; |
|||
height: 22px; |
|||
padding: 0 10px; |
|||
font-size: 12px; |
|||
line-height: 20px; |
|||
border: 1px solid var(--song-border); |
|||
border-radius: var(--song-radius-s); |
|||
color: var(--song-text-secondary); |
|||
background: transparent; |
|||
} |
|||
.song-tag--primary { color: var(--song-primary); border-color: var(--song-primary); background: var(--song-primary-bg); } |
|||
.song-tag--success { color: var(--song-success); border-color: var(--song-success); background: var(--song-success-bg); } |
|||
.song-tag--warning { color: var(--song-warning); border-color: var(--song-warning); background: var(--song-warning-bg); } |
|||
.song-tag--danger { color: var(--song-danger); border-color: var(--song-danger); background: var(--song-danger-bg); } |
|||
</style> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue