Revert "feat: migrate frontend to Astro SSG with design system"

This reverts commit 8ad888da28.
This commit is contained in:
asepharyana
2026-07-02 03:54:44 +07:00
parent 880c68fbab
commit bf86fcda8e
110 changed files with 4980 additions and 3396 deletions
@@ -1,106 +0,0 @@
---
export interface Props {
variant?: "default" | "secondary" | "success" | "warning" | "destructive" | "outline";
size?: "sm" | "default";
dot?: boolean;
class?: string;
}
const {
variant = "default",
size = "default",
dot = false,
class: className = "",
} = Astro.props;
---
<span class:list={[`badge badge--${variant} badge--${size}`, className]}>
{dot && <span class="badge__dot" aria-hidden="true" />}
<slot />
</span>
<style is:global>
.badge {
--fs-xs: 0.75rem;
--fs-xxs: 0.625rem;
display: inline-flex;
align-items: center;
gap: 0.375rem;
border-radius: 999px;
border: 1px solid transparent;
font-weight: var(--fw-medium, 500);
transition:
background-color var(--duration-fast, 150ms) var(--ease-out, ease-out),
color var(--duration-fast, 150ms) var(--ease-out, ease-out);
white-space: nowrap;
user-select: none;
}
.badge--default {
padding-inline: 0.625rem;
padding-block: 0.125rem;
font-size: var(--fs-xs);
background-color: oklch(var(--primary));
color: oklch(var(--primary-foreground));
}
.badge--secondary {
padding-inline: 0.625rem;
padding-block: 0.125rem;
font-size: var(--fs-xs);
background-color: oklch(var(--muted));
color: oklch(var(--muted-foreground));
}
.badge--success {
padding-inline: 0.625rem;
padding-block: 0.125rem;
font-size: var(--fs-xs);
background-color: oklch(var(--success) / 0.15);
color: oklch(var(--success));
}
.badge--warning {
padding-inline: 0.625rem;
padding-block: 0.125rem;
font-size: var(--fs-xs);
background-color: oklch(var(--warning) / 0.15);
color: oklch(var(--warning));
}
.badge--destructive {
padding-inline: 0.625rem;
padding-block: 0.125rem;
font-size: var(--fs-xs);
background-color: oklch(var(--destructive) / 0.15);
color: oklch(var(--destructive));
}
.badge--outline {
padding-inline: 0.625rem;
padding-block: 0.125rem;
font-size: var(--fs-xs);
border-color: oklch(var(--border));
background-color: transparent;
color: oklch(var(--foreground));
}
/* ── Size sm ───────────────────────────────────── */
.badge--sm {
padding-inline: 0.375rem;
padding-block: 0.0625rem;
font-size: var(--fs-xxs);
}
/* ── Dot indicator ─────────────────────────────── */
.badge__dot {
display: inline-block;
width: 0.375rem;
height: 0.375rem;
border-radius: 50%;
background-color: currentColor;
flex-shrink: 0;
}
</style>
@@ -1,146 +0,0 @@
---
export interface Props {
variant?: "primary" | "secondary" | "destructive" | "outline" | "ghost";
size?: "sm" | "default" | "lg" | "icon";
disabled?: boolean;
href?: string;
class?: string;
}
const {
variant = "primary",
size = "default",
disabled = false,
href,
class: className = "",
} = Astro.props;
const Tag = href ? "a" : "button";
const attrs: Record<string, string | number | boolean> = {
class: `btn btn--${variant} btn--${size} ${className}`,
};
if (Tag === "button") {
attrs.disabled = disabled;
} else if (disabled) {
attrs["aria-disabled"] = true;
attrs.role = "link";
}
---
<Tag {...attrs}>
<slot />
</Tag>
<style is:global>
.btn {
--rd-md: calc(var(--radius, 1rem) - 2px);
--fs-sm: 0.875rem;
--fw-medium: 500;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
white-space: nowrap;
border-radius: var(--rd-md);
font-size: var(--fs-sm);
font-weight: var(--fw-medium);
line-height: 1.25rem;
transition:
background-color var(--duration-fast, 150ms) var(--ease-out, ease-out),
color var(--duration-fast, 150ms) var(--ease-out, ease-out),
border-color var(--duration-fast, 150ms) var(--ease-out, ease-out),
box-shadow var(--duration-fast, 150ms) var(--ease-out, ease-out),
transform var(--duration-fast, 150ms) var(--ease-out, ease-out);
cursor: pointer;
border: 1px solid transparent;
text-decoration: none;
outline: none;
user-select: none;
}
.btn:focus-visible {
outline: 2px solid oklch(var(--ring));
outline-offset: 2px;
}
.btn:active {
transform: scale(0.97);
}
.btn:disabled,
.btn[aria-disabled="true"] {
pointer-events: none;
opacity: 0.5;
}
/* ── Variants ──────────────────────────────────────────── */
.btn--primary {
background-color: oklch(var(--primary));
color: oklch(var(--primary-foreground));
box-shadow: 0 1px 2px oklch(0 0 0 / 0.05);
}
.btn--primary:hover {
background-color: oklch(var(--primary) / 0.9);
}
.btn--secondary {
background-color: oklch(var(--secondary));
color: oklch(var(--secondary-foreground));
}
.btn--secondary:hover {
background-color: oklch(var(--secondary) / 0.8);
}
.btn--destructive {
background-color: oklch(var(--destructive));
color: oklch(var(--destructive-foreground));
box-shadow: 0 1px 2px oklch(0 0 0 / 0.05);
}
.btn--destructive:hover {
background-color: oklch(var(--destructive) / 0.9);
}
.btn--outline {
border-color: oklch(var(--border));
background-color: oklch(var(--background));
color: oklch(var(--foreground));
}
.btn--outline:hover {
background-color: oklch(var(--accent));
color: oklch(var(--accent-foreground));
}
.btn--ghost {
background-color: transparent;
color: oklch(var(--foreground));
}
.btn--ghost:hover {
background-color: oklch(var(--accent));
color: oklch(var(--accent-foreground));
}
/* ── Sizes ─────────────────────────────────────────────── */
.btn--sm {
height: 2.25rem;
padding-inline: 0.75rem;
}
.btn--default {
height: 2.5rem;
padding-inline: 1rem;
}
.btn--lg {
height: 2.75rem;
padding-inline: 2rem;
}
.btn--icon {
height: 2.5rem;
width: 2.5rem;
padding: 0;
}
</style>
@@ -1,101 +0,0 @@
---
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>
@@ -1,97 +0,0 @@
---
export interface Props {
severity: "safe" | "low" | "medium" | "high" | "critical";
class?: string;
}
const { severity, class: className = "" } = Astro.props;
const ICONS: Record<string, string> = {
safe: "&#x2714;",
low: "&#x2197;",
medium: "&#x26A0;",
high: "&#x26A1;",
critical: "&#x2716;",
};
const icon = ICONS[severity] ?? "";
---
<span
class:list={[`severity-badge severity-badge--${severity}`, className]}
data-severity={severity}
role="status"
>
<span class="severity-badge__icon" aria-hidden="true" set:html={icon} />
<span class="severity-badge__label"><slot /></span>
</span>
<style is:global>
.severity-badge {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding-inline: 0.5rem;
padding-block: 0.2rem;
border-radius: 999px;
font-size: 0.75rem;
font-weight: 500;
border: 1px solid transparent;
line-height: 1;
user-select: none;
}
.severity-badge__icon {
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 0.75rem;
line-height: 1;
flex-shrink: 0;
}
.severity-badge__label {
text-transform: capitalize;
}
/* ── Severity: safe → success ──────────────────── */
.severity-badge--safe {
background-color: oklch(var(--success) / 0.15);
color: oklch(var(--success));
border-color: oklch(var(--success) / 0.25);
}
/* ── Severity: low → info ──────────────────────── */
.severity-badge--low {
background-color: oklch(var(--info) / 0.15);
color: oklch(var(--info));
border-color: oklch(var(--info) / 0.25);
}
/* ── Severity: medium → warning ────────────────── */
.severity-badge--medium {
background-color: oklch(var(--warning) / 0.15);
color: oklch(var(--warning));
border-color: oklch(var(--warning) / 0.25);
}
/* ── Severity: high → destructive ──────────────── */
.severity-badge--high {
background-color: oklch(var(--destructive) / 0.12);
color: oklch(var(--destructive));
border-color: oklch(var(--destructive) / 0.2);
}
/* ── Severity: critical ────────────────────────── */
.severity-badge--critical {
background-color: oklch(var(--destructive) / 0.25);
color: oklch(var(--destructive));
border-color: oklch(var(--destructive) / 0.4);
font-weight: 600;
}
</style>
@@ -1,74 +0,0 @@
---
export interface Props {
variant?: "text" | "card" | "circle" | "rect";
width?: string;
height?: string;
class?: string;
}
const {
variant = "text",
width,
height,
class: className = "",
} = Astro.props;
const style: Record<string, string> = {};
if (width) style.width = width;
if (height) style.height = height;
---
<div
aria-hidden="true"
role="presentation"
class:list={[`skeleton skeleton--${variant}`, className]}
style={Object.keys(style).length > 0 ? style : undefined}
>
<slot />
</div>
<style is:global>
.skeleton {
background: linear-gradient(
90deg,
oklch(var(--muted)) 25%,
oklch(var(--muted-foreground) / 0.15) 50%,
oklch(var(--muted)) 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s ease-in-out infinite;
border-radius: 0.5rem;
}
/* ── Variant: text (default) ───────────────────── */
.skeleton--text {
width: 100%;
height: 1rem;
border-radius: calc(var(--radius, 1rem) - 4px);
}
/* ── Variant: card ─────────────────────────────── */
.skeleton--card {
width: 100%;
height: 8rem;
border-radius: var(--radius, 1rem);
}
/* ── Variant: circle ───────────────────────────── */
.skeleton--circle {
width: 2.5rem;
height: 2.5rem;
border-radius: 50%;
}
/* ── Variant: rect ─────────────────────────────── */
.skeleton--rect {
width: 100%;
height: 3rem;
border-radius: calc(var(--radius, 1rem) - 2px);
}
</style>
@@ -1,60 +0,0 @@
---
export interface Props {
size?: "sm" | "default" | "lg";
class?: string;
}
const { size = "default", class: className = "" } = Astro.props;
---
<span
aria-label="Loading"
role="status"
class:list={[`spinner spinner--${size}`, className]}
>
<span class="spinner__ring" aria-hidden="true" />
</span>
<style is:global>
@keyframes spin {
to {
transform: rotate(360deg);
}
}
.spinner {
display: inline-flex;
align-items: center;
justify-content: center;
vertical-align: middle;
}
.spinner__ring {
display: block;
border-radius: 50%;
border-style: solid;
border-color: oklch(var(--muted));
border-top-color: oklch(var(--primary));
animation: spin 0.6s linear infinite;
}
/* ── Sizes ─────────────────────────────────────── */
.spinner--sm .spinner__ring {
width: 1rem;
height: 1rem;
border-width: 2px;
}
.spinner--default .spinner__ring {
width: 1.5rem;
height: 1.5rem;
border-width: 2.5px;
}
.spinner--lg .spinner__ring {
width: 2.5rem;
height: 2.5rem;
border-width: 3px;
}
</style>