mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-25 17:14:57 +02:00
feat(settings): badge pulse animation with settings toggle (#676)
* feat: animate panel count badge on new data arrival * feat(settings): gate badge pulse animation behind toggle (off by default) PR #671 adds CSS pulse on panel count badges. This commit gates it behind a new `badgeAnimation` setting in UnifiedSettings so users opt-in. Adds i18n keys for all 18 locales. --------- Co-authored-by: jeronlxj <jeronliaw@u.nus.edu>
This commit is contained in:
1
package-lock.json
generated
1
package-lock.json
generated
@@ -6382,7 +6382,6 @@
|
||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz",
|
||||
"integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@epic-web/invariant": "^1.0.0",
|
||||
"cross-spawn": "^7.0.6"
|
||||
|
||||
@@ -3,6 +3,7 @@ import { invokeTauri } from '../services/tauri-bridge';
|
||||
import { t } from '../services/i18n';
|
||||
import { h, replaceChildren, safeHtml } from '../utils/dom-utils';
|
||||
import { trackPanelResized } from '@/services/analytics';
|
||||
import { getAiFlowSettings } from '@/services/ai-flow-settings';
|
||||
|
||||
export interface PanelOptions {
|
||||
id: string;
|
||||
@@ -661,7 +662,13 @@ export class Panel {
|
||||
|
||||
public setCount(count: number): void {
|
||||
if (this.countEl) {
|
||||
const prev = parseInt(this.countEl.textContent ?? '0', 10);
|
||||
this.countEl.textContent = count.toString();
|
||||
if (count > prev && getAiFlowSettings().badgeAnimation) {
|
||||
this.countEl.classList.remove('bump');
|
||||
void this.countEl.offsetWidth;
|
||||
this.countEl.classList.add('bump');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -172,6 +172,8 @@ export class UnifiedSettings {
|
||||
this.updateAiStatus();
|
||||
} else if (target.id === 'us-map-flash') {
|
||||
setAiFlowSetting('mapNewsFlash', target.checked);
|
||||
} else if (target.id === 'us-badge-anim') {
|
||||
setAiFlowSetting('badgeAnimation', target.checked);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -288,6 +290,10 @@ export class UnifiedSettings {
|
||||
html += `<div class="ai-flow-section-label">${t('components.insights.sectionMap')}</div>`;
|
||||
html += this.toggleRowHtml('us-map-flash', t('components.insights.mapFlashLabel'), t('components.insights.mapFlashDesc'), settings.mapNewsFlash);
|
||||
|
||||
// Panels section
|
||||
html += `<div class="ai-flow-section-label">${t('components.insights.sectionPanels')}</div>`;
|
||||
html += this.toggleRowHtml('us-badge-anim', t('components.insights.badgeAnimLabel'), t('components.insights.badgeAnimDesc'), settings.badgeAnimation);
|
||||
|
||||
// AI Analysis section (web-only)
|
||||
if (!this.config.isDesktopApp) {
|
||||
html += `<div class="ai-flow-section-label">${t('components.insights.sectionAi')}</div>`;
|
||||
|
||||
@@ -910,6 +910,9 @@
|
||||
"sectionAi": "AI Analysis",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "Cloud AI (Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "إرسال العناوين إلى السحابة لتلخيص الذكاء الاصطناعي (موصى به)",
|
||||
|
||||
@@ -1176,6 +1176,9 @@
|
||||
"sectionAi": "AI Analysis",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "Cloud-KI (Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "Schlagzeilen zur KI-Zusammenfassung an die Cloud senden (empfohlen)",
|
||||
|
||||
@@ -949,6 +949,9 @@
|
||||
"sectionAi": "AI Analysis",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "Cloud AI (Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "Αποστολή τίτλων στο cloud για σύνοψη AI (συνιστάται)",
|
||||
|
||||
@@ -981,6 +981,9 @@
|
||||
"streamQualityDesc": "Set quality for all live streams (lower saves bandwidth)",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "Cloud AI (Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "Send headlines to cloud for AI summarization (recommended)",
|
||||
|
||||
@@ -1176,6 +1176,9 @@
|
||||
"sectionAi": "AI Analysis",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "IA en la nube (Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "Enviar titulares a la nube para resumen con IA (recomendado)",
|
||||
|
||||
@@ -910,6 +910,9 @@
|
||||
"sectionAi": "AI Analysis",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "IA Cloud (Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "Envoyer les titres au cloud pour le résumé IA (recommandé)",
|
||||
|
||||
@@ -1176,6 +1176,9 @@
|
||||
"sectionAi": "AI Analysis",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "IA Cloud (Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "Invia i titoli al cloud per il riepilogo IA (consigliato)",
|
||||
|
||||
@@ -910,6 +910,9 @@
|
||||
"sectionAi": "AI Analysis",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "クラウドAI(Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "見出しをクラウドに送信してAI要約(推奨)",
|
||||
|
||||
@@ -967,6 +967,9 @@
|
||||
"streamQualityDesc": "모든 라이브 스트림의 품질 설정 (낮추면 대역폭 절약)",
|
||||
"mapFlashLabel": "실시간 이벤트 펄스",
|
||||
"mapFlashDesc": "속보 수신 시 지도에서 해당 위치를 깜박임",
|
||||
"sectionPanels": "패널",
|
||||
"badgeAnimLabel": "카운트 배지 펄스",
|
||||
"badgeAnimDesc": "새 항목이 도착하면 패널 카운트 배지에 애니메이션 적용",
|
||||
"aiFlowTitle": "설정",
|
||||
"aiFlowCloudLabel": "클라우드 AI (Groq 및 OpenRouter)",
|
||||
"aiFlowCloudDesc": "헤드라인을 클라우드로 전송하여 AI 요약 (권장)",
|
||||
|
||||
@@ -979,6 +979,9 @@
|
||||
"sectionAi": "AI Analysis",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "Cloud AI (Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "Koppen naar de cloud sturen voor AI-samenvatting (aanbevolen)",
|
||||
|
||||
@@ -1176,6 +1176,9 @@
|
||||
"sectionAi": "AI Analysis",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "Cloud AI (Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "Wyślij nagłówki do chmury w celu podsumowania AI (zalecane)",
|
||||
|
||||
@@ -979,6 +979,9 @@
|
||||
"sectionAi": "AI Analysis",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "IA na nuvem (Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "Enviar manchetes para a nuvem para resumo IA (recomendado)",
|
||||
|
||||
@@ -910,6 +910,9 @@
|
||||
"sectionAi": "AI Analysis",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "Облачный ИИ (Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "Отправлять заголовки в облако для ИИ-суммирования (рекомендуется)",
|
||||
|
||||
@@ -979,6 +979,9 @@
|
||||
"sectionAi": "AI Analysis",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "Moln-AI (Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "Skicka rubriker till molnet för AI-sammanfattning (rekommenderat)",
|
||||
|
||||
@@ -910,6 +910,9 @@
|
||||
"sectionAi": "AI Analysis",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "Cloud AI (Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "ส่งพาดหัวข่าวไปยังคลาวด์เพื่อสรุปด้วย AI (แนะนำ)",
|
||||
|
||||
@@ -910,6 +910,9 @@
|
||||
"sectionAi": "AI Analysis",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "Bulut AI (Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "Basliklari AI ozetleme icin buluta gonder (onerilen)",
|
||||
|
||||
@@ -910,6 +910,9 @@
|
||||
"sectionAi": "AI Analysis",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "Cloud AI (Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "Gửi tiêu đề tới cloud để AI tóm tắt (khuyến nghị)",
|
||||
|
||||
@@ -910,6 +910,9 @@
|
||||
"sectionAi": "AI Analysis",
|
||||
"mapFlashLabel": "Live Event Pulse",
|
||||
"mapFlashDesc": "Flash locations on the map when breaking news arrives",
|
||||
"sectionPanels": "Panels",
|
||||
"badgeAnimLabel": "Count Badge Pulse",
|
||||
"badgeAnimDesc": "Animate panel count badges when new items arrive",
|
||||
"aiFlowTitle": "Settings",
|
||||
"aiFlowCloudLabel": "云端AI(Groq & OpenRouter)",
|
||||
"aiFlowCloudDesc": "将标题发送到云端进行AI摘要(推荐)",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
const STORAGE_KEY_BROWSER_MODEL = 'wm-ai-flow-browser-model';
|
||||
const STORAGE_KEY_CLOUD_LLM = 'wm-ai-flow-cloud-llm';
|
||||
const STORAGE_KEY_MAP_NEWS_FLASH = 'wm-map-news-flash';
|
||||
const STORAGE_KEY_BADGE_ANIMATION = 'wm-badge-animation';
|
||||
const STORAGE_KEY_STREAM_QUALITY = 'wm-stream-quality';
|
||||
const EVENT_NAME = 'ai-flow-changed';
|
||||
const STREAM_QUALITY_EVENT = 'stream-quality-changed';
|
||||
@@ -17,6 +18,7 @@ export interface AiFlowSettings {
|
||||
browserModel: boolean;
|
||||
cloudLlm: boolean;
|
||||
mapNewsFlash: boolean;
|
||||
badgeAnimation: boolean;
|
||||
}
|
||||
|
||||
function readBool(key: string, defaultValue: boolean): boolean {
|
||||
@@ -41,12 +43,14 @@ const STORAGE_KEY_MAP: Record<keyof AiFlowSettings, string> = {
|
||||
browserModel: STORAGE_KEY_BROWSER_MODEL,
|
||||
cloudLlm: STORAGE_KEY_CLOUD_LLM,
|
||||
mapNewsFlash: STORAGE_KEY_MAP_NEWS_FLASH,
|
||||
badgeAnimation: STORAGE_KEY_BADGE_ANIMATION,
|
||||
};
|
||||
|
||||
const DEFAULTS: AiFlowSettings = {
|
||||
browserModel: false,
|
||||
cloudLlm: true,
|
||||
mapNewsFlash: true,
|
||||
badgeAnimation: false,
|
||||
};
|
||||
|
||||
export function getAiFlowSettings(): AiFlowSettings {
|
||||
@@ -54,6 +58,7 @@ export function getAiFlowSettings(): AiFlowSettings {
|
||||
browserModel: readBool(STORAGE_KEY_BROWSER_MODEL, DEFAULTS.browserModel),
|
||||
cloudLlm: readBool(STORAGE_KEY_CLOUD_LLM, DEFAULTS.cloudLlm),
|
||||
mapNewsFlash: readBool(STORAGE_KEY_MAP_NEWS_FLASH, DEFAULTS.mapNewsFlash),
|
||||
badgeAnimation: readBool(STORAGE_KEY_BADGE_ANIMATION, DEFAULTS.badgeAnimation),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1061,6 +1061,17 @@ body.panel-resize-active iframe {
|
||||
background: var(--border);
|
||||
padding: 2px 6px;
|
||||
border-radius: 2px;
|
||||
transition: color 0.3s ease, background 0.3s ease;
|
||||
}
|
||||
|
||||
.panel-count.bump {
|
||||
animation: count-bump 0.5s ease-out;
|
||||
}
|
||||
|
||||
@keyframes count-bump {
|
||||
0% { transform: scale(1); background: var(--border); color: var(--text-dim); }
|
||||
40% { transform: scale(1.3); background: var(--accent); color: var(--bg); }
|
||||
100% { transform: scale(1); background: var(--border); color: var(--text-dim); }
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user