feat(app-widget): add layout option (#3875)
This commit is contained in:
@@ -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 extends SelectOption> = 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 (
|
||||
<Select
|
||||
@@ -39,9 +51,29 @@ export const WidgetSelectInput = ({ property, kind, options }: CommonWidgetInput
|
||||
label: translateIfNecessary(t, option.label) ?? option.value,
|
||||
},
|
||||
)}
|
||||
leftSection={CurrentIcon && <CurrentIcon size={16} stroke={1.5} />}
|
||||
renderOption={({ option, checked }) => {
|
||||
const Icon = getIconFor(options.options, option.value);
|
||||
|
||||
return (
|
||||
<Group flex="1" gap="xs">
|
||||
{Icon && <Icon color="currentColor" opacity={0.6} size={18} stroke={1.5} />}
|
||||
{option.label}
|
||||
{checked && (
|
||||
<IconCheck
|
||||
style={{ marginInlineStart: "auto" }}
|
||||
color="currentColor"
|
||||
opacity={0.6}
|
||||
size={18}
|
||||
stroke={1.5}
|
||||
/>
|
||||
)}
|
||||
</Group>
|
||||
);
|
||||
}}
|
||||
description={options.withDescription ? tWidget("description") : undefined}
|
||||
searchable={options.searchable}
|
||||
{...form.getInputProps(`options.${property}`)}
|
||||
{...inputProps}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user