Fallback file upload for room/space images
This commit is contained in:
parent
647375b8c9
commit
c2684497f9
7 changed files with 58 additions and 54 deletions
|
|
@ -22,7 +22,7 @@
|
|||
import {makeEditor} from "@app/editor"
|
||||
import {DraftKey} from "@app/drafts"
|
||||
import {canEnforceNip70} from "@app/relays"
|
||||
import {uploadFile} from "@app/uploads"
|
||||
import {compressFileForUpload, uploadFile} from "@app/uploads"
|
||||
|
||||
type Values = {
|
||||
d: string
|
||||
|
|
@ -103,7 +103,7 @@
|
|||
if (typeof image === "string") {
|
||||
tags.push(["image", image])
|
||||
} else {
|
||||
const {result, error} = await uploadFile(image, {url})
|
||||
const {result, error} = await uploadFile(await compressFileForUpload(image), {url})
|
||||
|
||||
if (error) {
|
||||
return pushToast({
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<script lang="ts">
|
||||
import {randomId} from "@welshman/lib"
|
||||
import {preventDefault, stopPropagation, compressFile} from "@lib/html"
|
||||
import {preventDefault, stopPropagation} from "@lib/html"
|
||||
import CloseCircle from "@assets/icons/close-circle.svg?dataurl"
|
||||
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
|
||||
import GallerySend from "@assets/icons/gallery-send.svg?dataurl"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import {uploadFile} from "@app/uploads"
|
||||
import {compressFileForUpload, uploadFileOrFallback} from "@app/uploads"
|
||||
|
||||
interface Props {
|
||||
file?: File | undefined
|
||||
|
|
@ -43,33 +43,17 @@
|
|||
submit(e.target.files[0])
|
||||
}
|
||||
|
||||
const submit = async (file: File) => {
|
||||
const submit = async (newFile: File) => {
|
||||
if (!newFile) {
|
||||
url = initialUrl
|
||||
return
|
||||
}
|
||||
|
||||
loading = true
|
||||
|
||||
try {
|
||||
file = await compressFile(file, compressOptions)
|
||||
|
||||
if (file) {
|
||||
const {result} = await uploadFile(file)
|
||||
|
||||
if (result?.url) {
|
||||
url = result.url
|
||||
} else {
|
||||
const reader = new FileReader()
|
||||
|
||||
reader.addEventListener(
|
||||
"load",
|
||||
() => {
|
||||
url = reader.result as string
|
||||
},
|
||||
false,
|
||||
)
|
||||
|
||||
reader.readAsDataURL(file)
|
||||
}
|
||||
} else {
|
||||
url = initialUrl
|
||||
}
|
||||
file = await compressFileForUpload(newFile, compressOptions)
|
||||
url = (await uploadFileOrFallback(file)).url
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
tagPubkey,
|
||||
loadRelayList,
|
||||
} from "@welshman/app"
|
||||
import {compressFile} from "@lib/html"
|
||||
import Copy from "@assets/icons/copy.svg?dataurl"
|
||||
import LinkRound from "@assets/icons/link-round.svg?dataurl"
|
||||
import Letter from "@assets/icons/letter-opened.svg?dataurl"
|
||||
|
|
@ -32,7 +31,7 @@
|
|||
import WotScore from "@app/components/WotScore.svelte"
|
||||
import Content from "@app/components/Content.svelte"
|
||||
import {updateProfile} from "@app/profiles"
|
||||
import {uploadFile} from "@app/uploads"
|
||||
import {compressFileForUpload, uploadFile} from "@app/uploads"
|
||||
import {pushModal} from "@app/modal"
|
||||
import {clip, pushToast} from "@app/toast"
|
||||
import {goToChat} from "@app/routes"
|
||||
|
|
@ -90,7 +89,7 @@
|
|||
bannerLoading = true
|
||||
|
||||
try {
|
||||
const {result} = await uploadFile(await compressFile(file))
|
||||
const {result} = await uploadFile(await compressFileForUpload(file))
|
||||
|
||||
if (result?.url) {
|
||||
await updateProfile({profile: {...$profile, banner: result.url}})
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
import Modal from "@lib/components/Modal.svelte"
|
||||
import ModalBody from "@lib/components/ModalBody.svelte"
|
||||
import {pushToast} from "@app/toast"
|
||||
import {uploadFile} from "@app/uploads"
|
||||
import {compressFileForUpload, uploadFileOrFallback} from "@app/uploads"
|
||||
import {deriveHasLivekit} from "@app/relays"
|
||||
import {getRoomType, RoomType} from "@app/groups"
|
||||
|
||||
|
|
@ -45,17 +45,14 @@
|
|||
room.livekit = roomType === RoomType.Voice
|
||||
|
||||
if (imageFile) {
|
||||
const {error, result} = await uploadFile(imageFile, {
|
||||
maxWidth: 256,
|
||||
maxHeight: 256,
|
||||
const compressedFile = await compressFileForUpload(imageFile, {
|
||||
maxWidth: 128,
|
||||
maxHeight: 128,
|
||||
})
|
||||
|
||||
if (error) {
|
||||
return pushToast({theme: "error", message: error})
|
||||
}
|
||||
const result = await uploadFileOrFallback(compressedFile)
|
||||
|
||||
room.picture = result.url
|
||||
room.pictureMeta = result.tags
|
||||
}
|
||||
|
||||
const createMessage = await waitForThunkError(createRoom(url, room))
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
import IconPickerButton from "@lib/components/IconPickerButton.svelte"
|
||||
import {pushToast} from "@app/toast"
|
||||
import {clearModals} from "@app/modal"
|
||||
import {uploadFile} from "@app/uploads"
|
||||
import {compressFileForUpload, uploadFileOrFallback} from "@app/uploads"
|
||||
|
||||
type Props = {
|
||||
url: string
|
||||
|
|
@ -58,11 +58,8 @@
|
|||
}
|
||||
|
||||
if (imageFile) {
|
||||
const {error, result} = await uploadFile(imageFile, {maxWidth: 256, maxHeight: 256})
|
||||
|
||||
if (error) {
|
||||
return pushToast({theme: "error", message: error})
|
||||
}
|
||||
const compressedFile = await compressFileForUpload(imageFile, {maxWidth: 128, maxHeight: 128})
|
||||
const result = await uploadFileOrFallback(compressedFile)
|
||||
|
||||
const res = await manageRelay(url, {
|
||||
method: ManagementMethod.ChangeRelayIcon,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import ProfileSuggestion from "@app/editor/ProfileSuggestion.svelte"
|
|||
import {RoomReferenceExtension} from "@app/editor/RoomReferenceExtension"
|
||||
import RoomSuggestion from "@app/editor/RoomSuggestion.svelte"
|
||||
import {NativeClipboardPasteExtension} from "@app/editor/clipboard"
|
||||
import {uploadFile} from "@app/uploads"
|
||||
import {compressFileForUpload, uploadFile} from "@app/uploads"
|
||||
import {deriveSpaceMembers} from "@app/members"
|
||||
import {makeRoomId, splitRoomId, userSpaceUrls, roomsByUrl} from "@app/groups"
|
||||
import {pushToast} from "@app/toast"
|
||||
|
|
@ -137,8 +137,8 @@ export const makeEditor = async ({
|
|||
},
|
||||
fileUpload: {
|
||||
config: {
|
||||
upload: (attrs: FileAttributes) =>
|
||||
uploadFile(attrs.file, {url, encrypt: encryptFiles}),
|
||||
upload: async (attrs: FileAttributes) =>
|
||||
uploadFile(await compressFileForUpload(attrs.file), {url, encrypt: encryptFiles}),
|
||||
onDrop: () => uploading?.set(true),
|
||||
onComplete: () => uploading?.set(false),
|
||||
onUploadError(currentEditor, task) {
|
||||
|
|
|
|||
|
|
@ -67,11 +67,20 @@ export const getBlossomServer = async (options: GetBlossomServerOptions = {}) =>
|
|||
return first(DEFAULT_BLOSSOM_SERVERS)!
|
||||
}
|
||||
|
||||
export type CompressFileOptions = {
|
||||
maxWidth?: number
|
||||
maxHeight?: number
|
||||
quality?: number
|
||||
mimeType?: string
|
||||
}
|
||||
|
||||
// Webp/gif/svg either break the compressor or lose animation, pass them through untouched
|
||||
export const compressFileForUpload = async (file: File, options: CompressFileOptions = {}) =>
|
||||
file.type.match("image/(webp|gif|svg)") ? file : compressFile(file, options)
|
||||
|
||||
export type UploadFileOptions = {
|
||||
url?: string
|
||||
encrypt?: boolean
|
||||
maxWidth?: number
|
||||
maxHeight?: number
|
||||
}
|
||||
|
||||
export type UploadFileResult = {
|
||||
|
|
@ -83,10 +92,6 @@ export const uploadFile = async (file: File, options: UploadFileOptions = {}) =>
|
|||
try {
|
||||
const {name, type} = file
|
||||
|
||||
if (!type.match("image/(webp|gif|svg)")) {
|
||||
file = await compressFile(file, options)
|
||||
}
|
||||
|
||||
const tags: string[][] = []
|
||||
|
||||
if (options.encrypt) {
|
||||
|
|
@ -140,3 +145,25 @@ export const uploadFile = async (file: File, options: UploadFileOptions = {}) =>
|
|||
return {error: e.toString()}
|
||||
}
|
||||
}
|
||||
|
||||
const readFileAsDataUrl = (file: File) =>
|
||||
new Promise<string>((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
|
||||
reader.addEventListener("load", () => resolve(reader.result as string))
|
||||
reader.addEventListener("error", () => reject(reader.error))
|
||||
reader.readAsDataURL(file)
|
||||
})
|
||||
|
||||
export const uploadFileOrFallback = async (
|
||||
file: File,
|
||||
options: UploadFileOptions = {},
|
||||
): Promise<{url: string; tags: string[][]}> => {
|
||||
const {result} = await uploadFile(file, options)
|
||||
|
||||
if (result?.url) {
|
||||
return result
|
||||
}
|
||||
|
||||
return {url: await readFileAsDataUrl(file), tags: []}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue