Add settings modal

This commit is contained in:
Dallas Hoffman 2023-09-23 01:43:20 -04:00
parent 18831d2e3f
commit 37a64cd488
No known key found for this signature in database
9 changed files with 68 additions and 7 deletions

View File

@ -40,6 +40,7 @@
.app-modal { .app-modal {
article { article {
max-width: var(--max-width, none); max-width: var(--max-width, none);
flex: 1 0 auto;
} }
header { header {

View File

@ -43,7 +43,7 @@
<NoteTags {noteTags} bind:this={tagsComponent} /> <NoteTags {noteTags} bind:this={tagsComponent} />
</div> </div>
</header> </header>
<div class="note-card__body"> <div class="note-card__body" class:note-card__body--editing={$editing}>
<NoteContent {note} {noteEditorStore} /> <NoteContent {note} {noteEditorStore} />
</div> </div>
<footer class="note-card__footer"> <footer class="note-card__footer">
@ -94,6 +94,10 @@
&__body { &__body {
flex-grow: 1; flex-grow: 1;
overflow: auto; overflow: auto;
&--editing {
overflow: hidden;
}
} }
&__footer { &__footer {

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import NoteCard from '$lib/components/notes/note-card.svelte'; import NoteCard from '$lib/components/notes/note-card.svelte';
import { notes } from '$lib/stores'; import { notes, settings } from '$lib/stores';
import { onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
import { get, type Unsubscriber } from 'svelte/store'; import { get, type Unsubscriber } from 'svelte/store';
@ -15,6 +15,8 @@
let notesLimit = 100; let notesLimit = 100;
let prevNotesCount = 0; let prevNotesCount = 0;
const { noteScale } = settings;
let scaleUnsubscribe: Unsubscriber;
let countUnsubscribe: Unsubscriber; let countUnsubscribe: Unsubscriber;
const resizeObserver = new ResizeObserver(updateVirtualScroll); const resizeObserver = new ResizeObserver(updateVirtualScroll);
@ -24,7 +26,7 @@
.getComputedStyle(noteListElement) .getComputedStyle(noteListElement)
.getPropertyValue('grid-template-columns') .getPropertyValue('grid-template-columns')
.split(' ').length; .split(' ').length;
const rowHeight = noteHeight + noteGap; const rowHeight = Math.floor(noteHeight * get(noteScale)) + noteGap;
const fullHeight = Math.ceil(notesCount / columnCount) * rowHeight; const fullHeight = Math.ceil(notesCount / columnCount) * rowHeight;
const windowHeight = window.innerHeight; const windowHeight = window.innerHeight;
const scrollTop = window.scrollY + noteListElement.offsetTop; const scrollTop = window.scrollY + noteListElement.offsetTop;
@ -46,12 +48,14 @@
} }
onMount(() => { onMount(() => {
scaleUnsubscribe = settings.noteScale.subscribe(updateVirtualScroll);
countUnsubscribe = notes.count.subscribe(updateVirtualScroll); countUnsubscribe = notes.count.subscribe(updateVirtualScroll);
resizeObserver.observe(noteListElement); resizeObserver.observe(noteListElement);
window.addEventListener('scroll', updateVirtualScroll); window.addEventListener('scroll', updateVirtualScroll);
}); });
onDestroy(() => { onDestroy(() => {
scaleUnsubscribe();
countUnsubscribe(); countUnsubscribe();
resizeObserver.disconnect(); resizeObserver.disconnect();
window.removeEventListener('scroll', updateVirtualScroll); window.removeEventListener('scroll', updateVirtualScroll);
@ -61,7 +65,7 @@
<ul <ul
bind:this={noteListElement} bind:this={noteListElement}
class="note-list" class="note-list"
style:--note-height={`${noteHeight}px`} style:--note-height={`${Math.floor(noteHeight * $noteScale)}px`}
style:--note-gap={`${noteGap}px`} style:--note-gap={`${noteGap}px`}
style:--scroll-height={`${scrollHeight}px`} style:--scroll-height={`${scrollHeight}px`}
style:--scroll-offset={`translateY(${scrollOffset}px)`} style:--scroll-offset={`translateY(${scrollOffset}px)`}

View File

@ -0,0 +1,9 @@
<script lang="ts">
import Button from '../button.svelte';
import FaGear from '$icon/fa-gear.svelte';
import { settings } from '$lib/stores';
</script>
<Button plain icon size="lg" label="Settings" on:click={() => settings.open.set(true)}>
<FaGear />
</Button>

View File

@ -0,0 +1,21 @@
<script lang="ts">
import Modal from '../modal.svelte';
import { settings } from '$lib/stores';
const { open, noteScale } = settings;
</script>
<Modal title="Settings" size="sm" bind:open={$open}>
<label>
Note Size
<input
type="range"
name="noteScale"
min="0.80"
max="1.50"
step="0.05"
bind:value={$noteScale}
/>
</label>
<!-- TODO: setting for default note color -->
</Modal>

View File

@ -2,9 +2,12 @@ import { derived } from 'svelte/store';
import { NotesStore } from './notes'; import { NotesStore } from './notes';
import { ThemeStore, type Theme } from './theme'; import { ThemeStore, type Theme } from './theme';
import { TagsStore } from './tags'; import { TagsStore } from './tags';
import { SettingsStore } from './settings';
export const tags = new TagsStore(); export const tags = new TagsStore();
export const notes = new NotesStore(tags); export const notes = new NotesStore(tags);
export const settings = new SettingsStore();
export const theme = new ThemeStore(); export const theme = new ThemeStore();
export const themeUpperCase = derived(theme, ($theme) => $theme.toUpperCase() as Uppercase<Theme>); export const themeUpperCase = derived(theme, ($theme) => $theme.toUpperCase() as Uppercase<Theme>);

View File

@ -3,6 +3,7 @@ import type { Schema } from '$lib/db/schema';
import type { Insertable, Selectable, Updateable } from 'kysely'; import type { Insertable, Selectable, Updateable } from 'kysely';
import { writable, type Readable, get, readonly } from 'svelte/store'; import { writable, type Readable, get, readonly } from 'svelte/store';
import type { TagsStore } from './tags'; import type { TagsStore } from './tags';
import { settings } from '.';
export type Note = Selectable<Schema['note']>; export type Note = Selectable<Schema['note']>;
export type NewNote = Insertable<Schema['note']>; export type NewNote = Insertable<Schema['note']>;
@ -68,7 +69,7 @@ export class NotesStore implements Readable<Note[]> {
add = async (newNote?: NewNote, scrollToTop?: boolean) => { add = async (newNote?: NewNote, scrollToTop?: boolean) => {
if (!newNote) { if (!newNote) {
newNote = { newNote = {
color: 'YELLOW', // TODO: add way to set the default color color: get(settings.defaultNoteColor),
content: '', content: '',
}; };
} }

View File

@ -0,0 +1,14 @@
import type { NoteColor } from '$lib/db/enums/note-color';
import { writable } from 'svelte/store';
export class SettingsStore {
open = writable<boolean>(false);
noteScale = writable<number>(localStorage.noteScale ? parseFloat(localStorage.noteScale) : 1);
defaultNoteColor = writable<keyof typeof NoteColor>(localStorage.defaultNoteColor ?? 'YELLOW');
constructor() {
this.noteScale.subscribe((value) => (localStorage.noteScale = value.toString()));
this.defaultNoteColor.subscribe((value) => (localStorage.defaultNoteColor = value));
}
}

View File

@ -3,6 +3,8 @@
import NoteAddButton from '$lib/components/notes/note-add-button.svelte'; import NoteAddButton from '$lib/components/notes/note-add-button.svelte';
import NoteListPlaceholder from '$lib/components/notes/note-list-placeholder.svelte'; import NoteListPlaceholder from '$lib/components/notes/note-list-placeholder.svelte';
import NoteList from '$lib/components/notes/note-list.svelte'; import NoteList from '$lib/components/notes/note-list.svelte';
import SettingsButton from '$lib/components/settings/settings-button.svelte';
import SettingsModal from '$lib/components/settings/settings-modal.svelte';
import ThemeToggle from '$lib/components/theme-toggle.svelte'; import ThemeToggle from '$lib/components/theme-toggle.svelte';
import { notes, tags } from '$lib/stores'; import { notes, tags } from '$lib/stores';
@ -10,8 +12,9 @@
</script> </script>
<header> <header>
<h1>Notes</h1>
<ThemeToggle /> <ThemeToggle />
<h1>Notes</h1>
<SettingsButton />
</header> </header>
<main> <main>
<section hidden={$tags.length === 0}> <section hidden={$tags.length === 0}>
@ -26,13 +29,14 @@
<NoteAddButton /> <NoteAddButton />
</section> </section>
</main> </main>
<SettingsModal />
<style lang="scss"> <style lang="scss">
header { header {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 1.2rem; gap: 2rem;
margin: 1.5rem; margin: 1.5rem;
h1 { h1 {