mirror of
https://github.com/SirBlobby/Hoya26.git
synced 2026-02-04 11:44:34 -05:00
Frontend Update
This commit is contained in:
608
frontend/src/lib/components/CameraScreen.svelte
Normal file
608
frontend/src/lib/components/CameraScreen.svelte
Normal file
@@ -0,0 +1,608 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
|
||||
interface Props {
|
||||
onClose: () => void;
|
||||
onScanComplete: (item: any) => void;
|
||||
}
|
||||
|
||||
let { onClose, onScanComplete }: Props = $props();
|
||||
|
||||
let videoElement: HTMLVideoElement;
|
||||
let stream: MediaStream | null = null;
|
||||
let analyzing = $state(false);
|
||||
let showResult = $state(false);
|
||||
let capturedImage = $state<string | null>(null);
|
||||
let displayTitle = $state("");
|
||||
let resultTranslateY = $state(100);
|
||||
let useCamera = $state(true); // Toggle between camera and file upload
|
||||
let fileInputElement: HTMLInputElement;
|
||||
|
||||
onMount(() => {
|
||||
const initCamera = async () => {
|
||||
if (useCamera) {
|
||||
try {
|
||||
stream = await navigator.mediaDevices.getUserMedia({
|
||||
video: { facingMode: "environment" },
|
||||
});
|
||||
if (videoElement) {
|
||||
videoElement.srcObject = stream;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Camera access denied:", err);
|
||||
}
|
||||
}
|
||||
};
|
||||
initCamera();
|
||||
|
||||
return () => {
|
||||
if (stream) {
|
||||
stream.getTracks().forEach((track) => track.stop());
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
function handleFileUpload(event: Event) {
|
||||
const input = event.target as HTMLInputElement;
|
||||
const file = input.files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const imageData = e.target?.result as string;
|
||||
capturedImage = imageData;
|
||||
analyzing = true;
|
||||
|
||||
// Simulate analysis
|
||||
setTimeout(() => {
|
||||
const newItem = {
|
||||
id: Date.now(),
|
||||
title: "Plastic Bottle",
|
||||
date: new Date().toLocaleString(),
|
||||
impact: "High",
|
||||
imageUri: capturedImage,
|
||||
};
|
||||
|
||||
onScanComplete(newItem);
|
||||
analyzing = false;
|
||||
showResult = true;
|
||||
resultTranslateY = 0;
|
||||
typeText();
|
||||
}, 1200);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
async function takePicture() {
|
||||
analyzing = true;
|
||||
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = videoElement.videoWidth;
|
||||
canvas.height = videoElement.videoHeight;
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (ctx) {
|
||||
ctx.drawImage(videoElement, 0, 0);
|
||||
capturedImage = canvas.toDataURL("image/png");
|
||||
}
|
||||
|
||||
// Simulate analysis
|
||||
setTimeout(() => {
|
||||
const newItem = {
|
||||
id: Date.now(),
|
||||
title: "Plastic Bottle",
|
||||
date: new Date().toLocaleString(),
|
||||
impact: "High",
|
||||
imageUri: capturedImage,
|
||||
};
|
||||
|
||||
onScanComplete(newItem);
|
||||
analyzing = false;
|
||||
showResult = true;
|
||||
resultTranslateY = 0;
|
||||
typeText();
|
||||
}, 1200);
|
||||
}
|
||||
|
||||
function typeText() {
|
||||
let i = 0;
|
||||
const txt = "Detected: Plastic Bottle";
|
||||
const interval = setInterval(() => {
|
||||
displayTitle = txt.substring(0, i);
|
||||
i++;
|
||||
if (i > txt.length) clearInterval(interval);
|
||||
}, 50);
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
if (stream) {
|
||||
stream.getTracks().forEach((track) => track.stop());
|
||||
}
|
||||
onClose();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="camera-container">
|
||||
{#if capturedImage}
|
||||
<img src={capturedImage} alt="Captured" class="captured-image" />
|
||||
{:else if useCamera}
|
||||
<video
|
||||
bind:this={videoElement}
|
||||
autoplay
|
||||
playsinline
|
||||
class="video-element"
|
||||
></video>
|
||||
{:else}
|
||||
<!-- File upload placeholder -->
|
||||
<div class="upload-placeholder">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
fill="#4ade80"
|
||||
class="upload-icon"
|
||||
>
|
||||
<path
|
||||
d="M194.6 32H317.4C338.1 32 356.4 45.22 362.9 64.82L373.3 96H448C483.3 96 512 124.7 512 160V416C512 451.3 483.3 480 448 480H64C28.65 480 0 451.3 0 416V160C0 124.7 28.65 96 64 96H138.7L149.1 64.82C155.6 45.22 173.9 32 194.6 32H194.6zM256 384C309 384 352 341 352 288C352 234.1 309 192 256 192C202.1 192 160 234.1 160 288C160 341 202.1 384 256 384z"
|
||||
/>
|
||||
</svg>
|
||||
<p class="upload-text">Click the button below to upload an image</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="camera-overlay">
|
||||
{#if !showResult}
|
||||
<button class="close-btn" on:click={handleClose}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
fill="white"
|
||||
>
|
||||
<path
|
||||
d="M256 48C141.1 48 48 141.1 48 256s93.1 208 208 208 208-93.1 208-208S370.9 48 256 48zm52.7 283.3L256 278.6l-52.7 52.7c-6.2 6.2-16.4 6.2-22.6 0-3.1-3.1-4.7-7.2-4.7-11.3 0-4.1 1.6-8.2 4.7-11.3l52.7-52.7-52.7-52.7c-3.1-3.1-4.7-7.2-4.7-11.3 0-4.1 1.6-8.2 4.7-11.3 6.2-6.2 16.4-6.2 22.6 0l52.7 52.7 52.7-52.7c6.2-6.2 16.4-6.2 22.6 0 6.2 6.2 6.2 16.4 0 22.6L278.6 256l52.7 52.7c6.2 6.2 6.2 16.4 0 22.6-6.2 6.3-16.4 6.3-22.6 0z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- Toggle button between camera and upload -->
|
||||
<button
|
||||
class="mode-toggle-btn"
|
||||
on:click={() => (useCamera = !useCamera)}
|
||||
>
|
||||
{#if useCamera}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
fill="white"
|
||||
>
|
||||
<path
|
||||
d="M0 96C0 60.7 28.7 32 64 32H448c35.3 0 64 28.7 64 64V416c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V96zM323.8 202.5c-4.5-6.6-11.9-10.5-19.8-10.5s-15.4 3.9-19.8 10.5l-87 127.6L170.7 297c-4.6-5.7-11.5-9-18.7-9s-14.2 3.3-18.7 9l-64 80c-5.8 7.2-6.9 17.1-2.9 25.4s12.4 13.6 21.6 13.6h96 32H424c8.9 0 17.1-4.9 21.2-12.8s3.6-17.4-1.4-24.7l-120-176zM112 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z"
|
||||
/>
|
||||
</svg>
|
||||
<span>Upload File</span>
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
fill="white"
|
||||
>
|
||||
<path
|
||||
d="M194.6 32H317.4C338.1 32 356.4 45.22 362.9 64.82L373.3 96H448C483.3 96 512 124.7 512 160V416C512 451.3 483.3 480 448 480H64C28.65 480 0 451.3 0 416V160C0 124.7 28.65 96 64 96H138.7L149.1 64.82C155.6 45.22 173.9 32 194.6 32H194.6zM256 384C309 384 352 341 352 288C352 234.1 309 192 256 192C202.1 192 160 234.1 160 288C160 341 202.1 384 256 384z"
|
||||
/>
|
||||
</svg>
|
||||
<span>Use Camera</span>
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#if analyzing}
|
||||
<div class="loading-container">
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if !analyzing && !showResult}
|
||||
<div class="shutter-container">
|
||||
{#if useCamera}
|
||||
<button class="shutter-button" on:click={takePicture}
|
||||
></button>
|
||||
{:else}
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
bind:this={fileInputElement}
|
||||
on:change={handleFileUpload}
|
||||
style="display: none;"
|
||||
/>
|
||||
<button
|
||||
class="shutter-button upload-button"
|
||||
on:click={() => fileInputElement.click()}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
fill="#0f172a"
|
||||
>
|
||||
<path
|
||||
d="M288 109.3V352c0 17.7-14.3 32-32 32s-32-14.3-32-32V109.3l-73.4 73.4c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l128-128c12.5-12.5 32.8-12.5 45.3 0l128 128c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L288 109.3zM64 352H192c0 35.3 28.7 64 64 64s64-28.7 64-64H448c35.3 0 64 28.7 64 64v32c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V416c0-35.3 28.7-64 64-64zM432 456a24 24 0 1 0 0-48 24 24 0 1 0 0 48z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if showResult}
|
||||
<div
|
||||
class="result-sheet"
|
||||
style="transform: translateY({resultTranslateY}%);"
|
||||
>
|
||||
<button class="sheet-close-btn" on:click={handleClose}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 320 512"
|
||||
fill="#0f172a"
|
||||
>
|
||||
<path
|
||||
d="M310.6 361.4c12.5 12.5 12.5 32.75 0 45.25C304.4 412.9 296.2 416 288 416s-16.38-3.125-22.62-9.375L160 301.3L54.63 406.6C48.38 412.9 40.19 416 32 416S15.63 412.9 9.375 406.6c-12.5-12.5-12.5-32.75 0-45.25l105.4-105.4L9.375 150.6c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0L160 210.8l105.4-105.4c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25l-105.4 105.4L310.6 361.4z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<h2 class="sheet-title">{displayTitle}</h2>
|
||||
|
||||
<p class="alternatives-label">Top Sustainable Alternatives</p>
|
||||
|
||||
<div class="alternatives-scroll">
|
||||
<div class="alternative-card glass-bottle">
|
||||
<div class="alt-header">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 384 512"
|
||||
fill="#60a5fa"
|
||||
>
|
||||
<path
|
||||
d="M192 512C86 512 0 426 0 320C0 228.8 130.2 57.7 166.6 11.7C172.6 4.2 181.5 0 191.1 0h1.8c9.6 0 18.5 4.2 24.5 11.7C253.8 57.7 384 228.8 384 320c0 106-86 192-192 192zM96 336c0-8.8-7.2-16-16-16s-16 7.2-16 16c0 61.9 50.1 112 112 112 8.8 0 16-7.2 16-16s-7.2-16-16-16c-44.2 0-80-35.8-80-80z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="rating">★ 4.9</span>
|
||||
</div>
|
||||
<h3 class="alt-name">Glass Bottle</h3>
|
||||
<p class="alt-price">$2.49</p>
|
||||
</div>
|
||||
|
||||
<div class="alternative-card boxed-water">
|
||||
<div class="alt-header">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 448 512"
|
||||
fill="#a78bfa"
|
||||
>
|
||||
<path
|
||||
d="M384 480H64c-35.3 0-64-28.7-64-64V96C0 60.7 28.7 32 64 32h320c35.3 0 64 28.7 64 64v320c0 35.3-28.7 64-64 64z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="rating">★ 4.7</span>
|
||||
</div>
|
||||
<h3 class="alt-name">Boxed Water</h3>
|
||||
<p class="alt-price">$1.89</p>
|
||||
</div>
|
||||
|
||||
<div class="alternative-card aluminum">
|
||||
<div class="alt-header">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
fill="#9ca3af"
|
||||
>
|
||||
<path
|
||||
d="M0 192c0-35.3 28.7-64 64-64c.5 0 1.1 0 1.6 0C73 91.5 105.3 64 144 64c15 0 29 4.1 40.9 11.2C198.2 49.6 225.1 32 256 32s57.8 17.6 71.1 43.2C339 68.1 353 64 368 64c38.7 0 71 27.5 78.4 64c.5 0 1.1 0 1.6 0c35.3 0 64 28.7 64 64c0 11.7-3.1 22.6-8.6 32H8.6C3.1 214.6 0 203.7 0 192zm0 91.4C0 268.3 12.3 256 27.4 256H484.6c15.1 0 27.4 12.3 27.4 27.4c0 70.5-44.4 130.7-106.7 154.1L403.5 452c-2 16-15.6 28-31.8 28H140.2c-16.1 0-29.8-12-31.8-28l-1.8-14.4C44.4 414.1 0 353.9 0 283.4z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="rating">★ 4.5</span>
|
||||
</div>
|
||||
<h3 class="alt-name">Aluminum</h3>
|
||||
<p class="alt-price">$1.29</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="report-btn" on:click={handleClose}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 448 512"
|
||||
fill="#ef4444"
|
||||
>
|
||||
<path
|
||||
d="M64 32C64 14.3 49.7 0 32 0S0 14.3 0 32V64 368 480c0 17.7 14.3 32 32 32s32-14.3 32-32V352l64.3-16.1c41.1-10.3 84.6-5.5 122.5 13.4c44.2 22.1 95.5 24.8 141.7 7.4l34.7-13c12.5-4.7 20.8-16.6 20.8-30V66.1c0-23-24.2-38-44.8-27.7l-9.6 4.8c-46.3 23.2-100.8 23.2-147.1 0c-35.1-17.6-75.4-22-113.5-12.5L64 48V32z"
|
||||
/>
|
||||
</svg>
|
||||
<span>Report Greenwashing</span>
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.camera-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background-color: #000;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.video-element,
|
||||
.captured-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.camera-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
left: 20px;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.close-btn svg {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 4px solid rgba(74, 222, 128, 0.2);
|
||||
border-top-color: #4ade80;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.shutter-container {
|
||||
position: absolute;
|
||||
bottom: 50px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.shutter-button {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 40px;
|
||||
background-color: white;
|
||||
border: 6px solid #e2e8f0;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.shutter-button:active {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
|
||||
.result-sheet {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
background-color: white;
|
||||
border-top-left-radius: 32px;
|
||||
border-top-right-radius: 32px;
|
||||
padding: 32px;
|
||||
transition: transform 0.5s ease-out;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.sheet-close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
align-self: flex-end;
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.sheet-close-btn svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.sheet-title {
|
||||
font-size: 28px;
|
||||
font-weight: 800;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 24px;
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
.alternatives-label {
|
||||
color: #64748b;
|
||||
margin-bottom: 12px;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.alternatives-scroll {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
overflow-x: auto;
|
||||
padding-bottom: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.alternatives-scroll::-webkit-scrollbar {
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
.alternatives-scroll::-webkit-scrollbar-track {
|
||||
background: #f1f5f9;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.alternatives-scroll::-webkit-scrollbar-thumb {
|
||||
background: #cbd5e1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.alternative-card {
|
||||
min-width: 140px;
|
||||
background-color: #f8fafc;
|
||||
padding: 16px;
|
||||
border-radius: 16px;
|
||||
border: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.alt-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.alt-header svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.rating {
|
||||
font-weight: bold;
|
||||
color: #f59e0b;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.alt-name {
|
||||
font-weight: bold;
|
||||
color: #0f172a;
|
||||
font-size: 16px;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.alt-price {
|
||||
color: #64748b;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.report-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
margin: 20px auto 0;
|
||||
padding: 12px 24px;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: #ef4444;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.report-btn svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.report-btn:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.upload-placeholder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
background-color: #0f172a;
|
||||
}
|
||||
|
||||
.upload-icon {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
margin-bottom: 24px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.upload-text {
|
||||
color: #94a3b8;
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
padding: 0 32px;
|
||||
}
|
||||
|
||||
.mode-toggle-btn {
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 20px;
|
||||
background: rgba(15, 23, 42, 0.8);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 12px;
|
||||
padding: 10px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.mode-toggle-btn:hover {
|
||||
background: rgba(15, 23, 42, 0.9);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.mode-toggle-btn svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.mode-toggle-btn span {
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.upload-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.upload-button svg {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user