@birdycom/omniaui-vue 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.
- package/LICENSE +21 -0
- package/README.md +49 -3
- package/dist/blocks/OcBlockAboutTimeline.vue.d.ts +29 -0
- package/dist/blocks/OcBlockAppHeader.vue.d.ts +33 -0
- package/dist/blocks/OcBlockAppShell.vue.d.ts +33 -0
- package/dist/blocks/OcBlockAuth.vue.d.ts +28 -0
- package/dist/blocks/OcBlockAuthSplit.vue.d.ts +45 -0
- package/dist/blocks/OcBlockContactGrid.vue.d.ts +32 -0
- package/dist/blocks/OcBlockCta.vue.d.ts +17 -0
- package/dist/blocks/OcBlockDataTable.vue.d.ts +33 -0
- package/dist/blocks/OcBlockFaq.vue.d.ts +32 -0
- package/dist/blocks/OcBlockFeatures.vue.d.ts +25 -0
- package/dist/blocks/OcBlockFooter.vue.d.ts +27 -0
- package/dist/blocks/OcBlockFormPage.vue.d.ts +36 -0
- package/dist/blocks/OcBlockHero.vue.d.ts +18 -0
- package/dist/blocks/OcBlockHeroCode.vue.d.ts +32 -0
- package/dist/blocks/OcBlockHeroOrbit.vue.d.ts +36 -0
- package/dist/blocks/OcBlockHeroSplit.vue.d.ts +19 -0
- package/dist/blocks/OcBlockModuleHeader.vue.d.ts +24 -0
- package/dist/blocks/OcBlockPageHero.vue.d.ts +18 -0
- package/dist/blocks/OcBlockPortfolioGrid.vue.d.ts +34 -0
- package/dist/blocks/OcBlockPricing.vue.d.ts +38 -0
- package/dist/blocks/OcBlockProcess.vue.d.ts +18 -0
- package/dist/blocks/OcBlockProductGrid.vue.d.ts +25 -0
- package/dist/blocks/OcBlockProfileHeader.vue.d.ts +36 -0
- package/dist/blocks/OcBlockShowcase.vue.d.ts +23 -0
- package/dist/blocks/OcBlockSiteFooter.vue.d.ts +42 -0
- package/dist/blocks/OcBlockSiteHeader.vue.d.ts +32 -0
- package/dist/blocks/OcBlockSpotlight.vue.d.ts +32 -0
- package/dist/blocks/OcBlockStats.vue.d.ts +10 -0
- package/dist/blocks/OcBlockStatsCounter.vue.d.ts +10 -0
- package/dist/blocks/OcBlockTeamList.vue.d.ts +42 -0
- package/dist/blocks/OcBlockTwoFactor.vue.d.ts +38 -0
- package/dist/blocks/OcBlockWizardDialog.vue.d.ts +52 -0
- package/dist/components/OcAccordion.vue.d.ts +15 -0
- package/dist/components/OcAccordionAccent.vue.d.ts +20 -0
- package/dist/components/OcAccordionItem.vue.d.ts +24 -0
- package/dist/components/OcAffixInput.vue.d.ts +31 -0
- package/dist/components/OcAlert.vue.d.ts +21 -0
- package/dist/components/OcAlertDialog.vue.d.ts +48 -0
- package/dist/components/OcAlphaTabs.vue.d.ts +23 -0
- package/dist/components/OcAspectRatio.vue.d.ts +16 -0
- package/dist/components/OcAttachment.vue.d.ts +26 -0
- package/dist/components/OcAttachmentImage.vue.d.ts +10 -0
- package/dist/components/OcAttachmentList.vue.d.ts +31 -0
- package/dist/components/OcAttachmentThumb.vue.d.ts +16 -0
- package/dist/components/OcAvatar.vue.d.ts +21 -0
- package/dist/components/OcAvatarGroup.vue.d.ts +12 -0
- package/dist/components/OcBackLink.vue.d.ts +18 -0
- package/dist/components/OcBadge.vue.d.ts +18 -0
- package/dist/components/OcBarcodeInput.vue.d.ts +27 -0
- package/dist/components/OcBreadcrumb.vue.d.ts +24 -0
- package/dist/components/OcBrowserFrame.vue.d.ts +35 -0
- package/dist/components/OcBusyOverlay.vue.d.ts +30 -0
- package/dist/components/OcButton.vue.d.ts +31 -0
- package/dist/components/OcButtonGroup.vue.d.ts +17 -0
- package/dist/components/OcButtonGroupText.vue.d.ts +12 -0
- package/dist/components/OcCard.vue.d.ts +27 -0
- package/dist/components/OcChartLine.vue.d.ts +28 -0
- package/dist/components/OcChatComposer.vue.d.ts +33 -0
- package/dist/components/OcCheckbox.vue.d.ts +26 -0
- package/dist/components/OcChecklist.vue.d.ts +32 -0
- package/dist/components/OcChipFilter.vue.d.ts +24 -0
- package/dist/components/OcCollapsible.vue.d.ts +28 -0
- package/dist/components/OcColorField.vue.d.ts +17 -0
- package/dist/components/OcColorSelect.vue.d.ts +24 -0
- package/dist/components/OcColumnMenu.vue.d.ts +31 -0
- package/dist/components/OcCommand.vue.d.ts +28 -0
- package/dist/components/OcConfirmDialog.vue.d.ts +44 -0
- package/dist/components/OcCookieConsent.vue.d.ts +52 -0
- package/dist/components/OcCopyField.vue.d.ts +14 -0
- package/dist/components/OcCounter.vue.d.ts +9 -0
- package/dist/components/OcDataTable.vue.d.ts +37 -0
- package/dist/components/OcDecimalInput.vue.d.ts +19 -0
- package/dist/components/OcDefinitionList.vue.d.ts +34 -0
- package/dist/components/OcDocViewer.vue.d.ts +24 -0
- package/dist/components/OcDropdown.vue.d.ts +19 -0
- package/dist/components/OcDropdownItem.vue.d.ts +18 -0
- package/dist/components/OcDropdownLabel.vue.d.ts +12 -0
- package/dist/components/OcDropdownSeparator.vue.d.ts +2 -0
- package/dist/components/OcDropzone.vue.d.ts +29 -0
- package/dist/components/OcEmojiPicker.vue.d.ts +32 -0
- package/dist/components/OcEmptyState.vue.d.ts +24 -0
- package/dist/components/OcEntityCard.vue.d.ts +37 -0
- package/dist/components/OcFactList.vue.d.ts +29 -0
- package/dist/components/OcFilterCounts.vue.d.ts +25 -0
- package/dist/components/OcFlipCard.vue.d.ts +31 -0
- package/dist/components/OcFormField.vue.d.ts +26 -0
- package/dist/components/OcGreeting.vue.d.ts +26 -0
- package/dist/components/OcHeading.vue.d.ts +24 -0
- package/dist/components/OcHoverCard.vue.d.ts +22 -0
- package/dist/components/OcImageZoom.vue.d.ts +28 -0
- package/dist/components/OcInput.vue.d.ts +13 -0
- package/dist/components/OcInputGroup.vue.d.ts +21 -0
- package/dist/components/OcItem.vue.d.ts +39 -0
- package/dist/components/OcItemGroup.vue.d.ts +12 -0
- package/dist/components/OcItemSeparator.vue.d.ts +2 -0
- package/dist/components/OcKbd.vue.d.ts +12 -0
- package/dist/components/OcKbdGroup.vue.d.ts +17 -0
- package/dist/components/OcLabel.vue.d.ts +19 -0
- package/dist/components/OcLanguageSelect.vue.d.ts +32 -0
- package/dist/components/OcLauncherCard.vue.d.ts +26 -0
- package/dist/components/OcLightbox.vue.d.ts +45 -0
- package/dist/components/OcLinkArrow.vue.d.ts +23 -0
- package/dist/components/OcListToolbar.vue.d.ts +44 -0
- package/dist/components/OcMarquee.vue.d.ts +16 -0
- package/dist/components/OcMediaCard.vue.d.ts +24 -0
- package/dist/components/OcMediaRow.vue.d.ts +21 -0
- package/dist/components/OcMediaThumb.vue.d.ts +32 -0
- package/dist/components/OcMessage.vue.d.ts +63 -0
- package/dist/components/OcMessageList.vue.d.ts +35 -0
- package/dist/components/OcMessageThread.vue.d.ts +80 -0
- package/dist/components/OcModal.vue.d.ts +36 -0
- package/dist/components/OcNavmenu.vue.d.ts +24 -0
- package/dist/components/OcNavmenuList.vue.d.ts +29 -0
- package/dist/components/OcNextTeaser.vue.d.ts +29 -0
- package/dist/components/OcNumberInput.vue.d.ts +25 -0
- package/dist/components/OcOtpInput.vue.d.ts +19 -0
- package/dist/components/OcPageHeader.vue.d.ts +36 -0
- package/dist/components/OcPagination.vue.d.ts +20 -0
- package/dist/components/OcPasswordInput.vue.d.ts +18 -0
- package/dist/components/OcPasswordRequirements.vue.d.ts +19 -0
- package/dist/components/OcPhoneInput.vue.d.ts +25 -0
- package/dist/components/OcPopover.vue.d.ts +24 -0
- package/dist/components/OcPriceCard.vue.d.ts +41 -0
- package/dist/components/OcProductMark.vue.d.ts +25 -0
- package/dist/components/OcProgress.vue.d.ts +11 -0
- package/dist/components/OcProjectCard.vue.d.ts +35 -0
- package/dist/components/OcProse.vue.d.ts +25 -0
- package/dist/components/OcRadio.vue.d.ts +27 -0
- package/dist/components/OcRadioGroup.vue.d.ts +32 -0
- package/dist/components/OcRecoveryCodes.vue.d.ts +36 -0
- package/dist/components/OcScrollArea.vue.d.ts +18 -0
- package/dist/components/OcSegmented.vue.d.ts +21 -0
- package/dist/components/OcSelect.vue.d.ts +28 -0
- package/dist/components/OcSeparator.vue.d.ts +21 -0
- package/dist/components/OcSeverityCard.vue.d.ts +36 -0
- package/dist/components/OcSheet.vue.d.ts +37 -0
- package/dist/components/OcSidebar.vue.d.ts +28 -0
- package/dist/components/OcSidebarCollapsible.vue.d.ts +27 -0
- package/dist/components/OcSidebarGroup.vue.d.ts +16 -0
- package/dist/components/OcSidebarMenu.vue.d.ts +12 -0
- package/dist/components/OcSidebarMenuButton.vue.d.ts +21 -0
- package/dist/components/OcSidebarSeparator.vue.d.ts +2 -0
- package/dist/components/OcSkeleton.vue.d.ts +8 -0
- package/dist/components/OcSlider.vue.d.ts +18 -0
- package/dist/components/OcSortableRow.vue.d.ts +32 -0
- package/dist/components/OcSpinner.vue.d.ts +8 -0
- package/dist/components/OcStackCard.vue.d.ts +22 -0
- package/dist/components/OcStackList.vue.d.ts +28 -0
- package/dist/components/OcStatCard.vue.d.ts +25 -0
- package/dist/components/OcStepper.vue.d.ts +24 -0
- package/dist/components/OcSwitch.vue.d.ts +9 -0
- package/dist/components/OcTable.vue.d.ts +61 -0
- package/dist/components/OcTableActions.vue.d.ts +18 -0
- package/dist/components/OcTableCompact.vue.d.ts +37 -0
- package/dist/components/OcTabs.vue.d.ts +28 -0
- package/dist/components/OcTagInput.vue.d.ts +18 -0
- package/dist/components/OcTerminalLog.vue.d.ts +20 -0
- package/dist/components/OcTextarea.vue.d.ts +13 -0
- package/dist/components/OcThemeSwitch.vue.d.ts +20 -0
- package/dist/components/OcTimeInput.vue.d.ts +14 -0
- package/dist/components/OcTimeline.vue.d.ts +33 -0
- package/dist/components/OcToast.vue.d.ts +31 -0
- package/dist/components/OcToastContainer.vue.d.ts +8 -0
- package/dist/components/OcToggle.vue.d.ts +29 -0
- package/dist/components/OcToggleField.vue.d.ts +27 -0
- package/dist/components/OcToggleGroup.vue.d.ts +27 -0
- package/dist/components/OcTooltip.vue.d.ts +16 -0
- package/dist/components/OcTopProgress.vue.d.ts +18 -0
- package/dist/components/OcTree.vue.d.ts +40 -0
- package/dist/components/OcUpgradeBanner.vue.d.ts +41 -0
- package/dist/components/OcUser.vue.d.ts +20 -0
- package/dist/components/OcVersionBanner.vue.d.ts +32 -0
- package/dist/composables/chartLine.d.ts +6 -0
- package/dist/composables/keys.d.ts +19 -0
- package/dist/composables/useAttrsSplit.d.ts +14 -0
- package/dist/composables/useDialog.d.ts +9 -0
- package/dist/composables/useToast.d.ts +34 -0
- package/dist/composables/useUid.d.ts +5 -0
- package/dist/index.d.ts +233 -0
- package/dist/omniaui-vue.js +8811 -0
- package/dist/omniaui-vue.js.map +1 -0
- package/manifest.json +1036 -0
- package/package.json +69 -6
- package/src/blocks/OcBlockAboutTimeline.vue +44 -0
- package/src/blocks/OcBlockAppHeader.vue +36 -0
- package/src/blocks/OcBlockAppShell.vue +29 -0
- package/src/blocks/OcBlockAuth.vue +24 -0
- package/src/blocks/OcBlockAuthSplit.vue +47 -0
- package/src/blocks/OcBlockContactGrid.vue +53 -0
- package/src/blocks/OcBlockCta.vue +12 -0
- package/src/blocks/OcBlockDataTable.vue +27 -0
- package/src/blocks/OcBlockFaq.vue +49 -0
- package/src/blocks/OcBlockFeatures.vue +23 -0
- package/src/blocks/OcBlockFooter.vue +25 -0
- package/src/blocks/OcBlockFormPage.vue +24 -0
- package/src/blocks/OcBlockHero.vue +13 -0
- package/src/blocks/OcBlockHeroCode.vue +42 -0
- package/src/blocks/OcBlockHeroOrbit.vue +69 -0
- package/src/blocks/OcBlockHeroSplit.vue +15 -0
- package/src/blocks/OcBlockModuleHeader.vue +21 -0
- package/src/blocks/OcBlockPageHero.vue +13 -0
- package/src/blocks/OcBlockPortfolioGrid.vue +63 -0
- package/src/blocks/OcBlockPricing.vue +39 -0
- package/src/blocks/OcBlockProcess.vue +39 -0
- package/src/blocks/OcBlockProductGrid.vue +41 -0
- package/src/blocks/OcBlockProfileHeader.vue +50 -0
- package/src/blocks/OcBlockShowcase.vue +43 -0
- package/src/blocks/OcBlockSiteFooter.vue +54 -0
- package/src/blocks/OcBlockSiteHeader.vue +34 -0
- package/src/blocks/OcBlockSpotlight.vue +47 -0
- package/src/blocks/OcBlockStats.vue +17 -0
- package/src/blocks/OcBlockStatsCounter.vue +20 -0
- package/src/blocks/OcBlockTeamList.vue +53 -0
- package/src/blocks/OcBlockTwoFactor.vue +61 -0
- package/src/blocks/OcBlockWizardDialog.vue +67 -0
- package/src/components/OcAccordion.vue +12 -0
- package/src/components/OcAccordionAccent.vue +27 -0
- package/src/components/OcAccordionItem.vue +19 -0
- package/src/components/OcAffixInput.vue +40 -0
- package/src/components/OcAlert.vue +17 -0
- package/src/components/OcAlertDialog.vue +66 -0
- package/src/components/OcAlphaTabs.vue +54 -0
- package/src/components/OcAspectRatio.vue +21 -0
- package/src/components/OcAttachment.vue +59 -0
- package/src/components/OcAttachmentImage.vue +13 -0
- package/src/components/OcAttachmentList.vue +31 -0
- package/src/components/OcAttachmentThumb.vue +14 -0
- package/src/components/OcAvatar.vue +18 -0
- package/src/components/OcAvatarGroup.vue +7 -0
- package/src/components/OcBackLink.vue +8 -0
- package/src/components/OcBadge.vue +13 -0
- package/src/components/OcBarcodeInput.vue +51 -0
- package/src/components/OcBreadcrumb.vue +22 -0
- package/src/components/OcBrowserFrame.vue +33 -0
- package/src/components/OcBusyOverlay.vue +32 -0
- package/src/components/OcButton.vue +47 -0
- package/src/components/OcButtonGroup.vue +10 -0
- package/src/components/OcButtonGroupText.vue +7 -0
- package/src/components/OcCard.vue +20 -0
- package/src/components/OcChartLine.vue +80 -0
- package/src/components/OcChatComposer.vue +42 -0
- package/src/components/OcCheckbox.vue +26 -0
- package/src/components/OcChecklist.vue +29 -0
- package/src/components/OcChipFilter.vue +48 -0
- package/src/components/OcCollapsible.vue +19 -0
- package/src/components/OcColorField.vue +15 -0
- package/src/components/OcColorSelect.vue +33 -0
- package/src/components/OcColumnMenu.vue +50 -0
- package/src/components/OcCommand.vue +119 -0
- package/src/components/OcConfirmDialog.vue +65 -0
- package/src/components/OcCookieConsent.vue +119 -0
- package/src/components/OcCopyField.vue +37 -0
- package/src/components/OcCounter.vue +15 -0
- package/src/components/OcDataTable.vue +144 -0
- package/src/components/OcDecimalInput.vue +53 -0
- package/src/components/OcDefinitionList.vue +35 -0
- package/src/components/OcDocViewer.vue +79 -0
- package/src/components/OcDropdown.vue +23 -0
- package/src/components/OcDropdownItem.vue +9 -0
- package/src/components/OcDropdownLabel.vue +7 -0
- package/src/components/OcDropdownSeparator.vue +7 -0
- package/src/components/OcDropzone.vue +36 -0
- package/src/components/OcEmojiPicker.vue +45 -0
- package/src/components/OcEmptyState.vue +13 -0
- package/src/components/OcEntityCard.vue +47 -0
- package/src/components/OcFactList.vue +37 -0
- package/src/components/OcFilterCounts.vue +38 -0
- package/src/components/OcFlipCard.vue +36 -0
- package/src/components/OcFormField.vue +36 -0
- package/src/components/OcGreeting.vue +52 -0
- package/src/components/OcHeading.vue +19 -0
- package/src/components/OcHoverCard.vue +25 -0
- package/src/components/OcImageZoom.vue +39 -0
- package/src/components/OcInput.vue +9 -0
- package/src/components/OcInputGroup.vue +12 -0
- package/src/components/OcItem.vue +40 -0
- package/src/components/OcItemGroup.vue +7 -0
- package/src/components/OcItemSeparator.vue +7 -0
- package/src/components/OcKbd.vue +7 -0
- package/src/components/OcKbdGroup.vue +15 -0
- package/src/components/OcLabel.vue +10 -0
- package/src/components/OcLanguageSelect.vue +40 -0
- package/src/components/OcLauncherCard.vue +34 -0
- package/src/components/OcLightbox.vue +63 -0
- package/src/components/OcLinkArrow.vue +25 -0
- package/src/components/OcListToolbar.vue +44 -0
- package/src/components/OcMarquee.vue +36 -0
- package/src/components/OcMediaCard.vue +28 -0
- package/src/components/OcMediaRow.vue +28 -0
- package/src/components/OcMediaThumb.vue +38 -0
- package/src/components/OcMessage.vue +91 -0
- package/src/components/OcMessageList.vue +43 -0
- package/src/components/OcMessageThread.vue +155 -0
- package/src/components/OcModal.vue +42 -0
- package/src/components/OcNavmenu.vue +18 -0
- package/src/components/OcNavmenuList.vue +38 -0
- package/src/components/OcNextTeaser.vue +25 -0
- package/src/components/OcNumberInput.vue +47 -0
- package/src/components/OcOtpInput.vue +34 -0
- package/src/components/OcPageHeader.vue +34 -0
- package/src/components/OcPagination.vue +33 -0
- package/src/components/OcPasswordInput.vue +27 -0
- package/src/components/OcPasswordRequirements.vue +28 -0
- package/src/components/OcPhoneInput.vue +72 -0
- package/src/components/OcPopover.vue +25 -0
- package/src/components/OcPriceCard.vue +69 -0
- package/src/components/OcProductMark.vue +31 -0
- package/src/components/OcProgress.vue +21 -0
- package/src/components/OcProjectCard.vue +36 -0
- package/src/components/OcProse.vue +57 -0
- package/src/components/OcRadio.vue +40 -0
- package/src/components/OcRadioGroup.vue +32 -0
- package/src/components/OcRecoveryCodes.vue +55 -0
- package/src/components/OcScrollArea.vue +15 -0
- package/src/components/OcSegmented.vue +28 -0
- package/src/components/OcSelect.vue +21 -0
- package/src/components/OcSeparator.vue +18 -0
- package/src/components/OcSeverityCard.vue +46 -0
- package/src/components/OcSheet.vue +49 -0
- package/src/components/OcSidebar.vue +16 -0
- package/src/components/OcSidebarCollapsible.vue +19 -0
- package/src/components/OcSidebarGroup.vue +11 -0
- package/src/components/OcSidebarMenu.vue +7 -0
- package/src/components/OcSidebarMenuButton.vue +31 -0
- package/src/components/OcSidebarSeparator.vue +7 -0
- package/src/components/OcSkeleton.vue +8 -0
- package/src/components/OcSlider.vue +27 -0
- package/src/components/OcSortableRow.vue +40 -0
- package/src/components/OcSpinner.vue +13 -0
- package/src/components/OcStackCard.vue +24 -0
- package/src/components/OcStackList.vue +31 -0
- package/src/components/OcStatCard.vue +39 -0
- package/src/components/OcStepper.vue +34 -0
- package/src/components/OcSwitch.vue +15 -0
- package/src/components/OcTable.vue +115 -0
- package/src/components/OcTableActions.vue +26 -0
- package/src/components/OcTableCompact.vue +46 -0
- package/src/components/OcTabs.vue +37 -0
- package/src/components/OcTagInput.vue +50 -0
- package/src/components/OcTerminalLog.vue +50 -0
- package/src/components/OcTextarea.vue +9 -0
- package/src/components/OcThemeSwitch.vue +31 -0
- package/src/components/OcTimeInput.vue +50 -0
- package/src/components/OcTimeline.vue +36 -0
- package/src/components/OcToast.vue +31 -0
- package/src/components/OcToastContainer.vue +21 -0
- package/src/components/OcToggle.vue +63 -0
- package/src/components/OcToggleField.vue +28 -0
- package/src/components/OcToggleGroup.vue +40 -0
- package/src/components/OcTooltip.vue +8 -0
- package/src/components/OcTopProgress.vue +54 -0
- package/src/components/OcTree.vue +70 -0
- package/src/components/OcUpgradeBanner.vue +42 -0
- package/src/components/OcUser.vue +25 -0
- package/src/components/OcVersionBanner.vue +34 -0
- package/src/composables/chartLine.ts +28 -0
- package/src/composables/keys.ts +22 -0
- package/src/composables/useAttrsSplit.ts +16 -0
- package/src/composables/useDialog.ts +21 -0
- package/src/composables/useToast.ts +66 -0
- package/src/composables/useUid.ts +12 -0
- package/src/index.ts +589 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/** Page header (the oc-hero used on every docs page): eyebrow, title, text, actions. Classes: .oc-hero, -eyebrow, -title, -text, -actions */
|
|
3
|
+
defineProps<{ eyebrow?: string; title: string; text?: string }>()
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<template>
|
|
7
|
+
<section class="oc-hero">
|
|
8
|
+
<span v-if="eyebrow" class="oc-hero-eyebrow">{{ eyebrow }}</span>
|
|
9
|
+
<h1 class="oc-hero-title">{{ title }}</h1>
|
|
10
|
+
<p v-if="text" class="oc-hero-text">{{ text }}</p>
|
|
11
|
+
<div v-if="$slots.actions" class="oc-hero-actions"><slot name="actions" /></div>
|
|
12
|
+
</section>
|
|
13
|
+
</template>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<!-- File: packages/vue/src/blocks/OcBlockPortfolioGrid.vue | Map: props -> head (title, lead, link slot) -> grid of OcProjectCard -->
|
|
2
|
+
<script setup lang="ts">
|
|
3
|
+
/**
|
|
4
|
+
* Portfolio section: heading, lead, "all projects" link and a grid of project cards.
|
|
5
|
+
* `title` + `highlight` (gradient word). Slots: link, default (own cards). Classes: .oc-block-portfolio (--two), -head, -lead, -grid
|
|
6
|
+
*/
|
|
7
|
+
import OcProjectCard from '../components/OcProjectCard.vue'
|
|
8
|
+
import { useUid } from '../composables/useUid'
|
|
9
|
+
|
|
10
|
+
export interface PortfolioGridProject {
|
|
11
|
+
href: string
|
|
12
|
+
name: string
|
|
13
|
+
type?: string
|
|
14
|
+
meta?: string
|
|
15
|
+
more?: string
|
|
16
|
+
image?: string
|
|
17
|
+
imageAlt?: string
|
|
18
|
+
accent?: string
|
|
19
|
+
}
|
|
20
|
+
withDefaults(
|
|
21
|
+
defineProps<{
|
|
22
|
+
eyebrow?: string
|
|
23
|
+
title?: string
|
|
24
|
+
highlight?: string
|
|
25
|
+
lead?: string
|
|
26
|
+
projects?: PortfolioGridProject[]
|
|
27
|
+
two?: boolean
|
|
28
|
+
}>(),
|
|
29
|
+
{ projects: () => [] },
|
|
30
|
+
)
|
|
31
|
+
const titleId = useUid('oc-portfolio-title')
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<section :class="['oc-block-portfolio oc-section-pad', two && 'oc-block-portfolio--two']" :aria-labelledby="titleId">
|
|
36
|
+
<div class="oc-container">
|
|
37
|
+
<div class="oc-block-portfolio-head">
|
|
38
|
+
<div>
|
|
39
|
+
<p v-if="eyebrow" class="oc-eyebrow">{{ eyebrow }}</p>
|
|
40
|
+
<h2 :id="titleId" class="oc-display oc-display--md">{{ title }} <span v-if="highlight" class="oc-text-gradient">{{ highlight }}</span></h2>
|
|
41
|
+
<p v-if="lead" class="oc-block-portfolio-lead">{{ lead }}</p>
|
|
42
|
+
</div>
|
|
43
|
+
<slot name="link" />
|
|
44
|
+
</div>
|
|
45
|
+
<div class="oc-block-portfolio-grid">
|
|
46
|
+
<slot>
|
|
47
|
+
<OcProjectCard
|
|
48
|
+
v-for="(p, i) in projects"
|
|
49
|
+
:key="i"
|
|
50
|
+
:class="p.accent && `oc-accent--${p.accent}`"
|
|
51
|
+
:href="p.href"
|
|
52
|
+
:name="p.name"
|
|
53
|
+
:type="p.type"
|
|
54
|
+
:meta="p.meta"
|
|
55
|
+
:more="p.more ?? 'View project'"
|
|
56
|
+
:image="p.image"
|
|
57
|
+
:image-alt="p.imageAlt"
|
|
58
|
+
/>
|
|
59
|
+
</slot>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</section>
|
|
63
|
+
</template>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Pricing cards with a featured plan. Emits `select` with the plan when its button is clicked.
|
|
4
|
+
* Slot `action` (scoped: { plan }) replaces the button. Classes: .oc-block-pricing, -grid, -card(--featured),
|
|
5
|
+
* -name, -desc, -price, -features
|
|
6
|
+
*/
|
|
7
|
+
export interface PricingPlan {
|
|
8
|
+
name: string
|
|
9
|
+
description?: string
|
|
10
|
+
price: string
|
|
11
|
+
/** e.g. "/month" */
|
|
12
|
+
period?: string
|
|
13
|
+
features: string[]
|
|
14
|
+
cta: string
|
|
15
|
+
featured?: boolean
|
|
16
|
+
}
|
|
17
|
+
defineProps<{ title?: string; description?: string; plans: PricingPlan[] }>()
|
|
18
|
+
defineEmits<{ select: [plan: PricingPlan] }>()
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<template>
|
|
22
|
+
<div class="oc-block-pricing">
|
|
23
|
+
<h2 v-if="title">{{ title }}</h2>
|
|
24
|
+
<p v-if="description">{{ description }}</p>
|
|
25
|
+
<div class="oc-block-pricing-grid">
|
|
26
|
+
<div v-for="plan in plans" :key="plan.name" :class="['oc-block-pricing-card', plan.featured && 'oc-block-pricing-card--featured']">
|
|
27
|
+
<p class="oc-block-pricing-name">{{ plan.name }}</p>
|
|
28
|
+
<p v-if="plan.description" class="oc-block-pricing-desc">{{ plan.description }}</p>
|
|
29
|
+
<p class="oc-block-pricing-price">{{ plan.price }} <span v-if="plan.period">{{ plan.period }}</span></p>
|
|
30
|
+
<ul class="oc-block-pricing-features">
|
|
31
|
+
<li v-for="f in plan.features" :key="f">{{ f }}</li>
|
|
32
|
+
</ul>
|
|
33
|
+
<slot name="action" :plan="plan">
|
|
34
|
+
<button :class="['oc-btn', !plan.featured && 'oc-btn--outline']" type="button" style="width: 100%" @click="$emit('select', plan)">{{ plan.cta }}</button>
|
|
35
|
+
</slot>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</template>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Numbered steps (CSS counter) + an endless marquee of technologies (the list is rendered twice, the copy aria-hidden).
|
|
4
|
+
* Classes: .oc-section-pad, .oc-container, .oc-eyebrow, .oc-display(--md), .oc-text-gradient, .oc-steps, .oc-marquee
|
|
5
|
+
*/
|
|
6
|
+
export interface ProcessStep {
|
|
7
|
+
title: string
|
|
8
|
+
text: string
|
|
9
|
+
}
|
|
10
|
+
defineProps<{
|
|
11
|
+
eyebrow?: string
|
|
12
|
+
title?: string
|
|
13
|
+
highlight?: string
|
|
14
|
+
steps: ProcessStep[]
|
|
15
|
+
marquee?: string[]
|
|
16
|
+
marqueeLabel?: string
|
|
17
|
+
}>()
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<section class="oc-section-pad">
|
|
22
|
+
<div class="oc-container">
|
|
23
|
+
<p v-if="eyebrow" class="oc-eyebrow">{{ eyebrow }}</p>
|
|
24
|
+
<h2 class="oc-display oc-display--md">{{ title }} <span v-if="highlight" class="oc-text-gradient">{{ highlight }}</span></h2>
|
|
25
|
+
<ol class="oc-steps">
|
|
26
|
+
<li v-for="step in steps" :key="step.title">
|
|
27
|
+
<h3>{{ step.title }}</h3>
|
|
28
|
+
<p>{{ step.text }}</p>
|
|
29
|
+
</li>
|
|
30
|
+
</ol>
|
|
31
|
+
<div v-if="marquee?.length" class="oc-marquee mt-4" :aria-label="marqueeLabel">
|
|
32
|
+
<div class="oc-marquee__track">
|
|
33
|
+
<span v-for="item in marquee" :key="item" class="oc-marquee__item">{{ item }}</span>
|
|
34
|
+
<span v-for="item in marquee" :key="'copy-' + item" class="oc-marquee__item" aria-hidden="true">{{ item }}</span>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</section>
|
|
39
|
+
</template>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Section title + grid of product cards, each with its own accent color (oc-accent--green|orange|violet|cyan...).
|
|
4
|
+
* Classes: .oc-card-grid, .oc-product-card, -top, -name, -tagline, -summary, -more, .oc-icon-tile, .oc-pill
|
|
5
|
+
*/
|
|
6
|
+
export interface ProductItem {
|
|
7
|
+
name: string
|
|
8
|
+
tagline?: string
|
|
9
|
+
summary?: string
|
|
10
|
+
/** Pill text, e.g. "Own product" */
|
|
11
|
+
tag?: string
|
|
12
|
+
/** Glyph for the icon tile */
|
|
13
|
+
icon?: string
|
|
14
|
+
/** Accent name: green, orange, violet, cyan, ... */
|
|
15
|
+
accent?: string
|
|
16
|
+
href?: string
|
|
17
|
+
more?: string
|
|
18
|
+
}
|
|
19
|
+
defineProps<{ eyebrow?: string; title?: string; highlight?: string; products: ProductItem[] }>()
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<section class="oc-section-pad">
|
|
24
|
+
<div class="oc-container">
|
|
25
|
+
<p v-if="eyebrow" class="oc-eyebrow">{{ eyebrow }}</p>
|
|
26
|
+
<h2 class="oc-display oc-display--md">{{ title }} <span v-if="highlight" class="oc-text-gradient">{{ highlight }}</span></h2>
|
|
27
|
+
<div class="oc-card-grid">
|
|
28
|
+
<a v-for="p in products" :key="p.name" :class="['oc-product-card', p.accent && `oc-accent--${p.accent}`]" :href="p.href ?? '#'">
|
|
29
|
+
<div class="oc-product-card__top">
|
|
30
|
+
<span class="oc-icon-tile" aria-hidden="true">{{ p.icon }}</span>
|
|
31
|
+
<span v-if="p.tag" class="oc-pill">{{ p.tag }}</span>
|
|
32
|
+
</div>
|
|
33
|
+
<h3 class="oc-product-card__name">{{ p.name }}</h3>
|
|
34
|
+
<p v-if="p.tagline" class="oc-product-card__tagline">{{ p.tagline }}</p>
|
|
35
|
+
<p v-if="p.summary" class="oc-product-card__summary">{{ p.summary }}</p>
|
|
36
|
+
<span v-if="p.more" class="oc-product-card__more">{{ p.more }}</span>
|
|
37
|
+
</a>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</section>
|
|
41
|
+
</template>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<!-- File: packages/vue/src/blocks/OcBlockProfileHeader.vue | Map: props -> banner -> bar (avatar slot, info, actions slot) -> tabs -->
|
|
2
|
+
<script setup lang="ts">
|
|
3
|
+
/**
|
|
4
|
+
* Profile / channel header: banner, overhanging avatar, name, meta, bio, actions and link tabs.
|
|
5
|
+
* Slots: avatar (initials or <img>), actions, bio. Classes: .oc-block-profile (--compact), -banner, -bar, -avatar,
|
|
6
|
+
* -info, -name, -meta, -bio, -actions, -tabs, -tab (aria-current="page")
|
|
7
|
+
*/
|
|
8
|
+
import { computed } from 'vue'
|
|
9
|
+
import { useUid } from '../composables/useUid'
|
|
10
|
+
|
|
11
|
+
export interface ProfileHeaderTab {
|
|
12
|
+
label: string
|
|
13
|
+
href: string
|
|
14
|
+
current?: boolean
|
|
15
|
+
}
|
|
16
|
+
const props = withDefaults(
|
|
17
|
+
defineProps<{
|
|
18
|
+
name: string
|
|
19
|
+
meta?: string
|
|
20
|
+
bio?: string
|
|
21
|
+
initials?: string
|
|
22
|
+
banner?: string
|
|
23
|
+
tabs?: ProfileHeaderTab[]
|
|
24
|
+
tabsLabel?: string
|
|
25
|
+
compact?: boolean
|
|
26
|
+
headingLevel?: 1 | 2
|
|
27
|
+
}>(),
|
|
28
|
+
{ tabs: () => [], tabsLabel: 'Profile sections', headingLevel: 1 },
|
|
29
|
+
)
|
|
30
|
+
const nameId = useUid('oc-profile-name')
|
|
31
|
+
const bannerStyle = computed(() => (props.banner ? `--oc-profile-banner: url("${props.banner}")` : undefined))
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<section :class="['oc-block-profile', compact && 'oc-block-profile--compact']" :aria-labelledby="nameId">
|
|
36
|
+
<div class="oc-block-profile-banner" :style="bannerStyle" aria-hidden="true"></div>
|
|
37
|
+
<div class="oc-block-profile-bar">
|
|
38
|
+
<span class="oc-avatar oc-block-profile-avatar" aria-hidden="true"><slot name="avatar">{{ initials }}</slot></span>
|
|
39
|
+
<div class="oc-block-profile-info">
|
|
40
|
+
<component :is="headingLevel === 1 ? 'h1' : 'h2'" :id="nameId" class="oc-block-profile-name">{{ name }}</component>
|
|
41
|
+
<p v-if="meta" class="oc-block-profile-meta">{{ meta }}</p>
|
|
42
|
+
<p v-if="bio || $slots.bio" class="oc-block-profile-bio"><slot name="bio">{{ bio }}</slot></p>
|
|
43
|
+
</div>
|
|
44
|
+
<div v-if="$slots.actions" class="oc-block-profile-actions"><slot name="actions" /></div>
|
|
45
|
+
</div>
|
|
46
|
+
<nav v-if="tabs.length" class="oc-block-profile-tabs" :aria-label="tabsLabel">
|
|
47
|
+
<a v-for="(tab, i) in tabs" :key="i" class="oc-block-profile-tab" :href="tab.href" :aria-current="tab.current ? 'page' : undefined">{{ tab.label }}</a>
|
|
48
|
+
</nav>
|
|
49
|
+
</section>
|
|
50
|
+
</template>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Portfolio grid: project cards with a browser frame around the screenshot.
|
|
4
|
+
* `background` is any CSS background (use Omnia tokens, e.g. linear-gradient(135deg, var(--color-green-40), var(--color-teal-80))); `image` shows an img.
|
|
5
|
+
* Classes: .oc-card-grid, .oc-product-card, .oc-browser-frame(__bar/__body), .oc-pill--accent
|
|
6
|
+
*/
|
|
7
|
+
export interface ShowcaseProject {
|
|
8
|
+
name: string
|
|
9
|
+
summary?: string
|
|
10
|
+
tag?: string
|
|
11
|
+
accent?: string
|
|
12
|
+
href?: string
|
|
13
|
+
background?: string
|
|
14
|
+
image?: string
|
|
15
|
+
more?: string
|
|
16
|
+
}
|
|
17
|
+
defineProps<{ eyebrow?: string; title?: string; highlight?: string; projects: ShowcaseProject[] }>()
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<section class="oc-section-pad">
|
|
22
|
+
<div class="oc-container">
|
|
23
|
+
<p v-if="eyebrow" class="oc-eyebrow">{{ eyebrow }}</p>
|
|
24
|
+
<h2 class="oc-display oc-display--md">{{ title }} <span v-if="highlight" class="oc-text-gradient">{{ highlight }}</span></h2>
|
|
25
|
+
<div class="oc-card-grid" style="--oc-card-min: 26rem">
|
|
26
|
+
<a v-for="p in projects" :key="p.name" :class="['oc-product-card', p.accent && `oc-accent--${p.accent}`, 'p-0 overflow-hidden']" :href="p.href ?? '#'">
|
|
27
|
+
<span class="oc-browser-frame m-1">
|
|
28
|
+
<span class="oc-browser-frame__bar"><i></i><i></i><i></i></span>
|
|
29
|
+
<span class="oc-browser-frame__body" :style="p.background ? { background: p.background } : undefined">
|
|
30
|
+
<img v-if="p.image" :src="p.image" alt="" />
|
|
31
|
+
</span>
|
|
32
|
+
</span>
|
|
33
|
+
<span class="grid gap-0.5 p-1.5 pt-0">
|
|
34
|
+
<span v-if="p.tag" class="oc-pill oc-pill--accent">{{ p.tag }}</span>
|
|
35
|
+
<span class="oc-product-card__name">{{ p.name }}</span>
|
|
36
|
+
<span v-if="p.summary" class="oc-product-card__summary">{{ p.summary }}</span>
|
|
37
|
+
<span v-if="p.more" class="oc-product-card__more">{{ p.more }}</span>
|
|
38
|
+
</span>
|
|
39
|
+
</a>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</section>
|
|
43
|
+
</template>
|
|
@@ -0,0 +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>
|
|
@@ -0,0 +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">☰</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>
|
|
@@ -0,0 +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>
|
|
@@ -0,0 +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>
|
|
@@ -0,0 +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>
|
|
@@ -0,0 +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'">…</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>
|
|
@@ -0,0 +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>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Modal wizard: stepper rail on the left, step content and a Back / Next footer.
|
|
4
|
+
* v-model:open opens the dialog, v-model:step is the active step index. Emits `finish` on the last step's button.
|
|
5
|
+
* Slots: step-<index> (or default, scoped: { step, index }) for the content of each step.
|
|
6
|
+
* Classes: dialog.oc-modal > .oc-modal-content--xl, .oc-block-wizard(-rail/-main/-step), .oc-stepper, .oc-modal-footer
|
|
7
|
+
*/
|
|
8
|
+
import { computed, ref } from 'vue'
|
|
9
|
+
import OcStepper from '../components/OcStepper.vue'
|
|
10
|
+
import { useDialog } from '../composables/useDialog'
|
|
11
|
+
import { useUid } from '../composables/useUid'
|
|
12
|
+
|
|
13
|
+
const props = withDefaults(
|
|
14
|
+
defineProps<{
|
|
15
|
+
steps: { label: string }[]
|
|
16
|
+
backLabel?: string
|
|
17
|
+
nextLabel?: string
|
|
18
|
+
finishLabel?: string
|
|
19
|
+
stepsLabel?: string
|
|
20
|
+
/** Text for "Step 2 of 3"; receives the 1-based index and the count */
|
|
21
|
+
stepText?: (index: number, total: number) => string
|
|
22
|
+
}>(),
|
|
23
|
+
{ backLabel: 'Back', nextLabel: 'Next', finishLabel: 'Finish', stepsLabel: 'Setup steps' },
|
|
24
|
+
)
|
|
25
|
+
const emit = defineEmits<{ finish: [] }>()
|
|
26
|
+
const open = defineModel<boolean>('open', { default: false })
|
|
27
|
+
const step = defineModel<number>('step', { default: 0 })
|
|
28
|
+
const el = ref<HTMLDialogElement | null>(null)
|
|
29
|
+
const { onClose } = useDialog(open, el)
|
|
30
|
+
const titleId = useUid('oc-wizard-title')
|
|
31
|
+
const last = computed(() => step.value >= props.steps.length - 1)
|
|
32
|
+
const description = computed(() => (props.stepText ?? ((i, n) => `Step ${i} of ${n}`))(step.value + 1, props.steps.length))
|
|
33
|
+
|
|
34
|
+
function next() {
|
|
35
|
+
if (last.value) {
|
|
36
|
+
emit('finish')
|
|
37
|
+
open.value = false
|
|
38
|
+
} else {
|
|
39
|
+
step.value++
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<template>
|
|
45
|
+
<dialog ref="el" class="oc-modal" closedby="closerequest" :aria-labelledby="titleId" @close="onClose">
|
|
46
|
+
<div class="oc-modal-content oc-modal-content--xl">
|
|
47
|
+
<div class="oc-block-wizard">
|
|
48
|
+
<div class="oc-block-wizard-rail">
|
|
49
|
+
<OcStepper v-model="step" :steps="steps" :label="stepsLabel" />
|
|
50
|
+
</div>
|
|
51
|
+
<div class="oc-block-wizard-main">
|
|
52
|
+
<div class="oc-modal-header">
|
|
53
|
+
<h2 :id="titleId" class="oc-modal-title">{{ steps[step]?.label }}</h2>
|
|
54
|
+
<p class="oc-modal-description">{{ description }}</p>
|
|
55
|
+
</div>
|
|
56
|
+
<div class="oc-block-wizard-step">
|
|
57
|
+
<slot :name="`step-${step}`" :step="steps[step]" :index="step"><slot :step="steps[step]" :index="step" /></slot>
|
|
58
|
+
</div>
|
|
59
|
+
<div class="oc-modal-footer">
|
|
60
|
+
<button class="oc-btn oc-btn--outline" type="button" :disabled="step === 0" @click="step--">{{ backLabel }}</button>
|
|
61
|
+
<button class="oc-btn" type="button" @click="next">{{ last ? finishLabel : nextLabel }}</button>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</dialog>
|
|
67
|
+
</template>
|