feat: support file and image attachments (#98)
* upload & view attachments to particles * allow download of attachments
This commit was merged in pull request #98.
This commit is contained in:
@@ -1,2 +1,8 @@
|
||||
/** How far back to look when filtering particles by recency. */
|
||||
export const RECENCY_WINDOW_HOURS = 24;
|
||||
|
||||
/** Maximum file size for attachments (25 MB). */
|
||||
export const MAX_ATTACHMENT_SIZE_BYTES = 25 * 1024 * 1024;
|
||||
|
||||
/** Maximum number of file attachments per particle. */
|
||||
export const MAX_ATTACHMENTS = 10;
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
onSnapshot,
|
||||
addDoc,
|
||||
getDoc,
|
||||
getDocs,
|
||||
updateDoc,
|
||||
query,
|
||||
orderBy,
|
||||
@@ -126,6 +127,19 @@ export async function getParticle(docPath: string): Promise<Particle | null> {
|
||||
return doc.data();
|
||||
}
|
||||
|
||||
export async function getParticleChildren(
|
||||
collectionPath: string,
|
||||
orderByField: string = "created_at",
|
||||
orderDirection: "asc" | "desc" = "asc",
|
||||
): Promise<Particle[]> {
|
||||
const q = query(
|
||||
typedCollection(collectionPath),
|
||||
orderBy(orderByField, orderDirection),
|
||||
);
|
||||
const snap = await getDocs(q);
|
||||
return snap.docs.map((d) => d.data());
|
||||
}
|
||||
|
||||
export function subscribeToParticleChildren(
|
||||
collectionPath: string,
|
||||
onData: (children: Particle[]) => void,
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Downscale an image file to a thumbnail and return an object URL.
|
||||
* Returns undefined for non-image files.
|
||||
* Caller is responsible for revoking the URL via URL.revokeObjectURL().
|
||||
*/
|
||||
export async function createImageThumbnail(
|
||||
file: File,
|
||||
maxDim = 200,
|
||||
): Promise<string | undefined> {
|
||||
if (!file.type.startsWith("image/")) return undefined;
|
||||
|
||||
const bitmap = await createImageBitmap(file);
|
||||
const scale = Math.min(1, maxDim / Math.max(bitmap.width, bitmap.height));
|
||||
const w = Math.round(bitmap.width * scale);
|
||||
const h = Math.round(bitmap.height * scale);
|
||||
|
||||
const canvas = new OffscreenCanvas(w, h);
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
ctx.drawImage(bitmap, 0, 0, w, h);
|
||||
bitmap.close();
|
||||
|
||||
const blob = await canvas.convertToBlob({ type: "image/jpeg", quality: 0.7 });
|
||||
return URL.createObjectURL(blob);
|
||||
}
|
||||
Reference in New Issue
Block a user