bump next, use next-themes, remove geist icons and most of geist core

This commit is contained in:
Max Leiter 2022-11-29 00:43:04 -08:00
parent 23b7343963
commit fc79f7df4d
28 changed files with 313 additions and 695 deletions

View file

@ -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={<GithubIcon />}
iconLeft={<GitHub />}
onClick={(e) => {
e.preventDefault()
signIn("github", {

View file

@ -12,6 +12,11 @@
width: 100%;
}
.contentWrapper {
z-index: 1000;
}
.content {
list-style: none;
width: 100%;

View file

@ -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: <CodeIcon />
icon: <Code />
}
} else {
return {
@ -60,7 +58,7 @@ const FileDropdown = ({ files }: { files: File[] }) => {
Jump to {files.length} {files.length === 1 ? "file" : "files"}
</span>
</Popover.Trigger>
<Popover.Content>{content}</Popover.Content>
<Popover.Content className={styles.contentWrapper}>{content}</Popover.Content>
</Popover>
)
}

View file

@ -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"

View file

@ -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

View file

@ -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
</Button>
{post.parentId && (
<Button iconLeft={<Parent />} onClick={viewParentClick}>
<Button iconLeft={<ArrowUpCircle />} onClick={viewParentClick}>
View Parent
</Button>
)}

View file

@ -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 = {

View file

@ -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 (
<Popover
title={title}
content={
<>
{showTitle && <Popover.Item title>{title}</Popover.Item>}
{actions.map((action) => (
<Popover.Item onClick={action.onClick} key={action.title}>
{action.title}
</Popover.Item>
))}
</>
}
hideArrow
>
<Button iconRight={<MoreVertical />} auto></Button>
</Popover>
)
}
export default ActionDropdown

View file

@ -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;
}

View file

@ -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 (
<ActionDropdown
title="Actions"
actions={[
{
title: "Delete",
onClick: () => deletePost()
}
]}
/>
)
}
}
]
return (
<SettingsGroup title="Posts">
{!posts && <Fieldset.Subtitle>Loading...</Fieldset.Subtitle>}
{posts && (
<Fieldset.Subtitle>
<h5>{posts.length} posts</h5>
</Fieldset.Subtitle>
)}
{posts && <Table columns={tableColumns} data={tablePosts} />}
</SettingsGroup>
)
}
export default PostTable

View file

@ -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 (
<ActionDropdown
title="Actions"
actions={[
{
title: user.role === "admin" ? "Change role" : "Make admin",
onClick: () =>
toggleRole(user.id, user.role === "admin" ? "user" : "admin")
},
{
title: "Delete",
onClick: () => deleteUser(user.id)
}
]}
/>
)
}
}
]
return (
<SettingsGroup title="Users">
{!users && <Fieldset.Subtitle>Loading...</Fieldset.Subtitle>}
{users && (
<Fieldset.Subtitle>
<h5>{users.length} users</h5>
</Fieldset.Subtitle>
)}
{users && <Table columns={usernameColumns} data={tableUsers} />}
</SettingsGroup>
)
}
export default UserTable

View file

@ -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 (
<div className={styles.adminWrapper}>
<h2>Administration</h2>
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: "var(--gap)"
}}
>
<UserTable users={users} />
<PostTable posts={posts} />
</div>
</div>
)
}
export default AdminPage

View file

@ -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
>
<Button
iconLeft={<DownIcon />}
iconLeft={<ArrowDown />}
type={type}
className={styles.icon}
/>

View file

@ -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 {

View file

@ -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: <GitHubIcon />,
icon: <GitHub />,
value: "github"
},
{
@ -64,7 +64,7 @@ const Header = ({ signedIn = false, isAdmin = false }) => {
if (typeof window !== "undefined")
setTheme(theme === "light" ? "dark" : "light")
},
icon: theme === "light" ? <MoonIcon /> : <SunIcon />,
icon: theme === "light" ? <Moon /> : <Sun />,
value: "theme"
}
]
@ -72,7 +72,7 @@ const Header = ({ signedIn = false, isAdmin = false }) => {
if (isAdmin) {
defaultPages.push({
name: "Admin",
icon: <SettingsIcon />,
icon: <Settings />,
value: "admin",
href: "/admin"
})
@ -82,29 +82,30 @@ const Header = ({ signedIn = false, isAdmin = false }) => {
return [
{
name: "New",
icon: <NewIcon />,
icon: <PlusCircle />,
value: "new",
href: "/new"
},
{
name: "Yours",
icon: <YourIcon />,
icon: <User />,
value: "yours",
href: "/mine"
},
{
name: "Settings",
icon: <SettingsIcon />,
icon: <Settings />,
value: "settings",
href: "/settings"
},
{
name: "Sign Out",
icon: <SignOutIcon />,
icon: <UserX />,
value: "signout",
onClick: () => signOut({
callbackUrl: "/",
})
onClick: () =>
signOut({
callbackUrl: "/"
})
},
...defaultPages
]
@ -112,19 +113,19 @@ const Header = ({ signedIn = false, isAdmin = false }) => {
return [
{
name: "Home",
icon: <HomeIcon />,
icon: <Home />,
value: "home",
href: "/"
},
{
name: "Sign in",
icon: <SignInIcon />,
icon: <User />,
value: "signin",
href: "/signin"
},
{
name: "Sign up",
icon: <SignUpIcon />,
icon: <UserPlus />,
value: "signup",
href: "/signup"
},
@ -180,7 +181,7 @@ const Header = ({ signedIn = false, isAdmin = false }) => {
</div>
<div className={styles.controls}>
<Button onClick={() => setExpanded(!expanded)} aria-label="Menu">
<MenuIcon />
<Menu />
</Button>
</div>
{/* setExpanded should occur elsewhere; we don't want to close if they change themes */}

View file

@ -2,8 +2,6 @@
color: var(--fg);
margin: 0;
padding: var(--gap);
margin-top: 0.5em;
margin-bottom: 0.5em;
border-radius: var(--radius);
}

View file

@ -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? */}
{
<Modal visible={isOpen} disableBackdropClick={false}>
<Modal.Title>Enter a password</Modal.Title>
<Modal.Content>
{!error && creating && (
<Note type="warning" label="Warning">
This doesn&apos;t protect your post from the server
administrator.
</Note>
)}
{error && (
<Note type="error" label="Error">
{error}
</Note>
)}
<Spacer />
<Input
width={"100%"}
label="Password"
marginBottom={1}
htmlType="password"
placeholder="Password"
onChange={(e) => setPassword(e.target.value)}
/>
{creating && (
<Input
width={"100%"}
label="Confirm"
htmlType="password"
placeholder="Confirm Password"
onChange={(e) => setConfirmPassword(e.target.value)}
/>
)}
</Modal.Content>
<Modal.Action passive onClick={onClose}>
Cancel
</Modal.Action>
<Modal.Action onClick={onSubmit}>Submit</Modal.Action>
</Modal>
<Dialog.Root
open={isOpen}
onOpenChange={(open) => {
if (!open) onClose()
}}
>
{/* <Dialog.Trigger asChild>Enter a password</Dialog.Trigger> */}
<Dialog.Portal>
<Dialog.Overlay className={styles.overlay} />
<Dialog.Content
className={styles.content}
onEscapeKeyDown={onClose}
>
<Dialog.Title>
{creating ? "Create a password" : "Enter password"}
</Dialog.Title>
<Dialog.Description>
{creating
? "Enter a password to protect your post"
: "Enter the password to access the post"}
</Dialog.Description>
<fieldset className={styles.fieldset}>
{error && <Note type="error">{error}</Note>}
<Input
width={"100%"}
label="Password"
type="password"
placeholder="Password"
onChange={(e) => setPassword(e.currentTarget.value)}
/>
{creating && (
<Input
width={"100%"}
label="Confirm"
type="password"
placeholder="Confirm Password"
onChange={(e) => setConfirmPassword(e.currentTarget.value)}
/>
)}
{!error && creating && (
<Note type="warning">
This doesn&apos;t protect your post from the server
administrator.
</Note>
)}
</fieldset>
<Dialog.Close className={styles.close}>
<Button onClick={onSubmit}>Submit</Button>
<Button>Cancel</Button>
</Dialog.Close>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
}
</>
)

View file

@ -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);
}
}

View file

@ -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 && (
<Tooltip content={"View parent"}>
<Button
iconRight={<Parent />}
iconRight={<ArrowUpCircle />}
onClick={viewParentClick}
height={38}
/>

View file

@ -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 = () => {

View file

@ -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<UseThemeProps | null>(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<Props> = ({
defaultTheme,
children
}) => {
const [theme, setThemeState] = useState<Theme>(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 <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
}
export default ThemeClientContextProvider

View file

@ -1,28 +0,0 @@
import type { FunctionComponent, PropsWithChildren } from "react"
import ThemeClientContextProvider from "./ThemeClientContextProvider"
import ThemeServerContextProvider, {
useServerTheme
} from "./ThemeServerContextProvider"
const ThemeProviderWrapper: FunctionComponent<PropsWithChildren<{}>> = ({
children
}) => {
const theme = useServerTheme()
return (
<ThemeClientContextProvider defaultTheme={theme}>
{children}
</ThemeClientContextProvider>
)
}
const ThemeProvider: FunctionComponent<PropsWithChildren<{}>> = ({
children
}) => {
return (
<ThemeServerContextProvider>
<ThemeProviderWrapper>{children}</ThemeProviderWrapper>
</ThemeServerContextProvider>
)
}
export default ThemeProvider

View file

@ -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<Theme | null>(null)
export function useServerTheme(): Theme {
return useContext(ThemeContext)
}
const ThemeServerContextProvider: FunctionComponent<PropsWithChildren<{}>> = ({
children
}) => {
const cookiesList = cookies()
const theme = cookiesList.get(THEME_COOKIE_NAME)?.value ?? DEFAULT_THEME
return <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>
}
export default ThemeServerContextProvider

View file

@ -1,5 +0,0 @@
export type Theme = "light" | "dark"
export const DEFAULT_THEME: Theme = "light"
export const THEME_COOKIE_NAME = "drift-theme"

View file

@ -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 (
<html lang="en">
<head>
<script
dangerouslySetInnerHTML={{
__html: `
(function() {
var theme = document.cookie
.split('; ')
.find(row => row.startsWith('${THEME_COOKIE_NAME}='))
.split('=')[1];
document.documentElement.setAttribute('data-theme', theme);
})();
`
}}
/>
</head>
<ThemeProvider>
<ServerThemeProvider
enableSystem={true}
defaultTheme="dark"
disableTransitionOnChange
cookieName={"drift-theme"}
attribute="data-theme"
enableColorScheme={true}
>
<html lang="en">
<head />
<body className={styles.main}>
<LayoutWrapper
signedIn={Boolean(session?.user)}
@ -38,7 +30,7 @@ export default async function RootLayout({ children }: RootLayoutProps) {
{children}
</LayoutWrapper>
</body>
</ThemeProvider>
</html>
</html>
</ServerThemeProvider>
)
}

View file

@ -4,6 +4,7 @@ import Header from "@components/header"
import Page from "@components/page"
import { Toasts } from "@components/toasts"
import * as RadixTooltip from "@radix-ui/react-tooltip"
import { ThemeProvider } from "@wits/next-themes"
import { Toaster } from "react-hot-toast"
export function LayoutWrapper({
@ -19,7 +20,16 @@ export function LayoutWrapper({
<RadixTooltip.Provider delayDuration={200}>
<Toasts />
<Page>
<Header isAdmin={isAdmin} signedIn={signedIn} />
<ThemeProvider
enableSystem={true}
defaultTheme="dark"
disableTransitionOnChange
cookieName={"drift-theme"}
attribute="data-theme"
enableColorScheme={true}
>
<Header isAdmin={isAdmin} signedIn={signedIn} />
</ThemeProvider>
{children}
</Page>
</RadixTooltip.Provider>

View file

@ -14,30 +14,32 @@
},
"dependencies": {
"@geist-ui/core": "^2.3.8",
"@geist-ui/icons": "1.0.2",
"@next-auth/prisma-adapter": "^1.0.5",
"@next/eslint-plugin-next": "13.0.5-canary.3",
"@prisma/client": "^4.6.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",
"@wcj/markdown-to-html": "^2.1.2",
"@wits/next-themes": "^0.2.12",
"bcrypt": "^5.1.0",
"client-zip": "2.2.1",
"cookies-next": "^2.1.1",
"jest": "^29.3.1",
"next": "13.0.6-canary.1",
"next": "13.0.6-canary.2",
"next-auth": "^4.17.0",
"prisma": "^4.6.1",
"rc-table": "7.24.1",
"react": "18.2.0",
"react-datepicker": "4.8.0",
"react-dom": "18.2.0",
"react-dropzone": "14.2.3",
"react-feather": "^2.0.10",
"react-hot-toast": "^2.4.0",
"server-only": "^0.0.1",
"swr": "1.3.0",
"prisma": "^4.6.1",
"textarea-markdown-editor": "0.1.13",
"ts-jest": "^29.0.3"
},

View file

@ -2,11 +2,11 @@ lockfileVersion: 5.4
specifiers:
'@geist-ui/core': ^2.3.8
'@geist-ui/icons': 1.0.2
'@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
'@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
@ -17,6 +17,7 @@ specifiers:
'@types/react-datepicker': 4.4.1
'@types/react-dom': 18.0.3
'@wcj/markdown-to-html': ^2.1.2
'@wits/next-themes': ^0.2.12
bcrypt: ^5.1.0
client-zip: 2.2.1
clsx: ^1.2.1
@ -26,7 +27,7 @@ specifiers:
eslint-config-next: 13.0.3
jest: ^29.3.1
katex: ^0.16.3
next: 13.0.6-canary.1
next: 13.0.6-canary.2
next-auth: ^4.17.0
next-unused: 0.0.6
prettier: 2.6.2
@ -36,6 +37,7 @@ specifiers:
react-datepicker: 4.8.0
react-dom: 18.2.0
react-dropzone: 14.2.3
react-feather: ^2.0.10
react-hot-toast: ^2.4.0
server-only: ^0.0.1
sharp: ^0.31.2
@ -47,27 +49,29 @@ specifiers:
dependencies:
'@geist-ui/core': 2.3.8_biqbaboplfbrettd7655fr4n2y
'@geist-ui/icons': 1.0.2_zhza2kbnl2wkkf7vqdl3ton2f4
'@next-auth/prisma-adapter': 1.0.5_o53gfpk3vz2btjrokqfjjwwn3m
'@next/eslint-plugin-next': 13.0.5-canary.3
'@prisma/client': 4.6.1_prisma@4.6.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
'@radix-ui/react-tabs': 1.0.1_biqbaboplfbrettd7655fr4n2y
'@radix-ui/react-tooltip': 1.0.2_jbvntnid6ohjelon6ccj5dhg2u
'@wcj/markdown-to-html': 2.1.2
'@wits/next-themes': 0.2.12_hzq4dmqplfkom7c35ucps6atz4
bcrypt: 5.1.0
client-zip: 2.2.1
cookies-next: 2.1.1
jest: 29.3.1_@types+node@17.0.23
next: 13.0.6-canary.1_biqbaboplfbrettd7655fr4n2y
next-auth: 4.17.0_cejjzyjft5qpe7pbv5t5jzassa
next: 13.0.6-canary.2_biqbaboplfbrettd7655fr4n2y
next-auth: 4.17.0_hzq4dmqplfkom7c35ucps6atz4
prisma: 4.6.1
rc-table: 7.24.1_biqbaboplfbrettd7655fr4n2y
react: 18.2.0
react-datepicker: 4.8.0_biqbaboplfbrettd7655fr4n2y
react-dom: 18.2.0_react@18.2.0
react-dropzone: 14.2.3_react@18.2.0
react-feather: 2.0.10_react@18.2.0
react-hot-toast: 2.4.0_biqbaboplfbrettd7655fr4n2y
server-only: 0.0.1
swr: 1.3.0_react@18.2.0
@ -497,16 +501,6 @@ packages:
react-dom: 18.2.0_react@18.2.0
dev: false
/@geist-ui/icons/1.0.2_zhza2kbnl2wkkf7vqdl3ton2f4:
resolution: {integrity: sha512-Npfa0NW6fQ31qw/+iMPWbs1hAcJ/3FqBjSLYgEfITDqy/3TJFpFKeVyK04AC/hTmYTsdNruVYczqPNcham5FOQ==}
peerDependencies:
'@geist-ui/core': '>=1.0.0'
react: '>=16.13.0'
dependencies:
'@geist-ui/core': 2.3.8_biqbaboplfbrettd7655fr4n2y
react: 18.2.0
dev: false
/@humanwhocodes/config-array/0.11.7:
resolution: {integrity: sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==}
engines: {node: '>=10.10.0'}
@ -819,7 +813,7 @@ packages:
next-auth: ^4
dependencies:
'@prisma/client': 4.6.1_prisma@4.6.1
next-auth: 4.17.0_cejjzyjft5qpe7pbv5t5jzassa
next-auth: 4.17.0_hzq4dmqplfkom7c35ucps6atz4
dev: false
/@next/bundle-analyzer/12.1.6:
@ -831,8 +825,8 @@ packages:
- utf-8-validate
dev: true
/@next/env/13.0.6-canary.1:
resolution: {integrity: sha512-L88vP2GvU2NvF5YSIDjqYzzJQRNDg3F08qE/pTLClsYXLusRWAJ1lgI9sZFqLrMbZuj2xd0hWYyYjCrrg/LLLw==}
/@next/env/13.0.6-canary.2:
resolution: {integrity: sha512-2qCq6TDCDRGYWYy7gmugOdDZ+d770uMW3+Kxv50CCLIKtCvO6TS+v2ObzHltkvjMI3su7LAaHgGVXHLTx1fO4w==}
dev: false
/@next/eslint-plugin-next/13.0.3:
@ -847,8 +841,8 @@ packages:
glob: 7.1.7
dev: false
/@next/swc-android-arm-eabi/13.0.6-canary.1:
resolution: {integrity: sha512-3/ZSIsm2yYZXUyqupAri4+6J97wVdHIP2yrcTLoKdYQKm1lp1z5hIZLtxQCV4vLyYNlNIafvIqeasfYWuYzCgw==}
/@next/swc-android-arm-eabi/13.0.6-canary.2:
resolution: {integrity: sha512-9wPxj5uzH3DUNP7dZg9snd6FM7LY/LHvuOgoofAO2x3j0A1udA2sq96T09w3nzRBlRgIL6PKlH/P3kT9+Yihsg==}
engines: {node: '>= 10'}
cpu: [arm]
os: [android]
@ -856,8 +850,8 @@ packages:
dev: false
optional: true
/@next/swc-android-arm64/13.0.6-canary.1:
resolution: {integrity: sha512-/J2EXT8L82HgV8sf2SzSdpTuT5gtpPGgekPRCF1ttYyN8FAR/VHPKOLYTbKz3NQ95ogttrW28RFPsMSekQpLaQ==}
/@next/swc-android-arm64/13.0.6-canary.2:
resolution: {integrity: sha512-pDDNYMFD3T5WTX0fjKXqYxVcUt3YKr4PXfvH3aci74Vrm732ky7WKhDEEbl0EfHtpQWeJJo5GlrUOhF/a0Lu8Q==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [android]
@ -865,8 +859,8 @@ packages:
dev: false
optional: true
/@next/swc-darwin-arm64/13.0.6-canary.1:
resolution: {integrity: sha512-n+IxXIJSEm3HdumauULSZCehyKyQ0EfWU/qf5oMjyGOQ/sHQfgT5sGYtfnnNvvhSlVgFhyz7MalPRwJQWAIIZQ==}
/@next/swc-darwin-arm64/13.0.6-canary.2:
resolution: {integrity: sha512-SfeNfQ/gDt9DM1eHIYAapE1PMcI6lru/eqI0jxFupHlgmE2e1zLyhUlADSFqCEQT5sVdm0rWg6Ne7KyYc7X6VQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
@ -874,8 +868,8 @@ packages:
dev: false
optional: true
/@next/swc-darwin-x64/13.0.6-canary.1:
resolution: {integrity: sha512-0gQ2zLBFJT8rO080APvY/fHxjSIRVD7VpF0C12BXroFJ3XMnCoa6scniVgKwV4pjhTtlJoLSk3y4wNITyouLDQ==}
/@next/swc-darwin-x64/13.0.6-canary.2:
resolution: {integrity: sha512-y9mJQK4DfLiXxcM+85Y5mt5tPIbiW+e1UI1W1nJOGUoQsYcaKfmEDcFxblxFDrTe952D7bv0SHNW984cugIpcw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
@ -883,8 +877,8 @@ packages:
dev: false
optional: true
/@next/swc-freebsd-x64/13.0.6-canary.1:
resolution: {integrity: sha512-zAnm1JtxgrNkjiBef7U8lO9JOqNhy13mKA0Z27XCeAunhaar0hNZNHnKUlISVhAZovpHs96fp0mm7Skw0WCkpA==}
/@next/swc-freebsd-x64/13.0.6-canary.2:
resolution: {integrity: sha512-kvd/30cQveHC85Ml8rLkh7kWJYNcHgZin6QXYNwJ/pa0a5cOtHkBoyHr/49x4F9wRHB3YGdYHTBY9jRJbVH5HQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [freebsd]
@ -892,8 +886,8 @@ packages:
dev: false
optional: true
/@next/swc-linux-arm-gnueabihf/13.0.6-canary.1:
resolution: {integrity: sha512-JJCdGBEeNzGXm0AQUfVY9x3C3WvxCcawZ1tCYYkOqLD21Dj5gDTNSZT2cAGFDovfyn5hN/Vltf20Zs8ilUPr1w==}
/@next/swc-linux-arm-gnueabihf/13.0.6-canary.2:
resolution: {integrity: sha512-1uaCAqiPz2DcjfK5Nb/tlrFJuKHz2SCqF8ghQg/dkPNx3B5u2js6irIcCu/Rcz0fGk0mI97Rzx3IeLvwiXsn+A==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
@ -901,8 +895,8 @@ packages:
dev: false
optional: true
/@next/swc-linux-arm64-gnu/13.0.6-canary.1:
resolution: {integrity: sha512-oE9D+Mm240fRpZWZBhFiztmJ/D7uwQ3jfOZcQVf1aN3P+9De+5jyv2TKoHrjrRh5xjloTEDIpt2wNKimlwZvkg==}
/@next/swc-linux-arm64-gnu/13.0.6-canary.2:
resolution: {integrity: sha512-5GlB7eRwZ1posKCaZnJB09JtsYx1YZ3USZ2OUyQimFEXUQWbOG/dR/+faKdml6LqxFUyOXnpwwZbTFZNYd8tmQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
@ -910,8 +904,8 @@ packages:
dev: false
optional: true
/@next/swc-linux-arm64-musl/13.0.6-canary.1:
resolution: {integrity: sha512-+DukK2LdoZo4Ds0o2XGAC9324O9auxvHMF4MwDzrXrherBFEeSZUDIxcz4zu5/pd8dyQ8JY9nwILJEevla23pA==}
/@next/swc-linux-arm64-musl/13.0.6-canary.2:
resolution: {integrity: sha512-//xak9BwCQzJrD89n5JTaWz2NFvIwzuvvCHdP8dBDyizrDwhSQ6r5p4IE49mZ8d8VfIGQMG6S8FK/M2ocw574w==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
@ -919,8 +913,8 @@ packages:
dev: false
optional: true
/@next/swc-linux-x64-gnu/13.0.6-canary.1:
resolution: {integrity: sha512-1bULat6aif5E48s23lAh4vmuVogxz3arXMawlqHwHqwJWpzxF2vyAl3Ilh4mXJnD1xvwiGRH7Aov7HMQJhF2+g==}
/@next/swc-linux-x64-gnu/13.0.6-canary.2:
resolution: {integrity: sha512-SeQZy+Fbm9YUedtNjAdOjgtXABmZItxjZ3RENO1RkIt7vJrBpi4emFkMAvsEYJBspM30aWP8g8fS3kO11ETdvw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
@ -928,8 +922,8 @@ packages:
dev: false
optional: true
/@next/swc-linux-x64-musl/13.0.6-canary.1:
resolution: {integrity: sha512-LN9qXV3Rh1jMcaSXg5DGZYbN6nVCn6A/aQBTw4K5DWu7bHTiEkq4d7/OZN+gfJcqW8BuRtG4zLeraae/1RO9pw==}
/@next/swc-linux-x64-musl/13.0.6-canary.2:
resolution: {integrity: sha512-kUtDYdhKSSfkMn8jgAkfE5pyamMhu5vRNFUr+mF5i1yz05FsBYApDlMcLMC5lhB5JDSta/kDj1gmubZqzX3gNw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
@ -937,8 +931,8 @@ packages:
dev: false
optional: true
/@next/swc-win32-arm64-msvc/13.0.6-canary.1:
resolution: {integrity: sha512-792QCYO+lF4N1c2bwYVwhLwMJMhnmvQRVOnCmRlGhbaZJ0f6ZuIYCxjqAqV8Por+u0ErenRMv5BGleK8wHfQJA==}
/@next/swc-win32-arm64-msvc/13.0.6-canary.2:
resolution: {integrity: sha512-orQDh3ozGZXGWcocHSPy4f3CxIQMUpHfWk87e6bYPqu4g5Xt7SfBIx4RTopovyc5x3rGswV5zvEtn0mrSlPOFA==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
@ -946,8 +940,8 @@ packages:
dev: false
optional: true
/@next/swc-win32-ia32-msvc/13.0.6-canary.1:
resolution: {integrity: sha512-hwL9JjT7C1ZP+Wj7F4QIoewEErqc70Ax0aeKqQZdKU57djmIWvvvnyh9p/uUQFHLc3M4Um+XvtqpyFZB6RcYbg==}
/@next/swc-win32-ia32-msvc/13.0.6-canary.2:
resolution: {integrity: sha512-GrF/vCKyDUfYOght5lV4RFjV7X+pM8YYrfxo8eBYzSwFW/vWtQCP5m85idNQ/XlJnxUFmhQG9+CCQac+lwKcBQ==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
@ -955,8 +949,8 @@ packages:
dev: false
optional: true
/@next/swc-win32-x64-msvc/13.0.6-canary.1:
resolution: {integrity: sha512-KA6/9W7ZEfkN/ecH8f/fg+WyQaJnRG/UE2IKOdQHbL4uVtHJk5PQmYT+nBZFVnbNHJB2ouNmL4pFJM/7JjNBww==}
/@next/swc-win32-x64-msvc/13.0.6-canary.2:
resolution: {integrity: sha512-zjd7KUJ+wrrWzfR/THoIUGnoa0gnlNV2c07TFk5bFHrjP4VVTQvw1P3wqzx+1bbJB+6O4pwkr6IW3axoy5vtaQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
@ -1070,6 +1064,33 @@ packages:
react: 18.2.0
dev: false
/@radix-ui/react-dialog/1.0.2_jbvntnid6ohjelon6ccj5dhg2u:
resolution: {integrity: sha512-EKxxp2WNSmUPkx4trtWNmZ4/vAYEg7JkAfa1HKBUnaubw9eHzf1Orr9B472lJYaYz327RHDrd4R95fsw7VR8DA==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.20.1
'@radix-ui/primitive': 1.0.0
'@radix-ui/react-compose-refs': 1.0.0_react@18.2.0
'@radix-ui/react-context': 1.0.0_react@18.2.0
'@radix-ui/react-dismissable-layer': 1.0.2_biqbaboplfbrettd7655fr4n2y
'@radix-ui/react-focus-guards': 1.0.0_react@18.2.0
'@radix-ui/react-focus-scope': 1.0.1_biqbaboplfbrettd7655fr4n2y
'@radix-ui/react-id': 1.0.0_react@18.2.0
'@radix-ui/react-portal': 1.0.1_biqbaboplfbrettd7655fr4n2y
'@radix-ui/react-presence': 1.0.0_biqbaboplfbrettd7655fr4n2y
'@radix-ui/react-primitive': 1.0.1_biqbaboplfbrettd7655fr4n2y
'@radix-ui/react-slot': 1.0.1_react@18.2.0
'@radix-ui/react-use-controllable-state': 1.0.0_react@18.2.0
aria-hidden: 1.2.1_ulhmhxukhxjgxaybrsjlob7ffu
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
react-remove-scroll: 2.5.5_ulhmhxukhxjgxaybrsjlob7ffu
transitivePeerDependencies:
- '@types/react'
dev: false
/@radix-ui/react-direction/1.0.0_react@18.2.0:
resolution: {integrity: sha512-2HV05lGUgYcA6xgLQ4BKPDmtL+QbIZYH5fCOTAOOcJ5O0QbWS3i9lKaurLzliYUDhORI2Qr3pyjhJh44lKA3rQ==}
peerDependencies:
@ -1719,6 +1740,18 @@ packages:
- supports-color
dev: false
/@wits/next-themes/0.2.12_hzq4dmqplfkom7c35ucps6atz4:
resolution: {integrity: sha512-P/qtLW68n4xBLT8UfLkCD/0jmF0yWxdf3xpGCDbfR6WuvK2brJDQ0DhPbhsucGkJ42ArA6ItKqcIo7/cnKzhGg==}
peerDependencies:
next: '*'
react: '*'
react-dom: '*'
dependencies:
next: 13.0.6-canary.2_biqbaboplfbrettd7655fr4n2y
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
dev: false
/abbrev/1.1.1:
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
dev: false
@ -5215,7 +5248,7 @@ packages:
dev: true
optional: true
/next-auth/4.17.0_cejjzyjft5qpe7pbv5t5jzassa:
/next-auth/4.17.0_hzq4dmqplfkom7c35ucps6atz4:
resolution: {integrity: sha512-aN2tdnjS0MDeUpB2tBDOaWnegkgeMWrsccujbXRGMJ607b+EwRcy63MFGSr0OAboDJEe0902piXQkt94GqF8Qw==}
engines: {node: ^12.19.0 || ^14.15.0 || ^16.13.0 || ^18.12.0}
peerDependencies:
@ -5231,7 +5264,7 @@ packages:
'@panva/hkdf': 1.0.2
cookie: 0.5.0
jose: 4.11.0
next: 13.0.6-canary.1_biqbaboplfbrettd7655fr4n2y
next: 13.0.6-canary.2_biqbaboplfbrettd7655fr4n2y
oauth: 0.9.15
openid-client: 5.3.0
preact: 10.11.2
@ -5252,8 +5285,8 @@ packages:
- supports-color
dev: true
/next/13.0.6-canary.1_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-aLHWxU8tMcsVKyStTQvfATZ8TzX/X/VbfV1erVn+pF4uI5+ETvAGWO1geo1FrLzrW+xB/h+9UPAUiqh21oVZEA==}
/next/13.0.6-canary.2_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-f8/fUo42tlc+IPE7Yo0dtfW08EEsnLel0cjEqv3OqJwOJfGV3xdJAfvPJz0iyGGMx2ig2TS5VzRL/riyBsa/Gg==}
engines: {node: '>=14.6.0'}
hasBin: true
peerDependencies:
@ -5270,7 +5303,7 @@ packages:
sass:
optional: true
dependencies:
'@next/env': 13.0.6-canary.1
'@next/env': 13.0.6-canary.2
'@swc/helpers': 0.4.14
caniuse-lite: 1.0.30001431
postcss: 8.4.14
@ -5278,19 +5311,19 @@ packages:
react-dom: 18.2.0_react@18.2.0
styled-jsx: 5.1.0_react@18.2.0
optionalDependencies:
'@next/swc-android-arm-eabi': 13.0.6-canary.1
'@next/swc-android-arm64': 13.0.6-canary.1
'@next/swc-darwin-arm64': 13.0.6-canary.1
'@next/swc-darwin-x64': 13.0.6-canary.1
'@next/swc-freebsd-x64': 13.0.6-canary.1
'@next/swc-linux-arm-gnueabihf': 13.0.6-canary.1
'@next/swc-linux-arm64-gnu': 13.0.6-canary.1
'@next/swc-linux-arm64-musl': 13.0.6-canary.1
'@next/swc-linux-x64-gnu': 13.0.6-canary.1
'@next/swc-linux-x64-musl': 13.0.6-canary.1
'@next/swc-win32-arm64-msvc': 13.0.6-canary.1
'@next/swc-win32-ia32-msvc': 13.0.6-canary.1
'@next/swc-win32-x64-msvc': 13.0.6-canary.1
'@next/swc-android-arm-eabi': 13.0.6-canary.2
'@next/swc-android-arm64': 13.0.6-canary.2
'@next/swc-darwin-arm64': 13.0.6-canary.2
'@next/swc-darwin-x64': 13.0.6-canary.2
'@next/swc-freebsd-x64': 13.0.6-canary.2
'@next/swc-linux-arm-gnueabihf': 13.0.6-canary.2
'@next/swc-linux-arm64-gnu': 13.0.6-canary.2
'@next/swc-linux-arm64-musl': 13.0.6-canary.2
'@next/swc-linux-x64-gnu': 13.0.6-canary.2
'@next/swc-linux-x64-musl': 13.0.6-canary.2
'@next/swc-win32-arm64-msvc': 13.0.6-canary.2
'@next/swc-win32-ia32-msvc': 13.0.6-canary.2
'@next/swc-win32-x64-msvc': 13.0.6-canary.2
transitivePeerDependencies:
- '@babel/core'
- babel-plugin-macros
@ -5977,6 +6010,15 @@ packages:
/react-fast-compare/3.2.0:
resolution: {integrity: sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==}
/react-feather/2.0.10_react@18.2.0:
resolution: {integrity: sha512-BLhukwJ+Z92Nmdcs+EMw6dy1Z/VLiJTzEQACDUEnWMClhYnFykJCGWQx+NmwP/qQHGX/5CzQ+TGi8ofg2+HzVQ==}
peerDependencies:
react: '>=16.8.6'
dependencies:
prop-types: 15.8.1
react: 18.2.0
dev: false
/react-hot-toast/2.4.0_biqbaboplfbrettd7655fr4n2y:
resolution: {integrity: sha512-qnnVbXropKuwUpriVVosgo8QrB+IaPJCpL8oBI6Ov84uvHZ5QQcTp2qg6ku2wNfgJl6rlQXJIQU5q+5lmPOutA==}
engines: {node: '>=10'}