127 lines
9.5 KiB
Vue
127 lines
9.5 KiB
Vue
<!-- Product-specific miniature interfaces, built from type and line, no screenshots to download. -->
|
||
<script setup lang="ts">
|
||
const props = defineProps<{ product: { fa: string; en: string; kind: string }; compact?: boolean }>();
|
||
const k = computed(() => props.product.kind);
|
||
const ledger = [["فروش آنلاین", "۱۲٬۴۰۰٬۰۰۰"], ["کارمزد درگاه", "۱۸۶٬۰۰۰"], ["مالیات بر ارزش افزوده", "۱٬۱۱۶٬۰۰۰"], ["حمل و ارسال", "۹۴۰٬۰۰۰"]];
|
||
const payroll = [["مریم احمدی", "۴۲٬۸۰۰٬۰۰۰"], ["علی رضایی", "۳۸٬۲۰۰٬۰۰۰"], ["سارا کریمی", "۳۶٬۵۰۰٬۰۰۰"], ["رضا موسوی", "۳۱٬۹۰۰٬۰۰۰"]];
|
||
const bars = [30, 42, 38, 55, 48, 62, 58, 70, 66, 80, 76, 92];
|
||
const store = [["کوزهٔ لعابی", "۸۲۰", "#2341B8"], ["گلیم ۲×۳", "۴٬۹۰۰", "#C2330F"], ["قوری مسی", "۱٬۲۵۰", "#14213A"]];
|
||
const services = [["auth", true], ["checkout", true], ["search", false], ["media", true]] as const;
|
||
const results = ["پیشنویس قرارداد اجاره — واحد حقوقی", "صورتجلسهٔ تمدید اجاره — شعبهٔ شیراز", "پیوست مالی قرارداد — ۱۴۰۲/۰۶"];
|
||
const wave = Array.from({ length: 48 }, (_, i) => Math.min(100, 18 + Math.abs(Math.sin(i * 1.7) * 60) + (i % 5) * 4));
|
||
const apps = [["دفتر", true], ["پیام", true], ["سنجه", false], ["بندر", true]] as const;
|
||
const buckets = [["media-prod", "۷۸%", "78%"], ["backups", "۵۲%", "52%"], ["logs-archive", "۳۱%", "31%"]];
|
||
const days = ["ش", "ی", "د", "س", "چ", "پ"];
|
||
const booked = new Set([1, 2, 7, 9, 10, 14, 15, 16, 20, 22]);
|
||
</script>
|
||
|
||
<template>
|
||
<figure class="flex flex-col overflow-hidden rounded-[12px] border border-ink/10 bg-surface text-ink" :class="compact ? 'h-[min(176px,22svh)]' : 'h-[min(270px,32vh)]'">
|
||
<figcaption class="flex items-center justify-between border-b border-ink/[0.07] px-4 py-[9px] text-[14px] text-mute">
|
||
<span>{{ product.fa }}</span>
|
||
<bdi dir="ltr" class="font-mono text-[13px] tracking-wide">{{ product.en.toLowerCase() }}.rasad.ir</bdi>
|
||
</figcaption>
|
||
<div class="min-h-0 flex-1 overflow-hidden" :class="compact ? 'p-3' : 'p-5'">
|
||
<div v-if="k === 'pay'" class="flex h-full flex-col justify-between">
|
||
<div>
|
||
<p class="text-[14px] text-mute">تسویهٔ امروز</p>
|
||
<p class="mt-1 text-[clamp(1.6rem,3vw,2.4rem)] font-extrabold leading-none">۲٬۴۸۰٬۰۰۰<span class="ms-2 text-[14px] font-normal text-mute">تومان</span></p>
|
||
</div>
|
||
<div class="flex h-16 items-end gap-[5px]">
|
||
<span v-for="(h, i) in bars" :key="i" class="flex-1 rounded-t-[2px]" :class="i === 11 ? 'bg-verm' : 'bg-lapis/25'" :style="{ height: h + '%' }" />
|
||
</div>
|
||
</div>
|
||
|
||
<div v-else-if="k === 'ledger' || k === 'payroll'" class="flex h-full flex-col justify-center gap-[10px] text-[14px]">
|
||
<div v-for="([a, b], i) in (k === 'ledger' ? ledger : payroll)" :key="i" class="flex items-center justify-between gap-3" :class="i < 3 ? 'border-b border-ink/[0.07] pb-[9px]' : ''">
|
||
<span>{{ a }}</span><span class="font-medium tabular-nums">{{ b }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-else-if="k === 'store'" class="grid h-full grid-cols-3 gap-3">
|
||
<div v-for="[n, p, c] in store" :key="n" class="flex flex-col gap-2">
|
||
<div class="flex-1 rounded-[6px]" :style="{ background: `repeating-linear-gradient(135deg, ${c}22 0 6px, ${c}0d 6px 12px)` }" />
|
||
<p class="truncate text-[14px]">{{ n }}</p><p class="text-[14px] text-mute">{{ p }} هزار</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-else-if="k === 'chart'" class="flex h-full flex-col gap-2">
|
||
<p class="text-[14px] text-mute">«فروش هفتگی تهران در برابر اصفهان»</p>
|
||
<svg viewBox="0 0 300 110" class="w-full flex-1" preserveAspectRatio="none" aria-hidden="true">
|
||
<line v-for="y in [20, 50, 80]" :key="y" x1="0" x2="300" :y1="y" :y2="y" stroke="#14213A" stroke-opacity=".08" />
|
||
<polyline fill="none" stroke="#2341B8" stroke-width="2" points="300,80 260,70 220,74 180,52 140,58 100,36 60,40 20,18" />
|
||
<polyline fill="none" stroke="#14213A" stroke-opacity=".35" stroke-width="1.5" stroke-dasharray="4 4" points="300,92 260,88 220,84 180,80 140,70 100,72 60,62 20,58" />
|
||
<circle cx="100" cy="36" r="4" fill="#C2330F" />
|
||
</svg>
|
||
</div>
|
||
|
||
<div v-else-if="k === 'monitor'" class="grid h-full grid-cols-2 gap-x-5 gap-y-3 text-[14px]">
|
||
<div v-for="[n, ok] in services" :key="n" class="flex flex-col justify-center gap-1">
|
||
<div class="flex items-center justify-between"><bdi dir="ltr" class="font-mono">{{ n }}</bdi><span :class="ok ? 'text-lapis' : 'text-verm'">{{ ok ? 'سالم' : 'کُند' }}</span></div>
|
||
<svg viewBox="0 0 100 24" class="h-6 w-full" preserveAspectRatio="none" aria-hidden="true">
|
||
<polyline fill="none" :stroke="ok ? '#2341B8' : '#C2330F'" stroke-width="1.5" :points="ok ? '0,16 15,14 30,17 45,12 60,15 75,13 100,14' : '0,18 20,16 40,15 55,6 70,9 85,4 100,7'" />
|
||
</svg>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-else-if="k === 'search'" class="flex h-full flex-col gap-3 text-[14px]">
|
||
<div class="rounded-[6px] border border-ink/15 px-3 py-2">قرارداد اجارهٔ دفتر <span class="text-mute">۱۴۰۲</span></div>
|
||
<p v-for="t in results" :key="t" class="truncate"><mark class="bg-lapis/[0.12] text-inherit">{{ t.split(' ')[0] }}</mark> {{ t.split(' ').slice(1).join(' ') }}</p>
|
||
</div>
|
||
|
||
<div v-else-if="k === 'wave'" class="flex h-full flex-col justify-between gap-3">
|
||
<div class="flex h-14 items-center gap-[3px]">
|
||
<span v-for="(h, i) in wave" :key="i" class="flex-1 rounded-full" :class="i > 30 ? 'bg-ink/15' : 'bg-lapis'" :style="{ height: h + '%' }" />
|
||
</div>
|
||
<p class="text-[15px] leading-7">سلام، برای پیگیری سفارشم تماس گرفتم، <span class="rounded-[3px] bg-verm/[0.12] px-1 text-verm">کِی</span> میرسه؟</p>
|
||
</div>
|
||
|
||
<div v-else-if="k === 'terminal'" dir="ltr" class="flex h-full flex-col justify-center gap-[7px] text-left font-mono text-[14px]">
|
||
<p><span class="text-mute">$</span> bandar deploy --prod</p>
|
||
<p class="text-mute">build ······ 14.2s</p><p class="text-mute">health ····· 3/3 ok</p>
|
||
<p class="text-mute">traffic ···· 0 → 100%</p><p class="text-lapis">● live in 41s</p>
|
||
</div>
|
||
|
||
<div v-else-if="k === 'keys'" class="flex h-full flex-col justify-center gap-[10px] text-[14px]">
|
||
<div v-for="[n, on] in apps" :key="n" class="flex items-center justify-between">
|
||
<span>{{ n }}</span>
|
||
<span class="relative h-[18px] w-8 rounded-full" :class="on ? 'bg-lapis' : 'bg-ink/15'">
|
||
<span class="absolute top-[3px] h-3 w-3 rounded-full bg-white" :class="on ? 'end-[3px]' : 'start-[3px]'" />
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-else-if="k === 'storage'" class="flex h-full flex-col justify-center gap-3 text-[14px]">
|
||
<div v-for="[n, p, w] in buckets" :key="n" class="flex flex-col gap-[6px]">
|
||
<div class="flex items-center justify-between"><bdi dir="ltr" class="font-mono">{{ n }}</bdi><span class="text-mute">{{ p }}</span></div>
|
||
<span class="h-[6px] rounded-full bg-ink/[0.07]"><span class="block h-[6px] rounded-full bg-lapis" :style="{ width: w }" /></span>
|
||
</div>
|
||
</div>
|
||
|
||
<div v-else-if="k === 'api'" dir="ltr" class="flex h-full flex-col justify-center gap-[6px] text-left font-mono text-[14px]">
|
||
<p><span class="text-lapis">GET</span> /v2/orders/8841 <span class="text-mute">200 · 2.1ms</span></p>
|
||
<p class="text-mute">{</p><p class="ps-4">"status": <span class="text-verm">"shipped"</span>,</p><p class="ps-4">"city": "Tabriz"</p><p class="text-mute">}</p>
|
||
</div>
|
||
|
||
<div v-else-if="k === 'chat'" class="flex h-full flex-col justify-center gap-2 text-[14px]">
|
||
<p class="max-w-[80%] self-start rounded-[12px] rounded-ss-[3px] bg-ink/[0.06] px-3 py-2">نسخهٔ جدید «بندر» آماده است؟</p>
|
||
<p class="max-w-[80%] self-end rounded-[12px] rounded-se-[3px] bg-lapis px-3 py-2 text-white">بله، ساعت ۱۶ منتشر میشود.</p>
|
||
<p class="self-start text-mute">نیلوفر در حال نوشتن…</p>
|
||
</div>
|
||
|
||
<div v-else-if="k === 'calendar'" class="grid h-full grid-cols-6 gap-[5px] text-center text-[14px]">
|
||
<span v-for="d in days" :key="d" class="text-mute">{{ d }}</span>
|
||
<span v-for="i in 24" :key="i" class="rounded-[4px]" :class="i - 1 === 9 ? 'bg-verm' : booked.has(i - 1) ? 'bg-lapis/70' : 'bg-ink/[0.06]'" />
|
||
</div>
|
||
|
||
<svg v-else-if="k === 'map'" viewBox="0 0 300 140" class="h-full w-full" aria-hidden="true">
|
||
<line v-for="i in 7" :key="'v' + i" :x1="(i - 1) * 50" :x2="(i - 1) * 50 + 20" y1="0" y2="140" stroke="#14213A" stroke-opacity=".07" />
|
||
<line v-for="i in 4" :key="'h' + i" x1="0" x2="300" :y1="(i - 1) * 40 + 10" :y2="(i - 1) * 40 + 18" stroke="#14213A" stroke-opacity=".07" />
|
||
<path d="M280 120 C 240 110, 230 70, 190 72 S 130 40, 100 52 S 40 30, 22 20" fill="none" stroke="#2341B8" stroke-width="2.5" />
|
||
<circle v-for="([x, y], i) in [[280, 120], [190, 72], [100, 52], [22, 20]]" :key="i" :cx="x" :cy="y" :r="i === 3 ? 6 : 4"
|
||
:fill="i === 3 ? '#C2330F' : '#F8F9FB'" :stroke="i === 3 ? 'none' : '#2341B8'" stroke-width="2" />
|
||
</svg>
|
||
</div>
|
||
</figure>
|
||
</template>
|