Give a site its own layout
Every page has a layout: the frame around its content. The portal has two of its own, one-column and two-column. A site can also have layouts of its own, with its header, navigation and footer, and marked places for what each page holds.
A page can also hold its own text, written in HTML, without an app: an HTML block.
Administrators can also choose a page’s layout and arrange its blocks in the console, under Pages.
A layout of the site’s own
Section titled “A layout of the site’s own”A site’s layouts sit in the layouts folder beside its pages:
sites/main/layouts/ civic.html the frame, for every language civic.en.html the frame in English, when English needs its own words civic.css its stylesheet (optional)The name of the file is the name of the layout: lower-case letters, digits and hyphens, starting with a letter. A frame for one language adds the language’s two-letter code. A page uses the layout by its name:
path: /despretitle: { ro: Despre, en: About }layout: civicregions: main: - id: story app: portal preferences: html: ro: | <h2>Cine suntem</h2> <p>…</p> en: | <h2>Who we are</h2> <p>…</p> aside: - { id: news, app: content-block }A site has at most 32 layouts. one-column and two-column are taken.
The marked places
Section titled “The marked places”The frame is HTML, with three elements of the portal’s own, each written empty with its end tag:
| Element | What goes there |
|---|---|
<portal-region name="main"></portal-region> | the page’s main content; required. Add other regions, such as name="aside", as the layout needs, each name once; a page’s regions name them. |
<portal-title></portal-title> | the page’s title, as its heading; at most once. Without one, the title opens the main region. |
<portal-locales></portal-locales> | links to the same page in each of the site’s languages; at most once. |
They stand at the top of the frame, or directly inside div, section, article, aside, header, footer, nav, li, td, th, figure, details or blockquote.
<header class="civic-top"> <nav aria-label="Meniu principal"> <a href="/">Acasă</a> <a href="/servicii">Servicii</a> </nav> <portal-locales></portal-locales></header><div class="civic-hero"><portal-title></portal-title></div><div class="civic-body"> <portal-region name="main"></portal-region> <aside aria-label="Noutăți"><portal-region name="aside"></portal-region></aside></div><footer class="civic-foot"><p>Primăria Exemplu</p></footer>A frame for one language, such as civic.en.html, has the same regions as civic.html.
What a frame may hold
Section titled “What a frame may hold”The portal checks the markup and refuses what it does not take, naming the element or attribute; nothing is quietly dropped.
- Elements: text and structure, such as
header,nav,footer,section,article,aside,div,p,h2toh6, lists, links, images, figures, tables anddetails. Nomainorh1: the page gives one of each. No scripts, styles, frames, forms, buttons orsvg, and no comments. - Attributes:
class,id,role,lang,dir,title,hidden,tabindex,aria-*anddata-*, plus each element’s own, such ashref,srcandalt. Nostyleand no event handlers. Images needalt, empty for decoration. - The portal’s own names: the frame cannot use
id="main", ids starting withportal-, the rolesmain,headingandapplication, or thedata-attributes the portal puts on placements.tabindexis0or-1, andtargetonly_blank. - Addresses: links to pages of the site (
/…, but not the portal’s own/_portal/…),?…,#…,https:,http:,mailto:andtel:; images fromhttps:or embedded as PNG, JPEG, GIF, WebP or AVIF. An address relative to the page, such aslogo.png, is refused: it would change from page to page.
A frame takes at most 256 KB.
Images in each screen’s size
Section titled “Images in each screen’s size”Give an image its width in pixels, such as <img src="https://img.example.ro/hero.jpg" width="640" alt="…">. The portal then serves it at that width, and twice that for sharp screens, in a lighter format, so phones load less. An image without a width, or with sizes of its own (srcset), is shown as it is. If the portal cannot resize an image, visitors get the original.
Its stylesheet
Section titled “Its stylesheet”The stylesheet styles the frame with the site’s design tokens, by their own names:
.civic-top { display: flex; justify-content: space-between; background: var(--surface); border-bottom: 1px solid var(--border);}.civic-foot { color: var(--muted); }- It fetches nothing from elsewhere: no
@import, andurl()only for addresses on the site (/…) or embedded images and fonts. - It styles the frame’s own elements and classes, not
htmlorbody, and not the content: onhtml,bodyand inside a region, the token names belong to the apps’ widgets. - It leaves the portal’s own controls alone: the placement menus and the skip link.
- It takes at most 256 KB.
An HTML block
Section titled “An HTML block”An HTML block is text a page holds itself: app: portal, with the text for each of the site’s languages under preferences.html. It needs no app and no approval.
- id: story app: portal preferences: html: ro: | <h2>Cine suntem</h2> <p>Program: luni–vineri.</p> en: | <h2>Who we are</h2> <p>Open: Monday to Friday.</p>Write each text as a | block, as above: a plain value breaks at the first colon followed by a space. Give the text of every language of the site, and no other. The text is checked like a frame, without the portal’s own elements, and takes at most 64 KB per language. An HTML block can go in any layout’s regions.
Fragments and page templates
Section titled “Fragments and page templates”A fragment is text kept once and placed on many pages, in sites/<site>/fragments/<id>.yaml:
name: { ro: Program, en: Opening hours }html: ro: | <p>Luni–vineri, 8–16.</p> en: | <p>Monday to Friday, 8 to 4.</p>A page places it by its id; change the file, and every page that holds it changes:
- id: hours app: portal widget: fragment preferences: { fragment: program }Its text holds what an HTML block holds. A site has at most 200 fragments.
A page template, in sites/<site>/templates/<id>.yaml, is a page’s starting point. It holds a name in each language, a layout and regions, written as a page’s. It is never shown to visitors; administrators start new pages from it in the console. A site has at most 50.
Check it
Section titled “Check it”portal check reads the layouts and blocks with the rest of the site, and names each problem with its file:
- a page naming a layout the site does not have, or a region its layout does not have;
- markup or a stylesheet the portal does not take, with the reason;
- a frame without a main region, or with a region named twice;
- a frame for a language the site does not have.
A problem keeps the whole change from going live. To see the layout, render the pages:
portal check ./portal-config --start --render