diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/admin/templates/form.html | 81 |
1 files changed, 56 insertions, 25 deletions
diff --git a/internal/admin/templates/form.html b/internal/admin/templates/form.html index 1b577c9..61c7cac 100644 --- a/internal/admin/templates/form.html +++ b/internal/admin/templates/form.html @@ -1,19 +1,28 @@ {{define "form-content"}} <h1>{{.Title}}</h1> - <form method="POST" action="{{.Action}}"> + <form method="POST" action="{{.Action}}" id="postForm"> <label for="title">Title</label> <input type="text" id="title" name="title" value="{{.Post.Title}}" required autofocus> + <label for="slug">Slug</label> + <input type="text" id="slug" name="slug" value="{{.Post.Slug}}" placeholder="auto-generated from title"> + <p class="hint">URL path for this post (e.g. "my-post" → /my-post). Lowercase letters, numbers, and hyphens only.</p> + <label for="date">Date</label> <input type="date" id="date" name="date" value="{{.Post.Date}}"> <label for="tags">Tags</label> - <input type="text" id="tags" name="tags" value="{{.Post.Tags}}" placeholder="tag1, tag2, tag3"> + <input type="text" id="tags" name="tags" value="{{range $i, $t := .Post.Tags}}{{if $i}}, {{end}}{{$t}}{{end}}" placeholder="tag1, tag2, tag3"> <p class="hint">Comma-separated list of tags.</p> - <label for="content">Content (Markdown)</label> - <textarea id="content" name="content" style="display: none;">{{.Post.Content}}</textarea> + <label for="draft"> + <input type="checkbox" id="draft" name="draft"{{if .Post.Draft}} checked{{end}}> + Draft (not published) + </label> + + <label for="blocks">Content</label> <div id="editor" style="border: 1px solid #ccc; border-radius: 4px; min-height: 340px;"></div> + <input type="hidden" id="blocks" name="blocks" value=""> <div class="form-actions"> <button type="submit" class="btn btn-primary"> @@ -24,39 +33,61 @@ </form> <script type="module"> - import { Crepe } from '@milkdown/crepe'; + import { EditorJS, Header, Paragraph, List, Code, Quote, ImageTool } from 'editorjs-bundle'; + import ComponentTool from '/assets/admin/lib/component-tool.js'; + + const blocksField = document.getElementById('blocks'); + const form = document.getElementById('postForm'); + const titleInput = document.getElementById('title'); + const slugInput = document.getElementById('slug'); - const contentField = document.getElementById('content'); - const editorContainer = document.getElementById('editor'); - const form = contentField.closest('form'); + // Auto-populate slug from title for new posts only, until user edits slug manually. + {{if .IsNew}} + let slugManuallyEdited = slugInput.value !== ''; + slugInput.addEventListener('input', () => { slugManuallyEdited = true; }); + titleInput.addEventListener('input', () => { + if (slugManuallyEdited) return; + slugInput.value = titleInput.value + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/^-+|-+$/g, ''); + }); + {{end}} + + let initialData = []; + try { + initialData = JSON.parse(blocksField.value || '[]'); + } catch (e) { + console.error('Failed to parse blocks JSON:', e); + } - // Initialize Crepe with the textarea content - const crepe = new Crepe({ - root: editorContainer, - defaultValue: contentField.value, + const editor = new EditorJS({ + holder: 'editor', + tools: { + header: Header, + paragraph: Paragraph, + list: List, + code: Code, + quote: Quote, + image: ImageTool, + component: ComponentTool, + }, + data: { blocks: initialData }, }); - // Sync editor content back to textarea before form submission + // Sync editor content back to hidden field before form submission form.addEventListener('submit', async (e) => { e.preventDefault(); try { - // Get the markdown content from Crepe - const markdown = await crepe.getMarkdown(); - contentField.value = markdown; + const editorData = await editor.save(); + blocksField.value = JSON.stringify(editorData); } catch (err) { - console.error('Failed to get markdown from editor:', err); + console.error('Failed to save editor data:', err); + return; } - // Submit the form form.submit(); }); </script> - - <noscript> - <style> - #editor { display: none; } - #content { display: block !important; } - </style> - </noscript> {{end}} |
