Browse Source

Lazy Imgix

zhejiushizhuce 2 năm trước cách đây
mục cha
commit
455374d684

+ 2 - 1
src/api/config.js

@@ -11,7 +11,8 @@ export const BASE_API="https://api.ouro777.com/";
 
 export const BASE_PREFIX="game/";
 
-export const APP_AVATAR="https://cdn.moeda777.com/24680/assets/avatar/1/";
+// export const APP_AVATAR="https://cdn.moeda777.com/24680/assets/avatar/1/";
+export const APP_AVATAR="https://24680.imgix.net/24680/assets/avatar/2/"
 //路由
 export const APP_ROUTES=BASE_PREFIX+"routes";
 //page 模块

BIN
src/assets/moneyrain/Close.png


BIN
src/assets/moneyrain/rain_bg2.png


+ 3 - 1
src/components/AutoBanner/index.jsx

@@ -27,6 +27,7 @@ import {NavLink, useNavigate} from "react-router-dom";
 import styles from './styles.module.scss';
 import {ROUTE_PATH} from "@constants/routes";
 import Imgix from "@components/Imgix";
+import LazyImgix from "@components/Imgix/LazyImgix";
 
 const AutoBanner = ({data,perview=3,spaceBetween=15,delay=3000,speed=1000}) => {
     const [swiper, setSwiper] = useState(null);
@@ -94,7 +95,8 @@ const AutoBanner = ({data,perview=3,spaceBetween=15,delay=3000,speed=1000}) => {
                                         }}>
                                             {/*<LazyImage style={{borderRadius:"var(--border-radius)"}} className="img-box-content" src={item.img} alt={item.alt}>*/}
                                             {/*</LazyImage>*/}
-                                            <Imgix className="lazyload img-box-content" style={{borderRadius:"var(--border-radius)"}} src={item.img} alt={item.alt} width={675}></Imgix>
+                                            {/*<Imgix className="lazyload img-box-content" style={{borderRadius:"var(--border-radius)"}} src={item.img} alt={item.alt} width={675}></Imgix>*/}
+                                            <LazyImgix className="lazyload img-box-content" style={{borderRadius:"var(--border-radius)"}} src={item.img} alt={item.alt} width={675}></LazyImgix>
                                         </button>
                                     ))
                                 }

+ 19 - 6
src/components/AutoWinList/index.jsx

@@ -15,6 +15,7 @@ import usdimg from "@assets/lvicon/USD.black.png";
 import symbol from '@assets/symbol-defs.svg';
 import {useNavigate} from "react-router";
 import {numFormatter} from "@utils/helpers";
+import LazyImgix from "@components/Imgix/LazyImgix";
 
 
 const i18n=global.i18n;
@@ -237,11 +238,17 @@ const AutoWinList=({data})=>{
                          <div key={index} className={styles.swiper_item} onClick={()=>{
                              onClickLink(item.link);
                          }}>
-                             <LazyLoadImage
+                             {/*<LazyLoadImage*/}
+                             {/*    src={item.img}*/}
+                             {/*    alt={"game-icon"}*/}
+                             {/*    effect={"blur"}*/}
+                             {/*    wrapperClassName={`lazy-image ${styles.game_icon}`}*/}
+                             {/*/>*/}
+                             <LazyImgix
                                  src={item.img}
                                  alt={"game-icon"}
-                                 effect={"blur"}
-                                 wrapperClassName={`lazy-image ${styles.game_icon}`}
+                                 width={75}
+                                 className={`${styles.game_icon}`}
                              />
                              <div className={styles.nick_name}>
                                 <img src={lvicon[item.lv-1]}/>
@@ -288,11 +295,17 @@ const AutoWinList=({data})=>{
                                     <div className={styles.swiper_item_m} onClick={()=>{
                                         onClickLink(item.link);
                                     }}>
-                                        <LazyLoadImage
+                                        {/*<LazyLoadImage*/}
+                                        {/*    src={item.img}*/}
+                                        {/*    alt={"game-icon"}*/}
+                                        {/*    effect={"blur"}*/}
+                                        {/*    wrapperClassName={`lazy-image ${styles.game_icon_m}`}*/}
+                                        {/*/>*/}
+                                        <LazyImgix
                                             src={item.img}
                                             alt={"game-icon"}
-                                            effect={"blur"}
-                                            wrapperClassName={`lazy-image ${styles.game_icon_m}`}
+                                            width={16}
+                                            className={`${styles.game_icon_m}`}
                                         />
                                         <div className={styles.user_name_m}>
                                             {item.nick}

+ 3 - 1
src/components/GameItem/index.jsx

@@ -7,6 +7,7 @@ import {ROUTE_PATH} from "@constants/routes";
 import {localStorageSet} from "@utils/helpers";
 import {LOCAL_GAME_URL} from "@constants/localkey";
 import Imgix from "@components/Imgix";
+import LazyImgix from "@components/Imgix/LazyImgix";
 
 const GameItem=({data,handleRoom,...props})=>{
     const navigate=useNavigate();
@@ -95,7 +96,8 @@ const GameItem=({data,handleRoom,...props})=>{
                 {/*    effect={"blur"}*/}
                 {/*    wrapperClassName={`lazy-image ${styles.game_img}`}*/}
                 {/*/>*/}
-                <Imgix className={`lazyload ${styles.game_img}`} src={data.img} alt={"game-icon"} width={192}></Imgix>
+                {/*<Imgix className={`lazyload ${styles.game_img}`} src={data.img} alt={"game-icon"} width={192}></Imgix>*/}
+                <LazyImgix className={`lazyload ${styles.game_img}`} src={data.img} alt={"game-icon"} width={192}></LazyImgix>
             </button>
         </div>
     )

+ 29 - 0
src/components/Imgix/LazyImgix.jsx

@@ -0,0 +1,29 @@
+import { LazyLoadComponent,LazyLoadImage } from 'react-lazy-load-image-component';
+import ReactImgix, {buildURL} from "react-imgix";
+import PropTypes from "prop-types";
+import styles from "./styles.module.scss";
+import {useState} from "react";
+const LazyImgix = ({ src,alt="",className="",blur=true, ...props}) => {
+    const [loaded, setLoaded] = useState(false);
+    const effectClass=blur?styles.blur:'';
+    const effLoadedClass=blur?(loaded?styles.loaded:''):'';
+    return (
+        <LazyLoadComponent>
+            <ReactImgix
+                className={`${className} ${effectClass} ${effLoadedClass}`}
+                src={src}
+                alt={alt}
+                htmlAttributes={{
+                    onLoad: () => {
+                        setLoaded(true);
+                    },
+                }}
+                {...props}
+            ></ReactImgix>
+        </LazyLoadComponent>
+    )
+}
+LazyImgix.propTypes = {
+    src:PropTypes.string.isRequired
+}
+export default LazyImgix;

+ 10 - 0
src/components/Imgix/styles.module.scss

@@ -0,0 +1,10 @@
+.blur {
+  filter: blur(15px);
+  opacity: 0;
+  transition: all .3s;
+}
+
+.loaded {
+  filter: blur(0);
+  opacity: 1;
+}

+ 3 - 1
src/layout/Navbar/index.jsx

@@ -29,6 +29,7 @@ import LazyImage from "@components/LazyImage";
 import {numFormatter, sleep} from "@utils/helpers";
 import {ROUTE_PATH} from "@constants/routes";
 import {toast} from "react-toastify";
+import LazyImgix from "@components/Imgix/LazyImgix";
 const i18n=global.i18n;
 
 const StyledToggleGroup= styled(ToggleButtonGroup)`
@@ -231,7 +232,8 @@ const UserInfo=()=>{
                             <div className={styles.nick}>{user.NickName}</div>
                             <div className={styles.score}>{global.DOLLAR+" "+numFormatter(user.Score)}</div>
                         </div>
-                        <LazyImage wrapperClassName={styles.avatar} src={user.img} alt={"Head"}/>
+                        {/*<LazyImage wrapperClassName={styles.avatar} src={user.img} alt={"Head"}/>*/}
+                        <LazyImgix className={styles.avatar} src={user.img} alt={"Head"} width={40}/>
                     </div>
                 ):(<></>)
             }

+ 3 - 5
src/layout/Navbar/styles.module.scss

@@ -134,11 +134,9 @@
   justify-content: flex-end;
   gap: 0.5rem;
   & .avatar{
-    img{
-      height: 3rem;
-      width: auto;
-      border-radius: 50%;
-    }
+    height: 3rem;
+    width: auto;
+    border-radius: 50%;
   }
   & .info{
     display: flex;

+ 10 - 0
src/locales/languages/en_US.json

@@ -447,6 +447,16 @@
       "tips_1": "Maximum Cash Drop Value: Each Cash Rain session is given away for free with",
       "tips_2": "Recharged members can claim for free",
       "tips_3": "The money received can be used to play or withdrawn directly."
+    },
+    "redPack": {
+      "title": "Money rain",
+      "tips_0": "Recharged members can claim for free.",
+      "tips_1": "Maximum cash drop value: {0}",
+      "btn": "GRAB"
+    },
+    "redOpen": {
+      "time_tips": "Collection Schedule:",
+      "max_drop": "Max drop "
     }
   }
 }

+ 3 - 1
src/widgets/UserSettings/index.jsx

@@ -26,6 +26,7 @@ import {REQ_STATUS} from "@api/config";
 import SmallLoading from "@components/SmallLoading";
 import {APP_GENDER, APP_THEME} from "@constants/app";
 import AntSwitch from "@components/AntSwitch";
+import LazyImgix from "@components/Imgix/LazyImgix";
 const i18n=global.i18n;
 
 const UserSettings=()=>{
@@ -118,7 +119,8 @@ const UserSettings=()=>{
             <div className={styles.wrap_item}>
                 <div className={styles.user_con}>
                     <div className={styles.user_info}>
-                        <LazyImage wrapperClassName={styles.avatar} src={user.img} alt={"avatar"}></LazyImage>
+                        {/*<LazyImage wrapperClassName={styles.avatar} src={user.img} alt={"avatar"}></LazyImage>*/}
+                        <LazyImgix className={styles.avatar} src={user.img} alt={"avatar"} width={50}></LazyImgix>
                         <div className={`${styles.user_info} ${styles.info}`}>
                             <div className={styles.info_item}>
                                 <div className={styles.name}>{user.NickName}</div>

+ 1 - 0
src/widgets/UserSettings/styles.module.scss

@@ -88,6 +88,7 @@
 }
 .avatar{
   width: 4rem;
+  border-radius: 50%;
   img{
     width: 4rem;
     height: auto;

+ 6 - 3
src/widgets/WEditProfile/index.jsx

@@ -14,9 +14,10 @@ import SmallLoading from "@components/SmallLoading";
 import {reqChangeEmail, reqChangeInfo, reqChangePhone} from "@features/api";
 import {APP_GENDER} from "@constants/app";
 import {validateCountryPhone} from "@utils/helpers";
+import LazyImgix from "@components/Imgix/LazyImgix";
 const i18n=global.i18n;
 const getAvatarUrl=(id)=>{
-    return `${APP_AVATAR}avatar_${id}.png`;
+    return `${APP_AVATAR}avatar_${id}.png?auto=format,compress&cs=srgb`;
 }
 const SelectAvatar=({innerRef, ...props})=>{
     const [value, setValue] = useState(props.value);
@@ -34,7 +35,8 @@ const SelectAvatar=({innerRef, ...props})=>{
                             setValue(item);
                             if (props.onChange)props.onChange(item);
                         }}>
-                            <LazyImage wrapperClassName={`${styles.avatar} ${item==value?styles.active:''}`} src={getAvatarUrl(item)} alt={"avatar_" + index}/>
+                            {/*<LazyImage wrapperClassName={`${styles.avatar} ${item==value?styles.active:''}`} src={getAvatarUrl(item)} alt={"avatar_" + index}/>*/}
+                        <LazyImgix className={`${styles.avatar} ${item==value?styles.active:''}`} src={getAvatarUrl(item)} alt={"avatar_" + index} width={30} />
                         </button>
                     )
                 })
@@ -77,7 +79,8 @@ const WEditProfile=({close})=>{
     const renderAvatar=()=>{
         return (
             <div className={styles.avatar_con}>
-                <LazyImage wrapperClassName={styles.avatar} src={getAvatarUrl(avatarID)} alt={"avator"}/>
+                {/*<LazyImage wrapperClassName={styles.avatar} src={getAvatarUrl(avatarID)} alt={"avator"}/>*/}
+                <LazyImgix className={styles.avatar} src={getAvatarUrl(avatarID)} alt={"avatar"} width={50}></LazyImgix>
             </div>
         )
     }

+ 6 - 0
src/widgets/WEditProfile/styles.module.scss

@@ -22,6 +22,8 @@
   & .avatar{
     width: 35%;
     height: auto;
+    border-radius: 50%;
+    border: solid .25rem rgba(151, 151, 151, .15);
     img{
       width: 100%;
       height: auto;
@@ -69,11 +71,15 @@
         border-radius: 50%;
         border: solid .15rem transparent;
       }
+      border-radius: 50%;
+      border: solid .15rem transparent;
       &.active{
         img{
           border-radius: 50%;
           border: solid .15rem var(--primary-color);
         }
+        border-radius: 50%;
+        border: solid .15rem var(--primary-color);
       }
     }
   }

+ 98 - 0
src/widgets/WMoneyRain/WRainAni/WRainAni.jsx

@@ -0,0 +1,98 @@
+import styles from './styles.module.scss';
+import img_money from "@assets/moneyrain/money.png";
+import {useEffect, useRef, useState} from "react";
+const eleWH=[
+    {
+        width: 77,
+        height: 48
+    }, {
+        width: 77,
+        height: 47
+    }, {
+        width: 77,
+        height: 45
+    }, {
+        width: 77,
+        height: 46
+    }, {
+        width: 101,
+        height: 45
+    }
+]
+const WRainAni=()=>{
+    const moneyRain=useRef(null);
+    const testRain=(t, e)=>{
+        return Math.random() * (e - t) + t;
+    }
+    const createMoneySymbol=(t)=>{
+        if (moneyRain&&moneyRain.isShow){
+            let i = Math.ceil(4 * Math.random());
+            let a = document.createElement("div");
+            a.classList.add(styles["money"+i]);
+            let s = eleWH[i - 1];
+            let n = Math.random() * window.innerWidth;
+            let o = 30 * testRain(.7, 1) - 100;
+            if (t)o = 800 * testRain(0, 1);
+            a.style.left = "".concat(n, "px");
+            a.style.top = "".concat(o, "px");
+            a.style.transform = "rotate(".concat(360 * Math.random(), "deg)");
+            let r = testRain(.4, 1);
+            a.style.width = "".concat(r * s.width, "px");
+            a.style.height = "".concat(r * s.height, "px");
+            a.style["animation-name"] = t ? styles["fallAndSpin3D".concat(Math.ceil(3 * Math.random()))] : styles["fallAndSpin".concat(Math.ceil(3 * Math.random()))];
+            a.style["background-size"] = "".concat(r * s.width, "px ").concat(r * s.height, "px");
+            let c = 5 * Math.random() + 5;
+            if (t){c = 2 * Math.random() + 3;}
+            a.style.animationDuration = "".concat(c, "s, ").concat(c / 2, "s");
+            if (moneyRain&&moneyRain.current){
+                moneyRain.current.appendChild(a);
+                a.addEventListener("animationend", function() {
+                    a.remove();
+                    createMoneySymbol();
+                })
+            }
+        }
+    }
+    const showMoneyRain=(t)=>{
+        clearMoneyRain();
+        if (t){
+            moneyRain.isShow=true;
+            var e = Math.ceil(window.innerWidth / 4);
+            for (let i = 0; i < e; i++) {
+                let timer=setTimeout(function() {
+                    createMoneySymbol(true)
+                    createMoneySymbol()
+                }, 20 * i * Math.random());
+                moneyRain.timerList.push(timer);
+            }
+        }
+        else moneyRain.isShow=false;
+    }
+    const initMoneyRain=()=>{
+        if (moneyRain!=null){
+            moneyRain.timerList=[];
+            showMoneyRain(true);
+        }
+    }
+    const clearMoneyRain=()=>{
+        if (moneyRain){
+            let timerList=moneyRain.timerList;
+            for (let i = 0; i < timerList.length; i++) {
+                let timer=timerList[i];
+                clearTimeout(timer);
+            }
+            moneyRain.timerList=[];
+        }
+    }
+    useEffect(()=>{
+        initMoneyRain();
+        return ()=>{
+            clearMoneyRain();
+        }
+    },[])
+    return (
+        <div ref={moneyRain} className={styles.rain_con}>
+        </div>
+    )
+}
+export default WRainAni;

+ 412 - 0
src/widgets/WMoneyRain/WRainAni/styles.module.scss

@@ -0,0 +1,412 @@
+$money_bg:"./../../../assets/moneyrain/money.png";
+//2.77
+.rain_con{
+  position: absolute;
+  z-index: 0;
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+  font-size: 2.77rem;
+}
+.money1 {
+  height: .24em;
+  background: url($money_bg) no-repeat;
+  background-size: .385em .24em
+}
+.money1,.money2 {
+  position: absolute;
+  z-index: 112;
+  width: .385em;
+  -webkit-animation-timing-function: linear;
+  animation-timing-function: linear;
+  -webkit-transform-style: preserve-3d;
+  transform-style: preserve-3d;
+}
+.money2 {
+  height: .235em;
+  background: url($money_bg) no-repeat;
+  background-size: .385em .235em
+}
+
+.money3 {
+  height: .225em;
+  background: url($money_bg) no-repeat;
+  background-size: .385em .225em
+}
+
+.money3,.money4 {
+  position: absolute;
+  z-index: 112;
+  width: .385em;
+  -webkit-animation-timing-function: linear;
+  animation-timing-function: linear;
+  -webkit-transform-style: preserve-3d;
+  transform-style: preserve-3d
+}
+
+.money4 {
+  height: .23em;
+  background: url($money_bg) no-repeat;
+  background-size: .385em .23em
+}
+
+.money5 {
+  position: absolute;
+  z-index: 112;
+  width: .505em;
+  height: .225em;
+  background: url($money_bg) no-repeat;
+  background-size: .505em .225em;
+  -webkit-animation-timing-function: linear;
+  animation-timing-function: linear;
+  -webkit-transform-style: preserve-3d;
+  transform-style: preserve-3d
+}
+@-webkit-keyframes fallAndSpin1 {
+  0% {
+    -webkit-transform: translateY(-.534em) rotate(0deg) translateX(0) translateZ(0);
+    transform: translateY(-.534em) rotate(0deg) translateX(0) translateZ(0);
+
+  }
+
+  25% {
+    -webkit-transform: translateY(.4em) rotate(180deg) translateX(.4em) translateZ(0);
+    transform: translateY(.4em) rotate(180deg) translateX(.4em) translateZ(0);
+  }
+
+  50% {
+    -webkit-transform: translateY(9.345em) rotate(1turn) translateX(0) translateZ(0);
+    transform: translateY(9.345em) rotate(1turn) translateX(0) translateZ(0);
+  }
+
+  75% {
+    -webkit-transform: translateY(15.35em) rotate(540deg) translateX(-.4em) translateZ(0);
+    transform: translateY(15.35em) rotate(540deg) translateX(-.4em) translateZ(0);
+  }
+
+  to {
+    -webkit-transform: translateY(24em) rotate(2turn) translateX(0) translateZ(0);
+    transform: translateY(24em) rotate(2turn) translateX(0) translateZ(0);
+  }
+}
+
+@keyframes fallAndSpin1 {
+  0% {
+    -webkit-transform: translateY(-.534em) rotate(0deg) translateX(0) translateZ(0);
+    transform: translateY(-.534em) rotate(0deg) translateX(0) translateZ(0);
+  }
+
+  25% {
+    -webkit-transform: translateY(.4em) rotate(180deg) translateX(.4em) translateZ(0);
+    transform: translateY(.4em) rotate(180deg) translateX(.4em) translateZ(0);
+  }
+
+  50% {
+    -webkit-transform: translateY(9.345em) rotate(1turn) translateX(0) translateZ(0);
+    transform: translateY(9.345em) rotate(1turn) translateX(0) translateZ(0);
+  }
+
+  75% {
+    -webkit-transform: translateY(15.35em) rotate(540deg) translateX(-.4em) translateZ(0);
+    transform: translateY(15.35em) rotate(540deg) translateX(-.4em) translateZ(0);
+  }
+
+  to {
+    -webkit-transform: translateY(24em) rotate(2turn) translateX(0) translateZ(0);
+    transform: translateY(24em) rotate(2turn) translateX(0) translateZ(0);
+  }
+}
+
+@-webkit-keyframes fallAndSpin2 {
+  0% {
+    -webkit-transform: translateY(-.534em) rotate(0deg) translateX(0) translateZ(0);
+    transform: translateY(-.534em) rotate(0deg) translateX(0) translateZ(0);
+  }
+
+  25% {
+    -webkit-transform: translateY(.4em) rotate(-180deg) translateX(.4em) translateZ(0);
+    transform: translateY(.4em) rotate(-180deg) translateX(.4em) translateZ(0);
+  }
+
+  50% {
+    -webkit-transform: translateY(9.345em) rotate(-1turn) translateX(0) translateZ(0);
+    transform: translateY(9.345em) rotate(-1turn) translateX(0) translateZ(0);
+  }
+
+  75% {
+    -webkit-transform: translateY(15.35em) rotate(-540deg) translateX(-.4em) translateZ(0);
+    transform: translateY(15.35em) rotate(-540deg) translateX(-.4em) translateZ(0);
+  }
+
+  to {
+    -webkit-transform: translateY(24em) rotate(-2turn) translateX(0) translateZ(0);
+    transform: translateY(24em) rotate(-2turn) translateX(0) translateZ(0);
+  }
+}
+
+@keyframes fallAndSpin2 {
+  0% {
+    -webkit-transform: translateY(-.534em) rotate(0deg) translateX(0) translateZ(0);
+    transform: translateY(-.534em) rotate(0deg) translateX(0) translateZ(0);
+  }
+
+  25% {
+    -webkit-transform: translateY(.4em) rotate(-180deg) translateX(.4em) translateZ(0);
+    transform: translateY(.4em) rotate(-180deg) translateX(.4em) translateZ(0);
+  }
+
+  50% {
+    -webkit-transform: translateY(9.345em) rotate(-1turn) translateX(0) translateZ(0);
+    transform: translateY(9.345em) rotate(-1turn) translateX(0) translateZ(0);
+  }
+
+  75% {
+    -webkit-transform: translateY(15.35em) rotate(-540deg) translateX(-.4em) translateZ(0);
+    transform: translateY(15.35em) rotate(-540deg) translateX(-.4em) translateZ(0);
+  }
+
+  to {
+    -webkit-transform: translateY(24em) rotate(-2turn) translateX(0) translateZ(0);
+    transform: translateY(24em) rotate(-2turn) translateX(0) translateZ(0);
+  }
+}
+
+@-webkit-keyframes fallAndSpin3 {
+  0% {
+    -webkit-transform: translateY(-.534em) rotate(0deg) translateX(0) translateZ(0);
+    transform: translateY(-.534em) rotate(0deg) translateX(0) translateZ(0);
+  }
+
+  25% {
+    -webkit-transform: translateY(.4em) rotate(90deg) translateX(.4em) translateZ(0);
+    transform: translateY(.4em) rotate(90deg) translateX(.4em) translateZ(0);
+  }
+
+  50% {
+    -webkit-transform: translateY(9.345em) rotate(180deg) translateX(0) translateZ(0);
+    transform: translateY(9.345em) rotate(180deg) translateX(0) translateZ(0);
+  }
+
+  75% {
+    -webkit-transform: translateY(15.35em) rotate(270deg) translateX(-.4em) translateZ(0);
+    transform: translateY(15.35em) rotate(270deg) translateX(-.4em) translateZ(0);
+  }
+
+  to {
+    -webkit-transform: translateY(24em) rotate(1turn) translateX(0) translateZ(0);
+    transform: translateY(24em) rotate(1turn) translateX(0) translateZ(0);
+  }
+}
+
+@keyframes fallAndSpin3 {
+  0% {
+    -webkit-transform: translateY(-.534em) rotate(0deg) translateX(0) translateZ(0);
+    transform: translateY(-.534em) rotate(0deg) translateX(0) translateZ(0);
+  }
+
+  25% {
+    -webkit-transform: translateY(.4em) rotate(90deg) translateX(.4em) translateZ(0);
+    transform: translateY(.4em) rotate(90deg) translateX(.4em) translateZ(0);
+  }
+
+  50% {
+    -webkit-transform: translateY(9.345em) rotate(180deg) translateX(0) translateZ(0);
+    transform: translateY(9.345em) rotate(180deg) translateX(0) translateZ(0);
+  }
+
+  75% {
+    -webkit-transform: translateY(15.35em) rotate(270deg) translateX(-.4em) translateZ(0);
+    transform: translateY(15.35em) rotate(270deg) translateX(-.4em) translateZ(0);
+  }
+
+  to {
+    -webkit-transform: translateY(24em) rotate(1turn) translateX(0) translateZ(0);
+    transform: translateY(24em) rotate(1turn) translateX(0) translateZ(0);
+  }
+}
+
+@-webkit-keyframes fallAndSpin3D1 {
+  0% {
+    -webkit-transform: translateY(0) rotate(0deg) translateX(0) translateZ(0);
+    transform: translateY(0) rotate(0deg) translateX(0) translateZ(0);
+  }
+
+  25% {
+    -webkit-transform: translateY(2em) rotate(180deg) translateX(.4em) translateZ(0);
+    transform: translateY(2em) rotate(180deg) translateX(.4em) translateZ(0);
+  }
+
+  50% {
+    -webkit-transform: translateY(4.5em) rotateX(1turn) translateX(0) translateZ(0);
+    transform: translateY(4.5em) rotateX(1turn) translateX(0) translateZ(0);
+  }
+
+  75% {
+    -webkit-transform: translateY(15.35em) rotate(540deg) translateX(-.4em) translateZ(0);
+    transform: translateY(15.35em) rotate(540deg) translateX(-.4em) translateZ(0);
+  }
+
+  to {
+    -webkit-transform: translateY(24em) rotate(2turn) translateX(0) translateZ(0);
+    transform: translateY(24em) rotate(2turn) translateX(0) translateZ(0);
+  }
+}
+
+@keyframes fallAndSpin3D1 {
+  0% {
+    -webkit-transform: translateY(0) rotate(0deg) translateX(0) translateZ(0);
+    transform: translateY(0) rotate(0deg) translateX(0) translateZ(0);
+  }
+
+  25% {
+    -webkit-transform: translateY(2em) rotate(180deg) translateX(.4em) translateZ(0);
+    transform: translateY(2em) rotate(180deg) translateX(.4em) translateZ(0);
+  }
+
+  50% {
+    -webkit-transform: translateY(4.5em) rotateX(1turn) translateX(0) translateZ(0);
+    transform: translateY(4.5em) rotateX(1turn) translateX(0) translateZ(0);
+  }
+
+  75% {
+    -webkit-transform: translateY(15.35em) rotate(540deg) translateX(-.4em) translateZ(0);
+    transform: translateY(15.35em) rotate(540deg) translateX(-.4em) translateZ(0);
+  }
+
+  to {
+    -webkit-transform: translateY(24em) rotate(2turn) translateX(0) translateZ(0);
+    transform: translateY(24em) rotate(2turn) translateX(0) translateZ(0);
+  }
+}
+
+@-webkit-keyframes fallAndSpin3D2 {
+  0% {
+    -webkit-transform: translateY(0) rotate(0deg) translateX(0) translateZ(0);
+    transform: translateY(0) rotate(0deg) translateX(0) translateZ(0);
+  }
+
+  25% {
+    -webkit-transform: translateY(2em) rotate(-180deg) translateX(.4em) translateZ(0);
+    transform: translateY(2em) rotate(-180deg) translateX(.4em) translateZ(0);
+  }
+
+  50% {
+    -webkit-transform: translateY(4.5em) rotate(-1turn) translateX(0) translateZ(0);
+    transform: translateY(4.5em) rotate(-1turn) translateX(0) translateZ(0);
+  }
+
+  75% {
+    -webkit-transform: translateY(15.35em) rotate(-540deg) translateX(-.4em) translateZ(0);
+    transform: translateY(15.35em) rotate(-540deg) translateX(-.4em) translateZ(0);
+  }
+
+  to {
+    -webkit-transform: translateY(24em) rotate(-2turn) translateX(0) translateZ(0);
+    transform: translateY(24em) rotate(-2turn) translateX(0) translateZ(0);
+  }
+}
+
+@keyframes fallAndSpin3D2 {
+  0% {
+    -webkit-transform: translateY(0) rotate(0deg) translateX(0) translateZ(0);
+    transform: translateY(0) rotate(0deg) translateX(0) translateZ(0);
+  }
+
+  25% {
+    -webkit-transform: translateY(2em) rotate(-180deg) translateX(.4em) translateZ(0);
+    transform: translateY(2em) rotate(-180deg) translateX(.4em) translateZ(0);
+  }
+
+  50% {
+    -webkit-transform: translateY(4.5em) rotate(-1turn) translateX(0) translateZ(0);
+    transform: translateY(4.5em) rotate(-1turn) translateX(0) translateZ(0);
+  }
+
+  75% {
+    -webkit-transform: translateY(15.35em) rotate(-540deg) translateX(-.4em) translateZ(0);
+    transform: translateY(15.35em) rotate(-540deg) translateX(-.4em) translateZ(0);
+  }
+
+  to {
+    -webkit-transform: translateY(24em) rotate(-2turn) translateX(0) translateZ(0);
+    transform: translateY(24em) rotate(-2turn) translateX(0) translateZ(0);
+  }
+}
+
+@-webkit-keyframes fallAndSpin3D3 {
+  0% {
+    -webkit-transform: translateY(0) rotate(0deg) translateX(0) translateZ(0);
+    transform: translateY(0) rotate(0deg) translateX(0) translateZ(0);
+  }
+
+  25% {
+    -webkit-transform: translateY(2em) rotate(-180deg) translateX(.4em) translateZ(0);
+    transform: translateY(2em) rotate(-180deg) translateX(.4em) translateZ(0);
+  }
+
+  50% {
+    -webkit-transform: translateY(4.5em) rotate(-1turn) translateX(0) translateZ(0);
+    transform: translateY(4.5em) rotate(-1turn) translateX(0) translateZ(0);
+  }
+
+  75% {
+    -webkit-transform: translateY(15.35em) rotate(-540deg) translateX(-.4em) translateZ(0);
+    transform: translateY(15.35em) rotate(-540deg) translateX(-.4em) translateZ(0);
+  }
+
+  to {
+    -webkit-transform: translateY(24em) rotate(-2turn) translateX(0) translateZ(0);
+    transform: translateY(24em) rotate(-2turn) translateX(0) translateZ(0);
+  }
+}
+
+@keyframes fallAndSpin3D3 {
+  0% {
+    -webkit-transform: translateY(0) rotate(0deg) translateX(0) translateZ(0);
+    transform: translateY(0) rotate(0deg) translateX(0) translateZ(0);
+  }
+
+  25% {
+    -webkit-transform: translateY(2em) rotate(-180deg) translateX(.4em) translateZ(0);
+    transform: translateY(2em) rotate(-180deg) translateX(.4em) translateZ(0);
+  }
+
+  50% {
+    -webkit-transform: translateY(4.5em) rotate(-1turn) translateX(0) translateZ(0);
+    transform: translateY(4.5em) rotate(-1turn) translateX(0) translateZ(0);
+  }
+
+  75% {
+    -webkit-transform: translateY(15.35em) rotate(-540deg) translateX(-.4em) translateZ(0);
+    transform: translateY(15.35em) rotate(-540deg) translateX(-.4rem) translateZ(0);
+  }
+
+  to {
+    -webkit-transform: translateY(24em) rotate(-2turn) translateX(0) translateZ(0);
+    transform: translateY(24em) rotate(-2turn) translateX(0) translateZ(0);
+  }
+}
+
+@-webkit-keyframes fallAndRotate {
+  0% {
+    -webkit-transform: translateY(-100%) translateZ(0);
+    transform: translateY(-100%) translateZ(0);
+  }
+
+  to {
+    -webkit-transform: translateY(100%) translateZ(0);
+    transform: translateY(100%) translateZ(0);
+  }
+}
+
+@keyframes fallAndRotate {
+  0% {
+    -webkit-transform: translateY(-100%) translateZ(0);
+    transform: translateY(-100%) translateZ(0);
+  }
+
+  to {
+    -webkit-transform: translateY(100%) translateZ(0);
+    transform: translateY(100%) translateZ(0);
+  }
+}

+ 69 - 1
src/widgets/WMoneyRain/index.jsx

@@ -6,11 +6,15 @@ import Grow from "@mui/material/Grow";
 import styled from 'styled-components/macro';
 import rain_bg3 from "@assets/moneyrain/rain_bg3.png";
 import close_bai from "@assets/moneyrain/Close_bai.png";
+import close_icon from "@assets/moneyrain/Close.png";
 import rain_card from "@assets/moneyrain/rain_card.png";
 import red_box from "@assets/moneyrain/huodongrukou5_jianbian.png";
 import time_icon from "@assets/moneyrain/shijian_bai.png";
 import star_icon from "@assets/moneyrain/bofang_bai.png";
+import rain_bg1 from "@assets/moneyrain/rain_bg1.png";
+import rain_bg2 from "@assets/moneyrain/rain_bg2.png";
 import {format2LongChips, stringFormat} from "@utils/helpers";
+import WRainAni from "@widgets/WMoneyRain/WRainAni/WRainAni";
 const i18n=global.i18n;
 const StyledRules=styled.div`
     background: url(${rain_bg3});
@@ -18,6 +22,13 @@ const StyledRules=styled.div`
 const StyledRewardCon=styled.div`
     background: url(${rain_card});
 `
+const StyledRedPack=styled.div`
+    background: url(${rain_bg1});
+`
+const StyledRedOpen=styled.div`
+    background: url(${rain_bg2});
+`
+
 const WMoneyRain = ({close}) => {
     const getRuleTxt=(totalStr)=>{
         let txt=[];
@@ -101,10 +112,66 @@ const WMoneyRain = ({close}) => {
             </Grow>
         )
     }
+    const renderRedPack=()=>{
+        let toatlNum=10000000;
+        let maxNum=777700;
+        let totalStr=format2LongChips(toatlNum);
+        let maxStr=format2LongChips(maxNum);
+        return (
+            <Grow in={true} timeout={500}>
+                <StyledRedPack className={styles.red_pack_con}>
+                    <button className={styles.close} onClick={close}>
+                        <img src={close_bai}/>
+                    </button>
+                    <div className={styles.title}>
+                        {i18n.t("moneyRain.redPack.title")}
+                    </div>
+                    <div className={styles.red_content}>
+                        <div className={styles.red_item}>
+                            <img src={star_icon}/>
+                            <div>{i18n.t("moneyRain.redPack.tips_0")}</div>
+                        </div>
+                        <div className={styles.red_item}>
+                            <img src={star_icon}/>
+                            <div>{stringFormat(i18n.t("moneyRain.redPack.tips_1"),[global.DOLLAR+maxStr])}</div>
+                        </div>
+                    </div>
+                    <div className={styles.red_btn_con}>
+                        <button className={styles.red_btn}>
+                            {i18n.t("moneyRain.redPack.btn")}
+                        </button>
+                    </div>
+                </StyledRedPack>
+            </Grow>
+        )
+    }
+    const renderRedOpen=()=>{
+        let reciveNum=10000;
+        let maxNum=777700;
+        let maxStr=format2LongChips(maxNum);
+        let reciveStr=format2LongChips(reciveNum);
+        return (
+            <Grow in={true} timeout={500}>
+                <StyledRedOpen className={styles.red_open_con}>
+                    <button className={styles.close} onClick={close} style={{right: "0.5rem"}}>
+                        <img src={close_icon}/>
+                    </button>
+                    <div className={styles.red_amount_uint}>{i18n.t("moneyRain.redOpen.max_drop")+maxStr}</div>
+                    <div className={styles.red_amount_recive}>{reciveStr}</div>
+                    <div className={styles.red_open_tips}>
+                        <div>{i18n.t("moneyRain.redOpen.time_tips")}</div>
+                        <div className={styles.time}>12:00:01</div>
+                    </div>
+                </StyledRedOpen>
+            </Grow>
+        )
+    }
     const renderMain = () => {
         return (
             <>
-                {renderRules()}
+                {/*{renderRules()}*/}
+                {/*{renderRedPack()}*/}
+                {renderRedOpen()}
             </>
         )
     }
@@ -112,6 +179,7 @@ const WMoneyRain = ({close}) => {
         <Modal open={true} onClose={close} closeAfterTransition>
             <Fade in={true} timeout={500}>
                 <div className={styles.container}>
+                    <WRainAni></WRainAni>
                     <div className={styles.content}>
                         {renderMain()}
                     </div>

+ 102 - 0
src/widgets/WMoneyRain/styles.module.scss

@@ -6,6 +6,7 @@
   width: 100%;
   height: 100%;
   pointer-events: none;
+  position: relative;
 }
 .content{
   display: flex;
@@ -16,6 +17,7 @@
   width: 100%;
   height: 100%;
   max-width: 414px;
+  z-index: 1;
 }
 .close{
   display: flex;
@@ -129,4 +131,104 @@
       color: rgba(255, 255, 255, 0.85);
     }
   }
+}
+.red_pack_con{
+  width: 70%;
+  aspect-ratio: 600/750;
+  background-size: 100% 100%;
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  padding: 1rem 1.5rem;
+  pointer-events: auto;
+  gap: 1rem;
+  font-size: 1rem;
+  font-weight: 600;
+  justify-content: space-between;
+  & .title{
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    color: rgb(252, 215, 161);
+    font-size: 1.3rem;
+    font-weight: 600;
+  }
+  & .red_content{
+    display: flex;
+    flex-direction: column;
+    margin-top: -3rem;
+    gap: 1.8rem;
+    img{
+      width: 0.8rem;
+      height: 0.8rem;
+      opacity: 0.65;
+      margin-top: 0.3rem;
+    }
+    & .red_item{
+      display: flex;
+      gap: 0.5rem;
+      color: rgba(255, 255, 255, 0.65);
+    }
+  }
+  & .red_btn_con{
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-bottom: 1rem;
+    & .red_btn{
+      color: rgb(252, 215, 161);
+      background-image: linear-gradient(rgb(221, 145, 78) 0%, rgb(107, 55, 26) 100%);
+      border: 2px solid rgb(252, 215, 161);
+      width: 70%;
+      height: 3rem;
+      border-radius: 1.6rem;
+      text-align: center;
+      //line-height: 2.4rem;
+      font-size: 1.2rem;
+      font-weight: bold;
+    }
+  }
+}
+.red_open_con{
+  width: 70%;
+  aspect-ratio: 600/750;
+  background-size: 100% 100%;
+  display: flex;
+  flex-direction: column;
+  position: relative;
+  padding: 1rem 2rem;
+  pointer-events: auto;
+  gap: 1rem;
+  font-size: 1rem;
+  font-weight: 600;
+  & .red_amount_uint{
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 1.3rem;
+    color: #740000;
+  }
+  & .red_amount_recive{
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-top: 4.5rem;
+    font-size: 3.5rem;
+    font-weight: bold;
+    color: #970000;
+  }
+  & .red_open_tips{
+    margin-top: 3rem;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    color: rgba(0,0,0,0.45);
+    font-size: 1.03rem;
+    gap: 0.5rem;
+    & .time{
+      font-size: 1.1rem;
+      color: #970000;
+    }
+  }
 }