Simplify templates to pure Jinja2 + CodeMirror editor + variable reference
Some checks failed
Validate / Hassfest (push) Has been cancelled
Some checks failed
Validate / Hassfest (push) Has been cancelled
Major template system overhaul:
- TemplateConfig simplified from 21 fields to 9: removed all sub-templates
(asset_image, asset_video, assets_format, people_format, etc.)
Users write full Jinja2 with {% for %}, {% if %} inline.
- Default EN/RU templates seeded on first startup (user_id=0, system-owned)
with proper Jinja2 loops over added_assets, people, albums.
- build_full_context() simplified: passes raw data directly to Jinja2
instead of pre-rendering sub-templates.
- CodeMirror editor for template slots (HTML syntax highlighting,
line wrapping, dark theme support via oneDark).
- Variable reference API: GET /api/template-configs/variables returns
per-slot variable descriptions + asset_fields for loop contexts.
- Variable reference modal in UI: click "{{ }} Variables" next to any
slot to see available variables with Jinja2 syntax examples.
- Route ordering fix: /variables registered before /{config_id}.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
63
frontend/src/lib/components/JinjaEditor.svelte
Normal file
63
frontend/src/lib/components/JinjaEditor.svelte
Normal file
@@ -0,0 +1,63 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { EditorView, keymap, placeholder as cmPlaceholder } from '@codemirror/view';
|
||||
import { EditorState } from '@codemirror/state';
|
||||
import { html } from '@codemirror/lang-html';
|
||||
import { oneDark } from '@codemirror/theme-one-dark';
|
||||
import { getTheme } from '$lib/theme.svelte';
|
||||
|
||||
let { value = '', onchange, rows = 6, placeholder = '' } = $props<{
|
||||
value: string;
|
||||
onchange: (val: string) => void;
|
||||
rows?: number;
|
||||
placeholder?: string;
|
||||
}>();
|
||||
|
||||
let container: HTMLDivElement;
|
||||
let view: EditorView;
|
||||
const theme = getTheme();
|
||||
|
||||
onMount(() => {
|
||||
const extensions = [
|
||||
html(), // Jinja2 is close enough to HTML template syntax for highlighting
|
||||
EditorView.updateListener.of((update) => {
|
||||
if (update.docChanged) {
|
||||
onchange(update.state.doc.toString());
|
||||
}
|
||||
}),
|
||||
EditorView.lineWrapping,
|
||||
EditorView.theme({
|
||||
'&': { fontSize: '13px', fontFamily: 'monospace' },
|
||||
'.cm-content': { minHeight: `${rows * 1.5}em`, padding: '8px' },
|
||||
'.cm-editor': { borderRadius: '0.375rem', border: '1px solid var(--color-border)' },
|
||||
'.cm-focused': { outline: '2px solid var(--color-primary)', outlineOffset: '0px' },
|
||||
}),
|
||||
];
|
||||
|
||||
if (theme.isDark) {
|
||||
extensions.push(oneDark);
|
||||
}
|
||||
|
||||
if (placeholder) {
|
||||
extensions.push(cmPlaceholder(placeholder));
|
||||
}
|
||||
|
||||
view = new EditorView({
|
||||
state: EditorState.create({ doc: value, extensions }),
|
||||
parent: container,
|
||||
});
|
||||
|
||||
return () => view.destroy();
|
||||
});
|
||||
|
||||
// Sync external value changes (e.g. when editing different config)
|
||||
$effect(() => {
|
||||
if (view && view.state.doc.toString() !== value) {
|
||||
view.dispatch({
|
||||
changes: { from: 0, to: view.state.doc.length, insert: value },
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div bind:this={container}></div>
|
||||
Reference in New Issue
Block a user