feat(backoffice): redesign UI with enhanced background and glassmorphism effects
- Add vibrant radial gradient backgrounds with multiple color zones - Implement glassmorphism effects on header and cards - Add subtle grain texture overlay - Update card hover effects with smooth transitions - Improve dark mode background visibility
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { redirect } from "next/navigation";
|
||||
import { listTokens, createToken, revokeToken, TokenDto } from "../../lib/api";
|
||||
import { Card, CardHeader, Button, FormField, FormInput, FormSelect, FormRow } from "../components/ui";
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent, Button, Badge, FormField, FormInput, FormSelect, FormRow } from "../components/ui";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -33,68 +33,90 @@ export default async function TokensPage({
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1 className="text-3xl font-bold text-foreground mb-6 flex items-center gap-3">
|
||||
<svg className="w-8 h-8 text-error" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" /></svg>
|
||||
API Tokens
|
||||
</h1>
|
||||
<div className="mb-6">
|
||||
<h1 className="text-3xl font-bold text-foreground flex items-center gap-3">
|
||||
<svg className="w-8 h-8 text-destructive" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" />
|
||||
</svg>
|
||||
API Tokens
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{params.created ? (
|
||||
<Card className="mb-6">
|
||||
<strong className="text-foreground block mb-2">Token created (copy it now, it won't be shown again):</strong>
|
||||
<pre className="p-4 bg-muted/10 rounded-lg text-sm font-mono text-foreground overflow-x-auto">{params.created}</pre>
|
||||
<Card className="mb-6 border-success/50 bg-success/5">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-success">Token Created</CardTitle>
|
||||
<CardDescription>Copy it now, it won't be shown again</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="p-4 bg-background rounded-lg text-sm font-mono text-foreground overflow-x-auto border">{params.created}</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : null}
|
||||
|
||||
<Card className="mb-6">
|
||||
<form action={createTokenAction}>
|
||||
<FormRow>
|
||||
<FormField>
|
||||
<FormInput name="name" placeholder="token name" required />
|
||||
</FormField>
|
||||
<FormField>
|
||||
<FormSelect name="scope" defaultValue="read">
|
||||
<option value="read">read</option>
|
||||
<option value="admin">admin</option>
|
||||
</FormSelect>
|
||||
</FormField>
|
||||
<Button type="submit">➕ Create Token</Button>
|
||||
</FormRow>
|
||||
</form>
|
||||
<CardHeader>
|
||||
<CardTitle>Create New Token</CardTitle>
|
||||
<CardDescription>Generate a new API token with the desired scope</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form action={createTokenAction}>
|
||||
<FormRow>
|
||||
<FormField className="flex-1 min-w-48">
|
||||
<FormInput name="name" placeholder="Token name" required />
|
||||
</FormField>
|
||||
<FormField className="w-32">
|
||||
<FormSelect name="scope" defaultValue="read">
|
||||
<option value="read">Read</option>
|
||||
<option value="admin">Admin</option>
|
||||
</FormSelect>
|
||||
</FormField>
|
||||
<Button type="submit">Create Token</Button>
|
||||
</FormRow>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="overflow-hidden">
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full">
|
||||
<thead>
|
||||
<tr className="border-b border-line bg-muted/5">
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold text-muted uppercase tracking-wider">Name</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold text-muted uppercase tracking-wider">Scope</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold text-muted uppercase tracking-wider">Prefix</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold text-muted uppercase tracking-wider">Revoked</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold text-muted uppercase tracking-wider">Actions</th>
|
||||
<tr className="border-b border-border/60 bg-muted/50">
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold text-muted-foreground uppercase tracking-wider">Name</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold text-muted-foreground uppercase tracking-wider">Scope</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold text-muted-foreground uppercase tracking-wider">Prefix</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold text-muted-foreground uppercase tracking-wider">Status</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold text-muted-foreground uppercase tracking-wider">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-line">
|
||||
<tbody className="divide-y divide-border/60">
|
||||
{tokens.map((token) => (
|
||||
<tr key={token.id} className="hover:bg-muted/5">
|
||||
<tr key={token.id} className="hover:bg-accent/50 transition-colors">
|
||||
<td className="px-4 py-3 text-sm text-foreground">{token.name}</td>
|
||||
<td className="px-4 py-3 text-sm text-foreground">{token.scope}</td>
|
||||
<td className="px-4 py-3 text-sm">
|
||||
<code className="px-2 py-1 bg-muted/10 rounded font-mono text-foreground">{token.prefix}</code>
|
||||
<Badge variant={token.scope === "admin" ? "destructive" : "secondary"}>
|
||||
{token.scope}
|
||||
</Badge>
|
||||
</td>
|
||||
<td className="px-4 py-3 text-sm">
|
||||
<code className="px-2 py-1 bg-muted rounded font-mono text-foreground">{token.prefix}</code>
|
||||
</td>
|
||||
<td className="px-4 py-3 text-sm">
|
||||
{token.revoked_at ? (
|
||||
<span className="inline-flex px-2 py-1 rounded-full text-xs font-semibold bg-error-soft text-error">yes</span>
|
||||
<Badge variant="error">Revoked</Badge>
|
||||
) : (
|
||||
<span className="inline-flex px-2 py-1 rounded-full text-xs font-semibold bg-success-soft text-success">no</span>
|
||||
<Badge variant="success">Active</Badge>
|
||||
)}
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
{!token.revoked_at && (
|
||||
<form action={revokeTokenAction}>
|
||||
<input type="hidden" name="id" value={token.id} />
|
||||
<Button type="submit" variant="danger" size="sm">
|
||||
🚫 Revoke
|
||||
<Button type="submit" variant="destructive" size="sm">
|
||||
<svg className="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
Revoke
|
||||
</Button>
|
||||
</form>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user