mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
Merge pull request #1196 from hgiesel/csscleanup
Use TextInputModal directly
This commit is contained in:
commit
bd307ff890
9 changed files with 104 additions and 107 deletions
|
@ -6,3 +6,4 @@ export const disabledKey = Symbol("disabled");
|
||||||
export const buttonToolbarKey = Symbol("buttonToolbar");
|
export const buttonToolbarKey = Symbol("buttonToolbar");
|
||||||
export const buttonGroupKey = Symbol("buttonGroup");
|
export const buttonGroupKey = Symbol("buttonGroup");
|
||||||
export const dropdownKey = Symbol("dropdown");
|
export const dropdownKey = Symbol("dropdown");
|
||||||
|
export const modalsKey = Symbol("modals");
|
||||||
|
|
|
@ -61,15 +61,14 @@ ts_library(
|
||||||
"lib.ts",
|
"lib.ts",
|
||||||
"steps.ts",
|
"steps.ts",
|
||||||
"strings.ts",
|
"strings.ts",
|
||||||
"textInputModal.ts",
|
|
||||||
],
|
],
|
||||||
module_name = "deckoptions",
|
module_name = "deckoptions",
|
||||||
deps = [
|
deps = [
|
||||||
"TextInputModal",
|
|
||||||
"//ts:image_module_support",
|
"//ts:image_module_support",
|
||||||
"//ts/lib",
|
"//ts/lib",
|
||||||
"//ts/lib:backend_proto",
|
"//ts/lib:backend_proto",
|
||||||
"//ts/sveltelib",
|
"//ts/sveltelib",
|
||||||
|
"//ts/components",
|
||||||
"@npm//lodash-es",
|
"@npm//lodash-es",
|
||||||
"@npm//svelte",
|
"@npm//svelte",
|
||||||
],
|
],
|
||||||
|
@ -133,10 +132,12 @@ svelte_check(
|
||||||
"*.ts",
|
"*.ts",
|
||||||
"*.svelte",
|
"*.svelte",
|
||||||
]) + [
|
]) + [
|
||||||
|
"//ts/sass:button_mixins_lib",
|
||||||
|
"//ts/sass/bootstrap",
|
||||||
"@npm//@types/bootstrap",
|
"@npm//@types/bootstrap",
|
||||||
"@npm//@types/lodash-es",
|
"@npm//@types/lodash-es",
|
||||||
"@npm//@types/marked",
|
"@npm//@types/marked",
|
||||||
"//ts/components:svelte_components",
|
"//ts/components",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,14 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import * as tr from "lib/i18n";
|
import * as tr from "lib/i18n";
|
||||||
|
import { getContext } from "svelte";
|
||||||
|
import { modalsKey } from "components/contextKeys";
|
||||||
import type { DeckOptionsState, ConfigListEntry } from "./lib";
|
import type { DeckOptionsState, ConfigListEntry } from "./lib";
|
||||||
|
import type Modal from "bootstrap/js/dist/modal";
|
||||||
|
|
||||||
import WithTheming from "components/WithTheming.svelte";
|
import TextInputModal from "./TextInputModal.svelte";
|
||||||
import StickyBar from "components/StickyBar.svelte";
|
import StickyBar from "components/StickyBar.svelte";
|
||||||
|
import WithTheming from "components/WithTheming.svelte";
|
||||||
import ButtonToolbar from "components/ButtonToolbar.svelte";
|
import ButtonToolbar from "components/ButtonToolbar.svelte";
|
||||||
import ButtonToolbarItem from "components/ButtonToolbarItem.svelte";
|
import ButtonToolbarItem from "components/ButtonToolbarItem.svelte";
|
||||||
import ButtonGroup from "components/ButtonGroup.svelte";
|
import ButtonGroup from "components/ButtonGroup.svelte";
|
||||||
|
@ -28,8 +32,46 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
function blur(event: Event): void {
|
function blur(event: Event): void {
|
||||||
state.setCurrentIndex(parseInt((event.target! as HTMLSelectElement).value));
|
state.setCurrentIndex(parseInt((event.target! as HTMLSelectElement).value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onAddConfig(text: string): void {
|
||||||
|
const trimmed = text.trim();
|
||||||
|
if (trimmed.length) {
|
||||||
|
state.addConfig(trimmed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRenameConfig(text: string): void {
|
||||||
|
state.setCurrentName(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
const modals = getContext<Map<string, Modal>>(modalsKey);
|
||||||
|
|
||||||
|
let addModalKey: string;
|
||||||
|
let renameModalKey: string;
|
||||||
|
let oldName = "";
|
||||||
|
|
||||||
|
function onAdd() {
|
||||||
|
modals.get(addModalKey)!.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onRename() {
|
||||||
|
oldName = state.getCurrentName();
|
||||||
|
modals.get(renameModalKey)!.show();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<TextInputModal
|
||||||
|
title="Add Config"
|
||||||
|
prompt="Name"
|
||||||
|
onOk={onAddConfig}
|
||||||
|
bind:modalKey={addModalKey} />
|
||||||
|
<TextInputModal
|
||||||
|
title="Rename Config"
|
||||||
|
prompt="Name"
|
||||||
|
onOk={onRenameConfig}
|
||||||
|
value={oldName}
|
||||||
|
bind:modalKey={renameModalKey} />
|
||||||
|
|
||||||
<StickyBar>
|
<StickyBar>
|
||||||
<WithTheming style="--toolbar-size: 2.3rem; --toolbar-wrap: nowrap">
|
<WithTheming style="--toolbar-size: 2.3rem; --toolbar-wrap: nowrap">
|
||||||
<ButtonToolbar class="justify-content-between">
|
<ButtonToolbar class="justify-content-between">
|
||||||
|
@ -50,7 +92,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
</ButtonToolbarItem>
|
</ButtonToolbarItem>
|
||||||
|
|
||||||
<ButtonToolbarItem>
|
<ButtonToolbarItem>
|
||||||
<SaveButton {state} />
|
<SaveButton {state} on:add={onAdd} on:rename={onRename} />
|
||||||
</ButtonToolbarItem>
|
</ButtonToolbarItem>
|
||||||
</ButtonToolbar>
|
</ButtonToolbar>
|
||||||
</WithTheming>
|
</WithTheming>
|
||||||
|
|
|
@ -41,21 +41,5 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
onDestroy(() => registerCleanup?.());
|
onDestroy(() => registerCleanup?.());
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.editor {
|
|
||||||
// without this, the initial viewport can be wrong
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<ConfigSelector {state} />
|
<ConfigSelector {state} />
|
||||||
|
<ConfigEditor {state} />
|
||||||
<div>
|
|
||||||
<div id="modal">
|
|
||||||
<!-- filled in later-->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="editor">
|
|
||||||
<ConfigEditor {state} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import * as tr from "lib/i18n";
|
import * as tr from "lib/i18n";
|
||||||
import { textInputModal } from "./textInputModal";
|
import { createEventDispatcher } from "svelte";
|
||||||
import type { DeckOptionsState } from "./lib";
|
import type { DeckOptionsState } from "./lib";
|
||||||
|
|
||||||
import ButtonGroup from "components/ButtonGroup.svelte";
|
import ButtonGroup from "components/ButtonGroup.svelte";
|
||||||
|
@ -16,32 +16,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import DropdownDivider from "components/DropdownDivider.svelte";
|
import DropdownDivider from "components/DropdownDivider.svelte";
|
||||||
import WithDropdownMenu from "components/WithDropdownMenu.svelte";
|
import WithDropdownMenu from "components/WithDropdownMenu.svelte";
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
export let state: DeckOptionsState;
|
export let state: DeckOptionsState;
|
||||||
|
|
||||||
function addConfig(): void {
|
|
||||||
textInputModal({
|
|
||||||
title: "Add Config",
|
|
||||||
prompt: "Name:",
|
|
||||||
onOk: (text: string) => {
|
|
||||||
const trimmed = text.trim();
|
|
||||||
if (trimmed.length) {
|
|
||||||
state.addConfig(trimmed);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function renameConfig(): void {
|
|
||||||
textInputModal({
|
|
||||||
title: "Rename Config",
|
|
||||||
prompt: "Name:",
|
|
||||||
startingValue: state.getCurrentName(),
|
|
||||||
onOk: (text: string) => {
|
|
||||||
state.setCurrentName(text);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeConfig(): void {
|
function removeConfig(): void {
|
||||||
// show pop-up after dropdown has gone away
|
// show pop-up after dropdown has gone away
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -78,8 +56,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
<WithDropdownMenu let:createDropdown let:activateDropdown let:menuId>
|
<WithDropdownMenu let:createDropdown let:activateDropdown let:menuId>
|
||||||
<LabelButton on:mount={createDropdown} on:click={activateDropdown} />
|
<LabelButton on:mount={createDropdown} on:click={activateDropdown} />
|
||||||
<DropdownMenu id={menuId}>
|
<DropdownMenu id={menuId}>
|
||||||
<DropdownItem on:click={addConfig}>Add Config</DropdownItem>
|
<DropdownItem on:click={() => dispatch('add')}>Add Config</DropdownItem>
|
||||||
<DropdownItem on:click={renameConfig}>Rename Config</DropdownItem>
|
<DropdownItem on:click={() => dispatch('rename')}>
|
||||||
|
Rename Config
|
||||||
|
</DropdownItem>
|
||||||
<DropdownItem on:click={removeConfig}>Remove Config</DropdownItem>
|
<DropdownItem on:click={removeConfig}>Remove Config</DropdownItem>
|
||||||
<DropdownDivider />
|
<DropdownDivider />
|
||||||
<DropdownItem on:click={() => save(true)}>
|
<DropdownItem on:click={() => save(true)}>
|
||||||
|
|
|
@ -6,54 +6,72 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
/* eslint
|
/* eslint
|
||||||
@typescript-eslint/no-non-null-assertion: "off",
|
@typescript-eslint/no-non-null-assertion: "off",
|
||||||
*/
|
*/
|
||||||
import { onMount, onDestroy } from "svelte";
|
import { onMount, onDestroy, getContext } from "svelte";
|
||||||
|
import { nightModeKey, modalsKey } from "components/contextKeys";
|
||||||
import Modal from "bootstrap/js/dist/modal";
|
import Modal from "bootstrap/js/dist/modal";
|
||||||
|
|
||||||
export let title: string;
|
export let title: string;
|
||||||
export let prompt: string;
|
export let prompt: string;
|
||||||
export let startingValue = "";
|
export let value = "";
|
||||||
export let onOk: (text: string) => void;
|
export let onOk: (text: string) => void;
|
||||||
|
|
||||||
let inputRef: HTMLInputElement;
|
export const modalKey: string = Math.random().toString(36).substring(2);
|
||||||
|
|
||||||
|
const modals = getContext<Map<string, Modal>>(modalsKey);
|
||||||
|
|
||||||
|
let modalRef: HTMLDivElement;
|
||||||
let modal: Modal;
|
let modal: Modal;
|
||||||
|
|
||||||
|
let inputRef: HTMLInputElement;
|
||||||
|
|
||||||
|
function onOkClicked(): void {
|
||||||
|
onOk(inputRef.value);
|
||||||
|
modal.hide();
|
||||||
|
value = "";
|
||||||
|
}
|
||||||
|
|
||||||
function onShown(): void {
|
function onShown(): void {
|
||||||
inputRef.focus();
|
inputRef.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onHidden(): void {
|
|
||||||
const container = document.getElementById("modal")!;
|
|
||||||
container.removeChild(container.firstElementChild!);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onOkClicked(): void {
|
|
||||||
onOk(inputRef.value);
|
|
||||||
modal.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const container = document.getElementById("modal")!;
|
modalRef.addEventListener("shown.bs.modal", onShown);
|
||||||
container.addEventListener("shown.bs.modal", onShown);
|
modal = new Modal(modalRef);
|
||||||
container.addEventListener("hidden.bs.modal", onHidden);
|
modals.set(modalKey, modal);
|
||||||
modal = new Modal(container.firstElementChild!, {});
|
|
||||||
modal.show();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
const container = document.getElementById("modal")!;
|
modalRef.removeEventListener("shown.bs.modal", onShown);
|
||||||
container.removeEventListener("shown.bs.modal", onShown);
|
|
||||||
container.removeEventListener("hidden.bs.modal", onHidden);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const nightMode = getContext<boolean>(nightModeKey);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="modal fade" tabindex="-1" aria-labelledby="modalLabel" aria-hidden="true">
|
<style lang="scss">
|
||||||
|
.default-colors {
|
||||||
|
background-color: var(--window-bg);
|
||||||
|
color: var(--text-fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.invert {
|
||||||
|
filter: invert(1) grayscale(100%) brightness(200%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:this={modalRef}
|
||||||
|
class="modal fade"
|
||||||
|
tabindex="-1"
|
||||||
|
aria-labelledby="modalLabel"
|
||||||
|
aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content" class:default-colors={nightMode}>
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="modalLabel">{title}</h5>
|
<h5 class="modal-title" id="modalLabel">{title}</h5>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn-close"
|
class="btn-close"
|
||||||
|
class:invert={nightMode}
|
||||||
data-bs-dismiss="modal"
|
data-bs-dismiss="modal"
|
||||||
aria-label="Close" />
|
aria-label="Close" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -62,13 +80,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label
|
<label
|
||||||
for="prompt-input"
|
for="prompt-input"
|
||||||
class="col-form-label">{prompt}</label>
|
class="col-form-label">{prompt}:</label>
|
||||||
<input
|
<input
|
||||||
id="prompt-input"
|
id="prompt-input"
|
||||||
bind:this={inputRef}
|
bind:this={inputRef}
|
||||||
type="text"
|
type="text"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
value={startingValue} />
|
bind:value />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -14,7 +14,7 @@ import SpinBoxFloat from "./SpinBoxFloat.svelte";
|
||||||
import EnumSelector from "./EnumSelector.svelte";
|
import EnumSelector from "./EnumSelector.svelte";
|
||||||
import CheckBox from "./CheckBox.svelte";
|
import CheckBox from "./CheckBox.svelte";
|
||||||
|
|
||||||
import { nightModeKey } from "components/contextKeys";
|
import { nightModeKey, modalsKey } from "components/contextKeys";
|
||||||
|
|
||||||
export async function deckOptions(
|
export async function deckOptions(
|
||||||
target: HTMLDivElement,
|
target: HTMLDivElement,
|
||||||
|
@ -35,6 +35,9 @@ export async function deckOptions(
|
||||||
const context = new Map();
|
const context = new Map();
|
||||||
context.set(nightModeKey, nightMode);
|
context.set(nightModeKey, nightMode);
|
||||||
|
|
||||||
|
const modals = new Map();
|
||||||
|
context.set(modalsKey, modals);
|
||||||
|
|
||||||
const state = new DeckOptionsState(deckId, info);
|
const state = new DeckOptionsState(deckId, info);
|
||||||
return new DeckOptionsPage({
|
return new DeckOptionsPage({
|
||||||
target,
|
target,
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
||||||
|
|
||||||
/* eslint
|
|
||||||
@typescript-eslint/no-non-null-assertion: "off",
|
|
||||||
*/
|
|
||||||
|
|
||||||
import TextInputModal from "./TextInputModal.svelte";
|
|
||||||
|
|
||||||
export interface TextInputModalProps {
|
|
||||||
title: string;
|
|
||||||
prompt: string;
|
|
||||||
startingValue?: string;
|
|
||||||
onOk: (string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function textInputModal(props: TextInputModalProps): TextInputModal {
|
|
||||||
const target = document.getElementById("modal")!;
|
|
||||||
return new TextInputModal({
|
|
||||||
target,
|
|
||||||
props,
|
|
||||||
});
|
|
||||||
}
|
|
9
ts/sass/bootstrap-dark.scss
vendored
9
ts/sass/bootstrap-dark.scss
vendored
|
@ -14,13 +14,4 @@
|
||||||
background-color: var(--window-bg);
|
background-color: var(--window-bg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
background-color: var(--window-bg);
|
|
||||||
color: var(--text-fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-close {
|
|
||||||
filter: invert(1) grayscale(100%) brightness(200%);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue