zero-knowledge file sharing
13
fork

Configure Feed

Select the types of activity you want to include in your feed.

animate between views

juliet.paris 4add0fc1 3ab0a7f1

verified
+108 -96
+108 -96
web/src/pages/Upload.tsx
··· 3 3 import { generateKey, encrypt } from "../lib/crypto"; 4 4 import { formatBytes } from "../lib/utils"; 5 5 6 + const viewClass = "flex flex-col items-center gap-2 sm:gap-3"; 7 + const fadeIn = { animation: "fade-in 0.4s" }; 8 + 6 9 const btnClass = 7 - "bg-transparent hover:bg-accent/10 border-accent text-accent rounded-md border px-4 py-1.5 font-medium transition-colors"; 10 + "bg-transparent hover:bg-accent/10 active:scale-95 border-accent text-accent rounded-md border px-4 py-1.5 font-medium transition"; 8 11 const btnStyle = { "font-size": "clamp(1rem, 3vw, 1.5rem)" }; 9 12 const ghostClass = 10 13 "text-muted hover:text-text border-none bg-transparent p-0 text-xs"; ··· 247 250 </clipPath> 248 251 </defs> 249 252 <style>{`@keyframes wave { from { transform: translateX(0) } to { transform: translateX(-${WAVE_LEN}px) } }`}</style> 253 + <style>{`@keyframes fade-in { 0% { opacity: 0; transform: translateY(4px) } 100% { opacity: 1; transform: translateY(0) } }`}</style> 250 254 <circle 251 255 cx={CENTER} 252 256 cy={CENTER} ··· 290 294 </g> 291 295 </svg> 292 296 293 - <div class="z-10 flex flex-col items-center gap-2 text-center sm:gap-3"> 297 + <div class="z-10 flex flex-col items-center text-center"> 294 298 <Show when={view() === "result"}> 295 - <span 296 - class="text-muted" 297 - style={{ "font-size": "clamp(0.75rem, 2vw, 1rem)" }} 298 - > 299 - expires in {expiryValue()} 300 - </span> 301 - <button class={btnClass} style={btnStyle} onClick={copyLink}> 302 - {copied() ? "copied!" : "copy link"} 303 - </button> 304 - <button 305 - class={ghostClass} 306 - onClick={(e) => { 307 - e.stopPropagation(); 308 - setResultUrl(""); 309 - removeFile(); 310 - }} 311 - > 312 - new drop 313 - </button> 299 + <div class={viewClass} style={fadeIn}> 300 + <span 301 + class="text-muted" 302 + style={{ "font-size": "clamp(0.75rem, 2vw, 1rem)" }} 303 + > 304 + expires in {expiryValue()} 305 + </span> 306 + <button class={btnClass} style={btnStyle} onClick={copyLink}> 307 + {copied() ? "copied!" : "copy link"} 308 + </button> 309 + <button 310 + class={ghostClass} 311 + onClick={(e) => { 312 + e.stopPropagation(); 313 + setResultUrl(""); 314 + removeFile(); 315 + }} 316 + > 317 + new drop 318 + </button> 319 + </div> 314 320 </Show> 315 321 316 322 <Show when={view() === "uploading"}> 317 - <span 318 - class="text-accent font-medium tabular-nums" 319 - style={{ "font-size": "clamp(1.5rem, 5vw, 2.5rem)" }} 320 - > 321 - {progress()}% 322 - </span> 323 - <span class="text-muted text-xs"> 324 - {status() === "encrypting" 325 - ? "encrypting\u2026" 326 - : "uploading\u2026"} 327 - </span> 328 - <button 329 - class={ghostClass} 330 - onClick={(e) => { 331 - e.stopPropagation(); 332 - cancelUpload(); 333 - }} 334 - > 335 - cancel 336 - </button> 323 + <div class={viewClass} style={fadeIn}> 324 + <span 325 + class="text-accent font-medium tabular-nums" 326 + style={{ "font-size": "clamp(1.5rem, 5vw, 2.5rem)" }} 327 + > 328 + {progress()}% 329 + </span> 330 + <span class="text-muted text-xs"> 331 + {status() === "encrypting" 332 + ? "encrypting\u2026" 333 + : "uploading\u2026"} 334 + </span> 335 + <button 336 + class={ghostClass} 337 + onClick={(e) => { 338 + e.stopPropagation(); 339 + cancelUpload(); 340 + }} 341 + > 342 + cancel 343 + </button> 344 + </div> 337 345 </Show> 338 346 339 347 <Show when={view() === "file"}> 340 - <span 341 - class="text-text flex gap-1.5 truncate" 342 - style={{ "max-width": "clamp(120px, 40vw, 300px)" }} 343 - > 348 + <div class={viewClass} style={fadeIn}> 344 349 <span 345 - class="truncate" 346 - style={{ "font-size": "clamp(0.75rem, 2vw, 1rem)" }} 350 + class="text-text flex gap-1.5 truncate" 351 + style={{ "max-width": "clamp(120px, 40vw, 300px)" }} 347 352 > 348 - {file()!.name} 353 + <span 354 + class="truncate" 355 + style={{ "font-size": "clamp(0.75rem, 2vw, 1rem)" }} 356 + > 357 + {file()!.name} 358 + </span> 359 + <span 360 + class={`shrink-0 font-medium ${tooLarge() ? "text-danger" : "text-muted"}`} 361 + style={{ "font-size": "clamp(0.75rem, 2vw, 1rem)" }} 362 + > 363 + {tooLarge() 364 + ? `${formatBytes(file()!.size)} / ${formatBytes(maxFileSize())}` 365 + : formatBytes(file()!.size)} 366 + </span> 349 367 </span> 350 - <span 351 - class={`shrink-0 font-medium ${tooLarge() ? "text-danger" : "text-muted"}`} 352 - style={{ "font-size": "clamp(0.75rem, 2vw, 1rem)" }} 368 + <button 369 + class={`${btnClass} disabled:cursor-not-allowed disabled:opacity-40`} 370 + style={btnStyle} 371 + disabled={tooLarge()} 372 + onClick={(e) => { 373 + e.stopPropagation(); 374 + handleUpload(); 375 + }} 353 376 > 354 - {tooLarge() 355 - ? `${formatBytes(file()!.size)} / ${formatBytes(maxFileSize())}` 356 - : formatBytes(file()!.size)} 357 - </span> 358 - </span> 359 - <button 360 - class={`${btnClass} disabled:cursor-not-allowed disabled:opacity-40`} 361 - style={btnStyle} 362 - disabled={tooLarge()} 363 - onClick={(e) => { 364 - e.stopPropagation(); 365 - handleUpload(); 366 - }} 367 - > 368 - upload 369 - </button> 370 - <button 371 - class={ghostClass} 372 - onClick={(e) => { 373 - e.stopPropagation(); 374 - removeFile(); 375 - }} 376 - > 377 - remove 378 - </button> 377 + upload 378 + </button> 379 + <button 380 + class={ghostClass} 381 + onClick={(e) => { 382 + e.stopPropagation(); 383 + removeFile(); 384 + }} 385 + > 386 + remove 387 + </button> 388 + </div> 379 389 </Show> 380 390 381 391 <Show when={view() === "empty"}> 382 - <span 383 - class="text-muted font-medium" 384 - style={{ "font-size": "clamp(0.75rem, 2vw, 1rem)" }} 385 - > 386 - drop a file, or 387 - </span> 388 - <button 389 - class={btnClass} 390 - style={btnStyle} 391 - onClick={(e) => { 392 - e.stopPropagation(); 393 - fileInput.click(); 394 - }} 395 - > 396 - browse 397 - </button> 398 - <Show when={maxFileSize()}> 399 - <span class="text-muted text-xs"> 400 - up to {formatBytes(maxFileSize())} 392 + <div class={viewClass} style={fadeIn}> 393 + <span 394 + class="text-muted font-medium" 395 + style={{ "font-size": "clamp(0.75rem, 2vw, 1rem)" }} 396 + > 397 + drop a file, or 401 398 </span> 402 - </Show> 399 + <button 400 + class={btnClass} 401 + style={btnStyle} 402 + onClick={(e) => { 403 + e.stopPropagation(); 404 + fileInput.click(); 405 + }} 406 + > 407 + browse 408 + </button> 409 + <Show when={maxFileSize()}> 410 + <span class="text-muted text-xs"> 411 + up to {formatBytes(maxFileSize())} 412 + </span> 413 + </Show> 414 + </div> 403 415 </Show> 404 416 </div> 405 417