feat(widget): add minecraft server status widget (#1801)
This commit is contained in:
@@ -22,6 +22,7 @@ import * as mediaRequestsList from "./media-requests/list";
|
||||
import * as mediaRequestsStats from "./media-requests/stats";
|
||||
import * as mediaServer from "./media-server";
|
||||
import * as mediaTranscoding from "./media-transcoding";
|
||||
import * as minecraftServerStatus from "./minecraft/server-status";
|
||||
import * as notebook from "./notebook";
|
||||
import type { WidgetOptionDefinition } from "./options";
|
||||
import * as rssFeed from "./rssFeed";
|
||||
@@ -54,6 +55,7 @@ export const widgetImports = {
|
||||
indexerManager,
|
||||
healthMonitoring,
|
||||
mediaTranscoding,
|
||||
minecraftServerStatus,
|
||||
} satisfies WidgetImportRecord;
|
||||
|
||||
export type WidgetImports = typeof widgetImports;
|
||||
|
||||
61
packages/widgets/src/minecraft/server-status/component.tsx
Normal file
61
packages/widgets/src/minecraft/server-status/component.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
"use client";
|
||||
|
||||
import { Box, Flex, Group, Text, Tooltip } from "@mantine/core";
|
||||
import { IconUsersGroup } from "@tabler/icons-react";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { useScopedI18n } from "@homarr/translation/client";
|
||||
|
||||
import type { WidgetComponentProps } from "../../definition";
|
||||
|
||||
export default function MinecraftServerStatusWidget({ options }: WidgetComponentProps<"minecraftServerStatus">) {
|
||||
const [{ data }] = clientApi.widget.minecraft.getServerStatus.useSuspenseQuery(options);
|
||||
const utils = clientApi.useUtils();
|
||||
clientApi.widget.minecraft.subscribeServerStatus.useSubscription(options, {
|
||||
onData(data) {
|
||||
utils.widget.minecraft.getServerStatus.setData(options, {
|
||||
data,
|
||||
timestamp: new Date(),
|
||||
});
|
||||
},
|
||||
});
|
||||
const tStatus = useScopedI18n("widget.minecraftServerStatus.status");
|
||||
|
||||
const title = options.title.trim().length > 0 ? options.title : options.domain;
|
||||
|
||||
return (
|
||||
<Flex
|
||||
className="minecraftServerStatus-wrapper"
|
||||
h="100%"
|
||||
w="100%"
|
||||
direction="column"
|
||||
p="7.5cqmin"
|
||||
justify="center"
|
||||
align="center"
|
||||
>
|
||||
<Group gap="5cqmin" wrap="nowrap" align="center">
|
||||
<Tooltip label={data.online ? tStatus("online") : tStatus("offline")}>
|
||||
<Box w="8cqmin" h="8cqmin" bg={data.online ? "teal" : "red"} style={{ borderRadius: "100%" }}></Box>
|
||||
</Tooltip>
|
||||
<Text size="10cqmin" fw="bold">
|
||||
{title}
|
||||
</Text>
|
||||
</Group>
|
||||
{data.online && (
|
||||
<>
|
||||
<img
|
||||
style={{ flex: 1, transform: "scale(0.8)", objectFit: "contain" }}
|
||||
alt={`minecraft icon ${options.domain}`}
|
||||
src={data.icon}
|
||||
/>
|
||||
<Group gap="2cqmin" c="gray.6" align="center">
|
||||
<IconUsersGroup style={{ width: "10cqmin", height: "10cqmin" }} />
|
||||
<Text size="10cqmin">
|
||||
{data.players.online}/{data.players.max}
|
||||
</Text>
|
||||
</Group>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
15
packages/widgets/src/minecraft/server-status/index.ts
Normal file
15
packages/widgets/src/minecraft/server-status/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { IconBrandMinecraft } from "@tabler/icons-react";
|
||||
|
||||
import { z } from "@homarr/validation";
|
||||
|
||||
import { createWidgetDefinition } from "../../definition";
|
||||
import { optionsBuilder } from "../../options";
|
||||
|
||||
export const { componentLoader, definition } = createWidgetDefinition("minecraftServerStatus", {
|
||||
icon: IconBrandMinecraft,
|
||||
options: optionsBuilder.from((factory) => ({
|
||||
title: factory.text({ defaultValue: "" }),
|
||||
domain: factory.text({ defaultValue: "hypixel.net", validate: z.string().nonempty() }),
|
||||
isBedrockServer: factory.switch({ defaultValue: false }),
|
||||
})),
|
||||
}).withDynamicImport(() => import("./component"));
|
||||
Reference in New Issue
Block a user