Commit Graph

201 Commits

Author SHA1 Message Date
Jure 7b7116fd58 Release v0.14.1 — fix Support view crash, add proxy/Tor support
Fixes a crash that blanked the Support (About/donate) view with React
error #130 on every release build since v0.13.2. react-qr-code ships
CommonJS, and since the Vite 8 / Rolldown migration its default import
resolved to the module namespace object ({ QRCode, default }) instead of
the component, making <QRCode/> an invalid element. AboutView now unwraps
the import to the real component. Reproduced against the production bundle
and verified fixed the same way.

Also ships the configurable HTTP/SOCKS5 network proxy (incl. Tor) from
PR #10 by Anderseta, merged earlier: routes relay WebSockets, Rust-side
fetches and update checks through the proxy. The proxy settings and the
README/CHANGELOG note that DNS is not yet guaranteed private (issue #11).

Adds a Contributors section to the README (Anderseta, SondreB).
2026-07-15 11:16:07 +02:00
Anderson Henrique Orso 7f4eab58c2 Add configurable HTTP/SOCKS5 network proxy (#10)
Adds a Settings UI to route Vega through an HTTP or SOCKS5 proxy (e.g. Tor).

Covers both network stacks: the webview (proxy_url applied at build time, so
relay WebSocket traffic is proxied) and all five Rust-side plugin-http call
sites (converted to fetchWithProxy). The auto-updater's check and download are
also routed via check({ proxy }), so update traffic no longer bypasses the
proxy and leaks the user's IP.

socks5h:// is intentionally rejected for now: Tauri's webview proxy API only
documents http and socks5, so accepting socks5h globally would imply a DNS-leak
guarantee the webview can't yet make. Tracking a cross-platform DNS-leak test
as follow-up.

By Anderseta.
2026-07-15 10:34:49 +02:00
Jure 08f231fb7e feat: show new-version changelog in the update banner
The updater already fetched the release notes (update.body) but never
displayed them. The banner now has a 'What's new' toggle that expands a
panel showing only the newest version's section (sliced out of the
cumulative release body), rendered as markdown, with a 'Full changelog
on GitHub' link to the releases page.
2026-06-15 21:43:54 +02:00
Jure 2e0af4e6bf feat: make the left sidebar width resizable (#6)
Adds a drag handle on the right edge of the expanded sidebar; width is
clamped to 160-360px, double-click resets to the default, and the chosen
width persists to localStorage. Collapsed state is unchanged.

Closes #6
2026-06-15 21:30:13 +02:00
Jure 7d15ae3070 feat: collapse compose box to a single line when idle (#6)
The posting area was always full-height, which felt oversized (reported
on macOS). It now shows a single line when empty and unfocused, and
expands to full height + toolbar on focus or when it has content. Uses
focus-within blur semantics so clicking the emoji/attach/poll/post
controls doesn't collapse it mid-interaction, and resets the auto-resize
inline height on collapse. A saved draft starts expanded.

Part of #6
2026-06-15 21:30:13 +02:00
Jure 5db0a14a38 fix: respect mute-list in search results (#7)
Search only filtered the people *suggestions* list — actual note,
article, and people results ignored the mute-list entirely, so muted
spam accounts still showed up. Now notes/articles are filtered by muted
pubkey and muted keyword, and people by muted pubkey, reusing the same
logic the feed uses. Tab counts, zero-result states, and all result
lists use the filtered sets and react to mute changes.

Closes #7
2026-06-15 21:30:05 +02:00
Jure 94f610c2d3 fix: article reader scroll lock + click-to-zoom for body images
WebKitGTK collapses body <img> elements to 0 height during re-decode,
shrinking scrollHeight and clamping scrollTop — articles with body images
locked partway down. Give every .prose-article img a fixed 16:9
aspect-ratio + object-fit: contain so the layout box survives the collapse
and scrollHeight stays constant. Body images now click-to-open the existing
ImageLightbox (with cursor: zoom-in affordance), and the lightbox image
itself now closes on click instead of swallowing it.
2026-05-24 20:07:06 +02:00
Jure 1c73f1e320 fix: harden updater null-handling, dev-mock install_info, honest interests copy
- useUpdater: guard the install_info response — a null/garbage value no
  longer overwrites the optimistic default and crash the whole app on
  installInfo.can_self_update. (Real app never returns null here; this is
  defensive — a failed updater check must not take down Vega.)
- tauri-dev-mock: add an install_info case so browser dev mode
  (localhost:1420) doesn't crash on the post-onboarding render.
- onboarding: the interests step claimed "you can always change this
  later" — there is no interests editor anywhere. Copy is now honest
  about what interests do (surface as hashtag pills on an empty
  Following feed).
2026-05-22 14:59:57 +02:00
Jure 349e9d12f8 polish: onboarding step indicator + safe backup escape hatch
- Onboarding Shell: larger accent VEGA wordmark + step-progress dots
  across the create -> backup -> interests path.
- Backup step gains an "I'll back up my key later" escape hatch. It runs
  the SAME keychain-saving login as confirming (skips only the checkbox)
  — wiring it to onComplete alone would have lost the generated key.
- Settings -> Identity now reveals the secret key (nsec): reveal/hide/
  copy via the existing load_nsec keychain command, hidden for read-only
  and remote-signer accounts. This makes the escape hatch honest — its
  note truthfully points users to where they can retrieve the key, and
  fills a real gap (the nsec was previously unreachable after onboarding).
2026-05-21 21:19:55 +02:00
Jure da8aab7de5 polish: replace sidebar Unicode glyphs with Lucide icons
The Unicode/symbol icons (◈ ☰ ▶ ⌕ ⟐ ✦ …) rendered inconsistently across
platforms and sizes. Lucide is crisp and pixel-perfect at any zoom.

- Add lucide-react (pinned exact); tree-shakes to the 15 icons used.
- NAV_ITEMS is now NavItem[] with ReactNode icons (the as-const array
  couldn't carry JSX). View type exported from the ui store for it.
- Icon spans switched from text-centred glyphs to flex-centred SVGs.
- Write-article ✦ -> PenLine.
2026-05-21 21:19:55 +02:00
Jure 5c490dbb56 feat: easy-read font option (Atkinson Hyperlegible)
New Settings → Appearance toggle, "Easy-Read Font". When on, swaps the
UI sans-serif to Atkinson Hyperlegible — a typeface designed by the
Braille Institute for legibility (distinct b/d/p/q, clear 1/I/l). Helps
dyslexic readers and anyone in a long reading session.

- Bundled via @fontsource/atkinson-hyperlegible (400 + 700), pinned exact
  — no runtime font fetch, works offline.
- Toggle adds an html.font-readable class; CSS overrides --font-ui and
  nudges letter-spacing (+0.012em) and line-height (1.6 -> 1.65) per
  evidence-based dyslexia guidance.
- Persisted to localStorage (wrystr_easy_read_font), applied on <html>
  at startup. Independent of theme — pairs with any, Reader included.
- Code blocks keep font-mono; articles keep their reading serif.

Follow-up to the Reader theme: colour was ~60-70% of the dyslexia-
friendly benefit, the font is most of the rest.
2026-05-21 17:30:59 +02:00
Jure 5cd11667ae polish: Sepia + Hackerman redesigned, new Reader theme
- Sepia: refined warm-dark elevation ladder (was muddy), proper text
  hierarchy (text-muted/text-dim were near-identical), considered amber
  accent. The reading-by-candlelight feel kept and sharpened.
- Hackerman: deeper phosphor base. Fixed a real bug — accent was the
  same hex as primary text (#00ff41), so the accent disappeared into
  the text. Accent is now a lighter phosphor green, distinguishable.
  Acid #ffff00 zap softened to a less-painful warm yellow.
- Reader (new, 8th theme): cream + dark-warm-grey + saddle-brown accent.
  Bookish, low-glare, moderate contrast. Helps dyslexic readers (per
  evidence-based guidance: off-white base, no pure-black text, calmer
  contrast) and anyone reading long-form articles. Borrows from print
  book design rather than screen design. A dyslexia-friendly font is
  a worthwhile follow-up but lives outside the colour-only theme system.
2026-05-20 22:53:48 +02:00
Jure 87c9a49e6c polish: Light theme redesign — soft off-white base, real text hierarchy
- Base shifts from #f5f5f5 to #fbfbfc (softer off-white, faint cool tint)
  — pure-white-card-on-soft-base elevation reads instead of being flat.
- bg-hover #f0f1f4 (darker on hover, the light-theme inverse).
- text-muted vs text-dim were near-identical (#697180 vs #6c717a) — no
  real hierarchy. Now #5b5f6e (WCAG AA on bg) and #888c98 for hints.
- Deeper violet accent #6d28d9 — carries more weight on white than the
  previous shade did.
- Semantic colours retuned for light backgrounds (zap, danger, warning,
  success all use the deeper Tailwind-700 family for proper presence).
2026-05-20 22:42:12 +02:00
Jure a4a4648aa6 polish: Midnight theme redesign — proper elevation + refined palette
- Base shifts from pure #0a0a0a to a barely-cool #0d0e12 ("midnight sky"
  reads as deep blue-black, not generic OLED black).
- Even elevation ladder: bg -> bg-raised -> bg-hover now reads as clear,
  perceptible steps instead of muddy near-duplicates.
- Three-tier text hierarchy with verified contrast: primary near-white,
  muted (WCAG AA on bg), dim for timestamps/hints.
- More luminous violet accent (#a78bfa) with proper pressed variant.
- Semantic colours retuned to harmonise (zap warm gold, success fresh
  green, danger softer red).

Mirrored into index.css @theme so pre-applyTheme initial paint matches.
2026-05-20 22:33:20 +02:00
Jure 7b6f67f42e fix: feed flicker — fixed-height quote box + content-aware row estimate
Two remaining causes of upward-scroll flicker in the virtualized feed:

- QuotePreview rendered nothing until fetchNoteById resolved, then popped
  in a box — a 70-200px late growth that desynced the virtualizer every
  time a quote note mounted. It now renders a fixed 80px (h-20) box,
  reserved whether or not the quoted note has loaded; a 2-line clamp keeps
  resolved content inside it.

- estimateSize was a flat 140px, so every row snapped from 140 to its real
  height (96-1660px) on first measurement. New estimateNoteHeight predicts
  height from note content (text, media boxes, quote box) so the
  first-measure correction is small enough to be imperceptible.

Remaining: a <=25px transient on some notes' first few views (a flex-wrap
row reflowing as async content lands); self-heals as caches warm.
2026-05-19 17:50:37 +02:00
Jure 30f050119b fix: feed virtualization — overlapping cards and phantom gaps
Three compounding causes in the v0.12.17 virtualized feed:

- Measurement cache was keyed by list index; the feed reorders (refresh
  merge, WoT filter, tab switch, cached->fresh swap) so cached heights
  reattached to the wrong note. Fixed with getItemKey by note id.
- <video> and single <img> had no reserved height and resized after
  metadata/image load — after the virtualizer measured the row. They
  now sit in fixed aspect-ratio boxes.
- The custom measureElement returned the 140px estimate for not-yet-
  measured rows on backward scroll (e.g. notes revealed by toggling
  WoT), so tall cards rendered far bigger than their recorded size.
  Removed — stable box heights make the flicker workaround obsolete.

Media boxes always render (stable height); the <img>/<video> inside
mounts only when the card is on screen, keeping scroll light.
2026-05-18 20:12:28 +02:00
Jure 9051c14205 polish: capitalise sidebar labels, rounded avatars, stronger article titles
- sidebar nav labels Title Case; follows -> People, dm -> Messages
- NoteCard + ArticleCard avatars rounded-sm -> rounded-md
- ArticleCard title 14px/medium -> 15px/semibold; larger tag pills
2026-05-18 18:17:13 +02:00
Jure 2250e2daf6 polish: sans-serif body font + midnight theme contrast refresh
- body font-family mono -> system sans-serif; 13px/1.5 -> 14px/1.6
- add --font-ui theme token
- midnight theme: readable muted text (#7c7c7c -> #a0a0a0, WCAG AA),
  restored muted/dim hierarchy, visible card borders, friendlier accent
- index.css @theme vars mirror themes.ts midnight (no first-paint flash)
2026-05-18 18:17:13 +02:00
Jure 7678ad2f1f Feed virtualization Stage 2: infinite scroll
Adds older-notes pagination to the Global feed. fetchGlobalFeed gains an
optional until param (fetch events before a timestamp, no since bound).
The feed store's new loadOlderNotes action fetches 50 older notes when
triggered, dedups, merges, re-sorts. MAX_FEED_SIZE raised 200 to 1000 —
virtualization bounds the DOM-node/bitmap count, so this just caps the JS
notes array as hygiene.

Feed.tsx auto-triggers loadOlderNotes when the user scrolls within ~8 rows
of the bottom; a 'Loading older notes' row shows during the fetch. Global
tab only (Following uses a separate path, Trending is a ranked snapshot).

Pending: sandboxed memory verification.
2026-05-17 20:26:15 +02:00
Jure 73c1bd1ac9 Virtualize feed list with @tanstack/react-virtual
Stage 1 of the feed virtualization work. The feed now renders only the
visible window of note cards (~25-35 in the DOM) instead of all up to 200,
via @tanstack/react-virtual (pinned 3.13.24). This structurally caps the
WebKit decoded-bitmap accumulation that caused the v0.12.6-era OOM.

Error and 'new notes' banners moved above the scroll container so the
virtualizer's coordinate space always starts at scrollTop 0. Upward-scroll
flicker fixed with a scroll-direction-aware measureElement that reuses the
cached row height on backward scroll (TanStack/virtual#659).

Feed still capped at MAX_FEED_SIZE; infinite scroll is Stage 2.
2026-05-16 19:02:18 +02:00
Jure db81de9007 Bump to v0.12.16 — security hardening: http(s) scheme guard on link sinks, loop-stable HTML tag strip 2026-05-16 13:59:10 +02:00
Jure 61c6703513 Bump to v0.12.15 — install-aware update banner (Arch/deb/rpm get manual update guidance) 2026-05-16 13:43:38 +02:00
Jure 0d4153e6de Bump to v0.12.13 — union legacy + cloud on first podcast hydrate 2026-05-15 20:50:47 +02:00
Jure 1cbd13031d Bump to v0.12.12 — podcast subscriptions sync via Nostr (kind 30003) 2026-05-15 20:35:36 +02:00
Jure 7e998be45b Bump to v0.12.11 — read-only mode write-action guards
The app now behaves coherently for users without a signer (fully logged
out, or signed in with an npub). No broken Publish buttons, no dead-end
"Not logged in" toasts.

- Add useCanSign() hook in src/stores/user.ts as the single source of
  truth for write-capability. Captures both "no pubkey" and
  "npub-only login" states.
- ReadOnlyBanner now fires for both states (was only "no pubkey" before).
- Hide account-bound sidebar entries (Bookmarks, Messages, Notifications,
  Zaps, V4V) in read-only mode. Read-only-OK views (Feed, Articles, Media,
  Podcasts, Search, Follows, Relays, Settings, Support) stay visible.
- Guard every write surface, two patterns:
  - Hide inline UI: ComposeBox, InlineReplyBox, NoteActions row, NoteCard
    context menu, ArticleFeed "Write article", FollowsView per-row
    follow/unfollow, ThreadView root reply, PollWidget vote controls,
    RelaysView "Publish list", PodcastPlayerBar ShareButton.
  - "Sign in to X" CTA: ArticleEditor publish, QuoteModal post, ZapModal,
    EditProfileForm save. CTAs open LoginModal.
- ProfileView edit/follow/mute/zap/DM buttons each gated by canSign.
- ArticleView like/repost/comment/bookmark/zap each gated by canSign.
- Belt-and-suspenders runtime guards in user store follow/unfollow.

Bookmark / mute stores already swallow publish errors via .catch(() => {}),
so they don't need explicit runtime guards.
2026-05-11 22:08:06 +02:00
Jure 7a07d732e6 Remove broken "new account" badge
The badge marked notes from pubkeys whose kind-0 profile event was
newer than 60 days, on the theory that that approximated account age.
It doesn't: kind-0 created_at is "profile last updated," so any user
who refreshed their bio recently got flagged as new regardless of how
long they've been on Nostr. The proxy was misleading, so drop it
entirely until there's a real signal to use.

- NoteCard.tsx: remove isNewAccount badge.
- social.ts: remove batchFetchProfileAges, getProfileAge, and the
  module-level profileAgeCache Map.
- nostr/index.ts: drop the barrel re-exports.
2026-04-23 19:20:37 +02:00
Jure 6a23f0223c Apply WoT filter to reactions, zaps, and all feed tabs
WoT was previously global-feed only. Now it filters notes on every feed
tab (global, following, trending) and also gates reaction pills and zap
totals — so a reaction from someone outside your social graph no longer
shows up in the counts.

- engagement.ts: wotSet param threaded through groupReactions,
  fetchReactions, fetchZapCount, fetchBatchEngagement. Zaps are filtered
  by the pubkey inside the zap request (the actual zapper), not the
  outer event.pubkey (the LNURL wallet). Extracted getZapperPubkey and
  getZapAmountSats.
- useReactions / useZapCount: cache key embeds WoT state so filtered
  and unfiltered counts don't collide. Hooks subscribe to the WoT store
  so toggling re-renders.
- feed store: reads WoT state and passes wotSet to fetchBatchEngagement,
  seeds cache with the correct key.
- Feed.tsx: drop the tab === "global" guard.
- SettingsView.tsx: update copy to reflect the wider scope.
2026-04-23 19:20:29 +02:00
Jure bc4c72d6a0 Fix Linux OOM: disable Blossom SHA-256 URL auto-detection
Commit 214c42b (v0.12.6) added auto-detection of content-addressed
Blossom URLs (64-hex SHA-256 paths) as <img> elements. Blossom is
widespread in modern Nostr feeds — every feed page started rendering
3-5x more <img> elements. Combined with WebKitGTK's weak decoded-
bitmap eviction, feed scrolling grew the WebKit web process to
8-12 GB and triggered WebKit's self-kill threshold with:

  Unable to shrink memory footprint of process (9022 MB) below
  the kill threshold (8192 MB). Killed

Disable BLOSSOM_URL_REGEX in parseContent(). Real Blossom images
shared via standard upload flows (with proper extensions) still
render. Proper reintroduction (HEAD request + Content-Type
validation, or known-server whitelist) planned for v0.12.9.

Also restore feed depth caps to pre-crisis values now that memory
is under control:
  - MAX_FEED_SIZE 30 → 200 (v0.12.6 baseline)
  - fetchFollowFeed limit 30 → 100
  - fetchGlobalFeed fetch 80 → 100
  - Following tab slice 30 → 100

The earlier 30-caps were themselves OOM firefighting that shipped
in v0.12.7 and were no longer needed.

Memory verified 2026-04-16: oscillates 1.1-1.6 GB across all tabs
(Global / Following / Trending / Media / profile / thread) under
heavy use with embedded relay enabled. No crashes. Elastic cache
behaviour rather than monotonic leak — memory spikes briefly on
content loads and reclaims within seconds.

See private_docs/WEBKIT_OOM_INVESTIGATION.md for the full
investigation (4 days of chasing symptoms before finding the
one-line regex as the real cause).
2026-04-16 21:31:04 +02:00
Jure 5fe3554579 Fix feed OOM: cap follow feed at 30, WebKit software rendering, dedup notification fetches
- followNotes capped at 30 (was 80) — following feed was rendering 2.7x more
  notes than global, causing 4GB+ spike on media-heavy follow content
- fetchFollowFeed limit 80→30 to match
- WEBKIT_FORCE_SOFTWARE_RENDERING=1 replaces WEBKIT_DISABLE_COMPOSITING_MODE=1
  (compositing mode killed Wayland path → blank window on Hyprland)
- HardwareAccelerationPolicy::Never → OnDemand (Never also caused blank screen)
- set_enable_page_cache(false) — SPA never navigates, bfcache is pure waste
- Removed duplicate fetchNotifications calls on login (was firing 3x in 8s)
- First notification poll delayed 8s→90s to avoid competing with feed load
- Result: login 3600MB→453MB, following feed crash→737MB, plateau at ~950MB
2026-04-16 11:43:48 +02:00
Jure 0894389fe0 Fix feed OOM: lazy image loading, inView gating, WebKit memory tuning
- NoteContent: remove ImageGrid from inline mode — images now only load
  when note is inView (via mediaOnly), stopping runaway scrolling leak
- NoteCard: content-visibility:auto to skip layout/paint for off-screen
  cards; inView-gated media, NoteActions, NIP-05 verification
- useInView: new IntersectionObserver hook with 300px rootMargin
- useProfile: MAX_PROFILE_CONCURRENT=8 throttle with fetch queue
- useReplyCount/useZapCount/useReactions: enabled param, throttled queues
- feed.ts: MAX_FEED_SIZE 200→30, live sub disabled (pendingNotes pattern),
  250ms batch debounce on live events
- core.ts: MAX_CONCURRENT_FETCHES=25 global NDK cap, fetchWithTimeout
  uses subscribe+stop instead of fetchEvents (no zombie subscriptions)
- lib.rs: HardwareAccelerationPolicy::Never + CacheModel::DocumentViewer
- main.rs: WEBKIT_DISABLE_COMPOSITING_MODE=1 for Linux
- relay/db.rs: TTL eviction + 5000 event cap
- feedDiagnostics.ts: file-flushing diag log survives crashes
2026-04-15 20:36:14 +02:00
Jure 018ee0e0f3 Fix thread OOM: hard-truncate events client-side, remove batchFetchProfileAges from thread 2026-04-13 22:16:02 +02:00
Jure a87abb6d97 Fix thread OOM: cap fetchThreadEvents at 300 events, cap profile cache at 500 entries 2026-04-13 21:37:41 +02:00
Jure 5d59797d5d Add thread load timing diagnostics (Ctrl+Shift+D to view) 2026-04-13 21:34:40 +02:00
Jure 95785dcb07 Fix profile fetch architecture: batch kind-0 queries, restore NDK pooling 2026-04-13 21:06:08 +02:00
Jure d8217bda49 Add new account age badge on notes (< 60 days) 2026-04-13 20:51:24 +02:00
Jure 4ce272ce5a Add opt-in WoT feed filter (hop-1 + hop-2 social graph) 2026-04-13 18:11:45 +02:00
Jure f3b92004f0 Bump to v0.12.7 — fix NIP-96 upload endpoints, block SVG uploads 2026-04-13 14:43:03 +02:00
Jure a393469c17 Add interest selection step to new-user onboarding
New users now choose topics after backing up their key. Selected interests
are saved to localStorage (wrystr_interests) and surfaced as clickable
hashtag pills in the Following feed empty state, giving new users a path
into content without auto-following strangers.

Flow: welcome → create → backup → interests → app
Login path is unchanged.
2026-04-11 22:29:25 +02:00
Jure 4759c2df64 Parse URLs, mentions and hashtags in profile bio
Profile about/bio text now renders clickable links, nostr mentions,
and hashtags instead of plain text.
2026-04-10 20:40:35 +02:00
Jure 214c42b9e5 Fix Blossom image URLs with non-standard extensions (.jp etc.)
SHA-256 hash filenames from content-addressed storage (Blossom/NIP-96)
now always treated as images regardless of extension. Also broaden
IMAGE_EXTENSIONS to cover avif, bmp, tiff, jp2 and common variants.
2026-04-10 20:09:44 +02:00
Jure f4878f9d4f Polish DM view: clickable links, inline images, nostr entity rendering
- DM messages now parse and render URLs as clickable accent links
- Image URLs show inline in the bubble (max-h-48)
- nostr:naddr and mentions rendered as styled clickable links
- nostr:nevent quotes show a subtle indicator
- Media URLs (video/audio/youtube etc.) rendered as clickable links
- parseContent regex now case-insensitive for nostr: prefix; entity
  lowercased before nip19.decode for robustness
- renderTextSegments: add case for quote type (↩ note indicator)
2026-04-10 17:49:11 +02:00
Jure 7375ddc7e3 Fix multi-image upload in article editor; add thumbnail lightbox
- All selected images now upload and insert correctly (was: only last
  image kept due to stale content closure in loop)
- Images inserted as a block with proper newline padding
- Thumbnail strip thumbnails are now clickable — opens a lightbox;
  click overlay to dismiss
2026-04-10 11:33:13 +02:00
Jure c0fbc93377 Polish pass 14 — silence remaining console calls in production
- feedDiagnostics.ts: guard styled console.log with isDev, plain log → debug.log
- main.tsx: error boundary console.error → debug.error
2026-04-09 19:56:05 +02:00
Jure 9fb0a7ef2e Polish pass 13 — final sentence case sweep
- NoteActions: Share, Follow/Unfollow
- SearchView: Search button, Notes/Articles/People result tabs
- RelaysView: Check all, Add (suggested relays)
- SettingsView: Add (mute keywords), Export data/Exporting…/Exported ✓
- InlineReplyBox: Reply/Replied ✓/Posting…
2026-04-09 19:51:16 +02:00
Jure 721a552f91 Polish pass 12 — sentence case on ArticleView, ComposeBox, DMView, SettingsView
- ArticleView: Back, Save/Saved, Repost/Reposted, Comment, Copy link,
  Like/Liked, Post — all button labels capitalised (header + footer)
- ComposeBox: Post, Post poll, Posting…
- DMView: Send, Start
- SettingsView: mute keyword placeholder + Remove button
2026-04-09 19:49:24 +02:00
Jure 63a0f05e92 Polish pass 11 — color tokens, text size consistency, overlay fix
- V4VHistory: text-amber-400 → text-zap on sats total
- V4VSettings: size status dot to text-[8px] for visual consistency
- Feed: last-updated timestamp text-[10px] → text-[11px] (matches siblings)
- NoteContent: +N overlay bg-black/50 → bg-bg/60, text-white → text-text,
  text-lg → text-[14px] (consistent with rest of file)
- RelaysView: last-checked timestamp text-[9px] → text-[10px]
2026-04-09 19:47:19 +02:00
Jure 9b3783b640 Polish pass 10 — hover titles, focus rings, disabled states
- NoteCard: title tooltip on truncated name and NIP-05
- NoteActions: emoji pill buttons dim (opacity-50) while disabled
- DMView: title tooltip on truncated conv name; focus ring on send button
- RelaysView: title tooltip on truncated relay URL
- OnboardingFlow: title tooltips on npub/nsec (nsec only when revealed)
- ArticleEditor: visible focus indicator on title and body textareas
2026-04-09 19:27:22 +02:00
Jure f34f5dc1a3 Polish pass 9 — console → debug in search.ts and localRelay.ts 2026-04-09 19:24:07 +02:00
Jure d6287fc240 Polish pass 8 — console → debug, sentence case, attachment button
- core.ts, feed.ts, user.ts: replace all console.log/warn/error with
  debug.log/warn/error (silent in production builds)
- ArticleFeed: "write article" → "Write article"
- ComposeBox: attachment remove x → ×, add aria-label
2026-04-09 19:20:47 +02:00
Jure f2546b5af7 Polish pass 7 — sentence case across profile, thread, follows, podcasts
- ProfileView: Cancel/Back, Edit profile, Zap, Follow/Unfollow, Mute/Unmute,
  Message, Notes/Articles/Media tab labels
- ThreadView: Back, Retry, Reply/Posting…/Replied ✓; console.error → debug.error
- ThreadNode: Reply/Posting…/Replied ✓
- FollowsView: Follow/Unfollow, Followers/Following tabs, Follows header
- EpisodeList: Back, Loading episodes…, amber → zap theme token on V4V badge
- AccountSwitcher: Login, Add account, Sign out, Remove
- PodcastCard: + Subscribe / Subscribed
2026-04-09 18:42:03 +02:00