@birdycom/omniaui 0.0.0-stage → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -3
  3. package/bin/lib/add.mjs +126 -0
  4. package/bin/lib/catalog.mjs +169 -0
  5. package/bin/lib/project.mjs +90 -0
  6. package/bin/omniaui.mjs +70 -0
  7. package/dist/code-block.css +163 -0
  8. package/dist/components-extra.css +916 -0
  9. package/dist/components.css +10171 -0
  10. package/dist/components.min.css +1 -0
  11. package/dist/data-table.d.ts +9 -0
  12. package/dist/data-table.js +505 -0
  13. package/dist/docs-ui.css +267 -0
  14. package/dist/oc-theme.css +69 -0
  15. package/dist/parts/.gitkeep +0 -0
  16. package/dist/parts/app-accordion-accent.css +60 -0
  17. package/dist/parts/app-alpha-tabs.css +68 -0
  18. package/dist/parts/app-busy-overlay.css +25 -0
  19. package/dist/parts/app-column-menu.css +85 -0
  20. package/dist/parts/app-confirm-dialog.css +70 -0
  21. package/dist/parts/app-cookie-consent.css +63 -0
  22. package/dist/parts/app-data-table.css +174 -0
  23. package/dist/parts/app-greeting.css +47 -0
  24. package/dist/parts/app-list-toolbar.css +81 -0
  25. package/dist/parts/app-page-header.css +54 -0
  26. package/dist/parts/app-severity-card.css +91 -0
  27. package/dist/parts/app-sidebar-dark.css +15 -0
  28. package/dist/parts/app-sortable-row.css +52 -0
  29. package/dist/parts/app-stat-card.css +68 -0
  30. package/dist/parts/app-table-actions.css +71 -0
  31. package/dist/parts/app-table-compact.css +54 -0
  32. package/dist/parts/app-top-progress.css +68 -0
  33. package/dist/parts/app-tree.css +104 -0
  34. package/dist/parts/app-upgrade-banner.css +90 -0
  35. package/dist/parts/app-version-banner.css +80 -0
  36. package/dist/parts/data-chart-line.css +167 -0
  37. package/dist/parts/forms-affix-input.css +75 -0
  38. package/dist/parts/forms-barcode-input.css +75 -0
  39. package/dist/parts/forms-chip-filter.css +91 -0
  40. package/dist/parts/forms-color-select.css +97 -0
  41. package/dist/parts/forms-decimal-input.css +51 -0
  42. package/dist/parts/forms-filter-counts.css +94 -0
  43. package/dist/parts/forms-language-select.css +89 -0
  44. package/dist/parts/forms-number-input.css +98 -0
  45. package/dist/parts/forms-password-requirements.css +55 -0
  46. package/dist/parts/forms-phone-input.css +85 -0
  47. package/dist/parts/forms-time-input.css +74 -0
  48. package/dist/parts/forms-toggle-field.css +69 -0
  49. package/dist/parts/media-art.css +21 -0
  50. package/dist/parts/media-attachment.css +160 -0
  51. package/dist/parts/media-browser-frame.css +73 -0
  52. package/dist/parts/media-card.css +83 -0
  53. package/dist/parts/media-chat-composer.css +90 -0
  54. package/dist/parts/media-doc-viewer.css +151 -0
  55. package/dist/parts/media-emoji-picker.css +88 -0
  56. package/dist/parts/media-entity-card.css +52 -0
  57. package/dist/parts/media-flip-card.css +78 -0
  58. package/dist/parts/media-image-zoom.css +68 -0
  59. package/dist/parts/media-lightbox.css +131 -0
  60. package/dist/parts/media-message-thread.css +136 -0
  61. package/dist/parts/media-message.css +160 -0
  62. package/dist/parts/media-row.css +78 -0
  63. package/dist/parts/media-stack-card.css +82 -0
  64. package/dist/parts/media-terminal-log.css +76 -0
  65. package/dist/parts/media-thumb.css +71 -0
  66. package/dist/parts/site-fact-list.css +25 -0
  67. package/dist/parts/site-link-arrow.css +34 -0
  68. package/dist/parts/site-marquee.css +34 -0
  69. package/dist/parts/site-next-teaser.css +75 -0
  70. package/dist/parts/site-price-card.css +91 -0
  71. package/dist/parts/site-product-mark.css +66 -0
  72. package/dist/parts/site-project-card.css +111 -0
  73. package/dist/parts/site-prose.css +124 -0
  74. package/dist/parts/site-stack-list.css +48 -0
  75. package/dist/parts/site-timeline.css +54 -0
  76. package/dist/showcase.css +404 -0
  77. package/manifest.json +1108 -0
  78. package/package.json +69 -6
  79. package/snippets/accordion-accent.html +24 -0
  80. package/snippets/accordion.html +11 -0
  81. package/snippets/affix-input.html +30 -0
  82. package/snippets/alert-dialog.html +22 -0
  83. package/snippets/alert.html +5 -0
  84. package/snippets/alpha-tabs.html +37 -0
  85. package/snippets/aspect-ratio.html +15 -0
  86. package/snippets/attachment.html +43 -0
  87. package/snippets/avatar.html +6 -0
  88. package/snippets/back-link.html +5 -0
  89. package/snippets/badge.html +5 -0
  90. package/snippets/barcode-input.html +18 -0
  91. package/snippets/breadcrumb.html +6 -0
  92. package/snippets/browser-frame.html +18 -0
  93. package/snippets/busy-overlay.html +31 -0
  94. package/snippets/button-group.html +21 -0
  95. package/snippets/button.html +8 -0
  96. package/snippets/calendar.html +43 -0
  97. package/snippets/card.html +17 -0
  98. package/snippets/carousel.html +21 -0
  99. package/snippets/chart-line.html +46 -0
  100. package/snippets/chart.html +27 -0
  101. package/snippets/chat-composer.html +21 -0
  102. package/snippets/checkbox.html +5 -0
  103. package/snippets/checklist.html +23 -0
  104. package/snippets/chip-filter.html +14 -0
  105. package/snippets/code-window.html +20 -0
  106. package/snippets/collapsible.html +19 -0
  107. package/snippets/color-field.html +13 -0
  108. package/snippets/color-select.html +18 -0
  109. package/snippets/column-menu.html +38 -0
  110. package/snippets/combobox.html +19 -0
  111. package/snippets/command.html +24 -0
  112. package/snippets/confirm-dialog.html +32 -0
  113. package/snippets/context-menu.html +25 -0
  114. package/snippets/cookie-consent.html +70 -0
  115. package/snippets/copy-field.html +19 -0
  116. package/snippets/counter.html +2 -0
  117. package/snippets/data-table.html +151 -0
  118. package/snippets/date-picker.html +32 -0
  119. package/snippets/decimal-input.html +20 -0
  120. package/snippets/definition-list.html +20 -0
  121. package/snippets/demo-panel.html +18 -0
  122. package/snippets/doc-viewer.html +58 -0
  123. package/snippets/drawer.html +30 -0
  124. package/snippets/dropdown-menu.html +27 -0
  125. package/snippets/dropdown.html +9 -0
  126. package/snippets/dropzone.html +13 -0
  127. package/snippets/emoji-picker.html +51 -0
  128. package/snippets/empty-state.html +17 -0
  129. package/snippets/entity-card.html +26 -0
  130. package/snippets/expandable-table.html +26 -0
  131. package/snippets/fact-list.html +14 -0
  132. package/snippets/filter-counts.html +30 -0
  133. package/snippets/flip-card.html +22 -0
  134. package/snippets/form-field.html +6 -0
  135. package/snippets/greeting.html +22 -0
  136. package/snippets/heading.html +14 -0
  137. package/snippets/hover-card.html +18 -0
  138. package/snippets/image-zoom.html +30 -0
  139. package/snippets/input-group.html +10 -0
  140. package/snippets/input.html +5 -0
  141. package/snippets/item.html +26 -0
  142. package/snippets/kbd.html +13 -0
  143. package/snippets/label.html +9 -0
  144. package/snippets/language-select.html +26 -0
  145. package/snippets/launcher-card.html +14 -0
  146. package/snippets/lightbox.html +50 -0
  147. package/snippets/link-arrow.html +10 -0
  148. package/snippets/list-toolbar.html +33 -0
  149. package/snippets/marquee.html +15 -0
  150. package/snippets/media-card.html +28 -0
  151. package/snippets/media-row.html +21 -0
  152. package/snippets/media-thumb.html +12 -0
  153. package/snippets/menubar.html +30 -0
  154. package/snippets/message-thread.html +123 -0
  155. package/snippets/message.html +51 -0
  156. package/snippets/modal.html +15 -0
  157. package/snippets/native-select.html +15 -0
  158. package/snippets/navmenu.html +23 -0
  159. package/snippets/next-teaser.html +15 -0
  160. package/snippets/number-input.html +27 -0
  161. package/snippets/otp-input.html +9 -0
  162. package/snippets/page-header.html +24 -0
  163. package/snippets/pagination.html +6 -0
  164. package/snippets/password-input.html +24 -0
  165. package/snippets/password-requirements.html +30 -0
  166. package/snippets/phone-input.html +22 -0
  167. package/snippets/popover.html +15 -0
  168. package/snippets/price-card.html +34 -0
  169. package/snippets/product-mark.html +13 -0
  170. package/snippets/progress.html +4 -0
  171. package/snippets/project-card.html +23 -0
  172. package/snippets/prose.html +54 -0
  173. package/snippets/radio.html +17 -0
  174. package/snippets/recovery-codes.html +20 -0
  175. package/snippets/resizable.html +16 -0
  176. package/snippets/scroll-area.html +20 -0
  177. package/snippets/search.html +8 -0
  178. package/snippets/segmented.html +11 -0
  179. package/snippets/select.html +7 -0
  180. package/snippets/separator.html +15 -0
  181. package/snippets/severity-card.html +35 -0
  182. package/snippets/sheet.html +32 -0
  183. package/snippets/sidebar-docs.html +24 -0
  184. package/snippets/sidebar.html +55 -0
  185. package/snippets/site-footer.html +6 -0
  186. package/snippets/site-header.html +26 -0
  187. package/snippets/skeleton.html +4 -0
  188. package/snippets/slider.html +17 -0
  189. package/snippets/sortable-row.html +31 -0
  190. package/snippets/spinner.html +14 -0
  191. package/snippets/stack-card.html +17 -0
  192. package/snippets/stack-list.html +16 -0
  193. package/snippets/stat-card.html +24 -0
  194. package/snippets/stepper.html +13 -0
  195. package/snippets/switch.html +6 -0
  196. package/snippets/table-actions.html +39 -0
  197. package/snippets/table-compact.html +24 -0
  198. package/snippets/table.html +29 -0
  199. package/snippets/tabs.html +9 -0
  200. package/snippets/tag-input.html +60 -0
  201. package/snippets/terminal-log.html +23 -0
  202. package/snippets/textarea.html +3 -0
  203. package/snippets/theme-switch.html +6 -0
  204. package/snippets/time-input.html +26 -0
  205. package/snippets/timeline.html +28 -0
  206. package/snippets/toast-stack.html +10 -0
  207. package/snippets/toast.html +36 -0
  208. package/snippets/toc.html +13 -0
  209. package/snippets/toggle-field.html +20 -0
  210. package/snippets/toggle.html +22 -0
  211. package/snippets/tooltip.html +4 -0
  212. package/snippets/top-progress.html +12 -0
  213. package/snippets/tree.html +38 -0
  214. package/snippets/upgrade-banner.html +28 -0
  215. package/snippets/user.html +15 -0
  216. package/snippets/version-banner.html +15 -0
@@ -0,0 +1,27 @@
1
+ <!-- OmniaUI component: number-input - Number field with minus and plus step buttons. Needs @birdycom/omniaui CSS.
2
+ File: packages/ui/snippets/number-input.html | Map: wrapper -> minus button -> number field -> plus button -> optional script
3
+ Class API (modifiers are extra classes / attributes on the same element):
4
+ .oc-number-input: Frame around buttons and field. Modifiers: --sm, --block (full width), --error.
5
+ .oc-number-input-step: Minus / plus button (data-oc-step="-1" or "1")
6
+ .oc-number-input-field: input type="number" (min, max, step work natively; spinners hidden)
7
+ States: :focus-within (ring), :user-invalid outside min/max (red), disabled field (dimmed)
8
+ The field works without JavaScript (arrow keys). The script below makes the buttons call stepDown()/stepUp().
9
+ -->
10
+ <div class="oc-number-input">
11
+ <button class="oc-number-input-step" type="button" data-oc-step="-1" aria-label="Decrease">&minus;</button>
12
+ <input class="oc-number-input-field" type="number" name="quantity" value="2" min="0" max="99" step="1" aria-label="Quantity">
13
+ <button class="oc-number-input-step" type="button" data-oc-step="1" aria-label="Increase">+</button>
14
+ </div>
15
+ <script>
16
+ // One listener for every number input on the page. stepUp/stepDown respect min, max and step.
17
+ document.addEventListener('click', (e) => {
18
+ const btn = e.target.closest('.oc-number-input-step');
19
+ if (!btn) return;
20
+ const input = btn.parentElement.querySelector('.oc-number-input-field');
21
+ if (!input || input.disabled) return;
22
+ btn.dataset.ocStep === '-1' ? input.stepDown() : input.stepUp();
23
+ // Let forms and frameworks know the value changed.
24
+ input.dispatchEvent(new Event('input', { bubbles: true }));
25
+ input.dispatchEvent(new Event('change', { bubbles: true }));
26
+ });
27
+ </script>
@@ -0,0 +1,9 @@
1
+ <!-- OmniaUI component: otp-input - One-time code field drawn as separate cells on a single real input. Needs @birdycom/omniaui CSS.
2
+ Class API (modifiers are extra classes / attributes on the same element):
3
+ .oc-otp: The input. Set style="--oc-otp-length: 6" and maxlength to the code length. aria-invalid="true" shows the error state.
4
+ -->
5
+ <div class="oc-field">
6
+ <label class="oc-field-label" for="oc-otp-demo">Authentication code</label>
7
+ <input class="oc-otp" id="oc-otp-demo" name="code" type="text" inputmode="numeric" autocomplete="one-time-code" maxlength="6" pattern="[0-9]*" style="--oc-otp-length: 6" value="123">
8
+ <p class="oc-field-description">Enter the 6-digit code from your authenticator app.</p>
9
+ </div>
@@ -0,0 +1,24 @@
1
+ <!-- OmniaUI component: page-header - Page title row with back link, subtitle, meta and actions; actions move under the title in narrow containers. Needs @birdycom/omniaui CSS.
2
+ File: packages/ui/snippets/page-header.html | Map: header -> back row -> main (text: title + badge, subtitle, meta | actions)
3
+ Class API (modifiers are extra classes / attributes on the same element):
4
+ .oc-page-header: Header (size container). Modifiers: --bordered (line under it), --sticky, --sm.
5
+ .oc-page-header-back: Optional row for an .oc-back-link
6
+ .oc-page-header-main: Text block + actions (side by side from a 36rem container width)
7
+ .oc-page-header-text / -title / -subtitle / -meta: Text column, h1 (may hold a badge), sub line, meta row
8
+ .oc-page-header-actions: Buttons
9
+ Slots: back, title, subtitle, meta, actions
10
+ -->
11
+ <header class="oc-page-header oc-page-header--bordered">
12
+ <div class="oc-page-header-back"><a class="oc-back-link" href="#">Projects</a></div>
13
+ <div class="oc-page-header-main">
14
+ <div class="oc-page-header-text">
15
+ <h1 class="oc-page-header-title">Kitchen renovation <span class="oc-badge oc-badge--success">Active</span></h1>
16
+ <p class="oc-page-header-subtitle">Main street 12, Ghent - started 2 September 2026.</p>
17
+ <div class="oc-page-header-meta"><span>Owner: Ada Lovelace</span><span>Updated 2 hours ago</span></div>
18
+ </div>
19
+ <div class="oc-page-header-actions">
20
+ <button class="oc-btn oc-btn--outline" type="button">Share</button>
21
+ <button class="oc-btn" type="button">New quote</button>
22
+ </div>
23
+ </div>
24
+ </header>
@@ -0,0 +1,6 @@
1
+ <!-- OmniaUI component: pagination — Pagination. Needs @birdycom/omniaui CSS. -->
2
+ <nav class="oc-pagination" aria-label="Pagination">
3
+ <a class="oc-pagination-item" href="?page=1">1</a>
4
+ <a class="oc-pagination-item" href="?page=2" aria-current="page">2</a>
5
+ <a class="oc-pagination-item" href="?page=3">3</a>
6
+ </nav>
@@ -0,0 +1,24 @@
1
+ <!-- OmniaUI component: password-input - Password field with show/hide button. Needs @birdycom/omniaui CSS.
2
+ Class API (modifiers are extra classes / attributes on the same element):
3
+ .oc-input-reveal: Wrapper (relative)
4
+ .oc-input: The password input
5
+ .oc-input-reveal-button: Toggle button (aria-pressed reflects the state)
6
+ -->
7
+ <div class="oc-field">
8
+ <label class="oc-field-label" for="oc-password-demo">Password</label>
9
+ <div class="oc-input-reveal">
10
+ <input class="oc-input" id="oc-password-demo" type="password" autocomplete="current-password" value="secret-value">
11
+ <button class="oc-input-reveal-button" type="button" aria-pressed="false" aria-label="Toggle password visibility">Show</button>
12
+ </div>
13
+ </div>
14
+ <script>
15
+ document.addEventListener('click', (e) => {
16
+ const btn = e.target.closest('.oc-input-reveal-button');
17
+ if (!btn) return;
18
+ const input = btn.parentElement.querySelector('input');
19
+ const show = input.type === 'password';
20
+ input.type = show ? 'text' : 'password';
21
+ btn.setAttribute('aria-pressed', String(show));
22
+ btn.textContent = show ? 'Hide' : 'Show';
23
+ });
24
+ </script>
@@ -0,0 +1,30 @@
1
+ <!-- OmniaUI component: password-requirements - Live checklist of password rules under a password field. Needs @birdycom/omniaui CSS.
2
+ File: packages/ui/snippets/password-requirements.html | Map: field (label + password input) -> rule list -> optional script
3
+ Class API (modifiers are extra classes / attributes on the same element):
4
+ .oc-password-requirements: The list (aria-live="polite"). Modifier: --inline (rules side by side).
5
+ .oc-password-requirement: One rule. Modifier: --met (green with a check mark).
6
+ Optional script attributes: data-oc-password-for="<input id>" on the list; per rule data-min="8" or data-pattern="[A-Z]".
7
+ Without JavaScript the list is a static hint; the script (or a React/Vue wrapper) toggles --met while typing.
8
+ -->
9
+ <div class="oc-field">
10
+ <label class="oc-field-label" for="oc-password-rules-demo">New password</label>
11
+ <input class="oc-input" id="oc-password-rules-demo" type="password" autocomplete="new-password" aria-describedby="oc-password-rules-demo-list" value="Secret1">
12
+ <ul class="oc-password-requirements" id="oc-password-rules-demo-list" aria-live="polite" data-oc-password-for="oc-password-rules-demo">
13
+ <li class="oc-password-requirement" data-min="8">At least 8 characters</li>
14
+ <li class="oc-password-requirement oc-password-requirement--met" data-pattern="[A-Z]">One uppercase letter</li>
15
+ <li class="oc-password-requirement oc-password-requirement--met" data-pattern="[0-9]">One number</li>
16
+ <li class="oc-password-requirement" data-pattern="[^A-Za-z0-9]">One symbol</li>
17
+ </ul>
18
+ </div>
19
+ <script>
20
+ // Re-check every rule of a linked list when its password field changes.
21
+ document.addEventListener('input', (e) => {
22
+ const list = e.target.id && document.querySelector(`[data-oc-password-for="${e.target.id}"]`);
23
+ if (!list) return;
24
+ for (const rule of list.querySelectorAll('.oc-password-requirement')) {
25
+ const value = e.target.value;
26
+ const met = rule.dataset.min ? value.length >= Number(rule.dataset.min) : new RegExp(rule.dataset.pattern).test(value);
27
+ rule.classList.toggle('oc-password-requirement--met', met);
28
+ }
29
+ });
30
+ </script>
@@ -0,0 +1,22 @@
1
+ <!-- OmniaUI component: phone-input - Phone field with a country dial code select and the national number. Needs @birdycom/omniaui CSS.
2
+ File: packages/ui/snippets/phone-input.html | Map: field wrapper -> label -> phone frame (dial select + tel input) -> hint
3
+ Class API (modifiers are extra classes / attributes on the same element):
4
+ .oc-phone-input: Frame around both parts. Modifiers: --sm, --error.
5
+ .oc-phone-input-dial: Native select with the dial codes (+32, +31...)
6
+ .oc-phone-input-number: The national number (type="tel", autocomplete="tel-national")
7
+ States: :focus-within (ring), aria-invalid="true" or :user-invalid on the number (red), disabled number (dimmed)
8
+ Slots: one <option> per country; the value of the form is dial code + number (join them on the server)
9
+ -->
10
+ <div class="oc-field">
11
+ <label class="oc-field-label" for="oc-phone-demo">Mobile number</label>
12
+ <div class="oc-phone-input">
13
+ <select class="oc-phone-input-dial" name="phone_dial" aria-label="Country code">
14
+ <option value="+32" selected>BE +32</option>
15
+ <option value="+31">NL +31</option>
16
+ <option value="+33">FR +33</option>
17
+ <option value="+49">DE +49</option>
18
+ </select>
19
+ <input class="oc-phone-input-number" id="oc-phone-demo" name="phone" type="tel" inputmode="tel" autocomplete="tel-national" placeholder="470 12 34 56" pattern="[0-9 ]{8,14}">
20
+ </div>
21
+ <p class="oc-field-description">Digits only; spaces are fine.</p>
22
+ </div>
@@ -0,0 +1,15 @@
1
+ <!-- OmniaUI component: popover - Floating panel on popover + anchor positioning - no JavaScript. Needs @birdycom/omniaui CSS.
2
+ Class API (modifiers are extra classes / attributes on the same element):
3
+ .oc-popover[popover]: The panel. Sizes: --sm, --lg.
4
+ .oc-popover-title / -text: Optional heading and body text
5
+ button[popovertarget]: Trigger
6
+ -->
7
+ <button class="oc-btn oc-btn--outline" type="button" popovertarget="oc-popover-demo">Dimensions</button>
8
+ <div class="oc-popover" id="oc-popover-demo" popover>
9
+ <h3 class="oc-popover-title">Dimensions</h3>
10
+ <p class="oc-popover-text">Set the width and height of the layer.</p>
11
+ <div class="oc-field" style="margin-top:.75rem">
12
+ <label class="oc-field-label" for="oc-popover-width">Width</label>
13
+ <input class="oc-input" id="oc-popover-width" value="100%">
14
+ </div>
15
+ </div>
@@ -0,0 +1,34 @@
1
+ <!-- OmniaUI component: price-card - Plan card with a monthly / yearly toggle (radio + :has), discount badge and included / excluded features. Needs @birdycom/omniaui CSS.
2
+ File: packages/ui/snippets/price-card.html | Map: article.oc-price-card -> head (name + discount) -> toggle -> prices -> features -> cta
3
+ Class API (modifiers are extra classes / attributes on the same element):
4
+ .oc-price-card: The card. Modifier: --featured (accent border + glow; use with .oc-accent--*)
5
+ .oc-price-card__head / __name / __desc: Title row, plan name, short description
6
+ .oc-price-card__discount: Badge ("Save 20%"), dimmed while monthly is selected
7
+ .oc-price-card__toggle: Put on an .oc-segmented with radios value="monthly" and value="yearly" (unique name per card)
8
+ .oc-price-card__price--monthly / --yearly: Price rows; the checked radio decides which one shows
9
+ .oc-price-card__amount / __period / __was / __note: Big number, "/month", old price (<s>), small note
10
+ .oc-price-card__features: List. .oc-price-card__feature (✓), modifier --excluded (✕ + muted)
11
+ .oc-price-card__cta: Full-width button
12
+ Slots: name, discount, description, prices, features, cta
13
+ -->
14
+ <article class="oc-price-card">
15
+ <div class="oc-price-card__head">
16
+ <h3 class="oc-price-card__name">Pro</h3>
17
+ <span class="oc-price-card__discount">Save 20%</span>
18
+ </div>
19
+ <p class="oc-price-card__desc">For small teams that send invoices every week.</p>
20
+ <div class="oc-segmented oc-price-card__toggle" role="radiogroup" aria-label="Billing period">
21
+ <label class="oc-segmented-item"><input type="radio" name="oc-price-pro" value="monthly" checked> Monthly</label>
22
+ <label class="oc-segmented-item"><input type="radio" name="oc-price-pro" value="yearly"> Yearly</label>
23
+ </div>
24
+ <p class="oc-price-card__price oc-price-card__price--monthly"><span class="oc-price-card__amount">&euro;12</span><span class="oc-price-card__period">/month</span></p>
25
+ <p class="oc-price-card__price oc-price-card__price--yearly"><span class="oc-price-card__amount">&euro;115</span><span class="oc-price-card__period">/year</span><s class="oc-price-card__was">&euro;144</s><span class="oc-price-card__note">Billed once a year</span></p>
26
+ <ul class="oc-price-card__features">
27
+ <li class="oc-price-card__feature">Unlimited invoices</li>
28
+ <li class="oc-price-card__feature">5 team members</li>
29
+ <li class="oc-price-card__feature">Bank import</li>
30
+ <li class="oc-price-card__feature oc-price-card__feature--excluded">Custom domain</li>
31
+ <li class="oc-price-card__feature oc-price-card__feature--excluded">Priority support</li>
32
+ </ul>
33
+ <a class="oc-btn oc-price-card__cta" href="#signup">Choose Pro</a>
34
+ </article>
@@ -0,0 +1,13 @@
1
+ <!-- OmniaUI component: product-mark - Squircle app icon tile in the accent gradient (sm / lg / xl). Needs @birdycom/omniaui CSS.
2
+ File: packages/ui/snippets/product-mark.html | Map: span.oc-product-mark (glyph, img or svg) per size
3
+ Class API (modifiers are extra classes / attributes on the same element):
4
+ .oc-product-mark: The tile. Uses corner-shape: squircle where supported, a rounded square otherwise.
5
+ Sizes: --sm, (default), --lg, --xl. Styles: --soft (tinted), --glow, --cover (full-bleed img)
6
+ .oc-accent--*: Accent preset (green, violet, orange, cyan, red, yellow, blue)
7
+ --oc-mark-size: Custom size
8
+ Slots: content (glyph, emoji, <img alt=""> or inline SVG)
9
+ -->
10
+ <span class="oc-product-mark oc-product-mark--sm oc-accent--green" aria-hidden="true">&#9670;</span>
11
+ <span class="oc-product-mark oc-accent--violet" aria-hidden="true">&#9673;</span>
12
+ <span class="oc-product-mark oc-product-mark--lg oc-accent--orange" aria-hidden="true">&#9650;</span>
13
+ <span class="oc-product-mark oc-product-mark--xl oc-accent--cyan" aria-hidden="true">&#9733;</span>
@@ -0,0 +1,4 @@
1
+ <!-- OmniaUI component: progress — Progress bar. Needs @birdycom/omniaui CSS. -->
2
+ <div class="oc-progress" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100">
3
+ <div class="oc-progress-bar" style="width: 60%"></div>
4
+ </div>
@@ -0,0 +1,23 @@
1
+ <!-- OmniaUI component: project-card - Portfolio card with a browser-like preview, type badge, name, meta and an arrow link. Needs @birdycom/omniaui CSS.
2
+ File: packages/ui/snippets/project-card.html | Map: a.oc-project-card -> __frame (__bar + __shot) -> __body (type, name, meta, more)
3
+ Class API (modifiers are extra classes / attributes on the same element):
4
+ .oc-project-card: The card (usually an <a>, the whole card is clickable). Modifier: --flat (edge-to-edge preview)
5
+ .oc-project-card__frame: Preview window. .oc-project-card__bar: title bar with three <i> dots
6
+ .oc-project-card__shot: Screenshot <img>, or an empty <span> for a gradient placeholder
7
+ .oc-project-card__body: Text column
8
+ .oc-project-card__type / __name / __meta / __more: Badge, title, sector line, "View" link with arrow
9
+ .oc-accent--*: Accent preset for the badge, dot, border and placeholder
10
+ Slots: shot (image), type, name, meta, more
11
+ -->
12
+ <a class="oc-project-card oc-accent--green" href="#project">
13
+ <span class="oc-project-card__frame">
14
+ <span class="oc-project-card__bar" aria-hidden="true"><i></i><i></i><i></i></span>
15
+ <span class="oc-project-card__shot" role="img" aria-label="Northwind Bakery website, screenshot"></span>
16
+ </span>
17
+ <span class="oc-project-card__body">
18
+ <span class="oc-project-card__type">Website</span>
19
+ <span class="oc-project-card__name">Northwind Bakery</span>
20
+ <span class="oc-project-card__meta">Food &amp; retail &middot; Antwerp</span>
21
+ <span class="oc-project-card__more">View project</span>
22
+ </span>
23
+ </a>
@@ -0,0 +1,54 @@
1
+ <!-- OmniaUI component: prose — Typography for long-form CMS, blog and help text: headings, lists, quotes, code, tables, figures. Needs @birdycom/omniaui CSS.
2
+ File: packages/ui/snippets/prose.html | Map: article -> lead -> h2 + list -> figure -> h3 + ordered list -> blockquote -> table -> code -> hr + small print
3
+ Class API (modifiers are extra classes / attributes on the same element):
4
+ .oc-prose: Wrapper around HTML without classes (h1–h4, p, a, strong, em, mark, code, kbd, ul, ol, dl, blockquote,
5
+ pre, table, figure, img, figcaption, hr). Width is 68ch. Modifiers: --sm, --lg (all spacing scales along), --full (no max width)
6
+ .oc-prose-lead: Larger intro paragraph
7
+ Rules use :where(), so they carry no extra weight: a utility class on an element inside the text still wins. No JavaScript.
8
+ -->
9
+ <article class="oc-prose">
10
+ <h1>Planning a kitchen renovation</h1>
11
+ <p class="oc-prose-lead">A new kitchen takes eight to twelve weeks from the first visit to the last cabinet handle. This guide explains every step, so you know what to expect and when we need you.</p>
12
+ <h2>Before the first visit</h2>
13
+ <p>Collect a few photos of kitchens you like and measure the room roughly. Exact measurements are not needed yet: our site manager does that during the visit. Read the <a href="#checklist">preparation checklist</a> if you want to be fully ready.</p>
14
+ <ul>
15
+ <li>The <strong>budget range</strong> you have in mind, including appliances</li>
16
+ <li>Which walls, doors and windows can move, and which cannot
17
+ <ul><li>Load-bearing walls need a structural engineer</li><li>Moving a window needs a permit in most towns</li></ul>
18
+ </li>
19
+ <li>Appliances you want to keep</li>
20
+ </ul>
21
+ <figure>
22
+ <div class="oc-media-art oc-media-art--6" role="img" aria-label="Kitchen with oak fronts and a light stone worktop"></div>
23
+ <figcaption>Villa Dewitte: oak fronts with a Calacatta matt worktop, finished in October 2026.</figcaption>
24
+ </figure>
25
+ <h3>From design to installation</h3>
26
+ <ol>
27
+ <li>Site visit and measurements (week 1)</li>
28
+ <li>Design and quote, with two revision rounds (weeks 2–3)</li>
29
+ <li>Order and production of the cabinets (weeks 4–9)</li>
30
+ <li>Installation, worktop and finishing (weeks 10–11)</li>
31
+ </ol>
32
+ <blockquote>
33
+ <p>The planning was clear from day one. We always knew who was coming and when, and the kitchen was ready a week early.</p>
34
+ <footer>— Ann Dewitte, client in Ghent</footer>
35
+ </blockquote>
36
+ <h2>Worktop materials compared</h2>
37
+ <table>
38
+ <caption>Prices per running metre, 60 cm deep, installed.</caption>
39
+ <thead><tr><th>Material</th><th>Thickness</th><th>Heat resistant</th><th>Price</th></tr></thead>
40
+ <tbody>
41
+ <tr><td>Compact laminate</td><td>12 mm</td><td>Up to 180 °C</td><td>€ 290</td></tr>
42
+ <tr><td>Quartz composite</td><td>20 mm</td><td>Up to 150 °C</td><td>€ 540</td></tr>
43
+ <tr><td>Natural stone</td><td>20 mm</td><td>Yes</td><td>€ 720</td></tr>
44
+ </tbody>
45
+ </table>
46
+ <h3>Sharing your floor plan</h3>
47
+ <p>Upload a PDF or a photo in the client portal, or send it by e-mail. Press <kbd>Ctrl</kbd> + <kbd>V</kbd> in the chat to paste a screenshot. Files are stored as <code>project-id/plans/</code> and only your project team can see them.</p>
48
+ <pre><code>Project: 2026-114 Villa Dewitte
49
+ Room: Kitchen, ground floor
50
+ Wall A: 412 cm (window at 160 cm)
51
+ Wall B: 298 cm (door at the left)</code></pre>
52
+ <hr>
53
+ <p><small>Lead times are an estimate. <mark>Natural stone</mark> can take two weeks longer in summer.</small></p>
54
+ </article>
@@ -0,0 +1,17 @@
1
+ <!-- OmniaUI component: radio - Radio group: native inputs, stacked or row, descriptions, card style. Needs @birdycom/omniaui CSS.
2
+ Class API (modifiers are extra classes / attributes on the same element):
3
+ .oc-radio: the input (accent-color from the theme)
4
+ .oc-radio-group: fieldset/div wrapper. Modifier: --row
5
+ .oc-radio-item: label around input + text. Modifier: --card (bordered, highlights when checked)
6
+ -->
7
+ <fieldset class="oc-radio-group">
8
+ <legend class="oc-label">Plan</legend>
9
+ <label class="oc-radio-item"><input class="oc-radio" type="radio" name="oc-plan" value="free" checked> Free</label>
10
+ <label class="oc-radio-item"><input class="oc-radio" type="radio" name="oc-plan" value="pro"> Pro</label>
11
+ <label class="oc-radio-item"><input class="oc-radio" type="radio" name="oc-plan" value="team" disabled> Team (soon)</label>
12
+ </fieldset>
13
+
14
+ <div class="oc-radio-group">
15
+ <label class="oc-radio-item oc-radio-item--card"><input class="oc-radio" type="radio" name="oc-bill" value="month" checked><span>Monthly<small>Billed every month, cancel anytime.</small></span></label>
16
+ <label class="oc-radio-item oc-radio-item--card"><input class="oc-radio" type="radio" name="oc-bill" value="year"><span>Yearly<small>Two months free.</small></span></label>
17
+ </div>
@@ -0,0 +1,20 @@
1
+ <!-- OmniaUI component: recovery-codes - Warning panel with a code grid plus copy and download actions. Needs @birdycom/omniaui CSS.
2
+ Class API (modifiers are extra classes / attributes on the same element):
3
+ .oc-recovery-codes: Panel (warning tint)
4
+ .oc-recovery-codes-title / -warning: Heading and explanation
5
+ .oc-recovery-codes-list: Two-column monospace grid (selectable with one click)
6
+ .oc-recovery-codes-actions: Button row
7
+ -->
8
+ <div class="oc-recovery-codes">
9
+ <h3 class="oc-recovery-codes-title">Recovery codes</h3>
10
+ <p class="oc-recovery-codes-warning">Store these codes somewhere safe. Each code works once.</p>
11
+ <ul class="oc-recovery-codes-list">
12
+ <li>4F8K-92QA</li><li>M3ZP-71LD</li>
13
+ <li>7TQX-0BNE</li><li>C8WV-5YHR</li>
14
+ <li>2JDA-KE63</li><li>R9UG-X4MS</li>
15
+ </ul>
16
+ <div class="oc-recovery-codes-actions">
17
+ <button class="oc-btn oc-btn--outline oc-btn--sm" type="button">Copy all</button>
18
+ <button class="oc-btn oc-btn--outline oc-btn--sm" type="button">Download .txt</button>
19
+ </div>
20
+ </div>
@@ -0,0 +1,16 @@
1
+ <!-- OmniaUI component: resizable - Resizable panels using CSS resize (horizontal, vertical, free box). Needs @birdycom/omniaui CSS.
2
+ Class API (modifiers are extra classes / attributes on the same element):
3
+ .oc-resizable: flex container. Modifier: --vertical
4
+ .oc-resizable-panel: pane. Modifier: --resizable (gets the resize grip; sets min/max size)
5
+ .oc-resizable-box: any element with resize: both
6
+ -->
7
+ <div class="oc-resizable" style="block-size:11rem">
8
+ <div class="oc-resizable-panel oc-resizable-panel--resizable"><strong>Sidebar</strong><br>Drag the corner grip to resize.</div>
9
+ <div class="oc-resizable-panel"><strong>Content</strong><br>Takes the remaining space.</div>
10
+ </div>
11
+
12
+ <div class="oc-resizable oc-resizable--vertical" style="block-size:14rem">
13
+ <div class="oc-resizable-panel oc-resizable-panel--resizable"><strong>Editor</strong></div>
14
+ <div class="oc-resizable-panel"><strong>Preview</strong></div>
15
+ </div>
16
+ <div class="oc-resizable-box oc-resizable" style="inline-size:14rem;block-size:6rem"><div class="oc-resizable-panel">Resize me in both directions</div></div>
@@ -0,0 +1,20 @@
1
+ <!-- OmniaUI component: scroll-area - Scroll area: bounded scroll region with themed thin scrollbar and edge shadows. Needs @birdycom/omniaui CSS.
2
+ Class API (modifiers are extra classes / attributes on the same element):
3
+ .oc-scroll-area: bordered scroll region (max-block-size 14rem). Modifiers: --x (horizontal), --shadows (edge shadows, CSS only)
4
+ .oc-scrollbar: themed scrollbar for any overflow element. Modifiers: --thin, --hidden
5
+ -->
6
+ <div class="oc-scroll-area oc-scroll-area--shadows" tabindex="0" role="region" aria-label="Release notes">
7
+ <h4 style="margin:0 0 .5rem">Release notes</h4>
8
+ <p>Version 0.9.0 &ndash; light-dark() tokens for every component.</p>
9
+ <p>Version 0.8.0 &ndash; sheet, popover and command on native dialog and popover.</p>
10
+ <p>Version 0.6.0 &ndash; toast with CSS auto-dismiss.</p>
11
+ <p>Version 0.6.0 &ndash; segmented control and stepper.</p>
12
+ <p>Version 0.5.0 &ndash; otp input, tag input and copy field.</p>
13
+ <p>Version 0.4.0 &ndash; sidebar with icon-only mode.</p>
14
+ <p>Version 0.3.0 &ndash; tabs, accordion on details.</p>
15
+ <p>Version 0.2.0 &ndash; alerts and badges.</p>
16
+ </div>
17
+
18
+ <div class="oc-scroll-area oc-scroll-area--x" tabindex="0" role="region" aria-label="Tags">
19
+ <span class="oc-badge">design</span> <span class="oc-badge">tokens</span> <span class="oc-badge">dark mode</span> <span class="oc-badge">anchor positioning</span> <span class="oc-badge">popover</span> <span class="oc-badge">container queries</span> <span class="oc-badge">scroll snap</span> <span class="oc-badge">view transitions</span> <span class="oc-badge">oklch</span> <span class="oc-badge">light-dark</span> <span class="oc-badge">color-mix</span>
20
+ </div>
@@ -0,0 +1,8 @@
1
+ <!-- OmniaUI component: search - Search field. Needs @birdycom/omniaui CSS.
2
+ Class API: .oc-search (label wrapper) · .oc-search-icon (svg) · .oc-search-input (input type="search") · .oc-search-hint (kbd, hidden while focused)
3
+ -->
4
+ <label class="oc-search">
5
+ <svg class="oc-search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>
6
+ <input class="oc-search-input" type="search" name="q" placeholder="Search the docs" aria-label="Search the docs">
7
+ <kbd class="oc-search-hint">/</kbd>
8
+ </label>
@@ -0,0 +1,11 @@
1
+ <!-- OmniaUI component: segmented - Radio group as a pill switcher for a single choice - no JavaScript. Needs @birdycom/omniaui CSS.
2
+ Class API (modifiers are extra classes / attributes on the same element):
3
+ .oc-segmented: Group wrapper (role="radiogroup"). Modifiers: --block (full width), --sm.
4
+ .oc-segmented-item: Label that wraps one radio input and its text
5
+ Slots: one .oc-segmented-item per option (radio input + label text)
6
+ -->
7
+ <div class="oc-segmented" role="radiogroup" aria-label="Period">
8
+ <label class="oc-segmented-item"><input type="radio" name="oc-period" value="month" checked> Month</label>
9
+ <label class="oc-segmented-item"><input type="radio" name="oc-period" value="quarter"> Quarter</label>
10
+ <label class="oc-segmented-item"><input type="radio" name="oc-period" value="year"> Year</label>
11
+ </div>
@@ -0,0 +1,7 @@
1
+ <!-- OmniaUI component: select - Native select. Needs @birdycom/omniaui CSS.
2
+ -->
3
+ <select class="oc-select" aria-label="Country">
4
+ <option>Belgium</option>
5
+ <option>Netherlands</option>
6
+ <option>Germany</option>
7
+ </select>
@@ -0,0 +1,15 @@
1
+ <!-- OmniaUI component: separator - Separator: horizontal, vertical and with label. Needs @birdycom/omniaui CSS.
2
+ Class API (modifiers are extra classes / attributes on the same element):
3
+ .oc-separator: 1px divider (use on <hr>). Modifiers: --vertical, --strong
4
+ .oc-separator-text: divider lines with a centered label
5
+ -->
6
+ <p style="margin:0;font-size:.875rem">Content above</p>
7
+ <hr class="oc-separator">
8
+ <p style="margin:0;font-size:.875rem">Content below</p>
9
+
10
+ <div style="display:flex;align-items:center;block-size:1.5rem;font-size:.875rem">
11
+ <span>Blog</span><span class="oc-separator oc-separator--vertical" role="separator" aria-orientation="vertical"></span>
12
+ <span>Docs</span><span class="oc-separator oc-separator--vertical" role="separator" aria-orientation="vertical"></span>
13
+ <span>Source</span>
14
+ </div>
15
+ <div class="oc-separator-text" role="separator"><span>or continue with</span></div>
@@ -0,0 +1,35 @@
1
+ <!-- OmniaUI component: severity-card - Risk-colored expandable card (low, medium, high, critical) on details / summary - no JavaScript. Needs @birdycom/omniaui CSS.
2
+ File: packages/ui/snippets/severity-card.html | Map: high card (open: head, body, actions) -> low resolved card
3
+ Class API (modifiers are extra classes / attributes on the same element):
4
+ details.oc-severity-card: Card. Levels: --low, --medium, --high, --critical. State: .is-resolved (neutral, title struck). Same name="..." = one open at a time.
5
+ summary.oc-severity-card-head: Head row with chevron
6
+ .oc-severity-card-icon / -main / -title: Icon, text column, title in the level color
7
+ .oc-severity-card-tags / -tag: Small monospace tags under the title
8
+ .oc-severity-card-level: Level badge at the end of the head
9
+ .oc-severity-card-body / -actions: Details text and action buttons
10
+ Slots: icon, title, tags, level, body, actions
11
+ -->
12
+ <details class="oc-severity-card oc-severity-card--high" name="oc-findings" open>
13
+ <summary class="oc-severity-card-head">
14
+ <span class="oc-severity-card-icon" aria-hidden="true"><svg class="" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/><path d="M12 9v4M12 17h.01"/></svg></span>
15
+ <span class="oc-severity-card-main">
16
+ <span class="oc-severity-card-title">shop-example.com data breach</span>
17
+ <span class="oc-severity-card-tags"><span class="oc-severity-card-tag">email</span><span class="oc-severity-card-tag">password</span><span class="oc-severity-card-tag">phone</span></span>
18
+ </span>
19
+ <span class="oc-severity-card-level">High</span>
20
+ </summary>
21
+ <div class="oc-severity-card-body">
22
+ <p>Your e-mail address and a hashed password appeared in a leak from March 2026. Change the password on this site and everywhere you reused it.</p>
23
+ <div class="oc-severity-card-actions">
24
+ <a class="oc-btn oc-btn--sm" href="#">Change password</a>
25
+ <button class="oc-btn oc-btn--outline oc-btn--sm" type="button">Mark as resolved</button>
26
+ </div>
27
+ </div>
28
+ </details>
29
+ <details class="oc-severity-card oc-severity-card--low is-resolved" name="oc-findings">
30
+ <summary class="oc-severity-card-head">
31
+ <span class="oc-severity-card-main"><span class="oc-severity-card-title">Old forum profile</span></span>
32
+ <span class="oc-severity-card-level">Resolved</span>
33
+ </summary>
34
+ <div class="oc-severity-card-body"><p>The profile was removed on 2 October 2026.</p></div>
35
+ </details>
@@ -0,0 +1,32 @@
1
+ <!-- OmniaUI component: sheet - Side panel on <dialog> (right, left, top, bottom) - no JavaScript. Needs @birdycom/omniaui CSS.
2
+ Class API (modifiers are extra classes / attributes on the same element):
3
+ dialog.oc-sheet: The dialog. Side modifiers: --left, --top, --bottom (default right).
4
+ .oc-sheet-content: Panel. Modifier: --wide.
5
+ .oc-sheet-header / -title / -description: Heading area
6
+ .oc-sheet-body: Scrolling content
7
+ .oc-sheet-footer: Action row
8
+ .oc-sheet-close: Close button (command="close")
9
+ Slots: header (title, description), body (default), footer, trigger button outside the dialog
10
+ -->
11
+ <button class="oc-btn oc-btn--outline" type="button" command="show-modal" commandfor="oc-sheet-demo">Open sheet</button>
12
+
13
+ <dialog class="oc-sheet" id="oc-sheet-demo" closedby="any" aria-labelledby="oc-sheet-demo-title">
14
+ <div class="oc-sheet-content">
15
+ <button class="oc-sheet-close" type="button" command="close" commandfor="oc-sheet-demo" aria-label="Close">&times;</button>
16
+ <div class="oc-sheet-header">
17
+ <h2 class="oc-sheet-title" id="oc-sheet-demo-title">Table design</h2>
18
+ <p class="oc-sheet-description">Choose the columns you want to see.</p>
19
+ </div>
20
+ <div class="oc-sheet-body">
21
+ <div class="oc-field-group">
22
+ <label><input class="oc-checkbox" type="checkbox" checked> Name</label>
23
+ <label><input class="oc-checkbox" type="checkbox" checked> E-mail</label>
24
+ <label><input class="oc-checkbox" type="checkbox"> Phone</label>
25
+ </div>
26
+ </div>
27
+ <div class="oc-sheet-footer">
28
+ <button class="oc-btn oc-btn--outline" type="button" command="close" commandfor="oc-sheet-demo">Cancel</button>
29
+ <button class="oc-btn" type="button" command="close" commandfor="oc-sheet-demo">Save</button>
30
+ </div>
31
+ </div>
32
+ </dialog>
@@ -0,0 +1,24 @@
1
+ <!-- OmniaUI component: sidebar-docs - The navigation used on the left of the OmniaCSS documentation (variant of the sidebar). Needs @birdycom/omniaui CSS.
2
+ Class API: .oc-sidebar.oc-sidebar--docs (root nav) · .oc-sidebar-title · .oc-sidebar-group-label · .oc-sidebar-menu (ul) ·
3
+ .oc-sidebar-menu-button (a; aria-current="page" = current page, .is-active = section that contains it) · .oc-sidebar-menu-sub (nested ul)
4
+ -->
5
+ <nav class="oc-sidebar oc-sidebar--docs" aria-label="Documentation">
6
+ <h2 class="oc-sidebar-title">Documentation</h2>
7
+ <p class="oc-sidebar-group-label">Getting started</p>
8
+ <ul class="oc-sidebar-menu">
9
+ <li><a class="oc-sidebar-menu-button" href="#">Introduction</a></li>
10
+ <li><a class="oc-sidebar-menu-button" href="#">Installation</a></li>
11
+ </ul>
12
+ <p class="oc-sidebar-group-label">Layout</p>
13
+ <ul class="oc-sidebar-menu">
14
+ <li>
15
+ <a class="oc-sidebar-menu-button is-active" href="#">Flexbox</a>
16
+ <ul class="oc-sidebar-menu-sub">
17
+ <li><a class="oc-sidebar-menu-button" aria-current="page" href="#">Flex direction</a></li>
18
+ <li><a class="oc-sidebar-menu-button" href="#">Flex wrap</a></li>
19
+ </ul>
20
+ </li>
21
+ <li><a class="oc-sidebar-menu-button" href="#">Grid</a></li>
22
+ </ul>
23
+ </nav>
24
+
@@ -0,0 +1,55 @@
1
+ <!-- OmniaUI component: sidebar - Vertical navigation: header, groups, menu items, badges, nested menu, footer, icon-only mode. Needs @birdycom/omniaui CSS.
2
+ Class API (modifiers are extra classes / attributes on the same element):
3
+ .oc-sidebar: Root (aside/nav). Modifiers: --collapsed (icon only), --right, --floating. Width via --oc-sidebar-width / --oc-sidebar-width-icon.
4
+ .oc-sidebar-header / -footer: Fixed top / bottom area (logo, workspace switcher / user)
5
+ .oc-sidebar-content: Scrolling middle area
6
+ .oc-sidebar-group: Group of items; optional .oc-sidebar-group-label heading
7
+ .oc-sidebar-separator: Divider line
8
+ .oc-sidebar-menu: ul of items
9
+ .oc-sidebar-menu-button: Link or button of an item. State: aria-current="page" or .is-active; aria-disabled="true". Modifier: --lg.
10
+ .oc-sidebar-menu-icon: 16px icon (inline SVG)
11
+ .oc-sidebar-menu-label: Label (hidden when collapsed)
12
+ .oc-sidebar-menu-badge: Count pill on the right
13
+ .oc-sidebar-menu-sub: Nested ul with a guide line
14
+ details.oc-sidebar-collapsible: Expandable item: <summary class="oc-sidebar-menu-button"> + .oc-sidebar-menu-sub
15
+ Slots: header, group label, menu items (default), nested items (.oc-sidebar-menu-sub), footer
16
+ -->
17
+ <aside class="oc-sidebar " aria-label="Main navigation">
18
+ <div class="oc-sidebar-header">
19
+ <a class="oc-sidebar-menu-button oc-sidebar-menu-button--lg" href="#">
20
+ <svg class="oc-sidebar-menu-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 11l9-8 9 8v10a1 1 0 0 1-1 1h-5v-6H9v6H4a1 1 0 0 1-1-1z"/></svg>
21
+ <span class="oc-sidebar-menu-label"><strong>OmniaDesk</strong></span>
22
+ </a>
23
+ </div>
24
+ <div class="oc-sidebar-content">
25
+ <div class="oc-sidebar-group">
26
+ <div class="oc-sidebar-group-label">Platform</div>
27
+ <ul class="oc-sidebar-menu">
28
+ <li><a class="oc-sidebar-menu-button" href="#" aria-current="page"><svg class="oc-sidebar-menu-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 11l9-8 9 8v10a1 1 0 0 1-1 1h-5v-6H9v6H4a1 1 0 0 1-1-1z"/></svg><span class="oc-sidebar-menu-label">Dashboard</span></a></li>
29
+ <li><a class="oc-sidebar-menu-button" href="#"><svg class="oc-sidebar-menu-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="9" cy="8" r="4"/><path d="M2 21c0-4 3-6 7-6s7 2 7 6"/></svg><span class="oc-sidebar-menu-label">Contacts</span><span class="oc-sidebar-menu-badge">12</span></a></li>
30
+ <li>
31
+ <details class="oc-sidebar-collapsible" open>
32
+ <summary class="oc-sidebar-menu-button"><svg class="oc-sidebar-menu-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 2h8l5 5v15H6z"/><path d="M14 2v5h5"/></svg><span class="oc-sidebar-menu-label">Invoices</span></summary>
33
+ <ul class="oc-sidebar-menu-sub">
34
+ <li><a class="oc-sidebar-menu-button" href="#">Sales</a></li>
35
+ <li><a class="oc-sidebar-menu-button" href="#">Purchases</a></li>
36
+ </ul>
37
+ </details>
38
+ </li>
39
+ <li><a class="oc-sidebar-menu-button" href="#"><svg class="oc-sidebar-menu-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 20V10M10 20V4M16 20v-8M22 20H2"/></svg><span class="oc-sidebar-menu-label">Reports</span></a></li>
40
+ </ul>
41
+ </div>
42
+ <div class="oc-sidebar-separator"></div>
43
+ <div class="oc-sidebar-group">
44
+ <ul class="oc-sidebar-menu">
45
+ <li><a class="oc-sidebar-menu-button" href="#"><svg class="oc-sidebar-menu-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M5 5l2 2M17 17l2 2M19 5l-2 2M7 17l-2 2"/></svg><span class="oc-sidebar-menu-label">Settings</span></a></li>
46
+ </ul>
47
+ </div>
48
+ </div>
49
+ <div class="oc-sidebar-footer">
50
+ <div class="oc-user">
51
+ <span class="oc-avatar oc-avatar--sm">SC</span>
52
+ <span class="oc-user-text"><span class="oc-user-name">Serge Cools</span><span class="oc-user-email">serge@example.com</span></span>
53
+ </div>
54
+ </div>
55
+ </aside>
@@ -0,0 +1,6 @@
1
+ <!-- OmniaUI component: site-footer - Slim footer bar. Needs @birdycom/omniaui CSS.
2
+ Class API: .oc-footerbar (footer; --fixed pins it to the bottom of the viewport). Links inside use the primary color. Tokens: --ocm-footer-height, --ocm-footer-bg
3
+ -->
4
+ <footer class="oc-footerbar">
5
+ OmniaCSS v1 &mdash; modern CSS, utilities, components and blocks &middot; <a href="#">Docs</a> &middot; <a href="#">GitHub</a>
6
+ </footer>