client: mine page fixes, remove lodash.debounce
This commit is contained in:
parent
1369bdf996
commit
fe589d63d8
11 changed files with 100 additions and 103 deletions
|
@ -10,49 +10,43 @@ import { TextareaMarkdownRef } from "textarea-markdown-editor"
|
|||
// TODO: clean up
|
||||
|
||||
const FormattingIcons = ({
|
||||
textareaRef,
|
||||
textareaRef
|
||||
}: {
|
||||
textareaRef?: RefObject<TextareaMarkdownRef>
|
||||
}) => {
|
||||
|
||||
|
||||
|
||||
const formattingActions = useMemo(
|
||||
() => {
|
||||
const handleBoldClick = () => textareaRef?.current?.trigger("bold")
|
||||
const handleItalicClick = () => textareaRef?.current?.trigger("italic")
|
||||
const handleLinkClick = () => textareaRef?.current?.trigger("link")
|
||||
const handleImageClick = () => textareaRef?.current?.trigger("image")
|
||||
return [
|
||||
{
|
||||
icon: <Bold />,
|
||||
name: "bold",
|
||||
action: handleBoldClick
|
||||
},
|
||||
{
|
||||
icon: <Italic />,
|
||||
name: "italic",
|
||||
action: handleItalicClick
|
||||
},
|
||||
// {
|
||||
// icon: <Underline />,
|
||||
// name: 'underline',
|
||||
// action: handleUnderlineClick
|
||||
// },
|
||||
{
|
||||
icon: <Link />,
|
||||
name: "hyperlink",
|
||||
action: handleLinkClick
|
||||
},
|
||||
{
|
||||
icon: <ImageIcon />,
|
||||
name: "image",
|
||||
action: handleImageClick
|
||||
}
|
||||
]
|
||||
},
|
||||
[textareaRef]
|
||||
)
|
||||
const formattingActions = useMemo(() => {
|
||||
const handleBoldClick = () => textareaRef?.current?.trigger("bold")
|
||||
const handleItalicClick = () => textareaRef?.current?.trigger("italic")
|
||||
const handleLinkClick = () => textareaRef?.current?.trigger("link")
|
||||
const handleImageClick = () => textareaRef?.current?.trigger("image")
|
||||
return [
|
||||
{
|
||||
icon: <Bold />,
|
||||
name: "bold",
|
||||
action: handleBoldClick
|
||||
},
|
||||
{
|
||||
icon: <Italic />,
|
||||
name: "italic",
|
||||
action: handleItalicClick
|
||||
},
|
||||
// {
|
||||
// icon: <Underline />,
|
||||
// name: 'underline',
|
||||
// action: handleUnderlineClick
|
||||
// },
|
||||
{
|
||||
icon: <Link />,
|
||||
name: "hyperlink",
|
||||
action: handleLinkClick
|
||||
},
|
||||
{
|
||||
icon: <ImageIcon />,
|
||||
name: "image",
|
||||
action: handleImageClick
|
||||
}
|
||||
]
|
||||
}, [textareaRef])
|
||||
|
||||
return (
|
||||
<div className={styles.actionWrapper}>
|
||||
|
|
|
@ -9,15 +9,9 @@ import {
|
|||
import styles from "./document.module.css"
|
||||
import Trash from "@geist-ui/icons/trash"
|
||||
import FormattingIcons from "./formatting-icons"
|
||||
import TextareaMarkdown, { TextareaMarkdownRef } from "textarea-markdown-editor";
|
||||
import TextareaMarkdown, { TextareaMarkdownRef } from "textarea-markdown-editor"
|
||||
|
||||
import {
|
||||
Button,
|
||||
Input,
|
||||
Spacer,
|
||||
Tabs,
|
||||
Textarea,
|
||||
} from "@geist-ui/core"
|
||||
import { Button, Input, Spacer, Tabs, Textarea } from "@geist-ui/core"
|
||||
import Preview from "@components/preview"
|
||||
|
||||
// import Link from "next/link"
|
||||
|
@ -121,9 +115,7 @@ const Document = ({
|
|||
)}
|
||||
</div>
|
||||
<div className={styles.descriptionContainer}>
|
||||
{tab === "edit" && (
|
||||
<FormattingIcons textareaRef={codeEditorRef} />
|
||||
)}
|
||||
{tab === "edit" && <FormattingIcons textareaRef={codeEditorRef} />}
|
||||
<Tabs
|
||||
onChange={handleTabChange}
|
||||
initialValue={initialTab}
|
||||
|
|
|
@ -46,7 +46,7 @@ const FileDropdown = ({
|
|||
setItems(newItems)
|
||||
}, [files])
|
||||
|
||||
const content =
|
||||
const content = (
|
||||
<ul className={styles.content}>
|
||||
{items.map((item) => (
|
||||
<li key={item.id} onClick={onClose}>
|
||||
|
@ -61,6 +61,7 @@ const FileDropdown = ({
|
|||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
|
||||
// a list of files with an icon and a title
|
||||
return (
|
||||
|
|
|
@ -65,7 +65,6 @@ const Post = ({
|
|||
}
|
||||
}, [emptyDoc, initialPost])
|
||||
|
||||
|
||||
const [passwordModalVisible, setPasswordModalVisible] = useState(false)
|
||||
|
||||
const sendRequest = useCallback(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Button, Code, Dot, Input, Note, Text } from "@geist-ui/core"
|
||||
import { Button, Input, Select, Text } from "@geist-ui/core"
|
||||
import NextLink from "next/link"
|
||||
import Link from "../Link"
|
||||
|
||||
|
@ -7,8 +7,8 @@ import ListItemSkeleton from "./list-item-skeleton"
|
|||
import ListItem from "./list-item"
|
||||
import { Post } from "@lib/types"
|
||||
import { ChangeEvent, useCallback, useEffect, useMemo, useState } from "react"
|
||||
import debounce from "lodash.debounce"
|
||||
import Cookies from "js-cookie"
|
||||
import useDebounce from "@lib/hooks/use-debounce"
|
||||
|
||||
type Props = {
|
||||
initialPosts: Post[]
|
||||
|
@ -21,6 +21,9 @@ const PostList = ({ morePosts, initialPosts, error }: Props) => {
|
|||
const [posts, setPosts] = useState<Post[]>(initialPosts)
|
||||
const [searching, setSearching] = useState(false)
|
||||
const [hasMorePosts, setHasMorePosts] = useState(morePosts)
|
||||
|
||||
const debouncedSearchValue = useDebounce(search, 200)
|
||||
|
||||
const loadMoreClick = useCallback(
|
||||
(e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.preventDefault()
|
||||
|
@ -46,13 +49,15 @@ const PostList = ({ morePosts, initialPosts, error }: Props) => {
|
|||
|
||||
// update posts on search
|
||||
useEffect(() => {
|
||||
if (search) {
|
||||
if (debouncedSearchValue) {
|
||||
// fetch results from /server-api/posts/search
|
||||
const fetchResults = async () => {
|
||||
setSearching(true)
|
||||
//encode search
|
||||
const res = await fetch(
|
||||
`/server-api/posts/search?q=${encodeURIComponent(search)}`,
|
||||
`/server-api/posts/search?q=${encodeURIComponent(
|
||||
debouncedSearchValue
|
||||
)}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
|
@ -70,22 +75,22 @@ const PostList = ({ morePosts, initialPosts, error }: Props) => {
|
|||
} else {
|
||||
setPosts(initialPosts)
|
||||
}
|
||||
}, [initialPosts, search])
|
||||
}, [initialPosts, debouncedSearchValue])
|
||||
|
||||
const handleSearchChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setSearchValue(e.target.value)
|
||||
}
|
||||
|
||||
const debouncedSearchHandler = useMemo(
|
||||
() => debounce(handleSearchChange, 300),
|
||||
[]
|
||||
)
|
||||
// const debouncedSearchHandler = useMemo(
|
||||
// () => debounce(handleSearchChange, 300),
|
||||
// []
|
||||
// )
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
debouncedSearchHandler.cancel()
|
||||
}
|
||||
}, [debouncedSearchHandler])
|
||||
// useEffect(() => {
|
||||
// return () => {
|
||||
// debouncedSearchHandler.cancel()
|
||||
// }
|
||||
// }, [debouncedSearchHandler])
|
||||
|
||||
const deletePost = useCallback(
|
||||
(postId: string) => async () => {
|
||||
|
@ -114,7 +119,7 @@ const PostList = ({ morePosts, initialPosts, error }: Props) => {
|
|||
scale={3 / 2}
|
||||
clearable
|
||||
placeholder="Search..."
|
||||
onChange={debouncedSearchHandler}
|
||||
onChange={handleSearchChange}
|
||||
/>
|
||||
</div>
|
||||
{error && <Text type="error">Failed to load.</Text>}
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
.searchContainer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column-reverse;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
margin-bottom: var(--gap-double);
|
||||
gap: var(--gap-half);
|
||||
margin-bottom: var(--gap);
|
||||
}
|
||||
|
|
|
@ -1,29 +1,35 @@
|
|||
const replaceLastInString = (
|
||||
string: string,
|
||||
search: string,
|
||||
replace: string
|
||||
string: string,
|
||||
search: string,
|
||||
replace: string
|
||||
): string => {
|
||||
const index = string.lastIndexOf(search);
|
||||
if (index === -1) {
|
||||
return string;
|
||||
}
|
||||
return string.substring(0, index) + replace + string.substring(index + search.length);
|
||||
const index = string.lastIndexOf(search)
|
||||
if (index === -1) {
|
||||
return string
|
||||
}
|
||||
return (
|
||||
string.substring(0, index) +
|
||||
replace +
|
||||
string.substring(index + search.length)
|
||||
)
|
||||
}
|
||||
|
||||
const getTitleForPostCopy = (
|
||||
title: string,
|
||||
) => {
|
||||
const numberAtEndOfTitle = title.split(" ").pop()
|
||||
if (numberAtEndOfTitle) {
|
||||
const number = parseInt(numberAtEndOfTitle)
|
||||
if (number) {
|
||||
return replaceLastInString(title, numberAtEndOfTitle, (number + 1).toString())
|
||||
} else {
|
||||
return title + " 1"
|
||||
}
|
||||
} else {
|
||||
return title + " 1"
|
||||
}
|
||||
const getTitleForPostCopy = (title: string) => {
|
||||
const numberAtEndOfTitle = title.split(" ").pop()
|
||||
if (numberAtEndOfTitle) {
|
||||
const number = parseInt(numberAtEndOfTitle)
|
||||
if (number) {
|
||||
return replaceLastInString(
|
||||
title,
|
||||
numberAtEndOfTitle,
|
||||
(number + 1).toString()
|
||||
)
|
||||
} else {
|
||||
return title + " 1"
|
||||
}
|
||||
} else {
|
||||
return title + " 1"
|
||||
}
|
||||
}
|
||||
|
||||
export default getTitleForPostCopy
|
||||
export default getTitleForPostCopy
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// useDebounce.js
|
||||
import { useState, useEffect } from "react"
|
||||
|
||||
export default function useDebounce(value: any, delay: number) {
|
||||
export default function useDebounce<T>(value: T, delay: number) {
|
||||
const [debouncedValue, setDebouncedValue] = useState(value)
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
"cookie": "^0.4.2",
|
||||
"dotenv": "^16.0.0",
|
||||
"js-cookie": "^3.0.1",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"marked": "^4.0.12",
|
||||
"next": "^12.1.1-canary.15",
|
||||
"next-themes": "^0.1.1",
|
||||
|
|
|
@ -2310,11 +2310,6 @@ lodash.camelcase@^4.3.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
|
||||
integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
|
||||
|
||||
lodash.debounce@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
|
||||
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
|
||||
|
||||
lodash.merge@^4.6.2:
|
||||
version "4.6.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
|
||||
|
|
|
@ -42,7 +42,7 @@ posts.post(
|
|||
parentId: Joi.string().optional().allow(null, "")
|
||||
}
|
||||
}),
|
||||
async (req, res, next) => {
|
||||
async (req, res) => {
|
||||
try {
|
||||
// check if all files have titles
|
||||
const files = req.body.files as File[]
|
||||
|
@ -218,7 +218,13 @@ posts.get(
|
|||
},
|
||||
{
|
||||
model: User,
|
||||
as: "users"
|
||||
as: "users",
|
||||
attributes: ["id", "username"]
|
||||
},
|
||||
{
|
||||
model: Post,
|
||||
as: "parent",
|
||||
attributes: ["id", "title", "visibility"]
|
||||
}
|
||||
],
|
||||
attributes: ["id", "title", "visibility", "createdAt", "deletedAt"],
|
||||
|
|
Loading…
Reference in a new issue