feat(settings): add security center, 2FA/TOTP, avatar upload, system settings
- Add TOTP implementation and two-factor data-access for 2FA enrollment - Add security center card with password policy and session management - Add avatar upload action and component - Add system settings actions and data-access (actions-system-settings, data-access-system-settings) - Add notification preferences and service actions - Add security-utils and student-overview-data with tests - Update existing settings views, data-access, and types for new features
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
"use client"
|
||||
import { Monitor, Moon, Sun } from "lucide-react"
|
||||
|
||||
import { Monitor, Moon, Sun, Globe } from "lucide-react"
|
||||
import { useTheme } from "next-themes"
|
||||
import { useTranslations } from "next-intl"
|
||||
|
||||
import { LocaleSwitcher } from "@/shared/components/locale-switcher"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/shared/components/ui/card"
|
||||
import { Label } from "@/shared/components/ui/label"
|
||||
import {
|
||||
@@ -15,8 +17,15 @@ import {
|
||||
|
||||
type ThemeChoice = "system" | "light" | "dark"
|
||||
|
||||
export function ThemePreferencesCard() {
|
||||
/**
|
||||
* 外观偏好卡片
|
||||
*
|
||||
* 包含主题切换(system/light/dark)和语言切换。
|
||||
* 语言切换复用 shared/components/locale-switcher 组件。
|
||||
*/
|
||||
export function ThemePreferencesCard(): React.ReactElement {
|
||||
const t = useTranslations("settings.appearance.theme")
|
||||
const tLang = useTranslations("settings.appearance.language")
|
||||
const { theme, setTheme } = useTheme()
|
||||
|
||||
const value: ThemeChoice = theme === "light" || theme === "dark" || theme === "system" ? theme : "system"
|
||||
@@ -27,7 +36,7 @@ export function ThemePreferencesCard() {
|
||||
<CardTitle>{t("title")}</CardTitle>
|
||||
<CardDescription>{t("description")}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="grid gap-3 sm:max-w-md">
|
||||
<CardContent className="grid gap-4 sm:max-w-md">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="theme">{t("label")}</Label>
|
||||
<Select value={value} onValueChange={(v) => setTheme(v)}>
|
||||
@@ -56,6 +65,17 @@ export function ThemePreferencesCard() {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="language" className="flex items-center gap-1.5">
|
||||
<Globe className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
{tLang("label")}
|
||||
</Label>
|
||||
<div id="language">
|
||||
<LocaleSwitcher />
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">{tLang("description")}</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user