This commit is contained in:
2021-11-22 20:07:06 +01:00
parent ee29c0b25b
commit 1acc0d4244
17 changed files with 275 additions and 163 deletions

View File

@@ -0,0 +1,14 @@
<script>
export let value
</script>
{#if Array.isArray(value)}
<input type="number" class="form-input" placeholder="1" bind:value={value[0]} />
<select class="form-select" bind:value={value[1]}>
<option value="m">Minutes</option>
<option value="h">Hours</option>
<option value="d">Days</option>
<option value="w">Weeks</option>
<option value="M">Months</option>
</select>
{/if}

View File

@@ -1,9 +1,10 @@
<footer>
<a href="https://github.com/cupcakearmy/ora" target="_blank" rel="noreferrer">Source Code</a>
- v0.8
<br />
Made with ❤️ by
<a href="https://nicco.io" target="_blank" rel="noreferrer">🐘</a>
<small>
Made with ❤️ by
<a href="https://nicco.io" target="_blank" rel="noreferrer">🐘</a>
— v0.8 —
<a href="https://github.com/cupcakearmy/ora" target="_blank" rel="noreferrer">Source Code</a>
</small>
</footer>
<style>

View File

@@ -19,17 +19,23 @@
end = new Date()
}
const intervals = [
{ label: 'Year', set: set('year', 1) },
{ label: 'Month', set: set('month', 1) },
{ label: 'Week', set: set('week', 1) },
{ label: '3 Days', set: set('day', 3) },
{ label: 'Today', set: set('day', 0) },
]
// Init
onMount(() => set('day', 0)())
</script>
<div class="flex items-center">
<div class="btn-group">
<button class="btn btn-sm" on:click={all}>All</button>
<button class="btn btn-sm" on:click={set('month', 1)}>Month</button>
<button class="btn btn-sm" on:click={set('week', 1)}>Week</button>
<button class="btn btn-sm" on:click={set('day', 3)}>3 Days</button>
<button class="btn btn-sm" on:click={set('day', 0)}>Today</button>
{#each intervals as interval (interval.label)}
<button class="btn btn-sm" on:click={interval.set}>{interval.label}</button>
{/each}
</div>
<div class="spacer" />
<div class="input-group">

View File

@@ -3,11 +3,14 @@
import { cloneDeep } from 'lodash'
import { DB } from '../../shared/db'
import { checkForErrors, LimitValidator } from '../../shared/validation'
import DurationInput from './DurationInput.svelte'
const dispatch = createEventDispatcher()
const init = { limit: ['1', 'h'], every: [1, 'd'] }
export let limit = null
export let error = null
$: active = limit !== null
function add() {
@@ -23,6 +26,11 @@
}
async function save() {
const errors = checkForErrors(LimitValidator, limit)
if (errors) {
error = errors
return
}
await DB.limits.put(limit)
dispatch('update')
close()
@@ -45,25 +53,11 @@
</label>
<div class="form-label">Rules</div>
{#each limit.rules as { limit, every }, i}
{#each limit.rules as rule, i}
<div class="input-group mb-3">
<input type="text" class="form-input" placeholder="1" bind:value={limit[0]} />
<select class="form-select" bind:value={limit[1]}>
<option value="m">Minutes</option>
<option value="h">Hours</option>
<option value="d">Days</option>
<option value="w">Weeks</option>
<option value="M">Months</option>
</select>
<DurationInput bind:value={rule.limit} />
<span class="input-group-addon">every</span>
<input type="text" class="form-input" bind:value={every[0]} />
<select class="form-select" bind:value={every[1]}>
<option value="m">Minutes</option>
<option value="h">Hours</option>
<option value="d">Days</option>
<option value="w">Weeks</option>
<option value="M">Months</option>
</select>
<DurationInput bind:value={rule.every} />
<button class="btn btn-error input-group-btn" on:click={del(i)}>X</button>
</div>
{/each}
@@ -73,6 +67,9 @@
</div>
<div class="modal-footer">
<div>
{#if error}
<span class="text-error">{error}</span>
{/if}
<button on:click={close} class="btn">Cancel</button>
<button on:click={save} class="btn btn-primary">Save</button>
</div>

View File

@@ -0,0 +1,17 @@
<script>
import pretty from 'pretty-bytes'
import { onMount } from 'svelte'
let usage = null
onMount(async () => {
const estimate = await window.navigator.storage.estimate()
usage = pretty(estimate.usage)
})
</script>
{#if usage === null}
<span class="loading" />
{:else}
<span>Storage used: <span class="font-mono">{usage}</span></span>
{/if}

View File

@@ -1,5 +1,6 @@
<script>
import { onMount } from 'svelte'
import { cloneDeep } from 'lodash'
import RulesEditor from '../components/RulesEditor.svelte'
import Rules from '../components/Rules.svelte'
@@ -15,7 +16,7 @@
}
function edit(id) {
limit = limits.find((limit) => limit.id === id)
limit = cloneDeep(limits.find((limit) => limit.id === id))
}
async function load() {

View File

@@ -1,93 +1,7 @@
<script>
import { onMount } from 'svelte'
import browser from 'webextension-polyfill'
import { saveAs } from 'file-saver'
import dj from 'dayjs'
import FileUpload from '../components/FileUpload.svelte'
import { dump as dumpDB, load as loadDB, clear as clearDB, validate } from '../../shared/db'
import { longPress } from '../../shared/lib'
const DEFAULT = {
retention: 90,
}
let settings = DEFAULT
let uploaded
let disabled = true
async function read() {
settings = {
...DEFAULT,
...(await browser.storage.local.get()),
}
}
function write() {
return browser.storage.local.set(settings)
}
async function reset() {
await browser.storage.local.clear()
await read()
}
async function dump() {
const data = await dumpDB()
const blob = new Blob([JSON.stringify(data)], { type: 'application/json;charset=utf-8' })
const filename = `Ora [${dj().format('YYYY-MM-DD HH-mm-ss')}].json`
saveAs(blob, filename)
}
async function clear() {
await clearDB()
alert('Done')
}
async function load() {
try {
await loadDB(uploaded)
alert('Imported')
} catch {
alert('Error importing')
}
}
$: {
disabled = !validate(uploaded)
}
onMount(read)
import YourData from '../views/YourData.svelte'
import Settings from '../views/Settings.svelte'
</script>
<h2 class="mt-8 text-2xl">Settings</h2>
<form class="mt-2" on:submit|preventDefault={write}>
<div class="form-group">
<label class="form-label">
Retention
<small>(Days)</small>
<input
id="retention"
class="form-input"
type="number"
min="3"
max="365"
step="1"
bind:value={settings.retention}
/>
</label>
<div class="mt-2">
<button type="reset" class="btn" on:click={reset}>Reset</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
</div>
</form>
<h2 class="mt-8 text-2xl">Your Data</h2>
<div class="mt-2">
<FileUpload bind:value={uploaded} />
<button class="btn btn-primary" on:click={load} {disabled}>Import</button>
<button class="btn btn-primary" on:click={dump}>Export</button>
<button class="btn btn-error tooltip" data-tooltip="Hold to delete" use:longPress={clear}>Delete all data</button>
</div>
<Settings />
<YourData />

View File

@@ -0,0 +1,47 @@
<script>
import { onMount } from 'svelte'
import { DB } from '../../shared/db'
import { SettingsValidator } from '../../shared/validation'
let settings = null
async function load() {
const values = await DB.settings.toArray()
const fromDB = Object.fromEntries(values.map((v) => [v.key, v.value]))
settings = SettingsValidator.validate(fromDB).value
}
async function save() {
for (const [key, value] of Object.entries(settings)) {
await DB.settings.put({ key, value })
}
}
onMount(load)
</script>
<h2 class="mt-8 text-2xl">Settings</h2>
{#if settings}
<form class="mt-2" on:submit|preventDefault={save}>
<div class="form-group">
<label class="form-label">
Retention
<small>(Days)</small>
<input class="form-input" type="number" min="3" max="365" step="1" bind:value={settings.retention} />
</label>
<label class="form-label">
Idle Timeout
<small>(Minutes)</small>
<input class="form-input" type="number" min="0" step="1" bind:value={settings.idleTimeout} />
<p>Stop tracking after a certain period of idle behavior. <span class="font-mono">0</span> to disable.</p>
</label>
<div class="mt-2">
<button type="submit" class="btn btn-primary">Save</button>
</div>
</div>
</form>
{:else}
<div class="loading loading-lg" />
{/if}

View File

@@ -0,0 +1,49 @@
<script>
import { saveAs } from 'file-saver'
import dj from 'dayjs'
import FileUpload from '../components/FileUpload.svelte'
import { dump, load, clear } from '../../shared/db'
import { checkForErrors, DBValidator } from '../../shared/validation'
import { longPress } from '../../shared/lib'
let uploaded
async function exportDB() {
const data = await dump()
const blob = new Blob([JSON.stringify(data)], { type: 'application/json;charset=utf-8' })
const filename = `Ora [${dj().format('YYYY-MM-DD HH-mm-ss')}].json`
saveAs(blob, filename)
}
async function clearDB() {
await clear()
window.location.reload()
}
async function importDB() {
try {
await load(uploaded)
alert('Imported')
} catch {
alert('Error importing')
}
}
$: disabled = uploaded && !checkForErrors(DBValidator, uploaded)
</script>
<h2 class="mt-8 text-2xl">Your Data</h2>
<div class="mt-2">
<FileUpload bind:value={uploaded} />
<button class="btn btn-primary" on:click={importDB} {disabled}>
{#if uploaded && disabled}
Invalid data
{:else}
Import
{/if}
</button>
<button class="btn btn-primary" on:click={exportDB}>Export</button>
<button class="btn btn-error tooltip" data-tooltip="Hold to delete" use:longPress={clearDB}>Delete all data</button>
</div>