purge branch re-order

This commit is contained in:
Nikita Galaiko 2023-11-06 13:44:55 +01:00 committed by GitButler
parent f4f140afa5
commit 26800a81c6
8 changed files with 6 additions and 232 deletions

View File

@ -1,175 +0,0 @@
const zoneMap = new Map<string, Set<HTMLElement>>();
const optionsMap = new Map<HTMLElement, DzOptions>();
export interface DzOptions {
type: string;
hover: string;
active: string;
}
const defaultOptions: DzOptions = {
hover: 'drop-zone-hover',
active: 'drop-zone-active',
type: 'default'
};
function inactivateZones(zones: Set<HTMLElement>) {
zones?.forEach((zone) => {
const opts = optionsMap.get(zone);
opts && zone.classList.remove(opts.active);
});
}
function activateZones(zones: Set<HTMLElement>, activeZone: HTMLElement) {
zones?.forEach((zone) => {
if (zone !== activeZone && !isChildOf(activeZone, zone)) {
const opts = optionsMap.get(zone);
opts && zone.classList.add(opts.active);
}
});
}
function getZones(type: string): Set<HTMLElement> {
let zones = zoneMap.get(type);
if (!zones) {
zones = new Set([]);
zoneMap.set(type, zones);
}
return zones;
}
function isChildOf(child: any, parent: HTMLElement): boolean {
if (parent === child) return false;
if (!child.parentElement) return false;
if (child.parentElement == parent) return true;
return isChildOf(child.parentElement, parent);
}
export function dzTrigger(node: HTMLElement, opts: Partial<DzOptions> | undefined) {
const options = { ...defaultOptions, ...opts };
const zones = getZones(options.type);
let clone: HTMLElement;
/**
* The problem with the ghost element is that it gets clipped after rotation unless we enclose
* it within a larger bounding box. This means we have an extra `<div>` in the html that is
* only present to support the rotation
*/
function handleDragStart(e: DragEvent) {
// Start by cloning the node for the ghost element
clone = node.cloneNode(true) as HTMLElement;
clone.style.position = 'absolute';
clone.style.top = '-9999px'; // Element has to be in the DOM so we move it out of sight
clone.style.display = 'inline-block';
clone.style.padding = '30px'; // To prevent clipping of rotated element
// Style the inner node so it retains the shape and then rotate
const inner = clone.children[0] as HTMLElement;
inner.style.height = node.clientHeight + 'px';
inner.style.width = node.clientWidth + 'px';
inner.style.rotate = `${Math.floor(Math.random() * 3)}deg`;
document.body.appendChild(clone);
// Dim the original element while dragging
node.style.opacity = '0.6';
e.dataTransfer?.setDragImage(clone, e.offsetX + 30, e.offsetY + 30); // Adds the padding
activateZones(zones, node);
e.stopPropagation();
}
function handleDragEnd(e: DragEvent) {
node.style.opacity = '1'; // Undo the dimming from `dragstart`
clone.remove(); // Remove temporary ghost element
e.stopPropagation();
inactivateZones(zones);
}
node.addEventListener('dragstart', handleDragStart);
node.addEventListener('dragend', handleDragEnd);
return {
destroy() {
node.removeEventListener('dragstart', handleDragStart);
node.removeEventListener('dragend', handleDragEnd);
}
};
}
export function dzHighlight(node: HTMLElement, opts: Partial<DzOptions> | undefined) {
const options = { ...defaultOptions, ...opts };
const zones = getZones(options.type);
zones.add(node);
optionsMap.set(node, options);
function setHover(value: boolean) {
if (value) {
// We do this so we can set pointer-events-none on all dropzones from main css file,
// without it onMouseLeave fires every time a child container is left.
node.classList.add(defaultOptions.hover);
node.classList.add(options.hover);
} else {
node.classList.remove(defaultOptions.hover);
node.classList.remove(options.hover);
}
}
function handleDragEnter(e: DragEvent) {
if (!e.dataTransfer?.types.includes(options.type)) {
return;
}
setHover(true);
e.stopPropagation();
}
function handleDragLeave(e: DragEvent) {
if (!e.dataTransfer?.types.includes(options.type)) {
return;
}
if (!isChildOf(e.target, node)) {
setHover(false);
}
e.stopPropagation();
}
function handleDragEnd(e: DragEvent) {
setHover(false);
inactivateZones(zones);
e.stopPropagation();
}
function handleDrop(e: DragEvent) {
if (!e.dataTransfer?.types.includes(options.type)) {
return;
}
setHover(false);
inactivateZones(zones);
}
function handleDragOver(e: DragEvent) {
if (!e.dataTransfer?.types.includes(options.type)) {
e.stopImmediatePropagation(); // Stops event from reaching `on:dragover` on the element
}
if (e.dataTransfer?.types.includes(options.type)) e.preventDefault();
}
node.addEventListener('dragend', handleDragEnd);
node.addEventListener('dragenter', handleDragEnter);
node.addEventListener('dragleave', handleDragLeave);
node.addEventListener('dragover', handleDragOver);
node.addEventListener('drop', handleDrop);
node.classList.add('drop-zone');
return {
destroy() {
node.removeEventListener('dragend', handleDragEnd);
node.removeEventListener('dragenter', handleDragEnter);
node.removeEventListener('dragleave', handleDragLeave);
node.removeEventListener('dragover', handleDragOver);
node.removeEventListener('drop', handleDrop);
zones?.delete(node);
}
};
}

View File

@ -88,7 +88,7 @@
<p class="mb-2 w-full overflow-hidden font-semibold">Commits</p>
<div class="flex w-full flex-col gap-y-2">
{#each branch.commits as commit}
<CommitCard branchId={branch.id} {commit} {projectId} />
<CommitCard {commit} {projectId} />
{/each}
</div>
</div>

View File

@ -2,7 +2,6 @@
import BranchLane from '../components/BranchLane.svelte';
import NewBranchDropZone from './NewBranchDropZone.svelte';
import type { BaseBranch, Branch } from '$lib/vbranches/types';
import { dzHighlight } from '$lib/utils/dropZone';
import type { BranchController } from '$lib/vbranches/branchController';
import type { getCloudApiClient } from '$lib/backend/cloud';
import type { LoadState } from '@square/svelte-store';
@ -25,13 +24,6 @@
export let githubContext: GitHubIntegrationContext | undefined;
let dragged: any;
let dropZone: HTMLDivElement;
let priorPosition = 0;
let dropPosition = 0;
const dzType = 'text/branch';
function handleEmpty() {
const emptyIndex = branches?.findIndex((item) => !item.files || item.files.length == 0);
if (emptyIndex && emptyIndex != -1) {
@ -48,52 +40,9 @@
{:else if branchesState.isError || baseBranchState.isError}
<div class="p-4">Something went wrong...</div>
{:else if branches}
<div
bind:this={dropZone}
id="branch-lanes"
class="bg-color-2 flex h-full flex-shrink flex-grow items-start"
role="group"
use:dzHighlight={{ type: dzType, active: 'board-dz-active', hover: 'board-dz-hover' }}
on:dragover={(e) => {
const children = [...e.currentTarget.children];
dropPosition = 0;
// We account for the NewBranchDropZone by subtracting 2
for (let i = 0; i < children.length - 2; i++) {
const pos = children[i].getBoundingClientRect();
if (e.clientX > pos.left + pos.width) {
dropPosition = i + 1; // Note that this is declared in the <script>
} else {
break;
}
}
const idx = children.indexOf(dragged);
if (idx != dropPosition) {
idx >= dropPosition
? children[dropPosition].before(dragged)
: children[dropPosition].after(dragged);
}
}}
on:drop={() => {
if (!branches) return;
if (priorPosition != dropPosition) {
const el = branches.splice(priorPosition, 1);
branches.splice(dropPosition, 0, ...el);
branches.forEach((branch, i) => {
if (branch.order !== i) {
branchController.updateBranchOrder(branch.id, i);
}
});
}
}}
>
<div id="branch-lanes" class="bg-color-2 flex h-full flex-shrink flex-grow items-start">
{#each branches.filter((c) => c.active) as branch (branch.id)}
<BranchLane
on:dragstart={(e) => {
if (!e.dataTransfer) return;
e.dataTransfer.setData(dzType, branch.id);
dragged = e.currentTarget;
priorPosition = Array.from(dropZone.children).indexOf(dragged);
}}
on:empty={handleEmpty}
{branch}
{projectId}

View File

@ -1,5 +1,5 @@
<script lang="ts">
import { dropzone } from '$lib/dragable';
import { dropzone } from '$lib/utils/dragable';
import type { BranchController } from '$lib/vbranches/branchController';
import type { File, Hunk } from '$lib/vbranches/types';

View File

@ -1,5 +1,5 @@
<script lang="ts">
import { dropzone } from '$lib/dragable';
import { dropzone } from '$lib/utils/dragable';
import type { Hunk, File, RemoteCommit } from '$lib/vbranches/types';
import type { BranchController } from '$lib/vbranches/branchController';
import CommitCard from './CommitCard.svelte';

View File

@ -2,7 +2,7 @@
import { userStore } from '$lib/stores/user';
import type { BaseBranch, Branch, File, Hunk, RemoteCommit } from '$lib/vbranches/types';
import { getContext, onDestroy, onMount } from 'svelte';
import { dragable, dropzone } from '$lib/dragable';
import { dragable, dropzone } from '$lib/utils/dragable';
import { Ownership } from '$lib/vbranches/ownership';
import IconKebabMenu from '$lib/icons/IconKebabMenu.svelte';
import CommitCard from './CommitCard.svelte';

View File

@ -2,7 +2,7 @@
import { ContentSection, HunkSection, parseFileSections } from './fileSections';
import { createEventDispatcher, onDestroy } from 'svelte';
import type { File, Hunk } from '$lib/vbranches/types';
import { dragable } from '$lib/dragable';
import { dragable } from '$lib/utils/dragable';
import type { Ownership } from '$lib/vbranches/ownership';
import type { Writable } from 'svelte/store';
import RenderedLine from './RenderedLine.svelte';