void;
+ resProps: Object;
+};
+
+export const __Click_Modal__ = (props: __Click_modal__Type) => {
+ const { children, visible, closeModal, ...resProps } = props;
+ function handleClick(event: {
+ stopPropagation: () => void;
+ target: any;
+ currentTarget: any;
+ }) {
+ //点击蒙层本身时关闭模态框,点击模态框内容时不关闭
+ event.stopPropagation();
+ // event.nativeEvent.stopImmediatePropagation();
+ if (event.target === event.currentTarget) {
+ closeModal(event);
+ }
+ }
+ let modal;
+ typeof document !== "undefined" &&
+ (modal = createPortal(
+
+ {children}
+
,
+ document.body
+ ));
+ return <>{visible && modal}>;
+};
+
+type ModalType = {
+ isNoScroll: boolean;
+ children: ReactElement;
+ visible: boolean;
+ closeModal: (event: any) => void;
+};
+export default memo(function Modal(props: ModalType) {
+ const { isNoScroll = false, children, ...resProps } = props;
+ useEffect(() => {
+ if (isNoScroll) {
+ disableScroll();
+ return enableScroll;
+ }
+ }, [isNoScroll]);
+ //@ts-ignore
+ return <__Click_Modal__ {...resProps}>{children};
+});
+
+type useModalConfigOutputType = {
+ visible: boolean;
+ isNoScroll: boolean;
+ closeModal: () => void;
+};
+
+export const useModalConfig = (
+ _isvisible: boolean,
+ _isNoScroll: boolean
+): useModalConfigOutputType => {
+ const [isvisible, setVisible] = useState(_isvisible || false);
+ const [isNoScroll, setScroll] = useState(_isNoScroll || false);
+ const clickFunc = () => {
+ setScroll(!isNoScroll);
+ setVisible(!isvisible);
+ };
+ return { visible: isvisible, isNoScroll, closeModal: clickFunc };
+};
diff --git a/src/components/modal/modal.module.less b/src/components/modal/modal.module.less
new file mode 100644
index 0000000..5801b68
--- /dev/null
+++ b/src/components/modal/modal.module.less
@@ -0,0 +1,11 @@
+/* modal.less */
+.modal {
+ position: fixed;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ z-index: 1;
+ min-height: 100vh;
+ background-color: rgba(0, 0, 0, 0.7);
+}
\ No newline at end of file
diff --git a/src/components/modal/scrollFn.ts b/src/components/modal/scrollFn.ts
new file mode 100644
index 0000000..5524a8b
--- /dev/null
+++ b/src/components/modal/scrollFn.ts
@@ -0,0 +1,22 @@
+//@ts-nocheck
+//阻止默认行为
+export function preventDefault(e) {
+ // console.log({ e });
+ e.preventDefault();
+}
+
+export function enableScroll() {
+ const wheelEvent =
+ "onwheel" in document.createElement("div") ? "wheel" : "mousewheel";
+ window.removeEventListener("DOMMouseScroll", preventDefault, false);
+ window.removeEventListener(wheelEvent, preventDefault, { passive: false });
+ window.removeEventListener("touchmove", preventDefault, { passive: false });
+}
+
+export function disableScroll() {
+ const wheelEvent =
+ "onwheel" in document.createElement("div") ? "wheel" : "mousewheel";
+ window.addEventListener("DOMMouseScroll", preventDefault, false); // older FF
+ window.addEventListener(wheelEvent, preventDefault, { passive: false }); // modern desktop
+ window.addEventListener("touchmove", preventDefault, { passive: false }); // mobile
+}
diff --git a/src/components/proview/imageSize.tsx b/src/components/proview/imageSize.tsx
deleted file mode 100644
index 70c6ed2..0000000
--- a/src/components/proview/imageSize.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { useContext, useState, createContext, useEffect } from "react";
-import { thorttleFn } from "@utils/index";
-import { ReactChildrenType } from "./type";
-export const image_order_width = 200;
-
-const ImageContext = createContext<{ isShouldchangeSize: boolean }>({
- isShouldchangeSize: false,
-});
-
-const ImageShouldResizeProview = ({ children }: ReactChildrenType) => {
- const [isShouldchangeSize, setIs] = useState
(false);
- useEffect(() => {
- const handleWindowResize = () => {
- setIs(() => window.innerWidth < image_order_width * 2.5);
- };
- handleWindowResize();
- const handlerThrttleResize = thorttleFn(handleWindowResize, 10);
- window.addEventListener("resize", handlerThrttleResize);
- return () => window.removeEventListener("resize", handlerThrttleResize);
- }, []);
- return (
-
- {children}
-
- );
-};
-
-export const useImageShouldResize = () => {
- return useContext(ImageContext);
-};
-
-export default ImageShouldResizeProview;
diff --git a/src/components/proview/themePreview.tsx b/src/components/proview/themePreview.tsx
index f8cc3a4..9f4886d 100644
--- a/src/components/proview/themePreview.tsx
+++ b/src/components/proview/themePreview.tsx
@@ -36,9 +36,6 @@ declare module "@mui/material/Button" {
}
}
const theme = createTheme({
- typography: {
- fontFamily: "Proxima Soft",
- },
palette: {
luzao: { main: "#3dff9e", contrastText: "#fff" },
luzaoRed: { main: "#A0191D", contrastText: "#fff" },
diff --git a/src/main.tsx b/src/main.tsx
index 838daac..1c4256f 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -16,7 +16,6 @@ import "intersection-observer";
import "./normalize.css";
import "loading-attribute-polyfill";
import "./index.less";
-
const router = createBrowserRouter([
{
path: "/",
diff --git a/src/routers/error.tsx b/src/routers/error.tsx
index ca872ec..8eed330 100644
--- a/src/routers/error.tsx
+++ b/src/routers/error.tsx
@@ -1,3 +1,4 @@
+import message from "@components/message";
import { Button } from "@mui/material";
import { Link } from "react-router-dom";
@@ -24,11 +25,15 @@ export default function ErrorPage() {
- 和
-
+ 、
+
- 两个页面(虽然两个是同一个页面)。
+ 和
+
+
+
+ 。
请尝试点击链接
@@ -49,4 +54,5 @@ export default function ErrorPage() {
const deleteAllDataStorage = () => {
localStorage.clear();
sessionStorage.clear();
+ message.info("重置网站数据成功!");
};
diff --git a/src/routers/layout/header.tsx b/src/routers/layout/header.tsx
index e9f5052..c153dfb 100644
--- a/src/routers/layout/header.tsx
+++ b/src/routers/layout/header.tsx
@@ -1,19 +1,37 @@
-import { useSearchFocus } from "@components/proview/searchFocus";
-import { Flipped } from "react-flip-toolkit";
import styles from "./layout.module.less";
import LOGO from "./logo";
-import RightSide from "./rightSide";
-import Search from "./search";
+import RouterNav from "./routernav";
+import { useAppDispatch } from "@store/hooks";
+import { useLocation } from "react-router-dom";
+import { useEffect, useMemo } from "react";
+import { changeLoadingCauseByUrl } from "@store/loading";
+import { routerNameToLoading } from "@utils/router";
+import { styled } from "@mui/material";
export default function Header() {
- // const { focused } = useSearchFocus();
- return (
- //
-
- {/* {!focused && }
-
- {!focused && } */}
-
-
- //
+ const dispatch = useAppDispatch(),
+ location = useLocation();
+ useEffect(() => {
+ dispatch(
+ changeLoadingCauseByUrl({
+ stateName: routerNameToLoading(location.pathname),
+ })
+ );
+ }, [location.pathname]);
+ const JSXRes = useMemo(
+ () => (
+
+
+
+
+ ),
+ []
);
+ return <>{JSXRes}>;
}
+const Header_header = styled("header")(({ theme }) => ({
+ flexDirection: "row",
+ [theme.breakpoints.down("sm")]: {
+ flexDirection: "row-reverse",
+ justifyContent: "flex-end",
+ },
+}));
diff --git a/src/routers/layout/index.tsx b/src/routers/layout/index.tsx
index 3f5ab14..78c1011 100644
--- a/src/routers/layout/index.tsx
+++ b/src/routers/layout/index.tsx
@@ -4,16 +4,13 @@ import Header from "./header";
import Header_Nav from "./nav";
import { useAppSelector } from "@store/hooks";
import { selectNavMoreShowed } from "@store/device/index";
-import { useSearchFocus } from "@components/proview/searchFocus";
import styles from "./layout.module.less";
export default function Layout() {
- const showed = useAppSelector(selectNavMoreShowed),
- { focused } = useSearchFocus();
-
+ const showed = useAppSelector(selectNavMoreShowed);
return (
<>
-
-
+
+
diff --git a/src/routers/layout/layout.module.less b/src/routers/layout/layout.module.less
index 851856c..06ea5b4 100644
--- a/src/routers/layout/layout.module.less
+++ b/src/routers/layout/layout.module.less
@@ -17,105 +17,4 @@
display: flex;
align-items: center;
background-color: #fff;
-}
-
-.logo {
- display: flex;
- align-items: center;
-
- a {
- color: inherit;
- text-decoration: none;
- }
-
- &>a:only-child {
- display: flex;
- position: relative;
- flex-flow: row-reverse nowrap;
- align-items: center;
- padding: 5px 0;
-
- h1 {
- margin: 0;
- white-space: nowrap;
-
- button {
- position: absolute;
- transform: translate(-20px, -10px);
- }
- }
- }
-}
-
-.modal {
- position: absolute;
- left: 50%;
- top: 50%;
- transform: translate(-50%, -50%);
- background-color: #fff;
- border-radius: 4px;
- padding: 15px 10px;
- max-width: 400px;
- width: 90%;
-
-
-
-
- ul {
- display: flex;
- flex-flow: column nowrap;
- max-height: 60vh;
- overflow-y: auto;
- overflow-x: hidden;
- }
-
- li {
- margin: 10px;
- list-style: none;
- box-sizing: border-box;
-
- &>p:not(:last-of-type) {
- margin-bottom: 12px;
- color: grey;
- }
-
- &>p {
- display: flex;
-
- strong {
- flex: 0 0 25px;
- }
- }
-
-
- }
-}
-
-
-.line_text {
- width: 100%;
- // color: #a2a9b6;
- border: 0;
- font-size: 14px;
- padding: 1em 0;
- position: relative;
- -webkit-mask-image: linear-gradient(to right,
- transparent,
- black,
- transparent);
- mask-image: linear-gradient(to right, transparent, black, transparent);
-
- &::before {
- content: attr(data-content);
- position: absolute;
- padding: 0 1ch;
- line-height: 1px;
- border: solid #d0d0d5;
- border-width: 0 99vw;
- width: fit-content;
- /* for 不支持fit-content浏览器 */
- white-space: nowrap;
- left: 50%;
- transform: translateX(-50%);
- }
}
\ No newline at end of file
diff --git a/src/routers/layout/logo.tsx b/src/routers/layout/logo.tsx
deleted file mode 100644
index b7e1f59..0000000
--- a/src/routers/layout/logo.tsx
+++ /dev/null
@@ -1,143 +0,0 @@
-import { Button, Modal, styled } from "@mui/material";
-import { FC, useState } from "react";
-import { Link } from "react-router-dom";
-import styles from "./layout.module.less";
-
-export default function LOGO() {
- const [open, set] = useState(false),
- handlerClick = () => set((open) => !open);
- return (
-
-
-
- EOEfans-web端
-
-
-
-
-
- -
-
- Q:
- 为什么界面这么丑?
-
-
- A:
- web端没有UI捏🙇♂️🙇♂️🙇♂️果咩。
-
-
- -
-
- Q:
- 如何查找我想看的视频类型?
-
-
- A:
-
- 😩目前只能通过点击下方tag栏进行查询,其中各分区、原创和转载、
- 最新发布和最多播放互斥外其他tag皆满足异或查询。
-
- 🤔tag排序不是固定的,可以使用鼠标或者触摸按住tag半秒后进行移动。
-
- 🤗可以自定义任何你想要的tag栏顺序,下一次访问也有效。
-
-
-
- -
-
- Q:
- 露早tag为什么不是应援色?
-
-
- A:
-
- 露早GOGO的应援色为
-
- #3dff9e
-
- ,tag字面显示不明显,所以更换为黑露早形态的
- #A0191D
-
-
-
-
-
-
-
-
-
-
-
- );
-}
-const H1 = styled("h1")(({ theme }) => ({
- fontSize: "24px",
- [theme.breakpoints.down("sm")]: {
- fontSize: "15px",
- },
-}));
-
-//todo 修改logo
-
-const Yituo: FC<{
- height: number | string;
- width: number | string;
-}> = ({ height, width }) => (
-
-);
diff --git a/src/routers/layout/logo/index.tsx b/src/routers/layout/logo/index.tsx
new file mode 100644
index 0000000..61129b2
--- /dev/null
+++ b/src/routers/layout/logo/index.tsx
@@ -0,0 +1,71 @@
+import { Button, Badge } from "@mui/material";
+import { useState, useMemo, FC } from "react";
+import { H1, Explain, Yituo } from "./modal";
+import styles from "./logo.module.less";
+import { Storage } from "../tools";
+
+const QAStorage = new Storage("QAUpdate");
+//暂时先这样
+const _qa_update_time = `2023-2-2`;
+const useCheckQANews = () => {
+ const local_qa_value = useMemo(() => {
+ return QAStorage.getLocalStorage("");
+ }, []);
+ const [shouldShowNews, set] = useState(local_qa_value !== _qa_update_time),
+ handlerReadedNews = () => {
+ QAStorage.setLocalstorage(_qa_update_time);
+ set(() => false);
+ };
+ return [shouldShowNews, handlerReadedNews] as [boolean, () => void];
+};
+
+export default function LOGO() {
+ const [open, set] = useState(false);
+ const [shouldShowNews, handlerReadedNews] = useCheckQANews();
+ const handlerClick = () => {
+ set((open) => !open);
+ handlerReadedNews();
+ };
+ return (
+
+
+ EOEfans-web端
+
+
+
+
+
+ );
+}
+
+const Show_news: FC<{ visible: boolean }> = ({ visible }) => (
+
+
+
+);
diff --git a/src/routers/layout/logo/logo.module.less b/src/routers/layout/logo/logo.module.less
new file mode 100644
index 0000000..3beb0bc
--- /dev/null
+++ b/src/routers/layout/logo/logo.module.less
@@ -0,0 +1,94 @@
+.logo {
+ display: flex;
+ align-items: center;
+ flex-flow: row-reverse nowrap;
+ padding: 5px 0;
+
+ a {
+ color: inherit;
+ text-decoration: none;
+ }
+
+
+
+ h1 {
+ margin: 0;
+ white-space: nowrap;
+ position: relative;
+ padding-right: 30px;
+ }
+
+}
+
+.modal {
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ background-color: #fff;
+ border-radius: 4px;
+ padding: 15px 10px;
+ max-width: 400px;
+ width: 90%;
+
+
+
+
+ ul {
+ display: flex;
+ flex-flow: column nowrap;
+ max-height: 60vh;
+ overflow-y: auto;
+ overflow-x: hidden;
+ }
+
+ li {
+ margin: 10px;
+ list-style: none;
+ box-sizing: border-box;
+
+ &>p:not(:last-of-type) {
+ margin-bottom: 12px;
+ color: grey;
+ }
+
+ &>p {
+ display: flex;
+
+ strong {
+ flex: 0 0 25px;
+ }
+ }
+
+
+ }
+}
+
+
+.line_text {
+ width: 100%;
+ // color: #a2a9b6;
+ border: 0;
+ font-size: 14px;
+ padding: 1em 0;
+ position: relative;
+ -webkit-mask-image: linear-gradient(to right,
+ transparent,
+ black,
+ transparent);
+ mask-image: linear-gradient(to right, transparent, black, transparent);
+
+ &::before {
+ content: attr(data-content);
+ position: absolute;
+ padding: 0 1ch;
+ line-height: 1px;
+ border: solid #d0d0d5;
+ border-width: 0 99vw;
+ width: fit-content;
+ /* for 不支持fit-content浏览器 */
+ white-space: nowrap;
+ left: 50%;
+ transform: translateX(-50%);
+ }
+}
\ No newline at end of file
diff --git a/src/routers/layout/logo/modal.tsx b/src/routers/layout/logo/modal.tsx
new file mode 100644
index 0000000..135c03a
--- /dev/null
+++ b/src/routers/layout/logo/modal.tsx
@@ -0,0 +1,166 @@
+import { Button, Link, Modal, styled } from "@mui/material";
+import { FC } from "react";
+import styles from "./logo.module.less";
+
+export const Explain: FC<{ open: boolean; handlerClick: () => void }> = (
+ props
+) => (
+ <>
+
+
+
+
+
+
+
+ >
+);
+
+export const H1 = styled("h1")(({ theme }) => ({
+ fontSize: "24px",
+ [theme.breakpoints.down("sm")]: {
+ fontSize: "15px",
+ },
+}));
+
+export const QA = () => (
+
+ -
+
+ Q:
+ 为什么界面这么丑?
+
+
+ A:
+ web端没有UI捏🙇♂️🙇♂️🙇♂️果咩。
+
+
+ -
+
+ Q:
+ 如何查找我想看的视频类型?
+
+
+ A:
+
+ 😩目前只能通过点击下方tag栏进行查询,其中各分区、原创和转载、
+ 最新发布和最多播放互斥外其他tag皆满足异或查询。
+
+ 🤔tag排序不是固定的,可以使用鼠标或者触摸按住tag半秒后进行移动。
+
+ 🤗可以自定义任何你想要的tag栏顺序,下一次访问也有效。
+
+
+
+ -
+
+ Q:
+ 露早tag为什么不是应援色?
+
+
+ A:
+
+ 露早GOGO的应援色为
+
+ #3dff9e
+
+ ,tag字面显示不明显,所以更换为黑露早形态的
+ #A0191D
+
+
+
+ -
+
+ Q:
+ 如何进行用户反馈?
+
+
+ A:
+
+ 请前往
+
+ eoefans反馈
+
+
+
+
+ -
+
+ Q:
+ 图片页图片太小了?
+
+
+ A:
+
+ 图片页可点击图片进入放大镜模式,支持手势返回和空白处返回;可使用双指放大对图片大小进行调整。
+
+
+
+
+);
+
+export const Yituo: FC<{
+ height: number | string;
+ width: number | string;
+}> = ({ height, width }) => (
+
+);
diff --git a/src/routers/layout/nav/tools.ts b/src/routers/layout/nav/VideoTools.ts
similarity index 78%
rename from src/routers/layout/nav/tools.ts
rename to src/routers/layout/nav/VideoTools.ts
index 3de3859..4b8c25e 100644
--- a/src/routers/layout/nav/tools.ts
+++ b/src/routers/layout/nav/VideoTools.ts
@@ -3,35 +3,35 @@ import { useMemo, useState } from "react";
import { Storage } from "../tools";
import { getVersion } from "@utils/index";
-interface DnavStorage {
+export interface VideoNavStorage {
version: string;
- res: NavQueryItemType[];
+ res: VideoNavQueryItemType[];
}
-export const NavStorage = new Storage("navTagLists");
+export const VideoNavStorage = new Storage("navTagLists");
-export function useNavList(): [
- NavQueryItemType[],
- React.Dispatch>
+export function useVideoNavList(): [
+ VideoNavQueryItemType[],
+ React.Dispatch>
] {
const nav_ok_lists = useMemo(() => {
- const local_lists = NavStorage.getLocalStorage({
+ const local_lists = VideoNavStorage.getLocalStorage({
version: getVersion(),
res: [],
- } as DnavStorage);
+ } as VideoNavStorage);
if (!local_lists.version) {
- return query_nav_list;
+ return video_query_nav_list;
}
//todo 修改逻辑
if (parseFloat(local_lists.version) < parseFloat(getVersion())) {
- return query_nav_list;
+ return video_query_nav_list;
}
if (PassNavList(local_lists.res)) {
return local_lists.res;
}
- return query_nav_list;
+ return video_query_nav_list;
}, []);
- const [navLists, setLists] = useState(nav_ok_lists);
+ const [navLists, setLists] = useState(nav_ok_lists);
return [navLists, setLists];
}
// 判断类型
@@ -49,7 +49,7 @@ function checkPropertyType(
return input.hasOwnProperty(property) && typeof input[property] === type;
}
//检测从localstorage提取的querylist是否满足条件
-function PassNavList(lists: NavQueryItemType[]) {
+function PassNavList(lists: VideoNavQueryItemType[]) {
if (
lists.length > 0 &&
lists.every((item) => {
@@ -102,7 +102,7 @@ export type NavRouterItemType = {
name: string;
cancelable: boolean;
};
-export type NavQueryItemType = {
+export type VideoNavQueryItemType = {
id: string;
type: "query";
query: string;
@@ -110,8 +110,8 @@ export type NavQueryItemType = {
queryString: string;
cancelable: boolean;
};
-export type NavListItemType = NavQueryItemType | NavRouterItemType;
-const nav_tag_list_no_id: Omit[] = [
+export type NavListItemType = VideoNavQueryItemType | NavRouterItemType;
+const nav_tag_list_no_id: Omit[] = [
{
type: "query",
query: "露早",
@@ -197,25 +197,10 @@ const nav_tag_list_no_id: Omit[] = [
queryString: "view",
},
],
- query_nav_list = nav_tag_list_no_id.map((item) => ({
+ video_query_nav_list = nav_tag_list_no_id.map((item) => ({
...item,
id: nanoid(3),
cancelable: false,
- })) as NavQueryItemType[];
-const router_list: Omit[] = [
- {
- type: "router",
- pathname: "photo",
- name: "图片",
- },
- {
- type: "router",
- pathname: "video",
- name: "视频",
- },
-];
-export const router_nav_list = router_list.map((item) => ({
- ...item,
- id: nanoid(3),
- cancelable: false,
-})) as NavRouterItemType[];
+ })) as VideoNavQueryItemType[];
+
+export const VideoQueryNavList = video_query_nav_list;
diff --git a/src/routers/layout/nav/index.tsx b/src/routers/layout/nav/index.tsx
index d17645d..1375210 100644
--- a/src/routers/layout/nav/index.tsx
+++ b/src/routers/layout/nav/index.tsx
@@ -18,18 +18,45 @@ import { restrictToParentElement } from "@dnd-kit/modifiers";
import styles from "./nav.module.less";
import { FC, useMemo, memo } from "react";
import { Flipped } from "react-flip-toolkit";
-import { NavQueryItemType, useNavList, NavStorage } from "./tools";
+import {
+ VideoNavQueryItemType,
+ useVideoNavList,
+ VideoNavStorage,
+} from "./VideoTools";
import { useAppSelector, useAppDispatch } from "@store/hooks";
import { changeNavMoreShowed, selectNavMoreShowed } from "@store/device/index";
import { getVersion } from "@utils/index";
-import { selectVideoLoadingState } from "@store/loading/index";
import {
- handerAddTag,
- handerDeleteTag,
- selectActiveTags,
+ selectPhotoLoadingState,
+ selectVideoLoadingState,
+} from "@store/loading/index";
+import { useLocation } from "react-router-dom";
+import {
+ PhotoNavQueryItemType,
+ PhotoNavStorage,
+ usePhotoNavList,
+} from "./photoTools";
+import {
+ handerPhotoAddTag,
+ handerPhotoDeleteTag,
+ handerVideoAddTag,
+ handerVideoDeleteTag,
+ selectPhotoActiveTags,
+ selectVideoActiveTags,
} from "@store/tags/index";
+
+function useSelectList() {
+ const { pathname } = useLocation(),
+ flag = pathname === "/photo",
+ storageSelect = flag ? PhotoNavStorage : VideoNavStorage;
+ const PhotoHook = usePhotoNavList(),
+ VideoHook = useVideoNavList();
+ const [navLists, setLists] = flag ? PhotoHook : VideoHook;
+ return { navLists, setLists, storageSelect };
+}
+
export default function Header_Nav() {
- const [navLists, setLists] = useNavList();
+ const { navLists, setLists, storageSelect } = useSelectList();
//tag区是否展开
const showed = useAppSelector(selectNavMoreShowed);
//拖拽事件绑定
@@ -53,11 +80,11 @@ export default function Header_Nav() {
function handleDragEnd(event: DragEndEvent) {
const { active, over } = event;
if (over && active.id !== over.id) {
- setLists((items) => {
+ setLists((items: any[]) => {
const oldIndex = items.findIndex((item) => item.id === active.id),
newIndex = items.findIndex((item) => item.id === over.id),
newLists = arrayMove(items, oldIndex, newIndex);
- NavStorage.setLocalstorage({
+ storageSelect.setLocalstorage({
version: getVersion(),
res: newLists,
});
@@ -69,7 +96,7 @@ export default function Header_Nav() {
() => (
<>
{navLists.map((item) => (
-
+
))}
>
),
@@ -93,7 +120,9 @@ export default function Header_Nav() {
}}
data-showed={showed}
>
- {ComRes}
+
+ {ComRes}
+
@@ -117,7 +146,7 @@ const NavInViewItem = () => {
width: "1px",
}}
>
-
+
dispatch(changeNavMoreShowed())}
@@ -136,58 +165,78 @@ const NavInViewItem = () => {
);
};
-const NavItem: FC
= memo((props) => {
- const { attributes, listeners, setNodeRef, transform, transition } =
- useSortable({ id: props.id });
- const style = {
- transform: CSS.Translate.toString(transform),
- transition,
- };
- return (
-
-
-
-
-
- );
-});
+const NavItem: FC = memo(
+ (props) => {
+ const { attributes, listeners, setNodeRef, transform, transition } =
+ useSortable({ id: props.id as string });
+ const style = {
+ transform: CSS.Translate.toString(transform),
+ transition,
+ };
+ return (
+
+
+
+
+
+ );
+ }
+);
-const NavTagChipItem: FC = memo((props) => {
- const clicked = useAppSelector(selectActiveTags).some(
- (item) => item.id === props.id
- ),
+const useTagSelect = () => {
+ const { pathname } = useLocation(),
+ flag = pathname === "/photo",
+ tag_lists = flag
+ ? useAppSelector(selectPhotoActiveTags)
+ : useAppSelector(selectVideoActiveTags),
+ loading = flag
+ ? useAppSelector(selectPhotoLoadingState)
+ : useAppSelector(selectVideoLoadingState),
dispatch = useAppDispatch(),
- handerclick = () => {
+ addTagFunc = flag ? handerPhotoAddTag : handerVideoAddTag,
+ deleteFunc = flag ? handerPhotoDeleteTag : handerVideoDeleteTag;
+
+ return { tag_lists, loading, dispatch, addTagFunc, deleteFunc };
+};
+
+const NavTagChipItem: FC = memo(
+ (props) => {
+ const { tag_lists, loading, dispatch, addTagFunc, deleteFunc } =
+ useTagSelect();
+ const clicked = tag_lists.some((item) => item.query === props.query);
+ const handerclick = () => {
if (clicked) {
- dispatch(handerDeleteTag(props));
+ //@ts-ignore
+ dispatch(deleteFunc(props));
} else {
- dispatch(handerAddTag(props));
+ //@ts-ignore
+ dispatch(addTagFunc(props));
}
- },
- isVideoFetching = useAppSelector(selectVideoLoadingState),
+ };
//@ts-ignore
- color = nameToColor[props.query] || "info";
- return (
-
- );
-});
+ const color = nameToColor[props.query] || "info";
+ return (
+
+ );
+ }
+);
const nameToColor = {
露早: "luzaoRed",
diff --git a/src/routers/layout/nav/photoTools.ts b/src/routers/layout/nav/photoTools.ts
new file mode 100644
index 0000000..7b12cc4
--- /dev/null
+++ b/src/routers/layout/nav/photoTools.ts
@@ -0,0 +1,108 @@
+import { nanoid } from "nanoid";
+import { useMemo, useState } from "react";
+import { Storage } from "../tools";
+import { getVersion } from "@utils/index";
+import { IFetchPhotoParams } from "@utils/fetch/fetchtype";
+
+export interface PhotoNavStorage {
+ version: string;
+ res: PhotoNavQueryItemType[];
+}
+export const PhotoNavStorage = new Storage("photonavTagLists");
+
+export function usePhotoNavList(): [
+ PhotoNavQueryItemType[],
+ React.Dispatch>
+] {
+ const nav_ok_lists = useMemo(() => {
+ const local_lists = PhotoNavStorage.getLocalStorage({
+ version: getVersion(),
+ res: [],
+ } as PhotoNavStorage);
+ if (!local_lists.version || local_lists.res.length < 2) {
+ return photo_query_nav_list;
+ }
+ //todo change logi
+ if (parseFloat(local_lists.version) < parseFloat(getVersion())) {
+ return photo_query_nav_list;
+ }
+ return local_lists.res;
+ }, []);
+ const [navLists, setLists] = useState(nav_ok_lists);
+ return [navLists, setLists];
+}
+
+export type PhotoTopicType = {
+ id: String;
+ type: "photo-selected";
+ query: string;
+ queryType: "topic_id";
+ queryString: IFetchPhotoParams["topic_id"];
+};
+export type PhotoSearchType = {
+ id: String;
+ type: "photo-selected";
+ query: string;
+ queryType: "type";
+ queryString: IFetchPhotoParams["type"];
+};
+
+export type PhotoNavQueryItemType = PhotoTopicType | PhotoSearchType;
+
+const nav_tag_list_no_id: Pick<
+ PhotoNavQueryItemType,
+ "query" | "queryString" | "queryType"
+ >[] = [
+ {
+ query: "最新图片",
+ queryType: "type",
+ queryString: "latest",
+ },
+ {
+ query: "推荐图片",
+ queryType: "type",
+ queryString: "recommend",
+ },
+ {
+ query: "全部",
+ queryType: "topic_id",
+ queryString: 0,
+ },
+ {
+ query: "露早",
+ queryType: "topic_id",
+ queryString: 29067608,
+ },
+ {
+ query: "柚恩",
+ queryType: "topic_id",
+ queryString: 28950030,
+ },
+ {
+ query: "莞儿",
+ queryType: "topic_id",
+ queryString: 28953983,
+ },
+ {
+ query: "米诺",
+ queryType: "topic_id",
+ queryString: 29069147,
+ },
+ {
+ query: "虞莫",
+ queryType: "topic_id",
+ queryString: 28948378,
+ },
+ {
+ query: "EOE组合",
+ queryType: "topic_id",
+ queryString: 29156150,
+ },
+ ],
+ photo_query_nav_list = nav_tag_list_no_id.map((item) => ({
+ ...item,
+ id: nanoid(3),
+ type: "photo-selected",
+ })) as PhotoNavQueryItemType[];
+
+export const PhotoQueryNavList = photo_query_nav_list;
diff --git a/src/routers/layout/routernav/index.tsx b/src/routers/layout/routernav/index.tsx
index 0aa1f0d..88172e4 100644
--- a/src/routers/layout/routernav/index.tsx
+++ b/src/routers/layout/routernav/index.tsx
@@ -1,29 +1,61 @@
-import { Button, ButtonGroup, Stack } from "@mui/material";
-import { useMemo } from "react";
-import { NavLink } from "react-router-dom";
-import { useRouterList } from "./tools";
+import { Tab, Tabs } from "@mui/material";
+import { useState, useEffect, useCallback, memo } from "react";
+import { Link, useLocation } from "react-router-dom";
+import { useScreenSize } from "@components/proview/screenSize";
+import MenuRouter from "./menu";
+
+export const RouterList: TabProps[] = [
+ {
+ label: "视频",
+ to: "/video",
+ },
+ {
+ label: "图片",
+ to: "/photo",
+ },
+];
export default function RouterNav() {
- const routerlists = useRouterList(),
- routerRes = useMemo(
- () =>
- routerlists.map((item) => (
-
-
-
- )),
- [routerlists]
- );
+ const { pathname } = useLocation(),
+ handler = () => (pathname === "/photo" ? 1 : 0);
+ const [value, set] = useState(handler),
+ changehandler = useCallback(() => set(handler), [handler]);
+ useEffect(() => {
+ changehandler();
+ }, [pathname]);
+ const { sm } = useScreenSize();
+ return (
+ <>
+ {sm ? (
+
+ ) : (
+
+ {RouterList.map((item, index) => (
+
+ ))}
+
+ )}
+ >
+ );
+}
+export type TabProps = {
+ label: string;
+ to: string;
+};
+export function TabLink(props: TabProps) {
+ const { pathname } = useLocation();
return (
-
-
- {routerRes}
-
-
+
);
}
diff --git a/src/routers/layout/routernav/menu.tsx b/src/routers/layout/routernav/menu.tsx
new file mode 100644
index 0000000..3bb2b2d
--- /dev/null
+++ b/src/routers/layout/routernav/menu.tsx
@@ -0,0 +1,41 @@
+import { Menu, Button, MenuItem } from "@mui/material";
+import { Omit } from "@utils/index";
+import PopupState, { bindTrigger, bindMenu } from "material-ui-popup-state";
+import { RouterList, TabProps, TabLink } from ".";
+export default function MenuRouter() {
+ return (
+
+ {(popupState) => (
+ <>
+
+
+ >
+ )}
+
+ );
+}
+function RouterItem(props: TabProps & { onClick: () => void }) {
+ return (
+
+ );
+}
diff --git a/src/routers/layout/routernav/tools.ts b/src/routers/layout/routernav/tools.ts
deleted file mode 100644
index 401cab2..0000000
--- a/src/routers/layout/routernav/tools.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { NavRouterItemType, router_nav_list } from "../nav/tools";
-import { useState } from "react";
-export function useRouterList(): NavRouterItemType[] {
- const [list, _] = useState(router_nav_list);
- return list;
-}
diff --git a/src/routers/layout/tools.ts b/src/routers/layout/tools.ts
index 6a3dfb3..66bc376 100644
--- a/src/routers/layout/tools.ts
+++ b/src/routers/layout/tools.ts
@@ -5,7 +5,7 @@ export class Storage {
}
private getStorage(Storagename: globalThis.Storage, defaultRes: T): T {
if (!Storagename) {
- return Storagename;
+ return defaultRes;
}
if (!Storagename.getItem(this.itemName)) {
Storagename.setItem(this.itemName, JSON.stringify(defaultRes));
@@ -28,4 +28,7 @@ export class Storage {
setSessionStorage(targetRes: T): void {
this.setStorage(sessionStorage, targetRes);
}
+ clearLocalstorage(): void {
+ localStorage.removeItem(this.itemName);
+ }
}
diff --git a/src/routers/photo.tsx b/src/routers/photo.tsx
deleted file mode 100644
index c036aca..0000000
--- a/src/routers/photo.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-export default function PhotoPage() {
- return (
-
- 🙇♂️🙇♂️🙇♂️二创图片页还在制作中,敬请期待!
-
- );
-}
diff --git a/src/routers/photo/index.tsx b/src/routers/photo/index.tsx
new file mode 100644
index 0000000..38b5904
--- /dev/null
+++ b/src/routers/photo/index.tsx
@@ -0,0 +1,23 @@
+import Masonry from "./masonry";
+import { useAppSelector } from "@store/hooks";
+import { selectPhotoActiveTags } from "@store/tags";
+import {
+ PhotoSearchType,
+ PhotoTopicType,
+} from "@routers/layout/nav/photoTools";
+
+export default function PhotoPage() {
+ const activeTags = useAppSelector(selectPhotoActiveTags),
+ typeitem = activeTags.find(
+ (item) => item.queryType === "type"
+ )! as PhotoSearchType,
+ topicItem = activeTags.find(
+ (item) => item.queryType === "topic_id"
+ ) as PhotoTopicType;
+
+ return (
+ <>
+
+ >
+ );
+}
diff --git a/src/routers/photo/item/index.tsx b/src/routers/photo/item/index.tsx
new file mode 100644
index 0000000..d535e40
--- /dev/null
+++ b/src/routers/photo/item/index.tsx
@@ -0,0 +1,83 @@
+import { PhotoRouterImageCardType } from "../phototype";
+import { useState } from "react";
+import ImgModals from "./modal";
+import ChevronRightIcon from "@mui/icons-material/ChevronRight";
+import { Link, styled } from "@mui/material";
+import style from "./photo.module.less";
+import { ImageBasic } from "@components/image";
+import { Omit } from "@utils/index";
+import CollectionsIcon from "@mui/icons-material/Collections";
+type CardType = {
+ data: PhotoRouterImageCardType;
+};
+
+export default function PhotoCard(props: CardType) {
+ const { images, dynamic_id, ...resPorps } = props.data;
+ const [open, set] = useState(false),
+ handlerChangeOpen = () => set((open) => !open);
+ const modalPorps = { open, images, onClose: handlerChangeOpen };
+ return (
+
+
+
+
+
+
+
+
+ {images.length > 1 && (
+
+
+ {images.length}
+
+ )}
+
+ );
+}
+
+const DivImgNum = styled("div")(({ theme }) => ({
+ position: "absolute",
+ right: "0px",
+ top: "0px",
+ padding: "7px",
+ color: "white",
+ backgroundColor: "rgba(0, 0, 0, 0.4)",
+ display: "flex",
+ justifyContent: "center",
+ alignItems: "center",
+ columnGap: "2px",
+ pointerEvents: "none",
+ fontSize: "14px",
+}));
+
+const DivJump = styled("div")(({ theme }) => ({
+ borderBottomLeftRadius: "8px",
+ borderBottomRightRadius: "8px",
+ position: "absolute",
+ bottom: "0px",
+ width: "100%",
+ backgroundImage: `linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(90, 90,90, 0.8) 100%)`,
+ "&:hover": {
+ backgroundImage: `linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0,0, 0.8) 100%)`,
+ },
+ [theme.breakpoints.down("sm")]: {
+ borderBottomLeftRadius: "4px",
+ borderBottomRightRadius: "4px",
+ },
+}));
diff --git a/src/routers/photo/item/modal.tsx b/src/routers/photo/item/modal.tsx
new file mode 100644
index 0000000..abc3f09
--- /dev/null
+++ b/src/routers/photo/item/modal.tsx
@@ -0,0 +1,39 @@
+import { basicImageType } from "../phototype";
+import { PhotoSlider } from "react-photo-view";
+import "react-photo-view/dist/react-photo-view.css";
+import { useEffect } from "react";
+import { useLocation } from "react-router-dom";
+type ModalType = {
+ images: basicImageType[];
+ open: boolean;
+ onClose: () => void;
+};
+
+export default function ImgModals(props: ModalType) {
+ const { open, onClose, images } = props;
+ const location = useLocation();
+ useEffect(() => {
+ let flag = false;
+ const handler = () => {
+ flag = true;
+ onClose();
+ };
+ if (open) {
+ history.pushState(null, "", location.pathname);
+ window.addEventListener("popstate", handler, {
+ once: true,
+ });
+ return () => {
+ !flag && history.back();
+ window.removeEventListener("popstate", handler);
+ };
+ }
+ }, [open]);
+ return (
+ ({ src: item.src, key: index }))}
+ visible={open}
+ onClose={onClose}
+ />
+ );
+}
diff --git a/src/routers/photo/item/photo.module.less b/src/routers/photo/item/photo.module.less
new file mode 100644
index 0000000..06a560e
--- /dev/null
+++ b/src/routers/photo/item/photo.module.less
@@ -0,0 +1,8 @@
+.card {
+ position: relative;
+ border-radius: 4px;
+
+ .show-img {
+ min-height: 150px;
+ }
+}
\ No newline at end of file
diff --git a/src/routers/photo/masonry.tsx b/src/routers/photo/masonry.tsx
new file mode 100644
index 0000000..7cf9eed
--- /dev/null
+++ b/src/routers/photo/masonry.tsx
@@ -0,0 +1,83 @@
+import { selectPhotoLoadingState } from "@store/loading";
+import { Masonry as Masonic_masonry } from "masonic";
+import { useState, useEffect } from "react";
+import { useAppSelector, useAppDispatch } from "@store/hooks";
+
+import { changeLoading } from "@store/loading/index";
+import { fetchPhotoHandler } from "./tools";
+import { PhotoRouterImageCardType, PhotoRouterMasonryType } from "./phototype";
+import PhotoCard from "./item";
+import { useScreenSize } from "@components/proview/screenSize";
+import message from "@components/message";
+import styles from "./photo.module.less";
+//todo props type change
+export default function Masonry(props: PhotoRouterMasonryType) {
+ const [lists, setList] = useState([]);
+ const isLoading = useAppSelector(selectPhotoLoadingState),
+ dispatch = useAppDispatch(),
+ handerChangeLoading = (state: boolean) =>
+ dispatch(
+ changeLoading({
+ stateName: "photoIsloading",
+ Tostate: state,
+ })
+ );
+ useEffect(() => {
+ const fetchHandler = async (page: number = 0) => {
+ const data = await fetchPhotoHandler({
+ page,
+ ...props,
+ });
+ setList((lists) => {
+ return [
+ ...lists,
+ ...data.map((item, index) => {
+ const itemRes = {
+ dynamic_id: item.dynamic_id,
+ images: item.pictures.map((img) => ({
+ src: img.img_src,
+ height: img.img_height,
+ width: img.img_width,
+ })),
+ };
+ if (data.length < 3) {
+ message.info("没有更多图片了,尝试使用其他tag吧!");
+ }
+ if (index === data.length - 3) {
+ return {
+ ...itemRes,
+ observer: true,
+ callback: (inView: boolean) => {
+ fetchHandler(page + 1);
+ },
+ };
+ }
+ return itemRes;
+ }),
+ ];
+ });
+ };
+ setList(() => []);
+ handerChangeLoading(true);
+ fetchHandler(1).then(() => handerChangeLoading(false));
+ }, [props]);
+ const { sm, md } = useScreenSize(),
+ minCount = sm ? { columnCount: 2 } : {};
+ return (
+
+ {isLoading || (
+
+ )}
+
+ );
+}
diff --git a/src/routers/photo/photo.module.less b/src/routers/photo/photo.module.less
new file mode 100644
index 0000000..2cf7492
--- /dev/null
+++ b/src/routers/photo/photo.module.less
@@ -0,0 +1,10 @@
+.container:empty {
+ display: flex;
+ justify-content: center;
+
+ &::before {
+ margin-top: 50px;
+ content: "暂无数据";
+ color: #c1c1c1;
+ }
+}
\ No newline at end of file
diff --git a/src/routers/photo/phototype.ts b/src/routers/photo/phototype.ts
new file mode 100644
index 0000000..7adbae2
--- /dev/null
+++ b/src/routers/photo/phototype.ts
@@ -0,0 +1,17 @@
+import { IFetchPhotoParams } from "@utils/fetch/fetchtype";
+export type basicImageType = {
+ src: string;
+ width: number;
+ height: number;
+};
+/**
+ * 定义photo路由的类型
+ */
+export type PhotoRouterImageCardType = {
+ images: basicImageType[];
+ dynamic_id: number;
+ observer?: boolean;
+ callback?: (inView: boolean) => void;
+};
+
+export type PhotoRouterMasonryType = Omit;
diff --git a/src/routers/photo/tools.ts b/src/routers/photo/tools.ts
new file mode 100644
index 0000000..6de1a6b
--- /dev/null
+++ b/src/routers/photo/tools.ts
@@ -0,0 +1,16 @@
+import message from "@components/message";
+import { fetchPhotos } from "@utils/fetch";
+import { IFetchPhotoParams } from "@utils/fetch/fetchtype";
+
+export const fetchPhotoHandler = async (params: IFetchPhotoParams) => {
+ const res = await fetchPhotos(params);
+ if (res.code !== 0) {
+ res.code === 400 && message.info("参数错误,请尝试其他tag");
+ res.code === 500 && message.info(res.message);
+ return [];
+ } else if (res.data.result == null || res.data.result.length < 1) {
+ message.info("没有更多数据了,请尝试其他tag");
+ return [];
+ }
+ return res.data.result;
+};
diff --git a/src/routers/video/index.tsx b/src/routers/video/index.tsx
index a543f38..1ddc83d 100644
--- a/src/routers/video/index.tsx
+++ b/src/routers/video/index.tsx
@@ -1,12 +1,12 @@
import { useAppSelector } from "@store/hooks";
-import { selectActiveTags } from "@store/tags";
+import { selectVideoActiveTags } from "@store/tags";
import VideoMasonry from "./masonry";
import { VideoRouterMasonryType } from "./videotype";
type ValueOf = T[keyof T];
export default function VideoPage() {
//处理搜索条件
- const activeTags = useAppSelector(selectActiveTags),
+ const activeTags = useAppSelector(selectVideoActiveTags),
tname = activeTags.find((item) => item.queryType === "tname")
?.queryString as ValueOf>,
copyright = activeTags.find((item) => item.queryType === "copyright")
diff --git a/src/routers/video/item/index.tsx b/src/routers/video/item/index.tsx
index 30efc7b..add8b4b 100644
--- a/src/routers/video/item/index.tsx
+++ b/src/routers/video/item/index.tsx
@@ -1,4 +1,5 @@
import { ImageBasic } from "@components/image";
+import { useScreenSize } from "@components/proview/screenSize";
import { FC } from "react";
import { Link } from "@mui/material";
import { VideoRouterImageCardType } from "../videotype";
@@ -11,6 +12,7 @@ export const VideoRouterImageCard: FC<{ data: VideoRouterImageCardType }> = ({
data,
}) => {
const { pic, bvid } = data;
+ const { md } = useScreenSize();
return (
= ({
color='inherit'
>
> = (props) => {
diff --git a/src/routers/video/masonry.tsx b/src/routers/video/masonry.tsx
index 93e45f9..5cf5f3f 100644
--- a/src/routers/video/masonry.tsx
+++ b/src/routers/video/masonry.tsx
@@ -1,12 +1,11 @@
import { useState, useEffect, FC, memo } from "react";
import { VideoRouterImageCardType, VideoRouterMasonryType } from "./videotype";
import { Unstable_Grid2 as Grid } from "@mui/material";
-import ImageShouldResizeProview from "@components/proview/imageSize";
import { VideoRouterImageCard } from "./item";
import { Skeleton } from "@mui/material";
import { nanoid } from "nanoid";
import styles from "./video.module.less";
-import { fetchVideohnadler, PickVideoRouterImageCardType } from "./tools";
+import { fetchVideohandler, PickVideoRouterImageCardType } from "./tools";
import { useAppSelector, useAppDispatch } from "@store/hooks";
import { changeLoading, selectVideoLoadingState } from "@store/loading/index";
/**
@@ -23,7 +22,7 @@ export default function VideoMasonry(props: VideoRouterMasonryType) {
useEffect(() => {
// 在内部定义fetchHandler,保证拿到的是同步的
const fetchHandler = async (page: number = 1) => {
- const data = await fetchVideohnadler(page, props);
+ const data = await fetchVideohandler(page, props);
setLists((lists) => [
...lists,
...data.map((item, index) => {
@@ -48,30 +47,28 @@ export default function VideoMasonry(props: VideoRouterMasonryType) {
}, [props]);
return (
-
-
- {lists.map((item) => (
-
- ))}
- {isLoading && }
-
-
+
+ {lists.map((item) => (
+
+ ))}
+ {isLoading && }
+
);
}
diff --git a/src/routers/video/tools.ts b/src/routers/video/tools.ts
index f69a641..2f3f79e 100644
--- a/src/routers/video/tools.ts
+++ b/src/routers/video/tools.ts
@@ -3,7 +3,7 @@ import { fetchVideos } from "@utils/fetch/index";
import message from "@components/message";
import { Pick } from "@utils/index";
-export const fetchVideohnadler = async (
+export const fetchVideohandler = async (
page: number = 1,
props: VideoRouterMasonryType
) => {
diff --git a/src/routers/video/videotype.ts b/src/routers/video/videotype.ts
index ce56040..cb4f14f 100644
--- a/src/routers/video/videotype.ts
+++ b/src/routers/video/videotype.ts
@@ -3,7 +3,7 @@
*/
import { ImageProps } from "@components/image/imagetype";
import { RFetchVideoRes } from "@utils/fetch/fetchtype";
-import { IFetchVideoParams } from "../../utils/fetch/fetchtype";
+import { IFetchVideoParams } from "@utils/fetch/fetchtype";
/**
* @description video路由瀑布流卡片参数
diff --git a/src/store/loading/index.ts b/src/store/loading/index.ts
index b220a74..e26d5c9 100644
--- a/src/store/loading/index.ts
+++ b/src/store/loading/index.ts
@@ -2,11 +2,15 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import type { RootState } from "..";
-interface LoadingState {
+export interface LoadingState {
/**
* @description 视频接口是否正在获取
*/
videoIsLoading: boolean;
+ /**
+ * @description 图片接口是否正在获取
+ */
+ photoIsloading: boolean;
}
interface IchangeLoadingItem {
stateName: keyof LoadingState;
@@ -15,13 +19,14 @@ interface IchangeLoadingItem {
const initialState: LoadingState = {
videoIsLoading: true,
+ photoIsloading: true,
};
export const LoadingSlice = createSlice({
name: "loading",
initialState,
reducers: {
/**
- *
+ * @description 修改加载状态,注意因为spa的限制所有每个页面只有一种加载情况
*/
changeLoading: (state, action: PayloadAction) => {
const { stateName, Tostate } = action.payload;
@@ -31,11 +36,28 @@ export const LoadingSlice = createSlice({
state[stateName] = !state[stateName];
}
},
+ /**
+ * @description 此reducer应该只在url修改时调用
+ */
+ changeLoadingCauseByUrl: (
+ state,
+ action: PayloadAction
+ ) => {
+ Object.keys(state).map((name) => {
+ state[name as keyof LoadingState] =
+ name === action.payload.stateName ? true : false;
+ });
+ },
},
});
-export const { changeLoading } = LoadingSlice.actions;
+const selectLoadingState = (state: RootState, name: keyof LoadingState) =>
+ state.loading[name];
+
+export const { changeLoading, changeLoadingCauseByUrl } = LoadingSlice.actions;
export const selectVideoLoadingState = (state: RootState) =>
- state.loading.videoIsLoading;
+ selectLoadingState(state, "videoIsLoading"),
+ selectPhotoLoadingState = (state: RootState) =>
+ selectLoadingState(state, "photoIsloading");
export default LoadingSlice.reducer;
diff --git a/src/store/tags/index.ts b/src/store/tags/index.ts
index 567581f..803ef06 100644
--- a/src/store/tags/index.ts
+++ b/src/store/tags/index.ts
@@ -1,51 +1,124 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
-import { NavQueryItemType } from "@routers/layout/nav/tools";
-
+import {
+ VideoNavQueryItemType,
+ VideoQueryNavList,
+} from "@routers/layout/nav/VideoTools";
+import {
+ PhotoNavQueryItemType,
+ PhotoQueryNavList,
+} from "@routers/layout/nav/photoTools";
import type { RootState } from "..";
+const Photo_Topic_id_all = PhotoQueryNavList.find(
+ (item) => item.queryString === 0
+ )!,
+ Photo_type_default = PhotoQueryNavList.find(
+ (item) => item.queryString === "latest"
+ )!,
+ Video_default_show = VideoQueryNavList.find(
+ (item) => item.queryString === "pubdate"
+ )!;
+
interface TagStates {
/**
- * @description 用户点击的tag栏
+ * @description video页面点击tags
+ */
+ VideoActiveTags: VideoNavQueryItemType[];
+ /**
+ * @description photo page active tags
*/
- activeTags: NavQueryItemType[];
+ PhotoActivetags: PhotoNavQueryItemType[];
}
const initialState: TagStates = {
- activeTags: [],
+ VideoActiveTags: [Video_default_show],
+ PhotoActivetags: [Photo_Topic_id_all, Photo_type_default],
};
export const ActiveTagsSlice = createSlice({
- name: "activeTags",
+ name: "VideoActiveTags",
initialState,
reducers: {
/**
- * @description 添加tag
+ * @description video页面添加tag
*/
- handerAddTag: (state, action: PayloadAction) => {
- //这里需要注意的是queryType有三种,只有q可以同存.
+ handerVideoAddTag: (
+ state,
+ action: PayloadAction
+ ) => {
+ //这里需要注意的是queryType多种,只有q可以同存.
switch (action.payload.queryType) {
case "q":
break;
default:
- state.activeTags = state.activeTags.filter(
+ state.VideoActiveTags = state.VideoActiveTags.filter(
(item) => item.queryType !== action.payload.queryType
);
break;
}
- state.activeTags = [...state.activeTags, action.payload];
+ state.VideoActiveTags = [...state.VideoActiveTags, action.payload];
+ },
+ /**
+ * @description photo page add activeTags
+ */
+ handerPhotoAddTag: (
+ state,
+ action: PayloadAction
+ ) => {
+ state.PhotoActivetags = state.PhotoActivetags.filter(
+ (item) => item.queryType !== action.payload.queryType
+ );
+ state.PhotoActivetags.push(action.payload);
},
/**
- * @description 删除tag
+ * @description video页面删除tag
*/
- handerDeleteTag: (state, action: PayloadAction) => {
- state.activeTags = state.activeTags.filter(
+ handerVideoDeleteTag: (
+ state,
+ action: PayloadAction
+ ) => {
+ state.VideoActiveTags = state.VideoActiveTags.filter(
(item) => item.id !== action.payload.id
);
},
+ /**
+ * @description photo page delete activetags
+ */
+ handerPhotoDeleteTag: (
+ state,
+ action: PayloadAction
+ ) => {
+ state.PhotoActivetags = state.PhotoActivetags.filter(
+ (item) => item.id !== action.payload.id
+ );
+ if (
+ !state.PhotoActivetags.some(
+ (item) => item.queryType === action.payload.queryType
+ )
+ ) {
+ switch (action.payload.queryType) {
+ case "topic_id": {
+ state.PhotoActivetags.push(Photo_Topic_id_all);
+ break;
+ }
+ default: {
+ state.PhotoActivetags.push(Photo_type_default);
+ break;
+ }
+ }
+ }
+ },
},
});
-export const { handerAddTag, handerDeleteTag } = ActiveTagsSlice.actions;
+export const {
+ handerVideoAddTag,
+ handerVideoDeleteTag,
+ handerPhotoAddTag,
+ handerPhotoDeleteTag,
+} = ActiveTagsSlice.actions;
-export const selectActiveTags = (state: RootState) =>
- state.ActiveTags.activeTags;
+export const selectVideoActiveTags = (state: RootState) =>
+ state.ActiveTags.VideoActiveTags,
+ selectPhotoActiveTags = (state: RootState) =>
+ state.ActiveTags.PhotoActivetags;
export default ActiveTagsSlice.reducer;
diff --git a/src/utils/fetch/fetchtype.ts b/src/utils/fetch/fetchtype.ts
index 90afbe4..6d05df3 100644
--- a/src/utils/fetch/fetchtype.ts
+++ b/src/utils/fetch/fetchtype.ts
@@ -165,10 +165,8 @@ interface RFetchVideoResData {
numResults: number;
result: RFetchVideoResResult[];
}
-/**
- * @description video接口的返回类型
- */
-export interface RFetchVideoRes {
+
+type CustomFetchRes = {
/**
* @example 0
*/
@@ -184,5 +182,61 @@ export interface RFetchVideoRes {
/**
* @description 放数据的
*/
- data: RFetchVideoResData;
+ data: T;
+};
+/**
+ * @description video接口的返回类型
+ */
+export type RFetchVideoRes = CustomFetchRes;
+
+interface RFetchPhotoResPicturesArr {
+ /**
+ * @description img url src
+ */
+ img_src: string;
+ img_size: number;
+ /**
+ * @description img origin width
+ */
+ img_width: number;
+ /**
+ * @description img origin height
+ */
+ img_height: number;
}
+
+interface RFetchPhotoResData {
+ page: number;
+ total: number;
+ result: {
+ dynamic_id: number;
+ sent_at: number;
+ pictures: RFetchPhotoResPicturesArr[];
+ }[];
+}
+
+/**
+ * @description photo接口的返回类型
+ */
+export type RFetchPhotoRes = CustomFetchRes;
+
+/**
+ *
+ */
+export type IFetchPhotoParams = {
+ /**
+ * @description photo display rules
+ */
+ type: "recommend" | "latest";
+ /**
+ * @description topic recommend:28953983->莞儿
+ 28950030->柚恩
+ 29067608->露早
+ 28948378->虞莫
+ 29069147->猴子
+ 29156150->官号
+ 0 -> default,all
+ */
+ topic_id: 28953983 | 28950030 | 29067608 | 28948378 | 29069147 | 29156150 | 0;
+ page: number;
+};
diff --git a/src/utils/fetch/index.ts b/src/utils/fetch/index.ts
index 27d0582..30b2043 100644
--- a/src/utils/fetch/index.ts
+++ b/src/utils/fetch/index.ts
@@ -1,13 +1,29 @@
import axios from "axios";
+import JSONBigInt from "json-bigint";
/**
* 类型文件导入
*/
-import { IFetchVideoParams, RFetchVideoRes } from "./fetchtype";
+import {
+ IFetchVideoParams,
+ RFetchPhotoRes,
+ RFetchVideoRes,
+ IFetchPhotoParams,
+} from "./fetchtype";
import { Host_Url } from "./tool";
+import { Omit } from "../index";
export const BackEndAxios = axios.create({
baseURL: Host_Url,
- timeout: 2500,
+ timeout: 9000,
+ transformResponse: [
+ (data) => {
+ try {
+ return JSONBigInt.parse(data);
+ } catch (err) {
+ return data;
+ }
+ },
+ ],
});
/**
* 后端接口配置
@@ -28,7 +44,7 @@ export async function fetchVideos(
params: IFetchVideoParams
): Promise {
try {
- const res = await BackEndAxios.get("/v1/video-interface/advanced-search", {
+ const res = await BackEndAxios.get("/video-interface/advanced-search", {
params: {
order: params.order || "score",
page: params.page,
@@ -52,3 +68,28 @@ export async function fetchVideos(
};
}
}
+/**
+ * photo图片数据获取接口
+ */
+export async function fetchPhotos(
+ params: IFetchPhotoParams
+): Promise {
+ // console.log({ params });
+ try {
+ const res = await BackEndAxios.get(`/pic/${params.type}`, {
+ params: Omit(params, "type"),
+ });
+ return res.data;
+ } catch (e) {
+ return {
+ code: 500,
+ message: "网络请求错误,您似乎处于断网状态",
+ ttl: 0,
+ data: {
+ page: 0,
+ total: 0,
+ result: [],
+ },
+ };
+ }
+}
diff --git a/src/utils/fetch/tool.ts b/src/utils/fetch/tool.ts
index 1e1d51b..ff6aa87 100644
--- a/src/utils/fetch/tool.ts
+++ b/src/utils/fetch/tool.ts
@@ -1 +1 @@
-export const Host_Url = isdev ? "" : `https://api.eoe.best/eoefans-api`;
+export const Host_Url = isdev ? "/v1" : `https://api.eoe.best/eoefans-api/v1`;
diff --git a/src/utils/router/index.tsx b/src/utils/router/index.tsx
new file mode 100644
index 0000000..dbc45d7
--- /dev/null
+++ b/src/utils/router/index.tsx
@@ -0,0 +1,11 @@
+import type { LoadingState } from "@store/loading";
+type RouterConfig = {
+ [router: string]: keyof LoadingState;
+};
+const RouterMap: RouterConfig = {
+ default: "videoIsLoading",
+ "/photo": "photoIsloading",
+ "/video": "videoIsLoading",
+};
+export const routerNameToLoading = (pathname: string) =>
+ RouterMap[pathname] || RouterMap["default"];
diff --git a/vite.config.ts b/vite.config.ts
index 31cd616..9bb3ac2 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -8,7 +8,7 @@ import viteCompression from "vite-plugin-compression";
// polyfill
import legacy from "@vitejs/plugin-legacy";
// https://vitejs.dev/config/
-
+//@ts-ignore
export default defineConfig(({ mode }) => {
return {
define: {
@@ -45,6 +45,7 @@ export default defineConfig(({ mode }) => {
react: ["react", "react-dom"],
"react-router": ["react-router-dom"],
"react-redux": ["@reduxjs/toolkit", "react-redux"],
+ axios: ["axios"],
lib: [
"@mui/icons-material",
"@mui/lab",
@@ -52,6 +53,7 @@ export default defineConfig(({ mode }) => {
"@emotion/react",
"@emotion/styled",
],
+ transform: ["json-bigint"],
"dnd-tool": [
"@dnd-kit/core",
"@dnd-kit/modifiers",