diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a1b90a..ef9d7df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,8 +25,31 @@ jobs: - name: Run oxlint run: bun run lint + format: + name: Format Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + + - name: Install dependencies + run: bun install + + - name: Check code format + run: bun run format:check + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Check Rust formatting + working-directory: ./desktop/src-tauri + run: cargo fmt --check + test: - needs: lint + name: Test + needs: [lint, format] runs-on: ${{ matrix.os }} strategy: matrix: @@ -44,10 +67,6 @@ jobs: - name: Install dependencies run: bun install - - name: Check Rust formatting - working-directory: ./desktop/src-tauri - run: cargo fmt --check - - name: Run Rust tests working-directory: ./desktop/src-tauri run: cargo test diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..544138b --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,3 @@ +{ + "singleQuote": true +} diff --git a/bun.lock b/bun.lock index 8c12623..baf4dc6 100644 --- a/bun.lock +++ b/bun.lock @@ -10,7 +10,7 @@ "@types/better-sqlite3": "^7.6.13", "concurrently": "^9.2.1", "cross-env": "^10.1.0", - "oxlint": "^1.28.0", + "prettier": "^3.6.2", "wait-on": "^8.0.4", }, }, @@ -173,22 +173,6 @@ "@octokit/webhooks-methods": ["@octokit/webhooks-methods@6.0.0", "", {}, "sha512-MFlzzoDJVw/GcbfzVC1RLR36QqkTLUf79vLVO3D+xn7r0QgxnFoLZgtrzxiQErAjFUOdH6fas2KeQJ1yr/qaXQ=="], - "@oxlint/darwin-arm64": ["@oxlint/darwin-arm64@1.28.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-H7J41/iKbgm7tTpdSnA/AtjEAhxyzNzCMKWtKU5wDuP2v39jrc3fasQEJruk6hj1YXPbJY4N+1nK/jE27GMGDQ=="], - - "@oxlint/darwin-x64": ["@oxlint/darwin-x64@1.28.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-bGsSDEwpyYzNc6FIwhTmbhSK7piREUjMlmWBt7eoR3ract0+RfhZYYG4se1Ngs+4WOFC0B3gbv23fyF+cnbGGQ=="], - - "@oxlint/linux-arm64-gnu": ["@oxlint/linux-arm64-gnu@1.28.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-eNH/evMpV3xAA4jIS8dMLcGkM/LK0WEHM0RO9bxrHPAwfS72jhyPJtd0R7nZhvhG6U1bhn5jhoXbk1dn27XIAQ=="], - - "@oxlint/linux-arm64-musl": ["@oxlint/linux-arm64-musl@1.28.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-ickvpcekNeRLND3llndiZOtJBb6LDZqNnZICIDkovURkOIWPGJGmAxsHUOI6yW6iny9gLmIEIGl/c1b5nFk6Ag=="], - - "@oxlint/linux-x64-gnu": ["@oxlint/linux-x64-gnu@1.28.0", "", { "os": "linux", "cpu": "x64" }, "sha512-DkgAh4LQ8NR3DwTT7/LGMhaMau0RtZkih91Ez5Usk7H7SOxo1GDi84beE7it2Q+22cAzgY4hbw3c6svonQTjxg=="], - - "@oxlint/linux-x64-musl": ["@oxlint/linux-x64-musl@1.28.0", "", { "os": "linux", "cpu": "x64" }, "sha512-VBnMi3AJ2w5p/kgeyrjcGOKNY8RzZWWvlGHjCJwzqPgob4MXu6T+5Yrdi7EVJyIlouL8E3LYPYjmzB9NBi9gZw=="], - - "@oxlint/win32-arm64": ["@oxlint/win32-arm64@1.28.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-tomhIks+4dKs8axB+s4GXHy+ZWXhUgptf1XnG5cZg8CzRfX4JFX9k8l2fPUgFwytWnyyvZaaXLRPWGzoZ6yoHQ=="], - - "@oxlint/win32-x64": ["@oxlint/win32-x64@1.28.0", "", { "os": "win32", "cpu": "x64" }, "sha512-4+VO5P/UJ2nq9sj6kQToJxFy5cKs7dGIN2DiUSQ7cqyUi7EKYNQKe+98HFcDOjtm33jQOQnc4kw8Igya5KPozg=="], - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.52.3", "", { "os": "android", "cpu": "arm" }, "sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw=="], "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.52.3", "", { "os": "android", "cpu": "arm64" }, "sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw=="], @@ -489,8 +473,6 @@ "oniguruma-to-es": ["oniguruma-to-es@4.3.3", "", { "dependencies": { "oniguruma-parser": "^0.12.1", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg=="], - "oxlint": ["oxlint@1.28.0", "", { "optionalDependencies": { "@oxlint/darwin-arm64": "1.28.0", "@oxlint/darwin-x64": "1.28.0", "@oxlint/linux-arm64-gnu": "1.28.0", "@oxlint/linux-arm64-musl": "1.28.0", "@oxlint/linux-x64-gnu": "1.28.0", "@oxlint/linux-x64-musl": "1.28.0", "@oxlint/win32-arm64": "1.28.0", "@oxlint/win32-x64": "1.28.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.4.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint", "oxc_language_server": "bin/oxc_language_server" } }, "sha512-gE97d0BcIlTTSJrim395B49mIbQ9VO8ZVoHdWai7Svl+lEeUAyCLTN4d7piw1kcB8VfgTp1JFVlAvMPD9GewMA=="], - "package-manager-detector": ["package-manager-detector@1.5.0", "", {}, "sha512-uBj69dVlYe/+wxj8JOpr97XfsxH/eumMt6HqjNTmJDf/6NO9s+0uxeOneIz3AsPt2m6y9PqzDzd3ATcU17MNfw=="], "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], @@ -501,6 +483,8 @@ "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], + "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], diff --git a/desktop/src/App.vue b/desktop/src/App.vue index add7352..146e49c 100644 --- a/desktop/src/App.vue +++ b/desktop/src/App.vue @@ -79,7 +79,7 @@ onMounted(async () => { console.log('Initializing database:', dbPath); db = await Database.load(dbPath); console.log('Database loaded:', db); - + // Create table if it doesn't exist await db.execute(` CREATE TABLE IF NOT EXISTS notes ( @@ -89,7 +89,7 @@ onMounted(async () => { ) `); console.log('Table created/verified'); - + await loadNotes(); console.log('Notes loaded, count:', notes.value.length); } catch (error) { @@ -99,15 +99,18 @@ onMounted(async () => { const loadNotes = async () => { try { - const result: Array<{ id: number; content: string; created_at: string }> = await db.select( - 'SELECT id, content, created_at FROM notes ORDER BY created_at DESC' + const result: Array<{ id: number; content: string; created_at: string }> = + await db.select( + 'SELECT id, content, created_at FROM notes ORDER BY created_at DESC', + ); + + notes.value = result.map( + (note: { id: number; content: string; created_at: string }) => ({ + id: note.id, + content: note.content, + createdAt: new Date(note.created_at), + }), ); - - notes.value = result.map((note: { id: number; content: string; created_at: string }) => ({ - id: note.id, - content: note.content, - createdAt: new Date(note.created_at) - })); } catch (error) { console.error('Failed to load notes:', error); } @@ -117,7 +120,7 @@ const loadNotes = async () => { const extractTags = (content: string): string[] => { const tagRegex = /#(\w+)/g; const matches = content.matchAll(tagRegex); - return Array.from(matches, m => m[1].toLowerCase()); + return Array.from(matches, (m) => m[1].toLowerCase()); }; // Fuse.js configuration for fuzzy search @@ -131,31 +134,33 @@ const fuseOptions = { const filteredNotes = computed(() => { let filtered = notes.value; - + // Filter by search query using Fuse.js fuzzy search if (searchQuery.value.trim()) { const fuse = new Fuse(filtered, fuseOptions); const results = fuse.search(searchQuery.value); - filtered = results.map(result => result.item); + filtered = results.map((result) => result.item); } - + // Filter by date if (selectedDate.value) { - filtered = filtered.filter(note => { + filtered = filtered.filter((note) => { const noteDate = new Date(note.createdAt); return noteDate.toDateString() === selectedDate.value!.toDateString(); }); } - + // Filter by tags (AND logic - note must have ALL selected tags) if (selectedTags.value.length > 0) { - filtered = filtered.filter(note => { + filtered = filtered.filter((note) => { const tags = extractTags(note.content); // Check if note has ALL selected tags - return selectedTags.value.every(selectedTag => tags.includes(selectedTag)); + return selectedTags.value.every((selectedTag) => + tags.includes(selectedTag), + ); }); } - + return filtered; }); @@ -169,16 +174,20 @@ const hasMoreNotes = computed(() => { }); // Reset displayed count when filters change -watch([searchQuery, selectedDate, selectedTags], () => { - displayedNotesCount.value = NOTES_PER_PAGE; -}, { deep: true }); +watch( + [searchQuery, selectedDate, selectedTags], + () => { + displayedNotesCount.value = NOTES_PER_PAGE; + }, + { deep: true }, +); // Infinite scroll handler const handleScroll = (event: Event) => { const target = event.target as HTMLElement; const scrollPosition = target.scrollTop + target.clientHeight; const scrollHeight = target.scrollHeight; - + // Load more when user is within 200px of the bottom if (scrollHeight - scrollPosition < 200 && hasMoreNotes.value) { displayedNotesCount.value += NOTES_PER_PAGE; @@ -191,25 +200,25 @@ const createNote = async (content: string) => { console.error('Database not initialized'); return; } - + const now = new Date().toISOString(); - + console.log('Creating note with content:', content); - + const result = await db.execute( 'INSERT INTO notes (content, created_at) VALUES ($1, $2)', - [content, now] + [content, now], ); - + console.log('Insert result:', result); - + // Add to local array notes.value.unshift({ id: result.lastInsertId, content, - createdAt: new Date(now) + createdAt: new Date(now), }); - + console.log('Note created successfully'); } catch (error) { console.error('Failed to create note:', error); @@ -219,7 +228,7 @@ const createNote = async (content: string) => { const deleteNote = async (id: number) => { try { await db.execute('DELETE FROM notes WHERE id = $1', [id]); - notes.value = notes.value.filter(note => note.id !== id); + notes.value = notes.value.filter((note) => note.id !== id); } catch (error) { console.error('Failed to delete note:', error); } @@ -227,12 +236,12 @@ const deleteNote = async (id: number) => { const editNote = async (id: number, content: string) => { try { - await db.execute( - 'UPDATE notes SET content = $1 WHERE id = $2', - [content, id] - ); - - const note = notes.value.find(n => n.id === id); + await db.execute('UPDATE notes SET content = $1 WHERE id = $2', [ + content, + id, + ]); + + const note = notes.value.find((n) => n.id === id); if (note) { note.content = content; } @@ -245,11 +254,10 @@ const editNote = async (id: number, content: string) => {