Browse Source

feat: 增加首页轮播

Before 1 year ago
parent
commit
63813b66c6

+ 2 - 1
messages/br.json

@@ -8,6 +8,7 @@
 
   "Header": {
     "login": "Login",
-    "register": "Cadastre-se"
+    "register": "Cadastre-se",
+    "locale": "Preferência de Localização"
   }
 }

+ 3 - 1
package.json

@@ -20,7 +20,9 @@
     "next-themes": "^0.3.0",
     "react": "^18.3.1",
     "react-dom": "^18.3.1",
-    "sass": "^1.77.8"
+    "sass": "^1.77.8",
+    "swiper": "^11.1.5",
+    "tailwind-merge": "^2.4.0"
   },
   "devDependencies": {
     "@types/node": "^20.14.10",

+ 18 - 1
pnpm-lock.yaml

@@ -41,6 +41,12 @@ importers:
       sass:
         specifier: ^1.77.8
         version: 1.77.8
+      swiper:
+        specifier: ^11.1.5
+        version: 11.1.5
+      tailwind-merge:
+        specifier: ^2.4.0
+        version: 2.4.0
     devDependencies:
       '@types/node':
         specifier: ^20.14.10
@@ -2631,8 +2637,15 @@ packages:
     resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
     engines: {node: '>= 0.4'}
 
+  swiper@11.1.5:
+    resolution: {integrity: sha512-JJQWFXdxiMGC2j6ZGTYat5Z7NN9JORJBgHp0/joX9uPod+cRj0wr5H5VnWSNIz9JeAamQvYKaG7aFrGHIF9OEg==, tarball: https://registry.npmmirror.com/swiper/-/swiper-11.1.5.tgz}
+    engines: {node: '>= 4.7.0'}
+
   tailwind-merge@1.14.0:
-    resolution: {integrity: sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==}
+    resolution: {integrity: sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==, tarball: https://registry.npmmirror.com/tailwind-merge/-/tailwind-merge-1.14.0.tgz}
+
+  tailwind-merge@2.4.0:
+    resolution: {integrity: sha512-49AwoOQNKdqKPd9CViyH5wJoSKsCDjUlzL8DxuGp3P1FsGY36NJDAa18jLZcaHAUUuTj+JB8IAo8zWgBNvBF7A==, tarball: https://registry.npmmirror.com/tailwind-merge/-/tailwind-merge-2.4.0.tgz}
 
   tailwind-variants@0.1.20:
     resolution: {integrity: sha512-AMh7x313t/V+eTySKB0Dal08RHY7ggYK0MSn/ad8wKWOrDUIzyiWNayRUm2PIJ4VRkvRnfNuyRuKbLV3EN+ewQ==}
@@ -6281,8 +6294,12 @@ snapshots:
 
   supports-preserve-symlinks-flag@1.0.0: {}
 
+  swiper@11.1.5: {}
+
   tailwind-merge@1.14.0: {}
 
+  tailwind-merge@2.4.0: {}
+
   tailwind-variants@0.1.20(tailwindcss@3.4.4):
     dependencies:
       tailwind-merge: 1.14.0

BIN
public/homeGameIcon.png


+ 77 - 13
src/api/home.ts

@@ -1,17 +1,81 @@
 import { server } from "@/utils/server";
 
-type HomeInfo = {
-    type: number;
-    id: number;
-    imagePath: string;
-    linkType: number;
-    linkId: number;
-    linkUrl: string;
-    isVisible: number;
-    titleColor: string;
-};
-export const getHomeMultidata = () => {
-    return server.get<HomeInfo>({
-        url: "/home/multidata",
+export interface EntityGameListRep {
+    /**
+     * 游戏ICON
+     */
+    game_icon?: string;
+    /**
+     * 游戏ID
+     */
+    game_id?: string;
+    /**
+     * 游戏名称
+     */
+    game_name?: string;
+    /**
+     * 游戏名称中文
+     */
+    game_name_cn?: string;
+    /**
+     * 游戏类型
+     */
+    game_type?: string;
+    /**
+     * id
+     */
+    id?: number;
+    /**
+     * 厂商名字 besoft 等等
+     */
+    provider?: string;
+    /**
+     * 时间
+     */
+    release_date?: string;
+}
+
+export interface GroupType {
+    /**
+     * 多语言名字
+     */
+    category_name?: string;
+    /**
+     * 游戏列表
+     */
+    game_list?: EntityGameListRep[];
+    /**
+     * 分类图标
+     */
+    icon?: string;
+    /**
+     * 每页展示多少条
+     */
+    line_config_amount?: number;
+    /**
+     * 每页条数
+     */
+    line_num?: number;
+    /**
+     * 特殊显示 特殊显示,1:开启,2:关闭
+     */
+    special_show?: string;
+    /**
+     * 展示风格 展示风格,1:横排,2:竖排,3:竖排-分类左边-连续,4:竖排-分类左边-拆开
+     */
+    style_type?: number;
+    /**
+     * 标签
+     */
+    tag?: string;
+    /**
+     * 当前分类的数量
+     */
+    to_tal?: number;
+}
+
+export const getGamesApi = () => {
+    return server.post<GroupType[]>({
+        url: "/v1/api/front/game_list",
     });
 };

+ 21 - 0
src/app/[locale]/_home/HomeCard.tsx

@@ -0,0 +1,21 @@
+import { FC, PropsWithChildren } from "react";
+
+interface Props {}
+
+const urls = [
+    "https://9f.com/images/homePage/card/firstdeposit3.png",
+    "https://9f.com/images/homePage/card/cashwheel3.png",
+    "https://9f.com/images/homePage/card/telegram3.png",
+];
+
+const HomeCard: FC<PropsWithChildren<Props>> = (props) => {
+    return (
+        <div className={"my-[0.08rem] grid grid-cols-3 justify-between gap-x-2"}>
+            {urls.map((url, index) => (
+                <img src={url} alt="" className={"rounded-[0.04rem]"} key={index} />
+            ))}
+        </div>
+    );
+};
+
+export default HomeCard;

+ 33 - 0
src/app/[locale]/_home/HomeGames.tsx

@@ -0,0 +1,33 @@
+"use client";
+import { getGamesApi, GroupType } from "@/api/home";
+import { SwiperGroup } from "@/components/Card";
+import { FC, PropsWithChildren, useEffect, useState } from "react";
+import "swiper/css";
+interface Props {}
+const urls = [
+    "https://images.hibigwin.com/9f/202405/mqletkfLwGeZkSH.jpg",
+    "https://images.hibigwin.com/9f/202402/jLkCmSkItvcqlid.jpg",
+    "https://images.hibigwin.com/9f/202404/DDnZEhXKutDVIYn.jpg",
+    "https://images.hibigwin.com/9f/202406/wOBQjusbGUZkBMA.jpg",
+    "https://images.hibigwin.com/9f/202402/jLkCmSkItvcqlid.jpg",
+    "https://images.hibigwin.com/9f/202405/mqletkfLwGeZkSH.jpg",
+    "https://images.hibigwin.com/9f/202407/LPpEiiltiXwcdYz.jpg",
+    "https://images.hibigwin.com/9f/202406/veFfaahiTGAyDpy.jpg",
+];
+const HomeSwiper: FC<PropsWithChildren<Props>> = (props) => {
+    const [groupGames, setGroupGames] = useState<GroupType[]>([]);
+    useEffect(() => {
+        getGamesApi().then((res) => {
+            setGroupGames(res.data);
+        });
+    }, []);
+    return (
+        <div>
+            {groupGames.map((group, index) => {
+                return <SwiperGroup key={index} group={group}></SwiperGroup>;
+            })}
+        </div>
+    );
+};
+
+export default HomeSwiper;

+ 42 - 0
src/app/[locale]/_home/HomeSwiper.tsx

@@ -0,0 +1,42 @@
+"use client";
+import { FC, PropsWithChildren } from "react";
+import "swiper/css";
+import "swiper/css/autoplay";
+import "swiper/css/pagination";
+import "swiper/css/virtual";
+import { Autoplay, Pagination } from "swiper/modules";
+import { Swiper, SwiperSlide } from "swiper/react";
+interface Props {}
+const urls = [
+    "https://images.hibigwin.com/9f/202405/mqletkfLwGeZkSH.jpg",
+    "https://images.hibigwin.com/9f/202402/jLkCmSkItvcqlid.jpg",
+    "https://images.hibigwin.com/9f/202404/DDnZEhXKutDVIYn.jpg",
+    "https://images.hibigwin.com/9f/202406/wOBQjusbGUZkBMA.jpg",
+    "https://images.hibigwin.com/9f/202402/jLkCmSkItvcqlid.jpg",
+    "https://images.hibigwin.com/9f/202405/mqletkfLwGeZkSH.jpg",
+    "https://images.hibigwin.com/9f/202407/LPpEiiltiXwcdYz.jpg",
+    "https://images.hibigwin.com/9f/202406/veFfaahiTGAyDpy.jpg",
+];
+const HomeSwiper: FC<PropsWithChildren<Props>> = (props) => {
+    return (
+        <div style={{ height: "1.86rem" }}>
+            <Swiper
+                autoplay={{ delay: 2500 }}
+                pagination={{ clickable: true }}
+                spaceBetween={10}
+                scrollbar={{ draggable: true }}
+                slidesPerView={1}
+                loop
+                modules={[Pagination, Autoplay]}
+            >
+                {urls.map((url, index) => (
+                    <SwiperSlide key={index}>
+                        <img src={url} style={{ height: "1.86rem", width: "100%" }} alt={url} />
+                    </SwiperSlide>
+                ))}
+            </Swiper>
+        </div>
+    );
+};
+
+export default HomeSwiper;

+ 12 - 8
src/app/[locale]/page.tsx

@@ -1,19 +1,23 @@
+import HomeCard from "@/app/[locale]/_home/HomeCard";
+import HomeGames from "@/app/[locale]/_home/HomeGames";
+import Box from "@/components/Box";
 import Layout from "@/components/Layout";
 import { LocalPropsWithChildren } from "@/types";
 import { useTranslations } from "next-intl";
 import { FC } from "react";
-const arr = Array.from({ length: 100 }).map((_, i) => i);
-const Header = () => {
-    return <div>header</div>;
-};
+import HomeSwiper from "./_home/HomeSwiper";
+
 const App: FC<LocalPropsWithChildren> = (props) => {
     const t = useTranslations("global");
     return (
         <Layout>
-            <div>
-                this page
-                <div className="iconfont icon-zuqiu2"></div>
-            </div>
+            <>
+                <Box>
+                    <HomeSwiper></HomeSwiper>
+                    <HomeCard></HomeCard>
+                </Box>
+                <HomeGames />
+            </>
         </Layout>
     );
 };

+ 9 - 0
src/app/globals.css

@@ -2,6 +2,15 @@
 @tailwind components;
 @tailwind utilities;
 @import "@/styles/iconfont/iconfont.css";
+
+:root{
+  --swiper-pagination-bullet-width: 0.23rem;
+  --swiper-pagination-bullet-height: 0.05rem;
+  --swiper-pagination-bullet-border-radius: 0.03rem;
+  --swiper-pagination-color: #fff;
+  --swiper-pagination-bullet-active-bg: #fff;
+  --swiper-pagination-bullet-inactive-color: hsla(0, 0%, 100%, .8);
+}
 html, body {
     width: 100vw;
     height: auto;

+ 47 - 0
src/components/Box/index.tsx

@@ -0,0 +1,47 @@
+import clsx from "clsx";
+import { CSSProperties, FC, PropsWithChildren } from "react";
+import { twMerge } from "tailwind-merge";
+interface Props {
+    pt?: boolean;
+    pb?: boolean;
+    pl?: boolean;
+    pr?: boolean;
+    none?: boolean;
+    className?: string;
+    style?: CSSProperties;
+}
+
+/**
+ * @description
+ * 1`:接受padding属性, 有默认值, 有自定义值, 默认显示, 可自定并且合并
+ * todo 2: 可通过 clo / row 定义flex 布局
+ * todo 3: 可设置背景
+ */
+const Box: FC<PropsWithChildren<Props>> = (props) => {
+    const {
+        className,
+        children,
+        pt = true,
+        pb = true,
+        pl = true,
+        pr = true,
+        none = false,
+        style,
+    } = props;
+
+    const cls = clsx(
+        !none && {
+            ["pt-[0.08rem]"]: pt,
+            ["pb-[0.08rem]"]: pb,
+            ["px-[0.12rem]"]: pl || pr,
+        },
+        className
+    );
+    return (
+        <div className={twMerge(cls)} style={style}>
+            {children}
+        </div>
+    );
+};
+
+export default Box;

+ 18 - 0
src/components/Card/Card.tsx

@@ -0,0 +1,18 @@
+import { FC, PropsWithChildren, ReactNode } from "react";
+import styles from "./style.module.scss";
+export interface CardProps {
+    url?: string;
+    alt?: string;
+    render?: () => ReactNode;
+}
+
+const Card: FC<PropsWithChildren<CardProps>> = (props) => {
+    const { render, url, alt } = props;
+    return (
+        <div className={styles.cardWrap}>
+            {render ? render() : <img src={url} alt={alt} className={"h-1/1"} />}
+        </div>
+    );
+};
+
+export default Card;

+ 27 - 0
src/components/Card/GroupCard.tsx

@@ -0,0 +1,27 @@
+import { EntityGameListRep } from "@/api/home";
+import clsx from "clsx";
+import { FC } from "react";
+import Card, { CardProps } from "./Card";
+import styles from "./style.module.scss";
+export interface GroupProps extends CardProps {
+    data?: EntityGameListRep[];
+    col?: number;
+}
+
+const GroupCard: FC<GroupProps> = (props) => {
+    const { col = 3, data, ...other } = props;
+    const cls = clsx(
+        styles.groupWrap,
+        "grid",
+        `grid-cols-${col}`,
+        "gap-y-3 grid-rows-2",
+        "justify-between"
+    );
+    return (
+        <div className={"flex flex-wrap justify-between gap-y-4"}>
+            {data?.map((item, index) => <Card key={index} url={item.game_icon} {...other} />)}
+        </div>
+    );
+};
+
+export default GroupCard;

File diff suppressed because it is too large
+ 52 - 0
src/components/Card/SwiperGroup.tsx


+ 5 - 0
src/components/Card/index.tsx

@@ -0,0 +1,5 @@
+import Card from "./Card";
+import GroupCard from "./GroupCard";
+import SwiperGroup from "./SwiperGroup";
+
+export { Card, GroupCard, SwiperGroup };

+ 84 - 0
src/components/Card/style.module.scss

@@ -0,0 +1,84 @@
+
+
+.cardWrap {
+  position: relative;
+  width: 1.1rem;
+  height: 1.54rem;
+  overflow: hidden;
+  background: #212a36;
+  border-radius: .1rem;
+}
+
+
+.mainTitle{
+    height: .34rem;
+    display: flex;
+    position: relative;
+    justify-content: space-between;
+    img{
+      overflow-clip-margin: content-box;
+      overflow: clip;
+      flex: 1;
+    }
+  .mainLeft{
+    display: flex;
+    background: #1a1a1a;
+    padding-left: 0.12rem;
+    align-items: center;
+    width: 2.1rem;
+    .mainLeftIcon{
+      flex-shrink: 0;
+      background: url("/homeGameIcon.png") 0 0 no-repeat;
+      background-size: 3.2rem auto;
+      background-position-x: -1.15rem;
+      background-position-y: -.3rem;
+      display: inline-block;
+      width: .25rem;
+      height: .34rem;
+    }
+
+    .marginLeftTitle{
+      font-size: .13rem;
+      color: #fff;
+      margin: 0 .08rem 0 .06rem;
+      white-space: nowrap;
+    }
+    .marginLeftTag{
+      font-size: .14rem;
+      color: #ff6a01;
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+  }
+  .mainRight{
+    position: absolute;
+    top: 0;
+    right: 0;
+    display: flex;
+    padding-right: 0.12rem;
+    div{
+      padding: 0.05rem;
+      display: flex;
+      height: .25rem;
+      align-items: center;
+      background: #1a1a1a;
+      border-radius: .04rem;
+      justify-content: center;
+      margin-left: .05rem;
+      font-size: .12rem;
+      font-weight: 700;
+      color: #b3b3b3;
+    }
+
+    .marginRightCount {
+      color: $primary-color;
+      margin-left: 0.05rem;
+    }
+    span{
+      font-size: 0.12rem;
+      color: rgb(179, 179, 179);
+    }
+  }
+}

+ 1 - 1
src/components/Footer/style.module.scss

@@ -1,6 +1,6 @@
 
 .placeholder{
-  height: .6rem;
+  height: $-footer-height;
   max-width: 4.02rem;
 }
 .footerWrap{

File diff suppressed because it is too large
+ 4 - 7
src/components/Header/HerderTitle.tsx


+ 1 - 1
src/components/Header/style.module.scss

@@ -1,6 +1,6 @@
 
 .placeholder {
-  height: 0.4rem;
+  height: $-header-height;
 }
 
 .headerWrap{

+ 3 - 3
src/components/Layout/style.module.scss

@@ -1,6 +1,6 @@
 
-
 .main{
-  border: 1px solid white;
-  overflow-x:  hidden;
+  //padding: 0.08rem  0.12rem;
+  height: calc(calc(100vh - $-header-height) - $-footer-height);
+  overflow-y: scroll;
 }

+ 4 - 0
src/styles/variables.scss

@@ -2,4 +2,8 @@
 $-theme-color: #000;
 $-footer-bg: #292929;
 
+$primary-color: #ff6a01;
 
+
+$-header-height: 0.4rem;
+$-footer-height: 0.6rem;

+ 11 - 10
src/utils/index.ts

@@ -3,17 +3,18 @@ export const setHtmlFontSize = () => {
     console.count("setHtmlFontSize");
     (function (doc, win) {
         let resizeEvt = "orientationchange" in win ? "orientationchange" : "resize",
-        recalc = function () {
-            let htmlDom = doc.getElementsByTagName("html")[0]
-            requestAnimationFrame(() => {
-                let clientWidth = doc.documentElement.clientWidth || doc.body.clientWidth;
-                if (!clientWidth) return;
-                htmlDom.style.fontSize = clientWidth>=578.88 ? '144px' : 154.5 * (clientWidth / 578.88) + 'px';
-            })
-        };
+            recalc = function () {
+                let htmlDom = doc.getElementsByTagName("html")[0];
+                requestAnimationFrame(() => {
+                    let clientWidth = doc.documentElement.clientWidth || doc.body.clientWidth;
+                    if (!clientWidth) return;
+                    htmlDom.style.fontSize =
+                        clientWidth >= 578.88 ? "144px" : 154.5 * (clientWidth / 578.88) + "px";
+                });
+            };
         if (!doc.addEventListener) return;
         win.addEventListener(resizeEvt, recalc, false);
-        doc.addEventListener('DOMContentLoaded', recalc, false);   
-        recalc()   
+        doc.addEventListener("DOMContentLoaded", recalc, false);
+        recalc();
     })(document, window);
 };

+ 1 - 0
src/utils/server/index.ts

@@ -1,6 +1,7 @@
 import Request from "./axios";
 const server = new Request({
     timeout: 10 * 1000,
+    baseURL: "http://127.0.0.1:4523/m1/4790544-4444647-default",
     transform: {
         // instance  interceptor
         requestInterceptor: (config) => {

+ 29 - 8
tailwind.config.ts

@@ -1,20 +1,35 @@
 import { nextui } from "@nextui-org/react";
 import type { Config } from "tailwindcss";
 
-const fontSize: any = Array.from({ length: 100 }).reduce((map: any, _, index) => {
-    map[index] = `${index}px`;
+const MAX_WIDTH = 1440;
+const toRem = (px: number) => {
+    return `${((4 * px) / (MAX_WIDTH / 10)).toFixed(2)}rem`;
+};
+
+const size: any = Array.from({ length: 100 }).reduce((map: any, _, index) => {
+    map[index] = toRem(index);
     return map;
 }, {});
+
+// 0.0694rem
 const config: Config = {
     content: [
         "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
         "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
         "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
-        "./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}",
+        "./node_modules/@nextui-org/theme/dist/**/*.{" + "js,ts,jsx,tsx}",
     ],
     theme: {
+        space: size,
+        padding: size,
+        height: size,
+        minWidth: size,
+        lineHeight: size,
+        width: size,
+        gap: size,
+        minHeight: size,
+        fontSize: size,
         extend: {
-            fontSize,
             backgroundImage: {
                 "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
                 "gradient-conic":
@@ -26,10 +41,16 @@ const config: Config = {
         nextui({
             layout: {
                 fontSize: {
-                    // tiny: "10px", // text-tiny
-                    // small: "12px", // text-small
-                    // medium: "14px", // text-medium
-                    // large: "16px", // text-large
+                    tiny: "10px", // text-tiny
+                    small: "12px", // text-small
+                    medium: "14px", // text-medium
+                    large: "16px", // text-large
+                },
+                lineHeight: {
+                    tiny: "14px", // text-tiny
+                    small: "24px", // text-small
+                    medium: "22px", // text-medium
+                    large: "20px",
                 },
             },
             themes: {

Some files were not shown because too many files changed in this diff