Examples
These examples are intentionally small. They show the standard structure and class rhythm without binding teams to a single framework package.
Vue Admin Shell
Use this shape for authenticated Payd Labs dashboards and control planes.
<script setup lang="ts">
import { ref } from 'vue'
import { Menu, X, Moon, Sun, LogOut, LayoutDashboard } from 'lucide-vue-next'
const LOGO_LIGHT = 'https://res.cloudinary.com/dadkir6u2/image/upload/v1767808544/payd_logo_for_light_mode_scwwdc.png'
const LOGO_DARK = 'https://res.cloudinary.com/dadkir6u2/image/upload/v1767808543/payd_logo_for_dark_mode_otv7uv.png'
const isDark = ref(document.documentElement.classList.contains('dark'))
const mobileOpen = ref(false)
function toggleTheme() {
isDark.value = !isDark.value
document.documentElement.classList.toggle('dark', isDark.value)
}
const nav = [
{ label: 'Dashboard', to: '/', icon: LayoutDashboard },
]
</script>
<template>
<div class="min-h-screen bg-surface text-text">
<header class="fixed top-0 left-0 right-0 z-40 h-14 bg-surface/80 backdrop-blur-xl border-b border-border flex items-center px-4 lg:px-6">
<button class="lg:hidden p-2 -ml-2 rounded-lg text-text-secondary hover:text-text hover:bg-surface-tertiary" @click="mobileOpen = !mobileOpen">
<Menu v-if="!mobileOpen" :size="20" />
<X v-else :size="20" />
</button>
<img :src="isDark ? LOGO_DARK : LOGO_LIGHT" alt="Payd" class="h-6 w-auto ml-2 lg:ml-0" />
<span class="bg-accent-100 text-accent-dark px-2 py-0.5 rounded-md text-[10px] font-semibold font-heading ml-2">Product</span>
<div class="flex-1" />
<button class="p-2 rounded-lg text-text-tertiary hover:text-text hover:bg-surface-tertiary" @click="toggleTheme">
<Moon v-if="!isDark" :size="16" />
<Sun v-else :size="16" />
</button>
<button class="p-2 rounded-lg text-text-tertiary hover:text-error hover:bg-surface-tertiary ml-1">
<LogOut :size="16" />
</button>
</header>
<aside class="fixed top-14 bottom-0 left-0 w-56 bg-surface border-r border-border z-30 transition-transform duration-200"
:class="mobileOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0'">
<nav class="p-3 space-y-0.5 mt-2">
<router-link v-for="item in nav" :key="item.to" :to="item.to"
class="flex items-center gap-2.5 px-3 py-2 rounded-lg text-[13px] font-medium transition-all text-text-secondary hover:text-text hover:bg-surface-tertiary">
<component :is="item.icon" :size="16" />
{{ item.label }}
</router-link>
</nav>
</aside>
<main class="pt-14 lg:pl-56">
<div class="p-4 lg:p-6">
<router-view />
</div>
</main>
</div>
</template>
Login Panel
<div class="min-h-screen flex items-center justify-center bg-surface-secondary p-4">
<div class="w-full max-w-sm">
<div class="text-center mb-8">
<img src="PAYD_LOGO" alt="Payd" class="h-7 w-auto mx-auto mb-3" />
<div class="flex items-center justify-center gap-2">
<h1 class="text-lg font-heading font-semibold text-text">Product</h1>
<span class="bg-accent-100 text-accent-dark px-2 py-0.5 rounded-md text-[10px] font-semibold font-heading">Admin</span>
</div>
<p class="text-sm text-text-secondary mt-1">Product purpose</p>
</div>
<div class="bg-surface rounded-xl border border-border p-6 shadow-soft">
<form class="space-y-4">
<label class="block text-xs font-semibold text-text-secondary mb-1.5">Username</label>
<input class="input" autocomplete="username" />
<label class="block text-xs font-semibold text-text-secondary mb-1.5">Password</label>
<input class="input" type="password" autocomplete="current-password" />
<button class="w-full py-2.5 btn-accent text-sm">Sign In</button>
</form>
</div>
</div>
</div>
Table Panel
<div class="bg-surface rounded-xl border border-border overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead>
<tr class="bg-surface-secondary border-b border-border">
<th class="text-left px-4 py-2.5 font-heading font-semibold text-text-secondary text-xs uppercase tracking-wider">Reference</th>
<th class="text-left px-4 py-2.5 font-heading font-semibold text-text-secondary text-xs uppercase tracking-wider">Status</th>
<th class="text-left px-4 py-2.5 font-heading font-semibold text-text-secondary text-xs uppercase tracking-wider">Amount</th>
</tr>
</thead>
<tbody>
<tr class="border-b border-border/50 last:border-0 hover:bg-surface-secondary/50">
<td class="px-4 py-2.5 font-mono text-xs text-accent-dark">STB-1048</td>
<td class="px-4 py-2.5">
<span class="px-2 py-0.5 rounded-full text-[10px] font-semibold bg-accent-100 text-accent-dark">completed</span>
</td>
<td class="px-4 py-2.5 font-mono text-xs">250.00 USDT</td>
</tr>
</tbody>
</table>
</div>
</div>
Status Pill Function
export function statusClass(status: string) {
const value = status.toLowerCase()
if (['approved', 'active', 'settled', 'completed', 'delivered'].includes(value)) {
return 'bg-accent-100 text-accent-dark'
}
if (['pending', 'confirming', 'processing', 'received', 'awaiting_deposit'].includes(value)) {
return 'bg-blue-50 text-blue-600 dark:bg-blue-500/10 dark:text-blue-400'
}
if (['expired', 'underpaid'].includes(value)) {
return 'bg-amber-50 text-amber-600 dark:bg-amber-500/10 dark:text-amber-400'
}
if (['failed', 'rejected', 'suspended', 'settlement_failed'].includes(value)) {
return 'bg-red-50 text-red-600 dark:bg-red-500/10 dark:text-red-400'
}
return 'bg-surface-tertiary text-text-tertiary'
}