Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
0d0cda6
fix: resolve real project ID before creating onboarding task
h4yfans Mar 19, 2026
628e21f
feat(settings): add shortcuts section and expand editor settings UI
h4yfans Mar 19, 2026
5d7a022
feat(settings): implement account section (T029-T033)
h4yfans Mar 19, 2026
9fc5185
feat(settings): implement recovery key dialog (T034-T036)
h4yfans Mar 19, 2026
bc4540e
feat(settings): add global capture shortcut configuration
h4yfans Mar 19, 2026
bf87e01
fix(ci): regenerate IPC invoke map and fix account-handlers test mock
h4yfans Mar 19, 2026
dcc1930
perf: reduce cold-start time by parallelizing vault open with window …
h4yfans Mar 19, 2026
e967b9a
chore(ipc): update generated-ipc-invoke-map with current ts-printer f…
h4yfans Mar 19, 2026
103ebd6
perf: optimize startup I/O and large-vault indexing speed
h4yfans Mar 19, 2026
6024ec0
feat(a11y): WCAG 2.1 AA accessibility pass — keyboard nav, ARIA, focu…
h4yfans Mar 19, 2026
3f0bb37
feat(undo): add removeUndoEntry for double-fire prevention
h4yfans Mar 19, 2026
8106723
feat(undo): add Cmd+Z undo for all task CRUD and bulk operations
h4yfans Mar 19, 2026
fc1d6c3
refactor(tasks): wire task handlers to useUndoableTaskActions
h4yfans Mar 19, 2026
7af2034
chore: remove calendar view feature
h4yfans Mar 20, 2026
8efe6ea
chore: remove stale items feature
h4yfans Mar 20, 2026
06c92f5
feat(ui): add PageToolbar and Pill primitives
h4yfans Mar 20, 2026
7a9fba7
refactor(tasks): migrate design tokens and normalize typography
h4yfans Mar 20, 2026
2872836
feat(inbox): redesign inbox with toolbar, filters, and search
h4yfans Mar 20, 2026
baf7869
feat(capture): add compact mode and streamline layout
h4yfans Mar 20, 2026
567edfa
fix: add error toasts, a11y attributes, and polish misc components
h4yfans Mar 20, 2026
d54a217
chore(ipc): regenerate invoke map with current handler signatures
h4yfans Mar 20, 2026
ca9b2df
feat(theme): wire accent color setting to UI via tint CSS variables
h4yfans Mar 21, 2026
784d605
feat(settings): sync accent color across devices and prevent startup …
h4yfans Mar 21, 2026
6cfc829
feat(icons): add HugeIcons rendering infrastructure
h4yfans Mar 22, 2026
4be5e4f
feat(inbox): implement real capture patterns query
h4yfans Mar 22, 2026
b78f260
chore: remove inbox bankruptcy feature
h4yfans Mar 22, 2026
5ee5e60
feat(folders): polish tree component and add folder icon support
h4yfans Mar 22, 2026
75b7af1
feat(folders): add folder icon picker and NoteIconDisplay across UI
h4yfans Mar 22, 2026
d1cf7de
feat(inbox): redesign detail panel, archived view, list, and bulk bar
h4yfans Mar 22, 2026
a83a367
refactor(ui): simplify Input focus ring to border-only
h4yfans Mar 22, 2026
d903c9d
feat(inbox): polish detail panel with LinkPreview, inline filing, and…
h4yfans Mar 22, 2026
9319e34
refactor(inbox): extract DetailHeader and NoteDetail from detail panel
h4yfans Mar 22, 2026
f2f3078
refactor(inbox): simplify reminder TypeIcon and remove isViewed prop
h4yfans Mar 22, 2026
241a4cd
fix(tags): cast counts to Number and prune orphaned definitions
h4yfans Mar 23, 2026
de422ba
refactor(social): remove unused non-Twitter platform support
h4yfans Mar 23, 2026
f95ac8a
feat(inbox): add live title extraction, compact dates, and PDF icon
h4yfans Mar 23, 2026
24248bf
refactor(sidebar): use NoteIconDisplay and simplify task count badge
h4yfans Mar 23, 2026
8cfcc8c
fix(graph): guard nodeSummary memo against null graph data
h4yfans Mar 23, 2026
f96bd0e
style(ui): update dark theme to neutral charcoal and standardize bord…
h4yfans Mar 23, 2026
759f90a
feat(contracts): add tweetId to SocialMetadata type
h4yfans Mar 23, 2026
92f2cd1
refactor(social): replace server-side fetch with synchronous URL parsing
h4yfans Mar 23, 2026
40e65a1
build(desktop): add react-tweet and update CSP for Twitter embeds
h4yfans Mar 23, 2026
f62f81c
feat(inbox): add TweetCard component for embedded tweet rendering
h4yfans Mar 23, 2026
2cf38a0
feat(inbox): add ReminderDetail and wire content routing
h4yfans Mar 23, 2026
c628828
feat(inbox): add titleFromUrl and isBotPageTitle utilities
h4yfans Mar 23, 2026
ce1e332
fix(inbox): map metascraper fields to LinkMetadata and use slug titles
h4yfans Mar 23, 2026
bfe81a2
feat(inbox): redesign LinkPreview with hero image and domain bar
h4yfans Mar 23, 2026
f613523
fix(inbox): remove auto-link first suggested note on filing
h4yfans Mar 23, 2026
80f65af
feat(transcription): auto-title voice memos from first sentence
h4yfans Mar 24, 2026
82393f1
feat(inbox): add formatTimeAgo utility, new icons, and social-card ex…
h4yfans Mar 24, 2026
cf6c4cf
feat(inbox): add link preview IPC and quick-capture resize pipeline
h4yfans Mar 24, 2026
285f250
refactor(inbox): replace custom toast with Sonner and redesign empty …
h4yfans Mar 24, 2026
74c971d
feat(inbox): redesign quick capture with sub-components
h4yfans Mar 24, 2026
9245a2b
feat(inbox): redesign triage mode with inline filing panel
h4yfans Mar 24, 2026
0f2982a
feat(inbox): add waveform visualizer and redesign content section
h4yfans Mar 24, 2026
130813e
style(desktop): polish sidebar, vault switcher, and voice recorder
h4yfans Mar 24, 2026
34cd144
chore: add metascraper test script
h4yfans Mar 24, 2026
ab15103
style(inbox): use ArrowTurnBackward icon and accent color CSS variable
h4yfans Mar 24, 2026
0b4e8cc
style(desktop): replace per-component focus rings with global reset
h4yfans Mar 24, 2026
9784f0e
feat(desktop): add Gelasio, Geist, and Inter font families
h4yfans Mar 24, 2026
d6a1f11
refactor(settings): extract shared primitives and redesign all pages
h4yfans Mar 24, 2026
ee53f21
style(sync): redesign sync components and auth wizard
h4yfans Mar 24, 2026
eceb5df
style(desktop): polish vault switcher, tag manager, and integration list
h4yfans Mar 24, 2026
e1af7cf
chore(desktop): set app icon and regenerate IPC types
h4yfans Mar 24, 2026
7025ba4
chore: add icon generation script, favicon, and agents doc
h4yfans Mar 24, 2026
c72a261
style(sync): redesign QR device linking dialog
h4yfans Mar 24, 2026
36e07a6
refactor(settings): merge sync section into account section
h4yfans Mar 24, 2026
00e82ee
style(sync): polish sync component typography and layouts
h4yfans Mar 24, 2026
9c89c08
feat(vault): add vault:reveal IPC to open folder in Finder
h4yfans Mar 24, 2026
2260e07
style(tasks): rework project dropdown for keyboard accessibility
h4yfans Mar 24, 2026
85dc07e
style(icons): add gradient border and drop shadow to app icon
h4yfans Mar 24, 2026
ae8cb20
fix: update email sender domain and wizard step mapping
h4yfans Mar 24, 2026
4aefd92
test: update mocks and assertions for current API surface
h4yfans Mar 24, 2026
220de70
docs: add desktop polish changelog entry
h4yfans Mar 24, 2026
1124394
fix(deps): override undici and flatted for security audit
h4yfans Mar 24, 2026
8a3616d
chore(ipc): regenerate invoke map with updated printer format
h4yfans Mar 24, 2026
d4b86eb
fix: guard app.dock access for non-macOS platforms
h4yfans Mar 24, 2026
6b930bf
fix: resolve web typecheck errors in vault, tweet, and content types
h4yfans Mar 24, 2026
525258f
fix: add reveal method to vault service stub
h4yfans Mar 24, 2026
685de51
test: update email test to match memrynote.com sender domain
h4yfans Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions AGENTS.md
38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,44 @@ Format: weekly entries grouped by feature area.

---

## 2026-03-25 — Desktop Polish

### Added
- Add inbox redesign with toolbar, filters, triage mode, link previews, and waveform visualizer
- Add embedded tweet rendering with TweetCard component
- Add reminder detail view with content routing
- Add live URL title extraction and bot-page-title detection
- Auto-title voice memos from first transcribed sentence
- Add folder icon picker and NoteIconDisplay across tree and sidebar
- Add HugeIcons rendering infrastructure
- Sync accent color across devices with tint CSS variables
- Add compact capture mode
- Add PageToolbar and Pill UI primitives
- Add Cmd+Z undo for all task CRUD and bulk operations
- Add WCAG 2.1 AA accessibility pass — keyboard nav, ARIA, focus indicators
- Add account section, recovery key dialog, shortcuts section, and capture shortcut to settings
- Add Gelasio, Geist, and Inter font families

### Fixed
- Fix inbox filing auto-link and metascraper field mapping
- Fix graph crash on null node data
- Fix tag count casting and prune orphaned definitions
- Fix project ID resolution before creating onboarding task

### Changed
- Extract shared settings primitives and redesign all settings pages
- Replace custom toast notifications with Sonner
- Remove non-Twitter platform support and simplify social URL parsing
- Simplify sidebar with NoteIconDisplay and compact task count
- Extract DetailHeader and simplify reminder TypeIcon
- Migrate task design tokens and wire undoable task actions

### Performance
- Parallelize vault open with window creation to reduce cold-start time
- Optimize startup I/O and large-vault indexing speed

---

## 2026-03-19 — Tasks Refinement

### Added
Expand Down
7 changes: 6 additions & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@
"test:component": "vitest run --config config/vitest.config.ts tests/component",
"test:e2e": "playwright test --config config/playwright.config.ts",
"ipc:generate": "node scripts/generate-ipc-invoke-map.js",
"ipc:check": "node scripts/generate-ipc-invoke-map.js --check"
"ipc:check": "node scripts/generate-ipc-invoke-map.js --check",
"generate:icons": "node scripts/generate-icons.mjs"
},
"dependencies": {
"@ai-sdk/anthropic": "^3.0.58",
Expand Down Expand Up @@ -186,6 +187,7 @@
"react-day-picker": "^9.13.0",
"react-pdf": "^10.3.0",
"react-player": "^3.4.0",
"react-tweet": "^3.3.0",
"sharp": "0.34.5",
"sigma": "^3.0.2",
"sodium-native": "^5.0.10",
Expand All @@ -209,9 +211,12 @@
"@electron/rebuild": "^4.0.3",
"@fontsource-variable/crimson-pro": "^5.2.8",
"@fontsource-variable/dm-sans": "^5.2.8",
"@fontsource-variable/geist": "^5.2.8",
"@fontsource-variable/inter": "^5.2.8",
"@fontsource-variable/jetbrains-mono": "^5.2.8",
"@fontsource-variable/playfair-display": "^5.2.8",
"@fontsource-variable/space-grotesk": "^5.2.10",
"@fontsource/gelasio": "^5.2.8",
"@fontsource/instrument-serif": "^5.2.8",
"@playwright/test": "^1.57.0",
"@testing-library/jest-dom": "^6.9.1",
Expand Down
171 changes: 171 additions & 0 deletions apps/desktop/scripts/generate-icons.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import { execFileSync } from 'node:child_process'
import { mkdirSync, rmSync, writeFileSync } from 'node:fs'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import sharp from 'sharp'

const __dirname = dirname(fileURLToPath(import.meta.url))
const BUILD_DIR = join(__dirname, '..', 'build')

const ICON_SVG = `<?xml version="1.0" encoding="UTF-8"?>
<svg width="1024" height="1024" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="bg" x1="50" y1="10" x2="50" y2="90" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#2a2a2a"/>
<stop offset="1" stop-color="#111111"/>
</linearGradient>
<linearGradient id="topShine" x1="50" y1="10" x2="50" y2="30" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#ffffff" stop-opacity="0.12"/>
<stop offset="1" stop-color="#ffffff" stop-opacity="0"/>
</linearGradient>
<linearGradient id="borderGrad" x1="50" y1="10" x2="50" y2="90" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#ffffff" stop-opacity="0.15"/>
<stop offset="1" stop-color="#000000" stop-opacity="0.3"/>
</linearGradient>
<filter id="logoShadow" x="-10%" y="-10%" width="130%" height="130%">
<feDropShadow dx="0" dy="1.5" stdDeviation="1.8" flood-color="#000000" flood-opacity="0.55"/>
</filter>
<filter id="cardShadow" x="-5%" y="-5%" width="115%" height="118%">
<feDropShadow dx="0" dy="1.5" stdDeviation="2" flood-color="#000000" flood-opacity="0.4"/>
</filter>

<linearGradient id="borderTop" x1="10" y1="10" x2="90" y2="10" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#4a9e8e"/>
<stop offset="0.5" stop-color="#6366f1"/>
<stop offset="1" stop-color="#8b5cf6"/>
</linearGradient>
<linearGradient id="borderRight" x1="90" y1="10" x2="90" y2="90" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#8b5cf6"/>
<stop offset="1" stop-color="#d4944a"/>
</linearGradient>
<linearGradient id="borderBottom" x1="90" y1="90" x2="10" y2="90" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#d4944a"/>
<stop offset="0.5" stop-color="#d4944a"/>
<stop offset="1" stop-color="#4a9e8e"/>
</linearGradient>
<linearGradient id="borderLeft" x1="10" y1="90" x2="10" y2="10" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#4a9e8e"/>
<stop offset="1" stop-color="#4a9e8e"/>
</linearGradient>
<mask id="topMask"><rect x="10" y="8" width="80" height="20" fill="white"/></mask>
<mask id="rightMask"><rect x="70" y="10" width="22" height="80" fill="white"/></mask>
<mask id="bottomMask"><rect x="10" y="72" width="80" height="20" fill="white"/></mask>
<mask id="leftMask"><rect x="8" y="10" width="20" height="80" fill="white"/></mask>
</defs>

<rect x="10" y="10" width="80" height="80" rx="16" ry="16" fill="url(#bg)" filter="url(#cardShadow)"/>
<rect x="10" y="10" width="80" height="80" rx="16" ry="16" fill="none" stroke="url(#borderGrad)" stroke-width="0.8"/>
<rect x="10" y="10" width="80" height="20" rx="16" ry="16" fill="url(#topShine)"/>

<rect x="10" y="10" width="80" height="80" rx="16" ry="16" fill="none" stroke="url(#borderTop)" stroke-width="1.5" mask="url(#topMask)"/>
<rect x="10" y="10" width="80" height="80" rx="16" ry="16" fill="none" stroke="url(#borderRight)" stroke-width="1.5" mask="url(#rightMask)"/>
<rect x="10" y="10" width="80" height="80" rx="16" ry="16" fill="none" stroke="url(#borderBottom)" stroke-width="1.5" mask="url(#bottomMask)"/>
<rect x="10" y="10" width="80" height="80" rx="16" ry="16" fill="none" stroke="url(#borderLeft)" stroke-width="1.5" mask="url(#leftMask)"/>

<g transform="translate(10, 10) scale(0.8)" filter="url(#logoShadow)">
<path d="M20 70 L20 30 L35 45 L50 25 L65 45 L80 30 L80 70 L50 70"
stroke="#FFFFFF" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
<path d="M50 70 L50 85 L80 70"
stroke="#FFFFFF" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
</g>
</svg>`

const ICONSET_SIZES = [
{ name: 'icon_16x16.png', size: 16 },
{ name: 'icon_16x16@2x.png', size: 32 },
{ name: 'icon_32x32.png', size: 32 },
{ name: 'icon_32x32@2x.png', size: 64 },
{ name: 'icon_128x128.png', size: 128 },
{ name: 'icon_128x128@2x.png', size: 256 },
{ name: 'icon_256x256.png', size: 256 },
{ name: 'icon_256x256@2x.png', size: 512 },
{ name: 'icon_512x512.png', size: 512 },
{ name: 'icon_512x512@2x.png', size: 1024 }
]

const ICO_SIZES = [16, 32, 48, 64, 128, 256]

async function renderPng(size) {
return sharp(Buffer.from(ICON_SVG)).resize(size, size).png().toBuffer()
}

function buildIco(pngBuffers, sizes) {
const headerSize = 6
const dirEntrySize = 16
const dirSize = dirEntrySize * pngBuffers.length
let dataOffset = headerSize + dirSize

const header = Buffer.alloc(headerSize)
header.writeUInt16LE(0, 0)
header.writeUInt16LE(1, 2)
header.writeUInt16LE(pngBuffers.length, 4)

const dirEntries = []
const offsets = []
for (let i = 0; i < pngBuffers.length; i++) {
offsets.push(dataOffset)
dataOffset += pngBuffers[i].length
}

for (let i = 0; i < pngBuffers.length; i++) {
const entry = Buffer.alloc(dirEntrySize)
entry.writeUInt8(sizes[i] >= 256 ? 0 : sizes[i], 0)
entry.writeUInt8(sizes[i] >= 256 ? 0 : sizes[i], 1)
entry.writeUInt8(0, 2)
entry.writeUInt8(0, 3)
entry.writeUInt16LE(1, 4)
entry.writeUInt16LE(32, 6)
entry.writeUInt32LE(pngBuffers[i].length, 8)
entry.writeUInt32LE(offsets[i], 12)
dirEntries.push(entry)
}

return Buffer.concat([header, ...dirEntries, ...pngBuffers])
}

async function generateIcns() {
if (process.platform !== 'darwin') {
console.warn(' [skip] .icns generation requires macOS (iconutil)')
return
}

const iconsetDir = join(BUILD_DIR, 'icon.iconset')
mkdirSync(iconsetDir, { recursive: true })

await Promise.all(
ICONSET_SIZES.map(async ({ name, size }) => {
const buf = await renderPng(size)
writeFileSync(join(iconsetDir, name), buf)
})
)

const output = join(BUILD_DIR, 'icon.icns')
execFileSync('iconutil', ['-c', 'icns', '-o', output, iconsetDir])
rmSync(iconsetDir, { recursive: true })
console.log(' icon.icns')
}

async function generateIco() {
const pngBuffers = await Promise.all(ICO_SIZES.map((s) => renderPng(s)))
const ico = buildIco(pngBuffers, ICO_SIZES)
writeFileSync(join(BUILD_DIR, 'icon.ico'), ico)
console.log(' icon.ico')
}

async function generatePng() {
const buf = await renderPng(1024)
writeFileSync(join(BUILD_DIR, 'icon.png'), buf)
console.log(' icon.png')
}

async function main() {
mkdirSync(BUILD_DIR, { recursive: true })
console.log('Generating app icons...')
await Promise.all([generateIcns(), generateIco(), generatePng()])
console.log('Done.')
}

main().catch((err) => {
console.error('Icon generation failed:', err)
process.exit(1)
})
Loading
Loading