mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-10 15:35:55 +01:00
🎨 Merge change position modals
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
import { SelectItem } from '@mantine/core';
|
||||
import { closeModal, ContextModalProps } from '@mantine/modals';
|
||||
import { useConfigContext } from '../../../../config/provider';
|
||||
import { useConfigStore } from '../../../../config/store';
|
||||
import { IntegrationsType } from '../../../../types/integration';
|
||||
import { TileBaseType } from '../../../../types/tile';
|
||||
import { Tiles } from '../../Tiles/tilesDefinitions';
|
||||
import { ChangePositionModal } from './ChangePositionModal';
|
||||
|
||||
export type IntegrationChangePositionModalInnerProps = {
|
||||
integration: keyof IntegrationsType;
|
||||
module: TileBaseType;
|
||||
};
|
||||
|
||||
export const ChangeIntegrationPositionModal = ({
|
||||
context,
|
||||
id,
|
||||
innerProps,
|
||||
}: ContextModalProps<IntegrationChangePositionModalInnerProps>) => {
|
||||
const { name: configName } = useConfigContext();
|
||||
const updateConfig = useConfigStore((x) => x.updateConfig);
|
||||
|
||||
const handleSubmit = (x: number, y: number, width: number, height: number) => {
|
||||
if (!configName) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateConfig(configName, (prev) => ({
|
||||
...prev,
|
||||
integrations: {
|
||||
...prev.integrations,
|
||||
[innerProps.integration]: {
|
||||
...prev.integrations[innerProps.integration],
|
||||
shape: {
|
||||
location: {
|
||||
x,
|
||||
y,
|
||||
},
|
||||
size: {
|
||||
height,
|
||||
width,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}));
|
||||
context.closeModal(id);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
closeModal(id);
|
||||
};
|
||||
|
||||
const widthData = useWidthData(innerProps.integration);
|
||||
const heightData = useHeightData(innerProps.integration);
|
||||
|
||||
return (
|
||||
<ChangePositionModal
|
||||
onSubmit={handleSubmit}
|
||||
onCancel={handleCancel}
|
||||
heightData={heightData}
|
||||
widthData={widthData}
|
||||
initialX={innerProps.module.shape.location.x}
|
||||
initialY={innerProps.module.shape.location.y}
|
||||
initialWidth={innerProps.module.shape.size.width}
|
||||
initialHeight={innerProps.module.shape.size.height}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const useWidthData = (integration: keyof IntegrationsType): SelectItem[] => {
|
||||
const tileDefinitions = Tiles[integration];
|
||||
const offset = tileDefinitions.minWidth ?? 2;
|
||||
const length = (tileDefinitions.maxWidth ?? 12) - offset;
|
||||
return Array.from({ length }, (_, i) => i + offset).map((n) => ({
|
||||
value: n.toString(),
|
||||
label: `${64 * n}px`,
|
||||
}));
|
||||
};
|
||||
|
||||
const useHeightData = (integration: keyof IntegrationsType): SelectItem[] => {
|
||||
const tileDefinitions = Tiles[integration];
|
||||
const offset = tileDefinitions.minHeight ?? 2;
|
||||
const length = (tileDefinitions.maxHeight ?? 12) - offset;
|
||||
return Array.from({ length }, (_, i) => i + offset).map((n) => ({
|
||||
value: n.toString(),
|
||||
label: `${64 * n}px`,
|
||||
}));
|
||||
};
|
||||
@@ -1,44 +1,55 @@
|
||||
import { Button, Flex, Grid, NumberInput } from '@mantine/core';
|
||||
import { Button, Flex, Grid, NumberInput, Select, SelectItem } from '@mantine/core';
|
||||
import { useForm } from '@mantine/form';
|
||||
import { closeModal, ContextModalProps } from '@mantine/modals';
|
||||
import { useConfigContext } from '../../../../config/provider';
|
||||
import { useConfigStore } from '../../../../config/store';
|
||||
import { ServiceType } from '../../../../types/service';
|
||||
import { TileBaseType } from '../../../../types/tile';
|
||||
|
||||
interface ChangePositionModalProps {
|
||||
initialX: number;
|
||||
initialY: number;
|
||||
initialWidth: number;
|
||||
initialHeight: number;
|
||||
widthData: SelectItem[];
|
||||
heightData: SelectItem[];
|
||||
onSubmit: (x: number, y: number, width: number, height: number) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
export const ChangePositionModal = ({
|
||||
context,
|
||||
id,
|
||||
innerProps,
|
||||
}: ContextModalProps<{ type: 'service' | 'type'; tile: TileBaseType }>) => {
|
||||
const updateConfig = useConfigStore((x) => x.updateConfig);
|
||||
initialX,
|
||||
initialY,
|
||||
initialWidth,
|
||||
initialHeight,
|
||||
widthData,
|
||||
heightData,
|
||||
onCancel,
|
||||
onSubmit,
|
||||
}: ChangePositionModalProps) => {
|
||||
const { name: configName } = useConfigContext();
|
||||
|
||||
const form = useForm({
|
||||
const form = useForm<FormType>({
|
||||
initialValues: {
|
||||
tile: innerProps.tile,
|
||||
x: initialX,
|
||||
y: initialY,
|
||||
width: initialWidth,
|
||||
height: initialHeight,
|
||||
},
|
||||
validateInputOnChange: true,
|
||||
validateInputOnBlur: true,
|
||||
});
|
||||
|
||||
const onSubmit = () => {
|
||||
const handleSubmit = () => {
|
||||
if (!configName) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tileAsService = form.values.tile as ServiceType;
|
||||
|
||||
updateConfig(configName, (previous) => ({
|
||||
...previous,
|
||||
services: [...previous.services.filter((x) => x.id === tileAsService.id), tileAsService],
|
||||
}));
|
||||
|
||||
closeModal(id);
|
||||
onSubmit(form.values.x, form.values.y, form.values.width, form.values.height);
|
||||
};
|
||||
|
||||
console.log(`Initial: (${form.values.width} / ${form.values.height})`);
|
||||
console.log(widthData);
|
||||
console.log(heightData);
|
||||
|
||||
return (
|
||||
<form onSubmit={form.onSubmit(onSubmit)}>
|
||||
<form onSubmit={form.onSubmit(handleSubmit)}>
|
||||
<Grid>
|
||||
<Grid.Col xs={12} md={6}>
|
||||
<NumberInput
|
||||
@@ -46,7 +57,7 @@ export const ChangePositionModal = ({
|
||||
min={0}
|
||||
label="X Position"
|
||||
description="0 or higher"
|
||||
{...form.getInputProps('tile.shape.location.x')}
|
||||
{...form.getInputProps('x')}
|
||||
/>
|
||||
</Grid.Col>
|
||||
|
||||
@@ -56,39 +67,48 @@ export const ChangePositionModal = ({
|
||||
min={0}
|
||||
label="Y Position"
|
||||
description="0 or higher"
|
||||
{...form.getInputProps('tile.shape.location.y')}
|
||||
{...form.getInputProps('y')}
|
||||
/>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
|
||||
<Grid>
|
||||
<Grid.Col xs={12} md={6}>
|
||||
<NumberInput
|
||||
<Select
|
||||
data={widthData}
|
||||
max={24}
|
||||
min={1}
|
||||
label="Width"
|
||||
description="Between 1 and 24"
|
||||
{...form.getInputProps('tile.shape.size.width')}
|
||||
description={`Between ${widthData.at(0)?.label} and ${widthData.at(-1)?.label}`}
|
||||
{...form.getInputProps('width')}
|
||||
/>
|
||||
</Grid.Col>
|
||||
|
||||
<Grid.Col xs={12} md={6}>
|
||||
<NumberInput
|
||||
<Select
|
||||
data={heightData}
|
||||
max={24}
|
||||
min={1}
|
||||
label="Height"
|
||||
description="Between 1 and 24"
|
||||
{...form.getInputProps('tile.shape.size.height')}
|
||||
description={`Between ${heightData.at(0)?.label} and ${heightData.at(-1)?.label}`}
|
||||
{...form.getInputProps('height')}
|
||||
/>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
|
||||
<Flex justify="end" gap="sm" mt="md">
|
||||
<Button onClick={() => closeModal(id)} variant="light" color="gray">
|
||||
<Button onClick={() => onCancel()} variant="light" color="gray">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit">Change Position</Button>
|
||||
<Button type="submit">Save</Button>
|
||||
</Flex>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
type FormType = {
|
||||
x: number;
|
||||
y: number;
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import { SelectItem } from '@mantine/core';
|
||||
import { closeModal, ContextModalProps } from '@mantine/modals';
|
||||
import { useConfigContext } from '../../../../config/provider';
|
||||
import { useConfigStore } from '../../../../config/store';
|
||||
import { ServiceType } from '../../../../types/service';
|
||||
import { ChangePositionModal } from './ChangePositionModal';
|
||||
|
||||
type ChangeServicePositionModalInnerProps = {
|
||||
service: ServiceType;
|
||||
};
|
||||
|
||||
export const ChangeServicePositionModal = ({
|
||||
id,
|
||||
context,
|
||||
innerProps,
|
||||
}: ContextModalProps<ChangeServicePositionModalInnerProps>) => {
|
||||
const { name: configName } = useConfigContext();
|
||||
const updateConfig = useConfigStore((x) => x.updateConfig);
|
||||
|
||||
const handleSubmit = (x: number, y: number, width: number, height: number) => {
|
||||
if (!configName) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateConfig(configName, (previousConfig) => ({
|
||||
...previousConfig,
|
||||
services: [
|
||||
...previousConfig.services.filter((x) => x.id !== innerProps.service.id),
|
||||
{ ...innerProps.service, shape: { location: { x, y }, size: { width, height } } },
|
||||
],
|
||||
}));
|
||||
context.closeModal(id);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
closeModal(id);
|
||||
};
|
||||
|
||||
const widthData = useWidthData();
|
||||
const heightData = useHeightData();
|
||||
|
||||
return (
|
||||
<ChangePositionModal
|
||||
onSubmit={handleSubmit}
|
||||
onCancel={handleCancel}
|
||||
widthData={widthData}
|
||||
heightData={heightData}
|
||||
initialX={innerProps.service.shape.location.x}
|
||||
initialY={innerProps.service.shape.location.y}
|
||||
initialWidth={innerProps.service.shape.size.width}
|
||||
initialHeight={innerProps.service.shape.size.height}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const useHeightData = (): SelectItem[] =>
|
||||
Array.from(Array(11).keys()).map((n) => {
|
||||
const index = n + 1;
|
||||
return {
|
||||
value: index.toString(),
|
||||
label: `${64 * index}px`,
|
||||
};
|
||||
});
|
||||
|
||||
const useWidthData = (): SelectItem[] =>
|
||||
Array.from(Array(11).keys()).map((n) => {
|
||||
const index = n + 1;
|
||||
return {
|
||||
value: index.toString(),
|
||||
label: `${64 * index}px`,
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user