<% // Post editor — split into card sections for visual hierarchy: // - Identity : title, slug, excerpt // - Cover : thumbnail + URL + custom upload button // - Content : markdown textarea with attached toolbar // - Meta : status, type, pin, noindex, tags // // All behavior (IDs, names, upload endpoints) is preserved — only layout // and styling changed. const _hasCover = !!post.cover_image_url; // In hub mode, save/create/cancel must carry the /user// prefix, otherwise // the request falls back to the primary site (siteUrlBase empty) and the post // renders headerless (bareChrome) after saving. In solo mode _base is empty. const _base = (typeof siteUrlBase !== 'undefined' && siteUrlBase) ? siteUrlBase : ''; %>

<%= isNew ? t('pedit.title_new') : t('pedit.title_edit') %>

<%# ── TYPE (segmented) + type-specific inputs ──────────────── Post type lives at the TOP (above the body), and the selected type reveals its own input: Audio → inline upload, Video → embed URL, Foto → cover/insert hint. %> <% var ptype = post.type || 'post'; %> <% var TYPE_ICONS = { post: '📝', foto: '📷', video: '🎬', audio: '🎵' }; %>
<%= t('pedit.s_type') %>
<% ['post','foto','video','audio'].forEach(function (tt) { %> <% }); %>
<%# Audio: inline upload (transcodes + drops [[track]] into the post) %> <%# Video: paste a URL → embed chip %> <%# Foto: light hint toward cover + insert-image %>
<%# ── IDENTITY ─────────────────────────────────────────────── %>
<% var _postLang = (typeof post.language !== 'undefined' && post.language) ? post.language : (typeof lang !== 'undefined' ? lang : 'en'); %>
<%# ── COVER ────────────────────────────────────────────────── %>
<%= t('pedit.s_cover') %>
> > <% if (!_hasCover) { %>🖼<% } %>
<%# Muted loop MP4 for an animated cover (auto-made from an animated WebP). Hidden — set by the uploader. %>
<%# ── CONTENT ──────────────────────────────────────────────── %>
<%= t('pedit.s_content') %> <%= t('pedit.content_hint') %>
<%# Sticky "tap to edit" hint (only visible on touch + non-fullscreen via CSS). Purely visual (pointer-events:none); tapping the field opens fullscreen. %> <%# Hidden field is what actually submits to the server. The visible contenteditable's serialized HTML is copied here on submit. %> <%# Initial content is injected as a JSON string in a script tag so we can set innerHTML safely from JS. EJS-escaping HTML directly into the editor would render entity-escaped tags as text. %>
0 <%= t('pedit.chars') %>
<%# ── META ─────────────────────────────────────────────────── %>
<%= t('pedit.s_publication') %>
0) ? '' : 'hidden' %>>
<% var _fediOpen = (typeof fediOpenAudio !== 'undefined' && fediOpenAudio); %> <% if (_fediOpen) { %>

<%= t('pedit.fedi_audio_locked') %>

<% } else { %> <% } %> <% // Poll (federates as an AS2 Question). Free feature. A poll with votes is frozen. var _poll = null; try { _poll = post.poll_json ? JSON.parse(post.poll_json) : null; } catch (e) { _poll = null; } var _pollLocked = (typeof pollLocked !== 'undefined' && pollLocked); var _pollOpts = (_poll && Array.isArray(_poll.options) && _poll.options.length) ? _poll.options : [{ name: '' }, { name: '' }]; %> <%# NB: keep the condition INSIDE the quoted attribute — escaped output (equals-tag) turns a whole emitted style attribute into entity soup (fields showed always). %>
<% if (_pollLocked) { %>

<%= t('pedit.poll_locked') %>

<% } %>
<% _pollOpts.forEach(function (o) { %>
> <% if (!_pollLocked) { %><% } %>
<% }); %>
<% if (!_pollLocked) { %><% } %>
<% if (typeof premiumUnlocked === 'undefined' || premiumUnlocked) { %> <% var _scheduled = !!(post.publish_at && (post.status === 'scheduled' || Date.parse(String(post.publish_at).replace(' ', 'T')) > Date.now())); %>
data-iso="<%= post.publish_at || '' %>" value="" style="padding:8px 10px;border-radius:8px;border:1px solid var(--rule,rgba(128,128,128,.4));background:transparent;color:inherit"> <% if (post.status === 'scheduled' && post.publish_at) { %>
⏳ <%= t('pedit.scheduled_for', { d: post.publish_at }) %>
<% } %>
<%= t('pedit.schedule_hint') %>
<% } %>
<%# ── ACTIONS (sticky at bottom) ──────────────────────────── %>
<%= t('pedit.cancel') %>
<% if (!isNew && post.status !== 'published') { %> <% } %>
<%# ── Track picker modal (P59). Mobile-first: full-screen sheet on small viewports, centered modal on ≥640px. Populated lazily on first open. %> <% if (typeof user !== 'undefined' && user) { %> <% } %> <%# Playlist editor modal — included so its global window.openPlaylistEditor is available when the toolbar button fires. Only renders if user can post. %> <% if (typeof user !== 'undefined' && user) { %> <%- include('../partials/playlist-editor', { csrfToken: (typeof csrfToken !== 'undefined' ? csrfToken : '') }) %> <% } %>