{% extends sitecopy_base %} {% set sitecopy_screen = 'editor' %} {% set full_bleed = true %} {% block title %}Editor visual{% if sitecopy_brand %} · {{ sitecopy_brand }}{% endif %}{% endblock %} {% block head %}{% endblock %} {% block content %}
{# What already has a pending draft, whatever page it was typed on. The panel renders these too, so an edit made elsewhere is never invisible-but-counted. #}

Editor visual

Tocá un texto para editarlo; cada bloque trae sus botones.
{# Not tabs: these change the canvas WIDTH, they don't switch panels. Calling them a tablist promised arrow-key navigation that never existed. #}
{% for device in devices %} {% endfor %} {# The controls stand on every block, which is the point — but a page you are about to publish is also worth seeing as your customers will. On by default; the choice is remembered per browser. #}
{# Secondary on purpose. Editing happens on the page, block by block; this list is the way out when a text is somewhere you cannot get to by clicking (a , an alt, a page you are not on). #} <button type="button" class="ed-btn ed-btn-quiet" data-ed-panel-toggle aria-expanded="false" aria-controls="edPanel" title="Todos los textos de esta página, en una lista"> Lista de textos </button> <span class="ed-status" id="edStatus" data-ed-status role="status" aria-live="polite"></span> {# Outside the live region on purpose: a button inside role="status" gets re-announced with every message and is a strange place to park focus. #} <button type="button" class="ed-btn ed-btn-ghost" data-ed-undo hidden>Deshacer</button> <button type="button" class="ed-btn ed-btn-ghost" data-ed-find-drafts hidden>Ver cuál</button> <button type="button" class="ed-btn ed-btn-ghost" data-ed-discard hidden>Descartar</button> <button type="button" class="ed-btn ed-btn-ghost" data-ed-save disabled>Guardar borrador</button> <button type="button" class="ed-btn ed-btn-primary" data-ed-publish {% if not pending %}disabled{% endif %}> Publicar cambios<span class="ed-badge" data-ed-pending{% if not pending %} hidden{% endif %}>{{ pending }}</span> </button> </div> </div> <div class="ed-body"> {# The canvas is the whole public site: without this, reaching the panel or the Save button by keyboard costs ~34 tab stops. #} <a class="ed-skip" href="#edPanel" data-ed-skip>Saltar el sitio e ir a la lista de textos</a> <!-- ===================== CANVAS ===================== --> <div class="ed-stage" data-ed-stage> <div class="ed-frame" data-ed-frame> <iframe title="Sitio en edición" data-ed-iframe src="{{ start_path }}?edit=1"></iframe> </div> </div> <!-- ===================== SIDE PANEL ===================== --> <aside class="ed-panel" id="edPanel" data-ed-panel hidden> <div class="ed-panel-head"> <h2>Textos de esta página</h2> <button type="button" class="ed-panel-close" data-ed-panel-close aria-label="Cerrar panel">×</button> </div> <div class="ed-panel-tabs" role="tablist"> <button type="button" role="tab" id="edTabHidden" class="ed-tab" data-ed-tab="hidden" aria-selected="false" tabindex="-1" aria-controls="edPanelFields">No visibles <span class="ed-badge" data-ed-hidden-count>0</span></button> <button type="button" role="tab" id="edTabAll" class="ed-tab is-current" data-ed-tab="all" aria-selected="true" aria-controls="edPanelFields">Todos</button> <button type="button" role="tab" id="edTabCards" class="ed-tab" data-ed-tab="cards" aria-selected="false" tabindex="-1" aria-controls="edPanelCards">Al compartir</button> </div> {# One list for both field tabs: the tabs filter it. Rendering it twice would duplicate every input id, which breaks the labels. #} <div class="ed-panel-body" id="edPanelFields" role="tabpanel" aria-labelledby="edTabAll" data-ed-tabpanel="fields"> {# Hidden until the "No visibles" tab is picked: the panel now opens on "Todos", and setTab() is what shows it. #} <p class="ed-panel-note" data-ed-note hidden> Textos que no se ven en la página pero que igual importan: lo que lee Google, las descripciones de las fotos y las etiquetas para lectores de pantalla. </p> <label class="visually-hidden" for="edFilter">Buscar un texto</label> <input type="search" id="edFilter" class="ed-filter" data-ed-filter placeholder="Buscar un texto…" autocomplete="off"> <div data-ed-fields></div> <p class="ed-panel-empty" data-ed-no-results hidden> Ningún texto coincide con la búsqueda. </p> </div> {# Same three share/search formats as the group preview, built from the edited page's own <title>/meta tags. #} <div class="ed-panel-body" id="edPanelCards" role="tabpanel" aria-labelledby="edTabCards" data-ed-tabpanel="cards" hidden> <p class="ed-card-kind">Resultado en Google</p> <div class="serp"> <div class="serp-site"> <span class="serp-favicon" aria-hidden="true">{{ sitecopy_brand[:1] }}</span> <span> <span class="serp-name">{{ sitecopy_brand }}</span> <span class="serp-url" data-ct-serp-url></span> </span> </div> <p class="serp-title" data-ct-serp-title></p> <p class="serp-desc" data-ct-serp-desc></p> </div> <p class="ed-card-kind">Link compartido en WhatsApp</p> <div class="wa-bubble"> <div class="wa-preview"> <img class="wa-image" alt="" data-ct-og-image hidden> <div class="wa-text"> <p class="wa-title" data-ct-og-title></p> <p class="wa-desc" data-ct-og-desc></p> <p class="wa-host" data-ct-og-host></p> </div> </div> <p class="wa-link" data-ct-og-url></p> </div> <p class="ed-card-kind">Tarjeta en Twitter/X</p> <div class="tw-card"> <img class="tw-image" alt="" data-ct-tw-image hidden> <div class="tw-text"> <p class="tw-host" data-ct-tw-host></p> <p class="tw-title" data-ct-tw-title></p> <p class="tw-desc" data-ct-tw-desc></p> </div> </div> </div> </aside> </div> <p class="ed-footnote"> ¿Un texto que no ves en la página? Está todo también en <a href="{{ url_for(sitecopy_bp ~ '.index') }}">la lista completa por sección</a>. </p> {# A full editorial page gets its own editor: a readable column, a toolbar in words instead of symbols, and a count of the characters a reader actually sees (not of the HTML). #} <div class="ed-sheet" data-ed-sheet hidden role="dialog" aria-modal="true" aria-labelledby="edSheetTitle"> <div class="ed-sheet-panel"> <header class="ed-sheet-head"> <div> <h2 id="edSheetTitle" data-ed-sheet-title>Texto de la página</h2> <p class="ed-sheet-where" data-ed-sheet-where></p> </div> <button type="button" class="ed-sheet-close" data-ed-sheet-cancel aria-label="Cerrar sin guardar">×</button> </header> {# The braces inside a long text are machinery, not copy. The inline editor has always said so in its bubble; this one showed a raw "{brand}" mid-sentence and left the reader to guess. #} <p class="ed-sheet-tokens" data-ed-sheet-tokens hidden></p> {# How big this text renders. Same control as the panel's, here because this popup is where the text is actually being edited — going to look for it in a list on the other side of the screen is how it went unfound. #} <div class="ed-sheet-size" data-ed-sheet-size></div> <div class="ed-sheet-tools" role="group" aria-label="Formato"> <button type="button" class="ed-tool" data-ed-cmd="bold"><b>Negrita</b></button> <button type="button" class="ed-tool" data-ed-cmd="italic"><i>Cursiva</i></button> <button type="button" class="ed-tool" data-ed-cmd="formatBlock" data-ed-arg="<h2>">Subtítulo</button> <button type="button" class="ed-tool" data-ed-cmd="formatBlock" data-ed-arg="<p>">Párrafo</button> <button type="button" class="ed-tool" data-ed-cmd="insertUnorderedList">Lista</button> <button type="button" class="ed-tool" data-ed-cmd="createLink">Link</button> <button type="button" class="ed-tool" data-ed-cmd="unlink">Quitar link</button> <button type="button" class="ed-tool" data-ed-cmd="removeFormat">Quitar formato</button> </div> <div class="ed-sheet-body"> {# No role="textbox": the content is real rich structure (h2, ul, li), and role=textbox flattens it for assistive tech. A contenteditable already exposes an editable region; let the browser surface the real semantics. #} {# No aria-multiline either: it is only defined on role="textbox", and the comment above says why this deliberately has no role. Left on a generic element it is a critical ARIA violation — axe never saw it because nothing opened this popup during the a11y pass. #} <div class="ed-sheet-doc" data-ed-sheet-doc contenteditable="true" spellcheck="true" aria-labelledby="edSheetTitle"></div> </div> <footer class="ed-sheet-foot"> <p class="ed-sheet-note" data-ed-sheet-note role="status" aria-live="polite" hidden></p> <span class="ed-sheet-count" data-ed-sheet-count aria-live="polite"></span> <span class="ed-sheet-actions"> <button type="button" class="ed-btn ed-btn-ghost" data-ed-sheet-cancel>Cancelar</button> <button type="button" class="ed-btn ed-btn-primary" data-ed-sheet-apply>Listo</button> </span> </footer> </div> </div> {# Clicking a picture on the canvas opens ITS controls, right there. It used to send you to the side panel and scroll to the field, which is a correct answer to a question nobody asked: the thing you clicked is the thing you want to change. #} <div class="ed-media-dialog" data-ed-media hidden role="dialog" aria-modal="true" aria-labelledby="edMediaTitle"> <div class="ed-media-panel"> <header class="ed-media-head"> <div> <h2 id="edMediaTitle" data-ed-media-title>Imagen</h2> <p class="ed-media-where" data-ed-media-where></p> </div> <button type="button" class="ed-media-close" data-ed-media-close aria-label="Cerrar">×</button> </header> <div class="ed-media-body" data-ed-media-body></div> <footer class="ed-media-foot"> <p class="ed-media-hint"> Nada se ve en la web hasta que publiques. </p> <button type="button" class="ed-btn ed-btn-primary" data-ed-media-done>Listo</button> </footer> </div> </div> <noscript> <div class="adm-flash adm-flash-notice"> El editor visual necesita JavaScript. Podés editar todos los textos desde <a href="{{ url_for(sitecopy_bp ~ '.index') }}">la lista por sección</a>. </div> </noscript> </div> {% endblock %} {% block scripts %} <script defer src="{{ url_for(sitecopy_bp ~ '.static', filename='js/sitecopy-editor.js') }}"></script> {% endblock %}