Témata frontendu#
Téma je celý vizuální celek webu — rozvržení, šablony, SCSS a JavaScript
pohromadě. www/themes/, jádro výběru app/Core/Theme/.
Dvě navazující kapitoly rozvádějí jeho části: Struktura SCSS a Design systém a tokeny.
Struktura#
www/themes/
admin/default/desktop/ administrace, výchozí šablona
admin/template1/desktop/ administrace, druhá šablona (viz Témata administrace)
frontend/template1/desktop/ jedna z 18 front šablon (template1–template18)
layouts/ rozvržení a jejich části
assets/{scss,css,js,dist,imgs}
assets/skins/<název>/ barevné varianty (skiny), viz níž
ui-demo/ katalog komponent
webpack.config.js
frontend/template2/desktop/ další šablona, přepíná se z administrace
Téma má varianty podle zařízení: DefaultThemeResolver vybere mobile, tablet
nebo desktop podle DeviceDetector — a když varianta v tématu neexistuje, spadne
zpátky na desktop.
Které téma je aktivní#
Téma se nevybírá v kódu, ale nastavením v databázi: theme.frontend (název)
a theme.frontend.path (relativní cesta, dopočítaná). Ručně se dnes needituje —
administrátor je vybírá naráz se skinem v Nastavení → Vzhled webu
(ThemeSettingPresenter), viz Vzhled webu.
Šablon je dnes 18, template1–template18 (spočítáno
ls www/themes/frontend/*/theme.json | wc -l).
Téma v nastavení platí pro každý web nad touž databází
Tabulka nastavení nemá sloupec pro prostředí. Běží-li nad stejnou databází víc
instalací (třeba vývojová a ostrá), změna theme.frontend.path by na ostrém webu
nezměnila jen barvy — nemá-li tamní instalace soubory nové šablony, takže by jí přestaly fungovat všechny
frontové stránky kvůli chybějícím layoutům. Tohle riziko platí i pro obrazovku
„Vzhled webu“ — je to jen jiné rozhraní nad týmiž klíči nastavení.
Lokálně se téma přepíná proměnnou prostředí, ne nastavením
Bez proměnné je to no-op — produkce ji nikdy nenastaví. Neexistující adresář se ignoruje, aby překlep neshodil web.Přepnutí vzhledu pro jednoho návštěvníka#
Vedle nastavení v databázi umí DefaultThemeResolver přebít téma i skin jen pro
aktuální požadavek — databázi nemění. Volba se hledá v tomhle pořadí, vyhrává první
nalezená:
| Pořadí | Téma | Skin | Poznámka |
|---|---|---|---|
| 1 | ?_theme=<adresář> |
?_skin=<název> |
uloží se do session cookie, takže přežije další prokliky |
| 2 | cookie cms_theme_override |
cookie cms_skin_override |
zmizí se zavřením prohlížeče |
| 3 | env CMS_THEME_OVERRIDE |
env CMS_SKIN_OVERRIDE |
výchozí volba celého běhu serveru |
| — | nastavení theme.frontend |
nastavení theme.frontend.skin |
když nic z toho výš neplatí |
Hodnota off, reset, default, none (nebo prázdná) cookie smaže a vrátí volbu
z env, a teprve když env není nastavená, z databáze. URL stojí nad env schválně: server
spuštěný s CMS_THEME_OVERRIDE by jinak ?_theme= tiše ignoroval.
Přepínání přes URL a cookie je zapnuté pro každého návštěvníka, protože je součástí
ukázky CMS (přepínač vzhledu ThemeSwitcher). Vypíná se proměnnými prostředí, každá
zvlášť:
| Proměnná | Vypne | Nevypne |
|---|---|---|
CMS_THEME_SWITCH=0 |
?_theme= a cookie tématu |
skiny |
CMS_SKIN_SWITCH=0 |
?_skin= a cookie skinu |
šablony |
Env CMS_*_OVERRIDE platí i s vypnutým přepínáním. Kdo chce vzhled zamknout úplně,
nastaví obě *_SWITCH na 0.
Přepnout jde jen na šablonu, která má desktop/
Nabídka (availableThemes()) bere jen adresáře s variantou desktop/, protože bez
ní by se nenašel layout. Název mimo [a-z0-9_-] nebo neexistující adresář se
ignoruje a zůstane téma z nastavení.
Přepínání platí jen pro frontové téma
Resolver je jedna služba i pro administraci. Kdyby se přepnulo i admin téma, hledala
by administrace layouty ve frontové šabloně, findLayoutTemplateFile() by tiše vrátil
null a celý admin by se vykreslil jako holý obsah bez <html>, CSS a JS, bez
záznamu v logu. Kontrola větve proto stojí v applyLocalOverride() ještě před čtením
?_theme=. Administrace má vlastní parametry a cookie, viz
Témata administrace.
Přepínač vzhledu na webu#
Komponenta ThemeSwitcher nabízí návštěvníkovi šablony a jejich skiny jako barevná kolečka.
Kolečko vybírá dvojici šablona + skin; první kolečko šablony je vždy základní vzhled bez
skinu. Volba se uloží jen do cookie toho, kdo klikl, nastavení webu se nemění.
| Situace | Co komponenta nabídne |
|---|---|
CMS_THEME_SWITCH=0 i CMS_SKIN_SWITCH=0 |
nic, nevykreslí se |
jen CMS_THEME_SWITCH=0 |
jen aktivní šablonu a její skiny; cizí šablony by byly mrtvé odkazy, protože resolver ?_theme= ignoruje |
| celkem méně než dvě kolečka | nic: prázdný panel by jen zabíral roh obrazovky |
barva s duplicateColor |
kolečko se vynechá, kromě právě zapnutého skinu (jinak by fajfka neměla u čeho být) |
Odkaz kolečka je aktuální URL s ?_theme=…&_skin=…, takže návštěvník zůstane na téže stránce.
Není to signál (handle…): ten by potřeboval CSRF token a měnil by se s každým překreslením,
takže by odkaz nešel sdílet ani cachovat.
Volba shodná s nastavením webu musí posílat off
Kolečko výchozí šablony posílá _theme=off a kolečko výchozího skinu _skin=off, tedy
zrušení volby. Kdyby posílalo název, návštěvník by si cookie uložil natvrdo a pozdější změna
vzhledu v administraci by se k němu nedostala. Skin se s nastavením porovnává jen u šablony
z nastavení; stejně pojmenovaný skin jiné šablony off neposílá.
_theme a _skin jdou vždy spolu
Kolečko základního vzhledu musí skin zrušit (_skin=off). Bez toho by po přepnutí šablony
zůstal skin z předchozí volby, který do nové šablony nepatří.
Mount patří mimo {snippet page}
{control frontBaseThemeSwitcher} je v layouts/parts/shared/bottom.latte každé šablony,
vedle cookie lišty. Uvnitř snippetu by ho AJAX překreslení stránky sestřelilo.
Témata administrace#
Administrace má dvě šablony v www/themes/admin/: default a template1. Obě mají
stejné layouty a shodný JavaScript (desktop/assets/js je v obou stejný strom), liší se
jen SCSS:
| Šablona | Kde je její vzhled | Sestavení |
|---|---|---|
default |
společný základ; styly funkčních prvků administrace (drobečky, akce řádku, panel hromadných akcí, stav formuláře, seznam a detail) v assets/scss/modules/system/_admin_features.scss |
npm run build:admin |
template1 |
společný základ a odchylky šablony jen v assets/scss/custom/ (_admin_data_grid, _admin_edit_layout, _admin_form_facelift, …) |
npm run build:admin:t1 |
Oba příkazy se pouštějí z kořene projektu (package.json) a sestaví JS (webpack) i CSS
(sass) dané šablony.
Změnu skriptu administrace udělejte v obou šablonách
bin/theme-js-sync.php hlídá jen frontové šablony. Skript upravený jen v admin/default
v template1 chybí a prvek tam tiše nefunguje, i když markup je stejný.
Odchylka template1 patří do custom/
Ostatní složky SCSS jsou společný základ. Pravidlo jen pro template1 zapsané jinam
změní vzhled i šablony default.
Šablona komponenty pro admin téma#
Komponenta si šablonu pro konkrétní admin téma hledá stejně jako na frontu: soubor
v Templates/Template1/default/… má přednost před Templates/Default/…. Platí to i pro
jednotlivé části přes resolveThemeTemplatePath(), viz Komponenty.
Obě admin témata dnes sdílejí šablony z Templates/Default/ (akce řádku, patička gridu,
lišta akcí formuláře); liší se jen styly.
Vlastní admin téma uživatele#
Výchozí admin téma a skin jsou v nastavení theme.admin a theme.admin.skin (upravuje se
v Nastavení administrace). Přihlášený uživatel si vedle toho vybere vlastní téma přepínačem
v hlavičce administrace (ThemeSwitcherComponent, {control adminSystemThemeSwitcher}
v layouts/parts/shared/_header.latte). Volbu zpracuje
DefaultThemeResolver::applyAdminOverride():
| Parametr | Co udělá |
|---|---|
?_admin_theme=<adresář> |
uloží téma do cookie cms_admin_theme (rok) a smaže cookie skinu |
?_admin_skin=<název> |
uloží skin do cookie cms_admin_skin |
?_admin_theme=reset (off, none, prázdné) |
smaže obě cookie, platí zase nastavení |
?_admin_skin=reset |
smaže jen cookie skinu |
Po uložení resolver přesměruje (u GET) na tutéž adresu bez parametrů. Téma se přijme, jen
když ThemeCatalog::exists() najde v www/themes/admin/ adresář s theme.json, skin jen
když ho téma má; cokoli jiného se ignoruje, takže ručně podstrčená cookie nikam jinam nevede.
Odkazy přepínače jsou prosté GET bez signálu, není tedy co zfalšovat.
Existující téma má přednost před slovem pro reset
Základní admin šablona se jmenuje default, což je zároveň slovo pro reset. Resolver
proto nejdřív zkusí, jestli téma tohoto jména existuje: ?_admin_theme=default přepne
na šablonu default a uloží ji do cookie, nastavení nevrátí. Návrat k nastavení je
?_admin_theme=reset.
Cesty do tématu v šablonách#
Šablona se nesmí vázat na jméno tématu. K dispozici jsou dvě funkce (fungují i jako filtry) a jeden test:
| Zápis | Co udělá |
|---|---|
{=themeAsset('assets/dist/bundle.js')} |
cesta k souboru uvnitř aktivního tématu |
{=themeUrl('…')} |
absolutní URL do aktivního tématu |
{if $x is isTheme('template2')} |
větvení podle tématu |
Registruje je app/Core/Latte/Extensions/ThemeLatteExtension.php.
Cesta napsaná natvrdo přestane fungovat při přepnutí tématu
A nikdo to nezjistí, dokud se téma nepřepne — tedy typicky až u zákazníka
s vlastní šablonou. V template1 je themeAsset() použitý na 30 místech.
Za asset patří ?v= s časovým razítkem
Prohlížeč jinak drží starý soubor v mezipaměti a změna se „neprojeví“.
Postup: upravuji vzhled běžícího frontendu#
- Ověř, kterou větev sestavení používá. V
themes/je hodně mrtvých větví —desktop_bck,scss-backup,scss_2,js2,ui-demo_old. Editace mrtvé větve je nejčastější ztráta času v téhle části systému. - SCSS patří do
template1/desktop/assets/scss/, sestavení:
- JavaScript do
assets/js/{components,behaviors,pages}/, sestavení:
- Prohlédni výsledek v katalogu komponent (
ui-demo/) — je to jediné místo, kde je vidět většina prvků najednou. - Prokliknij i mobilní variantu, pokud ji téma má.
npx sass NENÍ totéž co sass
Je to jiná verze překladače a vyrobí jiný výstup. Používej sass.
Bez sestavení se změna SCSS neprojeví — ani po tvrdém obnovení
Aplikace čte css/style.css, ne scss/. K tomu ještě prohlížeč drží starou verzi
v mezipaměti.
Postup: zakládám nové téma#
- Zkopíruj celý základ existujícího tématu; rozdíly drž ve vlastní vrstvě
(
custom/), ne rozsypané po celém stromu. - Ověř to
diff -rproti zdrojovému tématu — mělo by ukázat jen tvoji vrstvu, katalog komponent a výstupy sestavení. Cokoli navíc je nechtěná odchylka, která se při další opravě zdrojového tématu rozejde. - Nezapínej ho v nastavení, dokud nejsou soubory nasazené všude (viz varování
výš). Na vývoj používej
CMS_THEME_OVERRIDE. - Projdi varianty zařízení — chybějící
mobilespadne nadesktop, což je v pořádku jen tehdy, když je desktopové rozvržení responzivní.
Jak přidat šablonu#
Nová šablona je adresář www/themes/frontend/<název>/ se stejnou strukturou jako
ostatní (desktop/, případně mobile//tablet/). Vedle něj patří manifest
theme.json:
{
"label": "Přírodní kosmetika",
"description": "Jemný e-shop s přírodní kosmetikou",
"color": "#c9785a",
"group": "eshop",
"subpage": "/eshop"
}
| Klíč | Význam |
|---|---|
label |
název v nabídce šablon |
description |
krátký popis pod názvem |
color |
barva kolečka / náhradní plochy, když chybí printscreen |
group |
slug skupiny, viz níž |
subpage |
adresa podstránky pro galerii šablony; čte ji jen bin/theme-previews.php |
Pořadí v nabídce určuje název adresáře, přirozeně (template2 před template10),
ne manifest — ThemeCatalog klíč order nečte. Texty manifestu nejsou překladové
klíče schválně: chybějící překlad shodí stránku, chybějící manifest jen ubere hezký
název.
Bez theme.json šablona v administraci chybí
Návštěvnický přepínač nabídne každý adresář s desktop/, bez manifestu pod názvem
adresáře. Obrazovka Vzhled webu i generátor náhledů ale berou jen adresáře,
ve kterých theme.json je — šablona bez něj se v administraci nedá vybrat.
group je slug ze slovníku App\Core\Theme\ThemeCatalog::GROUPS
(eshop, classifieds, company, magazine, other), ne volný text. Název
skupiny, který se zobrazí v administraci, je text CMS a musí být přeložený do
cs/sk/en — volný text z manifestu by se do překladů nedostal. Neznámý nebo
chybějící slug spadne do other, takže překlep v manifestu nikdy nezpůsobí pád
obrazovky.
Náhledy pro administraci#
Obrazovka Vzhled webu potřebuje ke každé šabloně a jejímu skinu printscreen hlavní strany. Generuje je:
php bin/theme-previews.php # všechny šablony
php bin/theme-previews.php template5 # jen jedna šablona
Skript vyfotí headless Chromem hlavní stranu lokálně běžícího webu na pevné
adrese 127.0.0.1:8000 (třeba php -S 127.0.0.1:8000 -t www) a uloží:
<šablona>/preview.webp— základní barva,<šablona>/previews/<skin>.webp— každá další barevná varianta.
Formát je WebP, ne PNG — táž sada náhledů měla v PNG 9,2 MB, ve WebP 1,4 MB.
Generátor nespouštěj, když se zrovna na webu pracuje
Vyfotí web přesně v tom stavu, v jakém zrovna je — rozpracované úpravy souborů nebo přepnuté téma v administraci se tak dostanou přímo do náhledu. Chyba se přitom nepozná automaticky: skript hlídá jen to, že Chrome doběhl a soubor vznikl, ne že snímek nezachytil chybovou stránku. Stalo se to a poznalo se to až okem.
Po předělání šablony náhledy přegeneruj
Negenerují se samy při buildu ani při deploy. Bez ručního spuštění skriptu administrace ukazuje starý vzhled.
Chybějící náhled není chyba — karta šablony nebo skinu se v administraci
vykreslí i bez obrázku, místo něj barevná plocha z color v manifestu.
Synchronizace skriptů mezi tématy#
Frontové skripty (www/themes/frontend/templateN/desktop/assets/js) jsou v každé šabloně
vlastní kopie téhož stromu. Oprava komponenty v jedné šabloně se proto do ostatních
sama nedostane. Rozjeté kopie hlídá a sjednocuje bin/theme-js-sync.php:
php bin/theme-js-sync.php # jen ohlásí rozdíly (exit 1 = rozjeté)
php bin/theme-js-sync.php --canonical=template1 # totéž s jinou kanonickou šablonou
php bin/theme-js-sync.php --canonical=template1 --apply # přepíše rozjeté kopie kanonickou
Kanonická šablona je ta, jejíž kopie se považuje za správnou. Bez --canonical je to
template2 (výchozí hodnota ve zdroji skriptu), proto změněný skript komponenty rozešli
vždy s výslovným --canonical= na šablonu, kde jsi ho opravil. Soubory, které se mají
lišit záměrně (dnes pages/homepage.js), jsou v konstantě EXPECTED_DIFFERENT a
--apply je nepřepíše. Skript neřeší SCSS ani obrázky.
Skiny#
Skin je barevná varianta jedné šablony: adresář
<šablona>/desktop/assets/skins/<název>/ se souborem skin.css, který obsahuje jen
přepis CSS proměnných (:root { --color-primary: …; }). Linkuje se za style.css,
takže jeho tokeny vyhrají; layouty ani komponenty nemění. Cestu do šablony dává
ThemeHelper::getSkinPath().
Vedle skin.css může ležet skin.json:
| Klíč | Význam | Když chybí |
|---|---|---|
label, description |
název a popis v nabídce | název adresáře, bez popisu |
color |
barva kolečka v přepínači | poslední --color-primary ze skin.css |
order |
pořadí skinů v nabídce, při shodě rozhoduje label |
1000, tedy na konec |
hidden |
true skin vynechá z nabídek |
skin se nabízí |
Seznam skinů skládá SkinCatalog a za skin počítá jen adresář se skin.css. Nemá
závislost na resolveru, protože ho potřebuje i administrace, kde resolver drží admin
téma; cestu k šabloně proto dostává parametrem.
Postup: přidávám skin
- Založ
desktop/assets/skins/<název>/skin.cssa přepiš v něm jen tokeny. Pro tablet a mobil skin nekopíruj —ThemeHelper::getAssetPath()sáhne na desktopový soubor. - Přidej
skin.jsonslabel,coloraorder. Bezcolorse barva kolečka hledá jen jako hex hodnota--color-primaryveskin.css; jiný zápis (rgb(),var()) nechá kolečko prázdné. - Ověř přes
?_skin=<název>a v administraci v Nastavení → Vzhled webu. - Přegeneruj náhledy (
php bin/theme-previews.php <šablona>).
Chybějící skin neshodí web
Na rozdíl od šablony je skin bezpečná volba: resolver ho ověřuje až proti výslednému
tématu (po přepnutí šablony) a název, který v té šabloně nemá adresář se skin.css
(Theme::skinExists(), stejné pravidlo jako SkinCatalog), vrátí jako NULL, tedy
základní barvy, ne odkaz na 404. Rozpracovaný adresář bez skin.css se tak nezapne
ani z nastavení, ani přes ?_skin=.
hidden skin dál funguje
Zmizí jen z nabídky. Přímý odkaz ?_skin=<název> ani theme.frontend.skin v nastavení
ho dál zapnou. Na zálohu barvy, která nemá být k výběru, je to správně; na skin, který
nemá fungovat, ho smaž.
Kolečko se stejnou barvou se jen označí
ThemeCatalog::variants() vrací základní vzhled a za ním skiny; variantě, jejíž barva
už v seznamu je, nastaví duplicateColor: true (vyhrává základní vzhled, pak nižší
order). Nezahazuje ji: přepínač musí právě zapnutý skin ukázat i s duplicitní barvou,
jinak by fajfka neměla u čeho být. O skrytí rozhoduje volající.
Strukturovaná data v hlavičce#
parts/shared/head/schema-org.latte (v každé z 18 šablon) vypisuje do hlavičky JSON-LD typu
WebSite: @id a url z $baseUrl, name z $ogData->getSiteName(), description
z $metaData->getDescription() a inLanguage z $ogData->getLocale().
Dřív se do stránky vypisoval nevyhodnocený text {latte:raw json_encode(…)}, protože
blok měl n:syntax="off" — vyhledávač neviděl platná data. Nově se JSON generuje výrazem
{=json_encode([...], JSON_UNESCAPED_UNICODE + JSON_UNESCAPED_SLASHES + JSON_HEX_TAG)|noescape}
uvnitř <script type="application/ld+json">.
V tiskové značce Latte | začíná filtr
Příznaky json_encode se proto sčítají (A + B + C), ne spojují |. JSON_HEX_TAG
zajistí, že < v názvu webu nebo popisu neuzavře element <script>.
Při přidání další šablony zkopíruj tuhle verzi
Starší tvar s n:syntax="off" do ní nepřenášej. Další typy (Organization, BreadcrumbList)
zatím nejsou; v souboru je TODO na dynamické generování.
Postup: ověřit strukturovaná data#
- Zobraz zdroj stránky a najdi
<script type="application/ld+json">. Uvnitř musí být platný JSON — žádné nevyhodnocené{=…}ani{latte:raw …}. - Z příkazové řádky:
curl -s https://vase-domena.cz/ | grep -o '<script type="application/ld+json">.*</script>'. Hlavní strana vrací například graf s jedním uzlemWebSite(@idje…/#website,inLanguagenapříkladcs-CZ). - Pro kontrolu vyhledávačem vlož adresu stránky do testu Rich Results Test Googlu.
Prázdný description je v pořádku
Má-li stránka prázdný meta popis, je "description": "". Strukturu
to nerozbije; doplň popis stránky v administraci.
Hledání šablony akce#
DefaultThemeResolver::formatTemplateFiles() vrací Nette kandidáty na šablonu akce
v tomhle pořadí:
- téma, aktivní varianta:
<varianta>/layouts/modules/<modul>/presenters/<presenter>/<akce>.latte(části názvu presenteru s malým počátečním písmenem, např.front/system/presenters/home/default.latte), - totéž ve variantě
desktop, Templates/<Presenter>/<view>.lattevedle presenteru vapp/.
Seznam kandidátů nesmí být prázdný
Když se nic nenajde, Nette vezme $files[0], aby chybějící šablonu pojmenovalo
v hlášce 404. Nad prázdným polem z toho je TypeError v strtr(), tedy HTTP 500
místo 404 u každé chybějící frontové šablony. Metoda proto kandidáty jen řadí podle
existence a při úpravě nesmí začít filtrovat.
Hledání layoutu#
ThemeInitTrait::formatLayoutTemplateFiles() bere jméno layoutu ze stránky
(cms_system_pages.layout, přihlášenému napřed loggedLayout, bez hodnoty @layout.latte)
a hledá ho v <varianta>/layouts/ a pak v desktop/layouts/ aktivního tématu.
Sloupec layoutu je jeden pro všechna témata, takže stránka nastavená na
@text_layout_two.latte chce tenhle soubor i v tématu, které ho nemá. Proto:
| Situace | Co se stane | Log |
|---|---|---|
| layout v tématu je | použije se | — |
| layout v tématu chybí | přidá se náhradní @layout_one.latte |
warning: „Layout '…' není v tématu …“ |
chybí i @layout_one.latte (nebo ho stránka chce rovnou) |
stránka se vykreslí bez layoutu, HTTP 200 | error: „Náhradní layout … CHYBÍ“ |
@layout_one.latte (jeden sloupec, sdílená hlavička a patička) mají dnes všech 18 témat
(spočítáno ls www/themes/frontend/*/*/layouts/@layout_one.latte). Náhradou není
@layout.latte: ten je holá kostra Nette bez hlavičky, patičky a stylů.
Nové téma musí mít @layout_one.latte
Bez něj nemá kam spadnout žádná stránka s layoutem, který téma nezná. Taková stránka
vrátí HTTP 200 bez hlavičky, patičky a stylů, takže ji monitoring dostupnosti nepozná;
vidět je jen řádek error v logu.
Chybová stránka#
Chybová stránka frontu (404, 403, 410 a ostatní 4xx) se kreslí v aktivním tématu a jazyce
požadavku přes Front:System:Error (ErrorPresenter). Přijde se na ni dvěma cestami:
forwardem z Error4xxPresenter, když front presenter nebo router skončí
BadRequestException, a přímo routou bez whitelistu stránek, kam spadne třeba
/?slug=neexistuje.
Stránka v databázi není, layout ale entitu stránky potřebuje. loadPageEntity() proto vrací
nepersistovanou Page s layoutem @layout_one.latte. HTTP kód nastavuje
renderDefault() sám (přímá routa ho jinak nenastaví a neexistující adresa by vrátila 200),
startup() vynuluje persistentní slug a podvržený jazyk v adrese spadne na hlavní jazyk webu.
Layout chybové stránky je vždy @layout_one.latte
Chybí-li v tématu, chybová stránka vyjde bez hlavičky, patičky a stylů. Vlastní kód z administrace se na ní nevykreslí (stránka nemá id, viz níž).
Chyba serveru (500) se v tématu nekreslí — téma ani databáze v tu chvíli nemusí
fungovat. Je to samostatná jednoduchá stránka app/UI/Error/Error5xx/500.phtml
v češtině, angličtině a slovenštině: jazyk určí předpona adresy (/en/, /sk/), pak
hlavička Accept-Language prohlížeče, jinak čeština. Odkazuje na hlavní stránku dané
jazykové verze. Vzhled ani texty se nenastavují v administraci; chcete-li je změnit,
upravte přímo tento soubor (bez DI a překladače, jen čisté PHP a HTML).
Vlastní kód z administrace#
Knihovna Web → Stránky → Vlastní kód vkládá do stránek CSS, JS nebo HTML (měřicí
kódy, chat, ověření domény). Na stránce běží přesně ty kódy, které jsou jí přiřazené
(vazba cms_system_custom_asset_page_relations); celowebový rozsah neexistuje,
„na všech stránkách“ je v administraci jen akce, která vazby ke všem stránkám vytvoří.
Komponenta frontSystemCustomAssets se v tématu volá jednou pro každé místo:
| Volání | Kde je ve všech 18 tématech |
|---|---|
{control frontSystemCustomAssets 'head'} |
layouts/parts/shared/head.latte, uvnitř <head> |
{control frontSystemCustomAssets 'body_start'} |
v každém layoutu hned za <body> (všech 26 layoutů tématu) |
{control frontSystemCustomAssets 'body_end'} |
layouts/parts/shared/bottom.latte, před </body> |
Všechna tři volání mají stejné jméno, takže dostanou tutéž instanci komponenty: kódy stránky
se načtou jedním dotazem (loadAssets(), filtr vazby je v dotazu) a jen se rozdělí podle
místa. Změna vazeb bumpuje cache třídy CustomAsset, výsledek tedy nezůstane viset.
| Typ | Co se vypíše |
|---|---|
| CSS | <style>…</style>, z kódu se odstraní </style v jakékoli podobě |
| JS | <script>…</script>, z kódu se odstraní </script; s vyplněnou kategorií cookies type="text/plain" + data-cookie-category, spustí ho cookie-bar.js až po souhlasu |
| HTML | beze změny |
Postup: nový layout tématu
- Vlož do layoutu hned za
<body>volání{control frontSystemCustomAssets 'body_start'}. - Ověř, že layout vkládá sdílené
head.latteabottom.latte(nesou místaheadabody_end). - Komponentu pojmenuj ve všech třech voláních stejně, žádný
multicontrol. - Přiřaď v administraci zkušební kód k jedné stránce a ověř ve zdroji stránky všechna tři místa.
Obsah se nesanitizuje
To je smysl knihovny. Ochranou je oprávnění autora (:Admin:System:CustomAsset:edit,
přiřazení :Admin:System:CustomAsset:assign), ne kód. Odstranění uzavírací značky
u CSS a JS jen brání vyskočit z elementu a dopsat do stránky libovolné HTML; typ HTML
žádnou pojistku nemá a mít nemůže. Kdo by komponentu volal pro každé místo jiným jménem,
dostane tři dotazy na každý požadavek.
Bez entity stránky se nekreslí nic
Kódy se hledají podle id stránky. Chybová stránka má nepersistovanou stránku bez id, takže vlastní kód na ní neběží.
Přístupnost#
Rozbalovací prvky dělej přes <details>, kde to jde
Funguje to bez JavaScriptu, čtečky si s tím poradí a nepotřebuje to žádné ARIA atributy navíc.
Skills pro práci se šablonami#
| Skill | Pro co |
|---|---|
cs-template-layout |
rozvržení |
cs-template-subpage |
podstránka |
cs-template-from-image |
šablona podle obrázku |
cs-template-from-sample |
šablona podle ukázky |
cs-ui-audit |
kontrola hotového vzhledu |
Kam sáhnout#
| Chci | Kde |
|---|---|
| výběr tématu, skinu a varianty | app/Core/Theme/DefaultThemeResolver.php |
nabídka šablon, theme.json, skupiny |
app/Core/Theme/ThemeCatalog.php |
nabídka skinů, skin.json |
app/Core/Theme/SkinCatalog.php |
cesta ke skin.css |
app/Core/Utils/Helpers/ThemeHelper.php → getSkinPath() |
| návštěvnický přepínač | app/UI/Front/Base/Components/ThemeSwitcherComponent/ |
funkce themeAsset / themeUrl |
app/Core/Latte/Extensions/ThemeLatteExtension.php |
| aktivní front téma | www/themes/frontend/template1/desktop/ |
| katalog komponent | www/themes/frontend/template1/desktop/ui-demo/ |
| téma administrace | www/themes/admin/default/desktop/, www/themes/admin/template1/desktop/ |
| přepínač admin tématu | app/UI/Admin/System/Components/ThemeSwitcherComponent/, DefaultThemeResolver::applyAdminOverride() |
| šablonu části komponenty podle tématu | app/Core/Base/BaseComponent.php → resolveThemeTemplatePath() |
Navazující kapitoly: Struktura SCSS · Design systém a tokeny · Šablony Latte · Komponenty