diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index a021043..e9f21c4 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -103,14 +103,15 @@ function App() {
// Screenshot handler with auth check
const handleScreenshot = useCallback(() => {
if (!user) {
- toast.warning('请先登录以拍摄宇宙快照');
- setShowAuthModal(true);
+ toast.warning('请先登录以拍摄宇宙快照', 3000, () => {
+ setShowAuthModal(true);
+ });
return;
}
// Use username or full_name or fallback
const nickname = user.full_name || user.username || 'Explorer';
takeScreenshot(nickname);
- }, [user, takeScreenshot]);
+ }, [user, takeScreenshot, toast]);
// Auth handlers
const handleLoginSuccess = (userData: any) => {
@@ -164,7 +165,15 @@ function App() {
isSoundOn={isSoundOn}
onToggleSound={() => setIsSoundOn(!isSoundOn)}
showMessageBoard={showMessageBoard}
- onToggleMessageBoard={() => setShowMessageBoard(!showMessageBoard)}
+ onToggleMessageBoard={() => {
+ if (!user) {
+ toast.warning('请先登录以访问留言板', 3000, () => {
+ setShowAuthModal(true);
+ });
+ } else {
+ setShowMessageBoard(!showMessageBoard);
+ }
+ }}
onScreenshot={handleScreenshot}
/>
diff --git a/frontend/src/components/FocusInfo.tsx b/frontend/src/components/FocusInfo.tsx
index 91947fb..2dbff66 100644
--- a/frontend/src/components/FocusInfo.tsx
+++ b/frontend/src/components/FocusInfo.tsx
@@ -41,35 +41,7 @@ export function FocusInfo({ body, onClose }: FocusInfoProps) {
}
};
- const terminalStyles = `
- .terminal-modal .ant-modal-content {
- background-color: #0d1117 !important;
- border: 1px solid #238636 !important;
- box-shadow: 0 0 30px rgba(35, 134, 54, 0.15) !important;
- color: #2ea043 !important;
- padding: 0 !important;
- overflow: hidden !important;
- }
- .terminal-modal .ant-modal-body {
- background-color: #0d1117 !important;
- }
- .terminal-modal .ant-modal-header {
- background-color: #161b22 !important;
- border-bottom: 1px solid #238636 !important;
- margin-bottom: 0 !important;
- }
- .terminal-modal .ant-modal-title {
- color: #2ea043 !important;
- }
- .terminal-modal .ant-modal-close {
- color: #2ea043 !important;
- }
- .terminal-modal .ant-modal-close:hover {
- background-color: rgba(35, 134, 54, 0.2) !important;
- }
- .terminal-modal .ant-modal-body .animate-in {
- color: #2ea043 !important; /* Ensure content text is green */
- }
+ const styles = `
@keyframes spin-slow {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
@@ -82,7 +54,7 @@ export function FocusInfo({ body, onClose }: FocusInfoProps) {
return (
// Remove fixed positioning, now handled by parent container (Html component in 3D)
-
+
{/* Main Info Card */}
@@ -165,54 +137,22 @@ export function FocusInfo({ body, onClose }: FocusInfoProps) {
{/* Connecting Line/Triangle pointing down to the body */}
- {/* Terminal Modal */}
-
setShowTerminal(false)}
- footer={null}
- width={800}
- centered
- className="terminal-modal"
- styles={{
- header: {
- backgroundColor: '#161b22',
- borderBottom: '1px solid #238636',
- padding: '12px 20px',
- marginBottom: 0,
- display: 'flex',
- alignItems: 'center'
- },
- mask: {
- backgroundColor: 'rgba(0, 0, 0, 0.85)',
- backdropFilter: 'blur(4px)'
- },
- body: {
- padding: '20px',
- backgroundColor: '#0d1117'
- }
- }}
+ onClose={() => setShowTerminal(false)}
title={
JPL/HORIZONS SYSTEM INTERFACE // {body.name.toUpperCase()}
}
- closeIcon={}
+ loading={loading}
+ loadingText="ESTABLISHING SECURE UPLINK..."
>
-
- {loading ? (
-
-
} />
-
ESTABLISHING SECURE UPLINK...
-
Connecting to ssd.jpl.nasa.gov...
-
- ) : (
-
- {terminalData}
-
- )}
+
+ {terminalData}
-
+
);
}
diff --git a/frontend/src/contexts/ToastContext.tsx b/frontend/src/contexts/ToastContext.tsx
index d1d9bcc..bd49420 100644
--- a/frontend/src/contexts/ToastContext.tsx
+++ b/frontend/src/contexts/ToastContext.tsx
@@ -1,4 +1,5 @@
import { createContext, useContext, useState, useCallback, useRef } from 'react';
+import type { ReactNode } from 'react';
import { X, CheckCircle, AlertCircle, AlertTriangle, Info } from 'lucide-react';
// Types
@@ -7,16 +8,17 @@ type ToastType = 'success' | 'error' | 'warning' | 'info';
interface Toast {
id: string;
type: ToastType;
- message: string;
+ message: ReactNode;
duration?: number;
+ onClose?: () => void;
}
interface ToastContextValue {
- showToast: (message: string, type?: ToastType, duration?: number) => string;
- success: (message: string, duration?: number) => string;
- error: (message: string, duration?: number) => string;
- warning: (message: string, duration?: number) => string;
- info: (message: string, duration?: number) => string;
+ showToast: (message: ReactNode, type?: ToastType, duration?: number, onClose?: () => void) => string;
+ success: (message: ReactNode, duration?: number, onClose?: () => void) => string;
+ error: (message: ReactNode, duration?: number, onClose?: () => void) => string;
+ warning: (message: ReactNode, duration?: number, onClose?: () => void) => string;
+ info: (message: ReactNode, duration?: number, onClose?: () => void) => string;
removeToast: (id: string) => void;
}
@@ -54,16 +56,22 @@ export function ToastProvider({ children }: { children: React.ReactNode }) {
const timersRef = useRef