From 3f6678ac2f3fc2275d72c473351344153112903d Mon Sep 17 00:00:00 2001 From: Ap_Tx <110907771+ApTx2012@users.noreply.github.com> Date: Sat, 10 Oct 2026 21:32:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=A7=BB=E6=A4=8D=E8=BF=9C=E7=A8=8B?= =?UTF-8?q?=E5=85=AC=E5=91=8A=E4=B8=AD=E5=BF=83=20(#9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 从 Axolotl 搬 RemoteAnnouncements.vue,顶栏加公告铃铛。远程拉取先禁用,等接口。 --- apps/app-frontend/src/App.vue | 2 + .../src/components/ui/AppActionBar.vue | 47 ++- .../src/components/ui/RemoteAnnouncements.vue | 388 ++++++++++++++++++ .../src/helpers/remote-announcements.ts | 3 + .../app-frontend/src/locales/en-US/index.json | 30 ++ .../app-frontend/src/locales/zh-CN/index.json | 5 +- packages/ui/src/composables/index.ts | 1 + 7 files changed, 474 insertions(+), 2 deletions(-) create mode 100644 apps/app-frontend/src/components/ui/RemoteAnnouncements.vue diff --git a/apps/app-frontend/src/App.vue b/apps/app-frontend/src/App.vue index 521a733..d0418bf 100644 --- a/apps/app-frontend/src/App.vue +++ b/apps/app-frontend/src/App.vue @@ -95,6 +95,7 @@ import NavRail from '@/components/ui/NavRail.vue' import OnboardingOverlay from '@/components/ui/onboarding/OnboardingOverlay.vue' import QuickInstanceSwitcher from '@/components/ui/QuickInstanceSwitcher.vue' import SkinSiteSessionFrame from '@/components/ui/SkinSiteSessionFrame.vue' +import RemoteAnnouncements from '@/components/ui/RemoteAnnouncements.vue' import StartupAnnouncementModal from '@/components/ui/StartupAnnouncementModal.vue' import SplashScreen from '@/components/ui/SplashScreen.vue' import WindowControls from '@/components/ui/WindowControls.vue' @@ -2227,6 +2228,7 @@ provideAppUpdateDownloadProgress(appUpdateDownload) +
+ + + import { BellIcon, + NewspaperIcon, DownloadIcon, DropdownIcon, OnlineIndicatorIcon, @@ -211,7 +229,7 @@ import { } from '@modrinth/ui' import { convertFileSrc } from '@tauri-apps/api/core' import { Dropdown } from 'floating-vue' -import { computed, onBeforeUnmount, ref, watch } from 'vue' +import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue' import { useRoute, useRouter } from 'vue-router' import AppUpdateButton from '@/components/ui/app-update-button/index.vue' @@ -222,6 +240,10 @@ import { get_many as getInstances } from '@/helpers/instance' import { get_all as getRunningProcesses, kill as killProcess } from '@/helpers/process' import type { LoadingBar } from '@/helpers/state' import { progress_bars_list } from '@/helpers/state' +import { + OPEN_REMOTE_ANNOUNCEMENT_CENTER_EVENT, + REMOTE_ANNOUNCEMENTS_UPDATED_EVENT, +} from '@/helpers/remote-announcements' import type { GameInstance } from '@/helpers/types' import { downloadBarTypes, injectDownloadManager } from '@/providers/download-manager' @@ -231,6 +253,25 @@ const popupNotificationManager = injectPopupNotificationManager() const downloadManager = injectDownloadManager() const { formatMessage } = useVIntl() +const announcementUnreadCount = ref(0) + +function openAnnouncementCenter() { + window.dispatchEvent(new CustomEvent(OPEN_REMOTE_ANNOUNCEMENT_CENTER_EVENT)) +} + +function updateAnnouncementCount(event: Event) { + const detail = (event as CustomEvent<{ unreadKeys?: string[] }>).detail + announcementUnreadCount.value = detail?.unreadKeys?.length ?? 0 +} + +onMounted(() => { + window.addEventListener(REMOTE_ANNOUNCEMENTS_UPDATED_EVENT, updateAnnouncementCount) +}) + +onBeforeUnmount(() => { + window.removeEventListener(REMOTE_ANNOUNCEMENTS_UPDATED_EVENT, updateAnnouncementCount) +}) + type NotificationHistoryItem = { key: string createdAt?: number @@ -370,6 +411,10 @@ const messages = defineMessages({ id: 'app.action-bar.notifications', defaultMessage: 'Notifications', }, + announcements: { + id: 'app.action-bar.announcements', + defaultMessage: 'Announcements', + }, clearNotifications: { id: 'app.action-bar.notifications.clear', defaultMessage: 'Clear all', diff --git a/apps/app-frontend/src/components/ui/RemoteAnnouncements.vue b/apps/app-frontend/src/components/ui/RemoteAnnouncements.vue new file mode 100644 index 0000000..4e23f3c --- /dev/null +++ b/apps/app-frontend/src/components/ui/RemoteAnnouncements.vue @@ -0,0 +1,388 @@ + + + diff --git a/apps/app-frontend/src/helpers/remote-announcements.ts b/apps/app-frontend/src/helpers/remote-announcements.ts index a8b2a24..92f7bfe 100644 --- a/apps/app-frontend/src/helpers/remote-announcements.ts +++ b/apps/app-frontend/src/helpers/remote-announcements.ts @@ -64,3 +64,6 @@ export function isAnnouncementActive(item: RemoteAnnouncement, now = Date.now()) export function announcementKey(item: RemoteAnnouncement) { return item.id + ':' + item.published_at } + +export const REMOTE_ANNOUNCEMENTS_UPDATED_EVENT = 'starlight:remote-announcements-updated' +export const OPEN_REMOTE_ANNOUNCEMENT_CENTER_EVENT = 'starlight:open-remote-announcement-center' diff --git a/apps/app-frontend/src/locales/en-US/index.json b/apps/app-frontend/src/locales/en-US/index.json index ec78130..76e7dec 100644 --- a/apps/app-frontend/src/locales/en-US/index.json +++ b/apps/app-frontend/src/locales/en-US/index.json @@ -11431,5 +11431,35 @@ }, "app.anniversary.banner": { "message": "Happy {ordinal} Anniversary, Starlight!" + }, + "app.action-bar.announcements": { + "message": "Announcements" + }, + "app.remote-announcements.center-title": { + "message": "Announcements" + }, + "app.remote-announcements.empty": { + "message": "No announcements" + }, + "app.remote-announcements.view": { + "message": "View announcement" + }, + "app.remote-announcements.unread": { + "message": "Unread" + }, + "app.remote-announcements.read-all": { + "message": "Mark all announcements as read" + }, + "app.remote-announcements.preview-title": { + "message": "Announcement style preview" + }, + "app.remote-announcements.preview-summary": { + "message": "This is a local preview notification. Select View announcement to see the full Markdown content." + }, + "app.remote-announcements.preview-content": { + "message": "## Announcement preview\n\nThis is **sample content**, not a published announcement.\n\n- Supports headings, lists, and links\n- Close buttons are always available\n\n> Previewing does not change real announcement read status.\n\n| Type | Display |\n| --- | --- |\n| Modal | Full Markdown content |\n| Popup | Summary, then full content |\n\n[Visit the website](https://skin.starlight.cool/)" + }, + "app.remote-announcements.preview-action": { + "message": "Visit website" } } diff --git a/apps/app-frontend/src/locales/zh-CN/index.json b/apps/app-frontend/src/locales/zh-CN/index.json index 8760bfe..2065faa 100644 --- a/apps/app-frontend/src/locales/zh-CN/index.json +++ b/apps/app-frontend/src/locales/zh-CN/index.json @@ -11351,5 +11351,8 @@ "app.settings.synced-options.game-settings.value-off": { "message": "关闭" }, "app.settings.synced-options.game-settings.value-on": { "message": "开启" }, "app.settings.synced-options.game-settings.value-unset": { "message": "选择一个值" }, - "app.anniversary.banner": { "message": "Starlight {ordinal} 周年快乐!" } + "app.anniversary.banner": { "message": "Starlight {ordinal} 周年快乐!" }, + "app.action-bar.announcements": { "message": "公告" }, + "app.remote-announcements.center-title": { "message": "公告" }, + "app.remote-announcements.empty": { "message": "暂无公告" } } diff --git a/packages/ui/src/composables/index.ts b/packages/ui/src/composables/index.ts index 8a74269..f66970b 100644 --- a/packages/ui/src/composables/index.ts +++ b/packages/ui/src/composables/index.ts @@ -8,6 +8,7 @@ export * from './format-number' export * from './how-ago' export * from './i18n' export * from './i18n-debug' +export * from './modal-stack' export * from './page-leave-safety' export * from './scroll-indicator' export type { ArmorPreviewConfig } from './skin-rendering/armor-preview-types'