重构组件样式系统为玻璃态设计风格并优化交互动效
Some checks failed
CI / Check / macos-latest (push) Has been cancelled
CI / Check / ubuntu-latest (push) Has been cancelled
CI / Check / windows-latest (push) Has been cancelled
CI / Test / macos-latest (push) Has been cancelled
CI / Test / ubuntu-latest (push) Has been cancelled
CI / Test / windows-latest (push) Has been cancelled
CI / Clippy (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Security Audit (push) Has been cancelled
CI / Secrets Scan (push) Has been cancelled
CI / Install Script Smoke Test (push) Has been cancelled

This commit is contained in:
iven
2026-03-01 18:24:02 +08:00
parent 810e32077e
commit 20093a6644
5 changed files with 2953 additions and 3706 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,14 +2,46 @@
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="OpenFang - Open Source Agent Operating System Dashboard">
<meta name="theme-color" content="#020617">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="description" content="OpenFang Open Source Agent Operating System. Manage, monitor, and orchestrate AI agents with a powerful dashboard.">
<meta name="keywords" content="OpenFang, AI, Agent, Operating System, Dashboard, LLM, Automation">
<meta name="author" content="OpenFang">
<meta name="theme-color" content="#020617" media="(prefers-color-scheme: dark)">
<meta name="theme-color" content="#F8F9FB" media="(prefers-color-scheme: light)">
<meta name="color-scheme" content="light dark">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="mobile-web-app-capable" content="yes">
<title>OpenFang Dashboard</title>
<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="icon" type="image/png" href="/logo.png">
<link rel="icon" type="image/png" sizes="32x32" href="/logo.png">
<link rel="apple-touch-icon" href="/logo.png">
<!-- Preconnect to Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- Typography: Inter (UI) + Geist Mono (Code) -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Geist+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<!-- Critical CSS for initial render -->
<style>
/* Prevent FOUC */
[x-cloak] { display: none !important; }
/* Initial theme before Alpine loads */
html {
background: #020617;
color-scheme: dark;
}
@media (prefers-color-scheme: light) {
html {
background: #F8F9FB;
color-scheme: light;
}
}
</style>
</head>

View File

@@ -360,14 +360,25 @@ impl PresenceManager {
.clone();
// Check if user is already in another session
if let Some(existing_user) = self.users.get(&connection_id) {
if existing_user.session_id != session_id {
// Leave the previous session first
self.leave_session(connection_id)?;
} else {
// Already in this session
return Ok(existing_user.clone());
// Note: We need to clone the data and drop the reference before calling leave_session
// to avoid a deadlock with DashMap
let should_leave = {
let user_ref = self.users.get(&connection_id);
match user_ref {
Some(u) => {
if u.session_id == session_id {
// Already in this session - return the user
return Ok(u.clone());
}
true // Need to leave the old session
}
None => false
}
};
// user_ref is now dropped, we can safely call leave_session
if should_leave {
self.leave_session(connection_id)?;
}
// Check max participants
@@ -535,11 +546,11 @@ impl PresenceManager {
for mut entry in self.users.iter_mut() {
let user = entry.value_mut();
let elapsed = now.signed_duration_since(user.last_activity);
let elapsed_secs = elapsed.num_seconds() as u64;
let elapsed_ms = elapsed.num_milliseconds() as u128;
let new_status = if elapsed_secs > self.config.away_timeout.as_secs() {
let new_status = if elapsed_ms > self.config.away_timeout.as_millis() {
PresenceStatus::Away
} else if elapsed_secs > self.config.idle_timeout.as_secs() {
} else if elapsed_ms > self.config.idle_timeout.as_millis() {
PresenceStatus::Idle
} else {
PresenceStatus::Active
@@ -566,8 +577,9 @@ impl PresenceManager {
for entry in self.users.iter() {
let user = entry.value();
let elapsed = now.signed_duration_since(user.last_activity);
let elapsed_ms = elapsed.num_milliseconds() as u64;
if elapsed.num_seconds() as u64 > self.config.cleanup_timeout.as_secs() {
if u128::from(elapsed_ms) > self.config.cleanup_timeout.as_millis() {
removed.push(user.connection_id);
}
}