Refactor Select component | Fix CSV import issue (#2227)

* Refactor Select component and implement/update it in various screens

* Remove redundant select CSS

* Tweak DeckOptionsPage

* Fix CSV import layout

* Fix save button margin in change notetype screen

* Fix sticky header positioning

* Remove unused imports

* Make StickyHeader sticky instead of fixed
This commit is contained in:
Matthias Metelka 2022-12-01 10:24:26 +01:00 committed by GitHub
parent 9ecc0ffdc6
commit 9c45a2f7d0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 248 additions and 197 deletions

View file

@ -105,8 +105,6 @@ $focus-color: var(--shadow-focus);
@mixin select($with-disabled: true) { @mixin select($with-disabled: true) {
width: 100%; width: 100%;
white-space: nowrap;
text-overflow: ellipsis;
pointer-events: all; pointer-events: all;
cursor: pointer; cursor: pointer;

View file

@ -57,44 +57,11 @@ samp {
unicode-bidi: normal !important; unicode-bidi: normal !important;
} }
[dir="rtl"] {
.form-select {
/* flip <select>'s arrow */
background-position: left 0.75rem center;
}
}
.form-select:focus {
outline: none;
border: 1px solid color(border-focus);
box-shadow: none !important;
}
.night-mode .form-select:disabled {
background-color: color(fg-disabled);
}
.reduced-motion * { .reduced-motion * {
transition: none !important; transition: none !important;
animation: none !important; animation: none !important;
} }
select {
@include button.background;
@include button.border-radius;
cursor: pointer;
outline: none;
&:focus,
&.focus {
border: 1px solid color(border-focus);
}
option {
background: color(canvas-elevated);
color: color(fg);
}
}
label, label,
input[type="radio"], input[type="radio"],
input[type="checkbox"] { input[type="checkbox"] {

View file

@ -19,14 +19,14 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
const options = $info.getOldNamesIncludingNothing(ctx); const options = $info.getOldNamesIncludingNothing(ctx);
$: state.setOldIndex(ctx, newIndex, oldIndex); $: state.setOldIndex(ctx, newIndex, oldIndex);
$: label = options[oldIndex];
</script> </script>
<Row --cols={2}> <Row --cols={2}>
<Col --col-size={1}> <Col --col-size={1}>
<!-- svelte-ignore a11y-no-onchange --> <Select bind:value={oldIndex} {label}>
<Select current={options[oldIndex]}>
{#each options as name, idx} {#each options as name, idx}
<SelectOption on:select={() => (oldIndex = idx)}>{name}</SelectOption> <SelectOption value={idx}>{name}</SelectOption>
{/each} {/each}
</Select> </Select>
</Col> </Col>

View file

@ -4,7 +4,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
--> -->
<script lang="ts"> <script lang="ts">
import Badge from "../components/Badge.svelte"; import Badge from "../components/Badge.svelte";
import ButtonGroup from "../components/ButtonGroup.svelte";
import ButtonToolbar from "../components/ButtonToolbar.svelte"; import ButtonToolbar from "../components/ButtonToolbar.svelte";
import LabelButton from "../components/LabelButton.svelte"; import LabelButton from "../components/LabelButton.svelte";
import Select from "../components/Select.svelte"; import Select from "../components/Select.svelte";
@ -16,13 +15,17 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export let state: ChangeNotetypeState; export let state: ChangeNotetypeState;
const notetypes = state.notetypes; const notetypes = state.notetypes;
const info = state.info; const info = state.info;
let value: number = 0;
$: state.setTargetNotetypeIndex(value); let value: number = 0;
$: options = Array.from($notetypes, (notetype) => notetype.name); $: options = Array.from($notetypes, (notetype) => notetype.name);
$: label = options[value];
function blur(e: CustomEvent): void {
state.setTargetNotetypeIndex(e.detail.newIdx);
}
</script> </script>
<ButtonToolbar class="justify-content-between" size={2.3} wrap={false}> <ButtonToolbar class="justify-content-between" wrap={false}>
<LabelButton disabled={true}> <LabelButton disabled={true}>
{$info.oldNotetypeName} {$info.oldNotetypeName}
</LabelButton> </LabelButton>
@ -33,13 +36,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{@html arrowRightIcon} {@html arrowRightIcon}
{/if} {/if}
</Badge> </Badge>
<ButtonGroup class="flex-grow-1"> <Select class="flex-grow-1" bind:value {label} on:change={blur}>
<Select class="flex-grow-1" current={options[value]}>
{#each options as option, idx} {#each options as option, idx}
<SelectOption on:select={() => (value = idx)}>{option}</SelectOption> <SelectOption value={idx}>{option}</SelectOption>
{/each} {/each}
</Select> </Select>
</ButtonGroup>
<SaveButton {state} /> <SaveButton {state} />
</ButtonToolbar> </ButtonToolbar>

View file

@ -29,7 +29,15 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
tooltip={getPlatformString(keyCombination)} tooltip={getPlatformString(keyCombination)}
on:click={save} on:click={save}
--border-left-radius="5px" --border-left-radius="5px"
--border-right-radius="5px">{tr.actionsSave()}</LabelButton --border-right-radius="5px"
> >
<div class="save">{tr.actionsSave()}</div>
</LabelButton>
<Shortcut {keyCombination} on:action={save} /> <Shortcut {keyCombination} on:action={save} />
</ButtonGroup> </ButtonGroup>
<style lang="scss">
.save {
margin: 0.15rem 0.75rem;
}
</style>

View file

@ -3,25 +3,48 @@ 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="ts"> <script lang="ts">
import { createEventDispatcher, setContext } from "svelte";
import { selectKey } from "./context-keys";
import IconConstrain from "./IconConstrain.svelte"; import IconConstrain from "./IconConstrain.svelte";
import { chevronDown } from "./icons"; import { chevronDown } from "./icons";
import Popover from "./Popover.svelte"; import Popover from "./Popover.svelte";
import WithFloating from "./WithFloating.svelte"; import WithFloating from "./WithFloating.svelte";
export let id: string | undefined = undefined; export let id: string | undefined = undefined;
let className = ""; let className = "";
export { className as class }; export { className as class };
export let disabled = false; export let disabled = false;
export let current: string = ""; export let label = "<br>";
export let value = 0;
const dispatch = createEventDispatcher();
function setValue(v: number) {
dispatch("change", { oldIdx: value, newIdx: v });
value = v;
}
export let element: HTMLElement | undefined = undefined;
export let tooltip: string | undefined = undefined; export let tooltip: string | undefined = undefined;
const rtl: boolean = window.getComputedStyle(document.body).direction == "rtl"; const rtl: boolean = window.getComputedStyle(document.body).direction == "rtl";
export let element: HTMLElement | undefined = undefined;
let hover = false; let hover = false;
let showFloating = false; let showFloating = false;
let clientWidth: number; let clientWidth: number;
async function handleKey(e: KeyboardEvent) {
if (e.code === "Enter") {
e.preventDefault();
showFloating = !showFloating;
}
}
setContext(selectKey, setValue);
</script> </script>
<WithFloating <WithFloating
@ -31,6 +54,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
hideArrow hideArrow
inline inline
closeOnInsideClick closeOnInsideClick
keepOnKeyup
on:close={() => (showFloating = false)} on:close={() => (showFloating = false)}
let:asReference let:asReference
> >
@ -41,7 +65,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
class:hover class:hover
{disabled} {disabled}
title={tooltip} title={tooltip}
tabindex="-1" tabindex="0"
on:keypress={handleKey}
on:mouseenter={() => (hover = true)} on:mouseenter={() => (hover = true)}
on:mouseleave={() => (hover = false)} on:mouseleave={() => (hover = false)}
on:click={() => (showFloating = !showFloating)} on:click={() => (showFloating = !showFloating)}
@ -49,7 +74,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use:asReference use:asReference
bind:clientWidth bind:clientWidth
> >
{current} <div class="inner">
<div class="label">{@html label}</div>
</div>
<div class="chevron"> <div class="chevron">
<IconConstrain iconSize={80}> <IconConstrain iconSize={80}>
{@html chevronDown} {@html chevronDown}
@ -63,26 +90,42 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<style lang="scss"> <style lang="scss">
@use "sass/button-mixins" as button; @use "sass/button-mixins" as button;
$padding-inline: 0.5rem;
.select-container { .select-container {
@include button.select($with-disabled: false); @include button.select($with-disabled: false);
padding: 0.2rem 2rem 0.2rem 0.75rem;
line-height: 1.5; line-height: 1.5;
height: var(--buttons-size, 100%); height: 100%;
position: relative; position: relative;
display: flex;
flex-flow: row;
justify-content: space-between;
.inner {
flex-grow: 1;
position: relative;
.label {
position: absolute;
top: 0;
right: $padding-inline;
bottom: 0;
left: $padding-inline;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
} }
.chevron { .chevron {
position: absolute; height: 100%;
top: 0; align-self: flex-end;
right: 0;
bottom: 0;
left: auto;
border-left: 1px solid var(--border-subtle); border-left: 1px solid var(--border-subtle);
} }
:global([dir="rtl"]) { :global([dir="rtl"]) {
.chevron { .chevron {
left: 0;
right: auto;
border-left: none; border-left: none;
border-right: 1px solid var(--border-subtle); border-right: 1px solid var(--border-subtle);
} }

View file

@ -3,22 +3,51 @@ 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="ts"> <script lang="ts">
import { createEventDispatcher } from "svelte"; import { getContext } from "svelte";
import { selectKey } from "./context-keys";
import DropdownItem from "./DropdownItem.svelte"; import DropdownItem from "./DropdownItem.svelte";
export let disabled = false; export let disabled = false;
export let value: number;
const dispatch = createEventDispatcher();
let element: HTMLButtonElement; let element: HTMLButtonElement;
function onSelect(): void { function handleKey(e: KeyboardEvent) {
if (!disabled) { /* Arrow key navigation */
dispatch("select"); switch (e.code) {
case "ArrowUp": {
const prevSibling = element?.previousElementSibling as HTMLElement;
if (prevSibling) {
prevSibling.focus();
} else {
// close popover
document.body.click();
}
break;
}
case "ArrowDown": {
const nextSibling = element?.nextElementSibling as HTMLElement;
if (nextSibling) {
nextSibling.focus();
} else {
// close popover
document.body.click();
}
break;
} }
} }
}
const setValue: Function = getContext(selectKey);
</script> </script>
<DropdownItem {disabled} on:click={onSelect} bind:buttonRef={element}> <DropdownItem
{disabled}
on:click={() => setValue(value)}
on:keydown={handleKey}
bind:buttonRef={element}
tabbable
>
<slot /> <slot />
</DropdownItem> </DropdownItem>

View file

@ -8,3 +8,4 @@ export const dropdownKey = Symbol("dropdown");
export const modalsKey = Symbol("modals"); export const modalsKey = Symbol("modals");
export const floatingKey = Symbol("floating"); export const floatingKey = Symbol("floating");
export const overlayKey = Symbol("overlay"); export const overlayKey = Symbol("overlay");
export const selectKey = Symbol("select");

View file

@ -8,7 +8,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import type Modal from "bootstrap/js/dist/modal"; import type Modal from "bootstrap/js/dist/modal";
import { createEventDispatcher, getContext } from "svelte"; import { createEventDispatcher, getContext } from "svelte";
import ButtonGroup from "../components/ButtonGroup.svelte";
import ButtonToolbar from "../components/ButtonToolbar.svelte"; import ButtonToolbar from "../components/ButtonToolbar.svelte";
import { modalsKey } from "../components/context-keys"; import { modalsKey } from "../components/context-keys";
import Select from "../components/Select.svelte"; import Select from "../components/Select.svelte";
@ -23,19 +22,18 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
const dispatchPresetChange = () => dispatch("presetchange"); const dispatchPresetChange = () => dispatch("presetchange");
$: { $: label = configLabel($configList.find((entry) => entry.current)!);
state.setCurrentIndex(value);
dispatchPresetChange();
}
$: options = Array.from($configList, (entry) => configLabel(entry));
$: value = $configList.find((entry) => entry.current)?.idx || 0;
function configLabel(entry: ConfigListEntry): string { function configLabel(entry: ConfigListEntry): string {
const count = tr.deckConfigUsedByDecks({ decks: entry.useCount }); const count = tr.deckConfigUsedByDecks({ decks: entry.useCount });
return `${entry.name} (${count})`; return `${entry.name} (${count})`;
} }
function blur(e: CustomEvent): void {
state.setCurrentIndex(e.detail.newIdx);
dispatchPresetChange();
}
function onAddConfig(text: string): void { function onAddConfig(text: string): void {
const trimmed = text.trim(); const trimmed = text.trim();
if (trimmed.length) { if (trimmed.length) {
@ -94,16 +92,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
/> />
<StickyContainer --gutter-block="0.5rem" --sticky-borders="0 0 1px" breakpoint="sm"> <StickyContainer --gutter-block="0.5rem" --sticky-borders="0 0 1px" breakpoint="sm">
<ButtonToolbar class="justify-content-between" size={2.3} wrap={false}> <ButtonToolbar class="justify-content-between flex-grow-1" wrap={false}>
<ButtonGroup class="flex-grow-1"> <Select class="flex-grow-1" {label} on:change={blur}>
<Select class="flex-grow-1" current={options[value]}> {#each $configList as entry}
{#each options as option, idx} <SelectOption value={entry.idx}>{configLabel(entry)}</SelectOption>
<SelectOption on:select={() => (value = idx)}
>{option}
</SelectOption>
{/each} {/each}
</Select> </Select>
</ButtonGroup>
<SaveButton <SaveButton
{state} {state}

View file

@ -9,11 +9,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export let options: string[] = []; export let options: string[] = [];
export let disabled: number[] = []; export let disabled: number[] = [];
export let value = 0; export let value = 0;
$: label = options[value];
</script> </script>
<Select current={options[value]}> <Select bind:value {label}>
{#each options as option, idx} {#each options as option, idx}
<SelectOption disabled={disabled.includes(idx)} on:select={() => (value = idx)} <SelectOption value={idx} disabled={disabled.includes(idx)}
>{option}</SelectOption >{option}</SelectOption
> >
{/each} {/each}

View file

@ -113,6 +113,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<style lang="scss"> <style lang="scss">
.save { .save {
margin: 0.2rem 0.75rem; margin: 0 0.75rem;
}
/* Todo: find more elegant fix for misalignment */
:global(.chevron) {
height: 100% !important;
} }
</style> </style>

View file

@ -10,8 +10,7 @@
.setting-title { .setting-title {
cursor: help; cursor: help;
&:hover { &:hover {
text-decoration: underline; text-decoration: underline dotted var(--fg-subtle);
text-decoration-style: dashed;
} }
} }
</style> </style>

View file

@ -3,7 +3,6 @@ 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="ts"> <script lang="ts">
import { pageTheme } from "../sveltelib/theme";
import { stepsToString, stringToSteps } from "./steps"; import { stepsToString, stringToSteps } from "./steps";
export let value: number[]; export let value: number[];
@ -16,18 +15,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
</script> </script>
<input <input type="text" value={stringValue} on:blur={update} />
type="text"
value={stringValue}
class="form-control"
class:nightMode={$pageTheme.isDark}
on:blur={update}
/>
<style lang="scss"> <style lang="scss">
@use "sass/night-mode" as nightmode; input {
width: 100%;
.nightMode {
@include nightmode.input;
} }
</style> </style>

View file

@ -14,3 +14,8 @@ $carousel-transition: 0.2s;
@import "bootstrap/scss/badge"; @import "bootstrap/scss/badge";
@import "sass/bootstrap-forms"; @import "sass/bootstrap-forms";
@import "sass/bootstrap-tooltip"; @import "sass/bootstrap-tooltip";
input[type="text"] {
padding-inline: 0.5rem;
background: var(--canvas-inset);
}

View file

@ -8,9 +8,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import Col from "../components/Col.svelte"; import Col from "../components/Col.svelte";
import Row from "../components/Row.svelte"; import Row from "../components/Row.svelte";
import Select from "../components/Select.svelte";
import SelectOption from "../components/SelectOption.svelte";
export let deckNameIds: Decks.DeckNameId[]; export let deckNameIds: Decks.DeckNameId[];
export let deckId: number; export let deckId: number;
$: label = deckNameIds.find((d) => d.id === deckId)?.name.replace(/^.+::/, "...");
</script> </script>
<Row --cols={2}> <Row --cols={2}>
@ -18,11 +22,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{tr.decksDeck()} {tr.decksDeck()}
</Col> </Col>
<Col --col-size={1}> <Col --col-size={1}>
<!-- svelte-ignore a11y-no-onchange --> <Select bind:value={deckId} {label}>
<select class="form-select" bind:value={deckId}>
{#each deckNameIds as { id, name }} {#each deckNameIds as { id, name }}
<option value={id}>{name}</option> <SelectOption value={id}>{name}</SelectOption>
{/each} {/each}
</select> </Select>
</Col> </Col>
</Row> </Row>

View file

@ -8,6 +8,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import Col from "../components/Col.svelte"; import Col from "../components/Col.svelte";
import Row from "../components/Row.svelte"; import Row from "../components/Row.svelte";
import Select from "../components/Select.svelte";
import SelectOption from "../components/SelectOption.svelte";
export let delimiter: ImportExport.CsvMetadata.Delimiter; export let delimiter: ImportExport.CsvMetadata.Delimiter;
export let disabled: boolean; export let disabled: boolean;
@ -21,6 +23,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{ value: Delimiter.COMMA, label: tr.importingComma() }, { value: Delimiter.COMMA, label: tr.importingComma() },
{ value: Delimiter.SPACE, label: tr.studyingSpace() }, { value: Delimiter.SPACE, label: tr.studyingSpace() },
]; ];
$: label = delimiters.find((d) => d.value === delimiter)?.label;
</script> </script>
<Row --cols={2}> <Row --cols={2}>
@ -28,11 +32,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{tr.importingFieldSeparator()} {tr.importingFieldSeparator()}
</Col> </Col>
<Col --col-size={1}> <Col --col-size={1}>
<!-- svelte-ignore a11y-no-onchange --> <Select bind:value={delimiter} {disabled} {label}>
<select class="form-select" bind:value={delimiter} {disabled}>
{#each delimiters as { value, label }} {#each delimiters as { value, label }}
<option {value}>{label}</option> <SelectOption {value}>{label}</SelectOption>
{/each} {/each}
</select> </Select>
</Col> </Col>
</Row> </Row>

View file

@ -8,6 +8,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import Col from "../components/Col.svelte"; import Col from "../components/Col.svelte";
import Row from "../components/Row.svelte"; import Row from "../components/Row.svelte";
import Select from "../components/Select.svelte";
import SelectOption from "../components/SelectOption.svelte";
export let dupeResolution: ImportExport.CsvMetadata.DupeResolution; export let dupeResolution: ImportExport.CsvMetadata.DupeResolution;
@ -25,6 +27,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
label: tr.importingPreserve(), label: tr.importingPreserve(),
}, },
]; ];
$: label = dupeResolutions.find((r) => r.value === dupeResolution)?.label;
</script> </script>
<Row --cols={2}> <Row --cols={2}>
@ -32,11 +36,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{tr.importingExistingNotes()} {tr.importingExistingNotes()}
</Col> </Col>
<Col --col-size={1}> <Col --col-size={1}>
<!-- svelte-ignore a11y-no-onchange --> <Select bind:value={dupeResolution} {label}>
<select class="form-select" bind:value={dupeResolution}>
{#each dupeResolutions as { label, value }} {#each dupeResolutions as { label, value }}
<option {value}>{label}</option> <SelectOption {value}>{label}</SelectOption>
{/each} {/each}
</select> </Select>
</Col> </Col>
</Row> </Row>

View file

@ -20,7 +20,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import { getColumnOptions, getCsvMetadata } from "./lib"; import { getColumnOptions, getCsvMetadata } from "./lib";
import NotetypeSelector from "./NotetypeSelector.svelte"; import NotetypeSelector from "./NotetypeSelector.svelte";
import Preview from "./Preview.svelte"; import Preview from "./Preview.svelte";
import StickyFooter from "./StickyFooter.svelte"; import StickyHeader from "./StickyHeader.svelte";
import Tags from "./Tags.svelte"; import Tags from "./Tags.svelte";
export let path: string; export let path: string;
@ -92,6 +92,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
</script> </script>
<StickyHeader {path} {onImport} />
<Container class="csv-page"> <Container class="csv-page">
<Row --cols={2}> <Row --cols={2}>
<Col --col-size={1} breakpoint="md"> <Col --col-size={1} breakpoint="md">
@ -128,7 +130,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
</Container> </Container>
</Col> </Col>
</Row> </Row>
<StickyFooter {path} {onImport} />
</Container> </Container>
<style lang="scss"> <style lang="scss">
@ -138,9 +139,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
:global(.row) { :global(.row) {
// rows have negative margins by default // rows have negative margins by default
--bs-gutter-x: 0; --bs-gutter-x: 0;
// ensure equal spacing between tall rows like margin-bottom: 0.5rem;
// dropdowns, and short rows like checkboxes
min-height: 3em;
} }
} }
</style> </style>

View file

@ -5,23 +5,28 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<script lang="ts"> <script lang="ts">
import Col from "../components/Col.svelte"; import Col from "../components/Col.svelte";
import Row from "../components/Row.svelte"; import Row from "../components/Row.svelte";
import Select from "../components/Select.svelte";
import SelectOption from "../components/SelectOption.svelte";
import type { ColumnOption } from "./lib"; import type { ColumnOption } from "./lib";
export let label: string; let rowLabel: string;
export { rowLabel as label };
export let columnOptions: ColumnOption[]; export let columnOptions: ColumnOption[];
export let value: number; export let value: number;
$: label = columnOptions.find((o) => o.value === value)?.label;
</script> </script>
<Row --cols={2}> <Row --cols={2}>
<Col --col-size={1}> <Col --col-size={1}>
{label} {rowLabel}
</Col> </Col>
<Col --col-size={1}> <Col --col-size={1}>
<!-- svelte-ignore a11y-no-onchange --> <Select bind:value {label}>
<select class="form-select" bind:value>
{#each columnOptions as { label, value, disabled }} {#each columnOptions as { label, value, disabled }}
<option {value} {disabled}>{label}</option> <SelectOption {value} {disabled}>{label}</SelectOption>
{/each} {/each}
</select> </Select>
</Col> </Col>
</Row> </Row>

View file

@ -8,9 +8,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import Col from "../components/Col.svelte"; import Col from "../components/Col.svelte";
import Row from "../components/Row.svelte"; import Row from "../components/Row.svelte";
import Select from "../components/Select.svelte";
import SelectOption from "../components/SelectOption.svelte";
export let notetypeNameIds: Notetypes.NotetypeNameId[]; export let notetypeNameIds: Notetypes.NotetypeNameId[];
export let notetypeId: number; export let notetypeId: number;
$: label = notetypeNameIds.find((n) => n.id === notetypeId)?.name;
</script> </script>
<Row --cols={2}> <Row --cols={2}>
@ -18,11 +22,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{tr.notetypesNotetype()} {tr.notetypesNotetype()}
</Col> </Col>
<Col --col-size={1}> <Col --col-size={1}>
<!-- svelte-ignore a11y-no-onchange --> <Select bind:value={notetypeId} {label}>
<select class="form-select" bind:value={notetypeId}>
{#each notetypeNameIds as { id, name }} {#each notetypeNameIds as { id, name }}
<option value={id}>{name}</option> <SelectOption value={id}>{name}</SelectOption>
{/each} {/each}
</select> </Select>
</Col> </Col>
</Row> </Row>

View file

@ -1,59 +0,0 @@
<!--
Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="ts">
import * as tr from "@tslib/ftl";
import { getPlatformString } from "@tslib/shortcuts";
import ButtonGroup from "../components/ButtonGroup.svelte";
import Col from "../components/Col.svelte";
import LabelButton from "../components/LabelButton.svelte";
import Row from "../components/Row.svelte";
import Shortcut from "../components/Shortcut.svelte";
export let path: string;
export let onImport: () => void;
const keyCombination = "Control+Enter";
function basename(path: String): String {
return path.split(/[\\/]/).pop()!;
}
</script>
<div style:flex-grow="1" />
<div class="sticky-footer">
<Row --cols={5}
><Col --col-size={4}>{basename(path)}</Col><Col --col-justify="end">
<ButtonGroup size={2}>
<LabelButton
primary
tooltip={getPlatformString(keyCombination)}
on:click={onImport}
--border-left-radius="5px"
--border-right-radius="5px">{tr.actionsImport()}</LabelButton
>
<Shortcut {keyCombination} on:action={onImport} />
</ButtonGroup></Col
></Row
>
</div>
<style lang="scss">
.sticky-footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 10;
margin: 0;
padding: 0.25rem;
background: var(--canvas);
border-style: solid none none;
border-color: var(--border);
border-width: thin;
}
</style>

View file

@ -0,0 +1,56 @@
<!--
Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="ts">
import * as tr from "@tslib/ftl";
import { getPlatformString } from "@tslib/shortcuts";
import LabelButton from "../components/LabelButton.svelte";
import Shortcut from "../components/Shortcut.svelte";
export let path: string;
export let onImport: () => void;
const keyCombination = "Control+Enter";
function basename(path: String): String {
return path.split(/[\\/]/).pop()!;
}
</script>
<div class="sticky-header d-flex flex-row justify-content-between">
<div class="filename">{basename(path)}</div>
<div class="accept">
<LabelButton
primary
tooltip={getPlatformString(keyCombination)}
on:click={onImport}
--border-left-radius="5px"
--border-right-radius="5px"
>
<div class="import">{tr.actionsImport()}</div>
</LabelButton>
<Shortcut {keyCombination} on:action={onImport} />
</div>
</div>
<style lang="scss">
.sticky-header {
position: sticky;
top: 0;
left: 0;
right: 0;
z-index: 10;
margin: 0;
padding: 0.5rem;
background: var(--canvas);
border-bottom: 1px solid var(--border);
.import {
margin-inline: 0.75rem;
}
}
</style>

View file

@ -14,13 +14,8 @@
} }
body { body {
height: 100vh;
width: min(100vw, 70em); width: min(100vw, 70em);
margin: 0 auto; margin: 0 auto;
padding: 1em; padding: 0 1em 1em 1em;
// pad out the underside of the footer
padding-bottom: 5em;
}
html {
overflow-x: hidden;
} }