Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions AUDIT_LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@

This log tracks all significant changes, updates, and versions in the PaperCache project.

## 2026-06-28 (v0.5.6 Release: Keybinds Modal, Shortcut Mappings, Timer Auto-Delete, and Graph Link Refinement)
**Change:** chore(release): bump version to 0.5.6; feat(shortcuts): add dedicated keybinds settings modal and update global hotkeys (`Cmd+R` for tasks, `Cmd+T` for timers); feat(timers): auto-delete expired timers after 5 seconds; feat(graph): support standard markdown links and wikilinks

**Details/Why:**
1. **Version Bump**: Bumped application version to 0.5.6 across `package.json`, `Cargo.toml`, `tauri.conf.json`, and added release notes file `New Features in v0.5.6.md`.
2. **Keybinds Settings Panel**: Created `ShortcutInput.tsx` as a shared component and `KeybindsModal.tsx` as a dedicated settings panel for remapping shortcuts, accessible via Settings. Added new storage keys in `settingsKeys.ts` and updated `useGlobalHotkey.ts` to dynamically match keyboard events against customizable shortcut settings. Refined UI layout so keycaps are centered horizontally and the container/buttons match the main Settings window.
3. **Keybind Updates**: Updated default shortcuts so `Cmd+R` opens Tasks/Reminders and `Cmd+T` opens the countdown Timers panel, aligning with user navigation habits. Preserved cleared shortcuts via `getShortcut` helper distinguishing `null` from `''`. Dynamically generated the shortcuts reference note (`Cmd+/`) and added recording guards in `useGlobalHotkey.ts` and `ShortcutInput.tsx`. Persisted toggle shortcut changes in `Settings.tsx`.
4. **Timer Auto-Deletion**: Updated `useTimerStore.ts` and `App.tsx` so that when a countdown timer completes, it schedules a targeted 5-second `setTimeout` to call `removeTimer(id)`, reducing UI clutter. Moved backend `timer-complete` event listener to `App.tsx` with robust late-resolution cleanup tracking so completion notifications and auto-cleanup function globally even when the panel is closed or unmounted.
5. **Graph View Link Parsing**: Expanded regex detection in `GraphView.tsx` to link notes using standard markdown links (`[Title](Title.md)`) and wikilinks (`[[Title]]`, stripping aliases like `[[Title|Display]]`) in addition to `/file` links, and removed unused `cz` centroid force values to keep layout logic consistent.

**Files changed:** `package.json`, `src-tauri/Cargo.toml`, `src-tauri/tauri.conf.json`, `notes/New Features in v0.5.6.md`, `src/lib/settingsKeys.ts`, `src/components/ShortcutInput.tsx`, `src/components/KeybindsModal.tsx`, `src/store/useAppStore.ts`, `src/App.tsx`, `src/Settings.tsx`, `src/hooks/useGlobalHotkey.ts`, `src/store/useTimerStore.ts`, `src/components/TimersPage.tsx`, `src/GraphView.tsx`, `CHANGELOG.md`, `AUDIT_LOG.md`.

---

## 2026-06-27 (API Key Persistence & Graph View Fixes)
**Change:** fix(ai): fix API key saving/clearing logic and macOS keychain credential updating; fix(graph): prevent `fg.graphData` crashes when opening or closing Graph View

Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ All notable, user-facing changes to PaperCache will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [v0.5.6] - 2026-06-28

### Added
- **Dedicated Keybinds Settings Panel**: Added a sleek, high-contrast dark modal accessible from Settings (`Cmd+Shift+S`) to view and remap all application shortcuts with live recording. Designed with rich typography, glassmorphic cards, and fixed-width input buttons for perfectly vertically aligned shortcut columns.

### Changed
- **Updated Default Shortcut Mappings**: Shifted the Reminders/Tasks view shortcut to `Cmd+R` and Timers panel shortcut to `Cmd+T`.
- **Timer Auto-Deletion**: Expired countdown timers are now automatically removed from the active list 5 seconds after completing, keeping the UI clean. Timer completion notifications and auto-cleanup now function globally even when the Timers panel is closed.
- **Enhanced Graph View Link Parsing**: Extended 3D Graph View link detection to support standard markdown links (`[Note](Note.md)`) and wikilinks (`[[Note]]`) alongside the existing `/file` syntax, and added z-axis forces for improved 3D layout stability.

## [v0.5.5] - 2026-06-27

### Added
Expand Down
11 changes: 11 additions & 0 deletions notes/New Features in v0.5.6.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# New Features in v0.5.6

Welcome to PaperCache v0.5.6!

Here are the new features and improvements implemented in this release:
- **Dedicated Keybinds Settings Panel**: Added a dedicated modal accessible from Settings (`Cmd+Shift+S`) to view and remap all application shortcuts with live keyboard shortcut recording. Designed with rich typography, centered 3D keycaps, and uniform layouts that seamlessly unify with the main Settings panel.
- **Updated Default Shortcut Mappings**: Shifted the Reminders/Tasks view shortcut to `Cmd+R` and open Timers panel shortcut to `Cmd+T` for faster, ergonomic navigation.
- **Automatic Timer Cleanup**: Completed countdown timers are now automatically removed from the active list 5 seconds after expiration, keeping your workspace uncluttered. Timer completion notifications and auto-cleanup function globally even when the Timers panel is closed.
- **Expanded Graph View Link Detection**: Extended 3D Graph View link parsing to support standard markdown links (`[Note](Note.md)`) and wikilinks (`[[Note]]`) alongside `/file` links, with enhanced z-axis centering forces for improved 3D layout stability.

*(If you have read this note, feel free to delete it)*
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "papercache",
"private": true,
"version": "0.5.5",
"version": "0.5.6",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "papercache"
version = "0.5.5"
version = "0.5.6"
description = "A PaperCache Tauri App"
authors = ["Aditya Sharma"]
edition = "2021"
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/2.0.0/tauri.schema.json",
"productName": "PaperCache",
"version": "0.5.5",
"version": "0.5.6",
"identifier": "com.variablethe.papercache",
"build": {
"beforeDevCommand": "npm run dev",
Expand Down
46 changes: 45 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ import './App.css'
const GraphView = lazy(() => import('./GraphView'))
import { RemindersPage } from './components/RemindersPage'
import { TimersPage } from './components/TimersPage'
import { KeybindsModal } from './components/KeybindsModal'

import { useAppStore } from './store/useAppStore'
import { useSettingsStore } from './store/useSettingsStore'
import { useTimerStore } from './store/useTimerStore'
import { listen } from '@tauri-apps/api/event'

import { useNoteStorage } from './hooks/useNoteStorage'
import { useVariables } from './hooks/useVariables'
Expand Down Expand Up @@ -37,6 +40,8 @@ function App() {
const setShowMainActionMenu = useAppStore((state) => state.setShowMainActionMenu)
const showSettingsModal = useAppStore((state) => state.showSettingsModal)
const setShowSettingsModal = useAppStore((state) => state.setShowSettingsModal)
const showKeybindsModal = useAppStore((state) => state.showKeybindsModal)
const setShowKeybindsModal = useAppStore((state) => state.setShowKeybindsModal)

const { themePreset, fontFamily, showRulings, bgType, bgColor, bgImage, textColor, numColor } =
useSettingsStore()
Expand Down Expand Up @@ -65,8 +70,27 @@ function App() {
type: 'info',
})
})

useTimerStore.getState().cleanExpiredTimers()

let unlistenTimer: (() => void) | undefined
let isUnmounted = false
listen<string>('timer-complete', (event) => {
const id = event.payload
useTimerStore.getState().completeTimer(id)
const t = useTimerStore.getState().timers.find((x) => x.id === id)
useAppStore
.getState()
.addToast({ message: `⏱ Timer done: ${t?.label || ''}`, type: 'success' })
}).then((fn) => {
if (isUnmounted) fn()
else unlistenTimer = fn
})

return () => {
isUnmounted = true
disposeUpdateReady()
unlistenTimer?.()
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
}, [])

Expand Down Expand Up @@ -231,7 +255,8 @@ function App() {
left: 0,
right: 0,
bottom: 0,
backgroundColor: bgType === 'color' ? bgColor : '#1a1a1a',
backgroundColor: 'rgba(0, 0, 0, 0.75)',
backdropFilter: 'blur(5px)',
zIndex: 9999,
overflow: 'auto',
}}
Expand All @@ -240,6 +265,25 @@ function App() {
</div>
)}

{showKeybindsModal && (
<div
onClick={(e) => e.stopPropagation()}
style={{
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0, 0, 0, 0.75)',
backdropFilter: 'blur(5px)',
zIndex: 10000,
overflow: 'auto',
}}
>
<KeybindsModal onClose={() => setShowKeybindsModal(false)} />
</div>
)}

{/* In-app toast notifications */}
{toasts.length > 0 && (
<div
Expand Down
32 changes: 28 additions & 4 deletions src/GraphView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,39 @@ export default function GraphView({
const nodeIds = new Set(nodes.map((n) => n.id))

notes.forEach((note) => {
const re = /\]\(\/file\s+([^)]+)\)/g
const targets = new Set<string>()

// 1. Match ](/file <path>)
const reFile = /\]\(\/file\s+([^)]+)\)/g
let match
while ((match = re.exec(note.content)) !== null) {
while ((match = reFile.exec(note.content)) !== null) {
let targetId = match[1].trim().replace(/\\/g, '/')
if (!targetId.endsWith('.md')) targetId += '.md'
if (nodeIds.has(targetId)) {
targets.add(targetId)
}

// 2. Match ](<path>.md)
const reMd = /\]\(([^)]+\.md)\)/g
while ((match = reMd.exec(note.content)) !== null) {
let targetId = match[1].trim().replace(/\\/g, '/')
if (targetId.startsWith('./')) targetId = targetId.slice(2)
if (targetId.startsWith('/')) targetId = targetId.slice(1)
targets.add(targetId)
}

// 3. Match [[<title>]]
const reWiki = /\[\[([^\]]+)\]\]/g
while ((match = reWiki.exec(note.content)) !== null) {
let targetId = match[1].split('|')[0].trim().replace(/\\/g, '/')
if (!targetId.endsWith('.md')) targetId += '.md'
targets.add(targetId)
}

targets.forEach((targetId) => {
if (nodeIds.has(targetId) && targetId !== note.id) {
links.push({ source: note.id, target: targetId })
}
}
})
})

return { nodes, links }
Expand Down
Loading
Loading