✨ feat:
|
@ -0,0 +1,10 @@
|
|||
###
|
||||
# @LastEditors: John
|
||||
# @Date: 2024-06-18 10:12:21
|
||||
# @LastEditTime: 2024-07-15 11:02:08
|
||||
# @Author: John
|
||||
###
|
||||
VITE_BASE_URL=
|
||||
VITE_BASE_API_URL=/dev
|
||||
VITE_TG_BOT_NAME=johntest_bot
|
||||
VITE_TG_BOT_WEBAPP_NAME=shortname
|
|
@ -0,0 +1,10 @@
|
|||
###
|
||||
# @LastEditors: John
|
||||
# @Date: 2024-06-26 15:04:10
|
||||
# @LastEditTime: 2024-07-15 11:01:57
|
||||
# @Author: John
|
||||
###
|
||||
VITE_BASE_URL=
|
||||
VITE_BASE_API_URL=/api
|
||||
VITE_TG_BOT_NAME=
|
||||
VITE_TG_BOT_WEBAPP_NAME=
|
|
@ -0,0 +1,18 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
],
|
||||
ignorePatterns: ['dist', '.eslintrc.cjs'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['react-refresh'],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
|
@ -0,0 +1 @@
|
|||
nodeLinker: node-modules
|
|
@ -0,0 +1,30 @@
|
|||
# React + TypeScript + Vite
|
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||
|
||||
Currently, two official plugins are available:
|
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
|
||||
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
||||
|
||||
- Configure the top-level `parserOptions` property like this:
|
||||
|
||||
```js
|
||||
export default {
|
||||
// other rules...
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
project: ['./tsconfig.json', './tsconfig.node.json'],
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
|
||||
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
|
||||
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
|
|
@ -0,0 +1,23 @@
|
|||
<!--
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-07-13 10:21:58
|
||||
* @LastEditTime: 2024-07-13 17:14:14
|
||||
* @Author: John
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0,maximum-scale=1, minimum-scale=1, user-scalable=no"
|
||||
/>
|
||||
<title>Vite + React + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"name": "tg-bot",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hyper-fetch/core": "^5.7.5",
|
||||
"@hyper-fetch/react": "^5.7.5",
|
||||
"@vkruglikov/react-telegram-web-app": "2.1.9",
|
||||
"antd-mobile": "^5.37.1",
|
||||
"antd-mobile-icons": "^0.3.0",
|
||||
"clsx": "^2.1.1",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-router-dom": "^6.24.1",
|
||||
"tailwind-merge": "^2.4.0",
|
||||
"vconsole": "^3.15.1",
|
||||
"zustand": "^4.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.14.10",
|
||||
"@types/postcss-pxtorem": "^6.0.3",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.13.1",
|
||||
"@typescript-eslint/parser": "^7.13.1",
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"eslint-plugin-react-refresh": "^0.4.7",
|
||||
"postcss": "^8.4.39",
|
||||
"postcss-pxtorem": "^6.1.0",
|
||||
"react-iconfont-cli": "^2.0.2",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^5.3.1",
|
||||
"vite-plugin-compression": "^0.5.1"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-06-17 18:25:10
|
||||
* @LastEditTime: 2024-07-13 14:06:25
|
||||
* @Author: John
|
||||
*/
|
||||
export default {
|
||||
plugins: {
|
||||
autoprefixer: {},
|
||||
"postcss-pxtorem": {
|
||||
rootValue: 37.5,
|
||||
propList: ["*"],
|
||||
exclude: (e) => {
|
||||
if (/.*-m\.css$/.test(e) || /.*-m.module\.css$/.test(e)) {
|
||||
console.log(e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,168 @@
|
|||
body,
|
||||
html,
|
||||
#root {
|
||||
height: var(--tg-viewport-height);
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Roboto";
|
||||
src: url("./assets/font/Roboto-Medium.ttf") format("truetype");
|
||||
}
|
||||
|
||||
* {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
div,
|
||||
dl,
|
||||
dt,
|
||||
dd,
|
||||
ul,
|
||||
ol,
|
||||
li,
|
||||
p,
|
||||
blockquote,
|
||||
pre,
|
||||
hr,
|
||||
figure,
|
||||
table,
|
||||
caption,
|
||||
th,
|
||||
td,
|
||||
form,
|
||||
fieldset,
|
||||
legend,
|
||||
input,
|
||||
button,
|
||||
textarea,
|
||||
menu {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
header,
|
||||
footer,
|
||||
section,
|
||||
article,
|
||||
aside,
|
||||
nav,
|
||||
hgroup,
|
||||
address,
|
||||
figure,
|
||||
figcaption,
|
||||
menu,
|
||||
details {
|
||||
display: block;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
caption,
|
||||
th {
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
}
|
||||
html,
|
||||
body,
|
||||
fieldset,
|
||||
img,
|
||||
iframe,
|
||||
abbr {
|
||||
border: 0;
|
||||
}
|
||||
i,
|
||||
cite,
|
||||
em,
|
||||
var,
|
||||
address,
|
||||
dfn {
|
||||
font-style: normal;
|
||||
}
|
||||
[hidefocus],
|
||||
summary {
|
||||
outline: 0;
|
||||
}
|
||||
li {
|
||||
list-style: none;
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
small {
|
||||
font-size: 100%;
|
||||
}
|
||||
sup,
|
||||
sub {
|
||||
font-size: 83%;
|
||||
}
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: inherit;
|
||||
}
|
||||
q:before,
|
||||
q:after {
|
||||
content: none;
|
||||
}
|
||||
textarea {
|
||||
overflow: auto;
|
||||
resize: none;
|
||||
}
|
||||
label,
|
||||
summary {
|
||||
cursor: default;
|
||||
}
|
||||
a,
|
||||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
em,
|
||||
strong,
|
||||
b {
|
||||
font-weight: bold;
|
||||
}
|
||||
del,
|
||||
ins,
|
||||
u,
|
||||
s,
|
||||
a,
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
body,
|
||||
textarea,
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
keygen,
|
||||
legend {
|
||||
font: 12px/1.14 Microsoft YaHei, arial, \5b8b\4f53;
|
||||
color: #333;
|
||||
outline: 0;
|
||||
}
|
||||
a,
|
||||
a:hover {
|
||||
color: #333;
|
||||
}
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-07-13 10:21:58
|
||||
* @LastEditTime: 2024-07-15 15:37:43
|
||||
* @Author: John
|
||||
*/
|
||||
import { Route, Routes, useNavigate } from "react-router-dom";
|
||||
import "./App.css";
|
||||
import { useInitData, useWebApp } from "@vkruglikov/react-telegram-web-app";
|
||||
import Home from "./pages/Home";
|
||||
import Guide from "./pages/Guide";
|
||||
import useUserStore from "./store/User";
|
||||
import { useEffect } from "react";
|
||||
import Index from "./pages/Index";
|
||||
import {
|
||||
api_get_user_information,
|
||||
api_login,
|
||||
api_query_whether_the_user_receives_the_registration_reward,
|
||||
} from "./server/api";
|
||||
|
||||
function App() {
|
||||
const WebApp = useWebApp();
|
||||
const [initDataUnsafe, initData] = useInitData();
|
||||
const { Token, UpdateToken, UpdateInvitationCode } = useUserStore();
|
||||
const navigate = useNavigate();
|
||||
console.log("WebApp:", WebApp);
|
||||
console.log("initDataUnsafe:", initDataUnsafe);
|
||||
console.log("initData:", initData);
|
||||
console.log("window.location", window.location);
|
||||
|
||||
WebApp.setBackgroundColor("#000000");
|
||||
WebApp.setHeaderColor("#000000");
|
||||
|
||||
useEffect(() => {
|
||||
// navigate("/guide");
|
||||
(async () => {
|
||||
if (initData && !Token) {
|
||||
const { data } = await api_login().send({
|
||||
data: {
|
||||
initData,
|
||||
...(initDataUnsafe?.start_param
|
||||
? { invitationCode: initDataUnsafe?.start_param }
|
||||
: {}),
|
||||
},
|
||||
});
|
||||
if (data?.data.token) UpdateToken(data?.data.token);
|
||||
}
|
||||
|
||||
const { data: userData } = await api_get_user_information().send({});
|
||||
UpdateInvitationCode(userData?.data.shareCode || "");
|
||||
const { data } =
|
||||
await api_query_whether_the_user_receives_the_registration_reward().send(
|
||||
{}
|
||||
);
|
||||
if (data?.data == "0") {
|
||||
navigate("/guide");
|
||||
}
|
||||
})();
|
||||
|
||||
return () => {};
|
||||
}, [initData, Token]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{Token && (
|
||||
<Routes>
|
||||
<Route path="/*" element={<Index />} />
|
||||
<Route path="/guide" element={<Guide />} />
|
||||
</Routes>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="375" height="65" viewBox="0 0 375 65"><defs><mask id="master_svg0_1_1782" style="mask-type:alpha" maskUnits="userSpaceOnUse"><g><rect x="0" y="0" width="375" height="65" rx="0" fill="#FFFFFF" fill-opacity="1"/></g></mask></defs><g mask="url(#master_svg0_1_1782)"><g><g><rect x="-260" y="0" width="635" height="109" rx="0" fill="#000000" fill-opacity="1"/></g><g><path d="M-136.387,0L-260,0C-225.86430000000001,0,-198.1944,28.5306,-198.1944,63.7231C-198.1944,28.5306,-170.5223,0,-136.387,0Z" fill="#489149" fill-opacity="1"/></g><g><path d="M0,26.184616088867188L0,45.84581608886719C11.0392,45.84581608886719,19.9882,54.64841608886719,19.9881,65.50691608886719C19.9869,76.36711608886719,11.0382,85.17041608886719,0,85.17041608886719L0,104.83151608886719C22.0796,104.83151608886719,39.9786,87.22531608886719,39.9786,65.50691608886719C39.9748,43.78871608886719,22.0769,26.184616088867188,0,26.184616088867188Z" fill="#489149" fill-opacity="1"/></g><g><path d="M-114.01179572753907,90.58208044433593C-102.69459572753905,79.45108044433593,-102.69459572753905,61.40308044433594,-114.01179572753907,50.27214044433594C-125.32789572753907,39.14006044433594,-143.67599572753906,39.14006044433594,-154.99207572753906,50.27214044433594C-166.30929572753905,61.40308044433594,-166.30929572753905,79.45108044433593,-154.99207572753906,90.58208044433593C-143.67599572753906,101.71418044433594,-125.32789572753907,101.71418044433594,-114.01179572753907,90.58208044433593ZM-134.49049572753907,86.68818044433593L-151.02199572753906,70.42708044433594L-134.49049572753907,54.16378044433594L-117.95899572753906,70.42488044433594L-134.49049572753907,86.68818044433593Z" fill="#489149" fill-opacity="1"/></g><g><path d="M158.9656,118.9656C176.34480000000002,101.5881,176.34480000000002,73.4119,158.9656,56.0344C141.5881,38.65519,113.4118,38.65519,96.0344,56.0344C78.65519,73.4119,78.65519,101.5882,96.0344,118.9656C113.4118,136.34480000000002,141.5881,136.34480000000002,158.9656,118.9656ZM127.5176,112.8865L102.1311,87.5L127.5176,62.11L152.9041,87.4965L127.5176,112.8865Z" fill="#489149" fill-opacity="1"/></g><g><path d="M282.9656,118.9656C300.3448,101.5881,300.3448,73.4119,282.9656,56.0344C265.5881,38.65519,237.4118,38.65519,220.0344,56.0344C202.65519,73.4119,202.65519,101.5882,220.0344,118.9656C237.4118,136.34480000000002,265.5881,136.34480000000002,282.9656,118.9656ZM251.51760000000002,112.8865L226.1311,87.5L251.51760000000002,62.11L276.90409999999997,87.4965L251.51760000000002,112.8865Z" fill="#489149" fill-opacity="1"/></g><g><ellipse cx="251.5" cy="65.5" rx="12.5" ry="12.5" fill="#489149" fill-opacity="1"/></g><g><ellipse cx="123.5" cy="65.5" rx="12.5" ry="12.5" fill="#489149" fill-opacity="1"/></g><g><path d="M-9.387,0L-133,0C-98.8643,0,-71.1944,28.5306,-71.1944,63.7231C-71.1944,28.5306,-43.5223,0,-9.387,0Z" fill="#489149" fill-opacity="1"/></g><g><path d="M127.77334594726562,0L0.773345947265625,0C35.84424594726563,0,64.27224594726562,28.5306,64.27224594726562,63.7231C64.27224594726562,28.5306,92.70244594726563,0,127.77334594726562,0Z" fill="#489149" fill-opacity="1"/></g><g><path d="M251.38634594726562,0L127.77334594726562,0C161.9090459472656,0,189.57894594726562,28.5306,189.57894594726562,63.7231C189.57894594726562,28.5306,217.25104594726562,0,251.38634594726562,0Z" fill="#489149" fill-opacity="1"/></g><g><path d="M374.9996882324219,0L251.38668823242188,0C285.52238823242186,0,313.1922882324219,28.5306,313.1922882324219,63.7231C313.1922882324219,28.5306,340.8643882324219,0,374.9996882324219,0Z" fill="#489149" fill-opacity="1"/></g><g transform="matrix(-1,0,0,1,750,0)"><path d="M375,26.184616088867188L375,45.84581608886719C386.0392,45.84581608886719,394.9882,54.64841608886719,394.9881,65.50691608886719C394.9869,76.36711608886719,386.0382,85.17041608886719,375,85.17041608886719L375,104.83151608886719C397.0796,104.83151608886719,414.97860000000003,87.22531608886719,414.97860000000003,65.50691608886719C414.9748,43.78871608886719,397.0769,26.184616088867188,375,26.184616088867188Z" fill="#489149" fill-opacity="1"/></g></g></g></svg>
|
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 16 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="24" height="24" viewBox="0 0 24 24"><defs><clipPath id="master_svg0_2_1471"><rect x="0" y="0" width="24" height="24" rx="0"/></clipPath><linearGradient x1="0.03729605674743652" y1="0.31006065011024475" x2="0.9624395370483398" y2="0.6896783113479614" id="master_svg1_2_1551"><stop offset="0%" stop-color="#F7BD00" stop-opacity="1"/><stop offset="27.000001072883606%" stop-color="#EDAA00" stop-opacity="1"/><stop offset="64.99999761581421%" stop-color="#F9EF00" stop-opacity="1"/><stop offset="100%" stop-color="#F7BD00" stop-opacity="1"/></linearGradient><linearGradient x1="0.1464466154575348" y1="0.14638635516166687" x2="0.8535534143447876" y2="0.8534931540489197" id="master_svg2_2_1552"><stop offset="0%" stop-color="#F7BD00" stop-opacity="1"/><stop offset="34.99999940395355%" stop-color="#F9EF00" stop-opacity="1"/><stop offset="73.00000190734863%" stop-color="#EDAA00" stop-opacity="1"/><stop offset="100%" stop-color="#F7BD00" stop-opacity="1"/></linearGradient><linearGradient x1="0.5" y1="0.91044682264328" x2="0.5" y2="0.046372897922992706" id="master_svg3_2_1553"><stop offset="0%" stop-color="#F7BD00" stop-opacity="1"/><stop offset="34.99999940395355%" stop-color="#F9EF00" stop-opacity="1"/><stop offset="73.00000190734863%" stop-color="#EDAA00" stop-opacity="1"/><stop offset="100%" stop-color="#F7BD00" stop-opacity="1"/></linearGradient></defs><g clip-path="url(#master_svg0_2_1471)"><g><g><g><g transform="matrix(0.9251434803009033,-0.3796176314353943,0.3796176314353943,0.9251434803009033,-2.343110720385255,-0.98151359480363)"><ellipse cx="8.33968448638916" cy="17.45051670074463" rx="12" ry="12" fill="url(#master_svg1_2_1551)" fill-opacity="1"/></g><g transform="matrix(0.7071067690849304,-0.7071067690849304,0.7071067690849304,0.7071067690849304,-9.688210810436317,0.6105614204093399)"><ellipse cx="7.281386375427246" cy="23.38846492767334" rx="11.388479232788086" ry="11.388479232788086" fill="url(#master_svg2_2_1552)" fill-opacity="1"/></g><g transform="matrix(0.7071067690849304,-0.7071067690849304,0.7071067690849304,0.7071067690849304,-8.41073581768785,3.6946586932858736)"><ellipse cx="8.55876350402832" cy="20.304269790649414" rx="8.30428409576416" ry="8.30428409576416" fill="url(#master_svg3_2_1553)" fill-opacity="1"/></g><g style="mix-blend-mode:overlay"><path d="M4.11220047076416,12.407671876525878C4.10715047076416,9.103421876525879,6.065618470764161,6.111971876525879,9.096098470764161,4.795041876525879C12.12657847076416,3.4781088765258787,15.64981847076416,4.087429876525879,18.06201847076416,6.345631876525879C14.84731847076416,2.9934568765258787,9.505728470764161,2.937523876525879,6.22159847076416,6.221651876525879C2.9374704707641603,9.50578187652588,2.99340447076416,14.847371876525878,6.34557847076416,18.062071876525877C4.90858847076416,16.530171876525877,4.10985847076416,14.507971876525879,4.11220047076416,12.407671876525878Z" fill="#FFFFFF" fill-opacity="1" style="mix-blend-mode:overlay"/></g><g style="opacity:0.5400000214576721;mix-blend-mode:multiply"><path d="M12.00013995513916,3.695725440979004L11.78743995513916,3.695725440979004C16.08378995513916,3.803684440979004,19.50098995513916,7.3347654409790035,19.46818995513916,11.632335440979004C19.43528995513916,15.929925440979003,15.964489955139161,19.408325440979006,11.66701995513916,19.450625440979003C7.369529955139161,19.492925440979004,3.83095995513916,16.083425440979006,3.71358203513916,11.787305440979004C3.70919245513916,11.858135440979003,3.70919245513916,11.929175440979003,3.71358203513916,12.000005440979004C3.71358161513916,16.586325440979003,7.43153995513916,20.304325440979003,12.01786995513916,20.304325440979003C16.604189955139162,20.304325440979003,20.32218995513916,16.586325440979003,20.32218995513916,12.000005440979004C20.32218995513916,7.413675440979004,16.604189955139162,3.695725440979004,12.01786995513916,3.695725440979004L12.00013995513916,3.695725440979004Z" fill="#AF4304" fill-opacity="1" style="mix-blend-mode:multiply"/></g><g><g><path d="M11.521418984375,15.952738550109864L11.521418984375,9.101928550109863L12.265878984375,9.855248550109863L9.970458984375,9.855248550109863L9.970458984375,8.463818550109863L13.214178984375,8.463818550109863L13.214178984375,15.952738550109864L11.521418984375,15.952738550109864Z" fill="#AF4304" fill-opacity="1"/></g></g></g></g></g></g></svg>
|
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 6.1 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 25 KiB |
|
@ -0,0 +1,41 @@
|
|||
.bottomTab {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 83px;
|
||||
padding: 0 39px;
|
||||
background-color: #000000;
|
||||
z-index: 999;
|
||||
li {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
span {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
text-align: right;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #adadad;
|
||||
z-index: 1;
|
||||
|
||||
&.active {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-07-13 18:07:43
|
||||
* @LastEditTime: 2024-07-15 15:36:30
|
||||
* @Author: John
|
||||
*/
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import classes from "./BottomTab-m.module.css";
|
||||
import { AppOutline, HistogramOutline, TeamFill } from "antd-mobile-icons";
|
||||
import { useEffect, useState } from "react";
|
||||
export default function () {
|
||||
const navigate = useNavigate();
|
||||
const { pathname } = useLocation();
|
||||
const [currentpathname, setCurrentpathname] = useState("");
|
||||
useEffect(() => {
|
||||
console.log("pathname:", pathname);
|
||||
setCurrentpathname(pathname);
|
||||
return () => {};
|
||||
}, [pathname]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ul className={classes.bottomTab}>
|
||||
<li onClick={() => navigate("/")}>
|
||||
<AppOutline color={currentpathname == "/" ? "#ffffff" : "#adadad"} />
|
||||
<span className={currentpathname == "/" ? classes.active : ""}>
|
||||
Home
|
||||
</span>
|
||||
</li>
|
||||
<li onClick={() => navigate("/leaderboard")}>
|
||||
<HistogramOutline
|
||||
color={currentpathname == "/leaderboard" ? "#ffffff" : "#adadad"}
|
||||
/>
|
||||
<span
|
||||
className={currentpathname == "/leaderboard" ? classes.active : ""}
|
||||
>
|
||||
Leaderboard
|
||||
</span>
|
||||
</li>
|
||||
<li onClick={() => navigate("/frends")}>
|
||||
<TeamFill
|
||||
color={currentpathname == "/frends" ? "#ffffff" : "#adadad"}
|
||||
/>
|
||||
<span className={currentpathname == "/frends" ? classes.active : ""}>
|
||||
Frends
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-06-17 17:57:13
|
||||
* @LastEditTime: 2024-07-13 13:59:23
|
||||
* @Author: John
|
||||
*/
|
||||
export enum ASYNC_STORAGE_KEY {
|
||||
Store = "user.store",
|
||||
}
|
||||
|
||||
export enum Lang {
|
||||
en = "en",
|
||||
cn = "cn",
|
||||
tw = "tw",
|
||||
jp = "jp",
|
||||
de = "de",
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-07-13 10:21:58
|
||||
* @LastEditTime: 2024-07-13 17:20:53
|
||||
* @Author: John
|
||||
*/
|
||||
import ReactDOM from "react-dom/client";
|
||||
import App from "./App.tsx";
|
||||
import "./index.css";
|
||||
import { WebAppProvider } from "@vkruglikov/react-telegram-web-app";
|
||||
import { MemoryRouter } from "react-router-dom";
|
||||
import VConsole from "vconsole";
|
||||
import flexible from "./utils/flexible.ts";
|
||||
|
||||
// if (getUrlParameterByName("vconsole") === "1") {
|
||||
new VConsole();
|
||||
// }
|
||||
flexible(window, document);
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
// <WebAppProvider>
|
||||
<MemoryRouter>
|
||||
<App />
|
||||
</MemoryRouter>
|
||||
// </WebAppProvider>
|
||||
);
|
|
@ -0,0 +1,147 @@
|
|||
.frends {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.top_title {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
line-height: normal;
|
||||
text-align: center;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 0;
|
||||
|
||||
margin-top: 35px;
|
||||
}
|
||||
.logo {
|
||||
width: 141px;
|
||||
height: 149px;
|
||||
margin-top: 31px;
|
||||
}
|
||||
.tip {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 22px;
|
||||
font-weight: normal;
|
||||
line-height: normal;
|
||||
text-align: center;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 0;
|
||||
|
||||
margin-top: 61px;
|
||||
}
|
||||
.frends_list {
|
||||
padding: 0 16px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 30px;
|
||||
margin-top: 17px;
|
||||
padding-bottom: 165px;
|
||||
.frends_list_title {
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.frends_list_item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
> svg {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
span {
|
||||
&:nth-of-type(1) {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
line-height: normal;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&:nth-of-type(2) {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
line-height: normal;
|
||||
text-align: right;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 1;
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.bottom_btn {
|
||||
padding: 17px 15px;
|
||||
position: fixed;
|
||||
bottom: 83px;
|
||||
background-color: #000000;
|
||||
z-index: 999;
|
||||
button {
|
||||
width: 345px;
|
||||
height: 48px;
|
||||
border-radius: 8px;
|
||||
opacity: 1;
|
||||
background: #ffffff;
|
||||
|
||||
> span {
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-07-13 16:08:30
|
||||
* @LastEditTime: 2024-07-15 15:31:58
|
||||
* @Author: John
|
||||
*/
|
||||
import logo from "@/assets/logo.png";
|
||||
import { Avatar, Button } from "antd-mobile";
|
||||
import classes from "./Frends-m.module.css";
|
||||
import { useWebApp } from "@vkruglikov/react-telegram-web-app";
|
||||
import useUserStore from "@/store/User";
|
||||
import { useEffect, useState } from "react";
|
||||
import { api_homepage_subordinates_users } from "@/server/api";
|
||||
import { subordinatesUsers } from "@/server/module";
|
||||
export default function () {
|
||||
const WebApp = useWebApp();
|
||||
const { InvitationCode } = useUserStore();
|
||||
const [frends, setFrends] = useState<subordinatesUsers[]>();
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const { data } = await api_homepage_subordinates_users().send({});
|
||||
setFrends(data?.data);
|
||||
})();
|
||||
|
||||
return () => {};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={classes.frends}>
|
||||
<span className={classes.top_title}>
|
||||
Invite friends and get more PEPES
|
||||
</span>
|
||||
<img className={classes.logo} src={logo} alt="" />
|
||||
<span className={classes.tip}>
|
||||
Tap on the button to invite your friends
|
||||
</span>
|
||||
<ul className={classes.frends_list}>
|
||||
<span className={classes.frends_list_title}>0 friends</span>
|
||||
{frends?.map((v, i) => (
|
||||
<FrendsItem key={i} userName={v.account} point={"0"} />
|
||||
))}
|
||||
</ul>
|
||||
<div className={classes.bottom_btn}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
const url = `https://t.me/${import.meta.env.VITE_TG_BOT_NAME}/${
|
||||
import.meta.env.VITE_TG_BOT_WEBAPP_NAME
|
||||
}?startapp=${InvitationCode}`;
|
||||
WebApp.openTelegramLink(`https://t.me/share/url?url=${url}`);
|
||||
}}
|
||||
>
|
||||
Invite friends
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function FrendsItem({ userName, point }: { userName: string; point: string }) {
|
||||
return (
|
||||
<li className={classes.frends_list_item}>
|
||||
<Avatar src="" />
|
||||
<span>{userName}</span>
|
||||
<span>+{point} PEPES</span>
|
||||
</li>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,296 @@
|
|||
.guide {
|
||||
height: 100%;
|
||||
.step1 {
|
||||
padding: 0 50px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
img {
|
||||
margin-bottom: 105.2px;
|
||||
}
|
||||
|
||||
> span {
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #adadad;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.step2 {
|
||||
padding: 0 15px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
> span {
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 34px;
|
||||
font-weight: 600;
|
||||
line-height: 44px;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
margin-top: 30px;
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
|
||||
.process {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
> div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 0;
|
||||
}
|
||||
> svg {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> button {
|
||||
margin-top: 109px;
|
||||
}
|
||||
}
|
||||
|
||||
.step3 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0 50px;
|
||||
|
||||
.step3_tabs {
|
||||
margin-top: 28px;
|
||||
margin-bottom: 33px;
|
||||
display: flex;
|
||||
gap: 10.9px;
|
||||
span {
|
||||
width: 148.55px;
|
||||
height: 3px;
|
||||
border-radius: 20px;
|
||||
opacity: 1;
|
||||
background: #777777;
|
||||
&.span_active {
|
||||
background: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page1,
|
||||
.page2 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
> span {
|
||||
&:nth-of-type(1) {
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 30px;
|
||||
font-weight: 600;
|
||||
line-height: 44px;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
&:nth-of-type(2) {
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
&:nth-of-type(3),
|
||||
&:nth-of-type(4) {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.years {
|
||||
width: 305px;
|
||||
height: 268px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
background-image: url("../assets/zhuashi.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
margin-top: 33px;
|
||||
margin-bottom: 23px;
|
||||
/* border: 1px solid #fff; */
|
||||
> span {
|
||||
&:nth-of-type(1) {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 200px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0em;
|
||||
line-height: 153px;
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
&:nth-of-type(2) {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 30px;
|
||||
font-weight: 600;
|
||||
line-height: 44px;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page2 {
|
||||
.point {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 25px;
|
||||
margin-top: 87px;
|
||||
margin-bottom: 56px;
|
||||
img {
|
||||
width: 168px;
|
||||
height: 136px;
|
||||
}
|
||||
/* 自动布局子元素 */
|
||||
> span {
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 34px;
|
||||
font-weight: 600;
|
||||
line-height: 44px;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> button {
|
||||
margin-top: 45px;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
height: 48px;
|
||||
border-radius: 8px;
|
||||
opacity: 1;
|
||||
|
||||
/* 自动布局 */
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
padding: 12px 89px;
|
||||
|
||||
background: #489149;
|
||||
|
||||
/* 自动布局子元素 */
|
||||
span {
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 0;
|
||||
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
import { api_receive_rewards } from "@/server/api";
|
||||
import classes from "./Guide-m.module.css";
|
||||
import logo from "@/assets/logo.png";
|
||||
import { cn } from "@/utils";
|
||||
import { Button, ProgressBar } from "antd-mobile";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { CheckCircleFill } from "antd-mobile-icons";
|
||||
|
||||
export default function () {
|
||||
const [step, setStep] = useState(1);
|
||||
return (
|
||||
<>
|
||||
<div className={classes.guide}>
|
||||
{step == 1 && <Step1 onNext={() => setStep(2)} />}
|
||||
{step == 2 && <Step2 onNext={() => setStep(3)} />}
|
||||
{step == 3 && <Step3 />}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Step1({ onNext }: { onNext: () => void }) {
|
||||
return (
|
||||
<div className={classes.step1}>
|
||||
<img src={logo} alt="" />
|
||||
<span>Hey!</span>
|
||||
<span>You've been in Telegram for a while,</span>
|
||||
<span>it's time to get rewarded!</span>
|
||||
|
||||
<Button block color="primary" fill="none" onClick={onNext}>
|
||||
Wow, let's go!
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Step2({ onNext }: { onNext: () => void }) {
|
||||
const [finishProcess, setFinishProcess] = useState(false);
|
||||
|
||||
return (
|
||||
<div className={classes.step2}>
|
||||
<span>Checking your account</span>
|
||||
|
||||
<ul>
|
||||
<Proccess delay={900} title="Account Age Verified" />
|
||||
<Proccess delay={1200} title="Activity Level Analyzed" />
|
||||
<Proccess delay={3000} title="Telegram Premium Checked" />
|
||||
<Proccess
|
||||
delay={4200}
|
||||
title="OG Status Confirmed"
|
||||
onFinish={() => {
|
||||
setFinishProcess(true);
|
||||
}}
|
||||
/>
|
||||
</ul>
|
||||
|
||||
<Button
|
||||
disabled={!finishProcess}
|
||||
block
|
||||
color="primary"
|
||||
fill="none"
|
||||
onClick={onNext}
|
||||
>
|
||||
Continue
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Step3() {
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const navigate = useNavigate();
|
||||
const [years, setYears] = useState<number | undefined>();
|
||||
const [reward, setReward] = useState<string | undefined>();
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const { data } = await api_receive_rewards().send({
|
||||
queryParams: { status: 1 },
|
||||
});
|
||||
setYears(data?.data.year);
|
||||
setReward(data?.data.reward);
|
||||
})();
|
||||
return () => {};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={classes.step3}>
|
||||
<div className={classes.step3_tabs}>
|
||||
<span className={classes.span_active}></span>
|
||||
<span
|
||||
className={cn(currentPage == 2 ? classes.span_active : "")}
|
||||
></span>
|
||||
</div>
|
||||
{currentPage == 1 && (
|
||||
<div className={classes.page1}>
|
||||
<span>Elite member!</span>
|
||||
<span>You've joined Telegram</span>
|
||||
<div className={classes.years}>
|
||||
<span>{years}</span>
|
||||
<span>years ago</span>
|
||||
</div>
|
||||
<span>Your account number is #1969081558.</span>
|
||||
<span>You're in the Top 30% Telegram users</span>
|
||||
</div>
|
||||
)}
|
||||
{currentPage == 2 && (
|
||||
<div className={classes.page2}>
|
||||
<span>You are amazing!</span>
|
||||
<span>Here is your PEPES reward</span>
|
||||
<div className={classes.point}>
|
||||
<img src={logo} alt="" />
|
||||
<span>{reward}</span>
|
||||
</div>
|
||||
<span>Thanks for your time on Telegram</span>
|
||||
</div>
|
||||
)}
|
||||
<Button
|
||||
block
|
||||
color="primary"
|
||||
fill="none"
|
||||
onClick={async () => {
|
||||
if (currentPage == 2) {
|
||||
await api_receive_rewards().send({});
|
||||
navigate("/");
|
||||
return;
|
||||
}
|
||||
setCurrentPage(2);
|
||||
}}
|
||||
>
|
||||
Continue
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Proccess({
|
||||
delay,
|
||||
title,
|
||||
onFinish,
|
||||
}: {
|
||||
delay: number;
|
||||
title: string;
|
||||
onFinish?: () => void;
|
||||
}) {
|
||||
const [percent, setPercent] = useState<number>(0);
|
||||
const [finish, setFinish] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
setPercent(30);
|
||||
setTimeout(() => {
|
||||
setPercent(60);
|
||||
setTimeout(() => {
|
||||
setPercent(100);
|
||||
setFinish(true);
|
||||
onFinish?.();
|
||||
}, delay / 3);
|
||||
}, delay / 3);
|
||||
}, delay / 3);
|
||||
|
||||
return () => {};
|
||||
}, [delay]);
|
||||
|
||||
return (
|
||||
<li className={classes.process}>
|
||||
<div>
|
||||
<span>{title}</span>
|
||||
<CheckCircleFill color={finish ? "#489149" : "#666666"} />
|
||||
</div>
|
||||
<ProgressBar
|
||||
percent={percent}
|
||||
style={{
|
||||
"--fill-color": "#489149",
|
||||
}}
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
.home {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.home_top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 65px;
|
||||
padding: 21px 0px;
|
||||
gap: 6px;
|
||||
background-image: url("../assets/home_top_bg.svg");
|
||||
background-size: contain;
|
||||
> svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
> span {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
.logo {
|
||||
width: 92px;
|
||||
margin-top: 35px;
|
||||
}
|
||||
.pepes {
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
line-height: 44px;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.join_card {
|
||||
width: 345px;
|
||||
height: 132px;
|
||||
border-radius: 16px;
|
||||
opacity: 1;
|
||||
|
||||
/* 自动布局 */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 16px 20px;
|
||||
|
||||
background: #1e1e1e;
|
||||
|
||||
gap: 8px;
|
||||
margin-top: 26px;
|
||||
|
||||
> span {
|
||||
&:nth-of-type(1) {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
&:nth-of-type(2) {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
/* 自动布局子元素 */
|
||||
width: 60px;
|
||||
height: 38px;
|
||||
border-radius: 38px;
|
||||
opacity: 1;
|
||||
|
||||
/* 自动布局 */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 7px 16px;
|
||||
|
||||
background: #ffffff;
|
||||
|
||||
z-index: 1;
|
||||
|
||||
> span {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #000000;
|
||||
|
||||
z-index: 0;
|
||||
|
||||
text-transform: capitalize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rewards {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 35px;
|
||||
width: 100%;
|
||||
.rewards_title {
|
||||
align-self: flex-start;
|
||||
margin: 0 15px;
|
||||
margin-top: 25px;
|
||||
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.reward_list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
padding: 0 15px;
|
||||
> span {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 1;
|
||||
&:last-of-type {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-07-13 10:50:24
|
||||
* @LastEditTime: 2024-07-15 15:32:17
|
||||
* @Author: John
|
||||
*/
|
||||
import classes from "./Home-m.module.css";
|
||||
import { Routes, useNavigate } from "react-router-dom";
|
||||
import home_top_bg from "@/assets/home_top_bg.svg";
|
||||
import logo from "@/assets/logo.png";
|
||||
import { CheckOutline, PlayOutline, StarOutline } from "antd-mobile-icons";
|
||||
import { Button } from "antd-mobile";
|
||||
import { useEffect, useState } from "react";
|
||||
import { api_homepage_query_user_income } from "@/server/api";
|
||||
import { useWebApp } from "@vkruglikov/react-telegram-web-app";
|
||||
export default function () {
|
||||
const WebApp = useWebApp();
|
||||
const navigate = useNavigate();
|
||||
const [totalPoint, setTotalPoint] = useState(0);
|
||||
const [signReward, setSignReward] = useState<string | undefined>();
|
||||
const [tgReward, setTgReward] = useState<string | undefined>();
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const { data } = await api_homepage_query_user_income().send({});
|
||||
const list = data?.data || [];
|
||||
setTotalPoint(list.reduce((acc, cur) => acc + parseInt(cur.opValue), 0));
|
||||
setSignReward(list.find((v) => v.opType == 4)?.opValue);
|
||||
setTgReward(list.find((v) => v.opType == 5)?.opValue);
|
||||
})();
|
||||
|
||||
return () => {};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={classes.home}>
|
||||
<div className={classes.home_top}>
|
||||
<PlayOutline color="#fff" />
|
||||
<span>Your Score</span>
|
||||
</div>
|
||||
|
||||
<img src={logo} alt="" className={classes.logo} />
|
||||
<span className={classes.pepes}>{totalPoint || 0} PEPES</span>
|
||||
|
||||
<div className={classes.join_card}>
|
||||
<span>DOGS COMMUNITY</span>
|
||||
<span>Home for Telegram OGs</span>
|
||||
<Button
|
||||
fill="none"
|
||||
onClick={() => {
|
||||
WebApp.openTelegramLink(
|
||||
`https://t.me/${import.meta.env.VITE_TG_BOT_NAME}`
|
||||
);
|
||||
}}
|
||||
>
|
||||
join
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className={classes.rewards}>
|
||||
<span className={classes.rewards_title}>Your rewards</span>
|
||||
|
||||
<div className={classes.reward_list}>
|
||||
<StarOutline color="#ffffff" />
|
||||
<span>Your rewards</span>
|
||||
<span>+{signReward || 0} PEPES</span>
|
||||
</div>
|
||||
|
||||
<div className={classes.reward_list}>
|
||||
<CheckOutline color="#ffffff" />
|
||||
<span>Telegram Premium</span>
|
||||
<span>{tgReward || 0}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
.index {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
.container {
|
||||
flex: auto;
|
||||
position: relative;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
import { Route, Routes, useNavigate } from "react-router-dom";
|
||||
import Home from "./Home";
|
||||
import { Badge, TabBar } from "antd-mobile";
|
||||
import {
|
||||
AppOutline,
|
||||
MessageFill,
|
||||
MessageOutline,
|
||||
UnorderedListOutline,
|
||||
UserOutline,
|
||||
} from "antd-mobile-icons";
|
||||
import classes from "./Index-m.module.css";
|
||||
import Leaderboard from "./Leaderboard";
|
||||
import Frends from "./Frends";
|
||||
import BottomTab from "@/components/BottomTab";
|
||||
const tabs = [
|
||||
{
|
||||
key: "0",
|
||||
title: "Home",
|
||||
icon: <AppOutline />,
|
||||
},
|
||||
{
|
||||
key: "1",
|
||||
title: "Leaderboard",
|
||||
icon: <UnorderedListOutline />,
|
||||
},
|
||||
{
|
||||
key: "2",
|
||||
title: "Frends",
|
||||
icon: <MessageOutline />,
|
||||
},
|
||||
];
|
||||
export default function () {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<>
|
||||
<div className={classes.index}>
|
||||
<div className={classes.container}>
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/leaderboard" element={<Leaderboard />} />
|
||||
<Route path="/frends" element={<Frends />} />
|
||||
</Routes>
|
||||
</div>
|
||||
|
||||
<BottomTab />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
.leaderboard {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.top_title {
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
line-height: normal;
|
||||
text-align: center;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
margin-top: 41px;
|
||||
}
|
||||
|
||||
.rank_data {
|
||||
width: 345px;
|
||||
height: 68px;
|
||||
border-radius: 12px;
|
||||
opacity: 1;
|
||||
|
||||
/* 自动布局 */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 13px 15px;
|
||||
|
||||
background: #1e1e1e;
|
||||
gap: 12px;
|
||||
margin-top: 38px;
|
||||
> div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
> span {
|
||||
&:nth-of-type(1) {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: normal;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
&:nth-of-type(2) {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: normal;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #adadad;
|
||||
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
> span {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: normal;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 1;
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
> button {
|
||||
margin-top: 16px;
|
||||
|
||||
width: 344px;
|
||||
height: 48px;
|
||||
border-radius: 8px;
|
||||
opacity: 1;
|
||||
|
||||
/* 自动布局 */
|
||||
display: flex;
|
||||
padding: 12px 115px;
|
||||
|
||||
background: #489149;
|
||||
> span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
> svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
> span {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: normal;
|
||||
text-align: center;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rank_title {
|
||||
align-self: flex-start;
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
margin: 0 15px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.rank_list {
|
||||
width: 100%;
|
||||
padding: 0 15px;
|
||||
padding-bottom: 94px;
|
||||
margin-top: 32px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 32px;
|
||||
.rank_item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
> svg {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
> div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
> span {
|
||||
&:nth-of-type(1) {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: normal;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 0;
|
||||
|
||||
max-width: 100px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&:nth-of-type(2) {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: normal;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #adadad;
|
||||
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.rank_item_icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.rank_index {
|
||||
/* 自动布局子元素 */
|
||||
opacity: 1;
|
||||
|
||||
font-family: Roboto;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0em;
|
||||
|
||||
font-variation-settings: "opsz" auto;
|
||||
font-feature-settings: "kern" on;
|
||||
color: #ffffff;
|
||||
|
||||
z-index: 1;
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-07-13 16:08:04
|
||||
* @LastEditTime: 2024-07-15 15:27:41
|
||||
* @Author: John
|
||||
*/
|
||||
import { Avatar, Button } from "antd-mobile";
|
||||
import classes from "./Leaderboard-m.module.css";
|
||||
import { StarOutline } from "antd-mobile-icons";
|
||||
import rank1 from "@/assets/rank1.svg";
|
||||
import rank2 from "@/assets/rank2.svg";
|
||||
import rank3 from "@/assets/rank3.svg";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { api_ranking } from "@/server/api";
|
||||
import { RewardVo } from "@/server/module";
|
||||
export default function () {
|
||||
const [userRank, setUserRank] = useState<RewardVo>();
|
||||
const [ranks, setRanks] = useState<RewardVo[]>();
|
||||
const [totalUser, setTotalUser] = useState<number>();
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const { data } = await api_ranking().send({});
|
||||
setUserRank(data?.data.rewardVo);
|
||||
setRanks(data?.data.rewardVos);
|
||||
setTotalUser(data?.data.numberOfUsers);
|
||||
})();
|
||||
|
||||
return () => {};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={classes.leaderboard}>
|
||||
<span className={classes.top_title}>Telegram Wall of Fame</span>
|
||||
<div className={classes.rank_data}>
|
||||
<Avatar src="" />
|
||||
<div>
|
||||
<span>{userRank?.tgName}</span>
|
||||
<span>{userRank?.amount} PEPES</span>
|
||||
</div>
|
||||
<span>#{userRank?.ranking}</span>
|
||||
</div>
|
||||
|
||||
<Button block fill="none">
|
||||
<StarOutline color="#ffffff" />
|
||||
<span>Boost score</span>
|
||||
</Button>
|
||||
<span className={classes.rank_title}>{totalUser || 0} holders</span>
|
||||
<ul className={classes.rank_list}>
|
||||
{ranks?.map((v, i) => (
|
||||
<RankItem
|
||||
userName={v.tgName}
|
||||
point={v.amount}
|
||||
key={i}
|
||||
index={i + 1}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function RankItem({
|
||||
userName,
|
||||
point,
|
||||
index,
|
||||
}: {
|
||||
userName: string;
|
||||
point: string;
|
||||
index: number;
|
||||
}) {
|
||||
return (
|
||||
<li className={classes.rank_item}>
|
||||
<Avatar src="" />
|
||||
<div>
|
||||
<span>{userName}</span>
|
||||
<span>{point} PEPES</span>
|
||||
</div>
|
||||
{index == 1 && (
|
||||
<img className={classes.rank_item_icon} src={rank1} alt="" />
|
||||
)}
|
||||
{index == 2 && (
|
||||
<img className={classes.rank_item_icon} src={rank2} alt="" />
|
||||
)}
|
||||
{index == 3 && (
|
||||
<img className={classes.rank_item_icon} src={rank3} alt="" />
|
||||
)}
|
||||
{index > 3 && <span className={classes.rank_index}>#{index}</span>}
|
||||
</li>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-07-15 10:35:20
|
||||
* @LastEditTime: 2024-07-15 15:25:54
|
||||
* @Author: John
|
||||
*/
|
||||
import { GET, POST } from "./client";
|
||||
import { RewardVo, subordinatesUsers, userBenefits } from "./module";
|
||||
|
||||
// 登录
|
||||
export function api_login() {
|
||||
return POST<
|
||||
{
|
||||
initData: string;
|
||||
invitationCode?: string;
|
||||
},
|
||||
{ token: string }
|
||||
>({
|
||||
url: "/api/account/signIn",
|
||||
});
|
||||
}
|
||||
|
||||
// 查询用户是否领取注册奖励
|
||||
export function api_query_whether_the_user_receives_the_registration_reward() {
|
||||
return GET<any, string>({
|
||||
url: "/api/reward/signUpForIncentives",
|
||||
});
|
||||
}
|
||||
|
||||
// 领取奖励
|
||||
export function api_receive_rewards() {
|
||||
return POST<any, { reward: string; year: number }, { status?: number }>({
|
||||
url: "/api/reward/claimYourRewards",
|
||||
});
|
||||
}
|
||||
|
||||
// 排行
|
||||
export function api_ranking() {
|
||||
return GET<
|
||||
any,
|
||||
{
|
||||
rewardVo: RewardVo;
|
||||
rewardVos: RewardVo[];
|
||||
numberOfUsers: number;
|
||||
}
|
||||
>({
|
||||
url: "/api/reward/rankingWalletLog",
|
||||
});
|
||||
}
|
||||
|
||||
// 首页查询用户收益
|
||||
export function api_homepage_query_user_income() {
|
||||
return GET<any, userBenefits[]>({
|
||||
url: "/api/reward/userBenefits",
|
||||
});
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
export function api_get_user_information() {
|
||||
return GET<
|
||||
any,
|
||||
{
|
||||
account: string;
|
||||
accountType: number;
|
||||
allPid: string;
|
||||
chainType: number;
|
||||
codePrompt: number;
|
||||
createTime: string;
|
||||
flag: number;
|
||||
id: string;
|
||||
level: number;
|
||||
minLevel: number;
|
||||
mintNumber: number;
|
||||
passwordLogin: string;
|
||||
passwordPay: string;
|
||||
presidentNumber: number;
|
||||
referId: string;
|
||||
shareCode: string;
|
||||
shareNum: number;
|
||||
teamNum: number;
|
||||
uid: string;
|
||||
updateTime: string;
|
||||
userImg: string;
|
||||
userType: number;
|
||||
}
|
||||
>({
|
||||
url: "/api/user/findUser",
|
||||
});
|
||||
}
|
||||
|
||||
// 首页下级用户
|
||||
export function api_homepage_subordinates_users() {
|
||||
return GET<any, subordinatesUsers[]>({
|
||||
url: "/api/reward/subordinateUsers",
|
||||
});
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-06-18 10:09:21
|
||||
* @LastEditTime: 2024-07-15 11:30:25
|
||||
* @Author: John
|
||||
*/
|
||||
import { Client } from "@hyper-fetch/core";
|
||||
import useUserStore from "@/store/User";
|
||||
import { Lang } from "@/constants";
|
||||
import { Toast } from "antd-mobile";
|
||||
import { BASE_RESPONSE } from "./module";
|
||||
import { api_login } from "./api";
|
||||
import { useInitData, useWebApp } from "@vkruglikov/react-telegram-web-app";
|
||||
function initClient({ catchErr }: { catchErr: boolean }) {
|
||||
return new Client({ url: import.meta.env.VITE_BASE_API_URL })
|
||||
.onAuth(async (req) => {
|
||||
const headers = {
|
||||
...req.headers,
|
||||
Authorization: useUserStore.getState().Token,
|
||||
};
|
||||
return req.setHeaders(headers);
|
||||
})
|
||||
.onResponse((res) => {
|
||||
console.log(res);
|
||||
if (!res.success) {
|
||||
Toast.clear();
|
||||
Toast.show({ content: "server error", icon: "fail" });
|
||||
throw new Error(res.error?.message);
|
||||
}
|
||||
const resData: BASE_RESPONSE = res.data;
|
||||
if (resData.code !== 200 && resData.code !== 0) {
|
||||
if (resData.msg) Toast.show({ content: resData.msg, icon: "fail" });
|
||||
if (catchErr) return res;
|
||||
throw new Error(resData.msg || "client on response error");
|
||||
}
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
export const POST = <P = any, R = any, QueryParams = any>({
|
||||
url,
|
||||
catchErr = false,
|
||||
}: {
|
||||
url: string;
|
||||
catchErr?: boolean;
|
||||
}) => {
|
||||
return initClient({ catchErr }).createRequest<
|
||||
BASE_RESPONSE<R>,
|
||||
P,
|
||||
any,
|
||||
QueryParams
|
||||
>()({
|
||||
method: "POST",
|
||||
endpoint: url,
|
||||
});
|
||||
};
|
||||
|
||||
export const GET = <P = any, R = any>({
|
||||
url,
|
||||
requiresToken = true,
|
||||
catchErr = false,
|
||||
}: {
|
||||
url: string;
|
||||
requiresToken?: boolean;
|
||||
catchErr?: boolean;
|
||||
}) => {
|
||||
return initClient({ catchErr }).createRequest<
|
||||
BASE_RESPONSE<R>,
|
||||
any,
|
||||
any,
|
||||
P
|
||||
>()({
|
||||
method: "GET",
|
||||
endpoint: url,
|
||||
});
|
||||
};
|
|
@ -0,0 +1,54 @@
|
|||
export type BASE_RESPONSE<T = any> = {
|
||||
code: 0 | 200;
|
||||
data: T;
|
||||
msg: string;
|
||||
timeMillis: number;
|
||||
}; // What's returned from request
|
||||
|
||||
export type RewardVo = {
|
||||
tgName: string;
|
||||
amount: string;
|
||||
ranking: number;
|
||||
};
|
||||
|
||||
export type userBenefits = {
|
||||
coinId: number;
|
||||
createTime: string;
|
||||
extRemark: string;
|
||||
flag: number;
|
||||
id: number;
|
||||
memberId: string;
|
||||
opAfter: string;
|
||||
opBefore: string;
|
||||
opRemark: string;
|
||||
opType: number;
|
||||
opValue: string;
|
||||
type: number;
|
||||
updateTime: string;
|
||||
walletId: number;
|
||||
};
|
||||
|
||||
export type subordinatesUsers = {
|
||||
account: string;
|
||||
accountType: number;
|
||||
allPid: string;
|
||||
chainType: number;
|
||||
codePrompt: number;
|
||||
createTime: string;
|
||||
flag: number;
|
||||
id: string;
|
||||
level: number;
|
||||
minLevel: number;
|
||||
mintNumber: number;
|
||||
passwordLogin: string;
|
||||
passwordPay: string;
|
||||
presidentNumber: number;
|
||||
referId: string;
|
||||
shareCode: string;
|
||||
shareNum: number;
|
||||
teamNum: number;
|
||||
uid: string;
|
||||
updateTime: string;
|
||||
userImg: string;
|
||||
userType: number;
|
||||
};
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-06-17 17:45:43
|
||||
* @LastEditTime: 2024-07-15 15:10:52
|
||||
* @Author: John
|
||||
*/
|
||||
import { ASYNC_STORAGE_KEY, Lang } from "@/constants";
|
||||
import { create } from "zustand";
|
||||
import { createJSONStorage, persist } from "zustand/middleware";
|
||||
|
||||
interface UserState {
|
||||
Token: string;
|
||||
UpdateToken: (t: string) => void;
|
||||
|
||||
InvitationCode: string;
|
||||
UpdateInvitationCode: (i: string) => void;
|
||||
}
|
||||
|
||||
export const useUserStore = create<UserState>()(
|
||||
persist(
|
||||
(set, _get) => ({
|
||||
Token: "",
|
||||
UpdateToken: (t) => set({ Token: t }),
|
||||
InvitationCode: "",
|
||||
UpdateInvitationCode(i) {
|
||||
set({ InvitationCode: i });
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: ASYNC_STORAGE_KEY.Store, // name of item in the storage (must be unique)
|
||||
storage: createJSONStorage(() => localStorage), // (optional) by default the 'localStorage' is used
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
export default useUserStore;
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-01-09 09:34:24
|
||||
* @LastEditTime: 2024-07-13 14:13:21
|
||||
* @Author: John
|
||||
*/
|
||||
|
||||
export default function flexible(window: Window, document: Document) {
|
||||
var docEl = document.documentElement;
|
||||
var dpr = window.devicePixelRatio || 1;
|
||||
|
||||
// adjust body font size
|
||||
function setBodyFontSize() {
|
||||
if (document.body) {
|
||||
document.body.style.fontSize = 12 * dpr + "px";
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", setBodyFontSize);
|
||||
}
|
||||
}
|
||||
setBodyFontSize();
|
||||
|
||||
// set 1rem = viewWidth / 10
|
||||
function setRemUnit() {
|
||||
var rem = docEl.clientWidth / 10;
|
||||
// console.log("rem:", rem);
|
||||
docEl.style.fontSize = rem + "px";
|
||||
}
|
||||
|
||||
setRemUnit();
|
||||
|
||||
// reset rem unit on page resize
|
||||
window.addEventListener("resize", setRemUnit);
|
||||
window.addEventListener("pageshow", function (e) {
|
||||
if (e.persisted) {
|
||||
setRemUnit();
|
||||
}
|
||||
});
|
||||
|
||||
// detect 0.5px supports
|
||||
if (dpr >= 2) {
|
||||
var fakeBody = document.createElement("body");
|
||||
var testElement = document.createElement("div");
|
||||
testElement.style.border = ".5px solid transparent";
|
||||
fakeBody.appendChild(testElement);
|
||||
docEl.appendChild(fakeBody);
|
||||
if (testElement.offsetHeight === 1) {
|
||||
docEl.classList.add("hairlines");
|
||||
}
|
||||
docEl.removeChild(fakeBody);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import { twMerge } from "tailwind-merge";
|
||||
import { type ClassValue, clsx } from "clsx";
|
||||
export function getUrlParameterByName(name: string, url?: string) {
|
||||
if (!url) url = window.location.href;
|
||||
name = name.replace(/[\[\]]/g, "\\$&");
|
||||
let regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
|
||||
results = regex.exec(url);
|
||||
if (!results) return null;
|
||||
if (!results[2]) return "";
|
||||
console.log("url params:", results);
|
||||
return decodeURIComponent(results[2].replace(/\+/g, " "));
|
||||
}
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_BASE_URL: string;
|
||||
readonly VITE_BASE_API_URL: string;
|
||||
readonly VITE_TG_BOT_NAME: string;
|
||||
readonly VITE_TG_BOT_WEBAPP_NAME: string;
|
||||
// 更多环境变量...
|
||||
readonly MODE: "development" | "production" | "test";
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-06-17 17:20:03
|
||||
* @LastEditTime: 2024-06-24 18:48:07
|
||||
* @Author: John
|
||||
*/
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-07-13 10:21:58
|
||||
* @LastEditTime: 2024-07-15 11:02:27
|
||||
* @Author: John
|
||||
*/
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import path from "path";
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
server: {
|
||||
host: "192.168.10.167",
|
||||
proxy: {
|
||||
"/dev": {
|
||||
target: "http://192.168.10.100:8096",
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/dev/, ""),
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [react()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
css: {},
|
||||
});
|