mirror of
https://github.com/PlatypusPus/MushroomEmpire.git
synced 2026-02-07 22:18:59 +00:00
progress bar
This commit is contained in:
@@ -32,13 +32,17 @@ export function FeatureGrid() {
|
|||||||
Proactive privacy protection tailored for Nordic identity ecosystems and EU data law.
|
Proactive privacy protection tailored for Nordic identity ecosystems and EU data law.
|
||||||
</p>
|
</p>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
<div className="mt-10 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-6">
|
<div className="mt-10 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-6 items-stretch">
|
||||||
{items.map((f, i) => (
|
{items.map((f, i) => (
|
||||||
<Reveal key={f.title} delayMs={i * 90}>
|
<Reveal key={f.title} delayMs={i * 90} className="h-full">
|
||||||
<div className="rounded-xl border border-slate-200 bg-white/80 p-6 shadow-sm transition-transform duration-300 hover:-translate-y-0.5">
|
<div className="h-full rounded-xl border border-slate-200 bg-white/80 p-6 shadow-sm transition-transform duration-300 hover:-translate-y-0.5 flex flex-col">
|
||||||
<div className="text-3xl">{f.emoji}</div>
|
<div className="text-3xl">{f.emoji}</div>
|
||||||
<h3 className="mt-3 font-semibold text-slate-900">{f.title}</h3>
|
<h3 className="mt-3 font-semibold text-slate-900">{f.title}</h3>
|
||||||
<p className="mt-2 text-sm text-slate-600">{f.desc}</p>
|
<p className="mt-2 text-sm text-slate-600">
|
||||||
|
{f.desc}
|
||||||
|
</p>
|
||||||
|
{/* Spacer to ensure consistent padding at bottom when descriptions vary */}
|
||||||
|
<div className="mt-auto" />
|
||||||
</div>
|
</div>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -18,24 +18,66 @@ export function CenterPanel({ tab }: CenterPanelProps) {
|
|||||||
const [fileMeta, setFileMeta] = useState<UploadedFileMeta | null>(null);
|
const [fileMeta, setFileMeta] = useState<UploadedFileMeta | null>(null);
|
||||||
const [isDragging, setIsDragging] = useState(false);
|
const [isDragging, setIsDragging] = useState(false);
|
||||||
const [progress, setProgress] = useState<number>(0);
|
const [progress, setProgress] = useState<number>(0);
|
||||||
|
const [progressLabel, setProgressLabel] = useState<string>("Processing");
|
||||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||||
const [loadedFromCache, setLoadedFromCache] = useState(false);
|
const [loadedFromCache, setLoadedFromCache] = useState(false);
|
||||||
|
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
setFileMeta(null);
|
setFileMeta(null);
|
||||||
setProgress(0);
|
setProgress(0);
|
||||||
|
setProgressLabel("Processing");
|
||||||
};
|
};
|
||||||
|
|
||||||
const processFile = useCallback((f: File) => {
|
const processFile = useCallback(async (f: File) => {
|
||||||
if (!f) return;
|
if (!f) return;
|
||||||
setProgress(0);
|
setProgress(0);
|
||||||
|
// For large files, show a progress bar while reading the file stream (no preview)
|
||||||
if (f.size > 1024 * 1024) {
|
if (f.size > 1024 * 1024) {
|
||||||
setFileMeta({
|
setProgressLabel("Uploading");
|
||||||
|
const metaObj: UploadedFileMeta = {
|
||||||
name: f.name,
|
name: f.name,
|
||||||
size: f.size,
|
size: f.size,
|
||||||
type: f.type,
|
type: f.type || "unknown",
|
||||||
contentPreview: "File too large for preview (limit 1MB).",
|
contentPreview: "File too large for preview (limit 1MB).",
|
||||||
});
|
};
|
||||||
|
setFileMeta(metaObj);
|
||||||
|
// Save to IndexedDB immediately so it persists without needing full read
|
||||||
|
(async () => {
|
||||||
|
try { await saveLatestUpload(f, metaObj); } catch {}
|
||||||
|
})();
|
||||||
|
// Use streaming read for progress without buffering entire file in memory
|
||||||
|
try {
|
||||||
|
const stream: ReadableStream<Uint8Array> | undefined = (typeof (f as any).stream === "function" ? (f as any).stream() : undefined);
|
||||||
|
if (stream && typeof stream.getReader === "function") {
|
||||||
|
const reader = stream.getReader();
|
||||||
|
let loaded = 0;
|
||||||
|
const total = f.size || 1;
|
||||||
|
for (;;) {
|
||||||
|
const { done, value } = await reader.read();
|
||||||
|
if (done) break;
|
||||||
|
loaded += value ? value.length : 0;
|
||||||
|
const pct = Math.min(100, Math.round((loaded / total) * 100));
|
||||||
|
setProgress(pct);
|
||||||
|
}
|
||||||
|
setProgress(100);
|
||||||
|
} else {
|
||||||
|
// Fallback to FileReader progress events
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onprogress = (evt) => {
|
||||||
|
if (evt.lengthComputable) {
|
||||||
|
const pct = Math.min(100, Math.round((evt.loaded / evt.total) * 100));
|
||||||
|
setProgress(pct);
|
||||||
|
} else {
|
||||||
|
setProgress((p) => (p < 90 ? p + 5 : p));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.onloadend = () => setProgress(100);
|
||||||
|
reader.onerror = () => setProgress(0);
|
||||||
|
reader.readAsArrayBuffer(f);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
setProgress(100);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
@@ -63,6 +105,7 @@ export function CenterPanel({ tab }: CenterPanelProps) {
|
|||||||
try {
|
try {
|
||||||
await saveLatestUpload(f, metaObj);
|
await saveLatestUpload(f, metaObj);
|
||||||
} catch {}
|
} catch {}
|
||||||
|
setProgressLabel("Processing");
|
||||||
setProgress(100);
|
setProgress(100);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const metaObj: UploadedFileMeta = {
|
const metaObj: UploadedFileMeta = {
|
||||||
@@ -75,6 +118,7 @@ export function CenterPanel({ tab }: CenterPanelProps) {
|
|||||||
try {
|
try {
|
||||||
await saveLatestUpload(f, metaObj);
|
await saveLatestUpload(f, metaObj);
|
||||||
} catch {}
|
} catch {}
|
||||||
|
setProgressLabel("Processing");
|
||||||
setProgress(100);
|
setProgress(100);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -163,7 +207,7 @@ export function CenterPanel({ tab }: CenterPanelProps) {
|
|||||||
style={{ width: `${progress}%` }}
|
style={{ width: `${progress}%` }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-1 text-xs text-slate-500">Processing {progress}%</div>
|
<div className="mt-1 text-xs text-slate-500">{progressLabel} {progress}%</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{fileMeta && (
|
{fileMeta && (
|
||||||
|
|||||||
Reference in New Issue
Block a user