feat: move share index to public route

This commit is contained in:
2026-08-16 02:56:06 +07:00 Unverified
parent 44ae9d5848
commit 6b162c6eff
4 changed files with 189 additions and 193 deletions
-185
View File
@@ -1,185 +0,0 @@
import Link from "next/link";
import { desc, sql } from "drizzle-orm";
import { ArrowUpRight, Plus } from "lucide-react";
import { AdminShellServer } from "@/components/admin-shell-server";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { db } from "@/db";
import { shareTexts } from "@/db/schema";
export const dynamic = "force-dynamic";
function formatBangkok(date: Date) {
return new Intl.DateTimeFormat("en-GB", {
dateStyle: "medium",
timeStyle: "short",
timeZone: "Asia/Bangkok",
}).format(date);
}
export default async function AdminSharePage() {
const shares = await db
.select({
id: shareTexts.id,
authorName: shareTexts.authorName,
source: shareTexts.source,
description: shareTexts.description,
contentPreview: sql<string>`left(${shareTexts.content}, 160)`,
createdAt: shareTexts.createdAt,
})
.from(shareTexts)
.orderBy(desc(shareTexts.createdAt));
return (
<AdminShellServer>
<main className="mx-auto flex w-full max-w-7xl flex-col gap-6 p-4 pb-12 md:p-6">
<header className="flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
<div>
<h1 className="text-3xl font-bold tracking-tight">Share</h1>
<p className="mt-1 text-muted-foreground">
{shares.length.toLocaleString("en-US")} published links
</p>
</div>
<Button asChild>
<Link href="/share">
<Plus data-icon="inline-start" />
Create share
</Link>
</Button>
</header>
<Card>
<CardHeader>
<CardTitle>All shares</CardTitle>
<CardDescription>
Open a public page without loading the full text into this list.
</CardDescription>
</CardHeader>
<CardContent>
<div className="hidden border md:block">
<Table>
<TableHeader>
<TableRow>
<TableHead>Share</TableHead>
<TableHead>Preview</TableHead>
<TableHead>Author</TableHead>
<TableHead>Source</TableHead>
<TableHead>Created</TableHead>
<TableHead className="text-right">Open</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{shares.length === 0 ? (
<TableRow>
<TableCell
colSpan={6}
className="h-24 text-center text-muted-foreground"
>
No shares yet.
</TableCell>
</TableRow>
) : (
shares.map((share) => (
<TableRow key={share.id}>
<TableCell className="font-mono font-medium">
<Link
href={`/share/${share.id}`}
className="hover:underline"
>
{share.id}
</Link>
</TableCell>
<TableCell>
<p className="max-w-md truncate text-muted-foreground">
{share.description || share.contentPreview}
</p>
</TableCell>
<TableCell>{share.authorName}</TableCell>
<TableCell>
<Badge
variant={
share.source === "bot" ? "secondary" : "outline"
}
>
{share.source === "bot" ? "Bot" : "Web"}
</Badge>
</TableCell>
<TableCell>{formatBangkok(share.createdAt)}</TableCell>
<TableCell className="text-right">
<Button variant="ghost" size="icon-sm" asChild>
<Link
href={`/share/${share.id}`}
aria-label={`Open share ${share.id}`}
>
<ArrowUpRight />
</Link>
</Button>
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</div>
<div className="flex flex-col gap-3 md:hidden">
{shares.length === 0 ? (
<p className="py-8 text-center text-sm text-muted-foreground">
No shares yet.
</p>
) : (
shares.map((share) => (
<Card key={share.id} size="sm">
<CardHeader>
<CardTitle className="font-mono">
<Link href={`/share/${share.id}`}>{share.id}</Link>
</CardTitle>
<CardDescription>
{share.authorName} · {formatBangkok(share.createdAt)}
</CardDescription>
</CardHeader>
<CardContent>
<p className="line-clamp-2 text-sm text-muted-foreground">
{share.description || share.contentPreview}
</p>
<div className="flex items-center justify-between gap-3">
<Badge
variant={
share.source === "bot" ? "secondary" : "outline"
}
>
{share.source === "bot" ? "Bot" : "Web"}
</Badge>
<Button variant="outline" size="sm" asChild>
<Link href={`/share/${share.id}`}>
Open
<ArrowUpRight data-icon="inline-end" />
</Link>
</Button>
</div>
</CardContent>
</Card>
))
)}
</div>
</CardContent>
</Card>
</main>
</AdminShellServer>
);
}
+182
View File
@@ -0,0 +1,182 @@
import Link from "next/link";
import { desc, sql } from "drizzle-orm";
import { ArrowUpRight, Plus } from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { db } from "@/db";
import { shareTexts } from "@/db/schema";
export const dynamic = "force-dynamic";
function formatBangkok(date: Date) {
return new Intl.DateTimeFormat("en-GB", {
dateStyle: "medium",
timeStyle: "short",
timeZone: "Asia/Bangkok",
}).format(date);
}
export default async function AllSharesPage() {
const shares = await db
.select({
id: shareTexts.id,
authorName: shareTexts.authorName,
source: shareTexts.source,
description: shareTexts.description,
contentPreview: sql<string>`left(${shareTexts.content}, 160)`,
createdAt: shareTexts.createdAt,
})
.from(shareTexts)
.orderBy(desc(shareTexts.createdAt));
return (
<div className="flex w-full flex-col gap-6">
<header className="flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
<div>
<h1 className="text-3xl font-bold tracking-tight">Share</h1>
<p className="mt-1 text-muted-foreground">
{shares.length.toLocaleString("th-TH")} ลิงก์สาธารณะ
</p>
</div>
<Button asChild>
<Link href="/share">
<Plus data-icon="inline-start" />
สร้างลิงก์ใหม่
</Link>
</Button>
</header>
<Card>
<CardHeader>
<CardTitle>ข้อความที่แชร์ทั้งหมด</CardTitle>
<CardDescription>
เลือกข้อความเพื่อเปิดหน้าสาธารณะ
</CardDescription>
</CardHeader>
<CardContent>
<div className="hidden border md:block">
<Table>
<TableHeader>
<TableRow>
<TableHead>Share</TableHead>
<TableHead>Preview</TableHead>
<TableHead>Author</TableHead>
<TableHead>Source</TableHead>
<TableHead>Created</TableHead>
<TableHead className="text-right">Open</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{shares.length === 0 ? (
<TableRow>
<TableCell
colSpan={6}
className="h-24 text-center text-muted-foreground"
>
ยังไม่มีข้อความที่แชร์
</TableCell>
</TableRow>
) : (
shares.map((share) => (
<TableRow key={share.id}>
<TableCell className="font-mono font-medium">
<Link
href={`/share/${share.id}`}
className="hover:underline"
>
{share.id}
</Link>
</TableCell>
<TableCell>
<p className="max-w-md truncate text-muted-foreground">
{share.description || share.contentPreview}
</p>
</TableCell>
<TableCell>{share.authorName}</TableCell>
<TableCell>
<Badge
variant={
share.source === "bot" ? "secondary" : "outline"
}
>
{share.source === "bot" ? "Bot" : "Web"}
</Badge>
</TableCell>
<TableCell>{formatBangkok(share.createdAt)}</TableCell>
<TableCell className="text-right">
<Button variant="ghost" size="icon-sm" asChild>
<Link
href={`/share/${share.id}`}
aria-label={`Open share ${share.id}`}
>
<ArrowUpRight />
</Link>
</Button>
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</div>
<div className="flex flex-col gap-3 md:hidden">
{shares.length === 0 ? (
<p className="py-8 text-center text-sm text-muted-foreground">
ยังไม่มีข้อความที่แชร์
</p>
) : (
shares.map((share) => (
<Card key={share.id} size="sm">
<CardHeader>
<CardTitle className="font-mono">
<Link href={`/share/${share.id}`}>{share.id}</Link>
</CardTitle>
<CardDescription>
{share.authorName} · {formatBangkok(share.createdAt)}
</CardDescription>
</CardHeader>
<CardContent>
<p className="line-clamp-2 text-sm text-muted-foreground">
{share.description || share.contentPreview}
</p>
<div className="flex items-center justify-between gap-3">
<Badge
variant={
share.source === "bot" ? "secondary" : "outline"
}
>
{share.source === "bot" ? "Bot" : "Web"}
</Badge>
<Button variant="outline" size="sm" asChild>
<Link href={`/share/${share.id}`}>
เปิด
<ArrowUpRight data-icon="inline-end" />
</Link>
</Button>
</div>
</CardContent>
</Card>
))
)}
</div>
</CardContent>
</Card>
</div>
);
}
+7 -1
View File
@@ -1,7 +1,7 @@
import type { Metadata } from "next";
import Link from "next/link";
import { getServerSession } from "next-auth";
import { ArrowLeft, Plus } from "lucide-react";
import { ArrowLeft, List, Plus } from "lucide-react";
import { DropdownMenuAvatar } from "@/components/avatar";
import { Button } from "@/components/ui/button";
import { ThemeToggle } from "@/components/theme-toggle";
@@ -36,6 +36,12 @@ export default async function ShareLayout({ children }: { children: React.ReactN
</Link>
</div>
<div className="flex items-center gap-2">
<Button variant="ghost" size="sm" asChild>
<Link href="/share/all">
<List data-icon="inline-start" />
ทั้งหมด
</Link>
</Button>
<Button variant="outline" size="sm" asChild>
<Link href="/share">
<Plus data-icon="inline-start" />