feat(webui): 🚧 selection via ctrl+drag
ci/woodpecker/push/woodpecker Pipeline was successful Details

pull/79/head
Tomáš Mládek 2023-10-21 22:53:36 +02:00
parent de8d6b1c59
commit 377f0af161
4 changed files with 134 additions and 2 deletions

View File

@ -0,0 +1,92 @@
<script lang="ts" context="module">
import { writable } from "svelte/store";
export const selected = writable<string[]>([]);
</script>
<script lang="ts">
import { onMount } from "svelte";
let canvas: HTMLCanvasElement;
onMount(() => {
const ctx = canvas.getContext("2d");
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener("resize", resizeCanvas);
resizeCanvas();
// if ctrl is pressed while right button is dragged over screen, draw a red line on canvas
let selecting = false;
document.addEventListener("mousedown", (ev) => {
if (ev.ctrlKey) {
ev.preventDefault();
selecting = true;
ctx.strokeStyle = "#dc322f77";
ctx.lineWidth = 7;
ctx.beginPath();
ctx.moveTo(ev.clientX, ev.clientY);
}
});
document.addEventListener("mousemove", (ev) => {
if (selecting) {
ev.preventDefault();
const el = document.elementFromPoint(
ev.clientX,
ev.clientY,
) as HTMLElement;
const addressElement = el.closest("[data-address]") as
| HTMLElement
| undefined;
if (addressElement) {
const address = addressElement.dataset.address;
selected.update((selected) => {
if (!selected.includes(address)) {
return [...selected, address];
} else {
return selected;
}
});
}
ctx.lineTo(ev.clientX, ev.clientY);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(ev.clientX, ev.clientY);
}
});
document.addEventListener("mouseup", () => {
selecting = false;
ctx.clearRect(0, 0, canvas.width, canvas.height);
});
});
</script>
<div class="selectIndicator">
<canvas bind:this={canvas}></canvas>
</div>
<style lang="scss">
.selectIndicator {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
pointer-events: none;
canvas {
width: 100%;
height: 100%;
}
}
</style>

View File

@ -0,0 +1,20 @@
<script lang="ts">
import { i18n } from "../i18n";
import { selected } from "./EntitySelect.svelte";
import EntityList from "./widgets/EntityList.svelte";
</script>
<div class="view">
<h1>{$i18n.t("Selected entities")}</h1>
<EntityList entities={$selected} />
</div>
<style lang="scss">
.view {
background: var(--background-lighter);
color: var(--foreground-lighter);
border: 1px solid var(--foreground-lightest);
border-radius: 0.5em;
padding: 1rem;
}
</style>

View File

@ -7,12 +7,12 @@
import UpObjectCard from "../display/UpObjectCard.svelte";
import { ATTR_LABEL } from "@upnd/upend/constants";
import { i18n } from "../../i18n";
import Icon from "../utils/Icon.svelte";
import IconButton from "../utils/IconButton.svelte";
import Selector from "../utils/Selector.svelte";
import { createEventDispatcher } from "svelte";
import type { WidgetChange } from "src/types/base";
import debug from "debug";
import { selected } from "../EntitySelect.svelte";
const dispatch = createEventDispatcher();
const dbg = debug(`kestrel:EntityList`);
@ -169,7 +169,12 @@
{/if}
<div class="items">
{#each sortedEntities as entity (entity)}
<div data-address={entity} use:observe class="item">
<div
data-address={entity}
use:observe
class="item"
class:selected={$selected.includes(entity)}
>
{#if visible.has(entity)}
{#if thumbnails}
<UpObjectCard
@ -242,6 +247,8 @@
</div>
<style lang="scss">
@use "../../styles/colors";
.items {
gap: 4px;
}
@ -327,4 +334,9 @@
.entitylist.style-grid .add {
grid-column: 1 / -1;
}
.selected {
margin: 0.12rem;
box-shadow: 0 0 0.1rem 0.11rem colors.$red;
}
</style>

View File

@ -3,6 +3,8 @@
import BrowseAdd from "../components/BrowseAdd.svelte";
import BrowseColumn from "../components/BrowseColumn.svelte";
import { updateTitle } from "../util/title";
import EntitySelect, { selected } from "../components/EntitySelect.svelte";
import SelectedColumn from "../components/SelectedColumn.svelte";
const navigate = useNavigate();
const params = useParams();
@ -57,6 +59,7 @@
}
detailMode = addresses.length === 1 && ev.detail;
}
$: if ($selected.length) detailMode = false;
$: updateTitle("Browse", identities.join(" / "));
</script>
@ -78,6 +81,9 @@
/>
</div>
{/each}
{#if $selected.length}
<SelectedColumn />
{/if}
{#if !detailMode}
{#key addresses}
<div class="column" data-index="add">
@ -90,6 +96,8 @@
{/if}
</div>
<EntitySelect />
<style lang="scss">
.browser {
height: 100%;