feat: update
@@ -8,8 +8,8 @@ VITE_APP_BASE_API='/api'
|
||||
VITE_APP_TITLE=开发环境
|
||||
|
||||
# 网络请求公用地址
|
||||
#VITE_API_BASE_URL='http://127.0.0.1:3000'
|
||||
VITE_API_BASE_URL='http://1.95.0.111:3000'
|
||||
VITE_API_BASE_URL='http://127.0.0.1:3000'
|
||||
#VITE_API_BASE_URL='http://1.95.0.111:4000'
|
||||
|
||||
VITE_TITLE_NAME='五味子云存储'
|
||||
|
||||
|
@@ -7,7 +7,7 @@ VITE_APP_BASE_API='/api'
|
||||
VITE_APP_TITLE=生产环境
|
||||
|
||||
# 网络请求公用地址
|
||||
VITE_API_BASE_URL='http://1.95.0.111:4000'
|
||||
VITE_API_BASE_URL='http://1.95.0.111:3000'
|
||||
|
||||
VITE_TITLE_NAME='五味子云存储'
|
||||
|
||||
@@ -15,4 +15,4 @@ VITE_TITLE_NAME='五味子云存储'
|
||||
VITE_APP_TOKEN_KEY='token'
|
||||
|
||||
# the upload url
|
||||
VITE_UPLOAD_URL='http://1.95.0.111:4000'
|
||||
VITE_UPLOAD_URL='http://1.95.0.111:3000'
|
||||
|
@@ -37,7 +37,7 @@ module.exports = {
|
||||
'react/jsx-use-react': 0, // React V17开始JSX已经不再需要引入React
|
||||
'react/react-in-jsx-scope': 0, // 同上
|
||||
'import/first': 0, // 消除绝对路径必须要在相对路径前引入,
|
||||
'no-mixed-spaces-and-tabs': 2, // 禁止空格和 tab 的混合缩进
|
||||
// 'no-mixed-spaces-and-tabs': 2, // 禁止空格和 tab 的混合缩进
|
||||
'no-debugger': 2, // 禁止有debugger
|
||||
'space-infix-ops': 2, // 要求操作符周围有空格
|
||||
'space-before-blocks': 2, // 要求语句块之前有空格
|
||||
|
@@ -1,16 +1,16 @@
|
||||
module.exports = {
|
||||
printWidth: 100, //单行长度
|
||||
tabWidth: 4, //缩进长度
|
||||
useTabs: false, //使用空格代替tab缩进
|
||||
semi: false, //句末使用分号
|
||||
singleQuote: true, //使用单引号
|
||||
// tabWidth: 4, //缩进长度
|
||||
// useTabs: true, //使用空格代替tab缩进
|
||||
semi: true, //句末使用分号
|
||||
// singleQuote: true, //使用单引号
|
||||
quoteProps: 'as-needed', //仅在必需时为对象的key添加引号
|
||||
jsxSingleQuote: true, // jsx中使用单引号
|
||||
jsxSingleQuote: false, // jsx中使用单引号
|
||||
bracketSpacing: true, //在对象前后添加空格-eg: { foo: bar }
|
||||
jsxBracketSameLine: true, //多属性html标签的‘>’折行放置
|
||||
arrowParens: 'always', //单参数箭头函数参数周围使用圆括号-eg: (x) => x
|
||||
requirePragma: false, //无需顶部注释即可格式化
|
||||
insertPragma: false, //在已被preitter格式化的文件顶部加上标注
|
||||
insertPragma: true, //在已被preitter格式化的文件顶部加上标注
|
||||
endOfLine: 'auto', //结束行形式
|
||||
embeddedLanguageFormatting: 'auto', //对引用代码进行格式化
|
||||
}
|
||||
|
@@ -32,6 +32,9 @@
|
||||
"react-rotate-captcha": "^1.0.26",
|
||||
"react-router-dom": "^6.23.0",
|
||||
"regenerator-runtime": "^0.14.1",
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-html": "^3.2.2",
|
||||
"vite-plugin-svg-icons": "^2.0.1"
|
||||
|
1190
pnpm-lock.yaml
generated
@@ -1,16 +1,28 @@
|
||||
import web from '@/utils/axios/web.ts'
|
||||
/** @format */
|
||||
|
||||
import web from "@/utils/axios/web.ts";
|
||||
|
||||
/**
|
||||
* 获取验证码
|
||||
*/
|
||||
export const getCaptcha = () => {
|
||||
return web.post('/ReactRotateCaptcha/get')
|
||||
}
|
||||
return web.request({
|
||||
url: "/ReactRotateCaptcha/get",
|
||||
method: "get",
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 验证验证码
|
||||
* @param data
|
||||
* @constructor
|
||||
*/
|
||||
export const VerfiyCaptcha = (data: any) => {
|
||||
return web.post('/ReactRotateCaptcha/verfiy', data)
|
||||
}
|
||||
return web.request({
|
||||
url: "/ReactRotateCaptcha/verfiy",
|
||||
method: "post",
|
||||
headers: {
|
||||
"Content-Type": "application/json;charset=UTF-8",
|
||||
},
|
||||
data: data,
|
||||
});
|
||||
};
|
||||
|
@@ -1,10 +1,10 @@
|
||||
const calcSize = (img: HTMLImageElement, size: number) => {
|
||||
const src_src = Math.max(Math.min(img.width, img.height, size), 160)
|
||||
const dst_w = src_src
|
||||
const dst_h = src_src
|
||||
const src_src = Math.max(Math.min(img.width, img.height, size), 160);
|
||||
const dst_w = src_src;
|
||||
const dst_h = src_src;
|
||||
|
||||
const dst_scale = dst_h / dst_w // Target image ratio
|
||||
const src_scale = img.height / img.width // Original image aspect ratio
|
||||
const dst_scale = dst_h / dst_w; // Target image ratio
|
||||
const src_scale = img.height / img.width; // Original image aspect ratio
|
||||
|
||||
const info =
|
||||
src_scale >= dst_scale
|
||||
@@ -17,52 +17,52 @@ const calcSize = (img: HTMLImageElement, size: number) => {
|
||||
Math.round(img.width * (src_src / img.height)),
|
||||
Math.round((img.width - img.height) / 2),
|
||||
0,
|
||||
]
|
||||
];
|
||||
|
||||
return [img.width, img.height, src_src, ...info]
|
||||
}
|
||||
return [img.width, img.height, src_src, ...info];
|
||||
};
|
||||
|
||||
const build = (img: HTMLImageElement, sizes: number[]): [number, string] => {
|
||||
const [src_w, src_h, size, tar_size, x, y] = sizes
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = size
|
||||
canvas.height = size
|
||||
const [src_w, src_h, size, tar_size, x, y] = sizes;
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = size;
|
||||
canvas.height = size;
|
||||
|
||||
const max = 275 - 50
|
||||
const min = 0
|
||||
const max = 275 - 50;
|
||||
const min = 0;
|
||||
|
||||
const ave = Math.round((360 / max) * 100) / 100
|
||||
const ctx = canvas.getContext('2d')
|
||||
const ave = Math.round((360 / max) * 100) / 100;
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
const coordinate = size / 2
|
||||
const moveX = Math.floor(Math.random() * (max - min + 1))
|
||||
const coordinate = size / 2;
|
||||
const moveX = Math.floor(Math.random() * (max - min + 1));
|
||||
|
||||
ctx?.beginPath()
|
||||
ctx?.translate(coordinate, coordinate)
|
||||
ctx?.rotate((moveX * -1 * ave * Math.PI) / 180)
|
||||
ctx?.translate(-coordinate, -coordinate)
|
||||
ctx?.drawImage(img, x, y, src_w, src_h, 0, 0, tar_size, size)
|
||||
ctx!.globalCompositeOperation = 'destination-in'
|
||||
ctx?.arc(size / 2, size / 2, size / 2, 0, (360 * Math.PI) / 180, false)
|
||||
ctx?.fill()
|
||||
ctx?.restore()
|
||||
ctx?.beginPath();
|
||||
ctx?.translate(coordinate, coordinate);
|
||||
ctx?.rotate((moveX * -1 * ave * Math.PI) / 180);
|
||||
ctx?.translate(-coordinate, -coordinate);
|
||||
ctx?.drawImage(img, x, y, src_w, src_h, 0, 0, tar_size, size);
|
||||
ctx!.globalCompositeOperation = "destination-in";
|
||||
ctx?.arc(size / 2, size / 2, size / 2, 0, (360 * Math.PI) / 180, false);
|
||||
ctx?.fill();
|
||||
ctx?.restore();
|
||||
|
||||
return [(360 / (max - min)) * moveX, canvas.toDataURL('image/png')]
|
||||
}
|
||||
return [(360 / (max - min)) * moveX, canvas.toDataURL("image/png")];
|
||||
};
|
||||
|
||||
export const handle = (url: string, size: number = 350) =>
|
||||
new Promise<[number, string]>((resovle) => {
|
||||
const img = new Image()
|
||||
const img = new Image();
|
||||
img.onerror = function () {
|
||||
console.log('image load error')
|
||||
}
|
||||
console.log("image load error");
|
||||
};
|
||||
|
||||
img.onload = function () {
|
||||
const sizes = calcSize(img, size)
|
||||
const arc_img = build(img, sizes)
|
||||
const sizes = calcSize(img, size);
|
||||
const arc_img = build(img, sizes);
|
||||
|
||||
resovle(arc_img)
|
||||
}
|
||||
resovle(arc_img);
|
||||
};
|
||||
|
||||
img.src = url
|
||||
})
|
||||
img.src = url;
|
||||
});
|
||||
|
@@ -1,44 +1,46 @@
|
||||
import type { TicketInfoType, TokenInfoType } from 'react-rotate-captcha'
|
||||
import { getCaptcha, VerfiyCaptcha } from '@/api/captcha/api.ts'
|
||||
import type { TicketInfoType, TokenInfoType } from "react-rotate-captcha";
|
||||
import { getCaptcha, VerfiyCaptcha } from "@/api/captcha/api.ts";
|
||||
|
||||
export type ActionType = {
|
||||
code: 0 | 1
|
||||
msg: string
|
||||
}
|
||||
let image: string = ''
|
||||
code: 0 | 1;
|
||||
msg: string;
|
||||
};
|
||||
let image: string = "";
|
||||
|
||||
export async function get(): Promise<TokenInfoType> {
|
||||
const res: any = await getCaptcha()
|
||||
image = res.data.str
|
||||
return res
|
||||
const res: any = await getCaptcha();
|
||||
image = res.data.str;
|
||||
return res;
|
||||
}
|
||||
|
||||
export function isSupportWebp() {
|
||||
try {
|
||||
return (
|
||||
document
|
||||
.createElement('canvas')
|
||||
.toDataURL('image/webp', 0.5)
|
||||
.indexOf('data:image/webp') === 0
|
||||
)
|
||||
.createElement("canvas")
|
||||
.toDataURL("image/webp", 0.5)
|
||||
.indexOf("data:image/webp") === 0
|
||||
);
|
||||
} catch (err) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function load() {
|
||||
return image
|
||||
return image;
|
||||
}
|
||||
|
||||
export function sleep(time: number) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => resolve(true), time)
|
||||
})
|
||||
setTimeout(() => resolve(true), time);
|
||||
});
|
||||
}
|
||||
|
||||
export async function verify(token: string, deg: number): Promise<TicketInfoType> {
|
||||
const data: any = {
|
||||
token: token,
|
||||
deg: deg,
|
||||
}
|
||||
const res: any = await VerfiyCaptcha(data)
|
||||
return res
|
||||
};
|
||||
const res: any = await VerfiyCaptcha(data);
|
||||
return res;
|
||||
}
|
||||
|
@@ -1,12 +1,30 @@
|
||||
import web from '@/utils/axios/web.ts'
|
||||
import web from "@/utils/axios/web.ts";
|
||||
|
||||
/**
|
||||
* 初始化minio
|
||||
*/
|
||||
export const initMinio = (data: string) => {
|
||||
return web.post('/oss/minio/init', data)
|
||||
}
|
||||
export const initMinio = (data: any) => {
|
||||
return web.request({
|
||||
url: "/oss/minio/init",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
},
|
||||
method: "post",
|
||||
data: {
|
||||
userId: data,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const getBaseInfo = (data: string) => {
|
||||
return web.post('/oss/minio/getBaseInfo', data)
|
||||
}
|
||||
export const getBaseInfo = (data: any) => {
|
||||
return web.request({
|
||||
url: "/oss/minio/getBaseInfo",
|
||||
method: "post",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
},
|
||||
data: {
|
||||
fileName: data,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
BIN
src/assets/images/cube-leg.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
src/assets/images/growth.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
src/assets/images/icon.ico
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
src/assets/images/icon.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
src/assets/images/looking-ahead.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
src/assets/images/pilot.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
src/assets/images/reflecting.png
Normal file
After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 0 B |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 0 B |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 0 B |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 0 B |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 0 B |
@@ -28,4 +28,3 @@
|
||||
&::-webkit-resizer {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
@@ -1,40 +1,43 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import styles from './index.module.less'
|
||||
import { gsap } from 'gsap'
|
||||
/** @format */
|
||||
|
||||
import React, { useEffect } from "react";
|
||||
import styles from "./index.module.less";
|
||||
import { gsap } from "gsap";
|
||||
|
||||
const BlurCard: React.FC = () => {
|
||||
useEffect(() => {
|
||||
const UPDATE = ({ x, y }: { x: any; y: any }) => {
|
||||
gsap.set(document.documentElement, {
|
||||
'--x': gsap.utils.mapRange(0, window.innerWidth, -1, 1, x),
|
||||
'--y': gsap.utils.mapRange(0, window.innerHeight, -1, 1, y),
|
||||
})
|
||||
}
|
||||
"--x": gsap.utils.mapRange(0, window.innerWidth, -1, 1, x),
|
||||
"--y": gsap.utils.mapRange(0, window.innerHeight, -1, 1, y),
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener('pointermove', UPDATE)
|
||||
}, [])
|
||||
window.addEventListener("pointermove", UPDATE);
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<article>
|
||||
<img src='https://assets.codepen.io/605876/osaka-sky.jpeg' alt='' />
|
||||
<img src="https://assets.codepen.io/605876/osaka-sky.jpeg" alt="" />
|
||||
<h3>Osaka</h3>
|
||||
<img src='https://assets.codepen.io/605876/osaka-tower.png' alt='' />
|
||||
<img src="https://assets.codepen.io/605876/osaka-tower.png" alt="" />
|
||||
<div className={styles.blur}>
|
||||
<img src='https://assets.codepen.io/605876/osaka.jpeg' alt='' />
|
||||
<img src="https://assets.codepen.io/605876/osaka.jpeg" alt="" />
|
||||
<div></div>
|
||||
-->
|
||||
</div>
|
||||
<div className={styles.content}>
|
||||
<p>
|
||||
<svg
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
viewBox='0 0 24 24'
|
||||
fill='currentColor'
|
||||
className='w-6 h-6'>
|
||||
<path d='M15.75 8.25a.75.75 0 0 1 .75.75c0 1.12-.492 2.126-1.27 2.812a.75.75 0 1 1-.992-1.124A2.243 2.243 0 0 0 15 9a.75.75 0 0 1 .75-.75Z'></path>
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
className="w-6 h-6">
|
||||
<path d="M15.75 8.25a.75.75 0 0 1 .75.75c0 1.12-.492 2.126-1.27 2.812a.75.75 0 1 1-.992-1.124A2.243 2.243 0 0 0 15 9a.75.75 0 0 1 .75-.75Z"></path>
|
||||
<path
|
||||
fillRule='evenodd'
|
||||
d='M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25ZM4.575 15.6a8.25 8.25 0 0 0 9.348 4.425 1.966 1.966 0 0 0-1.84-1.275.983.983 0 0 1-.97-.822l-.073-.437c-.094-.565.25-1.11.8-1.267l.99-.282c.427-.123.783-.418.982-.816l.036-.073a1.453 1.453 0 0 1 2.328-.377L16.5 15h.628a2.25 2.25 0 0 1 1.983 1.186 8.25 8.25 0 0 0-6.345-12.4c.044.262.18.503.389.676l1.068.89c.442.369.535 1.01.216 1.49l-.51.766a2.25 2.25 0 0 1-1.161.886l-.143.048a1.107 1.107 0 0 0-.57 1.664c.369.555.169 1.307-.427 1.605L9 13.125l.423 1.059a.956.956 0 0 1-1.652.928l-.679-.906a1.125 1.125 0 0 0-1.906.172L4.575 15.6Z'
|
||||
clipRule='evenodd'></path>
|
||||
fillRule="evenodd"
|
||||
d="M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25ZM4.575 15.6a8.25 8.25 0 0 0 9.348 4.425 1.966 1.966 0 0 0-1.84-1.275.983.983 0 0 1-.97-.822l-.073-.437c-.094-.565.25-1.11.8-1.267l.99-.282c.427-.123.783-.418.982-.816l.036-.073a1.453 1.453 0 0 1 2.328-.377L16.5 15h.628a2.25 2.25 0 0 1 1.983 1.186 8.25 8.25 0 0 0-6.345-12.4c.044.262.18.503.389.676l1.068.89c.442.369.535 1.01.216 1.49l-.51.766a2.25 2.25 0 0 1-1.161.886l-.143.048a1.107 1.107 0 0 0-.57 1.664c.369.555.169 1.307-.427 1.605L9 13.125l.423 1.059a.956.956 0 0 1-1.652.928l-.679-.906a1.125 1.125 0 0 0-1.906.172L4.575 15.6Z"
|
||||
clipRule="evenodd"></path>
|
||||
</svg>
|
||||
<span>GuGong GuGong</span>
|
||||
</p>
|
||||
@@ -42,6 +45,6 @@ const BlurCard: React.FC = () => {
|
||||
</div>
|
||||
</article>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default BlurCard
|
||||
);
|
||||
};
|
||||
export default BlurCard;
|
||||
|
@@ -1,8 +1,11 @@
|
||||
import Loading from '@/components/Loading'
|
||||
import { Suspense } from 'react'
|
||||
/** @format */
|
||||
|
||||
import Loading from "@/components/Loading";
|
||||
import { Suspense } from "react";
|
||||
|
||||
const ComponentLoading = (Component: any, props: any) => (
|
||||
<Suspense fallback={<Loading />}>
|
||||
<Component {...props} />
|
||||
</Suspense>
|
||||
)
|
||||
export default ComponentLoading
|
||||
);
|
||||
export default ComponentLoading;
|
||||
|
@@ -1,17 +1,19 @@
|
||||
import React from 'react'
|
||||
/** @format */
|
||||
|
||||
import React from "react";
|
||||
const FooterComponent: React.FC = () => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
color: 'black',
|
||||
textAlign: "center",
|
||||
color: "black",
|
||||
bottom: 0,
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
position: "absolute",
|
||||
width: "100%",
|
||||
}}>
|
||||
schisandra ©{new Date().getFullYear()} Created by schisandra
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default FooterComponent
|
||||
export default FooterComponent;
|
||||
|
@@ -1,92 +1,95 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import { gsap } from 'gsap'
|
||||
import { ScrollTrigger } from 'gsap/ScrollTrigger'
|
||||
import './index.less'
|
||||
import SvgIcon from '@/components/SvgIcon/SvgIcon.tsx'
|
||||
/** @format */
|
||||
|
||||
import React, { useEffect } from "react";
|
||||
import { gsap } from "gsap";
|
||||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||
import "./index.less";
|
||||
import SvgIcon from "@/components/SvgIcon/SvgIcon.tsx";
|
||||
|
||||
const HomeIndex: React.FC = () => {
|
||||
const animationFunction = () => {
|
||||
if (!CSS.supports('animation-timeline: scroll()')) {
|
||||
if (!CSS.supports("animation-timeline: scroll()")) {
|
||||
// const SPAN = 'max(45vw, 260px)';
|
||||
const CONFIG = [
|
||||
{
|
||||
x: () => {
|
||||
return Math.max(260, window.innerWidth * 0.45) * -1
|
||||
return Math.max(260, window.innerWidth * 0.45) * -1;
|
||||
},
|
||||
y: -10,
|
||||
r: -8,
|
||||
h: 160,
|
||||
w: (el: any) => {
|
||||
return Math.max(320, el.parentNode.offsetWidth * 0.55)
|
||||
return Math.max(320, el.parentNode.offsetWidth * 0.55);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
x: () => {
|
||||
return Math.max(260, window.innerWidth * 0.45)
|
||||
return Math.max(260, window.innerWidth * 0.45);
|
||||
},
|
||||
y: -50,
|
||||
r: 15,
|
||||
h: 360,
|
||||
w: (el: any) => {
|
||||
return Math.max(220, el.parentNode.offsetWidth * 0.3)
|
||||
return Math.max(220, el.parentNode.offsetWidth * 0.3);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
x: () => {
|
||||
return Math.max(260, window.innerWidth * 0.45) * -1
|
||||
return Math.max(260, window.innerWidth * 0.45) * -1;
|
||||
},
|
||||
y: -30,
|
||||
r: 6,
|
||||
h: 300,
|
||||
w: (el: any) => {
|
||||
return Math.max(330, el.parentNode.offsetWidth * 0.55)
|
||||
return Math.max(330, el.parentNode.offsetWidth * 0.55);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
x: () => {
|
||||
return Math.max(260, window.innerWidth * 0.45)
|
||||
return Math.max(260, window.innerWidth * 0.45);
|
||||
},
|
||||
y: -30,
|
||||
r: -5,
|
||||
h: 400,
|
||||
w: (el: any) => {
|
||||
return Math.max(305, el.parentNode.offsetWidth * 0.45)
|
||||
return Math.max(305, el.parentNode.offsetWidth * 0.45);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
x: () => {
|
||||
return Math.max(260, window.innerWidth * 0.45) * -1
|
||||
return Math.max(260, window.innerWidth * 0.45) * -1;
|
||||
},
|
||||
y: -45,
|
||||
r: -20,
|
||||
h: 525,
|
||||
w: (el: any) => {
|
||||
return Math.max(160, el.parentNode.offsetWidth * 0.3)
|
||||
return Math.max(160, el.parentNode.offsetWidth * 0.3);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
x: () => {
|
||||
return Math.max(260, window.innerWidth * 0.45)
|
||||
return Math.max(260, window.innerWidth * 0.45);
|
||||
},
|
||||
y: 10,
|
||||
r: 10,
|
||||
h: 160,
|
||||
w: (el: any) => {
|
||||
return Math.max(320, el.parentNode.offsetWidth * 0.55)
|
||||
return Math.max(320, el.parentNode.offsetWidth * 0.55);
|
||||
},
|
||||
},
|
||||
]
|
||||
];
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger)
|
||||
console.info('gsap: ScrollTrigger registered')
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
console.info("gsap: ScrollTrigger registered");
|
||||
|
||||
gsap.set('.hero', { position: 'absolute' })
|
||||
gsap.set(".hero", { position: "absolute" });
|
||||
|
||||
const cards = document.querySelectorAll('.card')
|
||||
const cards = document.querySelectorAll(".card");
|
||||
|
||||
for (const [index, card] of [...cards].entries()) {
|
||||
if (CONFIG[index]) {
|
||||
@@ -97,420 +100,420 @@ const HomeIndex: React.FC = () => {
|
||||
rotate: CONFIG[index].r,
|
||||
width: CONFIG[index].w,
|
||||
scrollTrigger: {
|
||||
trigger: '.scroller',
|
||||
start: 'top bottom',
|
||||
end: 'top 50%',
|
||||
trigger: ".scroller",
|
||||
start: "top bottom",
|
||||
end: "top 50%",
|
||||
scrub: true,
|
||||
},
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
gsap.from(
|
||||
[
|
||||
'.card__content',
|
||||
'.card--two .card__column:last-of-type',
|
||||
'.card--three .card__column:last-of-type',
|
||||
'.card--five .card__column:last-of-type',
|
||||
".card__content",
|
||||
".card--two .card__column:last-of-type",
|
||||
".card--three .card__column:last-of-type",
|
||||
".card--five .card__column:last-of-type",
|
||||
],
|
||||
|
||||
{
|
||||
y: '-100cqh',
|
||||
y: "-100cqh",
|
||||
scrollTrigger: {
|
||||
trigger: '.scroller',
|
||||
start: 'top 80%',
|
||||
end: 'top top',
|
||||
trigger: ".scroller",
|
||||
start: "top 80%",
|
||||
end: "top top",
|
||||
scrub: true,
|
||||
},
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
gsap.from(['.card__avatar img', '.password svg'], {
|
||||
gsap.from([".card__avatar img", ".password svg"], {
|
||||
opacity: 0,
|
||||
scrollTrigger: {
|
||||
trigger: '.scroller',
|
||||
start: 'top 50%',
|
||||
end: 'top top',
|
||||
trigger: ".scroller",
|
||||
start: "top 50%",
|
||||
end: "top top",
|
||||
scrub: true,
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
gsap.from(['.card--five .card__dummy', '.card--six .card__dummy'], {
|
||||
gsap.from([".card--five .card__dummy", ".card--six .card__dummy"], {
|
||||
width: (el: any) => el.parentNode.offsetWidth * 0.26,
|
||||
scrollTrigger: {
|
||||
trigger: '.scroller',
|
||||
start: 'top 80%',
|
||||
end: 'top top',
|
||||
trigger: ".scroller",
|
||||
start: "top 80%",
|
||||
end: "top top",
|
||||
scrub: true,
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
gsap.from(['.card--one .card__avatar', '.card--four .card__avatar'], {
|
||||
gsap.from([".card--one .card__avatar", ".card--four .card__avatar"], {
|
||||
scale: 2,
|
||||
scrollTrigger: {
|
||||
trigger: '.scroller',
|
||||
start: 'top bottom',
|
||||
end: 'top top',
|
||||
trigger: ".scroller",
|
||||
start: "top bottom",
|
||||
end: "top top",
|
||||
scrub: true,
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
gsap.from('.card--two .card__avatar', {
|
||||
gsap.from(".card--two .card__avatar", {
|
||||
width: (el: any) => Math.max(330, el.parentNode.offsetWidth * 0.55) - 32,
|
||||
borderRadius: '12px',
|
||||
height: 'calc(300cqh - 2rem)',
|
||||
borderRadius: "12px",
|
||||
height: "calc(300cqh - 2rem)",
|
||||
scrollTrigger: {
|
||||
trigger: '.scroller',
|
||||
start: 'top bottom',
|
||||
end: 'top 20%',
|
||||
trigger: ".scroller",
|
||||
start: "top bottom",
|
||||
end: "top 20%",
|
||||
scrub: true,
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
gsap.from('.card--six .card__column:last-of-type .card__company', {
|
||||
gsap.from(".card--six .card__column:last-of-type .card__company", {
|
||||
width: 120,
|
||||
x: '-1rem',
|
||||
x: "-1rem",
|
||||
scrollTrigger: {
|
||||
trigger: '.scroller',
|
||||
start: 'top bottom',
|
||||
end: 'top 20%',
|
||||
trigger: ".scroller",
|
||||
start: "top bottom",
|
||||
end: "top 20%",
|
||||
scrub: true,
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
gsap.from('.cta', {
|
||||
gsap.from(".cta", {
|
||||
scale: 1,
|
||||
scrollTrigger: {
|
||||
trigger: '.scroller',
|
||||
start: 'top bottom',
|
||||
end: 'top 20%',
|
||||
trigger: ".scroller",
|
||||
start: "top bottom",
|
||||
end: "top 20%",
|
||||
scrub: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
document.body.classList.add('body')
|
||||
window.addEventListener('resize', animationFunction)
|
||||
document.body.classList.add("body");
|
||||
window.addEventListener("resize", animationFunction);
|
||||
return () => {
|
||||
document.body.classList.remove('body')
|
||||
window.removeEventListener('resize', animationFunction)
|
||||
}
|
||||
}, [])
|
||||
document.body.classList.remove("body");
|
||||
window.removeEventListener("resize", animationFunction);
|
||||
};
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<nav className={'nav'}>
|
||||
<div className='navbar'>
|
||||
<nav className={"nav"}>
|
||||
<div className="navbar">
|
||||
<a
|
||||
className='bear-link'
|
||||
href='/login'
|
||||
target='_blank'
|
||||
rel='noreferrer noopener'>
|
||||
<SvgIcon name={'schisandra'} size={50} />
|
||||
className="bear-link"
|
||||
href="/login"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener">
|
||||
<SvgIcon name={"schisandra"} size={50} />
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
<header className={'header'}>
|
||||
<div className='hero'>
|
||||
<div className='content'>
|
||||
<h1 className={'h1'}>
|
||||
<header className={"header"}>
|
||||
<div className="hero">
|
||||
<div className="content">
|
||||
<h1 className={"h1"}>
|
||||
五 味 子 云 存 储
|
||||
<br />
|
||||
<span>schisandra</span>
|
||||
</h1>
|
||||
<p>Start your journey and join thousands of others.</p>
|
||||
<a href='/login' target='_blank' rel='noreferrer noopener'>
|
||||
<a href="/login" target="_blank" rel="noreferrer noopener">
|
||||
Start now
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className='sticker'>
|
||||
<div className='content'>
|
||||
<div className='panel'>
|
||||
<div className='panel__row'>
|
||||
<div className='card card--one'>
|
||||
<div className='card__column'>
|
||||
<div className='card__avatar'>
|
||||
<img src='@/assets/images/test/526.jpg' alt='' />
|
||||
<div className="sticker">
|
||||
<div className="content">
|
||||
<div className="panel">
|
||||
<div className="panel__row">
|
||||
<div className="card card--one">
|
||||
<div className="card__column">
|
||||
<div className="card__avatar">
|
||||
<img src="@/assets/images/test/526.jpg" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='card__content'>
|
||||
<div className='card__details'>
|
||||
<div className='text'></div>
|
||||
<div className='image headspace'>
|
||||
<div className="card__content">
|
||||
<div className="card__details">
|
||||
<div className="text"></div>
|
||||
<div className="image headspace">
|
||||
<svg
|
||||
role='img'
|
||||
viewBox='0 0 24 24'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Headspace</title>
|
||||
<path d='M23.9711 11.8612c.279 3.8878-1.5272 6.0933-2.6155 7.6357-1.694 1.7856-3.8397 4.2203-9.291 4.3565-4.6237.1827-6.8957-1.8508-8.8034-3.617-2.487-2.7336-3.1366-4.3512-3.261-8.3752-.0118-2.467.9397-4.9292 2.6025-7.0954C4.934 1.4736 8.6408.3699 12.0646.1426c3.5923-.1392 6.4493 1.6723 8.3993 3.624 2.4963 2.632 3.2629 4.8923 3.5054 8.0946Z'></path>
|
||||
<path d="M23.9711 11.8612c.279 3.8878-1.5272 6.0933-2.6155 7.6357-1.694 1.7856-3.8397 4.2203-9.291 4.3565-4.6237.1827-6.8957-1.8508-8.8034-3.617-2.487-2.7336-3.1366-4.3512-3.261-8.3752-.0118-2.467.9397-4.9292 2.6025-7.0954C4.934 1.4736 8.6408.3699 12.0646.1426c3.5923-.1392 6.4493 1.6723 8.3993 3.624 2.4963 2.632 3.2629 4.8923 3.5054 8.0946Z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div className='text'></div>
|
||||
<div className='card__dummy'>
|
||||
<div className='text-wrap'>
|
||||
<div className='text'></div>
|
||||
<div className='text'></div>
|
||||
<div className="text"></div>
|
||||
<div className="card__dummy">
|
||||
<div className="text-wrap">
|
||||
<div className="text"></div>
|
||||
<div className="text"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='card__column'>
|
||||
<div className='card__company alexa'>
|
||||
<div className="card__column">
|
||||
<div className="card__company alexa">
|
||||
<svg
|
||||
role='img'
|
||||
viewBox='0 0 24 24'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Amazon Alexa</title>
|
||||
<path d='M12 0C5.37 0 0 5.37 0 12C0 18.09 4.53 23.11 10.4 23.9V21.5A1.59 1.59 0 0 0 9.32 19.97A8.41 8.41 0 0 1 3.6 11.8A8.37 8.37 0 0 1 12.09 3.6A8.4 8.4 0 0 1 20.4 12.31L20.39 12.38A8.68 8.68 0 0 1 20.36 12.76C20.36 12.83 20.35 12.9 20.34 12.96C20.34 13.04 20.33 13.12 20.32 13.19L20.3 13.29C19.27 20.07 10.45 23.87 10.4 23.9C10.92 23.97 11.46 24 12 24C18.63 24 24 18.63 24 12S18.63 0 12 0Z'></path>
|
||||
<path d="M12 0C5.37 0 0 5.37 0 12C0 18.09 4.53 23.11 10.4 23.9V21.5A1.59 1.59 0 0 0 9.32 19.97A8.41 8.41 0 0 1 3.6 11.8A8.37 8.37 0 0 1 12.09 3.6A8.4 8.4 0 0 1 20.4 12.31L20.39 12.38A8.68 8.68 0 0 1 20.36 12.76C20.36 12.83 20.35 12.9 20.34 12.96C20.34 13.04 20.33 13.12 20.32 13.19L20.3 13.29C19.27 20.07 10.45 23.87 10.4 23.9C10.92 23.97 11.46 24 12 24C18.63 24 24 18.63 24 12S18.63 0 12 0Z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='panel__row'>
|
||||
<div className='card card--three'>
|
||||
<div className='card__column'>
|
||||
<div className='card__avatar'>
|
||||
<div className="panel__row">
|
||||
<div className="card card--three">
|
||||
<div className="card__column">
|
||||
<div className="card__avatar">
|
||||
<svg
|
||||
role='img'
|
||||
viewBox='0 0 24 24'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Google Chrome</title>
|
||||
<path
|
||||
fill='#4285F4'
|
||||
d='M12 0C8.21 0 4.831 1.757 2.632 4.501l3.953 6.848A5.454 5.454 0 0 1 12 6.545h10.691A12 12 0 0 0 12 0zM1.931 5.47A11.943 11.943 0 0 0 0 12c0 6.012 4.42 10.991 10.189 11.864l3.953-6.847a5.45 5.45 0 0 1-6.865-2.29zm13.342 2.166a5.446 5.446 0 0 1 1.45 7.09l.002.001h-.002l-5.344 9.257c.206.01.413.016.621.016 6.627 0 12-5.373 12-12 0-1.54-.29-3.011-.818-4.364zM12 16.364a4.364 4.364 0 1 1 0-8.728 4.364 4.364 0 0 1 0 8.728Z'></path>
|
||||
fill="#4285F4"
|
||||
d="M12 0C8.21 0 4.831 1.757 2.632 4.501l3.953 6.848A5.454 5.454 0 0 1 12 6.545h10.691A12 12 0 0 0 12 0zM1.931 5.47A11.943 11.943 0 0 0 0 12c0 6.012 4.42 10.991 10.189 11.864l3.953-6.847a5.45 5.45 0 0 1-6.865-2.29zm13.342 2.166a5.446 5.446 0 0 1 1.45 7.09l.002.001h-.002l-5.344 9.257c.206.01.413.016.621.016 6.627 0 12-5.373 12-12 0-1.54-.29-3.011-.818-4.364zM12 16.364a4.364 4.364 0 1 1 0-8.728 4.364 4.364 0 0 1 0 8.728Z"></path>
|
||||
</svg>
|
||||
<img src='@/assets/images/test/430.jpg' alt='' />
|
||||
<img src="@/assets/images/test/430.jpg" alt="" />
|
||||
</div>
|
||||
<div className='card__dummy'>
|
||||
<div className='text-wrap'>
|
||||
<div className='text'></div>
|
||||
<div className='text'></div>
|
||||
<div className="card__dummy">
|
||||
<div className="text-wrap">
|
||||
<div className="text"></div>
|
||||
<div className="text"></div>
|
||||
</div>
|
||||
<div className='cta'></div>
|
||||
<div className="cta"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='card__content'>
|
||||
<div className='card__details'>
|
||||
<div className='text'></div>
|
||||
<div className='image youtube'>
|
||||
<div className="card__content">
|
||||
<div className="card__details">
|
||||
<div className="text"></div>
|
||||
<div className="image youtube">
|
||||
<svg
|
||||
role='img'
|
||||
viewBox='0 0 24 24'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<title>YouTube</title>
|
||||
<path d='M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z'></path>
|
||||
<path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div className='text'></div>
|
||||
<div className="text"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='card__column'>
|
||||
<div className='card__company slack'>
|
||||
<div className="card__column">
|
||||
<div className="card__company slack">
|
||||
<svg
|
||||
role='img'
|
||||
viewBox='0 0 24 24'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Slack</title>
|
||||
<path d='M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z'></path>
|
||||
<path d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='panel__row'>
|
||||
<div className='card card--two'>
|
||||
<div className='card__column'>
|
||||
<div className='card__avatar'>
|
||||
<img src='@/assets/images/test/535.jpg' alt='' />
|
||||
<div className="panel__row">
|
||||
<div className="card card--two">
|
||||
<div className="card__column">
|
||||
<div className="card__avatar">
|
||||
<img src="@/assets/images/test/535.jpg" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='card__content'>
|
||||
<div className='card__details'>
|
||||
<div className='text'></div>
|
||||
<div className='image messenger'>
|
||||
<div className="card__content">
|
||||
<div className="card__details">
|
||||
<div className="text"></div>
|
||||
<div className="image messenger">
|
||||
<svg
|
||||
role='img'
|
||||
viewBox='0 0 24 24'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Messenger</title>
|
||||
<path d='M.001 11.639C.001 4.949 5.241 0 12.001 0S24 4.95 24 11.639c0 6.689-5.24 11.638-12 11.638-1.21 0-2.38-.16-3.47-.46a.96.96 0 00-.64.05l-2.39 1.05a.96.96 0 01-1.35-.85l-.07-2.14a.97.97 0 00-.32-.68A11.39 11.389 0 01.002 11.64zm8.32-2.19l-3.52 5.6c-.35.53.32 1.139.82.75l3.79-2.87c.26-.2.6-.2.87 0l2.8 2.1c.84.63 2.04.4 2.6-.48l3.52-5.6c.35-.53-.32-1.13-.82-.75l-3.79 2.87c-.25.2-.6.2-.86 0l-2.8-2.1a1.8 1.8 0 00-2.61.48z'></path>
|
||||
<path d="M.001 11.639C.001 4.949 5.241 0 12.001 0S24 4.95 24 11.639c0 6.689-5.24 11.638-12 11.638-1.21 0-2.38-.16-3.47-.46a.96.96 0 00-.64.05l-2.39 1.05a.96.96 0 01-1.35-.85l-.07-2.14a.97.97 0 00-.32-.68A11.39 11.389 0 01.002 11.64zm8.32-2.19l-3.52 5.6c-.35.53.32 1.139.82.75l3.79-2.87c.26-.2.6-.2.87 0l2.8 2.1c.84.63 2.04.4 2.6-.48l3.52-5.6c.35-.53-.32-1.13-.82-.75l-3.79 2.87c-.25.2-.6.2-.86 0l-2.8-2.1a1.8 1.8 0 00-2.61.48z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div className='text'></div>
|
||||
<div className="text"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='card__column'>
|
||||
<div className='card__company notion'>
|
||||
<div className="card__column">
|
||||
<div className="card__company notion">
|
||||
<svg
|
||||
role='img'
|
||||
viewBox='0 0 24 24'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Notion</title>
|
||||
<path d='M4.459 4.208c.746.606 1.026.56 2.428.466l13.215-.793c.28 0 .047-.28-.046-.326L17.86 1.968c-.42-.326-.981-.7-2.055-.607L3.01 2.295c-.466.046-.56.28-.374.466zm.793 3.08v13.904c0 .747.373 1.027 1.214.98l14.523-.84c.841-.046.935-.56.935-1.167V6.354c0-.606-.233-.933-.748-.887l-15.177.887c-.56.047-.747.327-.747.933zm14.337.745c.093.42 0 .84-.42.888l-.7.14v10.264c-.608.327-1.168.514-1.635.514-.748 0-.935-.234-1.495-.933l-4.577-7.186v6.952L12.21 19s0 .84-1.168.84l-3.222.186c-.093-.186 0-.653.327-.746l.84-.233V9.854L7.822 9.76c-.094-.42.14-1.026.793-1.073l3.456-.233 4.764 7.279v-6.44l-1.215-.139c-.093-.514.28-.887.747-.933zM1.936 1.035l13.31-.98c1.634-.14 2.055-.047 3.082.7l4.249 2.986c.7.513.934.653.934 1.213v16.378c0 1.026-.373 1.634-1.68 1.726l-15.458.934c-.98.047-1.448-.093-1.962-.747l-3.129-4.06c-.56-.747-.793-1.306-.793-1.96V2.667c0-.839.374-1.54 1.447-1.632z'></path>
|
||||
<path d="M4.459 4.208c.746.606 1.026.56 2.428.466l13.215-.793c.28 0 .047-.28-.046-.326L17.86 1.968c-.42-.326-.981-.7-2.055-.607L3.01 2.295c-.466.046-.56.28-.374.466zm.793 3.08v13.904c0 .747.373 1.027 1.214.98l14.523-.84c.841-.046.935-.56.935-1.167V6.354c0-.606-.233-.933-.748-.887l-15.177.887c-.56.047-.747.327-.747.933zm14.337.745c.093.42 0 .84-.42.888l-.7.14v10.264c-.608.327-1.168.514-1.635.514-.748 0-.935-.234-1.495-.933l-4.577-7.186v6.952L12.21 19s0 .84-1.168.84l-3.222.186c-.093-.186 0-.653.327-.746l.84-.233V9.854L7.822 9.76c-.094-.42.14-1.026.793-1.073l3.456-.233 4.764 7.279v-6.44l-1.215-.139c-.093-.514.28-.887.747-.933zM1.936 1.035l13.31-.98c1.634-.14 2.055-.047 3.082.7l4.249 2.986c.7.513.934.653.934 1.213v16.378c0 1.026-.373 1.634-1.68 1.726l-15.458.934c-.98.047-1.448-.093-1.962-.747l-3.129-4.06c-.56-.747-.793-1.306-.793-1.96V2.667c0-.839.374-1.54 1.447-1.632z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='panel__row'>
|
||||
<div className='card card--six'>
|
||||
<div className='card__column'>
|
||||
<div className='card__avatar'>
|
||||
<div className="panel__row">
|
||||
<div className="card card--six">
|
||||
<div className="card__column">
|
||||
<div className="card__avatar">
|
||||
<svg
|
||||
role='img'
|
||||
role="img"
|
||||
style={{ background: `white` }}
|
||||
viewBox='0 0 24 24'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Twilio</title>
|
||||
<path
|
||||
fill='#F22F46'
|
||||
d='M12 0C5.381-.008.008 5.352 0 11.971V12c0 6.64 5.359 12 12 12 6.64 0 12-5.36 12-12 0-6.641-5.36-12-12-12zm0 20.801c-4.846.015-8.786-3.904-8.801-8.75V12c-.014-4.846 3.904-8.786 8.75-8.801H12c4.847-.014 8.786 3.904 8.801 8.75V12c.015 4.847-3.904 8.786-8.75 8.801H12zm5.44-11.76c0 1.359-1.12 2.479-2.481 2.479-1.366-.007-2.472-1.113-2.479-2.479 0-1.361 1.12-2.481 2.479-2.481 1.361 0 2.481 1.12 2.481 2.481zm0 5.919c0 1.36-1.12 2.48-2.481 2.48-1.367-.008-2.473-1.114-2.479-2.48 0-1.359 1.12-2.479 2.479-2.479 1.361-.001 2.481 1.12 2.481 2.479zm-5.919 0c0 1.36-1.12 2.48-2.479 2.48-1.368-.007-2.475-1.113-2.481-2.48 0-1.359 1.12-2.479 2.481-2.479 1.358-.001 2.479 1.12 2.479 2.479zm0-5.919c0 1.359-1.12 2.479-2.479 2.479-1.367-.007-2.475-1.112-2.481-2.479 0-1.361 1.12-2.481 2.481-2.481 1.358 0 2.479 1.12 2.479 2.481z'></path>
|
||||
fill="#F22F46"
|
||||
d="M12 0C5.381-.008.008 5.352 0 11.971V12c0 6.64 5.359 12 12 12 6.64 0 12-5.36 12-12 0-6.641-5.36-12-12-12zm0 20.801c-4.846.015-8.786-3.904-8.801-8.75V12c-.014-4.846 3.904-8.786 8.75-8.801H12c4.847-.014 8.786 3.904 8.801 8.75V12c.015 4.847-3.904 8.786-8.75 8.801H12zm5.44-11.76c0 1.359-1.12 2.479-2.481 2.479-1.366-.007-2.472-1.113-2.479-2.479 0-1.361 1.12-2.481 2.479-2.481 1.361 0 2.481 1.12 2.481 2.481zm0 5.919c0 1.36-1.12 2.48-2.481 2.48-1.367-.008-2.473-1.114-2.479-2.48 0-1.359 1.12-2.479 2.479-2.479 1.361-.001 2.481 1.12 2.481 2.479zm-5.919 0c0 1.36-1.12 2.48-2.479 2.48-1.368-.007-2.475-1.113-2.481-2.48 0-1.359 1.12-2.479 2.481-2.479 1.358-.001 2.479 1.12 2.479 2.479zm0-5.919c0 1.359-1.12 2.479-2.479 2.479-1.367-.007-2.475-1.112-2.481-2.479 0-1.361 1.12-2.481 2.481-2.481 1.358 0 2.479 1.12 2.479 2.481z"></path>
|
||||
</svg>
|
||||
<img src='@/assets/images/test/332.jpg' alt='' />
|
||||
<img src="@/assets/images/test/332.jpg" alt="" />
|
||||
</div>
|
||||
<div className='card__dummy'>
|
||||
<div className='text-wrap'>
|
||||
<div className='text'></div>
|
||||
<div className='text'></div>
|
||||
<div className="card__dummy">
|
||||
<div className="text-wrap">
|
||||
<div className="text"></div>
|
||||
<div className="text"></div>
|
||||
</div>
|
||||
<div className='grid'>
|
||||
<div className='grid__panel'></div>
|
||||
<div className='grid__panel'></div>
|
||||
<div className='grid__panel'></div>
|
||||
<div className='grid__panel'></div>
|
||||
<div className="grid">
|
||||
<div className="grid__panel"></div>
|
||||
<div className="grid__panel"></div>
|
||||
<div className="grid__panel"></div>
|
||||
<div className="grid__panel"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='card__content'>
|
||||
<div className='card__details'>
|
||||
<div className='text'></div>
|
||||
<div className='image paypal'>
|
||||
<div className="card__content">
|
||||
<div className="card__details">
|
||||
<div className="text"></div>
|
||||
<div className="image paypal">
|
||||
<svg
|
||||
role='img'
|
||||
viewBox='0 0 24 24'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<title>PayPal</title>
|
||||
<path d='M7.016 19.198h-4.2a.562.562 0 0 1-.555-.65L5.093.584A.692.692 0 0 1 5.776 0h7.222c3.417 0 5.904 2.488 5.846 5.5-.006.25-.027.5-.066.747A6.794 6.794 0 0 1 12.071 12H8.743a.69.69 0 0 0-.682.583l-.325 2.056-.013.083-.692 4.39-.015.087zM19.79 6.142c-.01.087-.01.175-.023.261a7.76 7.76 0 0 1-7.695 6.598H9.007l-.283 1.795-.013.083-.692 4.39-.134.843-.014.088H6.86l-.497 3.15a.562.562 0 0 0 .555.65h3.612c.34 0 .63-.249.683-.585l.952-6.031a.692.692 0 0 1 .683-.584h2.126a6.793 6.793 0 0 0 6.707-5.752c.306-1.95-.466-3.744-1.89-4.906z'></path>
|
||||
<path d="M7.016 19.198h-4.2a.562.562 0 0 1-.555-.65L5.093.584A.692.692 0 0 1 5.776 0h7.222c3.417 0 5.904 2.488 5.846 5.5-.006.25-.027.5-.066.747A6.794 6.794 0 0 1 12.071 12H8.743a.69.69 0 0 0-.682.583l-.325 2.056-.013.083-.692 4.39-.015.087zM19.79 6.142c-.01.087-.01.175-.023.261a7.76 7.76 0 0 1-7.695 6.598H9.007l-.283 1.795-.013.083-.692 4.39-.134.843-.014.088H6.86l-.497 3.15a.562.562 0 0 0 .555.65h3.612c.34 0 .63-.249.683-.585l.952-6.031a.692.692 0 0 1 .683-.584h2.126a6.793 6.793 0 0 0 6.707-5.752c.306-1.95-.466-3.744-1.89-4.906z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div className='text'></div>
|
||||
<div className="text"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='card__column'>
|
||||
<div className='card__company password'>
|
||||
<div className="card__column">
|
||||
<div className="card__company password">
|
||||
<svg
|
||||
role='img'
|
||||
viewBox='0 0 24 24'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<title>1Password</title>
|
||||
<path d='M12 .007C5.373.007 0 5.376 0 11.999c0 6.624 5.373 11.994 12 11.994S24 18.623 24 12C24 5.376 18.627.007 12 .007Zm-.895 4.857h1.788c.484 0 .729.002.914.096a.86.86 0 0 1 .377.377c.094.185.095.428.095.912v6.016c0 .12 0 .182-.015.238a.427.427 0 0 1-.067.137.923.923 0 0 1-.174.162l-.695.564c-.113.092-.17.138-.191.194a.216.216 0 0 0 0 .15c.02.055.078.101.191.193l.695.565c.094.076.14.115.174.162.03.042.053.087.067.137a.936.936 0 0 1 .015.238v2.746c0 .484-.001.727-.095.912a.86.86 0 0 1-.377.377c-.185.094-.43.096-.914.096h-1.788c-.484 0-.726-.002-.912-.096a.86.86 0 0 1-.377-.377c-.094-.185-.095-.428-.095-.912v-6.016c0-.12 0-.182.015-.238a.437.437 0 0 1 .067-.139c.034-.047.08-.083.174-.16l.695-.564c.113-.092.17-.138.191-.194a.216.216 0 0 0 0-.15c-.02-.055-.078-.101-.191-.193l-.695-.565a.92.92 0 0 1-.174-.162.437.437 0 0 1-.067-.139.92.92 0 0 1-.015-.236V6.25c0-.484.001-.727.095-.912a.86.86 0 0 1 .377-.377c.186-.094.428-.096.912-.096z'></path>
|
||||
<path d="M12 .007C5.373.007 0 5.376 0 11.999c0 6.624 5.373 11.994 12 11.994S24 18.623 24 12C24 5.376 18.627.007 12 .007Zm-.895 4.857h1.788c.484 0 .729.002.914.096a.86.86 0 0 1 .377.377c.094.185.095.428.095.912v6.016c0 .12 0 .182-.015.238a.427.427 0 0 1-.067.137.923.923 0 0 1-.174.162l-.695.564c-.113.092-.17.138-.191.194a.216.216 0 0 0 0 .15c.02.055.078.101.191.193l.695.565c.094.076.14.115.174.162.03.042.053.087.067.137a.936.936 0 0 1 .015.238v2.746c0 .484-.001.727-.095.912a.86.86 0 0 1-.377.377c-.185.094-.43.096-.914.096h-1.788c-.484 0-.726-.002-.912-.096a.86.86 0 0 1-.377-.377c-.094-.185-.095-.428-.095-.912v-6.016c0-.12 0-.182.015-.238a.437.437 0 0 1 .067-.139c.034-.047.08-.083.174-.16l.695-.564c.113-.092.17-.138.191-.194a.216.216 0 0 0 0-.15c-.02-.055-.078-.101-.191-.193l-.695-.565a.92.92 0 0 1-.174-.162.437.437 0 0 1-.067-.139.92.92 0 0 1-.015-.236V6.25c0-.484.001-.727.095-.912a.86.86 0 0 1 .377-.377c.186-.094.428-.096.912-.096z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='panel__row'>
|
||||
<div className='card card--five'>
|
||||
<div className='card__column'>
|
||||
<div className='card__avatar'>
|
||||
<div className="panel__row">
|
||||
<div className="card card--five">
|
||||
<div className="card__column">
|
||||
<div className="card__avatar">
|
||||
<svg
|
||||
style={{ background: `white` }}
|
||||
role='img'
|
||||
viewBox='0 0 24 24'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Spotify</title>
|
||||
<path
|
||||
fill='#1DB954'
|
||||
d='M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.66 0 12 0zm5.521 17.34c-.24.359-.66.48-1.021.24-2.82-1.74-6.36-2.101-10.561-1.141-.418.122-.779-.179-.899-.539-.12-.421.18-.78.54-.9 4.56-1.021 8.52-.6 11.64 1.32.42.18.479.659.301 1.02zm1.44-3.3c-.301.42-.841.6-1.262.3-3.239-1.98-8.159-2.58-11.939-1.38-.479.12-1.02-.12-1.14-.6-.12-.48.12-1.021.6-1.141C9.6 9.9 15 10.561 18.72 12.84c.361.181.54.78.241 1.2zm.12-3.36C15.24 8.4 8.82 8.16 5.16 9.301c-.6.179-1.2-.181-1.38-.721-.18-.601.18-1.2.72-1.381 4.26-1.26 11.28-1.02 15.721 1.621.539.3.719 1.02.419 1.56-.299.421-1.02.599-1.559.3z'></path>
|
||||
fill="#1DB954"
|
||||
d="M12 0C5.4 0 0 5.4 0 12s5.4 12 12 12 12-5.4 12-12S18.66 0 12 0zm5.521 17.34c-.24.359-.66.48-1.021.24-2.82-1.74-6.36-2.101-10.561-1.141-.418.122-.779-.179-.899-.539-.12-.421.18-.78.54-.9 4.56-1.021 8.52-.6 11.64 1.32.42.18.479.659.301 1.02zm1.44-3.3c-.301.42-.841.6-1.262.3-3.239-1.98-8.159-2.58-11.939-1.38-.479.12-1.02-.12-1.14-.6-.12-.48.12-1.021.6-1.141C9.6 9.9 15 10.561 18.72 12.84c.361.181.54.78.241 1.2zm.12-3.36C15.24 8.4 8.82 8.16 5.16 9.301c-.6.179-1.2-.181-1.38-.721-.18-.601.18-1.2.72-1.381 4.26-1.26 11.28-1.02 15.721 1.621.539.3.719 1.02.419 1.56-.299.421-1.02.599-1.559.3z"></path>
|
||||
</svg>
|
||||
<img src='@/assets/images/test/1011.jpg' alt='' />
|
||||
<img src="@/assets/images/test/1011.jpg" alt="" />
|
||||
</div>
|
||||
<div className='card__dummy'>
|
||||
<div className='text-wrap'>
|
||||
<div className='text'></div>
|
||||
<div className='text'></div>
|
||||
<div className="card__dummy">
|
||||
<div className="text-wrap">
|
||||
<div className="text"></div>
|
||||
<div className="text"></div>
|
||||
</div>
|
||||
<div className='grid'>
|
||||
<div className='grid__panel'></div>
|
||||
<div className='grid__panel'></div>
|
||||
<div className='grid__panel'></div>
|
||||
<div className='grid__panel'></div>
|
||||
<div className="grid">
|
||||
<div className="grid__panel"></div>
|
||||
<div className="grid__panel"></div>
|
||||
<div className="grid__panel"></div>
|
||||
<div className="grid__panel"></div>
|
||||
</div>
|
||||
<div className='cta'></div>
|
||||
<div className="cta"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='card__content'>
|
||||
<div className='card__details'>
|
||||
<div className='text'></div>
|
||||
<div className='image calendly'>
|
||||
<div className="card__content">
|
||||
<div className="card__details">
|
||||
<div className="text"></div>
|
||||
<div className="image calendly">
|
||||
<svg
|
||||
role='img'
|
||||
viewBox='0 0 24 24'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Calendly</title>
|
||||
<path d='M19.655 14.262c.281 0 .557.023.828.064 0 .005-.005.01-.005.014-.105.267-.234.534-.381.786l-1.219 2.106c-1.112 1.936-3.177 3.127-5.411 3.127h-2.432c-2.23 0-4.294-1.191-5.412-3.127l-1.218-2.106a6.251 6.251 0 0 1 0-6.252l1.218-2.106C6.736 4.832 8.8 3.641 11.035 3.641h2.432c2.23 0 4.294 1.191 5.411 3.127l1.219 2.106c.147.252.271.519.381.786 0 .004.005.009.005.014-.267.041-.543.064-.828.064-1.816 0-2.501-.607-3.291-1.306-.764-.676-1.711-1.517-3.44-1.517h-1.029c-1.251 0-2.387.455-3.2 1.278-.796.805-1.233 1.904-1.233 3.099v1.411c0 1.196.437 2.295 1.233 3.099.813.823 1.949 1.278 3.2 1.278h1.034c1.729 0 2.676-.841 3.439-1.517.791-.703 1.471-1.306 3.287-1.301Zm.005-3.237c.399 0 .794-.036 1.179-.11-.002-.004-.002-.01-.002-.014-.073-.414-.193-.823-.349-1.218.731-.12 1.407-.396 1.986-.819 0-.004-.005-.013-.005-.018-.331-1.085-.832-2.101-1.489-3.03-.649-.915-1.435-1.719-2.331-2.395-1.867-1.398-4.088-2.138-6.428-2.138-1.448 0-2.855.28-4.175.841-1.273.543-2.423 1.315-3.407 2.299S2.878 6.552 2.341 7.83c-.557 1.324-.842 2.726-.842 4.175 0 1.448.281 2.855.842 4.174.542 1.274 1.314 2.423 2.298 3.407s2.129 1.761 3.407 2.299c1.324.556 2.727.841 4.175.841 2.34 0 4.561-.74 6.428-2.137a10.815 10.815 0 0 0 2.331-2.396c.652-.929 1.158-1.949 1.489-3.03 0-.004.005-.014.005-.018-.579-.423-1.255-.699-1.986-.819.161-.395.276-.804.349-1.218.005-.009.005-.014.005-.023.869.166 1.692.506 2.404 1.035.685.505.552 1.075.446 1.416C22.184 20.437 17.619 24 12.221 24c-6.625 0-12-5.375-12-12s5.37-12 12-12c5.398 0 9.963 3.563 11.471 8.464.106.341.239.915-.446 1.421-.717.529-1.535.873-2.404 1.034.128.716.128 1.45 0 2.166-.387-.074-.782-.11-1.182-.11-4.184 0-3.968 2.823-6.736 2.823h-1.029c-1.899 0-3.15-1.357-3.15-3.095v-1.411c0-1.738 1.251-3.094 3.15-3.094h1.034c2.768 0 2.552 2.823 6.731 2.827Z'></path>
|
||||
<path d="M19.655 14.262c.281 0 .557.023.828.064 0 .005-.005.01-.005.014-.105.267-.234.534-.381.786l-1.219 2.106c-1.112 1.936-3.177 3.127-5.411 3.127h-2.432c-2.23 0-4.294-1.191-5.412-3.127l-1.218-2.106a6.251 6.251 0 0 1 0-6.252l1.218-2.106C6.736 4.832 8.8 3.641 11.035 3.641h2.432c2.23 0 4.294 1.191 5.411 3.127l1.219 2.106c.147.252.271.519.381.786 0 .004.005.009.005.014-.267.041-.543.064-.828.064-1.816 0-2.501-.607-3.291-1.306-.764-.676-1.711-1.517-3.44-1.517h-1.029c-1.251 0-2.387.455-3.2 1.278-.796.805-1.233 1.904-1.233 3.099v1.411c0 1.196.437 2.295 1.233 3.099.813.823 1.949 1.278 3.2 1.278h1.034c1.729 0 2.676-.841 3.439-1.517.791-.703 1.471-1.306 3.287-1.301Zm.005-3.237c.399 0 .794-.036 1.179-.11-.002-.004-.002-.01-.002-.014-.073-.414-.193-.823-.349-1.218.731-.12 1.407-.396 1.986-.819 0-.004-.005-.013-.005-.018-.331-1.085-.832-2.101-1.489-3.03-.649-.915-1.435-1.719-2.331-2.395-1.867-1.398-4.088-2.138-6.428-2.138-1.448 0-2.855.28-4.175.841-1.273.543-2.423 1.315-3.407 2.299S2.878 6.552 2.341 7.83c-.557 1.324-.842 2.726-.842 4.175 0 1.448.281 2.855.842 4.174.542 1.274 1.314 2.423 2.298 3.407s2.129 1.761 3.407 2.299c1.324.556 2.727.841 4.175.841 2.34 0 4.561-.74 6.428-2.137a10.815 10.815 0 0 0 2.331-2.396c.652-.929 1.158-1.949 1.489-3.03 0-.004.005-.014.005-.018-.579-.423-1.255-.699-1.986-.819.161-.395.276-.804.349-1.218.005-.009.005-.014.005-.023.869.166 1.692.506 2.404 1.035.685.505.552 1.075.446 1.416C22.184 20.437 17.619 24 12.221 24c-6.625 0-12-5.375-12-12s5.37-12 12-12c5.398 0 9.963 3.563 11.471 8.464.106.341.239.915-.446 1.421-.717.529-1.535.873-2.404 1.034.128.716.128 1.45 0 2.166-.387-.074-.782-.11-1.182-.11-4.184 0-3.968 2.823-6.736 2.823h-1.029c-1.899 0-3.15-1.357-3.15-3.095v-1.411c0-1.738 1.251-3.094 3.15-3.094h1.034c2.768 0 2.552 2.823 6.731 2.827Z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div className='text'></div>
|
||||
<div className="text"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='card__column'>
|
||||
<div className='card__company bluesky'>
|
||||
<div className="card__column">
|
||||
<div className="card__company bluesky">
|
||||
<svg
|
||||
role='img'
|
||||
viewBox='0 0 24 24'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Bluesky</title>
|
||||
<path d='M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.136-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.953 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741 0 0 1-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.79.624-6.478 0-.69-.139-1.861-.902-2.206-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8Z'></path>
|
||||
<path d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.136-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.953 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741 0 0 1-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.79.624-6.478 0-.69-.139-1.861-.902-2.206-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8Z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='panel__row'>
|
||||
<div className='card card--four'>
|
||||
<div className='card__column'>
|
||||
<div className='card__avatar'>
|
||||
<img src='@/assets/images/test/47.jpg' alt='' />
|
||||
<div className="panel__row">
|
||||
<div className="card card--four">
|
||||
<div className="card__column">
|
||||
<div className="card__avatar">
|
||||
<img src="@/assets/images/test/47.jpg" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='card__content'>
|
||||
<div className='card__details'>
|
||||
<div className='text'></div>
|
||||
<div className='image instagram'>
|
||||
<div className="card__content">
|
||||
<div className="card__details">
|
||||
<div className="text"></div>
|
||||
<div className="image instagram">
|
||||
<svg
|
||||
role='img'
|
||||
viewBox='0 0 24 24'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<title>Instagram</title>
|
||||
<path d='M7.0301.084c-1.2768.0602-2.1487.264-2.911.5634-.7888.3075-1.4575.72-2.1228 1.3877-.6652.6677-1.075 1.3368-1.3802 2.127-.2954.7638-.4956 1.6365-.552 2.914-.0564 1.2775-.0689 1.6882-.0626 4.947.0062 3.2586.0206 3.6671.0825 4.9473.061 1.2765.264 2.1482.5635 2.9107.308.7889.72 1.4573 1.388 2.1228.6679.6655 1.3365 1.0743 2.1285 1.38.7632.295 1.6361.4961 2.9134.552 1.2773.056 1.6884.069 4.9462.0627 3.2578-.0062 3.668-.0207 4.9478-.0814 1.28-.0607 2.147-.2652 2.9098-.5633.7889-.3086 1.4578-.72 2.1228-1.3881.665-.6682 1.0745-1.3378 1.3795-2.1284.2957-.7632.4966-1.636.552-2.9124.056-1.2809.0692-1.6898.063-4.948-.0063-3.2583-.021-3.6668-.0817-4.9465-.0607-1.2797-.264-2.1487-.5633-2.9117-.3084-.7889-.72-1.4568-1.3876-2.1228C21.2982 1.33 20.628.9208 19.8378.6165 19.074.321 18.2017.1197 16.9244.0645 15.6471.0093 15.236-.005 11.977.0014 8.718.0076 8.31.0215 7.0301.0839m.1402 21.6932c-1.17-.0509-1.8053-.2453-2.2287-.408-.5606-.216-.96-.4771-1.3819-.895-.422-.4178-.6811-.8186-.9-1.378-.1644-.4234-.3624-1.058-.4171-2.228-.0595-1.2645-.072-1.6442-.079-4.848-.007-3.2037.0053-3.583.0607-4.848.05-1.169.2456-1.805.408-2.2282.216-.5613.4762-.96.895-1.3816.4188-.4217.8184-.6814 1.3783-.9003.423-.1651 1.0575-.3614 2.227-.4171 1.2655-.06 1.6447-.072 4.848-.079 3.2033-.007 3.5835.005 4.8495.0608 1.169.0508 1.8053.2445 2.228.408.5608.216.96.4754 1.3816.895.4217.4194.6816.8176.9005 1.3787.1653.4217.3617 1.056.4169 2.2263.0602 1.2655.0739 1.645.0796 4.848.0058 3.203-.0055 3.5834-.061 4.848-.051 1.17-.245 1.8055-.408 2.2294-.216.5604-.4763.96-.8954 1.3814-.419.4215-.8181.6811-1.3783.9-.4224.1649-1.0577.3617-2.2262.4174-1.2656.0595-1.6448.072-4.8493.079-3.2045.007-3.5825-.006-4.848-.0608M16.953 5.5864A1.44 1.44 0 1 0 18.39 4.144a1.44 1.44 0 0 0-1.437 1.4424M5.8385 12.012c.0067 3.4032 2.7706 6.1557 6.173 6.1493 3.4026-.0065 6.157-2.7701 6.1506-6.1733-.0065-3.4032-2.771-6.1565-6.174-6.1498-3.403.0067-6.156 2.771-6.1496 6.1738M8 12.0077a4 4 0 1 1 4.008 3.9921A3.9996 3.9996 0 0 1 8 12.0077'></path>
|
||||
<path d="M7.0301.084c-1.2768.0602-2.1487.264-2.911.5634-.7888.3075-1.4575.72-2.1228 1.3877-.6652.6677-1.075 1.3368-1.3802 2.127-.2954.7638-.4956 1.6365-.552 2.914-.0564 1.2775-.0689 1.6882-.0626 4.947.0062 3.2586.0206 3.6671.0825 4.9473.061 1.2765.264 2.1482.5635 2.9107.308.7889.72 1.4573 1.388 2.1228.6679.6655 1.3365 1.0743 2.1285 1.38.7632.295 1.6361.4961 2.9134.552 1.2773.056 1.6884.069 4.9462.0627 3.2578-.0062 3.668-.0207 4.9478-.0814 1.28-.0607 2.147-.2652 2.9098-.5633.7889-.3086 1.4578-.72 2.1228-1.3881.665-.6682 1.0745-1.3378 1.3795-2.1284.2957-.7632.4966-1.636.552-2.9124.056-1.2809.0692-1.6898.063-4.948-.0063-3.2583-.021-3.6668-.0817-4.9465-.0607-1.2797-.264-2.1487-.5633-2.9117-.3084-.7889-.72-1.4568-1.3876-2.1228C21.2982 1.33 20.628.9208 19.8378.6165 19.074.321 18.2017.1197 16.9244.0645 15.6471.0093 15.236-.005 11.977.0014 8.718.0076 8.31.0215 7.0301.0839m.1402 21.6932c-1.17-.0509-1.8053-.2453-2.2287-.408-.5606-.216-.96-.4771-1.3819-.895-.422-.4178-.6811-.8186-.9-1.378-.1644-.4234-.3624-1.058-.4171-2.228-.0595-1.2645-.072-1.6442-.079-4.848-.007-3.2037.0053-3.583.0607-4.848.05-1.169.2456-1.805.408-2.2282.216-.5613.4762-.96.895-1.3816.4188-.4217.8184-.6814 1.3783-.9003.423-.1651 1.0575-.3614 2.227-.4171 1.2655-.06 1.6447-.072 4.848-.079 3.2033-.007 3.5835.005 4.8495.0608 1.169.0508 1.8053.2445 2.228.408.5608.216.96.4754 1.3816.895.4217.4194.6816.8176.9005 1.3787.1653.4217.3617 1.056.4169 2.2263.0602 1.2655.0739 1.645.0796 4.848.0058 3.203-.0055 3.5834-.061 4.848-.051 1.17-.245 1.8055-.408 2.2294-.216.5604-.4763.96-.8954 1.3814-.419.4215-.8181.6811-1.3783.9-.4224.1649-1.0577.3617-2.2262.4174-1.2656.0595-1.6448.072-4.8493.079-3.2045.007-3.5825-.006-4.848-.0608M16.953 5.5864A1.44 1.44 0 1 0 18.39 4.144a1.44 1.44 0 0 0-1.437 1.4424M5.8385 12.012c.0067 3.4032 2.7706 6.1557 6.173 6.1493 3.4026-.0065 6.157-2.7701 6.1506-6.1733-.0065-3.4032-2.771-6.1565-6.174-6.1498-3.403.0067-6.156 2.771-6.1496 6.1738M8 12.0077a4 4 0 1 1 4.008 3.9921A3.9996 3.9996 0 0 1 8 12.0077"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div className='text'></div>
|
||||
<div className='card__dummy'>
|
||||
<div className='text-wrap'>
|
||||
<div className='text'></div>
|
||||
<div className='text'></div>
|
||||
<div className="text"></div>
|
||||
<div className="card__dummy">
|
||||
<div className="text-wrap">
|
||||
<div className="text"></div>
|
||||
<div className="text"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='card__column'>
|
||||
<div className='card__company x'>
|
||||
<div className="card__column">
|
||||
<div className="card__company x">
|
||||
<svg
|
||||
role='img'
|
||||
viewBox='0 0 24 24'
|
||||
xmlns='http://www.w3.org/2000/svg'>
|
||||
role="img"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<title>X</title>
|
||||
<path d='M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z'></path>
|
||||
<path d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
@@ -519,9 +522,9 @@ const HomeIndex: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='scroller'>
|
||||
<div className='content'>
|
||||
<div className='panel'>
|
||||
<div className="scroller">
|
||||
<div className="content">
|
||||
<div className="panel">
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
@@ -531,11 +534,11 @@ const HomeIndex: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='ring ring--under'>
|
||||
<img src='https://assets.codepen.io/605876/portal-ring.png' alt='' />
|
||||
<div className="ring ring--under">
|
||||
<img src="https://assets.codepen.io/605876/portal-ring.png" alt="" />
|
||||
</div>
|
||||
<div className='ring ring--over'>
|
||||
<img src='https://assets.codepen.io/605876/portal-ring.png' alt='' />
|
||||
<div className="ring ring--over">
|
||||
<img src="https://assets.codepen.io/605876/portal-ring.png" alt="" />
|
||||
</div>
|
||||
</header>
|
||||
<main>
|
||||
@@ -543,8 +546,8 @@ const HomeIndex: React.FC = () => {
|
||||
{/* <h2 className={'h2'}>Pretty rad.</h2>*/}
|
||||
{/*</section>*/}
|
||||
</main>
|
||||
<footer className={'footer'}>ʕ•ᴥ•ʔ schisandra © 2024</footer>
|
||||
<footer className={"footer"}>ʕ•ᴥ•ʔ schisandra © 2024</footer>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default HomeIndex
|
||||
);
|
||||
};
|
||||
export default HomeIndex;
|
||||
|
@@ -1,52 +1,55 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import './index.less'
|
||||
/** @format */
|
||||
|
||||
import React, { useEffect } from "react";
|
||||
import "./index.less";
|
||||
|
||||
const Loading: React.FC = () => {
|
||||
useEffect(() => {
|
||||
document.body.classList.add('loading-body')
|
||||
document.body.classList.add("loading-body");
|
||||
return () => {
|
||||
document.body.classList.remove('loading-body')
|
||||
}
|
||||
}, [])
|
||||
document.body.classList.remove("loading-body");
|
||||
};
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<svg className='gegga'>
|
||||
<svg className="gegga">
|
||||
<defs>
|
||||
<filter id='gegga'>
|
||||
<filter id="gegga">
|
||||
<feGaussianBlur
|
||||
in='SourceGraphic'
|
||||
stdDeviation='7'
|
||||
result='blur'></feGaussianBlur>
|
||||
in="SourceGraphic"
|
||||
stdDeviation="7"
|
||||
result="blur"></feGaussianBlur>
|
||||
<feColorMatrix
|
||||
in='blur'
|
||||
mode='matrix'
|
||||
values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -10'
|
||||
result='inreGegga'></feColorMatrix>
|
||||
in="blur"
|
||||
mode="matrix"
|
||||
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -10"
|
||||
result="inreGegga"></feColorMatrix>
|
||||
<feComposite
|
||||
in='SourceGraphic'
|
||||
in2='inreGegga'
|
||||
operator='atop'></feComposite>
|
||||
in="SourceGraphic"
|
||||
in2="inreGegga"
|
||||
operator="atop"></feComposite>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
||||
<svg className='snurra' width='200' height='200' viewBox='0 0 200 200'>
|
||||
<svg className="snurra" width="200" height="200" viewBox="0 0 200 200">
|
||||
<defs>
|
||||
<linearGradient id='linjärGradient'>
|
||||
<stop className='stopp1' offset='0'></stop>
|
||||
<stop className='stopp2' offset='1'></stop>
|
||||
<linearGradient id="linjärGradient">
|
||||
<stop className="stopp1" offset="0"></stop>
|
||||
<stop className="stopp2" offset="1"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2='160'
|
||||
x2='160'
|
||||
y1='40'
|
||||
x1='40'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
id='gradient'
|
||||
xlinkHref='#linjärGradient'></linearGradient>
|
||||
y2="160"
|
||||
x2="160"
|
||||
y1="40"
|
||||
x1="40"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="gradient"
|
||||
xlinkHref="#linjärGradient"></linearGradient>
|
||||
</defs>
|
||||
<path
|
||||
className='halvan'
|
||||
d='m 164,100 c 0,-35.346224 -28.65378,-64 -64,-64 -35.346224,0 -64,28.653776 -64,64 0,35.34622 28.653776,64 64,64 35.34622,0 64,-26.21502 64,-64 0,-37.784981 -26.92058,-64 -64,-64 -37.079421,0 -65.267479,26.922736 -64,64 1.267479,37.07726 26.703171,65.05317 64,64 37.29683,-1.05317 64,-64 64,-64'></path>
|
||||
<circle className='strecken' cx='100' cy='100' r='64'></circle>
|
||||
className="halvan"
|
||||
d="m 164,100 c 0,-35.346224 -28.65378,-64 -64,-64 -35.346224,0 -64,28.653776 -64,64 0,35.34622 28.653776,64 64,64 35.34622,0 64,-26.21502 64,-64 0,-37.784981 -26.92058,-64 -64,-64 -37.079421,0 -65.267479,26.922736 -64,64 1.267479,37.07726 26.703171,65.05317 64,64 37.29683,-1.05317 64,-64 64,-64"></path>
|
||||
<circle className="strecken" cx="100" cy="100" r="64"></circle>
|
||||
</svg>
|
||||
{/*<svg className='skugga' width='200' height='200' viewBox='0 0 200 200'>*/}
|
||||
{/* <path*/}
|
||||
@@ -55,6 +58,6 @@ const Loading: React.FC = () => {
|
||||
{/* <circle className='strecken' cx='100' cy='100' r='64'></circle>*/}
|
||||
{/*</svg>*/}
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default React.memo(Loading)
|
||||
);
|
||||
};
|
||||
export default React.memo(Loading);
|
||||
|
@@ -1 +0,0 @@
|
||||
export const DEFAULT_NAME = 'admin'
|
||||
|
@@ -1,25 +1,28 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import LeftArea from '@/layout/default/left-area'
|
||||
import MainArea from '@/layout/default/main-area'
|
||||
import RightArea from '@/layout/default/right-area'
|
||||
import './index.less'
|
||||
import Footer from '@/components/Footer'
|
||||
/** @format */
|
||||
|
||||
import React, { useEffect } from "react";
|
||||
import LeftArea from "@/layout/default/left-area";
|
||||
import MainArea from "@/layout/default/main-area";
|
||||
import RightArea from "@/layout/default/right-area";
|
||||
import "./index.less";
|
||||
import Footer from "@/components/Footer";
|
||||
|
||||
const DefaultLayOut: React.FC = () => {
|
||||
useEffect(() => {
|
||||
document.body.classList.add('main-body')
|
||||
document.body.classList.add("main-body");
|
||||
return () => {
|
||||
document.body.classList.remove('main-body')
|
||||
}
|
||||
}, [])
|
||||
document.body.classList.remove("main-body");
|
||||
};
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<div className='app-container'>
|
||||
<div className="app-container">
|
||||
<LeftArea />
|
||||
<MainArea />
|
||||
<RightArea />
|
||||
</div>
|
||||
<Footer />
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default DefaultLayOut
|
||||
);
|
||||
};
|
||||
export default DefaultLayOut;
|
||||
|
8
src/lib/utils.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/** @format */
|
||||
|
||||
import { type ClassValue, clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
28
src/main.tsx
@@ -1,16 +1,20 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import { RouterProvider, createBrowserRouter } from 'react-router-dom'
|
||||
import './assets/styles/index.less'
|
||||
import routeConfig from './router'
|
||||
import 'virtual:svg-icons-register'
|
||||
import { Provider as MobxProvider } from 'mobx-react'
|
||||
import { RootStore } from '@/store'
|
||||
const router = createBrowserRouter(routeConfig)
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
/** @format */
|
||||
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import { RouterProvider, createBrowserRouter } from "react-router-dom";
|
||||
import "./assets/styles/index.less";
|
||||
import routeConfig from "./router";
|
||||
import "virtual:svg-icons-register";
|
||||
import { Provider as MobxProvider } from "mobx-react";
|
||||
import { RootStore } from "@/store";
|
||||
|
||||
const router = createBrowserRouter(routeConfig);
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
<React.StrictMode>
|
||||
<MobxProvider {...RootStore}>
|
||||
<RouterProvider router={router} />
|
||||
</MobxProvider>,
|
||||
</MobxProvider>
|
||||
,
|
||||
</React.StrictMode>,
|
||||
)
|
||||
);
|
||||
|
@@ -1,23 +1,26 @@
|
||||
import type { RouteObject } from 'react-router-dom'
|
||||
/** @format */
|
||||
|
||||
import NoFound from '@/views/404/404'
|
||||
import Login from './modules/login/index.ts'
|
||||
import Register from './modules/register/index.ts'
|
||||
import home from './modules/home/index.ts'
|
||||
import Main from './modules/main/index.ts'
|
||||
import type { RouteObject } from "react-router-dom";
|
||||
|
||||
import NoFound from "@/views/404/404";
|
||||
import Login from "./modules/login/index.ts";
|
||||
import Register from "./modules/register/index.ts";
|
||||
import home from "./modules/home/index.ts";
|
||||
import Main from "./modules/main/index.ts";
|
||||
|
||||
import ComponentLoading from "@/components/ComponentLoading";
|
||||
|
||||
import ComponentLoading from '@/components/ComponentLoading'
|
||||
const routes: RouteObject[] = [
|
||||
{
|
||||
path: '/',
|
||||
path: "/",
|
||||
Component: (props) => ComponentLoading(home, props),
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
path: "*",
|
||||
Component: NoFound,
|
||||
},
|
||||
{
|
||||
path: '/register',
|
||||
path: "/register",
|
||||
Component: (props) => ComponentLoading(Register, props),
|
||||
},
|
||||
// {
|
||||
@@ -25,13 +28,13 @@ const routes: RouteObject[] = [
|
||||
// Component: home,
|
||||
// },
|
||||
{
|
||||
path: '/login',
|
||||
path: "/login",
|
||||
Component: (props) => ComponentLoading(Login, props),
|
||||
},
|
||||
{
|
||||
path: '/main',
|
||||
path: "/main",
|
||||
Component: (props) => ComponentLoading(Main, props),
|
||||
},
|
||||
]
|
||||
];
|
||||
|
||||
export default routes
|
||||
export default routes;
|
||||
|
@@ -1,9 +1,11 @@
|
||||
import { lazy } from 'react'
|
||||
/** @format */
|
||||
|
||||
import { lazy } from "react";
|
||||
|
||||
const home = lazy(
|
||||
() =>
|
||||
new Promise((resolve: any) => {
|
||||
setTimeout(() => resolve(import('@/views/Home/')), 1000)
|
||||
setTimeout(() => resolve(import("@/views/Home/")), 1000);
|
||||
}),
|
||||
)
|
||||
export default home
|
||||
);
|
||||
export default home;
|
||||
|
@@ -1,6 +1,8 @@
|
||||
import { useUserStore } from './modules/user.ts'
|
||||
/** @format */
|
||||
|
||||
import { useUserStore } from "./modules/user.ts";
|
||||
|
||||
/** 将每个Store实例化 */
|
||||
export const RootStore = {
|
||||
user: new useUserStore(),
|
||||
}
|
||||
};
|
||||
|
@@ -1,8 +1,12 @@
|
||||
import { action, makeAutoObservable } from 'mobx'
|
||||
import { makePersistable, isHydrated } from 'mobx-persist-store'
|
||||
import { handleLocalforage } from '@/utils/localforage'
|
||||
/** @format */
|
||||
|
||||
import { action, makeAutoObservable } from "mobx";
|
||||
import { makePersistable, isHydrated } from "mobx-persist-store";
|
||||
import { handleLocalforage } from "@/utils/localforage";
|
||||
|
||||
export class useUserStore {
|
||||
token: any = ''
|
||||
token: any = "";
|
||||
|
||||
constructor() {
|
||||
makeAutoObservable(
|
||||
this,
|
||||
@@ -10,13 +14,13 @@ export class useUserStore {
|
||||
setToken: action,
|
||||
},
|
||||
{ autoBind: true },
|
||||
)
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
makePersistable(this, {
|
||||
// 在构造函数内使用 makePersistable
|
||||
name: 'token', // 保存的name,用于在storage中的名称标识,只要不和storage中其他名称重复就可以
|
||||
properties: ['token'], // 要保存的字段,这些字段会被保存在name对应的storage中,注意:不写在这里面的字段将不会被保存,刷新页面也将丢失:get字段例外。get数据会在数据返回后再自动计算
|
||||
name: "token", // 保存的name,用于在storage中的名称标识,只要不和storage中其他名称重复就可以
|
||||
properties: ["token"], // 要保存的字段,这些字段会被保存在name对应的storage中,注意:不写在这里面的字段将不会被保存,刷新页面也将丢失:get字段例外。get数据会在数据返回后再自动计算
|
||||
storage: handleLocalforage, // 保存的位置:看自己的业务情况选择,可以是localStorage,sessionstorage
|
||||
// 。。还有一些其他配置参数,例如数据过期时间等等,可以康康文档,像storage这种字段可以配置在全局配置里,详见文档
|
||||
}).then(
|
||||
@@ -24,15 +28,18 @@ export class useUserStore {
|
||||
// persist 完成的回调,在这里可以执行一些拿到数据后需要执行的操作,如果在页面上要判断是否完成persist,使用 isHydrated
|
||||
// console.log(persistStore)
|
||||
}),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
get getToken() {
|
||||
return this.token ? this.token : null
|
||||
return this.token ? this.token : null;
|
||||
}
|
||||
|
||||
get isHydrated() {
|
||||
return isHydrated(this)
|
||||
return isHydrated(this);
|
||||
}
|
||||
|
||||
setToken(token: string) {
|
||||
this.token = token
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
|
@@ -1,19 +1,22 @@
|
||||
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
|
||||
import { message } from 'antd'
|
||||
/** @format */
|
||||
|
||||
import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
|
||||
import { message } from "antd";
|
||||
|
||||
class Request {
|
||||
private instance: AxiosInstance | undefined
|
||||
private instance: AxiosInstance | undefined;
|
||||
|
||||
constructor(config: AxiosRequestConfig) {
|
||||
this.instance = axios.create(config)
|
||||
this.instance = axios.create(config);
|
||||
// 全局请求拦截
|
||||
this.instance.interceptors.request.use(
|
||||
(config) => {
|
||||
return config
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error)
|
||||
return Promise.reject(error);
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
// 全局响应拦截
|
||||
this.instance.interceptors.response.use(
|
||||
@@ -22,124 +25,77 @@ class Request {
|
||||
// message.error(res.data.message).then()
|
||||
// return Promise.reject(res.data)
|
||||
// }
|
||||
return res.data
|
||||
return res.data;
|
||||
},
|
||||
(error) => {
|
||||
const { response } = error
|
||||
const { response } = error;
|
||||
if (response) {
|
||||
this.handleCode(response.status)
|
||||
this.handleCode(response.status);
|
||||
}
|
||||
if (!window.navigator.onLine) {
|
||||
message.error('网络连接失败')
|
||||
message.error("网络连接失败");
|
||||
// return router.push({
|
||||
// path: '/404',
|
||||
// })
|
||||
return Promise.reject(error)
|
||||
return Promise.reject(error);
|
||||
}
|
||||
},
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
handleCode(code: number): void {
|
||||
switch (code) {
|
||||
case 400:
|
||||
message.error('请求错误(400)')
|
||||
break
|
||||
message.error("请求错误(400)").then();
|
||||
break;
|
||||
case 401:
|
||||
message.error('未授权,请重新登录(401)')
|
||||
break
|
||||
message.error("未授权,请重新登录(401)").then();
|
||||
break;
|
||||
case 403:
|
||||
message.error('拒绝访问(403)')
|
||||
break
|
||||
message.error("拒绝访问(403)").then();
|
||||
break;
|
||||
case 404:
|
||||
message.error('请求出错(404)')
|
||||
break
|
||||
message.error("请求出错(404)").then();
|
||||
break;
|
||||
case 408:
|
||||
message.error('请求超时(408)')
|
||||
break
|
||||
message.error("请求超时(408)").then();
|
||||
break;
|
||||
case 500:
|
||||
message.error('服务器错误(500)')
|
||||
break
|
||||
message.error("服务器错误(500)").then();
|
||||
break;
|
||||
case 501:
|
||||
message.error('服务未实现(501)')
|
||||
break
|
||||
message.error("服务未实现(501)").then();
|
||||
break;
|
||||
case 502:
|
||||
message.error('网络错误(502)')
|
||||
break
|
||||
message.error("网络错误(502)").then();
|
||||
break;
|
||||
case 503:
|
||||
message.error('服务不可用(503)')
|
||||
break
|
||||
message.error("服务不可用(503)").then();
|
||||
break;
|
||||
case 504:
|
||||
message.error('网络超时(504)')
|
||||
break
|
||||
message.error("网络超时(504)").then();
|
||||
break;
|
||||
case 505:
|
||||
message.error('HTTP版本不受支持(505)')
|
||||
break
|
||||
message.error("HTTP版本不受支持(505)").then();
|
||||
break;
|
||||
default:
|
||||
message.error(`连接出错(${code})!`)
|
||||
break
|
||||
message.error(`连接出错(${code})!`).then();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
request<T>(config: AxiosRequestConfig<T>): Promise<T> {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
this.instance
|
||||
?.request<any, T>(config)
|
||||
.then((res) => {
|
||||
resolve(res)
|
||||
resolve(res);
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
get(url: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.instance
|
||||
?.get(url)
|
||||
.then((res) => {
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
post(url: string, data = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.instance
|
||||
?.post(url, data)
|
||||
.then((res) => {
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
put(url: string, data = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.instance
|
||||
?.put(url, data)
|
||||
.then((res) => {
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
delete(url: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.instance
|
||||
?.delete(url)
|
||||
.then((res) => {
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
export default Request
|
||||
|
||||
export default Request;
|
||||
|
@@ -1,7 +1,9 @@
|
||||
import Request from './request'
|
||||
import { handleLocalforage } from '@/utils/localforage'
|
||||
/** @format */
|
||||
|
||||
const token = String(handleLocalforage.getItem('token'))
|
||||
import Request from "./request";
|
||||
import { handleLocalforage } from "@/utils/localforage";
|
||||
|
||||
const token = String(handleLocalforage.getItem("token"));
|
||||
const web: Request = new Request({
|
||||
baseURL: import.meta.env.VITE_APP_BASE_API,
|
||||
headers: {
|
||||
@@ -9,6 +11,6 @@ const web: Request = new Request({
|
||||
// Accept: 'application/json',
|
||||
Authorization: token,
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
export default web
|
||||
export default web;
|
||||
|
@@ -1,19 +1,25 @@
|
||||
/** 配置 */
|
||||
/**
|
||||
* 配置
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
interface Options {
|
||||
/** key前缀 */
|
||||
prefix?: string
|
||||
prefix?: string;
|
||||
}
|
||||
|
||||
/** 默认配置 */
|
||||
const defaultOptions: Options = {
|
||||
prefix: '',
|
||||
}
|
||||
prefix: "",
|
||||
};
|
||||
|
||||
class CookieStorage {
|
||||
private prefix: string
|
||||
private prefix: string;
|
||||
|
||||
constructor(options: Options = defaultOptions) {
|
||||
const { prefix } = options
|
||||
this.prefix = prefix ?? ''
|
||||
const { prefix } = options;
|
||||
this.prefix = prefix ?? "";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -25,13 +31,13 @@ class CookieStorage {
|
||||
* @Author: mulingyuer
|
||||
*/
|
||||
public setItem(key: string, value: string | number, expires?: number): void {
|
||||
const timestamp = Date.now()
|
||||
if (typeof expires === 'number') {
|
||||
expires = timestamp + expires
|
||||
const timestamp = Date.now();
|
||||
if (typeof expires === "number") {
|
||||
expires = timestamp + expires;
|
||||
} else {
|
||||
expires = timestamp + 2 * 365 * 24 * 60 * 60 * 1000
|
||||
expires = timestamp + 2 * 365 * 24 * 60 * 60 * 1000;
|
||||
}
|
||||
document.cookie = `${this.prefix}${key}=${value};expires=${new Date(expires).toUTCString()}`
|
||||
document.cookie = `${this.prefix}${key}=${value};expires=${new Date(expires).toUTCString()}`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,18 +47,18 @@ class CookieStorage {
|
||||
* @Author: mulingyuer
|
||||
*/
|
||||
public getItem(key: string): string | undefined {
|
||||
const cookies = document.cookie.split('; ')
|
||||
let val: string | undefined = undefined
|
||||
const cookies = document.cookie.split("; ");
|
||||
let val: string | undefined = undefined;
|
||||
cookies.find((item) => {
|
||||
const [k, v] = item.split('=')
|
||||
const [k, v] = item.split("=");
|
||||
if (k === `${this.prefix}${key}`) {
|
||||
val = v
|
||||
return true
|
||||
val = v;
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
})
|
||||
return false;
|
||||
});
|
||||
|
||||
return val
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +68,7 @@ class CookieStorage {
|
||||
* @Author: mulingyuer
|
||||
*/
|
||||
public removeItem(key: string): void {
|
||||
this.setItem(key, '', -1)
|
||||
this.setItem(key, "", -1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,15 +77,15 @@ class CookieStorage {
|
||||
* @Author: mulingyuer
|
||||
*/
|
||||
public clear(): void {
|
||||
const cookies = document.cookie.split('; ')
|
||||
const cookies = document.cookie.split("; ");
|
||||
cookies.forEach((item) => {
|
||||
const [k] = item.split('=')
|
||||
this.removeItem(k)
|
||||
})
|
||||
const [k] = item.split("=");
|
||||
this.removeItem(k);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const cookieStorage = new CookieStorage()
|
||||
const cookieStorage = new CookieStorage();
|
||||
|
||||
export default cookieStorage
|
||||
export { CookieStorage }
|
||||
export default cookieStorage;
|
||||
export { CookieStorage };
|
||||
|
@@ -1,169 +1,173 @@
|
||||
import JSEncrypt from 'jsencrypt'
|
||||
import CryptoJS from 'crypto-js'
|
||||
/** @format */
|
||||
|
||||
import JSEncrypt from "jsencrypt";
|
||||
import CryptoJS from "crypto-js";
|
||||
|
||||
// 加密
|
||||
export function rsaEncrypt(Str: string, afterPublicKey: string) {
|
||||
const encryptor = new JSEncrypt()
|
||||
encryptor.setPublicKey(afterPublicKey) // 设置公钥
|
||||
return encryptor.encrypt(Str) // 对数据进行加密
|
||||
const encryptor = new JSEncrypt();
|
||||
encryptor.setPublicKey(afterPublicKey); // 设置公钥
|
||||
return encryptor.encrypt(Str); // 对数据进行加密
|
||||
}
|
||||
|
||||
// 解密
|
||||
export function rsaDecrypt(Str: string, frontPrivateKey: string) {
|
||||
const encryptor = new JSEncrypt()
|
||||
encryptor.setPrivateKey(frontPrivateKey) // 设置私钥
|
||||
return encryptor.decrypt(Str) // 对数据进行解密
|
||||
const encryptor = new JSEncrypt();
|
||||
encryptor.setPrivateKey(frontPrivateKey); // 设置私钥
|
||||
return encryptor.decrypt(Str); // 对数据进行解密
|
||||
}
|
||||
|
||||
export function aesEncrypt(aeskey: string, Str: string) {
|
||||
// 设置一个默认值,如果第二个参数为空采用默认值,不为空则采用新设置的密钥
|
||||
const key = CryptoJS.enc.Utf8.parse(aeskey)
|
||||
const srcs = CryptoJS.enc.Utf8.parse(Str)
|
||||
const key = CryptoJS.enc.Utf8.parse(aeskey);
|
||||
const srcs = CryptoJS.enc.Utf8.parse(Str);
|
||||
const encrypted = CryptoJS.AES.encrypt(srcs, key, {
|
||||
// 切记 需要和后端算法模式一致
|
||||
mode: CryptoJS.mode.ECB,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
})
|
||||
});
|
||||
|
||||
return encrypted.toString()
|
||||
return encrypted.toString();
|
||||
}
|
||||
|
||||
export function aesDecrypt(aeskey: string, Str: string) {
|
||||
const key = CryptoJS.enc.Utf8.parse(aeskey)
|
||||
const key = CryptoJS.enc.Utf8.parse(aeskey);
|
||||
const decrypt = CryptoJS.AES.decrypt(Str, key, {
|
||||
// 切记 需要和后端算法模式一致
|
||||
mode: CryptoJS.mode.ECB,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
})
|
||||
return CryptoJS.enc.Utf8.stringify(decrypt).toString()
|
||||
});
|
||||
return CryptoJS.enc.Utf8.stringify(decrypt).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取16位随机码AES
|
||||
* @returns {string}
|
||||
*/
|
||||
export function get16RandomNum() {
|
||||
const chars = [
|
||||
'0',
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
'A',
|
||||
'B',
|
||||
'C',
|
||||
'D',
|
||||
'E',
|
||||
'F',
|
||||
'G',
|
||||
'H',
|
||||
'I',
|
||||
'J',
|
||||
'K',
|
||||
'L',
|
||||
'M',
|
||||
'N',
|
||||
'O',
|
||||
'P',
|
||||
'Q',
|
||||
'R',
|
||||
'S',
|
||||
'T',
|
||||
'U',
|
||||
'V',
|
||||
'W',
|
||||
'X',
|
||||
'Y',
|
||||
'Z',
|
||||
'a',
|
||||
'b',
|
||||
'c',
|
||||
'd',
|
||||
'e',
|
||||
'f',
|
||||
'g',
|
||||
'h',
|
||||
'i',
|
||||
'j',
|
||||
'k',
|
||||
'l',
|
||||
'm',
|
||||
'n',
|
||||
'o',
|
||||
'p',
|
||||
'q',
|
||||
'r',
|
||||
's',
|
||||
't',
|
||||
'u',
|
||||
'v',
|
||||
'w',
|
||||
'x',
|
||||
'y',
|
||||
'z',
|
||||
]
|
||||
let nums = ''
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
"I",
|
||||
"J",
|
||||
"K",
|
||||
"L",
|
||||
"M",
|
||||
"N",
|
||||
"O",
|
||||
"P",
|
||||
"Q",
|
||||
"R",
|
||||
"S",
|
||||
"T",
|
||||
"U",
|
||||
"V",
|
||||
"W",
|
||||
"X",
|
||||
"Y",
|
||||
"Z",
|
||||
"a",
|
||||
"b",
|
||||
"c",
|
||||
"d",
|
||||
"e",
|
||||
"f",
|
||||
"g",
|
||||
"h",
|
||||
"i",
|
||||
"j",
|
||||
"k",
|
||||
"l",
|
||||
"m",
|
||||
"n",
|
||||
"o",
|
||||
"p",
|
||||
"q",
|
||||
"r",
|
||||
"s",
|
||||
"t",
|
||||
"u",
|
||||
"v",
|
||||
"w",
|
||||
"x",
|
||||
"y",
|
||||
"z",
|
||||
];
|
||||
let nums = "";
|
||||
//这个地方切记要选择16位,因为美国对密钥长度有限制,选择32位的话加解密会报错,需要根据jdk版本去修改相关jar包,有点恼火,选择16位就不用处理。
|
||||
for (let i = 0; i < 16; i++) {
|
||||
const id = parseInt(String(Math.random() * 61))
|
||||
nums += chars[id]
|
||||
const id = parseInt(String(Math.random() * 61));
|
||||
nums += chars[id];
|
||||
}
|
||||
return nums
|
||||
return nums;
|
||||
}
|
||||
|
||||
//获取rsa密钥对
|
||||
export function getRsaKeys() {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.crypto.subtle
|
||||
.generateKey(
|
||||
{
|
||||
name: 'RSA-OAEP',
|
||||
name: "RSA-OAEP",
|
||||
modulusLength: 2048, //can be 1024, 2048, or 4096
|
||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
||||
hash: { name: 'SHA-512' }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
|
||||
hash: { name: "SHA-512" }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
|
||||
},
|
||||
true, //whether the key is extractable (i.e. can be used in exportKey)
|
||||
['encrypt', 'decrypt'], //must be ["encrypt", "decrypt"] or ["wrapKey", "unwrapKey"]
|
||||
["encrypt", "decrypt"], //must be ["encrypt", "decrypt"] or ["wrapKey", "unwrapKey"]
|
||||
)
|
||||
.then(function (key) {
|
||||
window.crypto.subtle
|
||||
.exportKey('pkcs8', key.privateKey)
|
||||
.exportKey("pkcs8", key.privateKey)
|
||||
.then(function (keydata1) {
|
||||
window.crypto.subtle
|
||||
.exportKey('spki', key.publicKey)
|
||||
.exportKey("spki", key.publicKey)
|
||||
.then(function (keydata2) {
|
||||
const privateKey = RSA2text(keydata1, 1)
|
||||
const privateKey = RSA2text(keydata1, 1);
|
||||
|
||||
const publicKey = RSA2text(keydata2)
|
||||
const publicKey = RSA2text(keydata2);
|
||||
|
||||
resolve({ privateKey, publicKey })
|
||||
resolve({ privateKey, publicKey });
|
||||
})
|
||||
.catch(function (err) {
|
||||
reject(err)
|
||||
})
|
||||
reject(err);
|
||||
});
|
||||
})
|
||||
.catch(function (err) {
|
||||
reject(err)
|
||||
})
|
||||
reject(err);
|
||||
});
|
||||
})
|
||||
.catch(function (err) {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function RSA2text(buffer: any, _isPrivate: number = 0) {
|
||||
let binary = ''
|
||||
const bytes = new Uint8Array(buffer)
|
||||
const len = bytes.byteLength
|
||||
let binary = "";
|
||||
const bytes = new Uint8Array(buffer);
|
||||
const len = bytes.byteLength;
|
||||
for (let i = 0; i < len; i++) {
|
||||
binary += String.fromCharCode(bytes[i])
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
const base64 = window.btoa(binary)
|
||||
const text = base64.replace(/[^\x00-\xff]/g, '$&\x01').replace(/.{64}\x01?/g, '$&\n')
|
||||
const base64 = window.btoa(binary);
|
||||
const text = base64.replace(/[^\x00-\xff]/g, "$&\x01").replace(/.{64}\x01?/g, "$&\n");
|
||||
|
||||
return text
|
||||
return text;
|
||||
}
|
||||
|
@@ -1,96 +1,98 @@
|
||||
import { encrypt, decrypt } from './encry'
|
||||
import { globalConfig } from './interface'
|
||||
/** @format */
|
||||
|
||||
import { encrypt, decrypt } from "./encry";
|
||||
import { globalConfig } from "./interface";
|
||||
|
||||
const config: globalConfig = {
|
||||
type: 'localStorage', //存储类型,localStorage | sessionStorage
|
||||
prefix: 'schisandra_', //版本号
|
||||
type: "localStorage", //存储类型,localStorage | sessionStorage
|
||||
prefix: "schisandra_", //版本号
|
||||
expire: 24 * 60, //过期时间,默认为一天,单位为分钟
|
||||
isEncrypt: true, //支持加密、解密数据处理
|
||||
}
|
||||
};
|
||||
|
||||
const setStorage = (key: string, value: any, expire: number = 24 * 60): boolean => {
|
||||
//设定值
|
||||
if (value === '' || value === null || value === undefined) {
|
||||
if (value === "" || value === null || value === undefined) {
|
||||
//空值重置
|
||||
value = null
|
||||
value = null;
|
||||
}
|
||||
if (isNaN(expire) || expire < 0) {
|
||||
//过期时间值合理性判断
|
||||
throw new Error('Expire must be a number')
|
||||
throw new Error("Expire must be a number");
|
||||
}
|
||||
const data = {
|
||||
value, //存储值
|
||||
time: Date.now(), //存储日期
|
||||
expire: Date.now() + 1000 * 60 * expire, //过期时间
|
||||
}
|
||||
};
|
||||
//是否需要加密,判断装载加密数据或原数据
|
||||
window[config.type].setItem(
|
||||
autoAddPreFix(key),
|
||||
config.isEncrypt ? encrypt(JSON.stringify(data)) : JSON.stringify(data),
|
||||
)
|
||||
return true
|
||||
}
|
||||
);
|
||||
return true;
|
||||
};
|
||||
|
||||
const getStorageFromKey = (key: string) => {
|
||||
//获取指定值
|
||||
if (config.prefix) {
|
||||
key = autoAddPreFix(key)
|
||||
key = autoAddPreFix(key);
|
||||
}
|
||||
if (!window[config.type].getItem(key)) {
|
||||
//不存在判断
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
const storageVal = config.isEncrypt
|
||||
? JSON.parse(decrypt(window[config.type].getItem(key) as string))
|
||||
: JSON.parse(window[config.type].getItem(key) as string)
|
||||
const now = Date.now()
|
||||
: JSON.parse(window[config.type].getItem(key) as string);
|
||||
const now = Date.now();
|
||||
if (now >= storageVal.expire) {
|
||||
//过期销毁
|
||||
removeStorageFromKey(key)
|
||||
return null
|
||||
removeStorageFromKey(key);
|
||||
return null;
|
||||
//不过期回值
|
||||
} else {
|
||||
return storageVal.value
|
||||
return storageVal.value;
|
||||
}
|
||||
}
|
||||
};
|
||||
const getAllStorage = () => {
|
||||
//获取所有值
|
||||
const storageList: any = {}
|
||||
const keys = Object.keys(window[config.type])
|
||||
const storageList: any = {};
|
||||
const keys = Object.keys(window[config.type]);
|
||||
keys.forEach((key) => {
|
||||
const value = getStorageFromKey(autoRemovePreFix(key))
|
||||
const value = getStorageFromKey(autoRemovePreFix(key));
|
||||
if (value !== null) {
|
||||
//如果值没有过期,加入到列表中
|
||||
storageList[autoRemovePreFix(key)] = value
|
||||
storageList[autoRemovePreFix(key)] = value;
|
||||
}
|
||||
})
|
||||
return storageList
|
||||
}
|
||||
});
|
||||
return storageList;
|
||||
};
|
||||
const getStorageLength = () => {
|
||||
//获取值列表长度
|
||||
return window[config.type].length
|
||||
}
|
||||
return window[config.type].length;
|
||||
};
|
||||
const removeStorageFromKey = (key: string) => {
|
||||
//删除值
|
||||
if (config.prefix) {
|
||||
key = autoAddPreFix(key)
|
||||
key = autoAddPreFix(key);
|
||||
}
|
||||
window[config.type].removeItem(key)
|
||||
}
|
||||
window[config.type].removeItem(key);
|
||||
};
|
||||
const clearStorage = () => {
|
||||
window[config.type].clear()
|
||||
}
|
||||
window[config.type].clear();
|
||||
};
|
||||
const autoAddPreFix = (key: string) => {
|
||||
//添加前缀,保持唯一性
|
||||
const prefix = config.prefix || ''
|
||||
return `${prefix}_${key}`
|
||||
}
|
||||
const prefix = config.prefix || "";
|
||||
return `${prefix}_${key}`;
|
||||
};
|
||||
const autoRemovePreFix = (key: string) => {
|
||||
//删除前缀,进行增删改查
|
||||
const lineIndex = config.prefix.length + 1
|
||||
return key.substr(lineIndex)
|
||||
}
|
||||
const lineIndex = config.prefix.length + 1;
|
||||
return key.substr(lineIndex);
|
||||
};
|
||||
|
||||
export {
|
||||
setStorage,
|
||||
@@ -99,4 +101,4 @@ export {
|
||||
getStorageLength,
|
||||
removeStorageFromKey,
|
||||
clearStorage,
|
||||
}
|
||||
};
|
||||
|
@@ -1,37 +1,39 @@
|
||||
import CryptoJS from 'crypto-js'
|
||||
/** @format */
|
||||
|
||||
const SECRET_KEY = CryptoJS.enc.Utf8.parse('3333e6e143439161') //十六位十六进制数作为密钥
|
||||
const SECRET_IV = CryptoJS.enc.Utf8.parse('e3bbe7e3ba84431a') //十六位十六进制数作为密钥偏移量
|
||||
import CryptoJS from "crypto-js";
|
||||
|
||||
const SECRET_KEY = CryptoJS.enc.Utf8.parse("3333e6e143439161"); //十六位十六进制数作为密钥
|
||||
const SECRET_IV = CryptoJS.enc.Utf8.parse("e3bbe7e3ba84431a"); //十六位十六进制数作为密钥偏移量
|
||||
|
||||
const encrypt = (data: object | string): string => {
|
||||
//加密
|
||||
if (typeof data === 'object') {
|
||||
if (typeof data === "object") {
|
||||
try {
|
||||
data = JSON.stringify(data)
|
||||
data = JSON.stringify(data);
|
||||
} catch (e) {
|
||||
throw new Error('encrypt error' + e)
|
||||
throw new Error("encrypt error" + e);
|
||||
}
|
||||
}
|
||||
const dataHex = CryptoJS.enc.Utf8.parse(data)
|
||||
const dataHex = CryptoJS.enc.Utf8.parse(data);
|
||||
const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
|
||||
iv: SECRET_IV,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
})
|
||||
return encrypted.ciphertext.toString()
|
||||
}
|
||||
});
|
||||
return encrypted.ciphertext.toString();
|
||||
};
|
||||
|
||||
const decrypt = (data: string) => {
|
||||
//解密
|
||||
const encryptedHexStr = CryptoJS.enc.Hex.parse(data)
|
||||
const str = CryptoJS.enc.Base64.stringify(encryptedHexStr)
|
||||
const encryptedHexStr = CryptoJS.enc.Hex.parse(data);
|
||||
const str = CryptoJS.enc.Base64.stringify(encryptedHexStr);
|
||||
const decrypt = CryptoJS.AES.decrypt(str, SECRET_KEY, {
|
||||
iv: SECRET_IV,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
})
|
||||
const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8)
|
||||
return decryptedStr.toString()
|
||||
}
|
||||
});
|
||||
const decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
|
||||
return decryptedStr.toString();
|
||||
};
|
||||
|
||||
export { encrypt, decrypt }
|
||||
export { encrypt, decrypt };
|
||||
|
@@ -1,8 +1,10 @@
|
||||
/** @format */
|
||||
|
||||
interface globalConfig {
|
||||
type: 'localStorage' | 'sessionStorage'
|
||||
prefix: string
|
||||
expire: number
|
||||
isEncrypt: boolean
|
||||
type: "localStorage" | "sessionStorage";
|
||||
prefix: string;
|
||||
expire: number;
|
||||
isEncrypt: boolean;
|
||||
}
|
||||
|
||||
export type { globalConfig }
|
||||
export type { globalConfig };
|
||||
|
@@ -1,22 +1,24 @@
|
||||
import localforage from 'localforage'
|
||||
import CryptoJS from 'crypto-js'
|
||||
/** @format */
|
||||
|
||||
const SECRET_KEY = CryptoJS.enc.Utf8.parse('3333e6e143439161') //十六位十六进制数作为密钥
|
||||
const SECRET_IV = CryptoJS.enc.Utf8.parse('e3bbe7e3ba84431a') //十六位十六进制数作为密钥偏移量
|
||||
import localforage from "localforage";
|
||||
import CryptoJS from "crypto-js";
|
||||
|
||||
const SECRET_KEY = CryptoJS.enc.Utf8.parse("3333e6e143439161"); //十六位十六进制数作为密钥
|
||||
const SECRET_IV = CryptoJS.enc.Utf8.parse("e3bbe7e3ba84431a"); //十六位十六进制数作为密钥偏移量
|
||||
/**
|
||||
* 加密
|
||||
* @param data
|
||||
* @param output
|
||||
*/
|
||||
export const encrypt = (data: string, output?: any) => {
|
||||
const dataHex = CryptoJS.enc.Utf8.parse(data)
|
||||
const dataHex = CryptoJS.enc.Utf8.parse(data);
|
||||
const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, {
|
||||
iv: SECRET_IV,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
})
|
||||
return encrypted.ciphertext.toString(output)
|
||||
}
|
||||
});
|
||||
return encrypted.ciphertext.toString(output);
|
||||
};
|
||||
|
||||
/**
|
||||
* 解密
|
||||
@@ -24,51 +26,51 @@ export const encrypt = (data: string, output?: any) => {
|
||||
*/
|
||||
export const decrypt = (data: string | null) => {
|
||||
if (data === null) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
const encryptedHex = CryptoJS.enc.Hex.parse(data)
|
||||
const encryptedHexStr = CryptoJS.enc.Base64.stringify(encryptedHex)
|
||||
const encryptedHex = CryptoJS.enc.Hex.parse(data);
|
||||
const encryptedHexStr = CryptoJS.enc.Base64.stringify(encryptedHex);
|
||||
const decrypted = CryptoJS.AES.decrypt(encryptedHexStr, SECRET_KEY, {
|
||||
iv: SECRET_IV,
|
||||
mode: CryptoJS.mode.CBC,
|
||||
padding: CryptoJS.pad.Pkcs7,
|
||||
})
|
||||
const decryptedStr = decrypted.toString(CryptoJS.enc.Utf8)
|
||||
return decryptedStr.toString()
|
||||
}
|
||||
});
|
||||
const decryptedStr = decrypted.toString(CryptoJS.enc.Utf8);
|
||||
return decryptedStr.toString();
|
||||
};
|
||||
|
||||
export const handleLocalforage = {
|
||||
config: async (options?: LocalForageOptions) => localforage.config(options || {}),
|
||||
setItem: async (key: string, value: string): Promise<void> => {
|
||||
await localforage.setItem(key, encrypt(value))
|
||||
await localforage.setItem(key, encrypt(value));
|
||||
},
|
||||
getItem: async function getItem<T>(key: string): Promise<T | string | null> {
|
||||
try {
|
||||
const value: any = decrypt(await localforage.getItem(key)) as any
|
||||
const value: any = decrypt(await localforage.getItem(key)) as any;
|
||||
// 如果值是 undefined,返回 null
|
||||
if (value === undefined) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
// 如果值是 T 类型,直接返回
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
return value as T
|
||||
if (typeof value === "object" && value !== null) {
|
||||
return value as T;
|
||||
}
|
||||
// 如果值是 string 类型,直接返回
|
||||
return value as string
|
||||
return value as string;
|
||||
} catch (error) {
|
||||
console.error('Error retrieving data from localforage:', error)
|
||||
return null
|
||||
console.error("Error retrieving data from localforage:", error);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
removeItem: async (key: string): Promise<void> => {
|
||||
await localforage.removeItem(key)
|
||||
await localforage.removeItem(key);
|
||||
},
|
||||
clear: async () => {
|
||||
return await localforage.clear()
|
||||
return await localforage.clear();
|
||||
},
|
||||
createInstance: async (name: string) => {
|
||||
return localforage.createInstance({
|
||||
name,
|
||||
})
|
||||
});
|
||||
},
|
||||
}
|
||||
};
|
||||
|
@@ -1,11 +1,13 @@
|
||||
import { MobXProviderContext } from 'mobx-react'
|
||||
import { useContext } from 'react'
|
||||
import { RootStore } from '@/store'
|
||||
/** @format */
|
||||
|
||||
import { MobXProviderContext } from "mobx-react";
|
||||
import { useContext } from "react";
|
||||
import { RootStore } from "@/store";
|
||||
|
||||
// 根据RootStore来实现参数的自动获取和返回值的自动推导
|
||||
function useStore<T extends typeof RootStore, V extends keyof T>(name: V): T[V] {
|
||||
const store = useContext(MobXProviderContext) as T
|
||||
return store[name]
|
||||
const store = useContext(MobXProviderContext) as T;
|
||||
return store[name];
|
||||
}
|
||||
|
||||
export default useStore
|
||||
export default useStore;
|
||||
|
@@ -1,161 +1,164 @@
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import './index.less'
|
||||
import {useEffect} from "react";
|
||||
/** @format */
|
||||
|
||||
import { useNavigate } from "react-router-dom";
|
||||
// import "./index.less";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default () => {
|
||||
const navigate = useNavigate()
|
||||
const navigate = useNavigate();
|
||||
const goBack = () => {
|
||||
navigate(-1)
|
||||
}
|
||||
navigate(-1);
|
||||
};
|
||||
useEffect(() => {
|
||||
document.body.classList.add('not-fount-body')
|
||||
return ()=>{
|
||||
document.body.classList.remove('not-fount-body')
|
||||
}
|
||||
document.body.classList.add("not-fount-body");
|
||||
return () => {
|
||||
document.body.classList.remove("not-fount-body");
|
||||
};
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<body translate='no'>
|
||||
<div className='container container-star'>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-1'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<div className='star-2'></div>
|
||||
<body translate="no">
|
||||
<div className="container container-star">
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-1"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
<div className="star-2"></div>
|
||||
</div>
|
||||
<div className='container container-bird'>
|
||||
<div className='bird bird-anim'>
|
||||
<div className='bird-container'>
|
||||
<div className='wing wing-left'>
|
||||
<div className='wing-left-top'></div>
|
||||
<div className="container container-bird">
|
||||
<div className="bird bird-anim">
|
||||
<div className="bird-container">
|
||||
<div className="wing wing-left">
|
||||
<div className="wing-left-top"></div>
|
||||
</div>
|
||||
<div className='wing wing-right'>
|
||||
<div className='wing-right-top'></div>
|
||||
<div className="wing wing-right">
|
||||
<div className="wing-right-top"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='bird bird-anim'>
|
||||
<div className='bird-container'>
|
||||
<div className='wing wing-left'>
|
||||
<div className='wing-left-top'></div>
|
||||
<div className="bird bird-anim">
|
||||
<div className="bird-container">
|
||||
<div className="wing wing-left">
|
||||
<div className="wing-left-top"></div>
|
||||
</div>
|
||||
<div className='wing wing-right'>
|
||||
<div className='wing-right-top'></div>
|
||||
<div className="wing wing-right">
|
||||
<div className="wing-right-top"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='bird bird-anim'>
|
||||
<div className='bird-container'>
|
||||
<div className='wing wing-left'>
|
||||
<div className='wing-left-top'></div>
|
||||
<div className="bird bird-anim">
|
||||
<div className="bird-container">
|
||||
<div className="wing wing-left">
|
||||
<div className="wing-left-top"></div>
|
||||
</div>
|
||||
<div className='wing wing-right'>
|
||||
<div className='wing-right-top'></div>
|
||||
<div className="wing wing-right">
|
||||
<div className="wing-right-top"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='bird bird-anim'>
|
||||
<div className='bird-container'>
|
||||
<div className='wing wing-left'>
|
||||
<div className='wing-left-top'></div>
|
||||
<div className="bird bird-anim">
|
||||
<div className="bird-container">
|
||||
<div className="wing wing-left">
|
||||
<div className="wing-left-top"></div>
|
||||
</div>
|
||||
<div className='wing wing-right'>
|
||||
<div className='wing-right-top'></div>
|
||||
<div className="wing wing-right">
|
||||
<div className="wing-right-top"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='bird bird-anim'>
|
||||
<div className='bird-container'>
|
||||
<div className='wing wing-left'>
|
||||
<div className='wing-left-top'></div>
|
||||
<div className="bird bird-anim">
|
||||
<div className="bird-container">
|
||||
<div className="wing wing-left">
|
||||
<div className="wing-left-top"></div>
|
||||
</div>
|
||||
<div className='wing wing-right'>
|
||||
<div className='wing-right-top'></div>
|
||||
<div className="wing wing-right">
|
||||
<div className="wing-right-top"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='bird bird-anim'>
|
||||
<div className='bird-container'>
|
||||
<div className='wing wing-left'>
|
||||
<div className='wing-left-top'></div>
|
||||
<div className="bird bird-anim">
|
||||
<div className="bird-container">
|
||||
<div className="wing wing-left">
|
||||
<div className="wing-left-top"></div>
|
||||
</div>
|
||||
<div className='wing wing-right'>
|
||||
<div className='wing-right-top'></div>
|
||||
<div className="wing wing-right">
|
||||
<div className="wing-right-top"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='container-title'>
|
||||
<div className='title'>
|
||||
<div className='number'>4</div>
|
||||
<div className='moon'>
|
||||
<div className='face'>
|
||||
<div className='mouth'></div>
|
||||
<div className='eyes'>
|
||||
<div className='eye-left'></div>
|
||||
<div className='eye-right'></div>
|
||||
<div className="container-title">
|
||||
<div className="title">
|
||||
<div className="number">4</div>
|
||||
<div className="moon">
|
||||
<div className="face">
|
||||
<div className="mouth"></div>
|
||||
<div className="eyes">
|
||||
<div className="eye-left"></div>
|
||||
<div className="eye-right"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='number'>4</div>
|
||||
<div className="number">4</div>
|
||||
</div>
|
||||
<div className='subtitle'>Oops. Looks like you took a wrong turn.</div>
|
||||
<div className="subtitle">Oops. Looks like you took a wrong turn.</div>
|
||||
<button
|
||||
style={{
|
||||
marginTop: '1.5em',
|
||||
marginTop: "1.5em",
|
||||
}}
|
||||
onClick={goBack}>
|
||||
Go back
|
||||
@@ -164,5 +167,5 @@ export default () => {
|
||||
</div>
|
||||
</body>
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@@ -1,30 +1,13 @@
|
||||
import HomeIndex from '@/components/HomeIndex'
|
||||
import { useEffect } from 'react'
|
||||
import { getBaseInfo, initMinio } from '@/api/oss/minio'
|
||||
import { Button } from 'antd'
|
||||
/** @format */
|
||||
import { useEffect } from "react";
|
||||
|
||||
import HomeIndex from "@/components/HomeIndex";
|
||||
|
||||
export default () => {
|
||||
const minioInit = () => {
|
||||
initMinio('1').then(() => {
|
||||
getBaseInfo('wallhaven-1pd98v.jpg').then((res) => {
|
||||
console.log(res)
|
||||
})
|
||||
})
|
||||
}
|
||||
const init = () => {
|
||||
initMinio('2').then(() => {
|
||||
getBaseInfo('background.png').then((res) => {
|
||||
console.log(res)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {}, [])
|
||||
useEffect(() => {}, []);
|
||||
return (
|
||||
<div>
|
||||
<HomeIndex />
|
||||
<Button onClick={minioInit}>测试一</Button>
|
||||
<Button onClick={init}>测试二</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@@ -1,8 +1,11 @@
|
||||
import DefaultLayOut from '@/layout/default'
|
||||
/** @format */
|
||||
|
||||
import DefaultLayOut from "@/layout/default";
|
||||
|
||||
export default () => {
|
||||
return (
|
||||
<>
|
||||
<DefaultLayOut />
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@@ -1,3 +1,5 @@
|
||||
/** @format */
|
||||
|
||||
import {
|
||||
GithubOutlined,
|
||||
GitlabOutlined,
|
||||
@@ -6,31 +8,31 @@ import {
|
||||
QqOutlined,
|
||||
UserOutlined,
|
||||
WechatOutlined,
|
||||
} from '@ant-design/icons'
|
||||
import { ProFormCaptcha, ProFormCheckbox, ProFormText } from '@ant-design/pro-components'
|
||||
import { Divider, Space, Tabs, message, Image, Alert, Form, Button } from 'antd'
|
||||
import { CSSProperties, useRef } from 'react'
|
||||
import { useState } from 'react'
|
||||
import logo from '@/assets/icons/schisandra.svg'
|
||||
import qrCode from '@/assets/images/login_qrcode-landaiqing.jpg'
|
||||
import styles from './index.module.less'
|
||||
import { observer } from 'mobx-react'
|
||||
import FooterComponent from '@/components/Footer'
|
||||
import RotateCaptcha, { CaptchaInstance } from 'react-rotate-captcha'
|
||||
import { get, load, verify } from '@/api/captcha/index.ts'
|
||||
} from "@ant-design/icons";
|
||||
import { ProFormCaptcha, ProFormCheckbox, ProFormText } from "@ant-design/pro-components";
|
||||
import { Divider, Space, Tabs, message, Image, Alert, Form, Button } from "antd";
|
||||
import { CSSProperties, useRef } from "react";
|
||||
import { useState } from "react";
|
||||
import logo from "@/assets/icons/schisandra.svg";
|
||||
import qrCode from "@/assets/images/login_qrcode-landaiqing.jpg";
|
||||
import styles from "./index.module.less";
|
||||
import { observer } from "mobx-react";
|
||||
import FooterComponent from "@/components/Footer";
|
||||
import RotateCaptcha, { CaptchaInstance } from "react-rotate-captcha";
|
||||
import { get, load, verify } from "@/api/captcha/index.ts";
|
||||
// import useStore from '@/utils/store/useStore.tsx'
|
||||
type LoginType = 'account' | 'phone'
|
||||
type LoginType = "account" | "phone";
|
||||
|
||||
const iconStyles: CSSProperties = {
|
||||
color: 'rgba(0, 0, 0, 0.2)',
|
||||
fontSize: '18px',
|
||||
verticalAlign: 'middle',
|
||||
cursor: 'pointer',
|
||||
}
|
||||
color: "rgba(0, 0, 0, 0.2)",
|
||||
fontSize: "18px",
|
||||
verticalAlign: "middle",
|
||||
cursor: "pointer",
|
||||
};
|
||||
|
||||
export default observer(() => {
|
||||
const [form] = Form.useForm()
|
||||
const captcha = useRef<CaptchaInstance>(null)
|
||||
const [form] = Form.useForm();
|
||||
const captcha = useRef<CaptchaInstance>(null);
|
||||
const items = [
|
||||
{
|
||||
label: (
|
||||
@@ -39,7 +41,7 @@ export default observer(() => {
|
||||
账户登录
|
||||
</span>
|
||||
),
|
||||
key: 'account',
|
||||
key: "account",
|
||||
},
|
||||
{
|
||||
label: (
|
||||
@@ -48,22 +50,22 @@ export default observer(() => {
|
||||
短信登录
|
||||
</span>
|
||||
),
|
||||
key: 'phone',
|
||||
key: "phone",
|
||||
},
|
||||
]
|
||||
const [loginType, setLoginType] = useState<LoginType>('account')
|
||||
];
|
||||
const [loginType, setLoginType] = useState<LoginType>("account");
|
||||
|
||||
const onSubmit = async (formData: object) => {
|
||||
console.log(formData)
|
||||
}
|
||||
console.log(formData);
|
||||
};
|
||||
return (
|
||||
<RotateCaptcha get={get} load={load} verify={verify} limit={2} ref={captcha}>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.content}>
|
||||
<Space className={styles.content_content}>
|
||||
<Space className={styles.login_content}>
|
||||
<Space align='center' className={styles.mp_code}>
|
||||
<Space direction='vertical' align='center'>
|
||||
<Space align="center" className={styles.mp_code}>
|
||||
<Space direction="vertical" align="center">
|
||||
<span className={styles.mp_code_title}>微信扫码登录</span>
|
||||
<Image
|
||||
preview={false}
|
||||
@@ -100,12 +102,12 @@ export default observer(() => {
|
||||
initialValues={{
|
||||
autoLogin: true,
|
||||
}}>
|
||||
<Space direction='vertical' align='center'>
|
||||
<Space direction="vertical" align="center">
|
||||
<Space className={styles.logo}>
|
||||
<img
|
||||
alt='logo'
|
||||
alt="logo"
|
||||
src={logo}
|
||||
style={{ width: '44px', height: '44px' }}
|
||||
style={{ width: "44px", height: "44px" }}
|
||||
/>
|
||||
<span>五味子云存储</span>
|
||||
</Space>
|
||||
@@ -120,39 +122,39 @@ export default observer(() => {
|
||||
setLoginType(activeKey as LoginType)
|
||||
}></Tabs>
|
||||
|
||||
{loginType === 'account' && (
|
||||
{loginType === "account" && (
|
||||
<>
|
||||
<ProFormText
|
||||
name='username'
|
||||
name="username"
|
||||
fieldProps={{
|
||||
size: 'large',
|
||||
prefix: <UserOutlined className={'prefixIcon'} />,
|
||||
size: "large",
|
||||
prefix: <UserOutlined className={"prefixIcon"} />,
|
||||
}}
|
||||
placeholder={'请输入账号/邮箱/电话号码'}
|
||||
placeholder={"请输入账号/邮箱/电话号码"}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入用户名!',
|
||||
message: "请输入用户名!",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<ProFormText.Password
|
||||
name='password'
|
||||
name="password"
|
||||
fieldProps={{
|
||||
size: 'large',
|
||||
prefix: <LockOutlined className={'prefixIcon'} />,
|
||||
size: "large",
|
||||
prefix: <LockOutlined className={"prefixIcon"} />,
|
||||
}}
|
||||
placeholder={'请输入密码'}
|
||||
placeholder={"请输入密码"}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入密码!',
|
||||
message: "请输入密码!",
|
||||
},
|
||||
{
|
||||
pattern:
|
||||
/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z\\W]{6,18}$/,
|
||||
message:
|
||||
'密码长度需在6~18位字符,且必须包含字母和数字!',
|
||||
"密码长度需在6~18位字符,且必须包含字母和数字!",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
@@ -178,24 +180,24 @@ export default observer(() => {
|
||||
{/*/>*/}
|
||||
</>
|
||||
)}
|
||||
{loginType === 'phone' && (
|
||||
{loginType === "phone" && (
|
||||
<>
|
||||
<ProFormText
|
||||
fieldProps={{
|
||||
size: 'large',
|
||||
prefix: <MobileOutlined className={'prefixIcon'} />,
|
||||
autoComplete: 'off',
|
||||
size: "large",
|
||||
prefix: <MobileOutlined className={"prefixIcon"} />,
|
||||
autoComplete: "off",
|
||||
}}
|
||||
name='mobile'
|
||||
placeholder={'请输入手机号'}
|
||||
name="mobile"
|
||||
placeholder={"请输入手机号"}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入手机号!',
|
||||
message: "请输入手机号!",
|
||||
},
|
||||
{
|
||||
pattern: /^1\d{10}$/,
|
||||
message: '手机号格式错误!',
|
||||
message: "手机号格式错误!",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
@@ -221,149 +223,149 @@ export default observer(() => {
|
||||
{/*/>*/}
|
||||
<ProFormCaptcha
|
||||
fieldProps={{
|
||||
size: 'large',
|
||||
prefix: <LockOutlined className={'prefixIcon'} />,
|
||||
size: "large",
|
||||
prefix: <LockOutlined className={"prefixIcon"} />,
|
||||
}}
|
||||
captchaProps={{
|
||||
size: 'large',
|
||||
size: "large",
|
||||
}}
|
||||
placeholder={'请输入验证码'}
|
||||
placeholder={"请输入验证码"}
|
||||
captchaTextRender={(timing, count) => {
|
||||
if (timing) {
|
||||
return `${count} ${'获取验证码'}`
|
||||
return `${count} ${"获取验证码"}`;
|
||||
}
|
||||
return '获取验证码'
|
||||
return "获取验证码";
|
||||
}}
|
||||
name='captcha'
|
||||
name="captcha"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入验证码!',
|
||||
message: "请输入验证码!",
|
||||
},
|
||||
]}
|
||||
onGetCaptcha={async () => {
|
||||
captcha.current!.open()
|
||||
message.success('获取验证码成功!验证码为:1234')
|
||||
captcha.current!.open();
|
||||
message.success("获取验证码成功!验证码为:1234");
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<div style={{ marginBlockEnd: 14 }}>
|
||||
<ProFormCheckbox noStyle name='autoLogin'>
|
||||
<ProFormCheckbox noStyle name="autoLogin">
|
||||
自动登录
|
||||
</ProFormCheckbox>
|
||||
<a style={{ float: 'right' }}>忘记密码 </a>
|
||||
<a style={{ float: "right" }}>忘记密码 </a>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type='primary'
|
||||
type="primary"
|
||||
block
|
||||
size='large'
|
||||
size="large"
|
||||
onClick={async () => {
|
||||
let validateFields
|
||||
if (loginType === 'account') {
|
||||
validateFields = ['username', 'password', 'code']
|
||||
let validateFields;
|
||||
if (loginType === "account") {
|
||||
validateFields = ["username", "password", "code"];
|
||||
} else {
|
||||
validateFields = ['mobile', 'captcha', 'code']
|
||||
validateFields = ["mobile", "captcha", "code"];
|
||||
}
|
||||
|
||||
await form
|
||||
.validateFields(validateFields)
|
||||
.then(async (values) => {
|
||||
if (loginType === 'account') {
|
||||
captcha.current!.open()
|
||||
if (loginType === "account") {
|
||||
captcha.current!.open();
|
||||
}
|
||||
await onSubmit(values as API.PhoneRegisterRequest)
|
||||
await onSubmit(values as API.PhoneRegisterRequest);
|
||||
})
|
||||
.catch((errorInfo) => {
|
||||
console.error(errorInfo)
|
||||
})
|
||||
console.error(errorInfo);
|
||||
});
|
||||
}}>
|
||||
登录
|
||||
</Button>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'column',
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
}}>
|
||||
<Divider plain>
|
||||
<span
|
||||
style={{
|
||||
color: '#CCC',
|
||||
fontWeight: 'normal',
|
||||
color: "#CCC",
|
||||
fontWeight: "normal",
|
||||
fontSize: 14,
|
||||
}}>
|
||||
其他登录方式
|
||||
</span>
|
||||
</Divider>
|
||||
<Space align='center' size={24}>
|
||||
<Space align="center" size={24}>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'column',
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
height: 40,
|
||||
width: 40,
|
||||
border: '1px solid #D4D8DD',
|
||||
borderRadius: '50%',
|
||||
border: "1px solid #D4D8DD",
|
||||
borderRadius: "50%",
|
||||
}}>
|
||||
<QqOutlined
|
||||
style={{ ...iconStyles, color: '#1677FF' }}
|
||||
style={{ ...iconStyles, color: "#1677FF" }}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'column',
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
height: 40,
|
||||
width: 40,
|
||||
border: '1px solid #D4D8DD',
|
||||
borderRadius: '50%',
|
||||
border: "1px solid #D4D8DD",
|
||||
borderRadius: "50%",
|
||||
}}>
|
||||
<WechatOutlined
|
||||
style={{ ...iconStyles, color: '#08a327' }}
|
||||
style={{ ...iconStyles, color: "#08a327" }}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'column',
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
height: 40,
|
||||
width: 40,
|
||||
border: '1px solid #D4D8DD',
|
||||
borderRadius: '50%',
|
||||
border: "1px solid #D4D8DD",
|
||||
borderRadius: "50%",
|
||||
}}>
|
||||
<GithubOutlined
|
||||
style={{ ...iconStyles, color: '#333333' }}
|
||||
style={{ ...iconStyles, color: "#333333" }}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'column',
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
height: 40,
|
||||
width: 40,
|
||||
border: '1px solid #D4D8DD',
|
||||
borderRadius: '50%',
|
||||
border: "1px solid #D4D8DD",
|
||||
borderRadius: "50%",
|
||||
}}>
|
||||
<GitlabOutlined
|
||||
style={{ ...iconStyles, color: '#FF6A10' }}
|
||||
style={{ ...iconStyles, color: "#FF6A10" }}
|
||||
/>
|
||||
</div>
|
||||
</Space>
|
||||
</div>
|
||||
</Form>
|
||||
<a href='/register' className={styles.go_to_register}>
|
||||
<a href="/register" className={styles.go_to_register}>
|
||||
<span>注册</span>
|
||||
</a>
|
||||
</Space>
|
||||
@@ -372,5 +374,5 @@ export default observer(() => {
|
||||
<FooterComponent></FooterComponent>
|
||||
</div>
|
||||
</RotateCaptcha>
|
||||
)
|
||||
})
|
||||
);
|
||||
});
|
||||
|
@@ -1,21 +1,23 @@
|
||||
import { LockOutlined, MobileOutlined, WechatOutlined } from '@ant-design/icons'
|
||||
import { ProFormCaptcha, ProFormText } from '@ant-design/pro-components'
|
||||
import { Space, Tabs, message, Image, Alert, Form, Button } from 'antd'
|
||||
import { useState } from 'react'
|
||||
import logo from '@/assets/icons/schisandra.svg'
|
||||
/** @format */
|
||||
|
||||
import { LockOutlined, MobileOutlined, WechatOutlined } from "@ant-design/icons";
|
||||
import { ProFormCaptcha, ProFormText } from "@ant-design/pro-components";
|
||||
import { Space, Tabs, message, Image, Alert, Form, Button } from "antd";
|
||||
import { useState } from "react";
|
||||
import logo from "@/assets/icons/schisandra.svg";
|
||||
// import background from '@/assets/images/background.png'
|
||||
import qrCode from '@/assets/images/login_qrcode-landaiqing.jpg'
|
||||
import styles from './index.module.less'
|
||||
import { observer } from 'mobx-react'
|
||||
import FooterComponent from '@/components/Footer'
|
||||
import qrCode from "@/assets/images/login_qrcode-landaiqing.jpg";
|
||||
import styles from "./index.module.less";
|
||||
import { observer } from "mobx-react";
|
||||
import FooterComponent from "@/components/Footer";
|
||||
// import useStore from '@/utils/store/useStore.tsx'
|
||||
type LoginType = 'phone'
|
||||
type LoginType = "phone";
|
||||
|
||||
export default observer(() => {
|
||||
const [form] = Form.useForm()
|
||||
const [form] = Form.useForm();
|
||||
const items = [
|
||||
{
|
||||
key: 'phone',
|
||||
key: "phone",
|
||||
label: (
|
||||
<span>
|
||||
<MobileOutlined />
|
||||
@@ -23,19 +25,19 @@ export default observer(() => {
|
||||
</span>
|
||||
),
|
||||
},
|
||||
]
|
||||
const [loginType, setLoginType] = useState<LoginType>('phone')
|
||||
];
|
||||
const [loginType, setLoginType] = useState<LoginType>("phone");
|
||||
|
||||
const onSubmit = async (formData: object) => {
|
||||
console.log(formData)
|
||||
}
|
||||
console.log(formData);
|
||||
};
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.content}>
|
||||
<Space>
|
||||
<Space className={styles.login_content}>
|
||||
<Space align='center' className={styles.mp_code}>
|
||||
<Space direction='vertical' align='center'>
|
||||
<Space align="center" className={styles.mp_code}>
|
||||
<Space direction="vertical" align="center">
|
||||
<span className={styles.mp_code_title}>微信扫码登录</span>
|
||||
<Image
|
||||
preview={false}
|
||||
@@ -70,12 +72,12 @@ export default observer(() => {
|
||||
initialValues={{
|
||||
autoLogin: true,
|
||||
}}>
|
||||
<Space direction='vertical' align='center'>
|
||||
<Space direction="vertical" align="center">
|
||||
<Space className={styles.logo}>
|
||||
<img
|
||||
alt='logo'
|
||||
alt="logo"
|
||||
src={logo}
|
||||
style={{ width: '44px', height: '44px' }}
|
||||
style={{ width: "44px", height: "44px" }}
|
||||
/>
|
||||
<span>五味子云存储</span>
|
||||
</Space>
|
||||
@@ -93,123 +95,123 @@ export default observer(() => {
|
||||
<>
|
||||
<ProFormText
|
||||
fieldProps={{
|
||||
size: 'large',
|
||||
prefix: <MobileOutlined className={'prefixIcon'} />,
|
||||
autoComplete: 'off',
|
||||
size: "large",
|
||||
prefix: <MobileOutlined className={"prefixIcon"} />,
|
||||
autoComplete: "off",
|
||||
}}
|
||||
name='phone'
|
||||
placeholder='请输入手机号!'
|
||||
name="phone"
|
||||
placeholder="请输入手机号!"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入手机号!',
|
||||
message: "请输入手机号!",
|
||||
},
|
||||
{
|
||||
pattern: /^1\d{10}$/,
|
||||
message: '手机号格式错误!',
|
||||
message: "手机号格式错误!",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<ProFormText.Password
|
||||
name='password'
|
||||
name="password"
|
||||
fieldProps={{
|
||||
size: 'large',
|
||||
prefix: <LockOutlined className={'prefixIcon'} />,
|
||||
size: "large",
|
||||
prefix: <LockOutlined className={"prefixIcon"} />,
|
||||
}}
|
||||
placeholder='请输入密码'
|
||||
placeholder="请输入密码"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入密码!',
|
||||
message: "请输入密码!",
|
||||
},
|
||||
{
|
||||
pattern:
|
||||
/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z\\W]{6,18}$/,
|
||||
message:
|
||||
'密码长度需在6~18位字符,且必须包含字母和数字!',
|
||||
"密码长度需在6~18位字符,且必须包含字母和数字!",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<ProFormText.Password
|
||||
name='confirmPassword'
|
||||
dependencies={['password']}
|
||||
name="confirmPassword"
|
||||
dependencies={["password"]}
|
||||
fieldProps={{
|
||||
size: 'large',
|
||||
prefix: <LockOutlined className={'prefixIcon'} />,
|
||||
size: "large",
|
||||
prefix: <LockOutlined className={"prefixIcon"} />,
|
||||
}}
|
||||
placeholder='请再次确认密码'
|
||||
placeholder="请再次确认密码"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请再次确认密码!',
|
||||
message: "请再次确认密码!",
|
||||
},
|
||||
({ getFieldValue }) => ({
|
||||
validator(_, value) {
|
||||
if (!value || getFieldValue('password') === value) {
|
||||
return Promise.resolve()
|
||||
if (!value || getFieldValue("password") === value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject(
|
||||
new Error('两次输入的密码不一致!'),
|
||||
)
|
||||
new Error("两次输入的密码不一致!"),
|
||||
);
|
||||
},
|
||||
}),
|
||||
]}
|
||||
/>
|
||||
<ProFormCaptcha
|
||||
fieldProps={{
|
||||
size: 'large',
|
||||
prefix: <LockOutlined className={'prefixIcon'} />,
|
||||
size: "large",
|
||||
prefix: <LockOutlined className={"prefixIcon"} />,
|
||||
}}
|
||||
captchaProps={{
|
||||
size: 'large',
|
||||
size: "large",
|
||||
}}
|
||||
placeholder={'请输入验证码'}
|
||||
placeholder={"请输入验证码"}
|
||||
captchaTextRender={(timing, count) => {
|
||||
if (timing) {
|
||||
return `${count} ${'获取验证码'}`
|
||||
return `${count} ${"获取验证码"}`;
|
||||
}
|
||||
return '获取验证码'
|
||||
return "获取验证码";
|
||||
}}
|
||||
name='captcha'
|
||||
name="captcha"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入验证码!',
|
||||
message: "请输入验证码!",
|
||||
},
|
||||
]}
|
||||
onGetCaptcha={async () => {
|
||||
message.success('获取验证码成功!验证码为:1234')
|
||||
message.success("获取验证码成功!验证码为:1234");
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
<Button
|
||||
type='primary'
|
||||
type="primary"
|
||||
block
|
||||
size='large'
|
||||
size="large"
|
||||
onClick={async () => {
|
||||
const validateFields = [
|
||||
'phone',
|
||||
'username',
|
||||
'password',
|
||||
'captcha',
|
||||
'code',
|
||||
'confirmPassword',
|
||||
]
|
||||
"phone",
|
||||
"username",
|
||||
"password",
|
||||
"captcha",
|
||||
"code",
|
||||
"confirmPassword",
|
||||
];
|
||||
await form
|
||||
.validateFields(validateFields)
|
||||
.then(async (values) => {
|
||||
await onSubmit(values as API.PhoneRegisterRequest)
|
||||
await onSubmit(values as API.PhoneRegisterRequest);
|
||||
})
|
||||
.catch((errorInfo) => {
|
||||
console.error(errorInfo)
|
||||
})
|
||||
console.error(errorInfo);
|
||||
});
|
||||
}}>
|
||||
注册
|
||||
</Button>
|
||||
</Form>
|
||||
<a href='/login' className={styles.go_to_register}>
|
||||
<a href="/login" className={styles.go_to_register}>
|
||||
<span>登录</span>
|
||||
</a>
|
||||
</Space>
|
||||
@@ -217,5 +219,5 @@ export default observer(() => {
|
||||
</div>
|
||||
<FooterComponent />
|
||||
</div>
|
||||
)
|
||||
})
|
||||
);
|
||||
});
|
||||
|
59
src/vite-env.d.ts
vendored
@@ -1,34 +1,41 @@
|
||||
/** @format */
|
||||
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare interface ImportMetaEnv {
|
||||
readonly VITE_APP_BASE_API: string
|
||||
readonly VITE_APP_TITLE: string
|
||||
readonly VITE_API_BASE_URL: string
|
||||
readonly VITE_NODE_ENV: string
|
||||
readonly VITE_TITLE_NAME: string
|
||||
readonly VITE_APP_TOKEN_KEY?: string
|
||||
readonly VITE_UPLOAD_URL?: string
|
||||
readonly VITE_APP_BASE_API: string;
|
||||
readonly VITE_APP_TITLE: string;
|
||||
readonly VITE_API_BASE_URL: string;
|
||||
readonly VITE_NODE_ENV: string;
|
||||
readonly VITE_TITLE_NAME: string;
|
||||
readonly VITE_APP_TOKEN_KEY?: string;
|
||||
readonly VITE_UPLOAD_URL?: string;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
declare module '*.svg' {
|
||||
const content: any
|
||||
export default content
|
||||
}
|
||||
declare module '.*' {
|
||||
const value: any
|
||||
export default value
|
||||
}
|
||||
declare module '*.tsx'
|
||||
declare module '*.svg'
|
||||
declare module '*.png'
|
||||
declare module '*.jpg'
|
||||
declare module '*.jpeg'
|
||||
declare module '*.gif'
|
||||
declare module '*.bmp'
|
||||
declare module '*.tiff'
|
||||
|
||||
declare module 'gsap'
|
||||
declare module 'gsap/ScrollTrigger'
|
||||
declare module "*.svg" {
|
||||
const content: any;
|
||||
export default content;
|
||||
}
|
||||
declare module "*.js" {
|
||||
const content: any;
|
||||
export default content;
|
||||
}
|
||||
declare module ".*" {
|
||||
const value: any;
|
||||
export default value;
|
||||
}
|
||||
declare module "*.tsx";
|
||||
declare module "*.svg";
|
||||
declare module "*.png";
|
||||
declare module "*.jpg";
|
||||
declare module "*.jpeg";
|
||||
declare module "*.gif";
|
||||
declare module "*.bmp";
|
||||
declare module "*.tiff";
|
||||
|
||||
declare module "gsap";
|
||||
declare module "gsap/ScrollTrigger";
|
||||
|
@@ -11,7 +11,7 @@
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "node",
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
@@ -26,7 +26,7 @@
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
]
|
||||
],
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
@@ -35,7 +35,6 @@
|
||||
"src/**/*.tsx",
|
||||
"types/*.d.ts",
|
||||
"vite.config.ts",
|
||||
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
|
132
vite.config.ts
@@ -1,68 +1,70 @@
|
||||
import { defineConfig, loadEnv } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { resolve } from 'path'
|
||||
/** @format */
|
||||
|
||||
import { defineConfig, loadEnv } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import { resolve } from "path";
|
||||
// icons plugin
|
||||
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
|
||||
import * as path from 'path'
|
||||
import imagemin from 'unplugin-imagemin/vite'
|
||||
import viteCompression from 'vite-plugin-compression'
|
||||
import { createHtmlPlugin } from 'vite-plugin-html'
|
||||
import legacy from '@vitejs/plugin-legacy'
|
||||
import postcssPresetEnv from 'postcss-preset-env'
|
||||
import autoprefixer from 'autoprefixer'
|
||||
import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
|
||||
import * as path from "path";
|
||||
import imagemin from "unplugin-imagemin/vite";
|
||||
import viteCompression from "vite-plugin-compression";
|
||||
import { createHtmlPlugin } from "vite-plugin-html";
|
||||
import legacy from "@vitejs/plugin-legacy";
|
||||
import postcssPresetEnv from "postcss-preset-env";
|
||||
import autoprefixer from "autoprefixer";
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
//配置参数
|
||||
export default defineConfig(({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd())
|
||||
const env = loadEnv(mode, process.cwd());
|
||||
return {
|
||||
base: '/',
|
||||
base: "/",
|
||||
plugins: [
|
||||
react(),
|
||||
legacy({
|
||||
targets: [
|
||||
'ie >= 11',
|
||||
'chrome 52',
|
||||
'Chrome > 70',
|
||||
'Safari 12.1',
|
||||
'last 2 versions and since 2018 and > 0.5%',
|
||||
'iOS >= 9',
|
||||
'Android >= 4.4',
|
||||
'last 2 versions',
|
||||
"ie >= 11",
|
||||
"chrome 52",
|
||||
"Chrome > 70",
|
||||
"Safari 12.1",
|
||||
"last 2 versions and since 2018 and > 0.5%",
|
||||
"iOS >= 9",
|
||||
"Android >= 4.4",
|
||||
"last 2 versions",
|
||||
],
|
||||
additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
|
||||
additionalLegacyPolyfills: ["regenerator-runtime/runtime"],
|
||||
renderLegacyChunks: true,
|
||||
polyfills: [
|
||||
'es.promise.all-settled',
|
||||
'es.symbol',
|
||||
'es.array.filter',
|
||||
'es.promise',
|
||||
'es.promise.finally',
|
||||
'es/map',
|
||||
'es/set',
|
||||
'es.array.for-each',
|
||||
'es.object.define-properties',
|
||||
'es.object.define-property',
|
||||
'es.object.get-own-property-descriptor',
|
||||
'es.object.get-own-property-descriptors',
|
||||
'es.object.keys',
|
||||
'es.object.to-string',
|
||||
'web.dom-collections.for-each',
|
||||
'esnext.global-this',
|
||||
'esnext.string.match-all',
|
||||
"es.promise.all-settled",
|
||||
"es.symbol",
|
||||
"es.array.filter",
|
||||
"es.promise",
|
||||
"es.promise.finally",
|
||||
"es/map",
|
||||
"es/set",
|
||||
"es.array.for-each",
|
||||
"es.object.define-properties",
|
||||
"es.object.define-property",
|
||||
"es.object.get-own-property-descriptor",
|
||||
"es.object.get-own-property-descriptors",
|
||||
"es.object.keys",
|
||||
"es.object.to-string",
|
||||
"web.dom-collections.for-each",
|
||||
"esnext.global-this",
|
||||
"esnext.string.match-all",
|
||||
],
|
||||
modernPolyfills: ['es.promise.all-settled', 'es.object.entries'],
|
||||
modernPolyfills: ["es.promise.all-settled", "es.object.entries"],
|
||||
}),
|
||||
// 修改 icons 相关配置
|
||||
createSvgIconsPlugin({
|
||||
// 指定需要缓存的图标文件夹
|
||||
iconDirs: [path.resolve(__dirname, './src/assets/icons')],
|
||||
iconDirs: [path.resolve(__dirname, "./src/assets/icons")],
|
||||
// 指定symbolId格式
|
||||
symbolId: 'icon-[dir]-[name]',
|
||||
symbolId: "icon-[dir]-[name]",
|
||||
}),
|
||||
imagemin({
|
||||
// Default mode sharp. support squoosh and sharp
|
||||
mode: 'sharp',
|
||||
mode: "sharp",
|
||||
beforeBundle: true,
|
||||
// Default configuration options for compressing different pictures
|
||||
compress: {
|
||||
@@ -80,17 +82,17 @@ export default defineConfig(({ mode }) => {
|
||||
},
|
||||
},
|
||||
conversion: [
|
||||
{ from: 'jpeg', to: 'webp' },
|
||||
{ from: 'png', to: 'webp' },
|
||||
{ from: 'JPG', to: 'jpeg' },
|
||||
{ from: "jpeg", to: "webp" },
|
||||
{ from: "png", to: "webp" },
|
||||
{ from: "JPG", to: "jpeg" },
|
||||
],
|
||||
}),
|
||||
viteCompression({
|
||||
verbose: true, // 是否在控制台中输出压缩结果
|
||||
disable: false,
|
||||
threshold: 10240, // 如果体积大于阈值,将被压缩,单位为b,体积过小时请不要压缩,以免适得其反
|
||||
algorithm: 'gzip', // 压缩算法,可选['gzip',' brotliccompress ','deflate ','deflateRaw']
|
||||
ext: '.gz',
|
||||
algorithm: "gzip", // 压缩算法,可选['gzip',' brotliccompress ','deflate ','deflateRaw']
|
||||
ext: ".gz",
|
||||
deleteOriginFile: true, // 源文件压缩后是否删除
|
||||
}),
|
||||
createHtmlPlugin({
|
||||
@@ -99,12 +101,12 @@ export default defineConfig(({ mode }) => {
|
||||
* 在这里写entry后,你将不需要在`index.html`内添加 script 标签,原有标签需要删除
|
||||
* @default src/main.ts
|
||||
*/
|
||||
entry: 'src/main.tsx',
|
||||
entry: "src/main.tsx",
|
||||
/**
|
||||
* 如果你想将 `index.html`存放在指定文件夹,可以修改它,否则不需要配置
|
||||
* @default index.html
|
||||
*/
|
||||
template: 'index.html',
|
||||
template: "index.html",
|
||||
/**
|
||||
* 需要注入 index.html ejs 模版的数据
|
||||
*/
|
||||
@@ -117,15 +119,15 @@ export default defineConfig(({ mode }) => {
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve(__dirname, 'src'),
|
||||
"@": resolve(__dirname, "src"),
|
||||
},
|
||||
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'], // 默认值,这些文件引入时不需要写后缀
|
||||
extensions: [".mjs", ".js", ".ts", ".jsx", ".tsx", ".json"], // 默认值,这些文件引入时不需要写后缀
|
||||
},
|
||||
css: {
|
||||
modules: {
|
||||
// 一般我们可以通过 generateScopedName 属性来对生成的类名进行自定义
|
||||
// 其中,name 表示当前文件名,local 表示类名
|
||||
generateScopedName: '[name]__[local]___[hash:base64:5]',
|
||||
generateScopedName: "[name]__[local]___[hash:base64:5]",
|
||||
},
|
||||
postcss: {
|
||||
plugins: [
|
||||
@@ -133,11 +135,11 @@ export default defineConfig(({ mode }) => {
|
||||
autoprefixer({
|
||||
// 自动添加前缀
|
||||
overrideBrowserslist: [
|
||||
'Android 4.1',
|
||||
'iOS 7.1',
|
||||
'Chrome > 31',
|
||||
'ff > 31',
|
||||
'ie >= 8',
|
||||
"Android 4.1",
|
||||
"iOS 7.1",
|
||||
"Chrome > 31",
|
||||
"ff > 31",
|
||||
"ie >= 8",
|
||||
],
|
||||
}),
|
||||
],
|
||||
@@ -152,12 +154,12 @@ export default defineConfig(({ mode }) => {
|
||||
// drop: ['console', 'debugger'],
|
||||
},
|
||||
build: {
|
||||
outDir: 'dist', // 指定输出路径
|
||||
assetsDir: 'assets', // 指定生成静态文件目录
|
||||
assetsInlineLimit: '4096', // 小于此阈值的导入或引用资源将内联为 base64 编码
|
||||
outDir: "dist", // 指定输出路径
|
||||
assetsDir: "assets", // 指定生成静态文件目录
|
||||
assetsInlineLimit: "4096", // 小于此阈值的导入或引用资源将内联为 base64 编码
|
||||
cssCodeSplit: true, // 启用 CSS 代码拆分
|
||||
sourcemap: false, // 构建后是否生成 source map 文件
|
||||
minify: 'esbuild', // 指定使用哪种混淆器
|
||||
minify: "esbuild", // 指定使用哪种混淆器
|
||||
write: true, // 启用将构建后的文件写入磁盘
|
||||
emptyOutDir: true, // 构建时清空该目录
|
||||
brotliSize: true, // 启用 brotli 压缩大小报告
|
||||
@@ -171,9 +173,9 @@ export default defineConfig(({ mode }) => {
|
||||
target: env.VITE_API_BASE_URL,
|
||||
//是否允许跨域
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(RegExp(`^${env.VITE_APP_BASE_API}`), ''),
|
||||
rewrite: (path) => path.replace(RegExp(`^${env.VITE_APP_BASE_API}`), ""),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
};
|
||||
});
|
||||
|