@nuxtseo/design-system 0.0.0-stage → 0.1.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/README.md +181 -2
- package/app/app.config.ts +592 -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 +233 -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 +127 -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 +68 -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 +93 -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 +15 -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/app-favicon.ts +64 -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 +69 -0
- package/build/external-links.ts +38 -0
- package/build/fonts.ts +39 -0
- package/build/icon-server-bundle.ts +276 -0
- package/build/runtime/icon-server-bundle.ts +29 -0
- package/css/global.css +1896 -0
- package/nuxt.config.ts +143 -0
- package/package.json +93 -3
- package/public/fonts/README.md +33 -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/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,107 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { SemanticStatus } from '../../composables/semanticColors'
|
|
3
|
+
import { NuxtLink, UiHelpLabel, UiSkeleton } from '#components'
|
|
4
|
+
import { semanticColors } from '../../composables/semanticColors'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* UiFactsGrid — the quiet definition-list facts grid (label-over-value).
|
|
8
|
+
* Extracted from the hand-rolled `<dl>` in per-URL / scan / entity headers.
|
|
9
|
+
*
|
|
10
|
+
* Color budget: a fact's `status` renders as a calm LEADING DOT + neutral value
|
|
11
|
+
* (never a tinted value), so a grid of facts can't spend the page's color budget
|
|
12
|
+
* on non-events. `mono` is for IDs / hashes / URLs / raw machine strings ONLY —
|
|
13
|
+
* numerals stay `.numerals-display` at the call site, never mono.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export interface FactItem {
|
|
17
|
+
label: string
|
|
18
|
+
value?: string | number | null
|
|
19
|
+
/** Preserve the fact cell while its value is being resolved. */
|
|
20
|
+
loading?: boolean
|
|
21
|
+
/** Semantic status — renders a calm leading dot; never tints the value. */
|
|
22
|
+
status?: SemanticStatus
|
|
23
|
+
/** Mono value — IDs / hashes / raw machine strings ONLY (not URLs, not numerals). */
|
|
24
|
+
mono?: boolean
|
|
25
|
+
/** Span the full row (long values like a canonical URL). */
|
|
26
|
+
span?: boolean
|
|
27
|
+
/** Wrap long prose instead of truncating it. */
|
|
28
|
+
wrap?: boolean
|
|
29
|
+
/** Link the value (row-level navigation is fine; the value is not an @click). */
|
|
30
|
+
to?: string
|
|
31
|
+
/** Contextual help — renders a (?) UiHelpLabel on the fact label. */
|
|
32
|
+
tooltip?: string
|
|
33
|
+
/** Bold title in the help tooltip. Defaults to the label. */
|
|
34
|
+
tooltipTitle?: string
|
|
35
|
+
/** Full value shown on hover when the visible value is shortened. */
|
|
36
|
+
title?: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const { facts, columns = 3 } = defineProps<{
|
|
40
|
+
facts: FactItem[]
|
|
41
|
+
/** Max columns at sm+ (mobile is always 2). Default 3. */
|
|
42
|
+
columns?: 2 | 3
|
|
43
|
+
}>()
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<template>
|
|
47
|
+
<dl
|
|
48
|
+
data-ui="UiFactsGrid"
|
|
49
|
+
class="grid grid-cols-2 gap-x-6 gap-y-3"
|
|
50
|
+
:class="columns === 3 ? 'sm:grid-cols-3' : 'sm:grid-cols-2'"
|
|
51
|
+
>
|
|
52
|
+
<div
|
|
53
|
+
v-for="fact in facts"
|
|
54
|
+
:key="fact.label"
|
|
55
|
+
class="min-w-0"
|
|
56
|
+
:class="fact.span ? 'col-span-full' : ''"
|
|
57
|
+
>
|
|
58
|
+
<!--
|
|
59
|
+
`UiHelpLabel` wraps its text in a UiTooltip trigger BUTTON, whose own
|
|
60
|
+
type classes beat the inherited `.text-label` spec. Without this a fact
|
|
61
|
+
that carries a tooltip renders sentence-case at a different size than
|
|
62
|
+
the fact beside it, so one grid shows two label styles. Every property
|
|
63
|
+
inherits from `.text-label` rather than naming a case, so a site that
|
|
64
|
+
restyles the token restyles both kinds of fact.
|
|
65
|
+
-->
|
|
66
|
+
<dt class="text-label [&_button]:font-[inherit] [&_button]:text-[inherit] [&_button]:[text-transform:inherit] [&_button]:tracking-[inherit]">
|
|
67
|
+
<UiHelpLabel
|
|
68
|
+
v-if="fact.tooltip"
|
|
69
|
+
:text="fact.label"
|
|
70
|
+
:tooltip="fact.tooltip"
|
|
71
|
+
:tooltip-title="fact.tooltipTitle"
|
|
72
|
+
/>
|
|
73
|
+
<template v-else>
|
|
74
|
+
{{ fact.label }}
|
|
75
|
+
</template>
|
|
76
|
+
</dt>
|
|
77
|
+
<dd class="mt-0.5 flex items-center gap-1.5 text-sm">
|
|
78
|
+
<span
|
|
79
|
+
v-if="fact.status && !fact.loading"
|
|
80
|
+
class="size-1.5 shrink-0 rounded-full"
|
|
81
|
+
:class="semanticColors[fact.status].dot"
|
|
82
|
+
aria-hidden="true"
|
|
83
|
+
/>
|
|
84
|
+
<UiSkeleton
|
|
85
|
+
v-if="fact.loading"
|
|
86
|
+
type="text"
|
|
87
|
+
:base="80"
|
|
88
|
+
:range="20"
|
|
89
|
+
class="max-w-28"
|
|
90
|
+
/>
|
|
91
|
+
<component
|
|
92
|
+
:is="fact.to ? NuxtLink : 'span'"
|
|
93
|
+
v-else
|
|
94
|
+
:to="fact.to || undefined"
|
|
95
|
+
:class="[
|
|
96
|
+
fact.wrap ? 'break-words' : 'truncate',
|
|
97
|
+
fact.mono ? 'font-mono text-muted' : 'text-default',
|
|
98
|
+
fact.to ? 'underline-offset-2 hover:text-default hover:underline' : '',
|
|
99
|
+
]"
|
|
100
|
+
:title="fact.title ?? (fact.value != null ? String(fact.value) : undefined)"
|
|
101
|
+
>
|
|
102
|
+
{{ fact.value ?? '—' }}
|
|
103
|
+
</component>
|
|
104
|
+
</dd>
|
|
105
|
+
</div>
|
|
106
|
+
</dl>
|
|
107
|
+
</template>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* UiImpactMeter — monochrome 3-bar magnitude glyph (ascending signal bars).
|
|
4
|
+
* The magnitude counterpart of the severity dot/bar: severity says "how
|
|
5
|
+
* broken", the meter says "how big" (an opportunity's upside, a action's
|
|
6
|
+
* effort). Shape carries the scale, never color (Icons color rule) — filled
|
|
7
|
+
* bars read as dimmed text, empty bars as border. The owning layer maps its
|
|
8
|
+
* domain figure to the 1–3 tier (design-system knows shapes, not traffic or
|
|
9
|
+
* effort thresholds); the `label` names which magnitude this instance encodes.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { tier, label } = defineProps<{
|
|
13
|
+
/** 1 (low) – 3 (high). */
|
|
14
|
+
tier: 1 | 2 | 3
|
|
15
|
+
/** Accessible + tooltip label, e.g. "Projected impact: high". */
|
|
16
|
+
label?: string
|
|
17
|
+
}>()
|
|
18
|
+
|
|
19
|
+
const BAR_HEIGHT = ['h-1', 'h-1.5', 'h-2'] as const
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<span class="inline-flex items-end gap-px" :title="label">
|
|
24
|
+
<span v-if="label" class="sr-only">{{ label }}</span>
|
|
25
|
+
<span
|
|
26
|
+
v-for="i in 3"
|
|
27
|
+
:key="i"
|
|
28
|
+
class="w-[3px] rounded-[1px]"
|
|
29
|
+
:class="[BAR_HEIGHT[i - 1], i <= tier ? 'bg-[var(--ui-text-dimmed)]' : 'bg-[var(--ui-border)]']"
|
|
30
|
+
aria-hidden="true"
|
|
31
|
+
/>
|
|
32
|
+
</span>
|
|
33
|
+
</template>
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { RichSegment } from '../../../shared/rich-text'
|
|
3
|
+
import type { FaviconStackSite } from '../element/UiFaviconStack.vue'
|
|
4
|
+
import { computed } from 'vue'
|
|
5
|
+
import { UiFaviconStack, UiIcon, UiImpactMeter, UiNavIcon, UiRichText, UiSeverityMarker } from '#components'
|
|
6
|
+
/**
|
|
7
|
+
* The shared issue and opportunity row. Diagnosis leads. Source identity is
|
|
8
|
+
* available in regular layouts. Compact rows rely on their page context. A
|
|
9
|
+
* regular row may add a Site favicon for portfolio decisions.
|
|
10
|
+
*
|
|
11
|
+
* The row reads on ONE line from `sm` up. State ("New", "In progress") is an
|
|
12
|
+
* inline mark after the diagnosis, the Site and the value are right-aligned,
|
|
13
|
+
* and only a caller-supplied `evidence` string opens a second line. The parent
|
|
14
|
+
* owns interaction. `interactive` adds the matching hover and chevron without
|
|
15
|
+
* creating nested controls.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const {
|
|
19
|
+
title,
|
|
20
|
+
richSegments,
|
|
21
|
+
evidence,
|
|
22
|
+
severity,
|
|
23
|
+
showSeverity = true,
|
|
24
|
+
syncing = false,
|
|
25
|
+
subdued = false,
|
|
26
|
+
impact,
|
|
27
|
+
impactLabel,
|
|
28
|
+
density = 'compact',
|
|
29
|
+
glyphIcon,
|
|
30
|
+
glyphHint,
|
|
31
|
+
value,
|
|
32
|
+
novelty,
|
|
33
|
+
status,
|
|
34
|
+
site,
|
|
35
|
+
interactive = false,
|
|
36
|
+
} = defineProps<{
|
|
37
|
+
title: string
|
|
38
|
+
/**
|
|
39
|
+
* Typed headline tokens (`actionDisplay().headline`), rendered via `UiRichText`.
|
|
40
|
+
* Falls back to the plain `title` string when omitted.
|
|
41
|
+
*/
|
|
42
|
+
richSegments?: RichSegment[]
|
|
43
|
+
/** One dim secondary line; suppressed when it merely repeats the title. */
|
|
44
|
+
evidence?: string | null
|
|
45
|
+
/** The board's deterministic severity, shown with a distinct marker shape. */
|
|
46
|
+
severity: 'error' | 'warning' | 'info'
|
|
47
|
+
/**
|
|
48
|
+
* Render the severity bar. Off for opportunity lists, where severity is
|
|
49
|
+
* uniformly `info` — an identical bar on every row carries no signal (the
|
|
50
|
+
* `value` column is the differentiator there). On for Issues, where it varies.
|
|
51
|
+
*/
|
|
52
|
+
showSeverity?: boolean
|
|
53
|
+
/**
|
|
54
|
+
* The engine is checking this row (a claimed change awaiting verification).
|
|
55
|
+
* Renders a pulsing dot in the marker slot: the row is not a live fault to
|
|
56
|
+
* triage, so it must not read like one. The caller turns severity off.
|
|
57
|
+
*/
|
|
58
|
+
syncing?: boolean
|
|
59
|
+
/**
|
|
60
|
+
* Opportunity impact tier — renders a `UiImpactMeter` in the severity slot.
|
|
61
|
+
* Pass only on PURE opportunity lists (every row carries one), never in a
|
|
62
|
+
* mixed list where issues rows lead with the thinner severity bar — the two
|
|
63
|
+
* glyph widths would stagger the title column.
|
|
64
|
+
*/
|
|
65
|
+
impact?: 1 | 2 | 3 | null
|
|
66
|
+
/** Tooltip + sr-only label for the impact meter. */
|
|
67
|
+
impactLabel?: string
|
|
68
|
+
density?: 'compact' | 'regular'
|
|
69
|
+
/**
|
|
70
|
+
* Lower the diagnosis weight for rows listed under a pattern header. The
|
|
71
|
+
* readable 14px size stays unchanged.
|
|
72
|
+
*/
|
|
73
|
+
subdued?: boolean
|
|
74
|
+
/** `regular` fallback when the `leading` slot is empty. */
|
|
75
|
+
glyphIcon?: string
|
|
76
|
+
glyphHint?: string
|
|
77
|
+
/** The row's primary stat — the bold top of the right cell (e.g. "~17K/mo"). */
|
|
78
|
+
value?: string | null
|
|
79
|
+
/**
|
|
80
|
+
* "New" / "Returned" — a quiet inline mark after the diagnosis. It used to
|
|
81
|
+
* open a second line, which cost the row its whole height to carry one word.
|
|
82
|
+
*/
|
|
83
|
+
novelty?: string | null
|
|
84
|
+
/** Progress label, when the row itself owns that context. */
|
|
85
|
+
status?: string | null
|
|
86
|
+
/**
|
|
87
|
+
* Cross-site identity, shown as one framed favicon in the right column,
|
|
88
|
+
* before the value and the chevron. Spelled out, the Site name was a second
|
|
89
|
+
* text column that fought the diagnosis for the same truncating line; the
|
|
90
|
+
* favicon says the same thing in 20px and keeps the name one hover away.
|
|
91
|
+
*/
|
|
92
|
+
site?: FaviconStackSite | null
|
|
93
|
+
/** True when the parent is a link or button. Controls hover and the chevron. */
|
|
94
|
+
interactive?: boolean
|
|
95
|
+
}>()
|
|
96
|
+
|
|
97
|
+
// The dim secondary line drops a duplicate of the title.
|
|
98
|
+
const evidenceText = computed(() => (evidence && evidence.trim() !== title.trim() ? evidence.trim() : null))
|
|
99
|
+
// Only state that changes the next choice belongs in the summary row, and it
|
|
100
|
+
// reads on the HORIZONTAL plane: one word ("New", "In progress") is not worth
|
|
101
|
+
// a second line, and stacked down a list it painted a stripe rather than a
|
|
102
|
+
// signal. Callers already suppress a mark every row would carry.
|
|
103
|
+
const stateMark = computed(() => status || novelty)
|
|
104
|
+
</script>
|
|
105
|
+
|
|
106
|
+
<template>
|
|
107
|
+
<div
|
|
108
|
+
class="flex min-h-11 items-start gap-2.5 py-2.5 pl-4 pr-3.5 transition-colors sm:min-h-0 sm:items-center"
|
|
109
|
+
:class="interactive ? 'hover:bg-elevated/60' : ''"
|
|
110
|
+
>
|
|
111
|
+
<div class="flex min-w-0 flex-1 flex-col gap-1">
|
|
112
|
+
<!-- Severity, Source, then the diagnosis. -->
|
|
113
|
+
<p class="flex min-w-0 items-start gap-1.5 text-sm leading-5 text-highlighted sm:items-center" :class="subdued ? 'font-normal' : 'font-medium'">
|
|
114
|
+
<UiSyncDot v-if="syncing" status="syncing" size="2" class="shrink-0" />
|
|
115
|
+
<UiSeverityMarker v-else-if="showSeverity" :severity />
|
|
116
|
+
<UiImpactMeter v-else-if="impact" :tier="impact" :label="impactLabel" class="shrink-0" />
|
|
117
|
+
<span v-if="density !== 'compact' && ($slots.leading || glyphIcon)" :title="$slots.leading ? undefined : glyphHint" class="mt-0.5 shrink-0 sm:mt-0">
|
|
118
|
+
<slot name="leading">
|
|
119
|
+
<UiNavIcon :icon="glyphIcon!" size="xs" />
|
|
120
|
+
</slot>
|
|
121
|
+
</span>
|
|
122
|
+
<!-- No `flex-1`: the mark below must hug the diagnosis it qualifies.
|
|
123
|
+
Grown to fill, the title pushed the mark to the far right of this
|
|
124
|
+
column, where it read as a prefix of the value. -->
|
|
125
|
+
<span class="min-w-0 line-clamp-2 sm:line-clamp-1">
|
|
126
|
+
<UiRichText v-if="richSegments?.length" :segments="richSegments" size="sm" inert-links truncate />
|
|
127
|
+
<template v-else>
|
|
128
|
+
{{ title }}
|
|
129
|
+
</template>
|
|
130
|
+
</span>
|
|
131
|
+
<!-- Neutral text, never a tinted badge: these repeat down a list. -->
|
|
132
|
+
<span v-if="stateMark" class="shrink-0 text-mini font-medium uppercase tracking-wide text-dimmed">{{ stateMark }}</span>
|
|
133
|
+
</p>
|
|
134
|
+
<!-- Evidence stays a line of its own; the value falls under the title
|
|
135
|
+
only where the right column is hidden. -->
|
|
136
|
+
<p v-if="evidenceText || value" class="min-w-0 text-sm text-muted">
|
|
137
|
+
<span v-if="evidenceText" class="block truncate">{{ evidenceText }}</span>
|
|
138
|
+
<span v-if="value" class="mt-0.5 block truncate font-medium tabular-nums text-default sm:hidden">{{ value }}</span>
|
|
139
|
+
</p>
|
|
140
|
+
</div>
|
|
141
|
+
|
|
142
|
+
<!-- Site, Impact and the interaction cue earn a right column. -->
|
|
143
|
+
<div v-if="site || value || interactive" class="flex shrink-0 items-center gap-2.5 pt-0.5 sm:pt-0">
|
|
144
|
+
<UiFaviconStack v-if="site" :sites="[site]" size="xs" />
|
|
145
|
+
<span v-if="value" class="hidden whitespace-nowrap text-sm font-medium tabular-nums text-default sm:inline">{{ value }}</span>
|
|
146
|
+
<UiIcon v-if="interactive" name="chevron-right" class="size-3.5 shrink-0 text-muted" aria-hidden="true" />
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
</template>
|