ThumeMail/frontend/src/components/LoginScreen.tsx
2025-08-10 12:55:16 -04:00

150 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useEffect, useState } from 'react';
interface Props {
theme: 'light'|'dark';
onToggleTheme: ()=>void;
onLogin: ()=>void;
market?: string;
}
export const LoginScreen: React.FC<Props> = ({ theme, onToggleTheme, onLogin, market='en-US' }) => {
const [bgUrl,setBgUrl] = useState<string|null>(null);
const [attribution,setAttribution] = useState<string>('');
useEffect(()=>{
let cancelled = false;
fetch(`https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=${market}`)
.then(r=> r.ok ? r.json(): Promise.reject(r.status))
.then(json=>{
if (cancelled) return;
if (json?.images?.[0]) {
const img = json.images[0];
setBgUrl('https://www.bing.com' + img.url);
setAttribution(img.copyright || '');
}
})
.catch(()=>{ /* silent fallback */ });
return ()=> { cancelled = true; };
}, [market]);
const providerName: string = (typeof __OIDC_PROVIDER__ !== 'undefined' && __OIDC_PROVIDER__) || 'Identity Provider';
return (
<div style={{
position:'relative',
minHeight:'100vh',
fontFamily:'system-ui, sans-serif',
color:'var(--color-text)',
background: bgUrl
? `center/cover no-repeat url(${bgUrl}) fixed`
: 'linear-gradient(135deg,var(--grad-a),var(--grad-b))'
}}>
<div style={{
position:'absolute',
inset:0,
background:'var(--overlay)'
}}/>
<div style={{
position:'relative',
zIndex:2,
display:'flex',
flexDirection:'column',
minHeight:'100vh'
}}>
<header style={{
display:'flex',
justifyContent:'flex-end',
padding:'16px 20px',
gap:12
}}>
<button
onClick={onToggleTheme}
style={iconButtonStyle}
aria-label="Toggle dark mode"
title="Toggle dark mode"
>
{theme==='dark'
? '☀️'
: '🌙'}
</button>
</header>
<main style={{
flex:1,
display:'flex',
alignItems:'center',
justifyContent:'center',
padding:24
}}>
<div style={cardStyle}>
<h1 style={{ margin:'0 0 8px', fontSize:32, lineHeight:1.1 }}>IMAP Client</h1>
<p style={{ margin:'0 0 24px', opacity:0.85 }}>
Secure selfhosted mail dashboard. Sign in with your identity provider.
</p>
<button
onClick={onLogin}
style={primaryButtonStyle}
>
{`Sign in with ${providerName}`}
</button>
{attribution && (
<div style={{ marginTop:18, fontSize:11, opacity:0.6, textWrap:'balance' }}>
{attribution}
</div>
)}
</div>
</main>
<footer style={{
position:'relative',
zIndex:2,
textAlign:'center',
padding:'12px 8px',
fontSize:12,
color:'var(--color-footer)'
}}>
© {new Date().getFullYear()} IMAP Client Background: Bing Image of the Day
</footer>
</div>
</div>
);
};
const cardStyle: React.CSSProperties = {
width:'min(420px, 100%)',
backdropFilter:'blur(16px)',
background:'var(--card-bg)',
border:'1px solid var(--card-border)',
padding:'32px 34px 40px',
borderRadius:20,
boxShadow:'0 8px 32px -4px rgba(0,0,0,0.35)',
};
const primaryButtonStyle: React.CSSProperties = {
all:'unset',
cursor:'pointer',
background:'linear-gradient(90deg,var(--btn-a),var(--btn-b))',
color:'#fff',
fontWeight:600,
padding:'14px 22px',
borderRadius:12,
fontSize:15,
letterSpacing:0.3,
textAlign:'center',
boxShadow:'0 4px 18px -4px rgba(0,0,0,0.4)',
transition:'transform .15s ease, box-shadow .15s ease'
};
const iconButtonStyle: React.CSSProperties = {
all:'unset',
cursor:'pointer',
width:44,
height:44,
display:'grid',
placeItems:'center',
fontSize:20,
background:'var(--icon-btn-bg)',
border:'1px solid var(--icon-btn-border)',
borderRadius:12,
boxShadow:'0 4px 14px -4px rgba(0,0,0,0.4)',
transition:'background .2s'
};