feat : update
This commit is contained in:
@@ -12,7 +12,7 @@ import { Switch } from "@/components/ui/switch";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { toast } from "sonner";
|
||||
import { updateForm } from "@/app/admin/form/actions";
|
||||
import { updateForm } from "@/app/(ui)/admin/form/actions";
|
||||
import {
|
||||
createQuestion,
|
||||
updateQuestion,
|
||||
@@ -8,7 +8,7 @@ import { Input } from "@/components/ui/input";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { toast } from "sonner";
|
||||
import { testDiscordWebhook, updateForm } from "@/app/admin/form/actions";
|
||||
import { testDiscordWebhook, updateForm } from "@/app/(ui)/admin/form/actions";
|
||||
import { Loader2, ChevronDown, Send } from "lucide-react";
|
||||
import { getGuildRoles } from "@/app/actions/discord";
|
||||
import type { DiscordRole } from "@/lib/discord/discord";
|
||||
@@ -45,7 +45,7 @@ export default async function AdminFormLayout(
|
||||
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<div className="flex min-h-svh w-full bg-background text-foreground">
|
||||
<div className="flex min-h-svh w-full bg-transparent text-foreground">
|
||||
<FormAdminSidebar
|
||||
formId={params.id}
|
||||
formTitle={form.title}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { db } from "@/db";
|
||||
import { notFound } from "next/navigation";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { FormFillerClient } from "@/app/form/client";
|
||||
import { FormFillerClient } from "@/app/(ui)/form/client";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ import { stripHtml } from "@/lib/utils";
|
||||
import { HtmlDisplay } from "@/components/html-display";
|
||||
import { formatStoredAnswer } from "@/lib/form/form-answer-values";
|
||||
import { normalizeStoredAnswerSnapshot } from "@/lib/form/submission-intake";
|
||||
import { updateSubmissionAdminNote } from "@/app/admin/form/actions";
|
||||
import { updateSubmissionAdminNote } from "@/app/(ui)/admin/form/actions";
|
||||
import {
|
||||
useDebouncedAutoSave,
|
||||
} from "@/hooks/use-debounced-autosave";
|
||||
+1
-1
@@ -40,7 +40,7 @@ import { GuardedLink } from "@/components/guarded-link";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { getResponseNavigation } from "@/app/admin/form/actions";
|
||||
import { getResponseNavigation } from "@/app/(ui)/admin/form/actions";
|
||||
|
||||
type ResponseNavigationData = Awaited<ReturnType<typeof getResponseNavigation>>;
|
||||
|
||||
@@ -2,8 +2,33 @@
|
||||
|
||||
import { useState, type ReactNode } from "react";
|
||||
import { ArrowLeft, ArrowRight } from "lucide-react";
|
||||
import { Toaster } from "sonner";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { CardContent } from "@/components/ui/card";
|
||||
import { PageProgress } from "@/components/page-progress";
|
||||
import { ThemeProvider } from "@/components/theme-provider";
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import { VersionCheck } from "@/components/version-check";
|
||||
|
||||
export function UiProviders({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<PageProgress />
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="dark"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
<TooltipProvider>
|
||||
<Toaster richColors closeButton position="bottom-right" theme="dark" />
|
||||
<VersionCheck />
|
||||
{children}
|
||||
</TooltipProvider>
|
||||
</ThemeProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function LinkCarousel({
|
||||
primary,
|
||||
@@ -47,7 +47,7 @@ export default async function FormLayout({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="relative flex min-h-screen w-full flex-1 flex-col overflow-x-hidden bg-background text-foreground">
|
||||
<div className="relative flex min-h-svh w-full flex-1 flex-col overflow-x-hidden">
|
||||
<header className="relative z-10 flex shrink-0 items-center justify-between border-b border-border bg-background/90 px-6 py-3 backdrop-blur">
|
||||
<Link href="/">
|
||||
<span className="font-semibold text-sm">
|
||||
@@ -0,0 +1,24 @@
|
||||
import Image from "next/image";
|
||||
import Background from "@/public/background/space.webp";
|
||||
import { UiProviders } from "./client";
|
||||
|
||||
export default function UiLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<UiProviders>
|
||||
<div className="relative isolate min-h-svh overflow-x-clip text-foreground">
|
||||
<Image
|
||||
src={Background}
|
||||
alt=""
|
||||
priority
|
||||
sizes="100vw"
|
||||
className="pointer-events-none fixed inset-0 -z-20 size-full object-cover opacity-40"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="pointer-events-none fixed inset-0 -z-10 bg-background/40"
|
||||
/>
|
||||
{children}
|
||||
</div>
|
||||
</UiProviders>
|
||||
);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ export default function LeaderboardLayout({
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<main className="relative min-h-screen overflow-hidden bg-background text-foreground">
|
||||
<main className="relative min-h-svh overflow-hidden">
|
||||
{children}
|
||||
</main>
|
||||
);
|
||||
@@ -8,7 +8,6 @@ import { Finger_Paint } from "next/font/google";
|
||||
import { connection } from "next/server";
|
||||
import { getFollowerCounts } from "@/lib/followers";
|
||||
import { Share2, Trophy } from "lucide-react";
|
||||
import Background from "@/public/background/space.webp";
|
||||
import {
|
||||
formatCount,
|
||||
getCountForLink,
|
||||
@@ -128,18 +127,11 @@ export default async function Home() {
|
||||
|
||||
|
||||
return (
|
||||
<main className="relative flex min-h-screen flex-col items-center justify-center bg-background p-4 text-foreground">
|
||||
<main className="relative flex min-h-svh flex-col items-center justify-center p-4">
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
|
||||
/>
|
||||
<Image
|
||||
src={Background}
|
||||
alt="Background"
|
||||
fill
|
||||
priority
|
||||
className="fixed top-0 left-0 z-0 h-fit min-h-dvh w-full object-cover opacity-40"
|
||||
/>
|
||||
<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">
|
||||
@@ -13,7 +13,7 @@ export const metadata: Metadata = {
|
||||
|
||||
export default function PrivacyPolicyPage() {
|
||||
return (
|
||||
<main className="min-h-screen flex flex-col items-center p-4 md:p-8">
|
||||
<main className="flex flex-col items-center p-4 md:p-8">
|
||||
<div className="w-full max-w-2xl space-y-6">
|
||||
<div className="flex items-center gap-2">
|
||||
<Link href="/">
|
||||
@@ -9,7 +9,7 @@ export default function ProfileLayout({
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<main className="relative min-h-screen overflow-hidden bg-background text-foreground">
|
||||
<main className="relative min-h-svh overflow-hidden">
|
||||
<div className="relative mx-auto flex w-full max-w-5xl flex-col gap-6 px-4 py-6 sm:px-6 lg:py-10">
|
||||
<nav aria-label="ทางลัด" className="flex items-center justify-between gap-3">
|
||||
<Button variant="ghost" asChild>
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
CopyShareActions,
|
||||
DeleteCommentButton,
|
||||
DeleteShareButton,
|
||||
} from "@/app/share/[id]/client";
|
||||
} from "./client";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { ArrowLeft, List, Plus } from "lucide-react";
|
||||
import { ArrowLeft } from "lucide-react";
|
||||
import { DropdownMenuAvatar } from "@/components/avatar";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ThemeToggle } from "@/components/theme-toggle";
|
||||
@@ -22,7 +22,7 @@ export default async function ShareLayout({ children }: { children: React.ReactN
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background text-foreground">
|
||||
<div className="min-h-svh">
|
||||
<header className="sticky top-0 z-10 border-b bg-background/90 backdrop-blur">
|
||||
<div className="mx-auto flex h-14 max-w-6xl items-center justify-between gap-4 px-4 sm:px-6">
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -2,7 +2,7 @@ import { getServerSession } from "next-auth";
|
||||
import { LoginDialog } from "@/components/login-dialog";
|
||||
import { authOptions } from "@/lib/auth/auth-options";
|
||||
import { getSessionDiscordId } from "@/lib/auth/auth";
|
||||
import { ShareUploadClient } from "@/app/share/client";
|
||||
import { ShareUploadClient } from "./client";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -12,7 +12,7 @@ export const metadata: Metadata = {
|
||||
|
||||
export default function TermsOfServicePage() {
|
||||
return (
|
||||
<main className="min-h-screen flex flex-col items-center p-4 md:p-8">
|
||||
<main className="flex flex-col items-center p-4 md:p-8">
|
||||
<div className="w-full max-w-2xl space-y-6">
|
||||
<div className="flex items-center gap-2">
|
||||
<Link href="/">
|
||||
+2
-26
@@ -1,7 +1,6 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Anuphan, Inter } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { config } from "@/lib/config";
|
||||
|
||||
const inter = Inter({
|
||||
@@ -65,12 +64,6 @@ export const metadata: Metadata = {
|
||||
},
|
||||
};
|
||||
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import { Toaster } from "sonner";
|
||||
import { ThemeProvider } from "@/components/theme-provider";
|
||||
import { PageProgress } from "@/components/page-progress";
|
||||
import { VersionCheck } from "@/components/version-check";
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
@@ -79,28 +72,11 @@ export default function RootLayout({
|
||||
return (
|
||||
<html
|
||||
lang="th"
|
||||
className={cn(
|
||||
"h-full",
|
||||
"antialiased",
|
||||
inter.variable,
|
||||
anuphan.variable,
|
||||
)}
|
||||
className={`dark h-full antialiased ${inter.variable} ${anuphan.variable}`}
|
||||
suppressHydrationWarning
|
||||
>
|
||||
<body className="font-app" suppressHydrationWarning>
|
||||
<PageProgress />
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="dark"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
<TooltipProvider>
|
||||
<Toaster richColors closeButton position="bottom-right" theme="dark" />
|
||||
<VersionCheck />
|
||||
{children}
|
||||
</TooltipProvider>
|
||||
</ThemeProvider>
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
@@ -99,9 +99,13 @@ export function AdminShell({
|
||||
}) {
|
||||
const pathname = usePathname();
|
||||
|
||||
if (/^\/admin\/form\/[^/]+/.test(pathname)) {
|
||||
return children;
|
||||
}
|
||||
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<div className="flex min-h-screen w-full bg-background text-foreground">
|
||||
<div className="flex min-h-svh w-full bg-transparent text-foreground">
|
||||
<Sidebar variant="sidebar" collapsible="icon">
|
||||
<SidebarHeader className="border-b border-border py-4 px-4">
|
||||
<Link href="/admin">
|
||||
@@ -157,7 +161,7 @@ export function AdminShell({
|
||||
</SidebarContent>
|
||||
</Sidebar>
|
||||
|
||||
<SidebarInset>
|
||||
<SidebarInset className="bg-transparent">
|
||||
<div className="md:hidden p-2">
|
||||
<SidebarTrigger />
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Trash2, Loader2 } from "lucide-react";
|
||||
import { deleteForm } from "@/app/admin/form/actions";
|
||||
import { deleteForm } from "@/app/(ui)/admin/form/actions";
|
||||
import { deleteSubmission, deleteAllSubmissions } from "@/app/actions/submissions";
|
||||
import { toast } from "sonner";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
@@ -35,8 +35,8 @@ describe("share UI contracts", () => {
|
||||
test("keeps the extracted login dialog non-dismissible and shared", async () => {
|
||||
const [dialog, sharePage, formPage] = await Promise.all([
|
||||
Bun.file(new URL("../../components/login-dialog.tsx", import.meta.url)).text(),
|
||||
Bun.file(new URL("../../app/share/page.tsx", import.meta.url)).text(),
|
||||
Bun.file(new URL("../../app/form/[id]/page.tsx", import.meta.url)).text(),
|
||||
Bun.file(new URL("../../app/(ui)/share/page.tsx", import.meta.url)).text(),
|
||||
Bun.file(new URL("../../app/(ui)/form/[id]/page.tsx", import.meta.url)).text(),
|
||||
]);
|
||||
|
||||
expect(dialog).toContain("เข้าสู่ระบบก่อนกรอกแบบฟอร์ม");
|
||||
|
||||
Reference in New Issue
Block a user