style.css gains the classes the views spelled out in full: .section-label (17 sites), .hint (20), .form-error (13), .alert-error (5), .row-card (5), .list-empty (5), .field (5), .page-shell (3), and the small row action .btn-sm (4) / .btn-sm-danger (3). Only exact runs moved, so nothing renders differently; spacing a site adds beyond a run stays a utility beside it. Kept: the Reminders and Timeline small buttons. They carry no text colour and inherit it, so putting them on .btn-sm would recolour them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -62,7 +62,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section class="flex flex-col gap-5">
|
<section class="flex flex-col gap-5">
|
||||||
<h2 class="text-xs font-semibold uppercase tracking-wide text-neutral-400">People</h2>
|
<h2 class="section-label">People</h2>
|
||||||
|
|
||||||
<OneTimeLink
|
<OneTimeLink
|
||||||
v-if="fresh"
|
v-if="fresh"
|
||||||
@@ -71,14 +71,14 @@ onMounted(() => {
|
|||||||
@done="fresh = null"
|
@done="fresh = null"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<p v-if="error" class="text-sm text-red-600 dark:text-red-400">{{ error }}</p>
|
<p v-if="error" class="form-error">{{ error }}</p>
|
||||||
|
|
||||||
<div v-if="loading" class="py-6 text-center text-sm text-neutral-400">Loading…</div>
|
<div v-if="loading" class="list-empty">Loading…</div>
|
||||||
<ul v-else class="flex flex-col gap-2">
|
<ul v-else class="flex flex-col gap-2">
|
||||||
<li
|
<li
|
||||||
v-for="a in accounts"
|
v-for="a in accounts"
|
||||||
:key="a.id"
|
:key="a.id"
|
||||||
class="flex items-center justify-between gap-4 rounded-xl border border-neutral-200 px-4 py-3 dark:border-neutral-800"
|
class="row-card"
|
||||||
>
|
>
|
||||||
<div class="min-w-0">
|
<div class="min-w-0">
|
||||||
<p class="truncate text-sm font-medium text-neutral-800 dark:text-neutral-100">{{ a.display_name }}</p>
|
<p class="truncate text-sm font-medium text-neutral-800 dark:text-neutral-100">{{ a.display_name }}</p>
|
||||||
@@ -86,7 +86,7 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="shrink-0 rounded-md border border-neutral-300 px-2.5 py-1 text-xs text-neutral-700 hover:bg-neutral-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-brand disabled:opacity-50 dark:border-neutral-700 dark:text-neutral-200 dark:hover:bg-neutral-800"
|
class="shrink-0 btn-sm"
|
||||||
:disabled="busy === a.id"
|
:disabled="busy === a.id"
|
||||||
@click="resetLink(a)"
|
@click="resetLink(a)"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -93,11 +93,11 @@ onMounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section class="flex flex-col gap-5">
|
<section class="flex flex-col gap-5">
|
||||||
<h2 class="text-xs font-semibold uppercase tracking-wide text-neutral-400">Activity</h2>
|
<h2 class="section-label">Activity</h2>
|
||||||
|
|
||||||
<p v-if="error" class="text-sm text-red-600 dark:text-red-400">{{ error }}</p>
|
<p v-if="error" class="form-error">{{ error }}</p>
|
||||||
|
|
||||||
<div v-if="loading" class="py-6 text-center text-sm text-neutral-400">Loading…</div>
|
<div v-if="loading" class="list-empty">Loading…</div>
|
||||||
<p v-else-if="!events.length" class="text-sm text-neutral-400">Nothing yet.</p>
|
<p v-else-if="!events.length" class="text-sm text-neutral-400">Nothing yet.</p>
|
||||||
<ul v-else class="flex flex-col gap-2">
|
<ul v-else class="flex flex-col gap-2">
|
||||||
<li
|
<li
|
||||||
@@ -118,7 +118,7 @@ onMounted(() => {
|
|||||||
<button
|
<button
|
||||||
v-if="more"
|
v-if="more"
|
||||||
type="button"
|
type="button"
|
||||||
class="self-start rounded-md border border-neutral-300 px-2.5 py-1 text-xs text-neutral-700 hover:bg-neutral-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-brand disabled:opacity-50 dark:border-neutral-700 dark:text-neutral-200 dark:hover:bg-neutral-800"
|
class="self-start btn-sm"
|
||||||
:disabled="loadingMore"
|
:disabled="loadingMore"
|
||||||
@click="loadMore"
|
@click="loadMore"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -396,7 +396,7 @@ async function signOut() {
|
|||||||
</RouterLink>
|
</RouterLink>
|
||||||
|
|
||||||
<div class="mt-3 flex items-center justify-between px-3 pb-1">
|
<div class="mt-3 flex items-center justify-between px-3 pb-1">
|
||||||
<span class="text-xs font-semibold uppercase tracking-wide text-neutral-400">Tags</span>
|
<span class="section-label">Tags</span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="text-neutral-400 hover:text-neutral-600 dark:hover:text-neutral-200"
|
class="text-neutral-400 hover:text-neutral-600 dark:hover:text-neutral-200"
|
||||||
|
|||||||
@@ -132,6 +132,6 @@ onMounted(async () => {
|
|||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p v-else class="px-4 py-6 text-center text-sm text-neutral-400">No matches</p>
|
<p v-else class="px-4 list-empty">No matches</p>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ async function toggle() {
|
|||||||
<section v-if="status?.is_appimage" class="mt-10 border-t border-neutral-200 pt-8 dark:border-neutral-800">
|
<section v-if="status?.is_appimage" class="mt-10 border-t border-neutral-200 pt-8 dark:border-neutral-800">
|
||||||
<h2 class="text-sm font-semibold">Applications menu</h2>
|
<h2 class="text-sm font-semibold">Applications menu</h2>
|
||||||
<div class="mt-3 flex items-center justify-between gap-4">
|
<div class="mt-3 flex items-center justify-between gap-4">
|
||||||
<p class="text-sm text-neutral-500 dark:text-neutral-400">
|
<p class="hint">
|
||||||
{{ status.is_integrated ? "Inkwell is in your applications menu." : "Not in your applications menu." }}
|
{{ status.is_integrated ? "Inkwell is in your applications menu." : "Not in your applications menu." }}
|
||||||
</p>
|
</p>
|
||||||
<BaseButton
|
<BaseButton
|
||||||
|
|||||||
@@ -140,16 +140,16 @@ onMounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section class="flex flex-col gap-5">
|
<section class="flex flex-col gap-5">
|
||||||
<h2 class="text-xs font-semibold uppercase tracking-wide text-neutral-400">Groups</h2>
|
<h2 class="section-label">Groups</h2>
|
||||||
|
|
||||||
<form class="flex flex-wrap items-end gap-3" @submit.prevent="create">
|
<form class="flex flex-wrap items-end gap-3" @submit.prevent="create">
|
||||||
<BaseInput id="group-name" v-model="name" label="New group" placeholder="Family" class="min-w-48 flex-1" />
|
<BaseInput id="group-name" v-model="name" label="New group" placeholder="Family" class="min-w-48 flex-1" />
|
||||||
<BaseButton type="submit" :loading="creating" :disabled="!name.trim()">Create group</BaseButton>
|
<BaseButton type="submit" :loading="creating" :disabled="!name.trim()">Create group</BaseButton>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<p v-if="error" class="text-sm text-red-600 dark:text-red-400">{{ error }}</p>
|
<p v-if="error" class="form-error">{{ error }}</p>
|
||||||
|
|
||||||
<div v-if="loading" class="py-6 text-center text-sm text-neutral-400">Loading…</div>
|
<div v-if="loading" class="list-empty">Loading…</div>
|
||||||
<p v-else-if="empty" class="text-sm text-neutral-400">No groups yet.</p>
|
<p v-else-if="empty" class="text-sm text-neutral-400">No groups yet.</p>
|
||||||
<ul v-else class="flex flex-col gap-2">
|
<ul v-else class="flex flex-col gap-2">
|
||||||
<li
|
<li
|
||||||
@@ -167,7 +167,7 @@ onMounted(() => {
|
|||||||
<div class="flex shrink-0 items-center gap-2">
|
<div class="flex shrink-0 items-center gap-2">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="rounded-md border border-neutral-300 px-2.5 py-1 text-xs text-neutral-700 hover:bg-neutral-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-brand disabled:opacity-50 dark:border-neutral-700 dark:text-neutral-200 dark:hover:bg-neutral-800"
|
class="btn-sm"
|
||||||
:disabled="busy === g.id"
|
:disabled="busy === g.id"
|
||||||
@click="rename(g)"
|
@click="rename(g)"
|
||||||
>
|
>
|
||||||
@@ -175,7 +175,7 @@ onMounted(() => {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="rounded-md border border-neutral-300 px-2.5 py-1 text-xs text-red-600 hover:bg-red-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-brand disabled:opacity-50 dark:border-neutral-700 dark:text-red-400 dark:hover:bg-red-950/40"
|
class="btn-sm-danger"
|
||||||
:disabled="busy === g.id"
|
:disabled="busy === g.id"
|
||||||
@click="remove(g)"
|
@click="remove(g)"
|
||||||
>
|
>
|
||||||
@@ -216,7 +216,7 @@ onMounted(() => {
|
|||||||
</select>
|
</select>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="rounded-md border border-neutral-300 px-2.5 py-1.5 text-xs text-neutral-700 hover:bg-neutral-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-brand disabled:opacity-50 dark:border-neutral-700 dark:text-neutral-200 dark:hover:bg-neutral-800"
|
class="btn-sm py-1.5"
|
||||||
:disabled="busy === g.id || !picks[g.id]"
|
:disabled="busy === g.id || !picks[g.id]"
|
||||||
>
|
>
|
||||||
Add
|
Add
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section class="flex flex-col gap-5">
|
<section class="flex flex-col gap-5">
|
||||||
<h2 class="text-xs font-semibold uppercase tracking-wide text-neutral-400">Invites</h2>
|
<h2 class="section-label">Invites</h2>
|
||||||
|
|
||||||
<OneTimeLink
|
<OneTimeLink
|
||||||
v-if="freshLink"
|
v-if="freshLink"
|
||||||
@@ -132,7 +132,7 @@ onMounted(() => {
|
|||||||
<select
|
<select
|
||||||
id="invite-days"
|
id="invite-days"
|
||||||
v-model.number="days"
|
v-model.number="days"
|
||||||
class="rounded-lg border border-neutral-300 bg-white px-3 py-2 text-sm text-neutral-900 shadow-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-brand dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-100"
|
class="field"
|
||||||
>
|
>
|
||||||
<option v-for="l in LIFETIMES" :key="l.days" :value="l.days">{{ l.label }}</option>
|
<option v-for="l in LIFETIMES" :key="l.days" :value="l.days">{{ l.label }}</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -140,15 +140,15 @@ onMounted(() => {
|
|||||||
<BaseButton type="submit" :loading="creating">Create invite</BaseButton>
|
<BaseButton type="submit" :loading="creating">Create invite</BaseButton>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<p v-if="error" class="text-sm text-red-600 dark:text-red-400">{{ error }}</p>
|
<p v-if="error" class="form-error">{{ error }}</p>
|
||||||
|
|
||||||
<div v-if="loading" class="py-6 text-center text-sm text-neutral-400">Loading…</div>
|
<div v-if="loading" class="list-empty">Loading…</div>
|
||||||
<p v-else-if="!invites.length" class="text-sm text-neutral-400">No invites yet.</p>
|
<p v-else-if="!invites.length" class="text-sm text-neutral-400">No invites yet.</p>
|
||||||
<ul v-else class="flex flex-col gap-2">
|
<ul v-else class="flex flex-col gap-2">
|
||||||
<li
|
<li
|
||||||
v-for="i in invites"
|
v-for="i in invites"
|
||||||
:key="i.id"
|
:key="i.id"
|
||||||
class="flex items-center justify-between gap-4 rounded-xl border border-neutral-200 px-4 py-3 dark:border-neutral-800"
|
class="row-card"
|
||||||
>
|
>
|
||||||
<div class="min-w-0">
|
<div class="min-w-0">
|
||||||
<p class="truncate text-sm font-medium text-neutral-800 dark:text-neutral-100">
|
<p class="truncate text-sm font-medium text-neutral-800 dark:text-neutral-100">
|
||||||
@@ -159,7 +159,7 @@ onMounted(() => {
|
|||||||
<button
|
<button
|
||||||
v-if="i.status === 'pending'"
|
v-if="i.status === 'pending'"
|
||||||
type="button"
|
type="button"
|
||||||
class="shrink-0 rounded-md border border-neutral-300 px-2.5 py-1 text-xs text-red-600 hover:bg-red-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-brand dark:border-neutral-700 dark:text-red-400 dark:hover:bg-red-950/40"
|
class="shrink-0 btn-sm-danger"
|
||||||
@click="revoke(i)"
|
@click="revoke(i)"
|
||||||
>
|
>
|
||||||
Revoke
|
Revoke
|
||||||
|
|||||||
@@ -761,7 +761,7 @@ function revPreview(rev: NoteRevision): string {
|
|||||||
v-if="!isCreate && showHistory"
|
v-if="!isCreate && showHistory"
|
||||||
class="flex flex-col gap-1 border-t border-neutral-100 pt-2 dark:border-neutral-800"
|
class="flex flex-col gap-1 border-t border-neutral-100 pt-2 dark:border-neutral-800"
|
||||||
>
|
>
|
||||||
<p class="text-xs font-semibold uppercase tracking-wide text-neutral-400">History</p>
|
<p class="section-label">History</p>
|
||||||
<p v-if="!revisions.length" class="text-xs text-neutral-400">
|
<p v-if="!revisions.length" class="text-xs text-neutral-400">
|
||||||
No earlier versions yet — your edits will show up here.
|
No earlier versions yet — your edits will show up here.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ onMounted(load);
|
|||||||
<p v-if="loading" class="py-4 text-center text-sm text-neutral-400">Loading…</p>
|
<p v-if="loading" class="py-4 text-center text-sm text-neutral-400">Loading…</p>
|
||||||
|
|
||||||
<div v-else-if="loadError" class="py-4 text-center">
|
<div v-else-if="loadError" class="py-4 text-center">
|
||||||
<p class="text-sm text-red-600 dark:text-red-400">{{ loadError }}</p>
|
<p class="form-error">{{ loadError }}</p>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="mt-2 rounded-md border border-neutral-300 px-3 py-1 text-sm hover:bg-neutral-100 dark:border-neutral-700 dark:hover:bg-neutral-800"
|
class="mt-2 rounded-md border border-neutral-300 px-3 py-1 text-sm hover:bg-neutral-100 dark:border-neutral-700 dark:hover:bg-neutral-800"
|
||||||
@@ -126,7 +126,7 @@ onMounted(load);
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<p v-if="!anyone" class="text-sm text-neutral-500 dark:text-neutral-400">
|
<p v-if="!anyone" class="hint">
|
||||||
No one else has an account here yet. An admin can invite people from Settings.
|
No one else has an account here yet. An admin can invite people from Settings.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -156,10 +156,10 @@ onMounted(load);
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<p v-if="error" role="alert" class="text-sm text-red-600 dark:text-red-400">{{ error }}</p>
|
<p v-if="error" role="alert" class="form-error">{{ error }}</p>
|
||||||
|
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<p class="text-xs font-semibold uppercase tracking-wide text-neutral-400">Shared with</p>
|
<p class="section-label">Shared with</p>
|
||||||
<p v-if="!shares.length" class="text-sm text-neutral-400">Only you.</p>
|
<p v-if="!shares.length" class="text-sm text-neutral-400">Only you.</p>
|
||||||
<ul v-else class="flex flex-col gap-1">
|
<ul v-else class="flex flex-col gap-1">
|
||||||
<li v-for="s in shares" :key="s.id" class="flex items-center gap-2 rounded-lg px-1 py-1">
|
<li v-for="s in shares" :key="s.id" class="flex items-center gap-2 rounded-lg px-1 py-1">
|
||||||
|
|||||||
@@ -290,4 +290,52 @@ body {
|
|||||||
.nav-link-active {
|
.nav-link-active {
|
||||||
@apply bg-neutral-200 text-neutral-900 dark:bg-neutral-800 dark:text-neutral-100;
|
@apply bg-neutral-200 text-neutral-900 dark:bg-neutral-800 dark:text-neutral-100;
|
||||||
}
|
}
|
||||||
|
/* The small bordered action on a row in Account, Admin and Sync: Rename, Revoke,
|
||||||
|
* Sign out. Two colours, neutral and destructive; spacing a site needs beyond
|
||||||
|
* these (shrink-0, self-start, py-1.5) stays a utility beside it. */
|
||||||
|
.btn-sm {
|
||||||
|
@apply rounded-md border border-neutral-300 px-2.5 py-1 text-xs text-neutral-700
|
||||||
|
hover:bg-neutral-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-brand
|
||||||
|
disabled:opacity-50 dark:border-neutral-700 dark:text-neutral-200 dark:hover:bg-neutral-800;
|
||||||
|
}
|
||||||
|
.btn-sm-danger {
|
||||||
|
@apply rounded-md border border-neutral-300 px-2.5 py-1 text-xs text-red-600
|
||||||
|
hover:bg-red-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-brand
|
||||||
|
disabled:opacity-50 dark:border-neutral-700 dark:text-red-400 dark:hover:bg-red-950/40;
|
||||||
|
}
|
||||||
|
/* A plain text or number input on a settings page; its width is the site's. */
|
||||||
|
.field {
|
||||||
|
@apply rounded-lg border border-neutral-300 bg-white px-3 py-2 text-sm text-neutral-900
|
||||||
|
shadow-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-brand
|
||||||
|
dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-100;
|
||||||
|
}
|
||||||
|
/* A settings or account page: one centred column. */
|
||||||
|
.page-shell {
|
||||||
|
@apply mx-auto min-h-full max-w-2xl px-4 py-8;
|
||||||
|
}
|
||||||
|
/* The small caps heading over a group of rows or controls. */
|
||||||
|
.section-label {
|
||||||
|
@apply text-xs font-semibold uppercase tracking-wide text-neutral-400;
|
||||||
|
}
|
||||||
|
/* One bordered row in a list of things you can act on: a device, an account. */
|
||||||
|
.row-card {
|
||||||
|
@apply flex items-center justify-between gap-4 rounded-xl border border-neutral-200 px-4
|
||||||
|
py-3 dark:border-neutral-800;
|
||||||
|
}
|
||||||
|
/* The line a list shows when it has nothing in it. */
|
||||||
|
.list-empty {
|
||||||
|
@apply py-6 text-center text-sm text-neutral-400;
|
||||||
|
}
|
||||||
|
/* Secondary text under a heading or beside a control. */
|
||||||
|
.hint {
|
||||||
|
@apply text-sm text-neutral-500 dark:text-neutral-400;
|
||||||
|
}
|
||||||
|
/* A field's or a form's own error, in a line of text. */
|
||||||
|
.form-error {
|
||||||
|
@apply text-sm text-red-600 dark:text-red-400;
|
||||||
|
}
|
||||||
|
/* A form's error as a banner over its submit button. */
|
||||||
|
.alert-error {
|
||||||
|
@apply rounded-lg bg-red-50 px-3 py-2 text-sm text-red-700 dark:bg-red-950/50 dark:text-red-300;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,11 +142,11 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="mx-auto min-h-full max-w-2xl px-4 py-8">
|
<div class="page-shell">
|
||||||
<PageHeader title="Account" />
|
<PageHeader title="Account" />
|
||||||
|
|
||||||
<h2 class="mb-2 text-xs font-semibold uppercase tracking-wide text-neutral-400">Linked devices</h2>
|
<h2 class="mb-2 section-label">Linked devices</h2>
|
||||||
<p class="mb-6 max-w-xl text-sm text-neutral-500 dark:text-neutral-400">
|
<p class="mb-6 max-w-xl hint">
|
||||||
Link the Inkwell desktop or mobile app to sync your notes. Create a device token here, then
|
Link the Inkwell desktop or mobile app to sync your notes. Create a device token here, then
|
||||||
paste it into the app when it asks to connect. You can revoke a device at any time.
|
paste it into the app when it asks to connect. You can revoke a device at any time.
|
||||||
</p>
|
</p>
|
||||||
@@ -199,7 +199,7 @@ onMounted(() => {
|
|||||||
<BaseButton type="submit" :loading="creating">Create token</BaseButton>
|
<BaseButton type="submit" :loading="creating">Create token</BaseButton>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<p v-if="error" class="mb-4 text-sm text-red-600 dark:text-red-400">{{ error }}</p>
|
<p v-if="error" class="mb-4 form-error">{{ error }}</p>
|
||||||
|
|
||||||
<!-- Device list -->
|
<!-- Device list -->
|
||||||
<div v-if="devices.loading" class="py-10 text-center text-sm text-neutral-400">Loading…</div>
|
<div v-if="devices.loading" class="py-10 text-center text-sm text-neutral-400">Loading…</div>
|
||||||
@@ -207,13 +207,13 @@ onMounted(() => {
|
|||||||
v-else-if="!devices.items.length"
|
v-else-if="!devices.items.length"
|
||||||
class="rounded-xl border border-dashed border-neutral-300 py-10 text-center dark:border-neutral-700"
|
class="rounded-xl border border-dashed border-neutral-300 py-10 text-center dark:border-neutral-700"
|
||||||
>
|
>
|
||||||
<p class="text-sm text-neutral-500 dark:text-neutral-400">No devices linked yet.</p>
|
<p class="hint">No devices linked yet.</p>
|
||||||
</div>
|
</div>
|
||||||
<ul v-else class="flex flex-col gap-2">
|
<ul v-else class="flex flex-col gap-2">
|
||||||
<li
|
<li
|
||||||
v-for="d in devices.items"
|
v-for="d in devices.items"
|
||||||
:key="d.id"
|
:key="d.id"
|
||||||
class="flex items-center justify-between gap-4 rounded-xl border border-neutral-200 px-4 py-3 dark:border-neutral-800"
|
class="row-card"
|
||||||
>
|
>
|
||||||
<div class="flex min-w-0 items-center gap-3">
|
<div class="flex min-w-0 items-center gap-3">
|
||||||
<span class="text-neutral-400"><Icon name="device" /></span>
|
<span class="text-neutral-400"><Icon name="device" /></span>
|
||||||
@@ -226,7 +226,7 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="shrink-0 rounded-md border border-neutral-300 px-2.5 py-1 text-xs text-red-600 hover:bg-red-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-brand dark:border-neutral-700 dark:text-red-400 dark:hover:bg-red-950/40"
|
class="shrink-0 btn-sm-danger"
|
||||||
@click="revoke(d.id, d.name)"
|
@click="revoke(d.id, d.name)"
|
||||||
>
|
>
|
||||||
Revoke
|
Revoke
|
||||||
@@ -235,9 +235,9 @@ onMounted(() => {
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<template v-if="storage">
|
<template v-if="storage">
|
||||||
<h2 class="mb-2 mt-10 text-xs font-semibold uppercase tracking-wide text-neutral-400">Storage</h2>
|
<h2 class="mb-2 mt-10 section-label">Storage</h2>
|
||||||
<div
|
<div
|
||||||
class="flex items-center justify-between gap-4 rounded-xl border border-neutral-200 px-4 py-3 dark:border-neutral-800"
|
class="row-card"
|
||||||
>
|
>
|
||||||
<div class="min-w-0">
|
<div class="min-w-0">
|
||||||
<p class="text-sm font-medium text-neutral-800 dark:text-neutral-100">Attachments</p>
|
<p class="text-sm font-medium text-neutral-800 dark:text-neutral-100">Attachments</p>
|
||||||
@@ -247,8 +247,8 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<h2 class="mb-2 mt-10 text-xs font-semibold uppercase tracking-wide text-neutral-400">Password</h2>
|
<h2 class="mb-2 mt-10 section-label">Password</h2>
|
||||||
<p class="mb-4 text-sm text-neutral-500 dark:text-neutral-400">Changing it signs you out everywhere else.</p>
|
<p class="mb-4 hint">Changing it signs you out everywhere else.</p>
|
||||||
<form class="flex max-w-sm flex-col gap-3" @submit.prevent="changePassword">
|
<form class="flex max-w-sm flex-col gap-3" @submit.prevent="changePassword">
|
||||||
<BaseInput
|
<BaseInput
|
||||||
id="current-password"
|
id="current-password"
|
||||||
@@ -273,9 +273,9 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<h2 class="mb-2 mt-10 text-xs font-semibold uppercase tracking-wide text-neutral-400">Sessions</h2>
|
<h2 class="mb-2 mt-10 section-label">Sessions</h2>
|
||||||
<div
|
<div
|
||||||
class="flex items-center justify-between gap-4 rounded-xl border border-neutral-200 px-4 py-3 dark:border-neutral-800"
|
class="row-card"
|
||||||
>
|
>
|
||||||
<div class="min-w-0">
|
<div class="min-w-0">
|
||||||
<p class="text-sm font-medium text-neutral-800 dark:text-neutral-100">Sign out everywhere else</p>
|
<p class="text-sm font-medium text-neutral-800 dark:text-neutral-100">Sign out everywhere else</p>
|
||||||
|
|||||||
@@ -350,11 +350,11 @@ const gridBinds = computed(() => ({
|
|||||||
<template v-else>
|
<template v-else>
|
||||||
<template v-if="isMainBoard">
|
<template v-if="isMainBoard">
|
||||||
<section v-if="pinnedNotes.length">
|
<section v-if="pinnedNotes.length">
|
||||||
<h2 class="mb-2 text-xs font-semibold uppercase tracking-wide text-neutral-400">Pinned</h2>
|
<h2 class="mb-2 section-label">Pinned</h2>
|
||||||
<NoteGrid :notes="pinnedNotes" v-bind="gridBinds" />
|
<NoteGrid :notes="pinnedNotes" v-bind="gridBinds" />
|
||||||
</section>
|
</section>
|
||||||
<section v-if="otherNotes.length" :class="pinnedNotes.length ? 'mt-8' : ''">
|
<section v-if="otherNotes.length" :class="pinnedNotes.length ? 'mt-8' : ''">
|
||||||
<h2 v-if="pinnedNotes.length" class="mb-2 text-xs font-semibold uppercase tracking-wide text-neutral-400">
|
<h2 v-if="pinnedNotes.length" class="mb-2 section-label">
|
||||||
Others
|
Others
|
||||||
</h2>
|
</h2>
|
||||||
<NoteGrid :notes="otherNotes" v-bind="gridBinds" />
|
<NoteGrid :notes="otherNotes" v-bind="gridBinds" />
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ async function submit() {
|
|||||||
height="48"
|
height="48"
|
||||||
/>
|
/>
|
||||||
<h1 class="text-2xl font-bold tracking-tight">Forgot your password?</h1>
|
<h1 class="text-2xl font-bold tracking-tight">Forgot your password?</h1>
|
||||||
<p class="mt-1 text-sm text-neutral-500 dark:text-neutral-400">We'll email you a link to choose a new one.</p>
|
<p class="mt-1 hint">We'll email you a link to choose a new one.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p
|
<p
|
||||||
@@ -67,14 +67,14 @@ async function submit() {
|
|||||||
<p
|
<p
|
||||||
v-if="error"
|
v-if="error"
|
||||||
role="alert"
|
role="alert"
|
||||||
class="rounded-lg bg-red-50 px-3 py-2 text-sm text-red-700 dark:bg-red-950/50 dark:text-red-300"
|
class="alert-error"
|
||||||
>
|
>
|
||||||
{{ error }}
|
{{ error }}
|
||||||
</p>
|
</p>
|
||||||
<BaseButton type="submit" :loading="loading">Send reset link</BaseButton>
|
<BaseButton type="submit" :loading="loading">Send reset link</BaseButton>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<p class="mt-6 text-center text-sm text-neutral-500 dark:text-neutral-400">
|
<p class="mt-6 text-center hint">
|
||||||
<RouterLink to="/login" class="font-semibold text-brand-700 hover:underline dark:text-brand"
|
<RouterLink to="/login" class="font-semibold text-brand-700 hover:underline dark:text-brand"
|
||||||
>Back to sign in</RouterLink
|
>Back to sign in</RouterLink
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ async function submit() {
|
|||||||
height="48"
|
height="48"
|
||||||
/>
|
/>
|
||||||
<h1 class="text-2xl font-bold tracking-tight">Welcome back</h1>
|
<h1 class="text-2xl font-bold tracking-tight">Welcome back</h1>
|
||||||
<p class="mt-1 text-sm text-neutral-500 dark:text-neutral-400">Sign in to your thoughts.</p>
|
<p class="mt-1 hint">Sign in to your thoughts.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form class="flex flex-col gap-4" novalidate @submit.prevent="submit">
|
<form class="flex flex-col gap-4" novalidate @submit.prevent="submit">
|
||||||
@@ -77,7 +77,7 @@ async function submit() {
|
|||||||
<p
|
<p
|
||||||
v-if="error"
|
v-if="error"
|
||||||
role="alert"
|
role="alert"
|
||||||
class="rounded-lg bg-red-50 px-3 py-2 text-sm text-red-700 dark:bg-red-950/50 dark:text-red-300"
|
class="alert-error"
|
||||||
>
|
>
|
||||||
{{ error }}
|
{{ error }}
|
||||||
</p>
|
</p>
|
||||||
@@ -90,7 +90,7 @@ async function submit() {
|
|||||||
>
|
>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<p v-if="config.allowRegistration" class="mt-6 text-center text-sm text-neutral-500 dark:text-neutral-400">
|
<p v-if="config.allowRegistration" class="mt-6 text-center hint">
|
||||||
No account?
|
No account?
|
||||||
<RouterLink to="/register" class="font-semibold text-brand-700 hover:underline dark:text-brand"
|
<RouterLink to="/register" class="font-semibold text-brand-700 hover:underline dark:text-brand"
|
||||||
>Create one</RouterLink
|
>Create one</RouterLink
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ async function submit() {
|
|||||||
height="48"
|
height="48"
|
||||||
/>
|
/>
|
||||||
<h1 class="text-2xl font-bold tracking-tight">{{ invite ? "You're invited" : "Create your space" }}</h1>
|
<h1 class="text-2xl font-bold tracking-tight">{{ invite ? "You're invited" : "Create your space" }}</h1>
|
||||||
<p class="mt-1 text-sm text-neutral-500 dark:text-neutral-400">
|
<p class="mt-1 hint">
|
||||||
{{ invite ? `Create your account on ${config.siteName}.` : "Start capturing in seconds." }}
|
{{ invite ? `Create your account on ${config.siteName}.` : "Start capturing in seconds." }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -86,14 +86,14 @@ async function submit() {
|
|||||||
<p
|
<p
|
||||||
v-if="error"
|
v-if="error"
|
||||||
role="alert"
|
role="alert"
|
||||||
class="rounded-lg bg-red-50 px-3 py-2 text-sm text-red-700 dark:bg-red-950/50 dark:text-red-300"
|
class="alert-error"
|
||||||
>
|
>
|
||||||
{{ error }}
|
{{ error }}
|
||||||
</p>
|
</p>
|
||||||
<BaseButton type="submit" :loading="loading">Create account</BaseButton>
|
<BaseButton type="submit" :loading="loading">Create account</BaseButton>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<p class="mt-6 text-center text-sm text-neutral-500 dark:text-neutral-400">
|
<p class="mt-6 text-center hint">
|
||||||
Already have an account?
|
Already have an account?
|
||||||
<RouterLink to="/login" class="font-semibold text-brand-700 hover:underline dark:text-brand"
|
<RouterLink to="/login" class="font-semibold text-brand-700 hover:underline dark:text-brand"
|
||||||
>Sign in</RouterLink
|
>Sign in</RouterLink
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ async function submit() {
|
|||||||
height="48"
|
height="48"
|
||||||
/>
|
/>
|
||||||
<h1 class="text-2xl font-bold tracking-tight">Choose a new password</h1>
|
<h1 class="text-2xl font-bold tracking-tight">Choose a new password</h1>
|
||||||
<p class="mt-1 text-sm text-neutral-500 dark:text-neutral-400">
|
<p class="mt-1 hint">
|
||||||
You'll be signed out everywhere else, and your apps will ask you to sign in again.
|
You'll be signed out everywhere else, and your apps will ask you to sign in again.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -66,7 +66,7 @@ async function submit() {
|
|||||||
<p
|
<p
|
||||||
v-if="!token"
|
v-if="!token"
|
||||||
role="alert"
|
role="alert"
|
||||||
class="rounded-lg bg-red-50 px-3 py-2 text-sm text-red-700 dark:bg-red-950/50 dark:text-red-300"
|
class="alert-error"
|
||||||
>
|
>
|
||||||
This link is incomplete. Ask your admin for a new one.
|
This link is incomplete. Ask your admin for a new one.
|
||||||
</p>
|
</p>
|
||||||
@@ -91,14 +91,14 @@ async function submit() {
|
|||||||
<p
|
<p
|
||||||
v-if="error"
|
v-if="error"
|
||||||
role="alert"
|
role="alert"
|
||||||
class="rounded-lg bg-red-50 px-3 py-2 text-sm text-red-700 dark:bg-red-950/50 dark:text-red-300"
|
class="alert-error"
|
||||||
>
|
>
|
||||||
{{ error }}
|
{{ error }}
|
||||||
</p>
|
</p>
|
||||||
<BaseButton type="submit" :loading="loading">Set password</BaseButton>
|
<BaseButton type="submit" :loading="loading">Set password</BaseButton>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<p class="mt-6 text-center text-sm text-neutral-500 dark:text-neutral-400">
|
<p class="mt-6 text-center hint">
|
||||||
<RouterLink to="/login" class="font-semibold text-brand-700 hover:underline dark:text-brand"
|
<RouterLink to="/login" class="font-semibold text-brand-700 hover:underline dark:text-brand"
|
||||||
>Back to sign in</RouterLink
|
>Back to sign in</RouterLink
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -94,13 +94,13 @@ onMounted(load);
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="mx-auto min-h-full max-w-2xl px-4 py-8">
|
<div class="page-shell">
|
||||||
<PageHeader title="Settings" />
|
<PageHeader title="Settings" />
|
||||||
|
|
||||||
<AsyncState :loading="loading" :error="loadError" error-title="Couldn't load settings" @retry="load">
|
<AsyncState :loading="loading" :error="loadError" error-title="Couldn't load settings" @retry="load">
|
||||||
<form class="flex flex-col gap-8" @submit.prevent="save">
|
<form class="flex flex-col gap-8" @submit.prevent="save">
|
||||||
<section v-for="group in groups" :key="group.name" class="flex flex-col gap-5">
|
<section v-for="group in groups" :key="group.name" class="flex flex-col gap-5">
|
||||||
<h2 class="text-xs font-semibold uppercase tracking-wide text-neutral-400">{{ group.name }}</h2>
|
<h2 class="section-label">{{ group.name }}</h2>
|
||||||
|
|
||||||
<div v-for="it in group.entries" :key="it.key" class="flex flex-col gap-1">
|
<div v-for="it in group.entries" :key="it.key" class="flex flex-col gap-1">
|
||||||
<div class="flex items-center justify-between gap-6">
|
<div class="flex items-center justify-between gap-6">
|
||||||
@@ -126,14 +126,14 @@ onMounted(load);
|
|||||||
type="number"
|
type="number"
|
||||||
:min="it.minimum ?? undefined"
|
:min="it.minimum ?? undefined"
|
||||||
:max="it.maximum ?? undefined"
|
:max="it.maximum ?? undefined"
|
||||||
class="w-28 rounded-lg border border-neutral-300 bg-white px-3 py-2 text-sm text-neutral-900 shadow-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-brand dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-100"
|
class="w-28 field"
|
||||||
:value="Number(it.value)"
|
:value="Number(it.value)"
|
||||||
@input="it.value = Number(($event.target as HTMLInputElement).value)"
|
@input="it.value = Number(($event.target as HTMLInputElement).value)"
|
||||||
/>
|
/>
|
||||||
<select
|
<select
|
||||||
v-else-if="it.choices"
|
v-else-if="it.choices"
|
||||||
:id="it.key"
|
:id="it.key"
|
||||||
class="w-56 rounded-lg border border-neutral-300 bg-white px-3 py-2 text-sm text-neutral-900 shadow-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-brand dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-100"
|
class="w-56 field"
|
||||||
:value="String(it.value)"
|
:value="String(it.value)"
|
||||||
@change="it.value = ($event.target as HTMLSelectElement).value"
|
@change="it.value = ($event.target as HTMLSelectElement).value"
|
||||||
>
|
>
|
||||||
@@ -145,7 +145,7 @@ onMounted(load);
|
|||||||
type="password"
|
type="password"
|
||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
:placeholder="it.is_set ? 'Saved — type to replace' : ''"
|
:placeholder="it.is_set ? 'Saved — type to replace' : ''"
|
||||||
class="w-56 rounded-lg border border-neutral-300 bg-white px-3 py-2 text-sm text-neutral-900 shadow-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-brand dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-100"
|
class="w-56 field"
|
||||||
:value="String(it.value)"
|
:value="String(it.value)"
|
||||||
@input="it.value = ($event.target as HTMLInputElement).value"
|
@input="it.value = ($event.target as HTMLInputElement).value"
|
||||||
/>
|
/>
|
||||||
@@ -153,7 +153,7 @@ onMounted(load);
|
|||||||
v-else
|
v-else
|
||||||
:id="it.key"
|
:id="it.key"
|
||||||
type="text"
|
type="text"
|
||||||
class="w-56 rounded-lg border border-neutral-300 bg-white px-3 py-2 text-sm text-neutral-900 shadow-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-brand dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-100"
|
class="w-56 field"
|
||||||
:value="String(it.value)"
|
:value="String(it.value)"
|
||||||
@input="it.value = ($event.target as HTMLInputElement).value"
|
@input="it.value = ($event.target as HTMLInputElement).value"
|
||||||
/>
|
/>
|
||||||
@@ -178,7 +178,7 @@ onMounted(load);
|
|||||||
<BaseButton type="submit" :loading="saving" :disabled="!dirty">Save changes</BaseButton>
|
<BaseButton type="submit" :loading="saving" :disabled="!dirty">Save changes</BaseButton>
|
||||||
<span v-if="saved && !dirty" class="text-sm text-green-600 dark:text-green-400">Saved.</span>
|
<span v-if="saved && !dirty" class="text-sm text-green-600 dark:text-green-400">Saved.</span>
|
||||||
<span v-else-if="!dirty && !error" class="text-sm text-neutral-400">No unsaved changes</span>
|
<span v-else-if="!dirty && !error" class="text-sm text-neutral-400">No unsaved changes</span>
|
||||||
<span v-if="error" class="text-sm text-red-600 dark:text-red-400">{{ error }}</span>
|
<span v-if="error" class="form-error">{{ error }}</span>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</AsyncState>
|
</AsyncState>
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ onBeforeUnmount(() => stopSyncListener?.());
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="mx-auto min-h-full max-w-2xl px-4 py-8">
|
<div class="page-shell">
|
||||||
<PageHeader title="Sync" />
|
<PageHeader title="Sync" />
|
||||||
|
|
||||||
<div v-if="loading" class="py-10 text-center text-sm text-neutral-400">Loading…</div>
|
<div v-if="loading" class="py-10 text-center text-sm text-neutral-400">Loading…</div>
|
||||||
@@ -392,7 +392,7 @@ onBeforeUnmount(() => stopSyncListener?.());
|
|||||||
<p v-if="degraded.length" class="mt-3 text-xs text-amber-600 dark:text-amber-400">
|
<p v-if="degraded.length" class="mt-3 text-xs text-amber-600 dark:text-amber-400">
|
||||||
This server doesn't support: {{ degraded.join(", ") }}. Everything else syncs normally.
|
This server doesn't support: {{ degraded.join(", ") }}. Everything else syncs normally.
|
||||||
</p>
|
</p>
|
||||||
<p v-if="syncError" class="mt-3 text-sm text-red-600 dark:text-red-400">{{ syncError }}</p>
|
<p v-if="syncError" class="mt-3 form-error">{{ syncError }}</p>
|
||||||
<p v-else-if="autoError" class="mt-3 text-xs text-amber-600 dark:text-amber-400">
|
<p v-else-if="autoError" class="mt-3 text-xs text-amber-600 dark:text-amber-400">
|
||||||
The last automatic sync ({{ new Date(lastCycle!.at_ms).toLocaleTimeString() }}) didn't
|
The last automatic sync ({{ new Date(lastCycle!.at_ms).toLocaleTimeString() }}) didn't
|
||||||
go through: {{ autoError }} It will keep trying on its own.
|
go through: {{ autoError }} It will keep trying on its own.
|
||||||
@@ -428,7 +428,7 @@ onBeforeUnmount(() => stopSyncListener?.());
|
|||||||
<p class="text-sm font-medium text-neutral-800 dark:text-neutral-100">
|
<p class="text-sm font-medium text-neutral-800 dark:text-neutral-100">
|
||||||
Working offline on this device
|
Working offline on this device
|
||||||
</p>
|
</p>
|
||||||
<p class="mt-1 text-sm text-neutral-500 dark:text-neutral-400">
|
<p class="mt-1 hint">
|
||||||
Everything works without a server — your notes are stored on this machine. Connect an
|
Everything works without a server — your notes are stored on this machine. Connect an
|
||||||
Inkwell server if you want them to reach your other devices.
|
Inkwell server if you want them to reach your other devices.
|
||||||
</p>
|
</p>
|
||||||
@@ -452,7 +452,7 @@ onBeforeUnmount(() => stopSyncListener?.());
|
|||||||
Uses https unless you type http:// yourself.
|
Uses https unless you type http:// yourself.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p v-if="probeError" class="text-sm text-red-600 dark:text-red-400">{{ probeError }}</p>
|
<p v-if="probeError" class="form-error">{{ probeError }}</p>
|
||||||
|
|
||||||
<!-- What answered, BEFORE any credentials are handed over -->
|
<!-- What answered, BEFORE any credentials are handed over -->
|
||||||
<div
|
<div
|
||||||
@@ -531,7 +531,7 @@ onBeforeUnmount(() => stopSyncListener?.());
|
|||||||
/>
|
/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<p v-if="linkError" class="text-sm text-red-600 dark:text-red-400">{{ linkError }}</p>
|
<p v-if="linkError" class="form-error">{{ linkError }}</p>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<BaseButton type="submit" :loading="linking" :disabled="!canLink">
|
<BaseButton type="submit" :loading="linking" :disabled="!canLink">
|
||||||
@@ -546,7 +546,7 @@ onBeforeUnmount(() => stopSyncListener?.());
|
|||||||
updates: a hotkey that writes to the local store needs no server. -->
|
updates: a hotkey that writes to the local store needs no server. -->
|
||||||
<section class="mt-10 border-t border-neutral-200 pt-8 dark:border-neutral-800">
|
<section class="mt-10 border-t border-neutral-200 pt-8 dark:border-neutral-800">
|
||||||
<h2 class="text-sm font-semibold">Quick capture</h2>
|
<h2 class="text-sm font-semibold">Quick capture</h2>
|
||||||
<p class="mt-1 text-sm text-neutral-500 dark:text-neutral-400">
|
<p class="mt-1 hint">
|
||||||
A system-wide shortcut that opens a small window to write a note in, without
|
A system-wide shortcut that opens a small window to write a note in, without
|
||||||
bringing this one forward.
|
bringing this one forward.
|
||||||
</p>
|
</p>
|
||||||
@@ -570,7 +570,7 @@ onBeforeUnmount(() => stopSyncListener?.());
|
|||||||
</BaseButton>
|
</BaseButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p v-if="shortcutError" class="mt-2 text-sm text-red-600 dark:text-red-400">
|
<p v-if="shortcutError" class="mt-2 form-error">
|
||||||
{{ shortcutError }}
|
{{ shortcutError }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -585,10 +585,10 @@ onBeforeUnmount(() => stopSyncListener?.());
|
|||||||
{{ shortcut.shortcut }} is saved but isn't active — something else on this
|
{{ shortcut.shortcut }} is saved but isn't active — something else on this
|
||||||
system is holding it. Try a different combination.
|
system is holding it. Try a different combination.
|
||||||
</p>
|
</p>
|
||||||
<p v-else-if="shortcut.registered" class="mt-2 text-sm text-neutral-500 dark:text-neutral-400">
|
<p v-else-if="shortcut.registered" class="mt-2 hint">
|
||||||
Press {{ shortcut.shortcut }} anywhere to capture a note.
|
Press {{ shortcut.shortcut }} anywhere to capture a note.
|
||||||
</p>
|
</p>
|
||||||
<p v-else class="mt-2 text-sm text-neutral-500 dark:text-neutral-400">
|
<p v-else class="mt-2 hint">
|
||||||
Off. There's no default on purpose — any combination picked for you is one
|
Off. There's no default on purpose — any combination picked for you is one
|
||||||
taken away from something else on your machine.
|
taken away from something else on your machine.
|
||||||
<button
|
<button
|
||||||
@@ -605,12 +605,12 @@ onBeforeUnmount(() => stopSyncListener?.());
|
|||||||
has never touched a server still updates itself. -->
|
has never touched a server still updates itself. -->
|
||||||
<section class="mt-10 border-t border-neutral-200 pt-8 dark:border-neutral-800">
|
<section class="mt-10 border-t border-neutral-200 pt-8 dark:border-neutral-800">
|
||||||
<h2 class="text-sm font-semibold">App updates</h2>
|
<h2 class="text-sm font-semibold">App updates</h2>
|
||||||
<p class="mt-1 text-sm text-neutral-500 dark:text-neutral-400">
|
<p class="mt-1 hint">
|
||||||
This is version {{ update?.current_version ?? "—" }}.
|
This is version {{ update?.current_version ?? "—" }}.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<fieldset v-if="offeredServer" class="mt-4">
|
<fieldset v-if="offeredServer" class="mt-4">
|
||||||
<legend class="text-xs font-semibold uppercase tracking-wide text-neutral-400">
|
<legend class="section-label">
|
||||||
Updates from
|
Updates from
|
||||||
</legend>
|
</legend>
|
||||||
<div class="mt-2 flex flex-col gap-2">
|
<div class="mt-2 flex flex-col gap-2">
|
||||||
@@ -650,7 +650,7 @@ onBeforeUnmount(() => stopSyncListener?.());
|
|||||||
|
|
||||||
<!-- A server holds one build, so a channel only means something on the forge. -->
|
<!-- A server holds one build, so a channel only means something on the forge. -->
|
||||||
<fieldset v-if="source === null" class="mt-4">
|
<fieldset v-if="source === null" class="mt-4">
|
||||||
<legend class="text-xs font-semibold uppercase tracking-wide text-neutral-400">
|
<legend class="section-label">
|
||||||
Channel
|
Channel
|
||||||
</legend>
|
</legend>
|
||||||
<div class="mt-2 flex flex-col gap-2">
|
<div class="mt-2 flex flex-col gap-2">
|
||||||
@@ -704,7 +704,7 @@ onBeforeUnmount(() => stopSyncListener?.());
|
|||||||
</div>
|
</div>
|
||||||
<p
|
<p
|
||||||
v-else-if="checkedOnce && !updateError"
|
v-else-if="checkedOnce && !updateError"
|
||||||
class="mt-4 text-sm text-neutral-500 dark:text-neutral-400"
|
class="mt-4 hint"
|
||||||
>
|
>
|
||||||
<template v-if="source">You're on the newest build {{ source }} has.</template>
|
<template v-if="source">You're on the newest build {{ source }} has.</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
@@ -712,7 +712,7 @@ onBeforeUnmount(() => stopSyncListener?.());
|
|||||||
</template>
|
</template>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p v-if="updateError" class="mt-4 text-sm text-red-600 dark:text-red-400">{{ updateError }}</p>
|
<p v-if="updateError" class="mt-4 form-error">{{ updateError }}</p>
|
||||||
|
|
||||||
<div class="mt-4 flex flex-wrap gap-2">
|
<div class="mt-4 flex flex-wrap gap-2">
|
||||||
<BaseButton variant="ghost" :loading="checking" @click="checkUpdates">
|
<BaseButton variant="ghost" :loading="checking" @click="checkUpdates">
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ onMounted(load);
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="mb-5 text-sm text-neutral-500 dark:text-neutral-400">
|
<p class="mb-5 hint">
|
||||||
Your notes by when you captured them{{ hasRange ? " — filtered to the chosen dates" : "" }}.
|
Your notes by when you captured them{{ hasRange ? " — filtered to the chosen dates" : "" }}.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ onMounted(load);
|
|||||||
<EmptyState v-if="items.length === 0" :title="empty.title" :subtitle="empty.subtitle" />
|
<EmptyState v-if="items.length === 0" :title="empty.title" :subtitle="empty.subtitle" />
|
||||||
<div v-else class="flex flex-col gap-8">
|
<div v-else class="flex flex-col gap-8">
|
||||||
<section v-for="group in groups" :key="group.key">
|
<section v-for="group in groups" :key="group.key">
|
||||||
<h2 class="mb-3 text-xs font-semibold uppercase tracking-wide text-neutral-400">{{ group.label }}</h2>
|
<h2 class="mb-3 section-label">{{ group.label }}</h2>
|
||||||
<NoteGrid :notes="group.notes" @open="openEditor" />
|
<NoteGrid :notes="group.notes" @open="openEditor" />
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user