Skip to content

Commit 8731a47

Browse files
committed
feat(hub-ui): update client settings, have autoCollapseEdgeToolbar enabled by default
1 parent 867bcca commit 8731a47

16 files changed

Lines changed: 152 additions & 69 deletions

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ function edgeStory(position: 'top' | 'right' | 'bottom' | 'left', open = true) {
4242
selectedId: open ? 'overview' : null,
4343
panel: { mode: 'edge', position, height: 40, width: 30 },
4444
session: { open },
45+
// Pinned off so the toolbar stays expanded — `CollapsedIdle` below
46+
// covers the on-by-default auto-collapse behavior.
47+
settings: { autoCollapseEdgeToolbar: false },
4548
},
4649
ctx => [
4750
h(DockEdge, { context: ctx }, { view: ({ entry }: any) => body(entry) }),
@@ -68,9 +71,9 @@ export const Right: Story = edgeStory('right')
6871
export const ToolbarOnly: Story = edgeStory('bottom', false)
6972

7073
/**
71-
* Idle-collapsed: `autoCollapseEdgeToolbar` enabled with `inactiveTimeout: 0`
72-
* (the same trick `Dock.stories.ts`'s own `Minimized` story uses) shrinks the
73-
* toolbar down to a small corner pill immediately, with nothing selected.
74+
* Idle-collapsed: the default `autoCollapseEdgeToolbar` with `inactiveTimeout:
75+
* 0` (the same trick `Dock.stories.ts`'s own `Minimized` story uses) shrinks
76+
* the toolbar down to a small corner pill immediately, with nothing selected.
7477
*/
7578
export const CollapsedIdle: Story = {
7679
render: () => ({
@@ -80,7 +83,6 @@ export const CollapsedIdle: Story = {
8083
selectedId: null,
8184
panel: { mode: 'edge', position: 'bottom', inactiveTimeout: 0 },
8285
session: { open: false },
83-
settings: { autoCollapseEdgeToolbar: true },
8486
},
8587
ctx => [
8688
h(DockEdge, { context: ctx }, { view: ({ entry }: any) => body(entry) }),

‎packages/hub-ui/src/client/components/dock/DockEdge.vue‎

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
<script setup lang="ts">
22
import type { DocksContext } from '@devframes/hub/client'
33
import type { CSSProperties } from 'vue'
4-
import type { DevframeDocksUserSettings } from '../../state/dock-settings'
54
import type { DockEdge as DockEdgePosition, DockLayout } from './dock-layout'
65
import { useEventListener } from '@vueuse/core'
76
import { computed, h, onMounted, ref, useTemplateRef } from 'vue'
87
import { getEntryGroup } from '../../state/dock-settings'
9-
import { sharedStateToRef } from '../../state/docks'
108
import { setEdgePositionDropdown, setFloatingTooltip, useDocksGroupPanel, useEdgePositionDropdown } from '../../state/floating-tooltip'
9+
import { useSettings } from '../../state/settings-defaults'
1110
import { useIframePanes } from '../../utils/useIframePanes'
1211
import BrandMark from '../icons/BrandMark.vue'
1312
import ViewEntry from '../views/ViewEntry.vue'
@@ -24,7 +23,7 @@ const props = defineProps<{
2423
2524
const context = props.context
2625
const store = context.panel.store
27-
const settings = sharedStateToRef<DevframeDocksUserSettings>(context.docks.settings)
26+
const settings = useSettings(context)
2827
const layout = computed(() => resolveDockLayout(props.layout))
2928
3029
const viewsContainer = useTemplateRef<HTMLElement>('viewsContainer')
@@ -42,11 +41,11 @@ const hasPanelContent = computed(() => {
4241
&& entry.type !== 'action'
4342
})
4443
45-
// Auto-collapse (opt-in via `settings.autoCollapseEdgeToolbar`): idle-timeout +
46-
// hover tracking, mirroring Dock.vue's own float-bar minimize mechanism
47-
// (`isHovering`/`bringUp`/`isMinimized`). Kept entirely local/ephemeral — it's
48-
// not part of the hub-defined `DockPanelStorage`, same as Dock.vue's own
49-
// `isHovering` isn't either.
44+
// Auto-collapse (on by default, opt out via `settings.autoCollapseEdgeToolbar:
45+
// false`): idle-timeout + hover tracking, mirroring Dock.vue's own float-bar
46+
// minimize mechanism (`isHovering`/`bringUp`/`isMinimized`). Kept entirely
47+
// local/ephemeral — it's not part of the hub-defined `DockPanelStorage`, same
48+
// as Dock.vue's own `isHovering` isn't either.
5049
const isHovering = ref(false)
5150
let _idleTimer: ReturnType<typeof setTimeout> | null = null
5251
function bringUp() {

‎packages/hub-ui/src/client/components/dock/DockEmbedded.vue‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import type { DocksContext } from '@devframes/hub/client'
33
import type { DockLayout } from './dock-layout'
44
import { useEventListener } from '@vueuse/core'
55
import { onUnmounted } from 'vue'
6-
import { sharedStateToRef } from '../../state/docks'
76
import { closeDockPopup, useIsDockPopupOpen } from '../../state/popup'
7+
import { useSettings } from '../../state/settings-defaults'
88
import { useIsRpcTrusted } from '../../utils/useIsRpcTrusted'
99
import CommandPalette from '../command-palette/CommandPalette.vue'
1010
import Confirm from '../display/Confirm.vue'
@@ -22,7 +22,7 @@ const props = defineProps<{
2222
}>()
2323
2424
const isDockPopupOpen = useIsDockPopupOpen()
25-
const settings = sharedStateToRef(props.context.docks.settings)
25+
const settings = useSettings(props.context)
2626
2727
// Force float mode when unauthorized, regardless of store setting
2828
const isRpcTrusted = useIsRpcTrusted(props.context)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { DocksContext } from '@devframes/hub/client'
44
import { evaluateWhen } from 'devframe/utils/when'
55
import { toRefs } from 'vue'
66
import { getGroupMembers, resolveGroupDefaultChild } from '../../state/dock-settings'
7-
import { sharedStateToRef } from '../../state/docks'
7+
import { useSettings } from '../../state/settings-defaults'
88
import DockEntry from './DockEntry.vue'
99
import DockGroupButton from './DockGroupButton.vue'
1010
@@ -24,7 +24,7 @@ const emit = defineEmits<{
2424
2525
const { selected, isVertical, entries } = toRefs(props)
2626
27-
const settings = sharedStateToRef(props.context.docks.settings)
27+
const settings = useSettings(props.context)
2828
2929
function isDockVisible(dock: DevframeDockEntry): boolean {
3030
// Hide empty groups — a group button with no members has nothing to reveal.

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import type { DocksContext } from '@devframes/hub/client'
44
import { watchDebounced } from '@vueuse/core'
55
import { computed, h, ref, useTemplateRef } from 'vue'
66
import { getGroupMembers, getGroupMembersGrouped, resolveGroupDefaultChild } from '../../state/dock-settings'
7-
import { sharedStateToRef } from '../../state/docks'
87
import { setDocksGroupPanel, useDocksGroupPanel } from '../../state/floating-tooltip'
8+
import { useSettings } from '../../state/settings-defaults'
99
import { accentVarStyle } from '../../utils/accent-color'
1010
import DockEntry from './DockEntry.vue'
1111
import DockGroupPopover from './DockGroupPopover.vue'
@@ -24,7 +24,7 @@ const emit = defineEmits<{
2424
(e: 'select', entry: DevframeDockEntry): void
2525
}>()
2626
27-
const settings = sharedStateToRef(props.context.docks.settings)
27+
const settings = useSettings(props.context)
2828
2929
const members = computed(() => getGroupMembers(
3030
props.context.docks.entries,

‎packages/hub-ui/src/client/components/dock/DockGroupSidebar.vue‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import type { DocksContext } from '@devframes/hub/client'
44
import { watchDebounced } from '@vueuse/core'
55
import { computed, h, ref, useTemplateRef, watch } from 'vue'
66
import { deriveSidebarCapacity, docksSplitGroupsWithCapacity, getGroupMembersGrouped } from '../../state/dock-settings'
7-
import { sharedStateToRef } from '../../state/docks'
87
import { setDocksSidebarOverflowPanel, setFloatingTooltip, useDocksSidebarOverflowPanel } from '../../state/floating-tooltip'
8+
import { useSettings } from '../../state/settings-defaults'
99
import { accentVarStyle } from '../../utils/accent-color'
1010
import DockGroupPopover from './DockGroupPopover.vue'
1111
import DockIcon from './DockIcon.vue'
@@ -25,7 +25,7 @@ const DIVIDER_HEIGHT = 7 // 5 divider + 2 gap
2525
// Root padding (12) + anchor (32) + gap (2) + anchor divider (5) + gap (2).
2626
const RESERVED_HEIGHT = 53
2727
28-
const settings = sharedStateToRef(props.context.docks.settings)
28+
const settings = useSettings(props.context)
2929
3030
// Members split by in-group sub-category so the sidebar can divide sections.
3131
const memberGroups = computed(() => getGroupMembersGrouped(

‎packages/hub-ui/src/client/components/views-builtin/SettingsAdvanced.vue‎

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
<script setup lang="ts">
22
import type { DocksContext } from '@devframes/hub/client'
3-
import type { SharedState } from 'devframe/utils/shared-state'
4-
import type { DevframeDocksUserSettings } from '../../state/dock-settings'
53
import { DEFAULT_STATE_USER_SETTINGS } from '@devframes/hub/constants'
64
import { useBranding } from '../../state/branding'
75
import { useConfirm } from '../../state/confirm'
8-
import { sharedStateToRef } from '../../state/docks'
6+
import { useSettings } from '../../state/settings-defaults'
97
108
const props = defineProps<{
119
context: DocksContext
12-
settingsStore: SharedState<DevframeDocksUserSettings>
1310
}>()
1411
15-
const settings = sharedStateToRef(props.settingsStore)
12+
const settings = useSettings(props.context)
13+
const settingsStore = props.context.docks.settings
1614
const branding = useBranding()
1715
const confirm = useConfirm()
1816
@@ -21,7 +19,7 @@ async function resetAllSettings() {
2119
title: 'Reset All Settings',
2220
message: 'Reset all settings to defaults? This includes appearance, docks, and shortcuts.',
2321
})) {
24-
props.settingsStore.mutate(() => {
22+
settingsStore.mutate(() => {
2523
return DEFAULT_STATE_USER_SETTINGS()
2624
})
2725
}
@@ -32,7 +30,7 @@ async function resetShortcuts() {
3230
title: 'Reset Keyboard Shortcuts',
3331
message: 'Reset all keyboard shortcuts to defaults?',
3432
})) {
35-
props.settingsStore.mutate((state) => {
33+
settingsStore.mutate((state) => {
3634
state.commandShortcuts = {}
3735
})
3836
}
@@ -43,7 +41,7 @@ async function resetDocks() {
4341
title: 'Reset Dock Settings',
4442
message: 'Reset dock visibility, order, and pinning to defaults?',
4543
})) {
46-
props.settingsStore.mutate((state) => {
44+
settingsStore.mutate((state) => {
4745
const defaults = DEFAULT_STATE_USER_SETTINGS()
4846
state.docksHidden = defaults.docksHidden
4947
state.docksCategoriesHidden = defaults.docksCategoriesHidden
@@ -73,7 +71,7 @@ async function deauthorize() {
7371
<button
7472
class="w-10 h-6 rounded-full transition-colors relative shrink-0"
7573
:class="settings.showDevframeInspector ? 'bg-primary' : 'bg-gray/30'"
76-
@click="settingsStore.mutate((s) => { s.showDevframeInspector = !s.showDevframeInspector })"
74+
@click="settingsStore.mutate((s) => { s.showDevframeInspector = !settings.showDevframeInspector })"
7775
>
7876
<div
7977
class="absolute top-1 w-4 h-4 rounded-full bg-white shadow transition-transform"

‎packages/hub-ui/src/client/components/views-builtin/SettingsAppearance.vue‎

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
<script setup lang="ts">
22
import type { DocksContext } from '@devframes/hub/client'
3-
import type { SharedState } from 'devframe/utils/shared-state'
4-
import type { DevframeDocksUserSettings } from '../../state/dock-settings'
53
import { computed } from 'vue'
64
import { useBranding } from '../../state/branding'
75
import { colorSchemePreference, setColorSchemePreference } from '../../state/color-mode'
8-
import { sharedStateToRef } from '../../state/docks'
96
import { isDockPopupSupported, requestDockPopupOpen, useIsDockPopupOpen } from '../../state/popup'
7+
import { useSettings } from '../../state/settings-defaults'
108
119
const props = defineProps<{
1210
context: DocksContext
13-
settingsStore: SharedState<DevframeDocksUserSettings>
1411
}>()
1512
16-
const settings = sharedStateToRef(props.settingsStore)
13+
const settings = useSettings(props.context)
14+
const settingsStore = props.context.docks.settings
1715
const branding = useBranding()
1816
const panelStore = props.context.panel.store
1917
const isEmbedded = props.context.clientType === 'embedded'
@@ -99,7 +97,7 @@ function setDockMode(mode: string) {
9997
<button
10098
class="w-10 h-6 rounded-full transition-colors relative shrink-0"
10199
:class="settings.showIframeAddressBar ? 'bg-primary' : 'bg-gray/30'"
102-
@click="settingsStore.mutate((s) => { s.showIframeAddressBar = !s.showIframeAddressBar })"
100+
@click="settingsStore.mutate((s) => { s.showIframeAddressBar = !settings.showIframeAddressBar })"
103101
>
104102
<div
105103
class="absolute top-1 w-4 h-4 rounded-full bg-white shadow transition-transform"
@@ -117,7 +115,7 @@ function setDockMode(mode: string) {
117115
<button
118116
class="w-10 h-6 rounded-full transition-colors relative shrink-0"
119117
:class="settings.closeOnOutsideClick ? 'bg-primary' : 'bg-gray/30'"
120-
@click="settingsStore.mutate((s) => { s.closeOnOutsideClick = !s.closeOnOutsideClick })"
118+
@click="settingsStore.mutate((s) => { s.closeOnOutsideClick = !settings.closeOnOutsideClick })"
121119
>
122120
<div
123121
class="absolute top-1 w-4 h-4 rounded-full bg-white shadow transition-transform"
@@ -135,7 +133,7 @@ function setDockMode(mode: string) {
135133
<button
136134
class="w-10 h-6 rounded-full transition-colors relative shrink-0"
137135
:class="settings.autoCollapseEdgeToolbar ? 'bg-primary' : 'bg-gray/30'"
138-
@click="settingsStore.mutate((s) => { s.autoCollapseEdgeToolbar = !s.autoCollapseEdgeToolbar })"
136+
@click="settingsStore.mutate((s) => { s.autoCollapseEdgeToolbar = !settings.autoCollapseEdgeToolbar })"
139137
>
140138
<div
141139
class="absolute top-1 w-4 h-4 rounded-full bg-white shadow transition-transform"

‎packages/hub-ui/src/client/components/views-builtin/SettingsDocks.vue‎

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
<script setup lang="ts">
22
import type { DevframeDockEntry } from '@devframes/hub'
33
import type { DocksContext } from '@devframes/hub/client'
4-
import type { SharedState } from 'devframe/utils/shared-state'
5-
import type { DevframeDockEntriesGrouped, DevframeDocksUserSettings } from '../../state/dock-settings'
4+
import type { DevframeDockEntriesGrouped } from '../../state/dock-settings'
65
import { useDraggable } from '@vueuse/core'
76
import { computed, ref, useTemplateRef } from 'vue'
87
import { docksGroupByCategories, getCategoryLabel, getGroupMembers, getGroupMembersGrouped, isCategoryHideable } from '../../state/dock-settings'
9-
import { sharedStateToRef } from '../../state/docks'
8+
import { useSettings } from '../../state/settings-defaults'
109
import HashBadge from '../display/HashBadge.vue'
1110
import DockIcon from '../dock/DockIcon.vue'
1211
1312
const props = defineProps<{
1413
context: DocksContext
15-
settingsStore: SharedState<DevframeDocksUserSettings>
1614
}>()
1715
18-
const settings = sharedStateToRef(props.settingsStore)
16+
const settings = useSettings(props.context)
17+
const settingsStore = props.context.docks.settings
1918
2019
// Top-level rows are grouped by category with members collapsed under their
2120
// group button. A group's members are split by their in-group sub-category, and
@@ -106,7 +105,7 @@ function isInteractiveElement(el: HTMLElement | null): boolean {
106105
function applyOrder(container: string, items: DevframeDockEntry[]) {
107106
const def = defaultItemsOfContainer(container).map(i => i.id)
108107
const isDefault = items.length === def.length && items.every((item, i) => item.id === def[i])
109-
props.settingsStore.mutate((state) => {
108+
settingsStore.mutate((state) => {
110109
items.forEach((item, index) => {
111110
if (isDefault)
112111
delete state.docksCustomOrder[item.id]
@@ -185,12 +184,12 @@ function toggleDock(id: string, visible?: boolean) {
185184
const shouldShow = visible ?? isHidden
186185
187186
if (shouldShow) {
188-
props.settingsStore.mutate((state) => {
187+
settingsStore.mutate((state) => {
189188
state.docksHidden = state.docksHidden.filter((i: string) => i !== id)
190189
})
191190
}
192191
else {
193-
props.settingsStore.mutate((state) => {
192+
settingsStore.mutate((state) => {
194193
state.docksHidden = [...state.docksHidden, id]
195194
})
196195
}
@@ -204,12 +203,12 @@ function toggleCategory(category: string, visible?: boolean) {
204203
const shouldShow = visible ?? isHidden
205204
206205
if (shouldShow) {
207-
props.settingsStore.mutate((state) => {
206+
settingsStore.mutate((state) => {
208207
state.docksCategoriesHidden = state.docksCategoriesHidden.filter((i: string) => i !== category)
209208
})
210209
}
211210
else {
212-
props.settingsStore.mutate((state) => {
211+
settingsStore.mutate((state) => {
213212
state.docksCategoriesHidden = [...state.docksCategoriesHidden, category]
214213
})
215214
}
@@ -218,12 +217,12 @@ function toggleCategory(category: string, visible?: boolean) {
218217
function togglePin(id: string) {
219218
const pinned = settings.value.docksPinned
220219
if (pinned.includes(id)) {
221-
props.settingsStore.mutate((state) => {
220+
settingsStore.mutate((state) => {
222221
state.docksPinned = state.docksPinned.filter((i: string) => i !== id)
223222
})
224223
}
225224
else {
226-
props.settingsStore.mutate((state) => {
225+
settingsStore.mutate((state) => {
227226
state.docksPinned = [...state.docksPinned, id]
228227
})
229228
}
@@ -273,7 +272,7 @@ function doesContainerHaveCustomOrder(container: string): boolean {
273272
274273
function resetCustomOrderForContainer(container: string) {
275274
const ids = customOrderIdsForContainer(container)
276-
props.settingsStore.mutate((state) => {
275+
settingsStore.mutate((state) => {
277276
ids.forEach((id) => {
278277
delete state.docksCustomOrder[id]
279278
})

‎packages/hub-ui/src/client/components/views-builtin/SettingsShortcuts.vue‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ import type { DevframeCommandEntry, DevframeCommandKeybinding } from '@devframes
33
import type { DocksContext } from '@devframes/hub/client'
44
import DisplayKbd from '@antfu/design/components/Display/DisplayKbd.vue'
55
import { computed, nextTick, ref, watch } from 'vue'
6-
import { sharedStateToRef } from '../../state/docks'
76
import { filterCommandsByWhen, formatKeybinding, isKeybindingOverrideDifferentFromDefault, isMac, KNOWN_BROWSER_SHORTCUTS } from '../../state/keybindings'
7+
import { useSettings } from '../../state/settings-defaults'
88
import DockIcon from '../dock/DockIcon.vue'
99
1010
const props = defineProps<{
1111
context: DocksContext
1212
}>()
1313
1414
const commandsCtx = props.context.commands
15-
const settings = sharedStateToRef(commandsCtx.settings)
15+
const settings = useSettings(props.context)
1616
const shortcutOverrides = computed(() => settings.value.commandShortcuts ?? {})
1717
const shortcutSearch = ref('')
1818

0 commit comments

Comments
 (0)