Compare commits

...
3 Commits
Author SHA1 Message Date
github-actions[bot] 76431b7bc3 chore: bump version to 0.19.0 2026-03-10 14:55:19 +00:00
Frederic CabassutandClaude Opus 4.6 871d17e55f feat: add About settings page with version and project info
Add /settings/about page showing version, project description,
Bretzel ecosystem info, open source details, and tech stack.
Move version display from sidebar to About page and align
Settings nav item styling with other sidebar items.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 15:54:40 +01:00
Frederic Cabassut fa60c65337 fix: prevent e2e test pollution from preferences shared state
Settings tests set defaultNoteMode to 'markdown' without resetting,
causing parallel sharing test to timeout when TiptapEditor wasn't
rendered (textarea shown instead). Two fixes:
- Reset preferences in settings tests after changing them
- Create note via API in sharing test (tests sharing, not note creation)
2026-03-10 15:54:40 +01:00
8 changed files with 115 additions and 20 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "crumbs",
"private": true,
"version": "0.18.0",
"version": "0.19.0",
"type": "module",
"license": "MIT",
"author": "Bretzel (https://bretzel.app)",
+3 -9
View File
@@ -6,10 +6,9 @@
interface Props {
open: boolean;
onClose?: () => void;
appVersion?: string;
}
let { open, onClose, appVersion }: Props = $props();
let { open, onClose }: Props = $props();
function closeMobile() {
if (window.matchMedia('(max-width: 1023px)').matches) {
@@ -75,17 +74,12 @@
<div class="absolute bottom-0 left-0 w-full border-t border-[var(--border-subtle)]">
<a
href="/settings"
class="flex w-full items-center gap-3 px-6 py-3 text-sm text-[var(--text-muted)] transition-colors hover:text-[var(--primary)]"
class="flex w-full items-center gap-3 rounded-sm px-6 py-3 text-left text-sm transition-colors {$page.url.pathname.startsWith('/settings') ? 'bg-[var(--primary)]/15 text-[var(--primary)]' : 'text-[var(--text)] hover:bg-[var(--bg-base)]'}"
onclick={closeMobile}
data-testid="settings-link"
>
<Settings size={16} />
<Settings size={20} />
Settings
</a>
{#if appVersion}
<div class="border-t border-[var(--border-subtle)] px-6 py-2 text-right text-xs text-[var(--text-muted)]">
v{appVersion}
</div>
{/if}
</div>
</aside>
+1 -1
View File
@@ -34,7 +34,7 @@
<div class="flex min-h-screen flex-col bg-[var(--bg-base)] text-[var(--text)]">
<Header onMenuToggle={() => (sidebarOpen = !sidebarOpen)} />
<Sidebar open={sidebarOpen} onClose={() => (sidebarOpen = false)} appVersion={data.appVersion} />
<Sidebar open={sidebarOpen} onClose={() => (sidebarOpen = false)} />
<main class="flex-1 pt-4 transition-all {sidebarOpen ? 'lg:ml-64' : ''}">
<div class="mx-auto max-w-7xl px-4">
+10 -1
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import { page } from '$app/state';
import { User, Cpu, ShieldCheck, SlidersHorizontal } from 'lucide-svelte';
import { User, Cpu, ShieldCheck, SlidersHorizontal, Info } from 'lucide-svelte';
let { data, children } = $props();
let pathname = $derived(page.url.pathname);
@@ -56,6 +56,15 @@
</a>
</li>
{/if}
<li>
<a
href="/settings/about"
class="flex items-center gap-2 rounded-sm px-3 py-2 text-sm whitespace-nowrap transition-colors {pathname === '/settings/about' ? 'bg-[var(--primary)]/15 text-[var(--primary)] font-medium' : 'text-[var(--text)] hover:bg-[var(--bg-base)]'}"
>
<Info size={16} />
About
</a>
</li>
</ul>
</nav>
@@ -0,0 +1,81 @@
<script lang="ts">
import { page } from '$app/stores';
let appVersion = $derived($page.data.appVersion);
</script>
<div class="space-y-8">
<div class="flex items-center gap-3">
<h2 class="text-xl font-bold text-[var(--text)]">About Crumbs</h2>
<span
class="rounded-sm border border-[var(--border-subtle)] bg-[var(--bg-base)] px-2 py-0.5 text-xs font-medium text-[var(--text-muted)]"
>
v{appVersion}
</span>
</div>
<section
class="space-y-2 rounded-sm border border-[var(--border-subtle)] bg-[var(--bg-surface)] p-4 shadow-[var(--card-shadow)]"
>
<h3 class="text-sm font-bold text-[var(--text)]">What is Crumbs?</h3>
<p class="text-sm leading-relaxed text-[var(--text-muted)]">
Crumbs is a self-hostable note-taking app. Like breadcrumbs left along a trail, Crumbs
captures the small scattered thoughts, ideas, and notes you leave behind as you go — so you
can always find your way back to them.
</p>
</section>
<section
class="space-y-2 rounded-sm border border-[var(--border-subtle)] bg-[var(--bg-surface)] p-4 shadow-[var(--card-shadow)]"
>
<h3 class="text-sm font-bold text-[var(--text)]">Bretzel App Universe</h3>
<p class="text-sm leading-relaxed text-[var(--text-muted)]">
Crumbs is part of the
<a
href="https://bretzel.app"
target="_blank"
rel="noopener noreferrer"
class="text-[var(--primary)] underline hover:text-[var(--primary-hover)]">Bretzel</a
> family of apps.
</p>
</section>
<section
class="space-y-2 rounded-sm border border-[var(--border-subtle)] bg-[var(--bg-surface)] p-4 shadow-[var(--card-shadow)]"
>
<h3 class="text-sm font-bold text-[var(--text)]">Open Source</h3>
<p class="text-sm leading-relaxed text-[var(--text-muted)]">
Crumbs is licensed under the MIT License. Source code is available on
<a
href="https://github.com/bretzel-app/crumbs/"
target="_blank"
rel="noopener noreferrer"
class="text-[var(--primary)] underline hover:text-[var(--primary-hover)]">GitHub</a
>.
</p>
</section>
<section
class="space-y-2 rounded-sm border border-[var(--border-subtle)] bg-[var(--bg-surface)] p-4 shadow-[var(--card-shadow)]"
>
<h3 class="text-sm font-bold text-[var(--text)]">Feedback</h3>
<p class="text-sm leading-relaxed text-[var(--text-muted)]">
Feedback is welcome! Please open an issue on
<a
href="https://github.com/bretzel-app/crumbs/issues"
target="_blank"
rel="noopener noreferrer"
class="text-[var(--primary)] underline hover:text-[var(--primary-hover)]">GitHub Issues</a
>.
</p>
</section>
<section
class="space-y-2 rounded-sm border border-[var(--border-subtle)] bg-[var(--bg-surface)] p-4 shadow-[var(--card-shadow)]"
>
<h3 class="text-sm font-bold text-[var(--text)]">Tech Stack</h3>
<p class="text-sm leading-relaxed text-[var(--text-muted)]">
Built with SvelteKit, SQLite, and Drizzle ORM. Offline-first PWA with CRDT-based sync.
</p>
</section>
</div>
+12
View File
@@ -26,6 +26,13 @@ test.describe('Settings — Preferences', () => {
// Then the note editor opens in markdown mode (textarea visible)
await expect(page.getByTestId('note-content-input')).toBeVisible();
// Cleanup: reset to richtext so parallel tests aren't affected
await page.getByTestId('close-editor-btn').click();
await page.goto('/settings/preferences');
const resetResponse = page.waitForResponse((res) => res.url().includes('/api/preferences') && res.request().method() === 'PUT');
await page.getByTestId('pref-mode-richtext').click();
await resetResponse;
});
test('Scenario: Footer toggle hides and shows footer', async ({
@@ -65,6 +72,11 @@ test.describe('Settings — Preferences', () => {
// Then the Markdown button is still selected (has primary styling)
const mdBtn = page.getByTestId('pref-mode-markdown');
await expect(mdBtn).toHaveClass(/font-medium/);
// Cleanup: reset to richtext so parallel tests aren't affected
const resetResponse = page.waitForResponse((res) => res.url().includes('/api/preferences') && res.request().method() === 'PUT');
await page.getByTestId('pref-mode-richtext').click();
await resetResponse;
});
});
+6 -7
View File
@@ -35,13 +35,12 @@ test.describe('Note Sharing', () => {
authenticatedPage: page,
collabPage
}) => {
// When the owner creates a note titled "Share Test"
await page.getByTestId('new-note-btn').click();
await page.getByTestId('note-title-input').fill('Share Test');
const editor = page.getByTestId('tiptap-editor').locator('.tiptap');
await editor.click();
await editor.pressSequentially('Shared content');
await page.getByTestId('close-editor-btn').click();
// Given a note titled "Share Test" exists
await page.request.post('/api/notes', {
data: { title: 'Share Test', content: 'Shared content' }
});
await page.reload();
await page.waitForLoadState('networkidle');
await expect(noteCard(page, 'Share Test')).toBeVisible();
// And the owner opens the share dialog and adds the collaborator
+1 -1
View File
@@ -253,7 +253,7 @@
<li><a href="https://github.com/bretzel-app/crumbs/blob/main/docs/DEPLOYMENT.md" target="_blank" rel="noopener">Docs</a></li>
<li><a href="https://github.com/bretzel-app/crumbs/blob/main/LICENSE" target="_blank" rel="noopener">License</a></li>
</ul>
<span class="footer-version">v0.18.0</span>
<span class="footer-version">v0.19.0</span>
</div>
</footer>