Skip to content

Instantly share code, notes, and snippets.

@screeny05
Created July 6, 2026 10:26
Show Gist options
  • Select an option

  • Save screeny05/04b3712e0d771b4ab55b118e9227dc63 to your computer and use it in GitHub Desktop.

Select an option

Save screeny05/04b3712e0d771b4ab55b118e9227dc63 to your computer and use it in GitHub Desktop.
Frontend-Core 0.33.0 & Laioutr UI 2.5.0

Release notes

Core 0.33.0

Minor Changes

  • Emit SEO and locale head tags automatically on every page. Each page now renders a self-referential <link rel="canonical">, <link rel="alternate" hreflang> alternates for every market domain plus x-default, og:locale / og:locale:alternate, and <html lang> — with no per-page or per-layout call required. Alternates are scoped to a page's marketIds, so a market-restricted page never advertises (or links to a 404 for) markets it does not belong to. MetaPage gains an optional marketIds field that carries this scope onto the route.

    Customize the emitted head with one new filter hook, registered in a Nuxt plugin: frontend-core:page-head:resolve. Its result.value carries frontend-core's computed head in two slots — seo (title, description, robots, and any og/twitter field) and locale (canonical, hreflang, og:locale, html lang) — so a handler can add, override, or remove any tag.

    Breaking: the useMarketHead() composable is removed. hreflang and canonical links are now emitted automatically, and the frontend-core:page-head:resolve hook replaces the customization it offered.

    // Before — manual call, typically in a layout
    useMarketHead();
    
    // After — nothing to call; to customize, register the hook in a plugin
    nuxtApp.hook('frontend-core:page-head:resolve', ({ result }) => {
      result.value.locale.link = result.value.locale.link.filter((l) => l.hreflang !== 'x-default');
    });

Patch Changes

  • Closed-option fields (select / radio / toggle_button) now clamp a stored value that isn't one of the field's declared options to a valid option when resolving render props, instead of passing it through. Previously a malformed stored value (e.g. a double-encoded select value) could reach a dynamic component tag and throw at render, breaking the page.

UI 2.5.0

Minor Changes

  • Breaking: DescriptionList is renamed to BasicTable and DescriptionListItem to BasicTableRow — the generic two-column label/value table primitive (outlined / plain variants). The label column is now overridable via the public --basic-table-label-col custom property. OpeningHoursWeeklyTable also moves out of ui-kit into @laioutr-core/ui as TableOpeningHours.

    Repoint imports:

    -import DescriptionList from '#ui-kit/components/DescriptionList/DescriptionList.vue';
    -import DescriptionListItem from '#ui-kit/components/DescriptionList/DescriptionListItem.vue';
    +import BasicTable from '#ui-kit/components/BasicTable/BasicTable.vue';
    +import BasicTableRow from '#ui-kit/components/BasicTable/BasicTableRow.vue';
    
    -import OpeningHoursWeeklyTable from '#ui-kit/components/OpeningHoursWeeklyTable/OpeningHoursWeeklyTable.vue';
    +import TableOpeningHours from '#ui/components/TableOpeningHours/TableOpeningHours.vue';

    BasicTable now renders as a semantic description list (<dl> with <dt>/<dd> rows) instead of presentational <div>s, so label/value pairs are exposed to assistive technology. Grid/subgrid layout and the public CSS surface (.basic-table root class, BEM classes, --basic-table-label-col) are unchanged. (DEV-370)

  • Editors can now override typography size and colour per heading and subline region in ContentGrid, ContentSlider, CategoryCardGrid, CategoryCardSlider, and EditorialGrid sections — selectable inline next to the existing Heading as / Subline as controls. Leaving the new Text Size at Default keeps the previous rendering. (DEV-31)

  • Add CountdownBoxed, a countdown that renders each unit (days, hours, minutes) as boxed digit tiles with a label, in four painted styles (default / pale / bright / solid). It counts down to an endDate (no start date) and reuses the existing useCountdown clock. (DEV-47)

  • Per-field Body Size + Color Override (DEV-31 C + B Foundation)

    @laioutr-core/ui-kit — Card gains four optional props:

    • bodySize?: TextSize (default 's') — typography size for the description / body block.
    • captionColor? / headingColor? / sublineColor? / bodyColor?: string — CSS-value colour overrides. When unset (or 'initial'), the theme's default colour applies.

    All four are pure additions; existing call sites render identically.

    @laioutr-app/ui:

    • New shared field shared-fields/textColor.ts — exports textColorField (name 'color', type 'color', allowCustom: true). Use inline next to textSizeField in headingStyle / sublineStyle / bodyStyle / contentStyle decorators.
    • BlockText and BlockCard extended end-to-end: schema adds textColor next to textSize in every style decorator, plus a new bodyStyle (on BlockText) / extended contentStyle (on BlockCard) that exposes both for the body region. Template forwards via colorValueToCss to Card's new *Color props.

    Caption text in CaptionFlag-based banners still has no colour override at the size scale — depends on a separate ui-kit primitive change to CaptionFlag.

  • Breaking — Card: the single textSize prop has been split into three per-region props: captionSize, headingSize, sublineSize. The new props accept the full typography scale ('xs' | 's' | 'sm' | 'm' | 'ml' | 'l' | 'xl' | '2xl' | '3xl' | '4xl').

    Defaults reproduce the previous textSize='m' behaviour exactly: captionSize='s', headingSize='ml', sublineSize='m'. Existing consumers that did not pass textSize render identically.

    Consumers that previously passed :text-size="'s'" must update to:

    <Card :caption-size="'xs'" :heading-size="'m'" :subline-size="'sm'" />

    :text-size="'l'" maps to captionSize='sm', headingSize='l', sublineSize='ml'.

    The body-text (description) size is now fixed to 's' (the historical default for textSize=undefined). If a different body size was previously achieved through textSize, it is no longer adjustable via Card — wrap the description content in a <Text> element with an explicit size instead.

    Breaking — LTextGroup / SwiperChrome text tags: the captionTag prop (and the TextGroupCaptionTag type) are removed — the caption always renders as <span>. headingAs / sublineAs no longer accept 'span'; a heading or subline is always block-level (h1h6 / div, and p for subline). No shipped configuration used either, so no data migration is required.

    Breaking — shared typography types: the per-component TextGroupTextSize, TextGroupHeadingAs, and TextGroupSublineAs are replaced by TextSize, HeadingTag, and SublineTag, exported from the new #ui-kit/types/text module (consumed by Card, LTextGroup, and SwiperChrome). Update imports:

    // before
    import type { TextGroupHeadingAs, TextGroupTextSize } from '#ui-kit/components/TextGroup/TextGroup.vue';
    // after
    import type { HeadingTag, TextSize } from '#ui-kit/types/text';
  • Add an independent tablet aspect-ratio stage to Sizer and move the responsive-fixed desktop switch to the --lg breakpoint (DEV-341)

    Sizer now resolves both responsive-aspect-ratio and responsive-fixed against one breakpoint scheme, in lockstep with the Columns grid:

    • mobile (< --sm, < 600px) — mobile values
    • tablet (@media (--sm), 600–1279px) — new aspect-ratio stage, falling back to the mobile ratio when unset
    • desktop (@media (--lg), ≥ 1280px) — desktop values

    New Sizing.aspectRatioTablet field and --sizer-aspect-ratio-tablet custom property. The aspectRatioMobile / aspectRatioDesktop keys are unchanged.

    Breaking: existing configs render differently across the 600–1279px band.

    • responsive-aspect-ratio configs with only a mobile and desktop ratio now show the mobile ratio from 600–1279px (previously the desktop ratio applied from 800px up). Set aspectRatioTablet to give tablets their own ratio.
    • responsive-fixed configs now switch to the desktop height at 1280px instead of 800px, so the mobile height covers 0–1279px.
    // responsive-aspect-ratio at a 900px viewport
    before: desktop ratio
    after:  mobile ratio (or aspectRatioTablet, when set)
    
  • Breaking: BenefitsBox now renders a single benefits list. The dedicated free-delivery row is gone — deliveryBenefit and isFreeDelivery were removed from BenefitsBoxProps. Free delivery is now just a regular benefit; add it as an entry in benefits.

    // before
    <BenefitsBox :delivery-benefit="delivery" :is-free-delivery="false" :benefits="benefits" />
    
    // after
    <BenefitsBox :benefits="[delivery, ...benefits]" />

    (DEV-170)

  • Editors can now override typography size (and, where the existing schema didn't already expose one, colour) per heading and subline region in the Brand Hero, Page Hero, Page Not Found, Newsletter Registration, Product Slider, Product Slider Showcase, Logo Slider, and Logo Grid sections — selectable inline next to the existing Heading as / Subline as controls. Leaving the new Text Size at Default keeps the previous rendering. (DEV-31)

  • PriceInfo: make the texts below the price configurable. New optional props strikethroughPriceLabel, vatInfo, shippingPrefix, and shippingSuffix override the respective labels, each falling back to its existing pdp.* locale string when empty. The new vatInfoVisible prop toggles rendering of the tax/legal note, which previously always rendered. The displayed price values are unchanged. (DEV-329, SUPPORT-11)

  • Per-field Text Size — Banner & HeroSlide rollout.

    @laioutr-core/ui:

    • BannerBasic, BannerIntegrated, BannerShowcase gain optional headingSize (and where applicable sublineSize) props on the full 10-step typography scale. Existing internal size→heading mappings remain as fallback defaults when the override is unset, so existing call sites render identically.
    • HeroSlide: headingSize / sublineSize widened from 's' | 'm' | 'l' to the full 10-step scale. Existing values ('s' | 'm' | 'l') remain valid — pure widening.
    • Banner, HeroSlide, and the content / product / logo / category sliders and grids now type their headingAs / sublineAs / size props with the shared HeadingTag / SublineTag / TextSize from #ui-kit/types/text instead of per-component unions. Breaking: sublineAs no longer accepts 'span' (a subline is always block-level: p / h1h6 / div); no shipped configuration used it.

    @laioutr-app/ui:

    • headingStyle / sublineStyle style decorators in SectionBannerBasic, SectionBannerIntegrated, SectionBannerShowcase, BlockBannerBasic, BlockBannerIntegrated, BlockBannerShowcase now expose an inline textSize select. Templates resolve via resolveOverride and forward to the underlying ui-component's per-region size prop.
    • BlockHeroSliderSlide is not yet migrated — it already has a legacy size field (S/M/L) on its headingStyle / sublineStyle that conflicts conceptually with textSize. Unifying the two requires a one-time RcProject migration manifest and is a separate change.

    Caption sizing (captionVariant.textSize) remains out of scope pending CaptionFlag refactor + caption typography tokens beyond xl.

  • PopUpPromotion can now show a countdown instead of a coupon: set countdownEndDate (and the optional countdownVariant) to render a CountdownBoxed. (DEV-47)

  • Container: add gapMobile / gapDesktop props to configure the spacing between child elements per breakpoint. auto (the default) preserves the previous hardcoded gap; an explicit value (none|s|m|l|xl) drives both axes. The gap now also applies at a single column (with two or more children) instead of only when a multi-column grid is active. (DEV-373, SUPPORT-8)

  • Add TableOpeningHours (moved from ui-kit, now built on the BasicTable primitive) and TableProductSpecifications. TableOpeningHours keeps its weekday-grouping logic and gains an outlined / plain variant; TableProductSpecifications renders specification rows over BasicTable, formatting each typed value (string | number | boolean | Measurement | Money) per locale via the new TableProductSpecificationsValue subcomponent, and grouping rows into sections when a sectionName is present. (DEV-370)

  • BannerIntegrated and BannerShowcase: render the caption through CaptionFlag and accept a captionVariant prop ({ variant, colorScheme, textShadow }), matching BannerBasic and the Hero Slider caption. This enables plain/boxed styling, a colour scheme, and a text shadow on the banner caption.

    Breaking: the captionColor prop was removed from BannerIntegrated and BannerShowcase — caption colour is now governed by captionVariant.colorScheme (only applied in the boxed variant). Migrate a freeform caption colour to a boxed caption:

    <!-- before -->
    <BannerShowcase caption="Sale" caption-color="#ffffff" />
    <!-- after -->
    <BannerShowcase caption="Sale" :caption-variant="{ variant: 'boxed', colorScheme: 'primary' }" />

    The default (plain caption, no shadow) renders via CaptionFlag; the caption now follows the shared caption-flag typography (uppercase) like the other banners. (DEV-342, SUPPORT-26)

  • SectionBannerBasic, SectionBannerIntegrated, and SectionBannerShowcase: expose the caption-styling controls (plain/boxed style, colour scheme, text shadow) at the caption field in Studio, identical to the Hero Slider caption. The colour control is only shown when the style is set to boxed. Existing banners keep their look (default plain, no shadow). (DEV-342, SUPPORT-26)

  • Content Slider: added a "Card-Design" panel that lets editors choose the heading element (H1–H6 / DIV) for cards generated from a blog collection (query mode). The section's own styling panel is now labelled "Slider-Design" to distinguish it from the card controls.

  • Per-field Text Size foundation. Editors can now override the typography size for heading and subline regions independently of the block-wide size (S / M / L) default, on the full 10-step scale (xs · s · sm · m · ml · l · xl · 2xl · 3xl · 4xl).

    New shared field:

    • shared-fields/textSize.ts — exports textSizeField (select, first option 'auto' = inherit) and textSizeOptions. Use inline as a second field in any headingStyle / sublineStyle style decorator.

    New utility:

    • utils/resolveTextSize.tsresolveHeadingSize / resolveSublineSize / resolveCaptionSize (map a block 's' | 'm' | 'l' + optional override to a region-specific size) plus resolveOverride (override-or-undefined, for Card-style blocks without a block-level size default).

    Migrated to the new pattern in this release:

    • BlockText — heading + subline both honour headingStyle.textSize / sublineStyle.textSize.
    • BlockCard — heading honours headingStyle.textSize.

    Caption (captionVariant) is intentionally not included yet — CaptionFlag has no size prop today and caption tokens stop at xl. Tracking as a follow-up.

    The remaining sections/blocks that have headingStyle / sublineStyle are unchanged for now; their schemas will gain textSize as their underlying ui-component is widened to accept per-region sizes.

  • BlockPopUpPromotion now offers a Promotion type toggle to switch between a voucher (discount code) and a countdown. The countdown runs toward a configurable end date and exposes a style selector. (DEV-47)

  • SectionContainer: expose Gap (Mobile) and Gap (Desktop) controls in Design → Layout so editors can set the spacing between child elements. Fixes the 0px vertical gap on single-column mobile layouts. (DEV-373, SUPPORT-8)

  • Add SectionPopUp, a modal overlay section, together with three content blocks selectable in its slot: BlockPopUpInfo, BlockPopUpNewsletter, and BlockPopUpPromotion. The section wraps the PopUp component and each block wraps its matching PopUpInfo / PopUpNewsletter / PopUpPromotion component, exposing their content and layout as Studio fields. The pop-up opens on mount and can be dismissed by the visitor; triggers, scheduling, and frequency capping are not wired yet. (DEV-47)

  • Add a Tablet aspect-ratio field to sizingField and clarify the sizing Mode copy (DEV-341, DEV-333)

    • A Tablet aspect-ratio field now sits between Mobile and Desktop, shown when the mode is responsive-aspect-ratio. It maps to Sizer's aspectRatioTablet and falls back to the Mobile ratio when left empty. Mobile / Desktop are unchanged.
    • The Mode select now describes each mode in plain intent words, with hints for Auto and Fill. No runtime change — auto still applies no height, fill still fills the parent's height.

    BlockMedia and BlockIframe use the shared sizingField, so they pick up the Tablet field automatically. Their prop types are unaffected.

  • Add two standalone Studio blocks: BlockTableOpeningHours and BlockTableProductSpecifications. Each can be filled either from a query (a Location's opening hours / a Product's specifications) or with manually entered rows, switchable via a Data Source toggle, and exposes an outlined / plain style toggle. BlockTableProductSpecifications forwards the product's typed specification values unchanged and supports per-row sections (an optional Section field on manual rows) for grouped output. (DEV-370)

  • Hero-slider slides now use the same Text Size selector as every other section and block (the 10-step scale xs · s · sm · m · ml · l · xl · 2xl · 3xl · 4xl plus Default). The former slide-specific S/M/L size selector on BlockHeroSliderSlide's headingStyle and sublineStyle has been replaced by the canonical textSizeField. Existing slides with a stored size of 's' / 'm' / 'l' are rewritten to the new textSize field via the migration manifest — the values stay valid on the new scale, so the rendering is unchanged. (DEV-380)

  • BlockProductDetailPriceInfo: add Studio fields to configure the texts below the price (strikethrough-price label, tax/legal note with a visibility toggle, and shipping-note prefix/suffix). Empty fields keep the translated defaults. The block now also binds the variant's shipping rate (already fetched via ProductVariantShipping), so the shipping line ("zzgl. 5,95 € Versand") renders on the PDP. All values still come from the product — no query change. (DEV-329, SUPPORT-11)

  • Breaking: BlockProductDetailBenefitsBox no longer has a separate free-delivery configuration. The deliveryBenefit object field and the forced free-delivery row were removed — the block now exposes only the benefits list, with free delivery pre-filled as a normal, removable default benefit. Stored configs lose their deliveryBenefit/isFreeDelivery values; re-add free delivery as a benefit entry where needed.

    (DEV-170)

Patch Changes

  • Accordion now expands and collapses smoothly instead of jolting open. The content animation easing changed from ease-out to ease-in-out (and the duration from 0.2s to 0.25s), so the content slides rather than shooting out and decelerating. The catch-all transition: all on the item was also narrowed to the properties that actually change (background-color, outline-color, border-color).

  • CaptionFlag: hug the caption text (width: fit-content) instead of stretching to full width when placed as a flex item in a column with align-items: stretch (e.g. a banner text stack). Center/end alignment from the parent is still honoured. Fixes the boxed caption spanning the full banner width. (DEV-342, SUPPORT-26)

  • LinkTileBasic images now render sharp at any tile width.

    The <Media> sizes hint on LinkTileBasic stays at its nominal 103px but now enables retina, so a standalone tile is crisp on 2× displays. When the tile is stretched to fill a grid cell, CategoryCardGrid provides a layout-accurate, breakpoint-aware sizes value (via MediaSizesProvider) for every variant and column-count, so <Media> requests an appropriately sized srcset instead of upscaling the 103px image. (DEV-69)

  • OptionTileText and OptionTileImage now expose their state to assistive technology. The selected option is signalled via aria-pressed (previously only a CSS class, so screen readers couldn't tell which option was active), unavailable tiles carry aria-disabled="true" and the same aria-pressed state as available ones, and OptionTileImage buttons get an accessible name from the label prop via aria-label (it was previously never rendered). Both buttons are also explicitly type="button". This makes the variant selector composing these tiles (VariantSelectorOptions) announce option state correctly.

  • SwiperChrome: bottom-rendered slider navigation now aligns to textAlign instead of always rendering centered. Fixes misaligned buttons in the Logo Slider (and other SwiperChrome-based sliders) on mobile when the section is set to left alignment. (DEV-369)

  • MobileMenuBasic: the social icon buttons in the footer now use the ghost-white button style with a white icon instead of secondary-white with a dark icon. The variant follows the documented design (ghost buttons on a colored footer background). (DEV-348)

  • QuoteCard: das Logo rendert jetzt scharf auf Retina/HiDPI-Displays. Die Media-Komponente bekommt das retina-Flag, sodass für die fix-breite Anzeige (130×50) zusätzlich eine 2x-Variante im srcset ausgespielt wird statt nur die 1x-Variante hochzuskalieren. (DEV-379)

  • The Basic Header's mobile menu button now adapts to the header's surface tone. Previously the button surface and the menu icon stayed dark regardless of the header configuration, so on a header set to light text on a dark background the button and its icon were invisible. The trigger now switches to the light token set on dark headers, and its icon colour follows the active theme instead of a hardcoded black. (DEV-349)

  • SectionProductSliderShowcase: add an "Image background" colour control for the product tiles and pass it through as the tile fallbackColor, so the tile image background can be set — matching the normal Product Slider. Previously the showcase's tiles had no image-background option (its existing "Image Background" field styles the banner, not the tiles). (DEV-70)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment