Browse Source

feat: 添加部分库

main
谢亚昕 5 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", "@blueprintjs/table": "^5.2.5",
"@types/lodash": "^4.17.13", "@types/lodash": "^4.17.13",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
"axios": "^1.7.7",
"appwrite": "^16.0.2", "appwrite": "^16.0.2",
"axios": "^1.7.7",
"framer-motion": "^11.11.17", "framer-motion": "^11.11.17",
"jotai": "^2.10.3", "jotai": "^2.10.3",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-hook-form": "^7.53.2",
"react-markdown": "^9.0.1", "react-markdown": "^9.0.1",
"react-router-dom": "^5.3.4", "react-router-dom": "^5.3.4",
"react-toastify": "^10.0.6",
"styled-components": "^6.1.13" "styled-components": "^6.1.13"
}, },
"devDependencies": { "devDependencies": {

40
pnpm-lock.yaml

@ -26,12 +26,12 @@ importers:
'@types/react-router-dom': '@types/react-router-dom':
specifier: ^5.3.3 specifier: ^5.3.3
version: 5.3.3 version: 5.3.3
axios:
specifier: ^1.7.7
version: 1.7.7
appwrite: appwrite:
specifier: ^16.0.2 specifier: ^16.0.2
version: 16.0.2 version: 16.0.2
axios:
specifier: ^1.7.7
version: 1.7.7
framer-motion: framer-motion:
specifier: ^11.11.17 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) 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: react-dom:
specifier: ^18.3.1 specifier: ^18.3.1
version: 18.3.1(react@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: react-markdown:
specifier: ^9.0.1 specifier: ^9.0.1
version: 9.0.1(@types/react@18.3.12)(react@18.3.1) version: 9.0.1(@types/react@18.3.12)(react@18.3.1)
react-router-dom: react-router-dom:
specifier: ^5.3.4 specifier: ^5.3.4
version: 5.3.4(react@18.3.1) 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: styled-components:
specifier: ^6 specifier: ^6
version: 6.1.13(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 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: classnames@2.5.1:
resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} 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: color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'} engines: {node: '>=7.0.0'}
@ -1295,6 +1305,12 @@ packages:
react-fast-compare@3.2.2: react-fast-compare@3.2.2:
resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} 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: react-innertext@1.1.5:
resolution: {integrity: sha512-PWAqdqhxhHIv80dT9znP2KvS+hfkbRovFp4zFYHFFlOoQLRiawIic81gKb3U1wEyJZgMwgs3JoLtwryASRWP3Q==} resolution: {integrity: sha512-PWAqdqhxhHIv80dT9znP2KvS+hfkbRovFp4zFYHFFlOoQLRiawIic81gKb3U1wEyJZgMwgs3JoLtwryASRWP3Q==}
peerDependencies: peerDependencies:
@ -1327,6 +1343,12 @@ packages:
peerDependencies: peerDependencies:
react: '>=15' react: '>=15'
react-toastify@10.0.6:
resolution: {integrity: sha512-yYjp+omCDf9lhZcrZHKbSq7YMuK0zcYkDFTzfRFgTXkTFHZ1ToxwAonzA4JI5CxA91JpjFLmwEsZEgfYfOqI1A==}
peerDependencies:
react: '>=18'
react-dom: '>=18'
react-transition-group@4.4.5: react-transition-group@4.4.5:
resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
peerDependencies: peerDependencies:
@ -2111,6 +2133,8 @@ snapshots:
classnames@2.5.1: {} classnames@2.5.1: {}
clsx@2.1.1: {}
color-convert@2.0.1: color-convert@2.0.1:
dependencies: dependencies:
color-name: 1.1.4 color-name: 1.1.4
@ -2833,6 +2857,10 @@ snapshots:
react-fast-compare@3.2.2: {} 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): react-innertext@1.1.5(@types/react@18.3.12)(react@18.3.1):
dependencies: dependencies:
'@types/react': 18.3.12 '@types/react': 18.3.12
@ -2889,6 +2917,12 @@ snapshots:
tiny-invariant: 1.3.3 tiny-invariant: 1.3.3
tiny-warning: 1.0.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): react-transition-group@4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies: dependencies:
'@babel/runtime': 7.26.0 '@babel/runtime': 7.26.0

26
src/App.tsx

@ -1,5 +1,29 @@
import AppRouter from "@/router/AppRouter" import AppRouter from "@/router/AppRouter"
import { ToastContainer, Bounce } from 'react-toastify';
export default function App() { 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 { Account, Client, ID } from "appwrite"
import { toast } from "react-toastify"
const client = new Client() const client = new Client()
client.setProject(import.meta.env.VUE_APPWRITE_PROJECT_ID) client.setProject(import.meta.env.VUE_APPWRITE_PROJECT_ID)
@ -10,7 +9,7 @@ export async function register(opts: { email: string; password: string }, errTex
try { try {
await account.create(ID.unique(), opts.email, opts.password) await account.create(ID.unique(), opts.email, opts.password)
} catch (error: any) { } catch (error: any) {
Toast.error(error?.message ?? errText) toast.error(error?.message ?? errText)
return Promise.reject(error) return Promise.reject(error)
} }
} }

1
src/index.css

@ -1,4 +1,5 @@
@import "normalize.css"; @import "normalize.css";
@import 'react-toastify/dist/ReactToastify.css';
@import "@blueprintjs/core/lib/css/blueprint.css"; @import "@blueprintjs/core/lib/css/blueprint.css";
@import "@blueprintjs/icons/lib/css/blueprint-icons.css"; @import "@blueprintjs/icons/lib/css/blueprint-icons.css";
@import "@blueprintjs/table/lib/css/table.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" { declare module "axios" {
interface AxiosRequestConfig { interface AxiosRequestConfig {
/**
* RepeatPlugin插件的clearPendingPool清除
*/
global?: boolean global?: boolean
} }
} }

17
src/plugins/http/index.ts

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

4
src/ui/Hero/index.tsx

@ -40,10 +40,10 @@ export function Hero() {
return ( return (
<FigureElement> <FigureElement>
<OpacityIn className="img-wrapper"> <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" 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="月宫" alt="月宫"
/> /> */}
</OpacityIn> </OpacityIn>
<div className="mask"></div> <div className="mask"></div>
<figcaption></figcaption> <figcaption></figcaption>

29
src/ui/Register/Register.tsx

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

60
src/views/Home/index.tsx

@ -3,28 +3,58 @@ import { Hero } from "@/ui/Hero"
import { Button } from "@blueprintjs/core" import { Button } from "@blueprintjs/core"
import { ReactNode, useCallback } from "react" import { ReactNode, useCallback } from "react"
import { Fly } from "@/plugins/request" import { Fly } from "@/plugins/request"
import { toast } from "react-toastify"
import { useForm, SubmitHandler } from "react-hook-form";
interface IProps { interface IProps {
children: ReactNode 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) { 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(() => { console.log(watch("example")) // watch input value by passing the name of it
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)
}, [])
return ( return (
<> /* "handleSubmit" will validate your inputs before invoking "onSubmit" */
<Hero></Hero> <form onSubmit={handleSubmit(onSubmit)}>
{/* register your input into the hook by invoking the "register" function */}
<div className="container"> <input defaultValue="test" {...register("example")} />
<Button onClick={onClick}></Button>
</div> {/* 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