lane style updates

This commit is contained in:
Pavel Laptev 2024-01-23 16:38:46 +01:00 committed by GitButler
parent 7f0434cbb1
commit db309df701
5 changed files with 278 additions and 253 deletions

View File

@ -205,9 +205,10 @@
flex-shrink: 1; flex-shrink: 1;
align-items: flex-start; align-items: flex-start;
height: 100%; height: 100%;
padding: 0 var(--space-8); /* padding: 0 var(--space-8); */
user-select: none; user-select: none;
} }
.loading { .loading {
display: flex; display: flex;
justify-content: center; justify-content: center;

View File

@ -142,143 +142,164 @@
} }
</script> </script>
<div bind:this={rsViewport} class="branch-card resize-viewport" data-tauri-drag-region> <div class="branch-card" data-tauri-drag-region class:target-branch={branch.selectedForChanges}>
<ScrollableContainer> <div
<div style:width={`${laneWidth || $defaultBranchWidthRem}rem`} class="branch-card__contents"> bind:this={rsViewport}
<BranchHeader style:width={`${laneWidth || $defaultBranchWidthRem}rem`}
{readonly} class="branch-card__contents"
{branchController} class:first-child={branch.order == 0}
{branch} >
{base} <BranchHeader
{githubService} {readonly}
projectId={project.id} {branchController}
on:action={(e) => { {branch}
if (e.detail == 'generate-branch-name') { {base}
generateBranchName(); {githubService}
} projectId={project.id}
}} on:action={(e) => {
/> if (e.detail == 'generate-branch-name') {
<!-- DROPZONES --> generateBranchName();
}
}}
/>
<!-- DROPZONES -->
<DropzoneOverlay class="cherrypick-dz-marker" label="Apply here" />
<DropzoneOverlay class="lane-dz-marker" label="Move here" />
<div
class="branch-card__dropzone-wrapper"
use:dropzone={{
hover: 'cherrypick-dz-hover',
active: 'cherrypick-dz-active',
accepts: acceptCherrypick,
onDrop: onCherrypicked
}}
use:dropzone={{
hover: 'lane-dz-hover',
active: 'lane-dz-active',
accepts: acceptBranchDrop,
onDrop: onBranchDrop
}}
>
<DropzoneOverlay class="cherrypick-dz-marker" label="Apply here" /> <DropzoneOverlay class="cherrypick-dz-marker" label="Apply here" />
<DropzoneOverlay class="lane-dz-marker" label="Move here" /> <DropzoneOverlay class="lane-dz-marker" label="Move here" />
{#if branch.files?.length > 0}
<div <div class="card">
class="branch-card__dropzone-wrapper" <BranchFiles
use:dropzone={{ {branch}
hover: 'cherrypick-dz-hover', {readonly}
active: 'cherrypick-dz-active', {selectedOwnership}
accepts: acceptCherrypick, {selectedFiles}
onDrop: onCherrypicked showCheckboxes={$commitBoxOpen}
}} />
use:dropzone={{ {#if branch.active}
hover: 'lane-dz-hover', <CommitDialog
active: 'lane-dz-active', projectId={project.id}
accepts: acceptBranchDrop, {branchController}
onDrop: onBranchDrop
}}
>
<DropzoneOverlay class="cherrypick-dz-marker" label="Apply here" />
<DropzoneOverlay class="lane-dz-marker" label="Move here" />
{#if branch.files?.length > 0}
<div class="card">
<BranchFiles
{branch} {branch}
{readonly} {cloud}
{selectedOwnership} {selectedOwnership}
{selectedFiles} {user}
showCheckboxes={$commitBoxOpen} bind:expanded={commitBoxOpen}
on:action={(e) => {
if (e.detail == 'generate-branch-name') {
generateBranchName();
}
}}
/> />
{#if branch.active} {/if}
<CommitDialog </div>
projectId={project.id} {:else if branch.commits.length == 0}
{branchController} <div class="new-branch card" data-dnd-ignore>
{branch} <div class="new-branch__content">
{cloud} <div class="new-branch__image">
{selectedOwnership} <ImgThemed
{user} imgSet={{
bind:expanded={commitBoxOpen} light: '/images/lane-new-light.webp',
on:action={(e) => { dark: '/images/lane-new-dark.webp'
if (e.detail == 'generate-branch-name') {
generateBranchName();
}
}} }}
/> />
{/if}
</div>
{:else if branch.commits.length == 0}
<div class="new-branch card" data-dnd-ignore>
<div class="new-branch__content">
<div class="new-branch__image">
<ImgThemed
imgSet={{
light: '/images/lane-new-light.webp',
dark: '/images/lane-new-dark.webp'
}}
/>
</div>
<h2 class="new-branch__title text-base-body-15 text-semibold">
This is a new branch.
</h2>
<p class="new-branch__caption text-base-body-13">
You can drag and drop files or parts of files here.
</p>
</div> </div>
<h2 class="new-branch__title text-base-body-15 text-semibold">This is a new branch.</h2>
<p class="new-branch__caption text-base-body-13">
You can drag and drop files or parts of files here.
</p>
</div> </div>
{:else} </div>
<!-- attention: these markers have custom css at the bottom of thise file --> {:else}
<div class="no-changes card" data-dnd-ignore> <!-- attention: these markers have custom css at the bottom of thise file -->
<div class="new-branch__content"> <div class="no-changes card" data-dnd-ignore>
<div class="new-branch__image"> <div class="new-branch__content">
<ImgThemed <div class="new-branch__image">
imgSet={{ <ImgThemed
light: '/images/lane-no-changes-light.webp', imgSet={{
dark: '/images/lane-no-changes-dark.webp' light: '/images/lane-no-changes-light.webp',
}} dark: '/images/lane-no-changes-dark.webp'
/> }}
</div> />
<h2 class="new-branch__caption text-base-body-13">
No uncommitted changes<br />on this branch
</h2>
</div> </div>
<h2 class="new-branch__caption text-base-body-13">
No uncommitted changes<br />on this branch
</h2>
</div> </div>
{/if} </div>
</div> {/if}
<BranchCommits
{base}
{branch}
{project}
{githubService}
{branchController}
{branchCount}
{readonly}
/>
</div> </div>
</ScrollableContainer> <BranchCommits
{base}
{branch}
{project}
{githubService}
{branchController}
{branchCount}
{readonly}
/>
<Resizer <Resizer
viewport={rsViewport} viewport={rsViewport}
direction="right" direction="right"
inside={$selectedFiles.length > 0} inside={$selectedFiles.length > 0}
minWidth={320} minWidth={320}
on:width={(e) => { on:width={(e) => {
laneWidth = e.detail / (16 * $userSettings.zoom); laneWidth = e.detail / (16 * $userSettings.zoom);
lscache.set(laneWidthKey + branch.id, laneWidth, 7 * 1440); // 7 day ttl lscache.set(laneWidthKey + branch.id, laneWidth, 7 * 1440); // 7 day ttl
$defaultBranchWidthRem = laneWidth; $defaultBranchWidthRem = laneWidth;
}} }}
/> />
</div>
<slot name="file-view" />
</div> </div>
<style lang="postcss"> <style lang="postcss">
.resize-viewport { .branch-card {
height: 100%; height: 100%;
position: relative; position: relative;
display: flex; display: flex;
--target-branch-background: var(--clr-theme-container-pale);
display: flex;
/* flex-direction: column; */
user-select: none;
overflow-x: hidden;
overflow-y: scroll;
/* padding: 8px; */
/* border-radius: var(--radius-l); */
background-color: var(--target-branch-background);
/* remover scrollbar */
&::-webkit-scrollbar {
width: 0px;
background: transparent; /* Chrome/Safari/Webkit */
}
} }
.branch-card { .target-branch {
display: flex; --target-branch-background: color-mix(
flex-direction: column; in srgb,
user-select: none; var(--clr-theme-scale-pop-60) 30%,
var(--clr-theme-container-pale)
);
} }
.branch-card__dropzone-wrapper { .branch-card__dropzone-wrapper {
@ -286,15 +307,15 @@
} }
.branch-card__contents { .branch-card__contents {
position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding-top: 20px;
gap: var(--space-4); gap: var(--space-4);
padding: var(--space-16) var(--space-8) var(--space-16) var(--space-8); padding: var(--space-8);
} }
.resize-viewport { .first-child {
position: relative; /* padding-left: var(--space-16); */
} }
.new-branch__content { .new-branch__content {

View File

@ -148,7 +148,7 @@
.header__wrapper { .header__wrapper {
z-index: 10; z-index: 10;
position: sticky; position: sticky;
top: var(--space-16); top: var(--space-8);
} }
.header { .header {
z-index: 2; z-index: 2;
@ -170,7 +170,7 @@
left: 0; left: 0;
width: 100%; width: 100%;
height: var(--space-20); height: var(--space-20);
background: var(--clr-theme-container-pale); background: var(--target-branch-background);
/* background-color: red; */ /* background-color: red; */
} }
.header__info { .header__info {

View File

@ -49,24 +49,26 @@
{user} {user}
{selectedFiles} {selectedFiles}
{githubService} {githubService}
/> >
<svelte:fragment slot="file-view">
{#if selected} {#if selected}
<FileCard <FileCard
conflicted={selected.conflicted} conflicted={selected.conflicted}
branchId={branch.id} branchId={branch.id}
file={selected} file={selected}
projectId={project.id} projectId={project.id}
{projectPath} {projectPath}
{branchController} {branchController}
{selectedOwnership} {selectedOwnership}
selectable={$commitBoxOpen && !readonly} selectable={$commitBoxOpen && !readonly}
on:close={() => { on:close={() => {
const selectedId = selected?.id; const selectedId = selected?.id;
selectedFiles.update((fileIds) => fileIds.filter((file) => file.id != selectedId)); selectedFiles.update((fileIds) => fileIds.filter((file) => file.id != selectedId));
}} }}
/> />
{/if} {/if}
</svelte:fragment>
</BranchCard>
</div> </div>
<style lang="postcss"> <style lang="postcss">

View File

@ -131,137 +131,138 @@
</div> </div>
{/if} {/if}
<ScrollableContainer wide> <div class="hunks">
<div class="hunks"> {#if file.binary}
{#if file.binary} Binary content not shown
Binary content not shown {:else if file.large}
{:else if file.large} Diff too large to be shown
Diff too large to be shown {:else}
{:else} {#each sections as section}
{#each sections as section} {@const { added, removed } = computedAddedRemoved(section)}
{@const { added, removed } = computedAddedRemoved(section)} {#if 'hunk' in section}
{#if 'hunk' in section} <div class="hunk-wrapper">
<div class="hunk-wrapper"> <div class="indicators text-base-11">
<div class="indicators text-base-11"> <span class="added">+{added}</span>
<span class="added">+{added}</span> <span class="removed">+{removed}</span>
<span class="removed">+{removed}</span> {#if section.hunk.locked}
{#if section.hunk.locked} <div title={section.hunk.lockedTo}>
<div title={section.hunk.lockedTo}> <Icon name="locked-small" color="warn" />
<Icon name="locked-small" color="warn" /> </div>
</div> {/if}
{/if} </div>
</div> <div
<div tabindex="0"
tabindex="0" role="cell"
role="cell" use:draggable={{
use:draggable={{ ...draggableHunk(branchId, section.hunk),
...draggableHunk(branchId, section.hunk), disabled: readonly || section.hunk.locked
disabled: readonly || section.hunk.locked }}
}} on:dblclick
on:dblclick class="hunk"
class="hunk" class:opacity-60={section.hunk.locked && !isFileLocked}
class:opacity-60={section.hunk.locked && !isFileLocked} >
> <div class="hunk__inner custom-scrollbar">
<div class="hunk__inner custom-scrollbar"> <div class="hunk__inner_inner">
<div class="hunk__inner_inner"> {#each section.subSections as subsection, sidx}
{#each section.subSections as subsection, sidx} {@const hunk = section.hunk}
{@const hunk = section.hunk} {#each subsection.lines.slice(0, subsection.expanded ? subsection.lines.length : 0) as line}
{#each subsection.lines.slice(0, subsection.expanded ? subsection.lines.length : 0) as line} <RenderedLine
<RenderedLine {line}
{line} {minWidth}
{minWidth} {selectable}
{selectable} selected={$selectedOwnership.containsHunk(hunk.filePath, hunk.id)}
selected={$selectedOwnership.containsHunk(hunk.filePath, hunk.id)} on:selected={(e) => onHunkSelected(hunk, e.detail)}
on:selected={(e) => onHunkSelected(hunk, e.detail)} sectionType={subsection.sectionType}
sectionType={subsection.sectionType} filePath={file.path}
filePath={file.path} on:contextmenu={(e) =>
on:contextmenu={(e) => popupMenu.openByMouse(e, {
popupMenu.openByMouse(e, { hunk,
hunk, section: subsection,
section: subsection, lineNumber: line.afterLineNumber
lineNumber: line.afterLineNumber ? line.afterLineNumber
? line.afterLineNumber : line.beforeLineNumber
: line.beforeLineNumber })}
})} />
/>
{/each}
{#if !subsection.expanded}
<div
role="group"
class="border-color-3 flex w-full"
class:border-t={sidx == section.subSections.length - 1 ||
(sidx > 0 && sidx < section.subSections.length - 1)}
class:border-b={sidx == 0 ||
(sidx > 0 && sidx < section.subSections.length - 1)}
on:contextmenu|preventDefault={(e) =>
popupMenu.openByMouse(e, {
section: section,
hunk
})}
>
<div
class="bg-color-4 text-color-4 hover:text-color-2 border-color-3 border-r text-center"
style:min-width={`calc(${2 * minWidth}rem - 1px)`}
>
<button
class="flex justify-center py-0.5 text-sm"
style:width={`calc(${2 * minWidth}rem - 1px)`}
on:click={() => {
if ('expanded' in subsection) {
subsection.expanded = true;
}
}}
>
{#if sidx == 0}
<IconExpandUp />
{:else if sidx == section.subSections.length - 1}
<IconExpandDown />
{:else}
<IconExpandUpDown />
{/if}
</button>
</div>
<div class="bg-color-4 flex-grow" />
</div>
{/if}
{/each} {/each}
</div> {#if !subsection.expanded}
<div
role="group"
class="border-color-3 flex w-full"
class:border-t={sidx == section.subSections.length - 1 ||
(sidx > 0 && sidx < section.subSections.length - 1)}
class:border-b={sidx == 0 ||
(sidx > 0 && sidx < section.subSections.length - 1)}
on:contextmenu|preventDefault={(e) =>
popupMenu.openByMouse(e, {
section: section,
hunk
})}
>
<div
class="bg-color-4 text-color-4 hover:text-color-2 border-color-3 border-r text-center"
style:min-width={`calc(${2 * minWidth}rem - 1px)`}
>
<button
class="flex justify-center py-0.5 text-sm"
style:width={`calc(${2 * minWidth}rem - 1px)`}
on:click={() => {
if ('expanded' in subsection) {
subsection.expanded = true;
}
}}
>
{#if sidx == 0}
<IconExpandUp />
{:else if sidx == section.subSections.length - 1}
<IconExpandDown />
{:else}
<IconExpandUpDown />
{/if}
</button>
</div>
<div class="bg-color-4 flex-grow" />
</div>
{/if}
{/each}
</div> </div>
</div> </div>
</div> </div>
{/if} </div>
{/each} {/if}
{/if} {/each}
</div> {/if}
</ScrollableContainer> </div>
<Resizer
viewport={rsViewport}
direction="right"
inside
minWidth={240}
on:width={(e) => {
fileWidth = e.detail / (16 * $userSettings.zoom);
lscache.set(fileWidthKey + file.id, fileWidth, 7 * 1440); // 7 day ttl
$defaultFileWidthRem = fileWidth;
}}
/>
</div> </div>
<Resizer
viewport={rsViewport}
direction="right"
inside
minWidth={240}
on:width={(e) => {
fileWidth = e.detail / (16 * $userSettings.zoom);
lscache.set(fileWidthKey + file.id, fileWidth, 7 * 1440); // 7 day ttl
$defaultFileWidthRem = fileWidth;
}}
/>
</div> </div>
<style lang="postcss"> <style lang="postcss">
.resize-viewport { .resize-viewport {
position: relative; position: sticky;
top: 0;
display: flex; display: flex;
height: 100%; height: 100%;
align-items: self-start; align-items: self-start;
overflow: hidden; overflow: hidden;
padding: var(--space-16) var(--space-6); padding: var(--space-8) var(--space-8) var(--space-8) 0;
margin-left: calc(var(--space-4) * -1);
} }
.file-card { .file-card {
background: var(--clr-theme-container-light); background: var(--clr-theme-container-light);
overflow: hidden; overflow: hidden;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%;
max-height: 100%; max-height: 100%;
} }
.hunks { .hunks {