{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "tabs", "type": "registry:item", "title": "aesthetic Tabs", "description": "Aesthetic Tabs primitive, v0.25.0. Installs ae-nav-ind, ae-tabs without the full stylesheet. Recipes: nav.js.", "registryDependencies": [ "https://aesthetic.mistystep.io/r/aesthetic-base.json" ], "meta": { "version": "0.25.0", "tier": "primitive", "route": "tabs", "classes": ["ae-nav-ind", "ae-tabs"], "attributes": [], "tokens": [ "--ae-surface", "--ae-wash", "--ae-ink", "--ae-ink-faint", "--ae-accent", "--ae-surface-dark", "--ae-wash-dark", "--ae-ink-dark", "--ae-ink-faint-dark", "--ae-accent-dark", "--ae-font", "--ae-font-mono", "--ae-w-regular", "--ae-ease", "--ae-quick", "--ae-ink-muted", "--ae-ink-muted-dark", "--ae-w-medium", "--ae-space-6", "--ae-soft" ], "recipes": ["nav.js"] }, "files": [ { "path": "registry/tabs/aesthetic.tabs.css", "type": "registry:file", "target": "~/aesthetic.tabs.css", "content": "/* aesthetic tabs v0.25.0 — generated by scripts/build-registry.mjs. */\n@import './aesthetic.base.css';\n\n:root {\n --ae-ink-muted: #737373;\n --ae-ink-muted-dark: #8f8f8f;\n --ae-w-medium: 550;\n --ae-space-6: 2em;\n --ae-soft: 240ms;\n}\n\n@media (prefers-color-scheme: dark) {\n :root:not(.light):not([data-ae-mode='light']) {\n --ae-ink-muted: var(--ae-ink-muted-dark);\n }\n}\n\n.light,\n[data-ae-mode='light'] {\n color-scheme: light;\n}\n\n:root.dark,\n:root[data-ae-mode='dark'] {\n color-scheme: dark;\n --ae-ink-muted: var(--ae-ink-muted-dark);\n}\n\n.ae-tabs {\nposition: relative;\n display: flex;\n gap: var(--ae-space-6);\n}\n\n.ae-tabs a,\n.ae-tabs button {\nbackground: transparent;\n border: 0;\n padding: 0 0 0.6em;\n margin-block: 0;\n cursor: pointer;\n color: var(--ae-ink-muted);\n font-weight: var(--ae-w-medium);\n text-decoration: none;\n transition: color var(--ae-quick) var(--ae-ease);\n}\n\n.ae-tabs a:hover,\n.ae-tabs button:hover {\ncolor: var(--ae-ink);\n}\n\n.ae-tabs [aria-current],\n.ae-tabs [aria-selected='true'],\n.ae-tabs .is-active {\ncolor: var(--ae-ink);\n}\n\n.ae-nav-ind {\nposition: absolute;\n bottom: 0;\n height: 2px;\n background: var(--ae-ink);\n transition:\n left var(--ae-soft) var(--ae-ease),\n width var(--ae-soft) var(--ae-ease);\n}\n" }, { "path": "recipes/nav.js", "type": "registry:file", "target": "~/aesthetic.nav.js", "content": "/* the nav indicator: position the sliding ink underline under the\n active item on activation, resize, and font load (metrics shift\n when Geist arrives). Exposes window.aePlaceInds for page scripts\n that swap views and need the indicator re-placed after a display\n change. Works for .ae-nav and .ae-tabs alike. */\n(() => {\n if (window.aePlaceInds) return;\n const placeInd = (nav) => {\n const active = nav.querySelector(\n '[aria-current], [aria-selected=\"true\"], .is-active',\n );\n const ind = nav.querySelector('.ae-nav-ind');\n if (!active || !ind || !nav.offsetWidth) return;\n ind.style.left = active.offsetLeft + 'px';\n ind.style.width = active.offsetWidth + 'px';\n };\n const placeAllInds = () =>\n document.querySelectorAll('.ae-nav, .ae-tabs').forEach(placeInd);\n\n document.querySelectorAll('.ae-nav, .ae-tabs').forEach((nav) => {\n nav.querySelectorAll('a, button').forEach((item) => {\n item.addEventListener('click', () => {\n nav\n .querySelectorAll('a, button')\n .forEach((b) => b.classList.remove('is-active'));\n item.classList.add('is-active');\n placeInd(nav);\n });\n });\n });\n addEventListener('resize', placeAllInds);\n if (document.fonts) document.fonts.ready.then(placeAllInds);\n placeAllInds();\n\n window.aePlaceInds = placeAllInds;\n})();\n" } ] }