Files
GMW/services/frontend/src/components/ui/Card.astro
T
asepharyana 8ad888da28 feat: migrate frontend to Astro SSG with design system
- Replace monolithic React SPA (App.tsx) with 7 Astro pages (+ routing)
- Implement full design system from design/ (OKLCH tokens, Tailwind 4 @theme)
- Add 12 Astro components (Button, Badge, Card, Sidebar, Header, states)
- Add 11 React islands (AuthGuard, MessageFeed, VoiceControls, AudioVisualizer, etc.)
- Add 3 Zustand stores (UI, voice, message state)
- Add CSS architecture: dark/light themes, glassmorphism, fluid typography, animations
- Add 404, login, settings, recordings pages
- Remove 40+ legacy React SPA files
- Add Particles background and MascotChat deferred islands
- Wire WebSocket bridge for real-time messages and voice events

Build: 7 pages in ~900ms
Typecheck: clean (0 errors)
Lint: clean (0 errors)
2026-07-02 01:18:45 +07:00

102 lines
2.8 KiB
Plaintext

---
export interface Props {
variant?: "default" | "elevated" | "glass" | "interactive";
padding?: "none" | "sm" | "md" | "lg";
class?: string;
}
const {
variant = "default",
padding = "md",
class: className = "",
} = Astro.props;
---
<div class:list={[`card card--${variant} card--pad-${padding}`, className]}>
<slot />
</div>
<style is:global>
.card {
--rd-lg: var(--radius, 1rem);
border-radius: var(--rd-lg);
transition:
background-color var(--duration-normal, 300ms) var(--ease-out, ease-out),
color var(--duration-normal, 300ms) var(--ease-out, ease-out),
border-color var(--duration-normal, 300ms) var(--ease-out, ease-out),
box-shadow var(--duration-normal, 300ms) var(--ease-out, ease-out),
transform var(--duration-normal, 300ms) var(--ease-out, ease-out);
}
/* ── Padding variants ──────────────────────────── */
.card--pad-none {
padding: 0;
}
.card--pad-sm {
padding: 0.75rem;
}
.card--pad-md {
padding: 1.5rem;
}
.card--pad-lg {
padding: 2rem;
}
/* ── Variant: default ──────────────────────────── */
.card--default {
background-color: oklch(var(--card));
color: oklch(var(--card-foreground));
border: 1px solid oklch(var(--border));
box-shadow: 0 1px 2px oklch(0 0 0 / 0.05);
}
/* ── Variant: elevated ─────────────────────────── */
.card--elevated {
background-color: oklch(var(--card));
color: oklch(var(--card-foreground));
border: 1px solid oklch(var(--border));
box-shadow:
0 4px 6px -1px oklch(0 0 0 / 0.1),
0 2px 4px -2px oklch(0 0 0 / 0.1);
}
/* ── Variant: glass ────────────────────────────── */
.card--glass {
background-color: oklch(var(--glass-bg));
border: 1px solid oklch(var(--glass-border));
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
box-shadow: 0 4px 24px oklch(var(--glass-shadow));
}
/* ── Variant: interactive ──────────────────────── */
.card--interactive {
background-color: oklch(var(--card));
color: oklch(var(--card-foreground));
border: 1px solid oklch(var(--border));
box-shadow: 0 1px 2px oklch(0 0 0 / 0.05);
cursor: pointer;
}
.card--interactive:hover {
transform: translateY(-4px);
box-shadow:
0 10px 15px -3px oklch(0 0 0 / 0.1),
0 4px 6px -4px oklch(0 0 0 / 0.1);
border-color: oklch(var(--primary) / 0.3);
}
.card--interactive:focus-visible {
outline: 2px solid oklch(var(--ring));
outline-offset: 2px;
}
</style>