Skip to content

Commit 6a9fd8a

Browse files
committed
changes
1 parent 5565c70 commit 6a9fd8a

4 files changed

Lines changed: 193 additions & 66 deletions

File tree

‎react-app/public/bg.jpg‎

27.3 KB
Loading

‎react-app/public/profile_image.png‎

120 KB
Loading

‎react-app/src/index.css‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,33 @@ body {
9292
height: 100%;
9393
}
9494

95+
/* ── Login page gradient button ─────────────────────────────────────── */
96+
.login-button {
97+
border: none;
98+
color: white;
99+
padding: 20px;
100+
text-align: center;
101+
display: block;
102+
font-size: 16px;
103+
margin: 4px 0;
104+
cursor: pointer;
105+
border-radius: 15px;
106+
background: linear-gradient(90deg, rgba(129, 223, 244, 1) 0%, rgba(80, 56, 237, 1) 100%);
107+
width: 100%;
108+
box-sizing: border-box;
109+
transition: background 0.2s, color 0.2s;
110+
}
111+
112+
.login-button:hover, .login-button:focus {
113+
background: #fff !important;
114+
color: #000 !important;
115+
}
116+
117+
.login-button:disabled {
118+
opacity: 0.5;
119+
cursor: not-allowed;
120+
}
121+
95122
/* ── Top bar ────────────────────────────────────────────────────────── */
96123
.topbar {
97124
background: #111;

‎react-app/src/pages/LoginPage.tsx‎

Lines changed: 166 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { useEffect } from 'react';
1+
import { useEffect, useState } from 'react';
2+
import { useNavigate } from 'react-router-dom';
23
import { useVoiceStore, useVoicesDataStore } from '../store';
34
import { useAWSServices } from '../hooks/useAWSServices';
45
import { VoiceSelect } from '../components/shared/VoiceSelect';
@@ -16,14 +17,19 @@ function getUserLanguage() {
1617
return (navigator.language ?? 'en').substring(0, 2);
1718
}
1819

20+
type View = 'landing' | 'streamer' | 'viewer';
21+
1922
export default function LoginPage() {
23+
const navigate = useNavigate();
2024
const { initialized, error } = useAWSServices();
2125
const {
2226
systemVoice, systemVoiceOption, defaultChatterVoice, defaultChatterVoiceOption,
2327
dstLangSelect, setVoice,
2428
} = useVoiceStore();
2529
const { } = useVoicesDataStore();
2630

31+
const [view, setView] = useState<View>('landing');
32+
2733
useEffect(() => {
2834
if (!dstLangSelect) {
2935
setVoice('dstLangSelect', getUserLanguage());
@@ -37,87 +43,181 @@ export default function LoginPage() {
3743
};
3844

3945
return (
40-
<div className="container-fluid min-vh-100 d-flex align-items-center justify-content-center" style={{ background: '#1a1a2e' }}>
41-
<div className="card bg-dark text-white p-4" style={{ maxWidth: 600, width: '100%' }}>
42-
<h2 className="text-center mb-1">tts.bot</h2>
43-
<p className="text-center text-muted mb-4">by Security_Live</p>
44-
45-
{!initialized && !error && (
46-
<div className="text-center py-4">
47-
<div className="spinner-border text-primary" role="status" />
48-
<p className="mt-2 text-muted">Initializing AWS services…</p>
49-
</div>
50-
)}
46+
<div
47+
style={{
48+
backgroundColor: '#000',
49+
backgroundImage: 'url(/bg.jpg)',
50+
backgroundPosition: 'center center',
51+
backgroundSize: 'cover',
52+
fontFamily: '"Poppins", "Helvetica Neue Light", Helvetica, Arial, sans-serif',
53+
color: 'white',
54+
display: 'flex',
55+
justifyContent: 'center',
56+
alignItems: 'center',
57+
minHeight: '100vh',
58+
margin: 0,
59+
}}
60+
>
61+
<div style={{ maxWidth: 550, width: '100%', textAlign: 'center', padding: '0 20px' }}>
62+
63+
{/* Logo */}
64+
<div style={{
65+
fontFamily: 'Poppins, sans-serif',
66+
marginBottom: 20,
67+
fontSize: 84,
68+
lineHeight: '80px',
69+
fontWeight: 900,
70+
textShadow: '-6px 8px 12px #000',
71+
}}>
72+
<img src="/profile_image.png" alt="tts.bot" style={{ height: 70, marginBottom: -10 }} />
73+
{' '}tts.bot for <span style={{ color: '#b36aff' }}>Twitch</span>
74+
</div>
75+
76+
<h1 style={{ textShadow: '6px 8px 4px rgba(0,0,0,0.25)' }}>
77+
Access requires a{' '}
78+
<span style={{ color: '#b36aff' }}>
79+
<a style={{ color: '#b36aff' }} href="https://www.twitch.tv/signup" target="_blank" rel="noreferrer">
80+
Twitch
81+
</a>
82+
</span>{' '}
83+
account.
84+
</h1>
5185

52-
{error && (
53-
<div className="alert alert-danger">Failed to connect to AWS: {error.message}</div>
86+
{/* ── Landing: Streamer / Viewer choice ── */}
87+
{view === 'landing' && (
88+
<div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
89+
<button className="login-button btn" onClick={() => setView('streamer')}>
90+
Streamer
91+
</button>
92+
<button className="login-button btn" onClick={() => navigate('/viewer')}>
93+
Viewer
94+
</button>
95+
</div>
5496
)}
5597

56-
{initialized && (
98+
{/* ── Streamer options ── */}
99+
{view === 'streamer' && (
57100
<>
58-
<div className="row g-3 mb-3">
59-
<div className="col-md-6">
60-
<VoiceSelect
61-
label="System Voice"
62-
voiceId={systemVoice}
63-
voiceOption={systemVoiceOption}
64-
onVoiceChange={(v) => setVoice('systemVoice', v)}
65-
onOptionChange={(v) => setVoice('systemVoiceOption', v)}
66-
/>
67-
</div>
68-
<div className="col-md-6">
69-
<VoiceSelect
70-
label="Default Chatter Voice"
71-
voiceId={defaultChatterVoice}
72-
voiceOption={defaultChatterVoiceOption}
73-
onVoiceChange={(v) => setVoice('defaultChatterVoice', v)}
74-
onOptionChange={(v) => setVoice('defaultChatterVoiceOption', v)}
75-
/>
101+
<h2 style={{ fontWeight: 100 }}>Streamer Options</h2>
102+
103+
{!initialized && !error && (
104+
<div style={{ padding: '20px 0' }}>
105+
<div className="spinner-border text-light" role="status" />
106+
<p className="mt-2" style={{ opacity: 0.7 }}>Initializing AWS services…</p>
76107
</div>
77-
</div>
108+
)}
78109

79-
<div className="mb-4">
80-
<label className="form-label">Translation Language</label>
81-
<select
82-
className="form-select form-select-sm bg-dark text-white"
83-
value={dstLangSelect}
84-
onChange={(e) => setVoice('dstLangSelect', e.target.value)}
85-
>
86-
<option value="">Choose your language</option>
87-
<option value="en">English</option>
88-
<option value="es">Spanish</option>
89-
<option value="fr">French</option>
90-
<option value="de">German</option>
91-
<option value="pt">Portuguese</option>
92-
<option value="ja">Japanese</option>
93-
<option value="ko">Korean</option>
94-
<option value="zh">Chinese</option>
95-
<option value="ar">Arabic</option>
96-
<option value="ru">Russian</option>
97-
<option value="it">Italian</option>
98-
<option value="pl">Polish</option>
99-
<option value="nl">Dutch</option>
100-
<option value="sv">Swedish</option>
101-
<option value="tr">Turkish</option>
102-
</select>
103-
</div>
110+
{error && (
111+
<div className="alert alert-danger">Failed to connect to AWS: {error.message}</div>
112+
)}
113+
114+
{initialized && (
115+
<dl style={{ textAlign: 'left' }}>
116+
<div style={{ marginBottom: 16 }}>
117+
<VoiceSelect
118+
label="System Voice"
119+
voiceId={systemVoice}
120+
voiceOption={systemVoiceOption}
121+
onVoiceChange={(v) => setVoice('systemVoice', v)}
122+
onOptionChange={(v) => setVoice('systemVoiceOption', v)}
123+
/>
124+
</div>
125+
<div style={{ marginBottom: 16 }}>
126+
<VoiceSelect
127+
label="Default Chatter Voice"
128+
voiceId={defaultChatterVoice}
129+
voiceOption={defaultChatterVoiceOption}
130+
onVoiceChange={(v) => setVoice('defaultChatterVoice', v)}
131+
onOptionChange={(v) => setVoice('defaultChatterVoiceOption', v)}
132+
/>
133+
</div>
134+
<div style={{ marginBottom: 16 }}>
135+
<label style={{ display: 'block', marginBottom: 6 }}>Translation Language</label>
136+
<select
137+
style={{
138+
width: '100%', padding: 12, borderRadius: 10,
139+
border: '2px solid #b36aff', background: '#666', color: 'white',
140+
boxSizing: 'border-box',
141+
}}
142+
value={dstLangSelect}
143+
onChange={(e) => setVoice('dstLangSelect', e.target.value)}
144+
>
145+
<option value="">Choose your language</option>
146+
<option value="en">English</option>
147+
<option value="es">Spanish</option>
148+
<option value="fr">French</option>
149+
<option value="de">German</option>
150+
<option value="pt">Portuguese</option>
151+
<option value="ja">Japanese</option>
152+
<option value="ko">Korean</option>
153+
<option value="zh">Chinese</option>
154+
<option value="ar">Arabic</option>
155+
<option value="ru">Russian</option>
156+
<option value="it">Italian</option>
157+
<option value="pl">Polish</option>
158+
<option value="nl">Dutch</option>
159+
<option value="sv">Swedish</option>
160+
<option value="tr">Turkish</option>
161+
</select>
162+
</div>
163+
</dl>
164+
)}
165+
166+
<h2 style={{ fontWeight: 100 }}>Choose your desired capabilities and click authenticate.</h2>
104167

105-
<div className="d-grid gap-2">
168+
<dl style={{ textAlign: 'left', marginBottom: 16 }}>
169+
<dd style={{ margin: '10px 0' }}>
170+
<input type="radio" id="moderation" name="capability" defaultChecked readOnly />
171+
<label htmlFor="moderation" style={{ marginLeft: 8 }}>Moderation (Recommended)</label>
172+
</dd>
173+
<dd style={{ margin: '10px 0' }}>
174+
<input type="radio" id="chat" name="capability" readOnly />
175+
<label htmlFor="chat" style={{ marginLeft: 8 }}>Basic Chat</label>
176+
</dd>
177+
</dl>
178+
179+
<button
180+
className="login-button btn"
181+
onClick={() => handleLogin(true)}
182+
disabled={!initialized}
183+
>
184+
Authenticate
185+
</button>
186+
187+
<div style={{ marginTop: 10 }}>
106188
<button
107-
className="btn btn-primary"
108-
onClick={() => handleLogin(true)}
189+
className="login-button btn"
190+
style={{ fontSize: 13, padding: '12px 20px', opacity: 0.8 }}
191+
onClick={() => handleLogin(false)}
192+
disabled={!initialized}
109193
>
110-
Authorize on Twitch (Full Permissions)
194+
Authenticate with minimal permissions
111195
</button>
196+
</div>
197+
198+
<div style={{ marginTop: 10 }}>
112199
<button
113-
className="btn btn-outline-secondary btn-sm"
114-
onClick={() => handleLogin(false)}
200+
className="login-button btn"
201+
style={{ fontSize: 13, padding: '12px 20px', opacity: 0.6 }}
202+
onClick={() => setView('landing')}
115203
>
116-
Authorize with minimal permissions
204+
← Back
117205
</button>
118206
</div>
119207
</>
120208
)}
209+
210+
{/* Footer */}
211+
<div style={{ fontSize: 10, marginTop: 30 }}>
212+
<p>Super Secure Login<br />Like Banks Have</p>
213+
<p>*** Voice Recognition is only supported with Chrome ***</p>
214+
<p>
215+
<a style={{ color: '#b36aff' }} href="https://aws.amazon.com/polly/" target="_blank" rel="noreferrer">
216+
Powered by Amazon Web Services (AWS) API Gateway, Lambda, DynamoDB, Polly and Translate
217+
</a>
218+
</p>
219+
</div>
220+
121221
</div>
122222
</div>
123223
);

0 commit comments

Comments
 (0)