Admin can now upload a png/jpg event photo (SPEC §8 exception added): - new image-upload admin field kind with live preview, uploading via POST /api/admin/upload (fenja-only, type + 5MB validation); - files stored under data/uploads (gitignored, BIFROST_UPLOAD_DIR overridable) and served by GET /uploads/[file] with a traversal guard. Reworks the /pulse event card: the greeting moved inside a taller box, the "next gathering" label sits above the date + title, and the photo renders as a top-right background that blends into the indigo via gradient masks. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
59 lines
2.6 KiB
Text
59 lines
2.6 KiB
Text
---
|
|
/* ---------------------------------------------------------------------------
|
|
* FieldRenderer — dispatches on field.kind to the right input component
|
|
* and wraps it with label + helper + error.
|
|
*
|
|
* Branches must stay exhaustive; the `never` fallback flags any unhandled
|
|
* Field kind at compile time.
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
import TextField from './fields/TextField.astro';
|
|
import TextareaField from './fields/TextareaField.astro';
|
|
import MarkdownField from './fields/MarkdownField.astro';
|
|
import SelectField from './fields/SelectField.astro';
|
|
import SelectAsyncField from './fields/SelectAsyncField.astro';
|
|
import MultiSelectAsyncField from './fields/MultiSelectAsyncField.astro';
|
|
import MultiTextField from './fields/MultiTextField.astro';
|
|
import DateField from './fields/DateField.astro';
|
|
import DatetimeField from './fields/DatetimeField.astro';
|
|
import NumberField from './fields/NumberField.astro';
|
|
import ReadonlyField from './fields/ReadonlyField.astro';
|
|
import ImageUploadField from './fields/ImageUploadField.astro';
|
|
import type { Field } from '../resource-types';
|
|
|
|
interface Props {
|
|
field: Field;
|
|
value: unknown;
|
|
error?: string;
|
|
item: Record<string, unknown> | null;
|
|
}
|
|
|
|
const { field, value, error, item } = Astro.props;
|
|
---
|
|
|
|
<div class="bs-field" data-field={field.key}>
|
|
<label class="bs-label" for={`f-${field.key}`}>
|
|
{field.label}
|
|
{field.required && <span class="bs-required" aria-hidden="true">*</span>}
|
|
</label>
|
|
|
|
{field.kind === 'text' && <TextField field={field} value={value} />}
|
|
{field.kind === 'textarea' && <TextareaField field={field} value={value} />}
|
|
{field.kind === 'markdown' && <MarkdownField field={field} value={value} />}
|
|
{field.kind === 'select' && <SelectField field={field} value={value} />}
|
|
{field.kind === 'select-async' && <SelectAsyncField field={field} value={value} />}
|
|
{field.kind === 'multi-select-async' && <MultiSelectAsyncField field={field} value={value} />}
|
|
{field.kind === 'multi-text' && <MultiTextField field={field} value={value} />}
|
|
{field.kind === 'date' && <DateField field={field} value={value} />}
|
|
{field.kind === 'datetime' && <DatetimeField field={field} value={value} />}
|
|
{field.kind === 'number' && <NumberField field={field} value={value} />}
|
|
{field.kind === 'readonly' && <ReadonlyField field={field} value={value} item={item} />}
|
|
{field.kind === 'image-upload' && <ImageUploadField field={field} value={value} />}
|
|
|
|
{field.helperText && (
|
|
<p class="bs-helper">{field.helperText}</p>
|
|
)}
|
|
{error && (
|
|
<p class="bs-field-error" role="alert">{error}</p>
|
|
)}
|
|
</div>
|