Restructure layout and add widget

This commit is contained in:
Dreamgineer
2025-11-12 20:52:50 -05:00 Unverified
parent b831e2f2a1
commit f2551e5d51
51 changed files with 181 additions and 121 deletions
+5
View File
@@ -0,0 +1,5 @@
import { Section } from "./page";
export function SettingsAccountSection() {
return <Section title="บัญชี">ask dreamgineer bruh</Section>;
}
+32
View File
@@ -0,0 +1,32 @@
"use server";
import { exec } from "node:child_process";
import { promisify } from "node:util";
import { revalidatePath } from "next/cache";
import { actionLog } from "@/lib/api";
import { db } from "@/lib/db";
import { settings } from "@/lib/db/schema";
export async function getEnka() {
const [{ enka } = { enka: true }] = await db.select().from(settings).limit(1);
return enka;
}
export async function toggleEnka(state: boolean) {
const last = await getEnka();
if (last === state) return;
await db
.insert(settings)
.values({ enka: state })
.onConflictDoUpdate({ target: settings.id, set: { enka: state } });
actionLog("Changed a settings", { enka: state });
revalidatePath("/admin/settings");
revalidatePath("/artifact");
}
export async function syncAmber() {
const res = await promisify(exec)("bun util/sync 2>&1");
actionLog("Triggered an Amber sync", { result: res.stdout });
return res.stdout;
}
+51
View File
@@ -0,0 +1,51 @@
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { cn } from "@/lib/utils";
import { SettingsAccountSection } from "./account";
import { getEnka } from "./api";
import { SettingsServicesSection } from "./services";
export default async function () {
const enka = await getEnka();
return (
<div className="grid gap-8 h-full w-full p-2 pl-0">
<Tabs defaultValue="external">
<TabsList className="w-full">
<TabsTrigger value="external">บริการนอก</TabsTrigger>
<TabsTrigger value="account">บัญชี</TabsTrigger>
</TabsList>
<TabsContent value="external">
<SettingsServicesSection enka={enka} />
</TabsContent>
<TabsContent value="account">
<SettingsAccountSection />
</TabsContent>
</Tabs>
</div>
);
}
export function Section({
title,
description,
children,
className,
...props
}: React.ComponentProps<"div"> & { description?: string }) {
return (
<Card className={cn("h-full", className)} {...props}>
<CardHeader>
{title && <CardTitle className="text-2xl">{title}</CardTitle>}
{description && <CardDescription>{description}</CardDescription>}
</CardHeader>
<CardContent className="h-full">{children}</CardContent>
</Card>
);
}
+49
View File
@@ -0,0 +1,49 @@
"use client";
import { FolderSync } from "lucide-react";
import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import { Spinner } from "@/components/ui/spinner";
import { Switch } from "@/components/ui/switch";
import { syncAmber, toggleEnka } from "./api";
import { Section } from "./page";
export function SettingsServicesSection({
enka: enkaInitial,
}: {
enka: boolean;
}) {
const [syncing, setSyncing] = useState(false);
const [syncResult, setSyncResult] = useState("");
const [enka, setEnka] = useState<boolean>();
useEffect(() => {
if (typeof enka !== "boolean") return setEnka(enkaInitial);
toggleEnka(enka);
}, [enka, enkaInitial]);
async function sync() {
setSyncing(true);
syncAmber()
.then(setSyncResult)
.finally(() => setSyncing(false));
}
return (
<Section title="บริการนอก">
<div className="flex flex-col gap-2 h-full">
<div className="flex items-center gap-2">
<Switch checked={enka} onCheckedChange={setEnka} />
เปิดใช้การดึงตัวละครใน Artifact
</div>
<Button disabled={syncing} onClick={sync} className="w-min">
{syncing ? <Spinner /> : <FolderSync />}
Sync Amber
</Button>
{syncResult && (
<pre className="border bg-muted rounded h-full p-2">{syncResult}</pre>
)}
</div>
</Section>
);
}