Add welcome modal with data persistence permission prompt
This commit is contained in:
parent
70f3f31370
commit
ea345e6e61
|
@ -1,11 +1,14 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Button from './button.svelte';
|
import Button from './button.svelte';
|
||||||
import FaXmark from '$icon/fa-xmark.svelte';
|
import FaXmark from '$icon/fa-xmark.svelte';
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
|
||||||
export let open: boolean;
|
export let open: boolean;
|
||||||
export let title: string;
|
export let title: string;
|
||||||
export let size: 'sm' | 'md' | 'lg' = 'md';
|
export let size: 'sm' | 'md' | 'lg' = 'md';
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
const maxWidths = {
|
const maxWidths = {
|
||||||
sm: '400px',
|
sm: '400px',
|
||||||
md: '700px',
|
md: '700px',
|
||||||
|
@ -20,6 +23,7 @@
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
open = false;
|
open = false;
|
||||||
|
dispatch('close');
|
||||||
}
|
}
|
||||||
|
|
||||||
function escape(event: KeyboardEvent) {
|
function escape(event: KeyboardEvent) {
|
||||||
|
@ -47,7 +51,7 @@
|
||||||
.app-modal {
|
.app-modal {
|
||||||
article {
|
article {
|
||||||
max-width: var(--max-width, none);
|
max-width: var(--max-width, none);
|
||||||
flex: 1 0 auto;
|
flex: 1 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import Modal from './modal.svelte';
|
||||||
|
import Button from './button.svelte';
|
||||||
|
import { persistence } from '$lib/stores';
|
||||||
|
|
||||||
|
let open = false;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if (!persistence.prompted) {
|
||||||
|
open = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
persistence.prompt();
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Modal title="Welcome!" size="sm" bind:open on:close={close}>
|
||||||
|
<p>
|
||||||
|
Capture your thoughts for later by writing a quick note. Add tags to categorize it and organize
|
||||||
|
your notes.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This app keeps all of its data on your device. Your notes are private, never sent to an external
|
||||||
|
server.
|
||||||
|
</p>
|
||||||
|
<footer>
|
||||||
|
<Button on:click={close}>Get Started</Button>
|
||||||
|
</footer>
|
||||||
|
</Modal>
|
|
@ -3,10 +3,12 @@ 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';
|
import { SettingsStore } from './settings';
|
||||||
|
import { PersistenceStore } from './persistence';
|
||||||
|
|
||||||
export const tags = new TagsStore();
|
export const tags = new TagsStore();
|
||||||
export const notes = new NotesStore(tags);
|
export const notes = new NotesStore(tags);
|
||||||
|
|
||||||
|
export const persistence = new PersistenceStore();
|
||||||
export const settings = new SettingsStore();
|
export const settings = new SettingsStore();
|
||||||
|
|
||||||
export const theme = new ThemeStore();
|
export const theme = new ThemeStore();
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { writable, type Readable } from 'svelte/store';
|
||||||
|
|
||||||
|
export class PersistenceStore implements Readable<boolean | null> {
|
||||||
|
private persistence = writable<boolean | null>(null);
|
||||||
|
|
||||||
|
get prompted() {
|
||||||
|
return !!localStorage.promptedForPersistence;
|
||||||
|
}
|
||||||
|
private set prompted(value: boolean) {
|
||||||
|
localStorage.promptedForPersistence = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.check();
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribe = this.persistence.subscribe;
|
||||||
|
|
||||||
|
async check() {
|
||||||
|
if (navigator.storage && navigator.storage.persisted) {
|
||||||
|
let persisted: boolean | null = await navigator.storage.persisted();
|
||||||
|
|
||||||
|
if (persisted !== true) {
|
||||||
|
persisted = this.prompted ? false : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.persistence.set(persisted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async prompt() {
|
||||||
|
this.prompted = true;
|
||||||
|
|
||||||
|
if (navigator.storage && navigator.storage.persist) {
|
||||||
|
const persisted = await navigator.storage.persist();
|
||||||
|
this.persistence.set(persisted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
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 SettingsModal from '$lib/components/settings/settings-modal.svelte';
|
import SettingsModal from '$lib/components/settings/settings-modal.svelte';
|
||||||
|
import WelcomeModal from '$lib/components/welcome-modal.svelte';
|
||||||
import { notes, tags } from '$lib/stores';
|
import { notes, tags } from '$lib/stores';
|
||||||
|
|
||||||
const notesCount = notes.count;
|
const notesCount = notes.count;
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
<NoteAddButton />
|
<NoteAddButton />
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
<WelcomeModal />
|
||||||
<SettingsModal />
|
<SettingsModal />
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
Loading…
Reference in New Issue