File styling adjustments

This commit is contained in:
Max Leiter 2022-12-18 01:14:46 -08:00
parent 5e976bfc0d
commit 23a850253b
21 changed files with 156 additions and 131 deletions

View file

@ -1,3 +1,12 @@
.markdownPreview {
padding: var(--gap-quarter);
}
.markdownPreview p {
margin-top: var(--gap);
margin-bottom: var(--gap);
}
.markdownPreview pre { .markdownPreview pre {
border-radius: 3px; border-radius: 3px;
font-family: "Courier New", Courier, monospace; font-family: "Courier New", Courier, monospace;

View file

@ -8,7 +8,7 @@
background: #efefef; background: #efefef;
} }
.descriptionContainer { .documentContainer {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 400px; min-height: 400px;

View file

@ -82,7 +82,7 @@ const Document = ({
/> />
)} )}
</div> </div>
<div className={styles.descriptionContainer}> <div className={styles.documentContainer}>
<DocumentTabs <DocumentTabs
isEditing={true} isEditing={true}
defaultTab={defaultTab} defaultTab={defaultTab}

View file

@ -139,7 +139,7 @@ const Post = ({
for (const doc of docs) { for (const doc of docs) {
if (!doc.title) { if (!doc.title) {
setToast({ setToast({
message: "Please fill out all the document titles", message: "Please fill out all the filenames",
type: "error" type: "error"
}) })
hasErrored = true hasErrored = true

View file

@ -77,7 +77,11 @@ const PostFiles = ({
} }
return ( return (
<> <main style={{
display: "flex",
flexDirection: "column",
gap: "var(--gap-double)"
}}>
{post.files?.map(({ id, content, title, html }) => ( {post.files?.map(({ id, content, title, html }) => (
<DocumentComponent <DocumentComponent
skeleton={false} skeleton={false}
@ -89,7 +93,7 @@ const PostFiles = ({
preview={html} preview={html}
/> />
))} ))}
</> </main>
) )
} }

View file

@ -1,47 +1,24 @@
.card { .card header {
padding: var(--gap); display: flex;
border: 1px solid var(--light-gray); align-items: center;
border-radius: var(--radius); flex-direction: row;
justify-content: space-between;
height: 40px;
line-height: 40px;
padding: 0 16px;
background: var(--lighter-gray);
border-radius: 8px 8px 0px 0px;
} }
.descriptionContainer { .documentContainer {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 400px; min-height: 400px;
overflow: auto; overflow: auto;
} padding: var(--gap);
border: 1px solid var(--lighter-gray);
.fileNameContainer { border-top: none;
font-family: var(--font-mono) !important; border-radius: 0px 0px 8px 8px;
border-radius: var(--radius) !important;
margin-bottom: var(--gap-half) !important;
width: 100% !important;
}
.fileNameContainer span {
transition: background-color var(--transition) !important;
border-color: var(--light-gray) !important;
}
.fileNameContainer span:target,
.fileNameContainer span:hover {
background-color: var(--lighter-gray) !important;
}
.fileNameContainer > div {
/* Override geist-ui styling */
margin: 0 !important;
}
.actionWrapper {
position: relative;
z-index: 1;
padding-top: 4px;
}
.actionWrapper .actions {
position: absolute;
right: 0;
} }
.textarea { .textarea {

View file

@ -9,7 +9,6 @@ import Tooltip from "@components/tooltip"
import Button from "@components/button" import Button from "@components/button"
import ButtonGroup from "@components/button-group" import ButtonGroup from "@components/button-group"
import DocumentTabs from "app/(posts)/components/tabs" import DocumentTabs from "app/(posts)/components/tabs"
import Input from "@components/input"
import { Download, ExternalLink } from "react-feather" import { Download, ExternalLink } from "react-feather"
type SharedProps = { type SharedProps = {
@ -32,8 +31,7 @@ type Props = (
const DownloadButtons = ({ rawLink }: { rawLink?: string }) => { const DownloadButtons = ({ rawLink }: { rawLink?: string }) => {
return ( return (
<div className={styles.actionWrapper}> <ButtonGroup>
<ButtonGroup className={styles.actions}>
<Tooltip content="Download"> <Tooltip content="Download">
<Link <Link
href={`${rawLink}?download=true`} href={`${rawLink}?download=true`}
@ -41,23 +39,22 @@ const DownloadButtons = ({ rawLink }: { rawLink?: string }) => {
rel="noopener noreferrer" rel="noopener noreferrer"
> >
<Button <Button
iconRight={<Download />} iconRight={<Download color="var(--fg)" />}
aria-label="Download" aria-label="Download"
style={{ borderTopRightRadius: 0, borderBottomRightRadius: 0 }} style={{ border: "none", background: "transparent" }}
/> />
</Link> </Link>
</Tooltip> </Tooltip>
<Tooltip content="Open raw in new tab"> <Tooltip content="Open raw in new tab">
<Link href={rawLink || ""} target="_blank" rel="noopener noreferrer"> <Link href={rawLink || ""} target="_blank" rel="noopener noreferrer">
<Button <Button
iconLeft={<ExternalLink />} iconLeft={<ExternalLink color="var(--fg)" />}
aria-label="Open raw file in new tab" aria-label="Open raw file in new tab"
style={{ borderTopLeftRadius: 0, borderBottomLeftRadius: 0 }} style={{ border: "none", background: "transparent" }}
/> />
</Link> </Link>
</Tooltip> </Tooltip>
</ButtonGroup> </ButtonGroup>
</div>
) )
} }
@ -67,9 +64,9 @@ const Document = ({ skeleton, ...props }: Props) => {
<> <>
<div className={styles.card}> <div className={styles.card}>
<div className={styles.fileNameContainer}> <div className={styles.fileNameContainer}>
<Skeleton width={'100%'} height={36} /> <Skeleton width={"100%"} height={36} />
</div> </div>
<div className={styles.descriptionContainer}> <div className={styles.documentContainer}>
<Skeleton width={145} height={36} borderRadius={"4px 4px 0 0"} /> <Skeleton width={145} height={36} borderRadius={"4px 4px 0 0"} />
<Skeleton <Skeleton
width={"100%"} width={"100%"}
@ -87,21 +84,21 @@ const Document = ({ skeleton, ...props }: Props) => {
return ( return (
<> <>
<div className={styles.card}> <div className={styles.card}>
<Link href={`#${title}`} className={styles.fileNameContainer}> <header>
<Input <Link
id={`${title}`} href={`#${title}`}
width={"100%"} aria-label="File"
height={"2rem"} style={{
style={{ borderRadius: 0 }} textDecoration: "none",
value={title || "Untitled"} color: "var(--fg)"
onChange={() => {}} }}
disabled >
aria-label="Document title" {title}
/>
</Link> </Link>
<div className={styles.descriptionContainer}>
{/* Not /api/ because of rewrites defined in next.config.mjs */}
<DownloadButtons rawLink={`/file/raw/${id}`} /> <DownloadButtons rawLink={`/file/raw/${id}`} />
</header>
<div className={styles.documentContainer}>
{/* Not /api/ because of rewrites defined in next.config.mjs */}
<DocumentTabs <DocumentTabs
defaultTab={initialTab} defaultTab={initialTab}
preview={preview} preview={preview}

View file

@ -6,6 +6,7 @@
.header { .header {
flex-direction: column; flex-direction: column;
gap: var(--gap); gap: var(--gap);
margin-bottom: var(--gap);
} }
} }

View file

@ -9,7 +9,7 @@
.card .content { .card .content {
padding: var(--gap); padding: var(--gap-half);
width: 100%; width: 100%;
height: auto; height: auto;
} }

View file

@ -34,7 +34,6 @@ type Tab = {
const Header = () => { const Header = () => {
const session = useSession() const session = useSession()
console.log("session", session)
const isSignedIn = session?.status === "authenticated" const isSignedIn = session?.status === "authenticated"
const isAdmin = session?.data?.user?.role === "admin" const isAdmin = session?.data?.user?.role === "admin"
const isLoading = session?.status === "loading" const isLoading = session?.status === "loading"

View file

@ -38,9 +38,12 @@ type InputProps = Omit<Props, "onChange" | "value" | "label" | "aria-label"> &
"aria-label": Props["aria-label"] "aria-label": Props["aria-label"]
} }
) )
// eslint-disable-next-line react/display-name
const Input = React.forwardRef<HTMLInputElement, InputProps>( const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ label, className, required, width, height, labelClassName, ...props }, ref) => { (
{ label, className, required, width, height, labelClassName, ...props },
ref
) => {
const labelId = label?.replace(/\s/g, "-").toLowerCase()
return ( return (
<div <div
className={styles.wrapper} className={styles.wrapper}
@ -51,7 +54,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
> >
{label && ( {label && (
<label <label
aria-labelledby={label} htmlFor={labelId}
className={clsx(styles.label, labelClassName)} className={clsx(styles.label, labelClassName)}
> >
{label} {label}
@ -59,7 +62,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
)} )}
<input <input
ref={ref} ref={ref}
id={label} id={labelId}
className={clsx(styles.input, label && styles.withLabel, className)} className={clsx(styles.input, label && styles.withLabel, className)}
{...props} {...props}
style={{ style={{
@ -73,4 +76,6 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
} }
) )
Input.displayName = "Input"
export default Input export default Input

View file

@ -5,6 +5,5 @@
position: relative; position: relative;
width: 100%; width: 100%;
height: auto; height: auto;
padding: 0 calc(1.34 * 16px) 0 calc(1.34 * 16px);
margin: 0 auto; margin: 0 auto;
} }

View file

@ -1,3 +1,4 @@
"use client";
import Toast, { Toaster } from "react-hot-toast" import Toast, { Toaster } from "react-hot-toast"
export type ToastType = "success" | "error" | "loading" | "default" export type ToastType = "success" | "error" | "loading" | "default"

View file

@ -3,19 +3,19 @@
} }
[data-side='top'] .tooltip{ [data-side='top'] .tooltip{
margin-bottom: var(--gap); margin-bottom: var(--gap-quarter);
} }
.tooltip[data-side='bottom'] { .tooltip[data-side='bottom'] {
margin-top: var(--gap); margin-top: var(--gap-quarter);
} }
.tooltip[data-side='left'] { .tooltip[data-side='left'] {
margin-right: var(--gap); margin-right: var(--gap-quarter);
} }
.tooltip[data-side='right'] { .tooltip[data-side='right'] {
margin-left: var(--gap); margin-left: var(--gap-quarter);
} }
@keyframes fadein { @keyframes fadein {

View file

@ -1,6 +1,9 @@
import "@styles/globals.css" import "@styles/globals.css"
import { LayoutWrapper } from "./root-layout-wrapper" import { Providers } from "./providers"
import { ServerThemeProvider } from "@wits/next-themes" // import { ServerThemeProvider } from "@wits/next-themes"
import Page from "@components/page"
import { Toasts } from "@components/toasts"
import Header from "@components/header"
interface RootLayoutProps { interface RootLayoutProps {
children: React.ReactNode children: React.ReactNode
@ -18,7 +21,13 @@ export default async function RootLayout({ children }: RootLayoutProps) {
<html lang="en"> <html lang="en">
<head /> <head />
<body> <body>
<LayoutWrapper>{children}</LayoutWrapper> <Toasts />
<Page>
<Providers>
<Header />
{children}
</Providers>
</Page>
</body> </body>
</html> </html>
) )

14
src/app/providers.tsx Normal file
View file

@ -0,0 +1,14 @@
"use client"
import * as RadixTooltip from "@radix-ui/react-tooltip"
import { SessionProvider } from "next-auth/react"
export function Providers({ children }: { children: React.ReactNode }) {
return (
<SessionProvider>
<RadixTooltip.Provider delayDuration={200}>
{children}
</RadixTooltip.Provider>
</SessionProvider>
)
}

View file

@ -1,21 +0,0 @@
"use client"
import Header from "@components/header"
import Page from "@components/page"
import { Toasts } from "@components/toasts"
import * as RadixTooltip from "@radix-ui/react-tooltip"
import { SessionProvider } from "next-auth/react"
export function LayoutWrapper({ children }: { children: React.ReactNode }) {
return (
<SessionProvider>
<RadixTooltip.Provider delayDuration={200}>
<Toasts />
<Page>
<Header />
{children}
</Page>
</RadixTooltip.Provider>
</SessionProvider>
)
}

View file

@ -1,7 +1,8 @@
article { article {
max-width: var(--main-content); max-width: var(--main-content);
margin: 0 auto; margin: 0 auto;
line-height: 1.9; font-size: 1rem;
line-height: 1.55;
} }
article video, article video,
@ -108,6 +109,7 @@ article pre {
line-height: 1.8; line-height: 1.8;
padding: 1rem; padding: 1rem;
font-size: 0.875rem; font-size: 0.875rem;
background-color: var(--lighter-gray);
} }
table { table {

View file

@ -111,11 +111,25 @@ export async function getPostsByUser(userId: User["id"], withFiles?: boolean) {
where: { where: {
authorId: userId authorId: userId
}, },
include: {
files: withFiles
},
orderBy: { orderBy: {
createdAt: "desc" createdAt: "desc"
},
select: {
id: true,
title: true,
createdAt: true,
updatedAt: true,
authorId: true,
visibility: true,
...(withFiles && {
files: {
select: {
id: true,
title: true,
createdAt: true,
}
}
})
} }
}) })

View file

@ -38,7 +38,8 @@
"react-hot-toast": "2.4.0-beta.0", "react-hot-toast": "2.4.0-beta.0",
"server-only": "^0.0.1", "server-only": "^0.0.1",
"textarea-markdown-editor": "1.0.4", "textarea-markdown-editor": "1.0.4",
"ts-jest": "^29.0.3" "ts-jest": "^29.0.3",
"uuid": "^9.0.0"
}, },
"devDependencies": { "devDependencies": {
"@next/bundle-analyzer": "13.0.7-canary.4", "@next/bundle-analyzer": "13.0.7-canary.4",
@ -48,6 +49,7 @@
"@types/react": "18.0.9", "@types/react": "18.0.9",
"@types/react-datepicker": "4.4.1", "@types/react-datepicker": "4.4.1",
"@types/react-dom": "18.0.3", "@types/react-dom": "18.0.3",
"@types/uuid": "^9.0.0",
"clsx": "^1.2.1", "clsx": "^1.2.1",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"csstype": "^3.1.1", "csstype": "^3.1.1",

View file

@ -16,6 +16,7 @@ specifiers:
'@types/react': 18.0.9 '@types/react': 18.0.9
'@types/react-datepicker': 4.4.1 '@types/react-datepicker': 4.4.1
'@types/react-dom': 18.0.3 '@types/react-dom': 18.0.3
'@types/uuid': ^9.0.0
'@wcj/markdown-to-html': ^2.1.2 '@wcj/markdown-to-html': ^2.1.2
'@wits/next-themes': 0.2.14 '@wits/next-themes': 0.2.14
client-only: ^0.0.1 client-only: ^0.0.1
@ -44,6 +45,7 @@ specifiers:
ts-jest: ^29.0.3 ts-jest: ^29.0.3
typescript: 4.6.4 typescript: 4.6.4
typescript-plugin-css-modules: 3.4.0 typescript-plugin-css-modules: 3.4.0
uuid: ^9.0.0
dependencies: dependencies:
'@next-auth/prisma-adapter': 1.0.5_64qbzg5ec56bux2misz3l4u6g4 '@next-auth/prisma-adapter': 1.0.5_64qbzg5ec56bux2misz3l4u6g4
@ -72,6 +74,7 @@ dependencies:
server-only: 0.0.1 server-only: 0.0.1
textarea-markdown-editor: 1.0.4_biqbaboplfbrettd7655fr4n2y textarea-markdown-editor: 1.0.4_biqbaboplfbrettd7655fr4n2y
ts-jest: 29.0.3_7hcmezpa7bajbjecov7p46z4aa ts-jest: 29.0.3_7hcmezpa7bajbjecov7p46z4aa
uuid: 9.0.0
optionalDependencies: optionalDependencies:
sharp: 0.31.2 sharp: 0.31.2
@ -84,6 +87,7 @@ devDependencies:
'@types/react': 18.0.9 '@types/react': 18.0.9
'@types/react-datepicker': 4.4.1_biqbaboplfbrettd7655fr4n2y '@types/react-datepicker': 4.4.1_biqbaboplfbrettd7655fr4n2y
'@types/react-dom': 18.0.3 '@types/react-dom': 18.0.3
'@types/uuid': 9.0.0
clsx: 1.2.1 clsx: 1.2.1
cross-env: 7.0.3 cross-env: 7.0.3
csstype: 3.1.1 csstype: 3.1.1
@ -1581,6 +1585,10 @@ packages:
resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==}
dev: false dev: false
/@types/uuid/9.0.0:
resolution: {integrity: sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==}
dev: true
/@types/yargs-parser/21.0.0: /@types/yargs-parser/21.0.0:
resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==}
dev: false dev: false
@ -6950,6 +6958,11 @@ packages:
hasBin: true hasBin: true
dev: false dev: false
/uuid/9.0.0:
resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==}
hasBin: true
dev: false
/uvu/0.5.6: /uvu/0.5.6:
resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==} resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==}
engines: {node: '>=8'} engines: {node: '>=8'}