Add keyboard mode toggle and QR scanner improvements

- Add keyboard mode toggle button (⇧K) in sidebar
- Triple-Escape to quickly exit keyboard mode
- Extract QrScannerModal to shared component
- Add QR scanner for NWC wallet connection in Settings
- Update Help page with keyboard toggle documentation
- Fix keyboard navigation getting stuck on inbox
- Improve feed loading after login (loads immediately)
- DM conversation page layout improvements

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
woikos
2026-01-04 11:08:06 +01:00
parent 4c3e8d5cc7
commit d1ec24b85a
16 changed files with 1224 additions and 476 deletions

View File

@@ -23,15 +23,33 @@ export default function Help() {
<AccordionContent className="pb-4">
<div className="space-y-4 text-sm text-muted-foreground">
<p>{t('Navigate the app entirely with your keyboard:')}</p>
<p className="font-medium">{t('Toggle Keyboard Mode:')}</p>
<div className="space-y-2">
<KeyBinding keys={['Arrow Up', 'Arrow Down']} description={t('Move between items in a list')} />
<KeyBinding keys={['Arrow Left', 'Arrow Right']} description={t('Switch between columns (sidebar, feed, detail)')} />
<KeyBinding keys={['Enter']} description={t('Open or activate the selected item')} />
<KeyBinding keys={['Escape']} description={t('Close current view or go to sidebar')} />
<KeyBinding keys={['Backspace']} description={t('Go back to previous view')} />
<KeyBinding keys={['Page Up', 'Page Down']} description={t('Jump to top or bottom of list')} />
<KeyBinding keys={['Tab']} description={t('Cycle through note actions (reply, repost, quote, react, zap)')} />
<KeyBinding keys={['⇧K']} description={t('Toggle keyboard navigation on/off')} />
<KeyBinding keys={['Esc', 'Esc', 'Esc']} description={t('Triple-Escape to quickly exit keyboard mode')} />
</div>
<p className="text-xs opacity-70">{t('You can also click the keyboard button in the sidebar to toggle.')}</p>
<p className="font-medium mt-4">{t('Movement:')}</p>
<div className="space-y-2">
<KeyBinding keys={['↑', '↓']} altKeys={['k', 'j']} description={t('Move between items in a list')} />
<KeyBinding keys={['Tab']} description={t('Switch to next column (Shift+Tab for previous)')} />
<KeyBinding keys={['Page Up', 'Page Down']} description={t('Jump to top or bottom of list')} />
</div>
<p className="font-medium mt-4">{t('Actions:')}</p>
<div className="space-y-2">
<KeyBinding keys={['→', 'Enter']} altKeys={['l']} description={t('Activate the selected item')} />
<KeyBinding keys={['←']} altKeys={['h']} description={t('Go back (close panel or move to sidebar)')} />
<KeyBinding keys={['Escape']} description={t('Close current view or cancel')} />
</div>
<p className="font-medium mt-4">{t('Note Actions (when a note is selected):')}</p>
<div className="space-y-2">
<KeyBinding keys={['r']} description={t('Reply')} />
<KeyBinding keys={['p']} description={t('Repost')} />
<KeyBinding keys={['q']} description={t('Quote')} />
<KeyBinding keys={['R']} description={t('React with emoji')} />
<KeyBinding keys={['z']} description={t('Zap (send sats)')} />
</div>
<p className="text-xs opacity-70 pt-2">{t('Selected items are centered on screen for easy viewing.')}</p>
</div>
</AccordionContent>
</AccordionItem>
@@ -156,18 +174,33 @@ export default function Help() {
)
}
function KeyBinding({ keys, description }: { keys: string[]; description: string }) {
function KeyBinding({
keys,
altKeys,
description
}: {
keys: string[]
altKeys?: string[]
description: string
}) {
return (
<div className="flex items-center gap-3">
<div className="flex gap-1">
<div className="flex items-center gap-1">
{keys.map((key) => (
<kbd
key={key}
className="px-2 py-1 text-xs font-mono bg-muted border rounded"
>
<kbd key={key} className="px-2 py-1 text-xs font-mono bg-muted border rounded">
{key}
</kbd>
))}
{altKeys && (
<>
<span className="text-xs text-muted-foreground mx-1">/</span>
{altKeys.map((key) => (
<kbd key={key} className="px-2 py-1 text-xs font-mono bg-muted border rounded">
{key}
</kbd>
))}
</>
)}
</div>
<span>{description}</span>
</div>