@nuxtseo/design-system 0.0.0-stage → 0.1.0
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/README.md +101 -2
- package/app/app.config.ts +596 -0
- package/app/component-attributes.d.ts +8 -0
- package/app/components/README.md +38 -0
- package/app/components/brand/UiBrandMark.vue +63 -0
- package/app/components/brand/UiModuleIcon.vue +45 -0
- package/app/components/brand/UiProLettering.vue +26 -0
- package/app/components/brand/UiRangeTerrain.vue +311 -0
- package/app/components/brand/range-glyphs.ts +18 -0
- package/app/components/container/BrowserTab.vue +145 -0
- package/app/components/container/IntegrationRow.vue +120 -0
- package/app/components/container/KnowDoRails.vue +40 -0
- package/app/components/container/RailPanel.vue +93 -0
- package/app/components/container/UiAlert.vue +120 -0
- package/app/components/container/UiAppShell.vue +165 -0
- package/app/components/container/UiCard.vue +204 -0
- package/app/components/container/UiDisclosure.vue +43 -0
- package/app/components/container/UiEmptyState.vue +102 -0
- package/app/components/container/UiErrorState.vue +61 -0
- package/app/components/container/UiLoadingState.vue +20 -0
- package/app/components/container/UiPageHeader.vue +95 -0
- package/app/components/container/UiPopover.vue +102 -0
- package/app/components/container/UiSampleDataOverlay.vue +47 -0
- package/app/components/container/UiSectionHeader.vue +83 -0
- package/app/components/container/UiSummaryStrip.vue +40 -0
- package/app/components/container/UiToast.vue +230 -0
- package/app/components/container/UiToaster.vue +271 -0
- package/app/components/container/UiWidgetState.vue +143 -0
- package/app/components/container/ui-nav-drawer.ts +48 -0
- package/app/components/data/ActionRail.vue +152 -0
- package/app/components/data/FacetStrip.vue +93 -0
- package/app/components/data/UiBarCell.vue +37 -0
- package/app/components/data/UiBarChart.vue +281 -0
- package/app/components/data/UiChartAnnotationControls.vue +74 -0
- package/app/components/data/UiChartAnnotations.vue +163 -0
- package/app/components/data/UiChartBrushOverlay.vue +96 -0
- package/app/components/data/UiChartDataReveal.vue +81 -0
- package/app/components/data/UiChartFrame.vue +123 -0
- package/app/components/data/UiChartTooltip.vue +81 -0
- package/app/components/data/UiCoverageNote.vue +90 -0
- package/app/components/data/UiCwvSparkline.vue +188 -0
- package/app/components/data/UiDataList.vue +276 -0
- package/app/components/data/UiDataTableSection.vue +232 -0
- package/app/components/data/UiDistributionBars.vue +164 -0
- package/app/components/data/UiDonutChart.vue +132 -0
- package/app/components/data/UiDoorwayColumn.vue +108 -0
- package/app/components/data/UiDoorwayGrid.vue +58 -0
- package/app/components/data/UiDoorwayRow.vue +83 -0
- package/app/components/data/UiEntitySummary.vue +261 -0
- package/app/components/data/UiFactsGrid.vue +107 -0
- package/app/components/data/UiImpactMeter.vue +33 -0
- package/app/components/data/UiIssueRow.vue +149 -0
- package/app/components/data/UiLineChart.vue +431 -0
- package/app/components/data/UiMetricBarPopover.vue +121 -0
- package/app/components/data/UiMetricLabel.vue +30 -0
- package/app/components/data/UiMetricStat.vue +73 -0
- package/app/components/data/UiMetricToggle.vue +156 -0
- package/app/components/data/UiMetricsRow.vue +64 -0
- package/app/components/data/UiPositionMetric.vue +53 -0
- package/app/components/data/UiRelatedFixes.vue +113 -0
- package/app/components/data/UiRichText.vue +325 -0
- package/app/components/data/UiScatterPlot.vue +144 -0
- package/app/components/data/UiSeverityMarker.vue +30 -0
- package/app/components/data/UiSparkColumns.vue +160 -0
- package/app/components/data/UiSparkline.vue +681 -0
- package/app/components/data/UiStat.vue +445 -0
- package/app/components/data/UiStats.vue +76 -0
- package/app/components/data/UiTable.vue +517 -0
- package/app/components/data/UiTableExport.vue +40 -0
- package/app/components/data/UiTableFrame.vue +149 -0
- package/app/components/data/UiTablePagination.vue +37 -0
- package/app/components/data/UiTableShell.vue +48 -0
- package/app/components/data/UiTableTd.vue +39 -0
- package/app/components/data/UiTableTh.vue +61 -0
- package/app/components/data/UiTopEntityStackChart.vue +393 -0
- package/app/components/data/cells/UiTableDash.vue +3 -0
- package/app/components/data/cells/UiTableHeaderCell.vue +72 -0
- package/app/components/data/cells/UiTableMetricCell.vue +72 -0
- package/app/components/data/cells/UiTablePathCell.vue +76 -0
- package/app/components/data/cells/UiTableScoreTile.vue +49 -0
- package/app/components/data/cells/UiTableTrendCell.vue +41 -0
- package/app/components/element/UiAtmosphere.vue +64 -0
- package/app/components/element/UiAuthHeading.vue +24 -0
- package/app/components/element/UiAuthProviders.vue +46 -0
- package/app/components/element/UiBrandIcon.vue +39 -0
- package/app/components/element/UiButton.vue +549 -0
- package/app/components/element/UiCelebration.vue +65 -0
- package/app/components/element/UiChannelChips.vue +62 -0
- package/app/components/element/UiChatQuickLink.vue +319 -0
- package/app/components/element/UiChip.vue +101 -0
- package/app/components/element/UiConfirmDialog.vue +84 -0
- package/app/components/element/UiCopyButton.vue +90 -0
- package/app/components/element/UiDitherAvatar.vue +177 -0
- package/app/components/element/UiDotLabel.vue +19 -0
- package/app/components/element/UiEjectMenu.vue +181 -0
- package/app/components/element/UiEjectOverlay.vue +29 -0
- package/app/components/element/UiFavicon.vue +235 -0
- package/app/components/element/UiFaviconStack.vue +84 -0
- package/app/components/element/UiFilterMenu.vue +324 -0
- package/app/components/element/UiFocusedSurface.vue +129 -0
- package/app/components/element/UiHealthDot.vue +32 -0
- package/app/components/element/UiHelpLabel.vue +28 -0
- package/app/components/element/UiIcon.vue +22 -0
- package/app/components/element/UiInput.vue +35 -0
- package/app/components/element/UiLogoPlausible.vue +12 -0
- package/app/components/element/UiLogoPro.vue +25 -0
- package/app/components/element/UiLogoUmami.vue +12 -0
- package/app/components/element/UiNavIcon.vue +107 -0
- package/app/components/element/UiNavList.vue +156 -0
- package/app/components/element/UiOnboardingAnswers.vue +125 -0
- package/app/components/element/UiOverflowCount.vue +31 -0
- package/app/components/element/UiProBadge.vue +19 -0
- package/app/components/element/UiProgressCircle.vue +79 -0
- package/app/components/element/UiProgressPercent.vue +35 -0
- package/app/components/element/UiRelativeTime.vue +58 -0
- package/app/components/element/UiScrollFade.vue +16 -0
- package/app/components/element/UiSelect.vue +55 -0
- package/app/components/element/UiSeverityDot.vue +27 -0
- package/app/components/element/UiSiteFavicon.vue +24 -0
- package/app/components/element/UiSkeleton.vue +148 -0
- package/app/components/element/UiSlotText.vue +65 -0
- package/app/components/element/UiSourceLogos.vue +113 -0
- package/app/components/element/UiSourceRail.vue +71 -0
- package/app/components/element/UiStaticTerminal.vue +107 -0
- package/app/components/element/UiStatusBadge.vue +62 -0
- package/app/components/element/UiSyncDot.vue +46 -0
- package/app/components/element/UiTabs.vue +245 -0
- package/app/components/element/UiTogglePill.vue +86 -0
- package/app/components/element/UiTooltip.vue +390 -0
- package/app/components/element/UiTooltipGrid.vue +457 -0
- package/app/components/element/UiTrend.vue +184 -0
- package/app/components/element/UiTrialBenefits.vue +71 -0
- package/app/components/element/UiUrlLabel.vue +75 -0
- package/app/components/element/UiValenceDot.vue +37 -0
- package/app/components/element/UiWizardModal.vue +284 -0
- package/app/components/element/UiWizardNav.vue +59 -0
- package/app/components/element/UiWizardProgress.vue +78 -0
- package/app/components/element/UiWizardShell.vue +43 -0
- package/app/components/element/eject-menu.ts +359 -0
- package/app/components/element/eject-tracker.ts +34 -0
- package/app/components/element/onboarding-answers.ts +68 -0
- package/app/components/element/onboarding-intents.ts +19 -0
- package/app/composables/dataVizColors.ts +350 -0
- package/app/composables/formatting.ts +252 -0
- package/app/composables/semanticColors.ts +80 -0
- package/app/composables/useActivityOverlay.ts +55 -0
- package/app/composables/useAppShellNav.ts +21 -0
- package/app/composables/useChartBrush.ts +221 -0
- package/app/composables/useChartHover.ts +153 -0
- package/app/composables/useChartTickPlan.ts +186 -0
- package/app/composables/useCloseOnNavigation.ts +7 -0
- package/app/composables/useConfirm.ts +38 -0
- package/app/composables/useEdgeFade.ts +37 -0
- package/app/composables/useEject.ts +69 -0
- package/app/composables/useEntranceMotion.ts +22 -0
- package/app/composables/useFaviconBacking.ts +164 -0
- package/app/composables/useGridCols.ts +39 -0
- package/app/composables/useIssueOverlay.ts +43 -0
- package/app/composables/useOnboardingService.ts +106 -0
- package/app/composables/useOpenedOnce.ts +19 -0
- package/app/composables/useScrollSpy.ts +178 -0
- package/app/composables/useSquircleFallback.ts +21 -0
- package/app/composables/useWizardRoute.ts +123 -0
- package/app/plugins/favicon.ts +29 -0
- package/app/plugins/lazy-motion.ts +22 -0
- package/app/plugins/selection-highlight.client.ts +176 -0
- package/app/shared/cli.ts +10 -0
- package/app/shared/error-state.ts +150 -0
- package/app/shared/icons.ts +1 -0
- package/app/shared/motion.ts +1 -0
- package/app/shared/nav.ts +38 -0
- package/app/shared/navigation.ts +5 -0
- package/app/shared/static-terminal.ts +14 -0
- package/app/shared/table-export.ts +36 -0
- package/app/shared/table.ts +105 -0
- package/app/shared/ui-icons.ts +1 -0
- package/app/shared/view-state.ts +85 -0
- package/app/shared/widget-failure.ts +126 -0
- package/app/utils/chartAnnotations.ts +326 -0
- package/app/utils/countries.ts +337 -0
- package/app/utils/export-download.ts +100 -0
- package/app/utils/favicon-fallback.ts +12 -0
- package/app/utils/icon-color.ts +105 -0
- package/app/utils/number.ts +74 -0
- package/app/utils/render-link.ts +14 -0
- package/app/utils/slot-text.ts +18 -0
- package/app/utils/squircle.ts +154 -0
- package/app/utils/topEntityStack.ts +197 -0
- package/app/utils/vue.ts +57 -0
- package/build/design-system.ts +47 -0
- package/build/icon-server-bundle.ts +276 -0
- package/build/runtime/icon-server-bundle.ts +29 -0
- package/css/global.css +1892 -0
- package/nuxt.config.ts +132 -0
- package/package.json +86 -3
- package/public/brand-icon-dark.png +0 -0
- package/public/brand-icon-light.png +0 -0
- package/public/favicon-dark.png +0 -0
- package/public/favicon-light.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/fonts/README.md +31 -0
- package/public/fonts/fira-code-OFL.txt +93 -0
- package/public/fonts/fira-code-var-latin.woff2 +0 -0
- package/public/fonts/hubot-sans-OFL.txt +93 -0
- package/public/fonts/hubot-sans-var-latin.woff2 +0 -0
- package/public/icon-dark.png +0 -0
- package/public/icon.png +0 -0
- package/public/touch-icon-dark.png +0 -0
- package/public/touch-icon.png +0 -0
- package/server/api/favicon.get.ts +122 -0
- package/server/utils/favicon-source.ts +51 -0
- package/shared/contracts/feedback.ts +42 -0
- package/shared/contracts/index.ts +1 -0
- package/shared/delivery-channels.ts +53 -0
- package/shared/icons/index.ts +143 -0
- package/shared/icons/registry.ts +347 -0
- package/shared/icons/ui-slots.ts +58 -0
- package/shared/markdown.ts +44 -0
- package/shared/motion.ts +120 -0
- package/shared/rangi.ts +60 -0
- package/shared/rich-text.ts +34 -0
- package/shared/ui-icons.ts +6 -0
- package/shared/utils/urls.ts +64 -0
- package/types/index.ts +1 -0
- package/types/ui.ts +339 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { UiTableDash, UiTrend } from '#components'
|
|
4
|
+
import { calcTrendPercent } from '../../../composables/formatting'
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
current,
|
|
8
|
+
previous,
|
|
9
|
+
inverted = false,
|
|
10
|
+
size = '2xs',
|
|
11
|
+
align = 'right',
|
|
12
|
+
} = defineProps<{
|
|
13
|
+
current: number | null | undefined
|
|
14
|
+
previous: number | null | undefined
|
|
15
|
+
/** When true, a decrease is treated as positive (e.g. position ranking). */
|
|
16
|
+
inverted?: boolean
|
|
17
|
+
size?: '2xs' | 'xs' | 'sm'
|
|
18
|
+
align?: 'left' | 'center' | 'right'
|
|
19
|
+
}>()
|
|
20
|
+
|
|
21
|
+
// Raw change only. UiTrend owns the `inverted` handling, so flipping the sign
|
|
22
|
+
// here too would point the number against its own arrow and colour. A rise
|
|
23
|
+
// from 0 has no percent: it is new, which a dash ("no data") hid.
|
|
24
|
+
const change = computed<{ _tag: 'Missing' } | { _tag: 'New' } | { _tag: 'Percent', value: number }>(() => {
|
|
25
|
+
if (current == null || previous == null)
|
|
26
|
+
return { _tag: 'Missing' }
|
|
27
|
+
if (previous === 0)
|
|
28
|
+
return current > 0 ? { _tag: 'New' } : { _tag: 'Missing' }
|
|
29
|
+
return { _tag: 'Percent', value: calcTrendPercent(current, previous) }
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const alignClass = computed(() => align === 'right' ? 'justify-end' : align === 'center' ? 'justify-center' : 'justify-start')
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<template>
|
|
36
|
+
<div class="flex items-center" :class="alignClass">
|
|
37
|
+
<UiTableDash v-if="change._tag === 'Missing'" />
|
|
38
|
+
<UiTrend v-else-if="change._tag === 'New'" is-new :size="size" />
|
|
39
|
+
<UiTrend v-else :value="change.value" format="percent" :inverted="inverted" :size="size" />
|
|
40
|
+
</div>
|
|
41
|
+
</template>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
// The greydient application primitive. Turns intent into a correctly-rendered
|
|
4
|
+
// atmospheric layer — palette × geometry × intensity, plus grain — with the
|
|
5
|
+
// mask/opacity/mode-handling all centralized in global.css (`.ui-atmosphere`).
|
|
6
|
+
// Consumers place it as the first child of a `relative` container (content then
|
|
7
|
+
// sits above it); for `sky` it spans the top of the nearest positioned ancestor.
|
|
8
|
+
//
|
|
9
|
+
// This is the ONE place greydient atmosphere is produced. Never on data surfaces
|
|
10
|
+
// (charts/tables/metrics); contained identity chrome follows DESIGN's explicit
|
|
11
|
+
// micro-surface exception — "atmosphere at the edges, silence at the center".
|
|
12
|
+
type Palette = 'ink' | 'twilight' | 'dawn' | 'dusk' | 'dusk-vivid' | 'mist' | 'ash'
|
|
13
|
+
type Geometry = 'sky' | 'bloom' | 'wash' | 'veil'
|
|
14
|
+
type Intensity = 'subtle' | 'ambient' | 'present' | 'vivid'
|
|
15
|
+
type Preset = 'front-door' | 'error' | 'ai' | 'preview' | 'share'
|
|
16
|
+
|
|
17
|
+
const {
|
|
18
|
+
palette: paletteProp,
|
|
19
|
+
geometry: geometryProp,
|
|
20
|
+
intensity: intensityProp,
|
|
21
|
+
grain = true,
|
|
22
|
+
preset,
|
|
23
|
+
} = defineProps<{
|
|
24
|
+
/** Which greydient — the day-cycle of visibility states. */
|
|
25
|
+
palette?: Palette
|
|
26
|
+
/** How it's shaped. sky = full-bleed top; bloom = soft glow; wash = framed directional; veil = preview scrim. */
|
|
27
|
+
geometry?: Geometry
|
|
28
|
+
/** How present, per mode. subtle behind text; vivid is reserved for tiny identity surfaces. */
|
|
29
|
+
intensity?: Intensity
|
|
30
|
+
/** Fine grain for tooth. Default on. */
|
|
31
|
+
grain?: boolean
|
|
32
|
+
/** Semantic shortcut — resolves palette+geometry+intensity from one intent. Explicit props win. */
|
|
33
|
+
preset?: Preset
|
|
34
|
+
}>()
|
|
35
|
+
|
|
36
|
+
// The semantic map — the design decision ("front door = dusk bloom") lives HERE,
|
|
37
|
+
// once, instead of scattered across surfaces. Explicit props still override.
|
|
38
|
+
// Canonical palette roles (DESIGN / brand-kit): ink = OG/share ground · twilight
|
|
39
|
+
// = auth · dawn = marketing warmth · dusk = hero (spends color) · mist = behind
|
|
40
|
+
// text · ash = neutral. Presets encode those roles once.
|
|
41
|
+
const PRESETS: Record<Preset, { palette: Palette, geometry: Geometry, intensity: Intensity }> = {
|
|
42
|
+
'front-door': { palette: 'twilight', geometry: 'bloom', intensity: 'present' },
|
|
43
|
+
'error': { palette: 'twilight', geometry: 'sky', intensity: 'subtle' },
|
|
44
|
+
'ai': { palette: 'dusk', geometry: 'bloom', intensity: 'ambient' },
|
|
45
|
+
'preview': { palette: 'mist', geometry: 'veil', intensity: 'subtle' },
|
|
46
|
+
'share': { palette: 'ink', geometry: 'wash', intensity: 'present' },
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const base = computed(() => (preset ? PRESETS[preset] : { palette: 'ash' as Palette, geometry: 'wash' as Geometry, intensity: 'ambient' as Intensity }))
|
|
50
|
+
const palette = computed(() => paletteProp ?? base.value.palette)
|
|
51
|
+
const geometry = computed(() => geometryProp ?? base.value.geometry)
|
|
52
|
+
const intensity = computed(() => intensityProp ?? base.value.intensity)
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<template>
|
|
56
|
+
<div
|
|
57
|
+
aria-hidden="true"
|
|
58
|
+
class="ui-atmosphere"
|
|
59
|
+
:data-geometry="geometry"
|
|
60
|
+
:data-intensity="intensity"
|
|
61
|
+
:data-grain="grain ? '' : undefined"
|
|
62
|
+
:style="{ '--_atmo-greydient': `var(--greydient-${palette})` }"
|
|
63
|
+
/>
|
|
64
|
+
</template>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// Presentational heading for the auth/onboarding panels (login, onboarding,
|
|
3
|
+
// brand-kit showcase). Title + optional description, in the canonical auth
|
|
4
|
+
// type scale. Pure presentation — no runtime services.
|
|
5
|
+
const { title, description, size = 'lg' } = defineProps<{
|
|
6
|
+
title: string
|
|
7
|
+
description?: string
|
|
8
|
+
size?: 'md' | 'lg'
|
|
9
|
+
}>()
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<div class="mb-6">
|
|
14
|
+
<h1
|
|
15
|
+
class="font-semibold tracking-tight text-highlighted leading-[1.1] mb-3"
|
|
16
|
+
:class="size === 'lg' ? 'text-3xl' : 'text-2xl'"
|
|
17
|
+
>
|
|
18
|
+
{{ title }}
|
|
19
|
+
</h1>
|
|
20
|
+
<p v-if="description" class="text-muted text-sm leading-relaxed">
|
|
21
|
+
{{ description }}
|
|
22
|
+
</p>
|
|
23
|
+
</div>
|
|
24
|
+
</template>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { UiButton } from '#components'
|
|
3
|
+
// Provider sign-in/sign-up button list shared by the login + onboarding auth
|
|
4
|
+
// panels (and the brand-kit showcase). The first provider renders as the CTA,
|
|
5
|
+
// the rest as secondary; a "Last used" label marks the promoted provider.
|
|
6
|
+
//
|
|
7
|
+
// Pure presentation: labels, hrefs and ordering are computed by the consumer
|
|
8
|
+
// (each page builds the source param + copy). This component only renders and
|
|
9
|
+
// emits `select` so the consumer can persist the last-used provider.
|
|
10
|
+
export interface UiAuthProvider {
|
|
11
|
+
id: string
|
|
12
|
+
label: string
|
|
13
|
+
icon: string
|
|
14
|
+
href?: string
|
|
15
|
+
external?: boolean
|
|
16
|
+
lastUsed?: boolean
|
|
17
|
+
testId?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const { providers } = defineProps<{ providers: UiAuthProvider[] }>()
|
|
21
|
+
const emit = defineEmits<{ select: [id: string] }>()
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<template>
|
|
25
|
+
<div class="flex flex-col gap-3">
|
|
26
|
+
<div v-for="(p, idx) in providers" :key="p.id" class="relative">
|
|
27
|
+
<UiButton
|
|
28
|
+
:data-testid="p.testId"
|
|
29
|
+
:to="p.href"
|
|
30
|
+
:external="p.external"
|
|
31
|
+
:purpose="idx === 0 ? 'cta' : 'secondary'"
|
|
32
|
+
size="lg"
|
|
33
|
+
:icon="p.icon"
|
|
34
|
+
block
|
|
35
|
+
@click="emit('select', p.id)"
|
|
36
|
+
>
|
|
37
|
+
{{ p.label }}
|
|
38
|
+
<template v-if="p.lastUsed && providers.length > 1" #trailing>
|
|
39
|
+
<span class="absolute right-4 text-[11px] font-medium tracking-wide opacity-60">
|
|
40
|
+
Last used
|
|
41
|
+
</span>
|
|
42
|
+
</template>
|
|
43
|
+
</UiButton>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</template>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { drawingToSvg, faviconDrawing, markDrawing } from 'nuxtseo-shared/brand'
|
|
3
|
+
import { computed, useId } from 'vue'
|
|
4
|
+
|
|
5
|
+
const { size = 'md', variant = 'tile' } = defineProps<{
|
|
6
|
+
size?: 'md' | 'lg'
|
|
7
|
+
variant?: 'tile' | 'mark'
|
|
8
|
+
}>()
|
|
9
|
+
|
|
10
|
+
const sizeClasses = {
|
|
11
|
+
md: 'size-7',
|
|
12
|
+
lg: 'size-8',
|
|
13
|
+
} as const
|
|
14
|
+
|
|
15
|
+
const pixelSizes = {
|
|
16
|
+
md: 28,
|
|
17
|
+
lg: 32,
|
|
18
|
+
} as const
|
|
19
|
+
|
|
20
|
+
// Pro surfaces only. The tile is the Pro favicon: the summit on the plate with
|
|
21
|
+
// the original violet gradient on the climb. The mark is the Pro summit, whose
|
|
22
|
+
// climb takes the theme's gradient.
|
|
23
|
+
const id = useId()
|
|
24
|
+
const svg = computed(() => {
|
|
25
|
+
const px = pixelSizes[size]
|
|
26
|
+
const drawing = variant === 'mark' ? markDrawing({ product: 'pro', size: px }) : faviconDrawing({ product: 'pro', size: px })
|
|
27
|
+
return drawingToSvg(drawing, { idPrefix: `brand-icon-${id}`, attrs: 'class="size-full" aria-hidden="true" focusable="false"' })
|
|
28
|
+
})
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<!-- Trusted markup: drawingToSvg only interpolates the brand's own path data. -->
|
|
33
|
+
<span
|
|
34
|
+
class="relative inline-block shrink-0"
|
|
35
|
+
:class="[sizeClasses[size], variant === 'mark' ? 'text-highlighted' : '']"
|
|
36
|
+
aria-hidden="true"
|
|
37
|
+
v-html="svg"
|
|
38
|
+
/>
|
|
39
|
+
</template>
|