In Laioutr, the frontend is built from pages that the customer configures in Studio. Each page has a page type: a named kind of page that defines what the page is (e.g. “Home”, “Product Detail”, “Landing Page”), what URL shape it has, what data it needs, and how it appears in the Studio UI. The customer can add multiple pages of the same type (e.g. many landing pages) or a single page per type (e.g. one Home). Page types are the backbone of routing, link resolution, and the “Add page” experience in Studio.
Laioutr provides a page type abstraction so that:
slug → product query).As a developer, you work with page type tokens: each token is a string identifier (e.g. 'ecommerce/product-detail-page') plus metadata (path rules, required data, Studio label/icon, and which reference types it resolves). You define tokens with definePageTypeToken and register them so the rest of the platform can use them.
Every page type has a kind:
static – The page type can exist multiple times in the same project (e.g. Landing Page, Content Page). Each page has its own ID; path generation typically includes that ID (e.g. /landingpage-<id> or a slug).dynamic – The page type usually exists once per project and is often driven by a route (e.g. Home at /, Product Detail at /products/:slug, Search at /search). Path constraints describe the URL pattern and required params.pathConstraints tell the platform how URLs for this page type look:
exact – A fixed path (e.g. Home '/', or Shopify content '/pages/:slug').default – Default path pattern (e.g. /products/:slug+, /search, /categories/:slug+). Studio uses this when suggesting a path for a new page.requiredParams – List of route param names (e.g. ['slug']) so Studio can generate a path that includes them.If you don’t set exact or default, the platform derives a path from the page type name and requiredParams (e.g. for dynamic kinds).
Many page types need data that depends on the current route (e.g. “the product for this slug”). requiredQueries declare that:
'product', 'products').'Product', 'Category') for Studio/orchestration.slug: { join: ['/', { var: 'route.params.slug' }] } or query: { var: 'route.query.q' }).So the abstraction connects “this page type” to “this query, with these inputs from the route.” The runtime then loads the right data for each page instance.
Links in Laioutr can be:
type: 'pageType' – Point to a page type with optional params and query (e.g. search page with q). The link resolver finds the route whose page has that type and resolves to that route with the given params/query.type: 'reference' – Point to an entity (e.g. Product, Category) by referenceType, slug, and optional id. The resolver looks up which page type resolveFor that referenceType and then finds the route for that page type, passing the reference as params (e.g. product slug).So resolveFor on a page type means: “links that reference this entity type should resolve to a page of this page type.” For example, Product Detail Page has resolveFor: [{ referenceType: 'Product' }], so a Product reference link becomes the URL of the product-detail route with the product slug.
Metadata is defined in PageTypeToken.ts: name, kind ('static' | 'dynamic'), studio (label, group, icon, variantIcon, groupBy, description), requiredQueries, suggestedQueries, pathConstraints, resolveFor.
Laioutr defines common page types in @laioutr-core/canonical-types (or equivalent), for example:
'/'./products/:slug+, resolveFor Product./categories/:slug+, resolveFor Category./search, input from route.query.q.Apps can add more: e.g. Shopify (shopify/content-page), App Store (app detail, app category). Each app defines its token with definePageTypeToken and ensures the defining module is loaded (e.g. via a Nuxt plugin that imports the token).
The link resolver (useLinkResolver(), resolve(link)) in @laioutr-core/frontend-core:
So custom page types that declare resolveFor automatically participate in reference link resolution once their routes exist.
Studio (Cockpit) uses page type metadata to:
generatePagePath in cockpit).So your custom page type’s studio and pathConstraints directly control how it appears and how its URL is proposed in Studio.
Create a module that defines your page type with definePageTypeToken from @laioutr-core/core-types/frontend (or the frontend entry that re-exports it). Use a unique name (e.g. 'your-app/your-page-type').
// e.g. runtime/shared/pageTypes/my-detail.pagetype.ts
import { definePageTypeToken } from '@laioutr-core/core-types/frontend';
import { MyEntityBySlugQuery } from '../queries/MyEntityBySlug.query';
export const MyDetailPage = definePageTypeToken('my-app/my-detail-page', {
kind: 'dynamic',
studio: {
label: 'My Detail Page',
group: 'Custom',
icon: 'file-lines',
},
requiredQueries: [
{
alias: 'entity',
entityType: 'MyEntity',
default: {
label: 'Page Entity',
urlAlias: '_',
token: MyEntityBySlugQuery,
inputRules: { slug: { join: ['/', { var: 'route.params.slug' }] } },
},
},
],
pathConstraints: {
requiredParams: ['slug'],
default: '/my-entity/:slug',
},
resolveFor: [{ referenceType: 'MyEntity' }],
});
'static' if the customer can add many pages of this type; 'dynamic' if it’s typically one per project and route-driven.For a static page type (e.g. a simple custom landing type), you can omit requiredQueries and resolveFor and only set pathConstraints if you need a specific default path pattern.
Registration happens when definePageTypeToken runs. So the module that defines the token must be executed (e.g. imported). A common pattern is a Nuxt plugin that imports the token so the app bundle loads it:
// e.g. plugins/pagetypes.ts
import { defineNuxtPlugin } from '#app';
import { pageTypeTokenRegistry } from '@laioutr-core/core-types/frontend';
import { MyDetailPage } from '../shared/pageTypes/my-detail.pagetype';
export default defineNuxtPlugin(() => {
[MyDetailPage].forEach((token) => pageTypeTokenRegistry.getMetadata(token));
});
This ensures the token is registered before the link resolver or Studio needs it.
'my-app/my-detail-page'). The frontend matches routes to pages by this type.So: define the token, load it, and ensure your backend/Studio can create pages with that type and the frontend registers routes for those pages. Then link resolution and Studio behaviour for your page type will follow.
Multi-language Support
Laioutr’s multi-language support lets customers switch between multiple languages and regions on their frontend. It includes a language switcher component, a dark mode toggle, and optional informational links.
PWA
Turn your Laioutr frontend into a Progressive Web App—installable on devices, with offline support and an app-like experience—using zero-config defaults and optional customization.