Replies: 1 comment 5 replies
|
Proposed API: import { LinkConfig } from '@/models/shared.model';
export interface Config {
header: HeaderConfig;
breadcrumbs: BreadcrumbsConfig;
footer: FooterConfig;
}
/**
* Header configuration.
*/
interface HeaderConfig {
/**
* Organization-wide header, shared across all apps.
*/
globalHeader: {
postLogo: ImageLinkConfig; // Link behind the Post logo.
audience?: Array<SimpleLinkConfig>; // Optional audience selection links (e.g. "Private customers", "Business customers").
primaryNavigation?: Array<IconLinkConfig>; // Primary navigation items: remain visible in the header on tablet and mobile.
secondaryNavigation?: Array<IconLinkConfig>; // Secondary navigation items: move to the footer of the burger menu on tablet and mobile.
languages?: Array<LanguageLinkConfig>; // Language menu options.
postLogin?: {
loginLink: IconLinkConfig; // Login link when the user is not authenticated.
accountSwitch: IconLinkConfig; // Shown when appropriate based on the user data
companySwitch: IconLinkConfig; // Shown when appropriate based on the user data
userProfile?: IconLinkConfig;
settings?: IconLinkConfig;
userLinks?: Array<IconLinkConfig>; // Additional actions available when the user is authenticated.
logoutLink: IconLinkConfig; // Logout link when the user is authenticated.
}
};
/**
* Application-specific header.
*
* At least one of `title` or `mainNav` should be present.
*/
localHeader: {
title?: string; // Application or page title.
mainNavigation?: Array<SimpleLinkConfig | MegadropdownConfig>; // Main navigation for the current application.
navigation?: Array<IconLinkConfig | UserMenuConfig>; // Optional application-specific actions (e.g. user menu, extra links).
};
}
/**
* Breadcrumb trail from the root to the current page.
*/
interface BreadcrumbsConfig {
rootUrl: string; // Base URL used for the first breadcrumb.
items: Array<SimpleLinkConfig>; // Ordered breadcrumb links, from root to current page.
}
/**
* Footer configuration.
*/
interface FooterConfig {
prefooter?: LinkListConfig<SimpleLinkConfig>; // Links to display in an optional pre-footer.
sections?: Array<LinkListConfig<SimpleLinkConfig>>; // Main footer sections.
socialLinks?: LinkListConfig<IconLinkConfig>; // Social media links (e.g. Facebook, LinkedIn, YouTube).
appStoreLinks?: LinkListConfig<ImageLinkConfig>; // App store links (e.g. App Store, Google Play).
companyLinks?: LinkListConfig<SimpleLinkConfig>; // Links to other Post websites.
complianceLinks?: LinkListConfig<SimpleLinkConfig>; // Legal and compliance links (e.g. Terms & Conditions, Data Protection).
copyright?: string; // Copyright notice text displayed at the very bottom.
}
/**
* A navigation item that opens a large dropdown panel
* with multiple grouped link sections.
*/
interface MegadropdownConfig {
trigger: AccessibleTextConfig; // Text used for the clickable trigger in the header.
overview?: SimpleLinkConfig; // Optional overview link for the dropdown.
sections: Array<LinkListConfig<SimpleLinkConfig>>; // Sections inside the dropdown.
}
/**
* A titled group of navigation links.
*/
interface LinkListConfig<T extends SimpleLinkConfig = LinkConfig> {
title: string | SimpleLinkConfig; // List heading (plain text or link).
items: Array<T>; // Links contained in this list.
}
/**
* Language option (for language menu).
*/
interface LanguageLinkConfig extends SimpleLinkConfig {
code: string; // Short language code (e.g. "en", "de", "fr").
}
/**
* A navigation link that also displays an image (e.g. app store badge).
*/
interface ImageLinkConfig extends SimpleLinkConfig {
image: {
src: string; // Image URL.
alt: string; // Alternative text for the image.
};
}
/**
* A navigation link with a text label and an icon.
*/
interface IconLinkConfig extends SimpleLinkConfig {
icon: string; // Icon name.
}
/**
* Basic navigation link with a URL and accessible text.
*/
interface SimpleLinkConfig extends AccessibleTextConfig {
url: string; // Target URL of the link.
active?: boolean; // Whether the link represents the current page.
}
/**
* Accessible text information for any UI element.
*/
interface AccessibleTextConfig {
text: string; // Base text content, can be visible or visually hidden.
label?: string; // ARIA label, screen readers will use this instead of `text`.
description?: string; // ARIA description for additional context, read after `text` or `label`.
} |
5 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
This is an attempt at describing the required data structure for a configuration based header v2. It was created in July 2024 so it likely needs some adaption to the updated header concept, but can serve as a starting point.
Old proposal, deprecated, see below
```typescript /** * Questions: * * Meeting 19.08.: * - How can icons be loaded/displayed efficiently (SSR)? -> Store number in sanity (create icon select component for sanity) * - How can the logo image be loaded/displayed efficiently? -> Sanity Asset Management CDN, maybe not only link but also size information available via config * - Does it make sense/is it possible to version the API? -> Possible when implementing an API on next.js * * Open: * - Does it make sense to handle skiplinks through the config? * - Not sure if user menu really is a generic array? * - Should header and footer config be separate endpoints (so they can be used independently of each other or footer data can be lazy loaded)? *//**
*/
/**
*/
interface Config {
header: Header;
footer: Footer;
}
/**
/
interface Header {
/*
*/
title: AccessibleText;
/**
/
globalNavigation: {
/*
*/
logo: {
link: Link;
image: Image;
};
};
/**
*/
contentNavigation?: {
menuButton: Button; // "Menü", displayed on mobile
closeButton: Button; // Button for closing megadropdown
backButton: Button; // "Zurück", "Zurück zur vorherigen Navigation", Button for goin back in the mobile menu
pageTitle?: AccessibleText;
navigationTitle: AccessibleText; // "Hauptnavigation", accessible name for the navigation
linkList: LinkList<LinkList> | StatefulLink; // Either a link or a megadropdown
};
/**
*/
applicationNavigation?: {
menuButton: Button; // "Menü"
navigationTitle: AccessibleText; // "Hauptnavigation", accessible name for the navigation
applicationTitle?: AccessibleText;
linkList: LinkList | StatefulLink; // No megadropdown possible, just a simple link list or a link
};
}
/**
*/
interface Footer {
title: AccessibleText;
/**
*/
directEntryLinks?: LinkList;
/**
*/
aboutLinks?: LinkList;
/**
*/
helpAndContactLinks?: LinkList;
/**
*/
serviceLinks?: LinkList;
/**
*/
socialLinks?: LinkList;
/**
*/
appStoreLinks?: LinkList;
/**
*/
companyLinks: LinkList;
/**
*/
complianceLinks: LinkList;
/**
*/
copyright: string;
}
// ========================================================== Shared interfaces & types ========================================================== //
/**
*/
interface AccessibleText {
text?: string; // What's displayed on screen
label?: string; // aria-label, replaces text for screenreaders
description?: string; // aria-description, being read after text or label
// title?: string; // Intended to be displayed as tooltip, acts like description for screenreaders <-- not used in the header
}
/**
*/
interface Link extends AccessibleText {
href: string;
attributes?: AnalyticsAttribute[];
}
/**
*/
interface Button extends AccessibleText {
attributes?: AnalyticsAttribute[];
}
/**
*/
interface StatefulLink extends Link {
active: boolean;
}
/**
*/
interface LanguageOption extends Link {
label: string; // Label is not optional for languages
languageShortCode: string; // ISO 639 2 char short code https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes
}
/**
*/
interface AnalyticsAttribute {
name: string;
value: string;
}
interface CoveoEnvironment {
organisation: string;
token: string;
}
interface Icon {
iconNumber: number;
}
interface Image {
src: string; // Source URL
width?: number; // Width in pixels
height?: number; // Height in pixels
alt: string; // Alternative text
}
type LinkWithIcon = Link & Icon;
interface LinkList<T = Link> {
title: AccessibleText;
linkList: T[];
}
/**
*/
interface InputField extends AccessibleText {
placeholder?: string;
}
All reactions