Going further
Going further
Section titled “Going further”This page collects advanced FrontMark operations: compiled Svelte components, optimized assets, cache policy, imports, upgrades, translations, protected content, Sveltia collections and deployment pipelines.
Compile Svelte components
Section titled “Compile Svelte components”Markdown can mount Svelte components with ::: svelte. The source files live in svelte-components/src/** and are compiled to public/svelte/ before Astro builds the site.
make svelte
During component development, run the watcher beside make dev:
make svelte_watch
make build, make preview and both Docker image builds compile the Svelte bundle before Astro. See Svelte Components for directive syntax and component configuration examples.
Optimize public images
Section titled “Optimize public images”FrontMark optimizes local PNG, JPEG and WebP images at build time with Sharp. Originals stay in place, generated variants go to public/_optimized/, and Markdown keeps referencing canonical public paths.
make optimize
make build, make preview and Docker builds run optimization before Astro. Existing variants are reused when the source image and image configuration have not changed.
images:
optimize: true
mode: build
output:
directory: /_optimized
keep_original_fallback: true
content_hash: true
formats:
- avif
- webp
- original
quality:
jpeg: 82
webp: 82
avif: 68
png_lossless: true
folders:
/images:
profile: documentation
/uploads:
profile: balanced
/brand:
profile: lossless
/icons:
profile: lossless
/media:
profile: balanced
skip:
max_width_below: 300
size_below_kb: 15
extensions:
- svg
- gif
Available profiles are balanced, documentation, screenshots, photos, lossless, brand, logos, icons and bypass. Use screenshots for captures containing text, photos for stronger compression, and lossless or bypass for brand-sensitive assets.
Configure static Nginx cache
Section titled “Configure static Nginx cache”Static Docker images generate nginx.conf from site.config.yaml.
runtime:
nginx:
cache:
validation:
etag: true
if_modified_since: exact
html: public, no-cache
stable_assets: public, no-cache
optimized_assets: public, max-age=31536000, immutable
optimized_manifest: public, no-cache
astro_assets: public, max-age=31536000, immutable
admin_config: public, no-cache
cms_bundle: public, max-age=31536000, immutable
stable_asset_paths:
- /brand/
- /documents/
- /icons/
- /images/
- /media/
- /scripts/
- /styles/
- /uploads/
- /videos/
Use immutable caching only for URLs that change when content changes: /_astro/, optimized image variants and /admin/sveltia-cms.js?v=<content-hash>. Keep HTML, manifests, admin config and stable asset paths in no-cache; Nginx sends ETag/Last-Modified validators so browsers revalidate changed files cleanly.
Import a MkDocs Material site
Section titled “Import a MkDocs Material site”Use the importer when an existing MkDocs Material project must become a FrontMark/Starlight site:
make import /path/to/mkdocs-site
make import MKDOCS=/path/to/mkdocs-site
make install import /path/to/mkdocs-site
The make install import /path/to/mkdocs-site form bootstraps dependencies first, then runs the same import. The importer reads mkdocs.yml or mkdocs.yaml, then copies the MkDocs docs_dir into FrontMark-friendly locations.
| Source item | Imported behavior |
|---|---|
index.md | Imported as the documentation entry page, with generated frontmatter when needed. |
| Markdown subfolders | Imported recursively, with slugified file and folder names. |
documents/ | Copied to public/documents/. |
images/ | Copied to public/images/. |
videos/ | Copied to public/videos/. |
tags.md | Ignored, because FrontMark builds its own tag index. |
overrides/, js/, css/ | Ignored, because FrontMark owns rendering, scripts and styles. |
The importer updates site.config.yaml with portable MkDocs values only.
| Config item | Imported behavior |
|---|---|
site_name, site_url, site_description, site_author, copyright | Mapped to FrontMark site, SEO and brand metadata. |
theme.logo, theme.favicon, theme.language or theme.locale | Mapped to FrontMark brand and language settings. |
nav | Converted to menus.sidebar. |
Existing astro.menu.links | Preserved during import. |
Previous-menu comments from make erase-all | Removed when site.config.yaml is rewritten. |
Analytics IDs found in ga.js | Mapped to analytics.ids. |
extra.consent | Normalized to FrontMark consent keys. |
Public encryptcontent UI labels | Normalized to security.encryptcontent. |
Run make erase-all before importing when you want a clean navigation state. It resets astro.menu.links and menus.sidebar to empty lists and comments their previous values temporarily; make import then fills menus.sidebar from the MkDocs nav and removes those comments.
Directory entries such as Raquettes a neige: raquettes are expanded from the matching folder. If include_dir_to_nav is configured, reverse_sort_file and reverse_sort_directory are respected so numbered files and folders keep the same ordering as MkDocs.
MkDocs Material features, palette, markdown_extensions, arbitrary extra data, plugin internals, passwords, theme internals, extra_css and extra_javascript are not migrated.
Every imported Markdown page receives at least frontmatter title; description is filled from site_description when the page does not define one. Relative links to copied assets are rewritten to public paths such as /images/photo.jpg, /documents/manual.pdf and /videos/demo.mp4.
Run the importer test after changing import behavior:
make import_test
Upgrade FrontMark core
Section titled “Upgrade FrontMark core”Use make upgrade to refresh the FrontMark engine of an existing site without replacing local content or central configuration.
make upgrade
By default, the upgrade clones https://gitea.newkube.ia86.cc/sigMAX/Image_frontmark, copies the core implementation over the current project, refreshes the Makefile so the upgrade target itself can evolve, then runs npm install.
Local IMAGE_NAME values in the Makefile and Dockerfile ARG IMAGE_NAME=... lines are preserved during the refresh, along with Dockerfile ARG VERSION_MAJOR=... values.
Protected paths are skipped:
| Protected path | Reason |
|---|---|
site.config.yaml | Central site configuration stays local; bundled theme entries under theme.availableStyles are synchronized from the reference. |
src/content/ | Markdown pages and collections stay local. |
src/imported/ | Imported MkDocs sidebar and redirects stay local. |
public/brand/, public/styles/overrides.css, public/styles/astro-overrides.css | Branding assets, generated favicon and both local CSS overrides stay local. |
public/images/, public/videos/, public/media/, public/documents/, public/icons/, public/uploads/ | Site assets stay local. |
public/scripts/mkdocs-import-config.js, public/search/, public/admin/, public/svelte/, dist/, .astro/, node_modules/ | Generated artifacts stay local or are rebuilt. |
Useful variants:
make upgrade UPGRADE_DRY_RUN=1
make upgrade UPGRADE_REF=main
make upgrade UPGRADE_INSTALL=0
make upgrade UPGRADE_REPO=https://example.test/FrontMark.git
make upgrade UPGRADE_PROTECTED_PATHS="site.config.yaml public/brand public/styles/overrides.css public/styles/astro-overrides.css"
Bundled themes under public/styles/themes/ are part of FrontMark core and are refreshed by make upgrade. The matching entries in theme.availableStyles are replaced from the reference so their metadata stays identical, and missing bundled themes are appended. Missing site.config.yaml options are added from the reference, while existing local values such as the active theme.style are kept. Local custom theme entries that do not exist in the reference are kept too. Put documentation-wide CSS changes in public/styles/overrides.css and top-menu Markdown page changes in public/styles/astro-overrides.css; both files are protected.
Configure navigation
Section titled “Configure navigation”The left documentation menu is controlled by menus.sidebar.
menus:
sidebar:
- label: FrontMark
items:
- label: Overview
link: /docs/
icon: material-home-outline
- label: Getting started
link: /docs/getting-started/
icon: material-playlist-check
- label: Going further
link: /docs/going-further/
icon: material-rocket-launch-outline
Rules:
linkvalues are written without the public prefix.site.baseis added at build time.- External entries use
hrefandexternal: true; they are rendered withtarget="_blank"and do not receivesite.base. iconvalues use the same icon shortcode style as the imported MkDocs Material content.
Configure footer categories
Section titled “Configure footer categories”Add footer.categories to define a structured multi-column footer. Each category and link is read from site.config.yaml; internal links receive site.base, while repository: true resolves to the configured Git repository. The structured layout is enabled per theme with categoriesEnabled: true.
footer:
showVersion: true
brand:
title: FrontMark
subtitle: Enriched Markdown
description: Write once. Publish clearly.
logo: /brand/icon.png
logoWidth: 45px
logoAlt: FrontMark
mode: both # text, logo, or both
categories:
- label: Domains
links:
- label: Enriched documentation
href: /docs/
- label: Contact
links:
- label: Contact us
href: /contact/
- label: Repository
repository: true
footer.showVersion: true displays the same build version badge as the header.
The value comes from PUBLIC_SITE_VERSION, or from APP_VERSION combined with
VERSION_MAJOR; no badge is rendered when none of these variables supplies a
version. PUBLIC_SHOW_FOOTER_VERSION=false can disable it at build time.
footer.brand.mode accepts text, logo, or both. In logo mode the configured image replaces the title and subtitle, while the description and social links remain available. footer.brand.logoWidth controls the displayed width and accepts either a number in pixels or a CSS length such as 45px or 3rem; the image height is calculated automatically from its original ratio.
Enable the categorized layout only on the themes that need it:
theme:
availableStyles:
- name: underground
footer:
enabled: true
fullWidthInDoc: true
alwaysOnTop: false
categoriesEnabled: true
Themes without categoriesEnabled: true keep the original compact footer, even when category data is configured globally. Astro pages already render the footer as a full-width child of the page; fullWidthInDoc: true gives documentation pages the same full-bleed behavior outside the Starlight content column.
Astro and documentation settings by theme
Section titled “Astro and documentation settings by theme”The top-level astro and documentation blocks provide defaults for every
theme. Add the matching block to a style when that rendering mode needs
different behavior; the style values override the global values and omitted
values keep inheriting them.
astro:
menuAlign: right
showQrCode: true
showBackToTop: false
documentation:
search: true
menu: frontmark
menuAlign: left
chapters: desktop-and-tablet
showQrCode: true
hideInactiveMenusOnScroll: true
bodyLineHeight: 1.75
theme:
availableStyles:
- name: underground
astro:
menuAlign: extreme-right
showQrCode: false
showBackToTop: true
documentation:
chapters: false
menuAlign: extreme-right
showQrCode: false
astro.showQrCode and documentation.showQrCode are independent. Setting one
to false removes the complete page-tools block in that mode, including the
source and edit actions; no empty placeholder is kept. The other supported
documentation overrides are search, menu, chapters,
hideInactiveMenusOnScroll, and bodyLineHeight. Setting chapters: false
hides the Previous/Next chapter links and keeps every documentation category
visible instead of applying the scroll-based chapter filter. Theme changes
made with the development style selector update these display settings
immediately.
astro.showBackToTop controls the translated return-to-top button on Astro
pages. It is hidden by default and appears after the visitor has scrolled down.
Set it globally under astro, then override it for one style under
theme.availableStyles[].astro. The button reuses the documentation
up-arrow icon and smooth-scroll behavior, and updates immediately in the
development style selector.
astro.menuAlign and documentation.menuAlign independently position the
desktop navigation menu. The global defaults are right for Astro and left
for documentation; the underground theme overrides both alignments with
extreme-right. The accepted values are:
extreme-left: before the logo;left: immediately after the logo;center: centered in the header;right: on the right, before the search field;extreme-right: after the search field but before the action icons;max-right: completely right, after the action icons.
max-left is accepted as a compatibility alias for max-right. Tablet and
mobile layouts continue to use the responsive sandwich menu.
Configure visual styles
Section titled “Configure visual styles”The active style is selected in site.config.yaml. A style is one folder containing its CSS and optional font files under public/styles/themes/<name>/.
theme:
defaultMode: auto
showThemeSwitcher: ondev
scrollProgress:
enabled: true
height: 4px
cssOverrides:
- /styles/overrides.css
style: sigmax
availableStyles:
- name: sigmax
label: sigMAX
colorMode: dark
stylesheet: /styles/themes/sigmax/theme.css
footer:
enabled: true
fullWidthInDoc: true
alwaysOnTop: true
i18n:
visibility: footer
header:
minimizeOnScroll: true
minimizeScrollY: 56
- name: underground
label: underground
colorMode: light
stylesheet: /styles/themes/underground/theme.css
header:
minimizeOnScroll: false
alwaysOnTop: transparent
transparentScrollY: 100
fullWidthInAstro: true
brandMode: logo
brandPosition: left
indexMenu: sandwich
astro:
fullWidthBody: true
showBackButton: false
showBackToTop: true
Available bundled styles include sigmax, health, mountains, caving, underground, software, blog, old and wired. Use theme.defaultMode: auto to follow the active style colorMode, or set dark or light to force the site theme. The top light/dark selector is only usable when the active style declares colorMode: switch. theme.scrollProgress controls the top scroll indicator; its gradient is provided by the active theme CSS.
For Astro pages, header.fullWidthInAstro: true expands the navigation bar inside responsive page gutters, while astro.fullWidthBody: true does the same for the page body below it. Header branding is also selected per style: header.brandMode accepts both, logo, or text, and header.brandPosition accepts left or right. header.indexMenu changes navigation only on the index page: use normal for desktop links, sandwich for the same compact menu used on tablets, or hidden for no navigation menu. Other pages retain their normal responsive menu. header.alwaysOnTop: true keeps the navigation fixed with its nominal surface, false lets it leave the viewport with the page, and transparent keeps it fixed but transparent until header.transparentScrollY (100 pixels by default), then restores the active style colors. The transparent_white_in_mini and transparent_black_in_mini variants retain that behavior and the existing responsive icon, while forcing a white/black or black/white button palette on tablet and mobile layouts. When the optional brand.logo2 is configured, it replaces brand.logo only during that transparent state. astro.showBackButton: false hides the small return-to-home icon for the selected style; page frontmatter can still set back: false to disable it on an individual page regardless of style. astro.showBackToTop: true independently enables the translated button that appears after scrolling and returns to the top of the current Astro page.
Override the page shell from frontmatter
Section titled “Override the page shell from frontmatter”Astro and documentation pages can override the active theme for one page. The
nested header.indexMenu form is preferred; a top-level indexMenu value is
also accepted as a short alias.
See Page shell, header and first-screen scrolling for the complete mode table, configuration precedence, responsive behavior and troubleshooting.
---
scrollonpage: true
header:
indexMenu: sandwich # normal, sandwich, or hidden
alwaysOnTop: transparent # false, true, transparent, or a transparent_*_in_mini mode
transparentScrollY: 100
footer:
alwaysOnTop: false
---
scrollonpage: true animates a downward wheel, touch, or keyboard gesture to
the end of the first root=top section whenever the current position is inside
it. The current viewport height is used as a fallback, so the destination
adapts to the screen size. Scrolling is normal from the section boundary onward;
returning inside the first section enables the animated jump again. Leave it
unset or use scrollonpage: false to disable the behavior. The camel-case alias
scrollOnPage is also accepted.
header.indexMenu: hidden removes both the desktop links and the sandwich
button, while normal restores the regular responsive navigation.
header.alwaysOnTop: false makes the complete documentation frame scroll: the
header, left navigation, and right table of contents all leave the viewport
with the page. It also keeps every left-navigation category visible, disables
the scroll-based current-category filter, and forces the footer into the normal
document flow even if footer.alwaysOnTop is true. With a fixed header,
footer.alwaysOnTop independently chooses between the normal document flow and
a footer fixed to the bottom of the viewport. A categorized footer always
remains in the document flow because its multi-column height is not suitable
for a fixed overlay. The transparent header mode is also treated as fixed;
on a top root container, combine it with root-header=light or dark to keep
the navigation legible over the hero before the nominal theme colors return.
CSS override files are loaded after the active bundled theme. The default public/styles/overrides.css and public/styles/astro-overrides.css files are protected from make upgrade, which makes them the safest places for project-specific CSS.
Configure translations
Section titled “Configure translations”The language selector is generated from i18n.languages. The number of available translation buttons is derived from that list, or limited explicitly with languageCount. Toolbar placement is configured per style with theme.availableStyles[].i18n.visibility.
i18n:
enabled: true
provider: google
defaultLanguage: en
defaultTextScale: xlarge
languageCount: 3
languages:
- code: en
label: English
nativeLabel: English
flag: GB
- code: fr
label: French
nativeLabel: Francais
flag: FR
The language and text-size toolbar is marked as notranslate, so Google Translate does not rewrite the controls themselves.
Cookie banner
Section titled “Cookie banner”The cookie consent banner is generated from the central YAML configuration.
consent:
enabled: true
storageKey: frontmark-cookie-consent
title: Cookie preferences
description: FrontMark can store local preferences such as language and text size.
acceptText: Accept
rejectText: Reject
policyLink: /docs/going-further/#cookie-banner
policyText: Learn more
Encrypt content
Section titled “Encrypt content”FrontMark supports the common mkdocs-encryptcontent-plugin frontmatter pattern. Use password for a page-specific password, or level for a named password stored centrally.
security:
encryptcontent:
enabled: true
rememberPassword: true
storage: session
levels:
demo: frontmark
---
title: Protected page
level: demo
---
The example page is available at Encrypt Content. Its demo password is frontmark.
Configure Sveltia collections
Section titled “Configure Sveltia collections”Collections live under admin.collections.
admin:
mediaFolder: public/uploads
publicFolder: /uploads
collections:
- name: docs
label: FrontMark Documentation
folder: src/content/docs
create: true
extension: md
format: frontmatter
slug: "{{slug}}"
previewPath: /docs/{{slug}}/
fields:
- label: Title
name: title
widget: string
- label: Content
name: body
widget: markdown
Important details:
folderpoints to the repository folder edited by Sveltia.previewPathis written without/frontmark; the activesite.baseis added automatically.publicFolderis also written without/frontmark; the generated Sveltia config adds the base.mediaFolderis the repository path where uploaded files are committed.fieldsare passed to Sveltia as-is, so nested fields, selects, booleans and lists are defined here.
The broader Sveltia backend setup is documented in Configure Sveltia.
Remove every prefix
Section titled “Remove every prefix”To publish the site at the domain root with no /frontmark prefix anywhere, change only site.base:
site:
base: ""
The build, tag routes, runtime config, Sveltia api_root, Sveltia base_url, public_folder, logo paths and every preview_path are generated from the same configuration. No manual edit is needed in generated runtime files.
After changing the base, rebuild:
make rebuild
Then check the site at /, the documentation at /docs/, the admin at /admin/, and static assets such as /brand/favicon.ico.
Verify generated configuration
Section titled “Verify generated configuration”After editing site.config.yaml, run:
make rebuild
Then check the generated Sveltia endpoints:
URL with /frontmark | Expected result |
|---|---|
/frontmark/admin/config.json | JSON config consumed by the CMS. |
/frontmark/admin/config.yml | YAML view useful for debugging. |
/frontmark/admin/sveltia-cms.js | Sveltia CMS JavaScript bundle. |
For a domain-root deployment, use /admin/config.json, /admin/config.yml and /admin/sveltia-cms.js.
Add it to a CI/CD pipeline
Section titled “Add it to a CI/CD pipeline”Use Make commands in CI:
steps:
- name: Install dependencies
run: make install
- name: Build site
run: make build
For Docker deployments:
make image IMAGE=registry.example.com/frontmark:latest
docker push registry.example.com/frontmark:latest
The default Dockerfile builds the fully static variant: Svelte is compiled, tags are generated, images are optimized, Astro writes static files, the CMS config is generated for Forgejo OAuth through the dedicated proxy, and Nginx serves the prepared static root. Cache headers are generated from runtime.nginx.cache.
Behind Traefik, keep site.base equal to the public prefix, for example /frontmark. The static Nginx runtime accepts both upstream shapes: Traefik can preserve the PathPrefix("/frontmark") path, or an existing StripPrefix("/frontmark") middleware can strip it before the request reaches the container.
For a static deployment with OAuth sign-in, build the static image and deploy the dedicated OAuth/API proxy container beside it:
make image IMAGE=registry.example.com/frontmark:latest
make image_oauth OAUTH_IMAGE=registry.example.com/frontmark-oauth:latest
docker push registry.example.com/frontmark:latest
docker push registry.example.com/frontmark-oauth:latest
Route these Traefik prefixes to the OAuth proxy service:
| Public path | Service |
|---|---|
/frontmark/oauth/forgejo/* | OAuth/API proxy container. |
/frontmark/api/forgejo/v1/* | OAuth/API proxy container. |
/frontmark/* | Static FrontMark container. |
The proxy container accepts both Traefik modes: preserving /frontmark or using StripPrefix("/frontmark"). Configure PUBLIC_GIT_ORIGIN when the Gitea/Forgejo origin should come from the environment instead of site.config.yaml.