feat(web): complete groups/contacts/favorites/settings/calls/system domains + extensive review-round fixes
Rounds out the full rewrite with the remaining feature domains: group management (admin panel, mute, files, announcements, QR-based invite/join), contacts (friend profile, add-friend, blocklist, new-friends), favorites (real media rendering across text/image/video/voice/file/link), settings (profile/security/privacy/general/about), calls (Agora-backed audio/video signaling + call history), and system messages/file assistant. Also folds in a large batch of live-verified fixes surfaced by repeated fresh code-review passes and hands-on E2E testing against the real backend, including: WS reconnect not resubscribing any topic after a disconnect, missing x-im-client-mid on every send path (protocol compliance for retry dedup), group mute/member-settings/self-profile endpoint corrections, relationship-state type fixes across search/QR/ friend-profile, tenant-switch logout gap, password-policy now read from the real per-tenant config instead of guessed, NavRail highlight/ aria-current desync, several call-state-machine races, and responsive layout fixes across all four breakpoints (mobile/tablet/laptop/desktop) including a full mobile rebuild of favorites, call UI, and the settings home/sub-list split. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
72b7b79caf
commit
5c3f3b7653
+30
-8
@@ -1,4 +1,4 @@
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { Link, useLocation } from 'react-router-dom';
|
||||
|
||||
import { Icon } from './Icon';
|
||||
|
||||
@@ -21,16 +21,38 @@ const BOTTOM_ITEMS: NavRailItem[] = [
|
||||
{ to: '/settings', icon: 'settings', label: '设置' },
|
||||
];
|
||||
|
||||
/** `/files` is `<Navigate to="/messages/slf" replace />` (App.tsx) -- the real URL right after
|
||||
* clicking "文件助手" is `/messages/slf`, which a plain (non-`end`) NavLink match makes "消息"
|
||||
* light up for (a same-topicId prefix match) while "文件助手" itself (`to: '/files'`, a path that
|
||||
* no longer exists once redirected) never matches at all. Overriding both items' active state off
|
||||
* the real pathname instead of trusting NavLink's own prefix match fixes both sides of the mix-up. */
|
||||
function isNavItemActive(to: string, pathname: string): boolean {
|
||||
if (to === '/files') return pathname === '/messages/slf';
|
||||
if (to === '/messages') return pathname.startsWith('/messages') && pathname !== '/messages/slf';
|
||||
return pathname === to || pathname.startsWith(`${to}/`);
|
||||
}
|
||||
|
||||
function NavRailButton({ item }: { item: NavRailItem }) {
|
||||
const location = useLocation();
|
||||
const isActive = isNavItemActive(item.to, location.pathname);
|
||||
return (
|
||||
<NavLink
|
||||
// Plain Link, not NavLink -- NavLink computes its OWN `aria-current` from ITS OWN prefix-match
|
||||
// logic unconditionally (confirmed by reading react-router's source: passing an `aria-current`
|
||||
// prop only changes the STRING used, not whether it's applied at all, which stays gated on
|
||||
// NavLink's internal isActive). That's exactly `/files`'s own problem above -- NavLink's naive
|
||||
// match would light up "消息" for `/messages/slf`, not "文件助手" -- so a second, independent
|
||||
// aria-current computation fighting the same override this file already needed for `className`
|
||||
// is a real, verifiable a11y bug (screen readers and sighted highlighting would disagree on
|
||||
// which icon is current). Driving both off the one already-correct `isActive` avoids that
|
||||
// entirely.
|
||||
<Link
|
||||
to={item.to}
|
||||
title={item.label}
|
||||
className={({ isActive }) =>
|
||||
`relative grid h-11 w-11 place-items-center rounded-[10px] no-underline ${
|
||||
isActive ? 'bg-accent-soft-bg text-accent' : 'text-text-secondary'
|
||||
}`
|
||||
}
|
||||
aria-label={item.label}
|
||||
aria-current={isActive ? 'page' : undefined}
|
||||
className={`relative grid h-11 w-11 place-items-center rounded-[10px] no-underline ${
|
||||
isActive ? 'bg-accent-soft-bg text-accent' : 'text-text-secondary'
|
||||
}`}
|
||||
>
|
||||
<Icon name={item.icon} className="!text-2xl" />
|
||||
{item.badge ? (
|
||||
@@ -38,7 +60,7 @@ function NavRailButton({ item }: { item: NavRailItem }) {
|
||||
{item.badge}
|
||||
</b>
|
||||
) : null}
|
||||
</NavLink>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user