Jun 06, 11-12 PM (6)
Jun 06, 12-1 PM (2)
Jun 06, 1-2 PM (2)
Jun 06, 2-3 PM (2)
Jun 06, 3-4 PM (18)
Jun 06, 4-5 PM (1)
Jun 06, 5-6 PM (6)
Jun 06, 6-7 PM (0)
Jun 06, 7-8 PM (6)
Jun 06, 8-9 PM (0)
Jun 06, 9-10 PM (1)
Jun 06, 10-11 PM (27)
Jun 06, 11-12 AM (9)
Jun 07, 12-1 AM (14)
Jun 07, 1-2 AM (2)
Jun 07, 2-3 AM (0)
Jun 07, 3-4 AM (0)
Jun 07, 4-5 AM (1)
Jun 07, 5-6 AM (1)
Jun 07, 6-7 AM (3)
Jun 07, 7-8 AM (0)
Jun 07, 8-9 AM (0)
Jun 07, 9-10 AM (1)
Jun 07, 10-11 AM (2)
Jun 07, 11-12 PM (2)
Jun 07, 12-1 PM (5)
Jun 07, 1-2 PM (35)
Jun 07, 2-3 PM (2)
Jun 07, 3-4 PM (4)
Jun 07, 4-5 PM (2)
Jun 07, 5-6 PM (4)
Jun 07, 6-7 PM (0)
Jun 07, 7-8 PM (0)
Jun 07, 8-9 PM (17)
Jun 07, 9-10 PM (1)
Jun 07, 10-11 PM (21)
Jun 07, 11-12 AM (9)
Jun 08, 12-1 AM (9)
Jun 08, 1-2 AM (5)
Jun 08, 2-3 AM (3)
Jun 08, 3-4 AM (4)
Jun 08, 4-5 AM (2)
Jun 08, 5-6 AM (9)
Jun 08, 6-7 AM (5)
Jun 08, 7-8 AM (25)
Jun 08, 8-9 AM (36)
Jun 08, 9-10 AM (41)
Jun 08, 10-11 AM (24)
Jun 08, 11-12 PM (22)
Jun 08, 12-1 PM (40)
Jun 08, 1-2 PM (48)
Jun 08, 2-3 PM (33)
Jun 08, 3-4 PM (27)
Jun 08, 4-5 PM (12)
Jun 08, 5-6 PM (23)
Jun 08, 6-7 PM (14)
Jun 08, 7-8 PM (3)
Jun 08, 8-9 PM (6)
Jun 08, 9-10 PM (19)
Jun 08, 10-11 PM (29)
Jun 08, 11-12 AM (8)
Jun 09, 12-1 AM (5)
Jun 09, 1-2 AM (3)
Jun 09, 2-3 AM (1)
Jun 09, 3-4 AM (3)
Jun 09, 4-5 AM (26)
Jun 09, 5-6 AM (5)
Jun 09, 6-7 AM (23)
Jun 09, 7-8 AM (51)
Jun 09, 8-9 AM (35)
Jun 09, 9-10 AM (45)
Jun 09, 10-11 AM (51)
Jun 09, 11-12 PM (46)
Jun 09, 12-1 PM (86)
Jun 09, 1-2 PM (84)
Jun 09, 2-3 PM (36)
Jun 09, 3-4 PM (38)
Jun 09, 4-5 PM (16)
Jun 09, 5-6 PM (18)
Jun 09, 6-7 PM (18)
Jun 09, 7-8 PM (19)
Jun 09, 8-9 PM (16)
Jun 09, 9-10 PM (16)
Jun 09, 10-11 PM (28)
Jun 09, 11-12 AM (10)
Jun 10, 12-1 AM (11)
Jun 10, 1-2 AM (16)
Jun 10, 2-3 AM (11)
Jun 10, 3-4 AM (19)
Jun 10, 4-5 AM (5)
Jun 10, 5-6 AM (2)
Jun 10, 6-7 AM (46)
Jun 10, 7-8 AM (82)
Jun 10, 8-9 AM (18)
Jun 10, 9-10 AM (59)
Jun 10, 10-11 AM (46)
Jun 10, 11-12 PM (134)
Jun 10, 12-1 PM (49)
Jun 10, 1-2 PM (33)
Jun 10, 2-3 PM (32)
Jun 10, 3-4 PM (28)
Jun 10, 4-5 PM (36)
Jun 10, 5-6 PM (12)
Jun 10, 6-7 PM (12)
Jun 10, 7-8 PM (38)
Jun 10, 8-9 PM (11)
Jun 10, 9-10 PM (9)
Jun 10, 10-11 PM (20)
Jun 10, 11-12 AM (7)
Jun 11, 12-1 AM (10)
Jun 11, 1-2 AM (2)
Jun 11, 2-3 AM (0)
Jun 11, 3-4 AM (2)
Jun 11, 4-5 AM (8)
Jun 11, 5-6 AM (12)
Jun 11, 6-7 AM (34)
Jun 11, 7-8 AM (106)
Jun 11, 8-9 AM (36)
Jun 11, 9-10 AM (20)
Jun 11, 10-11 AM (105)
Jun 11, 11-12 PM (25)
Jun 11, 12-1 PM (38)
Jun 11, 1-2 PM (37)
Jun 11, 2-3 PM (14)
Jun 11, 3-4 PM (20)
Jun 11, 4-5 PM (5)
Jun 11, 5-6 PM (7)
Jun 11, 6-7 PM (26)
Jun 11, 7-8 PM (90)
Jun 11, 8-9 PM (11)
Jun 11, 9-10 PM (5)
Jun 11, 10-11 PM (25)
Jun 11, 11-12 AM (5)
Jun 12, 12-1 AM (8)
Jun 12, 1-2 AM (2)
Jun 12, 2-3 AM (2)
Jun 12, 3-4 AM (4)
Jun 12, 4-5 AM (7)
Jun 12, 5-6 AM (15)
Jun 12, 6-7 AM (46)
Jun 12, 7-8 AM (19)
Jun 12, 8-9 AM (28)
Jun 12, 9-10 AM (22)
Jun 12, 10-11 AM (29)
Jun 12, 11-12 PM (42)
Jun 12, 12-1 PM (24)
Jun 12, 1-2 PM (26)
Jun 12, 2-3 PM (22)
Jun 12, 3-4 PM (38)
Jun 12, 4-5 PM (23)
Jun 12, 5-6 PM (19)
Jun 12, 6-7 PM (26)
Jun 12, 7-8 PM (12)
Jun 12, 8-9 PM (17)
Jun 12, 9-10 PM (5)
Jun 12, 10-11 PM (30)
Jun 12, 11-12 AM (6)
Jun 13, 12-1 AM (6)
Jun 13, 1-2 AM (2)
Jun 13, 2-3 AM (0)
Jun 13, 3-4 AM (3)
Jun 13, 4-5 AM (0)
Jun 13, 5-6 AM (3)
Jun 13, 6-7 AM (7)
Jun 13, 7-8 AM (5)
Jun 13, 8-9 AM (6)
Jun 13, 9-10 AM (14)
Jun 13, 10-11 AM (12)
Jun 13, 11-12 PM (0)
3,238 commits this week Jun 06, 2026 - Jun 13, 2026
feat(governance): color-coded proposal type chips
The proposal meta row showed the governance action type as plain uppercase
text ("TREASURY WITHDRAWALS"), visually indistinguishable from the other meta
fields and hard to scan in a long list.

Add a GovernanceTypeChip that renders each Conway action type as a color-coded
outline Badge with an icon:
- treasury_withdrawals  amber   Coins
- info_action           blue    FileText
- parameter_change      purple  Settings2
- hard_fork_initiation  orange  GitBranch
- no_confidence         red     XCircle
- new_constitution      teal    FileText
- new/update_committee  indigo  Users
- unknown               slate   Hash (Title-Cased fallback label)

Used in both the mobile and desktop meta rows (single shared component, no
view drift). Purely presentational — no data or vote-flow changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
feat(governance): clearer ballot voting UX — segmented vote + one entry per action
The per-proposal voting controls were confusing: a raw OS <select> for the
Yes/No/Abstain choice, plus TWO competing actions (a green "Add to Ballot"
button in proposals.tsx AND a mystery ballot icon in VoteButton).

- Replace the native <select> with a shadcn segmented Yes/No/Abstain control
  (color-coded selected state, icons). Guard `(v) => v && setVoteKind(v)` so a
  re-click can't blank the vote read into the tx.
- One clear primary: the Vote button now states the choice ("Vote Yes",
  "Vote Yes (Proxy)") and uses the themed primary style.
- One ballot entry: the icon-only ballot button becomes a labeled "Add to
  ballot" / "In N ballots" secondary, with a tooltip distinguishing the two
  flows (vote on-chain now vs collect for co-signers).
- Remove the now-duplicate green "Add to Ballot" buttons (mobile + desktop) in
  proposals.tsx; keep the View links.

vote()/voteProxy() bodies, proxy path, keepRelevant, metadata label 674, the
closed-vote Lock state, and all toasts are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
fix(assets): stop token rows overflowing the Assets card
Long token names ($drep.collective) and raw quantities pushed the value/ticker
past the card's right edge (the clipped "↗1 $S…"). Root cause: the flex row +
left group had no min-w-0, so text couldn't shrink, and the name/quantity/ticker
were never truncated.

- min-w-0 on the row + flex-1 min-w-0 on the left group (lets text shrink).
- 60px avatar wrappers flex-shrink-0 (so the image never compresses instead).
- name h3 truncates (+ title tooltip) and is bounded via truncateTokenSymbol
  for the raw-unit hex fallback; remove ml-auto from the link.
- value block flex-shrink-0; quantity via numberWithCommas (tabular-nums);
  ticker truncates with a max width + title.

Full name stays reachable via tooltip + the Cardanoscan token link.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
fix(ux): lead transaction rows with the human label, demote the hash
The on-chain history rows (desktop table + mobile cards) led with the raw
truncated tx hash — the least human-meaningful field — while the actual
description ("Ballot Vote: …") was buried below. Flip the hierarchy to match
the pending-tx cards:
- primary: the dbTransaction description, or a "Sent"/"Received" fallback (and
  the cert label on desktop) so rows without a DB record aren't identified by
  a bare hash.
- date below.
- hash demoted to a quiet muted mono link with the external-link arrow.

Also standardize the hash truncation on getFirstAndLast(hash, 8, 8) (was two
different inline substring schemes) and drop the now-redundant standalone
description block on mobile. Cardanoscan links, outputs, certs, signers, and
the row actions menu are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
fix(ux): themed, non-overflowing, mobile-friendly pagination control
The transactions pagination bar overflowed its card on the right and used
hardcoded dark colors + a raw <select>. Rewrite the body (props unchanged):
- container: themed `border bg-card`, `flex-wrap min-w-0 gap-3` so the groups
  reflow instead of spilling off the right edge.
- sort toggle: outline Button, icon-only on mobile (label hidden < sm).
- page size: shadcn Select (was a native unstyled <select>); same options +
  reset-to-page-1 behavior.
- nav: compact icon-only prev/next (h-9 w-9), muted tabular-nums page indicator;
  rely on Button's native disabled styling.

PaginationProps is unchanged, so both call sites (transactions + DRep list)
behave identically.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
feat(ux): friendly-error helper + toastError wrapper; adopt in DRep register
PR 5 of the UX/mobile quick-wins pass.
- src/utils/errors.ts `getFriendlyError(error)` maps the common raw errors
  (CIP-30 {code:-2}, account-changed, 429/too-many-requests, insufficient
  funds, Blockfrost/UTXOS, user-decline) to short human messages, falling back
  to the raw message.
- src/utils/toast-error.ts `toastError(error, title?)` — destructive toast with
  the normalized message (additive; doesn't touch the TOAST_LIMIT=1 reducer).
- Adopt in DRep registration's catch (raw e.message -> getFriendlyError), while
  keeping the "Copy Error" action for raw debug details.

Other error-prone flows (new-transaction, WalletAuthModal) can adopt the
helper incrementally.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
fix(mobile): keep dialogs within the viewport (responsive width + dvh + scroll)
PR 4 of the UX/mobile quick-wins pass. Centered Dialogs overflowed small
screens — content (and action buttons) got clipped off-screen, especially the
wide governance modals.

Make the base DialogContent mobile-safe without changing desktop layout:
w-[calc(100%-1.5rem)] (stay within the viewport with a small margin),
max-h-[90dvh] + overflow-y-auto (scroll internally instead of off-screen). The
max-w-lg cap and centered position are unchanged at desktop. BallotModal and
RegisterDrepModal switch their max-h from vh to dvh so the mobile toolbar
doesn't hide the bottom.

(Kept dialogs centered rather than converting to a bottom sheet to avoid
restructuring positioning on the shared base that backs every dialog; the
overflow fix is the critical part. Needs a quick on-device / Chrome-MCP visual
check before promoting past preprod.)

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
fix(mobile): bech32-safe address inputs + decimal keypad + no iOS zoom
PR 6 of the UX/mobile quick-wins pass (input correctness).
- Recipient address fields used invalid type="string" with mobile autocorrect/
  autocapitalize active — which can silently corrupt case-sensitive bech32
  addresses. Now type="text" with inputMode="text" autoCapitalize="off"
  autoCorrect="off" spellCheck={false}.
- Amount fields get inputMode="decimal" (numeric keypad on mobile).
- Base Input uses text-base on mobile (sm:text-sm on desktop) so iOS Safari
  no longer zooms in on focus (<16px triggers it).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
feat(ux): Skeleton + EmptyState primitives; fix blank wallet pages & loading/empty conflation
PR 3 of the UX/mobile quick-wins pass.
- Add shared `Skeleton` (shadcn) and `EmptyState` (Card-based) primitives.
- Wallet detail routes (info/transactions/governance/assets) rendered a blank
  fragment while `appWallet` loaded — replace with a `WalletDetailSkeleton` so
  there's no white flash on every wallet open.
- all-transactions: it showed "No transactions yet" *while still loading*
  (undefined === loading). Split into a skeleton (loading) vs an `EmptyState`
  (loaded and empty).
- proposals: plain-text "No proposals found" → `EmptyState`.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
feat(mobile): enforce >=44px touch targets on coarse-pointer devices
PR 2 of the UX/mobile quick-wins pass. Buttons/inputs were 32-36px, below
the recommended 44px touch target. A single @media (pointer: coarse) rule
enlarges interactive controls on touch devices only — no per-call-site
edits and zero change to desktop density. Plain text links are
intentionally excluded.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
feat(mobile): viewport-fit, dynamic viewport height, and safe-area insets
Foundational mobile fixes (PR 1 of the UX/mobile quick-wins pass):
- viewport meta gains viewport-fit=cover so env(safe-area-inset-*) resolves
  (without it the insets are always 0).
- Full-height containers use 100dvh instead of 100vh/h-screen so the layout
  isn't clipped by mobile-Safari / wallet-webview dynamic toolbars
  (_app, layout root + inner content column).
- Main header grows by the safe-area top inset on mobile so it clears the
  notch/status bar, and honors side insets in landscape.
- Mobile nav drawer offsets by the safe-area top, uses 100dvh, and pads the
  bottom for the home indicator.
- Bottom Sheet variant pads the bottom safe area.

Desktop is unchanged (insets are 0; header rule is scoped below md).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>