Bubble up some functionality from Tag to TagWithTooltip and TagDeleteBadge

This commit is contained in:
Henrik Giesel 2021-09-09 17:18:47 +02:00
parent fd89f296dd
commit 4fc3e059be
4 changed files with 112 additions and 87 deletions

View file

@ -5,23 +5,15 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<script lang="typescript"> <script lang="typescript">
import { onMount, getContext, createEventDispatcher } from "svelte"; import { onMount, getContext, createEventDispatcher } from "svelte";
import { nightModeKey } from "components/context-keys"; import { nightModeKey } from "components/context-keys";
import Badge from "components/Badge.svelte";
import { deleteIcon } from "./icons";
import { controlPressed, shiftPressed } from "lib/keys";
let className: string = ""; let className: string = "";
export { className as class }; export { className as class };
export let name: string;
export let tooltip: string | undefined = undefined; export let tooltip: string | undefined = undefined;
export let selected: boolean = false; export let selected: boolean = false;
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
function deleteTag(): void {
dispatch("tagdelete");
}
let flashing: boolean = false; let flashing: boolean = false;
export function flash(): void { export function flash(): void {
@ -29,26 +21,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
setTimeout(() => (flashing = false), 300); setTimeout(() => (flashing = false), 300);
} }
let control = false;
let shift = false;
function setDeleteIcon(event: KeyboardEvent | MouseEvent): void {
control = controlPressed(event);
shift = shiftPressed(event);
}
$: selectMode = control || shift;
function onClick(): void {
if (shift) {
dispatch("tagrange");
} else if (control) {
dispatch("tagselect");
} else {
dispatch("tagedit");
}
}
const nightMode = getContext<boolean>(nightModeKey); const nightMode = getContext<boolean>(nightModeKey);
let button: HTMLButtonElement; let button: HTMLButtonElement;
@ -56,30 +28,19 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
onMount(() => dispatch("mount", { button })); onMount(() => dispatch("mount", { button }));
</script> </script>
<svelte:body on:keydown={setDeleteIcon} on:keyup={setDeleteIcon} />
<button <button
bind:this={button} bind:this={button}
class="tag btn d-inline-flex align-items-center text-nowrap ps-2 pe-1 {className}" class="tag btn d-inline-flex align-items-center text-nowrap ps-2 pe-1 {className}"
class:selected class:selected
class:flashing class:flashing
class:select-mode={selectMode}
class:btn-day={!nightMode} class:btn-day={!nightMode}
class:btn-night={nightMode} class:btn-night={nightMode}
tabindex="-1" tabindex="-1"
title={tooltip} title={tooltip}
on:mousemove={setDeleteIcon} on:mousemove
on:click={onClick} on:click
> >
<span>{name}</span> <slot />
<Badge
class="delete-icon rounded-circle d-flex align-items-center ms-1"
on:click={() => {
if (!selectMode) {
deleteTag();
}
}}>{@html deleteIcon}</Badge
>
</button> </button>
<style lang="scss"> <style lang="scss">
@ -118,33 +79,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
animation: flash 0.3s linear; animation: flash 0.3s linear;
} }
&.select-mode {
cursor: crosshair;
&:hover :global(.delete-icon) {
opacity: 0;
}
}
&.selected { &.selected {
box-shadow: 0 0 0 2px var(--focus-shadow); box-shadow: 0 0 0 2px var(--focus-shadow);
--border-color: var(--focus-border); --border-color: var(--focus-border);
} }
} }
:global(.delete-icon > svg:hover) {
$white-translucent: rgba(255 255 255 / 0.5);
$dark-translucent: rgba(0 0 0 / 0.2);
.btn-day & {
background-color: $dark-translucent;
}
.btn-night & {
background-color: $white-translucent;
}
}
@include button.btn-day( @include button.btn-day(
$with-active: false, $with-active: false,
$with-disabled: false, $with-disabled: false,

View file

@ -0,0 +1,15 @@
<!--
Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="typescript">
import Badge from "components/Badge.svelte";
import { deleteIcon } from "./icons";
let className: string = "";
export { className as class };
</script>
<Badge class="rounded-circle d-flex align-items-center ms-1 {className}" on:click
>{@html deleteIcon}</Badge
>

View file

@ -490,6 +490,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
/> />
<div class="position-relative tag-margins hide-tag zero-width-tag"> <div class="position-relative tag-margins hide-tag zero-width-tag">
<!-- makes sure footer does not resize when adding first tag -->
<Tag name="SPACER" /> <Tag name="SPACER" />
</div> </div>
</ButtonToolbar> </ButtonToolbar>

View file

@ -5,7 +5,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<script lang="typescript"> <script lang="typescript">
import WithTooltip from "components/WithTooltip.svelte"; import WithTooltip from "components/WithTooltip.svelte";
import Tag from "./Tag.svelte"; import Tag from "./Tag.svelte";
import TagDeleteBadge from "./TagDeleteBadge.svelte";
import { createEventDispatcher, getContext } from "svelte";
import { nightModeKey } from "components/context-keys";
import { controlPressed, shiftPressed } from "lib/keys";
import { delimChar } from "./tags"; import { delimChar } from "./tags";
export let name: string; export let name: string;
@ -20,6 +24,32 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export let flash: () => void; export let flash: () => void;
const dispatch = createEventDispatcher();
function deleteTag(): void {
dispatch("tagdelete");
}
let control = false;
let shift = false;
$: selectMode = control || shift;
function setDeleteIcon(event: KeyboardEvent | MouseEvent): void {
control = controlPressed(event);
shift = shiftPressed(event);
}
function onClick(): void {
if (shift) {
dispatch("tagrange");
} else if (control) {
dispatch("tagselect");
} else {
dispatch("tagedit");
}
}
function processTagName(name: string): string { function processTagName(name: string): string {
const parts = name.split(delimChar); const parts = name.split(delimChar);
@ -33,33 +63,72 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
function hasMultipleParts(name: string): boolean { function hasMultipleParts(name: string): boolean {
return name.split(delimChar).length > 1; return name.split(delimChar).length > 1;
} }
function onClickDelete() {
if (!selectMode) {
deleteTag();
}
}
const nightMode = getContext<boolean>(nightModeKey);
</script> </script>
{#if active} <svelte:body on:keydown={setDeleteIcon} on:keyup={setDeleteIcon} />
<Tag class={className} {name} />
{:else if shorten && hasMultipleParts(name)} <div class:select-mode={selectMode} class:night-mode={nightMode}>
<WithTooltip {tooltip} placement="auto" let:createTooltip> {#if active}
<Tag class={className} on:mousemove={setDeleteIcon} on:click={onClick}>
{name}
<TagDeleteBadge class="delete-icon" on:click={onClickDelete} />
</Tag>
{:else if shorten && hasMultipleParts(name)}
<WithTooltip {tooltip} placement="auto" let:createTooltip>
<Tag
class={className}
bind:flash
bind:selected
on:mousemove={setDeleteIcon}
on:click={onClick}
on:mount={(event) => createTooltip(event.detail.button)}
>
<span>{processTagName(name)}</span>
<TagDeleteBadge class="delete-icon" on:click={onClickDelete} />
</Tag>
</WithTooltip>
{:else}
<Tag <Tag
class={className} class={className}
name={processTagName(name)}
bind:flash bind:flash
bind:selected bind:selected
on:tagedit on:mousemove={setDeleteIcon}
on:tagselect on:click={onClick}
on:tagrange >
on:tagdelete <span>{name}</span>
on:mount={(event) => createTooltip(event.detail.button)} <TagDeleteBadge class="delete-icon" on:click={onClickDelete} />
/> </Tag>
</WithTooltip> {/if}
{:else} </div>
<Tag
class={className} <style lang="scss">
{name} .select-mode :global(button) {
bind:flash display: contents;
bind:selected cursor: crosshair;
on:tagedit
on:tagselect :global(.delete-icon) {
on:tagrange opacity: 0;
on:tagdelete }
/> }
{/if}
:global(.delete-icon):hover {
$white-translucent: rgba(255 255 255 / 0.5);
$dark-translucent: rgba(0 0 0 / 0.2);
div & {
background-color: $dark-translucent;
}
.night-mode & {
background-color: $white-translucent;
}
}
</style>