feat: dashboard
This commit is contained in:
125
src/web/templates/components/dashboard/layout.tsx
Normal file
125
src/web/templates/components/dashboard/layout.tsx
Normal file
@@ -0,0 +1,125 @@
|
||||
// oxlint-disable-next-line no-unused-vars
|
||||
import { Html } from "@elysiajs/html";
|
||||
import type { Guild, GuildDetailData, User } from "./shared";
|
||||
import { GuildDetailView } from "./guild-detail";
|
||||
|
||||
export function DashboardEmptyState() {
|
||||
return (
|
||||
<div class="rounded-2xl border border-dashed border-slate-700 bg-slate-900/55 p-10 text-center">
|
||||
<div class="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-xl border border-slate-700 bg-slate-800/70 text-xl">🛡️</div>
|
||||
<h2 class="text-2xl font-semibold text-white">Select a server</h2>
|
||||
<p class="mx-auto mt-2 max-w-2xl text-sm text-slate-400">
|
||||
Choose a server from the sidebar to configure Joel's system prompts and bot options.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function DashboardSidebar({ user, guilds, initialGuild }: { user: User; guilds: Guild[]; initialGuild?: GuildDetailData }) {
|
||||
return (
|
||||
<aside class="h-fit rounded-2xl border border-slate-800 bg-slate-900/75 p-4 backdrop-blur-sm lg:sticky lg:top-6">
|
||||
<div class="mb-4 flex items-center gap-3 rounded-xl border border-slate-800 bg-slate-950/90 px-3 py-3">
|
||||
<div class="flex h-10 w-10 items-center justify-center rounded-xl bg-indigo-500/20 text-lg">🤖</div>
|
||||
<div>
|
||||
<div class="text-sm font-semibold text-white">Joel Dashboard</div>
|
||||
<div class="text-xs text-slate-400">Server control panel</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="mb-4 space-y-1 rounded-xl border border-slate-800 bg-slate-950/60 p-2">
|
||||
<button type="button" class="w-full rounded-lg bg-indigo-500/15 px-3 py-2 text-left text-sm font-medium text-indigo-200">
|
||||
Servers
|
||||
</button>
|
||||
<button type="button" class="w-full rounded-lg px-3 py-2 text-left text-sm text-slate-500" disabled>
|
||||
Settings
|
||||
</button>
|
||||
<button type="button" class="w-full rounded-lg px-3 py-2 text-left text-sm text-slate-500" disabled>
|
||||
Analytics
|
||||
</button>
|
||||
<button type="button" class="w-full rounded-lg px-3 py-2 text-left text-sm text-slate-500" disabled>
|
||||
Help
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div class="rounded-xl border border-slate-800 bg-slate-950/60 p-3">
|
||||
<div class="mb-2 flex items-center justify-between text-xs font-semibold uppercase tracking-wide text-slate-400">
|
||||
<span>Your Servers</span>
|
||||
<span>{guilds.length}</span>
|
||||
</div>
|
||||
<div id="guild-list" class="max-h-[52vh] space-y-2 overflow-y-auto pr-1">
|
||||
{guilds.length === 0 ? (
|
||||
<p class="text-sm text-slate-400">No shared servers found.</p>
|
||||
) : (
|
||||
guilds.map((g) => (
|
||||
<button
|
||||
type="button"
|
||||
class={`guild-list-item flex w-full items-center gap-3 rounded-xl border px-3 py-2.5 text-left text-sm transition ${
|
||||
initialGuild?.guildId === g.id
|
||||
? "guild-item-active"
|
||||
: "guild-item-inactive"
|
||||
}`}
|
||||
data-guild-id={g.id}
|
||||
hx-get={`/dashboard/guild/${g.id}`}
|
||||
hx-target="#guild-main-content"
|
||||
hx-swap="innerHTML"
|
||||
hx-push-url="true"
|
||||
{...{ preload: "mouseover" }}
|
||||
>
|
||||
<span class="text-base">🛡️</span>
|
||||
<span class="truncate">{g.name}</span>
|
||||
</button>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 rounded-xl border border-slate-800 bg-slate-950/90 px-3 py-3">
|
||||
<p class="text-[11px] font-medium uppercase tracking-wide text-slate-500">Logged in as</p>
|
||||
<p class="mt-1 truncate text-sm text-slate-200">{user.global_name || user.username}</p>
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
export function DashboardHeader() {
|
||||
return (
|
||||
<header class="flex flex-col gap-4 rounded-2xl border border-slate-800 bg-slate-900/75 px-4 py-4 backdrop-blur-sm sm:flex-row sm:items-center sm:justify-between sm:px-5">
|
||||
<div>
|
||||
<h1 class="text-lg font-semibold text-white sm:text-xl">Server Management</h1>
|
||||
<p class="mt-1 text-sm text-slate-400">Configure Joel's prompts, behavior, and response settings.</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<a
|
||||
href="/ai-helper"
|
||||
class="inline-flex items-center rounded-lg border border-indigo-500 bg-indigo-500/15 px-3 py-2 text-xs font-medium text-indigo-200 hover:bg-indigo-500/25"
|
||||
>
|
||||
🧠 AI Helper
|
||||
</a>
|
||||
<button
|
||||
class="inline-flex items-center rounded-lg border border-slate-700 bg-slate-800 px-3 py-2 text-xs font-medium text-slate-200 hover:bg-slate-700"
|
||||
hx-post="/auth/logout"
|
||||
hx-redirect="/"
|
||||
>
|
||||
Logout
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
export function DashboardMainContent({ initialGuild }: { initialGuild?: GuildDetailData }) {
|
||||
return (
|
||||
<section id="guild-main-content" class="space-y-4">
|
||||
{initialGuild ? (
|
||||
<GuildDetailView
|
||||
guildId={initialGuild.guildId}
|
||||
guildName={initialGuild.guildName}
|
||||
options={initialGuild.options}
|
||||
personalities={initialGuild.personalities}
|
||||
/>
|
||||
) : (
|
||||
<DashboardEmptyState />
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user