diff --git a/src/components/RecordModal.jsx b/src/components/RecordModal.jsx
index 1e295d2..e688000 100644
--- a/src/components/RecordModal.jsx
+++ b/src/components/RecordModal.jsx
@@ -234,6 +234,64 @@ function RelationManager({ recordId, rel }) {
);
}
+function HeroPanel({ record, meta, values, dirty, handleChange }) {
+ const { heroPanel, editableFields, fetchRelated } = meta;
+ const { imageField, quickFields, quickRelatedKey } = heroPanel;
+ const imageUrl = values[imageField];
+ const quickRel = fetchRelated?.find(r => r.key === quickRelatedKey);
+
+ return (
+
+ {/* Image side — ~40% */}
+
+ {imageUrl ? (
+

+ ) : (
+
Kein Bild
+ )}
+
+
+ {/* Info side — ~60% */}
+
+ {quickFields.map(key => {
+ const fieldDef = editableFields?.[key];
+ return (
+
+
+
+ {fieldDef ? (
+ handleChange(key, val)}
+ />
+ ) : (
+
+ )}
+
+ {dirty[key] && (
+
geändert
+ )}
+
+ );
+ })}
+
+ {quickRel && (
+
+
+
+ )}
+
+
+ );
+}
+
export default function RecordModal({ record, meta, onClose, onSaved }) {
const [values, setValues] = useState({});
const [dirty, setDirty] = useState({});
@@ -273,11 +331,18 @@ export default function RecordModal({ record, meta, onClose, onSaved }) {
if (!record) return null;
+ // Fields that are already shown in the hero panel — exclude from regular sections
+ const heroExclude = new Set([
+ ...(meta.heroPanel?.quickFields || []),
+ ...(meta.heroPanel ? [meta.heroPanel.imageField] : []),
+ ]);
+ const heroRelKey = meta.heroPanel?.quickRelatedKey;
+
// All field keys from the record
const allKeys = Object.keys(record);
- // Split into editable and read-only
- const editableKeys = allKeys.filter(k => !isReadOnly(k) && meta.editableFields?.[k]);
- const extraKeys = allKeys.filter(k => !isReadOnly(k) && !meta.editableFields?.[k] && !Array.isArray(record[k]));
+ // Split into editable and read-only (skip hero fields)
+ const editableKeys = allKeys.filter(k => !isReadOnly(k) && meta.editableFields?.[k] && !heroExclude.has(k));
+ const extraKeys = allKeys.filter(k => !isReadOnly(k) && !meta.editableFields?.[k] && !Array.isArray(record[k]) && !heroExclude.has(k));
const arrayKeys = allKeys.filter(k => Array.isArray(record[k]));
const roKeys = allKeys.filter(k => isReadOnly(k));
@@ -305,6 +370,17 @@ export default function RecordModal({ record, meta, onClose, onSaved }) {
{/* Body */}
+ {/* Hero panel (pictures) */}
+ {meta.heroPanel && (
+
+ )}
+
{/* Editable fields */}
{editableKeys.length > 0 && (
@@ -364,8 +440,8 @@ export default function RecordModal({ record, meta, onClose, onSaved }) {
)}
- {/* Related data with link/unlink */}
- {meta.fetchRelated?.map(rel => (
+ {/* Related data with link/unlink (skip the one already in hero) */}
+ {meta.fetchRelated?.filter(r => r.key !== heroRelKey).map(rel => (
))}
diff --git a/src/lib/tables.js b/src/lib/tables.js
index 911ef8d..db33492 100644
--- a/src/lib/tables.js
+++ b/src/lib/tables.js
@@ -45,6 +45,11 @@ export const TABLES = {
primaryLabel: 'design',
columns: ['design', 'status', 'picture_link', 'blurhash', 'created_at'],
linkedFields: {},
+ heroPanel: {
+ imageField: 'picture_link',
+ quickFields: ['status', 'design'],
+ quickRelatedKey: 'words',
+ },
editableFields: {
design: { type: 'text' },
status: { type: 'select', options: ['published', 'blocked', 'uploaded', 'requested', 'generated'] },