Redesign fields

This commit is contained in:
Matthias Metelka 2022-08-03 17:47:53 +02:00
parent 4200f35419
commit 3043789960
10 changed files with 176 additions and 83 deletions

View file

@ -189,10 +189,26 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
position: relative; position: relative;
background: var(--frame-bg); background: var(--frame-bg);
border-radius: 0 0 5px 5px; border-radius: 5px;
border: 1px solid var(--border);
&:focus { box-shadow: 0px 0px 2px 0px var(--border);
transition: box-shadow 80ms cubic-bezier(0.33, 1, 0.68, 1);
&:focus-within {
outline: none; outline: none;
border-color: var(--focus-border);
&::after {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
pointer-events: none;
border-radius: 5px;
box-shadow: inset 0 0 0 1px var(--focus-border);
}
} }
} }
</style> </style>

View file

@ -48,9 +48,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import { promiseWithResolver } from "../lib/promise"; import { promiseWithResolver } from "../lib/promise";
import type { Destroyable } from "./destroyable"; import type { Destroyable } from "./destroyable";
import EditingArea from "./EditingArea.svelte"; import EditingArea from "./EditingArea.svelte";
import FieldState from "./FieldState.svelte";
import LabelContainer from "./LabelContainer.svelte";
import LabelName from "./LabelName.svelte";
export let content: Writable<string>; export let content: Writable<string>;
export let field: FieldData; export let field: FieldData;
@ -90,14 +87,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
on:focusout on:focusout
on:click={() => editingArea.focus?.()} on:click={() => editingArea.focus?.()}
> >
<LabelContainer> <slot name="field-label" />
<span>
<LabelName>
{field.name}
</LabelName>
</span>
<FieldState><slot name="field-state" /></FieldState>
</LabelContainer>
<EditingArea <EditingArea
{content} {content}
fontFamily={field.fontFamily} fontFamily={field.fontFamily}
@ -110,16 +101,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<style lang="scss"> <style lang="scss">
.editor-field { .editor-field {
position: relative;
--border-color: var(--border); --border-color: var(--border);
border-radius: 5px;
border: 1px solid var(--border-color);
&:focus-within {
--border-color: var(--focus-border);
outline: none;
box-shadow: 0 0 0 3px var(--focus-shadow);
}
} }
</style> </style>

View file

@ -11,7 +11,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
display: flex; display: flex;
justify-content: flex; justify-content: flex;
flex-grow: 1; flex-grow: 1;
& > :global(*) { & > :global(*) {
margin-left: 2px; margin-left: 2px;
} }

View file

@ -3,35 +3,67 @@ 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 { getContext } from "svelte"; import { createEventDispatcher, getContext } from "svelte";
import type { Readable } from "svelte/store"; import type { Readable } from "svelte/store";
import { directionKey } from "../lib/context-keys"; import { directionKey } from "../lib/context-keys";
import * as tr from "../lib/ftl";
import Badge from "../components/Badge.svelte";
import { chevronRight, chevronDown } from "./icons";
export let off: boolean;
const direction = getContext<Readable<"ltr" | "rtl">>(directionKey); const direction = getContext<Readable<"ltr" | "rtl">>(directionKey);
const dispatch = createEventDispatcher();
function toggle() {
dispatch("toggle");
}
$: icon = off ? chevronRight : chevronDown;
</script> </script>
<div <div
class:collapsed={off}
class="label-container" class="label-container"
class:rtl={$direction === "rtl"} class:rtl={$direction === "rtl"}
on:mousedown|preventDefault on:mousedown|preventDefault
> >
<span class="clickable" on:click|stopPropagation={toggle}>
<span class="chevron">
<Badge
tooltip={tr.editingToggleVisualEditor()}
iconSize={80}
--icon-align="text-bottom"
>{@html icon}
</Badge>
</span>
<slot name="field-name" />
</span>
<slot /> <slot />
</div> </div>
<style lang="scss"> <style lang="scss">
.label-container { .label-container {
& .chevron {
opacity: 0.4;
transition: opacity 0.2s ease-in-out;
}
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
background-color: var(--label-color, transparent); background-color: var(--label-color, transparent);
border-width: 0 0 1px; padding: 2px 0;
border-style: dashed; }
border-color: var(--border-color); .clickable {
border-radius: 5px 5px 0 0; cursor: pointer;
&:hover .chevron {
padding: 0px 6px; opacity: 1;
}
} }
.rtl { .rtl {

View file

@ -9,6 +9,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type { EditorToolbarAPI } from "./editor-toolbar"; import type { EditorToolbarAPI } from "./editor-toolbar";
import type { EditorFieldAPI } from "./EditorField.svelte"; import type { EditorFieldAPI } from "./EditorField.svelte";
import LabelContainer from "./LabelContainer.svelte";
import LabelName from "./LabelName.svelte";
import FieldState from "./FieldState.svelte";
export interface NoteEditorAPI { export interface NoteEditorAPI {
fields: EditorFieldAPI[]; fields: EditorFieldAPI[];
focusedField: Writable<EditorFieldAPI | null>; focusedField: Writable<EditorFieldAPI | null>;
@ -322,34 +326,30 @@ the AddCards dialog) should be implemented in the user of this component.
? "var(--flag1-bg)" ? "var(--flag1-bg)"
: "transparent"} : "transparent"}
> >
<svelte:fragment slot="field-state"> <svelte:fragment slot="field-label">
{#if cols[index] === "dupe"} <LabelContainer
<DuplicateLink />
{/if}
<RichTextBadge
bind:off={richTextsHidden[index]} bind:off={richTextsHidden[index]}
on:toggle={() => { on:toggle={() => {
richTextsHidden[index] = !richTextsHidden[index]; richTextsHidden[index] = !richTextsHidden[index];
plainTextsHidden[index] = true;
if (!richTextsHidden[index]) { if (!richTextsHidden[index]) {
richTextInputs[index].api.refocus(); richTextInputs[index].api.refocus();
} }
}} }}
/> >
<PlainTextBadge <svelte:fragment slot="field-name">
bind:off={plainTextsHidden[index]} <LabelName>
on:toggle={() => { {field.name}
plainTextsHidden[index] = !plainTextsHidden[index]; </LabelName>
</svelte:fragment>
if (!plainTextsHidden[index]) { <FieldState>
plainTextInputs[index].api.refocus(); {#if cols[index] === "dupe"}
} <DuplicateLink />
}} {/if}
/> <slot name="field-state" {field} {index} />
</FieldState>
<slot name="field-state" {field} {index} /> </LabelContainer>
</svelte:fragment> </svelte:fragment>
<svelte:fragment slot="editing-inputs"> <svelte:fragment slot="editing-inputs">
<RichTextInput <RichTextInput
hidden={richTextsHidden[index]} hidden={richTextsHidden[index]}
@ -361,6 +361,20 @@ the AddCards dialog) should be implemented in the user of this component.
> >
<ImageHandle maxWidth={250} maxHeight={125} /> <ImageHandle maxWidth={250} maxHeight={125} />
<MathjaxHandle /> <MathjaxHandle />
<svelte:fragment slot="plain-text-badge">
<PlainTextBadge
bind:off={plainTextsHidden[index]}
on:toggle={() => {
plainTextsHidden[index] =
!plainTextsHidden[index];
if (!plainTextsHidden[index]) {
plainTextInputs[index].api.refocus();
}
}}
/>
</svelte:fragment>
</RichTextInput> </RichTextInput>
<PlainTextInput <PlainTextInput

View file

@ -5,11 +5,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<script lang="ts"> <script lang="ts">
import { createEventDispatcher, onMount } from "svelte"; import { createEventDispatcher, onMount } from "svelte";
import Badge from "../components/Badge.svelte"; import { registerShortcut } from "../lib/shortcuts";
import * as tr from "../lib/ftl";
import { getPlatformString, registerShortcut } from "../lib/shortcuts";
import { context as editorFieldContext } from "./EditorField.svelte"; import { context as editorFieldContext } from "./EditorField.svelte";
import { htmlOff, htmlOn } from "./icons";
const editorField = editorFieldContext.get(); const editorField = editorFieldContext.get();
const keyCombination = "Control+Shift+X"; const keyCombination = "Control+Shift+X";
@ -17,8 +14,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export let off = false; export let off = false;
$: icon = off ? htmlOff : htmlOn;
function toggle() { function toggle() {
dispatch("toggle"); dispatch("toggle");
} }
@ -28,29 +23,72 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
onMount(() => editorField.element.then(shortcut)); onMount(() => editorField.element.then(shortcut));
let width = 0;
</script> </script>
<span <div
class="plain-text-badge" class="clickable"
class:highlighted={!off} style="--width: {width}px"
on:click|stopPropagation={toggle} on:click|stopPropagation={toggle}
bind:clientWidth={width}
> >
<Badge <span class:off class:on={!off} class="plain-text-badge" class:highlighted={!off} />
tooltip="{tr.editingToggleHtmlEditor()} ({getPlatformString(keyCombination)})" </div>
iconSize={80}
--icon-align="text-top">{@html icon}</Badge
>
</span>
<style lang="scss"> <style lang="scss">
span { .clickable {
opacity: 0.4; right: calc(50% - var(--width) / 2);
position: absolute;
text-align: center;
bottom: -16px;
z-index: 3;
width: 32px;
height: 16px;
cursor: pointer;
}
.plain-text-badge {
left: 12px;
position: absolute;
opacity: 0;
width: 8px;
height: 8px;
transform: rotate(-45deg);
&.highlighted { transition: bottom 0.2s ease-out;
opacity: 1; &.on {
bottom: 0px;
background: var(--code-bg);
border-right: 1px solid var(--border);
border-top: 1px solid var(--border);
} }
&:hover { &.off {
opacity: 0.8; bottom: 10px;
background: var(--frame-bg);
border-left: 1px solid var(--border);
border-bottom: 1px solid var(--border);
}
&::before,
&::after {
width: 10px;
height: 10px;
}
}
:global(.editor-field) {
&:hover,
&:focus-within {
& .plain-text-badge {
opacity: 1;
transition: opacity 0.2s ease-in, bottom 0.2s ease-out;
&.on,
&.off {
bottom: 5px;
}
}
}
&:focus-within .plain-text-badge.off {
border-width: 2px;
border-color: var(--focus-border);
} }
} }
</style> </style>

View file

@ -24,7 +24,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<Badge <Badge
tooltip={tr.editingToggleVisualEditor()} tooltip={tr.editingToggleVisualEditor()}
iconSize={80} iconSize={80}
--icon-align="text-top">{@html icon}</Badge --icon-align="text-bottom">{@html icon}</Badge
> >
</span> </span>

View file

@ -10,12 +10,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import * as tr from "../lib/ftl"; import * as tr from "../lib/ftl";
import { getPlatformString, registerShortcut } from "../lib/shortcuts"; import { getPlatformString, registerShortcut } from "../lib/shortcuts";
import { context as editorFieldContext } from "./EditorField.svelte"; import { context as editorFieldContext } from "./EditorField.svelte";
import { stickyOff, stickyOn } from "./icons"; import { stickyIcon } from "./icons";
export let active: boolean; export let active: boolean;
$: icon = active ? stickyOn : stickyOff;
const editorField = editorFieldContext.get(); const editorField = editorFieldContext.get();
const keyCombination = "F9"; const keyCombination = "F9";
@ -38,19 +36,31 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<Badge <Badge
tooltip="{tr.editingToggleSticky()} ({getPlatformString(keyCombination)})" tooltip="{tr.editingToggleSticky()} ({getPlatformString(keyCombination)})"
widthMultiplier={0.7} widthMultiplier={0.7}
--icon-align="text-top">{@html icon}</Badge --icon-align="text-bottom">{@html stickyIcon}</Badge
> >
</span> </span>
<style lang="scss"> <style lang="scss">
span { span {
opacity: 0.4; cursor: pointer;
opacity: 0;
transition: opacity 0.2s ease-in;
&.highlighted { &.highlighted {
opacity: 1; opacity: 1;
} }
}
:global(.editor-field) {
&:focus-within,
&:hover { &:hover {
opacity: 0.8; & span {
opacity: 0.4;
&:hover {
opacity: 0.8;
}
&.highlighted {
opacity: 1;
}
}
} }
} }
</style> </style>

View file

@ -164,7 +164,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
:global(.CodeMirror-lines) { :global(.CodeMirror-lines) {
padding: 6px 0; padding: 8px 0;
} }
&.hidden { &.hidden {
@ -172,7 +172,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
} }
.light-theme :global(.CodeMirror) { :global(.CodeMirror) {
border-top: 1px solid #ddd; border-top: 1px solid var(--border);
background: var(--code-bg);
} }
</style> </style>

View file

@ -238,6 +238,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
</div> </div>
{/await} {/await}
</RichTextStyles> </RichTextStyles>
<slot name="plain-text-badge" />
</div> </div>
<style lang="scss"> <style lang="scss">