Browse Source

fix(responsive): 优化移动端导航与头像展示

version/1.2.14
thatsfelix 4 days ago
parent
commit
95271b847e
  1. 9
      src/components/UserAvatarMenu/index.scss
  2. 151
      src/layouts/Layout/Layout.scss
  3. 34
      src/layouts/Layout/Layout.tsx
  4. 1
      src/locales/en-US.json
  5. 1
      src/locales/zh-CN.json
  6. 1
      src/locales/zh-TW.json
  7. 2
      src/pages/Explore/ExploreFeatured/ExploreFeatured.scss
  8. 4
      src/pages/Explore/ExploreHero/ExploreHero.scss
  9. 2
      src/pages/Explore/index.scss

9
src/components/UserAvatarMenu/index.scss

@ -16,6 +16,7 @@
box-sizing: border-box;
display: block;
cursor: pointer;
overflow: hidden;
}
.userAvatarMenu__avatarImg {
@ -418,12 +419,16 @@
@media (max-width: 860px) {
.userAvatarMenu:not(.userAvatarMenu_landing),
.userAvatarMenu:not(.userAvatarMenu_landing) .userAvatarMenu__button,
.userAvatarMenu:not(.userAvatarMenu_landing).userAvatarMenu_guest,
.userAvatarMenu:not(.userAvatarMenu_landing) .userAvatarMenu__avatarImg {
.userAvatarMenu:not(.userAvatarMenu_landing).userAvatarMenu_guest {
width: 38px;
height: 38px;
}
.userAvatarMenu:not(.userAvatarMenu_landing) .userAvatarMenu__avatarImg {
width: 100%;
height: 100%;
}
.userAvatarMenu:not(.userAvatarMenu_landing) .userAvatarMenu__dropdown {
right: -8px;
width: min(327px, calc(100vw - 16px));

151
src/layouts/Layout/Layout.scss

@ -170,6 +170,10 @@
justify-content: flex-end;
}
.layoutShell__mobileBrand {
display: none;
}
.layoutShell__topbarRight {
display: inline-flex;
align-items: center;
@ -1023,6 +1027,12 @@
}
}
// "更多"内的移动端导航分区 底栏"更多"文字仅移动端展示桌面隐藏
.layoutShell__footerMenuText,
.layoutShell__footerPopoverNav {
display: none;
}
.layoutShell__footerPopoverPanel {
position: absolute;
left: 20px;
@ -1310,11 +1320,30 @@
grid-column: 1;
grid-row: 1;
padding: 0 12px;
justify-content: flex-end;
justify-content: space-between;
gap: 12px;
}
.layoutShell__mobileBrand {
width: 70px;
height: 36px;
border-radius: 24px;
display: flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
background: #ffffff;
}
.layoutShell__mobileBrandLogo {
width: 70px;
height: 36px;
display: block;
object-fit: contain;
}
.layoutShell__topbarRight {
width: 100%;
width: auto;
gap: 8px;
justify-content: flex-end;
}
@ -1398,12 +1427,12 @@
width: 100%;
min-width: 0;
height: var(--layout-tabbar-height);
padding: 6px 10px calc(6px + env(safe-area-inset-bottom, 0px));
padding: 6px 6px calc(6px + env(safe-area-inset-bottom, 0px));
border-top: 1px solid #eeeeee;
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
display: flex;
flex-direction: row;
align-items: center;
gap: 8px;
gap: 2px;
overflow: visible;
box-shadow: 0 -6px 18px rgba(15, 15, 15, 0.06);
}
@ -1412,28 +1441,29 @@
display: none;
}
// 底栏 5 等分4 个主导航项占 4 "更多" 1
.layoutShell__sideNav {
width: 100%;
flex: 4;
width: auto;
min-width: 0;
margin-top: 0;
display: flex;
flex-direction: row;
gap: 4px;
overflow-x: auto;
overflow-y: hidden;
scrollbar-width: none;
-ms-overflow-style: none;
gap: 2px;
overflow: visible;
}
.layoutShell__sideNav::-webkit-scrollbar {
// 教学/画布等溢出项不进底栏收进"更多"弹层
.layoutShell__sideItem_overflow {
display: none;
}
.layoutShell__sideItem {
width: clamp(54px, 15vw, 72px);
min-width: clamp(54px, 15vw, 72px);
flex: 1;
width: auto;
min-width: 0;
height: 52px;
padding: 6px 4px;
padding: 6px 2px;
border-radius: 16px;
gap: 2px;
}
@ -1460,39 +1490,58 @@
transform-origin: top right;
}
// "更多"占底栏第 5
.layoutShell__footer {
flex: 1;
width: auto;
height: auto;
margin-top: 0;
display: flex;
flex-direction: row;
align-items: center;
gap: 4px;
}
// 订阅/我的退到顶栏头像菜单底栏不再显示
.layoutShell__footerNav {
width: auto;
display: flex;
flex-direction: row;
gap: 4px;
display: none;
}
.layoutShell__footerPopoverTrigger {
width: 44px;
flex: 1;
width: auto;
height: 52px;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
flex-shrink: 0;
}
// "更多"按钮改成与主 Tab 一致的"图标+文字"竖排样式
.layoutShell__footerMenuBtn {
width: 36px;
height: 36px;
border-radius: 18px;
background: #f9f9f9;
width: 100%;
height: 52px;
flex-direction: column;
gap: 2px;
padding: 6px 2px;
border-radius: 16px;
background: transparent;
}
// 提高选择器优先级覆盖桌面基础的 `.layoutShell__footerMenuBtn img` 尺寸
.layoutShell__footerMenuBtn .layoutShell__footerMenuIcon {
width: 22px;
height: 22px;
}
.layoutShell__footerMenuText {
display: block;
max-width: 100%;
color: #333333;
font-size: 11px;
line-height: 14px;
overflow: hidden;
text-overflow: ellipsis;
}
.layoutShell__footerPopoverPanel {
@ -1504,6 +1553,54 @@
overflow-y: auto;
}
// "更多"弹层里的移动端导航分区教学/画布
.layoutShell__footerPopoverNav {
display: flex;
flex-direction: column;
padding-bottom: 4px;
margin-bottom: 4px;
border-bottom: 1px solid #f0f0f0;
}
.layoutShell__footerPopoverNavItem {
position: relative;
display: flex;
align-items: center;
gap: 10px;
height: 44px;
padding: 0 10px;
border-radius: 8px;
color: #333333;
font-size: 13px;
text-decoration: none;
}
.layoutShell__footerPopoverNavItem:hover {
background: #f0f0f0;
}
.layoutShell__footerPopoverNavItem .layoutShell__sideIcon,
.layoutShell__footerPopoverNavItem .layoutShell__sideIconImage {
width: 20px;
height: 20px;
}
.layoutShell__footerPopoverNavItem_active {
color: #6f47f5;
}
.layoutShell__footerPopoverNavItem_active .layoutShell__sideIconImage_default {
opacity: 0;
}
.layoutShell__footerPopoverNavItem_active .layoutShell__sideIconImage_active {
opacity: 1;
}
.layoutShell__footerPopoverNavBadge {
margin-left: auto;
}
.layoutShell__contentFrame {
grid-column: 1;
grid-row: 2;

34
src/layouts/Layout/Layout.tsx

@ -136,6 +136,9 @@ const LAYOUT_SIDE_NAV_ITEMS: readonly LayoutSideNavItem[] = [
},
];
// 移动端底部 Tab 栏仅展示这些主导航项(≤899px);其余项(如 teaching/canvas)收进"更多"弹层,避免底栏溢出滚动。
const LAYOUT_MOBILE_PRIMARY_NAV_IDS: readonly string[] = ["explore", "characters", "voice", "create"];
const LAYOUT_PROMO_BAR_DISMISSED_KEY = "popiart.layout.promoBar.dismissed";
const LAYOUT_NOTIFICATION_BROADCAST_CHANNEL = "popiart.layout.notification";
const LAYOUT_NOTIFICATION_IDLE_POLL_INTERVAL_MS = 60 * 1000;
@ -969,6 +972,9 @@ export function Layout({ children }: LayoutProps) {
</div>
) : null}
<header className="layoutShell__topbar" aria-label={t("layout.aria.topbar")} onClick={dismissMainDetailModals}>
<Link className="layoutShell__mobileBrand" to={ROUTES.EXPLORE} aria-label={t("layout.brand.aria")}>
<img className="layoutShell__mobileBrandLogo" src={LAYOUT_NAV_ASSETS.logo} alt="" />
</Link>
<div className="layoutShell__topbarRight" aria-label={t("layout.aria.userArea")}>
<div className="layoutShell__topbarNotificationTool" ref={notificationToolRef}>
<Tooltip content={t("layout.topbar.notification")}>
@ -1298,7 +1304,8 @@ export function Layout({ children }: LayoutProps) {
<nav className="layoutShell__sideNav" aria-label={t("layout.aria.sideNav")}>
{LAYOUT_SIDE_NAV_ITEMS.map((item) => {
const isActive = pathname === item.to || (item.to !== "/" && pathname.startsWith(`${item.to}/`));
const className = ["layoutShell__sideItem", isActive ? "layoutShell__sideItem_active" : ""].filter(Boolean).join(" ");
const isMobileOverflow = !LAYOUT_MOBILE_PRIMARY_NAV_IDS.includes(item.id);
const className = ["layoutShell__sideItem", isActive ? "layoutShell__sideItem_active" : "", isMobileOverflow ? "layoutShell__sideItem_overflow" : ""].filter(Boolean).join(" ");
return (
<Link
key={item.id}
@ -1352,7 +1359,8 @@ export function Layout({ children }: LayoutProps) {
aria-expanded={footerPopoverOpen}
aria-haspopup="dialog"
>
<img src={LAYOUT_NAV_ASSETS.more} alt="" />
<img className="layoutShell__footerMenuIcon" src={LAYOUT_NAV_ASSETS.more} alt="" />
<span className="layoutShell__footerMenuText">{t("layout.nav.more")}</span>
</button>
{footerPopoverOpen ? (
<div
@ -1363,6 +1371,28 @@ export function Layout({ children }: LayoutProps) {
e.stopPropagation();
}}
>
{/* 移动端:把未进底部 Tab 的导航项(教学/画布)收进"更多",桌面隐藏 */}
<nav className="layoutShell__footerPopoverNav" aria-label={t("layout.aria.sideNav")}>
{LAYOUT_SIDE_NAV_ITEMS.filter((item) => !LAYOUT_MOBILE_PRIMARY_NAV_IDS.includes(item.id)).map((item) => {
const isActive = pathname === item.to || (item.to !== "/" && pathname.startsWith(`${item.to}/`));
const navItemClassName = ["layoutShell__footerPopoverNavItem", isActive ? "layoutShell__footerPopoverNavItem_active" : ""].filter(Boolean).join(" ");
return (
<Link
key={item.id}
to={item.to}
className={navItemClassName}
onClick={(evt) => {
setFooterPopoverOpen(false);
handleLayoutNavClick(evt, item.to);
}}
>
<LayoutSideNavIcon item={item} />
<span className="layoutShell__footerPopoverNavText">{t(item.labelKey)}</span>
{item.badgeKey ? <span className="layoutShell__footerPopoverNavBadge">{t(item.badgeKey)}</span> : null}
</Link>
);
})}
</nav>
<button
type="button"
className="layoutShell__footerPopoverLink"

1
src/locales/en-US.json

@ -93,6 +93,7 @@
"layout.nav.canvas": "POPi.TV",
"layout.nav.canvasBadge": "BETA",
"layout.nav.voice": "Voice",
"layout.nav.more": "More",
"layout.nav.points": "Points",
"layout.topbar.skill": "SKILL",
"layout.footer.subscribe": "Membership",

1
src/locales/zh-CN.json

@ -93,6 +93,7 @@
"layout.nav.canvas": "画布",
"layout.nav.canvasBadge": "BETA",
"layout.nav.voice": "声音",
"layout.nav.more": "更多",
"layout.nav.points": "积分",
"layout.topbar.skill": "SKILL",
"layout.footer.subscribe": "会员",

1
src/locales/zh-TW.json

@ -93,6 +93,7 @@
"layout.nav.canvas": "畫布",
"layout.nav.canvasBadge": "BETA",
"layout.nav.voice": "聲音",
"layout.nav.more": "更多",
"layout.nav.points": "積分",
"layout.topbar.skill": "SKILL",
"layout.footer.subscribe": "會員",

2
src/pages/Explore/ExploreFeatured/ExploreFeatured.scss

@ -5,7 +5,7 @@
.explorePage__featured {
box-sizing: border-box;
width: min(100%, 1623px);
margin: 35px 0 0;
margin: 35px auto 0;
.explorePage__featuredGrid {
display: flex;

4
src/pages/Explore/ExploreHero/ExploreHero.scss

@ -3,7 +3,7 @@
z-index: 2;
box-sizing: border-box;
width: min(100%, 1623px);
margin: 0;
margin: 0 auto;
padding-top: 0;
.explorePage__heroCards {
@ -60,4 +60,4 @@
height: 170px;
}
}
}
}

2
src/pages/Explore/index.scss

@ -12,7 +12,7 @@
.explorePage__feed {
box-sizing: border-box;
width: min(100%, 1623px);
margin: 34px 0 0;
margin: 34px auto 0;
padding: 0 0 clamp(32px, 3vw, 48px);
.explorePage__feedTabs {

Loading…
Cancel
Save