docs(vue): add interactive demo for every composable

A beautiful, SSR-safe demo.vue next to each composable, auto-discovered by the docs extractor and rendered client-only on each composable's page.
This commit is contained in:
2026-06-08 15:51:16 +07:00
parent 59e995d0b5
commit e83f10fe32
214 changed files with 19584 additions and 74 deletions
@@ -0,0 +1,95 @@
<script setup lang="ts">
import { computed, ref } from 'vue';
import { useArrayMap } from './index';
interface Product {
name: string;
price: number;
}
const products = ref<Product[]>([
{ name: 'Mechanical keyboard', price: 129 },
{ name: 'Ultrawide monitor', price: 549 },
{ name: 'Noise-cancelling headset', price: 299 },
{ name: 'Standing desk', price: 419 },
]);
const taxRate = ref(8);
// Reactive Array.prototype.map — recomputes when products or taxRate change.
const priced = useArrayMap(products, (product) => {
const gross = product.price * (1 + taxRate.value / 100);
return { ...product, gross };
});
const formatter = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' });
const total = computed(() => priced.value.reduce((sum, p) => sum + p.gross, 0));
function bump(index: number, delta: number) {
const next = products.value.slice();
next[index] = { ...next[index], price: Math.max(0, next[index].price + delta) };
products.value = next;
}
</script>
<template>
<div class="w-full max-w-md flex flex-col gap-4">
<div class="flex items-center justify-between">
<span class="text-xs font-medium uppercase tracking-wide text-(--fg-subtle)">Cart</span>
<label class="flex items-center gap-2 text-sm text-(--fg-muted)">
Tax {{ taxRate }}%
<input
v-model.number="taxRate"
type="range"
min="0"
max="25"
class="accent-(--accent)"
>
</label>
</div>
<ul class="flex flex-col gap-2">
<li
v-for="(item, index) in priced"
:key="item.name"
class="flex items-center justify-between gap-3 rounded-lg border border-(--border) bg-(--bg-elevated) px-3 py-2"
>
<div class="min-w-0 flex-1">
<p class="truncate text-sm font-medium text-(--fg)">
{{ item.name }}
</p>
<p class="text-xs text-(--fg-subtle)">
base {{ formatter.format(item.price) }}
</p>
</div>
<div class="flex items-center gap-1.5">
<button
class="inline-flex size-7 items-center justify-center rounded-md border border-(--border) bg-(--bg-elevated) text-(--fg) transition hover:bg-(--bg-inset) active:scale-[0.98] cursor-pointer"
aria-label="Decrease price"
@click="bump(index, -10)"
>
&minus;
</button>
<button
class="inline-flex size-7 items-center justify-center rounded-md border border-(--border) bg-(--bg-elevated) text-(--fg) transition hover:bg-(--bg-inset) active:scale-[0.98] cursor-pointer"
aria-label="Increase price"
@click="bump(index, 10)"
>
+
</button>
</div>
<span class="w-20 text-right font-mono text-sm tabular-nums text-(--fg)">
{{ formatter.format(item.gross) }}
</span>
</li>
</ul>
<div class="flex items-center justify-between rounded-lg border border-(--border) bg-(--bg-inset) p-3">
<span class="text-xs font-medium uppercase tracking-wide text-(--fg-subtle)">Total with tax</span>
<span class="font-mono text-xl font-bold tabular-nums text-(--fg)">
{{ formatter.format(total) }}
</span>
</div>
</div>
</template>