Fork of atp.tools as a universal profile for people on the ATmosphere

what tha hell

Natalie B cec7b71f 88b45594

Changed files
+68 -37
src
routes
+68 -37
src/routes/post.lazy.tsx
··· 3 3 import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; 4 4 import { Input } from "@/components/ui/input"; 5 5 import { Switch } from "@/components/ui/switch"; 6 + import { Textarea } from "@/components/ui/textarea"; 6 7 import { QtContext } from "@/providers/qtprovider"; 7 8 import { AppBskyFeedPost } from "@atcute/client/lexicons"; 8 9 import { createLazyFileRoute, useNavigate } from "@tanstack/react-router"; ··· 25 26 const ctx = canvas.getContext("2d"); 26 27 27 28 img.onload = () => { 28 - let { width, height } = img; 29 - let quality = 0.9; 30 - let blob: Blob | null = null; 29 + // Calculate aspect ratio 30 + const aspectRatio = img.width / img.height; 31 31 32 - // First pass: try with original dimensions 33 - canvas.width = width; 34 - canvas.height = height; 35 - ctx?.drawImage(img, 0, 0, width, height); 32 + // Start with a reasonable size that's likely to be under 1MB 33 + let targetWidth = 2000; // common width for social media 34 + let targetHeight = Math.round(targetWidth / aspectRatio); 36 35 37 - // Try to get under maxSize with quality reduction first 38 - while (quality > 0.1) { 39 - blob = canvas.toBlob( 40 - (b) => { 41 - if (b && b.size <= maxSize) { 42 - resolve(b); 43 - } else if (quality > 0.1) { 44 - quality -= 0.1; 45 - canvas.toBlob((b) => (blob = b), "image/jpeg", quality); 46 - } else { 47 - // If we get here, we need to reduce dimensions 48 - width *= 0.9; 49 - height *= 0.9; 50 - canvas.width = width; 51 - canvas.height = height; 52 - ctx?.drawImage(img, 0, 0, width, height); 53 - quality = 0.9; 54 - canvas.toBlob((b) => (blob = b), "image/jpeg", quality); 55 - } 56 - }, 57 - "image/jpeg", 58 - quality, 59 - ); 36 + if (targetHeight > targetWidth) { 37 + // swap width and height 38 + const temp = targetHeight; 39 + targetHeight = targetWidth; 40 + targetWidth = temp; 60 41 } 61 42 62 - // If we still haven't resolved, use the last blob 63 - if (blob) { 64 - resolve(blob); 65 - } else { 66 - reject(new Error("Could not downscale image sufficiently")); 43 + // If image is smaller than target size, use original dimensions 44 + if (img.width < targetWidth) { 45 + targetWidth = img.width; 46 + targetHeight = img.height; 67 47 } 48 + 49 + // Set canvas size to target dimensions 50 + canvas.width = targetWidth; 51 + canvas.height = targetHeight; 52 + 53 + // Draw image at new size 54 + ctx?.drawImage(img, 0, 0, targetWidth, targetHeight); 55 + 56 + // Convert to blob with reasonable quality 57 + canvas.toBlob( 58 + (blob) => { 59 + if (!blob) { 60 + reject(new Error("Failed to create blob")); 61 + return; 62 + } 63 + // If still too large, reduce quality 64 + if (blob.size > maxSize) { 65 + canvas.toBlob( 66 + (finalBlob) => { 67 + if (!finalBlob) { 68 + reject(new Error("Failed to create blob")); 69 + return; 70 + } 71 + resolve(finalBlob); 72 + }, 73 + "image/jpeg", 74 + 0.7, // reduced quality 75 + ); 76 + } else { 77 + resolve(blob); 78 + } 79 + }, 80 + "image/jpeg", 81 + 0.9, // initial quality 82 + ); 68 83 }; 69 84 70 85 img.onerror = () => reject(new Error("Failed to load image")); ··· 82 97 const [isUploading, setIsUploading] = useState(false); 83 98 const [uploadError, setUploadError] = useState<Error | null>(null); 84 99 const [postToBluesky, setPostToBluesky] = useState(false); 100 + const [textToPost, setTextToPost] = useState(""); 85 101 const fileInputRef = useRef<HTMLInputElement | null>(null); 86 102 87 103 const navigate = useNavigate(); ··· 158 174 })); 159 175 160 176 let dummyRecord: AppBskyFeedPost.Record = { 161 - text: "", 177 + text: textToPost, 162 178 createdAt: new Date().toISOString(), 163 179 embed: { 164 180 $type: "app.bsky.embed.images", ··· 190 206 })); 191 207 192 208 let bskyRecord: AppBskyFeedPost.Record = { 193 - text: "", 209 + text: textToPost, 194 210 createdAt: new Date().toISOString(), 195 211 embed: { 196 212 $type: "app.bsky.embed.images", ··· 301 317 Select Images (up to 4) 302 318 </Button> 303 319 </div> 320 + 321 + <Textarea 322 + value={textToPost} 323 + onChange={(e) => setTextToPost(e.currentTarget.value)} 324 + placeholder="Blaze your glory! (leave empty if you don't want to include text with your post)" 325 + /> 326 + 327 + {textToPost.length > 300 - 16 ? ( 328 + <p> 329 + Your post is too long! Remove{" "} 330 + {Math.abs(textToPost.length - 300 - 16)} chars! 331 + </p> 332 + ) : ( 333 + <p>{textToPost.length}</p> 334 + )} 304 335 305 336 <div className="grid grid-cols-1 sm:grid-cols-2 gap-4"> 306 337 {images.map((imageData, index) => (