feat(ui): adopt Lyra theme

This commit is contained in:
2026-08-10 13:19:09 +07:00 Unverified
parent cbb40b665c
commit 6f1fd826d7
47 changed files with 153 additions and 153 deletions
+4 -4
View File
@@ -86,7 +86,7 @@ const RichTextEditor = dynamic(
{
ssr: false,
loading: () => (
<div className="h-32 animate-pulse rounded-md border bg-muted/40" />
<div className="h-32 animate-pulse border bg-muted/40" />
),
},
);
@@ -582,7 +582,7 @@ export default function FormEditorClient({ form, initialQuestions }: FormEditorC
/>
</div>
<div className="flex items-center gap-2 self-end sm:self-auto">
<div className="flex items-center gap-1 border rounded-md p-1">
<div className="flex items-center gap-1 border p-1">
<Button
variant="ghost"
size="icon"
@@ -633,7 +633,7 @@ export default function FormEditorClient({ form, initialQuestions }: FormEditorC
src={q.imageUrl}
alt={q.label}
unoptimized
className="w-32 h-auto rounded-md border object-contain"
className="h-auto w-32 border object-contain"
/>
<Button
variant="destructive"
@@ -649,7 +649,7 @@ export default function FormEditorClient({ form, initialQuestions }: FormEditorC
<div className="flex items-center gap-2">
<Label
htmlFor={`img-upload-${q.id}`}
className="flex items-center gap-2 px-3 py-2 border rounded-md cursor-pointer hover:bg-accent text-sm text-muted-foreground"
className="flex cursor-pointer items-center gap-2 border px-3 py-2 text-sm text-muted-foreground hover:bg-accent"
>
{uploadingId === q.id ? (
<Loader2 className="w-4 h-4 animate-spin text-primary" />
+2 -2
View File
@@ -351,7 +351,7 @@ export default function FormExtraClient({ form }: FormExtraClientProps) {
</Button>
))}
</div>
<div className="rounded-md border bg-muted/30 p-3">
<div className="border bg-muted/30 p-3">
<Badge variant="secondary">Preview</Badge>
<p className="mt-2 whitespace-pre-wrap text-sm">
{previewWebhookTemplate(webhookTemplate)}
@@ -383,7 +383,7 @@ export default function FormExtraClient({ form }: FormExtraClientProps) {
</Button>
))}
</div>
<div className="rounded-md border bg-muted/30 p-3">
<div className="border bg-muted/30 p-3">
<Badge variant="secondary">Preview</Badge>
<p className="mt-2 whitespace-pre-wrap text-sm">
{previewWebhookTemplate(webhookUpdateTemplate, { update: true })}
@@ -131,7 +131,7 @@ export default function SubmissionDetailClient({
>
<button
type="button"
className="cursor-pointer rounded-sm bg-[#5865f2]/30 px-1 font-medium text-[#c9cdfb] transition-colors hover:bg-[#5865f2] hover:text-white"
className="cursor-pointer bg-primary/15 px-1 font-medium text-primary transition-colors hover:bg-primary hover:text-primary-foreground"
aria-label={`View Discord profile for ${submission.userProfile.globalName}`}
>
@{submission.userProfile.globalName}
@@ -256,7 +256,7 @@ export default function SubmissionDetailClient({
)}
</div>
{q.imageUrl && (
<div className="relative w-24 h-24 overflow-hidden rounded-md border shrink-0">
<div className="relative size-24 shrink-0 overflow-hidden border">
<Image
src={q.imageUrl}
alt="Question image"
@@ -269,7 +269,7 @@ export default function SubmissionDetailClient({
</CardHeader>
<CardContent className="flex flex-col gap-4">
{answerValue && (
<div className="flex items-start justify-between gap-4 p-3 bg-muted rounded-md group">
<div className="group flex items-start justify-between gap-4 bg-muted p-3">
<div className="flex flex-col min-w-0">
<span className="text-sm whitespace-pre-wrap break-all">
{answerValue}
@@ -428,7 +428,7 @@ function AnswerImagePreview({ src, label }: { src: string; label: string }) {
className="max-h-40 max-w-56 rounded object-contain"
onError={() => setUnavailable(true)}
/>
<span className="absolute right-3 bottom-3 rounded-md bg-background/90 p-1.5 opacity-0 shadow-sm transition-opacity group-hover/image:opacity-100 group-focus-visible/image:opacity-100">
<span className="absolute right-3 bottom-3 bg-background/90 p-1.5 opacity-0 shadow-sm transition-opacity group-hover/image:opacity-100 group-focus-visible/image:opacity-100">
<Maximize2 />
</span>
</Button>
@@ -444,7 +444,7 @@ function AnswerImagePreview({ src, label }: { src: string; label: string }) {
width={1920}
height={1080}
unoptimized
className="max-h-[calc(100vh-10rem)] w-full rounded-md object-contain"
className="max-h-[calc(100vh-10rem)] w-full object-contain"
onError={() => setUnavailable(true)}
/>
<DialogFooter>
+1 -1
View File
@@ -49,7 +49,7 @@ export default async function AdminFormsPage() {
</form>
</div>
<div className="hidden rounded-md border md:block">
<div className="hidden border md:block">
<Table>
<TableHeader>
<TableRow>
+1 -1
View File
@@ -31,7 +31,7 @@ type LoginMethodProps = {
function EnvironmentBlock({ variables }: { variables: string[] }) {
return (
<pre className="overflow-x-auto rounded-xl bg-muted p-4 font-mono text-xs leading-6">
<pre className="overflow-x-auto border bg-muted p-4 font-mono text-xs leading-6">
<code>{variables.map((variable) => `${variable}=\n`).join("")}</code>
</pre>
);
+2 -2
View File
@@ -209,12 +209,12 @@ export default async function AdminPage() {
</CardHeader>
<CardContent>
{recentSubmissions.length === 0 ? (
<p className="rounded-md border p-6 text-sm text-muted-foreground">
<p className="border p-6 text-sm text-muted-foreground">
Responses will appear here after someone submits a form.
</p>
) : (
<>
<div className="hidden rounded-md border md:block">
<div className="hidden border md:block">
<Table>
<TableHeader>
<TableRow>
+1 -1
View File
@@ -59,7 +59,7 @@ export default async function AdminUploadHistoryPage() {
uploads.map((upload) => (
<div
key={upload.id}
className="flex flex-col gap-3 rounded-lg border p-4 md:flex-row md:items-center md:justify-between"
className="flex flex-col gap-3 border p-4 md:flex-row md:items-center md:justify-between"
>
<div className="min-w-0">
<p className="truncate font-medium">{upload.title}</p>
+2 -2
View File
@@ -34,9 +34,9 @@ export function LatestCard({
key={video.id}
href={video.url}
target="_blank"
className="group flex gap-3 rounded-lg border p-2 transition-colors hover:border-primary/60"
className="group flex gap-3 border p-2 transition-colors hover:border-primary/60"
>
<div className="relative aspect-square w-28 shrink-0 overflow-hidden rounded-md bg-muted">
<div className="relative aspect-square w-28 shrink-0 overflow-hidden bg-muted">
{video.thumbnailUrl ? (
<Image
src={video.thumbnailUrl}
+2 -2
View File
@@ -31,13 +31,13 @@ export default function NotFound() {
priority
className="z-[-1] object-cover opacity-20 grayscale"
/>
<div className="rounded-sm bg-white p-4 pb-12 shadow-lg max-sm:landscape:hidden">
<div className="border bg-card p-4 pb-12 shadow-lg max-sm:landscape:hidden">
<Image
src={Profile}
alt="404"
width={256}
height={256}
className="vintage-filter h-64 w-64 bg-gray-300"
className="vintage-filter size-64 bg-muted"
/>
</div>
<h2 className="text-2xl font-semibold">404 ไม่พบหน้านี้</h2>
+2 -2
View File
@@ -589,7 +589,7 @@ export function FormFillerClient({
alt={`รูปประกอบคำถาม ${plainQuestionLabel}`}
fill
unoptimized
className="rounded-md object-contain"
className="object-contain"
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 75vw, 60vw"
/>
</div>
@@ -879,7 +879,7 @@ export function FormFillerClient({
width={1200}
height={800}
unoptimized
className="max-h-[70vh] w-full rounded-md object-contain"
className="max-h-[70vh] w-full object-contain"
onError={(event) => {
event.currentTarget.style.display = "none";
}}
+2 -2
View File
@@ -41,7 +41,7 @@ export default async function FormsListingPage() {
return (
<>
<RealtimeRefresh topic="forms" />
<div className="mx-auto flex max-w-4xl flex-col gap-6 rounded-lg bg-background/90 p-4 text-foreground shadow-sm backdrop-blur md:p-6">
<div className="mx-auto flex max-w-4xl flex-col gap-6 p-4 text-foreground md:p-6">
<h1 className="text-3xl font-bold tracking-tight text-foreground">Form ทั้งหมด</h1>
{visibleForms.length === 0 ? (
<p className="text-muted-foreground">ตอนนี้ยังไม่เปิดรับสัก Form</p>
@@ -49,7 +49,7 @@ export default async function FormsListingPage() {
<div className="flex flex-col gap-4">
{visibleForms.map((form) => (
<Link key={form.id} href={`/form/${form.id}`}>
<Card className="hover:bg-muted/50 transition-colors h-full flex flex-col">
<Card className="h-full transition-colors hover:bg-muted/50">
<CardHeader>
<div className="flex flex-wrap items-start justify-between gap-3">
<CardTitle>{form.title}</CardTitle>
+55 -55
View File
@@ -51,71 +51,71 @@
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--foreground: oklch(0.148 0.004 228.8);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--card-foreground: oklch(0.148 0.004 228.8);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.518 0.253 323.949);
--primary-foreground: oklch(0.977 0.017 320.058);
--secondary: oklch(0.967 0.001 286.375);
--secondary-foreground: oklch(0.21 0.006 285.885);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--popover-foreground: oklch(0.148 0.004 228.8);
--primary: oklch(0.546 0.245 262.881);
--primary-foreground: oklch(0.97 0.014 254.604);
--secondary: oklch(0.963 0.002 197.1);
--secondary-foreground: oklch(0.218 0.008 223.9);
--muted: oklch(0.963 0.002 197.1);
--muted-foreground: oklch(0.56 0.021 213.5);
--accent: oklch(0.963 0.002 197.1);
--accent-foreground: oklch(0.218 0.008 223.9);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.833 0.145 321.434);
--chart-2: oklch(0.667 0.295 322.15);
--chart-3: oklch(0.591 0.293 322.896);
--chart-4: oklch(0.518 0.253 323.949);
--chart-5: oklch(0.452 0.211 324.591);
--radius: 0.625rem;
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.591 0.293 322.896);
--sidebar-primary-foreground: oklch(0.977 0.017 320.058);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
--border: oklch(0.925 0.005 214.3);
--input: oklch(0.925 0.005 214.3);
--ring: oklch(0.623 0.214 259.815);
--chart-1: oklch(0.809 0.105 251.813);
--chart-2: oklch(0.623 0.214 259.815);
--chart-3: oklch(0.546 0.245 262.881);
--chart-4: oklch(0.488 0.243 264.376);
--chart-5: oklch(0.424 0.199 265.638);
--radius: 0;
--sidebar: oklch(0.987 0.002 197.1);
--sidebar-foreground: oklch(0.148 0.004 228.8);
--sidebar-primary: oklch(0.546 0.245 262.881);
--sidebar-primary-foreground: oklch(0.97 0.014 254.604);
--sidebar-accent: oklch(0.963 0.002 197.1);
--sidebar-accent-foreground: oklch(0.218 0.008 223.9);
--sidebar-border: oklch(0.925 0.005 214.3);
--sidebar-ring: oklch(0.623 0.214 259.815);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.452 0.211 324.591);
--primary-foreground: oklch(0.977 0.017 320.058);
--secondary: oklch(0.274 0.006 286.033);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--background: oklch(0.148 0.004 228.8);
--foreground: oklch(0.987 0.002 197.1);
--card: oklch(0.218 0.008 223.9);
--card-foreground: oklch(0.987 0.002 197.1);
--popover: oklch(0.218 0.008 223.9);
--popover-foreground: oklch(0.987 0.002 197.1);
--primary: oklch(0.707 0.165 254.624);
--primary-foreground: oklch(0.97 0.014 254.604);
--secondary: oklch(0.275 0.011 216.9);
--secondary-foreground: oklch(0.987 0.002 197.1);
--muted: oklch(0.275 0.011 216.9);
--muted-foreground: oklch(0.723 0.014 214.4);
--accent: oklch(0.275 0.011 216.9);
--accent-foreground: oklch(0.987 0.002 197.1);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.833 0.145 321.434);
--chart-2: oklch(0.667 0.295 322.15);
--chart-3: oklch(0.591 0.293 322.896);
--chart-4: oklch(0.518 0.253 323.949);
--chart-5: oklch(0.452 0.211 324.591);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.667 0.295 322.15);
--sidebar-primary-foreground: oklch(0.977 0.017 320.058);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--ring: oklch(0.623 0.214 259.815);
--chart-1: oklch(0.809 0.105 251.813);
--chart-2: oklch(0.623 0.214 259.815);
--chart-3: oklch(0.546 0.245 262.881);
--chart-4: oklch(0.488 0.243 264.376);
--chart-5: oklch(0.424 0.199 265.638);
--sidebar: oklch(0.218 0.008 223.9);
--sidebar-foreground: oklch(0.987 0.002 197.1);
--sidebar-primary: oklch(0.707 0.165 254.624);
--sidebar-primary-foreground: oklch(0.97 0.014 254.604);
--sidebar-accent: oklch(0.275 0.011 216.9);
--sidebar-accent-foreground: oklch(0.987 0.002 197.1);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
--sidebar-ring: oklch(0.623 0.214 259.815);
}
@layer base {
+3 -3
View File
@@ -23,7 +23,7 @@ export default function NotFound() {
const [message] = useState(() => MESSAGES[Math.floor(Math.random() * MESSAGES.length)]);
return (
<div className="flex min-h-screen w-full flex-col items-center justify-center gap-2 bg-[#2225] backdrop-blur-md backdrop-grayscale">
<div className="flex min-h-screen w-full flex-col items-center justify-center gap-2 bg-background/80 backdrop-blur-md backdrop-grayscale">
<Image
src={Background}
alt="404 Background"
@@ -31,13 +31,13 @@ export default function NotFound() {
priority
className="fixed top-0 left-0 z-[-1] h-full w-full object-cover opacity-20"
/>
<div className="rounded-sm bg-white p-4 pb-12 shadow-lg max-sm:landscape:hidden">
<div className="border bg-card p-4 pb-12 shadow-lg max-sm:landscape:hidden">
<Image
src={Profile}
alt="404"
width={256}
height={256}
className="vintage-filter h-64 w-64 bg-gray-300"
className="vintage-filter size-64 bg-muted"
/>
</div>
<h2 className="text-2xl font-semibold">404 ไม่พบหน้านี้</h2>
+3 -3
View File
@@ -42,7 +42,7 @@ export default async function Home() {
return (
<main className="dark relative flex min-h-screen flex-col items-center justify-center bg-background text-foreground">
<main className="relative flex min-h-screen flex-col items-center justify-center bg-background p-4 text-foreground">
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
@@ -54,7 +54,7 @@ export default async function Home() {
priority
className="fixed top-0 left-0 z-0 h-full w-full object-cover opacity-60"
/>
<Card className="relative z-10 w-full max-w-sm overflow-hidden border-0 bg-black/20 md:max-w-lg md:border md:bg-card" role="article">
<Card className="relative z-10 w-full max-w-sm bg-card/90 backdrop-blur md:max-w-lg" role="article">
<CardHeader className="flex flex-col items-center gap-4 text-center">
<div className="relative w-24 h-24 overflow-hidden rounded-full">
<Image
@@ -67,7 +67,7 @@ export default async function Home() {
/>
</div>
<div>
<h1 className="text-2xl font-bold bg-linear-to-r from-pink-400 to-yellow-400 bg-clip-text text-transparent">
<h1 className="text-2xl font-bold text-primary">
{profileName}
</h1>
{visitorCount > 0 && (