Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/hub-ui/src/client/components/dock/DockEntries.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ function toggleDockEntry(dock: DevframeDockEntry) {
:is-dimmed="dimInactive && selected ? (selected.id !== dock.id) : false"
:is-vertical="isVertical"
:badge="dock.badge"
:badge-variant="dock.badgeVariant"
@click="toggleDockEntry(dock)"
/>
</template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface EntryArgs {
isVertical?: boolean
isAction?: boolean
badge?: string
badgeVariant?: 'default' | 'info' | 'success' | 'warning' | 'danger'
tooltip?: boolean
}

Expand Down Expand Up @@ -43,6 +44,7 @@ const meta = {
isVertical: args.isVertical,
isAction: args.isAction,
badge: args.badge || undefined,
badgeVariant: args.badgeVariant,
tooltip: args.tooltip,
}))),
),
Expand All @@ -67,6 +69,9 @@ export const Action: Story = { args: { isAction: true } }
/** A count badge in the corner (e.g. pending items). */
export const WithBadge: Story = { args: { badge: '3' } }

/** A colored badge, e.g. flagging a state that needs attention. */
export const WithBadgeVariant: Story = { args: { badge: '3', badgeVariant: 'warning' } }

/** Rotated for a left/right edge dock. */
export const Vertical: Story = { args: { isVertical: true } }

Expand All @@ -81,6 +86,8 @@ export const States: Story = {
h(DockEntry, { context: ctx, dock: sample, isDimmed: true }),
h(DockEntry, { context: ctx, dock: sample, isAction: true }),
h(DockEntry, { context: ctx, dock: sample, badge: '9+' }),
h(DockEntry, { context: ctx, dock: sample, badge: '2', badgeVariant: 'warning' }),
h(DockEntry, { context: ctx, dock: sample, badge: '5', badgeVariant: 'success' }),
])),
),
}),
Expand Down
31 changes: 28 additions & 3 deletions packages/hub-ui/src/client/components/dock/DockEntry.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<script setup lang="ts">
import type { DevframeDockEntryBase } from '@devframes/hub'
import type { DevframeDockBadgeVariant, DevframeDockEntryBase } from '@devframes/hub'
import type { DocksContext } from '@devframes/hub/client'
import { useEventListener } from '@vueuse/core'
import { useTemplateRef } from 'vue'
import { computed, useTemplateRef } from 'vue'
import { setFloatingTooltip } from '../../state/floating-tooltip'
import { openDockContextMenu } from './DockContextMenu'
import DockIcon from './DockIcon.vue'
Expand All @@ -16,13 +16,33 @@ const props = withDefaults(
isDimmed?: boolean
isVertical?: boolean
badge?: string
badgeVariant?: DevframeDockBadgeVariant
tooltip?: boolean
}>(),
{
tooltip: true,
},
)

// Mirrors json-render's `Badge` variant→color-name map (see
// `@devframes/json-render-ui`'s `Badge.ts`), applied as an inline fill since
// the dock bar doesn't pull in json-render-ui's `DisplayBadge` component.
// `undefined` at `'default'`/unset keeps the existing `bg-primary text-white`
// classes below — every existing badge consumer keeps its current look.
const badgeColors: Record<Exclude<DevframeDockBadgeVariant, 'default'>, { bg: string, fg: string }> = {
info: { bg: '#3b82f6', fg: '#eff6ff' },
success: { bg: '#22c55e', fg: '#f0fdf4' },
warning: { bg: '#f59e0b', fg: '#fffbeb' },
danger: { bg: '#ef4444', fg: '#fef2f2' },
}

const badgeStyle = computed(() => {
if (!props.badgeVariant || props.badgeVariant === 'default')
return undefined
const { bg, fg } = badgeColors[props.badgeVariant]
return { backgroundColor: bg, color: fg }
})

const button = useTemplateRef<HTMLButtonElement>('button')

function updateTooltip() {
Expand Down Expand Up @@ -87,7 +107,12 @@ useEventListener('pointerdown', () => {
class="flex items-center justify-center p1.5 hover:bg-[#8881] hover:scale-110 transition-all duration-300 relative outline-none"
>
<DockIcon :icon="dock.icon" class="w-5 h-5 select-none" />
<div v-if="badge" class="absolute top-0.5 right-0 bg-primary text-white text-0.6em px-1 rounded-full shadow">
<div
v-if="badge"
class="absolute top-0.5 right-0 text-0.6em px-1 rounded-full shadow"
:class="badgeStyle ? '' : 'bg-primary text-white'"
:style="badgeStyle"
>
{{ badge }}
</div>
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ function onClick() {
:is-selected="isActive || isPanelVisible"
:is-dimmed="dimInactive && selected ? !isActive : false"
:badge="group.badge"
:badge-variant="group.badgeVariant"
@click="onClick"
/>
</div>
Expand Down
8 changes: 8 additions & 0 deletions packages/hub/src/types/docks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ export type DevframeDockEntryCategory

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

/** Color for a dock-bar entry's {@link DevframeDockEntryBase.badge} — mirrors json-render's `TabDescriptor.badgeVariant`. */
export type DevframeDockBadgeVariant = 'default' | 'info' | 'success' | 'warning' | 'danger'

export interface DevframeDockEntryBase {
id: string
title: string
Expand Down Expand Up @@ -133,6 +136,11 @@ export interface DevframeDockEntryBase {
* Badge text to display on the dock icon (e.g., unread count)
*/
badge?: string
/**
* Colors {@link badge}. Omitted (or `'default'`) keeps the existing neutral
* fill, so every pre-existing badge consumer keeps its current look.
*/
badgeVariant?: DevframeDockBadgeVariant
/**
* Id of the group this entry belongs to. When set, hosts collapse this entry
* under the matching group's button instead of showing it directly on the
Expand Down
2 changes: 2 additions & 0 deletions tests/__snapshots__/tsnapi/@devframes/hub/index.snapshot.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export interface DevframeDockEntryBase {
when?: string;
visibility?: string;
badge?: string;
badgeVariant?: DevframeDockBadgeVariant;
groupId?: string;
}
export interface DevframeDockEntryRegistry {
Expand Down Expand Up @@ -339,6 +340,7 @@ export interface RemoteDockOptions {

// #region Types
export type DevframeCommandEntry = DevframeServerCommandEntry | DevframeClientCommand;
export type DevframeDockBadgeVariant = 'default' | 'info' | 'success' | 'warning' | 'danger';
export type DevframeDockEntriesGrouped = [category: string, entries: DevframeDockEntry[]][];
export type DevframeDockEntry = DevframeDockUserEntry;
export type DevframeDockEntryCategory = 'framework' | 'app' | 'ui' | 'data' | 'web' | 'performance' | 'advanced' | 'docs' | 'default' | '~builtin' | (string & {});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export { DevframeDiagnosticsDefinition }
export { DevframeDiagnosticsHost }
export { DevframeDiagnosticsLogger }
export { DevframeDockActivation }
export { DevframeDockBadgeVariant }
export { DevframeDockEntriesGrouped }
export { DevframeDockEntry }
export { DevframeDockEntryBase }
Expand Down
Loading