diff --git a/src/components/admin/admin-sidebar.tsx b/src/components/admin/admin-sidebar.tsx index f67d44a7..8f907e62 100644 --- a/src/components/admin/admin-sidebar.tsx +++ b/src/components/admin/admin-sidebar.tsx @@ -6,6 +6,7 @@ import { KeyRound, LayoutDashboard, Mail, + Megaphone, Settings, ShieldCheck, Users, @@ -32,6 +33,7 @@ const adminNavItems = [ { titleKey: 'admin.nav.auth', url: '/admin/settings/oauth', icon: KeyRound }, { titleKey: 'admin.nav.email', url: '/admin/settings/email', icon: Mail }, { titleKey: 'admin.nav.settings', url: '/admin/settings', icon: Settings }, + { titleKey: 'admin.nav.announcement', url: '/admin/announcement', icon: Megaphone }, { titleKey: 'admin.nav.audit', url: '/admin/audit', icon: ShieldCheck }, { titleKey: 'admin.nav.licensing', url: '/admin/licensing', icon: BadgeCheck }, ] diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 9b65992e..9cee8983 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -109,6 +109,7 @@ "admin.nav.management": "Management", "admin.nav.overview": "Overview", "admin.nav.storages": "Storages", + "admin.nav.announcement": "Announcement", "admin.nav.audit": "Audit Logs", "admin.nav.users": "Users", "admin.nav.settings": "Settings", @@ -164,6 +165,10 @@ "admin.audit.proTooltip": "Audit Logs are available with ZPan Pro.", "admin.audit.placeholderTitle": "Audit Logs Coming Soon", "admin.audit.placeholderDescription": "This page is reserved for the future audit log experience.", + "admin.announcement.title": "Site Announcement", + "admin.announcement.description": "Manage the announcement area shown to users across the site.", + "admin.announcement.placeholderTitle": "Site Announcement Coming Soon", + "admin.announcement.placeholderDescription": "This page is reserved for the future announcement management experience.", "admin.users.resendInvite": "Resend Invite", "admin.users.revokeInvite": "Revoke Invite", "admin.users.inviteStatus.pending": "Pending", diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json index 14748856..e1a2744e 100644 --- a/src/i18n/locales/zh.json +++ b/src/i18n/locales/zh.json @@ -109,6 +109,7 @@ "admin.nav.management": "管理", "admin.nav.overview": "概览", "admin.nav.storages": "存储", + "admin.nav.announcement": "站点公告", "admin.nav.audit": "审计日志", "admin.nav.users": "用户", "admin.nav.settings": "设置", @@ -164,6 +165,10 @@ "admin.audit.proTooltip": "审计日志仅在 ZPan Pro 中可用。", "admin.audit.placeholderTitle": "审计日志即将推出", "admin.audit.placeholderDescription": "此页面已预留给未来的审计日志体验。", + "admin.announcement.title": "站点公告", + "admin.announcement.description": "管理面向站点用户展示的公告区域。", + "admin.announcement.placeholderTitle": "站点公告即将推出", + "admin.announcement.placeholderDescription": "此页面已预留给未来的公告管理体验。", "admin.users.resendInvite": "重新发送邀请", "admin.users.revokeInvite": "撤销邀请", "admin.users.inviteStatus.pending": "待使用", diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index a61a1600..f7555b6d 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -34,6 +34,7 @@ import { Route as AuthenticatedSettingsIhostRouteImport } from './routes/_authen import { Route as AuthenticatedSettingsAppearanceRouteImport } from './routes/_authenticated/settings/appearance' import { Route as AuthenticatedAdminLicensingRouteImport } from './routes/_authenticated/admin/licensing' import { Route as AuthenticatedAdminAuditRouteImport } from './routes/_authenticated/admin/audit' +import { Route as AuthenticatedAdminAnnouncementRouteImport } from './routes/_authenticated/admin/announcement' import { Route as AuthenticatedTeamsTeamIdRouteRouteImport } from './routes/_authenticated/teams/$teamId/route' import { Route as AuthenticatedTeamsTeamIdIndexRouteImport } from './routes/_authenticated/teams/$teamId/index' import { Route as AuthenticatedAdminUsersIndexRouteImport } from './routes/_authenticated/admin/users/index' @@ -180,6 +181,12 @@ const AuthenticatedAdminAuditRoute = AuthenticatedAdminAuditRouteImport.update({ path: '/audit', getParentRoute: () => AuthenticatedAdminRouteRoute, } as any) +const AuthenticatedAdminAnnouncementRoute = + AuthenticatedAdminAnnouncementRouteImport.update({ + id: '/announcement', + path: '/announcement', + getParentRoute: () => AuthenticatedAdminRouteRoute, + } as any) const AuthenticatedTeamsTeamIdRouteRoute = AuthenticatedTeamsTeamIdRouteRouteImport.update({ id: '/teams/$teamId', @@ -251,6 +258,7 @@ export interface FileRoutesByFullPath { '/s/$token': typeof STokenRoute '/u/$username': typeof UUsernameRoute '/teams/$teamId': typeof AuthenticatedTeamsTeamIdRouteRouteWithChildren + '/admin/announcement': typeof AuthenticatedAdminAnnouncementRoute '/admin/audit': typeof AuthenticatedAdminAuditRoute '/admin/licensing': typeof AuthenticatedAdminLicensingRoute '/settings/appearance': typeof AuthenticatedSettingsAppearanceRoute @@ -284,6 +292,7 @@ export interface FileRoutesByTo { '/s/$token': typeof STokenRoute '/u/$username': typeof UUsernameRoute '/': typeof AuthenticatedIndexRoute + '/admin/announcement': typeof AuthenticatedAdminAnnouncementRoute '/admin/audit': typeof AuthenticatedAdminAuditRoute '/admin/licensing': typeof AuthenticatedAdminLicensingRoute '/settings/appearance': typeof AuthenticatedSettingsAppearanceRoute @@ -322,6 +331,7 @@ export interface FileRoutesById { '/u/$username': typeof UUsernameRoute '/_authenticated/': typeof AuthenticatedIndexRoute '/_authenticated/teams/$teamId': typeof AuthenticatedTeamsTeamIdRouteRouteWithChildren + '/_authenticated/admin/announcement': typeof AuthenticatedAdminAnnouncementRoute '/_authenticated/admin/audit': typeof AuthenticatedAdminAuditRoute '/_authenticated/admin/licensing': typeof AuthenticatedAdminLicensingRoute '/_authenticated/settings/appearance': typeof AuthenticatedSettingsAppearanceRoute @@ -360,6 +370,7 @@ export interface FileRouteTypes { | '/s/$token' | '/u/$username' | '/teams/$teamId' + | '/admin/announcement' | '/admin/audit' | '/admin/licensing' | '/settings/appearance' @@ -393,6 +404,7 @@ export interface FileRouteTypes { | '/s/$token' | '/u/$username' | '/' + | '/admin/announcement' | '/admin/audit' | '/admin/licensing' | '/settings/appearance' @@ -430,6 +442,7 @@ export interface FileRouteTypes { | '/u/$username' | '/_authenticated/' | '/_authenticated/teams/$teamId' + | '/_authenticated/admin/announcement' | '/_authenticated/admin/audit' | '/_authenticated/admin/licensing' | '/_authenticated/settings/appearance' @@ -642,6 +655,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthenticatedAdminAuditRouteImport parentRoute: typeof AuthenticatedAdminRouteRoute } + '/_authenticated/admin/announcement': { + id: '/_authenticated/admin/announcement' + path: '/announcement' + fullPath: '/admin/announcement' + preLoaderRoute: typeof AuthenticatedAdminAnnouncementRouteImport + parentRoute: typeof AuthenticatedAdminRouteRoute + } '/_authenticated/teams/$teamId': { id: '/_authenticated/teams/$teamId' path: '/teams/$teamId' @@ -716,6 +736,7 @@ declare module '@tanstack/react-router' { } interface AuthenticatedAdminRouteRouteChildren { + AuthenticatedAdminAnnouncementRoute: typeof AuthenticatedAdminAnnouncementRoute AuthenticatedAdminAuditRoute: typeof AuthenticatedAdminAuditRoute AuthenticatedAdminLicensingRoute: typeof AuthenticatedAdminLicensingRoute AuthenticatedAdminIndexRoute: typeof AuthenticatedAdminIndexRoute @@ -728,6 +749,7 @@ interface AuthenticatedAdminRouteRouteChildren { const AuthenticatedAdminRouteRouteChildren: AuthenticatedAdminRouteRouteChildren = { + AuthenticatedAdminAnnouncementRoute: AuthenticatedAdminAnnouncementRoute, AuthenticatedAdminAuditRoute: AuthenticatedAdminAuditRoute, AuthenticatedAdminLicensingRoute: AuthenticatedAdminLicensingRoute, AuthenticatedAdminIndexRoute: AuthenticatedAdminIndexRoute, diff --git a/src/routes/_authenticated/admin/announcement.tsx b/src/routes/_authenticated/admin/announcement.tsx new file mode 100644 index 00000000..ba4b3443 --- /dev/null +++ b/src/routes/_authenticated/admin/announcement.tsx @@ -0,0 +1,41 @@ +import { createFileRoute } from '@tanstack/react-router' +import { Megaphone } from 'lucide-react' +import { useTranslation } from 'react-i18next' +import { ProBadge } from '@/components/ProBadge' +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' + +export const Route = createFileRoute('/_authenticated/admin/announcement')({ + component: AnnouncementPage, +}) + +function AnnouncementPage() { + const { t } = useTranslation() + + return ( +
{t('admin.announcement.description')}
+ +