YuJian920
3 years ago
9 changed files with 261 additions and 45 deletions
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
import React from "react"; |
||||
import { Button, Drawer } from "antd"; |
||||
|
||||
const ProjectModal = (props: { |
||||
projectModalOpen: boolean; |
||||
onClose: () => void; |
||||
}) => { |
||||
return ( |
||||
<Drawer |
||||
onClose={props.onClose} |
||||
visible={props.projectModalOpen} |
||||
width="100%" |
||||
> |
||||
<h1>Project Modal</h1> |
||||
<Button onClick={props.onClose}>关闭</Button> |
||||
</Drawer> |
||||
); |
||||
}; |
||||
|
||||
export default React.memo(ProjectModal); |
@ -0,0 +1,38 @@
@@ -0,0 +1,38 @@
|
||||
import React from "react"; |
||||
import { Button, Divider, List, Popover, Typography } from "antd"; |
||||
import { useProjects } from "../hook/useProjects"; |
||||
import styled from "@emotion/styled"; |
||||
|
||||
const ProjectPopover = () => { |
||||
const { data: projects, isLoading } = useProjects(); |
||||
const pinnedProjects = projects?.filter((projects) => projects.pin); |
||||
|
||||
const content = ( |
||||
<ContentContainer> |
||||
<Typography.Text type="secondary">收藏项目</Typography.Text> |
||||
<List> |
||||
{pinnedProjects?.map((project) => ( |
||||
<List.Item key={project.id}> |
||||
<List.Item.Meta title={project.name} /> |
||||
</List.Item> |
||||
))} |
||||
</List> |
||||
<Divider /> |
||||
<Button style={{ padding: 0 }} type="link"> |
||||
创建项目 |
||||
</Button> |
||||
</ContentContainer> |
||||
); |
||||
|
||||
return ( |
||||
<Popover placement="bottom" content={content}> |
||||
<span>项目</span> |
||||
</Popover> |
||||
); |
||||
}; |
||||
|
||||
const ContentContainer = styled.div` |
||||
min-width: 30rem; |
||||
`;
|
||||
|
||||
export default React.memo(ProjectPopover); |
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
import { useEffect, useRef } from "react"; |
||||
|
||||
const useMountedRef = () => { |
||||
const mountedRef = useRef(false); |
||||
|
||||
useEffect(() => { |
||||
mountedRef.current = true; |
||||
return () => { |
||||
mountedRef.current = false; |
||||
}; |
||||
}, []); |
||||
|
||||
return mountedRef; |
||||
}; |
||||
|
||||
export default useMountedRef; |
@ -1,9 +1,14 @@
@@ -1,9 +1,14 @@
|
||||
import { useCallback } from "react"; |
||||
import { useAuth } from "../context/auth-context"; |
||||
import { request } from "../utils/request"; |
||||
|
||||
const useRequest = () => { |
||||
const { user } = useAuth(); |
||||
return (...[endpoint, config]: Parameters<typeof request>) => request(endpoint, { ...config, token: user?.token }); |
||||
return useCallback( |
||||
(...[endpoint, config]: Parameters<typeof request>) => |
||||
request(endpoint, { ...config, token: user?.token }), |
||||
[user?.token] |
||||
); |
||||
}; |
||||
|
||||
export default useRequest; |
||||
|
@ -0,0 +1,88 @@
@@ -0,0 +1,88 @@
|
||||
import { useCallback, useReducer, useState } from "react"; |
||||
|
||||
type State<T> = { |
||||
past: T[]; |
||||
present: T; |
||||
future: T[]; |
||||
}; |
||||
|
||||
type Action<T> = { |
||||
newPresent?: T; |
||||
type: typeof UNDO | typeof REDO | typeof SET | typeof RESET; |
||||
}; |
||||
|
||||
const UNDO = "UNDO"; |
||||
const REDO = "REDO"; |
||||
const SET = "SET"; |
||||
const RESET = "RESET"; |
||||
|
||||
const undoReducer = <T>(state: State<T>, action: Action<T>) => { |
||||
const { past, present, future } = state; |
||||
const { newPresent, type } = action; |
||||
|
||||
switch (type) { |
||||
case UNDO: { |
||||
if (past.length === 0) return state; |
||||
|
||||
const previous = past[past.length - 1]; |
||||
const newPast = past.slice(0, past.length - 1); |
||||
|
||||
return { |
||||
past: newPast, |
||||
present: previous, |
||||
future: [present, ...future], |
||||
}; |
||||
} |
||||
|
||||
case REDO: { |
||||
if (future.length !== 0) return state; |
||||
|
||||
const previous = future[0]; |
||||
const newPast = future.slice(1); |
||||
|
||||
return { |
||||
past: [...past, previous], |
||||
present: previous, |
||||
future: newPast, |
||||
}; |
||||
} |
||||
|
||||
case SET: { |
||||
if (newPresent === present) return state; |
||||
|
||||
return { |
||||
past: [...past, newPresent], |
||||
present: newPresent, |
||||
future: [], |
||||
}; |
||||
} |
||||
|
||||
case RESET: { |
||||
return { |
||||
past: [], |
||||
present: newPresent, |
||||
future: [], |
||||
}; |
||||
} |
||||
} |
||||
}; |
||||
|
||||
const useUndo = <T>(initialPresent: T) => { |
||||
const [state, dispatch] = useReducer(undoReducer, { |
||||
past: [], |
||||
present: initialPresent, |
||||
future: [], |
||||
} as State<T>); |
||||
|
||||
const canUndo = state.past.length !== 0; |
||||
const canRedo = state.future.length !== 0; |
||||
|
||||
const undo = useCallback(() => dispatch({ type: UNDO }), []); |
||||
const redo = useCallback(() => dispatch({ type: REDO }), []); |
||||
const set = useCallback((newPresent: T) => dispatch({ type: SET, newPresent }), []); |
||||
const reset = useCallback((newPresent: T) => dispatch({ type: RESET, newPresent }), []); |
||||
|
||||
return [state, { set, reset, undo, redo, canUndo, canRedo }] as const; |
||||
}; |
||||
|
||||
export default useUndo; |
Loading…
Reference in new issue