Files
infstarweb/src/components/layout/MobileNavDrawer.vue
zhangyuheng d254ec86df feat: add shared components for donation, facility, feature bento, filter panel, join wizard, leaderboard, player, playstyle, and town cards
- Implemented DonationCard.vue for displaying donation details.
- Created FacilityCard.vue to showcase facility information with status badges.
- Developed FeatureBentoCard.vue and FeatureBentoGrid.vue for feature display in a grid layout.
- Added FilterPanel.vue for filtering content with search and tag options.
- Introduced JoinWizard.vue for a step-by-step joining process with device and playstyle selection.
- Created LeaderboardCard.vue to display leaderboard information.
- Implemented PlayerCard.vue for showcasing player profiles and stats.
- Developed PlaystyleCard.vue for selecting playstyle options.
- Added TownCard.vue to present town details with badges and images.
- Included demo data in demoData.js for testing and development purposes.
2026-03-18 10:50:23 +08:00

144 lines
2.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
defineProps({
open: {
type: Boolean,
default: false,
},
items: {
type: Array,
default: () => [],
},
ctaLabel: {
type: String,
default: '加入游戏',
},
ctaHref: {
type: String,
default: '/join',
},
});
const emit = defineEmits(['close']);
</script>
<template>
<transition name="drawer-fade">
<div v-if="open" class="mobile-drawer-mask" @click="emit('close')">
<aside class="mobile-drawer" @click.stop>
<div class="mobile-drawer__header">
<p>站点导航</p>
<button type="button" class="mobile-drawer__close" aria-label="关闭菜单" @click="emit('close')">
×
</button>
</div>
<nav class="mobile-drawer__links" aria-label="移动端导航">
<a
v-for="item in items"
:key="item.href"
class="mobile-drawer__link"
:href="item.href"
@click="emit('close')"
>
<span>{{ item.label }}</span>
<small v-if="item.description">{{ item.description }}</small>
</a>
</nav>
<a class="mobile-drawer__cta" :href="ctaHref" @click="emit('close')">{{ ctaLabel }}</a>
</aside>
</div>
</transition>
</template>
<style scoped>
.drawer-fade-enter-active,
.drawer-fade-leave-active {
transition: opacity 0.25s ease;
}
.drawer-fade-enter-from,
.drawer-fade-leave-to {
opacity: 0;
}
.mobile-drawer-mask {
position: fixed;
inset: 0;
z-index: 1200;
display: flex;
justify-content: flex-end;
background: rgba(15, 23, 42, 0.28);
backdrop-filter: blur(12px);
}
.mobile-drawer {
width: min(360px, 100%);
height: 100%;
padding: 24px 20px 28px;
background: rgba(255, 255, 255, 0.96);
box-shadow: -20px 0 60px rgba(15, 23, 42, 0.16);
display: flex;
flex-direction: column;
}
.mobile-drawer__header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
}
.mobile-drawer__header p {
margin: 0;
font-size: 0.9rem;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--bl-text-tertiary);
}
.mobile-drawer__close {
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--bl-surface-muted);
font-size: 1.4rem;
cursor: pointer;
}
.mobile-drawer__links {
display: grid;
gap: 10px;
}
.mobile-drawer__link {
display: flex;
flex-direction: column;
gap: 2px;
padding: 14px 16px;
border-radius: var(--bl-radius-md);
background: #fff;
text-decoration: none;
border: 1px solid rgba(0, 0, 0, 0.05);
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.03);
}
.mobile-drawer__link span {
font-weight: 600;
}
.mobile-drawer__link small {
color: var(--bl-text-secondary);
}
.mobile-drawer__cta {
margin-top: auto;
display: inline-flex;
justify-content: center;
align-items: center;
min-height: 48px;
border-radius: 999px;
background: var(--bl-accent);
color: #fff;
text-decoration: none;
font-weight: 700;
}
</style>