Spaces:
Sleeping
Sleeping
Update client/src/App.jsx
Browse files- client/src/App.jsx +22 -31
client/src/App.jsx
CHANGED
|
@@ -7,9 +7,6 @@ const SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBh
|
|
| 7 |
|
| 8 |
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
|
| 9 |
|
| 10 |
-
// --- TEK BRANDED MODEL LIST ---
|
| 11 |
-
// The 'id' must remain the original Puter ID for functionality.
|
| 12 |
-
// The 'name' is what displays in the UI dropdown.
|
| 13 |
const AI_MODELS = [
|
| 14 |
{ id: 'openai/dall-e-3', name: 'TEK 3 (Best)' },
|
| 15 |
{ id: 'google/imagen-4.0-preview', name: 'TEK 4 HD (Real)' },
|
|
@@ -33,7 +30,6 @@ function App() {
|
|
| 33 |
const [previewUrl, setPreviewUrl] = useState(null);
|
| 34 |
const fileInputRef = useRef(null);
|
| 35 |
|
| 36 |
-
// PWA State
|
| 37 |
const [deferredPrompt, setDeferredPrompt] = useState(null);
|
| 38 |
const [showInstallBanner, setShowInstallBanner] = useState(false);
|
| 39 |
const [isIOS, setIsIOS] = useState(false);
|
|
@@ -42,10 +38,7 @@ function App() {
|
|
| 42 |
supabase.auth.getSession().then(({ data: { session } }) => setSession(session));
|
| 43 |
const { data: { subscription } } = supabase.auth.onAuthStateChange((_event, session) => setSession(session));
|
| 44 |
|
| 45 |
-
// PWA Detection Logic
|
| 46 |
const isIosDevice = /ipad|iphone|ipod/.test(navigator.userAgent.toLowerCase()) && !window.MSStream;
|
| 47 |
-
|
| 48 |
-
// Check if running in standalone mode
|
| 49 |
const isInStandaloneMode = window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone === true;
|
| 50 |
|
| 51 |
if (isIosDevice && !isInStandaloneMode) {
|
|
@@ -56,9 +49,7 @@ function App() {
|
|
| 56 |
window.addEventListener('beforeinstallprompt', (e) => {
|
| 57 |
e.preventDefault();
|
| 58 |
setDeferredPrompt(e);
|
| 59 |
-
if (!isInStandaloneMode)
|
| 60 |
-
setShowInstallBanner(true);
|
| 61 |
-
}
|
| 62 |
});
|
| 63 |
|
| 64 |
return () => subscription.unsubscribe();
|
|
@@ -67,8 +58,6 @@ function App() {
|
|
| 67 |
const handleInstallClick = async () => {
|
| 68 |
if (deferredPrompt) {
|
| 69 |
deferredPrompt.prompt();
|
| 70 |
-
const { outcome } = await deferredPrompt.userChoice;
|
| 71 |
-
console.log(`Outcome: ${outcome}`);
|
| 72 |
setDeferredPrompt(null);
|
| 73 |
setShowInstallBanner(false);
|
| 74 |
}
|
|
@@ -91,14 +80,12 @@ function App() {
|
|
| 91 |
if (!prompt) return;
|
| 92 |
setGenerating(true);
|
| 93 |
setImageSrc(null);
|
| 94 |
-
|
| 95 |
try {
|
| 96 |
if (!window.puter.auth.isSignedIn()) await window.puter.auth.signIn();
|
| 97 |
const ratioText = selectedRatio === '1:1' ? '' : ` --ar ${selectedRatio}`;
|
| 98 |
const finalPrompt = prompt + ratioText;
|
| 99 |
|
| 100 |
let imgElement;
|
| 101 |
-
// DALL-E 3 doesn't support img2img via this API, so we skip image param for it
|
| 102 |
if (inputImage && !selectedModel.includes('dall-e')) {
|
| 103 |
imgElement = await window.puter.ai.txt2img(finalPrompt, { model: selectedModel, image: inputImage });
|
| 104 |
} else {
|
|
@@ -113,40 +100,47 @@ function App() {
|
|
| 113 |
}
|
| 114 |
};
|
| 115 |
|
|
|
|
| 116 |
if (!session) {
|
| 117 |
return (
|
| 118 |
-
<div style={{
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
</div>
|
| 123 |
</div>
|
| 124 |
);
|
| 125 |
}
|
| 126 |
|
|
|
|
| 127 |
return (
|
| 128 |
<div style={{
|
| 129 |
minHeight: '100vh', display: 'flex', flexDirection: 'column',
|
| 130 |
-
paddingBottom: '150px',
|
| 131 |
-
boxSizing: 'border-box'
|
| 132 |
}}>
|
| 133 |
|
| 134 |
{/* HEADER */}
|
| 135 |
<div style={{
|
| 136 |
padding: '15px 20px', display: 'flex', justifyContent: 'space-between', alignItems: 'center',
|
| 137 |
-
position: 'sticky', top: 0, zIndex: 10,
|
| 138 |
-
gap: '20px'
|
| 139 |
}}>
|
| 140 |
<div className="logo-expand-container">
|
| 141 |
<span className="logo-main">TEK</span>
|
| 142 |
<span className="logo-hidden">BUILD</span>
|
| 143 |
</div>
|
| 144 |
-
|
| 145 |
<div style={{display: 'flex', gap: '8px', flexShrink: 0}}>
|
| 146 |
<select className="glass-pill" value={selectedRatio} onChange={(e) => setSelectedRatio(e.target.value)}>
|
| 147 |
{ASPECT_RATIOS.map(r => <option key={r.id} value={r.id}>{r.name}</option>)}
|
| 148 |
</select>
|
| 149 |
-
{/* The dropdown now shows your custom names */}
|
| 150 |
<select className="glass-pill" value={selectedModel} onChange={(e) => setSelectedModel(e.target.value)} style={{maxWidth:'130px'}}>
|
| 151 |
{AI_MODELS.map(m => <option key={m.id} value={m.id}>{m.name}</option>)}
|
| 152 |
</select>
|
|
@@ -156,8 +150,7 @@ function App() {
|
|
| 156 |
{/* VIEWPORT */}
|
| 157 |
<div style={{
|
| 158 |
flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
| 159 |
-
padding: '20px', flexDirection: 'column',
|
| 160 |
-
minHeight: 0
|
| 161 |
}}>
|
| 162 |
{generating ? (
|
| 163 |
<div className="glass-panel" style={{padding: '20px', borderRadius:'50%'}}>
|
|
@@ -172,16 +165,14 @@ function App() {
|
|
| 172 |
)}
|
| 173 |
</div>
|
| 174 |
|
| 175 |
-
{/* PWA
|
| 176 |
{showInstallBanner && (
|
| 177 |
<div className="pwa-banner">
|
| 178 |
{isIOS ? (
|
| 179 |
<div style={{display:'flex', alignItems:'center', gap:'10px'}}>
|
| 180 |
<span style={{fontSize:'24px'}}>📲</span>
|
| 181 |
-
<div style={{textAlign:'left', fontSize:'14px'}}>
|
| 182 |
-
|
| 183 |
-
</div>
|
| 184 |
-
<button onClick={() => setShowInstallBanner(false)} style={{background:'none', border:'none', color:'#aaa', fontSize:'20px', padding:'0 10px'}}>×</button>
|
| 185 |
</div>
|
| 186 |
) : (
|
| 187 |
<div style={{display:'flex', alignItems:'center', justifyContent:'space-between', width:'100%'}}>
|
|
|
|
| 7 |
|
| 8 |
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
|
| 9 |
|
|
|
|
|
|
|
|
|
|
| 10 |
const AI_MODELS = [
|
| 11 |
{ id: 'openai/dall-e-3', name: 'TEK 3 (Best)' },
|
| 12 |
{ id: 'google/imagen-4.0-preview', name: 'TEK 4 HD (Real)' },
|
|
|
|
| 30 |
const [previewUrl, setPreviewUrl] = useState(null);
|
| 31 |
const fileInputRef = useRef(null);
|
| 32 |
|
|
|
|
| 33 |
const [deferredPrompt, setDeferredPrompt] = useState(null);
|
| 34 |
const [showInstallBanner, setShowInstallBanner] = useState(false);
|
| 35 |
const [isIOS, setIsIOS] = useState(false);
|
|
|
|
| 38 |
supabase.auth.getSession().then(({ data: { session } }) => setSession(session));
|
| 39 |
const { data: { subscription } } = supabase.auth.onAuthStateChange((_event, session) => setSession(session));
|
| 40 |
|
|
|
|
| 41 |
const isIosDevice = /ipad|iphone|ipod/.test(navigator.userAgent.toLowerCase()) && !window.MSStream;
|
|
|
|
|
|
|
| 42 |
const isInStandaloneMode = window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone === true;
|
| 43 |
|
| 44 |
if (isIosDevice && !isInStandaloneMode) {
|
|
|
|
| 49 |
window.addEventListener('beforeinstallprompt', (e) => {
|
| 50 |
e.preventDefault();
|
| 51 |
setDeferredPrompt(e);
|
| 52 |
+
if (!isInStandaloneMode) setShowInstallBanner(true);
|
|
|
|
|
|
|
| 53 |
});
|
| 54 |
|
| 55 |
return () => subscription.unsubscribe();
|
|
|
|
| 58 |
const handleInstallClick = async () => {
|
| 59 |
if (deferredPrompt) {
|
| 60 |
deferredPrompt.prompt();
|
|
|
|
|
|
|
| 61 |
setDeferredPrompt(null);
|
| 62 |
setShowInstallBanner(false);
|
| 63 |
}
|
|
|
|
| 80 |
if (!prompt) return;
|
| 81 |
setGenerating(true);
|
| 82 |
setImageSrc(null);
|
|
|
|
| 83 |
try {
|
| 84 |
if (!window.puter.auth.isSignedIn()) await window.puter.auth.signIn();
|
| 85 |
const ratioText = selectedRatio === '1:1' ? '' : ` --ar ${selectedRatio}`;
|
| 86 |
const finalPrompt = prompt + ratioText;
|
| 87 |
|
| 88 |
let imgElement;
|
|
|
|
| 89 |
if (inputImage && !selectedModel.includes('dall-e')) {
|
| 90 |
imgElement = await window.puter.ai.txt2img(finalPrompt, { model: selectedModel, image: inputImage });
|
| 91 |
} else {
|
|
|
|
| 100 |
}
|
| 101 |
};
|
| 102 |
|
| 103 |
+
// --- NEW START SCREEN (TEK DREAMS) ---
|
| 104 |
if (!session) {
|
| 105 |
return (
|
| 106 |
+
<div style={{
|
| 107 |
+
height: '100vh', display: 'flex', flexDirection: 'column',
|
| 108 |
+
alignItems: 'center', justifyContent: 'center'
|
| 109 |
+
}}>
|
| 110 |
+
{/* The Outer Glass Box */}
|
| 111 |
+
<div className="dream-stack-outer">
|
| 112 |
+
{/* The Inner Glass Box */}
|
| 113 |
+
<div className="dream-stack-middle">
|
| 114 |
+
<div className="dream-title">TEK DREAMS</div>
|
| 115 |
+
<button onClick={handleLogin} className="dream-btn">
|
| 116 |
+
Enter
|
| 117 |
+
</button>
|
| 118 |
+
</div>
|
| 119 |
</div>
|
| 120 |
</div>
|
| 121 |
);
|
| 122 |
}
|
| 123 |
|
| 124 |
+
// --- MAIN APP ---
|
| 125 |
return (
|
| 126 |
<div style={{
|
| 127 |
minHeight: '100vh', display: 'flex', flexDirection: 'column',
|
| 128 |
+
paddingBottom: '150px', boxSizing: 'border-box'
|
|
|
|
| 129 |
}}>
|
| 130 |
|
| 131 |
{/* HEADER */}
|
| 132 |
<div style={{
|
| 133 |
padding: '15px 20px', display: 'flex', justifyContent: 'space-between', alignItems: 'center',
|
| 134 |
+
position: 'sticky', top: 0, zIndex: 10, gap: '20px'
|
|
|
|
| 135 |
}}>
|
| 136 |
<div className="logo-expand-container">
|
| 137 |
<span className="logo-main">TEK</span>
|
| 138 |
<span className="logo-hidden">BUILD</span>
|
| 139 |
</div>
|
|
|
|
| 140 |
<div style={{display: 'flex', gap: '8px', flexShrink: 0}}>
|
| 141 |
<select className="glass-pill" value={selectedRatio} onChange={(e) => setSelectedRatio(e.target.value)}>
|
| 142 |
{ASPECT_RATIOS.map(r => <option key={r.id} value={r.id}>{r.name}</option>)}
|
| 143 |
</select>
|
|
|
|
| 144 |
<select className="glass-pill" value={selectedModel} onChange={(e) => setSelectedModel(e.target.value)} style={{maxWidth:'130px'}}>
|
| 145 |
{AI_MODELS.map(m => <option key={m.id} value={m.id}>{m.name}</option>)}
|
| 146 |
</select>
|
|
|
|
| 150 |
{/* VIEWPORT */}
|
| 151 |
<div style={{
|
| 152 |
flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
| 153 |
+
padding: '20px', flexDirection: 'column', minHeight: 0
|
|
|
|
| 154 |
}}>
|
| 155 |
{generating ? (
|
| 156 |
<div className="glass-panel" style={{padding: '20px', borderRadius:'50%'}}>
|
|
|
|
| 165 |
)}
|
| 166 |
</div>
|
| 167 |
|
| 168 |
+
{/* PWA BANNER */}
|
| 169 |
{showInstallBanner && (
|
| 170 |
<div className="pwa-banner">
|
| 171 |
{isIOS ? (
|
| 172 |
<div style={{display:'flex', alignItems:'center', gap:'10px'}}>
|
| 173 |
<span style={{fontSize:'24px'}}>📲</span>
|
| 174 |
+
<div style={{textAlign:'left', fontSize:'14px'}}>Tap Share then "Add to Home Screen"</div>
|
| 175 |
+
<button onClick={() => setShowInstallBanner(false)} style={{background:'none', border:'none', color:'#aaa', fontSize:'20px'}}>×</button>
|
|
|
|
|
|
|
| 176 |
</div>
|
| 177 |
) : (
|
| 178 |
<div style={{display:'flex', alignItems:'center', justifyContent:'space-between', width:'100%'}}>
|