mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 06:22:22 -04:00
Better RTL support
This commit is contained in:
parent
eb71c97872
commit
c6e56e0465
8 changed files with 111 additions and 60 deletions
|
@ -21,6 +21,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
export let size: number | undefined = undefined;
|
export let size: number | undefined = undefined;
|
||||||
export let wrap: boolean | undefined = undefined;
|
export let wrap: boolean | undefined = undefined;
|
||||||
|
|
||||||
|
export let reverse = false;
|
||||||
|
|
||||||
$: buttonSize = size ? `--buttons-size: ${size}rem; ` : "";
|
$: buttonSize = size ? `--buttons-size: ${size}rem; ` : "";
|
||||||
let buttonWrap: string;
|
let buttonWrap: string;
|
||||||
$: if (wrap === undefined) {
|
$: if (wrap === undefined) {
|
||||||
|
@ -95,7 +97,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
<div
|
<div
|
||||||
bind:this={buttonGroupRef}
|
bind:this={buttonGroupRef}
|
||||||
{id}
|
{id}
|
||||||
class={`btn-group ${className}`}
|
class="btn-group {className}"
|
||||||
|
class:reverse
|
||||||
{style}
|
{style}
|
||||||
dir="ltr"
|
dir="ltr"
|
||||||
role="group"
|
role="group"
|
||||||
|
@ -110,8 +113,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div {
|
div {
|
||||||
|
flex-direction: row;
|
||||||
flex-wrap: var(--buttons-wrap);
|
flex-wrap: var(--buttons-wrap);
|
||||||
padding: calc(var(--buttons-size) / 10);
|
padding: calc(var(--buttons-size) / 10);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.reverse {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -18,6 +18,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
export let iconSize: number = 75;
|
export let iconSize: number = 75;
|
||||||
export let widthMultiplier: number = 1;
|
export let widthMultiplier: number = 1;
|
||||||
|
export let flipX: boolean = false;
|
||||||
|
|
||||||
let buttonRef: HTMLButtonElement;
|
let buttonRef: HTMLButtonElement;
|
||||||
|
|
||||||
|
@ -44,7 +45,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
on:click
|
on:click
|
||||||
on:mousedown|preventDefault
|
on:mousedown|preventDefault
|
||||||
>
|
>
|
||||||
<span style={`--width-multiplier: ${widthMultiplier};`}> <slot /> </span>
|
<span class:flip-x={flipX} style={`--width-multiplier: ${widthMultiplier};`}>
|
||||||
|
<slot />
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -80,6 +83,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
fill: currentColor;
|
fill: currentColor;
|
||||||
vertical-align: unset;
|
vertical-align: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.flip-x > :global(svg),
|
||||||
|
&.flip-x > :global(img) {
|
||||||
|
transform: scaleX(-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-toggle::after {
|
.dropdown-toggle::after {
|
||||||
|
|
|
@ -3,7 +3,7 @@ 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="typescript">
|
<script lang="typescript">
|
||||||
import ImageHandleButtons from "./ImageHandleButtons.svelte";
|
import ImageHandleFloat from "./ImageHandleFloat.svelte";
|
||||||
import ImageHandleSizeSelect from "./ImageHandleSizeSelect.svelte";
|
import ImageHandleSizeSelect from "./ImageHandleSizeSelect.svelte";
|
||||||
|
|
||||||
import { getContext } from "svelte";
|
import { getContext } from "svelte";
|
||||||
|
@ -11,6 +11,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
export let image: HTMLImageElement | null = null;
|
export let image: HTMLImageElement | null = null;
|
||||||
export let imageRule: CSSStyleRule | null = null;
|
export let imageRule: CSSStyleRule | null = null;
|
||||||
|
export let isRtl: boolean = false;
|
||||||
|
|
||||||
export let container: HTMLElement;
|
export let container: HTMLElement;
|
||||||
|
|
||||||
$: showDimensions = image
|
$: showDimensions = image
|
||||||
|
@ -37,9 +39,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
function updateSizes() {
|
function updateSizes() {
|
||||||
const imageRect = image!.getBoundingClientRect();
|
const imageRect = image!.getBoundingClientRect();
|
||||||
const containerRect = (
|
const containerRect = container.getBoundingClientRect();
|
||||||
container ?? document.documentElement
|
|
||||||
).getBoundingClientRect();
|
|
||||||
|
|
||||||
naturalWidth = image!.naturalWidth;
|
naturalWidth = image!.naturalWidth;
|
||||||
naturalHeight = image!.naturalHeight;
|
naturalHeight = image!.naturalHeight;
|
||||||
|
@ -100,21 +100,22 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
class="image-handle-selection"
|
class="image-handle-selection"
|
||||||
>
|
>
|
||||||
<div class="image-handle-bg" on:dblclick={onDblclick} />
|
<div class="image-handle-bg" on:dblclick={onDblclick} />
|
||||||
<div class="image-handle-buttons">
|
<div class="image-handle-buttons" class:is-rtl={isRtl}>
|
||||||
<ImageHandleButtons bind:float={image.style.float} />
|
<ImageHandleFloat {isRtl} bind:float={image.style.float} />
|
||||||
</div>
|
</div>
|
||||||
<div class="image-handle-size-select">
|
<div class="image-handle-size-select" class:is-rtl={isRtl}>
|
||||||
<ImageHandleSizeSelect
|
<ImageHandleSizeSelect
|
||||||
bind:this={sizeSelect}
|
bind:this={sizeSelect}
|
||||||
bind:active
|
bind:active
|
||||||
{selector}
|
|
||||||
{image}
|
{image}
|
||||||
{imageRule}
|
{imageRule}
|
||||||
|
{selector}
|
||||||
|
{isRtl}
|
||||||
on:update={updateSizes}
|
on:update={updateSizes}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{#if showDimensions}
|
{#if showDimensions}
|
||||||
<div class="image-handle-dimensions">
|
<div class="image-handle-dimensions" class:is-rtl={isRtl}>
|
||||||
{width}×{height} (Original: {naturalWidth}×{naturalHeight})
|
{width}×{height} (Original: {naturalWidth}×{naturalHeight})
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -159,24 +160,40 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
.image-handle-buttons {
|
.image-handle-buttons {
|
||||||
top: 3px;
|
top: 3px;
|
||||||
left: 3px;
|
left: 3px;
|
||||||
|
|
||||||
|
&.is-rtl {
|
||||||
|
left: auto;
|
||||||
|
right: 3px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-handle-size-select {
|
.image-handle-size-select {
|
||||||
bottom: 3px;
|
bottom: 3px;
|
||||||
left: 3px;
|
left: 3px;
|
||||||
|
|
||||||
|
&.is-rtl {
|
||||||
|
left: auto;
|
||||||
|
right: 3px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-handle-dimensions {
|
.image-handle-dimensions {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
bottom: 3px;
|
|
||||||
right: 3px;
|
|
||||||
|
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
background-color: rgba(0 0 0 / 0.3);
|
background-color: rgba(0 0 0 / 0.3);
|
||||||
border-color: black;
|
border-color: black;
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
|
|
||||||
|
bottom: 3px;
|
||||||
|
right: 3px;
|
||||||
|
|
||||||
|
&.is-rtl {
|
||||||
|
right: auto;
|
||||||
|
left: 3px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-handle-control {
|
.image-handle-control {
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
<!--
|
|
||||||
Copyright: Ankitects Pty Ltd and contributors
|
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
||||||
-->
|
|
||||||
<script lang="typescript">
|
|
||||||
import * as tr from "lib/i18n";
|
|
||||||
|
|
||||||
import ButtonToolbar from "components/ButtonToolbar.svelte";
|
|
||||||
import ButtonGroup from "components/ButtonGroup.svelte";
|
|
||||||
import ButtonGroupItem from "components/ButtonGroupItem.svelte";
|
|
||||||
import IconButton from "components/IconButton.svelte";
|
|
||||||
|
|
||||||
import { floatNoneIcon, floatLeftIcon, floatRightIcon } from "./icons";
|
|
||||||
|
|
||||||
export let float: string;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<ButtonToolbar size={1.6} wrap={false}>
|
|
||||||
<ButtonGroup>
|
|
||||||
<ButtonGroupItem>
|
|
||||||
<IconButton
|
|
||||||
tooltip={tr.editingFloatNone()}
|
|
||||||
active={float === "" || float === "none"}
|
|
||||||
on:click={() => (float = "")}>{@html floatNoneIcon}</IconButton
|
|
||||||
>
|
|
||||||
</ButtonGroupItem>
|
|
||||||
|
|
||||||
<ButtonGroupItem>
|
|
||||||
<IconButton
|
|
||||||
tooltip={tr.editingFloatLeft()}
|
|
||||||
active={float === "left"}
|
|
||||||
on:click={() => (float = "left")}>{@html floatLeftIcon}</IconButton
|
|
||||||
>
|
|
||||||
</ButtonGroupItem>
|
|
||||||
|
|
||||||
<ButtonGroupItem>
|
|
||||||
<IconButton
|
|
||||||
tooltip={tr.editingFloatRight()}
|
|
||||||
active={float === "right"}
|
|
||||||
on:click={() => (float = "right")}>{@html floatRightIcon}</IconButton
|
|
||||||
>
|
|
||||||
</ButtonGroupItem>
|
|
||||||
</ButtonGroup>
|
|
||||||
</ButtonToolbar>
|
|
61
ts/editor/ImageHandleFloat.svelte
Normal file
61
ts/editor/ImageHandleFloat.svelte
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
<!--
|
||||||
|
Copyright: Ankitects Pty Ltd and contributors
|
||||||
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
-->
|
||||||
|
<script lang="typescript">
|
||||||
|
import * as tr from "lib/i18n";
|
||||||
|
|
||||||
|
import ButtonGroup from "components/ButtonGroup.svelte";
|
||||||
|
import ButtonGroupItem from "components/ButtonGroupItem.svelte";
|
||||||
|
import IconButton from "components/IconButton.svelte";
|
||||||
|
|
||||||
|
import { floatNoneIcon, floatLeftIcon, floatRightIcon } from "./icons";
|
||||||
|
|
||||||
|
export let float: string;
|
||||||
|
export let isRtl: boolean;
|
||||||
|
|
||||||
|
const leftValues = {
|
||||||
|
position: "left",
|
||||||
|
label: tr.editingFloatLeft(),
|
||||||
|
icon: floatLeftIcon,
|
||||||
|
};
|
||||||
|
|
||||||
|
const rightValues = {
|
||||||
|
position: "right",
|
||||||
|
label: tr.editingFloatRight(),
|
||||||
|
};
|
||||||
|
|
||||||
|
$: inlineStart = isRtl ? rightValues : leftValues;
|
||||||
|
$: inlineEnd = isRtl ? leftValues : rightValues;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ButtonGroup size={1.6} wrap={false} reverse={isRtl}>
|
||||||
|
<ButtonGroupItem>
|
||||||
|
<IconButton
|
||||||
|
tooltip={tr.editingFloatNone()}
|
||||||
|
active={float === "" || float === "none"}
|
||||||
|
flipX={isRtl}
|
||||||
|
on:click={() => (float = "")}>{@html floatNoneIcon}</IconButton
|
||||||
|
>
|
||||||
|
</ButtonGroupItem>
|
||||||
|
|
||||||
|
<ButtonGroupItem>
|
||||||
|
<IconButton
|
||||||
|
tooltip={inlineStart.label}
|
||||||
|
active={float === inlineStart.position}
|
||||||
|
flipX={isRtl}
|
||||||
|
on:click={() => (float = inlineStart.position)}
|
||||||
|
>{@html floatLeftIcon}</IconButton
|
||||||
|
>
|
||||||
|
</ButtonGroupItem>
|
||||||
|
|
||||||
|
<ButtonGroupItem>
|
||||||
|
<IconButton
|
||||||
|
tooltip={inlineEnd.label}
|
||||||
|
active={float === inlineEnd.position}
|
||||||
|
flipX={isRtl}
|
||||||
|
on:click={() => (float = inlineEnd.position)}
|
||||||
|
>{@html floatRightIcon}</IconButton
|
||||||
|
>
|
||||||
|
</ButtonGroupItem>
|
||||||
|
</ButtonGroup>
|
|
@ -16,6 +16,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
export let imageRule: CSSStyleRule;
|
export let imageRule: CSSStyleRule;
|
||||||
export let selector: string;
|
export let selector: string;
|
||||||
export let active: boolean;
|
export let active: boolean;
|
||||||
|
export let isRtl: boolean;
|
||||||
|
|
||||||
$: icon = active ? sizeActual : sizeMinimized;
|
$: icon = active ? sizeActual : sizeMinimized;
|
||||||
|
|
||||||
|
@ -42,6 +43,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
<ButtonGroupItem>
|
<ButtonGroupItem>
|
||||||
<IconButton
|
<IconButton
|
||||||
{active}
|
{active}
|
||||||
|
flipX={isRtl}
|
||||||
tooltip={tr.editingActualSize()}
|
tooltip={tr.editingActualSize()}
|
||||||
on:click={toggleActualSize}>{@html icon}</IconButton
|
on:click={toggleActualSize}>{@html icon}</IconButton
|
||||||
>
|
>
|
||||||
|
|
|
@ -58,8 +58,6 @@ export class EditableContainer extends HTMLDivElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
isRightToLeft(): boolean {
|
isRightToLeft(): boolean {
|
||||||
const styleSheet = this.baseStyle.sheet as CSSStyleSheet;
|
return this.baseRule!.style.direction === "rtl";
|
||||||
const firstRule = styleSheet.cssRules[0] as CSSStyleRule;
|
|
||||||
return firstRule.style.direction === "rtl";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,6 +171,7 @@ export class EditingArea extends HTMLDivElement {
|
||||||
(this.imageHandle as any).$set({
|
(this.imageHandle as any).$set({
|
||||||
image: event.target,
|
image: event.target,
|
||||||
imageRule: this.editableContainer.imageRule,
|
imageRule: this.editableContainer.imageRule,
|
||||||
|
isRtl: this.isRightToLeft(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
(this.imageHandle as any).$set({
|
(this.imageHandle as any).$set({
|
||||||
|
|
Loading…
Reference in a new issue