diff --git a/apps/ops/src/components/shared/CommandPalette.vue b/apps/ops/src/components/shared/CommandPalette.vue new file mode 100644 index 0000000..4beb407 --- /dev/null +++ b/apps/ops/src/components/shared/CommandPalette.vue @@ -0,0 +1,212 @@ + + + + + diff --git a/apps/ops/src/components/shared/DisclosureSection.vue b/apps/ops/src/components/shared/DisclosureSection.vue new file mode 100644 index 0000000..04ecf40 --- /dev/null +++ b/apps/ops/src/components/shared/DisclosureSection.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/apps/ops/src/components/shared/OverflowMenu.vue b/apps/ops/src/components/shared/OverflowMenu.vue new file mode 100644 index 0000000..585986a --- /dev/null +++ b/apps/ops/src/components/shared/OverflowMenu.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/apps/ops/src/composables/useCommandPalette.js b/apps/ops/src/composables/useCommandPalette.js new file mode 100644 index 0000000..8620607 --- /dev/null +++ b/apps/ops/src/composables/useCommandPalette.js @@ -0,0 +1,52 @@ +import { ref, reactive, readonly } from 'vue' + +// ───────────────────────────────────────────────────────────────────────────── +// Palette de commandes globale (Cmd/Ctrl+K) — l'« escape hatch » qui permet de +// DÉCLUTTERER les pages : toute action reléguée dans un ⋮ ou une DisclosureSection +// reste joignable en tapant. Une seule instance, montée dans MainLayout. +// +// const { open, openPalette, registerActions } = useCommandPalette() +// +// Une PAGE enregistre ses actions contextuelles au montage et les retire au démontage : +// onMounted(() => registerActions('planif', [ +// { id:'publish', label:'Publier l’horaire', icon:'cloud_upload', group:'Planification', run: publishWeek }, +// ])) +// onUnmounted(() => unregisterActions('planif')) +// +// Chaque action : { id, label, icon?, caption?, group?, keywords?, run() }. +// ───────────────────────────────────────────────────────────────────────────── + +const open = ref(false) +const _sources = reactive({}) // sourceId → [actions] + +function openPalette () { open.value = true } +function closePalette () { open.value = false } +function togglePalette () { open.value = !open.value } + +// Enregistre (ou remplace) le lot d'actions d'une source contextuelle. +function registerActions (sourceId, actions) { + _sources[sourceId] = Array.isArray(actions) ? actions.filter(a => a && a.label && typeof a.run === 'function') : [] +} +function unregisterActions (sourceId) { + delete _sources[sourceId] +} + +// Toutes les actions contextuelles actuellement enregistrées, à plat. +function contextActions () { + const out = [] + for (const id in _sources) for (const a of _sources[id]) out.push({ ...a, _source: id }) + return out +} + +export function useCommandPalette () { + return { + open, + openPalette, + closePalette, + togglePalette, + registerActions, + unregisterActions, + contextActions, + sources: readonly(_sources), + } +} diff --git a/apps/ops/src/layouts/MainLayout.vue b/apps/ops/src/layouts/MainLayout.vue index 2df2eaa..f24c77f 100644 --- a/apps/ops/src/layouts/MainLayout.vue +++ b/apps/ops/src/layouts/MainLayout.vue @@ -98,8 +98,11 @@ @keydown.down.prevent="moveHighlight(1)" @keydown.up.prevent="moveHighlight(-1)" @update:model-value="onSearchInput" @blur="onSearchBlur"> -