From 70d7347ae3624607508f34dc017aa2d40be7f51d Mon Sep 17 00:00:00 2001 From: Mattias Granlund Date: Tue, 12 Dec 2023 23:24:33 +0100 Subject: [PATCH] Refactor context menus and popups - add dividers (sections) - stop using overlay for branch popup - click outside to dismiss (without canceling click) --- packages/ui/src/lib/clickOutside.ts | 5 +- .../ui/src/lib/components/DropDown.svelte | 10 +- .../ui/src/lib/components/PopupMenu.svelte | 24 ++-- .../components/contextmenu/ContextMenu.svelte | 2 - .../contextmenu/ContextMenuItem.svelte | 9 +- .../contextmenu/ContextMenuSection.svelte | 18 +++ packages/ui/src/lib/icons/Icon.svelte | 2 + .../[projectId]/components/BranchCard.svelte | 22 +--- .../components/BranchHeader.svelte | 49 ++++---- .../components/BranchLanePopupMenu.svelte | 109 ++++++++---------- .../components/CommitDialog.svelte | 25 ++-- .../[projectId]/components/PushButton.svelte | 19 +-- 12 files changed, 143 insertions(+), 151 deletions(-) create mode 100644 packages/ui/src/lib/components/contextmenu/ContextMenuSection.svelte diff --git a/packages/ui/src/lib/clickOutside.ts b/packages/ui/src/lib/clickOutside.ts index ada2da109..79db61d72 100644 --- a/packages/ui/src/lib/clickOutside.ts +++ b/packages/ui/src/lib/clickOutside.ts @@ -1,4 +1,4 @@ -export type ClickOpts = { trigger?: HTMLElement; handler: () => void; enabled: boolean }; +export type ClickOpts = { trigger?: HTMLElement; handler: () => void; enabled?: boolean }; export function clickOutside( node: HTMLElement, @@ -14,13 +14,14 @@ export function clickOutside( params.handler(); } } + document.addEventListener('click', onClick, true); return { destroy() { document.removeEventListener('click', onClick, true); }, update(opts: ClickOpts) { document.removeEventListener('click', onClick, true); - if (!opts.enabled) return; + if (opts.enabled !== undefined && !opts.enabled) return; trigger = opts.trigger; document.addEventListener('click', onClick, true); } diff --git a/packages/ui/src/lib/components/DropDown.svelte b/packages/ui/src/lib/components/DropDown.svelte index e6aa75c8c..bf83f9c7d 100644 --- a/packages/ui/src/lib/components/DropDown.svelte +++ b/packages/ui/src/lib/components/DropDown.svelte @@ -19,7 +19,7 @@ } let container: HTMLDivElement; - let popup: HTMLDivElement; + let contextMenuContainer: HTMLDivElement; let iconElt: HTMLElement; @@ -50,12 +50,12 @@ />
(visible = !visible), enabled: visible }} - bind:this={popup} + bind:this={contextMenuContainer} style:display={visible ? 'block' : 'none'} > - +
@@ -103,7 +103,7 @@ align-items: center; } - .context-wrapper { + .context-menu-container { position: absolute; right: 0; bottom: 100%; diff --git a/packages/ui/src/lib/components/PopupMenu.svelte b/packages/ui/src/lib/components/PopupMenu.svelte index f89962818..f1d772771 100644 --- a/packages/ui/src/lib/components/PopupMenu.svelte +++ b/packages/ui/src/lib/components/PopupMenu.svelte @@ -1,4 +1,6 @@ + +
+ +
+ + diff --git a/packages/ui/src/lib/icons/Icon.svelte b/packages/ui/src/lib/icons/Icon.svelte index 75cead1b2..f51dca7db 100644 --- a/packages/ui/src/lib/icons/Icon.svelte +++ b/packages/ui/src/lib/icons/Icon.svelte @@ -7,6 +7,7 @@ export let name: keyof typeof iconsJson; export let color: IconColor = undefined; + export let opacity: string | undefined = undefined; diff --git a/packages/ui/src/routes/[projectId]/components/BranchCard.svelte b/packages/ui/src/routes/[projectId]/components/BranchCard.svelte index 7cb59b7c2..ffc875f6c 100644 --- a/packages/ui/src/routes/[projectId]/components/BranchCard.svelte +++ b/packages/ui/src/routes/[projectId]/components/BranchCard.svelte @@ -9,7 +9,7 @@ type DraggableHunk } from '$lib/draggables'; import { Ownership } from '$lib/vbranches/ownership'; - import { getExpandedWithCacheFallback, setExpandedWithCache } from './cache'; + import { getExpandedWithCacheFallback } from './cache'; import type { BranchController } from '$lib/vbranches/branchController'; import type { User, getCloudApiClient } from '$lib/backend/cloud'; import Resizer from '$lib/components/Resizer.svelte'; @@ -65,18 +65,6 @@ $allCollapsed = branch.files.every((f) => getExpandedWithCacheFallback(f) == false); } - function handleCollapseAll() { - branch.files.forEach((f) => setExpandedWithCache(f, false)); - $allExpanded = false; - branch.files = branch.files; - } - - function handleExpandAll() { - branch.files.forEach((f) => setExpandedWithCache(f, true)); - $allExpanded = true; - branch.files = branch.files; - } - let commitDialogShown = false; $: if (commitDialogShown && branch.files.length === 0) { @@ -160,15 +148,9 @@ {readonly} {branchController} {branch} - {allCollapsed} - {allExpanded} projectId={project.id} on:action={(e) => { - if (e.detail == 'expand') { - handleExpandAll(); - } else if (e.detail == 'collapse') { - handleCollapseAll(); - } else if (e.detail == 'generate-branch-name') { + if (e.detail == 'generate-branch-name') { generateBranchName(); } }} diff --git a/packages/ui/src/routes/[projectId]/components/BranchHeader.svelte b/packages/ui/src/routes/[projectId]/components/BranchHeader.svelte index 282072cc4..24edd1a60 100644 --- a/packages/ui/src/routes/[projectId]/components/BranchHeader.svelte +++ b/packages/ui/src/routes/[projectId]/components/BranchHeader.svelte @@ -6,43 +6,22 @@ import { fade } from 'svelte/transition'; import BranchLabel from './BranchLabel.svelte'; import BranchLanePopupMenu from './BranchLanePopupMenu.svelte'; - import type { Writable } from 'svelte/store'; - import { createEventDispatcher, onDestroy, onMount } from 'svelte'; + import { clickOutside } from '$lib/clickOutside'; export let readonly = false; export let branch: Branch; - export let allExpanded: Writable; - export let allCollapsed: Writable; export let branchController: BranchController; export let projectId: string; - const dispatch = createEventDispatcher<{ action: string }>(); - let meatballButton: HTMLDivElement; - - // We have to create this manually for now. - // TODO: Use document.body.addEventListener to avoid having to use backdrop - let popupMenu = new BranchLanePopupMenu({ - target: document.body, - props: { allExpanded, allCollapsed, branchController, projectId } - }); + let visible = false; function handleBranchNameChange() { branchController.updateBranchName(branch.id, branch.name); } - - onMount(() => { - return popupMenu.$on('action', (e) => { - dispatch('action', e.detail); - }); - }); - - onDestroy(() => { - popupMenu.$destroy(); - }); -
+
{#if !readonly}
@@ -54,17 +33,22 @@
{#if !readonly}
- popupMenu.openByElement(meatballButton, branch)} - /> + (visible = !visible)} /> +
+
(visible = false) }} + > +
{/if}
diff --git a/packages/ui/src/routes/[projectId]/components/BranchLanePopupMenu.svelte b/packages/ui/src/routes/[projectId]/components/BranchLanePopupMenu.svelte index eb8587748..36e61a3d0 100644 --- a/packages/ui/src/routes/[projectId]/components/BranchLanePopupMenu.svelte +++ b/packages/ui/src/routes/[projectId]/components/BranchLanePopupMenu.svelte @@ -1,18 +1,19 @@ - - branch.id && branchController.unapplyBranch(branch.id)}> - Unapply - +{#if visible} + + + branch.id && branchController.unapplyBranch(branch.id)} + /> - deleteBranchModal.show(branch)}>Delete + deleteBranchModal.show(branch)} /> - dispatch('action', 'expand')} disabled={$allExpanded}> - Expand all - + dispatch('action', 'generate-branch-name')} + disabled={!$aiGenEnabled} + /> + - dispatch('action', 'collapse')} disabled={$allCollapsed}> - Collapse all - + + branchController.createBranch({ order: branch.order })} + /> - dispatch('action', 'generate-branch-name')} - disabled={!$aiGenEnabled} - > - Generate branch name - + branchController.createBranch({ order: branch.order + 1 })} + /> + + -
-
-
+ +
+ Deleting {branch.name} cannot be undone. +
+ + + + +
+{/if} - branchController.createBranch({ order: branch.order })}> - Create branch before - - - branchController.createBranch({ order: branch.order + 1 })}> - Create branch after - - - - -
- Deleting {branch.name} cannot be undone. -
- - - - -
+ diff --git a/packages/ui/src/routes/[projectId]/components/CommitDialog.svelte b/packages/ui/src/routes/[projectId]/components/CommitDialog.svelte index 1bf9f16e1..760ba4285 100644 --- a/packages/ui/src/routes/[projectId]/components/CommitDialog.svelte +++ b/packages/ui/src/routes/[projectId]/components/CommitDialog.svelte @@ -21,6 +21,7 @@ import Tooltip from '$lib/components/Tooltip.svelte'; import type { Writable } from 'svelte/store'; import { createEventDispatcher } from 'svelte'; + import ContextMenuSection from '$lib/components/contextmenu/ContextMenuSection.svelte'; const dispatch = createEventDispatcher<{ action: 'generate-branch-name'; @@ -127,17 +128,19 @@ on:click={() => generateCommitMessage(branch.files)} > Generate message - - commitGenerationExtraConcise.update((value) => !value)} - /> - commitGenerationUseEmojis.update((value) => !value)} - /> + + + commitGenerationExtraConcise.update((value) => !value)} + /> + commitGenerationUseEmojis.update((value) => !value)} + /> + diff --git a/packages/ui/src/routes/[projectId]/components/PushButton.svelte b/packages/ui/src/routes/[projectId]/components/PushButton.svelte index 1f6a8c951..ff2475a7e 100644 --- a/packages/ui/src/routes/[projectId]/components/PushButton.svelte +++ b/packages/ui/src/routes/[projectId]/components/PushButton.svelte @@ -5,6 +5,7 @@ import DropDown from '$lib/components/DropDown.svelte'; import ContextMenu from '$lib/components/contextmenu/ContextMenu.svelte'; import ContextMenuItem from '$lib/components/contextmenu/ContextMenuItem.svelte'; + import ContextMenuSection from '$lib/components/contextmenu/ContextMenuSection.svelte'; let disabled = false; @@ -37,19 +38,21 @@ {$selection$?.label} { $createPr = e.detail?.id == 'pr'; dropDown.close(); }} > - - + + + +