Compare commits
3 Commits
70d4743eef
...
c6fc2f6026
Author | SHA1 | Date | |
---|---|---|---|
c6fc2f6026
|
|||
8f82f8d5ad
|
|||
9d62de2c99
|
@@ -1,4 +1,6 @@
|
||||
export function DirectoryIcon() {
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
export function DirectoryIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -6,7 +8,10 @@ export function DirectoryIcon() {
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
className="icon icon-tabler icons-tabler-filled icon-tabler-folder text-orange-300"
|
||||
className={cn(
|
||||
"icon icon-tabler icons-tabler-filled icon-tabler-folder text-orange-300",
|
||||
className,
|
||||
)}
|
||||
aria-label="Directory"
|
||||
>
|
||||
<title>Directory</title>
|
||||
|
@@ -1,4 +1,6 @@
|
||||
export function TextFileIcon() {
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
export function TextFileIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -6,7 +8,10 @@ export function TextFileIcon() {
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
className="icon icon-tabler icons-tabler-filled icon-tabler-file-text text-blue-300"
|
||||
className={cn(
|
||||
"icon icon-tabler icons-tabler-filled icon-tabler-file-text text-blue-300",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<title>Text File</title>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
|
@@ -72,6 +72,7 @@ const columns: ColumnDef<DirectoryItem>[] = [
|
||||
),
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
size: 24,
|
||||
},
|
||||
{
|
||||
header: "Name",
|
||||
@@ -82,13 +83,14 @@ const columns: ColumnDef<DirectoryItem>[] = [
|
||||
return <FileNameCell initialName={row.original.doc.name} />
|
||||
case "directory":
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<DirectoryIcon />
|
||||
<div className="flex w-full items-center gap-2">
|
||||
<DirectoryIcon className="size-4" />
|
||||
{row.original.doc.name}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
size: 1000,
|
||||
},
|
||||
{
|
||||
header: "Size",
|
||||
@@ -217,7 +219,10 @@ export function FileTableContent() {
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<TableRow key={headerGroup.id}>
|
||||
{headerGroup.headers.map((header) => (
|
||||
<TableHead key={header.id}>
|
||||
<TableHead
|
||||
key={header.id}
|
||||
style={{ width: header.getSize() }}
|
||||
>
|
||||
{header.isPlaceholder
|
||||
? null
|
||||
: flexRender(
|
||||
@@ -240,7 +245,10 @@ export function FileTableContent() {
|
||||
}}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<TableCell key={cell.id}>
|
||||
<TableCell
|
||||
key={cell.id}
|
||||
style={{ width: cell.column.getSize() }}
|
||||
>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext(),
|
||||
@@ -250,14 +258,7 @@ export function FileTableContent() {
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell
|
||||
colSpan={columns.length}
|
||||
className="text-center"
|
||||
>
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<NoResultsRow />
|
||||
)}
|
||||
<NewItemRow />
|
||||
</TableBody>
|
||||
@@ -266,6 +267,20 @@ export function FileTableContent() {
|
||||
)
|
||||
}
|
||||
|
||||
function NoResultsRow() {
|
||||
const newItemKind = useAtomValue(newItemKindAtom)
|
||||
if (newItemKind) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="text-center">
|
||||
No results.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
}
|
||||
|
||||
function NewItemRow() {
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
const newItemFormId = useId()
|
||||
@@ -363,8 +378,8 @@ function NewItemRow() {
|
||||
|
||||
function FileNameCell({ initialName }: { initialName: string }) {
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<TextFileIcon />
|
||||
<div className="flex w-full items-center gap-2">
|
||||
<TextFileIcon className="size-4" />
|
||||
{initialName}
|
||||
</div>
|
||||
)
|
||||
|
@@ -1,8 +1,6 @@
|
||||
import { api } from "@convex/_generated/api"
|
||||
import {
|
||||
useMutation as useConvexMutation,
|
||||
useQuery as useConvexQuery,
|
||||
} from "convex/react"
|
||||
import { useMutation } from "@tanstack/react-query"
|
||||
import { useMutation as useConvexMutation } from "convex/react"
|
||||
import { useSetAtom } from "jotai"
|
||||
import {
|
||||
ChevronDownIcon,
|
||||
@@ -10,7 +8,7 @@ import {
|
||||
PlusIcon,
|
||||
UploadCloudIcon,
|
||||
} from "lucide-react"
|
||||
import { type ChangeEvent, useRef, useState } from "react"
|
||||
import { type ChangeEvent, useRef } from "react"
|
||||
import { toast } from "sonner"
|
||||
import {
|
||||
DropdownMenu,
|
||||
@@ -57,26 +55,10 @@ export function FilesPage() {
|
||||
|
||||
// tags: upload, uploadfile, uploadfilebutton, fileupload, fileuploadbutton
|
||||
function UploadFileButton() {
|
||||
const [isUploading, setIsUploading] = useState(false)
|
||||
const currentUser = useConvexQuery(api.users.getCurrentUser)
|
||||
const generateUploadUrl = useConvexMutation(api.files.generateUploadUrl)
|
||||
const saveFile = useConvexMutation(api.files.saveFile)
|
||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
const handleClick = () => {
|
||||
fileInputRef.current?.click()
|
||||
}
|
||||
|
||||
const onFileUpload = async (e: ChangeEvent<HTMLInputElement>) => {
|
||||
if (!currentUser?._id) {
|
||||
return
|
||||
}
|
||||
|
||||
const file = e.target.files?.[0]
|
||||
if (file) {
|
||||
try {
|
||||
setIsUploading(true)
|
||||
|
||||
const { mutate: uploadFile, isPending: isUploading } = useMutation({
|
||||
mutationFn: async (file: File) => {
|
||||
const uploadUrl = await generateUploadUrl()
|
||||
const uploadResult = await fetch(uploadUrl, {
|
||||
method: "POST",
|
||||
@@ -92,17 +74,23 @@ function UploadFileButton() {
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
mimeType: file.type,
|
||||
userId: currentUser._id,
|
||||
})
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success("File uploaded successfully.")
|
||||
},
|
||||
})
|
||||
|
||||
toast.success("File uploaded successfully.", {
|
||||
position: "top-center",
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
setIsUploading(false)
|
||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
const handleClick = () => {
|
||||
fileInputRef.current?.click()
|
||||
}
|
||||
|
||||
const onFileUpload = async (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0]
|
||||
if (file) {
|
||||
uploadFile(file)
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user