use custom input/buttons on postlist/new page
This commit is contained in:
parent
dfe0d39fa0
commit
45c2e59105
16 changed files with 99 additions and 74 deletions
|
@ -5,7 +5,7 @@ import { Note, Text } from "@geist-ui/core/dist"
|
|||
export default function ExpiredPage() {
|
||||
return (
|
||||
<Note type="error" label={false}>
|
||||
<Text h4>Error: The Drift you're trying to view has expired.</Text>
|
||||
<h2>Error: The Drift you're trying to view has expired.</h2>
|
||||
</Note>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Text, useMediaQuery, useTheme, useToasts } from "@geist-ui/core/dist"
|
||||
import { useMediaQuery, useTheme, useToasts } from "@geist-ui/core/dist"
|
||||
import { useDropzone } from "react-dropzone"
|
||||
import styles from "./drag-and-drop.module.css"
|
||||
import generateUUID from "@lib/generate-uuid"
|
||||
|
@ -79,7 +79,7 @@ function FileDropzone({ setDocs }: { setDocs: (docs: Document[]) => void }) {
|
|||
<ul>
|
||||
{errors.map((e) => (
|
||||
<li key={e.code}>
|
||||
<Text>{e.message}</Text>
|
||||
{e.message}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
@ -100,12 +100,12 @@ function FileDropzone({ setDocs }: { setDocs: (docs: Document[]) => void }) {
|
|||
{!isDragActive && (
|
||||
<p style={{color: "var(--gray)"}}>Drag some files here, or {verb} to select files</p>
|
||||
)}
|
||||
{isDragActive && <Text p>Release to drop the files here</Text>}
|
||||
{isDragActive && <p>Release to drop the files here</p>}
|
||||
</div>
|
||||
{fileRejections.length > 0 && (
|
||||
<ul className={styles.error}>
|
||||
{/* <Button style={{ float: 'right' }} type="abort" onClick={() => fileRejections.splice(0, fileRejections.length)} auto iconRight={<XCircle />}></Button> */}
|
||||
<Text h5>There was a problem with one or more of your files.</Text>
|
||||
<p>There was a problem with one or more of your files.</p>
|
||||
{fileRejectionItems}
|
||||
</ul>
|
||||
)}
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
.actionWrapper .actions {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
|
|
|
@ -7,9 +7,10 @@ import List from "@geist-ui/icons/list"
|
|||
import ImageIcon from "@geist-ui/icons/image"
|
||||
import { RefObject, useMemo } from "react"
|
||||
import styles from "../document.module.css"
|
||||
import { Button, ButtonGroup } from "@geist-ui/core/dist"
|
||||
import { TextareaMarkdownRef } from "textarea-markdown-editor"
|
||||
import Tooltip from "@components/tooltip"
|
||||
import Button from "@components/button"
|
||||
import ButtonGroup from "@components/button-group"
|
||||
|
||||
// TODO: clean up
|
||||
|
||||
|
@ -69,11 +70,8 @@ const FormattingIcons = ({
|
|||
key={name}
|
||||
>
|
||||
<Button
|
||||
auto
|
||||
scale={2 / 3}
|
||||
px={0.6}
|
||||
aria-label={name}
|
||||
icon={icon}
|
||||
iconRight={icon}
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
onClick={action}
|
||||
/>
|
||||
|
|
|
@ -11,8 +11,9 @@ import Trash from "@geist-ui/icons/trash"
|
|||
import FormattingIcons from "./formatting-icons"
|
||||
import TextareaMarkdown, { TextareaMarkdownRef } from "textarea-markdown-editor"
|
||||
|
||||
import { Button, Input, Spacer, Tabs, Textarea } from "@geist-ui/core/dist"
|
||||
import { Input, Tabs, Textarea } from "@geist-ui/core/dist"
|
||||
import Preview from "../../../../components/preview"
|
||||
import Button from "@components/button"
|
||||
|
||||
// import Link from "next/link"
|
||||
type Props = {
|
||||
|
@ -103,12 +104,11 @@ const Document = ({
|
|||
/>
|
||||
{remove && (
|
||||
<Button
|
||||
type="abort"
|
||||
ghost
|
||||
icon={<Trash />}
|
||||
auto
|
||||
iconLeft={<Trash />}
|
||||
height={"36px"}
|
||||
width={"36px"}
|
||||
width={"48px"}
|
||||
padding={0}
|
||||
margin={0}
|
||||
onClick={() => removeFile(remove)}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"use client"
|
||||
|
||||
import { Button, useToasts, Input, ButtonDropdown } from "@geist-ui/core/dist"
|
||||
import { useToasts, Input, ButtonDropdown } from "@geist-ui/core/dist"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { useCallback, useState } from "react"
|
||||
import generateUUID from "@lib/generate-uuid"
|
||||
|
@ -14,6 +14,7 @@ import { PostWithFiles } from "@lib/server/prisma"
|
|||
import PasswordModal from "../../../components/password-modal"
|
||||
import Title from "./title"
|
||||
import FileDropzone from "./drag-and-drop"
|
||||
import Button from "@components/button"
|
||||
const emptyDoc = {
|
||||
title: "",
|
||||
content: "",
|
||||
|
@ -162,21 +163,19 @@ const Post = ({
|
|||
|
||||
const onChangeExpiration = (date: Date) => setExpiresAt(date)
|
||||
|
||||
const onChangeTitle =
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
setTitle(e.target.value)
|
||||
}
|
||||
const onChangeTitle = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setTitle(e.target.value)
|
||||
}
|
||||
|
||||
const onChangeDescription =
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
setDescription(e.target.value)
|
||||
}
|
||||
const onChangeDescription = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setDescription(e.target.value)
|
||||
}
|
||||
|
||||
const updateDocTitle = (i: number) => (title: string) => {
|
||||
setDocs((docs) =>
|
||||
docs.map((doc, index) => (i === index ? { ...doc, title } : doc))
|
||||
)
|
||||
}
|
||||
setDocs((docs) =>
|
||||
docs.map((doc, index) => (i === index ? { ...doc, title } : doc))
|
||||
)
|
||||
}
|
||||
|
||||
const updateDocContent = (i: number) => (content: string) => {
|
||||
setDocs((docs) =>
|
||||
|
@ -278,6 +277,9 @@ const Post = ({
|
|||
])
|
||||
}}
|
||||
type="default"
|
||||
style={{
|
||||
flex: 1
|
||||
}}
|
||||
>
|
||||
Add a File
|
||||
</Button>
|
||||
|
|
13
client/app/components/button-group/button-group.module.css
Normal file
13
client/app/components/button-group/button-group.module.css
Normal file
|
@ -0,0 +1,13 @@
|
|||
.button-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
align-content: stretch;
|
||||
}
|
||||
|
||||
.button-group > * {
|
||||
flex: 1 1 auto;
|
||||
margin: 0;
|
||||
}
|
14
client/app/components/button-group/index.tsx
Normal file
14
client/app/components/button-group/index.tsx
Normal file
|
@ -0,0 +1,14 @@
|
|||
import styles from "./button-group.module.css"
|
||||
|
||||
export default function ButtonGroup({
|
||||
children,
|
||||
...props
|
||||
}: {
|
||||
children: React.ReactNode | React.ReactNode[]
|
||||
} & React.HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<div className={styles["button-group"]} {...props}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -9,14 +9,14 @@
|
|||
border-radius: var(--radius);
|
||||
border: 1px solid var(--border);
|
||||
padding: var(--gap-half) var(--gap);
|
||||
color: var(--darker-gray);
|
||||
}
|
||||
|
||||
.button:hover,
|
||||
.button:focus {
|
||||
outline: none;
|
||||
color: var(--hover);
|
||||
background: var(--hover-bg);
|
||||
border: var(--);
|
||||
border: 1px solid var(--darker-gray);
|
||||
}
|
||||
|
||||
.button[disabled] {
|
||||
|
|
|
@ -2,12 +2,16 @@ import styles from "./button.module.css"
|
|||
import { forwardRef, Ref } from "react"
|
||||
|
||||
type Props = React.HTMLProps<HTMLButtonElement> & {
|
||||
children: React.ReactNode
|
||||
children?: React.ReactNode
|
||||
buttonType?: "primary" | "secondary"
|
||||
className?: string
|
||||
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void
|
||||
iconRight?: React.ReactNode
|
||||
iconLeft?: React.ReactNode
|
||||
height?: string | number
|
||||
width?: string | number
|
||||
padding?: string | number
|
||||
margin?: string | number
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
|
@ -22,6 +26,10 @@ const Button = forwardRef<HTMLButtonElement, Props>(
|
|||
disabled = false,
|
||||
iconRight,
|
||||
iconLeft,
|
||||
height,
|
||||
width,
|
||||
padding,
|
||||
margin,
|
||||
...props
|
||||
},
|
||||
ref
|
||||
|
@ -32,15 +40,16 @@ const Button = forwardRef<HTMLButtonElement, Props>(
|
|||
className={`${styles.button} ${styles[type]} ${className || ""}`}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
style={{ height, width, margin, padding }}
|
||||
{...props}
|
||||
>
|
||||
{iconLeft && (
|
||||
{children && iconLeft && (
|
||||
<span className={`${styles.icon} ${styles.iconLeft}`}>
|
||||
{iconLeft}
|
||||
</span>
|
||||
)}
|
||||
{children}
|
||||
{iconRight && (
|
||||
{children ? children : <span className={`${styles.icon}`}>{iconLeft || iconRight}</span>}
|
||||
{children && iconRight && (
|
||||
<span className={`${styles.icon} ${styles.iconRight}`}>
|
||||
{iconRight}
|
||||
</span>
|
||||
|
|
|
@ -18,18 +18,16 @@
|
|||
background: var(--bg);
|
||||
}
|
||||
|
||||
.tabs .buttons > a:hover,
|
||||
.tabs .buttons > button:hover {
|
||||
color: var(--fg);
|
||||
box-shadow: inset 0 -1px 0 var(--fg);
|
||||
transition: box-shadow 0.2s ease-in-out;
|
||||
.tabs button,
|
||||
.tabs a {
|
||||
color: var(--darker-gray);
|
||||
transition: color, box-shadow 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.tabs a:active,
|
||||
.tabs a:focus,
|
||||
.tabs button:active,
|
||||
.tabs button:focus {
|
||||
color: var(--darker-gray);
|
||||
.tabs .buttons a:hover,
|
||||
.tabs .buttons button:hover {
|
||||
color: var(--fg);
|
||||
box-shadow: inset 0 -1px 0 var(--fg);
|
||||
}
|
||||
|
||||
.mobile {
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
@ -55,3 +54,9 @@
|
|||
margin-bottom: var(--gap);
|
||||
}
|
||||
}
|
||||
|
||||
.input:disabled {
|
||||
background-color: var(--lighter-gray);
|
||||
color: var(--fg);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
"use client"
|
||||
|
||||
import { Button, Input, Text } from "@geist-ui/core/dist"
|
||||
|
||||
import styles from "./post-list.module.css"
|
||||
import ListItemSkeleton from "./list-item-skeleton"
|
||||
import ListItem from "./list-item"
|
||||
|
@ -9,6 +7,8 @@ import { ChangeEvent, useCallback, useEffect, useState } from "react"
|
|||
import useDebounce from "@lib/hooks/use-debounce"
|
||||
import Link from "@components/link"
|
||||
import type { PostWithFiles } from "@lib/server/prisma"
|
||||
import Input from "@components/input"
|
||||
import Button from "@components/button"
|
||||
|
||||
type Props = {
|
||||
initialPosts: string | PostWithFiles[]
|
||||
|
@ -106,13 +106,13 @@ const PostList = ({
|
|||
<div className={styles.container}>
|
||||
<div className={styles.searchContainer}>
|
||||
<Input
|
||||
scale={3 / 2}
|
||||
placeholder="Search..."
|
||||
onChange={handleSearchChange}
|
||||
disabled={Boolean(!posts?.length)}
|
||||
style={{ maxWidth: 300 }}
|
||||
/>
|
||||
</div>
|
||||
{!posts && <Text type="error">Failed to load.</Text>}
|
||||
{!posts && <p style={{color: 'var(--warning)'}}>Failed to load.</p>}
|
||||
{!posts?.length && searching && (
|
||||
<ul>
|
||||
<li>
|
||||
|
@ -124,13 +124,13 @@ const PostList = ({
|
|||
</ul>
|
||||
)}
|
||||
{posts?.length === 0 && posts && (
|
||||
<Text type="secondary">
|
||||
<p>
|
||||
No posts found. Create one{" "}
|
||||
<Link colored href="/new">
|
||||
here
|
||||
</Link>
|
||||
.
|
||||
</Text>
|
||||
</p>
|
||||
)}
|
||||
{posts?.length > 0 && (
|
||||
<div>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import VisibilityBadge from "../badges/visibility-badge"
|
||||
import { Divider, Button } from "@geist-ui/core/dist"
|
||||
import FadeIn from "@components/fade-in"
|
||||
import Trash from "@geist-ui/icons/trash"
|
||||
import ExpirationBadge from "@components/badges/expiration-badge"
|
||||
|
@ -14,6 +13,7 @@ import type { File } from "@lib/server/prisma"
|
|||
import Tooltip from "@components/tooltip"
|
||||
import Badge from "@components/badges/badge"
|
||||
import Card from "@components/card"
|
||||
import Button from "@components/button"
|
||||
|
||||
// TODO: isOwner should default to false so this can be used generically
|
||||
const ListItem = ({
|
||||
|
@ -41,7 +41,7 @@ const ListItem = ({
|
|||
<Card style={{ overflowY: "scroll" }}>
|
||||
<>
|
||||
<div className={styles.title}>
|
||||
<h3 style={{ display: "inline-block" }}>
|
||||
<h3 style={{ display: "inline-block", margin: 0 }}>
|
||||
<Link
|
||||
colored
|
||||
style={{ marginRight: "var(--gap)" }}
|
||||
|
@ -55,17 +55,17 @@ const ListItem = ({
|
|||
{post.parentId && (
|
||||
<Tooltip content={"View parent"}>
|
||||
<Button
|
||||
auto
|
||||
icon={<Parent />}
|
||||
iconRight={<Parent />}
|
||||
onClick={viewParentClick}
|
||||
height={38}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip content={"Make a copy"}>
|
||||
<Button auto iconRight={<Edit />} onClick={editACopy} />
|
||||
<Button iconRight={<Edit />} onClick={editACopy} height={38} />
|
||||
</Tooltip>
|
||||
<Tooltip content={"Delete"}>
|
||||
<Button iconRight={<Trash />} onClick={deletePost} auto />
|
||||
<Button iconRight={<Trash />} onClick={deletePost} height={38} />
|
||||
</Tooltip>
|
||||
</span>
|
||||
)}
|
||||
|
@ -86,7 +86,7 @@ const ListItem = ({
|
|||
<ExpirationBadge postExpirationDate={post.expiresAt} />
|
||||
</div>
|
||||
</>
|
||||
<Divider h="1px" my={2} />
|
||||
<hr />
|
||||
<>
|
||||
{post?.files?.map((file: File) => {
|
||||
return (
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
"jest": "^29.3.1",
|
||||
"next": "13.0.3",
|
||||
"next-auth": "^4.16.4",
|
||||
"next-themes": "^0.2.1",
|
||||
"rc-table": "7.24.1",
|
||||
"react": "18.2.0",
|
||||
"react-datepicker": "4.8.0",
|
||||
|
|
|
@ -25,7 +25,6 @@ specifiers:
|
|||
katex: ^0.16.3
|
||||
next: 13.0.3
|
||||
next-auth: ^4.16.4
|
||||
next-themes: ^0.2.1
|
||||
next-unused: 0.0.6
|
||||
prettier: 2.6.2
|
||||
prisma: ^4.6.1
|
||||
|
@ -58,7 +57,6 @@ dependencies:
|
|||
jest: 29.3.1_@types+node@17.0.23
|
||||
next: 13.0.3_biqbaboplfbrettd7655fr4n2y
|
||||
next-auth: 4.16.4_ogpkrxaz2lg6nectum6dl66tn4
|
||||
next-themes: 0.2.1_ogpkrxaz2lg6nectum6dl66tn4
|
||||
rc-table: 7.24.1_biqbaboplfbrettd7655fr4n2y
|
||||
react: 18.2.0
|
||||
react-datepicker: 4.8.0_biqbaboplfbrettd7655fr4n2y
|
||||
|
@ -5117,18 +5115,6 @@ packages:
|
|||
uuid: 8.3.2
|
||||
dev: false
|
||||
|
||||
/next-themes/0.2.1_ogpkrxaz2lg6nectum6dl66tn4:
|
||||
resolution: {integrity: sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==}
|
||||
peerDependencies:
|
||||
next: '*'
|
||||
react: '*'
|
||||
react-dom: '*'
|
||||
dependencies:
|
||||
next: 13.0.3_biqbaboplfbrettd7655fr4n2y
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
dev: false
|
||||
|
||||
/next-unused/0.0.6:
|
||||
resolution: {integrity: sha512-dHFNNBanFq4wvYrULtsjfWyZ6BzOnr5VYI9EYMGAZYF2vkAhFpj2JOuT5Wu2o3LbFSG92PmAZnSUF/LstF82pA==}
|
||||
hasBin: true
|
||||
|
|
Loading…
Reference in a new issue