@birdycom/omniaui-vue 0.11.0 → 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 (178) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +49 -49
  3. package/dist/omniaui-vue.js.map +1 -1
  4. package/package.json +69 -69
  5. package/src/blocks/OcBlockAboutTimeline.vue +44 -44
  6. package/src/blocks/OcBlockAppHeader.vue +36 -36
  7. package/src/blocks/OcBlockAppShell.vue +29 -29
  8. package/src/blocks/OcBlockAuth.vue +24 -24
  9. package/src/blocks/OcBlockAuthSplit.vue +47 -47
  10. package/src/blocks/OcBlockContactGrid.vue +53 -53
  11. package/src/blocks/OcBlockCta.vue +12 -12
  12. package/src/blocks/OcBlockDataTable.vue +27 -27
  13. package/src/blocks/OcBlockFaq.vue +49 -49
  14. package/src/blocks/OcBlockFeatures.vue +23 -23
  15. package/src/blocks/OcBlockFooter.vue +25 -25
  16. package/src/blocks/OcBlockFormPage.vue +24 -24
  17. package/src/blocks/OcBlockHero.vue +13 -13
  18. package/src/blocks/OcBlockHeroCode.vue +42 -42
  19. package/src/blocks/OcBlockHeroOrbit.vue +69 -69
  20. package/src/blocks/OcBlockHeroSplit.vue +15 -15
  21. package/src/blocks/OcBlockModuleHeader.vue +21 -21
  22. package/src/blocks/OcBlockPageHero.vue +13 -13
  23. package/src/blocks/OcBlockPortfolioGrid.vue +63 -63
  24. package/src/blocks/OcBlockPricing.vue +39 -39
  25. package/src/blocks/OcBlockProcess.vue +39 -39
  26. package/src/blocks/OcBlockProductGrid.vue +41 -41
  27. package/src/blocks/OcBlockProfileHeader.vue +50 -50
  28. package/src/blocks/OcBlockShowcase.vue +43 -43
  29. package/src/blocks/OcBlockSiteFooter.vue +54 -54
  30. package/src/blocks/OcBlockSiteHeader.vue +34 -34
  31. package/src/blocks/OcBlockSpotlight.vue +47 -47
  32. package/src/blocks/OcBlockStats.vue +17 -17
  33. package/src/blocks/OcBlockStatsCounter.vue +20 -20
  34. package/src/blocks/OcBlockTeamList.vue +53 -53
  35. package/src/blocks/OcBlockTwoFactor.vue +61 -61
  36. package/src/blocks/OcBlockWizardDialog.vue +67 -67
  37. package/src/components/OcAccordion.vue +12 -12
  38. package/src/components/OcAccordionAccent.vue +27 -27
  39. package/src/components/OcAccordionItem.vue +19 -19
  40. package/src/components/OcAffixInput.vue +40 -40
  41. package/src/components/OcAlert.vue +17 -17
  42. package/src/components/OcAlertDialog.vue +66 -66
  43. package/src/components/OcAlphaTabs.vue +54 -54
  44. package/src/components/OcAspectRatio.vue +21 -21
  45. package/src/components/OcAttachment.vue +59 -59
  46. package/src/components/OcAttachmentImage.vue +13 -13
  47. package/src/components/OcAttachmentList.vue +31 -31
  48. package/src/components/OcAttachmentThumb.vue +14 -14
  49. package/src/components/OcAvatar.vue +18 -18
  50. package/src/components/OcAvatarGroup.vue +7 -7
  51. package/src/components/OcBackLink.vue +8 -8
  52. package/src/components/OcBadge.vue +13 -13
  53. package/src/components/OcBarcodeInput.vue +51 -51
  54. package/src/components/OcBreadcrumb.vue +22 -22
  55. package/src/components/OcBrowserFrame.vue +33 -33
  56. package/src/components/OcBusyOverlay.vue +32 -32
  57. package/src/components/OcButton.vue +47 -47
  58. package/src/components/OcButtonGroup.vue +10 -10
  59. package/src/components/OcButtonGroupText.vue +7 -7
  60. package/src/components/OcCard.vue +20 -20
  61. package/src/components/OcChartLine.vue +80 -80
  62. package/src/components/OcChatComposer.vue +42 -42
  63. package/src/components/OcCheckbox.vue +26 -26
  64. package/src/components/OcChecklist.vue +29 -29
  65. package/src/components/OcCollapsible.vue +19 -19
  66. package/src/components/OcColorField.vue +15 -15
  67. package/src/components/OcColorSelect.vue +33 -33
  68. package/src/components/OcColumnMenu.vue +50 -50
  69. package/src/components/OcCommand.vue +119 -119
  70. package/src/components/OcConfirmDialog.vue +65 -65
  71. package/src/components/OcCookieConsent.vue +119 -119
  72. package/src/components/OcCopyField.vue +37 -37
  73. package/src/components/OcCounter.vue +15 -15
  74. package/src/components/OcDataTable.vue +144 -144
  75. package/src/components/OcDefinitionList.vue +35 -35
  76. package/src/components/OcDropdown.vue +23 -23
  77. package/src/components/OcDropdownItem.vue +9 -9
  78. package/src/components/OcDropdownLabel.vue +7 -7
  79. package/src/components/OcDropdownSeparator.vue +7 -7
  80. package/src/components/OcDropzone.vue +36 -36
  81. package/src/components/OcEmojiPicker.vue +45 -45
  82. package/src/components/OcEmptyState.vue +13 -13
  83. package/src/components/OcEntityCard.vue +47 -47
  84. package/src/components/OcFactList.vue +37 -37
  85. package/src/components/OcFilterCounts.vue +38 -38
  86. package/src/components/OcFlipCard.vue +36 -36
  87. package/src/components/OcFormField.vue +36 -36
  88. package/src/components/OcGreeting.vue +52 -52
  89. package/src/components/OcHeading.vue +19 -19
  90. package/src/components/OcHoverCard.vue +25 -25
  91. package/src/components/OcImageZoom.vue +39 -39
  92. package/src/components/OcInput.vue +9 -9
  93. package/src/components/OcInputGroup.vue +12 -12
  94. package/src/components/OcItem.vue +40 -40
  95. package/src/components/OcItemGroup.vue +7 -7
  96. package/src/components/OcItemSeparator.vue +7 -7
  97. package/src/components/OcKbd.vue +7 -7
  98. package/src/components/OcKbdGroup.vue +15 -15
  99. package/src/components/OcLabel.vue +10 -10
  100. package/src/components/OcLanguageSelect.vue +40 -40
  101. package/src/components/OcLauncherCard.vue +34 -34
  102. package/src/components/OcLightbox.vue +63 -63
  103. package/src/components/OcLinkArrow.vue +25 -25
  104. package/src/components/OcListToolbar.vue +44 -44
  105. package/src/components/OcMarquee.vue +36 -36
  106. package/src/components/OcMediaCard.vue +28 -28
  107. package/src/components/OcMediaRow.vue +28 -28
  108. package/src/components/OcMediaThumb.vue +38 -38
  109. package/src/components/OcMessage.vue +91 -91
  110. package/src/components/OcMessageList.vue +43 -43
  111. package/src/components/OcMessageThread.vue +155 -155
  112. package/src/components/OcModal.vue +42 -42
  113. package/src/components/OcNavmenu.vue +18 -18
  114. package/src/components/OcNavmenuList.vue +38 -38
  115. package/src/components/OcNextTeaser.vue +25 -25
  116. package/src/components/OcNumberInput.vue +47 -47
  117. package/src/components/OcOtpInput.vue +34 -34
  118. package/src/components/OcPageHeader.vue +34 -34
  119. package/src/components/OcPagination.vue +33 -33
  120. package/src/components/OcPasswordInput.vue +27 -27
  121. package/src/components/OcPasswordRequirements.vue +28 -28
  122. package/src/components/OcPhoneInput.vue +72 -72
  123. package/src/components/OcPopover.vue +25 -25
  124. package/src/components/OcPriceCard.vue +69 -69
  125. package/src/components/OcProductMark.vue +31 -31
  126. package/src/components/OcProgress.vue +21 -21
  127. package/src/components/OcProjectCard.vue +36 -36
  128. package/src/components/OcProse.vue +57 -57
  129. package/src/components/OcRadio.vue +40 -40
  130. package/src/components/OcRadioGroup.vue +32 -32
  131. package/src/components/OcRecoveryCodes.vue +55 -55
  132. package/src/components/OcScrollArea.vue +15 -15
  133. package/src/components/OcSegmented.vue +28 -28
  134. package/src/components/OcSelect.vue +21 -21
  135. package/src/components/OcSeparator.vue +18 -18
  136. package/src/components/OcSeverityCard.vue +46 -46
  137. package/src/components/OcSheet.vue +49 -49
  138. package/src/components/OcSidebarCollapsible.vue +19 -19
  139. package/src/components/OcSidebarGroup.vue +11 -11
  140. package/src/components/OcSidebarMenu.vue +7 -7
  141. package/src/components/OcSidebarMenuButton.vue +31 -31
  142. package/src/components/OcSidebarSeparator.vue +7 -7
  143. package/src/components/OcSkeleton.vue +8 -8
  144. package/src/components/OcSlider.vue +27 -27
  145. package/src/components/OcSortableRow.vue +40 -40
  146. package/src/components/OcSpinner.vue +13 -13
  147. package/src/components/OcStackCard.vue +24 -24
  148. package/src/components/OcStackList.vue +31 -31
  149. package/src/components/OcStatCard.vue +39 -39
  150. package/src/components/OcStepper.vue +34 -34
  151. package/src/components/OcSwitch.vue +15 -15
  152. package/src/components/OcTable.vue +115 -115
  153. package/src/components/OcTableActions.vue +26 -26
  154. package/src/components/OcTableCompact.vue +46 -46
  155. package/src/components/OcTabs.vue +37 -37
  156. package/src/components/OcTagInput.vue +50 -50
  157. package/src/components/OcTerminalLog.vue +50 -50
  158. package/src/components/OcTextarea.vue +9 -9
  159. package/src/components/OcThemeSwitch.vue +31 -31
  160. package/src/components/OcTimeInput.vue +50 -50
  161. package/src/components/OcTimeline.vue +36 -36
  162. package/src/components/OcToast.vue +31 -31
  163. package/src/components/OcToastContainer.vue +21 -21
  164. package/src/components/OcToggle.vue +63 -63
  165. package/src/components/OcToggleField.vue +28 -28
  166. package/src/components/OcToggleGroup.vue +40 -40
  167. package/src/components/OcTooltip.vue +8 -8
  168. package/src/components/OcTopProgress.vue +54 -54
  169. package/src/components/OcTree.vue +70 -70
  170. package/src/components/OcUpgradeBanner.vue +42 -42
  171. package/src/components/OcUser.vue +25 -25
  172. package/src/components/OcVersionBanner.vue +34 -34
  173. package/src/composables/chartLine.ts +28 -28
  174. package/src/composables/keys.ts +22 -22
  175. package/src/composables/useAttrsSplit.ts +16 -16
  176. package/src/composables/useDialog.ts +21 -21
  177. package/src/composables/useToast.ts +66 -66
  178. package/src/composables/useUid.ts +12 -12
@@ -1,54 +1,54 @@
1
- <script setup lang="ts">
2
- /**
3
- * Brand column, link columns, a contact column and a bottom bar.
4
- * Slots: brand (the logo link), about (default: `about` text), bottom-start, bottom-end.
5
- * Classes: .oc-site-footer, __grid, __about, __title, __list, __bottom, .oc-site-header__brand
6
- */
7
- export interface SiteFooterColumn {
8
- title: string
9
- links: { label: string; href: string }[]
10
- }
11
- export interface SiteFooterContact {
12
- title: string
13
- lines: { label: string; href?: string }[]
14
- }
15
- defineProps<{
16
- about?: string
17
- columns?: SiteFooterColumn[]
18
- contact?: SiteFooterContact
19
- copyright?: string
20
- credit?: string
21
- }>()
22
- </script>
23
-
24
- <template>
25
- <footer class="oc-site-footer">
26
- <div class="oc-container">
27
- <div class="oc-site-footer__grid">
28
- <div class="oc-site-footer__about">
29
- <slot name="brand" />
30
- <p v-if="about">{{ about }}</p>
31
- </div>
32
- <div v-for="col in columns" :key="col.title">
33
- <h2 class="oc-site-footer__title">{{ col.title }}</h2>
34
- <ul class="oc-site-footer__list">
35
- <li v-for="link in col.links" :key="link.href + link.label"><a :href="link.href">{{ link.label }}</a></li>
36
- </ul>
37
- </div>
38
- <div v-if="contact">
39
- <h2 class="oc-site-footer__title">{{ contact.title }}</h2>
40
- <address class="oc-site-footer__list">
41
- <template v-for="line in contact.lines" :key="line.label">
42
- <a v-if="line.href" :href="line.href">{{ line.label }}</a>
43
- <span v-else>{{ line.label }}</span>
44
- </template>
45
- </address>
46
- </div>
47
- </div>
48
- <div v-if="copyright || credit || $slots['bottom-start'] || $slots['bottom-end']" class="oc-site-footer__bottom">
49
- <span><slot name="bottom-start">{{ copyright }}</slot></span>
50
- <span><slot name="bottom-end">{{ credit }}</slot></span>
51
- </div>
52
- </div>
53
- </footer>
54
- </template>
1
+ <script setup lang="ts">
2
+ /**
3
+ * Brand column, link columns, a contact column and a bottom bar.
4
+ * Slots: brand (the logo link), about (default: `about` text), bottom-start, bottom-end.
5
+ * Classes: .oc-site-footer, __grid, __about, __title, __list, __bottom, .oc-site-header__brand
6
+ */
7
+ export interface SiteFooterColumn {
8
+ title: string
9
+ links: { label: string; href: string }[]
10
+ }
11
+ export interface SiteFooterContact {
12
+ title: string
13
+ lines: { label: string; href?: string }[]
14
+ }
15
+ defineProps<{
16
+ about?: string
17
+ columns?: SiteFooterColumn[]
18
+ contact?: SiteFooterContact
19
+ copyright?: string
20
+ credit?: string
21
+ }>()
22
+ </script>
23
+
24
+ <template>
25
+ <footer class="oc-site-footer">
26
+ <div class="oc-container">
27
+ <div class="oc-site-footer__grid">
28
+ <div class="oc-site-footer__about">
29
+ <slot name="brand" />
30
+ <p v-if="about">{{ about }}</p>
31
+ </div>
32
+ <div v-for="col in columns" :key="col.title">
33
+ <h2 class="oc-site-footer__title">{{ col.title }}</h2>
34
+ <ul class="oc-site-footer__list">
35
+ <li v-for="link in col.links" :key="link.href + link.label"><a :href="link.href">{{ link.label }}</a></li>
36
+ </ul>
37
+ </div>
38
+ <div v-if="contact">
39
+ <h2 class="oc-site-footer__title">{{ contact.title }}</h2>
40
+ <address class="oc-site-footer__list">
41
+ <template v-for="line in contact.lines" :key="line.label">
42
+ <a v-if="line.href" :href="line.href">{{ line.label }}</a>
43
+ <span v-else>{{ line.label }}</span>
44
+ </template>
45
+ </address>
46
+ </div>
47
+ </div>
48
+ <div v-if="copyright || credit || $slots['bottom-start'] || $slots['bottom-end']" class="oc-site-footer__bottom">
49
+ <span><slot name="bottom-start">{{ copyright }}</slot></span>
50
+ <span><slot name="bottom-end">{{ credit }}</slot></span>
51
+ </div>
52
+ </div>
53
+ </footer>
54
+ </template>
@@ -1,34 +1,34 @@
1
- <script setup lang="ts">
2
- /**
3
- * Sticky header that turns into glass after scrolling; the mobile menu is a popover. No JavaScript needed.
4
- * Slots: brand (inside the brand link), nav (replaces the items), cta (the trailing button).
5
- * Classes: .oc-site-header, __inner, __brand, __toggle, __nav, .oc-container
6
- */
7
- import { useUid } from '../composables/useUid'
8
-
9
- export interface SiteHeaderLink {
10
- label: string
11
- href: string
12
- current?: boolean
13
- }
14
- withDefaults(
15
- defineProps<{ items?: SiteHeaderLink[]; homeHref?: string; menuLabel?: string; navLabel?: string }>(),
16
- { items: () => [], homeHref: '/', menuLabel: 'Menu', navLabel: 'Main' },
17
- )
18
- const navId = useUid('oc-site-nav')
19
- </script>
20
-
21
- <template>
22
- <header class="oc-site-header">
23
- <div class="oc-container oc-site-header__inner">
24
- <a class="oc-site-header__brand" :href="homeHref"><slot name="brand" /></a>
25
- <button class="oc-site-header__toggle" type="button" :popovertarget="navId" :aria-label="menuLabel">&#9776;</button>
26
- <nav :id="navId" class="oc-site-header__nav" popover :aria-label="navLabel">
27
- <slot name="nav">
28
- <a v-for="item in items" :key="item.href + item.label" :href="item.href" :aria-current="item.current ? 'page' : undefined">{{ item.label }}</a>
29
- </slot>
30
- <slot name="cta" />
31
- </nav>
32
- </div>
33
- </header>
34
- </template>
1
+ <script setup lang="ts">
2
+ /**
3
+ * Sticky header that turns into glass after scrolling; the mobile menu is a popover. No JavaScript needed.
4
+ * Slots: brand (inside the brand link), nav (replaces the items), cta (the trailing button).
5
+ * Classes: .oc-site-header, __inner, __brand, __toggle, __nav, .oc-container
6
+ */
7
+ import { useUid } from '../composables/useUid'
8
+
9
+ export interface SiteHeaderLink {
10
+ label: string
11
+ href: string
12
+ current?: boolean
13
+ }
14
+ withDefaults(
15
+ defineProps<{ items?: SiteHeaderLink[]; homeHref?: string; menuLabel?: string; navLabel?: string }>(),
16
+ { items: () => [], homeHref: '/', menuLabel: 'Menu', navLabel: 'Main' },
17
+ )
18
+ const navId = useUid('oc-site-nav')
19
+ </script>
20
+
21
+ <template>
22
+ <header class="oc-site-header">
23
+ <div class="oc-container oc-site-header__inner">
24
+ <a class="oc-site-header__brand" :href="homeHref"><slot name="brand" /></a>
25
+ <button class="oc-site-header__toggle" type="button" :popovertarget="navId" :aria-label="menuLabel">&#9776;</button>
26
+ <nav :id="navId" class="oc-site-header__nav" popover :aria-label="navLabel">
27
+ <slot name="nav">
28
+ <a v-for="item in items" :key="item.href + item.label" :href="item.href" :aria-current="item.current ? 'page' : undefined">{{ item.label }}</a>
29
+ </slot>
30
+ <slot name="cta" />
31
+ </nav>
32
+ </div>
33
+ </header>
34
+ </template>
@@ -1,47 +1,47 @@
1
- <script setup lang="ts">
2
- /**
3
- * Highlighted flagship product: badge, big title with icon tile, tagline, copy, button and a module list.
4
- * Slots: cta (default: a gradient link from `ctaLabel` / `ctaHref`). Classes: .oc-spotlight(__title/__tagline/__modules),
5
- * .oc-accent--<name>, .oc-pill--accent, .oc-status-dot, .oc-icon-tile(--lg/--sm), .oc-lead
6
- */
7
- export interface SpotlightModule {
8
- icon?: string
9
- label: string
10
- }
11
- defineProps<{
12
- accent?: string
13
- badge?: string
14
- icon?: string
15
- title: string
16
- tagline?: string
17
- lead?: string
18
- ctaLabel?: string
19
- ctaHref?: string
20
- modules?: SpotlightModule[]
21
- }>()
22
- </script>
23
-
24
- <template>
25
- <section class="oc-section-pad">
26
- <div class="oc-container">
27
- <div :class="['oc-spotlight', accent && `oc-accent--${accent}`]">
28
- <div>
29
- <span v-if="badge" class="oc-pill oc-pill--accent"><span class="oc-status-dot"></span>{{ badge }}</span>
30
- <h2 class="oc-spotlight__title">
31
- <span v-if="icon" class="oc-icon-tile oc-icon-tile--lg" aria-hidden="true">{{ icon }}</span>{{ title }}
32
- </h2>
33
- <p v-if="tagline" class="oc-spotlight__tagline">{{ tagline }}</p>
34
- <p v-if="lead" class="oc-lead">{{ lead }}</p>
35
- <slot name="cta">
36
- <a v-if="ctaLabel" class="oc-btn oc-btn--gradient oc-btn--lg" :href="ctaHref ?? '#'">{{ ctaLabel }}</a>
37
- </slot>
38
- </div>
39
- <ul v-if="modules?.length" class="oc-spotlight__modules">
40
- <li v-for="m in modules" :key="m.label">
41
- <span class="oc-icon-tile oc-icon-tile--sm" aria-hidden="true">{{ m.icon }}</span>{{ m.label }}
42
- </li>
43
- </ul>
44
- </div>
45
- </div>
46
- </section>
47
- </template>
1
+ <script setup lang="ts">
2
+ /**
3
+ * Highlighted flagship product: badge, big title with icon tile, tagline, copy, button and a module list.
4
+ * Slots: cta (default: a gradient link from `ctaLabel` / `ctaHref`). Classes: .oc-spotlight(__title/__tagline/__modules),
5
+ * .oc-accent--<name>, .oc-pill--accent, .oc-status-dot, .oc-icon-tile(--lg/--sm), .oc-lead
6
+ */
7
+ export interface SpotlightModule {
8
+ icon?: string
9
+ label: string
10
+ }
11
+ defineProps<{
12
+ accent?: string
13
+ badge?: string
14
+ icon?: string
15
+ title: string
16
+ tagline?: string
17
+ lead?: string
18
+ ctaLabel?: string
19
+ ctaHref?: string
20
+ modules?: SpotlightModule[]
21
+ }>()
22
+ </script>
23
+
24
+ <template>
25
+ <section class="oc-section-pad">
26
+ <div class="oc-container">
27
+ <div :class="['oc-spotlight', accent && `oc-accent--${accent}`]">
28
+ <div>
29
+ <span v-if="badge" class="oc-pill oc-pill--accent"><span class="oc-status-dot"></span>{{ badge }}</span>
30
+ <h2 class="oc-spotlight__title">
31
+ <span v-if="icon" class="oc-icon-tile oc-icon-tile--lg" aria-hidden="true">{{ icon }}</span>{{ title }}
32
+ </h2>
33
+ <p v-if="tagline" class="oc-spotlight__tagline">{{ tagline }}</p>
34
+ <p v-if="lead" class="oc-lead">{{ lead }}</p>
35
+ <slot name="cta">
36
+ <a v-if="ctaLabel" class="oc-btn oc-btn--gradient oc-btn--lg" :href="ctaHref ?? '#'">{{ ctaLabel }}</a>
37
+ </slot>
38
+ </div>
39
+ <ul v-if="modules?.length" class="oc-spotlight__modules">
40
+ <li v-for="m in modules" :key="m.label">
41
+ <span class="oc-icon-tile oc-icon-tile--sm" aria-hidden="true">{{ m.icon }}</span>{{ m.label }}
42
+ </li>
43
+ </ul>
44
+ </div>
45
+ </div>
46
+ </section>
47
+ </template>
@@ -1,17 +1,17 @@
1
- <script setup lang="ts">
2
- /** Key figures row. Classes: .oc-block-stats, -stat, -stat-value, -stat-label */
3
- export interface StatItem {
4
- value: string
5
- label: string
6
- }
7
- defineProps<{ items: StatItem[] }>()
8
- </script>
9
-
10
- <template>
11
- <div class="oc-block-stats">
12
- <div v-for="item in items" :key="item.label" class="oc-block-stat">
13
- <div class="oc-block-stat-value">{{ item.value }}</div>
14
- <div class="oc-block-stat-label">{{ item.label }}</div>
15
- </div>
16
- </div>
17
- </template>
1
+ <script setup lang="ts">
2
+ /** Key figures row. Classes: .oc-block-stats, -stat, -stat-value, -stat-label */
3
+ export interface StatItem {
4
+ value: string
5
+ label: string
6
+ }
7
+ defineProps<{ items: StatItem[] }>()
8
+ </script>
9
+
10
+ <template>
11
+ <div class="oc-block-stats">
12
+ <div v-for="item in items" :key="item.label" class="oc-block-stat">
13
+ <div class="oc-block-stat-value">{{ item.value }}</div>
14
+ <div class="oc-block-stat-label">{{ item.label }}</div>
15
+ </div>
16
+ </div>
17
+ </template>
@@ -1,20 +1,20 @@
1
- <script setup lang="ts">
2
- /** Key figures that count up when they scroll into view (CSS only). Classes: .oc-block-stats, -stat, -stat-value + .oc-counter, -stat-label */
3
- import OcCounter from '../components/OcCounter.vue'
4
-
5
- export interface CounterStat {
6
- to: number
7
- suffix?: string
8
- label: string
9
- }
10
- defineProps<{ items: CounterStat[] }>()
11
- </script>
12
-
13
- <template>
14
- <div class="oc-block-stats">
15
- <div v-for="item in items" :key="item.label" class="oc-block-stat">
16
- <OcCounter class="oc-block-stat-value" :to="item.to" :suffix="item.suffix" />
17
- <span class="oc-block-stat-label">{{ item.label }}</span>
18
- </div>
19
- </div>
20
- </template>
1
+ <script setup lang="ts">
2
+ /** Key figures that count up when they scroll into view (CSS only). Classes: .oc-block-stats, -stat, -stat-value + .oc-counter, -stat-label */
3
+ import OcCounter from '../components/OcCounter.vue'
4
+
5
+ export interface CounterStat {
6
+ to: number
7
+ suffix?: string
8
+ label: string
9
+ }
10
+ defineProps<{ items: CounterStat[] }>()
11
+ </script>
12
+
13
+ <template>
14
+ <div class="oc-block-stats">
15
+ <div v-for="item in items" :key="item.label" class="oc-block-stat">
16
+ <OcCounter class="oc-block-stat-value" :to="item.to" :suffix="item.suffix" />
17
+ <span class="oc-block-stat-label">{{ item.label }}</span>
18
+ </div>
19
+ </div>
20
+ </template>
@@ -1,53 +1,53 @@
1
- <script setup lang="ts">
2
- /**
3
- * Member rows with avatar, role badge and a row action menu (popover). Emits `action` ({ member, action }).
4
- * Slot `meta` (scoped: { member }) adds extra badges. Classes: .oc-block-team, -row, -meta, .oc-user, .oc-dropdown-menu
5
- */
6
- import { useUid } from '../composables/useUid'
7
-
8
- export interface TeamAction {
9
- label: string
10
- href?: string
11
- /** Draw a separator line before this action */
12
- separator?: boolean
13
- }
14
- export interface TeamMember {
15
- name: string
16
- email?: string
17
- initials?: string
18
- role?: string
19
- roleVariant?: 'default' | 'secondary' | 'outline' | 'destructive' | 'success' | 'warning' | 'info'
20
- actions?: TeamAction[]
21
- }
22
- defineProps<{ members: TeamMember[]; actionsLabel?: string }>()
23
- defineEmits<{ action: [payload: { member: TeamMember; action: TeamAction }] }>()
24
- const base = useUid('oc-team-menu')
25
- </script>
26
-
27
- <template>
28
- <div class="oc-block-team">
29
- <div v-for="(member, i) in members" :key="member.email ?? member.name" class="oc-block-team-row">
30
- <div class="oc-user">
31
- <span class="oc-avatar">{{ member.initials }}</span>
32
- <span class="oc-user-text">
33
- <span class="oc-user-name">{{ member.name }}</span>
34
- <span v-if="member.email" class="oc-user-email">{{ member.email }}</span>
35
- </span>
36
- </div>
37
- <div class="oc-block-team-meta">
38
- <span v-if="member.role" :class="['oc-badge', member.roleVariant && member.roleVariant !== 'default' && `oc-badge--${member.roleVariant}`]">{{ member.role }}</span>
39
- <slot name="meta" :member="member" />
40
- <template v-if="member.actions?.length">
41
- <button class="oc-btn oc-btn--ghost oc-btn--icon oc-btn--sm" type="button" :popovertarget="`${base}-${i}`" :aria-label="actionsLabel ?? 'Member actions'">&hellip;</button>
42
- <div :id="`${base}-${i}`" class="oc-dropdown-menu" popover>
43
- <template v-for="action in member.actions" :key="action.label">
44
- <div v-if="action.separator" class="oc-dropdown-separator"></div>
45
- <a v-if="action.href" class="oc-dropdown-item" :href="action.href" @click="$emit('action', { member, action })">{{ action.label }}</a>
46
- <button v-else class="oc-dropdown-item" type="button" @click="$emit('action', { member, action })">{{ action.label }}</button>
47
- </template>
48
- </div>
49
- </template>
50
- </div>
51
- </div>
52
- </div>
53
- </template>
1
+ <script setup lang="ts">
2
+ /**
3
+ * Member rows with avatar, role badge and a row action menu (popover). Emits `action` ({ member, action }).
4
+ * Slot `meta` (scoped: { member }) adds extra badges. Classes: .oc-block-team, -row, -meta, .oc-user, .oc-dropdown-menu
5
+ */
6
+ import { useUid } from '../composables/useUid'
7
+
8
+ export interface TeamAction {
9
+ label: string
10
+ href?: string
11
+ /** Draw a separator line before this action */
12
+ separator?: boolean
13
+ }
14
+ export interface TeamMember {
15
+ name: string
16
+ email?: string
17
+ initials?: string
18
+ role?: string
19
+ roleVariant?: 'default' | 'secondary' | 'outline' | 'destructive' | 'success' | 'warning' | 'info'
20
+ actions?: TeamAction[]
21
+ }
22
+ defineProps<{ members: TeamMember[]; actionsLabel?: string }>()
23
+ defineEmits<{ action: [payload: { member: TeamMember; action: TeamAction }] }>()
24
+ const base = useUid('oc-team-menu')
25
+ </script>
26
+
27
+ <template>
28
+ <div class="oc-block-team">
29
+ <div v-for="(member, i) in members" :key="member.email ?? member.name" class="oc-block-team-row">
30
+ <div class="oc-user">
31
+ <span class="oc-avatar">{{ member.initials }}</span>
32
+ <span class="oc-user-text">
33
+ <span class="oc-user-name">{{ member.name }}</span>
34
+ <span v-if="member.email" class="oc-user-email">{{ member.email }}</span>
35
+ </span>
36
+ </div>
37
+ <div class="oc-block-team-meta">
38
+ <span v-if="member.role" :class="['oc-badge', member.roleVariant && member.roleVariant !== 'default' && `oc-badge--${member.roleVariant}`]">{{ member.role }}</span>
39
+ <slot name="meta" :member="member" />
40
+ <template v-if="member.actions?.length">
41
+ <button class="oc-btn oc-btn--ghost oc-btn--icon oc-btn--sm" type="button" :popovertarget="`${base}-${i}`" :aria-label="actionsLabel ?? 'Member actions'">&hellip;</button>
42
+ <div :id="`${base}-${i}`" class="oc-dropdown-menu" popover>
43
+ <template v-for="action in member.actions" :key="action.label">
44
+ <div v-if="action.separator" class="oc-dropdown-separator"></div>
45
+ <a v-if="action.href" class="oc-dropdown-item" :href="action.href" @click="$emit('action', { member, action })">{{ action.label }}</a>
46
+ <button v-else class="oc-dropdown-item" type="button" @click="$emit('action', { member, action })">{{ action.label }}</button>
47
+ </template>
48
+ </div>
49
+ </template>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ </template>
@@ -1,61 +1,61 @@
1
- <script setup lang="ts">
2
- /**
3
- * Authenticator setup: QR, copyable key, OTP code and recovery codes. v-model = the typed code.
4
- * Emits `submit` with the code (form submit of the confirm step). Slot `qr` replaces the QR placeholder.
5
- * Classes: .oc-block-twofactor, -step, -center, -qr; reuses copy-field, otp, recovery-codes components.
6
- */
7
- import OcCopyField from '../components/OcCopyField.vue'
8
- import OcOtpInput from '../components/OcOtpInput.vue'
9
- import OcRecoveryCodes from '../components/OcRecoveryCodes.vue'
10
- import { useUid } from '../composables/useUid'
11
-
12
- withDefaults(
13
- defineProps<{
14
- setupKey: string
15
- recoveryCodes?: string[]
16
- length?: number
17
- scanTitle?: string
18
- scanText?: string
19
- confirmTitle?: string
20
- codeLabel?: string
21
- submitLabel?: string
22
- }>(),
23
- {
24
- length: 6,
25
- scanTitle: '1. Scan the QR code',
26
- scanText: 'Use an authenticator app, or enter the key manually.',
27
- confirmTitle: '2. Confirm with a code',
28
- codeLabel: 'Authentication code',
29
- submitLabel: 'Enable two-factor',
30
- },
31
- )
32
- defineEmits<{ submit: [code: string] }>()
33
- const code = defineModel<string>({ default: '' })
34
- const codeId = useUid('oc-twofactor-code')
35
- </script>
36
-
37
- <template>
38
- <div class="oc-block-twofactor">
39
- <section class="oc-block-twofactor-step">
40
- <div class="oc-heading oc-heading--sm">
41
- <h2 class="oc-heading-title">{{ scanTitle }}</h2>
42
- <p v-if="scanText" class="oc-heading-description">{{ scanText }}</p>
43
- </div>
44
- <div class="oc-block-twofactor-center">
45
- <slot name="qr"><div class="oc-block-twofactor-qr" role="img" aria-label="QR code">QR code</div></slot>
46
- <OcCopyField :value="setupKey" label="Setup key" />
47
- </div>
48
- </section>
49
- <section class="oc-block-twofactor-step">
50
- <div class="oc-heading oc-heading--sm"><h2 class="oc-heading-title">{{ confirmTitle }}</h2></div>
51
- <div class="oc-field">
52
- <label class="oc-field-label" :for="codeId">{{ codeLabel }}</label>
53
- <OcOtpInput :id="codeId" v-model="code" name="code" :length="length" />
54
- </div>
55
- <button class="oc-btn" type="submit" @click="$emit('submit', code)">{{ submitLabel }}</button>
56
- </section>
57
- <section v-if="recoveryCodes?.length" class="oc-block-twofactor-step">
58
- <OcRecoveryCodes :codes="recoveryCodes" />
59
- </section>
60
- </div>
61
- </template>
1
+ <script setup lang="ts">
2
+ /**
3
+ * Authenticator setup: QR, copyable key, OTP code and recovery codes. v-model = the typed code.
4
+ * Emits `submit` with the code (form submit of the confirm step). Slot `qr` replaces the QR placeholder.
5
+ * Classes: .oc-block-twofactor, -step, -center, -qr; reuses copy-field, otp, recovery-codes components.
6
+ */
7
+ import OcCopyField from '../components/OcCopyField.vue'
8
+ import OcOtpInput from '../components/OcOtpInput.vue'
9
+ import OcRecoveryCodes from '../components/OcRecoveryCodes.vue'
10
+ import { useUid } from '../composables/useUid'
11
+
12
+ withDefaults(
13
+ defineProps<{
14
+ setupKey: string
15
+ recoveryCodes?: string[]
16
+ length?: number
17
+ scanTitle?: string
18
+ scanText?: string
19
+ confirmTitle?: string
20
+ codeLabel?: string
21
+ submitLabel?: string
22
+ }>(),
23
+ {
24
+ length: 6,
25
+ scanTitle: '1. Scan the QR code',
26
+ scanText: 'Use an authenticator app, or enter the key manually.',
27
+ confirmTitle: '2. Confirm with a code',
28
+ codeLabel: 'Authentication code',
29
+ submitLabel: 'Enable two-factor',
30
+ },
31
+ )
32
+ defineEmits<{ submit: [code: string] }>()
33
+ const code = defineModel<string>({ default: '' })
34
+ const codeId = useUid('oc-twofactor-code')
35
+ </script>
36
+
37
+ <template>
38
+ <div class="oc-block-twofactor">
39
+ <section class="oc-block-twofactor-step">
40
+ <div class="oc-heading oc-heading--sm">
41
+ <h2 class="oc-heading-title">{{ scanTitle }}</h2>
42
+ <p v-if="scanText" class="oc-heading-description">{{ scanText }}</p>
43
+ </div>
44
+ <div class="oc-block-twofactor-center">
45
+ <slot name="qr"><div class="oc-block-twofactor-qr" role="img" aria-label="QR code">QR code</div></slot>
46
+ <OcCopyField :value="setupKey" label="Setup key" />
47
+ </div>
48
+ </section>
49
+ <section class="oc-block-twofactor-step">
50
+ <div class="oc-heading oc-heading--sm"><h2 class="oc-heading-title">{{ confirmTitle }}</h2></div>
51
+ <div class="oc-field">
52
+ <label class="oc-field-label" :for="codeId">{{ codeLabel }}</label>
53
+ <OcOtpInput :id="codeId" v-model="code" name="code" :length="length" />
54
+ </div>
55
+ <button class="oc-btn" type="submit" @click="$emit('submit', code)">{{ submitLabel }}</button>
56
+ </section>
57
+ <section v-if="recoveryCodes?.length" class="oc-block-twofactor-step">
58
+ <OcRecoveryCodes :codes="recoveryCodes" />
59
+ </section>
60
+ </div>
61
+ </template>