pull/150/head
Max Leiter 3 years ago
parent 24cf4a7c68
commit 2c62818174

@ -123,7 +123,7 @@ function Auth({
width="100%"
aria-label="Password"
/>
<Button width={"100%"} type="submit" loading={submitting}>
<Button type="submit">
Sign {signText}
</Button>
</>

@ -48,17 +48,9 @@ export const PostButtons = ({
return (
<span className={styles.buttons}>
<ButtonGroup verticalIfMobile>
<Button iconLeft={<Edit />} onClick={editACopy}>
Edit a Copy
</Button>
{parentId && (
<Button iconLeft={<ArrowUpCircle />} onClick={viewParentClick}>
View Parent
</Button>
)}
<Button onClick={downloadClick} iconLeft={<Archive />}>
Download as ZIP Archive
</Button>
<Button onClick={editACopy}>Edit a Copy</Button>
{parentId && <Button onClick={viewParentClick}>View Parent</Button>}
<Button onClick={downloadClick}>Download as ZIP Archive</Button>
<FileDropdown loading={loading} files={files || []} />
</ButtonGroup>
</span>

@ -87,10 +87,9 @@ const APIKeys = ({
<Button
type="button"
onClick={onCreateTokenClick}
loading={submitting}
disabled={!newToken}
>
Submit
{submitting ? <Spinner /> : "Submit"}
</Button>
</fieldset>
</form>

@ -9,6 +9,7 @@ import { useEffect, useState } from "react"
import styles from "./profile.module.css"
import useSWR from "swr"
import { User } from "@prisma/client"
import { Spinner } from "@components/spinner"
function Profile() {
const { session } = useSessionSWR()
@ -143,9 +144,7 @@ function Profile() {
</TooltipComponent>
</div> */}
<Button type="submit" loading={submitting}>
Submit
</Button>
<Button type="submit">{submitting ? <Spinner /> : "Submit"}</Button>
</form>
</>
)

@ -1,165 +0,0 @@
/** Based on https://github.com/pacocoursey/cmdk **/
.cmdk[cmdk-root] {
overflow: hidden;
font-family: var(--font-sans);
box-shadow: 0 0 0 1px var(--lighter-gray), 0 4px 16px rgba(0, 0, 0, 0.2);
transition: transform 100ms ease;
border-radius: var(--radius);
.dark & {
background: rgba(22, 22, 22, 0.7);
}
}
.cmdk {
/* centered */
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 999999;
/* size */
max-width: 640px;
width: 100%;
[cmdk-list] {
background: var(--bg);
height: 500px;
overflow: auto;
overscroll-behavior: contain;
}
[cmdk-input] {
font-family: var(--font-sans);
width: 100%;
font-size: 17px;
padding: 8px 8px 16px 8px;
outline: none;
/* background: var(--lightest-gray); */
color: var(--fg);
&::placeholder {
color: var(--gray);
}
}
[cmdk-badge] {
height: 20px;
background: var(--grayA3);
display: inline-flex;
align-items: center;
padding: 0 8px;
font-size: 12px;
color: var(--grayA11);
border-radius: 4px;
margin: 4px 0 4px 4px;
user-select: none;
text-transform: capitalize;
font-weight: 500;
}
[cmdk-item] {
content-visibility: auto;
cursor: pointer;
height: 48px;
border-radius: 8px;
font-size: 14px;
display: flex;
align-items: center;
gap: 8px;
padding: 0 16px;
color: var(--darker-gray);
user-select: none;
will-change: background, color;
transition: all 150ms ease;
transition-property: none;
background: var(--bg);
&[aria-selected="true"] {
background: var(--lightest-gray);
color: var(--fg);
}
&[aria-disabled="true"] {
/* TODO: improve this */
color: var(--bg);
cursor: not-allowed;
}
&:active {
transition-property: background;
background: var(--bg);
}
& + [cmdk-item] {
margin-top: 4px;
}
svg {
width: 18px;
height: 18px;
}
}
[cmdk-list] {
max-height: 400px;
overflow: auto;
overscroll-behavior: contain;
transition: 100ms ease;
transition-property: height;
}
[cmdk-shortcuts] {
display: flex;
margin-left: auto;
gap: 8px;
kbd {
font-family: var(--font-sans);
font-size: 12px;
min-width: 20px;
padding: var(--gap-half);
height: 20px;
border-radius: 4px;
color: var(--fg);
background: var(--light-gray);
display: inline-flex;
align-items: center;
justify-content: center;
text-transform: uppercase;
}
}
[cmdk-separator] {
height: 1px;
width: 100%;
background: var(--light-gray);
margin: 4px 0;
}
*:not([hidden]) + [cmdk-group] {
margin-top: var(--gap);
}
[cmdk-group-heading] {
user-select: none;
font-size: 12px;
color: var(--gray);
padding: 0 var(--gap);
display: flex;
align-items: center;
margin-bottom: var(--gap);
margin-top: var(--gap);
}
[cmdk-empty] {
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
height: 48px;
white-space: pre-wrap;
color: var(--gray);
}
}

@ -0,0 +1,163 @@
"use client"
import * as React from "react"
import { DialogProps } from "@radix-ui/react-dialog"
import { Command as CommandPrimitive } from "cmdk"
import { Search } from "react-feather"
import { cn } from "@lib/cn"
import { Dialog, DialogContent } from "@components/dialog"
const Command = React.forwardRef<
React.ElementRef<typeof CommandPrimitive>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
>(({ className, ...props }, ref) => (
<CommandPrimitive
ref={ref}
className={cn(
"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
className
)}
{...props}
/>
))
Command.displayName = CommandPrimitive.displayName
type CommandDialogProps = DialogProps
const CommandDialog = React.forwardRef<
React.ElementRef<typeof Dialog>,
CommandDialogProps
>(({ children, ...props }, ref) => {
return (
<Dialog {...props}>
<DialogContent className="overflow-hidden p-0 shadow-2xl">
<Command
ref={ref}
className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5"
>
{children}
</Command>
</DialogContent>
</Dialog>
)
})
CommandDialog.displayName = Dialog.displayName
const CommandInput = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Input>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
>(({ className, ...props }, ref) => (
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
<CommandPrimitive.Input
ref={ref}
className={cn(
"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}
/>
</div>
))
CommandInput.displayName = CommandPrimitive.Input.displayName
const CommandList = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.List>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
>(({ className, ...props }, ref) => (
<CommandPrimitive.List
ref={ref}
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
{...props}
/>
))
CommandList.displayName = CommandPrimitive.List.displayName
const CommandEmpty = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Empty>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
>((props, ref) => (
<CommandPrimitive.Empty
ref={ref}
className="py-6 text-center text-sm"
{...props}
/>
))
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
const CommandGroup = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Group>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Group
ref={ref}
className={cn(
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
className
)}
{...props}
/>
))
CommandGroup.displayName = CommandPrimitive.Group.displayName
const CommandSeparator = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Separator
ref={ref}
className={cn("-mx-1 h-px bg-border", className)}
{...props}
/>
))
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
const CommandItem = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...props}
/>
))
CommandItem.displayName = CommandPrimitive.Item.displayName
const CommandShortcut = ({
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn(
"ml-auto text-xs tracking-widest text-muted-foreground",
className
)}
{...props}
/>
)
}
CommandShortcut.displayName = "CommandShortcut"
export {
Command,
CommandDialog,
CommandInput,
CommandList,
CommandEmpty,
CommandGroup,
CommandItem,
CommandShortcut,
CommandSeparator
}

@ -1,16 +1,3 @@
body [cmdk-dialog] {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 999999;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.5);
/* backdrop-filter: blur(4px); */
transition: opacity 100ms ease;
pointer-events: none;
will-change: opacity;
}

@ -1,8 +1,12 @@
"use client"
import { Command } from "cmdk"
import {
CommandDialog,
CommandList,
CommandInput,
CommandEmpty
} from "./cmdk"
import { useEffect, useRef, useState } from "react"
import styles from "./cmdk.module.css"
import "./dialog.css"
import HomePage from "./pages/home"
import PostsPage from "./pages/posts"
@ -10,7 +14,7 @@ import PostsPage from "./pages/posts"
export type CmdKPage = "home" | "posts"
export default function CmdK() {
const [open, setOpen] = useState(false)
const ref = useRef<HTMLDivElement | null>(null)
const ref = useRef<HTMLDivElement>()
const [page, setPage] = useState<CmdKPage>("home")
// Toggle the menu when ⌘K is pressed
@ -53,21 +57,18 @@ export default function CmdK() {
}, [page])
return (
<Command.Dialog
<CommandDialog
open={open}
onOpenChange={setOpen}
label="Global Command Menu"
className={styles.cmdk}
ref={ref}
>
<Command.List>
<Command.Empty>No results found.</Command.Empty>
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
{page === "home" ? (
<HomePage setPage={setPage} setOpen={setOpen} />
) : null}
{page === "posts" ? <PostsPage setOpen={setOpen} /> : null}
</Command.List>
<Command.Input />
</Command.Dialog>
</CommandList>
<CommandInput />
</CommandDialog>
)
}

@ -1,4 +1,4 @@
import { Command } from "cmdk"
import { CommandItem } from "@components/cmdk/cmdk"
export default function Item({
children,
@ -12,7 +12,7 @@ export default function Item({
icon: React.ReactNode
}): JSX.Element {
return (
<Command.Item onSelect={onSelect}>
<CommandItem onSelect={onSelect}>
{icon}
{children}
{shortcut ? (
@ -22,6 +22,6 @@ export default function Item({
})}
</div>
) : null}
</Command.Item>
</CommandItem>
)
}

@ -1,9 +1,9 @@
import { Command } from "cmdk"
import { useTheme } from "next-themes"
import { useRouter } from "next/navigation"
import { FilePlus, Moon, Search, Settings, Sun } from "react-feather"
import { CmdKPage } from ".."
import Item from "../item"
import { CommandGroup } from "@components/cmdk/cmdk"
export default function HomePage({
setOpen,
@ -16,7 +16,7 @@ export default function HomePage({
const { setTheme, resolvedTheme } = useTheme()
return (
<>
<Command.Group heading="Posts">
<CommandGroup heading="Posts">
<Item
shortcut="R P"
onSelect={() => {
@ -36,8 +36,8 @@ export default function HomePage({
>
New Post
</Item>
</Command.Group>
<Command.Group heading="Settings">
</CommandGroup>
<CommandGroup heading="Settings">
<Item
shortcut="T"
onSelect={() => {
@ -57,7 +57,7 @@ export default function HomePage({
>
Go to Settings
</Item>
</Command.Group>
</CommandGroup>
</>
)
}

@ -0,0 +1,128 @@
"use client"
import * as React from "react"
import * as DialogPrimitive from "@radix-ui/react-dialog"
import { X } from "react-feather"
import { cn } from "@lib/cn"
const Dialog = DialogPrimitive.Root
const DialogTrigger = DialogPrimitive.Trigger
const DialogPortal = ({
className,
children,
...props
}: DialogPrimitive.DialogPortalProps) => (
<DialogPrimitive.Portal className={cn(className)} {...props}>
<div className="fixed inset-0 z-50 flex items-start justify-center sm:items-center">
{children}
</div>
</DialogPrimitive.Portal>
)
DialogPortal.displayName = DialogPrimitive.Portal.displayName
const DialogOverlay = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Overlay
ref={ref}
className={cn(
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm transition-all duration-100 data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in",
className
)}
{...props}
/>
))
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed z-50 grid w-full gap-4 rounded-b-lg border bg-background p-6 shadow-lg animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0",
className
)}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
))
DialogContent.displayName = DialogPrimitive.Content.displayName
const DialogHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-1.5 text-center sm:text-left",
className
)}
{...props}
/>
)
DialogHeader.displayName = "DialogHeader"
const DialogFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
)
DialogFooter.displayName = "DialogFooter"
const DialogTitle = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
))
DialogTitle.displayName = DialogPrimitive.Title.displayName
const DialogDescription = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
DialogDescription.displayName = DialogPrimitive.Description.displayName
export {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription
}

@ -1,24 +1,28 @@
import styles from "./list-item.module.css"
import { Card } from "@components/card"
import { Card, CardContent, CardHeader } from "@components/card"
import Skeleton from "@components/skeleton"
export const ListItemSkeleton = () => (
<li>
<Card style={{ overflowY: "scroll" }}>
{/* TODO: this is a bad way to do skeletons and is only accurate on desktop */}
<div style={{ display: "flex", gap: 16, marginBottom: 14 }}>
<div className={styles.title}>
{/* title */}
<Skeleton width={80} height={32} />
</div>
<CardHeader>
<div style={{ display: "flex", gap: 16, marginBottom: 14 }}>
<div className={styles.title}>
{/* title */}
<Skeleton width={80} height={32} />
</div>
<div className={styles.badges}>
<Skeleton width={60} height={32} />
<Skeleton width={60} height={32} />
<Skeleton width={60} height={32} />
<div className={styles.badges}>
<Skeleton width={60} height={32} />
<Skeleton width={60} height={32} />
<Skeleton width={60} height={32} />
</div>
</div>
</div>
<Skeleton width={100} height={32} />
</CardHeader>
<CardContent>
<Skeleton width={100} height={32} />
</CardContent>
</Card>
</li>
)

@ -27,9 +27,7 @@ const SettingsGroup = ({ title, children, skeleton }: Props) => {
return (
<Card>
<CardHeader>
<CardTitle>
<h4>{title}</h4>
</CardTitle>
<CardTitle>{title}</CardTitle>
</CardHeader>
<hr className="pb-4" />
<CardContent>

Loading…
Cancel
Save