[{"data":1,"prerenderedAt":3699},["ShallowReactive",2],{"navigation_docs":3,"-modules-interface-ui-composables":587,"-modules-interface-ui-composables-surround":3694},[4,50,155,441,504],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":49},"Get Started","i-lucide-rocket","\u002Fget-started","1.get-started",[10,15,20,25,30,35,40,45],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fget-started\u002Fintroduction","1.get-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fget-started\u002Finstallation","1.get-started\u002F2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Project structure","\u002Fget-started\u002Fproject-structure","1.get-started\u002F3.project-structure","i-lucide-folder-tree",{"title":26,"path":27,"stem":28,"icon":29},"Configuration","\u002Fget-started\u002Fconfiguration","1.get-started\u002F4.configuration","i-lucide-settings",{"title":31,"path":32,"stem":33,"icon":34},"Authentication","\u002Fget-started\u002Fauthentication","1.get-started\u002F5.authentication","i-lucide-lock",{"title":36,"path":37,"stem":38,"icon":39},"Adding modules","\u002Fget-started\u002Fadding-modules","1.get-started\u002F6.adding-modules","i-lucide-puzzle",{"title":41,"path":42,"stem":43,"icon":44},"Database","\u002Fget-started\u002Fdatabase","1.get-started\u002F7.database","i-lucide-database",{"title":46,"path":47,"stem":48,"icon":6},"Deployment","\u002Fget-started\u002Fdeployment","1.get-started\u002F8.deployment",false,{"title":51,"icon":52,"path":53,"stem":54,"children":55,"page":49},"Guide","i-lucide-book-open","\u002Fguide","2.guide",[56,90,115,125],{"title":57,"icon":49,"path":58,"stem":59,"children":60,"page":49},"Concepts","\u002Fguide\u002Fconcepts","2.guide\u002F1.concepts",[61,66,71,76,80,85],{"title":62,"path":63,"stem":64,"icon":65},"Architecture","\u002Fguide\u002Fconcepts\u002Farchitecture","2.guide\u002F1.concepts\u002F1.architecture","i-lucide-blocks",{"title":67,"path":68,"stem":69,"icon":70},"Access control","\u002Fguide\u002Fconcepts\u002Fauth-and-scopes","2.guide\u002F1.concepts\u002F2.auth-and-scopes","i-lucide-shield-check",{"title":72,"path":73,"stem":74,"icon":75},"Extension points","\u002Fguide\u002Fconcepts\u002Fextension-points","2.guide\u002F1.concepts\u002F3.extension-points","i-lucide-plug",{"title":77,"path":78,"stem":79,"icon":44},"Database extensions","\u002Fguide\u002Fconcepts\u002Fdatabase-extensions","2.guide\u002F1.concepts\u002F4.database-extensions",{"title":81,"path":82,"stem":83,"icon":84},"Identity","\u002Fguide\u002Fconcepts\u002Fidentity","2.guide\u002F1.concepts\u002F5.identity","i-lucide-fingerprint",{"title":86,"path":87,"stem":88,"icon":89},"Glossary","\u002Fguide\u002Fconcepts\u002Fglossary","2.guide\u002F1.concepts\u002F6.glossary","i-lucide-book-a",{"title":91,"icon":49,"path":92,"stem":93,"children":94,"page":49},"UX patterns","\u002Fguide\u002Fux-patterns","2.guide\u002F2.ux-patterns",[95,100,105,110],{"title":96,"path":97,"stem":98,"icon":99},"Layouts and navigation","\u002Fguide\u002Fux-patterns\u002Flayouts-and-navigation","2.guide\u002F2.ux-patterns\u002F1.layouts-and-navigation","i-lucide-layout-template",{"title":101,"path":102,"stem":103,"icon":104},"Pages","\u002Fguide\u002Fux-patterns\u002Fpages","2.guide\u002F2.ux-patterns\u002F2.pages","i-lucide-table",{"title":106,"path":107,"stem":108,"icon":109},"Forms and actions","\u002Fguide\u002Fux-patterns\u002Fforms-and-actions","2.guide\u002F2.ux-patterns\u002F3.forms-and-actions","i-lucide-square-pen",{"title":111,"path":112,"stem":113,"icon":114},"Text and formatting","\u002Fguide\u002Fux-patterns\u002Ftext-and-formatting","2.guide\u002F2.ux-patterns\u002F4.text-and-formatting","i-lucide-type",{"title":116,"icon":49,"path":117,"stem":118,"children":119,"page":49},"Best practices","\u002Fguide\u002Fbest-practices","2.guide\u002F3.best-practices",[120],{"title":121,"path":122,"stem":123,"icon":124},"HTTP routes","\u002Fguide\u002Fbest-practices\u002Fhttp-routes","2.guide\u002F3.best-practices\u002F1.http-routes","i-lucide-route",{"title":126,"icon":49,"path":127,"stem":128,"children":129,"page":49},"Going further","\u002Fguide\u002Fgoing-further","2.guide\u002F4.going-further",[130,135,140,145,150],{"title":131,"path":132,"stem":133,"icon":134},"Use your own OAuth server","\u002Fguide\u002Fgoing-further\u002Fown-oauth-server","2.guide\u002F4.going-further\u002F1.own-oauth-server","i-lucide-key-round",{"title":136,"path":137,"stem":138,"icon":139},"Create an OAuth application","\u002Fguide\u002Fgoing-further\u002Foauth-application","2.guide\u002F4.going-further\u002F2.oauth-application","i-lucide-app-window",{"title":141,"path":142,"stem":143,"icon":144},"Signing keys","\u002Fguide\u002Fgoing-further\u002Fsigning-keys","2.guide\u002F4.going-further\u002F3.signing-keys","i-lucide-key-square",{"title":146,"path":147,"stem":148,"icon":149},"Stripe setup","\u002Fguide\u002Fgoing-further\u002Fstripe-setup","2.guide\u002F4.going-further\u002F4.stripe-setup","i-lucide-credit-card",{"title":151,"path":152,"stem":153,"icon":154},"Migrate to the permission model","\u002Fguide\u002Fgoing-further\u002Fmigrate-access-control","2.guide\u002F4.going-further\u002F5.migrate-access-control","i-lucide-arrow-right-left",{"title":156,"icon":157,"path":158,"stem":159,"children":160},"Modules","i-lucide-boxes","\u002Fmodules","3.modules",[161,163,244,273,320,375],{"title":156,"path":158,"stem":162},"3.modules\u002Findex",{"title":81,"icon":49,"path":164,"stem":165,"children":166,"page":49},"\u002Fmodules\u002Fidentity","3.modules\u002F1.identity",[167,190,194,198,220,224,240],{"title":168,"path":169,"stem":170,"children":171},"Auth","\u002Fmodules\u002Fidentity\u002Fauth","3.modules\u002F1.identity\u002F1.auth\u002Findex",[172,174,178,182,186],{"title":173,"path":169,"stem":170},"Overview",{"title":175,"path":176,"stem":177},"Server API","\u002Fmodules\u002Fidentity\u002Fauth\u002Fserver","3.modules\u002F1.identity\u002F1.auth\u002F2.server",{"title":179,"path":180,"stem":181},"Reference","\u002Fmodules\u002Fidentity\u002Fauth\u002Freference","3.modules\u002F1.identity\u002F1.auth\u002F3.reference",{"title":183,"path":184,"stem":185},"Client mode","\u002Fmodules\u002Fidentity\u002Fauth\u002Fclient-mode","3.modules\u002F1.identity\u002F1.auth\u002F4.client-mode",{"title":187,"path":188,"stem":189},"OAuth providers","\u002Fmodules\u002Fidentity\u002Fauth\u002Foauth-providers","3.modules\u002F1.identity\u002F1.auth\u002F5.oauth-providers",{"title":191,"path":192,"stem":193},"Users","\u002Fmodules\u002Fidentity\u002Fusers","3.modules\u002F1.identity\u002F2.users",{"title":195,"path":196,"stem":197},"Account","\u002Fmodules\u002Fidentity\u002Faccount","3.modules\u002F1.identity\u002F3.account",{"title":199,"path":200,"stem":201,"children":202},"Authorization","\u002Fmodules\u002Fidentity\u002Fauthorization","3.modules\u002F1.identity\u002F4.authorization\u002Findex",[203,204,208,212,216],{"title":173,"path":200,"stem":201},{"title":205,"path":206,"stem":207},"Roles and requirements","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Froles-and-requirements","3.modules\u002F1.identity\u002F4.authorization\u002F2.roles-and-requirements",{"title":209,"path":210,"stem":211},"Policies","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fpolicies","3.modules\u002F1.identity\u002F4.authorization\u002F3.policies",{"title":213,"path":214,"stem":215},"Client","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fclient","3.modules\u002F1.identity\u002F4.authorization\u002F4.client",{"title":217,"path":218,"stem":219},"Admin","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fadmin","3.modules\u002F1.identity\u002F4.authorization\u002F5.admin",{"title":221,"path":222,"stem":223},"Preferences","\u002Fmodules\u002Fidentity\u002Fpreferences","3.modules\u002F1.identity\u002F5.preferences",{"title":225,"path":226,"stem":227,"children":228},"OAuth Server","\u002Fmodules\u002Fidentity\u002Foauth-server","3.modules\u002F1.identity\u002F6.oauth-server\u002Findex",[229,230,233,237],{"title":173,"path":226,"stem":227},{"title":175,"path":231,"stem":232},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Fserver","3.modules\u002F1.identity\u002F6.oauth-server\u002F2.server",{"title":234,"path":235,"stem":236},"Hooks","\u002Fmodules\u002Fidentity\u002Foauth-server\u002Fhooks","3.modules\u002F1.identity\u002F6.oauth-server\u002F3.hooks",{"title":179,"path":238,"stem":239},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Froutes-and-clients","3.modules\u002F1.identity\u002F6.oauth-server\u002F4.routes-and-clients",{"title":241,"path":242,"stem":243},"OAuth Resource","\u002Fmodules\u002Fidentity\u002Foauth-resource","3.modules\u002F1.identity\u002F8.oauth-resource",{"title":245,"icon":49,"path":246,"stem":247,"children":248,"page":49},"Commerce","\u002Fmodules\u002Fcommerce","3.modules\u002F2.commerce",[249,253,257],{"title":250,"path":251,"stem":252},"Stripe","\u002Fmodules\u002Fcommerce\u002Fstripe","3.modules\u002F2.commerce\u002F1.stripe",{"title":254,"path":255,"stem":256},"Payments","\u002Fmodules\u002Fcommerce\u002Fpayments","3.modules\u002F2.commerce\u002F2.payments",{"title":258,"path":259,"stem":260,"children":261},"Subscriptions","\u002Fmodules\u002Fcommerce\u002Fsubscriptions","3.modules\u002F2.commerce\u002F3.subscriptions\u002Findex",[262,263,266,270],{"title":173,"path":259,"stem":260},{"title":175,"path":264,"stem":265},"\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Fserver","3.modules\u002F2.commerce\u002F3.subscriptions\u002F2.server",{"title":267,"path":268,"stem":269},"App","\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Fapp","3.modules\u002F2.commerce\u002F3.subscriptions\u002F3.app",{"title":179,"path":271,"stem":272},"\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Freference","3.modules\u002F2.commerce\u002F3.subscriptions\u002F4.reference",{"title":274,"icon":49,"path":275,"stem":276,"children":277,"page":49},"Features","\u002Fmodules\u002Ffeatures","3.modules\u002F3.features",[278,293,312,316],{"title":279,"path":280,"stem":281,"children":282},"Events","\u002Fmodules\u002Ffeatures\u002Fevents","3.modules\u002F3.features\u002F1.events\u002Findex",[283,284,287,290],{"title":173,"path":280,"stem":281},{"title":175,"path":285,"stem":286},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Fserver","3.modules\u002F3.features\u002F1.events\u002F2.server",{"title":267,"path":288,"stem":289},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Fapp","3.modules\u002F3.features\u002F1.events\u002F3.app",{"title":179,"path":291,"stem":292},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Freference","3.modules\u002F3.features\u002F1.events\u002F4.reference",{"title":294,"path":295,"stem":296,"children":297},"Forms","\u002Fmodules\u002Ffeatures\u002Fforms","3.modules\u002F3.features\u002F2.forms\u002Findex",[298,299,303,306,309],{"title":173,"path":295,"stem":296},{"title":300,"path":301,"stem":302},"Definition","\u002Fmodules\u002Ffeatures\u002Fforms\u002Fdefinition","3.modules\u002F3.features\u002F2.forms\u002F2.definition",{"title":175,"path":304,"stem":305},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Fserver","3.modules\u002F3.features\u002F2.forms\u002F3.server",{"title":267,"path":307,"stem":308},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Fapp","3.modules\u002F3.features\u002F2.forms\u002F4.app",{"title":179,"path":310,"stem":311},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Freference","3.modules\u002F3.features\u002F2.forms\u002F5.reference",{"title":313,"path":314,"stem":315},"Cookie Consent","\u002Fmodules\u002Ffeatures\u002Fcookie-consent","3.modules\u002F3.features\u002F3.cookie-consent",{"title":317,"path":318,"stem":319},"MCP","\u002Fmodules\u002Ffeatures\u002Fmcp","3.modules\u002F3.features\u002F4.mcp",{"title":321,"icon":49,"path":322,"stem":323,"children":324,"page":49},"Interface","\u002Fmodules\u002Finterface","3.modules\u002F4.interface",[325,350,353,357,361],{"title":326,"path":327,"stem":328,"children":329},"UI","\u002Fmodules\u002Finterface\u002Fui","3.modules\u002F4.interface\u002F1.ui\u002Findex",[330,331,335,339,343,347],{"title":173,"path":327,"stem":328},{"title":332,"path":333,"stem":334},"Page components","\u002Fmodules\u002Finterface\u002Fui\u002Fpage-components","3.modules\u002F4.interface\u002F1.ui\u002F2.page-components",{"title":336,"path":337,"stem":338},"App shell","\u002Fmodules\u002Finterface\u002Fui\u002Fapp-shell","3.modules\u002F4.interface\u002F1.ui\u002F3.app-shell",{"title":340,"path":341,"stem":342},"Form inputs","\u002Fmodules\u002Finterface\u002Fui\u002Fform-inputs","3.modules\u002F4.interface\u002F1.ui\u002F4.form-inputs",{"title":344,"path":345,"stem":346},"Composables and helpers","\u002Fmodules\u002Finterface\u002Fui\u002Fcomposables","3.modules\u002F4.interface\u002F1.ui\u002F5.composables",{"title":179,"path":348,"stem":349},"\u002Fmodules\u002Finterface\u002Fui\u002Freference","3.modules\u002F4.interface\u002F1.ui\u002F6.reference",{"title":217,"path":351,"stem":352},"\u002Fmodules\u002Finterface\u002Fadmin","3.modules\u002F4.interface\u002F2.admin",{"title":354,"path":355,"stem":356},"Menu","\u002Fmodules\u002Finterface\u002Fmenu","3.modules\u002F4.interface\u002F3.menu",{"title":358,"path":359,"stem":360},"Widget","\u002Fmodules\u002Finterface\u002Fwidget","3.modules\u002F4.interface\u002F4.widget",{"title":362,"path":363,"stem":364,"children":365},"Mobile","\u002Fmodules\u002Finterface\u002Fmobile","3.modules\u002F4.interface\u002F5.mobile\u002Findex",[366,367,371],{"title":173,"path":363,"stem":364},{"title":368,"path":369,"stem":370},"CLI and devices","\u002Fmodules\u002Finterface\u002Fmobile\u002Fcli-and-devices","3.modules\u002F4.interface\u002F5.mobile\u002F2.cli-and-devices",{"title":372,"path":373,"stem":374},"Splash screen","\u002Fmodules\u002Finterface\u002Fmobile\u002Fsplash-screen","3.modules\u002F4.interface\u002F5.mobile\u002F3.splash-screen",{"title":376,"icon":49,"path":377,"stem":378,"children":379,"page":49},"Platform","\u002Fmodules\u002Fplatform","3.modules\u002F5.platform",[380,402,406,423],{"title":381,"path":382,"stem":383,"children":384},"Module Kit","\u002Fmodules\u002Fplatform\u002Fmodule-kit","3.modules\u002F5.platform\u002F1.module-kit\u002Findex",[385,386,390,394,398],{"title":173,"path":382,"stem":383},{"title":387,"path":388,"stem":389},"Server toolkit","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fserver-toolkit","3.modules\u002F5.platform\u002F1.module-kit\u002F2.server-toolkit",{"title":391,"path":392,"stem":393},"Registries and menus","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fregistries-and-menus","3.modules\u002F5.platform\u002F1.module-kit\u002F3.registries-and-menus",{"title":395,"path":396,"stem":397},"Translations","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fi18n","3.modules\u002F5.platform\u002F1.module-kit\u002F4.i18n",{"title":399,"path":400,"stem":401},"Database helpers","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fdatabase","3.modules\u002F5.platform\u002F1.module-kit\u002F5.database",{"title":403,"path":404,"stem":405},"Notify","\u002Fmodules\u002Fplatform\u002Fnotify","3.modules\u002F5.platform\u002F2.notify",{"title":407,"path":408,"stem":409,"children":410},"Email Templates","\u002Fmodules\u002Fplatform\u002Femail-templates","3.modules\u002F5.platform\u002F3.email-templates\u002Findex",[411,412,416,419],{"title":173,"path":408,"stem":409},{"title":413,"path":414,"stem":415},"Email components","\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fcomponents","3.modules\u002F5.platform\u002F3.email-templates\u002F2.components",{"title":175,"path":417,"stem":418},"\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fserver","3.modules\u002F5.platform\u002F3.email-templates\u002F3.server",{"title":420,"path":421,"stem":422},"Module emails","\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fmodule-emails","3.modules\u002F5.platform\u002F3.email-templates\u002F4.module-emails",{"title":424,"path":425,"stem":426,"children":427},"Base Layer","\u002Fmodules\u002Fplatform\u002Fbase-layer","3.modules\u002F5.platform\u002F4.base-layer\u002Findex",[428,429,433,437],{"title":173,"path":425,"stem":426},{"title":430,"path":431,"stem":432},"Content collections","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Fcontent-collections","3.modules\u002F5.platform\u002F4.base-layer\u002F2.content-collections",{"title":434,"path":435,"stem":436},"Layouts and routing","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Flayouts-and-routing","3.modules\u002F5.platform\u002F4.base-layer\u002F3.layouts-and-routing",{"title":438,"path":439,"stem":440},"Composables and utils","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Fcomposables-and-utils","3.modules\u002F5.platform\u002F4.base-layer\u002F4.composables-and-utils",{"title":442,"icon":443,"path":444,"stem":445,"children":446,"page":49},"Examples","i-lucide-code-xml","\u002Fexamples","4.examples",[447,466,476],{"title":448,"icon":49,"path":449,"stem":450,"children":451,"page":49},"Starters","\u002Fexamples\u002Fstarters","4.examples\u002F1.starters",[452,456,461],{"title":453,"path":454,"stem":455,"icon":6},"Workspace starter","\u002Fexamples\u002Fstarters\u002Fworkspace","4.examples\u002F1.starters\u002F1.workspace",{"title":457,"path":458,"stem":459,"icon":460},"Mobile starter","\u002Fexamples\u002Fstarters\u002Fmobile","4.examples\u002F1.starters\u002F2.mobile","i-lucide-smartphone",{"title":462,"path":463,"stem":464,"icon":465},"Standalone mobile starter","\u002Fexamples\u002Fstarters\u002Fmobile-standalone","4.examples\u002F1.starters\u002F3.mobile-standalone","i-lucide-tablet-smartphone",{"title":467,"icon":49,"path":468,"stem":469,"children":470,"page":49},"Apps","\u002Fexamples\u002Fapps","4.examples\u002F2.apps",[471],{"title":472,"path":473,"stem":474,"icon":475},"Frigear website app","\u002Fexamples\u002Fapps\u002Ffrigear-nu-website","4.examples\u002F2.apps\u002F1.frigear-nu-website","i-lucide-layout-dashboard",{"title":477,"icon":49,"path":478,"stem":479,"children":480,"page":49},"Tasks","\u002Fexamples\u002Ftasks","4.examples\u002F3.tasks",[481,485,489,494,499],{"title":482,"path":483,"stem":484,"icon":70},"Protect a route","\u002Fexamples\u002Ftasks\u002Fprotect-a-route","4.examples\u002F3.tasks\u002F1.protect-a-route",{"title":486,"path":487,"stem":488,"icon":475},"Add an admin page","\u002Fexamples\u002Ftasks\u002Fadd-an-admin-page","4.examples\u002F3.tasks\u002F2.add-an-admin-page",{"title":490,"path":491,"stem":492,"icon":493},"Sell event tickets","\u002Fexamples\u002Ftasks\u002Fsell-event-tickets","4.examples\u002F3.tasks\u002F3.sell-event-tickets","i-lucide-ticket",{"title":495,"path":496,"stem":497,"icon":498},"Build a form","\u002Fexamples\u002Ftasks\u002Fbuild-a-form","4.examples\u002F3.tasks\u002F4.build-a-form","i-lucide-clipboard-list",{"title":500,"path":501,"stem":502,"icon":503},"Send an email","\u002Fexamples\u002Ftasks\u002Fsend-an-email","4.examples\u002F3.tasks\u002F5.send-an-email","i-lucide-mail",{"title":505,"icon":506,"path":507,"stem":508,"children":509,"page":49},"Contribute","i-lucide-git-pull-request","\u002Fcontribute","5.contribute",[510,513,518,544,549,552,556,571],{"title":173,"path":511,"stem":512,"icon":506},"\u002Fcontribute\u002Foverview","5.contribute\u002F1.overview",{"title":514,"path":515,"stem":516,"icon":517},"Local development","\u002Fcontribute\u002Flocal-development","5.contribute\u002F2.local-development","i-lucide-terminal",{"title":519,"icon":49,"path":520,"stem":521,"children":522,"page":49},"Writing a module","\u002Fcontribute\u002Fwriting-a-module","5.contribute\u002F3.writing-a-module",[523,527,532,536,541],{"title":524,"path":525,"stem":526,"icon":39},"Scaffold a module","\u002Fcontribute\u002Fwriting-a-module\u002Fscaffold","5.contribute\u002F3.writing-a-module\u002F1.scaffold",{"title":528,"path":529,"stem":530,"icon":531},"Setup checklist","\u002Fcontribute\u002Fwriting-a-module\u002Fsetup-checklist","5.contribute\u002F3.writing-a-module\u002F2.setup-checklist","i-lucide-list-checks",{"title":533,"path":534,"stem":535,"icon":44},"Database tables","\u002Fcontribute\u002Fwriting-a-module\u002Fdatabase-tables","5.contribute\u002F3.writing-a-module\u002F3.database-tables",{"title":537,"path":538,"stem":539,"icon":540},"Testing","\u002Fcontribute\u002Fwriting-a-module\u002Ftesting","5.contribute\u002F3.writing-a-module\u002F4.testing","i-lucide-flask-conical",{"title":67,"path":542,"stem":543,"icon":70},"\u002Fcontribute\u002Fwriting-a-module\u002Faccess-control","5.contribute\u002F3.writing-a-module\u002F5.access-control",{"title":545,"path":546,"stem":547,"icon":548},"Publishing","\u002Fcontribute\u002Fpublishing","5.contribute\u002F4.publishing","i-lucide-package-check",{"title":448,"path":550,"stem":551,"icon":6},"\u002Fcontribute\u002Fstarters","5.contribute\u002F5.starters",{"title":553,"path":554,"stem":555,"icon":52},"Documentation","\u002Fcontribute\u002Fdocumentation","5.contribute\u002F6.documentation",{"title":557,"icon":49,"path":558,"stem":559,"children":560,"page":49},"Tooling","\u002Fcontribute\u002Ftooling","5.contribute\u002F7.tooling",[561,566],{"title":562,"path":563,"stem":564,"icon":565},"CLI","\u002Fcontribute\u002Ftooling\u002Fcli","5.contribute\u002F7.tooling\u002F1.cli","i-lucide-square-terminal",{"title":567,"path":568,"stem":569,"icon":570},"ESLint config","\u002Fcontribute\u002Ftooling\u002Feslint-config","5.contribute\u002F7.tooling\u002F2.eslint-config","i-lucide-spell-check",{"title":572,"icon":49,"path":573,"stem":574,"children":575},"Decisions","\u002Fcontribute\u002Fdecisions","5.contribute\u002F8.decisions\u002Findex",[576,578,583],{"title":572,"path":573,"stem":574,"icon":577},"i-lucide-scale",{"title":579,"path":580,"stem":581,"icon":582},"Session lifetimes per OAuth client","\u002Fcontribute\u002Fdecisions\u002Foauth-token-lifetimes","5.contribute\u002F8.decisions\u002F1.oauth-token-lifetimes","i-lucide-timer",{"title":584,"path":585,"stem":586,"icon":70},"One permission model","\u002Fcontribute\u002Fdecisions\u002Fpermission-model","5.contribute\u002F8.decisions\u002F2.permission-model",{"id":588,"title":344,"body":589,"description":3687,"extension":3688,"links":3689,"meta":3690,"navigation":3691,"path":345,"seo":3692,"stem":346,"__hash__":3693},"docs\u002F3.modules\u002F4.interface\u002F1.ui\u002F5.composables.md",{"type":590,"value":591,"toc":3675},"minimark",[592,600,611,616,622,771,781,1077,1081,1084,1332,1430,1591,1595,1601,1894,1910,1925,1937,2007,2332,2338,2343,2364,2406,2410,2493,2497,2500,2790,2801,2839,2844,2848,2851,2994,3008,3012,3021,3306,3318,3491,3497,3501,3504,3635,3654,3658,3671],[593,594,595,596,599],"p",{},"These composables and helpers do the small jobs every page repeats: confirm, show an error, keep data on screen,\nformat a date, sort a table. This page is for app developers and module authors. Set up the module first:\n",[597,598,173],"a",{"href":327},".",[593,601,602,603,607,608,599],{},"Everything here is auto-imported in a Nuxt app. Code outside the app imports the same names from\n",[604,605,606],"code",{},"@frigear-nu\u002Fui\u002Fcomposables"," and ",[604,609,610],{},"@frigear-nu\u002Fui\u002Futils",[612,613,615],"h2",{"id":614},"confirmations","Confirmations",[593,617,618,621],{},[604,619,620],{},"useConfirmDialog"," asks the user to confirm and resolves with the answer.",[623,624,629],"pre",{"className":625,"code":626,"language":627,"meta":628,"style":628},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","interface ConfirmDialogOptions {\n  title: string\n  description?: string\n  confirmText?: string \u002F\u002F default 'Confirm'\n  cancelText?: string \u002F\u002F default 'Cancel'\n  destructive?: boolean \u002F\u002F style the confirm button as destructive\n}\n\nuseConfirmDialog(): (options: ConfirmDialogOptions) => Promise\u003Cboolean> \u002F\u002F true = confirmed, false = cancelled\n","ts","",[604,630,631,648,661,672,687,700,714,720,727],{"__ignoreMap":628},[632,633,636,640,644],"span",{"class":634,"line":635},"line",1,[632,637,639],{"class":638},"spNyl","interface",[632,641,643],{"class":642},"sBMFI"," ConfirmDialogOptions",[632,645,647],{"class":646},"sMK4o"," {\n",[632,649,651,655,658],{"class":634,"line":650},2,[632,652,654],{"class":653},"swJcz","  title",[632,656,657],{"class":646},":",[632,659,660],{"class":642}," string\n",[632,662,664,667,670],{"class":634,"line":663},3,[632,665,666],{"class":653},"  description",[632,668,669],{"class":646},"?:",[632,671,660],{"class":642},[632,673,675,678,680,683],{"class":634,"line":674},4,[632,676,677],{"class":653},"  confirmText",[632,679,669],{"class":646},[632,681,682],{"class":642}," string",[632,684,686],{"class":685},"sHwdD"," \u002F\u002F default 'Confirm'\n",[632,688,690,693,695,697],{"class":634,"line":689},5,[632,691,692],{"class":653},"  cancelText",[632,694,669],{"class":646},[632,696,682],{"class":642},[632,698,699],{"class":685}," \u002F\u002F default 'Cancel'\n",[632,701,703,706,708,711],{"class":634,"line":702},6,[632,704,705],{"class":653},"  destructive",[632,707,669],{"class":646},[632,709,710],{"class":642}," boolean",[632,712,713],{"class":685}," \u002F\u002F style the confirm button as destructive\n",[632,715,717],{"class":634,"line":716},7,[632,718,719],{"class":646},"}\n",[632,721,723],{"class":634,"line":722},8,[632,724,726],{"emptyLinePlaceholder":725},true,"\n",[632,728,730,733,737,739,742,746,748,750,753,756,759,762,765,768],{"class":634,"line":729},9,[632,731,620],{"class":732},"s2Zo4",[632,734,736],{"class":735},"sTEyZ","()",[632,738,657],{"class":646},[632,740,741],{"class":646}," (",[632,743,745],{"class":744},"sHdIc","options",[632,747,657],{"class":646},[632,749,643],{"class":642},[632,751,752],{"class":646},")",[632,754,755],{"class":638}," =>",[632,757,758],{"class":642}," Promise",[632,760,761],{"class":646},"\u003C",[632,763,764],{"class":735},"boolean",[632,766,767],{"class":646},">",[632,769,770],{"class":685}," \u002F\u002F true = confirmed, false = cancelled\n",[593,772,773,774,777,778,599],{},"It is built on Nuxt UI's ",[604,775,776],{},"useOverlay",". A click outside or Escape does not close the dialog, so the promise resolves only\nthrough its buttons. What the title, description and button should say is on\n",[597,779,106],{"href":780},"\u002Fguide\u002Fux-patterns\u002Fforms-and-actions#destructive-actions",[623,782,786],{"className":783,"code":784,"language":785,"meta":628,"style":628},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Cscript setup lang=\"ts\">\nconst confirm = useConfirmDialog()\n\nasync function removeApplication(app: { id: string, name: string }) {\n  const confirmed = await confirm({\n    title: `Delete ${app.name}?`,\n    description: 'Every token issued to it stops working. This cannot be undone.',\n    confirmText: 'Delete application',\n    destructive: true,\n  })\n  if (!confirmed) return\n  await $fetch(`\u002Fapi\u002Fadmin\u002Foauth-server\u002Fapplications\u002F${app.id}`, { method: 'DELETE' })\n}\n\u003C\u002Fscript>\n","vue",[604,787,788,815,831,835,879,902,937,955,971,984,993,1013,1062,1067],{"__ignoreMap":628},[632,789,790,792,795,798,801,804,807,810,812],{"class":634,"line":635},[632,791,761],{"class":646},[632,793,794],{"class":653},"script",[632,796,797],{"class":638}," setup",[632,799,800],{"class":638}," lang",[632,802,803],{"class":646},"=",[632,805,806],{"class":646},"\"",[632,808,627],{"class":809},"sfazB",[632,811,806],{"class":646},[632,813,814],{"class":646},">\n",[632,816,817,820,823,825,828],{"class":634,"line":650},[632,818,819],{"class":638},"const",[632,821,822],{"class":735}," confirm ",[632,824,803],{"class":646},[632,826,827],{"class":732}," useConfirmDialog",[632,829,830],{"class":735},"()\n",[632,832,833],{"class":634,"line":663},[632,834,726],{"emptyLinePlaceholder":725},[632,836,837,840,843,846,849,852,854,857,860,862,864,867,870,872,874,877],{"class":634,"line":674},[632,838,839],{"class":638},"async",[632,841,842],{"class":638}," function",[632,844,845],{"class":732}," removeApplication",[632,847,848],{"class":646},"(",[632,850,851],{"class":744},"app",[632,853,657],{"class":646},[632,855,856],{"class":646}," {",[632,858,859],{"class":653}," id",[632,861,657],{"class":646},[632,863,682],{"class":642},[632,865,866],{"class":646},",",[632,868,869],{"class":653}," name",[632,871,657],{"class":646},[632,873,682],{"class":642},[632,875,876],{"class":646}," })",[632,878,647],{"class":646},[632,880,881,884,887,890,894,897,899],{"class":634,"line":689},[632,882,883],{"class":638},"  const",[632,885,886],{"class":735}," confirmed",[632,888,889],{"class":646}," =",[632,891,893],{"class":892},"s7zQu"," await",[632,895,896],{"class":732}," confirm",[632,898,848],{"class":653},[632,900,901],{"class":646},"{\n",[632,903,904,907,909,912,915,918,920,922,925,928,931,934],{"class":634,"line":702},[632,905,906],{"class":653},"    title",[632,908,657],{"class":646},[632,910,911],{"class":646}," `",[632,913,914],{"class":809},"Delete ",[632,916,917],{"class":646},"${",[632,919,851],{"class":735},[632,921,599],{"class":646},[632,923,924],{"class":735},"name",[632,926,927],{"class":646},"}",[632,929,930],{"class":809},"?",[632,932,933],{"class":646},"`",[632,935,936],{"class":646},",\n",[632,938,939,942,944,947,950,953],{"class":634,"line":716},[632,940,941],{"class":653},"    description",[632,943,657],{"class":646},[632,945,946],{"class":646}," '",[632,948,949],{"class":809},"Every token issued to it stops working. This cannot be undone.",[632,951,952],{"class":646},"'",[632,954,936],{"class":646},[632,956,957,960,962,964,967,969],{"class":634,"line":722},[632,958,959],{"class":653},"    confirmText",[632,961,657],{"class":646},[632,963,946],{"class":646},[632,965,966],{"class":809},"Delete application",[632,968,952],{"class":646},[632,970,936],{"class":646},[632,972,973,976,978,982],{"class":634,"line":729},[632,974,975],{"class":653},"    destructive",[632,977,657],{"class":646},[632,979,981],{"class":980},"sfNiH"," true",[632,983,936],{"class":646},[632,985,987,990],{"class":634,"line":986},10,[632,988,989],{"class":646},"  }",[632,991,992],{"class":653},")\n",[632,994,996,999,1001,1004,1007,1010],{"class":634,"line":995},11,[632,997,998],{"class":892},"  if",[632,1000,741],{"class":653},[632,1002,1003],{"class":646},"!",[632,1005,1006],{"class":735},"confirmed",[632,1008,1009],{"class":653},") ",[632,1011,1012],{"class":892},"return\n",[632,1014,1016,1019,1022,1024,1026,1029,1031,1033,1035,1038,1041,1043,1045,1048,1050,1052,1055,1057,1060],{"class":634,"line":1015},12,[632,1017,1018],{"class":892},"  await",[632,1020,1021],{"class":732}," $fetch",[632,1023,848],{"class":653},[632,1025,933],{"class":646},[632,1027,1028],{"class":809},"\u002Fapi\u002Fadmin\u002Foauth-server\u002Fapplications\u002F",[632,1030,917],{"class":646},[632,1032,851],{"class":735},[632,1034,599],{"class":646},[632,1036,1037],{"class":735},"id",[632,1039,1040],{"class":646},"}`",[632,1042,866],{"class":646},[632,1044,856],{"class":646},[632,1046,1047],{"class":653}," method",[632,1049,657],{"class":646},[632,1051,946],{"class":646},[632,1053,1054],{"class":809},"DELETE",[632,1056,952],{"class":646},[632,1058,1059],{"class":646}," }",[632,1061,992],{"class":653},[632,1063,1065],{"class":634,"line":1064},13,[632,1066,719],{"class":646},[632,1068,1070,1073,1075],{"class":634,"line":1069},14,[632,1071,1072],{"class":646},"\u003C\u002F",[632,1074,794],{"class":653},[632,1076,814],{"class":646},[612,1078,1080],{"id":1079},"errors-actions-and-clipboard","Errors, actions and clipboard",[593,1082,1083],{},"These helpers turn a failed request into a toast and track a running action.",[623,1085,1087],{"className":625,"code":1086,"language":627,"meta":628,"style":628},"errorMessage(e: unknown, fallback: string): string\nerrorToToast(e: unknown, overrides?: Partial\u003CToastProps>): Partial\u003CToastProps> \u002F\u002F an error toast carrying errorMessage(e)\nuseErrorToast(): (e: unknown, title?: string) => void \u002F\u002F toast.add(errorToToast(e, { title })), translated default title\n\nuseAction(): {\n  busy: Ref\u003Cboolean>\n  run\u003CT>(fn: () => Promise\u003CT>, options?: { success?: string, error?: string }): Promise\u003CT | undefined>\n}\n\nuseCopyToClipboard(): { copy(text: string, message?: string): Promise\u003Cboolean> } \u002F\u002F false on failure\n",[604,1088,1089,1102,1138,1176,1180,1190,1206,1277,1281,1285],{"__ignoreMap":628},[632,1090,1091,1094,1097,1099],{"class":634,"line":635},[632,1092,1093],{"class":732},"errorMessage",[632,1095,1096],{"class":735},"(e: unknown",[632,1098,866],{"class":646},[632,1100,1101],{"class":735}," fallback: string): string\n",[632,1103,1104,1107,1109,1111,1114,1116,1119,1121,1124,1126,1129,1131,1133,1135],{"class":634,"line":650},[632,1105,1106],{"class":732},"errorToToast",[632,1108,1096],{"class":735},[632,1110,866],{"class":646},[632,1112,1113],{"class":735}," overrides",[632,1115,669],{"class":646},[632,1117,1118],{"class":735}," Partial",[632,1120,761],{"class":646},[632,1122,1123],{"class":735},"ToastProps",[632,1125,767],{"class":646},[632,1127,1128],{"class":735},"): Partial",[632,1130,761],{"class":646},[632,1132,1123],{"class":735},[632,1134,767],{"class":646},[632,1136,1137],{"class":685}," \u002F\u002F an error toast carrying errorMessage(e)\n",[632,1139,1140,1143,1145,1147,1149,1152,1154,1157,1159,1162,1164,1166,1168,1170,1173],{"class":634,"line":663},[632,1141,1142],{"class":732},"useErrorToast",[632,1144,736],{"class":735},[632,1146,657],{"class":646},[632,1148,741],{"class":646},[632,1150,1151],{"class":744},"e",[632,1153,657],{"class":646},[632,1155,1156],{"class":642}," unknown",[632,1158,866],{"class":646},[632,1160,1161],{"class":744}," title",[632,1163,669],{"class":646},[632,1165,682],{"class":642},[632,1167,752],{"class":646},[632,1169,755],{"class":638},[632,1171,1172],{"class":646}," void",[632,1174,1175],{"class":685}," \u002F\u002F toast.add(errorToToast(e, { title })), translated default title\n",[632,1177,1178],{"class":634,"line":674},[632,1179,726],{"emptyLinePlaceholder":725},[632,1181,1182,1185,1188],{"class":634,"line":689},[632,1183,1184],{"class":732},"useAction",[632,1186,1187],{"class":735},"(): ",[632,1189,901],{"class":646},[632,1191,1192,1195,1197,1200,1202,1204],{"class":634,"line":702},[632,1193,1194],{"class":653},"  busy",[632,1196,657],{"class":646},[632,1198,1199],{"class":735}," Ref",[632,1201,761],{"class":646},[632,1203,764],{"class":735},[632,1205,814],{"class":646},[632,1207,1208,1211,1213,1216,1218,1221,1223,1225,1227,1229,1231,1234,1237,1239,1241,1244,1246,1248,1250,1253,1255,1258,1260,1263,1266,1268,1271,1274],{"class":634,"line":716},[632,1209,1210],{"class":732},"  run",[632,1212,761],{"class":646},[632,1214,1215],{"class":642},"T",[632,1217,767],{"class":646},[632,1219,1220],{"class":735},"(fn: ",[632,1222,736],{"class":646},[632,1224,755],{"class":638},[632,1226,758],{"class":642},[632,1228,761],{"class":646},[632,1230,1215],{"class":735},[632,1232,1233],{"class":646},">,",[632,1235,1236],{"class":735}," options",[632,1238,669],{"class":646},[632,1240,856],{"class":646},[632,1242,1243],{"class":735}," success?",[632,1245,657],{"class":646},[632,1247,682],{"class":735},[632,1249,866],{"class":646},[632,1251,1252],{"class":735}," error?",[632,1254,657],{"class":646},[632,1256,1257],{"class":735}," string ",[632,1259,927],{"class":646},[632,1261,1262],{"class":735},"): ",[632,1264,1265],{"class":642},"Promise",[632,1267,761],{"class":646},[632,1269,1270],{"class":735},"T ",[632,1272,1273],{"class":646},"|",[632,1275,1276],{"class":646}," undefined>\n",[632,1278,1279],{"class":634,"line":722},[632,1280,719],{"class":646},[632,1282,1283],{"class":634,"line":729},[632,1284,726],{"emptyLinePlaceholder":725},[632,1286,1287,1290,1292,1295,1298,1300,1303,1305,1307,1309,1312,1314,1316,1319,1321,1323,1325,1327,1329],{"class":634,"line":986},[632,1288,1289],{"class":732},"useCopyToClipboard",[632,1291,1187],{"class":735},[632,1293,1294],{"class":646},"{",[632,1296,1297],{"class":653}," copy",[632,1299,848],{"class":646},[632,1301,1302],{"class":744},"text",[632,1304,657],{"class":646},[632,1306,682],{"class":642},[632,1308,866],{"class":646},[632,1310,1311],{"class":744}," message",[632,1313,669],{"class":646},[632,1315,682],{"class":642},[632,1317,1318],{"class":646},"):",[632,1320,758],{"class":642},[632,1322,761],{"class":646},[632,1324,764],{"class":642},[632,1326,767],{"class":646},[632,1328,1059],{"class":646},[632,1330,1331],{"class":685}," \u002F\u002F false on failure\n",[1333,1334,1335,1378,1389,1417],"ul",{},[1336,1337,1338,1343,1344,1347,1348,1347,1351,1347,1354,1357,1358,1361,1362,1365,1366,1369,1370,1373,1374,1377],"li",{},[1339,1340,1341],"strong",{},[604,1342,1093],{}," reads ",[604,1345,1346],{},"data.message",", ",[604,1349,1350],{},"data.statusMessage",[604,1352,1353],{},"response._data.message",[604,1355,1356],{},"statusMessage"," and\n",[604,1359,1360],{},"message",", in that order. So the server's own message wins, for ",[604,1363,1364],{},"$fetch"," errors, ",[604,1367,1368],{},"createError"," payloads and plain\n",[604,1371,1372],{},"Error","s alike. It returns ",[604,1375,1376],{},"fallback"," when there is nothing to read.",[1336,1379,1380,1384,1385,1388],{},[1339,1381,1382],{},[604,1383,1106],{}," is a pure helper, so its default title, \"Something went wrong.\", is English. In components, use\n",[604,1386,1387],{},"useErrorToast()",", whose default title is translated.",[1336,1390,1391,1396,1397,1400,1401,1404,1405,1408,1409,1412,1413,1416],{},[1339,1392,1393],{},[604,1394,1395],{},"useAction().run"," sets ",[604,1398,1399],{},"busy"," while ",[604,1402,1403],{},"fn"," runs. On success it shows the ",[604,1406,1407],{},"success"," toast. On failure it shows an\nerror toast titled ",[604,1410,1411],{},"error"," and resolves ",[604,1414,1415],{},"undefined",". It replaces hand-written try, catch and saving flags.",[1336,1418,1419,1423,1424,1427,1428,599],{},[1339,1420,1421],{},[604,1422,1289],{}," copies with VueUse's ",[604,1425,1426],{},"useClipboard"," and shows a \"Copied\" toast, or ",[604,1429,1360],{},[623,1431,1433],{"className":783,"code":1432,"language":785,"meta":628,"style":628},"\u003Cscript setup lang=\"ts\">\nconst { busy, run } = useAction()\nconst { copy } = useCopyToClipboard()\n\nconst revoke = (id: string) => run(() => $fetch(`\u002Fapi\u002Fauth\u002Fme\u002Ftokens\u002F${id}`, { method: 'DELETE' }), { success: 'Token revoked' })\n\u003C\u002Fscript>\n",[604,1434,1435,1455,1478,1496,1500,1583],{"__ignoreMap":628},[632,1436,1437,1439,1441,1443,1445,1447,1449,1451,1453],{"class":634,"line":635},[632,1438,761],{"class":646},[632,1440,794],{"class":653},[632,1442,797],{"class":638},[632,1444,800],{"class":638},[632,1446,803],{"class":646},[632,1448,806],{"class":646},[632,1450,627],{"class":809},[632,1452,806],{"class":646},[632,1454,814],{"class":646},[632,1456,1457,1459,1461,1464,1466,1469,1471,1473,1476],{"class":634,"line":650},[632,1458,819],{"class":638},[632,1460,856],{"class":646},[632,1462,1463],{"class":735}," busy",[632,1465,866],{"class":646},[632,1467,1468],{"class":735}," run ",[632,1470,927],{"class":646},[632,1472,889],{"class":646},[632,1474,1475],{"class":732}," useAction",[632,1477,830],{"class":735},[632,1479,1480,1482,1484,1487,1489,1491,1494],{"class":634,"line":663},[632,1481,819],{"class":638},[632,1483,856],{"class":646},[632,1485,1486],{"class":735}," copy ",[632,1488,927],{"class":646},[632,1490,889],{"class":646},[632,1492,1493],{"class":732}," useCopyToClipboard",[632,1495,830],{"class":735},[632,1497,1498],{"class":634,"line":674},[632,1499,726],{"emptyLinePlaceholder":725},[632,1501,1502,1504,1507,1509,1511,1513,1515,1517,1519,1521,1524,1526,1528,1530,1532,1534,1536,1539,1541,1543,1545,1547,1549,1551,1553,1555,1557,1559,1561,1563,1565,1567,1570,1572,1574,1577,1579,1581],{"class":634,"line":689},[632,1503,819],{"class":638},[632,1505,1506],{"class":735}," revoke ",[632,1508,803],{"class":646},[632,1510,741],{"class":646},[632,1512,1037],{"class":744},[632,1514,657],{"class":646},[632,1516,682],{"class":642},[632,1518,752],{"class":646},[632,1520,755],{"class":638},[632,1522,1523],{"class":732}," run",[632,1525,848],{"class":735},[632,1527,736],{"class":646},[632,1529,755],{"class":638},[632,1531,1021],{"class":732},[632,1533,848],{"class":735},[632,1535,933],{"class":646},[632,1537,1538],{"class":809},"\u002Fapi\u002Fauth\u002Fme\u002Ftokens\u002F",[632,1540,917],{"class":646},[632,1542,1037],{"class":735},[632,1544,1040],{"class":646},[632,1546,866],{"class":646},[632,1548,856],{"class":646},[632,1550,1047],{"class":653},[632,1552,657],{"class":646},[632,1554,946],{"class":646},[632,1556,1054],{"class":809},[632,1558,952],{"class":646},[632,1560,1059],{"class":646},[632,1562,752],{"class":735},[632,1564,866],{"class":646},[632,1566,856],{"class":646},[632,1568,1569],{"class":653}," success",[632,1571,657],{"class":646},[632,1573,946],{"class":646},[632,1575,1576],{"class":809},"Token revoked",[632,1578,952],{"class":646},[632,1580,1059],{"class":646},[632,1582,992],{"class":735},[632,1584,1585,1587,1589],{"class":634,"line":702},[632,1586,1072],{"class":646},[632,1588,794],{"class":653},[632,1590,814],{"class":646},[612,1592,1594],{"id":1593},"loading-data-that-survives-navigation","Loading data that survives navigation",[593,1596,1597,1600],{},[604,1598,1599],{},"useCachedFetch"," keeps a page's data on screen when the visitor leaves and comes back.",[623,1602,1604],{"className":625,"code":1603,"language":627,"meta":628,"style":628},"useCachedFetch\u003CResT, DataT = ResT>(url: string | Ref\u003Cstring> | (() => string), options: UseFetchOptions & {\n  key: MaybeRefOrGetter\u003Cstring> \u002F\u002F required: names the cache entry\n  ttl?: number                  \u002F\u002F ms a remembered response is reused on mount; omitted = until refresh()\n}): {\n  data: Ref\u003CDataT | undefined>  \u002F\u002F undefined until the first response; there is no `default`\n  status, error, refresh, execute, clear\n  loading: ComputedRef\u003Cboolean> \u002F\u002F status === 'pending' && data === undefined: nothing to show yet\n} \u002F\u002F and awaitable: `await useCachedFetch(...)` resolves once the first response is in\n\nprimeCachedFetch(key: string, data: unknown): void \u002F\u002F remember a response loaded some other way\nclearCachedFetch(keys?: string | string[] | ((key: string) => boolean)): void \u002F\u002F forget them, e.g. on sign-out\n\nloadBootstrap(scope: string, options?: { ttl?: number }): Promise\u003Cvoid> \u002F\u002F one request primes an area's keys\nresetBootstrap(scope: string): void \u002F\u002F forget the area's bootstrap and the entries it primed\n",[604,1605,1606,1663,1682,1695,1703,1725,1750,1769,1776,1780,1799,1841,1845,1881],{"__ignoreMap":628},[632,1607,1608,1610,1612,1615,1617,1620,1623,1625,1627,1630,1632,1634,1636,1639,1641,1644,1646,1648,1650,1653,1655,1658,1661],{"class":634,"line":635},[632,1609,1599],{"class":732},[632,1611,761],{"class":646},[632,1613,1614],{"class":642},"ResT",[632,1616,866],{"class":646},[632,1618,1619],{"class":642}," DataT",[632,1621,1622],{"class":735}," = ",[632,1624,1614],{"class":642},[632,1626,767],{"class":646},[632,1628,1629],{"class":735},"(url: string ",[632,1631,1273],{"class":646},[632,1633,1199],{"class":735},[632,1635,761],{"class":646},[632,1637,1638],{"class":735},"string",[632,1640,767],{"class":646},[632,1642,1643],{"class":646}," |",[632,1645,741],{"class":735},[632,1647,736],{"class":646},[632,1649,755],{"class":638},[632,1651,1652],{"class":735}," string)",[632,1654,866],{"class":646},[632,1656,1657],{"class":735}," options: UseFetchOptions ",[632,1659,1660],{"class":646},"&",[632,1662,647],{"class":646},[632,1664,1665,1668,1670,1673,1675,1677,1679],{"class":634,"line":650},[632,1666,1667],{"class":653},"  key",[632,1669,657],{"class":646},[632,1671,1672],{"class":735}," MaybeRefOrGetter",[632,1674,761],{"class":646},[632,1676,1638],{"class":735},[632,1678,767],{"class":646},[632,1680,1681],{"class":685}," \u002F\u002F required: names the cache entry\n",[632,1683,1684,1687,1689,1692],{"class":634,"line":663},[632,1685,1686],{"class":735},"  ttl",[632,1688,669],{"class":646},[632,1690,1691],{"class":735}," number                  ",[632,1693,1694],{"class":685},"\u002F\u002F ms a remembered response is reused on mount; omitted = until refresh()\n",[632,1696,1697,1699,1701],{"class":634,"line":674},[632,1698,927],{"class":646},[632,1700,1262],{"class":735},[632,1702,901],{"class":646},[632,1704,1705,1708,1710,1712,1714,1717,1719,1722],{"class":634,"line":689},[632,1706,1707],{"class":653},"  data",[632,1709,657],{"class":646},[632,1711,1199],{"class":735},[632,1713,761],{"class":646},[632,1715,1716],{"class":735},"DataT ",[632,1718,1273],{"class":646},[632,1720,1721],{"class":646}," undefined>",[632,1723,1724],{"class":685},"  \u002F\u002F undefined until the first response; there is no `default`\n",[632,1726,1727,1730,1732,1735,1737,1740,1742,1745,1747],{"class":634,"line":702},[632,1728,1729],{"class":735},"  status",[632,1731,866],{"class":646},[632,1733,1734],{"class":735}," error",[632,1736,866],{"class":646},[632,1738,1739],{"class":735}," refresh",[632,1741,866],{"class":646},[632,1743,1744],{"class":735}," execute",[632,1746,866],{"class":646},[632,1748,1749],{"class":735}," clear\n",[632,1751,1752,1755,1757,1760,1762,1764,1766],{"class":634,"line":716},[632,1753,1754],{"class":653},"  loading",[632,1756,657],{"class":646},[632,1758,1759],{"class":735}," ComputedRef",[632,1761,761],{"class":646},[632,1763,764],{"class":735},[632,1765,767],{"class":646},[632,1767,1768],{"class":685}," \u002F\u002F status === 'pending' && data === undefined: nothing to show yet\n",[632,1770,1771,1773],{"class":634,"line":722},[632,1772,927],{"class":646},[632,1774,1775],{"class":685}," \u002F\u002F and awaitable: `await useCachedFetch(...)` resolves once the first response is in\n",[632,1777,1778],{"class":634,"line":729},[632,1779,726],{"emptyLinePlaceholder":725},[632,1781,1782,1785,1788,1790,1793,1796],{"class":634,"line":986},[632,1783,1784],{"class":732},"primeCachedFetch",[632,1786,1787],{"class":735},"(key: string",[632,1789,866],{"class":646},[632,1791,1792],{"class":735}," data: unknown): ",[632,1794,1795],{"class":646},"void",[632,1797,1798],{"class":685}," \u002F\u002F remember a response loaded some other way\n",[632,1800,1801,1804,1807,1809,1811,1813,1816,1818,1820,1822,1825,1827,1829,1831,1833,1836,1838],{"class":634,"line":995},[632,1802,1803],{"class":732},"clearCachedFetch",[632,1805,1806],{"class":735},"(keys",[632,1808,669],{"class":646},[632,1810,1257],{"class":735},[632,1812,1273],{"class":646},[632,1814,1815],{"class":735}," string[] ",[632,1817,1273],{"class":646},[632,1819,741],{"class":735},[632,1821,848],{"class":646},[632,1823,1824],{"class":744},"key",[632,1826,657],{"class":646},[632,1828,682],{"class":642},[632,1830,752],{"class":646},[632,1832,755],{"class":638},[632,1834,1835],{"class":735}," boolean)): ",[632,1837,1795],{"class":646},[632,1839,1840],{"class":685}," \u002F\u002F forget them, e.g. on sign-out\n",[632,1842,1843],{"class":634,"line":1015},[632,1844,726],{"emptyLinePlaceholder":725},[632,1846,1847,1850,1853,1855,1857,1859,1861,1864,1866,1869,1871,1873,1875,1878],{"class":634,"line":1064},[632,1848,1849],{"class":732},"loadBootstrap",[632,1851,1852],{"class":735},"(scope: string",[632,1854,866],{"class":646},[632,1856,1236],{"class":735},[632,1858,669],{"class":646},[632,1860,856],{"class":646},[632,1862,1863],{"class":735}," ttl?",[632,1865,657],{"class":646},[632,1867,1868],{"class":735}," number ",[632,1870,927],{"class":646},[632,1872,1262],{"class":735},[632,1874,1265],{"class":642},[632,1876,1877],{"class":646},"\u003Cvoid>",[632,1879,1880],{"class":685}," \u002F\u002F one request primes an area's keys\n",[632,1882,1883,1886,1889,1891],{"class":634,"line":1069},[632,1884,1885],{"class":732},"resetBootstrap",[632,1887,1888],{"class":735},"(scope: string): ",[632,1890,1795],{"class":646},[632,1892,1893],{"class":685}," \u002F\u002F forget the area's bootstrap and the entries it primed\n",[593,1895,1896,1897,1900,1901,1903,1904,1906,1907,1909],{},"Nuxt drops ",[604,1898,1899],{},"useFetch"," data once the last component that uses its key unmounts. Coming back then flashes the empty\nstate until the refetch lands. ",[604,1902,1599],{}," wraps ",[604,1905,1899],{}," and remembers each response by ",[604,1908,1824],{},". On mount it\ntakes the data from the first of these:",[1911,1912,1913,1916,1922],"ol",{},[1336,1914,1915],{},"The server's response in the payload, while hydrating. It is remembered too.",[1336,1917,1918,1919,599],{},"The remembered response, while it is younger than ",[604,1920,1921],{},"ttl",[1336,1923,1924],{},"A request. Until it lands, an older remembered response stays on screen.",[593,1926,1927,1347,1930,1933,1934,1936],{},[604,1928,1929],{},"refresh()",[604,1931,1932],{},"refreshNuxtData()"," and watchers always ask the server and update the remembered response. Only the\nbrowser remembers responses, so the cache adds nothing to the server-rendered payload. On the server,\n",[604,1935,1784],{}," puts the data in that request's payload instead.",[1333,1938,1939,1965,1984,1993],{},[1336,1940,1941,1947,1948,1951,1952,1954,1955,1957,1958,1961,1962,1964],{},[1339,1942,1943,1944,599],{},"No ",[604,1945,1946],{},"default"," A failed request leaves ",[604,1949,1950],{},"data"," ",[604,1953,1415],{},", or the last good response, and sets ",[604,1956,1411],{},". Derive\nlists with ",[604,1959,1960],{},"data.value ?? []",", and check ",[604,1963,1411],{}," before an empty state.",[1336,1966,1967,1972,1973,1976,1977,1980,1981,1983],{},[1339,1968,1969],{},[604,1970,1971],{},"loading"," is ",[604,1974,1975],{},"true"," only while there is nothing on screen yet, not during a background refresh. It is not named\n",[604,1978,1979],{},"pending",", which ",[604,1982,1899],{}," has deprecated.",[1336,1985,1986,1989,1990,599],{},[1339,1987,1988],{},"Await it in pages",", so the server renders the data. When to load lazily instead is on\n",[597,1991,101],{"href":1992},"\u002Fguide\u002Fux-patterns\u002Fpages#loading",[1336,1994,1995,1998,1999,2002,2003,2006],{},[1339,1996,1997],{},"Awaitable composables."," A composable built on it can return ",[604,2000,2001],{},"Object.assign(fetched.then(() => api), api)",". A page\nthen awaits ",[604,2004,2005],{},"useMyThing()",", and a widget calls it directly.",[623,2008,2010],{"className":783,"code":2009,"language":785,"meta":628,"style":628},"\u003Cscript setup lang=\"ts\">\nconst { data, error, loading } = await useCachedFetch\u003CTicketDto[]>('\u002Fapi\u002Fevents\u002Fme\u002Ftickets', {\n  key: 'events:tickets:mine',\n  ttl: 60_000,\n})\nconst tickets = computed(() => data.value ?? [])\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CSectionCard v-if=\"loading\" loading \u002F>\n  \u003CUEmpty v-else-if=\"error\" icon=\"i-lucide-circle-alert\" :description=\"errorMessage(error, 'Could not load tickets.')\" \u002F>\n  \u003CUEmpty v-else-if=\"!tickets.length\" icon=\"i-lucide-ticket\" title=\"No tickets yet\" \u002F>\n  \u003CTicketList v-else :tickets=\"tickets\" \u002F>\n\u003C\u002Ftemplate>\n",[604,2011,2012,2032,2082,2097,2109,2115,2146,2154,2158,2167,2192,2253,2300,2324],{"__ignoreMap":628},[632,2013,2014,2016,2018,2020,2022,2024,2026,2028,2030],{"class":634,"line":635},[632,2015,761],{"class":646},[632,2017,794],{"class":653},[632,2019,797],{"class":638},[632,2021,800],{"class":638},[632,2023,803],{"class":646},[632,2025,806],{"class":646},[632,2027,627],{"class":809},[632,2029,806],{"class":646},[632,2031,814],{"class":646},[632,2033,2034,2036,2038,2041,2043,2045,2047,2050,2052,2054,2056,2059,2061,2064,2067,2069,2071,2073,2076,2078,2080],{"class":634,"line":650},[632,2035,819],{"class":638},[632,2037,856],{"class":646},[632,2039,2040],{"class":735}," data",[632,2042,866],{"class":646},[632,2044,1734],{"class":735},[632,2046,866],{"class":646},[632,2048,2049],{"class":735}," loading ",[632,2051,927],{"class":646},[632,2053,889],{"class":646},[632,2055,893],{"class":892},[632,2057,2058],{"class":732}," useCachedFetch",[632,2060,761],{"class":646},[632,2062,2063],{"class":642},"TicketDto",[632,2065,2066],{"class":735},"[]",[632,2068,767],{"class":646},[632,2070,848],{"class":735},[632,2072,952],{"class":646},[632,2074,2075],{"class":809},"\u002Fapi\u002Fevents\u002Fme\u002Ftickets",[632,2077,952],{"class":646},[632,2079,866],{"class":646},[632,2081,647],{"class":646},[632,2083,2084,2086,2088,2090,2093,2095],{"class":634,"line":663},[632,2085,1667],{"class":653},[632,2087,657],{"class":646},[632,2089,946],{"class":646},[632,2091,2092],{"class":809},"events:tickets:mine",[632,2094,952],{"class":646},[632,2096,936],{"class":646},[632,2098,2099,2101,2103,2107],{"class":634,"line":674},[632,2100,1686],{"class":653},[632,2102,657],{"class":646},[632,2104,2106],{"class":2105},"sbssI"," 60_000",[632,2108,936],{"class":646},[632,2110,2111,2113],{"class":634,"line":689},[632,2112,927],{"class":646},[632,2114,992],{"class":735},[632,2116,2117,2119,2122,2124,2127,2129,2131,2133,2135,2137,2140,2143],{"class":634,"line":702},[632,2118,819],{"class":638},[632,2120,2121],{"class":735}," tickets ",[632,2123,803],{"class":646},[632,2125,2126],{"class":732}," computed",[632,2128,848],{"class":735},[632,2130,736],{"class":646},[632,2132,755],{"class":638},[632,2134,2040],{"class":735},[632,2136,599],{"class":646},[632,2138,2139],{"class":735},"value ",[632,2141,2142],{"class":646},"??",[632,2144,2145],{"class":735}," [])\n",[632,2147,2148,2150,2152],{"class":634,"line":716},[632,2149,1072],{"class":646},[632,2151,794],{"class":653},[632,2153,814],{"class":646},[632,2155,2156],{"class":634,"line":722},[632,2157,726],{"emptyLinePlaceholder":725},[632,2159,2160,2162,2165],{"class":634,"line":729},[632,2161,761],{"class":646},[632,2163,2164],{"class":653},"template",[632,2166,814],{"class":646},[632,2168,2169,2172,2175,2178,2180,2182,2184,2186,2189],{"class":634,"line":986},[632,2170,2171],{"class":646},"  \u003C",[632,2173,2174],{"class":653},"SectionCard",[632,2176,2177],{"class":892}," v-if",[632,2179,803],{"class":646},[632,2181,806],{"class":646},[632,2183,1971],{"class":735},[632,2185,806],{"class":646},[632,2187,2188],{"class":638}," loading",[632,2190,2191],{"class":646}," \u002F>\n",[632,2193,2194,2196,2199,2202,2204,2206,2208,2210,2213,2215,2217,2220,2222,2225,2228,2230,2232,2234,2236,2238,2240,2242,2245,2247,2249,2251],{"class":634,"line":995},[632,2195,2171],{"class":646},[632,2197,2198],{"class":653},"UEmpty",[632,2200,2201],{"class":892}," v-else-if",[632,2203,803],{"class":646},[632,2205,806],{"class":646},[632,2207,1411],{"class":735},[632,2209,806],{"class":646},[632,2211,2212],{"class":638}," icon",[632,2214,803],{"class":646},[632,2216,806],{"class":646},[632,2218,2219],{"class":809},"i-lucide-circle-alert",[632,2221,806],{"class":646},[632,2223,2224],{"class":646}," :",[632,2226,2227],{"class":638},"description",[632,2229,803],{"class":646},[632,2231,806],{"class":646},[632,2233,1093],{"class":732},[632,2235,848],{"class":646},[632,2237,1411],{"class":735},[632,2239,1347],{"class":646},[632,2241,952],{"class":646},[632,2243,2244],{"class":809},"Could not load tickets.",[632,2246,952],{"class":646},[632,2248,752],{"class":646},[632,2250,806],{"class":646},[632,2252,2191],{"class":646},[632,2254,2255,2257,2259,2261,2263,2265,2267,2270,2272,2275,2277,2279,2281,2283,2285,2287,2289,2291,2293,2296,2298],{"class":634,"line":1015},[632,2256,2171],{"class":646},[632,2258,2198],{"class":653},[632,2260,2201],{"class":892},[632,2262,803],{"class":646},[632,2264,806],{"class":646},[632,2266,1003],{"class":646},[632,2268,2269],{"class":735},"tickets",[632,2271,599],{"class":646},[632,2273,2274],{"class":735},"length",[632,2276,806],{"class":646},[632,2278,2212],{"class":638},[632,2280,803],{"class":646},[632,2282,806],{"class":646},[632,2284,493],{"class":809},[632,2286,806],{"class":646},[632,2288,1161],{"class":638},[632,2290,803],{"class":646},[632,2292,806],{"class":646},[632,2294,2295],{"class":809},"No tickets yet",[632,2297,806],{"class":646},[632,2299,2191],{"class":646},[632,2301,2302,2304,2307,2310,2312,2314,2316,2318,2320,2322],{"class":634,"line":1064},[632,2303,2171],{"class":646},[632,2305,2306],{"class":653},"TicketList",[632,2308,2309],{"class":892}," v-else",[632,2311,2224],{"class":646},[632,2313,2269],{"class":638},[632,2315,803],{"class":646},[632,2317,806],{"class":646},[632,2319,2269],{"class":735},[632,2321,806],{"class":646},[632,2323,2191],{"class":646},[632,2325,2326,2328,2330],{"class":634,"line":1069},[632,2327,1072],{"class":646},[632,2329,2164],{"class":653},[632,2331,814],{"class":646},[612,2333,2335,2336],{"id":2334},"one-request-for-an-area-loadbootstrap","One request for an area: ",[604,2337,1849],{},[593,2339,2340,2342],{},[604,2341,1849],{}," loads several modules' data for an area in one request instead of one per module. The account pages\nuse it for membership, tickets and applications.",[593,2344,2345,2346,2352,2353,2355,2356,2359,2360,2363],{},"Each module registers a provider for the area's scope with\n",[597,2347,2349],{"href":2348},"\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fregistries-and-menus#bootstrap-providers",[604,2350,2351],{},"registerBootstrapProvider",". It uses the key\nits composable already passes to ",[604,2354,1599],{},". The area calls ",[604,2357,2358],{},"loadBootstrap(scope)"," from a route middleware. That\nfetches ",[604,2361,2362],{},"GET \u002Fapi\u002Fauth\u002Fbootstrap?scope=\u003Cscope>"," and primes each returned key, so the composables need no request of\ntheir own.",[1333,2365,2366,2375,2387,2393],{},[1336,2367,2368,2371,2372,2374],{},[1339,2369,2370],{},"On the server,"," the data goes into the payload. The page's ",[604,2373,1599],{}," calls read it while rendering, and the\nbrowser reads it while hydrating.",[1336,2376,2377,2380,2381,2383,2384,2386],{},[1339,2378,2379],{},"On client navigation,"," it sends a request only when the last bootstrap is older than ",[604,2382,1921],{},", one minute by\ndefault. Keep it at or below the ",[604,2385,1921],{}," of the composables it primes.",[1336,2388,2389,2392],{},[1339,2390,2391],{},"On failure,"," it never throws. The composables then fetch from their own endpoints.",[1336,2394,2395,2398,2399,2402,2403,599],{},[1339,2396,2397],{},"When the user changes,"," call ",[604,2400,2401],{},"resetBootstrap(scope)"," on sign-in and sign-out. The Account module does this for\n",[604,2404,2405],{},"account",[2407,2408,2409],"warning",{},"Call it from a route middleware, not from the layout. A layout stays mounted between the area's pages, and its setup\nmay finish after the page's. A middleware runs before every page, on the server and on each client navigation.",[623,2411,2413],{"className":625,"code":2412,"language":627,"meta":628,"style":628},"\u002F\u002F runtime\u002Fapp\u002Fmiddleware\u002Fbootstrap.ts, added to the area's routes with a route rule\n\u002F\u002F (`appMiddleware: { 'my-area-bootstrap': true }`)\nexport default defineNuxtRouteMiddleware(async () => {\n  if (useUserSession().loggedIn.value) await loadBootstrap('my-area')\n})\n",[604,2414,2415,2420,2425,2447,2487],{"__ignoreMap":628},[632,2416,2417],{"class":634,"line":635},[632,2418,2419],{"class":685},"\u002F\u002F runtime\u002Fapp\u002Fmiddleware\u002Fbootstrap.ts, added to the area's routes with a route rule\n",[632,2421,2422],{"class":634,"line":650},[632,2423,2424],{"class":685},"\u002F\u002F (`appMiddleware: { 'my-area-bootstrap': true }`)\n",[632,2426,2427,2430,2433,2436,2438,2440,2443,2445],{"class":634,"line":663},[632,2428,2429],{"class":892},"export",[632,2431,2432],{"class":892}," default",[632,2434,2435],{"class":732}," defineNuxtRouteMiddleware",[632,2437,848],{"class":735},[632,2439,839],{"class":638},[632,2441,2442],{"class":646}," ()",[632,2444,755],{"class":638},[632,2446,647],{"class":646},[632,2448,2449,2451,2453,2456,2458,2460,2463,2465,2468,2470,2473,2476,2478,2480,2483,2485],{"class":634,"line":674},[632,2450,998],{"class":892},[632,2452,741],{"class":653},[632,2454,2455],{"class":732},"useUserSession",[632,2457,736],{"class":653},[632,2459,599],{"class":646},[632,2461,2462],{"class":735},"loggedIn",[632,2464,599],{"class":646},[632,2466,2467],{"class":735},"value",[632,2469,1009],{"class":653},[632,2471,2472],{"class":892},"await",[632,2474,2475],{"class":732}," loadBootstrap",[632,2477,848],{"class":653},[632,2479,952],{"class":646},[632,2481,2482],{"class":809},"my-area",[632,2484,952],{"class":646},[632,2486,992],{"class":653},[632,2488,2489,2491],{"class":634,"line":689},[632,2490,927],{"class":646},[632,2492,992],{"class":735},[612,2494,2496],{"id":2495},"formatting-and-links","Formatting and links",[593,2498,2499],{},"These helpers format dates and money in the visitor's locale and keep links under the locale prefix.",[623,2501,2503],{"className":625,"code":2502,"language":627,"meta":628,"style":628},"\u002F\u002F utils: pure functions; accept a Date, an ISO string or a timestamp. `locale` defaults to English\nformatDate(value, locale?): string\nformatDateTime(value, locale?): string\nformatTime(value, locale?): string\nformatDateRange(start, end, locale?): string\n\nuseFormat(): { locale, timeZone, date, dateTime, time, dateRange, money } \u002F\u002F bound to the locale and the app time zone\n\u002F\u002F money(15000, 'DKK') is formatMoney from @frigear-nu\u002Fui\u002Fmoney with the locale bound; amounts are in minor units\n\nuseLocaleLink(): {\n  localize(to: string): string \u002F\u002F prefixes the active locale when @nuxtjs\u002Fi18n is installed; unchanged otherwise\n  strip(path: string): string \u002F\u002F removes a leading locale code\n  isActive(to: string, options?: { exact?: boolean }): boolean \u002F\u002F the current route is `to` or below it\n}\n\nuseNavLinks(items: MaybeRefOrGetter\u003CMenuItem[]>, options?: { exact?: string[] }): ComputedRef\u003CNavigationMenuItem[]>\n",[604,2504,2505,2510,2531,2550,2569,2594,2598,2644,2649,2653,2662,2683,2704,2740,2744,2749],{"__ignoreMap":628},[632,2506,2507],{"class":634,"line":635},[632,2508,2509],{"class":685},"\u002F\u002F utils: pure functions; accept a Date, an ISO string or a timestamp. `locale` defaults to English\n",[632,2511,2512,2515,2518,2520,2523,2525,2527,2529],{"class":634,"line":650},[632,2513,2514],{"class":732},"formatDate",[632,2516,2517],{"class":735},"(value",[632,2519,866],{"class":646},[632,2521,2522],{"class":735}," locale",[632,2524,930],{"class":646},[632,2526,752],{"class":735},[632,2528,657],{"class":646},[632,2530,660],{"class":735},[632,2532,2533,2536,2538,2540,2542,2544,2546,2548],{"class":634,"line":663},[632,2534,2535],{"class":732},"formatDateTime",[632,2537,2517],{"class":735},[632,2539,866],{"class":646},[632,2541,2522],{"class":735},[632,2543,930],{"class":646},[632,2545,752],{"class":735},[632,2547,657],{"class":646},[632,2549,660],{"class":735},[632,2551,2552,2555,2557,2559,2561,2563,2565,2567],{"class":634,"line":674},[632,2553,2554],{"class":732},"formatTime",[632,2556,2517],{"class":735},[632,2558,866],{"class":646},[632,2560,2522],{"class":735},[632,2562,930],{"class":646},[632,2564,752],{"class":735},[632,2566,657],{"class":646},[632,2568,660],{"class":735},[632,2570,2571,2574,2577,2579,2582,2584,2586,2588,2590,2592],{"class":634,"line":689},[632,2572,2573],{"class":732},"formatDateRange",[632,2575,2576],{"class":735},"(start",[632,2578,866],{"class":646},[632,2580,2581],{"class":735}," end",[632,2583,866],{"class":646},[632,2585,2522],{"class":735},[632,2587,930],{"class":646},[632,2589,752],{"class":735},[632,2591,657],{"class":646},[632,2593,660],{"class":735},[632,2595,2596],{"class":634,"line":702},[632,2597,726],{"emptyLinePlaceholder":725},[632,2599,2600,2603,2605,2607,2609,2611,2614,2616,2619,2621,2624,2626,2629,2631,2634,2636,2639,2641],{"class":634,"line":716},[632,2601,2602],{"class":732},"useFormat",[632,2604,1187],{"class":735},[632,2606,1294],{"class":646},[632,2608,2522],{"class":735},[632,2610,866],{"class":646},[632,2612,2613],{"class":735}," timeZone",[632,2615,866],{"class":646},[632,2617,2618],{"class":735}," date",[632,2620,866],{"class":646},[632,2622,2623],{"class":735}," dateTime",[632,2625,866],{"class":646},[632,2627,2628],{"class":735}," time",[632,2630,866],{"class":646},[632,2632,2633],{"class":735}," dateRange",[632,2635,866],{"class":646},[632,2637,2638],{"class":735}," money ",[632,2640,927],{"class":646},[632,2642,2643],{"class":685}," \u002F\u002F bound to the locale and the app time zone\n",[632,2645,2646],{"class":634,"line":722},[632,2647,2648],{"class":685},"\u002F\u002F money(15000, 'DKK') is formatMoney from @frigear-nu\u002Fui\u002Fmoney with the locale bound; amounts are in minor units\n",[632,2650,2651],{"class":634,"line":729},[632,2652,726],{"emptyLinePlaceholder":725},[632,2654,2655,2658,2660],{"class":634,"line":986},[632,2656,2657],{"class":732},"useLocaleLink",[632,2659,1187],{"class":735},[632,2661,901],{"class":646},[632,2663,2664,2667,2669,2672,2674,2676,2678,2680],{"class":634,"line":995},[632,2665,2666],{"class":653},"  localize",[632,2668,848],{"class":646},[632,2670,2671],{"class":744},"to",[632,2673,657],{"class":646},[632,2675,682],{"class":642},[632,2677,1318],{"class":646},[632,2679,682],{"class":642},[632,2681,2682],{"class":685}," \u002F\u002F prefixes the active locale when @nuxtjs\u002Fi18n is installed; unchanged otherwise\n",[632,2684,2685,2688,2690,2693,2695,2697,2699,2701],{"class":634,"line":1015},[632,2686,2687],{"class":653},"  strip",[632,2689,848],{"class":646},[632,2691,2692],{"class":744},"path",[632,2694,657],{"class":646},[632,2696,682],{"class":642},[632,2698,1318],{"class":646},[632,2700,682],{"class":642},[632,2702,2703],{"class":685}," \u002F\u002F removes a leading locale code\n",[632,2705,2706,2709,2711,2713,2715,2717,2719,2721,2723,2725,2728,2730,2732,2735,2737],{"class":634,"line":1064},[632,2707,2708],{"class":653},"  isActive",[632,2710,848],{"class":646},[632,2712,2671],{"class":744},[632,2714,657],{"class":646},[632,2716,682],{"class":642},[632,2718,866],{"class":646},[632,2720,1236],{"class":744},[632,2722,669],{"class":646},[632,2724,856],{"class":646},[632,2726,2727],{"class":653}," exact",[632,2729,669],{"class":646},[632,2731,710],{"class":642},[632,2733,2734],{"class":646}," }):",[632,2736,710],{"class":642},[632,2738,2739],{"class":685}," \u002F\u002F the current route is `to` or below it\n",[632,2741,2742],{"class":634,"line":1069},[632,2743,719],{"class":646},[632,2745,2747],{"class":634,"line":2746},15,[632,2748,726],{"emptyLinePlaceholder":725},[632,2750,2752,2755,2758,2760,2763,2765,2767,2769,2771,2774,2776,2778,2780,2783,2785,2788],{"class":634,"line":2751},16,[632,2753,2754],{"class":732},"useNavLinks",[632,2756,2757],{"class":735},"(items: MaybeRefOrGetter",[632,2759,761],{"class":646},[632,2761,2762],{"class":735},"MenuItem[]",[632,2764,1233],{"class":646},[632,2766,1236],{"class":735},[632,2768,669],{"class":646},[632,2770,856],{"class":646},[632,2772,2773],{"class":735}," exact?",[632,2775,657],{"class":646},[632,2777,1815],{"class":735},[632,2779,927],{"class":646},[632,2781,2782],{"class":735},"): ComputedRef",[632,2784,761],{"class":646},[632,2786,2787],{"class":735},"NavigationMenuItem[]",[632,2789,814],{"class":646},[2407,2791,2792,2793,2796,2797,2800],{},"Set the time zone in ",[604,2794,2795],{},"app.config.ts",", as ",[604,2798,2799],{},"frigearUi: { timeZone: 'Europe\u002FCopenhagen' }",". Without it, a server in UTC\nand the visitor's browser format the same instant differently, and the page fails to hydrate.",[1333,2802,2803,2817],{},[1336,2804,2805,2809,2810,2813,2814,599],{},[1339,2806,2807],{},[604,2808,2657],{}," is not named ",[604,2811,2812],{},"useLocalePath",", so it never clashes with the composable of ",[604,2815,2816],{},"@nuxtjs\u002Fi18n",[1336,2818,2819,2823,2824,2827,2828,2830,2831,2834,2835,2838],{},[1339,2820,2821],{},[604,2822,2754],{}," turns menu items from ",[604,2825,2826],{},"useMenu"," into navigation items with a localised ",[604,2829,2671],{}," and an ",[604,2832,2833],{},"active"," flag.\nPaths in ",[604,2836,2837],{},"exact"," match only exactly, for an item such as a dashboard at the area's base path. The admin sidebar, the\naccount navigation and the site header use it.",[593,2840,2841,2842,599],{},"When to use these is on ",[597,2843,111],{"href":112},[612,2845,2847],{"id":2846},"status-and-styling","Status and styling",[593,2849,2850],{},"These helpers give every status badge, card and table the same look.",[623,2852,2854],{"className":625,"code":2853,"language":627,"meta":628,"style":628},"statusColor(status: string | null | undefined, overrides?: Record\u003Cstring, StatusColor>): StatusColor\n\u002F\u002F success: published, active, trialing, paid, succeeded\n\u002F\u002F warning: pending, past_due, incomplete, scheduled\n\u002F\u002F error:   failed\n\u002F\u002F neutral: everything else\n\nsurfaceClass \u002F\u002F 'bg-elevated\u002F50 ring ring-default rounded-lg overflow-hidden', the frame of every card\ntableUi(overrides?: TableUi, options?: { sticky?: boolean }): TableUi\n\u002F\u002F the shared UTable styling inside TableCard. `overrides` replace single slots (`tableUi({ tr: '' })` for rows that\n\u002F\u002F open nothing); `sticky` lets the table scroll inside its card (pair it with `\u003CUTable sticky>`)\n\nnumericColumn \u002F\u002F column meta for numbers: right-aligned, tabular figures (`{ meta: numericColumn }`)\nemptyCell(): VNode \u002F\u002F the dimmed dash of a cell without a value\n",[604,2855,2856,2895,2900,2905,2910,2915,2919,2927,2961,2966,2971,2975,2983],{"__ignoreMap":628},[632,2857,2858,2861,2864,2866,2869,2871,2874,2876,2878,2881,2883,2885,2887,2890,2892],{"class":634,"line":635},[632,2859,2860],{"class":732},"statusColor",[632,2862,2863],{"class":735},"(status: string ",[632,2865,1273],{"class":646},[632,2867,2868],{"class":646}," null",[632,2870,1643],{"class":646},[632,2872,2873],{"class":646}," undefined,",[632,2875,1113],{"class":735},[632,2877,669],{"class":646},[632,2879,2880],{"class":735}," Record",[632,2882,761],{"class":646},[632,2884,1638],{"class":735},[632,2886,866],{"class":646},[632,2888,2889],{"class":735}," StatusColor",[632,2891,767],{"class":646},[632,2893,2894],{"class":735},"): StatusColor\n",[632,2896,2897],{"class":634,"line":650},[632,2898,2899],{"class":685},"\u002F\u002F success: published, active, trialing, paid, succeeded\n",[632,2901,2902],{"class":634,"line":663},[632,2903,2904],{"class":685},"\u002F\u002F warning: pending, past_due, incomplete, scheduled\n",[632,2906,2907],{"class":634,"line":674},[632,2908,2909],{"class":685},"\u002F\u002F error:   failed\n",[632,2911,2912],{"class":634,"line":689},[632,2913,2914],{"class":685},"\u002F\u002F neutral: everything else\n",[632,2916,2917],{"class":634,"line":702},[632,2918,726],{"emptyLinePlaceholder":725},[632,2920,2921,2924],{"class":634,"line":716},[632,2922,2923],{"class":735},"surfaceClass ",[632,2925,2926],{"class":685},"\u002F\u002F 'bg-elevated\u002F50 ring ring-default rounded-lg overflow-hidden', the frame of every card\n",[632,2928,2929,2932,2935,2937,2940,2942,2944,2946,2948,2951,2953,2956,2958],{"class":634,"line":722},[632,2930,2931],{"class":732},"tableUi",[632,2933,2934],{"class":735},"(overrides",[632,2936,669],{"class":646},[632,2938,2939],{"class":735}," TableUi",[632,2941,866],{"class":646},[632,2943,1236],{"class":735},[632,2945,669],{"class":646},[632,2947,856],{"class":646},[632,2949,2950],{"class":735}," sticky?",[632,2952,657],{"class":646},[632,2954,2955],{"class":735}," boolean ",[632,2957,927],{"class":646},[632,2959,2960],{"class":735},"): TableUi\n",[632,2962,2963],{"class":634,"line":729},[632,2964,2965],{"class":685},"\u002F\u002F the shared UTable styling inside TableCard. `overrides` replace single slots (`tableUi({ tr: '' })` for rows that\n",[632,2967,2968],{"class":634,"line":986},[632,2969,2970],{"class":685},"\u002F\u002F open nothing); `sticky` lets the table scroll inside its card (pair it with `\u003CUTable sticky>`)\n",[632,2972,2973],{"class":634,"line":995},[632,2974,726],{"emptyLinePlaceholder":725},[632,2976,2977,2980],{"class":634,"line":1015},[632,2978,2979],{"class":735},"numericColumn ",[632,2981,2982],{"class":685},"\u002F\u002F column meta for numbers: right-aligned, tabular figures (`{ meta: numericColumn }`)\n",[632,2984,2985,2988,2991],{"class":634,"line":1064},[632,2986,2987],{"class":732},"emptyCell",[632,2989,2990],{"class":735},"(): VNode ",[632,2992,2993],{"class":685},"\u002F\u002F the dimmed dash of a cell without a value\n",[593,2995,2996,2997,3000,3001,3003,3004,3007],{},"Pass ",[604,2998,2999],{},"overrides"," to ",[604,3002,2860],{}," to recolour a status of your own module. ",[604,3005,3006],{},"StatusBadge"," uses it for you.",[612,3009,3011],{"id":3010},"tables","Tables",[593,3013,3014,607,3017,3020],{},[604,3015,3016],{},"useTableSort",[604,3018,3019],{},"useTableQuery"," give every list the same sortable headers, search and pagination.",[623,3022,3024],{"className":625,"code":3023,"language":627,"meta":628,"style":628},"useTableSort(initial?: { id, desc } | null, state?: Ref\u003C{ id, desc } | null>): {\n  sort: Ref\u003C{ id, desc } | null>\n  sorting: WritableComputedRef\u003C{ id, desc }[]> \u002F\u002F UTable's shape: `v-model:sorting` for client-sorted lists\n  query: ComputedRef\u003C{ sort?, order? }> \u002F\u002F for server-sorted lists\n  header(id: string, label: string): () => VNode \u002F\u002F a column's sortable `header`\n  toggle(id: string): void\n}\n\nuseTableQuery({ pageSize?, sort?, filters?, debounce? }): {\n  page, pageSize, sort, \u002F\u002F refs, kept in the URL (`?page=2&sort=name&order=asc`)\n  search, \u002F\u002F what the search input binds\n  q, \u002F\u002F `search` after a 300 ms pause\n  filters, \u002F\u002F reactive, one string per filter; a filter at its default stays out of the URL\n  query, \u002F\u002F what a server-paginated list sends to its API\n  filtered, \u002F\u002F the search or a filter narrows the list\n  reset(): void \u002F\u002F clears the search and the filters\n}\n",[604,3025,3026,3078,3102,3124,3145,3168,3179,3183,3187,3218,3238,3248,3258,3268,3278,3288,3301],{"__ignoreMap":628},[632,3027,3028,3030,3033,3035,3037,3039,3041,3044,3046,3048,3051,3054,3056,3058,3061,3063,3065,3067,3069,3071,3074,3076],{"class":634,"line":635},[632,3029,3016],{"class":732},[632,3031,3032],{"class":735},"(initial",[632,3034,669],{"class":646},[632,3036,856],{"class":646},[632,3038,859],{"class":735},[632,3040,866],{"class":646},[632,3042,3043],{"class":735}," desc ",[632,3045,927],{"class":646},[632,3047,1643],{"class":646},[632,3049,3050],{"class":646}," null,",[632,3052,3053],{"class":735}," state",[632,3055,669],{"class":646},[632,3057,1199],{"class":735},[632,3059,3060],{"class":646},"\u003C{",[632,3062,859],{"class":735},[632,3064,866],{"class":646},[632,3066,3043],{"class":735},[632,3068,927],{"class":646},[632,3070,1643],{"class":646},[632,3072,3073],{"class":646}," null>",[632,3075,1262],{"class":735},[632,3077,901],{"class":646},[632,3079,3080,3083,3085,3087,3089,3091,3093,3095,3097,3099],{"class":634,"line":650},[632,3081,3082],{"class":653},"  sort",[632,3084,657],{"class":646},[632,3086,1199],{"class":735},[632,3088,3060],{"class":646},[632,3090,859],{"class":735},[632,3092,866],{"class":646},[632,3094,3043],{"class":735},[632,3096,927],{"class":646},[632,3098,1643],{"class":646},[632,3100,3101],{"class":646}," null>\n",[632,3103,3104,3107,3109,3111,3113,3115,3117,3119,3121],{"class":634,"line":663},[632,3105,3106],{"class":735},"  sorting: WritableComputedRef",[632,3108,3060],{"class":646},[632,3110,859],{"class":735},[632,3112,866],{"class":646},[632,3114,3043],{"class":735},[632,3116,927],{"class":646},[632,3118,2066],{"class":735},[632,3120,767],{"class":646},[632,3122,3123],{"class":685}," \u002F\u002F UTable's shape: `v-model:sorting` for client-sorted lists\n",[632,3125,3126,3129,3131,3134,3136,3139,3142],{"class":634,"line":674},[632,3127,3128],{"class":735},"  query: ComputedRef",[632,3130,3060],{"class":646},[632,3132,3133],{"class":735}," sort?",[632,3135,866],{"class":646},[632,3137,3138],{"class":735}," order? ",[632,3140,3141],{"class":646},"}>",[632,3143,3144],{"class":685}," \u002F\u002F for server-sorted lists\n",[632,3146,3147,3150,3153,3155,3158,3160,3162,3165],{"class":634,"line":689},[632,3148,3149],{"class":732},"  header",[632,3151,3152],{"class":735},"(id: string",[632,3154,866],{"class":646},[632,3156,3157],{"class":735}," label: string): ",[632,3159,736],{"class":646},[632,3161,755],{"class":638},[632,3163,3164],{"class":735}," VNode ",[632,3166,3167],{"class":685},"\u002F\u002F a column's sortable `header`\n",[632,3169,3170,3173,3176],{"class":634,"line":702},[632,3171,3172],{"class":732},"  toggle",[632,3174,3175],{"class":735},"(id: string): ",[632,3177,3178],{"class":646},"void\n",[632,3180,3181],{"class":634,"line":716},[632,3182,719],{"class":646},[632,3184,3185],{"class":634,"line":722},[632,3186,726],{"emptyLinePlaceholder":725},[632,3188,3189,3191,3193,3195,3198,3200,3202,3204,3207,3209,3212,3214,3216],{"class":634,"line":729},[632,3190,3019],{"class":732},[632,3192,848],{"class":735},[632,3194,1294],{"class":646},[632,3196,3197],{"class":735}," pageSize?",[632,3199,866],{"class":646},[632,3201,3133],{"class":735},[632,3203,866],{"class":646},[632,3205,3206],{"class":735}," filters?",[632,3208,866],{"class":646},[632,3210,3211],{"class":735}," debounce? ",[632,3213,927],{"class":646},[632,3215,1262],{"class":735},[632,3217,901],{"class":646},[632,3219,3220,3223,3225,3228,3230,3233,3235],{"class":634,"line":986},[632,3221,3222],{"class":735},"  page",[632,3224,866],{"class":646},[632,3226,3227],{"class":735}," pageSize",[632,3229,866],{"class":646},[632,3231,3232],{"class":735}," sort",[632,3234,866],{"class":646},[632,3236,3237],{"class":685}," \u002F\u002F refs, kept in the URL (`?page=2&sort=name&order=asc`)\n",[632,3239,3240,3243,3245],{"class":634,"line":995},[632,3241,3242],{"class":735},"  search",[632,3244,866],{"class":646},[632,3246,3247],{"class":685}," \u002F\u002F what the search input binds\n",[632,3249,3250,3253,3255],{"class":634,"line":1015},[632,3251,3252],{"class":735},"  q",[632,3254,866],{"class":646},[632,3256,3257],{"class":685}," \u002F\u002F `search` after a 300 ms pause\n",[632,3259,3260,3263,3265],{"class":634,"line":1064},[632,3261,3262],{"class":735},"  filters",[632,3264,866],{"class":646},[632,3266,3267],{"class":685}," \u002F\u002F reactive, one string per filter; a filter at its default stays out of the URL\n",[632,3269,3270,3273,3275],{"class":634,"line":1069},[632,3271,3272],{"class":735},"  query",[632,3274,866],{"class":646},[632,3276,3277],{"class":685}," \u002F\u002F what a server-paginated list sends to its API\n",[632,3279,3280,3283,3285],{"class":634,"line":2746},[632,3281,3282],{"class":735},"  filtered",[632,3284,866],{"class":646},[632,3286,3287],{"class":685}," \u002F\u002F the search or a filter narrows the list\n",[632,3289,3290,3293,3296,3298],{"class":634,"line":2751},[632,3291,3292],{"class":653},"  reset",[632,3294,3295],{"class":646},"():",[632,3297,1172],{"class":642},[632,3299,3300],{"class":685}," \u002F\u002F clears the search and the filters\n",[632,3302,3304],{"class":634,"line":3303},17,[632,3305,719],{"class":646},[593,3307,3308,3309,3311,3312,3000,3315,3317],{},"A sortable header cycles through ascending, descending and unsorted. ",[604,3310,3019],{}," goes back to page 1 whenever the\nsearch, a filter, the sort or the page size changes. Pass its ",[604,3313,3314],{},"sort",[604,3316,3016],{}," so both share one state:",[623,3319,3321],{"className":625,"code":3320,"language":627,"meta":628,"style":628},"const { page, pageSize, search, sort: sortState, filters, query } = useTableQuery({\n  sort: { id: 'createdAt', desc: true },\n  filters: { role: 'all' },\n})\nconst { header } = useTableSort(null, sortState)\nconst { data } = await useFetch('\u002Fapi\u002Fadmin\u002Fusers', { query })\n",[604,3322,3323,3371,3402,3424,3430,3454],{"__ignoreMap":628},[632,3324,3325,3327,3329,3332,3334,3336,3338,3341,3343,3345,3347,3350,3352,3355,3357,3360,3362,3364,3367,3369],{"class":634,"line":635},[632,3326,819],{"class":638},[632,3328,856],{"class":646},[632,3330,3331],{"class":735}," page",[632,3333,866],{"class":646},[632,3335,3227],{"class":735},[632,3337,866],{"class":646},[632,3339,3340],{"class":735}," search",[632,3342,866],{"class":646},[632,3344,3232],{"class":653},[632,3346,657],{"class":646},[632,3348,3349],{"class":735}," sortState",[632,3351,866],{"class":646},[632,3353,3354],{"class":735}," filters",[632,3356,866],{"class":646},[632,3358,3359],{"class":735}," query ",[632,3361,927],{"class":646},[632,3363,889],{"class":646},[632,3365,3366],{"class":732}," useTableQuery",[632,3368,848],{"class":735},[632,3370,901],{"class":646},[632,3372,3373,3375,3377,3379,3381,3383,3385,3388,3390,3392,3395,3397,3399],{"class":634,"line":650},[632,3374,3082],{"class":653},[632,3376,657],{"class":646},[632,3378,856],{"class":646},[632,3380,859],{"class":653},[632,3382,657],{"class":646},[632,3384,946],{"class":646},[632,3386,3387],{"class":809},"createdAt",[632,3389,952],{"class":646},[632,3391,866],{"class":646},[632,3393,3394],{"class":653}," desc",[632,3396,657],{"class":646},[632,3398,981],{"class":980},[632,3400,3401],{"class":646}," },\n",[632,3403,3404,3406,3408,3410,3413,3415,3417,3420,3422],{"class":634,"line":663},[632,3405,3262],{"class":653},[632,3407,657],{"class":646},[632,3409,856],{"class":646},[632,3411,3412],{"class":653}," role",[632,3414,657],{"class":646},[632,3416,946],{"class":646},[632,3418,3419],{"class":809},"all",[632,3421,952],{"class":646},[632,3423,3401],{"class":646},[632,3425,3426,3428],{"class":634,"line":674},[632,3427,927],{"class":646},[632,3429,992],{"class":735},[632,3431,3432,3434,3436,3439,3441,3443,3446,3448,3451],{"class":634,"line":689},[632,3433,819],{"class":638},[632,3435,856],{"class":646},[632,3437,3438],{"class":735}," header ",[632,3440,927],{"class":646},[632,3442,889],{"class":646},[632,3444,3445],{"class":732}," useTableSort",[632,3447,848],{"class":735},[632,3449,3450],{"class":646},"null,",[632,3452,3453],{"class":735}," sortState)\n",[632,3455,3456,3458,3460,3463,3465,3467,3469,3472,3474,3476,3479,3481,3483,3485,3487,3489],{"class":634,"line":702},[632,3457,819],{"class":638},[632,3459,856],{"class":646},[632,3461,3462],{"class":735}," data ",[632,3464,927],{"class":646},[632,3466,889],{"class":646},[632,3468,893],{"class":892},[632,3470,3471],{"class":732}," useFetch",[632,3473,848],{"class":735},[632,3475,952],{"class":646},[632,3477,3478],{"class":809},"\u002Fapi\u002Fadmin\u002Fusers",[632,3480,952],{"class":646},[632,3482,866],{"class":646},[632,3484,856],{"class":646},[632,3486,3359],{"class":735},[632,3488,927],{"class":646},[632,3490,992],{"class":735},[593,3492,3493,3494,599],{},"The complete list page is on ",[597,3495,101],{"href":3496},"\u002Fguide\u002Fux-patterns\u002Fpages#lists",[612,3498,3500],{"id":3499},"translated-text-and-locale","Translated text and locale",[593,3502,3503],{},"These composables tell components which locale to show and translate built-in strings.",[623,3505,3507],{"className":625,"code":3506,"language":627,"meta":628,"style":628},"useTranslatedLocale(): ComputedRef\u003Cstring> \u002F\u002F the visitor's locale; `en` without @nuxtjs\u002Fi18n\nuseTranslatedLocales(): ComputedRef\u003Cstring[]> \u002F\u002F locales content can be translated into; ['en'] without @nuxtjs\u002Fi18n\nuseTranslatedFallbackLocale(): ComputedRef\u003Cstring> \u002F\u002F the default locale, used when a text lacks the current one\nuseUiT(namespace: string): (key: string, fallback: string, params?: Record\u003Cstring, string | number>) => string\n\nstripLocale(path: string, codes: string[]): string \u002F\u002F '\u002Fda\u002Fevents' with ['da', 'en'] -> '\u002Fevents'\n",[604,3508,3509,3526,3543,3559,3615,3619],{"__ignoreMap":628},[632,3510,3511,3514,3517,3519,3521,3523],{"class":634,"line":635},[632,3512,3513],{"class":732},"useTranslatedLocale",[632,3515,3516],{"class":735},"(): ComputedRef",[632,3518,761],{"class":646},[632,3520,1638],{"class":735},[632,3522,767],{"class":646},[632,3524,3525],{"class":685}," \u002F\u002F the visitor's locale; `en` without @nuxtjs\u002Fi18n\n",[632,3527,3528,3531,3533,3535,3538,3540],{"class":634,"line":650},[632,3529,3530],{"class":732},"useTranslatedLocales",[632,3532,3516],{"class":735},[632,3534,761],{"class":646},[632,3536,3537],{"class":735},"string[]",[632,3539,767],{"class":646},[632,3541,3542],{"class":685}," \u002F\u002F locales content can be translated into; ['en'] without @nuxtjs\u002Fi18n\n",[632,3544,3545,3548,3550,3552,3554,3556],{"class":634,"line":663},[632,3546,3547],{"class":732},"useTranslatedFallbackLocale",[632,3549,3516],{"class":735},[632,3551,761],{"class":646},[632,3553,1638],{"class":735},[632,3555,767],{"class":646},[632,3557,3558],{"class":685}," \u002F\u002F the default locale, used when a text lacks the current one\n",[632,3560,3561,3564,3567,3569,3571,3573,3575,3577,3579,3582,3584,3586,3588,3591,3593,3595,3597,3599,3601,3603,3605,3608,3611,3613],{"class":634,"line":674},[632,3562,3563],{"class":732},"useUiT",[632,3565,3566],{"class":735},"(namespace: string)",[632,3568,657],{"class":646},[632,3570,741],{"class":646},[632,3572,1824],{"class":744},[632,3574,657],{"class":646},[632,3576,682],{"class":642},[632,3578,866],{"class":646},[632,3580,3581],{"class":744}," fallback",[632,3583,657],{"class":646},[632,3585,682],{"class":642},[632,3587,866],{"class":646},[632,3589,3590],{"class":744}," params",[632,3592,669],{"class":646},[632,3594,2880],{"class":642},[632,3596,761],{"class":646},[632,3598,1638],{"class":642},[632,3600,866],{"class":646},[632,3602,682],{"class":642},[632,3604,1643],{"class":646},[632,3606,3607],{"class":642}," number",[632,3609,3610],{"class":646},">)",[632,3612,755],{"class":638},[632,3614,660],{"class":735},[632,3616,3617],{"class":634,"line":689},[632,3618,726],{"emptyLinePlaceholder":725},[632,3620,3621,3624,3627,3629,3632],{"class":634,"line":702},[632,3622,3623],{"class":732},"stripLocale",[632,3625,3626],{"class":735},"(path: string",[632,3628,866],{"class":646},[632,3630,3631],{"class":735}," codes: string[]): string ",[632,3633,3634],{"class":685},"\u002F\u002F '\u002Fda\u002Fevents' with ['da', 'en'] -> '\u002Fevents'\n",[593,3636,3637,3639,3640,3642,3643,3646,3647,3649,3650,3653],{},[604,3638,3563],{}," translates when ",[604,3641,2816],{}," has the key. Otherwise it returns the English fallback, with ",[604,3644,3645],{},"{name}"," params\nfilled in. The components use it, so their strings are translated without making ",[604,3648,2816],{}," required. Modules use\n",[604,3651,3652],{},"useModuleT"," for their own text.",[612,3655,3657],{"id":3656},"next-steps","Next steps",[1333,3659,3660,3665],{},[1336,3661,3662,3664],{},[597,3663,101],{"href":102}," – see these composables in a complete list and detail page.",[1336,3666,3667,3670],{},[597,3668,3669],{"href":348},"UI reference"," – look up the money and translated-text helpers and the string keys.",[3672,3673,3674],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":628,"searchDepth":650,"depth":650,"links":3676},[3677,3678,3679,3680,3682,3683,3684,3685,3686],{"id":614,"depth":650,"text":615},{"id":1079,"depth":650,"text":1080},{"id":1593,"depth":650,"text":1594},{"id":2334,"depth":650,"text":3681},"One request for an area: loadBootstrap",{"id":2495,"depth":650,"text":2496},{"id":2846,"depth":650,"text":2847},{"id":3010,"depth":650,"text":3011},{"id":3499,"depth":650,"text":3500},{"id":3656,"depth":650,"text":3657},"Look up the composables for confirmations, toasts, cached loading, formatting, tables and translated text.","md",null,{},{"title":344},{"title":344,"description":3687},"Cz8oymd0NN-PuSYBtCm8PanajyncsSCNVCob_qAokL4",[3695,3697],{"title":340,"path":341,"stem":342,"description":3696,"children":-1},"Look up the money, date, tag, translated and Markdown inputs that go inside a form field.",{"title":179,"path":348,"stem":349,"description":3698,"children":-1},"Look up the import paths, translated-text and money helpers, and translation keys of UI.",1794503158922]