File size: 5,083 Bytes
be54278 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | import { useVoxtral } from "./VoxtralContext";
import { THEME } from "../constants";
import {
AppGridBackground,
ErrorMessageBox,
useMountedTransition,
} from "./SharedUI";
export const LoadingPage = () => {
const { loadingProgress, loadingMessage, error } = useVoxtral();
const mounted = useMountedTransition();
const progressClamped = Math.min(100, Math.max(0, loadingProgress));
const isError = !!error;
return (
<AppGridBackground className="min-h-screen flex items-center justify-center p-8">
<div
className={`max-w-md w-full backdrop-blur-sm rounded-sm border shadow-xl transition-all duration-700 transform ${mounted ? "opacity-100 translate-y-0" : "opacity-0 translate-y-4"}`}
style={{
backgroundColor: `${THEME.beigeLight}F2`,
borderColor: THEME.beigeDark,
}}
>
<div
className={`h-1 w-full transition-colors duration-300 ${isError ? "bg-[var(--mistral-red)]" : "bg-[var(--mistral-orange)]"}`}
/>
<div className="p-8 space-y-8">
<div className="flex justify-center">
{isError ? (
<div
className="w-20 h-20 rounded-full flex items-center justify-center border"
style={{
backgroundColor: `${THEME.errorRed}1A`,
borderColor: `${THEME.errorRed}33`,
}}
>
<svg
className="w-10 h-10"
style={{ color: THEME.errorRed }}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z"
/>
</svg>
</div>
) : (
<div className="relative">
<div
className="w-20 h-20 border-4 rounded-full animate-spin"
style={{
borderColor: THEME.beigeDark,
borderTopColor: THEME.mistralOrange,
}}
/>
<div className="absolute inset-0 flex items-center justify-center">
<div
className="w-2 h-2 rounded-full animate-pulse"
style={{ backgroundColor: THEME.mistralOrange }}
/>
</div>
</div>
)}
</div>
<div className="text-center space-y-2">
<h2
className="text-2xl font-bold tracking-tight"
style={{ color: THEME.textBlack }}
>
{isError ? "Initialization Failed" : "Loading Model"}
</h2>
<p className="text-sm text-gray-500 font-mono uppercase tracking-widest">
{isError ? "Voxtral-Mini-4B-Realtime" : loadingMessage}
</p>
</div>
{!isError && (
<div className="space-y-4">
<div className="flex justify-between text-xs font-mono font-bold text-gray-500">
<span>PROGRESS</span>
<span>{Math.round(progressClamped)}%</span>
</div>
<div
className="w-full rounded-full h-4 overflow-hidden border"
style={{
backgroundColor: `${THEME.beigeDark}80`,
borderColor: THEME.beigeDark,
}}
>
<div
className="h-full progress-stripe transition-all duration-500 ease-out"
style={{
width: `${progressClamped}%`,
backgroundColor: THEME.mistralOrange,
}}
/>
</div>
<div
className="bg-white border p-3 rounded-sm"
style={{ borderColor: THEME.beigeDark }}
>
<div className="flex items-center space-x-2">
<div className="w-2 h-2 bg-green-500 rounded-full animate-pulse" />
<p className="font-mono text-xs text-gray-600 truncate">
{`> ${loadingMessage}`}
</p>
</div>
</div>
</div>
)}
{isError && (
<div className="space-y-4">
<ErrorMessageBox
className="border p-4 rounded text-left"
message={error}
/>
<button
onClick={() => window.location.reload()}
className="w-full py-3 text-white font-bold transition-colors shadow-lg hover:bg-black cursor-pointer"
style={{ backgroundColor: THEME.textBlack }}
>
RELOAD APPLICATION
</button>
</div>
)}
</div>
</div>
</AppGridBackground>
);
};
|