- custom_frames: per-user frames with full 9-slot palette (JSONB),
unique names; designer frame picker lists them alongside starters,
click to use, edit/delete via inline editor with live preview
- custom_symbols: upload cost icons (PNG/WebP/SVG, 2MB) keyed by short
code; re-uploading a code replaces the old icon; ManaPips renders
icon pips for {CODE} tokens with graceful text fallback
- custom_cards.custom_frame_id links designs to custom frames; API GETs
join and nest the palette; deleting a frame falls back to starter
- migration 1787700511000
54 lines
1.8 KiB
JavaScript
54 lines
1.8 KiB
JavaScript
import { sql } from '../../../lib/sql.js';
|
|
import { getUserFromRequest } from '../../../lib/permission-middleware';
|
|
import { validatePalette } from '../../../lib/frame-palette.js';
|
|
|
|
export default async function handler(req, res) {
|
|
try {
|
|
const user = await getUserFromRequest(req);
|
|
if (!user) {
|
|
return res.status(401).json({ error: 'Authentication required' });
|
|
}
|
|
|
|
if (req.method === 'GET') {
|
|
const result = await sql`
|
|
SELECT id, name, palette, created_at, updated_at
|
|
FROM custom_frames
|
|
WHERE user_id = ${user.userId}
|
|
ORDER BY name ASC
|
|
`;
|
|
return res.status(200).json({ frames: result.rows });
|
|
}
|
|
|
|
if (req.method === 'POST') {
|
|
const name = typeof req.body?.name === 'string' ? req.body.name.trim() : '';
|
|
if (!name || name.length > 100) {
|
|
return res.status(400).json({ error: 'Frame name is required (100 characters max)' });
|
|
}
|
|
|
|
const { palette, error } = validatePalette(req.body?.palette);
|
|
if (error) {
|
|
return res.status(400).json({ error });
|
|
}
|
|
|
|
const clash = await sql`
|
|
SELECT id FROM custom_frames
|
|
WHERE user_id = ${user.userId} AND lower(name) = ${name.toLowerCase()}
|
|
`;
|
|
if (clash.rows.length > 0) {
|
|
return res.status(409).json({ error: 'You already have a frame with that name' });
|
|
}
|
|
|
|
const inserted = await sql`
|
|
INSERT INTO custom_frames (user_id, name, palette)
|
|
VALUES (${user.userId}, ${name}, ${sql.json(palette)})
|
|
RETURNING id, name, palette, created_at, updated_at
|
|
`;
|
|
return res.status(201).json({ frame: inserted.rows[0] });
|
|
}
|
|
|
|
return res.status(405).json({ error: 'Method not allowed' });
|
|
} catch (error) {
|
|
console.error('Custom frames API error:', error);
|
|
return res.status(500).json({ error: 'Internal server error' });
|
|
}
|
|
}
|