mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-01 20:45:57 +03:00
Use branch lane for peeking at vbranches
- makes it more of a preview - experimental still, likely good direction - other trays should be styled in a similar direction
This commit is contained in:
parent
142a9a2c9a
commit
ac34a48f02
@ -67,6 +67,7 @@
|
||||
let targetChoice: string | undefined;
|
||||
let deltasUnsubscribe: (() => void) | undefined;
|
||||
let trayViewport: HTMLElement;
|
||||
let peekTrayExpanded: boolean;
|
||||
|
||||
// Used to prevent peek tray from showing while reducing tray size
|
||||
let peekTransitionsDisabled = false;
|
||||
@ -104,6 +105,9 @@
|
||||
{baseBranchStore}
|
||||
{branchController}
|
||||
{peekTransitionsDisabled}
|
||||
bind:peekTrayExpanded
|
||||
{cloud}
|
||||
{projectId}
|
||||
/>
|
||||
</div>
|
||||
<Resizer
|
||||
@ -144,7 +148,8 @@
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
class="lane-scroll flex flex-grow gap-1 overflow-x-auto overflow-y-hidden overscroll-none bg-light-300 dark:bg-dark-1100"
|
||||
class="lane-scroll flex flex-grow gap-1 overflow-x-auto overflow-y-hidden overscroll-none bg-light-300 duration-300 dark:bg-dark-1100"
|
||||
style:opacity={peekTrayExpanded ? '0.5' : undefined}
|
||||
>
|
||||
<Board
|
||||
branches={$branchesWithContent}
|
||||
|
@ -48,12 +48,14 @@
|
||||
});
|
||||
|
||||
export let branch: Branch;
|
||||
export let readonly = false;
|
||||
export let projectPath: string;
|
||||
export let projectId: string;
|
||||
export let base: BaseBranch | undefined;
|
||||
export let cloudEnabled: boolean;
|
||||
export let cloud: ReturnType<typeof getCloudApiClient>;
|
||||
export let branchController: BranchController;
|
||||
export let maximized = false;
|
||||
|
||||
const user = userStore;
|
||||
const userSettings = getContext<SettingsStore>(SETTINGS_CONTEXT);
|
||||
@ -65,7 +67,6 @@
|
||||
$: messageRows = Math.min(Math.max(commitMessage ? commitMessage.split('\n').length : 0, 1), 10);
|
||||
|
||||
let allExpanded: boolean | undefined;
|
||||
let maximized = false;
|
||||
let isPushing = false;
|
||||
let meatballButton: HTMLDivElement;
|
||||
let textAreaInput: HTMLTextAreaElement;
|
||||
@ -212,8 +213,8 @@
|
||||
|
||||
<div
|
||||
class="flex h-full shrink-0 snap-center"
|
||||
style:width={`${laneWidth}px`}
|
||||
draggable="true"
|
||||
style:width={maximized ? '100%' : `${laneWidth}px`}
|
||||
draggable={!readonly}
|
||||
role="group"
|
||||
use:dzHighlight={{ type: dzType, hover: hoverClass, active: 'drop-zone-active' }}
|
||||
on:dragstart
|
||||
@ -242,57 +243,90 @@
|
||||
bind:this={rsViewport}
|
||||
class="flex flex-grow cursor-default flex-col overflow-x-hidden border-l border-r border-light-400 bg-light-150 dark:border-dark-600 dark:bg-dark-1000 dark:text-dark-100"
|
||||
>
|
||||
<div
|
||||
class="flex bg-light-200 text-light-900 dark:bg-dark-800 dark:font-normal dark:text-dark-100"
|
||||
>
|
||||
<div class="flex text-light-900 dark:bg-dark-800 dark:font-normal dark:text-dark-100">
|
||||
<div class="flex flex-grow flex-col border-b border-light-400 dark:border-dark-600">
|
||||
<div class="flex w-full items-center py-1 pl-1.5">
|
||||
<div bind:this={meatballButton}>
|
||||
<IconButton
|
||||
icon={IconKebabMenu}
|
||||
title=""
|
||||
class="flex h-6 w-3 flex-grow-0 scale-90 items-center justify-center"
|
||||
on:click={() => popupMenu.openByElement(meatballButton, branch.id)}
|
||||
/>
|
||||
{#if !branch.mergeable}
|
||||
<!-- use of relative is for tooltip rendering -->
|
||||
<div class="bg-red-500 px-2 py-0.5 text-center font-bold dark:bg-red-700">
|
||||
<Tooltip label="Canflicts with changes in your working directory, cannot be applied">
|
||||
<span class="text-white">cannot be applied</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{:else if !branch.baseCurrent}
|
||||
<div class="bg-yellow-500 px-2 py-0.5 font-bold dark:bg-yellow-600">
|
||||
<Tooltip label="Will introduce merge conflicts if applied">
|
||||
<span class="">will cause merge conflicts</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex w-full items-center py-1 pl-1.5">
|
||||
{#if !readonly}
|
||||
<div bind:this={meatballButton}>
|
||||
<IconButton
|
||||
icon={IconKebabMenu}
|
||||
title=""
|
||||
class="flex h-6 w-3 flex-grow-0 scale-90 items-center justify-center"
|
||||
on:click={() => popupMenu.openByElement(meatballButton, branch.id)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex-grow pr-2">
|
||||
<input
|
||||
type="text"
|
||||
bind:value={branch.name}
|
||||
on:change={handleBranchNameChange}
|
||||
title={branch.name}
|
||||
class="w-full truncate rounded border border-transparent bg-light-200 px-1 font-mono font-bold text-light-800 hover:border-light-400 dark:bg-dark-800 dark:text-dark-100 dark:hover:border-dark-600"
|
||||
class="w-full truncate rounded border border-transparent bg-transparent px-1 font-mono font-bold text-light-800 hover:border-light-400 dark:text-dark-100 dark:hover:border-dark-600"
|
||||
on:dblclick|stopPropagation
|
||||
on:click={(e) => e.currentTarget.select()}
|
||||
/>
|
||||
</div>
|
||||
<div class:invisible={branch.files.length == 0} transition:fade={{ duration: 150 }}>
|
||||
<Button
|
||||
class="w-20"
|
||||
height="small"
|
||||
kind="outlined"
|
||||
color="purple"
|
||||
disabled={branch.files.length == 0}
|
||||
on:click={() => (commitDialogShown = !commitDialogShown)}
|
||||
{#if !readonly}
|
||||
{#if branch.files.length > 0}
|
||||
<div transition:fade={{ duration: 150 }}>
|
||||
<Button
|
||||
class="w-20"
|
||||
height="small"
|
||||
kind="outlined"
|
||||
color="purple"
|
||||
disabled={branch.files.length == 0}
|
||||
on:click={() => (commitDialogShown = !commitDialogShown)}
|
||||
>
|
||||
<span class="purple">
|
||||
{#if !commitDialogShown}
|
||||
Commit
|
||||
{:else}
|
||||
Cancel
|
||||
{/if}
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
<button
|
||||
class="scale-90 px-2 py-2 text-light-600 hover:text-light-800"
|
||||
title="Stash this branch"
|
||||
on:click={() => {
|
||||
if (branch.id) branchController.unapplyBranch(branch.id);
|
||||
}}
|
||||
>
|
||||
<span class="purple">
|
||||
{#if !commitDialogShown}
|
||||
Commit
|
||||
{:else}
|
||||
Cancel
|
||||
{/if}
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
<button
|
||||
class="scale-90 px-2 py-2 text-light-600 hover:text-light-800"
|
||||
title="Stash this branch"
|
||||
on:click={() => {
|
||||
if (branch.id) branchController.unapplyBranch(branch.id);
|
||||
}}
|
||||
>
|
||||
<IconCloseSmall />
|
||||
</button>
|
||||
<IconCloseSmall />
|
||||
</button>
|
||||
{/if}
|
||||
{#if readonly && branch.mergeable}
|
||||
<div transition:fade={{ duration: 150 }}>
|
||||
<Button
|
||||
class="w-20"
|
||||
height="small"
|
||||
kind="outlined"
|
||||
color="purple"
|
||||
on:click={() => {
|
||||
if (branch.id) branchController.applyBranch(branch.id);
|
||||
}}
|
||||
>
|
||||
<span class="purple"> Apply </span>
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if commitDialogShown}
|
||||
@ -389,7 +423,7 @@
|
||||
name: 'notes',
|
||||
displayName: 'Notes',
|
||||
component: NotesTabPanel,
|
||||
props: { notes: branch.notes, branch: branch.id, branchController }
|
||||
props: { notes: branch.notes, branchId: branch.id, branchController }
|
||||
}
|
||||
]}
|
||||
/>
|
||||
@ -416,7 +450,10 @@
|
||||
Drop here to add to virtual branch
|
||||
</div>
|
||||
{#if branch.files.length > 0}
|
||||
<div class="flex flex-shrink flex-col gap-y-2" transition:slide={{ duration: 150 }}>
|
||||
<div
|
||||
class="flex flex-shrink flex-col gap-y-2"
|
||||
transition:slide={{ duration: readonly ? 0 : 250, axis: 'x' }}
|
||||
>
|
||||
{#each branch.files as file (file.id)}
|
||||
<FileCard
|
||||
expanded={file.expanded}
|
||||
@ -426,6 +463,7 @@
|
||||
{projectId}
|
||||
{projectPath}
|
||||
{branchController}
|
||||
{readonly}
|
||||
on:expanded={(e) => {
|
||||
setExpandedWithCache(file, e.detail);
|
||||
expandFromCache();
|
||||
@ -441,10 +479,12 @@
|
||||
data-dnd-ignore
|
||||
>
|
||||
<p>Nothing on this branch yet.</p>
|
||||
<IconNewBadge class="mx-auto mt-4 h-16 w-16 text-blue-400 dark:text-dark-400" />
|
||||
<p class="px-12 text-light-600">
|
||||
Get some work done, then throw some files my way!
|
||||
</p>
|
||||
{#if !readonly}
|
||||
<IconNewBadge class="mx-auto mt-4 h-16 w-16 text-blue-400 dark:text-dark-400" />
|
||||
<p class="px-12 text-light-600">
|
||||
Get some work done, then throw some files my way!
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<!-- attention: these markers have custom css at the bottom of thise file -->
|
||||
@ -572,14 +612,16 @@
|
||||
<Scrollbar {viewport} {contents} width="0.4rem" />
|
||||
</div>
|
||||
</div>
|
||||
<Resizer
|
||||
minWidth={180}
|
||||
viewport={rsViewport}
|
||||
direction="horizontal"
|
||||
class="z-30"
|
||||
on:width={(e) => {
|
||||
laneWidth = e.detail;
|
||||
lscache.set(laneWidthKey + branch.id, e.detail, 7 * 1440); // 7 day ttl
|
||||
}}
|
||||
/>
|
||||
{#if !maximized}
|
||||
<Resizer
|
||||
minWidth={180}
|
||||
viewport={rsViewport}
|
||||
direction="horizontal"
|
||||
class="z-30"
|
||||
on:width={(e) => {
|
||||
laneWidth = e.detail;
|
||||
lscache.set(laneWidthKey + branch.id, e.detail, 7 * 1440); // 7 day ttl
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -29,6 +29,7 @@
|
||||
export let projectPath: string;
|
||||
export let expanded: boolean | undefined;
|
||||
export let branchController: BranchController;
|
||||
export let readonly = false;
|
||||
|
||||
const userSettings = getContext<SettingsStore>(SETTINGS_CONTEXT);
|
||||
const dispatch = createEventDispatcher<{
|
||||
@ -82,7 +83,7 @@
|
||||
|
||||
<div
|
||||
id={`file-${file.id}`}
|
||||
draggable={!isFileLocked}
|
||||
draggable={!isFileLocked && !readonly}
|
||||
use:dzTrigger={{ type: dzType }}
|
||||
on:dragstart={(e) => e.dataTransfer?.setData('text/hunk', getAllHunksOwnership())}
|
||||
role="group"
|
||||
@ -175,7 +176,7 @@
|
||||
class="my-1 flex w-full flex-col overflow-hidden rounded border border-light-400 bg-white dark:border-dark-400 dark:bg-dark-900"
|
||||
>
|
||||
<div
|
||||
draggable={!section.hunk.locked}
|
||||
draggable={!section.hunk.locked && !readonly}
|
||||
tabindex="0"
|
||||
role="cell"
|
||||
use:dzTrigger={{ type: dzType }}
|
||||
|
@ -4,17 +4,20 @@
|
||||
import type { BranchController } from '$lib/vbranches/branchController';
|
||||
import { BaseBranch, Branch, BranchData } from '$lib/vbranches/types';
|
||||
import { getContext } from 'svelte';
|
||||
import VirtualBranchPeek from './VirtualBranchPeek.svelte';
|
||||
import type { Readable } from '@square/svelte-store';
|
||||
import BaseBranchPeek from './BaseBranchPeek.svelte';
|
||||
import RemoteBranchPeek from './RemoteBranchPeek.svelte';
|
||||
import Resizer from '$lib/components/Resizer.svelte';
|
||||
import Lane from './BranchLane.svelte';
|
||||
import type { getCloudApiClient } from '$lib/api/cloud/api';
|
||||
|
||||
export let item: Readable<BranchData | Branch | BaseBranch | undefined> | undefined;
|
||||
export let cloud: ReturnType<typeof getCloudApiClient>;
|
||||
export let base: BaseBranch | undefined;
|
||||
export let branchController: BranchController;
|
||||
export let expanded: boolean;
|
||||
export let offsetTop: number;
|
||||
export let projectId: string;
|
||||
export let fullHeight = false;
|
||||
export let disabled = false;
|
||||
|
||||
@ -53,8 +56,8 @@
|
||||
style:top={fullHeight ? 0 : `${offsetTop}px`}
|
||||
style:width={`${$userSettings.peekTrayWidth}px`}
|
||||
style:translate={`${offsetLeft}px`}
|
||||
style:transition-property={!disabled ? (expanded ? 'top,translate,height' : 'translate') : 'none'}
|
||||
class="absolute z-30 flex shrink-0 overflow-visible bg-white text-light-800 duration-200 ease-in-out dark:bg-dark-800 dark:text-dark-100"
|
||||
style:transition-property={!disabled ? (expanded ? 'top,translate' : 'translate') : 'none'}
|
||||
class="absolute z-30 flex shrink-0 overflow-visible bg-white text-light-800 duration-300 ease-in-out dark:bg-dark-800 dark:text-dark-100"
|
||||
on:click|stopPropagation
|
||||
on:keydown|stopPropagation
|
||||
role="menu"
|
||||
@ -68,7 +71,17 @@
|
||||
{#if $item instanceof BranchData}
|
||||
<RemoteBranchPeek {branchController} {base} branch={$item} />
|
||||
{:else if $item instanceof Branch}
|
||||
<VirtualBranchPeek {branchController} {base} branch={$item} />
|
||||
<Lane
|
||||
branch={$item}
|
||||
{branchController}
|
||||
{base}
|
||||
{cloud}
|
||||
{projectId}
|
||||
maximized={true}
|
||||
cloudEnabled={false}
|
||||
projectPath=""
|
||||
readonly={true}
|
||||
/>
|
||||
{:else if $item instanceof BaseBranch}
|
||||
<BaseBranchPeek base={$item} {branchController} />
|
||||
{:else}
|
||||
|
@ -21,12 +21,16 @@
|
||||
import IconDelete from '$lib/icons/IconDelete.svelte';
|
||||
import IconAdd from '$lib/icons/IconAdd.svelte';
|
||||
import IconButton from '$lib/components/IconButton.svelte';
|
||||
import type { getCloudApiClient } from '$lib/api/cloud/api';
|
||||
|
||||
export let vbranchStore: Loadable<Branch[] | undefined>;
|
||||
export let remoteBranchStore: Loadable<BranchData[] | undefined>;
|
||||
export let baseBranchStore: Readable<BaseBranch | undefined>;
|
||||
export let branchController: BranchController;
|
||||
export let peekTransitionsDisabled = false;
|
||||
export let projectId: string;
|
||||
export let cloud: ReturnType<typeof getCloudApiClient>;
|
||||
export let peekTrayExpanded = false;
|
||||
|
||||
$: branchesState = vbranchStore?.state;
|
||||
$: remoteBranchesState = remoteBranchStore?.state;
|
||||
@ -48,7 +52,6 @@
|
||||
|
||||
let selectedItem: Readable<Branch | BranchData | BaseBranch | undefined> | undefined;
|
||||
let overlayOffsetTop = 0;
|
||||
let peekTrayExpanded = false;
|
||||
let fetching = false;
|
||||
|
||||
function select(detail: Branch | BranchData | BaseBranch | undefined, i: number): void {
|
||||
@ -58,7 +61,7 @@
|
||||
}
|
||||
if (detail instanceof Branch) {
|
||||
selectedItem = derived(vbranchStore, (branches) =>
|
||||
branches?.find((branch) => branch.id == detail.id)
|
||||
branches?.filter((b) => !b.active).find((branch) => branch.id == detail.id)
|
||||
);
|
||||
const element = vbContents.children[i] as HTMLDivElement;
|
||||
overlayOffsetTop = element.offsetTop + vbViewport.offsetTop - vbViewport.scrollTop;
|
||||
@ -124,6 +127,8 @@
|
||||
fullHeight={true}
|
||||
bind:expanded={peekTrayExpanded}
|
||||
disabled={peekTransitionsDisabled}
|
||||
{cloud}
|
||||
{projectId}
|
||||
/>
|
||||
<div
|
||||
class="z-30 flex w-80 shrink-0 flex-col border-r border-light-200 bg-white text-light-800 dark:border-dark-600 dark:bg-dark-900 dark:text-dark-100"
|
||||
@ -286,7 +291,7 @@
|
||||
/>
|
||||
<IconButton
|
||||
icon={IconAdd}
|
||||
class="scale-90 p-0"
|
||||
class="scale-90 p-0 text-purple-500 hover:text-purple-600 "
|
||||
title="apply branch"
|
||||
on:click={() => {
|
||||
peekTrayExpanded = false;
|
||||
|
Loading…
Reference in New Issue
Block a user