Editorul vizual îți deschide site-ul în Manifolio, cu ciornele la locul lor. Editorul dă click pe un titlu și scrie, alege o poză nouă din biblioteca media sau sare la un câmp din panoul lateral. Designul rămâne în cod: editorul schimbă conținutul, niciodată aspectul sau stilurile.
Pe site sunt de făcut trei lucruri: citești ciornele când pagina are un token de preview, marchezi elementele care arată un câmp și încarci scriptul bridge în preview.
Cum merge
- În admin, Editor vizual (dintr-o intrare sau din meniu) cere API-ului un token de preview: semnat, valabil 30 de minute, legat de un singur proiect și bun doar pentru citirea ciornelor.
- Admin-ul deschide adresa de preview într-un iframe, cu
?mf_preview=<token>adăugat. - Serverul tău vede tokenul, citește ciornele prin Preview API și randează pagina ca de obicei, cu atributele
data-mf-editși scriptul bridge. - Bridge-ul vorbește doar cu admin-ul Manifolio care a deschis pagina. Editările se întorc în admin, care le salvează ca ciorne (salvarea automată, conflictele și versiunile merg ca în editorul de intrări). Publicarea rămâne un click făcut cu intenție.
1. Ciornele, cu tokenul
import { createClient, previewTokenFrom } from "@manifolio/sdk";
export function cmsFor(request: Request) {
const token = previewTokenFrom(request.url); // null la vizitele obișnuite
return token
? createClient({ project: PROJECT_ID, preview: token }) // ciornele, fără cheie
: createClient({ project: PROJECT_ID, key: MANIFOLIO_KEY }); // conținutul publicat
}Răspunsurile de preview nu intră în cache. Când tokenul e prezent, ocolești CDN-ul sau cache-ul de date și trimiți Cache-Control: private, no-store.
Tokenul nu poate publica, nu poate scrie și nu poate citi alt proiect. Când expiră, admin-ul îi trimite bridge-ului unul nou, așa că navigarea în editor merge mai departe.
2. Elementele editabile
---
import { editable } from "@manifolio/sdk";
const page = await cms.entry("page", "despre");
---
<h1 {...editable(page, "title")}>{page.title}</h1>
<p {...editable(page, "lead")}>{page.lead}</p>
{page.sections.map((s, i) => (
<h2 {...editable(page, ["sections", i, "title"])}>{s.title}</h2>
))}
<img {...editable(page, "hero")} src={imageUrl(page.hero, { w: 1600 })} alt={page.hero.alt} />editable(entry, field, locale?) întoarce un singur atribut, data-mf-edit, cu tipul și id-ul intrării, drumul câmpului și limba. Listele și grupurile primesc un drum: ["sections", 2, "items", 0, "title"] sau "sections.2.items.0.title". Atributul e inofensiv pe o pagină publică; ca HTML-ul public să rămână curat, folosești client.editable(...), care nu scrie nimic dacă clientul n-a fost creat cu un token de preview.
Ce face un click depinde de câmp:
| Câmp | Pe pagină |
|---|---|
| Text, slug, adresă, email | se editează pe loc; Enter salvează, Esc renunță |
| Text lung | se editează pe loc; ⌘ Enter salvează, Enter adaugă un rând |
| Text lung randat ca Markdown, text formatat | panoul se deschide pe acel câmp |
| Media | se deschide biblioteca media; fișierul ales îl înlocuiește pe cel vechi |
| Orice altceva | panoul se deschide pe acel câmp |
Ce scrii în panou apare pe pagină pe loc. După salvare, pozele și textul formatat se reîmprospătează în pagină; un element adăugat sau mutat într-o listă reîncarcă pagina și păstrează poziția de derulare.
Secțiunile (blocuri)
Un câmp blocks ține secțiunile paginii; fiecare bloc are _type și un _key care nu se schimbă. Secțiunea întreagă se marchează cu blocul în drum, iar câmpurile din ea la fel:
{page.sections.map((b) => (
<section {...editable(page, ["sections", b])}>
<h2 {...editable(page, ["sections", b, "title"])}>{b.title}</h2>
</section>
))}Secțiunea primește data-mf-block: în editor se conturează la trecerea mouse-ului și arată o bară cu mutare sus sau jos, dublare și ștergere, plus un + deasupra și dedesubt care deschide meniul de secțiuni din panou. Drumul folosește cheia blocului (sections[a1b2c3d4e5].title), deci rămâne bun după mutări.
3. Bridge-ul, în preview
<script defer src="https://api.manifolio.com/v1/bridge.js" data-admin="https://app.manifolio.com"></script>Îl adaugi doar când tokenul e prezent. Scriptul are sub 4 KB comprimat, nicio dependență și nu face nimic când pagina nu e în admin-ul Manifolio: verifică fereastra-părinte și originea admin-ului la fiecare mesaj, în ambele sensuri. Nu folosește eval, nu adaugă <style> și merge sub un Content Security Policy strict. Din npm, import { startBridge } from "@manifolio/sdk/bridge" face același lucru.
Adresa de preview
O pui în Setări → Editor vizual. Manifolio completează {slug}, {type} și {locale} pentru intrarea deschisă:
https://example.com/{locale}/{slug}
https://example.com/preview?type={type}&slug={slug}&locale={locale}A doua formă duce la o rută mică de pe site care trimite fiecare tip la pagina lui și păstrează mf_preview. Redirecționările rămân pe aceeași origine. Adresa folosește https; http merge doar pe localhost.
Încadrarea și antetele
Browserele nu deschid site-ul în iframe când primesc X-Frame-Options sau o regulă frame-ancestors care lasă admin-ul pe dinafară. Pe răspunsurile de preview permiți admin-ul și nimic altceva:
Content-Security-Policy: frame-ancestors 'self' https://app.manifolio.com
Cache-Control: private, no-store
Referrer-Policy: same-originScoți X-Frame-Options de pe aceste răspunsuri sau îl păstrezi doar pe paginile obișnuite. Scripturile de analiză pot rămâne oprite în preview, ca vizitele editorului să nu se numere.
Limitele acestei versiuni
- Textul formatat se editează în panou, nu în pagină.
- Secțiunile se schimbă prin salvarea automată a editorului; după salvare pagina se reîncarcă, cu ordinea nouă.
- Pe telefon apare mesajul „folosește un ecran mai mare”: editorul are nevoie de pagină și de panou unul lângă altul.