mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
Add CommandIconButton functionality
This commit is contained in:
parent
0963d53e0c
commit
ccb7c5d68a
7 changed files with 173 additions and 53 deletions
|
@ -6,11 +6,19 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
span {
|
button {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
|
|
||||||
vertical-align: -webkit-baseline-middle;
|
vertical-align: -webkit-baseline-middle;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
|
@ -21,5 +29,7 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<ButtonItem>
|
<ButtonItem>
|
||||||
<span class={className}> <input type="color" on:change={onChange} /> </span>
|
<button>
|
||||||
|
<span class={className}> <input type="color" on:change={onChange} /> </span>
|
||||||
|
</button>
|
||||||
</ButtonItem>
|
</ButtonItem>
|
||||||
|
|
57
ts/editor-toolbar/CommandIconButton.svelte
Normal file
57
ts/editor-toolbar/CommandIconButton.svelte
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
<script lang="typescript" context="module">
|
||||||
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
|
export const commandMap = writable(new Map<string, boolean>());
|
||||||
|
|
||||||
|
function updateButton(key: string): void {
|
||||||
|
commandMap.update(
|
||||||
|
(map: Map<string, boolean>): Map<string, boolean> =>
|
||||||
|
new Map([...map, [key, document.queryCommandState(key)]])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateButtons() {
|
||||||
|
commandMap.update(
|
||||||
|
(map: Map<string, boolean>): Map<string, boolean> => {
|
||||||
|
const newMap = new Map<string, boolean>();
|
||||||
|
|
||||||
|
for (const key of map.keys()) {
|
||||||
|
newMap.set(key, document.queryCommandState(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return newMap;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="typescript">
|
||||||
|
import ButtonItem from "./ButtonItem.svelte";
|
||||||
|
import IconButtonInner from "./IconButtonInner.svelte";
|
||||||
|
|
||||||
|
export let className = "";
|
||||||
|
export let icon = "";
|
||||||
|
export let command: string;
|
||||||
|
export let activatable = true;
|
||||||
|
|
||||||
|
let active = false;
|
||||||
|
|
||||||
|
if (activatable) {
|
||||||
|
updateButton(command);
|
||||||
|
|
||||||
|
commandMap.subscribe((map: Record<string, boolean>): void => {
|
||||||
|
active = map.get(command);
|
||||||
|
return () => map.delete(command);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function onClick(event: ClickEvent): void {
|
||||||
|
document.execCommand(command);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ButtonItem>
|
||||||
|
<IconButtonInner {className} {active} {onClick}>
|
||||||
|
{@html icon}
|
||||||
|
</IconButtonInner>
|
||||||
|
</ButtonItem>
|
|
@ -5,19 +5,20 @@
|
||||||
import LabelButton from "./LabelButton.svelte";
|
import LabelButton from "./LabelButton.svelte";
|
||||||
import IconButton from "./IconButton.svelte";
|
import IconButton from "./IconButton.svelte";
|
||||||
|
|
||||||
import boldIcon from "./type-bold.svg";
|
|
||||||
import italicIcon from "./type-italic.svg";
|
|
||||||
import underlineIcon from "./type-underline.svg";
|
|
||||||
|
|
||||||
import superscriptIcon from "./format-superscript.svg";
|
|
||||||
import subscriptIcon from "./format-subscript.svg";
|
|
||||||
import bracketsIcon from "./code-brackets.svg";
|
import bracketsIcon from "./code-brackets.svg";
|
||||||
|
|
||||||
import eraserIcon from "./eraser.svg";
|
|
||||||
import paperclipIcon from "./paperclip.svg";
|
import paperclipIcon from "./paperclip.svg";
|
||||||
import micIcon from "./mic.svg";
|
import micIcon from "./mic.svg";
|
||||||
import threeDotsIcon from "./three-dots.svg";
|
import threeDotsIcon from "./three-dots.svg";
|
||||||
|
|
||||||
|
import {
|
||||||
|
boldButton,
|
||||||
|
italicButton,
|
||||||
|
underlineButton,
|
||||||
|
superscriptButton,
|
||||||
|
subscriptButton,
|
||||||
|
eraserButton,
|
||||||
|
} from "./format";
|
||||||
import { forecolorButton, colorpickerButton } from "./color";
|
import { forecolorButton, colorpickerButton } from "./color";
|
||||||
|
|
||||||
export let leftButtons = [
|
export let leftButtons = [
|
||||||
|
@ -26,14 +27,12 @@
|
||||||
];
|
];
|
||||||
|
|
||||||
export let rightButtons = [
|
export let rightButtons = [
|
||||||
{ component: IconButton, icon: boldIcon },
|
boldButton,
|
||||||
{ component: IconButton, icon: italicIcon },
|
italicButton,
|
||||||
{ component: IconButton, icon: underlineIcon },
|
underlineButton,
|
||||||
|
superscriptButton,
|
||||||
{ component: IconButton, icon: superscriptIcon },
|
subscriptButton,
|
||||||
{ component: IconButton, icon: subscriptIcon },
|
eraserButton,
|
||||||
|
|
||||||
{ component: IconButton, icon: eraserIcon },
|
|
||||||
|
|
||||||
forecolorButton,
|
forecolorButton,
|
||||||
colorpickerButton,
|
colorpickerButton,
|
||||||
|
|
|
@ -1,31 +1,14 @@
|
||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import ButtonItem from "./ButtonItem.svelte";
|
import ButtonItem from "./ButtonItem.svelte";
|
||||||
|
import IconButtonInner from "./IconButtonInner.svelte";
|
||||||
|
|
||||||
export let className: string;
|
export let className = "";
|
||||||
export let icon: string;
|
export let icon = "";
|
||||||
export let onClick: (event: ClickEvent) => void;
|
export let onClick: (event: ClickEvent) => void;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
span {
|
|
||||||
display: inline-block;
|
|
||||||
width: 28px;
|
|
||||||
height: 28px;
|
|
||||||
vertical-align: -webkit-baseline-middle;
|
|
||||||
|
|
||||||
& > :global(svg),
|
|
||||||
& > :global(img) {
|
|
||||||
vertical-align: unset;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<ButtonItem>
|
<ButtonItem>
|
||||||
<span class={className} on:click={onClick} on:mousedown|preventDefault>
|
<IconButtonInner {className} active={false} {onClick}>
|
||||||
{#if icon}
|
{@html icon}
|
||||||
{@html icon}
|
</IconButtonInner>
|
||||||
{/if}
|
|
||||||
</span>
|
|
||||||
</ButtonItem>
|
</ButtonItem>
|
||||||
|
|
36
ts/editor-toolbar/IconButtonInner.svelte
Normal file
36
ts/editor-toolbar/IconButtonInner.svelte
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<script lang="typescript">
|
||||||
|
export let className: string;
|
||||||
|
export let onClick: (event: ClickEvent) => void;
|
||||||
|
export let active: boolean;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
button {
|
||||||
|
display: inline-block;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
|
||||||
|
vertical-align: -webkit-baseline-middle;
|
||||||
|
padding: 2px;
|
||||||
|
|
||||||
|
& > :global(svg),
|
||||||
|
& > :global(img) {
|
||||||
|
vertical-align: unset;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.active {
|
||||||
|
border-bottom: 3px solid black;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
:global(.nightMode) & {
|
||||||
|
border-bottom-color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<button class={className} class:active on:click={onClick} on:mousedown|preventDefault>
|
||||||
|
<slot />
|
||||||
|
</button>
|
|
@ -10,10 +10,6 @@ button.linkb {
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nightMode & > img {
|
|
||||||
filter: invert(180);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
button:focus {
|
button:focus {
|
||||||
|
@ -28,13 +24,4 @@ button.highlighted {
|
||||||
background: linear-gradient(0deg, #333333 0%, #434343 100%);
|
background: linear-gradient(0deg, #333333 0%, #434343 100%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#topbutsright & {
|
|
||||||
border-bottom: 3px solid black;
|
|
||||||
border-radius: 3px;
|
|
||||||
|
|
||||||
.nightMode & {
|
|
||||||
border-bottom-color: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
48
ts/editor-toolbar/format.ts
Normal file
48
ts/editor-toolbar/format.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
// @ts-ignore
|
||||||
|
import CommandIconButton, { updateButtons } from "./CommandIconButton.svelte";
|
||||||
|
import boldIcon from "./type-bold.svg";
|
||||||
|
import italicIcon from "./type-italic.svg";
|
||||||
|
import underlineIcon from "./type-underline.svg";
|
||||||
|
import superscriptIcon from "./format-superscript.svg";
|
||||||
|
import subscriptIcon from "./format-subscript.svg";
|
||||||
|
import eraserIcon from "./eraser.svg";
|
||||||
|
|
||||||
|
export const boldButton = {
|
||||||
|
component: CommandIconButton,
|
||||||
|
icon: boldIcon,
|
||||||
|
command: "bold",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const italicButton = {
|
||||||
|
component: CommandIconButton,
|
||||||
|
icon: italicIcon,
|
||||||
|
command: "italic",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const underlineButton = {
|
||||||
|
component: CommandIconButton,
|
||||||
|
icon: underlineIcon,
|
||||||
|
command: "underline",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const superscriptButton = {
|
||||||
|
component: CommandIconButton,
|
||||||
|
icon: superscriptIcon,
|
||||||
|
command: "superscript",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const subscriptButton = {
|
||||||
|
component: CommandIconButton,
|
||||||
|
icon: subscriptIcon,
|
||||||
|
command: "subscript",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const eraserButton = {
|
||||||
|
component: CommandIconButton,
|
||||||
|
icon: eraserIcon,
|
||||||
|
command: "removeFormat",
|
||||||
|
highlightable: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
setInterval(updateButtons, 2000);
|
Loading…
Reference in a new issue