anki/ts/components/ButtonToolbar.svelte
RumovZ f2173fddb0
Live theme changes (#1497)
* Allow theme change at runtime and add hook

* Save or restore default palette on theme change

* Update aqt widget styles on theme change

* styling fixes

- drop _light_palette, as default_palette serves the same purpose
- save default platform theme, and restore it when switching away
from nightmode
- update macOS light/dark mode on theme switch
- fix unreadable menus on Windows

* update night-mode classes on theme change

This is the easy part - CSS styling that uses standard_css or our
css variables should update automatically. The main remaining issue
is JS code that sets colors based on the theme at the time it's run -
eg the graph code, and the editor.

* switch night mode value on toggle

* expose current theme via a store; switch graphs to use it

https://github.com/ankitects/anki/issues/1471#issuecomment-972402492

* start using currentTheme in editor/components

This fixes basic editing - there are still components that need updating.

* add simple xcodeproj for code completion

* add helper to get currently-active system theme on macOS

* fix setCurrentTheme not being immediately available

* live update tag color

* style().name() doesn't work on Qt5

* automatic theme switching on Windows/Mac

* currentTheme -> pageTheme

* Replace `nightModeKey` with `pageTheme`

Co-authored-by: Damien Elmes <gpg@ankiweb.net>
2021-11-25 07:17:41 +10:00

130 lines
3.9 KiB
Svelte

<!--
Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script context="module" lang="ts">
import type { Identifier } from "./identifier";
import type { SvelteComponent } from "./registration";
export interface ButtonToolbarAPI {
insertGroup(button: SvelteComponent, position: Identifier): void;
appendGroup(button: SvelteComponent, position: Identifier): void;
showGroup(position: Identifier): void;
hideGroup(position: Identifier): void;
toggleGroup(position: Identifier): void;
}
</script>
<script lang="ts">
import { setContext } from "svelte";
import { writable } from "svelte/store";
import Item from "./Item.svelte";
import type { Registration } from "./registration";
import { sectionKey } from "./context-keys";
import { insertElement, appendElement } from "./identifier";
import { makeInterface } from "./registration";
import { pageTheme } from "../sveltelib/theme";
export let id: string | undefined = undefined;
let className: string = "";
export { className as class };
export let size: number | undefined = undefined;
export let wrap: boolean | undefined = undefined;
$: buttonSize = size ? `--buttons-size: ${size}rem; ` : "";
let buttonWrap: string;
$: if (wrap === undefined) {
buttonWrap = "";
} else {
buttonWrap = wrap ? `--buttons-wrap: wrap; ` : `--buttons-wrap: nowrap; `;
}
$: style = buttonSize + buttonWrap;
function makeRegistration(): Registration {
const detach = writable(false);
return { detach };
}
const { registerComponent, dynamicItems, getDynamicInterface } =
makeInterface(makeRegistration);
setContext(sectionKey, registerComponent);
export let api: Partial<ButtonToolbarAPI> | undefined = undefined;
let buttonToolbarRef: HTMLDivElement;
function createApi(): void {
const { addComponent, updateRegistration } =
getDynamicInterface(buttonToolbarRef);
const insertGroup = (group: SvelteComponent, position: Identifier = 0) =>
addComponent(group, (added, parent) =>
insertElement(added, parent, position),
);
const appendGroup = (group: SvelteComponent, position: Identifier = -1) =>
addComponent(group, (added, parent) =>
appendElement(added, parent, position),
);
const showGroup = (id: Identifier) =>
updateRegistration(({ detach }) => detach.set(false), id);
const hideGroup = (id: Identifier) =>
updateRegistration(({ detach }) => detach.set(true), id);
const toggleGroup = (id: Identifier) =>
updateRegistration(
({ detach }) => detach.update((old: boolean): boolean => !old),
id,
);
Object.assign(api, {
insertGroup,
appendGroup,
showGroup,
hideGroup,
toggleGroup,
});
}
$: if (buttonToolbarRef && api) {
createApi();
}
</script>
<div
bind:this={buttonToolbarRef}
{id}
class="button-toolbar btn-toolbar {className}"
class:nightMode={$pageTheme.isDark}
{style}
role="toolbar"
on:focusout
>
<slot />
{#each $dynamicItems as item}
<Item id={item[0].id} registration={item[1]}>
<svelte:component this={item[0].component} {...item[0].props} />
</Item>
{/each}
</div>
<style lang="scss">
@use "sass/scrollbar";
.nightMode {
@include scrollbar.night-mode;
}
.button-toolbar {
flex-wrap: var(--buttons-wrap);
padding-left: 0.15rem;
> :global(*) > :global(*) {
/* TODO replace with gap once available */
margin-right: 0.15rem;
margin-bottom: 0.15rem;
}
}
</style>