mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
style: one spacing, title and skeleton language across the app
Icons inside buttons drop their manual margins in favour of the button's built-in gap (two hundred call sites), form field stacks settle on one spacing step, card titles on exactly two sizes, inline field errors on one text size, and a dozen hand-rolled loading pulses move onto the shared skeleton primitive while keeping their silhouettes. The intake dialog wording joins the rest of the app on 'übersprungen', and the UI guidelines now document the two deliberate footer and touch-target systems.
This commit is contained in:
1 parent
4ca3de5ff3
commit
04765ea8ac
92 files changed
+1433
-1445
No files matched your search
@@ -91,9 +91,9 @@ function RestoreRowDialog({
|
||||
className="min-h-11"
|
||||
>
|
||||
{pending ? (
|
||||
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
) : (
|
||||
<History className="mr-1 h-3.5 w-3.5" />
|
||||
<History className="h-3.5 w-3.5" />
|
||||
)}
|
||||
{t("admin.section.backups.restore")}
|
||||
</Button>
|
||||
@@ -366,9 +366,9 @@ export function BackupsSection() {
|
||||
className="min-h-11"
|
||||
>
|
||||
{runBackup.isPending ? (
|
||||
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
) : (
|
||||
<PlayCircle className="mr-1 h-3.5 w-3.5" />
|
||||
<PlayCircle className="h-3.5 w-3.5" />
|
||||
)}
|
||||
{t("admin.section.backups.runNow")}
|
||||
</Button>
|
||||
@@ -422,9 +422,9 @@ export function BackupsSection() {
|
||||
className="min-h-11"
|
||||
>
|
||||
{upload.isPending ? (
|
||||
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
) : (
|
||||
<Upload className="mr-1 h-3.5 w-3.5" />
|
||||
<Upload className="h-3.5 w-3.5" />
|
||||
)}
|
||||
{t("admin.section.backups.uploadButton")}
|
||||
</Button>
|
||||
@@ -463,9 +463,9 @@ export function BackupsSection() {
|
||||
className="min-h-11"
|
||||
>
|
||||
{runBackup.isPending ? (
|
||||
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
) : (
|
||||
<PlayCircle className="mr-1 h-3.5 w-3.5" />
|
||||
<PlayCircle className="h-3.5 w-3.5" />
|
||||
)}
|
||||
{t("admin.section.backups.runNow")}
|
||||
</Button>
|
||||
@@ -522,9 +522,9 @@ export function BackupsSection() {
|
||||
className="min-h-11"
|
||||
>
|
||||
{downloadingId === row.id ? (
|
||||
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
) : (
|
||||
<Download className="mr-1 h-3.5 w-3.5" />
|
||||
<Download className="h-3.5 w-3.5" />
|
||||
)}
|
||||
{t("admin.section.backups.download")}
|
||||
</Button>
|
||||
|
||||
@@ -119,7 +119,7 @@ export function BugReportSection() {
|
||||
disabled={updateSettings.isPending}
|
||||
>
|
||||
{updateSettings.isPending && (
|
||||
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
)}
|
||||
{t("common.save")}
|
||||
</Button>
|
||||
|
||||
@@ -85,9 +85,9 @@ export function DangerZoneSection() {
|
||||
disabled={wipeAllData.isPending}
|
||||
>
|
||||
{wipeAllData.isPending ? (
|
||||
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
) : (
|
||||
<Trash2 className="mr-1 h-3.5 w-3.5" />
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
)}
|
||||
{t("admin.deleteButton")}
|
||||
</Button>
|
||||
|
||||
@@ -366,7 +366,7 @@ function FeedbackDetailDialog({
|
||||
disabled={update.isPending || item.status === "ACKNOWLEDGED"}
|
||||
onClick={() => update.mutate({ status: "ACKNOWLEDGED" })}
|
||||
>
|
||||
<CheckCircle2 className="mr-1.5 h-3.5 w-3.5" />
|
||||
<CheckCircle2 className="h-3.5 w-3.5" />
|
||||
{t("admin.feedback.actionAcknowledge")}
|
||||
</Button>
|
||||
<Button
|
||||
@@ -374,7 +374,7 @@ function FeedbackDetailDialog({
|
||||
disabled={update.isPending || item.status === "RESOLVED"}
|
||||
onClick={() => update.mutate({ status: "RESOLVED" })}
|
||||
>
|
||||
<CheckCircle2 className="mr-1.5 h-3.5 w-3.5" />
|
||||
<CheckCircle2 className="h-3.5 w-3.5" />
|
||||
{t("admin.feedback.actionResolve")}
|
||||
</Button>
|
||||
<AlertDialog>
|
||||
@@ -384,7 +384,7 @@ function FeedbackDetailDialog({
|
||||
variant="destructive"
|
||||
disabled={archive.isPending || item.status === "ARCHIVED"}
|
||||
>
|
||||
<Trash2 className="mr-1.5 h-3.5 w-3.5" />
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
{t("admin.feedback.actionArchive")}
|
||||
</Button>
|
||||
</AlertDialogTrigger>
|
||||
@@ -419,9 +419,9 @@ function FeedbackDetailDialog({
|
||||
className="ml-auto"
|
||||
>
|
||||
{publish.isPending ? (
|
||||
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
) : (
|
||||
<GitPullRequest className="mr-1.5 h-3.5 w-3.5" />
|
||||
<GitPullRequest className="h-3.5 w-3.5" />
|
||||
)}
|
||||
{t("admin.feedback.actionPublishGithub")}
|
||||
</Button>
|
||||
@@ -517,7 +517,7 @@ function FeedbackDetailDialog({
|
||||
onClick={() => update.mutate({ adminNote: note || null })}
|
||||
>
|
||||
{update.isPending && (
|
||||
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
)}
|
||||
{t("admin.feedback.saveNote")}
|
||||
</Button>
|
||||
|
||||
@@ -148,7 +148,7 @@ export function GlitchtipSection() {
|
||||
disabled={testGlitchtip.isPending || updateSettings.isPending}
|
||||
>
|
||||
{testGlitchtip.isPending && (
|
||||
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
)}
|
||||
{t("common.test")}
|
||||
</Button>
|
||||
@@ -158,7 +158,7 @@ export function GlitchtipSection() {
|
||||
disabled={updateSettings.isPending}
|
||||
>
|
||||
{updateSettings.isPending && (
|
||||
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
)}
|
||||
{t("common.save")}
|
||||
</Button>
|
||||
|
||||
@@ -38,6 +38,7 @@ import {
|
||||
import { useMemo } from "react";
|
||||
import { useFormatters, useTranslations } from "@/lib/i18n/context";
|
||||
import { queryKeys } from "@/lib/query-keys";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
|
||||
interface HostMetricsApiSample {
|
||||
capturedAt: string;
|
||||
@@ -168,7 +169,7 @@ export function HostMetricsChart() {
|
||||
{t("admin.hostMetrics.last2hours")}
|
||||
</span>
|
||||
</div>
|
||||
<div className="bg-muted/40 h-[180px] w-full animate-pulse rounded-md motion-reduce:animate-none" />
|
||||
<Skeleton className="bg-muted/40 h-[180px] w-full" />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -331,7 +331,7 @@ export function LoginOverviewSection() {
|
||||
onClick={downloadCsv}
|
||||
disabled={entries.length === 0}
|
||||
>
|
||||
<Download className="mr-1 h-3.5 w-3.5" />
|
||||
<Download className="h-3.5 w-3.5" />
|
||||
{t("admin.section.auditLog.export")}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -181,9 +181,9 @@ export function RemindersSection() {
|
||||
disabled={testNotification.isPending}
|
||||
>
|
||||
{testNotification.isPending && (
|
||||
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
)}
|
||||
<Bell className="mr-1.5 h-3.5 w-3.5" />
|
||||
<Bell className="h-3.5 w-3.5" />
|
||||
{t("admin.notificationTestSend")}
|
||||
</Button>
|
||||
<Button
|
||||
@@ -193,9 +193,9 @@ export function RemindersSection() {
|
||||
disabled={reminderCheck.isPending}
|
||||
>
|
||||
{reminderCheck.isPending && (
|
||||
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
)}
|
||||
<Activity className="mr-1.5 h-3.5 w-3.5" />
|
||||
<Activity className="h-3.5 w-3.5" />
|
||||
{t("admin.reminderCheckRun")}
|
||||
</Button>
|
||||
<Button
|
||||
@@ -224,7 +224,7 @@ export function RemindersSection() {
|
||||
}
|
||||
>
|
||||
{updateSettings.isPending && (
|
||||
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
)}
|
||||
{t("common.save")}
|
||||
</Button>
|
||||
@@ -236,9 +236,9 @@ export function RemindersSection() {
|
||||
{testNotification.data.results.map((r, i) => (
|
||||
<div key={i} className="flex items-center gap-1.5 text-xs">
|
||||
{r.success ? (
|
||||
<CheckCircle2 className="text-success dark:text-green-400 h-3.5 w-3.5 shrink-0" />
|
||||
<CheckCircle2 className="text-success h-3.5 w-3.5 shrink-0 dark:text-green-400" />
|
||||
) : (
|
||||
<XCircle className="text-destructive dark:text-red-400 h-3.5 w-3.5 shrink-0" />
|
||||
<XCircle className="text-destructive h-3.5 w-3.5 shrink-0 dark:text-red-400" />
|
||||
)}
|
||||
<span className="font-medium">{r.channel}</span>
|
||||
{r.error && (
|
||||
@@ -299,7 +299,7 @@ export function RemindersSection() {
|
||||
</span>
|
||||
<span className={statusColor}>{sched.label}</span>
|
||||
{sched.notificationSent && (
|
||||
<span className="text-success dark:text-green-400 flex shrink-0 items-center gap-0.5">
|
||||
<span className="text-success flex shrink-0 items-center gap-0.5 dark:text-green-400">
|
||||
<Bell className="h-3 w-3" />
|
||||
{t("admin.reminderCheckNotifSent")}
|
||||
</span>
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
Users,
|
||||
} from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { formatDateTime } from "@/lib/format";
|
||||
import { useFormatters, useTranslations } from "@/lib/i18n/context";
|
||||
import { StatusItem, usePublicVersion, useSystemStatus } from "./_shared";
|
||||
@@ -36,7 +37,7 @@ const HostMetricsChart = dynamic(
|
||||
{
|
||||
ssr: false,
|
||||
loading: () => (
|
||||
<div className="bg-muted/40 h-[200px] w-full animate-pulse rounded-xl motion-reduce:animate-none" />
|
||||
<Skeleton className="bg-muted/40 h-[200px] w-full rounded-xl" />
|
||||
),
|
||||
},
|
||||
);
|
||||
@@ -207,9 +208,9 @@ export function SystemStatusSection() {
|
||||
data-testid="system-status-retry"
|
||||
>
|
||||
{isFetching ? (
|
||||
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
) : (
|
||||
<RotateCw className="mr-1 h-3.5 w-3.5" />
|
||||
<RotateCw className="h-3.5 w-3.5" />
|
||||
)}
|
||||
{t("admin.systemStatusRetry")}
|
||||
</Button>
|
||||
|
||||
@@ -149,7 +149,7 @@ export function UmamiSection() {
|
||||
disabled={testUmami.isPending || updateSettings.isPending}
|
||||
>
|
||||
{testUmami.isPending && (
|
||||
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
)}
|
||||
{t("common.test")}
|
||||
</Button>
|
||||
@@ -159,7 +159,7 @@ export function UmamiSection() {
|
||||
disabled={updateSettings.isPending}
|
||||
>
|
||||
{updateSettings.isPending && (
|
||||
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
)}
|
||||
{t("common.save")}
|
||||
</Button>
|
||||
|
||||
@@ -189,7 +189,7 @@ export function UserManagementSection() {
|
||||
: t("admin.promoteToAdmin")
|
||||
}
|
||||
>
|
||||
<Shield className="mr-1 h-3 w-3" aria-hidden="true" />
|
||||
<Shield className="h-3 w-3" aria-hidden="true" />
|
||||
{u.role === "ADMIN" ? t("admin.toUser") : t("admin.toAdmin")}
|
||||
</Button>
|
||||
<Button
|
||||
@@ -461,7 +461,7 @@ export function UserManagementSection() {
|
||||
}
|
||||
>
|
||||
{updateUser.isPending && (
|
||||
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
)}
|
||||
{t("common.save")}
|
||||
</Button>
|
||||
@@ -511,7 +511,7 @@ export function UserManagementSection() {
|
||||
}
|
||||
>
|
||||
{resetPw.isPending && (
|
||||
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
)}
|
||||
{t("admin.reset")}
|
||||
</Button>
|
||||
|
||||
@@ -135,7 +135,7 @@ export function WebPushVapidSection() {
|
||||
disabled={updateSettings.isPending}
|
||||
>
|
||||
{updateSettings.isPending && (
|
||||
<Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin motion-reduce:animate-none" />
|
||||
)}
|
||||
{t("common.save")}
|
||||
</Button>
|
||||
|
||||
Reference in new issue
Block a user