feat: 支持 github 登录
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import Image from 'next/image';
|
||||||
import { InputOTP, InputOTPGroup, InputOTPSlot } from '@/components/ui/input-otp';
|
import { InputOTP, InputOTPGroup, InputOTPSlot } from '@/components/ui/input-otp';
|
||||||
import { MailIcon } from './Icons';
|
import { MailIcon } from './Icons';
|
||||||
|
import githubImg from "../assets/github.svg";
|
||||||
|
|
||||||
export default function LoginModal({
|
export default function LoginModal({
|
||||||
onClose,
|
onClose,
|
||||||
@@ -13,7 +15,8 @@ export default function LoginModal({
|
|||||||
loginError,
|
loginError,
|
||||||
loginSuccess,
|
loginSuccess,
|
||||||
handleSendOtp,
|
handleSendOtp,
|
||||||
handleVerifyEmailOtp
|
handleVerifyEmailOtp,
|
||||||
|
handleGithubLogin
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -84,7 +87,6 @@ export default function LoginModal({
|
|||||||
type="button"
|
type="button"
|
||||||
className="button secondary"
|
className="button secondary"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
disabled={loginLoading}
|
|
||||||
>
|
>
|
||||||
取消
|
取消
|
||||||
</button>
|
</button>
|
||||||
@@ -98,6 +100,53 @@ export default function LoginModal({
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
{handleGithubLogin && (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className="login-divider"
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
margin: '20px 0',
|
||||||
|
gap: 12,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ flex: 1, height: 1, background: 'var(--border)' }} />
|
||||||
|
<span className="muted" style={{ fontSize: '12px', whiteSpace: 'nowrap' }}>或使用</span>
|
||||||
|
<div style={{ flex: 1, height: 1, background: 'var(--border)' }} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="github-login-btn"
|
||||||
|
onClick={handleGithubLogin}
|
||||||
|
disabled={loginLoading}
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
gap: 10,
|
||||||
|
padding: '12px 16px',
|
||||||
|
border: '1px solid var(--border)',
|
||||||
|
borderRadius: 8,
|
||||||
|
background: 'var(--bg)',
|
||||||
|
color: 'var(--text)',
|
||||||
|
cursor: loginLoading ? 'not-allowed' : 'pointer',
|
||||||
|
fontSize: '14px',
|
||||||
|
fontWeight: 500,
|
||||||
|
opacity: loginLoading ? 0.6 : 1,
|
||||||
|
transition: 'all 0.2s ease',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="github-icon-wrap">
|
||||||
|
<Image unoptimized alt="项目Github地址" src={githubImg} style={{ width: '24px', height: '24px', cursor: 'pointer' }} onClick={() => window.open("https://github.com/hzm0321/real-time-fund")} />
|
||||||
|
</span>
|
||||||
|
<span>使用 GitHub 登录</span>
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3348,6 +3348,35 @@ input[type="number"] {
|
|||||||
color: var(--success);
|
color: var(--success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ========== GitHub 登录按钮样式 ========== */
|
||||||
|
.github-login-btn {
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
-webkit-backdrop-filter: blur(12px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.github-login-btn:hover {
|
||||||
|
border-color: var(--primary);
|
||||||
|
background: rgba(34, 211, 238, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.github-login-btn:active {
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="light"] .github-login-btn {
|
||||||
|
background: #f8fafc;
|
||||||
|
border-color: #e2e8f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="light"] .github-login-btn:hover {
|
||||||
|
background: #f1f5f9;
|
||||||
|
border-color: #94a3af;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="light"] .github-login-btn img {
|
||||||
|
filter: brightness(0.2);
|
||||||
|
}
|
||||||
|
|
||||||
.button.secondary {
|
.button.secondary {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ const createNoopSupabase = () => ({
|
|||||||
data: { subscription: { unsubscribe: () => { } } }
|
data: { subscription: { unsubscribe: () => { } } }
|
||||||
}),
|
}),
|
||||||
signInWithOtp: async () => ({ data: null, error: { message: 'Supabase not configured' } }),
|
signInWithOtp: async () => ({ data: null, error: { message: 'Supabase not configured' } }),
|
||||||
|
signInWithOAuth: async () => ({ data: null, error: { message: 'Supabase not configured' } }),
|
||||||
verifyOtp: async () => ({ data: null, error: { message: 'Supabase not configured' } }),
|
verifyOtp: async () => ({ data: null, error: { message: 'Supabase not configured' } }),
|
||||||
signOut: async () => ({ error: null })
|
signOut: async () => ({ error: null })
|
||||||
},
|
},
|
||||||
|
|||||||
27
app/page.jsx
27
app/page.jsx
@@ -2415,6 +2415,29 @@ export default function HomePage() {
|
|||||||
setLoginLoading(false);
|
setLoginLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleGithubLogin = async () => {
|
||||||
|
setLoginError('');
|
||||||
|
if (!isSupabaseConfigured) {
|
||||||
|
showToast('未配置 Supabase,无法登录', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
isExplicitLoginRef.current = true;
|
||||||
|
setLoginLoading(true);
|
||||||
|
const { error } = await supabase.auth.signInWithOAuth({
|
||||||
|
provider: 'github',
|
||||||
|
options: {
|
||||||
|
redirectTo: window.location.origin
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (error) throw error;
|
||||||
|
} catch (err) {
|
||||||
|
setLoginError(err.message || 'GitHub 登录失败,请稍后再试');
|
||||||
|
isExplicitLoginRef.current = false;
|
||||||
|
setLoginLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 登出
|
// 登出
|
||||||
const handleLogout = async () => {
|
const handleLogout = async () => {
|
||||||
isLoggingOutRef.current = true;
|
isLoggingOutRef.current = true;
|
||||||
@@ -3560,7 +3583,6 @@ export default function HomePage() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const isAnyModalOpen =
|
const isAnyModalOpen =
|
||||||
settingsOpen ||
|
|
||||||
feedbackOpen ||
|
feedbackOpen ||
|
||||||
addResultOpen ||
|
addResultOpen ||
|
||||||
addFundToGroupOpen ||
|
addFundToGroupOpen ||
|
||||||
@@ -3596,7 +3618,6 @@ export default function HomePage() {
|
|||||||
containerRef.current.style.overflow = '';
|
containerRef.current.style.overflow = '';
|
||||||
};
|
};
|
||||||
}, [
|
}, [
|
||||||
settingsOpen,
|
|
||||||
feedbackOpen,
|
feedbackOpen,
|
||||||
addResultOpen,
|
addResultOpen,
|
||||||
addFundToGroupOpen,
|
addFundToGroupOpen,
|
||||||
@@ -4882,6 +4903,7 @@ export default function HomePage() {
|
|||||||
setLoginSuccess('');
|
setLoginSuccess('');
|
||||||
setLoginEmail('');
|
setLoginEmail('');
|
||||||
setLoginOtp('');
|
setLoginOtp('');
|
||||||
|
setLoginLoading(false);
|
||||||
}}
|
}}
|
||||||
loginEmail={loginEmail}
|
loginEmail={loginEmail}
|
||||||
setLoginEmail={setLoginEmail}
|
setLoginEmail={setLoginEmail}
|
||||||
@@ -4892,6 +4914,7 @@ export default function HomePage() {
|
|||||||
loginSuccess={loginSuccess}
|
loginSuccess={loginSuccess}
|
||||||
handleSendOtp={handleSendOtp}
|
handleSendOtp={handleSendOtp}
|
||||||
handleVerifyEmailOtp={handleVerifyEmailOtp}
|
handleVerifyEmailOtp={handleVerifyEmailOtp}
|
||||||
|
handleGithubLogin={isSupabaseConfigured ? handleGithubLogin : undefined}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user