Banner linkUrls come back from the API as unprefixed paths
(e.g. /browse?post=123). Navigating to them directly dropped non-English
viewers into the English version of the post. Localize both the rendered
href and the SPA navigate target via stripLangPrefix + localizePath.
Initialize the categories state from the cached response on first render so the
category icons stay visible when navigating back to the home page, instead of
flashing empty for a frame.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
With many banners the pagination dots overflowed the phone width. Show at most
10 dots in a window that follows the active slide; each dot still maps to its
real slide index.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Measure the image's rendered bottom edge with refs + ResizeObserver and
position the long-press save hint relative to it instead of pinning to
screen center or stage bottom. Enlarges the toast for mobile legibility
and clamps the offset so tall portrait images don't push it offscreen.
The app ships its own 7-language i18n and serves localized content, but mobile
browsers (Google Translate) were auto-translating the Chinese UI into broken
English (brand, nav, language dropdown). Add translate="no" + the Google
notranslate meta, and keep the attribute set on language changes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Revert desktop primary back to the direct injected sign (no WalletConnect relay,
which could spin forever) — reliable for a BNB-chain extension. Add console
diagnostics ([wallet-login] ...) and provider enumeration so a stuck/no-popup
flow can be pinpointed. WalletConnect stays as the explicit mobile MetaMask/
imToken option.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Raw window.ethereum is unreliable when several extensions contend for it, so
desktop now opens the RainbowKit connect modal (EIP-6963 wallet discovery +
WalletConnect QR) when a project id is configured, falling back to the injected
flow otherwise. In-wallet mobile browsers keep the direct injected sign.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Clear tpRequest when a TokenPocket login expires or fails so the mobile UI
returns to the initial state instead of showing a stuck waiting spinner
alongside the error.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Mobile TokenPocket now opens the tpoutside:// sign deep link and returns to
the original browser to finish login (no wallet in-app browser); desktop
keeps the QR. Fixes mobile login + logout being trapped in TP's browser.
- Desktop without an injected wallet shows a clear message instead of a dead
button; TokenPocket login card is always available as a working path.
- Raise toast z-index above the login modal so feedback is visible.
- Add native TokenPocket-login strings across 7 locales.
- Document that the live backend lacks favorites + TokenPocket routes (404),
the real blocker for those features in production.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Remove forced BNB chain switch on injected login (signature is chain-agnostic)
- Refine isMobileDevice so touch Macs stay on desktop flow
- Wire RainbowKit/WalletConnect as a real MetaMask/imToken QR fallback,
gated on a valid VITE_WALLETCONNECT_PROJECT_ID
- Rebuild login modal: single desktop primary action, collapsible other
methods, mobile open-app fallback feedback, brand icons
- Add My Favorites entry points (header, mobile menu, wallet dropdown)
- Favorites page: error retry, mobile filter drawer
- Auto sign-out and re-login prompt on favorites 401
- Full native translations for all wallet strings across 7 locales
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Extract zhDict/enDict from i18n.tsx into src/locales/{zh-CN,en}.ts
- Add full Korean dictionary (src/locales/ko.ts) covering all 115 UI keys
- Update formatBytes test/impl boundary for 1000-based units
- md (768-1023px): 2 columns with px-4 so cards don't kiss the screen edge.
- lg+ (>=1024px): 3 columns, parent wrapper provides spacing.
- <768px stays on the original single-column mobile branch.
- Matches Figma design (file uHDZkVHjAp7BXDKQKB0PM4, node 4367-11405).
- Mobile keeps the existing 5-post single column unchanged.
- Desktop (md+) renders all 12 latest posts in a CSS-columns masonry
with break-inside-avoid so each card's height stays content-driven.
- Adds an optional 'fluid' prop to MessageBubble that drops the
standalone-feed max-widths so bubbles fill the masonry column. The
/browse stream keeps the default non-fluid widths.
Match Figma node 4366-11092 desktop banner design:
- Slides shrink to 78%/72%/60% width on md/lg/xl with snap-center,
first/last get matching left/right margin so the edges still center.
- Each slide is wrapped in a framer-motion m.div that animates filter,
opacity, and scale between active and idle states.
- goTo and scroll/drag handlers use the slide's real offsetWidth so
centering math holds at every breakpoint; mobile (full-width, snap-start
visual) is unchanged.
- Replace the desktop header search field with a search icon button that
opens the search panel on click (matching mobile), so there is one search
input (in the panel) instead of a redundant header field, and the trigger
no longer vanishes when the panel opens.
- Lower the nav collapse breakpoint from 1100px to 1000px so the full menu
stays visible on smaller desktop widths before falling back to the
hamburger menu.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>