From fc79f7df4d7d1b9b450d5619459bf87d4411fad9 Mon Sep 17 00:00:00 2001 From: Max Leiter Date: Tue, 29 Nov 2022 00:43:04 -0800 Subject: [PATCH] bump next, use next-themes, remove geist icons and most of geist core --- client/app/(auth)/components/index.tsx | 5 +- .../file-dropdown/dropdown.module.css | 5 + .../components/file-dropdown/index.tsx | 8 +- .../edit-document/formatting-icons/index.tsx | 8 +- .../edit-document/index.tsx | 4 +- .../post/[id]/components/post-page/index.tsx | 6 +- .../post-page/view-document/index.tsx | 3 +- .../components/action-dropdown/index.tsx | 38 ---- client/app/admin/components/admin.module.css | 25 --- client/app/admin/components/post-table.tsx | 129 -------------- client/app/admin/components/user-table.tsx | 157 ----------------- client/app/admin/page.tsx | 39 ---- .../app/components/button-dropdown/index.tsx | 7 +- .../app/components/header/header.module.css | 5 + client/app/components/header/index.tsx | 57 +++--- client/app/components/note/note.module.css | 2 - .../app/components/password-modal/index.tsx | 99 ++++++----- .../password-modal/modal.module.css | 66 +++++++ client/app/components/post-list/list-item.tsx | 6 +- client/app/components/scroll-to-top/index.tsx | 2 +- .../theme/ThemeClientContextProvider.tsx | 62 ------- client/app/components/theme/ThemeProvider.tsx | 28 --- .../theme/ThemeServerContextProvider.tsx | 22 --- client/app/components/theme/theme.tsx | 5 - client/app/layout.tsx | 34 ++-- client/app/root-layout-wrapper.tsx | 12 +- client/package.json | 8 +- client/pnpm-lock.yaml | 166 +++++++++++------- 28 files changed, 313 insertions(+), 695 deletions(-) delete mode 100644 client/app/admin/components/action-dropdown/index.tsx delete mode 100644 client/app/admin/components/admin.module.css delete mode 100644 client/app/admin/components/post-table.tsx delete mode 100644 client/app/admin/components/user-table.tsx delete mode 100644 client/app/admin/page.tsx create mode 100644 client/app/components/password-modal/modal.module.css delete mode 100644 client/app/components/theme/ThemeClientContextProvider.tsx delete mode 100644 client/app/components/theme/ThemeProvider.tsx delete mode 100644 client/app/components/theme/ThemeServerContextProvider.tsx delete mode 100644 client/app/components/theme/theme.tsx diff --git a/client/app/(auth)/components/index.tsx b/client/app/(auth)/components/index.tsx index 6e782ae0..fc5cecc0 100644 --- a/client/app/(auth)/components/index.tsx +++ b/client/app/(auth)/components/index.tsx @@ -4,11 +4,10 @@ import { useState } from "react" import styles from "./auth.module.css" import Link from "../../components/link" import { signIn } from "next-auth/react" -import { Github as GithubIcon } from "@geist-ui/icons" import Input from "@components/input" import Button from "@components/button" import Note from "@components/note" - +import { GitHub } from 'react-feather' const Auth = ({ page, requiresServerPassword @@ -71,7 +70,7 @@ const Auth = ({ style={{ color: 'var(--fg)' }} - iconLeft={} + iconLeft={} onClick={(e) => { e.preventDefault() signIn("github", { diff --git a/client/app/(posts)/components/file-dropdown/dropdown.module.css b/client/app/(posts)/components/file-dropdown/dropdown.module.css index 116596e1..99c2ee01 100644 --- a/client/app/(posts)/components/file-dropdown/dropdown.module.css +++ b/client/app/(posts)/components/file-dropdown/dropdown.module.css @@ -12,6 +12,11 @@ width: 100%; } +.contentWrapper { + z-index: 1000; + +} + .content { list-style: none; width: 100%; diff --git a/client/app/(posts)/components/file-dropdown/index.tsx b/client/app/(posts)/components/file-dropdown/index.tsx index d7c3e3b8..51ecb3a3 100644 --- a/client/app/(posts)/components/file-dropdown/index.tsx +++ b/client/app/(posts)/components/file-dropdown/index.tsx @@ -1,14 +1,12 @@ import Button from "@components/button" import { Popover } from "@components/popover" import ShiftBy from "@components/shift-by" -import ChevronDown from "@geist-ui/icons/chevronDown" -import CodeIcon from "@geist-ui/icons/fileFunction" -import FileIcon from "@geist-ui/icons/fileText" import { codeFileExtensions } from "@lib/constants" import clsx from "clsx" import type { File } from "lib/server/prisma" import styles from "./dropdown.module.css" import buttonStyles from "@components/button/button.module.css" +import { ChevronDown, Code, File as FileIcon } from "react-feather" type Item = File & { icon: JSX.Element @@ -20,7 +18,7 @@ const FileDropdown = ({ files }: { files: File[] }) => { if (codeFileExtensions.includes(extension || "")) { return { ...file, - icon: + icon: } } else { return { @@ -60,7 +58,7 @@ const FileDropdown = ({ files }: { files: File[] }) => { Jump to {files.length} {files.length === 1 ? "file" : "files"} - {content} + {content} ) } diff --git a/client/app/(posts)/new/components/edit-document-list/edit-document/formatting-icons/index.tsx b/client/app/(posts)/new/components/edit-document-list/edit-document/formatting-icons/index.tsx index 381a8f6d..12e660ba 100644 --- a/client/app/(posts)/new/components/edit-document-list/edit-document/formatting-icons/index.tsx +++ b/client/app/(posts)/new/components/edit-document-list/edit-document/formatting-icons/index.tsx @@ -1,10 +1,4 @@ -import Bold from "@geist-ui/icons/bold" -import Italic from "@geist-ui/icons/italic" -import Link from "@geist-ui/icons/link" -import Code from "@geist-ui/icons/code" -import List from "@geist-ui/icons/list" - -import ImageIcon from "@geist-ui/icons/image" +import { Bold, Code, Image as ImageIcon, Italic, Link, List } from "react-feather" import { RefObject, useMemo } from "react" import styles from "./formatting-icons.module.css" import { TextareaMarkdownRef } from "textarea-markdown-editor" diff --git a/client/app/(posts)/new/components/edit-document-list/edit-document/index.tsx b/client/app/(posts)/new/components/edit-document-list/edit-document/index.tsx index e4f0c302..21ce7ac0 100644 --- a/client/app/(posts)/new/components/edit-document-list/edit-document/index.tsx +++ b/client/app/(posts)/new/components/edit-document-list/edit-document/index.tsx @@ -1,9 +1,9 @@ -import { ChangeEvent, memo, useCallback } from "react" +import { ChangeEvent, useCallback } from "react" import styles from "./document.module.css" -import Trash from "@geist-ui/icons/trash" import Button from "@components/button" import Input from "@components/input" import DocumentTabs from "app/(posts)/components/tabs" +import { Trash } from "react-feather" type Props = { title?: string diff --git a/client/app/(posts)/post/[id]/components/post-page/index.tsx b/client/app/(posts)/post/[id]/components/post-page/index.tsx index e5a1333a..6eebe027 100644 --- a/client/app/(posts)/post/[id]/components/post-page/index.tsx +++ b/client/app/(posts)/post/[id]/components/post-page/index.tsx @@ -5,9 +5,6 @@ import DocumentComponent from "./view-document" import styles from "./post-page.module.css" import { useEffect, useState } from "react" -import Archive from "@geist-ui/icons/archive" -import Edit from "@geist-ui/icons/edit" -import Parent from "@geist-ui/icons/arrowUpCircle" import FileDropdown from "app/(posts)/components/file-dropdown" import ScrollToTop from "@components/scroll-to-top" import { useRouter } from "next/navigation" @@ -18,6 +15,7 @@ import VisibilityControl from "@components/badges/visibility-control" import { File, PostWithFilesAndAuthor } from "@lib/server/prisma" import ButtonGroup from "@components/button-group" import Button from "@components/button" +import { Archive, ArrowUpCircle, Edit } from "react-feather" type Props = { post: string | PostWithFilesAndAuthor @@ -108,7 +106,7 @@ const PostPage = ({ post: initialPost, isProtected, isAuthor }: Props) => { Edit a Copy {post.parentId && ( - )} diff --git a/client/app/(posts)/post/[id]/components/post-page/view-document/index.tsx b/client/app/(posts)/post/[id]/components/post-page/view-document/index.tsx index 3ba83587..9b9a54bc 100644 --- a/client/app/(posts)/post/[id]/components/post-page/view-document/index.tsx +++ b/client/app/(posts)/post/[id]/components/post-page/view-document/index.tsx @@ -1,7 +1,5 @@ import { memo } from "react" import styles from "./document.module.css" -import Download from "@geist-ui/icons/download" -import ExternalLink from "@geist-ui/icons/externalLink" import Skeleton from "@components/skeleton" import Link from "next/link" @@ -10,6 +8,7 @@ import Button from "@components/button" import ButtonGroup from "@components/button-group" import DocumentTabs from "app/(posts)/components/tabs" import Input from "@components/input" +import { Download, ExternalLink } from "react-feather" // import Link from "next/link" type Props = { diff --git a/client/app/admin/components/action-dropdown/index.tsx b/client/app/admin/components/action-dropdown/index.tsx deleted file mode 100644 index 11256170..00000000 --- a/client/app/admin/components/action-dropdown/index.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { Popover, Button } from "@geist-ui/core/dist" -import { MoreVertical } from "@geist-ui/icons" - -type Action = { - title: string - onClick: () => void -} - -const ActionDropdown = ({ - title = "Actions", - actions, - showTitle = false -}: { - title?: string - showTitle?: boolean - actions: Action[] -}) => { - return ( - - {showTitle && {title}} - {actions.map((action) => ( - - {action.title} - - ))} - - } - hideArrow - > - - - ) -} - -export default ActionDropdown diff --git a/client/app/admin/components/admin.module.css b/client/app/admin/components/admin.module.css deleted file mode 100644 index 9c4cb99d..00000000 --- a/client/app/admin/components/admin.module.css +++ /dev/null @@ -1,25 +0,0 @@ -.adminWrapper table { - width: 100%; - border-spacing: 0; - border: 1px solid var(--gray); - border-radius: var(--radius); - padding: var(--gap-half); -} - -.adminWrapper table th { - text-align: left; - background: var(--gray-light); - color: var(--gray-dark); - font-weight: bold; -} - -.postModal details { - border-radius: var(--radius); - padding: var(--gap); - border-radius: var(--radius); -} - -.postModal summary { - cursor: pointer; - outline: none; -} diff --git a/client/app/admin/components/post-table.tsx b/client/app/admin/components/post-table.tsx deleted file mode 100644 index 150790e8..00000000 --- a/client/app/admin/components/post-table.tsx +++ /dev/null @@ -1,129 +0,0 @@ -"use client" -import SettingsGroup from "@components/settings-group" -import { Fieldset } from "@geist-ui/core/dist" -import byteToMB from "@lib/byte-to-mb" -import { PostWithFiles } from "@lib/server/prisma" -import Table from "rc-table" -import { useMemo } from "react" -import ActionDropdown from "./action-dropdown" - -const PostTable = ({ posts }: { posts: PostWithFiles[] }) => { - const tablePosts = useMemo( - () => - posts?.map((post) => { - return { - id: post.id, - title: post.title, - files: post.files?.length || 0, - createdAt: `${new Date( - post.createdAt - ).toLocaleDateString()} ${new Date( - post.createdAt - ).toLocaleTimeString()}`, - visibility: post.visibility, - size: post.files - ? byteToMB( - post.files.reduce((acc, file) => acc + file.html.length, 0) - ) - : 0, - actions: "" - } - }), - [posts] - ) - - const deletePost = async (/* id: string */) => { - return alert("Not implemented") - - // const confirm = window.confirm("Are you sure you want to delete this post?") - // if (!confirm) return - // const res = await adminFetcher(`/posts/${id}`, { - // method: "DELETE", - // }) - - // const json = await res.json() - - // if (res.status === 200) { - // setToast({ - // text: "Post deleted", - // type: "success" - // }) - - // setPosts((posts) => { - // const newPosts = posts?.filter((post) => post.id !== id) - // return newPosts - // }) - // } else { - // setToast({ - // text: json.error || "Something went wrong", - // type: "error" - // }) - // } - } - - const tableColumns = [ - { - title: "Title", - dataIndex: "title", - key: "title", - width: 50 - }, - { - title: "Files", - dataIndex: "files", - key: "files", - width: 10 - }, - { - title: "Created", - dataIndex: "createdAt", - key: "createdAt", - width: 100 - }, - { - title: "Visibility", - dataIndex: "visibility", - key: "visibility", - width: 50 - }, - { - title: "Size (MB)", - dataIndex: "size", - key: "size", - width: 10 - }, - { - title: "Actions", - dataIndex: "", - key: "actions", - width: 50, - render() { - return ( - deletePost() - } - ]} - /> - ) - } - } - ] - - return ( - - {!posts && Loading...} - {posts && ( - -
{posts.length} posts
-
- )} - {posts && } - - ) -} - -export default PostTable diff --git a/client/app/admin/components/user-table.tsx b/client/app/admin/components/user-table.tsx deleted file mode 100644 index 5e481631..00000000 --- a/client/app/admin/components/user-table.tsx +++ /dev/null @@ -1,157 +0,0 @@ -"use client" -import { Fieldset } from "@geist-ui/core/dist" -import Table from "rc-table" -import ActionDropdown from "./action-dropdown" -import SettingsGroup from "@components/settings-group" -import type { User, UserWithPosts } from "@lib/server/prisma" -import { useState } from "react" -import { useToasts } from "@components/toasts" - -const UserTable = ({ users: initial }: { users: UserWithPosts[] }) => { - const [users, setUsers] = useState(initial) - const { setToast } = useToasts() - - const toggleRole = async (id: string, role: "admin" | "user") => { - const res = await fetch("/api/admin?action=toggle-role", { - method: "POST", - body: JSON.stringify({ - userId: id, - role - }) - }) - - if (res.status === 200) { - setToast({ - message: "Role updated", - type: "success" - }) - - setUsers((users) => { - const newUsers = users?.map((user) => { - if (user.id === id) { - return { - ...user, - role - } - } - return user - }) - return newUsers - }) - } else { - setToast({ - message: "Something went wrong", - type: "error" - }) - } - } - - const deleteUser = async (id: string) => { - const confirm = window.confirm("Are you sure you want to delete this user?") - if (!confirm) return - // const res = await adminFetcher(`/users/${id}`, { - // method: "DELETE" - // }) - const res = await fetch("/api/admin?action=delete-user", { - method: "POST", - body: JSON.stringify({ - userId: id - }) - }) - - setUsers((users) => { - const newUsers = users?.filter((user) => user.id !== id) - return newUsers - }) - - if (res.status === 200) { - setToast({ - message: "User deleted", - type: "success" - }) - } else { - setToast({ - message: "Something went wrong", - type: "error" - }) - } - } - - const tableUsers = users?.map((user) => { - return { - id: user.id, - displayName: user.displayName, - posts: user.posts?.length || 0, - createdAt: `${new Date(user.createdAt).toLocaleDateString()} ${new Date( - user.createdAt - ).toLocaleTimeString()}`, - role: user.role, - actions: "" - } - }) - - const usernameColumns = [ - { - title: "Name", - dataIndex: "displayName", - key: "displayName", - width: 50 - }, - { - title: "Posts", - dataIndex: "posts", - key: "posts", - width: 10 - }, - { - title: "Created", - dataIndex: "createdAt", - key: "createdAt", - width: 100 - }, - { - title: "Role", - dataIndex: "role", - key: "role", - width: 50 - }, - { - title: "Actions", - dataIndex: "", - key: "actions", - width: 50, - render(user: User) { - return ( - - toggleRole(user.id, user.role === "admin" ? "user" : "admin") - }, - { - title: "Delete", - onClick: () => deleteUser(user.id) - } - ]} - /> - ) - } - } - ] - - return ( - - {!users && Loading...} - {users && ( - -
{users.length} users
-
- )} - {users &&
} - - ) -} - -export default UserTable diff --git a/client/app/admin/page.tsx b/client/app/admin/page.tsx deleted file mode 100644 index 3180f6d0..00000000 --- a/client/app/admin/page.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { getAllPosts, getAllUsers } from "@lib/server/prisma" -import { getCurrentUser } from "@lib/server/session" -import { notFound } from "next/navigation" -import styles from "./components/admin.module.css" -import PostTable from "./components/post-table" -import UserTable from "./components/user-table" - -const AdminPage = async () => { - const user = await getCurrentUser() - if (!user) { - return notFound() - } - - if (user.role !== "admin") { - return notFound() - } - - const posts = await getAllPosts() - const users = await getAllUsers() - - return ( -
-

Administration

-
- - -
-
- ) -} - -export default AdminPage diff --git a/client/app/components/button-dropdown/index.tsx b/client/app/components/button-dropdown/index.tsx index c533c558..87c665b8 100644 --- a/client/app/components/button-dropdown/index.tsx +++ b/client/app/components/button-dropdown/index.tsx @@ -1,9 +1,8 @@ import Button from "@components/button" -import React, { useCallback, useEffect } from "react" -import { useState } from "react" +import React from "react" import styles from "./dropdown.module.css" -import DownIcon from "@geist-ui/icons/arrowDown" import * as DropdownMenu from "@radix-ui/react-dropdown-menu" +import { ArrowDown } from "react-feather" type Props = { type?: "primary" | "secondary" loading?: boolean @@ -35,7 +34,7 @@ const ButtonDropdown: React.FC< asChild > {/* setExpanded should occur elsewhere; we don't want to close if they change themes */} diff --git a/client/app/components/note/note.module.css b/client/app/components/note/note.module.css index 739b3cd4..53e3f640 100644 --- a/client/app/components/note/note.module.css +++ b/client/app/components/note/note.module.css @@ -2,8 +2,6 @@ color: var(--fg); margin: 0; padding: var(--gap); - margin-top: 0.5em; - margin-bottom: 0.5em; border-radius: var(--radius); } diff --git a/client/app/components/password-modal/index.tsx b/client/app/components/password-modal/index.tsx index c15aae6e..90e28c5b 100644 --- a/client/app/components/password-modal/index.tsx +++ b/client/app/components/password-modal/index.tsx @@ -1,5 +1,9 @@ -import { Modal, Note, Spacer, Input } from "@geist-ui/core/dist" +import Button from "@components/button" +import Input from "@components/input" +import Note from "@components/note" +import * as Dialog from "@radix-ui/react-dialog" import { useState } from "react" +import styles from "./modal.module.css" type Props = { creating: boolean @@ -34,47 +38,60 @@ const PasswordModal = ({ return ( <> - {/* TODO: investigate disableBackdropClick not updating state? */} - { - - Enter a password - - {!error && creating && ( - - This doesn't protect your post from the server - administrator. - - )} - {error && ( - - {error} - - )} - - setPassword(e.target.value)} - /> - {creating && ( - setConfirmPassword(e.target.value)} - /> - )} - - - Cancel - - Submit - + { + if (!open) onClose() + }} + > + {/* Enter a password */} + + + + + {creating ? "Create a password" : "Enter password"} + + + {creating + ? "Enter a password to protect your post" + : "Enter the password to access the post"} + +
+ {error && {error}} + setPassword(e.currentTarget.value)} + /> + {creating && ( + setConfirmPassword(e.currentTarget.value)} + /> + )} + {!error && creating && ( + + This doesn't protect your post from the server + administrator. + + )} +
+ + + + +
+
+
} ) diff --git a/client/app/components/password-modal/modal.module.css b/client/app/components/password-modal/modal.module.css new file mode 100644 index 00000000..d7df1aa5 --- /dev/null +++ b/client/app/components/password-modal/modal.module.css @@ -0,0 +1,66 @@ +.overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0,0,0,0.5); + z-index: 1; +} + +.content { + background-color: var(--bg); + border-radius: var(--radius); + box-shadow: hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px; + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 90vw; + max-width: 450px; + max-height: 85vh; + padding: 25px; + animation: contentShow 150ms cubic-bezier(0.16, 1, 0.3, 1); + z-index: 2; + border: 1px solid var(--border); +} + +.fieldset { + border: none; + padding: 0; + margin: 0; + display: flex; + flex-direction: column; + gap: var(--gap-quarter); + margin-bottom: var(--gap-half); +} + +.content:focus { + outline: none; +} + +.close { + display: flex; + justify-content: flex-end; + width: 100%; +} + +@keyframes overlayShow { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes contentShow { + from { + opacity: 0; + transform: translate(-50%, -48%) scale(0.96); + } + to { + opacity: 1; + transform: translate(-50%, -50%) scale(1); + } +} diff --git a/client/app/components/post-list/list-item.tsx b/client/app/components/post-list/list-item.tsx index 46482589..d5458c68 100644 --- a/client/app/components/post-list/list-item.tsx +++ b/client/app/components/post-list/list-item.tsx @@ -1,11 +1,8 @@ import VisibilityBadge from "../badges/visibility-badge" import FadeIn from "@components/fade-in" -import Trash from "@geist-ui/icons/trash" import ExpirationBadge from "@components/badges/expiration-badge" import CreatedAgoBadge from "@components/badges/created-ago-badge" -import Edit from "@geist-ui/icons/edit" import { useRouter } from "next/navigation" -import Parent from "@geist-ui/icons/arrowUpCircle" import styles from "./list-item.module.css" import Link from "@components/link" import type { PostWithFiles } from "@lib/server/prisma" @@ -14,6 +11,7 @@ import Tooltip from "@components/tooltip" import Badge from "@components/badges/badge" import Card from "@components/card" import Button from "@components/button" +import { ArrowUpCircle, Edit, Trash } from "react-feather" // TODO: isOwner should default to false so this can be used generically const ListItem = ({ @@ -55,7 +53,7 @@ const ListItem = ({ {post.parentId && (