Spaces:
Running
Running
File size: 8,081 Bytes
d5c6d34 |
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 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
import Button from "./Button";
import { useState, useEffect } from "react";
import { THEME } from "../constants";
import HfIcon from "./HfIcon";
interface WelcomeScreenProps {
onStart: () => void;
}
export default function WelcomeScreen({ onStart }: WelcomeScreenProps) {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
return (
<>
<div
className="absolute inset-0 flex items-center justify-center p-6 overflow-y-auto"
style={{
backgroundColor: THEME.beigeLight,
backgroundImage: `
linear-gradient(${THEME.beigeDark} 1px, transparent 1px),
linear-gradient(90deg, ${THEME.beigeDark} 1px, transparent 1px)
`,
backgroundSize: "40px 40px",
color: THEME.textBlack,
}}
>
<div
className={`relative max-w-4xl w-full backdrop-blur-sm p-10 md:p-12 rounded-sm border shadow-2xl transition-all duration-700 ${mounted ? "opacity-100 translate-y-0" : "opacity-0 translate-y-4"}`}
style={{
backgroundColor: `${THEME.beigeLight}F2`, // 95% opacity
borderColor: THEME.beigeDark,
}}
>
{/* 1. Top Right Status Indicator */}
<div className="absolute top-6 right-6 group cursor-help z-10">
<span className="absolute right-full mr-4 top-1/2 -translate-y-1/2 whitespace-nowrap text-xs font-mono uppercase tracking-widest text-gray-500 opacity-0 group-hover:opacity-100 transition-all duration-300 translate-x-2 group-hover:translate-x-0 pointer-events-none">
System Ready
</span>
<div className="relative flex h-3 w-3">
<span
className="animate-ping absolute inline-flex h-full w-full rounded-full opacity-75"
style={{ backgroundColor: THEME.mistralOrange }}
></span>
<span
className="relative inline-flex rounded-sm h-3 w-3"
style={{ backgroundColor: THEME.mistralOrange }}
></span>
</div>
</div>
<div className="space-y-12">
{/* Header Section */}
<div className="text-center space-y-4 animate-enter">
<div className="flex flex-col items-center justify-center space-y-5">
<div className="relative group">
<img
src="Ministral.png"
alt="Ministral Logo"
className="h-24 object-contain transition-transform duration-500 group-hover:scale-105 drop-shadow-sm"
/>
</div>
<h1
className="text-6xl md:text-7xl font-semibold tracking-tighter"
style={{ color: THEME.textBlack }}
>
Ministral WebGPU
</h1>
</div>
<p className="text-xl md:text-2xl text-gray-600 max-w-2xl mx-auto font-light leading-relaxed">
Frontier multimodal AI, running entirely in your browser.
<br />
Powered by{" "}
<a
href="https://huggingface.co/mistralai/Ministral-3-3B-Instruct-2512-ONNX"
className="font-medium underline decoration-2 underline-offset-4 transition-all hover:decoration-[3px]"
style={{
color: THEME.mistralOrange,
textDecorationColor: THEME.mistralOrange,
}}
target="_blank"
rel="noopener noreferrer"
>
Ministral-3-3B
</a>
</p>
</div>
{/* Content Grid */}
<div
className="grid grid-cols-1 md:grid-cols-3 gap-8 border-t border-b py-10 animate-enter delay-100"
style={{ borderColor: THEME.beigeDark }}
>
{/* Feature 1 */}
<div className="space-y-3 group">
<div
className="w-10 h-10 flex items-center justify-center text-white font-bold text-lg shadow-sm transition-transform duration-300 group-hover:-translate-y-1"
style={{ backgroundColor: THEME.mistralOrange }}
>
1
</div>
<h4
className="font-semibold text-xl"
style={{ color: THEME.textBlack }}
>
Load Model
</h4>
<p className="text-gray-600 leading-relaxed">
Downloads the optimized Ministral model (~3GB) directly to
your browser cache.
</p>
</div>
{/* Feature 2 */}
<div className="space-y-3 group">
<div
className="w-10 h-10 flex items-center justify-center text-white font-bold text-lg shadow-sm transition-transform duration-300 group-hover:-translate-y-1"
style={{ backgroundColor: THEME.mistralOrange }}
>
2
</div>
<h4
className="font-semibold text-xl"
style={{ color: THEME.textBlack }}
>
Private & Local
</h4>
<p className="text-gray-600 leading-relaxed">
Your video feed is processed locally and never sent to a
server, powered by
<a href="https://github.com/huggingface/transformers.js">
<span className="font-medium underline">
<HfIcon className="size-6 ml-1 mt-[-1px] inline" />
Transformers.js
</span>
</a>
.
</p>
</div>
{/* Feature 3 */}
<div className="space-y-3 group">
<div
className="w-10 h-10 flex items-center justify-center text-white font-bold text-lg shadow-sm transition-transform duration-300 group-hover:-translate-y-1"
style={{ backgroundColor: THEME.mistralOrange }}
>
3
</div>
<h4
className="font-semibold text-xl"
style={{ color: THEME.textBlack }}
>
Real-time Vision
</h4>
<p className="text-gray-600 leading-relaxed">
The model analyzes the current frame and responds to the
user's prompt.
</p>
</div>
</div>
{/* Action Area */}
<div className="flex flex-col items-center animate-enter delay-200">
<Button
onClick={onStart}
className="group relative px-8 py-5 text-white overflow-hidden transition-all hover:shadow-2xl hover:-translate-y-0.5"
>
<div className="absolute inset-0 bg-white/20 translate-y-full group-hover:translate-y-0 transition-transform duration-300 ease-out" />
<span className="relative font-bold text-xl tracking-wide flex items-center gap-3">
START LIVE CAPTIONING
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={2.5}
stroke="currentColor"
className="w-5 h-5 transition-transform duration-300 group-hover:translate-x-1"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M13.5 4.5 21 12m0 0-7.5 7.5M21 12H3"
/>
</svg>
</span>
</Button>
</div>
</div>
</div>
</div>
</>
);
}
|