- 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 (
-
- )
-}
-
-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
>
}
+ iconLeft={}
type={type}
className={styles.icon}
/>
diff --git a/client/app/components/header/header.module.css b/client/app/components/header/header.module.css
index 87c94290..a145f453 100644
--- a/client/app/components/header/header.module.css
+++ b/client/app/components/header/header.module.css
@@ -35,6 +35,11 @@
z-index: 1000;
display: flex;
flex-direction: column;
+ background: var(--bg);
+ width: 100%;
+ height: 100%;
+ top: 70px;
+ left: 0;
}
.mobile button {
diff --git a/client/app/components/header/index.tsx b/client/app/components/header/index.tsx
index 486a2058..10e462d0 100644
--- a/client/app/components/header/index.tsx
+++ b/client/app/components/header/index.tsx
@@ -1,28 +1,28 @@
"use client"
-
-import { useBodyScroll, useMediaQuery } from "@geist-ui/core/dist"
+import { useBodyScroll, useMediaQuery } from "@geist-ui/core/dist"
import { useEffect, useState } from "react"
import styles from "./header.module.css"
-import HomeIcon from "@geist-ui/icons/home"
-import MenuIcon from "@geist-ui/icons/menu"
-import GitHubIcon from "@geist-ui/icons/github"
-import SignOutIcon from "@geist-ui/icons/userX"
-import SignInIcon from "@geist-ui/icons/user"
-import SignUpIcon from "@geist-ui/icons/userPlus"
-import NewIcon from "@geist-ui/icons/plusCircle"
-import YourIcon from "@geist-ui/icons/list"
-import MoonIcon from "@geist-ui/icons/moon"
-import SettingsIcon from "@geist-ui/icons/settings"
-import SunIcon from "@geist-ui/icons/sun"
// import useUserData from "@lib/hooks/use-user-data"
import Link from "next/link"
import { usePathname } from "next/navigation"
import { signOut } from "next-auth/react"
-import { useTheme } from "@components/theme/ThemeClientContextProvider"
import Button from "@components/button"
import clsx from "clsx"
+import { useTheme } from "@wits/next-themes"
+import {
+ GitHub,
+ Home,
+ Menu,
+ Moon,
+ PlusCircle,
+ Settings,
+ Sun,
+ User,
+ UserPlus,
+ UserX
+} from "react-feather"
type Tab = {
name: string
@@ -55,7 +55,7 @@ const Header = ({ signedIn = false, isAdmin = false }) => {
{
name: isMobile ? "GitHub" : "",
href: "https://github.com/maxleiter/drift",
- icon: ,
+ icon: ,
value: "github"
},
{
@@ -64,7 +64,7 @@ const Header = ({ signedIn = false, isAdmin = false }) => {
if (typeof window !== "undefined")
setTheme(theme === "light" ? "dark" : "light")
},
- icon: theme === "light" ? : ,
+ icon: theme === "light" ? : ,
value: "theme"
}
]
@@ -72,7 +72,7 @@ const Header = ({ signedIn = false, isAdmin = false }) => {
if (isAdmin) {
defaultPages.push({
name: "Admin",
- icon: ,
+ icon: ,
value: "admin",
href: "/admin"
})
@@ -82,29 +82,30 @@ const Header = ({ signedIn = false, isAdmin = false }) => {
return [
{
name: "New",
- icon: ,
+ icon: ,
value: "new",
href: "/new"
},
{
name: "Yours",
- icon: ,
+ icon: ,
value: "yours",
href: "/mine"
},
{
name: "Settings",
- icon: ,
+ icon: ,
value: "settings",
href: "/settings"
},
{
name: "Sign Out",
- icon: ,
+ icon: ,
value: "signout",
- onClick: () => signOut({
- callbackUrl: "/",
- })
+ onClick: () =>
+ signOut({
+ callbackUrl: "/"
+ })
},
...defaultPages
]
@@ -112,19 +113,19 @@ const Header = ({ signedIn = false, isAdmin = false }) => {
return [
{
name: "Home",
- icon: ,
+ icon: ,
value: "home",
href: "/"
},
{
name: "Sign in",
- icon: ,
+ icon: ,
value: "signin",
href: "/signin"
},
{
name: "Sign up",
- icon: ,
+ icon: ,
value: "signup",
href: "/signup"
},
@@ -180,7 +181,7 @@ const Header = ({ signedIn = false, isAdmin = false }) => {
{/* 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"}
+
+
+
+
+
+
+
+
+
}
>
)
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 && (
}
+ iconRight={}
onClick={viewParentClick}
height={38}
/>
diff --git a/client/app/components/scroll-to-top/index.tsx b/client/app/components/scroll-to-top/index.tsx
index 20262081..3caa3728 100644
--- a/client/app/components/scroll-to-top/index.tsx
+++ b/client/app/components/scroll-to-top/index.tsx
@@ -1,7 +1,7 @@
import Button from "@components/button"
import Tooltip from "@components/tooltip"
-import ChevronUp from "@geist-ui/icons/chevronUp"
import { useEffect, useState } from "react"
+import { ChevronUp } from "react-feather"
import styles from "./scroll.module.css"
const ScrollToTop = () => {
diff --git a/client/app/components/theme/ThemeClientContextProvider.tsx b/client/app/components/theme/ThemeClientContextProvider.tsx
deleted file mode 100644
index 1fead632..00000000
--- a/client/app/components/theme/ThemeClientContextProvider.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-"use client"
-
-import {
- FunctionComponent,
- PropsWithChildren,
- useCallback,
- useMemo
-} from "react"
-import React, { useContext, useState, createContext } from "react"
-import { DEFAULT_THEME, Theme, THEME_COOKIE_NAME } from "./theme"
-import { setCookie } from "cookies-next"
-
-interface UseThemeProps {
- theme: Theme
- setTheme: (theme: Theme) => void
-}
-
-const ThemeContext = createContext(null)
-
-export function useTheme(): {
- theme: Theme
- setTheme: (theme: Theme) => void
-} {
- return (
- useContext(ThemeContext) || {
- theme: DEFAULT_THEME,
- setTheme: () => {}
- }
- )
-}
-
-interface Props extends PropsWithChildren<{}> {
- defaultTheme: Theme
-}
-
-const ThemeClientContextProvider: FunctionComponent = ({
- defaultTheme,
- children
-}) => {
- const [theme, setThemeState] = useState(defaultTheme)
- const setCookieAndDocument = useCallback(
- (theme: Theme) => {
- setThemeState(theme)
- setCookie(THEME_COOKIE_NAME, theme)
- document.documentElement.setAttribute("data-theme", theme)
- },
- [setThemeState]
- )
-
- const setTheme = useCallback(
- (theme: Theme) => {
- setCookieAndDocument(theme)
- },
- [setCookieAndDocument]
- )
-
- const value = useMemo(() => ({ theme, setTheme }), [theme, setTheme])
-
- return {children}
-}
-
-export default ThemeClientContextProvider
diff --git a/client/app/components/theme/ThemeProvider.tsx b/client/app/components/theme/ThemeProvider.tsx
deleted file mode 100644
index a92e43cd..00000000
--- a/client/app/components/theme/ThemeProvider.tsx
+++ /dev/null
@@ -1,28 +0,0 @@
-import type { FunctionComponent, PropsWithChildren } from "react"
-import ThemeClientContextProvider from "./ThemeClientContextProvider"
-import ThemeServerContextProvider, {
- useServerTheme
-} from "./ThemeServerContextProvider"
-
-const ThemeProviderWrapper: FunctionComponent> = ({
- children
-}) => {
- const theme = useServerTheme()
- return (
-
- {children}
-
- )
-}
-
-const ThemeProvider: FunctionComponent> = ({
- children
-}) => {
- return (
-
- {children}
-
- )
-}
-
-export default ThemeProvider
diff --git a/client/app/components/theme/ThemeServerContextProvider.tsx b/client/app/components/theme/ThemeServerContextProvider.tsx
deleted file mode 100644
index 9b7454cd..00000000
--- a/client/app/components/theme/ThemeServerContextProvider.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import type { FunctionComponent, PropsWithChildren } from "react"
-// @ts-ignore -- createServerContext is not in @types/react atm
-import { useContext, createServerContext } from "react"
-import { cookies } from "next/headers"
-import { Theme, THEME_COOKIE_NAME } from "./theme"
-import { DEFAULT_THEME } from "./theme"
-
-const ThemeContext = createServerContext(null)
-
-export function useServerTheme(): Theme {
- return useContext(ThemeContext)
-}
-
-const ThemeServerContextProvider: FunctionComponent> = ({
- children
-}) => {
- const cookiesList = cookies()
- const theme = cookiesList.get(THEME_COOKIE_NAME)?.value ?? DEFAULT_THEME
- return {children}
-}
-
-export default ThemeServerContextProvider
diff --git a/client/app/components/theme/theme.tsx b/client/app/components/theme/theme.tsx
deleted file mode 100644
index a816d3aa..00000000
--- a/client/app/components/theme/theme.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-export type Theme = "light" | "dark"
-
-export const DEFAULT_THEME: Theme = "light"
-
-export const THEME_COOKIE_NAME = "drift-theme"
diff --git a/client/app/layout.tsx b/client/app/layout.tsx
index 8f6f1593..21068515 100644
--- a/client/app/layout.tsx
+++ b/client/app/layout.tsx
@@ -2,8 +2,7 @@ import "@styles/globals.css"
import { LayoutWrapper } from "./root-layout-wrapper"
import styles from "@styles/Home.module.css"
import { getSession } from "@lib/server/session"
-import ThemeProvider from "@components/theme/ThemeProvider"
-import { THEME_COOKIE_NAME } from "@components/theme/theme"
+import { ServerThemeProvider } from "@wits/next-themes"
interface RootLayoutProps {
children: React.ReactNode
@@ -13,23 +12,16 @@ export default async function RootLayout({ children }: RootLayoutProps) {
// TODO: this opts out of SSG
const session = await getSession()
return (
-
-
-