improve actions, add dark mode
This commit is contained in:
parent
3d6f0d2f01
commit
f4e80302dc
|
@ -1,6 +1,8 @@
|
|||
<script>
|
||||
import MainInput from './lib/MainInput.svelte'
|
||||
import Note from './lib/Note.svelte'
|
||||
import Actions from './lib/Actions.svelte'
|
||||
|
||||
import Storage from './storage'
|
||||
import {createNote, toggleDoneState} from './note'
|
||||
|
||||
|
@ -8,7 +10,15 @@
|
|||
let notes = storage.getNotes()
|
||||
let shownNotes = notes
|
||||
let hasNotes = notes.length > 0
|
||||
let clearConfirm = false
|
||||
let filter = null
|
||||
let theme = storage.getTheme()
|
||||
|
||||
$: hasFinishedNotes = notes.filter(note => !note.done).length === notes.length
|
||||
$: darkMode = theme === "dark"
|
||||
$: document.body.className = theme;
|
||||
|
||||
// $: filterText = filter ? `Clear '${filter}' filter` : "Clear filter"
|
||||
// $: hasFinishedNotes = notes.filter(note => !note.done).length === notes.length
|
||||
|
||||
function handleNewNote(e) {
|
||||
notes.push(createNote(e.detail))
|
||||
|
@ -26,27 +36,34 @@
|
|||
}
|
||||
|
||||
function handleFilter(e) {
|
||||
filter = e.detail
|
||||
shownNotes = shownNotes.filter(note => {
|
||||
return note.tags.includes(e.detail)
|
||||
return note.tags.includes(filter)
|
||||
})
|
||||
}
|
||||
|
||||
function handleClearDone(e) {
|
||||
if (clearConfirm === false) {
|
||||
clearConfirm = true
|
||||
} else {
|
||||
clearConfirm = false
|
||||
notes = notes.filter(note => !note.done)
|
||||
shownNotes = notes
|
||||
storage.saveNotes(notes)
|
||||
}
|
||||
notes = notes.filter(note => !note.done)
|
||||
shownNotes = notes
|
||||
storage.saveNotes(notes)
|
||||
}
|
||||
|
||||
function handleClearFilter(e) {
|
||||
filter = null
|
||||
shownNotes = notes
|
||||
}
|
||||
|
||||
function handleToggleDarkMode(e) {
|
||||
console.log("Dark Mode: " + !darkMode)
|
||||
theme = theme === "dark" ? "" : "dark"
|
||||
storage.saveTheme(theme)
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Notes</title>
|
||||
</svelte:head>
|
||||
|
||||
<main>
|
||||
<MainInput on:added={handleNewNote} />
|
||||
|
||||
|
@ -56,11 +73,13 @@
|
|||
{/each}
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<button on:click={handleClearFilter}>Clear filter</button>
|
||||
<div class="flex-1" />
|
||||
<button on:click={handleClearDone} class:confirm={clearConfirm}>Clear finished notes</button>
|
||||
</footer>
|
||||
<Actions
|
||||
filter={filter}
|
||||
hasFinishedNotes={hasFinishedNotes}
|
||||
darkMode={darkMode}
|
||||
on:clearDone={handleClearDone}
|
||||
on:clearFilter={handleClearFilter}
|
||||
on:toggleDarkMode={handleToggleDarkMode} />
|
||||
|
||||
</main>
|
||||
|
||||
|
@ -81,10 +100,24 @@
|
|||
--gray-900: #0F172A;
|
||||
}
|
||||
|
||||
:global(.dark) {
|
||||
--gray-50: #0F172A;
|
||||
--gray-100: #1E293B;
|
||||
--gray-200: #334155;
|
||||
--gray-300: #475569;
|
||||
--gray-400: #64748B;
|
||||
--gray-500: #94A3B8;
|
||||
--gray-600: #CBD5E1;
|
||||
--gray-700: #E2E8F0;
|
||||
--gray-800: #F1F5F9;
|
||||
--gray-900: #F8FAFC;
|
||||
}
|
||||
|
||||
:global(body) {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background: var(--gray-100);
|
||||
transition: 0.1s ease-in all;
|
||||
}
|
||||
|
||||
main {
|
||||
|
@ -93,33 +126,7 @@
|
|||
margin: 0 auto;
|
||||
}
|
||||
|
||||
footer {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.notes {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.flex-1 {
|
||||
display: flex;
|
||||
flex: 1 1 0;
|
||||
}
|
||||
|
||||
button {
|
||||
background: var(--gray-200);
|
||||
padding: 0.5rem;
|
||||
border: 1px solid var(--gray-300);
|
||||
transition: 0.1s ease-in all;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: var(--gray-300);
|
||||
color: var(--gray-700);
|
||||
border: 1px solid var(--gray-400);
|
||||
}
|
||||
|
||||
button.confirm {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
<script>
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
export let filter = null
|
||||
export let hasFinishedNotes = false
|
||||
export let darkMode = false
|
||||
|
||||
let clearConfirmed = false
|
||||
$: filterText = filter ? `Clear '${filter}' filter` : "Clear filter"
|
||||
|
||||
function confirmClear(e) {
|
||||
if (!clearConfirmed) {
|
||||
clearConfirmed = true
|
||||
} else {
|
||||
clearConfirmed = false
|
||||
dispatch('clearDone', null)
|
||||
}
|
||||
}
|
||||
|
||||
function clearFilter(e) {
|
||||
dispatch('clearFilter', null)
|
||||
}
|
||||
|
||||
function toggleDarkMode() {
|
||||
dispatch('toggleDarkMode', null)
|
||||
}
|
||||
</script>
|
||||
|
||||
<aside class="flex gap">
|
||||
<button
|
||||
on:click={clearFilter}
|
||||
disabled={filter === null}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-funnel" viewBox="0 0 16 16">
|
||||
<path d="M1.5 1.5A.5.5 0 0 1 2 1h12a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.128.334L10 8.692V13.5a.5.5 0 0 1-.342.474l-3 1A.5.5 0 0 1 6 14.5V8.692L1.628 3.834A.5.5 0 0 1 1.5 3.5v-2zm1 .5v1.308l4.372 4.858A.5.5 0 0 1 7 8.5v5.306l2-.666V8.5a.5.5 0 0 1 .128-.334L13.5 3.308V2h-11z"/>
|
||||
</svg>
|
||||
{filterText}
|
||||
</button>
|
||||
<div class="flex-1" />
|
||||
<button
|
||||
on:click={confirmClear}
|
||||
class:confirm={clearConfirmed}
|
||||
disabled={hasFinishedNotes}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-archive" viewBox="0 0 16 16">
|
||||
<path d="M0 2a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1v7.5a2.5 2.5 0 0 1-2.5 2.5h-9A2.5 2.5 0 0 1 1 12.5V5a1 1 0 0 1-1-1V2zm2 3v7.5A1.5 1.5 0 0 0 3.5 14h9a1.5 1.5 0 0 0 1.5-1.5V5H2zm13-3H1v2h14V2zM5 7.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5z"/>
|
||||
</svg>
|
||||
Clear finished notes
|
||||
</button>
|
||||
<button on:click={toggleDarkMode}>
|
||||
{#if darkMode}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-moon" viewBox="0 0 16 16">
|
||||
<path d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278zM4.858 1.311A7.269 7.269 0 0 0 1.025 7.71c0 4.02 3.279 7.276 7.319 7.276a7.316 7.316 0 0 0 5.205-2.162c-.337.042-.68.063-1.029.063-4.61 0-8.343-3.714-8.343-8.29 0-1.167.242-2.278.681-3.286z"/>
|
||||
</svg>
|
||||
{:else}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-brightness-high" viewBox="0 0 16 16">
|
||||
<path d="M8 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0 1a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z"/>
|
||||
</svg>
|
||||
{/if}
|
||||
</button>
|
||||
</aside>
|
||||
|
||||
<style>
|
||||
aside {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
button {
|
||||
color: var(--gray-800);
|
||||
background: var(--gray-200);
|
||||
padding: 0.5rem;
|
||||
border: 1px solid var(--gray-300);
|
||||
border-radius: 0.15rem;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
color: var(--gray-400);
|
||||
}
|
||||
|
||||
button:hover:not(:disabled) {
|
||||
background: var(--gray-300);
|
||||
color: var(--gray-700);
|
||||
border: 1px solid var(--gray-400);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button.confirm, button.confirm:hover {
|
||||
color: red;
|
||||
}
|
||||
|
||||
button svg {
|
||||
display: inline-block;
|
||||
vertical-align: -0.25em;
|
||||
fill: currentcolor;
|
||||
margin-right: 0.125em;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.flex-1 {
|
||||
display: flex;
|
||||
flex: 1 1 0;
|
||||
}
|
||||
|
||||
.gap {
|
||||
gap: 0.5rem;
|
||||
}
|
||||
</style>
|
|
@ -11,7 +11,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<input type="text" on:keyup={handleKeyup} placeholder="Add a new note, tag with #foo and #bar">
|
||||
<input type="text" on:keyup={handleKeyup} placeholder="Add a new note, tag with #foo and #bar and press ENTER">
|
||||
|
||||
<style>
|
||||
input {
|
||||
|
@ -20,5 +20,8 @@
|
|||
box-sizing: border-box;
|
||||
border: 1px solid var(--gray-400);
|
||||
border-radius: 0.15rem;
|
||||
font-size: 1rem;
|
||||
color: var(--gray-800);
|
||||
background: var(--gray-50);
|
||||
}
|
||||
</style>
|
|
@ -34,9 +34,10 @@
|
|||
display: flex;
|
||||
gap: 0.5rem;
|
||||
|
||||
color: var(--gray-800);
|
||||
padding: 0.5rem;
|
||||
background: white;
|
||||
border: 1px solid var(--gray-400);
|
||||
background: var(--gray-100);
|
||||
border: 1px solid var(--gray-300);
|
||||
border-radius: 0.15rem;
|
||||
|
||||
margin-bottom: 0.25rem;
|
||||
|
@ -59,5 +60,7 @@
|
|||
|
||||
.title {
|
||||
flex: 1;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
}
|
||||
</style>
|
|
@ -3,6 +3,14 @@ export default class Storage {
|
|||
this.prefix = "notesapp"
|
||||
}
|
||||
|
||||
getTheme() {
|
||||
return localStorage.getItem(`${this.prefix}-theme`) || ""
|
||||
}
|
||||
|
||||
saveTheme(theme) {
|
||||
localStorage.setItem(`${this.prefix}-theme`, theme)
|
||||
}
|
||||
|
||||
getNotes() {
|
||||
const notesString = localStorage.getItem(`${this.prefix}-notes`)
|
||||
if (notesString) {
|
||||
|
|
Loading…
Reference in New Issue