Correction: check.happ.su/sendtv is a single API serving both Android TV and
Apple TV, not Android-only. Re-enable the TV connect widget for Apple TV
(gate on androidTV || appleTV again) and make the code input flexible again
(inputMode text, alphanumeric) since the code isn't guaranteed numeric.
Switching the platform dropdown always reset the app to the new platform's
featured/first one, discarding the user's choice (e.g. picked Happ → switched
platform → snapped back to the first app). Now it keeps the same app by name if
it exists on the new platform, falling back to featured/first only otherwise.
The TV quick-connect was rendered as standalone cards inserted between two
sliced block lists, which broke the panel's chosen style (e.g. split the
timeline rail) and dropped a step. Now it renders THROUGH the active renderer:
- Blocks gain an optional customNode; every renderer (cards/timeline/accordion/
minimal) drops it into the block body, so it inherits that exact style.
- InstallationGuide renders the FULL block list in the active style and injects
the TV connect widget as customNode on the "add subscription" step (no more
slicing / dropped steps) — only for the Happ Android TV app.
- TvQuickConnect is now content-only (no one-off cards/titles); the block step is
the wrapper. Buttons already use the shared blockButtonClass.
Verified against Happ docs: the sendtv 5-digit-code / Web-Import API
(check.happ.su/sendtv) is Android-TV-only. Apple TV (tvOS) uses a different
mechanism (tv.happ.su temporary code), so POSTing the code to check.happ.su
would hit the wrong endpoint. The block was gated on isTvPlatform (androidTV ||
appleTV); narrow it to androidTV. Apple TV now renders its normal config blocks.
The TV quick-connect block (Подключить TV / Сканировать QR) is a Happ-only
feature (check.happ.su/sendtv), but it rendered for ANY app on a TV platform and
used one-off button styles (solid btn-primary + grey btn-secondary) that clashed
with the outlined-accent buttons that come from the subscription-page config.
- Show TvQuickConnect only for the Happ app (detected by its happ:// deep-link
scheme, name as fallback).
- Extract the config-block button style into a shared blockButtonClass and use it
for the TV buttons too, so they adapt to exactly the same visual language as the
panel-config blocks (no divergent one-off styling).
- Align the code input with the Happ Android TV API doc (5-digit numeric):
placeholder 12345 + inputMode numeric. The send call already matches the spec
(POST check.happ.su/sendtv/{code}, body {"data": base64(subscriptionUrl)}).
A personal glyph-by-glyph re-review of the migration (the "steering wheel"
guard) found two wrong matches:
- MaintenanceScreen: a wrench/maintenance svg had been mapped to AdjustmentsIcon
(sliders) → use a proper WrenchIcon (PiWrench).
- InstallationGuide tutorial button: an open-book svg had been mapped to
DocumentIcon (file) → use BookOpenIcon (PiBookOpen).
Add WrenchIcon and BookOpenIcon to the central barrel. All other replacements
were verified correct (paper-plane→Send, server→HardDrives, warning-triangle→
Warning, etc.).
Audit-driven sweep: replaced 168 hand-written inline <svg> icons across 77
files with the central Phosphor (react-icons/pi) components from
@/components/icons, preserving each icon's size classes and colour (dynamic
stroke colours via the parent's currentColor, RefreshIcon's spinning state,
conditional rotate-180 chevrons).
Verified: tsc + vite build + eslint clean; an adversarial diff review of all
changed files found the replacements correct (70 files clean, 0 blockers).
Remaining inline <svg> dropped from 262 to ~95 — the survivors are legitimate
non-icons (brand/provider logos, loading spinners & framer-motion animations,
charts/sparklines, background decoration) plus a few ambiguous glyphs.
Replace the cabinet's hand-written heroicons-style SVG icon components with
the Remnawave panel's own icon family — Phosphor via react-icons/pi (Duotone).
All icons now live in a single central barrel (src/components/icons:
index + extended-icons + editor-icons, 144 icons); every feature file imports
from it instead of redefining inline SVGs (~440 icon defs removed).
- Add react-icons dependency
- Desktop nav (AppShell) now uses the central Phosphor icons, removing a
stroke-vs-duotone inconsistency the partial migration introduced
- Icons with custom props (SortIcon's direction, expandable chevrons) kept as
thin Phosphor wrappers; the RemnawaveIcon brand logo and animated SVGs
(checkmarks, spinners) are intentionally left as-is
- Restore the original per-call-site icon sizes wherever the centralized
default differed (211 call sites)
Subscription copy-URL button only had a title attribute; back and QR-open buttons in
InstallationGuide had no accessible name. Add aria-label so screen readers announce
the action (WCAG 2.4.6).
Sweep non-brand blue across admin pages, AnalyticsTab, TvQuickConnect, and menuLayout
style picker to accent tokens. Telegram-brand blue kept in BroadcastPreview (TG chat
mockup), the blocking screens (TG channel/bot CTAs), and the SuccessNotificationModal hero.
Sweep all amber-N color classes to warning-N (uniformly pending/warning semantics).
Yellow and orange left for per-file review (mixed Stars brand + semantic uses).
Sweep 30 files: text/bg/border/ring/from/to/via/fill/stroke/shadow/divide/decoration/
outline/placeholder-red-N → -error-N. All red usages were semantically error/danger
(no brand red), so tokens now flow through the design-system CSS variables and respond
to palette overrides.
When user selects Android TV or Apple TV platform (from non-TV device),
shows 5-char code input + QR scanner to send subscription to TV via
Happ TV API. Hybrid QR strategy: native Telegram scanner on mobile,
html5-qrcode CDN fallback on desktop. i18n keys for ru/en/zh/fa.
Based on PR #415 by @smediainfo.
- Fix stale initData comparison in clearStaleSessionIfNeeded that destroyed
valid refresh tokens on mobile WebView reopens
- Restrict X-Telegram-Init-Data header to auth endpoints only
- Close Mini App on auth retry to force fresh initData from Telegram
- Merge Connection page error/not-configured states for better UX
- Remove unnecessary comments across 40+ files (section dividers,
restating comments, noise catch block comments)
- Configure ESLint allowEmptyCatch to properly handle intentional
empty catch blocks (62 warnings resolved)
- New ConnectionQR page with fullscreen QR display (no modal)
- QR button in InstallationGuide header next to platform selector
- Respects hideLink setting: shows URL below QR only when visible
- i18n translations for ru, en, zh, fa