feat: promote command grid builder

This commit is contained in:
jb
2026-07-29 20:18:58 -04:00
parent a434cbe60c
commit f1b473ffa8
7 changed files with 355 additions and 25 deletions
+18 -7
View File
@@ -4,6 +4,7 @@ import { getSessionUser } from '$lib/server/auth/session';
import { fail } from '@sveltejs/kit';
import { randomUUID } from 'node:crypto';
import { parseLoadoutDraft } from '$lib/builder/loadout';
import { normalizeUserMarkdown } from '$lib/markdown';
import type { Actions, PageServerLoad } from './$types';
import { attachWeaponCategoryBonuses } from '$lib/weapons/category-bonuses';
@@ -27,10 +28,17 @@ export const load: PageServerLoad = async ({ cookies, url }) => {
let initialBuild = null;
if (requestedSlug && viewer) {
const row = await (await database.prepare(
'SELECT id,title,slug,visibility,loadout_json FROM builds WHERE slug=? AND owner_id=?'
'SELECT id,title,slug,visibility,summary,guide_body,loadout_json FROM builds WHERE slug=? AND owner_id=?'
)).get(requestedSlug, viewer.id);
const loadout = typeof row?.loadout_json === 'string' ? parseLoadout(row.loadout_json) : null;
if (row && loadout) initialBuild = { id: String(row.id), slug: String(row.slug), visibility: String(row.visibility), loadout };
if (row && loadout) initialBuild = {
id: String(row.id),
slug: String(row.slug),
visibility: String(row.visibility),
summary: String(row.summary ?? ''),
guideBody: String(row.guide_body ?? ''),
loadout
};
}
const [
attributes, gear, gearBrands, gearTalents, gearAugments, gearAugmentCosts, brands, brandEffects,
@@ -239,7 +247,10 @@ export const actions: Actions = {
const loadout = parseLoadout(formData.get('loadout'));
const visibility = String(formData.get('visibility') ?? 'private');
const id = String(formData.get('id') ?? '').trim();
const summary = normalizeUserMarkdown(formData.get('summary'), 500);
const guideBody = normalizeUserMarkdown(formData.get('guideBody'), 12_000);
if (!loadout) return fail(400, { buildError: 'The loadout data is invalid. Refresh the builder and try again.' });
if (summary === null || guideBody === null) return fail(400, { buildError: 'Build notes contain unsupported characters or exceed their length limit.' });
const title = loadout.buildName.trim();
if (title.length < 2 || title.length > 100) return fail(400, { buildError: 'Build names must be between 2 and 100 characters.' });
if (!validVisibility.has(visibility)) return fail(400, { buildError: 'Choose a valid build visibility.' });
@@ -253,15 +264,15 @@ export const actions: Actions = {
if (!existing) return fail(404, { buildError: 'This saved build could not be found.' });
slug = String(existing.slug);
await (await database.prepare(
'UPDATE builds SET title=?,visibility=?,loadout_json=?,updated_at=? WHERE id=? AND owner_id=?'
)).run(title, visibility, JSON.stringify(loadout), now, buildId, user.id);
'UPDATE builds SET title=?,visibility=?,summary=?,guide_body=?,loadout_json=?,updated_at=? WHERE id=? AND owner_id=?'
)).run(title, visibility, summary, guideBody, JSON.stringify(loadout), now, buildId, user.id);
} else {
buildId = randomUUID();
slug = `${slugify(title)}-${buildId.slice(0, 8)}`;
await (await database.prepare(
`INSERT INTO builds(id,owner_id,title,slug,visibility,loadout_json,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?)`
)).run(buildId, user.id, title, slug, visibility, JSON.stringify(loadout), now, now);
`INSERT INTO builds(id,owner_id,title,slug,visibility,summary,guide_body,loadout_json,created_at,updated_at)
VALUES(?,?,?,?,?,?,?,?,?,?)`
)).run(buildId, user.id, title, slug, visibility, summary, guideBody, JSON.stringify(loadout), now, now);
}
return {
buildSaved: true,