feat: smart video size warnings + Jinja2 template autocomplete
Video size warnings:
- Add file_size field to ImmichAssetInfo from exifInfo.fileSizeInByte
- Expose per-target max_video_size (50 MB for Telegram, none for others)
- Compute has_oversized_videos and per-asset oversized flag in template context
- Default templates show warning only when videos actually exceed the limit
- Templates no longer hardcode Telegram-specific logic
Template autocomplete:
- New jinja-autocomplete.ts engine with contextual completions
- Top-level variables ({{ }}), asset/album fields (dot access in loops),
Jinja2 filters (|), block tags ({% %}), and loop.* special vars
- JinjaEditor accepts optional variables prop via CodeMirror Compartment
- Wired into template-configs and command-template-configs pages
Also: fix template emoji (📷 → 📎) and sync sample_context with new vars.
This commit is contained in:
@@ -1,19 +1,24 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { EditorView, Decoration, placeholder as cmPlaceholder, type DecorationSet } from '@codemirror/view';
|
||||
import { EditorState, StateField, StateEffect } from '@codemirror/state';
|
||||
import { EditorView, Decoration, keymap, placeholder as cmPlaceholder, type DecorationSet } from '@codemirror/view';
|
||||
import { EditorState, StateField, StateEffect, Compartment } from '@codemirror/state';
|
||||
import { StreamLanguage } from '@codemirror/language';
|
||||
import { oneDark } from '@codemirror/theme-one-dark';
|
||||
import { acceptCompletion } from '@codemirror/autocomplete';
|
||||
import { getTheme } from '$lib/theme.svelte';
|
||||
import { jinjaAutocomplete, type SlotVariables } from '$lib/editor/jinja-autocomplete';
|
||||
|
||||
let { value = '', onchange, rows = 6, placeholder = '', errorLine = null } = $props<{
|
||||
let { value = '', onchange, rows = 6, placeholder = '', errorLine = null, variables = undefined } = $props<{
|
||||
value: string;
|
||||
onchange: (val: string) => void;
|
||||
rows?: number;
|
||||
placeholder?: string;
|
||||
errorLine?: number | null;
|
||||
variables?: SlotVariables;
|
||||
}>();
|
||||
|
||||
const autocompleteCompartment = new Compartment();
|
||||
|
||||
let container: HTMLDivElement;
|
||||
let view: EditorView;
|
||||
const theme = getTheme();
|
||||
@@ -71,6 +76,8 @@
|
||||
const extensions = [
|
||||
jinjaLang,
|
||||
errorLineField,
|
||||
autocompleteCompartment.of(variables ? jinjaAutocomplete(variables) : []),
|
||||
keymap.of([{ key: 'Tab', run: acceptCompletion }]),
|
||||
EditorView.updateListener.of((update) => {
|
||||
if (update.docChanged) {
|
||||
onchange(update.state.doc.toString());
|
||||
@@ -86,6 +93,11 @@
|
||||
'.ͼc': { color: '#e879f9' },
|
||||
'.ͼd': { color: '#38bdf8' },
|
||||
'.ͼ5': { color: '#6b7280' },
|
||||
'.cm-tooltip-autocomplete': {
|
||||
border: '1px solid var(--color-border)',
|
||||
borderRadius: '0.375rem',
|
||||
fontSize: '12px',
|
||||
},
|
||||
}),
|
||||
];
|
||||
if (isDark) extensions.push(oneDark);
|
||||
@@ -116,6 +128,17 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Update autocomplete when variables change
|
||||
$effect(() => {
|
||||
if (view) {
|
||||
view.dispatch({
|
||||
effects: autocompleteCompartment.reconfigure(
|
||||
variables ? jinjaAutocomplete(variables) : [],
|
||||
),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Recreate editor when theme changes
|
||||
let lastIsDark: boolean | undefined;
|
||||
$effect(() => {
|
||||
|
||||
Reference in New Issue
Block a user