图片预览组件添加切换按钮,修改其他有关样式

This commit is contained in:
al 2024-08-07 16:00:39 +08:00
parent e7886b717a
commit bfcdbb60f4
17 changed files with 342 additions and 66 deletions

View File

@ -37,6 +37,9 @@ footer{
/* .adm-image-viewer-slides-inner > *{ /* .adm-image-viewer-slides-inner > *{
margin: 0; margin: 0;
} */ } */
.adm-swiper-horizontal .adm-swiper-track {
transform: none;
}
.custom-tabs .adm-tabs { .custom-tabs .adm-tabs {
border: none; border: none;
--active-line-color: #ff8383; --active-line-color: #ff8383;
@ -301,4 +304,5 @@ footer{
.adm-checkbox.adm-checkbox-checked .adm-checkbox-icon { .adm-checkbox.adm-checkbox-checked .adm-checkbox-icon {
border-color: #FF669E; border-color: #FF669E;
background-color: #FF669E; background-color: #FF669E;
} }

View File

@ -35,4 +35,29 @@
} }
.imagesBtnsControllers{
position: fixed;
top: 50%;
width: 100%;
display: flex;
padding: 0 12px;
justify-content: space-between;
z-index: 10001;
pointer-events: none;
}
.imagesBtnsControllerLeft,.imagesBtnsControllerRight{
width: 42px;
height: 42px;
border-radius: 53px;
background-color: #0000001A;
background-size: contain;
background-repeat: no-repeat;
pointer-events: all;
}
.imagesBtnsControllerLeft{
background-image: url("/icons/left.png");
opacity: 0.5;
}
.imagesBtnsControllerRight{
background-image: url("/icons/right.png");
}

View File

@ -193,6 +193,7 @@ export default function RootLayout({ children }) {
<main className={`w-full bg-deepBg h-full`}> <main className={`w-full bg-deepBg h-full`}>
{withAuth(<Provider store={store}>{children}</Provider>)} {withAuth(<Provider store={store}>{children}</Provider>)}
{/* <Provider store={store}>{children}</Provider> */} {/* <Provider store={store}>{children}</Provider> */}
<div id="maskDomBox"></div>
</main> </main>
<footer className="fixed left-0 w-screen bg-black"> <footer className="fixed left-0 w-screen bg-black">
<div> <div>

View File

@ -60,10 +60,7 @@ function Login({ handleLogin }) {
if(res && account){ if(res && account){
router.replace("/") router.replace("/")
} }
}) })
}, []); }, []);
useEffect(() => { useEffect(() => {
let interval; let interval;
@ -158,11 +155,11 @@ function Login({ handleLogin }) {
} }
); );
if (data.ret === -1) { if (data.ret === -1) {
Toast.show({ // Toast.show({
icon: "fail", // icon: "fail",
content: data.msg, // content: data.msg,
position: "top", // position: "top",
}); // });
return; return;
} }
//登录 //登录

View File

@ -116,7 +116,7 @@ export default function UnlockedWechat() {
streamerData={{ streamerData={{
streamer_ext: { streamer_ext: {
wechat_lock_type: wechat_lock_type:
currentStreamer.current?.streamer?.wechat_lock_type, currentStreamer.current?.lock_type,
}, },
}} }}
/> />

View File

@ -76,6 +76,7 @@ export default function Home() {
</div> </div>
<Swiper <Swiper
direction="horizontal" direction="horizontal"
allowTouchMove={false}
loop={false} loop={false}
indicator={() => null} indicator={() => null}
ref={swiperRef} ref={swiperRef}
@ -83,6 +84,7 @@ export default function Home() {
onIndexChange={(index) => { onIndexChange={(index) => {
setActiveIndex(index); setActiveIndex(index);
}} }}
> >
<Swiper.Item> <Swiper.Item>
{!activeIndex && ( {!activeIndex && (
@ -97,7 +99,7 @@ export default function Home() {
</Swiper> </Swiper>
<div <div
id="rightddd" id="rightddd"
className={`fixed bottom-[96px] right-4 z-[999] w-10 h-10 flex items-center justify-center bg-[#1d1d1d71] rounded-full text-white className={`fixed bottom-[96px] right-4 z-[50] w-10 h-10 flex items-center justify-center bg-[#1d1d1d71] rounded-full text-white
}`} }`}
onClick={childrenFunc} onClick={childrenFunc}
> >

View File

@ -179,6 +179,8 @@ const ZoneItem = ({ data, showMore, link,search }) => {
<Image <Image
className="flex-none w-10 h-10 rounded-full mr-2" className="flex-none w-10 h-10 rounded-full mr-2"
src={data?.avatar?.images[0]?.urls[0]} src={data?.avatar?.images[0]?.urls[0]}
width="2.5rem"
height="2.5rem"
alt="" alt=""
fit="cover" fit="cover"
/> />

View File

@ -434,7 +434,7 @@ export default function PersonSpace() {
</JumboTabs> </JumboTabs>
</FloatingPanel> </FloatingPanel>
<div <div
className={`fixed bottom-[96px] right-4 z-[999] w-10 h-10 flex items-center justify-center bg-[#1d1d1d71] rounded-full text-white ${ className={`fixed bottom-[96px] right-4 z-[50] w-10 h-10 flex items-center justify-center bg-[#1d1d1d71] rounded-full text-white ${
loading && !offset ? "animate-spin" : "" loading && !offset ? "animate-spin" : ""
}`} }`}
> >

View File

@ -129,10 +129,7 @@ export default function Space() {
} }
} }
return ( return (
<div <div className="">
className=""
>
<div className="flex justify-between items-center px-2 custom-tabs text-gray-400 sticky top-0 z-10 bg-deepBg"> <div className="flex justify-between items-center px-2 custom-tabs text-gray-400 sticky top-0 z-10 bg-deepBg">
<Tabs <Tabs
activeKey={tabItems[activeIndex].key} activeKey={tabItems[activeIndex].key}
@ -299,7 +296,7 @@ export default function Space() {
</Swiper.Item> </Swiper.Item>
</Swiper> </Swiper>
<div <div
className={`fixed bottom-[96px] right-4 z-[999] w-10 h-10 flex items-center justify-center bg-[#1d1d1d71] rounded-full text-white ${ className={`fixed bottom-[96px] right-4 z-[50] w-10 h-10 flex items-center justify-center bg-[#1d1d1d71] rounded-full text-white ${
loading && !offset ? "animate-spin" : "" loading && !offset ? "animate-spin" : ""
}`} }`}
> >

View File

@ -1,42 +1,88 @@
"use client"; "use client";
import React,{useState,useEffect} from "react"; import React, { useState, useEffect } from "react";
import { Image ,Toast} from "antd-mobile"; import { Image } from "antd-mobile";
import { get,save } from "@/utils/storeInfo"; import { get,save } from "@/utils/storeInfo";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faAngleUp, faClose } from "@fortawesome/free-solid-svg-icons";
export default function AddToHome() { export default function AddToHome() {
const [firstLogin, setFirstLogin] = useState("0"); const [firstLogin, setFirstLogin] = useState({ first: "0", second: false });
useEffect(() => { useEffect(() => {
if(!(("standalone" in window.navigator) && window.navigator.standalone) if (!("standalone" in window.navigator && window.navigator.standalone)) {
){ setFirstLogin((old) => ({ ...old, first: get("firstLogin") }));
setFirstLogin(get("firstLogin"))
} }
}, []); }, []);
return ( return firstLogin.first == "1" ? (
firstLogin=="1"?<div <div
className="fixed top-0 z-[999] flex flex-col justify-end items-center h-screen w-screen bg-[#262626b0]" className="fixed z-[50]"
onClick={() => {save("firstLogin", 0);setFirstLogin("0")}} style={{ bottom: !firstLogin.second ? "57px" : "0" }}
> >
<div className="font-bold text-xl mb-2 flex items-center"> {!firstLogin.second ? (
点击 <div className="bg-[#13121f] p-3 w-screen flex items-center justify-between relative">
<Image <div className="flex items-center">
fit="cover" <Image
// src={process.env.NEXT_PUBLIC_WEB_ASSETS_URL+"/icons/nodata.png"} fit="cover"
src={"/icons/ios_share.png"} className="rounded-md mr-3"
placeholder="" // src={process.env.NEXT_PUBLIC_WEB_ASSETS_URL+"/icons/nodata.png"}
width={32} src={"/images/icon.png"}
height={32} placeholder=""
/> width={46}
添加到主屏幕 height={46}
</div> />
<Image <div>
fit="cover" <p className="font-bold text-[0.9rem]">
// src={process.env.NEXT_PUBLIC_WEB_ASSETS_URL+"/icons/nodata.png"} 建议您添加<span className="text-primary">铁粉空间</span>
src={"/images/addToHome.png"} 到手机桌面
placeholder="" </p>
width={54} <p className="text-[#ffffffb2] text-xs">以便随时关注圈子动态</p>
height={54} </div>
/> </div>
</div>:null <div
); className="bg-primary px-4 py-2 rounded-full font-bold"
onClick={() => setFirstLogin((old) => ({ ...old, second: true }))}
>
去添加
</div>
<FontAwesomeIcon
icon={faClose}
size=""
className="absolute left-1 top-1"
onClick={() => {
save("firstLogin", 0);
setFirstLogin((old) => ({ first: "0", second: false }));
}}
/>
</div>
) : (
<div
className="flex flex-col justify-end items-center h-screen w-screen bg-[#00000099]"
onClick={() => {
save("firstLogin", 0);
setFirstLogin((old) => ({ first: "0", second: false }));
}}
>
<div className="font-bold text-xl mb-2 flex items-center">
点击
<Image
fit="cover"
// src={process.env.NEXT_PUBLIC_WEB_ASSETS_URL+"/icons/nodata.png"}
src={"/icons/ios_share.png"}
placeholder=""
width={32}
height={32}
/>
添加到主屏幕
</div>
<Image
fit="contain"
// src={process.env.NEXT_PUBLIC_WEB_ASSETS_URL+"/icons/nodata.png"}
src={"/images/addToHome.png"}
placeholder=""
width={54}
height={70}
/>
</div>
)}
</div>
) : null;
} }

View File

@ -0,0 +1,117 @@
"use client";
import React, {
useState,
useEffect,
useRef,
forwardRef,
useImperativeHandle,
} from "react";
import { Mask, Image } from "antd-mobile";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faAngleLeft, faAngleRight } from "@fortawesome/free-solid-svg-icons";
function ImagesMask({}, ref) {
const [currentIndex, setCurrentIndex] = useState(0);
const [visible, setVisible] = useState(false);
const [images, setImages] = useState([]);
const [distance, setDistance] = useState(0);
const scrollRef = useRef(null);
useEffect(() => {
if (scrollRef.current) {
setTimeout(() => {
scrollRef.current.scrollLeft = 414 * currentIndex;
}, 200);
}
}, [currentIndex]);
useImperativeHandle(ref, () => ({
show: (arr, index) => {
setCurrentIndex(index);
setImages(arr);
setVisible(true);
// Mask.show
// const maskDomBox = document.getElementById("maskDomBox");
},
close: () => setVisible(false),
}));
const getDistance = (e) => {
e.stopPropagation();
const distance = scrollRef.current.scrollLeft;
setDistance(distance);
};
const handleMoveImages = (e,index) => {
e.stopPropagation();
// console.log("distance",distance)
if (
distance > window.innerWidth * currentIndex &&
distance < window.innerWidth + window.innerWidth * currentIndex
) {
setCurrentIndex(Math.ceil(distance/414))
} else if(distance < window.innerWidth * currentIndex) {
setCurrentIndex(Math.ceil(distance/414)-1)
}
};
return (
<Mask
visible={visible}
className="z-[99] h-screen flex justify-center items-center"
>
<div className="relative">
<div className="text-center mb-2">
{currentIndex + 1}/{images.length}
</div>
<div
ref={scrollRef}
id="imagesScrollBox"
className="flex overflow-auto"
>
{images.map((item, index) => {
return (
// <Image
// key={index}
// fit="cover"
// className="mr-3"
// // src={process.env.NEXT_PUBLIC_WEB_ASSETS_URL+"/icons/nodata.png"}
// src={item}
// placeholder=""
// width="100vw"
// // height="90vh"
// />
<img
key={index}
src={item}
// onTouchMove={(e) => handleMoveImages(e, index)}
onTouchMove={getDistance}
onTouchEnd={(e) => handleMoveImages(e,index)}
onClick={() => {
setVisible(false), setImages([]), setCurrentIndex(0);
}}
/>
);
})}
</div>
<div className="flex justify-between items-center w-screen absolute top-1/2 px-4 pointer-events-none">
<div
className="w-9 h-9 flex items-center justify-center bg-[#FFFFFF1A] rounded-full float-left pointer-events-auto"
onClick={() => {
setCurrentIndex((old) => (old > 0 ? old - 1 : old));
}}
>
<FontAwesomeIcon icon={faAngleLeft} size="xl" />
</div>
<div
className="w-9 h-9 flex items-center justify-center bg-[#FFFFFF1A] rounded-full float-left pointer-events-auto"
onClick={() => {
setCurrentIndex((old) =>
old < images.length - 1 ? old + 1 : old
);
}}
>
<FontAwesomeIcon icon={faAngleRight} size="xl" />
</div>
</div>
</div>
</Mask>
);
}
export default forwardRef(ImagesMask);

View File

@ -1,12 +1,14 @@
"use client"; "use client";
import React, { useEffect, useState,useRef } from "react"; import React, { useEffect, useState, useRef } from "react";
import { Image, ImageViewer, Dialog } from "antd-mobile"; import { Image, ImageViewer, Dialog } from "antd-mobile";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faAngleUp, faClose } from "@fortawesome/free-solid-svg-icons"; import { faAngleUp, faClose } from "@fortawesome/free-solid-svg-icons";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import baseRequest from "@/utils/baseRequest"; import baseRequest from "@/utils/baseRequest";
import Player from "next-video/player"; import Player from "next-video/player";
// import ImagesMask from "@/components/ImagesMask";
// import Viewer from 'react-viewer';
export default function Photos({ export default function Photos({
isUnlocked, isUnlocked,
mediaVisibleRange, mediaVisibleRange,
@ -18,7 +20,10 @@ export default function Photos({
const [seeAllPhotos, setSeeAllPhotos] = useState(false); const [seeAllPhotos, setSeeAllPhotos] = useState(false);
const [currentPhotos, setCurrentPhotos] = useState([]); const [currentPhotos, setCurrentPhotos] = useState([]);
const [photos, setPhotos] = useState([]); const [photos, setPhotos] = useState([]);
const [visible, setVisible] = useState(false);
const currentIndex = useRef(); const currentIndex = useRef();
const swiper = useRef(null);
// const imagesMaskRef = useRef(null);
const router = useRouter(); const router = useRouter();
const base = baseRequest(); const base = baseRequest();
useEffect(() => { useEffect(() => {
@ -57,22 +62,65 @@ export default function Photos({
} }
}, [media]); }, [media]);
const showPhotos = (photos, index) => { const showPhotos = (photos, index) => {
currentIndex.current=index; currentIndex.current = index;
// const interval = setInterval(() => {
// const bodyBox = document.getElementsByClassName("photos-bodyBox")[0];
// if (bodyBox) {
// bodyBox.firstChild.lastChild.style.transform = `translateX(-${
// currentIndex.current * (window.innerWidth + 16)
// }px)`;
// // console.log(bodyBox.firstChild.lastChild.style.transform);
// }
// }, 400);
// 添加左右切换按钮
const btns = document.createElement("div");
btns.className = "imagesBtnsControllers";
const btnL = document.createElement("div");
btnL.className = "imagesBtnsControllerLeft";
btnL.addEventListener("click", () => {
if (currentIndex.current > 0) {
currentIndex.current = currentIndex.current - 1;
handleShowImages(currentIndex.current, photos, btns);
if (!currentIndex.current) {
btnL.style.opacity = 0.5;
btnR.style.opacity = 1;
} else {
btnR.style.opacity = 1;
btnL.style.opacity = 1;
}
}
});
const btnR = document.createElement("div");
btnR.className = "imagesBtnsControllerRight";
btnR.addEventListener("click", () => {
if (currentIndex.current < currentPhotos.length - 1) {
currentIndex.current = currentIndex.current + 1;
handleShowImages(currentIndex.current, photos, btns);
if (currentIndex.current == currentPhotos.length - 1) {
btnR.style.opacity = 0.5;
btnL.style.opacity = 1;
} else {
btnR.style.opacity = 1;
btnL.style.opacity = 1;
}
}
});
btns.append(btnL, btnR);
handleShowImages(index, photos, btns);
// setVisible(true)
// imagesMaskRef.current.show(photos.map((item) => item?.url),index)
};
const handleShowImages = (index, photos, btns) => {
const mediaDom = document.createElement("div"); const mediaDom = document.createElement("div");
mediaDom.style.width = "100vw"; mediaDom.style.width = "100vw";
document.body.appendChild(mediaDom); document.body.appendChild(mediaDom);
mediaDom.className = `${ mediaDom.className = `${
photos[index]?.type == "hid" ? "mediaDom photos-body" : "mediaDom" photos[index]?.type == "hid" ? "mediaDom photos-body" : "mediaDom"
}`; }`;
const interval = setInterval(() => { mediaDom.appendChild(btns);
const bodyBox = document.getElementsByClassName("photos-bodyBox")[0]; ImageViewer.clear();
if(bodyBox){
bodyBox.firstChild.lastChild.style.transform = `translateX(-${
(currentIndex.current) * (window.innerWidth + 16)
}px)`;
// console.log(bodyBox.firstChild.lastChild.style.transform);
}
}, 400);
ImageViewer.Multi.show({ ImageViewer.Multi.show({
images: photos.map((item) => item?.url), images: photos.map((item) => item?.url),
defaultIndex: index, defaultIndex: index,
@ -82,18 +130,31 @@ export default function Photos({
getContainer: mediaDom, getContainer: mediaDom,
onIndexChange: (index) => { onIndexChange: (index) => {
currentIndex.current=index; currentIndex.current = index;
mediaDom.className = `${ mediaDom.className = `${
photos[index]?.type == "hid" ? "mediaDom photos-body" : "mediaDom" photos[index]?.type == "hid" ? "mediaDom photos-body" : "mediaDom"
}`; }`;
const leftBtn = document.getElementsByClassName("imagesBtnsControllerLeft")[0]
const rightBtn = document.getElementsByClassName("imagesBtnsControllerRight")[0]
if(leftBtn && rightBtn){
if(!index){
leftBtn.style.opacity=0.5
rightBtn.style.opacity=1
}else if(index==currentPhotos.length-1){
leftBtn.style.opacity=1
rightBtn.style.opacity=0.5
}else{
leftBtn.style.opacity=1
rightBtn.style.opacity=1
}
}
}, },
afterClose: () => { afterClose: () => {
mediaDom.remove(); mediaDom.remove();
clearInterval(interval); // clearInterval(interval);
}, },
classNames: { body: "photos-bodyBox" }, classNames: { body: "photos-bodyBox" },
}); });
}; };
const handleShowVideo = (video) => { const handleShowVideo = (video) => {
Dialog.className = "videoMask"; Dialog.className = "videoMask";
@ -293,6 +354,12 @@ export default function Photos({
); );
})} })}
</div> </div>
{/* <ImagesMask ref={imagesMaskRef}/> */}
{/* <Viewer
visible={visible}
onClose={() => { setVisible(false); } }
images={currentPhotos.map((it,index)=>({src:it.url,alt:index}))}
/> */}
</> </>
); );
} }

View File

@ -219,7 +219,7 @@ export default function PostItem({
"天前" "天前"
}有更新`} }有更新`}
空间 */} 空间 */}
{formatZoneUpdateTime( 空间{formatZoneUpdateTime(
data?.streamer_ext data?.streamer_ext
?.days_elapsed_since_the_last_zones_update ?.days_elapsed_since_the_last_zones_update
)} )}

17
package-lock.json generated
View File

@ -26,6 +26,7 @@
"react-dom": "^18", "react-dom": "^18",
"react-player": "^2.16.0", "react-player": "^2.16.0",
"react-redux": "^9.1.2", "react-redux": "^9.1.2",
"react-viewer": "^3.2.2",
"redux": "^5.0.1", "redux": "^5.0.1",
"sass": "^1.77.6" "sass": "^1.77.6"
}, },
@ -5876,6 +5877,14 @@
} }
} }
}, },
"node_modules/react-viewer": {
"version": "3.2.2",
"resolved": "https://registry.npmmirror.com/react-viewer/-/react-viewer-3.2.2.tgz",
"integrity": "sha512-DHOq1x6cXsAViY43204ILRzLVR5ovP1MgzsC+LzZCWlInRuHjzAgpQZ8GzWm1CkiNYuHGwCxH36X0JUHl2xDSg==",
"dependencies": {
"classnames": "^2.2.5"
}
},
"node_modules/read-cache": { "node_modules/read-cache": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz", "resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz",
@ -11195,6 +11204,14 @@
"use-sync-external-store": "^1.0.0" "use-sync-external-store": "^1.0.0"
} }
}, },
"react-viewer": {
"version": "3.2.2",
"resolved": "https://registry.npmmirror.com/react-viewer/-/react-viewer-3.2.2.tgz",
"integrity": "sha512-DHOq1x6cXsAViY43204ILRzLVR5ovP1MgzsC+LzZCWlInRuHjzAgpQZ8GzWm1CkiNYuHGwCxH36X0JUHl2xDSg==",
"requires": {
"classnames": "^2.2.5"
}
},
"read-cache": { "read-cache": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz", "resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz",

View File

@ -27,6 +27,7 @@
"react-dom": "^18", "react-dom": "^18",
"react-player": "^2.16.0", "react-player": "^2.16.0",
"react-redux": "^9.1.2", "react-redux": "^9.1.2",
"react-viewer": "^3.2.2",
"redux": "^5.0.1", "redux": "^5.0.1",
"sass": "^1.77.6" "sass": "^1.77.6"
}, },

BIN
public/icons/left.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
public/icons/right.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB