Skip to content

Commit e3c6fe7

Browse files
antfubotdvcolomban
andauthored
feat(hub,hub-ui): color a dock-bar entry's badge via badgeVariant (#216)
Co-authored-by: Dinh-Van Colomban <dinh-van.colomban@contentsquare.com>
1 parent 3133852 commit e3c6fe7

7 files changed

Lines changed: 48 additions & 3 deletions

File tree

packages/hub-ui/src/client/components/dock/DockEntries.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ function toggleDockEntry(dock: DevframeDockEntry) {
7777
:is-dimmed="dimInactive && selected ? (selected.id !== dock.id) : false"
7878
:is-vertical="isVertical"
7979
:badge="dock.badge"
80+
:badge-variant="dock.badgeVariant"
8081
@click="toggleDockEntry(dock)"
8182
/>
8283
</template>

packages/hub-ui/src/client/components/dock/DockEntry.stories.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ interface EntryArgs {
1212
isVertical?: boolean
1313
isAction?: boolean
1414
badge?: string
15+
badgeVariant?: 'default' | 'info' | 'success' | 'warning' | 'danger'
1516
tooltip?: boolean
1617
}
1718

@@ -43,6 +44,7 @@ const meta = {
4344
isVertical: args.isVertical,
4445
isAction: args.isAction,
4546
badge: args.badge || undefined,
47+
badgeVariant: args.badgeVariant,
4648
tooltip: args.tooltip,
4749
}))),
4850
),
@@ -67,6 +69,9 @@ export const Action: Story = { args: { isAction: true } }
6769
/** A count badge in the corner (e.g. pending items). */
6870
export const WithBadge: Story = { args: { badge: '3' } }
6971

72+
/** A colored badge, e.g. flagging a state that needs attention. */
73+
export const WithBadgeVariant: Story = { args: { badge: '3', badgeVariant: 'warning' } }
74+
7075
/** Rotated for a left/right edge dock. */
7176
export const Vertical: Story = { args: { isVertical: true } }
7277

@@ -81,6 +86,8 @@ export const States: Story = {
8186
h(DockEntry, { context: ctx, dock: sample, isDimmed: true }),
8287
h(DockEntry, { context: ctx, dock: sample, isAction: true }),
8388
h(DockEntry, { context: ctx, dock: sample, badge: '9+' }),
89+
h(DockEntry, { context: ctx, dock: sample, badge: '2', badgeVariant: 'warning' }),
90+
h(DockEntry, { context: ctx, dock: sample, badge: '5', badgeVariant: 'success' }),
8491
])),
8592
),
8693
}),

packages/hub-ui/src/client/components/dock/DockEntry.vue

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<script setup lang="ts">
2-
import type { DevframeDockEntryBase } from '@devframes/hub'
2+
import type { DevframeDockBadgeVariant, DevframeDockEntryBase } from '@devframes/hub'
33
import type { DocksContext } from '@devframes/hub/client'
44
import { useEventListener } from '@vueuse/core'
5-
import { useTemplateRef } from 'vue'
5+
import { computed, useTemplateRef } from 'vue'
66
import { setFloatingTooltip } from '../../state/floating-tooltip'
77
import { openDockContextMenu } from './DockContextMenu'
88
import DockIcon from './DockIcon.vue'
@@ -16,13 +16,33 @@ const props = withDefaults(
1616
isDimmed?: boolean
1717
isVertical?: boolean
1818
badge?: string
19+
badgeVariant?: DevframeDockBadgeVariant
1920
tooltip?: boolean
2021
}>(),
2122
{
2223
tooltip: true,
2324
},
2425
)
2526
27+
// Mirrors json-render's `Badge` variant→color-name map (see
28+
// `@devframes/json-render-ui`'s `Badge.ts`), applied as an inline fill since
29+
// the dock bar doesn't pull in json-render-ui's `DisplayBadge` component.
30+
// `undefined` at `'default'`/unset keeps the existing `bg-primary text-white`
31+
// classes below — every existing badge consumer keeps its current look.
32+
const badgeColors: Record<Exclude<DevframeDockBadgeVariant, 'default'>, { bg: string, fg: string }> = {
33+
info: { bg: '#3b82f6', fg: '#eff6ff' },
34+
success: { bg: '#22c55e', fg: '#f0fdf4' },
35+
warning: { bg: '#f59e0b', fg: '#fffbeb' },
36+
danger: { bg: '#ef4444', fg: '#fef2f2' },
37+
}
38+
39+
const badgeStyle = computed(() => {
40+
if (!props.badgeVariant || props.badgeVariant === 'default')
41+
return undefined
42+
const { bg, fg } = badgeColors[props.badgeVariant]
43+
return { backgroundColor: bg, color: fg }
44+
})
45+
2646
const button = useTemplateRef<HTMLButtonElement>('button')
2747
2848
function updateTooltip() {
@@ -87,7 +107,12 @@ useEventListener('pointerdown', () => {
87107
class="flex items-center justify-center p1.5 hover:bg-[#8881] hover:scale-110 transition-all duration-300 relative outline-none"
88108
>
89109
<DockIcon :icon="dock.icon" class="w-5 h-5 select-none" />
90-
<div v-if="badge" class="absolute top-0.5 right-0 bg-primary text-white text-0.6em px-1 rounded-full shadow">
110+
<div
111+
v-if="badge"
112+
class="absolute top-0.5 right-0 text-0.6em px-1 rounded-full shadow"
113+
:class="badgeStyle ? '' : 'bg-primary text-white'"
114+
:style="badgeStyle"
115+
>
91116
{{ badge }}
92117
</div>
93118
</button>

packages/hub-ui/src/client/components/dock/DockGroupButton.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ function onClick() {
128128
:is-selected="isActive || isPanelVisible"
129129
:is-dimmed="dimInactive && selected ? !isActive : false"
130130
:badge="group.badge"
131+
:badge-variant="group.badgeVariant"
131132
@click="onClick"
132133
/>
133134
</div>

packages/hub/src/types/docks.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ export type DevframeDockEntryCategory
6969

7070
export type DevframeDockEntryIcon = string | { light: string, dark: string }
7171

72+
/** Color for a dock-bar entry's {@link DevframeDockEntryBase.badge} — mirrors json-render's `TabDescriptor.badgeVariant`. */
73+
export type DevframeDockBadgeVariant = 'default' | 'info' | 'success' | 'warning' | 'danger'
74+
7275
export interface DevframeDockEntryBase {
7376
id: string
7477
title: string
@@ -133,6 +136,11 @@ export interface DevframeDockEntryBase {
133136
* Badge text to display on the dock icon (e.g., unread count)
134137
*/
135138
badge?: string
139+
/**
140+
* Colors {@link badge}. Omitted (or `'default'`) keeps the existing neutral
141+
* fill, so every pre-existing badge consumer keeps its current look.
142+
*/
143+
badgeVariant?: DevframeDockBadgeVariant
136144
/**
137145
* Id of the group this entry belongs to. When set, hosts collapse this entry
138146
* under the matching group's button instead of showing it directly on the

tests/__snapshots__/tsnapi/@devframes/hub/index.snapshot.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export interface DevframeDockEntryBase {
9090
when?: string;
9191
visibility?: string;
9292
badge?: string;
93+
badgeVariant?: DevframeDockBadgeVariant;
9394
groupId?: string;
9495
}
9596
export interface DevframeDockEntryRegistry {
@@ -339,6 +340,7 @@ export interface RemoteDockOptions {
339340

340341
// #region Types
341342
export type DevframeCommandEntry = DevframeServerCommandEntry | DevframeClientCommand;
343+
export type DevframeDockBadgeVariant = 'default' | 'info' | 'success' | 'warning' | 'danger';
342344
export type DevframeDockEntriesGrouped = [category: string, entries: DevframeDockEntry[]][];
343345
export type DevframeDockEntry = DevframeDockUserEntry;
344346
export type DevframeDockEntryCategory = 'framework' | 'app' | 'ui' | 'data' | 'web' | 'performance' | 'advanced' | 'docs' | 'default' | '~builtin' | (string & {});

tests/__snapshots__/tsnapi/@devframes/hub/types.snapshot.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export { DevframeDiagnosticsDefinition }
2323
export { DevframeDiagnosticsHost }
2424
export { DevframeDiagnosticsLogger }
2525
export { DevframeDockActivation }
26+
export { DevframeDockBadgeVariant }
2627
export { DevframeDockEntriesGrouped }
2728
export { DevframeDockEntry }
2829
export { DevframeDockEntryBase }

0 commit comments

Comments
 (0)