From 893ac8cd4ab01f18e88fa113a4ff2602c05b67d3 Mon Sep 17 00:00:00 2001 From: louispaulb Date: Thu, 9 Jul 2026 06:53:24 -0400 Subject: [PATCH] =?UTF-8?q?D=C3=A9clutter:=20primitives=20r=C3=A9utilisabl?= =?UTF-8?q?es=20+=20palette=20=E2=8C=98K=20+=20Planif=20=C3=A9pur=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajoute 3 primitives partagées pour standardiser le désencombrement (philosophie 3 paliers : coup d'œil → survol → détail) : - OverflowMenu.vue : « ⋮ » standardisé (une action primaire visible, le secondaire dans le menu). - DisclosureSection.vue : section repliée par défaut (résumé + corps révélé), état persisté par utilisateur (useUserPrefs). - CommandPalette.vue + useCommandPalette.js : palette globale ⌘K (actions rapides + pages + actions contextuelles de page + recherche clients/équipe), registre d'actions par page = escape hatch. Câblage MainLayout : palette montée + raccourci Cmd/Ctrl+K + indice ⌘K dans la recherche desktop. Adoptions : - RapportsPage : PageHeader + stubs « Opérations » repliés + rapports enregistrés dans la palette. - DashboardPage : bloc admin replié (DisclosureSection) + PPA rétrogradé dans un OverflowMenu (anti clic accidentel) + actions dans la palette. - PlanificationPage : le panneau « Jobs à assigner » n'ouvre plus au chargement ; alerte « N à assigner » par jour (clic → panneau filtré) ; undo/redo/refresh regroupés dans un OverflowMenu ; actions dans la palette. Co-Authored-By: Claude Opus 4.8 --- .../src/components/shared/CommandPalette.vue | 212 ++++++++++++++++++ .../components/shared/DisclosureSection.vue | 71 ++++++ .../src/components/shared/OverflowMenu.vue | 79 +++++++ apps/ops/src/composables/useCommandPalette.js | 52 +++++ apps/ops/src/layouts/MainLayout.vue | 26 ++- apps/ops/src/pages/DashboardPage.vue | 40 ++-- apps/ops/src/pages/PlanificationPage.vue | 33 ++- apps/ops/src/pages/RapportsPage.vue | 50 +++-- 8 files changed, 530 insertions(+), 33 deletions(-) create mode 100644 apps/ops/src/components/shared/CommandPalette.vue create mode 100644 apps/ops/src/components/shared/DisclosureSection.vue create mode 100644 apps/ops/src/components/shared/OverflowMenu.vue create mode 100644 apps/ops/src/composables/useCommandPalette.js 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"> -