Add UI enhancements and refactor components

In this commit, a series of UI enhancements and changes have been made on some components. The modifications help to improve the user interaction experience and the organization of the code by refactoring some of the elements, improving their visibility and adding new interactive elements.

Changes include:

- Improved opacity state for the 'isFileLocked' feature. 
- Added and integrated new Tooltip and IconLock classes.
- Refactored color configurations in the color config section.
- Introduced the creation of an SVG file for Icon elements rendering.
- Modified text to "No uncommitted changes on this branch" for better clarity.
- Added options to maximize and minimize in the PopupMenu. 
- Changed modal title from "Update target" to "Merge Upstream Work", and expanded the explanation of the work's impact.
- Removed some redundant conditions in the checkbox state in the branches component. 
- Added help icon library. 
- Changed the modal confirmation button from "Update" to "Merge Upstream
This commit is contained in:
Scott Chacon 2023-08-02 17:27:32 +02:00 committed by GitButler
parent 77a5356266
commit abb0d94543
8 changed files with 151 additions and 40 deletions

View File

@ -0,0 +1,19 @@
<script lang="ts">
let className = '';
export { className as class };
</script>
<svg
class={className}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z"
/>
</svg>

View File

@ -0,0 +1,19 @@
<script lang="ts">
let className = '';
export { className as class };
</script>
<svg
class={className}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z"
/>
</svg>

View File

@ -51,7 +51,7 @@
<div class="flex w-full max-w-full" role="group" on:dragover|preventDefault> <div class="flex w-full max-w-full" role="group" on:dragover|preventDefault>
<Tray {branches} {remoteBranches} /> <Tray {branches} {remoteBranches} />
<div <div
class="z-50 -ml-[0.250rem] w-[0.250rem] shrink-0 cursor-col-resize hover:bg-orange-200 dark:bg-dark-1000 dark:hover:bg-orange-700" class="z-30 -ml-[0.250rem] w-[0.250rem] shrink-0 cursor-col-resize hover:bg-orange-200 dark:bg-dark-1000 dark:hover:bg-orange-700"
draggable="true" draggable="true"
role="separator" role="separator"
on:drag={(e) => { on:drag={(e) => {

View File

@ -396,7 +396,7 @@
class="no-changes rounded text-center font-mono text-light-700 dark:border-zinc-700" class="no-changes rounded text-center font-mono text-light-700 dark:border-zinc-700"
data-dnd-ignore data-dnd-ignore
> >
No uncommitted changes No uncommitted changes on this branch
</div> </div>
{/if} {/if}
{/if} {/if}
@ -512,6 +512,16 @@
</div> </div>
<PopupMenu bind:this={popupMenu} let:item={branchId}> <PopupMenu bind:this={popupMenu} let:item={branchId}>
{#if !maximized}
<PopupMenuItem on:click={() => (maximized = !maximized)}>Maximize</PopupMenuItem>
{:else}
<PopupMenuItem on:click={() => (maximized = !maximized)}>Minimize</PopupMenuItem>
{/if}
<div class="mx-3">
<div class="my-2 h-[0.0625rem] w-full bg-light-300 dark:bg-dark-500" />
</div>
<PopupMenuItem on:click={() => branchId && branchController.unapplyBranch(branchId)}> <PopupMenuItem on:click={() => branchId && branchController.unapplyBranch(branchId)}>
Unapply Unapply
</PopupMenuItem> </PopupMenuItem>

View File

@ -22,6 +22,8 @@
import { slide } from 'svelte/transition'; import { slide } from 'svelte/transition';
import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/userSettings'; import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/userSettings';
import { summarizeHunk } from '$lib/summaries'; import { summarizeHunk } from '$lib/summaries';
import Tooltip from '$lib/components/Tooltip/Tooltip.svelte';
import IconLock from '$lib/icons/IconLock.svelte';
export let file: File; export let file: File;
export let conflicted: boolean; export let conflicted: boolean;
@ -84,7 +86,7 @@
on:dragstart={(e) => e.dataTransfer?.setData('text/hunk', getAllHunksOwnership())} on:dragstart={(e) => e.dataTransfer?.setData('text/hunk', getAllHunksOwnership())}
role="group" role="group"
class="changed-file inner" class="changed-file inner"
class:opacity-60={isFileLocked} class:opacity-80={isFileLocked}
> >
<div <div
class="flex w-full flex-col justify-center gap-2 border-b border-t border-light-300 bg-light-50 py-1 text-light-900 dark:border-dark-500 dark:bg-dark-800 dark:text-light-300" class="flex w-full flex-col justify-center gap-2 border-b border-t border-light-300 bg-light-50 py-1 text-light-900 dark:border-dark-500 dark:bg-dark-800 dark:text-light-300"
@ -112,6 +114,15 @@
{@html boldenFilename(file.path)} {@html boldenFilename(file.path)}
</div> </div>
{#if isFileLocked}
<div class="flex flex-grow-0">
<Tooltip
label="File changes cannot be moved because part of this file was already committed into this branch"
>
<IconLock class="h-4 w-4 text-yellow-600" />
</Tooltip>
</div>
{/if}
<div <div
on:click|stopPropagation={() => { on:click|stopPropagation={() => {
expanded = !expanded; expanded = !expanded;
@ -120,7 +131,7 @@
on:keypress={() => (expanded = !expanded)} on:keypress={() => (expanded = !expanded)}
role="button" role="button"
tabindex="0" tabindex="0"
class="cursor-pointer px-3 py-2 text-light-600 dark:text-dark-200" class="flex-grow-0 cursor-pointer px-3 py-2 text-light-600 dark:text-dark-200"
> >
{#if !file.binary} {#if !file.binary}
{#if expanded} {#if expanded}

View File

@ -14,6 +14,7 @@
import Tooltip from '$lib/components/Tooltip/Tooltip.svelte'; import Tooltip from '$lib/components/Tooltip/Tooltip.svelte';
import Scrollbar from '$lib/components/Scrollbar.svelte'; import Scrollbar from '$lib/components/Scrollbar.svelte';
import IconMeatballMenu from '$lib/icons/IconMeatballMenu.svelte'; import IconMeatballMenu from '$lib/icons/IconMeatballMenu.svelte';
import IconHelp from '$lib/icons/IconHelp.svelte';
export let branches: Branch[]; export let branches: Branch[];
export let remoteBranches: BranchData[]; export let remoteBranches: BranchData[];
@ -124,8 +125,24 @@
bind:checked={branch.active} bind:checked={branch.active}
disabled={!(branch.mergeable || !branch.baseCurrent) || branch.conflicted} disabled={!(branch.mergeable || !branch.baseCurrent) || branch.conflicted}
/> />
<div class="ml-2 w-full truncate text-black dark:text-white">
{branch.name}
</div>
</div>
<button
class="h-8 w-8 flex-grow-0 p-2 text-light-600 transition-colors hover:bg-zinc-300 dark:text-dark-200 dark:hover:bg-zinc-800"
on:keydown={(e) => yourBranchContextMenu.openByMouse(e, branch)}
on:click={(e) => yourBranchContextMenu.openByMouse(e, branch)}
>
<IconMeatballMenu />
</button>
</div>
<div class="flex items-center text-sm text-light-700 dark:text-dark-300">
<div class="flex-grow">
{latestModifiedAt ? formatDistanceToNow(latestModifiedAt) : ''}
</div>
{#if !branch.active} {#if !branch.active}
<div class="ml-1"> <div class="mr-2">
{#if !branch.baseCurrent} {#if !branch.baseCurrent}
<!-- branch will cause merge conflicts if applied --> <!-- branch will cause merge conflicts if applied -->
<Tooltip label="Will introduce merge conflicts if applied"> <Tooltip label="Will introduce merge conflicts if applied">
@ -144,22 +161,6 @@
{/if} {/if}
</div> </div>
{/if} {/if}
<div class="ml-2 w-full truncate text-black dark:text-white">
{branch.name}
</div>
</div>
<button
class="h-8 w-8 flex-grow-0 p-2 text-light-600 transition-colors hover:bg-zinc-300 dark:text-dark-200 dark:hover:bg-zinc-800"
on:keydown={(e) => yourBranchContextMenu.openByMouse(e, branch)}
on:click={(e) => yourBranchContextMenu.openByMouse(e, branch)}
>
<IconMeatballMenu />
</button>
</div>
<div class="flex items-center text-sm text-light-700 dark:text-dark-300">
<div class="flex-grow">
{latestModifiedAt ? formatDistanceToNow(latestModifiedAt) : ''}
</div>
<div class="flex gap-1 font-mono text-sm font-bold"> <div class="flex gap-1 font-mono text-sm font-bold">
<span class="text-green-500"> <span class="text-green-500">
+{added} +{added}
@ -181,7 +182,16 @@
<div <div
class="flex items-center justify-between border-b border-light-400 bg-light-100 px-2 py-1 pr-1 dark:border-dark-600 dark:bg-dark-800" class="flex items-center justify-between border-b border-light-400 bg-light-100 px-2 py-1 pr-1 dark:border-dark-600 dark:bg-dark-800"
> >
<div class="flex flex-row place-items-center space-x-2">
<div class="font-bold">Remote Branches</div> <div class="font-bold">Remote Branches</div>
<a
target="_blank"
rel="noreferrer"
href="https://docs.gitbutler.com/features/virtual-branches/remote-branches"
>
<IconHelp class="h-3 w-3 text-light-600" />
</a>
</div>
<div class="flex h-4 w-4 justify-around"> <div class="flex h-4 w-4 justify-around">
<button class="h-full w-full" on:click={() => (remoteBranchesOpen = !remoteBranchesOpen)}> <button class="h-full w-full" on:click={() => (remoteBranchesOpen = !remoteBranchesOpen)}>
{#if remoteBranchesOpen} {#if remoteBranchesOpen}
@ -222,9 +232,15 @@
<div class="flex flex-row items-center gap-x-2 pr-1"> <div class="flex flex-row items-center gap-x-2 pr-1">
<div class="text-light-600 dark:text-dark-200"> <div class="text-light-600 dark:text-dark-200">
{#if branch.name.match('refs/remotes')} {#if branch.name.match('refs/remotes')}
<Tooltip
label="This is a remote branch that you don't have a virtual branch tracking yet"
>
<IconRemote class="h-4 w-4" /> <IconRemote class="h-4 w-4" />
</Tooltip>
{:else} {:else}
<Tooltip label="This is a local branch that is not a virtual branch yet">
<IconGitBranch class="h-4 w-4" /> <IconGitBranch class="h-4 w-4" />
</Tooltip>
{/if} {/if}
</div> </div>
<div class="flex-grow truncate text-black dark:text-white" title={branch.name}> <div class="flex-grow truncate text-black dark:text-white" title={branch.name}>
@ -233,15 +249,32 @@
.replace('origin/', '') .replace('origin/', '')
.replace('refs/heads/', '')} .replace('refs/heads/', '')}
</div> </div>
<div>{branch.ahead}/{branch.behind}</div> <button
class="h-8 w-8 flex-grow-0 p-2 text-light-600 transition-colors hover:bg-zinc-300 dark:text-dark-200 dark:hover:bg-zinc-800"
on:keydown={(e) => remoteBranchContextMenu.openByMouse(e, branch)}
on:click={(e) => remoteBranchContextMenu.openByMouse(e, branch)}
>
<IconMeatballMenu />
</button>
</div>
<div
class="flex flex-row justify-between space-x-2 rounded bg-light-100 p-1 pr-1 text-light-700 dark:bg-dark-700 dark:text-dark-300"
>
<div class="flex-grow-0 text-sm">
{formatDistanceToNow(branch.lastCommitTs * 1000)}
</div>
<div class="flex flex-grow-0 flex-row space-x-2">
<Tooltip
label="This branch has {branch.ahead} commits not on your base branch and your base has {branch.behind} commits not on this branch yet"
>
<div class="text-sm">{branch.ahead}/{branch.behind}</div>
</Tooltip>
{#if !branch.mergeable} {#if !branch.mergeable}
<div class="font-bold text-red-500" title="Can't be merged">!</div> <div class="font-bold text-red-500" title="Can't be merged">!</div>
{/if} {/if}
</div> </div>
<div class="flex flex-row justify-between pr-1 text-light-700 dark:text-dark-300">
<div class="text-sm">{formatDistanceToNow(branch.lastCommitTs * 1000)}</div>
<div <div
class="isolate flex -space-x-2 overflow-hidden transition duration-300 ease-in-out hover:space-x-1 hover:transition hover:ease-in" class="isolate flex flex-grow justify-end -space-x-2 overflow-hidden transition duration-300 ease-in-out hover:space-x-1 hover:transition hover:ease-in"
> >
{#each branch.authors as author} {#each branch.authors as author}
<img <img

View File

@ -149,8 +149,20 @@
<!-- Confirm target update modal --> <!-- Confirm target update modal -->
<Modal width="small" bind:this={updateTargetModal}> <Modal width="small" bind:this={updateTargetModal}>
<svelte:fragment slot="title">Update target</svelte:fragment> <svelte:fragment slot="title">Merge Upstream Work</svelte:fragment>
<p>You are about to update the base branch.</p> <div class="flex flex-col space-y-2">
<p class="text-blue-600">You are about to merge upstream work from your base branch.</p>
<p class="font-bold">What will this do?</p>
<p>
We will try to merge the work that is upstream into each of your virtual branches, so that
they are all up to date.
</p>
<p>
Any virtual branches that we can't merge cleanly, we will unapply and mark with a blue dot.
You can merge these manually later.
</p>
<p>Any virtual branches that are fully integrated upstream will be automatically removed.</p>
</div>
<svelte:fragment slot="controls" let:close> <svelte:fragment slot="controls" let:close>
<Button height="small" kind="outlined" on:click={close}>Cancel</Button> <Button height="small" kind="outlined" on:click={close}>Cancel</Button>
<Button <Button
@ -161,7 +173,7 @@
close(); close();
}} }}
> >
Update Merge Upstream
</Button> </Button>
</svelte:fragment> </svelte:fragment>
</Modal> </Modal>

View File

@ -102,9 +102,16 @@ const config = {
900: '#1e3a8a' 900: '#1e3a8a'
}, },
yellow: { yellow: {
400: '#facc15', 50: '#FFFBE6',
500: '#eab308', 100: '#FFF7CC',
900: '#713f12' 200: '#FEF0A2',
300: '#FDE978',
400: '#FACC15',
500: '#EAB308',
600: '#C19206',
700: '#987105',
800: '#6F5004',
900: '#713F12',
}, },
red: { red: {
400: '#F87171', 400: '#F87171',