Add settings modal
This commit is contained in:
		
							parent
							
								
									18831d2e3f
								
							
						
					
					
						commit
						37a64cd488
					
				|  | @ -40,6 +40,7 @@ | |||
| 	.app-modal { | ||||
| 		article { | ||||
| 			max-width: var(--max-width, none); | ||||
| 			flex: 1 0 auto; | ||||
| 		} | ||||
| 
 | ||||
| 		header { | ||||
|  |  | |||
|  | @ -43,7 +43,7 @@ | |||
| 			<NoteTags {noteTags} bind:this={tagsComponent} /> | ||||
| 		</div> | ||||
| 	</header> | ||||
| 	<div class="note-card__body"> | ||||
| 	<div class="note-card__body" class:note-card__body--editing={$editing}> | ||||
| 		<NoteContent {note} {noteEditorStore} /> | ||||
| 	</div> | ||||
| 	<footer class="note-card__footer"> | ||||
|  | @ -94,6 +94,10 @@ | |||
| 		&__body { | ||||
| 			flex-grow: 1; | ||||
| 			overflow: auto; | ||||
| 
 | ||||
| 			&--editing { | ||||
| 				overflow: hidden; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		&__footer { | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| <script lang="ts"> | ||||
| 	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 { get, type Unsubscriber } from 'svelte/store'; | ||||
| 
 | ||||
|  | @ -15,6 +15,8 @@ | |||
| 	let notesLimit = 100; | ||||
| 	let prevNotesCount = 0; | ||||
| 
 | ||||
| 	const { noteScale } = settings; | ||||
| 	let scaleUnsubscribe: Unsubscriber; | ||||
| 	let countUnsubscribe: Unsubscriber; | ||||
| 	const resizeObserver = new ResizeObserver(updateVirtualScroll); | ||||
| 
 | ||||
|  | @ -24,7 +26,7 @@ | |||
| 			.getComputedStyle(noteListElement) | ||||
| 			.getPropertyValue('grid-template-columns') | ||||
| 			.split(' ').length; | ||||
| 		const rowHeight = noteHeight + noteGap; | ||||
| 		const rowHeight = Math.floor(noteHeight * get(noteScale)) + noteGap; | ||||
| 		const fullHeight = Math.ceil(notesCount / columnCount) * rowHeight; | ||||
| 		const windowHeight = window.innerHeight; | ||||
| 		const scrollTop = window.scrollY + noteListElement.offsetTop; | ||||
|  | @ -46,12 +48,14 @@ | |||
| 	} | ||||
| 
 | ||||
| 	onMount(() => { | ||||
| 		scaleUnsubscribe = settings.noteScale.subscribe(updateVirtualScroll); | ||||
| 		countUnsubscribe = notes.count.subscribe(updateVirtualScroll); | ||||
| 		resizeObserver.observe(noteListElement); | ||||
| 		window.addEventListener('scroll', updateVirtualScroll); | ||||
| 	}); | ||||
| 
 | ||||
| 	onDestroy(() => { | ||||
| 		scaleUnsubscribe(); | ||||
| 		countUnsubscribe(); | ||||
| 		resizeObserver.disconnect(); | ||||
| 		window.removeEventListener('scroll', updateVirtualScroll); | ||||
|  | @ -61,7 +65,7 @@ | |||
| <ul | ||||
| 	bind:this={noteListElement} | ||||
| 	class="note-list" | ||||
| 	style:--note-height={`${noteHeight}px`} | ||||
| 	style:--note-height={`${Math.floor(noteHeight * $noteScale)}px`} | ||||
| 	style:--note-gap={`${noteGap}px`} | ||||
| 	style:--scroll-height={`${scrollHeight}px`} | ||||
| 	style:--scroll-offset={`translateY(${scrollOffset}px)`} | ||||
|  |  | |||
|  | @ -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> | ||||
|  | @ -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> | ||||
|  | @ -2,9 +2,12 @@ import { derived } from 'svelte/store'; | |||
| import { NotesStore } from './notes'; | ||||
| import { ThemeStore, type Theme } from './theme'; | ||||
| import { TagsStore } from './tags'; | ||||
| import { SettingsStore } from './settings'; | ||||
| 
 | ||||
| export const tags = new TagsStore(); | ||||
| export const notes = new NotesStore(tags); | ||||
| 
 | ||||
| export const settings = new SettingsStore(); | ||||
| 
 | ||||
| export const theme = new ThemeStore(); | ||||
| export const themeUpperCase = derived(theme, ($theme) => $theme.toUpperCase() as Uppercase<Theme>); | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ import type { Schema } from '$lib/db/schema'; | |||
| import type { Insertable, Selectable, Updateable } from 'kysely'; | ||||
| import { writable, type Readable, get, readonly } from 'svelte/store'; | ||||
| import type { TagsStore } from './tags'; | ||||
| import { settings } from '.'; | ||||
| 
 | ||||
| export type Note = Selectable<Schema['note']>; | ||||
| export type NewNote = Insertable<Schema['note']>; | ||||
|  | @ -68,7 +69,7 @@ export class NotesStore implements Readable<Note[]> { | |||
| 	add = async (newNote?: NewNote, scrollToTop?: boolean) => { | ||||
| 		if (!newNote) { | ||||
| 			newNote = { | ||||
| 				color: 'YELLOW', // TODO: add way to set the default color
 | ||||
| 				color: get(settings.defaultNoteColor), | ||||
| 				content: '', | ||||
| 			}; | ||||
| 		} | ||||
|  |  | |||
|  | @ -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)); | ||||
| 	} | ||||
| } | ||||
|  | @ -3,6 +3,8 @@ | |||
| 	import NoteAddButton from '$lib/components/notes/note-add-button.svelte'; | ||||
| 	import NoteListPlaceholder from '$lib/components/notes/note-list-placeholder.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 { notes, tags } from '$lib/stores'; | ||||
| 
 | ||||
|  | @ -10,8 +12,9 @@ | |||
| </script> | ||||
| 
 | ||||
| <header> | ||||
| 	<h1>Notes</h1> | ||||
| 	<ThemeToggle /> | ||||
| 	<h1>Notes</h1> | ||||
| 	<SettingsButton /> | ||||
| </header> | ||||
| <main> | ||||
| 	<section hidden={$tags.length === 0}> | ||||
|  | @ -26,13 +29,14 @@ | |||
| 		<NoteAddButton /> | ||||
| 	</section> | ||||
| </main> | ||||
| <SettingsModal /> | ||||
| 
 | ||||
| <style lang="scss"> | ||||
| 	header { | ||||
| 		display: flex; | ||||
| 		align-items: center; | ||||
| 		justify-content: center; | ||||
| 		gap: 1.2rem; | ||||
| 		gap: 2rem; | ||||
| 		margin: 1.5rem; | ||||
| 
 | ||||
| 		h1 { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue