Make field description a placeholder inside EditingArea (#1912)
* Move field description into EditingArea as placeholder * Prevent insertion of breaks into empty fields to allow :empty CSS selector to also work on fields other than the first one. * Remove redundant setContext from EditingArea * Fix import order * Revert "Prevent insertion of breaks into empty fields" This reverts commit 1615fd5cf441b1047dae6a34265acb9c5cae50b2. * Use class:empty instead of :empty CSS pseudo-class * Restrict description to single line, ellipse overflow * Make description in field dialog a bit clearer
This commit is contained in:
parent
4d51ee8a64
commit
6d8fb35fab
@ -4,7 +4,7 @@ fields-editing-font = Editing Font
|
||||
fields-field = Field:
|
||||
fields-field-name = Field name:
|
||||
fields-description = Description
|
||||
fields-description-placeholder = Tooltip to show next to the field's name in the editing screen
|
||||
fields-description-placeholder = Text to show inside the field when it's empty
|
||||
fields-fields-for = Fields for { $val }
|
||||
fields-font = Font:
|
||||
fields-new-position-1 = New position (1...{ $val }):
|
||||
|
@ -7,9 +7,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import type { Writable } from "svelte/store";
|
||||
import { getContext } from "svelte";
|
||||
import type { Readable, Writable } from "svelte/store";
|
||||
|
||||
import { updateAllState } from "../components/WithState.svelte";
|
||||
import { descriptionKey } from "../lib/context-keys";
|
||||
import actionList from "../sveltelib/action-list";
|
||||
import type { MirrorAction } from "../sveltelib/dom-mirror";
|
||||
import type { SetupInputHandlerAction } from "../sveltelib/input-handler";
|
||||
@ -33,10 +35,18 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
const [focusHandler, setupFocusHandling] = useFocusHandler();
|
||||
|
||||
Object.assign(api, { focusHandler });
|
||||
|
||||
const description = getContext<Readable<string>>(descriptionKey);
|
||||
$: descriptionCSSValue = `"${$description}"`;
|
||||
|
||||
let innerHTML = "";
|
||||
$: empty = ["", "<br>"].includes(innerHTML);
|
||||
</script>
|
||||
|
||||
<anki-editable
|
||||
class:empty
|
||||
contenteditable="true"
|
||||
bind:innerHTML
|
||||
use:resolve
|
||||
use:setupFocusHandling
|
||||
use:preventBuiltinShortcuts
|
||||
@ -46,11 +56,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
on:blur
|
||||
on:click={updateAllState}
|
||||
on:keyup={updateAllState}
|
||||
style="--description: {descriptionCSSValue}"
|
||||
/>
|
||||
|
||||
<style lang="scss">
|
||||
anki-editable {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding: 6px;
|
||||
overflow: auto;
|
||||
overflow-wrap: anywhere;
|
||||
@ -60,6 +72,17 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
&.empty::before {
|
||||
content: var(--description);
|
||||
opacity: 0.4;
|
||||
cursor: text;
|
||||
/* stay on single line */
|
||||
position: absolute;
|
||||
max-width: 95%;
|
||||
overflow-x: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
/* editable-base.scss contains styling targeting user HTML */
|
||||
|
@ -10,10 +10,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
export interface FieldData {
|
||||
name: string;
|
||||
description: string;
|
||||
fontFamily: string;
|
||||
fontSize: number;
|
||||
direction: "ltr" | "rtl";
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface EditorFieldAPI {
|
||||
@ -33,13 +33,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
import type { Writable } from "svelte/store";
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
import { directionKey } from "../lib/context-keys";
|
||||
import { descriptionKey, directionKey } from "../lib/context-keys";
|
||||
import { promiseWithResolver } from "../lib/promise";
|
||||
import type { Destroyable } from "./destroyable";
|
||||
import EditingArea from "./EditingArea.svelte";
|
||||
import FieldState from "./FieldState.svelte";
|
||||
import LabelContainer from "./LabelContainer.svelte";
|
||||
import LabelDescription from "./LabelDescription.svelte";
|
||||
import LabelName from "./LabelName.svelte";
|
||||
|
||||
export let content: Writable<string>;
|
||||
@ -50,6 +49,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
$: $directionStore = field.direction;
|
||||
|
||||
const descriptionStore = writable<string>();
|
||||
setContext(descriptionKey, descriptionStore);
|
||||
|
||||
$: $descriptionStore = field.description;
|
||||
|
||||
const editingArea: Partial<EditingAreaAPI> = {};
|
||||
const [element, elementResolve] = promiseWithResolver<HTMLElement>();
|
||||
|
||||
@ -79,9 +83,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
<LabelName>
|
||||
{field.name}
|
||||
</LabelName>
|
||||
{#if field.description}
|
||||
<LabelDescription description={field.description} />
|
||||
{/if}
|
||||
</span>
|
||||
<FieldState><slot name="field-state" /></FieldState>
|
||||
</LabelContainer>
|
||||
|
@ -1,39 +0,0 @@
|
||||
<!--
|
||||
Copyright: Ankitects Pty Ltd and contributors
|
||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
-->
|
||||
<script lang="ts">
|
||||
import Badge from "../components/Badge.svelte";
|
||||
import WithTooltip from "../components/WithTooltip.svelte";
|
||||
import { descriptionIcon } from "./icons";
|
||||
|
||||
export let description: string;
|
||||
</script>
|
||||
|
||||
<span>
|
||||
<WithTooltip
|
||||
tooltip={description}
|
||||
showDelay={250}
|
||||
offset={[0, 20]}
|
||||
placement="right"
|
||||
let:createTooltip
|
||||
>
|
||||
<Badge
|
||||
--icon-align="sub"
|
||||
iconSize={65}
|
||||
on:mount={(event) => createTooltip(event.detail.span)}
|
||||
>
|
||||
{@html descriptionIcon}
|
||||
</Badge>
|
||||
</WithTooltip>
|
||||
</span>
|
||||
|
||||
<style lang="scss">
|
||||
span {
|
||||
opacity: 0.4;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -12,4 +12,3 @@ export { default as richTextOn } from "@mdi/svg/svg/eye-outline.svg";
|
||||
export { default as stickyOff } from "@mdi/svg/svg/pin-off-outline.svg";
|
||||
export { default as stickyOn } from "@mdi/svg/svg/pin-outline.svg";
|
||||
export { default as htmlOff } from "@mdi/svg/svg/xml.svg";
|
||||
export { default as descriptionIcon } from "bootstrap-icons/icons/info-circle.svg";
|
||||
|
@ -4,3 +4,4 @@
|
||||
export const fontFamilyKey = Symbol("fontFamily");
|
||||
export const fontSizeKey = Symbol("fontSize");
|
||||
export const directionKey = Symbol("direction");
|
||||
export const descriptionKey = Symbol("description");
|
||||
|
Loading…
Reference in New Issue
Block a user