Browse Source

feat: 添加部分库

main
谢亚昕 4 months ago
parent
commit
e1578aeb5a
  1. 4
      package.json
  2. 40
      pnpm-lock.yaml
  3. 26
      src/App.tsx
  4. 5
      src/api/index.ts
  5. 1
      src/index.css
  6. 3
      src/plugins/http/Repeat.ts
  7. 17
      src/plugins/http/index.ts
  8. 4
      src/ui/Hero/index.tsx
  9. 29
      src/ui/Register/Register.tsx
  10. 60
      src/views/Home/index.tsx

4
package.json

@ -18,16 +18,18 @@
"@blueprintjs/table": "^5.2.5",
"@types/lodash": "^4.17.13",
"@types/react-router-dom": "^5.3.3",
"axios": "^1.7.7",
"appwrite": "^16.0.2",
"axios": "^1.7.7",
"framer-motion": "^11.11.17",
"jotai": "^2.10.3",
"lodash": "^4.17.21",
"normalize.css": "^8.0.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.53.2",
"react-markdown": "^9.0.1",
"react-router-dom": "^5.3.4",
"react-toastify": "^10.0.6",
"styled-components": "^6.1.13"
},
"devDependencies": {

40
pnpm-lock.yaml

@ -26,12 +26,12 @@ importers:
'@types/react-router-dom':
specifier: ^5.3.3
version: 5.3.3
axios:
specifier: ^1.7.7
version: 1.7.7
appwrite:
specifier: ^16.0.2
version: 16.0.2
axios:
specifier: ^1.7.7
version: 1.7.7
framer-motion:
specifier: ^11.11.17
version: 11.11.17(@emotion/is-prop-valid@1.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@ -50,12 +50,18 @@ importers:
react-dom:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
react-hook-form:
specifier: ^7.53.2
version: 7.53.2(react@18.3.1)
react-markdown:
specifier: ^9.0.1
version: 9.0.1(@types/react@18.3.12)(react@18.3.1)
react-router-dom:
specifier: ^5.3.4
version: 5.3.4(react@18.3.1)
react-toastify:
specifier: ^10.0.6
version: 10.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
styled-components:
specifier: ^6
version: 6.1.13(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@ -733,6 +739,10 @@ packages:
classnames@2.5.1:
resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
clsx@2.1.1:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'}
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
@ -1295,6 +1305,12 @@ packages:
react-fast-compare@3.2.2:
resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==}
react-hook-form@7.53.2:
resolution: {integrity: sha512-YVel6fW5sOeedd1524pltpHX+jgU2u3DSDtXEaBORNdqiNrsX/nUI/iGXONegttg0mJVnfrIkiV0cmTU6Oo2xw==}
engines: {node: '>=18.0.0'}
peerDependencies:
react: ^16.8.0 || ^17 || ^18 || ^19
react-innertext@1.1.5:
resolution: {integrity: sha512-PWAqdqhxhHIv80dT9znP2KvS+hfkbRovFp4zFYHFFlOoQLRiawIic81gKb3U1wEyJZgMwgs3JoLtwryASRWP3Q==}
peerDependencies:
@ -1327,6 +1343,12 @@ packages:
peerDependencies:
react: '>=15'
react-toastify@10.0.6:
resolution: {integrity: sha512-yYjp+omCDf9lhZcrZHKbSq7YMuK0zcYkDFTzfRFgTXkTFHZ1ToxwAonzA4JI5CxA91JpjFLmwEsZEgfYfOqI1A==}
peerDependencies:
react: '>=18'
react-dom: '>=18'
react-transition-group@4.4.5:
resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
peerDependencies:
@ -2111,6 +2133,8 @@ snapshots:
classnames@2.5.1: {}
clsx@2.1.1: {}
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
@ -2833,6 +2857,10 @@ snapshots:
react-fast-compare@3.2.2: {}
react-hook-form@7.53.2(react@18.3.1):
dependencies:
react: 18.3.1
react-innertext@1.1.5(@types/react@18.3.12)(react@18.3.1):
dependencies:
'@types/react': 18.3.12
@ -2889,6 +2917,12 @@ snapshots:
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
react-toastify@10.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
clsx: 2.1.1
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
react-transition-group@4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@babel/runtime': 7.26.0

26
src/App.tsx

@ -1,5 +1,29 @@
import AppRouter from "@/router/AppRouter"
import { ToastContainer, Bounce } from 'react-toastify';
export default function App() {
return <AppRouter></AppRouter>
return <>
<AppRouter></AppRouter>
<ToastContainer
position="bottom-right"
autoClose={5000}
hideProgressBar
closeOnClick={false}
pauseOnFocusLoss
pauseOnHover
theme="light"
transition={Bounce}
/>
{/* <ToastContainer
stacked
position="bottom-right"
autoClose={5000}
hideProgressBar
closeOnClick={false}
pauseOnFocusLoss
pauseOnHover
theme="light"
transition={Bounce}
/> */}
</>
}

5
src/api/index.ts

@ -1,6 +1,5 @@
import { Toast } from "@/utils/toast"
import { Account, Client, ID } from "appwrite"
import { toast } from "react-toastify"
const client = new Client()
client.setProject(import.meta.env.VUE_APPWRITE_PROJECT_ID)
@ -10,7 +9,7 @@ export async function register(opts: { email: string; password: string }, errTex
try {
await account.create(ID.unique(), opts.email, opts.password)
} catch (error: any) {
Toast.error(error?.message ?? errText)
toast.error(error?.message ?? errText)
return Promise.reject(error)
}
}

1
src/index.css

@ -1,4 +1,5 @@
@import "normalize.css";
@import 'react-toastify/dist/ReactToastify.css';
@import "@blueprintjs/core/lib/css/blueprint.css";
@import "@blueprintjs/icons/lib/css/blueprint-icons.css";
@import "@blueprintjs/table/lib/css/table.css";

3
src/plugins/http/Repeat.ts

@ -3,6 +3,9 @@ import { IPlugin } from "./base"
declare module "axios" {
interface AxiosRequestConfig {
/**
* RepeatPlugin插件的clearPendingPool清除
*/
global?: boolean
}
}

17
src/plugins/http/index.ts

@ -57,11 +57,20 @@ class Fly extends httpBase {
super()
this.name = name
}
get(...argus: [url: string, config?: AxiosRequestConfig<unknown> | undefined]) {
return this.instance!.get.apply(this.instance, argus ?? []) as Promise<AxiosResponse>
get<T = any, Data = unknown>(...argus: [url: string, config?: AxiosRequestConfig<Data> | undefined]) {
return this.instance!.get.apply(this.instance, argus ?? []) as Promise<AxiosResponse<T>>
}
request(...argus: [config: AxiosRequestConfig<unknown>]): Promise<AxiosResponse> {
return this.instance!.request.apply(this.instance, argus) as Promise<AxiosResponse>
post<T = any, Data = unknown>(...argus: [url: string, config?: AxiosRequestConfig<Data> | undefined]) {
return this.instance!.post.apply(this.instance, argus ?? []) as Promise<AxiosResponse<T>>
}
put<T = any, Data = unknown>(...argus: [url: string, config?: AxiosRequestConfig<Data> | undefined]) {
return this.instance!.put.apply(this.instance, argus ?? []) as Promise<AxiosResponse<T>>
}
delete<T = any, Data = unknown>(...argus: [url: string, config?: AxiosRequestConfig<Data> | undefined]) {
return this.instance!.delete.apply(this.instance, argus ?? []) as Promise<AxiosResponse<T>>
}
request<T = any, Data = unknown>(...argus: [config: AxiosRequestConfig<Data>]) {
return this.instance!.request.apply(this.instance, argus) as Promise<AxiosResponse<T>>
}
#init(config: AxiosRequestConfig) {
this.callPlugin("beforeCreate")

4
src/ui/Hero/index.tsx

@ -40,10 +40,10 @@ export function Hero() {
return (
<FigureElement>
<OpacityIn className="img-wrapper">
<img
{/* <img
src="https://api.r10086.com/%E5%9B%BE%E5%8C%85webp/%E5%8A%A8%E6%BC%AB%E7%BB%BC%E5%90%882/48cf0b92dd80ccdd4898e6b4734105fc.png!q90.webp"
alt="月宫"
/>
/> */}
</OpacityIn>
<div className="mask"></div>
<figcaption></figcaption>

29
src/ui/Register/Register.tsx

@ -1,9 +1,9 @@
// import { Tag } from "@blueprintjs/core";
import { register } from "@/api"
import { Toast } from "@/utils/toast"
import { Button, FormGroup, InputGroup, Intent, Tooltip } from "@blueprintjs/core"
import { FC, ReactNode, useCallback, useEffect, useState } from "react"
import { FC, ReactNode, useCallback, useEffect, useRef, useState } from "react"
import { toast } from "react-toastify"
interface IProps {
onSuccess?: () => void
@ -22,29 +22,30 @@ export function Register({ onSuccess, children }: IProps) {
const clickRegister = useCallback(async () => {
if (isLoading) {
Toast.success("正在请求中")
toast.info("正在请求中")
return
}
if (!email) return Toast.error("请输入邮箱")
if (!password) return Toast.error("请输入密码")
if (!repeatPassword) return Toast.error("请再一次输入密码")
if (repeatPassword !== password) return Toast.error("两次输入的密码不一致")
let toastID = Toast.loading("注册中")
if (!email) return toast.error("请输入邮箱")
if (!password) return toast.error("请输入密码")
if (!repeatPassword) return toast.error("请再一次输入密码")
if (repeatPassword !== password) return toast.error("两次输入的密码不一致")
setIsLoading(true)
try {
await register({ email, password }, "注册失败")
Toast.success("注册成功")
await toast.promise(register({ email, password }, "注册失败"), {
pending: '注册中',
success: '注册成功',
error: '注册失败'
})
onSuccess && onSuccess()
} catch (error) {
console.error(error)
} finally {
Toast.loadingDismiss(toastID)
setIsLoading(false)
}
}, [password, email, repeatPassword, isLoading])
useEffect(()=>{
return ()=>{
useEffect(() => {
return () => {
console.log("取消请求");
}
}, [])
@ -60,7 +61,7 @@ export function Register({ onSuccess, children }: IProps) {
return (
<>
<form onSubmit={()=>false} onSubmitCapture={clickRegister}>
<form onSubmit={() => false} onSubmitCapture={clickRegister}>
<WrapperComp>
<FormGroup helperText="请输入一个可用的邮箱" label="邮箱" labelFor="text-input" labelInfo="(必须)">
<InputGroup

60
src/views/Home/index.tsx

@ -3,28 +3,58 @@ import { Hero } from "@/ui/Hero"
import { Button } from "@blueprintjs/core"
import { ReactNode, useCallback } from "react"
import { Fly } from "@/plugins/request"
import { toast } from "react-toastify"
import { useForm, SubmitHandler } from "react-hook-form";
interface IProps {
children: ReactNode
}
type Inputs = {
example: string,
exampleRequired: string,
};
// export default withPage(function Project({ }: IProps) {
// const onClick = useCallback(() => {
// toast.success("Wow so easy !")
// // Fly.invoke().request<{a: number}>({
// // method: "get",
// // url: "http://api.juheapi.com/japi/toh",
// // global: false
// // }).then((res) => console.log(res.data)).catch(console.log)
// }, [])
// return (
// <>
// <Hero></Hero>
// <div className="container">
// <Button onClick={onClick}>请求</Button>
// </div>
// </>
// )
// })
export default withPage(function Project({ }: IProps) {
const { register, handleSubmit, watch, formState: { errors } } = useForm<Inputs>();
const onSubmit: SubmitHandler<Inputs> = data => console.log(data);
const onClick = useCallback(() => {
Fly.invoke().request({
method: "get",
url: "https://api.52vmy.cn/api/wl/word/bing/tu",
global: false
}).then((res) => console.log(res.data)).catch(console.log)
}, [])
console.log(watch("example")) // watch input value by passing the name of it
return (
<>
<Hero></Hero>
<div className="container">
<Button onClick={onClick}></Button>
</div>
</>
)
/* "handleSubmit" will validate your inputs before invoking "onSubmit" */
<form onSubmit={handleSubmit(onSubmit)}>
{/* register your input into the hook by invoking the "register" function */}
<input defaultValue="test" {...register("example")} />
{/* include validation with required or other standard HTML validation rules */}
<input {...register("exampleRequired", { required: true })} />
{/* errors will return when field validation fails */}
{errors.exampleRequired && <span>This field is required</span>}
<input type="submit" />
</form>
);
})

Loading…
Cancel
Save