Skip to content
Twilight React Playground
ثيم رائدaren

Category, MenuItem, Breadcrumb, Page

interfaceBeginner

Describes categories, menu links, breadcrumb steps, and the Page record a route loader returns to name the current page.

import { Category, MenuItem, Breadcrumb, Page } from '@salla.sa/twilight-theme-engine/types';

In plain words

Four small shapes that help shoppers find their way. A Category is a product category, possibly with sub_categories. A MenuItem is one link in a menu the merchant built, with its own children. A Breadcrumb is one step of a trail such as "Home › Chairs".

Page describes the page being shown: a slug naming its kind (such as product.single), a title, and optionally its breadcrumbs. Each engine route has a loader, a function that fetches the page's data before it renders, and every loader returns a page.

Signature

interface Category {
  id: number | string;            // the hashed id, e.g. 'QlayPG'
  id_?: number;                   // the numeric id, e.g. 1309167683
  name: string;  url: string;
  description?: string;  icon?: string | null;  image?: string | null;
  products_count?: number;
  sub_categories?: Category[];
  items?: null;
}

interface MenuItem {
  id: number | string;
  title: string;
  url: string;
  children?: MenuItem[];
  has_children?: boolean;
}

interface Breadcrumb { name: string; url: string }

interface Page {
  title: string;
  slug: string;                   // a RouteId value, e.g. 'product.index'
  description?: string;
  id?: string | number;
  url?: string;
  parent?: { id: string | number; name: string; url: string } | null;
  breadcrumbs?: Breadcrumb[];
}

Example

app/lib/categoryPage.ts
import { RouteId } from '@salla.sa/twilight-theme-engine';
import type { Breadcrumb, Category, Page } from '@salla.sa/twilight-theme-engine/types';

/** The page record a category listing's loader returns next to its own data. */
export function categoryPage(category: Category, homeLabel: string): Page {
  const breadcrumbs: Breadcrumb[] = [
    { name: homeLabel, url: '/' },
    { name: category.name, url: category.url },
  ];

  return {
    slug: RouteId.PRODUCT_INDEX,
    id: category.id_ ?? category.id,
    title: category.name,
    breadcrumbs,
  };
}

How it behaves

  • category.list() and category.find(id) (@salla.sa/twilight-theme-engine/api/category) return Category; menu.header() and menu.footer() (/api/menu) return MenuItem[]. The category on a product is the smaller ProductCategory.

  • After a route loads, the engine takes the page of the deepest route match that returned one, stores it as getTwilightContext().page, and hands it to the Salla SDK with Salla.config.set('page', …), adding url from the address bar when the page has none.

  • useBreadcrumbs(page) returns page.breadcrumbs when the loader set them, and otherwise builds Home › page.title (nothing on the home page). The Breadcrumb component takes a page and renders that trail.

  • Category and menu urls are absolute store addresses (https://demostore.salla.sa/ar/dev-vgckq3fssfhjewwi/offers on the demo store). The engine MainMenu passes item.url to Link unchanged; do the same rather than cutting the address apart.

Gotchas

  • Category.id is the hashed id ("QlayPG" on the demo store). The numeric id is id_, and only id_ works as a products sourceValue.

  • Menu item ids are not always numbers, or present: header items use slugs such as "offers", and some footer items have no id at all (demo store). key={item.id} then produces duplicate keys; use item.id ?? item.url.

  • Menu items also carry target, attrs, link_attrs and order, which the type leaves out (demo store). target is the link target the merchant chose; reading it needs a cast.

  • A route whose loader returns no page does not clear the previous one: after a client-side navigation, getTwilightContext().page and the SDK's page config still describe the last page that had one. Return a page from every page loader.

Related

Source and docs