Browse Source

feat(component): add surface and nav components

main
Mohan 1 month ago
parent
commit
42108cc6f8
  1. 42
      src/components/SongCard.vue
  2. 92
      src/components/SongNav.vue
  3. 32
      src/components/SongTag.vue

42
src/components/SongCard.vue

@ -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>

92
src/components/SongNav.vue

@ -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>

32
src/components/SongTag.vue

@ -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>
Loading…
Cancel
Save