feat(layout): 优化底部路由导航
This commit is contained in:
parent
c78e3ed5ff
commit
a2c9f86df9
|
|
@ -5,7 +5,6 @@ import '../css/iconfont.css';
|
||||||
import '../css/iconfont-v2.css';
|
import '../css/iconfont-v2.css';
|
||||||
import './globals.css';
|
import './globals.css';
|
||||||
import { Providers } from '@/layout/Providers';
|
import { Providers } from '@/layout/Providers';
|
||||||
import ProgressBar from '@/layout/Providers/ProgressBar';
|
|
||||||
import Script from 'next/script';
|
import Script from 'next/script';
|
||||||
|
|
||||||
const poppins = Poppins({
|
const poppins = Poppins({
|
||||||
|
|
@ -46,7 +45,7 @@ export default async function RootLayout({
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en-US">
|
||||||
<body
|
<body
|
||||||
className={`${poppins.variable} ${oleoScriptSwashCaps.variable} ${NumDisplay.variable} antialiased`}
|
className={`${poppins.variable} ${oleoScriptSwashCaps.variable} ${NumDisplay.variable} antialiased`}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { useEffect, useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
export const useMedia = (config: Record<string, number>) => {
|
|
||||||
// 追踪客户端是否已挂载
|
|
||||||
const [mounted, setMounted] = useState(false);
|
|
||||||
const [response, setResponse] = useState<Record<keyof typeof config, boolean>>();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setMounted(true);
|
|
||||||
const onResize = () => {
|
|
||||||
const newResponse = Object.fromEntries(
|
|
||||||
Object.entries(config).map(([key, value]) => {
|
|
||||||
if (window.innerWidth > value) {
|
|
||||||
return [key, true];
|
|
||||||
}
|
|
||||||
return [key, false];
|
|
||||||
})
|
|
||||||
) as Record<keyof typeof config, boolean>;
|
|
||||||
setResponse(newResponse);
|
|
||||||
};
|
|
||||||
window.addEventListener('resize', onResize);
|
|
||||||
onResize();
|
|
||||||
return () => window.removeEventListener('resize', onResize);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (!mounted) return undefined;
|
|
||||||
|
|
||||||
return response;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 异步函数hook, 自动托管loading状态
|
* 异步函数hook, 自动托管loading状态
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,10 @@
|
||||||
import { usePathname } from 'next/navigation';
|
import { usePathname } from 'next/navigation';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
|
import { useRef } from 'react';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { useMedia } from '@/hooks/tools';
|
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
|
import { useSize } from 'ahooks';
|
||||||
|
|
||||||
export const items = [
|
export const items = [
|
||||||
{
|
{
|
||||||
|
|
@ -37,14 +38,18 @@ export const items = [
|
||||||
export default function BottomBar() {
|
export default function BottomBar() {
|
||||||
const t = useTranslations('bottomBar');
|
const t = useTranslations('bottomBar');
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const response = useMedia({ hide: 500 });
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
const size = useSize(containerRef);
|
||||||
|
|
||||||
if (!items.some((i) => i.path === pathname)) {
|
if (!items.some((i) => i.path === pathname)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-20 border-outline-normal bg-[rgba(10,14,43,1)] z-100 flex border-t items-center justify-between">
|
<div
|
||||||
|
ref={containerRef}
|
||||||
|
className="h-20 border-outline-normal bg-[rgba(10,14,43,1)] z-100 flex border-t items-center justify-between"
|
||||||
|
>
|
||||||
{items.map((item) => {
|
{items.map((item) => {
|
||||||
const isSelected = pathname === item.path;
|
const isSelected = pathname === item.path;
|
||||||
const label = t(item.labelKey as 'explore' | 'search' | 'chat' | 'me');
|
const label = t(item.labelKey as 'explore' | 'search' | 'chat' | 'me');
|
||||||
|
|
@ -63,7 +68,7 @@ export default function BottomBar() {
|
||||||
width={48}
|
width={48}
|
||||||
height={48}
|
height={48}
|
||||||
/>
|
/>
|
||||||
{response?.hide && <span>{label}</span>}
|
{size?.width && size.width > 500 && <span>{label}</span>}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ interface ConditionalLayoutProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化聊天
|
||||||
const useInitChat = () => {
|
const useInitChat = () => {
|
||||||
const { data } = useCurrentUser();
|
const { data } = useCurrentUser();
|
||||||
const connect = useStreamChatStore((state) => state.connect);
|
const connect = useStreamChatStore((state) => state.connect);
|
||||||
|
|
@ -31,24 +32,27 @@ const useInitChat = () => {
|
||||||
}, [data]);
|
}, [data]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ConditionalLayout({ children }: ConditionalLayoutProps) {
|
// 路由切换时重置滚动位置
|
||||||
|
const useAutoScrollOnRouteChange = (ref: React.RefObject<HTMLDivElement | null>) => {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const mainContentRef = useRef<HTMLDivElement>(null);
|
|
||||||
const prevPathnameRef = useRef<string>(pathname);
|
const prevPathnameRef = useRef<string>(pathname);
|
||||||
const response = useLayoutStore((s) => s.response);
|
|
||||||
|
|
||||||
// 初始化聊天
|
|
||||||
useInitChat();
|
|
||||||
|
|
||||||
// 路由切换时重置滚动位置
|
// 路由切换时重置滚动位置
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (prevPathnameRef.current !== pathname) {
|
if (prevPathnameRef.current !== pathname) {
|
||||||
if (mainContentRef.current) {
|
if (ref.current) {
|
||||||
mainContentRef.current.scrollTop = 0;
|
ref.current.scrollTop = 0;
|
||||||
}
|
}
|
||||||
prevPathnameRef.current = pathname;
|
prevPathnameRef.current = pathname;
|
||||||
}
|
}
|
||||||
}, [pathname]);
|
}, [pathname]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function ConditionalLayout({ children }: ConditionalLayoutProps) {
|
||||||
|
const mainContentRef = useRef<HTMLDivElement>(null);
|
||||||
|
const response = useLayoutStore((s) => s.response);
|
||||||
|
|
||||||
|
useInitChat();
|
||||||
|
useAutoScrollOnRouteChange(mainContentRef);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen bg-[url('/common-bg.png')] bg-[length:100%_30%] bg-top bg-no-repeat">
|
<div className="flex h-screen bg-[url('/common-bg.png')] bg-[length:100%_30%] bg-top bg-no-repeat">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue