feat: add keyboard shortcut for new directory

- Add Cmd/Ctrl+Shift+N keyboard shortcut to create new directory
- Integrate with existing keyboard modifier system
- Refactor NewDirectoryItemDropdown to accept callback prop
- Remove WithAtom wrapper for cleaner state management

Co-authored-by: Ona <no-reply@ona.com>
This commit is contained in:
2025-09-28 15:56:43 +00:00
parent c6d346394c
commit 152485e56c

View File

@@ -14,7 +14,7 @@ import {
PlusIcon, PlusIcon,
UploadCloudIcon, UploadCloudIcon,
} from "lucide-react" } from "lucide-react"
import React, { type ChangeEvent, Fragment, useContext, useRef } from "react" import React, { type ChangeEvent, Fragment, useContext, useEffect, useRef } from "react"
import { toast } from "sonner" import { toast } from "sonner"
import { ImagePreviewDialog } from "@/components/image-preview-dialog" import { ImagePreviewDialog } from "@/components/image-preview-dialog"
import { import {
@@ -42,6 +42,7 @@ import {
import { WithAtom } from "../../components/with-atom" import { WithAtom } from "../../components/with-atom"
import { useFileDrop } from "../../files/use-file-drop" import { useFileDrop } from "../../files/use-file-drop"
import { cn } from "../../lib/utils" import { cn } from "../../lib/utils"
import { isControlOrCommandKeyActive, keyboardModifierAtom } from "../../lib/keyboard"
import { DirectoryPageContext } from "./context" import { DirectoryPageContext } from "./context"
import { DirectoryContentTable } from "./directory-content-table" import { DirectoryContentTable } from "./directory-content-table"
import { NewDirectoryDialog } from "./new-directory-dialog" import { NewDirectoryDialog } from "./new-directory-dialog"
@@ -50,12 +51,32 @@ import { dragInfoAtom, newFileTypeAtom, openedFileAtom } from "./state"
export function DirectoryPage() { export function DirectoryPage() {
const { directory } = useContext(DirectoryPageContext) const { directory } = useContext(DirectoryPageContext)
const [newFileType, setNewFileType] = useAtom(newFileTypeAtom)
const keyboardModifiers = useAtomValue(keyboardModifierAtom)
// Keyboard shortcut handler for Cmd/Ctrl+Shift+N to create new directory
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (
event.key === "N" &&
event.shiftKey &&
isControlOrCommandKeyActive(keyboardModifiers)
) {
event.preventDefault()
setNewFileType(FileType.Directory)
}
}
window.addEventListener("keydown", handleKeyDown)
return () => window.removeEventListener("keydown", handleKeyDown)
}, [keyboardModifiers, setNewFileType])
return ( return (
<> <>
<header className="flex py-1 shrink-0 items-center gap-2 border-b px-4 w-full"> <header className="flex py-1 shrink-0 items-center gap-2 border-b px-4 w-full">
<FilePathBreadcrumb /> <FilePathBreadcrumb />
<div className="ml-auto flex flex-row gap-2"> <div className="ml-auto flex flex-row gap-2">
<NewDirectoryItemDropdown /> <NewDirectoryItemDropdown onNewDirectory={() => setNewFileType(FileType.Directory)} />
<UploadFileButton /> <UploadFileButton />
</div> </div>
</header> </header>
@@ -64,19 +85,15 @@ export function DirectoryPage() {
</div> </div>
<RenameFileDialog /> <RenameFileDialog />
<PreviewDialog /> <PreviewDialog />
<WithAtom atom={newFileTypeAtom}> <NewDirectoryDialog
{(newFileType, setNewFileType) => ( open={newFileType === FileType.Directory}
<NewDirectoryDialog directoryId={directory._id}
open={newFileType === FileType.Directory} onOpenChange={(open) => {
directoryId={directory._id} if (!open) {
onOpenChange={(open) => { setNewFileType(null)
if (!open) { }
setNewFileType(null) }}
} />
}}
/>
)}
</WithAtom>
</> </>
) )
} }
@@ -210,11 +227,11 @@ function UploadFileButton() {
) )
} }
function NewDirectoryItemDropdown() { function NewDirectoryItemDropdown({ onNewDirectory }: { onNewDirectory: () => void }) {
const [newFileType, setNewFileType] = useAtom(newFileTypeAtom) const [newFileType] = useAtom(newFileTypeAtom)
const addNewDirectory = () => { const addNewDirectory = () => {
setNewFileType(FileType.Directory) onNewDirectory()
} }
const handleCloseAutoFocus = (event: Event) => { const handleCloseAutoFocus = (event: Event) => {