Fejlesztőknek
Kezdj bele
Témák/Szekciók, blokkok és elemstílusok

Szekciók, blokkok és elemstílusok

Hozz létre témaszekciókat és -blokkokat a defineSection és defineBlock segítségével, adj hozzájuk beállításokat és stílusfunkciókat, és regisztráld őket a webáruházhoz és a témaszerkesztőhöz.

Ezen az oldalon

Minden szekciót és blokkot, amelyet egy téma hozzáad, egyszer deklarálsz, TSX-ben, közvetlenül a komponense mellett. Egyetlen defineSection({...}) vagy defineBlock({...}) objektum tartalmazza a típuskulcsot, a választó címkéjét és ikonját, az inspector beállításait, az elfogadott gyermekelemeket, a stílusfunkciókat és a komponenst. A téma fordítója ezeket az objektumokat kód futtatása nélkül olvassa be, és ebből buildeli fel a témaszerkesztő katalógusát, a kódszerkesztő elrendezéshez használt JSON Schema-ját és a közzétételi ellenőrzéseket. Nincs külön manifest.

Az elrendezés és a tartalom a kód mellett, JSON-ban marad: pages/*.json, pages/custom/*.json, layout/*.json és settings/values.json. A témaszerkesztő és a kódszerkesztő ugyanazokat a fájlokat módosítja. A témaszerkesztő soha nem módosítja a theme.json fájlt.

Egy szekció

src/sections/quote-wall.tsx
import { EditableText, Slot, defineBlock, defineSection, field } from '@poltura/theme-sdk/elements';
import { cn } from '@poltura/theme-sdk/ui';

export const wallQuote = defineBlock({
  type: 'wall-quote',
  label: 'Quote',
  icon: 'quote',
  category: 'content',
  settings: {
    quote: field.textarea({ label: 'Quote', default: 'Best purchase this year.' }),
    author: field.text({ label: 'Author' }),
  },
  style: ['typography', 'color', 'spacing'],
  component: ({ settings }) => (
    <figure>
      <EditableText setting='quote' as='blockquote' className='text-lg' />
      {settings.author ? <figcaption>{settings.author}</figcaption> : null}
    </figure>
  ),
});

export const quoteWall = defineSection({
  type: 'quote-wall',
  label: 'Quote wall',
  description: 'Customer quotes in a grid',
  icon: 'quote',
  category: 'marketing',
  templates: ['home', 'page'],
  settings: {
    heading: field.text({ label: 'Heading', default: 'What customers say' }),
    columns: field.range({ label: 'Columns', min: 1, max: 4, default: 3 }),
  },
  blocks: { accepts: [wallQuote], max: 12 },
  style: ['spacing', 'background', 'visibility'],
  component: ({ attrs }) => (
    <section {...attrs} className={cn(attrs.className, 'theme-container py-14')}>
      <EditableText setting='heading' as='h2' className='mb-8 text-3xl font-semibold' />
      <Slot className='grid gap-6 md:grid-cols-3' />
    </section>
  ),
});
  • A type az a kulcs, amelyet az elrendezés JSON használ. A kulcsok témánként egyediek; egy platformkulcs (hero, heading, button, link-list…) újbóli használata mindenhol felülírja a platformelemet.
  • A settings egy objektumkonstans. A kulcsai a setting ID-k, a sorrendje az inspector sorrendjét követi, a komponens settings propja pedig ebből kap típust az alapértelmezett értékek alkalmazásával és a vásárló nyelvének feloldásával. Minden komponens megkapja a { settings, attrs, id } objektumot. A definíción kívül megírt komponens, amely egy const-ban tartott setting objectre épül, ElementProps<typeof schema> típust kap.
  • A blocks.accepts felsorolja a gyermekelemek típusait: importált definíciókat, típuskulcsokat vagy egy helyettesítő karaktert (lásd alább). A blocks.max korlátozza a darabszámot.
  • A templates template ID-kra (home, product, collection, page, …) korlátozza a szekciót. Hagyd el, ha a szekciót mindenhol elérhetővé tennéd.
  • A slots: [{ name: 'media', label: 'Media' }, …] nevesített régiókat deklarál; mindegyiket a <Slot name='media' /> segítségével jelenítheted meg.
  • Egy defineSection komponensnek kötelező az attrs objektumot átadnia (spread) egyetlen root node-nak. Ez a node hordozza az element ID-t, amelyet a témaszerkesztő kiválaszt, a kereskedő horgonyát (anchor) és a kereskedő Stílus fülének scope-ra korlátozott CSS-ét. A scope-ra korlátozott CSS egy olyan class-t céloz, amelyet a spread az attrs.className mezőben hoz be, így a node saját class-ai a @poltura/theme-sdk/ui csomagból származó cn(attrs.className, 'py-14') segítségével fésülhetők össze vele. Egy egyszerű className='py-14' a spread után felülírja ezt a class-t: a kereskedő térközei, háttere és láthatósága ekkor hatástalanná válnak, és a témaellenőrzés ezt hibaként jelzi.
  • Egy blokknak nincs szüksége semmire a root elementjén: a platform minden blokkot a saját keretén (frame) belül rajzol ki, egy div-ben (vagy a li, illetve span elemben, amelyet a frame megnevez), amely magában foglalja a szerkesztő horgonyát, az oldalon belüli horgonyt és a kereskedő stílusát, a blokknak pedig egy üres attrs értéket ad át. A kereskedők külön fejlesztői ráfordítás nélkül bármelyik blokkot újrastílusozhatják.
  • A context: { requires: ['product'] } deklarálja, hogy egy blokk a legközelebbi termék adatait olvassa (useNearestProduct a @poltura/theme-sdk/product csomagból); a provides deklarálja azokat a scope-okat, amelyeket egy elem a gyermekei számára megnyit. A terméksablon, minden termékkártya és a ProductScope product scope-ot nyit. A gyűjtemény-, kategória- és minden terméket felsoroló oldalak collection scope-ot nyitnak, amelynek listázási adatait a useListing olvassa a @poltura/theme-sdk/listing csomagból. A témaszerkesztő visszautasítja az olyan blokkot, amely olyan helyen kér scope-ot, ahol az nem elérhető.
  • A presets nevesített kiindulási konfigurációk (beállítások, stílus, gyermekelemek). Csak a default azonosítójú preset kerül alkalmazásra, amikor a kereskedő beszúrja az egyszerű elemet. Minden más preset saját csempeként jelenik meg a választóban közvetlenül az elem után, Element (Preset) címkével. Annak a presetnek, amellyel egy containernek indulnia kell, add a default nevet, különben üres marad.
  • A keywords: ['kosárba', 'ATC'] keresési kifejezéseket ad a választóhoz. Szekcióknál a groups: ['header'] a fejléc- vagy lábléc-csoportban kínálja fel a szekciót, a limit: 1 pedig sablononként vagy csoportonként korlátozza a példányainak számát.

Mit jelent a „statikus”?

A fordító a component kivételével mindent kiértékel anélkül, hogy futtatná a kódot. Engedélyezett: literálok, field.* hívások literál argumentumokkal, field.group('Label') és field.note('…'), hivatkozások ugyanazon fájlban lévő const literálokra, valamint importált definíciók az accepts mezőben. Minden más (függvényhívás, másik modulból származó spread, számított kulcs) schema hibát eredményez a témaellenőrzésben és a kódszerkesztőben a forrásbeli pozíció megjelölésével. A component lehet helyi függvény vagy inline arrow function, és egyetlen komponens több típust is kiszolgálhat.

Szekcióhoz tartozó blokkok

Minden blokk rendelkezik component értékkel, és egy régión keresztül rajzolja ki magát. A témaellenőrzés accepted-without-component hibát jelez az olyan elfogadott blocknál, amely nem rendelkezik ilyennel. Az a blokk, amelyet név szerint csak egyetlen szekció fogad el, ahhoz a szekcióhoz tartozik: a választó csak ott kínálja fel és sehol máshol, mint például az alapértelmezett téma GYIK osztott kérdései és a megamenü oszlopai esetében.

Mezőkészítők (field builders)

A field a @poltura/theme-sdk/elements csomagból érkezik. Minden builder fogadja a label paramétert, és opcionálisan a következőket: description, placeholder, visibleIf: { field, value }, translatable, content, renamedFrom és purpose (egy egysoros leírás arról, mit fejez ki az érték, eligazítást adva a szövegírónak). A legtöbb builder elfogad default értéket is; a video és a katalógusválasztók (product, collection és hasonlók) nem. A text, textarea és richtext mezők a maxLength értéket is fogadják, amely a dizájn által megengedett maximális karakterszám. A select és a radio a renamedValues: { old: 'new' } beállítást is fogadja: ha átnevezel egy opcióértéket, az az áruház, amely a régit mentette, az új értéken megtartja a választását. Az értéket átnevező frissítés előbb a kereskedőt kérdezi, azt pedig, amelyik átnevezés nélkül hagy el egy opciót, nem lehet közzétenni.

BuilderÉrték
text, textarea, richtextstring, alapértelmezetten fordítható
number, range (min, max, step, unit)number
checkboxboolean
select, radio (options; a radio kaphat icon-t)az opcióértékek uniója
color (darkDefault hozzáadja: <id>_dark), gradientstring
imageegy media:// vagy asset:// hivatkozás
urlbolton belüli útvonal vagy abszolút URL
videoegy forrás, vagy { src, poster?, autoplay?, loop?, muted?, alt? }
link (withLabel){ href, new_tab?, rel?, label? }
fontCSS fontkészlet (font stack)
linkListlinkek opcionális gyermekelemekkel
product, collection, categoryegyetlen azonosító
productsazonosítók tömbje
collectionList (max, alapértelmezetten 12){ kind: 'collection' | 'category', handle }[] a kereskedő sorrendjében
pagetartalmi oldal útvonala (pl. /about); a usePage olvassa
post{ kind: 'post' | 'guide', slug }; a usePost olvassa
menuegy menü handle-je, amelyet a useMenu olvas
menuItemannak a menünek az egyik legfelső szintű link ID-ja, amelyben az elem található
list (fields, min, max, alapértelmezetten 24 sor)a sorok beállításai sorrendben
colorSchemea téma egy nevesített színsémája; ha üres, megtartja a szülőét, a useColorScheme olvassa
colorSchemeGroupa téma színsémái témabeállításként
partnerBadges{ order, hidden } jelvénykulcsok
iconegy Lucide ikonnév vagy feltöltött SVG
datetimeISO 8601 string időeltolódással (offset), vagy üres
copy (key)nincs: egy szöveget szerkeszt a texts/ alatt
group('Label'), note('Text')nincs: inspector címsor és súgószöveg
variablecsak e-mail: az e-mail egyik változójának neve
keyValuescsak e-mail: fordított címke és változóérték sorai
stepscsak e-mail: számozott sorok fordított címmel és leírással
linkscsak e-mail: fordított hivatkozásszöveg és a címet tároló változó sorai
htmlcsak e-mail: HTML változatlan formában elküldve
promotioncsak e-mail: egy kóddal rendelkező bolti promóció azonosítója

A modulban található fieldSet olyan beállításokat csoportosít, amelyeken több elem osztozik, mint például egy gomb címkéje és linkje: a készlet előtaggal történő meghívása <prefix>_<key> formában illeszti be a mezőit a schemába. A defineThemeSettings a témabeállítások paneljét deklarálja az src/settings.ts fájlban ugyanezen field.* builderek használatával.

Egy icon beállítás a teljes Lucide készletből választ (shopping-bag, truck), vagy a kereskedő által feltöltött, megtisztított és beágyazottan tárolt SVG-t tartalmaz. Rajzold ki a @poltura/theme-sdk/ui csomagból származó <Icon value={settings.icon} /> komponenssel: a webáruház csak azokat az ikonokat ágyazza be, amelyeket az oldal ténylegesen használ, így nem kerül felesleges ikonkönyvtár a böngészőbe.

A partnerBadges beállítás a bolt aktív feedjeinek jelvényeit tárolja { order: [...], hidden: [...] } formában: minden aktív jelvény megjelenik, amely nem szerepel a hidden listában; először az order-ben lévő kulcsok, a többi pedig a feedek közzétételi sorrendjében, így a később élesedő jelvény magától megjelenik. A szüneteltetett feedek kulcsai megmaradnak az értékben arra az esetre, ha újra aktívvá válnának.

A datetime beállítás naptárral és a bolt órája szerinti időponttal választható ki, és az eltolódásával együtt kerül tárolásra (2026-12-31T23:59:00+01:00). A @poltura/theme-sdk/content csomagból származó useCountdown ugyanúgy olvassa be, ahogyan a platform visszaszámlálója: a puszta dátum éjfélkor indul, az eltolódás nélküli időpont pedig a bolt órája szerint kerül értelmezésre, mindkettő a bolt időzónájában.

A link beállítás a bolt oldalai, termékei, gyűjteményei, kategóriái és űrlapjai közül választható ki, vagy címként gépelhető be, új lapos kapcsolóval, más oldalak esetén pedig nofollow és sponsored értékekkel. A default a kezdő href (field.link({ label: 'Link', default: '/products' })), az elrendezési fájlban lévő egyszerű string pedig href-ként értelmeződik. Add át az értéket a @poltura/theme-sdk/routing csomag Link komponensének, amely ellenőrzi a href-et, alkalmazza az új lapot és a rel attribútumot, új lap esetén pedig hozzáadja a noopener noreferrer értéket:

<Link href={settings.cta} className='pol-cta' />

A withLabel: true a link látható szövegét is kéri, amelyet label néven tárol; a Link ezt jeleníti meg, ha nem foglal magában semmit. Ez a szöveg nyelvenként külön fordítható, míg a href, a lap és a rel minden nyelven ugyanaz marad.

A richtext beállítás egy eszköztárral szerkeszthető (félkövér, dőlt, linkek akár új lapon megnyitva, pontozott és számozott listák, 3-as és 4-es szintű címsorok; Cmd/Ctrl+B, I és K), és egyszerű formázást tartalmazó szövegként tárolódik, soha nem HTML-ként: **bold**, *italic*, [label](/path), [label](https://…){target=_blank}, - item, 1. item, ### Heading, #### Subheading, és üres sor a bekezdések között. Megjelenítéséhez használd az EditableRichText komponenst a @poltura/theme-sdk/elements csomagból, amely kirajzolja a szöveget, és lehetővé teszi a kereskedőknek, hogy a vásznon szerkesszék. A formázott szövegként érkező bolti szövegek, például a termékleírások rendereléséhez használd a RichText komponenst a @poltura/theme-sdk/content csomagból.

A font beállítás egy CSS fontkészletet tárol a betűtípus-választóból, például: ui-serif, Georgia, Cambria, serif; alkalmazd a style={{ fontFamily: settings.font }} formában. A rendszerkészletek mindig renderelődnek; a webes betűtípus akkor jelenik meg, ha a téma betöltötte. A number és a range egy mértékegységet (unit: px, %, em, rem, vh, vw, ms, s, deg) is elfogad, amely az érték mellett jelenik meg; a tárolt érték egyszerű szám marad.

A video beállítás YouTube- vagy Vimeo-linket, illetve a kereskedő által feltöltött, legfeljebb 20 MB-os MP4- vagy WebM-fájlt fogad el borítóképpel, lejátszási beállításokkal (automatikus lejátszás, ismétlés, némítás) és szöveges alternatívával. A @poltura/theme-sdk/media csomagból származó useVideoSetting feloldja ezt a megjelenítendő fájlra vagy lejátszóra.

A text, textarea és richtext mezőkben lévő kereskedői szövegek lefordításra kerülnek a bolt nyelveire (settings_i18n az elrendezési fájlban). A style értékei soha nem kerülnek lefordításra.

Az image, video, url és link beállítások minden nyelven közösek mindaddig, amíg a kereskedő valamelyik nyelvnek nem ad meg egyedit (például egy magyar nyelvű bannert, egy /hu/… linket) a témaszerkesztő „Másik használata ehhez: …” funkciójával. Ez az érték a lefordított szöveghez hasonlóan a settings_i18n[<locale>] alatt tárolódik, soha nem kerül gépi fordításra, az „A(z) … használata” gombbal pedig törölhető, így a nyelv újra az alapértéken osztozik. A settings prop már eleve a vásárló nyelvét tartalmazza, így az elemnek nincs szüksége semmi pluszra a megfelelő kép megjelenítéséhez.

A kép- és videobeállítások a bolt médiatárát is felkínálják: a bolt adminfelületén keresztül feltöltött összes kép és videó elérhető, fájlnév szerint kereshető formában. A nem használt fájlok a választóból törölhetők.

Megjelenés és tartalom

Minden mező vagy megjelenés (look) – amelyet egy stíluspreset felülírhat –, vagy tartalom (content), amelyhez egy preset soha nem nyúl hozzá. A színek, színátmenetek, betűtípusok, legördülő listák (select), választógombok (radio), számok, csúszkák és checkboxok a megjelenéshez tartoznak; minden más tartalom. A content: true megtart egy olyan megjelenés típusú értéket, amely valójában a kereskedő döntése, a content: false pedig a megjelenés részévé tesz egy tartalom típusú mezőt:

showReviews: field.checkbox({ label: 'Show reviews', default: true, content: true }),

Az src/settings.ts fájlban található globális beállítások ugyanezt a content kulcsot fogadják; lásd: Stíluspresetek.

Stílusfunkciók

A style felsorolja azokat a Stílus fülön megjelenő csoportokat, amelyeket egy elem kínál. Az inspector csak ezeket jeleníti meg, a témaellenőrzés és a témaszerkesztő pedig hibát jelez az ezeken kívül eső tárolt stílusok esetén.

FunkcióVezérlők
layoutelrendezés (display), irány (és fordított), törés (wrap), igazítás (justify, align), rés (gap), oszlopok, overflow
alignaz elem elhelyezkedése a siblingjei között: balra, középre vagy jobbra rendezés, nyújtás (grow), sorrend, rögzítés (sticky), z-index
spacingbelső és külső margók (padding és margin)
sizeszélesség (beleértve a törtrészeket, pl. 1/3), maximális szélesség, minimális magasság, képarány
mediahogyan illeszkedik az elem saját képe vagy videója a keretéhez, és annak fókuszpontja
typographyméret, vastagság, igazítás, transzformáció, betűköz, sormagasság, betűszerepkör, dőlt, díszítés, sorok száma (line clamp)
colorszövegszín (szerepkör vagy egyéni szín), hover szövegszín
backgroundháttérszín (szerepkör vagy egyéni) vagy színátmenet, lebegtetési kitöltés
bordervastagság és egyes oldalak, stílus, szín, lekerekítés és egyes sarkok, hover keretszín
effectsárnyék, áttetszőség, szűrők, háttérelmosás, hoverkor: árnyék, áttetszőség, kiemelés (lift), szűrők
background-mediaháttérkép és -videó eszközönként, illeszkedés, fókuszpont, rögzített görgetés, overlay
motionbelépési animáció, amely akkor indul el, amikor az elem a képernyőre görgődik
dividersalakzatos elválasztók (shape dividers) a szekció felső és alsó szélén
visibilityelrejtés asztali gépen, táblagépen vagy mobilon

Az értékek tokenek, soha nem pixelek. A színek szigorúan ellenőrzött egyéni színek is lehetnek. Bármely érték lehet reszponzív: { "base": "lg", "tablet": "md", "mobile": "sm" }, ahol a tablet 64rem alatt, a mobil pedig 48rem alatt érvényes. A tablet örökli a base értéket, a mobil pedig a tabletet. A base hiányában az asztali nézet megtartja az elem saját dizájnját, és csak a felülírt eszközök változnak.

Design tokenek

StílusútvonalTokenekCSS-változó
spacing.padding.*, layout.gapnone, 3xs, 2xs, xs, sm, md, lg, xl, 2xl, 3xl--pt-sp-*
spacing.margin.*a térközskála plusz auto--pt-sp-*
size.minHeighta térközskála plusz half-screen, screen--pt-sp-*, svh
size.widthauto, full, fit, vagy a parent törtrésze: 1/4, 1/3, 1/2, 2/3, 3/4nincs
size.aspectauto, 1:1, 4:3, 3:2, 16:9, 21:9, 3:4, 2:3, 4:5nincs
media.fit, media.positioncover, contain; top-left, top, top-right, left, center, right, bottom-left, bottom, bottom-rightnincs
size.maxWidthnarrow, prose, content, wide, full--pt-maxw-*
typography.sizexs, sm, body, lg, h4, h3, h2, h1, display (beállítja a hozzá tartozó sormagasságot)--pt-fs-*
typography.weightregular, medium, semibold, bold--pt-fw-*
typography.leadingtight, normal, relaxed (felülírja a mérethez társított sormagasságot)--pt-lh-*
typography.trackingtight, normal, wide--pt-tracking-*
typography.alignleft, center, right, justifynincs
typography.transformnone, uppercase, lowercase, capitalizenincs
typography.familyheading, body, accent (a téma betűszerepkörei)--pt-font-*
typography.style, typography.decorationnormal, italic; none, underline, line-throughnincs
typography.clampnone, vagy legfeljebb 1 és 4 sor közöttnincs
layout.displayblock, flex, gridnincs
layout.direction, layout.wraprow, column, row-reverse, column-reverse; wrap, nowrapnincs
layout.overflowvisible, hidden, clip, autonincs
layout.justifystart, center, end, between, aroundnincs
layout.alignstart, center, end, stretchnincs
layout.columnsegész számok 1 és 6 között (display: grid esetén)nincs
layout.selfleft, center, right (az align funkció)nincs
layout.grow, layout.orderfill, fit; first, 1–6, last (az align funkció)nincs
layout.position, layout.topstatic, relative, sticky; header (az alapértelmezett) vagy a térközskála--pt-sticky-header, --pt-sp-*
layout.zIndexbase, raised, overlay, top--pt-z-*
color.text, border.colorszínszerepkörök: foreground, muted-foreground, primary, primary-foreground, secondary, secondary-foreground, accent, accent-foreground, background, card, card-foreground, muted, border, destructive; vagy egyéni szín (lásd alább)--<role>
color.backgroundegy színszerepkör, egyéni szín, vagy linear-gradient(<0-999>deg, #hex <0-999>%, …) 2–8 hex színponttal--<role>
border.width, border.sides.*none, thin, medium, thick; a sides értékei: top, right, bottom, left--pt-border-*
border.stylesolid, dashed, dotted (a stílus nélküli vastagság folytonos vonalat rajzol)nincs
border.radius, border.corners.*none, sm, md, lg, pill; a corners értékei: topLeft, topRight, bottomRight, bottomLeft--pt-radius-*
effects.shadownone, sm, md, lg--pt-shadow-*
effects.opacityszázalék, 0 és 100 között 5-ös lépésközzelnincs
hover.text, .background, .borderColormegegyezik a color.text, color.background és border.color értékeivel--<role>
hover.shadow, .opacity, .liftmegegyezik az effects.shadow és effects.opacity értékeivel; lift: none, sm, md, lg--pt-lift-*
hover.transitionnone, fast, normal, slow (normal, ha be van állítva hover érték)--pt-duration-*
effects.blur, effects.backdropBlurnone, sm, md, lg, xl--pt-blur-*, --pt-backdrop-*
effects.brightness, .contrast, .saturateszázalék, 0 és 200 között 5-ös lépésközzel (100 a változatlan)nincs
effects.grayscaleszázalék, 0 és 100 között 5-ös lépésközzelnincs
hover.blur, .brightness, .contrast, .grayscale, .saturatemegegyezik az effects szűrőivel; mindegyik csak a saját szűrőjét cseréli lea fentiek szerint
background.image, background.videooldalon belüli útvonal (/media/…) vagy legfeljebb 512 URL-biztos karakterből álló http(s) URL, illetve none az adott eszközön való elhagyáshoznincs
background.posteregy cím a fentiek szerint; egyetlen érték minden eszközrenincs
background.fit, background.positionmegegyezik a media.fit és media.position értékeivelnincs
background.attachmentscroll, fixednincs
background.overlay, .overlayOpacityszínszerepkör vagy egyéni szín; százalék 5-ös lépésközzel (50, ha nincs megadva)--<role>
motion.entrancenone, fade, fade-up, fade-down, zoom, slide-left, slide-rightnincs
motion.duration, motion.delayfast, normal, slow; none, sm, md, lg--pt-enter-*, --pt-delay-*
motion.repeatonce, repeat; egyetlen érték minden eszközrenincs
dividers.top, dividers.bottompattern (egy érték): wave, curve, tilt, triangle, zigzag; height: none, sm, md, lg, xl; color: egy szín; flip: none, mirror--pt-divider-*
visibility.desktop, .tablet, .mobilea false érték csak az adott eszközön rejti el az elemetnincs

Az egyéni szín pontosan #rgb, #rrggbb, #rrggbbaa, rgb(r, g, b) vagy rgba(r, g, b, a) formátumú lehet (csatornák 0 és 255 között, alfa 0 és 1 között, legfeljebb egy opcionális szóköz az egyes vesszők után). A színnevek, a var(…), a hsl(…) és a szóközökkel körülvett stringek elutasításra kerülnek. Változatlanul kerül beírásra a CSS-be. A háttérszínnel rendelkező link vagy gomb root eleme a hoverhez is kap egy árnyalatot ebből a színből, a szövegszíne felé keverve, mivel az elem saját kitöltése felülírja a változat hover-színét.

Az Elhelyezés (layout.self, amelyet az align funkció biztosít) automatikus sorirányú külső margókkal (auto inline margins) mozgatja az elem saját dobozát, így ott is működik, ahol a typography.align nem: gombnál, visszaszámlálónál, árnál vagy korlátozott méretű képnél. Elhelyezi az elemet flex vagy grid parentben (minden platformkonténerben), és parent blockban minden olyan dobozban, amely keskenyebb nála. Az elhelyezett elem megtartja saját szélességét a nyújtás helyett; egy alapértelmezetten teljes szélességű elem elhelyezése akkor válik láthatóvá, ha a size.maxWidth korlátozza. A typography.align csak a dobozon belüli szöveget igazítja. Add meg az align funkciót minden olyan elemnek, amelyet a kereskedő szabadon elhelyezhet egy konténerben.

Törtrészek és sorrend. A size.width törtrésze a parent százalékos aránya; flex sorban a részek együtt zsugorodnak, hogy helyet adjanak a résnek (gap), így az 1/3 és a 2/3 egymás mellett helyezkedik el. A layout.grow: fill hatására a gyermekelem kitölti a sorában maradt helyet. A layout.order és a fordított irányok csak a vizuális sorrendet változtatják meg eszközönként: a „képernyőn kép jobbra, telefonon kép legfelül” beállítás: direction: { base: "row-reverse", mobile: "column" }.

A Rögzülő (layout.position: sticky) nézetben tartja az elemet a layout.top pozíciótól kezdve, alapértelmezetten a bolt fejléce alatt, és megakadályozza, hogy a sorához nyúljon, ami miatt nem tudna hova rögzülni. A layout.zIndex pozicionálja is az elemet, hogy érvényesüljön a rétegszintje. A header követi a fejlécet, ahogy az elrejtőzik, megjelenik vagy összemegy (lásd: A bolt fejléce).

Keretek. A border.width és a border.radius minden oldalt és sarkot beállít; a border.sides és a border.corners egyedi értékeket ír felül, így a felső szegély: { "sides": { "top": "thin" } }. Elválasztón (egy <hr> root elemen) a minden oldalra érvényes vastagság egyetlen vonalat rajzol, soha nem kettőt egymásra téve.

Képarány és média. A size.aspect határozza meg a doboz formáját. Az elem saját képe vagy videója – a root elem közvetlen gyermeke – kitölti a dobozt, amelyet a media.fit vág körbe (alapértelmezetten cover) a media.position fókuszpont körül.

Színséma. A színséma beállítás, nem pedig stílus: minden dobozt rajzoló szekció és blokk fogadja a settings.color_scheme értéket, amely a téma nevesített színsémáinak egyike (a color_schemes témabeállítás). A doboz és minden benne lévő elem a séma színeivel jelenik meg, így minden színszerepkört használó gyermekelem újrastílusozás nélkül olvasható marad rajta; ha üres, megtartja a parent sémáját. A kifejezetten megadott color.text vagy color.background felülírja a sémát.

Hover. A hover csoport tartalmazza mindazt, ami megváltozik, amikor a kurzor az elem felett van, billentyűzetfókuszt kap, vagy a témaszerkesztő előnézetet jelenít meg róla (data-pe-state="hover" a root elemen). Minden leaf elem a nyugalmi megfelelőjének képességével rendelkezik. A hover szín a színátmenetes kitöltést is felülírja, és a hover kitöltés nélküli színátmenet is saját árnyalatot kap. Az átmenetek sebességét a --pt-duration-* határozza meg, amelyet a rendszer nullára állít azoknál a vásárlóknál, akik csökkentett mozgást kértek.

Hátterek (background-media). A kép és a videó a tartalom mögött, a kitöltési szín vagy színátmenet felett helyezkedik el, mindkettő felett pedig egy fedőszín található. Minden eszköznek lehet saját képe vagy videója, vagy none; csak az töltődik be, amelyik megjelenik az adott eszközön. A fixed rögzítve tartja a képet, miközben az oldal elgördül felette, kivéve azoknál a vásárlóknál, akik csökkentett mozgást kértek. A videó némított és ismétlődik, csak akkor töltődik be, amikor a nézőtérhez közeledik, csak addig játszódik le, amíg a képernyőn van, és csökkentett mozgás esetén megáll az első képkockáján vagy a poster képnél. A fedőszín a dobozon belül oldódik fel, így a szerepkör követi a színsémát: egy sötét séma background overlay-jel a séma alapjával színezi a képet, és világossá teszi a szöveget. A címek csak a DOM-attribútumokba jutnak el, a CSS-be soha. A platform Konténer, Oszlop és Egyéni szekciója kirajzolja; a background-media képességet deklaráló témaelem pedig a @poltura/theme-sdk/elements csomagból származó <ElementBackground /> komponenst rendereli a root elem első childjaként.

Szűrők (effects). A fényerő, a kontraszt, a szürkeárnyalat, a telítettség és az elmosás rögzített sorrendben érvényesül az elem saját képpontjaira; a backdropBlur homályossá teszi azt, ami átlátszik az áttetsző kitöltésen keresztül (üveg hatású panelekhez). A hover szűrő csak a saját funkcióját váltja fel, és a hover átmenettel animálódik, így egy szürkeárnyalatos logófal hoverkor színessé válhat.

Belépők (motion). A belépő animációval rendelkező elem a szerveroldali jelölésben a data-pe-motion attribútumot hordozza, és semmi olyat, ami elrejtené. Amint a JavaScript lefut, a webáruház az első képkockán tartja, és elindítja a presetet, amikor az egyhatoda láthatóvá válik: once, vagy minden alkalommal, amikor újra láthatóvá válik. JavaScript nélkül semmi sem rejtőzik el, és semmi sem mozog a csökkentett mozgást kérő vásárlók számára. A none egy eszközön kikapcsolja a belépést. A témaszerkesztő a Motion csoportból játssza újra a belépést.

Alakzatos elválasztók (dividers). Beépített, inline SVG a szekció felső vagy alsó szélén, a kisegítő technológiák elől elrejtve, alapértelmezetten az oldal háttérszínével, így a sáv vágottnak tűnik. A minta eszközönként egyetlen érték; állítsd a magasságot none értékre az adott eszközön történő elhagyáshoz. Az Egyéni szekció kirajzolja őket; a dividers funkciót deklaráló témaszekció pedig a @poltura/theme-sdk/elements csomagból származó <ElementDividers /> komponenst rendereli a root elemén belül.

Bármi más (pixelérték, ismeretlen kulcs, url(…), tetszőleges CSS string) figyelmen kívül marad, mielőtt elérné a CSS-t, és a témaszerkesztő, a témaellenőrzés és a kódszerkesztő a JSON-útvonalával együtt jelzi, így egy kézzel szerkesztett elrendezési fájl soha nem fecskendezhet be CSS-t.

{
  "id": "q1",
  "type": "wall-quote",
  "settings": { "quote": "Fast delivery." },
  "settings_i18n": { "hu": { "quote": "Gyors szállítás." } },
  "style": {
    "typography": { "size": "h3" },
    "spacing": { "padding": { "top": { "base": "md", "mobile": "sm" } } }
  }
}

A tokenek semleges CSS-változókra képződnek le (--pt-sp-*, --pt-fs-*, --pt-lh-*, --pt-fw-*, --pt-radius-*, --pt-shadow-*, --pt-maxw-*, --pt-gutter, --pt-font-*, --pt-z-*, --pt-lift-*, --pt-duration-*, --pt-sticky-header, --pt-blur-*, --pt-backdrop-*, --pt-enter-*, --pt-delay-*, --pt-divider-*, --pt-page-background), a színszerepkörök pedig a téma --primary, --foreground és egyéb változóira. A platform biztosítja az alapértelmezett értékeket. Képezd le a semleges réteget a saját skáládra az src/styles/tokens.css fájlban, hogy a kereskedő választásai natívnak hassanak:

src/styles/tokens.css (excerpt)
:where(:root) {
  --pt-sp-md: var(--my-space-4);
  --pt-fs-h1: var(--my-font-h1);
  --pt-radius-md: var(--my-radius);
  --pt-font-heading: var(--my-display-font);
  --pt-font-body: var(--my-text-font);
  --pt-font-accent: var(--my-accent-font);
  --pt-maxw-content: var(--my-container);
  --pt-gutter: var(--my-gutter);
}

A --pt-maxw-content és a --pt-gutter felel meg a .theme-container class-odnak: a border-box maximális szélességének és az oldalsó paddingjének. Egy dobozos Egyéni szekció pontosan ezzel a párossal húzza be a tartalmát, ezért képezd le mindkettőt a konténered által használt értékekre, különben a kereskedői szekciók nem fognak egy vonalba esni a tieiddel.

A webáruház rendereléskor minden szekció stílusát egyetlen, [data-pe="<id>"] scoped <style> szabálykészletbe fordítja, ezért kötelező a deklarált szekció rootjának hordoznia az attrs értéket.

Honnan veszik a stílusukat a platformelemek?

  • Grid-natív elemek. Az Oszlopok, a Termékrács és a Gyűjteménylista saját rácsot jelenítenek meg (layout_default: 'grid' a sémájukban). Az irány vagy a törés soha nem alakítja őket flexxé; csak a kifejezett layout.display teszi ezt meg. A saját breakpoint oszlopaik megmaradnak, amíg egy eszköz nem kap saját layout.columns értéket: az asztali darabszám megmarad az asztali nézetben, a telefon pedig a táblagép darabszámát követi.
  • A belső részek öröklik. A betűvastagság, a szín, a kis-/nagybetűs írásmód és a betűköz – ahol az elem felkínálja őket – átadódik az akciós árnak, a visszaszámláló számainak és címkéinek, a fülcímkéknek, a harmonika törzsének és a listaikonoknak.
  • Szövegszín dobozon. A Konténer, az Oszlop és az Egyéni szekció esetében a szövegszín beállítja a dobozon belüli --foreground szerepkört és a lágyabb --muted-foreground értéket is, így a benne lévő címsorok és szövegek követik azt; a színséma pedig a doboz egészét átszínezi.
  • A Kosárba gomb mindig saját dobozban helyezkedik el (data-pe-group), amely az opcióválasztóit tartalmazza: a térköz és a méret ezt a dobozt stílusozza, a kitöltés és a keret pedig a gombot.
  • Konténerlink. A linkkel ellátott konténer egésze kattintható a doboz feletti valódi hivatkozáson keresztül, elérhető a Tab billentyűvel, a nevét pedig a benne lévő első címsorról, gombról vagy képről kapja.
  • Egyéni szekció. A minimális magasság, a tartalom elhelyezkedése és a háttérkép a Stílus fülről érkezik (size.minHeight, layout.justify, background). A dobozos tartalom a témakonténerre illeszkedik (--pt-maxw-content, --pt-gutter), a széles a --pt-maxw-wide értékre ugyanazzal az oldaltávolsággal, az oldalsó padding pedig hozzáadódik ehhez a távolsághoz. A teljes szélesség a háttereket a szélekig futtatja, és megtartja a téma oldaltávolságát a tartalom számára, amíg az oldalsó padding felül nem írja a behúzást: a none a tartalmat a szélekig futtatja.

Gyermekelemek: Slot és helyettesítő karakterek

A parent soha nem maga rajzolja ki a childot. A name nélküli <Slot /> azokat a gyermekelemeket rendereli, amelyeket a kereskedők az aktuális elem alapértelmezett régiójába helyeztek, az elmentett sorrendben, mindegyiket a saját komponensén és keretén keresztül, egyetlen className attribútumot hordozó burkoló div-ben. A <Slot name='media' /> ugyanezt teszi egy deklarált slottal. Az as határozza meg a régió címkéjét (div, ul, ol, nav, vagy none, ha nincs szükség dobozra); az as='ul' vagy as='ol' formában megjelenített régió csak olyan blokkokat fogad el, amelyek frame értéke li. Az üres régió semmit sem renderel és nem foglal helyet sem az éles oldalon, sem a témaszerkesztőben: a témaszerkesztő a behúzási célterületét az oldal fölé rajzolja ki a slot label címkéjével ellátva. A @poltura/theme-sdk/elements csomagból származó useChildBlocks('media') visszaadja a régió megjelenített gyermekeit (id, type és a beállítások a vásárló nyelvén) darabszámokhoz, fülekhez és elrendezési döntésekhez; rajzold ki őket a Slot segítségével.

A blocks.static fejlesztői azonosítókkal ellátott fix gyermekelemeket deklarál. Ez a definíciórészlet hármat deklarál:

blocks: {
  accepts: [ELEMENT_WILDCARD],
  static: [
    { id: 'title', type: 'heading', slot: 'details' },
    { id: 'buy', type: 'add-to-cart', slot: 'details', required: true },
    { id: 'summary', type: 'text' },
  ],
},

A kereskedők elrejthetik és újrastílusozhatják a statikus elemeket, de nem mozgathatják vagy törölhetik őket; a required elemek nem is rejthetők el. A slot értékkel rendelkező statikus elem abban a régióban renderelődik a kereskedő blokkjai között; amelyik nem rendelkezik ilyennel, az az alapértelmezett régióban jelenik meg a <Slot /> által kirajzolva.

Két helyettesítő karakter használható az accepts mezőben:

  • ELEMENT_WILDCARD ('@element'): minden elem, amelyet bármely aktív szolgáltató kínál. Ez magában foglalja a platformelemeket (konténer, címsor, szöveg, gomb, kép, termékkártya…), valamint minden olyan plugint, appot vagy témablokkot, amely kirajzolja magát.
  • THEME_BLOCK_WILDCARD ('@theme'): az összes szolgáltató eleme a platform kivételével, vagyis a plugin-, app- és témablokkok.

A szekció saját nevesített gyermekelemei mindig először a szekció saját blokklistájában oldódnak fel, így egy olyan témablokk, amelynek kulcsa megegyezik egy platformszekció childjának kulcsával (stat, quote, item), soha nem módosítja az adott platformszekciót.

Slotok és az általuk elfogadott elemek

Egy slot szűkítheti az általa fogadott elemek körét a saját accepts mezőjével, amely az elem blocks.accepts mezőjének részhalmaza. Ez a szekció az ELEMENT_WILDCARD, Slot és defineSection elemeket importálja a @poltura/theme-sdk/elements csomagból, a cn függvényt pedig a @poltura/theme-sdk/ui csomagból:

export const promoSplit = defineSection({
  type: 'promo-split',
  label: 'Promo split',
  icon: 'columns',
  category: 'marketing',
  settings: {},
  blocks: { accepts: [ELEMENT_WILDCARD], max: 12 },
  slots: [
    { name: 'media', label: 'Media', accepts: ['image', 'video'] },
    { name: 'body', label: 'Text and buttons' },
  ],
  component: ({ attrs }) => (
    <section {...attrs} className={cn(attrs.className, 'grid gap-8 md:grid-cols-2')}>
      <Slot name='media' />
      <Slot name='body' />
    </section>
  ),
});

Minden gyermekelem rögzíti a régióját a "slot": "media" mezőben az elrendezési fájlban. Az accepts nélküli slot mindent elfogad, amit az eleme elfogad. A választó, a navigátor drag and drop funkciója, a mentési érvényesítés, az AI-asszisztens és a kódszerkesztő JSON Schema-ja mind ugyanazt a szabályt alkalmazza, a témaellenőrzés pedig hibát jelez az olyan deklarált slot esetén, amelyet a komponens soha nem renderel.

Inline szöveg: EditableText

Az <EditableText setting='heading' as='h2' /> az aktuális elem egy egyszerű text vagy textarea beállítását jeleníti meg a vásárló nyelvén, és lehetővé teszi a kereskedők számára, hogy a vásznon írják át. A témaszerkesztőn kívül pontosan <h2>text</h2> formában jelenik meg, üres szöveg esetén pedig semmi sem renderelődik.

Az <EditableRichText setting='body' className='flex flex-col gap-3' /> ugyanezt teszi a richtext beállításnál: dupla kattintással megnyílik a formázásával együtt, a Cmd/Ctrl+B és a Cmd/Ctrl+I váltja a félkövér és dőlt stílust, az Enter új bekezdést indít, a Cmd/Ctrl+Enter vagy egy kattintás máshova pedig elmenti. Az Escape billentyű elveti a módosítást.

Kereskedelmi elemek

Hat platformelem jelenít meg élő katalógusadatokat mindenhol, ahol az elrendezés elemeket fogad el:

ElemTípuskulcsMit mutat
Termékkártyaproduct-cardegy termék: kép, név, ár, opcionális jelvény és kosárba gomb
Termékrácsproduct-grid2–24 termék egy gyűjteményből, kategóriából vagy kézi kiválasztásból
Árpricea termék ára, akció esetén az eredeti árral
Kosárbaadd-to-cartgomb a termék opcióival (méret, szín…)
Gyűjteménylistacollection-list2–24 csempe, amely gyűjteményekre vagy egy kategória alkategóriáira mutat
Visszaszámlálócountdownnapok, órák, percek és másodpercek az end_at időpontig (datetime beállítás)

A price és az add-to-cart üres product értékkel annak a termékoldalnak a termékét használja, amelyen elhelyezkedik. A beállítások azonosítókat tartalmaznak, soha nem a katalógusadatok másolatait, így a nevek, az árak és a készlet mindig naprakészek, a vásárló nyelvén és pénznemében jelennek meg.

A webáruház összegyűjti azokat a katalógusadatokat, amelyekre az oldalon lévő összes kereskedelmi elemnek szüksége van (beleértve a sablonokat, az oldalakat, a fejlécet és a láblécet, valamint a megamenü paneleit), és egyetlen batch kérésben tölti be őket a szerveroldali renderelés során, így az elemek az első kirajzoláskor (first paint) teljesen megjelennek minden útvonalon. A témaszerkesztőben a hozzáadott elem egyetlen követő kéréssel tölti be az adatait. Az üresen hagyott címkék (kosárba helyezés szövegezése, visszaszámláló mértékegységei) a platform szövegezését használják a bolt minden nyelvén. A kitöltött címkék kereskedői szövegek, és a többihez hasonlóan fordíthatók.

Bolti data bindingok

A text, textarea, richtext, image, url vagy link beállítások a saját érték tárolása helyett élő bolti adatokat is beolvashatnak. A kereskedők az inspectorban a mezőcímke melletti adatbázis gombbal bindelhetnek be egyet. Az elrendezési fájlban a beállítás egy binding objektumot tárol:

{
  "id": "b_12",
  "type": "heading",
  "settings": {
    "text": {
      "$bind": { "source": "product", "id": "organic-tee", "field": "title", "fallback": "Our tee" }
    }
  }
}
ForrásMezők
producttitle, subtitle, description, price, compare_at_price, vendor, image, url
collectiontitle, url
categorytitle, description, url
storename, tagline
customerfirst_name
  • Az id a termék, gyűjtemény vagy kategória handle-je, ahogyan azt a termékválasztók tárolják. Hagyd el, ha azt szeretnéd beolvasni, amiről az oldal szól: egy termékoldal termékét, egy kategóriaoldal kategóriáját, vagy azt a gyűjteményt, amely szerint a lista szűr. A témaszerkesztőben a terméket nem tartalmazó sablonon lévő product binding egy mintaterméket jelenít meg.
  • A field mezőnek illeszkednie kell a beállításhoz: a szöveges beállítások szöveges mezőket (és a description mezőt) fogadnak, az image beállítások az image-et, az url és link beállítások pedig az url-t. A mentési érvényesítés elutasít minden mást, és az elrendezés JSON Schema-ja csak a megfelelő mezőket kínálja fel.
  • A fallback (legfeljebb 500 karakter) akkor jelenik meg, ha a boltban nincs érték: törölt vagy ismeretlen termék, alcím nélküli termék, vagy vendég vásárló a customer esetén. Fallback érték nélkül a beállítás saját alapértelmezett értéke érvényesül.

A kötött értékek a szerveren oldódnak fel a renderelés során, ugyanazon a kötegelt kérésen keresztül, mint a kereskedelmi elemek, így az első kirajzoláskor már láthatók, és az oldal soha nem indít kötésenként külön kérést. Az árak a vásárló pénznemében formázódnak. A címek és leírások a vásárló nyelvén érkeznek a bolt katalógusfordításaiból. A kötött beállítás soha nem kerül gépi fordításra, és nem tartalmaz settings_i18n bejegyzést: egy mező bekötése törli a fordításait.

A leírások bolti szövegek, gyakran importálásból származó HTML-ek. Soha nem kerülnek az oldalra formázott jelölésként: a richtext beállítás a rich text szabályrendszer szerint olvassa be őket (bekezdések, címsorok, listák, félkövér, dőlt, biztonságos linkek), minden más szöveges beállítás pedig egyszerű szövegként olvassa őket.

Az elemkomponensek a feloldott értéket a settings propban kapják meg, mint bármely más beállítást. Az EditableText kihagyja a bindelt beállítást a vásznon történő közvetlen szerkesztésből.

Alapnyelv

Minden elrendezési fájl alap settings értékei a bolt alapértelmezett nyelvét tartalmazzák, amelyet a settings/values.json fájlban a base_locale határoz meg. Minden más nyelv egy override (overlay) a settings_i18n[<locale>] alatt, amely csak az eltérő mezőket tartalmazza. A téma alapértelmezett szövegét azon a nyelven írd meg, amelyen kiadod, és a base_locale értékét a tiszta nyelvkódra állítsd ("hu", nem "hu-HU"); az e nélküli témát a rendszer angolnak tekinti.

  • A vásznon és az inspectorban végzett közvetlen szerkesztés az alapbeállításokat az alapnyelven írja, az override-ot pedig a kiválasztott egyéb nyelven.
  • Ha a bolt alapértelmezett nyelve eltér a téma alapnyelvétől, a témaszerkesztő felajánlja az rebase-t: az adott nyelv override-jai válnak az alappá, a régi alap override-dá válik, és a fordítási ujjlenyomatok követik ezt, így semmi sem vész el és nem kerül újrafordításra.
  • A boltba bekerülő téma (telepítés, induló sablon betöltése, visszaállítás) csak akkor alapozódik újra automatikusan, ha a bolt nyelve már tartalmazza az összes szöveget; ellenkező esetben a kiadott állapotában marad.

Feltételek és horgonyok

Minden szekció és elem tartalmazhat egy opcionális conditions kulcsot a settings és a style mellett, amely a Haladó fülön, a Láthatóság alatt szerkeszthető:

{
  "id": "b_07",
  "type": "button",
  "settings": { "label": "Sign in for 10% off", "anchor": "member-offer" },
  "conditions": {
    "audience": "guests",
    "from": "2026-11-27T00:00:00+01:00",
    "until": "2026-12-01T00:00:00+01:00"
  }
}
  • audience: guests (be nem jelentkezett vásárlók) vagy customers (bejelentkezett vásárlók). Az all az alapértelmezett, és soha nem kerül tárolásra.
  • from / until: datetime értékek a bolt órája szerint. A from az első pillanat, amikor az elem megjelenik, az until pedig az első pillanat, amikor már nem látható. A puszta dátum az adott nap kezdetének éjfélét jelenti a bolt időzónájában.
  • settings.anchor: az elem oldalon belüli hivatkozási célpontja. Az ugyanazon az oldalon lévő #member-offer link odagörget hozzá. Kisbetűs a-z, 0-9, - és _, egyedi az elrendezési fájlon belül; soha nem fordítható. Bármely elem beállíthatja anélkül, hogy anchor mezőt kellene deklarálnia.

A webáruház a szerveren értékeli ki a feltételeket. A másik célközönségnek szánt vagy az időzítésen kívül eső elem kimarad a renderelt HTML-ből és a benne szerializált oldaldatokból, így a csak vásárlóknak szóló kód soha nem jut el a vendégekhez. Az elemkomponensek soha nem látják a feltételeket: a block- és section renderer-ek kezelik őket, és a horgonyt id-ként helyezik el az elem gyökerén (az attrs segítségével, ezért fontos a spread).

A témaszerkesztő vászna követi az Előnézet mint beállítást: a másik célközönség pontosan úgy marad ki, mint a webáruházban. Az időzítésükön kívül eső elemek a vásznon sávozott felülettel és „Most rejtve: időzítve” jelvénnyel maradnak meg, a navigátorsorukban pedig egy óra jelenik meg.

A feltételek minden kérésnél kiértékelődnek, így az oldal soha nem jelenít meg lejárt promóciót, és nem rejt el már elindultat sem. A megnyitott oldal a rajta lévő bármely elem következő from vagy until időpontjában újratölti az adatait.

A mentési érvényesítés elutasítja az ismeretlen feltételkulcsokat, az ismeretlen célközönséget, a hibás formátumú dátumot és a hibás vagy ismétlődő horgonyt. A from előtti until megengedett: az ilyen elem soha nem jelenik meg, és a szerkesztő ezt jelzi is.

Korlátok

A mentési érvényesítés ugyanazokat a korlátokat kényszeríti ki a témaszerkesztőben, a kódszerkesztőben, az AI-asszisztensben és közzétételkor, a kódszerkesztő JSON Schema-ja pedig gépelés közben jelzi őket:

Korlát (limit a hibában)Maximum elrendezési fájlonként
elements1 000 szekció és beágyazott blokk összesen
sections40 szekció
children24 gyermekelem szekciónként vagy konténerenként (a séma blocks.max értéke csak csökkentheti)
depth8 blokkszint egy szekció alatt, mind a témaszerkesztőben, mind a témaellenőrzésben
style_size12 KiB szerializált style elemenként (minden levél minden eszközön, a leghosszabb hét háttércímmel körülbelül 10,3 KiB)
string_length20 000 karakter stringenként a settings vagy settings_i18n mezőkben
file_size1 MiB szerializált JSON

A korlátot túllépő mentést a rendszer egészében elutasítja egy layout_limit_exceeded hibával, amely megnevezi a korlátot, a maximumot és a tényleges értéket. A témaszerkesztő ezt a saját nyelvén magyarázza el a kereskedőnek, és már a művelet előtt visszautasítja a beszúrást, a beillesztést vagy a duplikálást, ha az túllépné a korlátot.

A bolt fejléce

A promóciós sáv és a fejléc egyetlen közös dobozon, a [data-theme-chrome="header"] elemen belül jelenik meg, amelynek görgetési viselkedését a header section saját beállításai határozzák meg a layout/header.json fájlban. A webáruház ezt minden témánál futtatja. A téma csak az állapotokat stílusozza. A beállítások a következők:

BeállításÉrtékek
behaviorsticky (az alapértelmezett), reveal (lefelé görgetve eltűnik, felfelé visszatér), static
pinall (az alapértelmezett) vagy last_row: csak az utolsó sáv marad a képernyőn; csak sticky és reveal esetén
shrinka true érték összecsukja a rögzített fejlécet az oldal görgetésekor; csak sticky és reveal esetén
transparentoff (az alapértelmezett), home, all: átlátszó az első szekció felett
mobile_fromtablet (az alapértelmezett), mobile vagy desktop: ettől a mérettől lefelé a menügomb váltja fel a menüsávot
drawer_sideleft (az alapértelmezett) vagy right: az oldal, amelyről a mobilmenü kinyílik
drawer_widthsm, md (az alapértelmezett) vagy full: a mobilmenü szélessége

A beállítások minden nyelven közösek. A beállítás nélküli header section az alapértelmezett értéket kapja, az ismeretlen érték pedig mezőnként esik vissza az alapértelmezettre. Az átlátszó és a görgetett színek a header section stílusállapotai a Stílus fülön, nem pedig beállítások.

A doboz attribútumként hordozza az állapotot. A szerver rendereli a data-header-behavior, data-header-pin, data-header-overlay (átlátszó ezen az oldalon) és data-header-shrink attribútumokat. A runtime hozzáadja a data-header-scrolled (meghaladta a fejléc magasságát), data-header-hidden (reveal lefelé görgetés közben) és data-header-shrunk értékeket. A header section rootja a data-header-mobile-from attribútumot hordozza.

  • Nincs elrendezési elcsúszás (layout shift). Az átfedő fejléc az első bájttól kezdve kikerül a document flow-ból, így semmi sem mozdul el az oldal görgetésekor. Az összecsukódó fejléc pontosan --pt-header-shrink-by értéket veszít, amelyet a platform a doboz alsó margójaként ad vissza ugyanabban az átmenetben. Az összecsukódást alkalmazó téma ezt a hosszt a :root elemen deklarálja, és ezzel csökkenti egy sor magasságát: :where([data-header-shrunk]) .my-row { height: calc(var(--my-row-h) - var(--pt-header-shrink-by)); }. Deklaráció nélkül csak a logó méreteződik át.
  • A fejléc alatt. Az átfedő fejléc elfedné az oldal tetejét, ezért az oldaltörzs alatta kezdődik: a platform nyugalmi állapotban a fejléc magasságával tolja le (a promóciós sávval együtt), ami soha nem változik, miközben a fejléc elrejtőzik vagy összecsukódik. Az a teljes szélességű szekció, amelynek az átlátszó fejléc alatt kell elhelyezkednie, ezt a gyökerén lévő data-header-underlay attribútummal jelzi; amikor ez nyitja az oldalt, a letolás megszűnik, és a szekció a saját tartalmát tolja le a --pt-header-underlay értékkel (mindenhol máshol 0px): padding-top: calc(4rem + var(--pt-header-underlay, 0px)).
  • Eltolás (Offset). A --pt-header-height a rögzített fejléc tényleges magassága: a téma --sticky-top értéke nyugalmi állapotban, csökkentve az összenyomódással, rejtett vagy statikus állapotban pedig 0px. A --pt-sticky-header (a layout.top: header eltolás) és a --sticky-top követi ezt, így a rögzülő elemek közvetlenül a fejléc alatt helyezkednek el annak mozgása közben.
  • Átlátszó. Átlátszó állapotban a fejlécsáv --background és --border értéke transparent, a --foreground és a --muted-foreground pedig a sötét séma értékeit olvassa be (--pt-header-overlay-fg, --pt-header-overlay-muted), amíg az átfedési stílusállapot át nem színezi őket. Az egyéb szerepkört színező fejléc (egy --card sáv, egy saját színű tömb) törli azt a :where([data-header-overlay]:not([data-header-scrolled]):not(:focus-within)) szabály alatt. A lebegtetés és a billentyűzetfókusz tömörré teszi, így a nyitott menük és a kereső soha nem látszanak átlátszó alapon.
  • Billentyűzet. Az elrejtett fejléc a tab orderben marad, és visszatér, ha bármely eleme fókuszt kap, így a fókusz soha nem kerül alá.
  • Keresés. A field formában megjelenített search blokk a mező alá rögzített előugró ablakban ([data-search-results]) nyitja meg a javaslatait és találatait, így a fejléc megtartja a magasságát a vásárló gépelése közben; az icon egy ilyen előugró ablakban nyitja meg a mezőt, az overlay pedig egy modalban. A nyílbillentyűkkel lépkedhetsz a lehetőségek között, az Enter megnyitja a kiválasztottat, az Escape vagy a kívülre kattintás pedig bezárja az ablakot.
  • Mozgás. Az átmenetek a --pt-header-duration (--pt-duration-normal) időtartammal futnak, ami nulla azoknál a vásárlóknál, akik csökkentett mozgást kértek.

Az a fejléc, amelynek felső sorainak el kell gördülniük, a header section pin értékét last_row-ra állítja: a doboz ekkor felemelkedik az utolsó sáv feletti sorok magasságával (a promóciós sávval együtt), amit a runtime a --pt-header-pin-offset változóba mér be, és csak az az utolsó sor marad a képernyőn. Az Editorial így rögzíti az élőfejét, a Pop pedig azt a sort rögzíti, amely a lebegő gombját hordozza. A Launch a mobile_from értéket desktop-ra állítja, ami minden képernyőméreten a gomb mögött tartja a menüt.

Platformelemek restyle-olása

Ha meg szeretnéd tartani egy platformszekció vagy -blokk beállításait, és csak a jelölését módosítanád, írd felül a rendererjét egy olyan fájlban, amelynek a neve megegyezik a típusával:

Itt a CatalogHero a saját témád egyik komponense:

src/sections/hero.tsx
import { overrideSection } from '@poltura/theme-sdk/elements';
import { CatalogHero } from '../components/catalog-hero';

export const hero = overrideSection('hero', CatalogHero);
src/blocks/contact-hero.tsx
import {
  overrideBlock,
  type ElementRenderProps,
  type PlatformBlockSettings,
} from '@poltura/theme-sdk/elements';

function ContactHero({ settings }: ElementRenderProps<PlatformBlockSettings<'contact-hero'>>) {
  return <h1 className='text-5xl font-semibold'>{settings.heading}</h1>;
}

export const contactHero = overrideBlock('contact-hero', ContactHero);

A komponens megkapja a { settings, attrs, id } objektumot. A platform megtartja a sémát, az inspectort és az adatokat, és maga rajzolja meg a felülírt elem keretét, így az attrs üres az override-ban, és a renderer semmit sem ad át spreadként. A beállítások a tárolt formában érkeznek, a platform közzétett schema-jából tipizálva (ElementRenderProps<PlatformSectionSettings<'hero'>>, PlatformBlockSettings<'faq-item'>), ezért az opcionális mezőknek adj meg alapértelmezett értéket. Ha a beállításokat is módosítani szeretnéd, használd a defineSection függvényt ugyanezzel a típuskulccsal.

A pénztár kivétel: a Poltura önállóan rajzolja ki. Ott semmilyen témaszekció, blokk vagy elem nem renderelődik. A fejléc sora és az összegző oszlopa csak a checkout blockokat fogadja el (logó, megbízhatósági jelvény, breadcrumb, megjegyzés), valamint a platform címsorát, szövegét, képét, ikonját, elválasztóját, térközét és fizetési ikonjait, és a téma client code-ja sem töltődik be rajta. A téma stylesheetje és tokenjei továbbra is érvényesülnek, így a téma CSS-sel, a platformjelölés data-checkout hookjain keresztül stílusozhatja a pénztárat.

A GYIK, a vélemények, a logólista, a statisztikák és a lépések szekciók blokkként jelenítik meg a soraikat, így a téma külön stílusozhatja a szekció keretét és az egyes sorokat: írd felül a szekciót a címsor és a <Slot /> kirajzolásához, a row type-ot pedig az overrideBlock segítségével. A row type-ok: faq-item, quote, partner-logo, stat és step.

src/sections/faq.tsx
import {
  EditableRichText,
  Slot,
  overrideBlock,
  overrideSection,
  type ElementRenderProps,
  type PlatformBlockSettings,
  type PlatformSectionSettings,
} from '@poltura/theme-sdk/elements';

function Faq({ settings }: ElementRenderProps<PlatformSectionSettings<'faq'>>) {
  return (
    <section className='theme-container py-16'>
      <h2>{settings.heading ?? ''}</h2>
      <Slot className='divide-y' />
    </section>
  );
}

function Question({ settings }: ElementRenderProps<PlatformBlockSettings<'faq-item'>>) {
  return (
    <details open={settings.open_by_default ?? false}>
      <summary>{settings.question ?? ''}</summary>
      <EditableRichText setting='answer' />
    </details>
  );
}

export const faq = overrideSection('faq', Faq);
export const faqItem = overrideBlock('faq-item', Question);

Minden platformszekció saját rendererje a @poltura/theme-sdk/sections csomagból származik (BentoSection, FaqSection, HeroSection, TestimonialsSection és a többi), így az override becsomagolhatja vagy delegálhatja a feladatot, és a platformjavítások továbbra is eljutnak a témához. A product blockok ugyanezt teszik a @poltura/theme-sdk/product részeivel: a variant-picker felülírása a VariantPicker komponenst rajzolja ki a classes propjaival, a product-reviews felülírása pedig a Reviews komponenst a className és listClassName értékekkel.

src/sections/bento.tsx
import { overrideSection } from '@poltura/theme-sdk/elements';
import { BentoSection } from '@poltura/theme-sdk/sections';

export const bento = overrideSection('bento', (props) => (
  <div className='theme-frame'>
    <BentoSection {...props} />
  </div>
));

A bento maga rajzolja meg a rácsát és az opcionális legnépszerűbb termékek sávját; a csempéi a kereskedő elemei a régiójában, alapértelmezés szerint képek, product cardok és link cardok rácsa.

Regisztráció

Minden olyan elem, amely az src/sections/ vagy src/blocks/ alatti fájlból kerül exportálásra, közvetlenül vagy újraexportálva regisztrálja magát. Nincs külön regisztrációs fájl: a fordító ezekből az exportokból építi fel a téma elemeinek listáját, a webáruház pedig ebből rajzol.

  • Fájlonként egy elem, és a fájlnév a típusa: az src/sections/quote-wall.tsx a quoteWall elemet exportálja, az src/blocks/product-title.tsx a productTitle elemet. Az exportot a típus után camelCase formátumban nevezd el.
  • Azok a blokkok, amelyek csak egyetlen szekción belül léteznek (a fenti wall-quote, a megamenü menuColumn és promoCard elemei), az adott szekció fájljában maradnak, és onnan kerülnek exportálásra. Az a blokk, amelyet egy másik szekció is elfogad, saját fájlt kap az src/blocks alatt.
  • Azok a segédfüggvények, amelyek nem elemek, az src/components vagy az src/lib mappába tartoznak.

A fordító és a kódszerkesztő a következőket jelzi problémaként:

ProblémaSúlyosság
Két elem ugyanazt a típust regisztráljahiba
A fájlnév nem egyezik a típussalhiba
Egy blokk megosztja a szekciója fájlját, de egy másik szekció is elfogadjahiba
Egy defineSection, defineBlock vagy felülírás nincs exportálva, vagy az src/sections és src/blocks mappán kívül találhatóhiba
A definíció be van csomagolva (w(defineSection(...))), vagy namespace-en keresztül hívják meg (E.defineSection(...))hiba
Az override olyan típust nevez meg, amelyet egyetlen szolgáltató sem definiálfigyelmeztetés

A témabejegyzések elfedik az azonos kulcsú platform-, plugin- és appbejegyzéseket.

Elemszolgáltatók

A téma a négy elemszolgáltató egyike. A másik három a platform, a Poltura alapvető extensionjei és a telepített appok. Mindegyikre ugyanazok a szabályok vonatkoznak:

  • Definíció: minden szolgáltató ugyanazokat a defineSection és defineBlock objektumokat és ugyanazokat a field.* buildereket használja.
  • Kinyerés: ugyanaz a statikus olvasó olvassa az összes szolgáltatót. Egyik szolgáltató kódja sem fut le.
  • Katalógus: a platform a szolgáltatókat egyetlen katalógusba vonja össze, és minden ezt olvassa: a témaszerkesztő, a mentési és közzétételi ellenőrzések, a fordítás, a kódszerkesztő elrendezési JSON Schema-ja és a webáruház.

Minden elem hordozza a provider értékét ({ kind, id }). A választó ez alapján csoportosít: Ez a téma a témaelemeknél, Appok az appelemeknél, a platform- és pluginelemeknél pedig kategória szerint.

SzolgáltatóHol van definiálvaTípuskulcsokFeltétele
platform@poltura/theme-elements primitive-ek, platform sectionöktiszta, fenntartottsoha
pluginegy Poltura alap-extensiontiszta; egyedi a platformon és az összes pluginon belüla plugin saját be- és kikapcsolója
appaz app forráskódjaapp:<id>/<name>; a nyilvános appok telepítésenként kapnak kulcsottelepítve és engedélyezve
témaa téma TSX kódjatisztasoha

Az elsőbbségi sorrend: platform, majd plugin, majd app, majd téma:

  • A téma újradefiniálhat egy platform- vagy plugintípust. A sémája ekkor felülírja az övékét.
  • A téma egy apptípust csak restyle-olhat az overrideBlock / overrideSection segítségével.
  • Bármilyen más ütközés hibát eredményez, és az első definíció marad érvényben.

Ha egy feltételhez kötött szolgáltató ki van kapcsolva, az elemei eltűnnek a választóból és minden accepts listából, és semmit sem renderelnek az éles oldalon. Az őket használó mentett elrendezések továbbra is átmennek az ellenőrzésen, így a szolgáltató visszakapcsolása minden elhelyezést visszaállít. A témaszerkesztő és a webáruház ugyanazt a be- és kikapcsolt állapotot olvassa be a boltból.

Ellenőrzések

A témaellenőrzés (poltura theme check <dir>, amelyet a kódszerkesztő minden mentéskor, a közzétételkor és a téma buildelésekor futtat) a pozíciók megjelölésével jelzi a következőket:

  • nem statikus definíciók, ismeretlen ikonok, kategóriák vagy sablonok, ismeretlen accepts típusok és duplikált típuskulcsok;
  • olyan szekció component nélkül, amelyet egyetlen platform renderer sem fed le;
  • usage: hiba, ha egy komponens (és az általa hívott, azonos fájlban lévő függvények) olyan beállítást olvas, amelyet a saját definíciója nem deklarál; figyelmeztetés, ha egy deklarált beállítást soha nem olvas;
  • children: minden olyan child type-ot, amelyet egy szekció vagy blokk elfogad, a komponensének ki kell rajzolnia: régió nélkül mentett gyermekek esetén a <Slot /> segítségével, a típust elfogadó <Slot name> segítségével, vagy a platform renderer-en keresztül. Az a típus, amely csak akkor rajzolódik ki, ha egy beállítás egy bizonyos értékkel egyenlő (source === 'blocks'), kirajzolatlannak számít, mert a kereskedő által bármely más állapotban hozzáadott blokk soha nem jelenne meg. A módosítás által érintett fájlok hibát jelentenek; a téma többi része figyelmeztetést ad;
  • accepted-without-component: elfogadott témablokk component nélkül; hiba a módosítás által érintett fájlokban, figyelmeztetés máshol;
  • checkout-locked: a pénztár kizárólag a platformhoz tartozik. Hiba, ha egy téma definiálja vagy felülírja a checkout szekciót, a checkout sectionhöz tartozó bármely blokkot (checkout-brand, checkout-trust-badge, checkout-breadcrumbs, checkout-express, checkout-address, checkout-shipping, checkout-payment, checkout-summary, checkout-note) vagy a kosár cart-checkout gombját, és a közzététel, valamint a téma buildelése visszautasítja. A webáruház figyelmen kívül hagyja az ilyen komponenst, és a Poltura sajátját rajzolja ki. A téma csak CSS-sel és tokenekkel stílusozhatja a pénztárat;
  • slots: deklarált slot, amely soha nem kerül renderelésre a <Slot name> segítségével (missing-slot), slot nélkül deklarált statikus elem olyan komponensben, amely nem rajzol ki alapértelmezett vagy dinamikus <Slot>-ot (static-not-rendered), valamint as='ul' vagy as='ol' formában renderelt régió, amely nem li keretű blokkokat fogad el (frame-mismatch);
  • olyan elrendezési fájlok, amelyek beállításai vagy stílusa kívül esik az elemük schema-ján, vagy amelyek átlépnek egy korlátot;
  • media/*: a képeknek médiatári fájlnak (media://<id>) vagy a téma által szállított fájlnak kell lenniük (asset://<path under assets/>, vagy asset('<path>') kódban). A távoli cím (media/no-remote-url) figyelmeztetés a CLI-ben és a kódszerkesztőben, és hiba a téma telepítésekor; a javascript:, data: és file: címek (media/unsafe-url), a nem kiszolgált útvonalak, például /images/hero.jpg (media/unresolvable-path), a hiányzó asset (media/unknown-asset) és a media:// kódban (media/ref-in-code) hibák. Az alt szöveg nélküli kép (media/image-alt), a keretét túllépő kép és az ismeretlen médiatári fájl (media/unknown-media, csak kódszerkesztő és telepítés esetén) figyelmeztetések; a korlátot meghaladó asset vagy a nem woff2 formátumú betűtípus (media/asset-size) hiba; a sehol sem használt asset (media/unused-asset) megjegyzés. A teljes táblázatot a Theme assetek és média tartalmazza.

Következő lépések

Utoljára frissítve