mirror of
https://github.com/ankitects/anki.git
synced 2025-11-12 23:57:13 -05:00
Add dropdown menu to mathjax button
This commit is contained in:
parent
391f64f648
commit
fa900e1565
11 changed files with 124 additions and 73 deletions
|
|
@ -60,6 +60,6 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<SquareButton {id} {className} {props} {active} {onClick}>
|
||||
<SquareButton {id} {className} {props} {active} {onClick} on:mount>
|
||||
{@html icon}
|
||||
</SquareButton>
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
<script lang="typescript">
|
||||
export let onClick: (event: ClickEvent) => void;
|
||||
</script>
|
||||
|
||||
<li>
|
||||
<button class="dropdown-item" on:click={onClick} on:mousedown|preventDefault>
|
||||
{#if $$slots.default}
|
||||
<slot />
|
||||
{:else}
|
||||
<span class="float-start"><slot name="start" /></span>
|
||||
<span class="float-end"><slot name="end" /></span>
|
||||
{/if}
|
||||
</button>
|
||||
</li>
|
||||
|
|
@ -1,40 +1,26 @@
|
|||
<script lang="typescript">
|
||||
import { onMount } from "svelte";
|
||||
|
||||
import type { ButtonDefinition } from "./types";
|
||||
|
||||
export let button: ButtonDefinition;
|
||||
export let menuId: string;
|
||||
|
||||
function extend({ className, props, ...rest }: ButtonDefinition): ButtonDefinition {
|
||||
return {
|
||||
className: `${className} dropdown-toggle`,
|
||||
props: {
|
||||
"data-bs-toggle": "dropdown",
|
||||
"aria-expanded": "false",
|
||||
...props,
|
||||
},
|
||||
...rest,
|
||||
};
|
||||
interface DropdownItem {
|
||||
label: string;
|
||||
endLabel: string;
|
||||
onClick: (event: ClickEvent) => void;
|
||||
}
|
||||
|
||||
function createDropdown({ detail }: CustomEvent): void {
|
||||
const button: HTMLButtonElement = detail.button;
|
||||
|
||||
/* Prevent focus on menu activation */
|
||||
const noop = () => {};
|
||||
Object.defineProperty(button, "focus", { value: noop });
|
||||
|
||||
/* Set custom menu without using .dropdown
|
||||
* Rendering the menu here would cause the menu to
|
||||
* be displayed outside of the visible area
|
||||
*/
|
||||
const dropdown = new bootstrap.Dropdown(button);
|
||||
dropdown._menu = button.getRootNode().getElementById(menuId);
|
||||
}
|
||||
export let id: string;
|
||||
export let menuItems: DropdownItem[];
|
||||
</script>
|
||||
|
||||
<svelte:component
|
||||
this={button.component}
|
||||
{...extend(button)}
|
||||
on:mount={createDropdown} />
|
||||
<ul class="dropdown-menu" {id}>
|
||||
{#each menuItems as menuItem}
|
||||
<li>
|
||||
<button
|
||||
class="dropdown-item"
|
||||
on:click={menuItem.onClick}
|
||||
on:mousedown|preventDefault>
|
||||
<span class="float-start">{menuItem.label}</span>
|
||||
{#if menuItem.endLabel}
|
||||
<span class="float-end">{menuItem.endLabel}</span>
|
||||
{/if}
|
||||
</button>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="typescript">
|
||||
import DropdownItem from "./DropdownItem.svelte";
|
||||
import type { Readable } from "svelte/store";
|
||||
import { setContext } from "svelte";
|
||||
import { disabledKey, nightModeKey } from "./contextKeys";
|
||||
|
|
@ -8,11 +7,13 @@
|
|||
import type { Buttons } from "./types";
|
||||
|
||||
export let buttons: Buttons = [];
|
||||
export let menus: SvelteComponent[];
|
||||
|
||||
export let nightMode: boolean;
|
||||
export let disabled: Readable<boolean> = false;
|
||||
|
||||
setContext(disabledKey, disabled);
|
||||
setContext(nightModeKey, nightMode);
|
||||
setContext(disabledKey, disabled);
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
@ -38,14 +39,11 @@
|
|||
}
|
||||
</style>
|
||||
|
||||
<ul class="dropdown-menu" id="dropdownMenuButton123" aria-labelledby="dropdownMenuButton123">
|
||||
<DropdownItem>
|
||||
<svelte:fragment slot="start">Action</svelte:fragment>
|
||||
<svelte:fragment slot="end">Shortcut</svelte:fragment>
|
||||
</DropdownItem>
|
||||
<DropdownItem>Action 1</DropdownItem>
|
||||
<DropdownItem>Action 2</DropdownItem>
|
||||
</ul>
|
||||
<div>
|
||||
{#each menus as menu}
|
||||
<svelte:component this={menu.component} {...menu} />
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<ButtonGroup {buttons} />
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@
|
|||
export let onClick: (event: ClickEvent) => void;
|
||||
</script>
|
||||
|
||||
<SquareButton {id} {className} {props} {onClick}>
|
||||
<SquareButton {id} {className} {props} {onClick} on:mount>
|
||||
{@html icon}
|
||||
</SquareButton>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
export let label: string;
|
||||
export let onClick: (event: ClickEvent) => void;
|
||||
export let disables = true;
|
||||
|
||||
let buttonRef: HTMLButtonElement;
|
||||
|
||||
|
|
@ -21,7 +22,7 @@
|
|||
onMount(() => dispatch("mount", { button: buttonRef }));
|
||||
|
||||
const disabledStore = getContext(disabledKey);
|
||||
$: disabled = $disabledStore;
|
||||
$: disabled = disables && $disabledStore;
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="typescript">
|
||||
import { getContext } from "svelte";
|
||||
import { getContext, onMount, createEventDispatcher } from "svelte";
|
||||
import type { Readable } from "svelte/store";
|
||||
import { disabledKey } from "./contextKeys";
|
||||
|
||||
|
|
@ -10,8 +10,13 @@
|
|||
export let onClick: (event: ClickEvent) => void;
|
||||
export let active = false;
|
||||
|
||||
let buttonRef: HTMLButtonElement;
|
||||
|
||||
const disabledStore = getContext(disabledKey);
|
||||
$: disabled = $disabledStore;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
onMount(() => dispatch("mount", { button: buttonRef }));
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
@ -75,6 +80,7 @@
|
|||
</style>
|
||||
|
||||
<button
|
||||
bind:this={buttonRef}
|
||||
{id}
|
||||
class={className}
|
||||
{...props}
|
||||
|
|
|
|||
46
ts/editor-toolbar/WithDropdownMenu.svelte
Normal file
46
ts/editor-toolbar/WithDropdownMenu.svelte
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<script lang="typescript">
|
||||
import { onMount } from "svelte";
|
||||
|
||||
import type { ButtonDefinition } from "./types";
|
||||
|
||||
export let button: ButtonDefinition;
|
||||
export let menuId: string;
|
||||
|
||||
function extend({ className, props, ...rest }: ButtonDefinition): ButtonDefinition {
|
||||
return {
|
||||
className: `${className} dropdown-toggle`,
|
||||
props: {
|
||||
"data-bs-toggle": "dropdown",
|
||||
"aria-expanded": "false",
|
||||
...props,
|
||||
},
|
||||
...rest,
|
||||
};
|
||||
}
|
||||
|
||||
function createDropdown({ detail }: CustomEvent): void {
|
||||
const button: HTMLButtonElement = detail.button;
|
||||
|
||||
/* Prevent focus on menu activation */
|
||||
const noop = () => {};
|
||||
Object.defineProperty(button, "focus", { value: noop });
|
||||
|
||||
/* Set custom menu without using .dropdown
|
||||
* Rendering the menu here would cause the menu to
|
||||
* be displayed outside of the visible area
|
||||
*/
|
||||
const dropdown = new bootstrap.Dropdown(button);
|
||||
const menu = button.getRootNode().getElementById(menuId);
|
||||
|
||||
if (!menu) {
|
||||
console.log(`Could not find menu "${menuId}" for dropdown menu.`);
|
||||
}
|
||||
|
||||
dropdown._menu = menu;
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:component
|
||||
this={button.component}
|
||||
{...extend(button)}
|
||||
on:mount={createDropdown} />
|
||||
|
|
@ -20,8 +20,8 @@ function onCloze(): void {
|
|||
bridgeCommand("cloze");
|
||||
}
|
||||
|
||||
function onMore(): void {
|
||||
bridgeCommand("more");
|
||||
function onHtmlEdit(): void {
|
||||
bridgeCommand("htmlEdit");
|
||||
}
|
||||
|
||||
export const attachmentButton = {
|
||||
|
|
@ -41,11 +41,10 @@ export const clozeButton = {
|
|||
export const mathjaxButton = {
|
||||
component: IconButton,
|
||||
icon: functionIcon,
|
||||
onClick: onMore,
|
||||
};
|
||||
|
||||
export const htmlButton = {
|
||||
component: IconButton,
|
||||
icon: xmlIcon,
|
||||
onClick: onMore,
|
||||
onClick: onHtmlEdit,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,13 +5,15 @@ import { setupI18n, ModuleName } from "anki/i18n";
|
|||
|
||||
import EditorToolbarSvelte from "./EditorToolbar.svelte";
|
||||
|
||||
import LabelButton from "./LabelButton.svelte";
|
||||
import DropdownMenu from "./DropdownMenu.svelte";
|
||||
import WithDropdownMenu from "./WithDropdownMenu.svelte";
|
||||
|
||||
// @ts-ignore
|
||||
export { updateActiveButtons, clearActiveButtons } from "./CommandIconButton.svelte";
|
||||
import { Writable, writable } from "svelte/store";
|
||||
|
||||
import { fieldsButton, cardsButton } from "./notetype";
|
||||
|
||||
import {
|
||||
boldButton,
|
||||
italicButton,
|
||||
|
|
@ -31,11 +33,16 @@ import {
|
|||
htmlButton,
|
||||
} from "./extra";
|
||||
|
||||
const defaultMenus = [
|
||||
{
|
||||
component: DropdownMenu,
|
||||
id: "mathjaxMenu",
|
||||
menuItems: [{ label: "Foo", onClick: () => console.log("foo") }],
|
||||
},
|
||||
];
|
||||
|
||||
const defaultButtons = [
|
||||
[
|
||||
{ component: LabelButton, label: "Fields..." },
|
||||
{ component: LabelButton, label: "Cards..." },
|
||||
],
|
||||
[fieldsButton, cardsButton],
|
||||
[
|
||||
boldButton,
|
||||
italicButton,
|
||||
|
|
@ -45,7 +52,13 @@ const defaultButtons = [
|
|||
eraserButton,
|
||||
],
|
||||
[forecolorButton, colorpickerButton],
|
||||
[attachmentButton, recordButton, clozeButton, mathjaxButton, htmlButton],
|
||||
[
|
||||
attachmentButton,
|
||||
recordButton,
|
||||
clozeButton,
|
||||
{ component: WithDropdownMenu, menuId: "mathjaxMenu", button: mathjaxButton },
|
||||
htmlButton,
|
||||
],
|
||||
];
|
||||
|
||||
class EditorToolbar extends HTMLElement {
|
||||
|
|
@ -60,6 +73,7 @@ class EditorToolbar extends HTMLElement {
|
|||
this.component = new EditorToolbarSvelte({
|
||||
target: this,
|
||||
props: {
|
||||
menus: defaultMenus,
|
||||
buttons: defaultButtons,
|
||||
nightMode: checkNightMode(),
|
||||
disabled: this.disabled,
|
||||
|
|
|
|||
15
ts/editor-toolbar/notetype.ts
Normal file
15
ts/editor-toolbar/notetype.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { bridgeCommand } from "anki/bridgecommand";
|
||||
import LabelButton from "./LabelButton.svelte";
|
||||
|
||||
export const fieldsButton = {
|
||||
component: LabelButton,
|
||||
label: "Fields...",
|
||||
onClick: () => bridgeCommand("fields"),
|
||||
disables: false,
|
||||
};
|
||||
export const cardsButton = {
|
||||
component: LabelButton,
|
||||
label: "Cards...",
|
||||
onClick: () => bridgeCommand("cards"),
|
||||
disables: false,
|
||||
};
|
||||
Loading…
Reference in a new issue