mirror of
https://github.com/ankitects/anki.git
synced 2025-09-25 09:16:38 -04:00
Redesign fields
This commit is contained in:
parent
4200f35419
commit
3043789960
10 changed files with 176 additions and 83 deletions
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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">
|
||||||
|
|
Loading…
Reference in a new issue