Added modal to menu
This commit is contained in:
@@ -0,0 +1,280 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted } from 'vue';
|
||||
import UiIcon from '@/components/UiIcon.vue';
|
||||
import type { NavHubDef } from '@/lib/nav-hubs';
|
||||
|
||||
defineProps<{
|
||||
hub: NavHubDef;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
close: [];
|
||||
go: [to: string];
|
||||
}>();
|
||||
|
||||
function onKey(event: KeyboardEvent) {
|
||||
if (event.key === 'Escape') emit('close');
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('keydown', onKey);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('keydown', onKey);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="hub" role="dialog" aria-modal="true" :aria-label="hub.title">
|
||||
<header class="head">
|
||||
<div class="copy">
|
||||
<h1>{{ hub.title }}</h1>
|
||||
<p>{{ hub.desc }}</p>
|
||||
</div>
|
||||
<span class="head-ico" :class="hub.tint" aria-hidden="true">
|
||||
<UiIcon :name="hub.icon" :size="20" />
|
||||
</span>
|
||||
</header>
|
||||
|
||||
<div class="grid">
|
||||
<button
|
||||
v-for="card in hub.cards"
|
||||
:key="card.to + card.title"
|
||||
class="card"
|
||||
type="button"
|
||||
@click="emit('go', card.to)"
|
||||
>
|
||||
<span class="card-top">
|
||||
<span class="card-title">
|
||||
{{ card.title }}
|
||||
<UiIcon name="chevron" :size="13" class="go" />
|
||||
</span>
|
||||
<span class="card-ico" :class="card.tint" aria-hidden="true">
|
||||
<UiIcon :name="card.icon" :size="16" />
|
||||
</span>
|
||||
</span>
|
||||
<span class="card-desc">{{ card.desc }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="hub.shortcuts.length" class="quick">
|
||||
<span class="quick-label">دسترسی سریع</span>
|
||||
<div class="quick-row">
|
||||
<button
|
||||
v-for="item in hub.shortcuts"
|
||||
:key="item.to + item.title"
|
||||
class="quick-btn"
|
||||
type="button"
|
||||
@click="emit('go', item.to)"
|
||||
>
|
||||
<UiIcon :name="item.icon" :size="15" />
|
||||
{{ item.title }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.hub {
|
||||
width: min(28rem, calc(100vw - var(--hub-offset, 16rem) - 1.5rem));
|
||||
max-height: calc(100dvh - 56px);
|
||||
overflow: hidden;
|
||||
padding: 0.9rem 0.9rem 0.8rem;
|
||||
display: grid;
|
||||
align-content: start;
|
||||
gap: 0.7rem;
|
||||
border-radius: 28px;
|
||||
background: #fff;
|
||||
box-shadow: 0 18px 40px rgba(15, 23, 42, 0.12);
|
||||
}
|
||||
|
||||
.head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.8rem;
|
||||
padding: 0 0.15rem;
|
||||
}
|
||||
|
||||
.copy h1 {
|
||||
margin: 0;
|
||||
font-size: 1.05rem;
|
||||
font-weight: 800;
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
.copy p {
|
||||
margin: 0.15rem 0 0;
|
||||
color: #94a3b8;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.head-ico,
|
||||
.card-ico {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.head-ico {
|
||||
width: 2.2rem;
|
||||
height: 2.2rem;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.card-ico {
|
||||
width: 1.9rem;
|
||||
height: 1.9rem;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.card-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.card {
|
||||
display: grid;
|
||||
justify-items: stretch;
|
||||
align-content: start;
|
||||
gap: 0.28rem;
|
||||
padding: 0.65rem 0.7rem 0.55rem;
|
||||
border: 0;
|
||||
border-radius: 16px;
|
||||
background: #f7f8fa;
|
||||
cursor: pointer;
|
||||
text-align: start;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
background: #f1f5f9;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
font-size: 0.88rem;
|
||||
font-weight: 800;
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
.card-desc {
|
||||
color: #94a3b8;
|
||||
font-size: 0.72rem;
|
||||
line-height: 1.5;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.go {
|
||||
transform: scaleX(-1);
|
||||
color: #94a3b8;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.quick {
|
||||
display: grid;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.quick-label {
|
||||
padding-inline: 0.15rem;
|
||||
color: #64748b;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.quick-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.quick-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.35rem;
|
||||
min-height: 2.4rem;
|
||||
padding: 0.45rem 0.7rem;
|
||||
border: 0;
|
||||
border-radius: 999px;
|
||||
background: #ecfdf8;
|
||||
color: #0f766e;
|
||||
font: inherit;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.quick-btn:hover {
|
||||
background: #d8faf3;
|
||||
}
|
||||
|
||||
.mint {
|
||||
background: #d8faf3;
|
||||
color: #0f766e;
|
||||
}
|
||||
|
||||
.violet {
|
||||
background: #eee7ff;
|
||||
color: #6d28d9;
|
||||
}
|
||||
|
||||
.peach {
|
||||
background: #ffedd5;
|
||||
color: #c2410c;
|
||||
}
|
||||
|
||||
.sky {
|
||||
background: #e0f2fe;
|
||||
color: #0369a1;
|
||||
}
|
||||
|
||||
.rose {
|
||||
background: #fce7f3;
|
||||
color: #be185d;
|
||||
}
|
||||
|
||||
.amber {
|
||||
background: #fef3c7;
|
||||
color: #b45309;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.hub {
|
||||
width: 100%;
|
||||
max-height: min(86dvh, calc(100dvh - 3.5rem));
|
||||
overflow: auto;
|
||||
padding: 0.85rem 0.9rem calc(0.9rem + env(safe-area-inset-bottom));
|
||||
border-radius: 24px 24px 0 0;
|
||||
box-shadow: 0 -12px 40px rgba(15, 23, 42, 0.16);
|
||||
}
|
||||
|
||||
.hub::before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 2.6rem;
|
||||
height: 0.28rem;
|
||||
margin: 0 auto 0.65rem;
|
||||
border-radius: 999px;
|
||||
background: #e2e8f0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user