Make resizer snap to closest end and improve toggle (#2129)

* Make resizer snap to closest end and improve toggle

* Snap on window resize

* Remove event parameter

* Remove nested ternary expression
This commit is contained in:
Matthias Metelka 2022-10-13 02:13:19 +02:00 committed by GitHub
parent 0a3d38125d
commit f5abd3c6af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 79 additions and 29 deletions

View file

@ -3,6 +3,9 @@ Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
--> -->
<script lang="ts"> <script lang="ts">
import { createEventDispatcher } from "svelte";
import { fly } from "svelte/transition";
import { on } from "../lib/events"; import { on } from "../lib/events";
import { Callback, singleCallback } from "../lib/typing"; import { Callback, singleCallback } from "../lib/typing";
import IconConstrain from "./IconConstrain.svelte"; import IconConstrain from "./IconConstrain.svelte";
@ -12,8 +15,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export let panes: ResizablePane[]; export let panes: ResizablePane[];
export let index = 0; export let index = 0;
export let tip = ""; export let tip = "";
export let showIndicator = false;
export let clientHeight: number; export let clientHeight: number;
const rtl = window.getComputedStyle(document.body).direction == "rtl";
const dispatch = createEventDispatcher();
let destroy: Callback; let destroy: Callback;
let before: ResizablePane; let before: ResizablePane;
@ -77,18 +85,31 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
destroy = singleCallback( destroy = singleCallback(
on(window, "pointermove", onMove), on(window, "pointermove", onMove),
on(window, "pointerup", releasePointer), on(window, "pointerup", () => {
releasePointer.call(window);
dispatch("release");
}),
); );
} }
</script> </script>
<div <div
class="horizontal-resizer" class="horizontal-resizer"
class:rtl
title={tip} title={tip}
bind:clientHeight={resizerHeight} bind:clientHeight={resizerHeight}
on:pointerdown|preventDefault={lockPointer} on:pointerdown|preventDefault={lockPointer}
on:dblclick on:dblclick|preventDefault
> >
{#if showIndicator}
<div
class="resize-indicator"
transition:fly={{ x: rtl ? 25 : -25, duration: 200 }}
>
<slot />
</div>
{/if}
<div class="drag-handle"> <div class="drag-handle">
<IconConstrain iconSize={80}>{@html horizontalHandle}</IconConstrain> <IconConstrain iconSize={80}>{@html horizontalHandle}</IconConstrain>
</div> </div>
@ -99,7 +120,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
width: 100%; width: 100%;
cursor: row-resize; cursor: row-resize;
position: relative; position: relative;
height: 10px; height: 25px;
border-top: 1px solid var(--border); border-top: 1px solid var(--border);
z-index: 20; z-index: 20;
@ -113,5 +134,15 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
&:hover .drag-handle { &:hover .drag-handle {
opacity: 0.8; opacity: 0.8;
} }
.resize-indicator {
position: absolute;
font-size: small;
bottom: 0;
}
&.rtl .resize-indicator {
padding: 0.5rem 0 0 0.5rem;
right: 0;
}
} }
</style> </style>

View file

@ -59,5 +59,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
.pane { .pane {
@include panes.resizable(column, true, true); @include panes.resizable(column, true, true);
opacity: var(--opacity, 1);
} }
</style> </style>

View file

@ -355,12 +355,28 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
$: tagAmount = $tags.length; $: tagAmount = $tags.length;
let snapTags = $tagsCollapsed;
function collapseTags(): void { function collapseTags(): void {
lowerResizer.move([tagsPane, fieldsPane], tagsPane.minHeight); lowerResizer.move([tagsPane, fieldsPane], tagsPane.minHeight);
$tagsCollapsed = snapTags = true;
} }
function expandTags(): void { function expandTags(): void {
lowerResizer.move([tagsPane, fieldsPane], tagsPane.maxHeight); lowerResizer.move([tagsPane, fieldsPane], tagsPane.maxHeight);
$tagsCollapsed = snapTags = false;
}
window.addEventListener("resize", () => snapResizer(snapTags));
function snapResizer(collapse: boolean): void {
if (collapse) {
collapseTags();
bridgeCommand("collapseTags");
} else {
expandTags();
bridgeCommand("expandTags");
}
} }
</script> </script>
@ -390,7 +406,9 @@ the AddCards dialog) should be implemented in the user of this component.
<Pane <Pane
bind:this={fieldsPane.resizable} bind:this={fieldsPane.resizable}
on:resize={(e) => (fieldsPane.height = e.detail.height)} on:resize={(e) => {
fieldsPane.height = e.detail.height;
}}
> >
<PaneContent> <PaneContent>
<Fields> <Fields>
@ -553,7 +571,17 @@ the AddCards dialog) should be implemented in the user of this component.
</PaneContent> </PaneContent>
</Pane> </Pane>
{#if $tagsCollapsed} <HorizontalResizer
panes={[fieldsPane, tagsPane]}
showIndicator={$tagsCollapsed || snapTags}
tip={`Double click to ${$tagsCollapsed ? "expand" : "collapse"} tag editor`}
{clientHeight}
bind:this={lowerResizer}
on:dblclick={() => snapResizer(!$tagsCollapsed)}
on:release={() => {
snapResizer(snapTags);
}}
>
<div class="tags-expander"> <div class="tags-expander">
<TagAddButton <TagAddButton
on:tagappend={() => { on:tagappend={() => {
@ -564,36 +592,28 @@ the AddCards dialog) should be implemented in the user of this component.
{@html tagAmount > 0 ? `${tagAmount} Tags` : ""} {@html tagAmount > 0 ? `${tagAmount} Tags` : ""}
</TagAddButton> </TagAddButton>
</div> </div>
{/if} </HorizontalResizer>
<HorizontalResizer
panes={[fieldsPane, tagsPane]}
tip={`Double click to ${$tagsCollapsed ? "expand" : "collapse"} tag editor`}
{clientHeight}
bind:this={lowerResizer}
on:dblclick={() => {
if ($tagsCollapsed) {
expandTags();
bridgeCommand("expandTags");
$tagsCollapsed = false;
} else {
collapseTags();
bridgeCommand("collapseTags");
$tagsCollapsed = true;
}
}}
/>
<Pane <Pane
bind:this={tagsPane.resizable} bind:this={tagsPane.resizable}
on:resize={(e) => { on:resize={(e) => {
tagsPane.height = e.detail.height; tagsPane.height = e.detail.height;
$tagsCollapsed = tagsPane.height == 0; if (tagsPane.maxHeight > 0) {
snapTags = tagsPane.height < tagsPane.maxHeight / 2;
}
}} }}
--opacity={(() => {
if (!$tagsCollapsed) {
return 1;
} else {
return snapTags ? tagsPane.height / tagsPane.maxHeight : 1;
}
})()}
> >
<PaneContent scroll={false}> <PaneContent scroll={false}>
<TagEditor <TagEditor
{tags} {tags}
--button-opacity={snapTags ? 0 : 1}
bind:this={tagEditor} bind:this={tagEditor}
on:tagsupdate={saveTags} on:tagsupdate={saveTags}
on:tagsFocused={() => { on:tagsFocused={() => {
@ -617,7 +637,4 @@ the AddCards dialog) should be implemented in the user of this component.
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
} }
.tags-expander {
margin-top: 0.5rem;
}
</style> </style>

View file

@ -25,6 +25,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<style lang="scss"> <style lang="scss">
.tag-options-button { .tag-options-button {
padding: 6px 3px 0; transition: opacity 0.2s linear;
opacity: var(--button-opacity, 1);
} }
</style> </style>