mirror of
https://github.com/fankes/beszel.git
synced 2025-10-19 01:39:34 +08:00
add time format (12h, 24h) settings (#424)
- Some biome formatting :/ - Changed chartTime update to use listenkeys
This commit is contained in:
@@ -1,26 +1,16 @@
|
|||||||
import { pb } from "@/lib/api"
|
import { t } from "@lingui/core/macro"
|
||||||
import { cn, formatDuration, formatShortDate } from "@/lib/utils"
|
import { Trans } from "@lingui/react/macro"
|
||||||
import { alertInfo } from "@/lib/alerts"
|
|
||||||
import { AlertsHistoryRecord } from "@/types"
|
|
||||||
import {
|
import {
|
||||||
|
type ColumnFiltersState,
|
||||||
|
flexRender,
|
||||||
getCoreRowModel,
|
getCoreRowModel,
|
||||||
|
getFilteredRowModel,
|
||||||
getPaginationRowModel,
|
getPaginationRowModel,
|
||||||
getSortedRowModel,
|
getSortedRowModel,
|
||||||
getFilteredRowModel,
|
type SortingState,
|
||||||
useReactTable,
|
useReactTable,
|
||||||
flexRender,
|
type VisibilityState,
|
||||||
ColumnFiltersState,
|
|
||||||
SortingState,
|
|
||||||
VisibilityState,
|
|
||||||
} from "@tanstack/react-table"
|
} from "@tanstack/react-table"
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
|
||||||
import { Button, buttonVariants } from "@/components/ui/button"
|
|
||||||
import { Input } from "@/components/ui/input"
|
|
||||||
import { alertsHistoryColumns } from "../../alerts-history-columns"
|
|
||||||
import { Checkbox } from "@/components/ui/checkbox"
|
|
||||||
import { memo, useEffect, useState } from "react"
|
|
||||||
import { Label } from "@/components/ui/label"
|
|
||||||
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "@/components/ui/select"
|
|
||||||
import {
|
import {
|
||||||
ChevronLeftIcon,
|
ChevronLeftIcon,
|
||||||
ChevronRightIcon,
|
ChevronRightIcon,
|
||||||
@@ -29,9 +19,7 @@ import {
|
|||||||
DownloadIcon,
|
DownloadIcon,
|
||||||
Trash2Icon,
|
Trash2Icon,
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
import { Trans } from "@lingui/react/macro"
|
import { memo, useEffect, useState } from "react"
|
||||||
import { t } from "@lingui/core/macro"
|
|
||||||
import { useToast } from "@/components/ui/use-toast"
|
|
||||||
import {
|
import {
|
||||||
AlertDialog,
|
AlertDialog,
|
||||||
AlertDialogAction,
|
AlertDialogAction,
|
||||||
@@ -43,6 +31,18 @@ import {
|
|||||||
AlertDialogTitle,
|
AlertDialogTitle,
|
||||||
AlertDialogTrigger,
|
AlertDialogTrigger,
|
||||||
} from "@/components/ui/alert-dialog"
|
} from "@/components/ui/alert-dialog"
|
||||||
|
import { Button, buttonVariants } from "@/components/ui/button"
|
||||||
|
import { Checkbox } from "@/components/ui/checkbox"
|
||||||
|
import { Input } from "@/components/ui/input"
|
||||||
|
import { Label } from "@/components/ui/label"
|
||||||
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||||
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||||
|
import { useToast } from "@/components/ui/use-toast"
|
||||||
|
import { alertInfo } from "@/lib/alerts"
|
||||||
|
import { pb } from "@/lib/api"
|
||||||
|
import { cn, formatDuration, formatShortDate } from "@/lib/utils"
|
||||||
|
import type { AlertsHistoryRecord } from "@/types"
|
||||||
|
import { alertsHistoryColumns } from "../../alerts-history-columns"
|
||||||
|
|
||||||
const SectionIntro = memo(() => {
|
const SectionIntro = memo(() => {
|
||||||
return (
|
return (
|
||||||
|
@@ -1,15 +1,15 @@
|
|||||||
import { t } from "@lingui/core/macro"
|
import { t } from "@lingui/core/macro"
|
||||||
import { Trans } from "@lingui/react/macro"
|
import { Trans } from "@lingui/react/macro"
|
||||||
import { Separator } from "@/components/ui/separator"
|
|
||||||
import { Button } from "@/components/ui/button"
|
|
||||||
import { redirectPage } from "@nanostores/router"
|
import { redirectPage } from "@nanostores/router"
|
||||||
import { $router } from "@/components/router"
|
import clsx from "clsx"
|
||||||
import { AlertCircleIcon, FileSlidersIcon, LoaderCircleIcon } from "lucide-react"
|
import { AlertCircleIcon, FileSlidersIcon, LoaderCircleIcon } from "lucide-react"
|
||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
|
import { $router } from "@/components/router"
|
||||||
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { Separator } from "@/components/ui/separator"
|
||||||
import { Textarea } from "@/components/ui/textarea"
|
import { Textarea } from "@/components/ui/textarea"
|
||||||
import { toast } from "@/components/ui/use-toast"
|
import { toast } from "@/components/ui/use-toast"
|
||||||
import clsx from "clsx"
|
|
||||||
import { isAdmin, pb } from "@/lib/api"
|
import { isAdmin, pb } from "@/lib/api"
|
||||||
|
|
||||||
export default function ConfigYaml() {
|
export default function ConfigYaml() {
|
||||||
|
@@ -1,18 +1,18 @@
|
|||||||
import { Trans } from "@lingui/react/macro"
|
/** biome-ignore-all lint/correctness/useUniqueElementIds: component is only rendered once */
|
||||||
|
import { Trans, useLingui } from "@lingui/react/macro"
|
||||||
|
import { LanguagesIcon, LoaderCircleIcon, SaveIcon } from "lucide-react"
|
||||||
|
import { useState } from "react"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { Input } from "@/components/ui/input"
|
||||||
import { Label } from "@/components/ui/label"
|
import { Label } from "@/components/ui/label"
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||||
import { chartTimeData } from "@/lib/utils"
|
|
||||||
import { Separator } from "@/components/ui/separator"
|
import { Separator } from "@/components/ui/separator"
|
||||||
import { LanguagesIcon, LoaderCircleIcon, SaveIcon } from "lucide-react"
|
import { HourFormat, Unit } from "@/lib/enums"
|
||||||
import { UserSettings } from "@/types"
|
|
||||||
import { saveSettings } from "./layout"
|
|
||||||
import { useState } from "react"
|
|
||||||
import languages from "@/lib/languages"
|
|
||||||
import { dynamicActivate } from "@/lib/i18n"
|
import { dynamicActivate } from "@/lib/i18n"
|
||||||
import { useLingui } from "@lingui/react/macro"
|
import languages from "@/lib/languages"
|
||||||
import { Input } from "@/components/ui/input"
|
import { chartTimeData, currentHour12 } from "@/lib/utils"
|
||||||
import { Unit } from "@/lib/enums"
|
import type { UserSettings } from "@/types"
|
||||||
|
import { saveSettings } from "./layout"
|
||||||
|
|
||||||
export default function SettingsProfilePage({ userSettings }: { userSettings: UserSettings }) {
|
export default function SettingsProfilePage({ userSettings }: { userSettings: UserSettings }) {
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
@@ -82,6 +82,8 @@ export default function SettingsProfilePage({ userSettings }: { userSettings: Us
|
|||||||
<Trans>Adjust display options for charts.</Trans>
|
<Trans>Adjust display options for charts.</Trans>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="grid sm:grid-cols-3 gap-4">
|
||||||
|
<div className="grid gap-2">
|
||||||
<Label className="block" htmlFor="chartTime">
|
<Label className="block" htmlFor="chartTime">
|
||||||
<Trans>Default time period</Trans>
|
<Trans>Default time period</Trans>
|
||||||
</Label>
|
</Label>
|
||||||
@@ -97,9 +99,29 @@ export default function SettingsProfilePage({ userSettings }: { userSettings: Us
|
|||||||
))}
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<p className="text-[0.8rem] text-muted-foreground">
|
</div>
|
||||||
<Trans>Sets the default time range for charts when a system is viewed.</Trans>
|
<div className="grid gap-2">
|
||||||
</p>
|
<Label className="block" htmlFor="hourFormat">
|
||||||
|
<Trans>Time format</Trans>
|
||||||
|
</Label>
|
||||||
|
<Select
|
||||||
|
name="hourFormat"
|
||||||
|
key={userSettings.hourFormat}
|
||||||
|
defaultValue={userSettings.hourFormat ?? (currentHour12() ? HourFormat["12h"] : HourFormat["24h"])}
|
||||||
|
>
|
||||||
|
<SelectTrigger id="hourFormat">
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{Object.keys(HourFormat).map((value) => (
|
||||||
|
<SelectItem key={value} value={value}>
|
||||||
|
{value}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Separator />
|
<Separator />
|
||||||
<div className="grid gap-2">
|
<div className="grid gap-2">
|
||||||
|
@@ -1,18 +1,17 @@
|
|||||||
import { t } from "@lingui/core/macro"
|
import { t } from "@lingui/core/macro"
|
||||||
import { Trans } from "@lingui/react/macro"
|
import { Trans, useLingui } from "@lingui/react/macro"
|
||||||
|
import { useStore } from "@nanostores/react"
|
||||||
|
import { getPagePath, redirectPage } from "@nanostores/router"
|
||||||
|
import { AlertOctagonIcon, BellIcon, FileSlidersIcon, FingerprintIcon, SettingsIcon } from "lucide-react"
|
||||||
import { lazy, useEffect } from "react"
|
import { lazy, useEffect } from "react"
|
||||||
|
import { $router } from "@/components/router.tsx"
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card.tsx"
|
||||||
|
import { toast } from "@/components/ui/use-toast.ts"
|
||||||
|
import { pb } from "@/lib/api"
|
||||||
|
import { $userSettings } from "@/lib/stores.ts"
|
||||||
|
import type { UserSettings } from "@/types"
|
||||||
import { Separator } from "../../ui/separator"
|
import { Separator } from "../../ui/separator"
|
||||||
import { SidebarNav } from "./sidebar-nav.tsx"
|
import { SidebarNav } from "./sidebar-nav.tsx"
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card.tsx"
|
|
||||||
import { useStore } from "@nanostores/react"
|
|
||||||
import { $router } from "@/components/router.tsx"
|
|
||||||
import { getPagePath, redirectPage } from "@nanostores/router"
|
|
||||||
import { BellIcon, FileSlidersIcon, FingerprintIcon, SettingsIcon, AlertOctagonIcon } from "lucide-react"
|
|
||||||
import { $userSettings } from "@/lib/stores.ts"
|
|
||||||
import { toast } from "@/components/ui/use-toast.ts"
|
|
||||||
import { UserSettings } from "@/types"
|
|
||||||
import { useLingui } from "@lingui/react/macro"
|
|
||||||
import { pb } from "@/lib/api"
|
|
||||||
|
|
||||||
const generalSettingsImport = () => import("./general.tsx")
|
const generalSettingsImport = () => import("./general.tsx")
|
||||||
const notificationsSettingsImport = () => import("./notifications.tsx")
|
const notificationsSettingsImport = () => import("./notifications.tsx")
|
||||||
@@ -93,9 +92,10 @@ export default function SettingsLayout() {
|
|||||||
|
|
||||||
const page = useStore($router)
|
const page = useStore($router)
|
||||||
|
|
||||||
|
// biome-ignore lint/correctness/useExhaustiveDependencies: no dependencies
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = t`Settings` + " / Beszel"
|
document.title = `${t`Settings`} / Beszel`
|
||||||
// @ts-ignore redirect to account page if no page is specified
|
// @ts-expect-error redirect to account page if no page is specified
|
||||||
if (!page?.params?.name) {
|
if (!page?.params?.name) {
|
||||||
redirectPage($router, "settings", { name: "general" })
|
redirectPage($router, "settings", { name: "general" })
|
||||||
}
|
}
|
||||||
|
@@ -1,19 +1,19 @@
|
|||||||
import { t } from "@lingui/core/macro"
|
import { t } from "@lingui/core/macro"
|
||||||
import { Trans } from "@lingui/react/macro"
|
import { Trans } from "@lingui/react/macro"
|
||||||
import { Button } from "@/components/ui/button"
|
|
||||||
import { Input } from "@/components/ui/input"
|
|
||||||
import { Label } from "@/components/ui/label"
|
|
||||||
import { Separator } from "@/components/ui/separator"
|
|
||||||
import { Card } from "@/components/ui/card"
|
|
||||||
import { BellIcon, LoaderCircleIcon, PlusIcon, SaveIcon, Trash2Icon } from "lucide-react"
|
import { BellIcon, LoaderCircleIcon, PlusIcon, SaveIcon, Trash2Icon } from "lucide-react"
|
||||||
import { ChangeEventHandler, useEffect, useState } from "react"
|
import { type ChangeEventHandler, useEffect, useState } from "react"
|
||||||
import { toast } from "@/components/ui/use-toast"
|
|
||||||
import { InputTags } from "@/components/ui/input-tags"
|
|
||||||
import { UserSettings } from "@/types"
|
|
||||||
import { saveSettings } from "./layout"
|
|
||||||
import * as v from "valibot"
|
import * as v from "valibot"
|
||||||
import { prependBasePath } from "@/components/router"
|
import { prependBasePath } from "@/components/router"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { Card } from "@/components/ui/card"
|
||||||
|
import { Input } from "@/components/ui/input"
|
||||||
|
import { InputTags } from "@/components/ui/input-tags"
|
||||||
|
import { Label } from "@/components/ui/label"
|
||||||
|
import { Separator } from "@/components/ui/separator"
|
||||||
|
import { toast } from "@/components/ui/use-toast"
|
||||||
import { isAdmin, pb } from "@/lib/api"
|
import { isAdmin, pb } from "@/lib/api"
|
||||||
|
import type { UserSettings } from "@/types"
|
||||||
|
import { saveSettings } from "./layout"
|
||||||
|
|
||||||
interface ShoutrrrUrlCardProps {
|
interface ShoutrrrUrlCardProps {
|
||||||
url: string
|
url: string
|
||||||
@@ -127,7 +127,7 @@ const SettingsNotificationsPage = ({ userSettings }: { userSettings: UserSetting
|
|||||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||||
<Trans>
|
<Trans>
|
||||||
Beszel uses{" "}
|
Beszel uses{" "}
|
||||||
<a href="https://beszel.dev/guide/notifications" target="_blank" className="link">
|
<a href="https://beszel.dev/guide/notifications" target="_blank" className="link" rel="noopener">
|
||||||
Shoutrrr
|
Shoutrrr
|
||||||
</a>{" "}
|
</a>{" "}
|
||||||
to integrate with popular notification services.
|
to integrate with popular notification services.
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
import React from "react"
|
|
||||||
import { cn } from "@/lib/utils"
|
|
||||||
import { isAdmin, isReadOnlyUser } from "@/lib/api"
|
|
||||||
import { buttonVariants } from "../../ui/button"
|
|
||||||
import { $router, Link, navigate } from "../../router"
|
|
||||||
import { useStore } from "@nanostores/react"
|
import { useStore } from "@nanostores/react"
|
||||||
|
import type React from "react"
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||||
import { Separator } from "@/components/ui/separator"
|
import { Separator } from "@/components/ui/separator"
|
||||||
|
import { isAdmin, isReadOnlyUser } from "@/lib/api"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
import { $router, Link, navigate } from "../../router"
|
||||||
|
import { buttonVariants } from "../../ui/button"
|
||||||
|
|
||||||
interface SidebarNavProps extends React.HTMLAttributes<HTMLElement> {
|
interface SidebarNavProps extends React.HTMLAttributes<HTMLElement> {
|
||||||
items: {
|
items: {
|
||||||
|
@@ -1,9 +1,6 @@
|
|||||||
import { Trans, useLingui } from "@lingui/react/macro"
|
|
||||||
import { t } from "@lingui/core/macro"
|
import { t } from "@lingui/core/macro"
|
||||||
import { $publicKey } from "@/lib/stores"
|
import { Trans, useLingui } from "@lingui/react/macro"
|
||||||
import { memo, useEffect, useMemo, useState } from "react"
|
import { redirectPage } from "@nanostores/router"
|
||||||
import { Table, TableCell, TableHead, TableBody, TableRow, TableHeader } from "@/components/ui/table"
|
|
||||||
import { FingerprintRecord } from "@/types"
|
|
||||||
import {
|
import {
|
||||||
CopyIcon,
|
CopyIcon,
|
||||||
FingerprintIcon,
|
FingerprintIcon,
|
||||||
@@ -13,9 +10,17 @@ import {
|
|||||||
ServerIcon,
|
ServerIcon,
|
||||||
Trash2Icon,
|
Trash2Icon,
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
import { toast } from "@/components/ui/use-toast"
|
import { memo, useEffect, useMemo, useState } from "react"
|
||||||
import { cn, copyToClipboard, generateToken, getHubURL, tokenMap } from "@/lib/utils"
|
import {
|
||||||
import { isReadOnlyUser, pb } from "@/lib/api"
|
copyDockerCompose,
|
||||||
|
copyDockerRun,
|
||||||
|
copyLinuxCommand,
|
||||||
|
copyWindowsCommand,
|
||||||
|
type DropdownItem,
|
||||||
|
InstallDropdown,
|
||||||
|
} from "@/components/install-dropdowns"
|
||||||
|
import { $router } from "@/components/router"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
@@ -23,20 +28,15 @@ import {
|
|||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu"
|
} from "@/components/ui/dropdown-menu"
|
||||||
import { Button } from "@/components/ui/button"
|
import { AppleIcon, DockerIcon, TuxIcon, WindowsIcon } from "@/components/ui/icons"
|
||||||
import { Separator } from "@/components/ui/separator"
|
import { Separator } from "@/components/ui/separator"
|
||||||
import { Switch } from "@/components/ui/switch"
|
import { Switch } from "@/components/ui/switch"
|
||||||
import {
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||||
copyDockerCompose,
|
import { toast } from "@/components/ui/use-toast"
|
||||||
copyDockerRun,
|
import { isReadOnlyUser, pb } from "@/lib/api"
|
||||||
copyLinuxCommand,
|
import { $publicKey } from "@/lib/stores"
|
||||||
copyWindowsCommand,
|
import { cn, copyToClipboard, generateToken, getHubURL, tokenMap } from "@/lib/utils"
|
||||||
DropdownItem,
|
import type { FingerprintRecord } from "@/types"
|
||||||
InstallDropdown,
|
|
||||||
} from "@/components/install-dropdowns"
|
|
||||||
import { AppleIcon, DockerIcon, TuxIcon, WindowsIcon } from "@/components/ui/icons"
|
|
||||||
import { redirectPage } from "@nanostores/router"
|
|
||||||
import { $router } from "@/components/router"
|
|
||||||
|
|
||||||
const pbFingerprintOptions = {
|
const pbFingerprintOptions = {
|
||||||
expand: "system",
|
expand: "system",
|
||||||
|
@@ -46,3 +46,10 @@ export enum BatteryState {
|
|||||||
Discharging,
|
Discharging,
|
||||||
Idle,
|
Idle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Time format */
|
||||||
|
export enum HourFormat {
|
||||||
|
// Default = "Default",
|
||||||
|
"12h" = "12h",
|
||||||
|
"24h" = "24h",
|
||||||
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { atom, computed, map, type ReadableAtom } from "nanostores"
|
import { atom, computed, listenKeys, map, type ReadableAtom } from "nanostores"
|
||||||
import type { AlertMap, ChartTimes, SystemRecord, UserSettings } from "@/types"
|
import type { AlertMap, ChartTimes, SystemRecord, UserSettings } from "@/types"
|
||||||
import { pb } from "./api"
|
import { pb } from "./api"
|
||||||
import { Unit } from "./enums"
|
import { Unit } from "./enums"
|
||||||
@@ -50,7 +50,7 @@ export const $userSettings = map<UserSettings>({
|
|||||||
unitTemp: Unit.Celsius,
|
unitTemp: Unit.Celsius,
|
||||||
})
|
})
|
||||||
// update chart time on change
|
// update chart time on change
|
||||||
$userSettings.subscribe((value) => $chartTime.set(value.chartTime))
|
listenKeys($userSettings, ["chartTime"], ({ chartTime }) => $chartTime.set(chartTime))
|
||||||
|
|
||||||
/** Container chart filter */
|
/** Container chart filter */
|
||||||
export const $containerFilter = atom("")
|
export const $containerFilter = atom("")
|
||||||
|
0
src/site/src/lib/time.ts
Normal file
0
src/site/src/lib/time.ts
Normal file
@@ -6,8 +6,9 @@ import { twMerge } from "tailwind-merge"
|
|||||||
import { prependBasePath } from "@/components/router"
|
import { prependBasePath } from "@/components/router"
|
||||||
import { toast } from "@/components/ui/use-toast"
|
import { toast } from "@/components/ui/use-toast"
|
||||||
import type { ChartTimeData, FingerprintRecord, SemVer, SystemRecord } from "@/types"
|
import type { ChartTimeData, FingerprintRecord, SemVer, SystemRecord } from "@/types"
|
||||||
import { MeterState, Unit } from "./enums"
|
import { HourFormat, MeterState, Unit } from "./enums"
|
||||||
import { $copyContent, $userSettings } from "./stores"
|
import { $copyContent, $userSettings } from "./stores"
|
||||||
|
import { listenKeys } from "nanostores"
|
||||||
|
|
||||||
export const FAVICON_DEFAULT = "favicon.svg"
|
export const FAVICON_DEFAULT = "favicon.svg"
|
||||||
export const FAVICON_GREEN = "favicon-green.svg"
|
export const FAVICON_GREEN = "favicon-green.svg"
|
||||||
@@ -36,24 +37,47 @@ export async function copyToClipboard(content: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const hourWithMinutesFormatter = new Intl.DateTimeFormat(undefined, {
|
// Create formatters directly without intermediate containers
|
||||||
|
const createHourWithMinutesFormatter = (hour12?: boolean) =>
|
||||||
|
new Intl.DateTimeFormat(undefined, {
|
||||||
hour: "numeric",
|
hour: "numeric",
|
||||||
minute: "numeric",
|
minute: "numeric",
|
||||||
|
hour12,
|
||||||
})
|
})
|
||||||
export const hourWithMinutes = (timestamp: string) => {
|
|
||||||
return hourWithMinutesFormatter.format(new Date(timestamp))
|
|
||||||
}
|
|
||||||
|
|
||||||
const shortDateFormatter = new Intl.DateTimeFormat(undefined, {
|
const createShortDateFormatter = (hour12?: boolean) =>
|
||||||
|
new Intl.DateTimeFormat(undefined, {
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
month: "short",
|
month: "short",
|
||||||
hour: "numeric",
|
hour: "numeric",
|
||||||
minute: "numeric",
|
minute: "numeric",
|
||||||
|
hour12,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Initialize formatters with default values
|
||||||
|
let hourWithMinutesFormatter = createHourWithMinutesFormatter()
|
||||||
|
let shortDateFormatter = createShortDateFormatter()
|
||||||
|
|
||||||
|
export const currentHour12 = () => shortDateFormatter.resolvedOptions().hour12
|
||||||
|
|
||||||
|
export const hourWithMinutes = (timestamp: string) => {
|
||||||
|
return hourWithMinutesFormatter.format(new Date(timestamp))
|
||||||
|
}
|
||||||
|
|
||||||
export const formatShortDate = (timestamp: string) => {
|
export const formatShortDate = (timestamp: string) => {
|
||||||
return shortDateFormatter.format(new Date(timestamp))
|
return shortDateFormatter.format(new Date(timestamp))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the time formatters if user changes hourFormat
|
||||||
|
listenKeys($userSettings, ["hourFormat"], ({ hourFormat }) => {
|
||||||
|
if (!hourFormat) return
|
||||||
|
const newHour12 = hourFormat === HourFormat["12h"]
|
||||||
|
if (currentHour12() !== newHour12) {
|
||||||
|
hourWithMinutesFormatter = createHourWithMinutesFormatter(newHour12)
|
||||||
|
shortDateFormatter = createShortDateFormatter(newHour12)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const dayFormatter = new Intl.DateTimeFormat(undefined, {
|
const dayFormatter = new Intl.DateTimeFormat(undefined, {
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
month: "short",
|
month: "short",
|
||||||
|
29
src/site/src/types.d.ts
vendored
29
src/site/src/types.d.ts
vendored
@@ -1,5 +1,5 @@
|
|||||||
import { RecordModel } from "pocketbase"
|
import type { RecordModel } from "pocketbase"
|
||||||
import { Unit, Os, BatteryState } from "./lib/enums"
|
import type { Unit, Os, BatteryState, HourFormat } from "./lib/enums"
|
||||||
|
|
||||||
// global window properties
|
// global window properties
|
||||||
declare global {
|
declare global {
|
||||||
@@ -238,6 +238,7 @@ export interface UserSettings {
|
|||||||
unitDisk?: Unit
|
unitDisk?: Unit
|
||||||
colorWarn?: number
|
colorWarn?: number
|
||||||
colorCrit?: number
|
colorCrit?: number
|
||||||
|
hourFormat?: HourFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChartDataContainer = {
|
type ChartDataContainer = {
|
||||||
@@ -262,17 +263,17 @@ export interface ChartData {
|
|||||||
chartTime: ChartTimes
|
chartTime: ChartTimes
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AlertInfo {
|
// interface AlertInfo {
|
||||||
name: () => string
|
// name: () => string
|
||||||
unit: string
|
// unit: string
|
||||||
icon: any
|
// icon: any
|
||||||
desc: () => string
|
// desc: () => string
|
||||||
max?: number
|
// max?: number
|
||||||
min?: number
|
// min?: number
|
||||||
step?: number
|
// step?: number
|
||||||
start?: number
|
// start?: number
|
||||||
/** Single value description (when there's only one value, like status) */
|
// /** Single value description (when there's only one value, like status) */
|
||||||
singleDesc?: () => string
|
// singleDesc?: () => string
|
||||||
}
|
// }
|
||||||
|
|
||||||
export type AlertMap = Record<string, Map<string, AlertRecord>>
|
export type AlertMap = Record<string, Map<string, AlertRecord>>
|
||||||
|
Reference in New Issue
Block a user