${e(stage.title)}
${e(stage.description)}
// @requirements REQ-PRODUCT-CF-HOST REQ-PRODUCT-MOBILE REQ-PRODUCT-A11Y // Shared task groups keep website entry points, examples and guides in the same order. const guide=(slug,label)=>({href:'/guide/'+slug,label}); const topic=(id,title,href,description,guideSlug,variants=[],section='')=>({id,title,href,description,guide:'/guide/'+guideSlug,variants:variants.map(([label,href])=>({label,href})),section}); export const siteSections=[ {id:'start',title:'Start here',description:'Configure your site, identify services and choose the components you need.',guides:[guide('package','Package & configuration'),guide('setup','Guided setup'),guide('discovery','Project discovery'),guide('service-catalog','Service catalog')],topics:[ topic('setup','Guided setup','/demo/admin/setup','Work through site practices and keep the reasons behind each configuration choice.','setup'), topic('discovery','Service discovery','/discovery','Inspect detected services and review what belongs in your site configuration.','discovery') ]}, {id:'privacy-information',title:'Publish privacy information',description:'Legal pages, service disclosures and notices beside the point of collection.',guides:[guide('services','Service directory'),guide('collection','Collection notices'),guide('indirect-collection','Indirect collection'),guide('rights','Privacy request links')],topics:[ topic('documents','Privacy, cookie & terms pages','/privacy','Static documents using the site’s typography, layout and declared processing.','package',[['Cookie policy','/cookies'],['Terms page','/terms'],['Dark','/dark/privacy']]), topic('services','Service directory','/services','Explain declared third parties and the purposes, data and storage associated with them.','services',[['Dark','/dark/services']]), topic('collection','Collection notice','/collection','Show privacy information beside a form, linked to an exact policy revision.','collection'), topic('indirect-collection','Indirect collection notice','/indirect-collection','Explain information received from another source, including advance-notice text.','indirect-collection'), topic('rights','Privacy request entry points','/rights','Give people clear contact and application routes for privacy requests.','rights') ]}, {id:'privacy-choices',title:'Manage privacy choices',description:'Cookie preferences, optional permissions and controls for tracking and processing.',guides:[guide('consent','Cookie choices'),guide('embeds','Gated media'),guide('storage-cleanup','Storage cleanup'),guide('form-permissions','Form permissions'),guide('privacy-signals','Global Privacy Control'),guide('processing-choices','Recorded opt-outs'),guide('google-basic','Google Basic'),guide('regional-prompts','Consent timing'),guide('scope-guards','Scope guards')],topics:[ topic('cookies','Cookie choices','/choices','Accept, reject or choose purposes, then see which declared services may run.','consent',[['Dark','/dark/choices']]), topic('embeds','Gated media','/embeds','Keep frames and images inert until their declared service is allowed.','embeds'), topic('storage','Storage cleanup','/storage-cleanup','Remove declared browser markers after withdrawal while leaving unrelated storage alone.','storage-cleanup'), topic('permissions','Form permissions','/form-permissions','Record an optional purpose and channel, with independent withdrawal and recovery.','form-permissions',[['React','/form-permissions/react/'],['Astro','/form-permissions/astro/']]), topic('signals','Global Privacy Control','/privacy-signals','Apply a browser privacy signal independently of optional cookie preferences.','privacy-signals'), topic('opt-outs','Processing opt-outs','/processing-choices','Record restrictions and inspect their current state alongside the original request.','processing-choices'), topic('exceptions','UK storage settings','/storage-exceptions','Separate on/off settings for declared statistical and appearance exceptions.','storage-exceptions',[],'Specialist controls'), topic('google','Google Basic simulator','/google-basic','Inspect the declared signals without loading a live Google tag.','google-basic',[],'Specialist controls'), topic('prompts','Consent timing','/repeat-prompts','Compare calendar grant expiry with independent rules for asking again.','regional-prompts',[],'Specialist controls'), topic('guards','Scope guards','/scope-guards','See how explicit site and purpose restrictions affect available controls.','scope-guards',[],'Specialist controls') ]}, {id:'contracts',title:'Terms and purchases',description:'Version-bound terms agreements and separate consumer-contract information and actions.',guides:[guide('terms','Terms agreements'),guide('guarantees','Guarantee notices'),guide('guarantee-labels','Product guarantee labels'),guide('guarantee-producer-example','Producer label example'),guide('paid-orders','Paid order reviews'),guide('contract-actions','Withdrawal & cancellation'),guide('contract-dispatch','Contract delivery runners')],topics:[ topic('agreement','Terms agreement','/agreement','An unchecked statement tied to the exact terms version and action wording.','terms',[['Portuguese','/localization/agreement/']]), topic('guarantee-notice','EU guarantee notice','/guarantees','Display the shop-level legal guarantee notice and its readable wording.','guarantees',[],'Consumer contracts'), topic('producer-label','Product guarantee label','/guarantees/product/','Place the complete producer guarantee label beside the product it covers.','guarantee-labels',[['Preparation & source','/guide/guarantee-producer-example']],'Consumer contracts'), topic('orders','Paid order review','/orders/mixed/','Present items, commitments and prices immediately before an explicit payment action.','paid-orders',[['Deposit & balance','/orders/deferred/'],['Conditional fee','/orders/conditional/'],['Dark','/dark/orders/mixed/']],'Consumer contracts'), topic('withdrawal','Contract withdrawal','/contract-actions/withdrawal','Inspect the declaration and its separate confirmation and application handoffs.','contract-actions',[],'Consumer contracts'), topic('cancellation','Contract cancellation','/contract-actions/cancellation','Try the German cancellation flow and review its retained request.','contract-actions',[],'Consumer contracts') ]}, {id:'records',title:'Keep and inspect records',description:'Retained versions, recorded choices, private inspection, exports and lifecycle controls.',guides:[guide('order-confirmations','Customer confirmations'),guide('releases','Retained releases'),guide('consent-evidence','Cookie-choice evidence'),guide('evidence-export','Evidence export'),guide('evidence-lifecycle','Retention & holds')],topics:[ topic('confirmations','Customer confirmations','/demo/admin/orders','Inspect retained customer copies, exact attachments and current delivery status.','order-confirmations'), topic('history','Document revisions','/demo/admin/history','Compare policy versions, authored source and rendered differences.','authoring'), topic('recorded-cookies','Recorded cookie choices','/recorded-choices','Follow a browser report from its pinned notice to a matching server receipt.','consent-evidence'), topic('releases','Public retained releases','/releases','Read two retained document versions at their original immutable addresses.','releases'), topic('catalog-history','Retained service references','/catalog-releases','Compare service-catalog selections separately from published legal text.','service-catalog'), topic('exports','Evidence export','/demo/admin/history/export','Review a filtered segment before downloading its scoped record projection.','evidence-export'), topic('lifecycle','Retention and holds','/demo/admin/lifecycle','Inspect holds, resumable purge progress and restore barriers.','evidence-lifecycle') ]}, {id:'integrations',title:'Integrate and deploy',description:'Choose a framework, author your documents and add a host-controlled backend when needed.',guides:[guide('authoring','Markdown & MDX'),guide('react','React'),guide('astro','Astro'),guide('cloudflare','Cloudflare backend'),guide('cloudflare-starter','Cloudflare starter'),guide('cloudflare-doctor','Deployment checks')],topics:[ topic('react','React integration','/react','Use the shared consent controller with hooks and hydration.','react'), topic('astro','Astro integration','/astro/','Build static legal pages with preferences that survive navigation.','astro'), topic('localization','Localized pages & choices','/localization','Supply versioned wording for legal pages and every consent-control state.','localization'), topic('authoring','Markdown and MDX','/authored/terms','Supply your wording and static custom components with revision metadata.','authoring'), topic('backend','Cloudflare workspace','/demo/admin','Inspect records in an isolated workspace with the same reusable admin components.','cloudflare',[['Starter guide','/guide/cloudflare-starter'],['Deployment checks','/guide/cloudflare-doctor']]) ]} ]; // Each guide has one place in the learning path. Specialist and maintainer material // belongs below its parent task rather than becoming another top-level destination. const group=(title,description,slugs,topicIds=[],options={})=>({title,description,slugs,topicIds,...options}); const areaGroups={ start:[group('Configure your site','Begin with an inventory, then review the setup recommendations.',['package','setup'],['setup']),group('Find the services you use','Discovery supplies findings for review; the catalog supplies reusable service descriptions.',['discovery','service-catalog'],['discovery'])], 'privacy-information':[group('Publish your documents','Supply reviewed wording and describe the services behind it.',['authoring','services'],['documents','services']),group('Explain collection and contact routes','Put the relevant information where people provide data or ask for help.',['collection','indirect-collection','rights'],['collection','indirect-collection','rights'])], 'privacy-choices':[group('Control optional services','Start with cookie preferences, then gate resources and clean up declared storage.',['consent','embeds','storage-cleanup'],['cookies','embeds','storage']),group('Offer separate permissions and opt-outs','Form permissions and processing restrictions have their own controls.',['form-permissions','privacy-signals','processing-choices'],['permissions','signals','opt-outs']),group('Specialist controls','Use these when your integration needs tag signals, grant expiry, repeat-prompt rules or explicit scope restrictions.',['storage-exceptions','google-basic','regional-prompts','scope-guards'],['exceptions','google','prompts','guards'],{specialist:true})], contracts:[group('Agree to terms','Bind the action and wording to the terms version people see.',['terms'],['agreement']),group('Before a purchase','Review the offer, applicable guarantee information and the final payment action.',['guarantees','guarantee-labels','paid-orders'],['guarantee-notice','producer-label','orders']),group('After a purchase','Retain the customer copy and handle withdrawal, cancellation and host delivery.',['order-confirmations','contract-actions','contract-dispatch'],['withdrawal','cancellation']),group('Example source and artwork','For readers who need to inspect or reproduce the prepared producer-label example.',['guarantee-producer-example'],[],{specialist:true})], records:[group('Retain versions and choices','Keep the released wording and link recorded choices to it.',['releases','consent-evidence'],['history','recorded-cookies','releases','catalog-history']),group('Inspect and manage evidence','Review customer confirmations, export scoped records and manage retention or holds.',['evidence-export','evidence-lifecycle'],['confirmations','exports','lifecycle'])], integrations:[group('Choose a frontend','The framework adapters use the same controllers. Authored documents are compiled at build time.',['react','astro','localization'],['react','astro','authoring','localization']),group('Add the backend when needed','Connect host-authorized records, then verify your deployment.',['cloudflare','cloudflare-starter','cloudflare-doctor'],['backend'])] }; // Cross-area references are links, not duplicate primary homes. const primaryHome={authoring:'privacy-information','order-confirmations':'contracts'}; export const referenceSection={id:'reference',title:'Reference and verification',description:'Requirements, primary sources, scope, verification reports and asset provenance.',guides:[guide('project','Project overview'),guide('requirements','Requirements catalog'),guide('requirements/sources','Primary sources'),guide('features','Feature status'),guide('scope','Scope & limits'),guide('research','Research workflow'),guide('all','All guides & reports')]}; const labels=new Map([...siteSections.flatMap(s=>s.guides),...referenceSection.guides].map(g=>[g.href,g.label])); labels.set('/guide/localization','Localization'); labels.set('/guide/storage-exceptions','UK storage settings'); for(const section of siteSections){ section.groups=areaGroups[section.id].map(g=>({...g,guides:g.slugs.map(slug=>guide(slug,labels.get('/guide/'+slug)??slug))})); section.guides=section.groups.flatMap(g=>g.guides); } // Stages are shared across the homepage and both directories. Areas keep stable URLs. export const siteStages=[ {id:'foundations',title:'Set up and publish',description:'Declare what your site does, then publish your reviewed legal wording.',areaIds:['start','privacy-information']}, {id:'features',title:'Add the controls you need',description:'Choose the privacy and contract flows that apply to your site.',areaIds:['privacy-choices','contracts']}, {id:'operations',title:'Integrate and keep records',description:'Choose your framework, connect the backend and inspect retained evidence.',areaIds:['integrations','records']} ]; export const orderedSiteSections=siteStages.flatMap(stage=>stage.areaIds.map(id=>siteSections.find(section=>section.id===id))); export const guideSections=[...orderedSiteSections,referenceSection]; export const stageForSection=section=>siteStages.find(stage=>stage.areaIds.includes(section.id)); const guideParents={ 'guarantee-producer-example':{slug:'guarantee-labels',label:'Product guarantee labels',kind:'Example source',description:'This page explains the prepared example and its source files. Start with the integration guide to add a label to your own site.'}, 'guarantee-asset-notice':{slug:'guarantee-labels',label:'Product guarantee labels',kind:'Asset provenance'}, 'authoring-package':{slug:'authoring',label:'Markdown & MDX',kind:'Package reference'}, 'catalog-data':{slug:'service-catalog',label:'Service catalog',kind:'Catalog reference'} }; export function parentForGuide(route){return guideParents[normalizeGuideRoute(route).replace(/^\/guide\//u,'')];} export function guideOrientation(route){ const parent=parentForGuide(route);if(!parent?.description)return ''; return ``; } export function stageDirectory(kind='examples'){ return `
${e(stage.description)}
${e(stage.description)}
${e(section.description)}
${kind==='examples'?`${section.topics.length} topics`:''}`).join('')}