4 Layout Template System Guidelines
namds29 edited this page 2025-12-25 03:25:09 +00:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Guidelines

  • We have defined 3 example pages which should be recreatable by our layout template system.
  • Our starting point is the next.js-starter template provided by medusa.
  • The starter template uses medusa ui .
  • Our Layout Template System should use medusa ui as base.
  • Custom Components should be built on top of medusa ui. If medusa ui does not provide a specific component, an independent custom component can be implemented.
  • To look into how different medusa patterns work, there are tutorials and resources for building a custom storefront.
  • Do not work destructively! This means guaranteeing that the new system can still represent the starter template design

Layout System

The Layout System is comprised of following modules:

  1. Data Layer: json data file
  • This file defines which component should be rendered where and how by parameters.
  • This should be the only file to edit.
  • A configloader.ts loads the json by filesystem.
  • It is abstracted as LayoutComponentNodes and LayoutContext
  1. Dynamic Render System
  • The Render System should be based on medusa next.js starter routes, components and templates.
  • Additional components and templates should be put into /vibentec/ subfolders
  • Each renderable component has to be added to the ComponentMap
  1. Shared dynamic Components
  • Each of the 3 example pages has to be analyzed and components have to be extracted so any of those different pages can be rendered by those same components.
  • This should never result in 3 different templates or components for the same ui-component or layouting block. (e.g. menu or button)
  • If the differences are great, try to manage differences by creating reusable sub-components first.
  1. Rules for Creating Custom Components
  • When creating a custom component, avoid creating singular components; instead, group related elements together to limit the length of the JSON file.
  • Components should be designed to allow flexible layout adjustments of the elements.
  • Once created, register the component in the component-map.tsx file. Set the key as the component's name, then map it back to the component you created for initialization when the JSON file uses that component.

Goal

  • Only the Json File is responsible for layout and design for the pages
  • Dynamic Render System uses json-file to build layout and page using shared dynamic components.

Layout Template System Guidelines

This guide explains how to configure and use the JSONdriven layout and page template system so UI components render only on the routes you intend.

Concepts

  • layout: global UI rendered around all pages (header, nav, PropsChildren, footer).
  • pages: routespecific UI, configured per page key (e.g., Home, Product).
  • DynamicLayoutRenderer: reads nodes and renders mapped React components.
  • componentMap: maps JSON keys to components and determines how config and children are passed.

Files

  • Design JSON: config/nam.mds-starter-design.json
  • Loader functions: src/vibentec/configloader.ts:1328
  • Component map: src/vibentec/component-map.tsx:76112
  • Renderer: src/vibentec/renderer.tsx:828
  • App layout usage: src/app/[countryCode]/(main)/layout.tsx:3445
  • Page usage (Home): src/app/[countryCode]/(main)/page.tsx:2742
  • Page usage (Product): src/app/[countryCode]/(main)/products/[handle]/page.tsx:102121

JSON Schema

Structure of the design file:

{
  "layout": [
    { "Header": { "config": { "sticky": true }, "children": [/* ... */] } },
    { "PropsChildren": {} },
    { "Footer": { "config": { /* footer columns */ } } }
  ],
  "pages": {
    "Home": [
      { "Hero": { "config": { "variant": "default", "className": "bg-custom-gradient" } } },
      { "VtFeaturedProducts": { "config": { "title": "best-seller" } } },
      { "FreeShippingPriceNudge": { "config": { "variant": "popup" } } }
    ],
    "Product": [
      { "VtFeaturedProducts": { "config": { "title": "best-seller" } } }
    ]
  }
}

See: config/nam.mds-starter-design.json:218, 188236.

Render Flow

  • App layout loads layout via loadLayoutConfig and renders it once for all routes: src/app/[countryCode]/(main)/layout.tsx:3445.
  • Each page loads its array via loadPageConfig("Key") and renders it where needed.

Example: Home

  • Loads and renders pages["Home"] with a layout context containing region and countryCode: src/app/[countryCode]/(main)/page.tsx:2742.

Example: Product

  • Renders ProductTemplate, then appends pages["Product"] below: src/app/[countryCode]/(main)/products/[handle]/page.tsx:115121.

Configuring Components

  • Components accept a config object and optional children arrays.
  • Map of available keys is defined in componentMap: src/vibentec/component-map.tsx:76112.
  • Two mapping strategies:
    • configOnly(Component): passes config props directly (e.g., banners like CartMismatchBanner).
    • nodesContextRenderer(Component): passes both nodes and rendering context (most layout templates).

VtFeaturedProducts

  • Place it under a page key to control visibility.
  • config.title can be a collection handle or title to filter rails.
  • Uses region and countryCode from the page context.

Example:

{
  "pages": {
    "Home": [
      { "VtFeaturedProducts": { "config": { "title": "best-seller" } } }
    ],
    "Product": [
      { "VtFeaturedProducts": { "config": { "title": "best-seller" } } }
    ]
  }
}

Hero

  • Configure variant and class names under the Home page to show only on the front page.

PropsChildren

  • Acts as a slot for the pages own React content.
  • Keep it in layout so page templates render inside the global shell.

Adding PageSpecific UI

  • Choose a page key like Home, Product, Category, Collection, Store.
  • Add an array under pages[Key] with your components.
  • In the corresponding page file, load and render:
import { DynamicLayoutRenderer } from "@vibentec/renderer"
import { loadPageConfig } from "@vibentec/configloader"
import { LayoutContext } from "@vibentec/component-map"

const nodes = await loadPageConfig("Home")
const context: LayoutContext = { /* region, countryCode, etc. */ }
return <DynamicLayoutRenderer nodes={nodes} context={context} />

Adding New Components

  • Implement a template component that accepts { nodes, context }.
  • Register the JSON key in componentMap using either nodesContextRenderer or configOnly.
  • Example map entry: src/vibentec/component-map.tsx:76112.

Selecting a Design File

  • Switch the active JSON file name in src/vibentec/devJsonFileNames.ts:18 and update fileName in src/vibentec/configloader.ts:5 if needed.
  • Current active file: jsonFileNames.namStarter.

Backward Compatibility

  • If the JSON is a toplevel array (legacy schema), loaders treat it as layout and pages resolve to empty arrays. Migrate incrementally by introducing pages per route.

Troubleshooting

  • Unknown component key logs a warning in the renderer: src/vibentec/renderer.tsx:1622.
  • Empty or missing pages[Key] renders nothing for that route.
  • Ensure page context includes region and countryCode when components depend on them.

Configuration Checklist

  • Update your design JSON with layout and pages keys.
  • Keep global UI under layout; place routespecific UI under pages[Key].
  • Verify page files call loadPageConfig("Key") and render DynamicLayoutRenderer.
  • Confirm componentMap includes the JSON keys you use.