More uniform home page spacing, close mobile menu on click
This commit is contained in:
parent
a84dad1dde
commit
72633c6ad2
18 changed files with 164 additions and 230 deletions
|
@ -1,5 +1,4 @@
|
|||
.card {
|
||||
margin: var(--gap) auto;
|
||||
padding: var(--gap);
|
||||
border: 1px solid var(--lighter-gray);
|
||||
border-radius: var(--radius);
|
||||
|
|
|
@ -252,7 +252,7 @@ const Post = ({
|
|||
)
|
||||
|
||||
return (
|
||||
<div style={{ paddingBottom: 200 }}>
|
||||
<div className={styles.root}>
|
||||
<Title title={title} onChange={onChangeTitle} />
|
||||
<Description description={description} onChange={onChangeDescription} />
|
||||
<FileDropzone setDocs={uploadDocs} />
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
.root {
|
||||
padding-bottom: 200px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--gap);
|
||||
}
|
||||
|
||||
.buttons {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
@ -19,7 +26,6 @@
|
|||
|
||||
.description {
|
||||
width: 100%;
|
||||
margin-bottom: var(--gap);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 650px) {
|
||||
|
|
|
@ -23,7 +23,7 @@ type props = {
|
|||
const Title = ({ onChange, title }: props) => {
|
||||
return (
|
||||
<div className={styles.title}>
|
||||
<h1>Drift</h1>
|
||||
<h1 style={{ margin: 0, padding: 0 }}>Drift</h1>
|
||||
<Input
|
||||
placeholder={placeholder}
|
||||
value={title}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: var(--gap);
|
||||
gap: inherit;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 650px) {
|
||||
|
|
|
@ -10,8 +10,8 @@ type TitleProps = {
|
|||
loading?: boolean
|
||||
displayName?: string
|
||||
visibility?: string
|
||||
createdAt?: Date
|
||||
expiresAt?: Date
|
||||
createdAt?: string
|
||||
expiresAt?: string
|
||||
authorId?: string
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
.card {
|
||||
margin: var(--gap) auto;
|
||||
padding: var(--gap);
|
||||
border: 1px solid var(--light-gray);
|
||||
border-radius: var(--radius);
|
||||
|
|
|
@ -20,7 +20,7 @@ type Props = {
|
|||
preview: string
|
||||
}
|
||||
|
||||
const DownloadButton = ({ rawLink }: { rawLink?: string }) => {
|
||||
const DownloadButtons = ({ rawLink }: { rawLink?: string }) => {
|
||||
return (
|
||||
<div className={styles.actionWrapper}>
|
||||
<ButtonGroup className={styles.actions}>
|
||||
|
@ -59,12 +59,6 @@ const Document = ({
|
|||
skeleton,
|
||||
id
|
||||
}: Props) => {
|
||||
const rawLink = () => {
|
||||
if (id) {
|
||||
return `/file/raw/${id}`
|
||||
}
|
||||
}
|
||||
|
||||
if (skeleton) {
|
||||
return (
|
||||
<>
|
||||
|
@ -98,7 +92,7 @@ const Document = ({
|
|||
/>
|
||||
</Link>
|
||||
<div className={styles.descriptionContainer}>
|
||||
<DownloadButton rawLink={rawLink()} />
|
||||
<DownloadButtons rawLink={`/api/file/raw/${id}`} />
|
||||
<DocumentTabs
|
||||
defaultTab={initialTab}
|
||||
preview={preview}
|
||||
|
|
|
@ -57,6 +57,7 @@ const getPost = async (id: string) => {
|
|||
|
||||
if (post.visibility === "protected" && !isAuthorOrAdmin) {
|
||||
return {
|
||||
// TODO: remove this. It's temporary to appease typescript
|
||||
post: {
|
||||
visibility: "protected",
|
||||
id: post.id,
|
||||
|
@ -64,6 +65,7 @@ const getPost = async (id: string) => {
|
|||
parentId: "",
|
||||
title: "",
|
||||
createdAt: new Date("1970-01-01"),
|
||||
expiresAt: new Date("1970-01-01"),
|
||||
author: {
|
||||
displayName: "",
|
||||
},
|
||||
|
@ -108,7 +110,8 @@ const PostView = async ({
|
|||
/>
|
||||
<PostTitle
|
||||
title={post.title}
|
||||
createdAt={post.createdAt}
|
||||
createdAt={post.createdAt.toString()}
|
||||
expiresAt={post.expiresAt?.toString()}
|
||||
displayName={post.author?.displayName || ""}
|
||||
visibility={post.visibility}
|
||||
authorId={post.authorId}
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
.selectContent {
|
||||
width: auto;
|
||||
height: 18px;
|
||||
|
@ -64,6 +63,10 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.contentWrapper {
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
.wrapper [data-tab="github"] {
|
||||
display: none;
|
||||
|
@ -71,6 +74,7 @@
|
|||
|
||||
.mobile {
|
||||
margin-top: var(--gap);
|
||||
margin-bottom: var(--gap);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
@ -79,6 +83,23 @@
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
.dropdownItem:not(:first-child):not(:last-child) :global(button) {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.dropdownItem:first-child :global(button) {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.dropdownItem:last-child :global(button) {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
.dropdownItem a,
|
||||
.dropdownItem button {
|
||||
width: 100%;
|
||||
|
|
|
@ -22,7 +22,7 @@ import {
|
|||
} from "react-feather"
|
||||
import * as DropdownMenu from "@radix-ui/react-dropdown-menu"
|
||||
import buttonStyles from "@components/button/button.module.css"
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
import { useMemo } from "react"
|
||||
|
||||
type Tab = {
|
||||
name: string
|
||||
|
@ -155,17 +155,13 @@ const Header = () => {
|
|||
]
|
||||
}, [isAdmin, resolvedTheme, isSignedIn, setTheme])
|
||||
|
||||
// // TODO: this should not be necessary.
|
||||
// if (!clientHydrated) {
|
||||
// return (
|
||||
// <header>
|
||||
// <div className={styles.tabs}>{getPages(true).map(getButton)}</div>
|
||||
// </header>
|
||||
// )
|
||||
// }
|
||||
|
||||
const buttons = pages.map(getButton)
|
||||
|
||||
// TODO: this is a hack to close the radix ui menu when a next link is clicked
|
||||
const onClick = () => {
|
||||
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
|
||||
}
|
||||
|
||||
return (
|
||||
<header className={clsx(styles.header, {
|
||||
[styles.loading]: isLoading,
|
||||
|
@ -188,6 +184,7 @@ const Header = () => {
|
|||
<DropdownMenu.Item
|
||||
key={button?.key}
|
||||
className={styles.dropdownItem}
|
||||
onClick={onClick}
|
||||
>
|
||||
{button}
|
||||
</DropdownMenu.Item>
|
||||
|
|
|
@ -2,15 +2,6 @@ import clsx from "clsx"
|
|||
import React from "react"
|
||||
import styles from "./input.module.css"
|
||||
|
||||
type RequireOnlyOne<T, Keys extends keyof T = keyof T> = Pick<
|
||||
T,
|
||||
Exclude<keyof T, Keys>
|
||||
> &
|
||||
{
|
||||
[K in Keys]-?: Required<Pick<T, K>> &
|
||||
Partial<Record<Exclude<Keys, K>, undefined>>
|
||||
}[Keys]
|
||||
|
||||
type Props = React.HTMLProps<HTMLInputElement> & {
|
||||
label?: string
|
||||
width?: number | string
|
||||
|
@ -18,8 +9,30 @@ type Props = React.HTMLProps<HTMLInputElement> & {
|
|||
labelClassName?: string
|
||||
}
|
||||
|
||||
type InputProps = RequireOnlyOne<Props, "label" | "aria-label">
|
||||
|
||||
// we have two special rules on top of the props:
|
||||
// if onChange or value is passed, we require both
|
||||
// if label is passed, we forbid aria-label and vice versa
|
||||
type InputProps = Omit<Props, "onChange" | "value" | "label" | "aria-label"> &
|
||||
(
|
||||
| {
|
||||
onChange: Props["onChange"]
|
||||
value: Props["value"]
|
||||
} // if onChange or value is passed, we require both
|
||||
| {
|
||||
onChange?: never
|
||||
value?: never
|
||||
}
|
||||
) &
|
||||
(
|
||||
| {
|
||||
label: Props["label"]
|
||||
"aria-label"?: never
|
||||
} // if label is passed, we forbid aria-label and vice versa
|
||||
| {
|
||||
label?: never
|
||||
"aria-label": Props["aria-label"]
|
||||
}
|
||||
)
|
||||
// eslint-disable-next-line react/display-name
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
({ label, className, width, height, labelClassName, ...props }, ref) => {
|
||||
|
|
|
@ -51,12 +51,6 @@
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.wrapper {
|
||||
margin-bottom: var(--gap);
|
||||
}
|
||||
}
|
||||
|
||||
.input:disabled {
|
||||
background-color: var(--lighter-gray);
|
||||
color: var(--fg);
|
||||
|
|
|
@ -2,14 +2,20 @@
|
|||
|
||||
import styles from "./post-list.module.css"
|
||||
import ListItem from "./list-item"
|
||||
import { ChangeEvent, useCallback, useEffect, useState } from "react"
|
||||
import useDebounce from "@lib/hooks/use-debounce"
|
||||
import {
|
||||
ChangeEvent,
|
||||
useCallback,
|
||||
useDeferredValue,
|
||||
useEffect,
|
||||
useState
|
||||
} from "react"
|
||||
import Link from "@components/link"
|
||||
import type { PostWithFiles } from "@lib/server/prisma"
|
||||
import Input from "@components/input"
|
||||
import Button from "@components/button"
|
||||
import { useToasts } from "@components/toasts"
|
||||
import { ListItemSkeleton } from "./list-item-skeleton"
|
||||
import debounce from "lodash.debounce"
|
||||
|
||||
type Props = {
|
||||
initialPosts: string | PostWithFiles[]
|
||||
|
@ -32,8 +38,6 @@ const PostList = ({
|
|||
const [hasMorePosts, setHasMorePosts] = useState(morePosts)
|
||||
const { setToast } = useToasts()
|
||||
|
||||
const debouncedSearchValue = useDebounce(search, 200)
|
||||
|
||||
const loadMoreClick = useCallback(
|
||||
(e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.preventDefault()
|
||||
|
@ -56,36 +60,30 @@ const PostList = ({
|
|||
[posts, hasMorePosts]
|
||||
)
|
||||
|
||||
// update posts on search
|
||||
useEffect(() => {
|
||||
if (debouncedSearchValue) {
|
||||
setSearching(true)
|
||||
async function fetchPosts() {
|
||||
const res = await fetch(
|
||||
`/api/post/search?q=${encodeURIComponent(
|
||||
debouncedSearchValue
|
||||
)}&userId=${userId}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
const onSearch = (query: string) => {
|
||||
setSearching(true)
|
||||
async function fetchPosts() {
|
||||
const res = await fetch(
|
||||
`/api/post/search?q=${encodeURIComponent(query)}&userId=${userId}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
)
|
||||
const json = await res.json()
|
||||
setPosts(json)
|
||||
setSearching(false)
|
||||
}
|
||||
fetchPosts()
|
||||
} else {
|
||||
setPosts(initialPosts)
|
||||
}
|
||||
)
|
||||
const json = await res.json()
|
||||
setPosts(json)
|
||||
setSearching(false)
|
||||
}
|
||||
// TODO: fix cyclical dependency issue
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [debouncedSearchValue, userId])
|
||||
fetchPosts()
|
||||
}
|
||||
|
||||
const debouncedSearch = debounce(onSearch, 500)
|
||||
|
||||
const handleSearchChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setSearchValue(e.target.value)
|
||||
debouncedSearch(e.target.value)
|
||||
}
|
||||
|
||||
const deletePost = useCallback(
|
||||
|
@ -117,10 +115,11 @@ const PostList = ({
|
|||
disabled={!posts}
|
||||
style={{ maxWidth: 300 }}
|
||||
aria-label="Search"
|
||||
value={search}
|
||||
/>
|
||||
</div>
|
||||
{!posts && <p style={{ color: "var(--warning)" }}>Failed to load.</p>}
|
||||
{!posts?.length && (
|
||||
{searching && (
|
||||
<ul>
|
||||
<ListItemSkeleton />
|
||||
<ListItemSkeleton />
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
"dependencies": {
|
||||
"@next-auth/prisma-adapter": "^1.0.5",
|
||||
"@next/eslint-plugin-next": "13.0.5-canary.3",
|
||||
"@prisma/client": "^4.6.1",
|
||||
"@prisma/client": "^4.7.1",
|
||||
"@radix-ui/react-dialog": "^1.0.2",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.1",
|
||||
"@radix-ui/react-popover": "^1.0.2",
|
||||
|
@ -26,6 +26,7 @@
|
|||
"bcrypt": "^5.1.0",
|
||||
"client-zip": "2.2.1",
|
||||
"jest": "^29.3.1",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"next": "13.0.7-canary.1",
|
||||
"next-auth": "^4.18.0",
|
||||
"prisma": "^4.7.1",
|
||||
|
@ -41,6 +42,7 @@
|
|||
"devDependencies": {
|
||||
"@next/bundle-analyzer": "12.1.6",
|
||||
"@types/bcrypt": "^5.0.0",
|
||||
"@types/lodash.debounce": "^4.0.7",
|
||||
"@types/node": "17.0.23",
|
||||
"@types/react": "18.0.9",
|
||||
"@types/react-datepicker": "4.4.1",
|
||||
|
|
|
@ -4,13 +4,14 @@ specifiers:
|
|||
'@next-auth/prisma-adapter': ^1.0.5
|
||||
'@next/bundle-analyzer': 12.1.6
|
||||
'@next/eslint-plugin-next': 13.0.5-canary.3
|
||||
'@prisma/client': ^4.6.1
|
||||
'@prisma/client': ^4.7.1
|
||||
'@radix-ui/react-dialog': ^1.0.2
|
||||
'@radix-ui/react-dropdown-menu': ^2.0.1
|
||||
'@radix-ui/react-popover': ^1.0.2
|
||||
'@radix-ui/react-tabs': ^1.0.1
|
||||
'@radix-ui/react-tooltip': ^1.0.2
|
||||
'@types/bcrypt': ^5.0.0
|
||||
'@types/lodash.debounce': ^4.0.7
|
||||
'@types/node': 17.0.23
|
||||
'@types/react': 18.0.9
|
||||
'@types/react-datepicker': 4.4.1
|
||||
|
@ -25,6 +26,7 @@ specifiers:
|
|||
eslint: 8.27.0
|
||||
eslint-config-next: 13.0.3
|
||||
jest: ^29.3.1
|
||||
lodash.debounce: ^4.0.8
|
||||
next: 13.0.7-canary.1
|
||||
next-auth: ^4.18.0
|
||||
next-unused: 0.0.6
|
||||
|
@ -43,9 +45,9 @@ specifiers:
|
|||
typescript-plugin-css-modules: 3.4.0
|
||||
|
||||
dependencies:
|
||||
'@next-auth/prisma-adapter': 1.0.5_qwexivae5olc6wqfcmxswm7qjy
|
||||
'@next-auth/prisma-adapter': 1.0.5_hpttyne5hky44pj2anoxcmv4zm
|
||||
'@next/eslint-plugin-next': 13.0.5-canary.3
|
||||
'@prisma/client': 4.6.1_prisma@4.7.1
|
||||
'@prisma/client': 4.7.1_prisma@4.7.1
|
||||
'@radix-ui/react-dialog': 1.0.2_jbvntnid6ohjelon6ccj5dhg2u
|
||||
'@radix-ui/react-dropdown-menu': 2.0.1_jbvntnid6ohjelon6ccj5dhg2u
|
||||
'@radix-ui/react-popover': 1.0.2_jbvntnid6ohjelon6ccj5dhg2u
|
||||
|
@ -56,6 +58,7 @@ dependencies:
|
|||
bcrypt: 5.1.0
|
||||
client-zip: 2.2.1
|
||||
jest: 29.3.1_@types+node@17.0.23
|
||||
lodash.debounce: 4.0.8
|
||||
next: 13.0.7-canary.1_biqbaboplfbrettd7655fr4n2y
|
||||
next-auth: 4.18.0_ihvxcpofhpc4k2aqfys2drrlkq
|
||||
prisma: 4.7.1
|
||||
|
@ -74,6 +77,7 @@ optionalDependencies:
|
|||
devDependencies:
|
||||
'@next/bundle-analyzer': 12.1.6
|
||||
'@types/bcrypt': 5.0.0
|
||||
'@types/lodash.debounce': 4.0.7
|
||||
'@types/node': 17.0.23
|
||||
'@types/react': 18.0.9
|
||||
'@types/react-datepicker': 4.4.1_biqbaboplfbrettd7655fr4n2y
|
||||
|
@ -785,13 +789,13 @@ packages:
|
|||
- supports-color
|
||||
dev: false
|
||||
|
||||
/@next-auth/prisma-adapter/1.0.5_qwexivae5olc6wqfcmxswm7qjy:
|
||||
/@next-auth/prisma-adapter/1.0.5_hpttyne5hky44pj2anoxcmv4zm:
|
||||
resolution: {integrity: sha512-VqMS11IxPXrPGXw6Oul6jcyS/n8GLOWzRMrPr3EMdtD6eOalM6zz05j08PcNiis8QzkfuYnCv49OvufTuaEwYQ==}
|
||||
peerDependencies:
|
||||
'@prisma/client': '>=2.26.0 || >=3'
|
||||
next-auth: ^4
|
||||
dependencies:
|
||||
'@prisma/client': 4.6.1_prisma@4.7.1
|
||||
'@prisma/client': 4.7.1_prisma@4.7.1
|
||||
next-auth: 4.18.0_ihvxcpofhpc4k2aqfys2drrlkq
|
||||
dev: false
|
||||
|
||||
|
@ -969,8 +973,8 @@ packages:
|
|||
/@popperjs/core/2.11.6:
|
||||
resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==}
|
||||
|
||||
/@prisma/client/4.6.1_prisma@4.7.1:
|
||||
resolution: {integrity: sha512-M1+NNrMzqaOIxT7PBGcTs3IZo7d1EW/+gVQd4C4gUgWBDGgD9AcIeZnUSidgWClmpMSgVUdnVORjsWWGUameYA==}
|
||||
/@prisma/client/4.7.1_prisma@4.7.1:
|
||||
resolution: {integrity: sha512-/GbnOwIPtjiveZNUzGXOdp7RxTEkHL4DZP3vBaFNadfr6Sf0RshU5EULFzVaSi9i9PIK9PYd+1Rn7z2B2npb9w==}
|
||||
engines: {node: '>=14.17'}
|
||||
requiresBuild: true
|
||||
peerDependencies:
|
||||
|
@ -979,12 +983,12 @@ packages:
|
|||
prisma:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@prisma/engines-version': 4.6.1-3.694eea289a8462c80264df36757e4fdc129b1b32
|
||||
'@prisma/engines-version': 4.7.1-1.272861e07ab64f234d3ffc4094e32bd61775599c
|
||||
prisma: 4.7.1
|
||||
dev: false
|
||||
|
||||
/@prisma/engines-version/4.6.1-3.694eea289a8462c80264df36757e4fdc129b1b32:
|
||||
resolution: {integrity: sha512-HUCmkXAU2jqp2O1RvNtbE+seLGLyJGEABZS/R38rZjSAafAy0WzBuHq+tbZMnD+b5OSCsTVtIPVcuvx1ySxcWQ==}
|
||||
/@prisma/engines-version/4.7.1-1.272861e07ab64f234d3ffc4094e32bd61775599c:
|
||||
resolution: {integrity: sha512-Bd4LZ+WAnUHOq31e9X/ihi5zPlr4SzTRwUZZYxvWOxlerIZ7HJlVa9zXpuKTKLpI9O1l8Ec4OYCKsivWCs5a3Q==}
|
||||
dev: false
|
||||
|
||||
/@prisma/engines/4.7.1:
|
||||
|
@ -1519,6 +1523,16 @@ packages:
|
|||
resolution: {integrity: sha512-DUlIj2nk0YnJdlWgsFuVKcX27MLW0KbKmGVoUHmFr+74FYYNUDAaj9ZqTADvsbE8rfxuVmSFc7KczYn5Y09ozg==}
|
||||
dev: false
|
||||
|
||||
/@types/lodash.debounce/4.0.7:
|
||||
resolution: {integrity: sha512-X1T4wMZ+gT000M2/91SYj0d/7JfeNZ9PeeOldSNoE/lunLeQXKvkmIumI29IaKMotU/ln/McOIvgzZcQ/3TrSA==}
|
||||
dependencies:
|
||||
'@types/lodash': 4.14.191
|
||||
dev: true
|
||||
|
||||
/@types/lodash/4.14.191:
|
||||
resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==}
|
||||
dev: true
|
||||
|
||||
/@types/mdast/3.0.10:
|
||||
resolution: {integrity: sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==}
|
||||
dependencies:
|
||||
|
@ -4584,6 +4598,10 @@ packages:
|
|||
resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
|
||||
dev: true
|
||||
|
||||
/lodash.debounce/4.0.8:
|
||||
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
|
||||
dev: false
|
||||
|
||||
/lodash.memoize/4.1.2:
|
||||
resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
|
||||
dev: false
|
||||
|
|
|
@ -1,109 +0,0 @@
|
|||
-- CreateTable
|
||||
CREATE TABLE "SequelizeMeta" (
|
||||
"name" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "SequelizeMeta_pkey" PRIMARY KEY ("name")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "files" (
|
||||
"id" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"content" TEXT NOT NULL,
|
||||
"sha" TEXT NOT NULL,
|
||||
"html" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3),
|
||||
"userId" TEXT NOT NULL,
|
||||
"postId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "files_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "posts" (
|
||||
"id" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"visibility" TEXT NOT NULL,
|
||||
"password" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"deletedAt" TIMESTAMP(3),
|
||||
"expiresAt" TIMESTAMP(3),
|
||||
"parentId" TEXT,
|
||||
"description" TEXT,
|
||||
"authorId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "posts_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "accounts" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"provider" TEXT NOT NULL,
|
||||
"providerAccountId" TEXT NOT NULL,
|
||||
"refresh_token" TEXT,
|
||||
"access_token" TEXT,
|
||||
"expires_at" INTEGER,
|
||||
"token_type" TEXT,
|
||||
"scope" TEXT,
|
||||
"id_token" TEXT,
|
||||
"session_state" TEXT,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"refresh_token_expires_in" INTEGER,
|
||||
|
||||
CONSTRAINT "accounts_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Session" (
|
||||
"id" TEXT NOT NULL,
|
||||
"sessionToken" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"expires" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "users" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT,
|
||||
"email" TEXT,
|
||||
"emailVerified" TIMESTAMP(3),
|
||||
"image" TEXT,
|
||||
"username" TEXT,
|
||||
"role" TEXT DEFAULT 'user',
|
||||
"password" TEXT,
|
||||
|
||||
CONSTRAINT "users_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "verification_tokens" (
|
||||
"identifier" TEXT NOT NULL,
|
||||
"token" TEXT NOT NULL,
|
||||
"expires" TIMESTAMP(3) NOT NULL
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "accounts_provider_providerAccountId_key" ON "accounts"("provider", "providerAccountId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "users_username_key" ON "users"("username");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "verification_tokens_token_key" ON "verification_tokens"("token");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "verification_tokens_identifier_token_key" ON "verification_tokens"("identifier", "token");
|
|
@ -1,15 +1,14 @@
|
|||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
previewFeatures = ["referentialIntegrity", "fullTextSearch"]
|
||||
previewFeatures = ["fullTextSearch"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
referentialIntegrity = "prisma"
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
relationMode = "prisma"
|
||||
}
|
||||
|
||||
|
||||
model SequelizeMeta {
|
||||
name String @id
|
||||
}
|
||||
|
@ -18,7 +17,7 @@ model File {
|
|||
id String @id @default(cuid())
|
||||
title String
|
||||
content String
|
||||
sha String
|
||||
sha String
|
||||
html String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
@ -27,6 +26,7 @@ model File {
|
|||
postId String
|
||||
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([postId, userId, id])
|
||||
@@map("files")
|
||||
}
|
||||
|
||||
|
@ -41,37 +41,35 @@ model Post {
|
|||
expiresAt DateTime?
|
||||
parentId String?
|
||||
description String?
|
||||
author User? @relation(fields: [authorId], references: [id])
|
||||
authorId String
|
||||
files File[]
|
||||
author User? @relation(fields: [authorId], references: [id])
|
||||
|
||||
@@index([authorId, id])
|
||||
@@map("posts")
|
||||
}
|
||||
|
||||
// Next auth stuff, from https://next-auth.js.org/adapters/prisma
|
||||
|
||||
model Account {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
type String
|
||||
provider String
|
||||
providerAccountId String
|
||||
refresh_token String? @db.Text
|
||||
access_token String? @db.Text
|
||||
expires_at Int?
|
||||
token_type String?
|
||||
scope String?
|
||||
id_token String? @db.Text
|
||||
session_state String?
|
||||
createdAt DateTime @default(now()) @map(name: "created_at")
|
||||
updatedAt DateTime @default(now()) @map(name: "updated_at")
|
||||
// https://next-auth.js.org/providers/github
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
type String
|
||||
provider String
|
||||
providerAccountId String
|
||||
refresh_token String?
|
||||
access_token String?
|
||||
expires_at Int?
|
||||
token_type String?
|
||||
scope String?
|
||||
id_token String?
|
||||
session_state String?
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @default(now()) @map("updated_at")
|
||||
refresh_token_expires_in Int?
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([provider, providerAccountId])
|
||||
@@map(name: "accounts")
|
||||
@@index([userId, providerAccountId], map: "accounts_provider_account_id")
|
||||
@@map("accounts")
|
||||
}
|
||||
|
||||
model Session {
|
||||
|
@ -80,6 +78,9 @@ model Session {
|
|||
userId String
|
||||
expires DateTime
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([userId, expires], map: "sessions_user_id_expires")
|
||||
@@map("sessions")
|
||||
}
|
||||
|
||||
model User {
|
||||
|
@ -88,16 +89,13 @@ model User {
|
|||
email String? @unique
|
||||
emailVerified DateTime?
|
||||
image String?
|
||||
role String? @default("user")
|
||||
createdAt DateTime @default(now())
|
||||
displayName String?
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
|
||||
// custom fields
|
||||
posts Post[]
|
||||
role String? @default("user")
|
||||
displayName String?
|
||||
posts Post[]
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue