-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: update dep * feat: add file-upload util * feat: add toast (sonner) * feat: add file upload for cell * chore: clean up * feat: add error toast for unauthenticated user
- Loading branch information
Showing
9 changed files
with
207 additions
and
48 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
"use client"; | ||
|
||
import { useTheme } from "@/context/theme-provider"; | ||
import { Toaster as Sonner } from "sonner"; | ||
|
||
type ToasterProps = React.ComponentProps<typeof Sonner>; | ||
|
||
const Toaster = ({ ...props }: ToasterProps) => { | ||
const { theme } = useTheme(); | ||
|
||
return ( | ||
<Sonner | ||
theme={theme as ToasterProps["theme"]} | ||
className="toaster group" | ||
toastOptions={{ | ||
classNames: { | ||
toast: | ||
"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg", | ||
description: "group-[.toast]:text-muted-foreground", | ||
actionButton: | ||
"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground", | ||
cancelButton: | ||
"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground", | ||
success: "[&>[data-icon]]:text-green-500", | ||
error: "[&>[data-icon]]:text-red-500", | ||
}, | ||
}} | ||
{...props} | ||
/> | ||
); | ||
}; | ||
|
||
export { Toaster }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import { Result, err, ok } from "@justmiracle/result"; | ||
import { safeFetch } from "./utils"; | ||
|
||
export interface TriggerFileUploadOptions { | ||
/** | ||
* Maximum file size in bytes | ||
* @default 10MB | ||
**/ | ||
maxSize?: number; | ||
|
||
/** | ||
* Maximum number of files that can be selected | ||
* @default 1 | ||
**/ | ||
maxFiles?: number; | ||
|
||
/** | ||
* Accept attribute for the file input | ||
* @default "" | ||
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept | ||
* | ||
* @example | ||
* // Accepts only images | ||
* accept="image/*" | ||
* | ||
* // Accepts only images and videos | ||
* accept="image/*,video/*" | ||
* | ||
* // Accepts only .jpg files | ||
* accept="image/jpg" | ||
**/ | ||
accept?: string; | ||
} | ||
|
||
const DEFAULT_ACCEPT = ""; // No restrictions | ||
const DEFAULT_MAX_SIZE = 1024 * 1024 * 10; // 10MB | ||
const DEFAULT_MAX_FILES = 1; | ||
|
||
export const triggerSelectFiles = ( | ||
options?: TriggerFileUploadOptions, | ||
): Promise<Result<File[]>> => { | ||
const { | ||
maxSize = DEFAULT_MAX_SIZE, | ||
maxFiles = DEFAULT_MAX_FILES, | ||
accept = DEFAULT_ACCEPT, | ||
} = options || {}; | ||
|
||
return new Promise<Result<File[]>>((resolve, reject) => { | ||
const fileInput = document.createElement("input"); | ||
fileInput.type = "file"; | ||
|
||
// options | ||
fileInput.accept = accept; | ||
fileInput.multiple = maxFiles > 1; | ||
|
||
fileInput.onchange = (event) => { | ||
const files = Array.from((event.target as HTMLInputElement).files || []); | ||
|
||
if (!files.length) { | ||
return reject(err("No files selected")); | ||
} | ||
|
||
// Check if the number of files exceeds the maximum limit | ||
if (maxFiles && files.length > maxFiles) { | ||
return reject( | ||
err("Too many files selected, maximum allowed is " + maxFiles), | ||
); | ||
} | ||
|
||
const invalidFileSizes = Array.from(files).some( | ||
(file) => file.size > maxSize, | ||
); | ||
|
||
if (invalidFileSizes) { | ||
return reject( | ||
err("Some file's size exceeds the maximum limit of " + maxSize), | ||
); | ||
} | ||
|
||
return resolve(ok(Array.from(files))); | ||
}; | ||
|
||
fileInput.click(); | ||
}); | ||
}; | ||
|
||
/** | ||
* Upload a file to the server | ||
* | ||
* @param file - The file to upload | ||
* @returns The url of the uploaded file | ||
* | ||
* @example | ||
* | ||
* const { data } = await uploadFile(file) | ||
* console.log(data?.url) | ||
* // https://r2.example.com/filename.jpg | ||
*/ | ||
export async function uploadFile(file: File) { | ||
const formData = new FormData(); | ||
formData.append("file", file); | ||
|
||
return safeFetch<{ url: string }>("/api/upload", { | ||
method: "POST", | ||
body: formData, | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters