diff --git a/src/components/AboutDialog.jsx b/src/components/AboutDialog.jsx
new file mode 100644
index 0000000..d135ef7
--- /dev/null
+++ b/src/components/AboutDialog.jsx
@@ -0,0 +1,59 @@
+import { useEffect } from 'react';
+
+/* =========================================================
+ AboutDialog —— 应用关于弹窗(PineSound 品牌)
+ 页眉右上角「ⓘ」按钮打开;展示产品名/版本/技术栈/版权
+ ========================================================= */
+
+const APP_INFO = {
+ brand: 'PineSound',
+ product: '园区智能语音交互助手',
+ version: '0.1.0',
+ tagline: '面向大屏的数字园区智能体 —— 看得见 · 听得懂 · 说得出',
+ tech: [
+ '前端:React + Vite + Tauri',
+ '后端:FastAPI + 实时语音栈(s2s)',
+ '识别:YOLO 人脸/姿态(举手开始·结束对话)',
+ '语音:qwen ASR / LLM / TTS(云端)',
+ ],
+ copyright: '© 2026 PineSound · 昆明大学生创业园',
+};
+
+export default function AboutDialog({ open, onClose }) {
+ // Esc 关闭
+ useEffect(() => {
+ if (!open) return;
+ const onKey = (e) => { if (e.key === 'Escape') onClose(); };
+ window.addEventListener('keydown', onKey);
+ return () => window.removeEventListener('keydown', onKey);
+ }, [open, onClose]);
+
+ if (!open) return null;
+ return (
+
+
e.stopPropagation()}>
+
+
+
+
PS
+
{APP_INFO.brand}
+
{APP_INFO.product}
+
+
+
{APP_INFO.tagline}
+
+
+
技术栈
+
+ {APP_INFO.tech.map((t, i) => - {t}
)}
+
+
+
+
+ 版本 v{APP_INFO.version}
+ {APP_INFO.copyright}
+
+
+
+ );
+}
diff --git a/src/components/Icons.jsx b/src/components/Icons.jsx
index dec5495..3b6c0bf 100644
--- a/src/components/Icons.jsx
+++ b/src/components/Icons.jsx
@@ -10,7 +10,7 @@ import {
Heart, Pill, Dna, Microscope, Atom, MapPin, Flag, Award, Medal,
History, Drone, Plane, Rocket, Satellite, Wallet, UserPlus, Activity,
Volume, VolumeOff, ChevronLeft, ChevronRight, PlayerPlay, PlayerPause,
- Send, Trash, Eraser, Headset, CircleDot,
+ Send, Trash, Eraser, Headset, CircleDot, AlertCircle,
Microphone, MicrophoneFilled, MicrophoneOff, MessageCircle,
} from '@appica/icons-react';
@@ -80,6 +80,7 @@ const NAME_MAP = {
eraser: Eraser,
headset: Headset,
'circle-dot': CircleDot,
+ info: AlertCircle,
microphone: Microphone,
'microphone-filled': MicrophoneFilled,
'microphone-off': MicrophoneOff,
@@ -116,6 +117,6 @@ export {
Heart, Pill, Dna, Microscope, Atom, MapPin, Flag, Award, Medal,
History, Drone, Plane, Rocket, Satellite, Wallet, UserPlus, Activity,
Volume, VolumeOff, ChevronLeft, ChevronRight, PlayerPlay, PlayerPause,
- Send, Trash, Eraser, Headset, CircleDot,
+ Send, Trash, Eraser, Headset, CircleDot, AlertCircle,
Microphone, MicrophoneFilled, MicrophoneOff, MessageCircle,
};
diff --git a/src/components/PageHeader.jsx b/src/components/PageHeader.jsx
index e70bcbc..e1ad5d4 100644
--- a/src/components/PageHeader.jsx
+++ b/src/components/PageHeader.jsx
@@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import Icon from './Icons';
import MediaHeaderControls from './MediaHeaderControls';
+import AboutDialog from './AboutDialog';
import { PAGE_ORDER, usePageIndex } from '../utils/pageNav';
import { Avatar, AvatarImage, AvatarFallback } from '@appica/ui-react/avatar'
@@ -21,6 +22,7 @@ export default function PageHeader() {
const navigate = useNavigate();
const location = useLocation();
const [now, setNow] = useState(new Date());
+ const [aboutOpen, setAboutOpen] = useState(false);
const pageIdx = usePageIndex();
useEffect(() => {
@@ -74,11 +76,23 @@ export default function PageHeader() {
{status}
+
{timeStr}
{dateStr} 周{week}
+
+ {/* 关于 PineSound */}
+ setAboutOpen(false)} />
);
}
diff --git a/src/styles/datascreen.css b/src/styles/datascreen.css
index c66ec80..5a8a0c2 100644
--- a/src/styles/datascreen.css
+++ b/src/styles/datascreen.css
@@ -2554,3 +2554,134 @@
@media (max-width: 1280px) {
.bd-hd-media-name { display: none; }
}
+
+/* ==================== 关于 PineSound 弹窗 ==================== */
+.bd-about-btn {
+ flex: none;
+ width: 30px;
+ height: 30px;
+ border-radius: 50%;
+ border: 1px solid rgba(47, 107, 255, 0.25);
+ background: rgba(255, 255, 255, 0.7);
+ color: var(--bd-sub, #7d8fa9);
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ transition: all 0.2s;
+}
+.bd-about-btn:hover {
+ color: #2f6bff;
+ border-color: #2f6bff;
+ background: #fff;
+}
+
+.about-overlay {
+ position: fixed;
+ inset: 0;
+ z-index: 300;
+ background: rgba(13, 28, 48, 0.45);
+ backdrop-filter: blur(4px);
+ -webkit-backdrop-filter: blur(4px);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+.about-modal {
+ position: relative;
+ width: min(420px, calc(100vw - 48px));
+ background: #fff;
+ border-radius: 16px;
+ padding: 28px 30px 22px;
+ box-shadow: 0 24px 60px rgba(15, 42, 96, 0.28);
+ animation: about-pop 0.25s ease;
+}
+@keyframes about-pop {
+ from { opacity: 0; transform: translateY(12px) scale(0.97); }
+ to { opacity: 1; transform: none; }
+}
+.about-close {
+ position: absolute;
+ top: 12px;
+ right: 14px;
+ width: 28px;
+ height: 28px;
+ border: none;
+ background: transparent;
+ color: #9fb0c6;
+ font-size: 20px;
+ line-height: 1;
+ cursor: pointer;
+ border-radius: 8px;
+}
+.about-close:hover { color: #1d2c44; background: #f0f4fa; }
+
+.about-brand { text-align: center; margin-bottom: 6px; }
+.about-logo {
+ width: 64px;
+ height: 64px;
+ margin: 0 auto 10px;
+ border-radius: 18px;
+ background: linear-gradient(135deg, #2f6bff 0%, #22d3ee 100%);
+ color: #fff;
+ font-size: 26px;
+ font-weight: 800;
+ letter-spacing: 0.02em;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 10px 24px rgba(47, 107, 255, 0.35);
+}
+.about-name {
+ margin: 0;
+ font-size: 24px;
+ font-weight: 800;
+ color: #1d2c44;
+ letter-spacing: 0.04em;
+}
+.about-product {
+ margin-top: 4px;
+ font-size: 13px;
+ color: #7d8fa9;
+}
+.about-tagline {
+ text-align: center;
+ margin: 14px 0 18px;
+ font-size: 12.5px;
+ color: #4a5b74;
+ line-height: 1.6;
+ padding: 10px 12px;
+ background: #f5f8ff;
+ border-radius: 10px;
+}
+.about-section h4 {
+ margin: 0 0 8px;
+ font-size: 12px;
+ color: #7d8fa9;
+ letter-spacing: 0.08em;
+}
+.about-section ul {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+}
+.about-section li {
+ font-size: 12.5px;
+ color: #33425c;
+ padding: 6px 10px;
+ background: #f8fafd;
+ border-radius: 8px;
+ border: 1px solid #eef2f8;
+}
+.about-meta {
+ margin-top: 18px;
+ padding-top: 14px;
+ border-top: 1px dashed #e3ecf7;
+ display: flex;
+ justify-content: space-between;
+ font-size: 11px;
+ color: #9fb0c6;
+}