From acd09c8c02c13daac6e5b2432bb72640f075cec6 Mon Sep 17 00:00:00 2001 From: Meier Lukas Date: Sun, 17 Aug 2025 17:49:05 +0200 Subject: [PATCH] feat(app-widget): add layout option (#3875) --- packages/old-import/src/mappers/map-item.ts | 1 + packages/translation/src/lang/en.json | 9 ++++ .../src/_inputs/widget-select-input.tsx | 36 +++++++++++++++- packages/widgets/src/app/component.tsx | 16 +++++-- packages/widgets/src/app/index.ts | 43 ++++++++++++++++++- 5 files changed, 99 insertions(+), 6 deletions(-) diff --git a/packages/old-import/src/mappers/map-item.ts b/packages/old-import/src/mappers/map-item.ts index 98c69b67d..b31344925 100644 --- a/packages/old-import/src/mappers/map-item.ts +++ b/packages/old-import/src/mappers/map-item.ts @@ -39,6 +39,7 @@ export const mapApp = ( pingEnabled: app.network.enabledStatusChecker, showDescriptionTooltip: app.behaviour.tooltipDescription !== "", showTitle: app.appearance.appNameStatus === "normal", + layout: app.appearance.positionAppName, } satisfies WidgetComponentProps<"app">["options"]), layouts: boardSizes.map((size) => { const shapeForSize = app.shape[size]; diff --git a/packages/translation/src/lang/en.json b/packages/translation/src/lang/en.json index e9a364d03..e360b8446 100644 --- a/packages/translation/src/lang/en.json +++ b/packages/translation/src/lang/en.json @@ -1271,6 +1271,15 @@ }, "pingEnabled": { "label": "Enable status check" + }, + "layout": { + "label": "Layout", + "option": { + "row": "Horizontal", + "row-reverse": "Horizontal (reversed)", + "column": "Vertical", + "column-reverse": "Vertical (reversed)" + } } }, "error": { diff --git a/packages/widgets/src/_inputs/widget-select-input.tsx b/packages/widgets/src/_inputs/widget-select-input.tsx index ec07b2932..74cbd4f29 100644 --- a/packages/widgets/src/_inputs/widget-select-input.tsx +++ b/packages/widgets/src/_inputs/widget-select-input.tsx @@ -1,10 +1,12 @@ "use client"; -import { Select } from "@mantine/core"; +import { Group, Select } from "@mantine/core"; +import { IconCheck } from "@tabler/icons-react"; import { translateIfNecessary } from "@homarr/translation"; import type { stringOrTranslation } from "@homarr/translation"; import { useI18n } from "@homarr/translation/client"; +import type { TablerIcon } from "@homarr/ui"; import type { CommonWidgetInputProps } from "./common"; import { useWidgetInputTranslation } from "./common"; @@ -12,6 +14,7 @@ import { useFormContext } from "./form"; export type SelectOption = | { + icon?: TablerIcon; value: string; label: stringOrTranslation; } @@ -23,10 +26,19 @@ export type inferSelectOptionValue = TOption exten ? TValue : TOption; +const getIconFor = (options: SelectOption[], value: string) => { + const current = options.find((option) => (typeof option === "string" ? option : option.value) === value); + if (!current) return null; + if (typeof current === "string") return null; + return current.icon; +}; + export const WidgetSelectInput = ({ property, kind, options }: CommonWidgetInputProps<"select">) => { const t = useI18n(); const tWidget = useWidgetInputTranslation(kind, property); const form = useFormContext(); + const inputProps = form.getInputProps(`options.${property}`); + const CurrentIcon = getIconFor(options.options, inputProps.value as string); return (