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