2026-03-19 15:05:13 +01:00
|
|
|
import { A, useNavigate, useParams } from '@solidjs/router';
|
2026-03-20 16:19:08 +01:00
|
|
|
import { createEffect, createResource, createSignal, Show } from 'solid-js';
|
2026-03-19 15:05:13 +01:00
|
|
|
import AdminShell from '~/components/AdminShell';
|
|
|
|
|
|
2026-03-20 16:19:08 +01:00
|
|
|
const API = '/api/gateway';
|
|
|
|
|
|
|
|
|
|
type KbArticle = {
|
|
|
|
|
id: string;
|
|
|
|
|
title: string;
|
|
|
|
|
slug?: string;
|
|
|
|
|
content?: string;
|
|
|
|
|
body?: string;
|
|
|
|
|
status?: string;
|
|
|
|
|
category_id?: string;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
async function loadArticle(id: string): Promise<KbArticle | null> {
|
|
|
|
|
try {
|
|
|
|
|
const res = await fetch(`${API}/api/admin/kb/articles/${id}`);
|
|
|
|
|
if (!res.ok) return null;
|
|
|
|
|
return res.json();
|
|
|
|
|
} catch {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default function KbArticleEditPage() {
|
2026-03-19 15:05:13 +01:00
|
|
|
const navigate = useNavigate();
|
|
|
|
|
const params = useParams();
|
2026-03-20 16:19:08 +01:00
|
|
|
const [article] = createResource(() => params.id, loadArticle);
|
|
|
|
|
const [title, setTitle] = createSignal('');
|
|
|
|
|
const [slug, setSlug] = createSignal('');
|
|
|
|
|
const [categoryId, setCategoryId] = createSignal('');
|
|
|
|
|
const [status, setStatus] = createSignal('DRAFT');
|
|
|
|
|
const [content, setContent] = createSignal('');
|
|
|
|
|
const [saving, setSaving] = createSignal(false);
|
|
|
|
|
const [error, setError] = createSignal('');
|
|
|
|
|
const [loaded, setLoaded] = createSignal(false);
|
|
|
|
|
|
|
|
|
|
createEffect(() => {
|
|
|
|
|
const value = article();
|
|
|
|
|
if (!value || loaded()) return;
|
|
|
|
|
setTitle(value.title || '');
|
|
|
|
|
setSlug(value.slug || '');
|
|
|
|
|
setCategoryId(value.category_id || '');
|
|
|
|
|
setStatus(value.status || 'DRAFT');
|
|
|
|
|
setContent(value.content || value.body || '');
|
|
|
|
|
setLoaded(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const save = async (e: Event) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
try {
|
|
|
|
|
setSaving(true);
|
|
|
|
|
setError('');
|
|
|
|
|
const res = await fetch(`${API}/api/admin/kb/articles/${params.id}`, {
|
|
|
|
|
method: 'PATCH',
|
|
|
|
|
headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
title: title(),
|
|
|
|
|
slug: slug(),
|
|
|
|
|
category_id: categoryId() || null,
|
|
|
|
|
status: status(),
|
|
|
|
|
content: content(),
|
|
|
|
|
}),
|
|
|
|
|
});
|
|
|
|
|
if (!res.ok) throw new Error('Failed to save article');
|
|
|
|
|
navigate(`/admin/kb/articles/${params.id}`);
|
|
|
|
|
} catch (err: any) {
|
|
|
|
|
setError(err.message || 'Failed to save article');
|
|
|
|
|
} finally {
|
|
|
|
|
setSaving(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2026-03-19 15:05:13 +01:00
|
|
|
return (
|
|
|
|
|
<AdminShell>
|
feat(admin): Phase 0 — Tailwind v4 foundation, shell rewrite, modern dashboard
- Install Tailwind CSS v4 via @tailwindcss/vite; configure vite.config.ts
- Rewrite app.css: Tailwind base, Exo 2 font, brand tokens (orange #fd6216, navy #050026), scrollbar utility; fix @import order
- Rewrite AdminShell.tsx: fixed header, fixed inset body grid (sidebar + main), session check, sub-tab system, logout, admin avatar/name/role
- Rewrite AdminSidebar.tsx: collapsible w-64/w-20, orange active rail + badge/dot, CSS filter for SVG icon tinting, min-h-0 flex fix
- Replace 84 route stub CSS classes (page-title, card, btn, table-wrap, etc.) with Tailwind equivalents via safe class-attr-only regex script
- Rewrite admin dashboard: Lucide icons in colored chip backgrounds, 4-col KPI grid, Control Plane 6-module grid, hover lift animations
- Disable SSR (ssr: false) to fix Vinxi dev manifest error; clear stale .vinxi cache
- Add lucide-solid icon library
- Add scripts/cleanup-css.mjs for class migration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 23:00:21 +01:00
|
|
|
<div class="mb-6 flex items-start justify-between gap-4">
|
2026-03-20 16:19:08 +01:00
|
|
|
<div>
|
feat(admin): Phase 0 — Tailwind v4 foundation, shell rewrite, modern dashboard
- Install Tailwind CSS v4 via @tailwindcss/vite; configure vite.config.ts
- Rewrite app.css: Tailwind base, Exo 2 font, brand tokens (orange #fd6216, navy #050026), scrollbar utility; fix @import order
- Rewrite AdminShell.tsx: fixed header, fixed inset body grid (sidebar + main), session check, sub-tab system, logout, admin avatar/name/role
- Rewrite AdminSidebar.tsx: collapsible w-64/w-20, orange active rail + badge/dot, CSS filter for SVG icon tinting, min-h-0 flex fix
- Replace 84 route stub CSS classes (page-title, card, btn, table-wrap, etc.) with Tailwind equivalents via safe class-attr-only regex script
- Rewrite admin dashboard: Lucide icons in colored chip backgrounds, 4-col KPI grid, Control Plane 6-module grid, hover lift animations
- Disable SSR (ssr: false) to fix Vinxi dev manifest error; clear stale .vinxi cache
- Add lucide-solid icon library
- Add scripts/cleanup-css.mjs for class migration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 23:00:21 +01:00
|
|
|
<h1 class="text-2xl font-bold text-gray-900">Edit KB Article</h1>
|
|
|
|
|
<p class="mt-1 text-sm text-gray-500">Update article metadata, status, and content.</p>
|
2026-03-20 16:19:08 +01:00
|
|
|
</div>
|
feat(admin): Phase 0 — Tailwind v4 foundation, shell rewrite, modern dashboard
- Install Tailwind CSS v4 via @tailwindcss/vite; configure vite.config.ts
- Rewrite app.css: Tailwind base, Exo 2 font, brand tokens (orange #fd6216, navy #050026), scrollbar utility; fix @import order
- Rewrite AdminShell.tsx: fixed header, fixed inset body grid (sidebar + main), session check, sub-tab system, logout, admin avatar/name/role
- Rewrite AdminSidebar.tsx: collapsible w-64/w-20, orange active rail + badge/dot, CSS filter for SVG icon tinting, min-h-0 flex fix
- Replace 84 route stub CSS classes (page-title, card, btn, table-wrap, etc.) with Tailwind equivalents via safe class-attr-only regex script
- Rewrite admin dashboard: Lucide icons in colored chip backgrounds, 4-col KPI grid, Control Plane 6-module grid, hover lift animations
- Disable SSR (ssr: false) to fix Vinxi dev manifest error; clear stale .vinxi cache
- Add lucide-solid icon library
- Add scripts/cleanup-css.mjs for class migration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 23:00:21 +01:00
|
|
|
<div class="flex items-center gap-2">
|
|
|
|
|
<A class="inline-flex items-center rounded-lg border border-gray-200 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors" href={`/admin/kb/articles/${params.id}`}>Back to Detail</A>
|
|
|
|
|
<A class="inline-flex items-center rounded-lg border border-gray-200 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors" href="/admin/kb/articles">Back to Articles</A>
|
2026-03-20 16:19:08 +01:00
|
|
|
</div>
|
2026-03-19 15:05:13 +01:00
|
|
|
</div>
|
2026-03-20 16:19:08 +01:00
|
|
|
|
|
|
|
|
<Show when={article.loading}>
|
feat(admin): Phase 0 — Tailwind v4 foundation, shell rewrite, modern dashboard
- Install Tailwind CSS v4 via @tailwindcss/vite; configure vite.config.ts
- Rewrite app.css: Tailwind base, Exo 2 font, brand tokens (orange #fd6216, navy #050026), scrollbar utility; fix @import order
- Rewrite AdminShell.tsx: fixed header, fixed inset body grid (sidebar + main), session check, sub-tab system, logout, admin avatar/name/role
- Rewrite AdminSidebar.tsx: collapsible w-64/w-20, orange active rail + badge/dot, CSS filter for SVG icon tinting, min-h-0 flex fix
- Replace 84 route stub CSS classes (page-title, card, btn, table-wrap, etc.) with Tailwind equivalents via safe class-attr-only regex script
- Rewrite admin dashboard: Lucide icons in colored chip backgrounds, 4-col KPI grid, Control Plane 6-module grid, hover lift animations
- Disable SSR (ssr: false) to fix Vinxi dev manifest error; clear stale .vinxi cache
- Add lucide-solid icon library
- Add scripts/cleanup-css.mjs for class migration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 23:00:21 +01:00
|
|
|
<section class="rounded-xl border border-gray-200 bg-white shadow-sm"><p class="notice">Loading article...</p></section>
|
2026-03-20 16:19:08 +01:00
|
|
|
</Show>
|
|
|
|
|
|
|
|
|
|
<Show when={!article.loading && !article()}>
|
feat(admin): Phase 0 — Tailwind v4 foundation, shell rewrite, modern dashboard
- Install Tailwind CSS v4 via @tailwindcss/vite; configure vite.config.ts
- Rewrite app.css: Tailwind base, Exo 2 font, brand tokens (orange #fd6216, navy #050026), scrollbar utility; fix @import order
- Rewrite AdminShell.tsx: fixed header, fixed inset body grid (sidebar + main), session check, sub-tab system, logout, admin avatar/name/role
- Rewrite AdminSidebar.tsx: collapsible w-64/w-20, orange active rail + badge/dot, CSS filter for SVG icon tinting, min-h-0 flex fix
- Replace 84 route stub CSS classes (page-title, card, btn, table-wrap, etc.) with Tailwind equivalents via safe class-attr-only regex script
- Rewrite admin dashboard: Lucide icons in colored chip backgrounds, 4-col KPI grid, Control Plane 6-module grid, hover lift animations
- Disable SSR (ssr: false) to fix Vinxi dev manifest error; clear stale .vinxi cache
- Add lucide-solid icon library
- Add scripts/cleanup-css.mjs for class migration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 23:00:21 +01:00
|
|
|
<section class="rounded-xl border border-gray-200 bg-white shadow-sm"><p class="notice">Article not found.</p></section>
|
2026-03-20 16:19:08 +01:00
|
|
|
</Show>
|
|
|
|
|
|
|
|
|
|
<Show when={article() && loaded()}>
|
feat(admin): Phase 0 — Tailwind v4 foundation, shell rewrite, modern dashboard
- Install Tailwind CSS v4 via @tailwindcss/vite; configure vite.config.ts
- Rewrite app.css: Tailwind base, Exo 2 font, brand tokens (orange #fd6216, navy #050026), scrollbar utility; fix @import order
- Rewrite AdminShell.tsx: fixed header, fixed inset body grid (sidebar + main), session check, sub-tab system, logout, admin avatar/name/role
- Rewrite AdminSidebar.tsx: collapsible w-64/w-20, orange active rail + badge/dot, CSS filter for SVG icon tinting, min-h-0 flex fix
- Replace 84 route stub CSS classes (page-title, card, btn, table-wrap, etc.) with Tailwind equivalents via safe class-attr-only regex script
- Rewrite admin dashboard: Lucide icons in colored chip backgrounds, 4-col KPI grid, Control Plane 6-module grid, hover lift animations
- Disable SSR (ssr: false) to fix Vinxi dev manifest error; clear stale .vinxi cache
- Add lucide-solid icon library
- Add scripts/cleanup-css.mjs for class migration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 23:00:21 +01:00
|
|
|
<form class="rounded-xl border border-gray-200 bg-white shadow-sm" onSubmit={save}>
|
|
|
|
|
<div class="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2">
|
2026-03-20 16:19:08 +01:00
|
|
|
<div class="field">
|
|
|
|
|
<label>Title</label>
|
|
|
|
|
<input value={title()} onInput={(e) => setTitle(e.currentTarget.value)} required />
|
|
|
|
|
</div>
|
|
|
|
|
<div class="field">
|
|
|
|
|
<label>Slug</label>
|
|
|
|
|
<input value={slug()} onInput={(e) => setSlug(e.currentTarget.value)} />
|
|
|
|
|
</div>
|
|
|
|
|
<div class="field">
|
|
|
|
|
<label>Category ID</label>
|
|
|
|
|
<input value={categoryId()} onInput={(e) => setCategoryId(e.currentTarget.value)} />
|
|
|
|
|
</div>
|
|
|
|
|
<div class="field">
|
|
|
|
|
<label>Status</label>
|
|
|
|
|
<select value={status()} onChange={(e) => setStatus(e.currentTarget.value)}>
|
|
|
|
|
<option value="DRAFT">DRAFT</option>
|
|
|
|
|
<option value="PUBLISHED">PUBLISHED</option>
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="field" style="grid-column:1 / -1">
|
|
|
|
|
<label>Content</label>
|
|
|
|
|
<textarea rows="16" value={content()} onInput={(e) => setContent(e.currentTarget.value)} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<Show when={error()}>
|
|
|
|
|
<p class="error-note">{error()}</p>
|
|
|
|
|
</Show>
|
|
|
|
|
|
|
|
|
|
<div class="actions" style="justify-content:flex-end">
|
feat(admin): Phase 0 — Tailwind v4 foundation, shell rewrite, modern dashboard
- Install Tailwind CSS v4 via @tailwindcss/vite; configure vite.config.ts
- Rewrite app.css: Tailwind base, Exo 2 font, brand tokens (orange #fd6216, navy #050026), scrollbar utility; fix @import order
- Rewrite AdminShell.tsx: fixed header, fixed inset body grid (sidebar + main), session check, sub-tab system, logout, admin avatar/name/role
- Rewrite AdminSidebar.tsx: collapsible w-64/w-20, orange active rail + badge/dot, CSS filter for SVG icon tinting, min-h-0 flex fix
- Replace 84 route stub CSS classes (page-title, card, btn, table-wrap, etc.) with Tailwind equivalents via safe class-attr-only regex script
- Rewrite admin dashboard: Lucide icons in colored chip backgrounds, 4-col KPI grid, Control Plane 6-module grid, hover lift animations
- Disable SSR (ssr: false) to fix Vinxi dev manifest error; clear stale .vinxi cache
- Add lucide-solid icon library
- Add scripts/cleanup-css.mjs for class migration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 23:00:21 +01:00
|
|
|
<button class="inline-flex items-center rounded-lg bg-[#fd6216] px-4 py-2 text-sm font-semibold text-white hover:bg-orange-600 transition-colors" type="submit" disabled={saving()}>
|
2026-03-20 16:19:08 +01:00
|
|
|
{saving() ? 'Saving...' : 'Save Article'}
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
</Show>
|
2026-03-19 15:05:13 +01:00
|
|
|
</AdminShell>
|
|
|
|
|
);
|
|
|
|
|
}
|