Added create filament page support for multi color

This commit is contained in:
Donkie
2024-05-28 20:09:20 +02:00
parent 4b155a93d2
commit ac2829ef84
3 changed files with 149 additions and 15 deletions

View File

@@ -204,6 +204,10 @@
"settings_extruder_temp": "Extruder Temp", "settings_extruder_temp": "Extruder Temp",
"settings_bed_temp": "Bed Temp", "settings_bed_temp": "Bed Temp",
"color_hex": "Color", "color_hex": "Color",
"single_color": "Single",
"multi_color": "Multi",
"coaxial": "Coextruded",
"longitudinal": "Longitudinal",
"external_id": "External ID", "external_id": "External ID",
"spools": "Show Spools" "spools": "Show Spools"
}, },
@@ -213,7 +217,8 @@
"price": "Price of a full spool.", "price": "Price of a full spool.",
"weight": "The filament weight of a full spool (net weight). This should not include the weight of the spool itself, only the filament. It is what is usually written on the packaging.", "weight": "The filament weight of a full spool (net weight). This should not include the weight of the spool itself, only the filament. It is what is usually written on the packaging.",
"spool_weight": "The weight of an empty spool. Used to determine measured weight of a spool.", "spool_weight": "The weight of an empty spool. Used to determine measured weight of a spool.",
"article_number": "E.g. EAN, UPC, etc." "article_number": "E.g. EAN, UPC, etc.",
"multi_color_direction": "Filaments can have multiple colors in two ways: either through coextrusion, like dual-color filaments with consistent multi-colors, or through longitudinal color changes, like gradient filaments that shift colors along the spool."
}, },
"titles": { "titles": {
"create": "Create Filament", "create": "Create Filament",

View File

@@ -0,0 +1,85 @@
import { CloseOutlined, PlusOutlined } from "@ant-design/icons";
import { Badge, Button, ColorPicker, InputNumber, Space } from "antd";
function generateRandomColor() {
return "000000".replace(/0/g, function () {
return (~~(Math.random() * 16)).toString(16);
});
}
function generateInitialColors(num: number) {
const colors = [];
for (let i = 0; i < num; i++) {
colors.push(generateRandomColor());
}
return colors;
}
/**
* An Ant Design compatible form input for multiple color pickers
* The value is a comma separated list of hex values, without hashtags
* @param props
* @returns
*/
export function MultiColorPicker(props: {
value?: string | null | undefined;
onChange?: (value: string | null | undefined) => void;
min?: number;
max?: number;
}) {
const values = props.value ? props.value.split(",") : generateInitialColors(props.min ?? 0);
if (!props.value && props.onChange) {
// Update value immediately
props.onChange(values.join(","));
}
const pickers = values.map((value, idx) => (
<Badge
key={idx}
count={
values.length > (props.min ?? 0) ? (
<span className="ant-badge-count">
<CloseOutlined
onClick={() => {
// Remove this picker
if (props.onChange) {
props.onChange(values.filter((v, i) => i !== idx).join(","));
}
}}
/>
</span>
) : (
<></>
)
}
>
<ColorPicker
format="hex"
value={value}
onChange={(_, newHex) => {
if (props.onChange) {
newHex = newHex.replace("#", "");
props.onChange(values.map((v, i) => (i === idx ? newHex : v)).join(","));
}
}}
/>
</Badge>
));
return (
<>
<Space direction="horizontal" size="middle">
{pickers}
{values.length < (props.max ?? Infinity) && (
<Button
icon={<PlusOutlined />}
onClick={() => {
if (props.onChange) {
props.onChange(values.concat(generateRandomColor()).join(","));
}
}}
/>
)}
</Space>
</>
);
}

View File

@@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import { HttpError, IResourceComponentsProps, useInvalidate, useTranslate } from "@refinedev/core"; import { HttpError, IResourceComponentsProps, useInvalidate, useTranslate } from "@refinedev/core";
import { Create, useForm, useSelect } from "@refinedev/antd"; import { Create, useForm, useSelect } from "@refinedev/antd";
import { Form, Input, Select, InputNumber, ColorPicker, Button, Typography, Modal } from "antd"; import { Form, Input, Select, InputNumber, ColorPicker, Button, Typography, Modal, Radio } from "antd";
import TextArea from "antd/es/input/TextArea"; import TextArea from "antd/es/input/TextArea";
import { numberFormatter, numberParser } from "../../utils/parsing"; import { numberFormatter, numberParser } from "../../utils/parsing";
import { IVendor } from "../vendors/model"; import { IVendor } from "../vendors/model";
@@ -16,6 +16,7 @@ import { ExternalFilament, useGetExternalDBFilaments } from "../../utils/queryEx
import { formatFilamentLabel } from "../spools/functions"; import { formatFilamentLabel } from "../spools/functions";
import { FilamentImportModal } from "../../components/filamentImportModal"; import { FilamentImportModal } from "../../components/filamentImportModal";
import { getOrCreateVendorFromExternal } from "../vendors/functions"; import { getOrCreateVendorFromExternal } from "../vendors/functions";
import { MultiColorPicker } from "../../components/multiColorPicker";
dayjs.extend(utc); dayjs.extend(utc);
@@ -33,6 +34,7 @@ export const FilamentCreate: React.FC<IResourceComponentsProps & CreateOrClonePr
const currency = useCurrency(); const currency = useCurrency();
const [isImportExtOpen, setIsImportExtOpen] = React.useState(false); const [isImportExtOpen, setIsImportExtOpen] = React.useState(false);
const invalidate = useInvalidate(); const invalidate = useInvalidate();
const [colorType, setColorType] = React.useState<"single" | "multi">("single");
const { form, formProps, formLoading, onFinish, redirect } = useForm< const { form, formProps, formLoading, onFinish, redirect } = useForm<
IFilament, IFilament,
@@ -160,20 +162,62 @@ export const FilamentCreate: React.FC<IResourceComponentsProps & CreateOrClonePr
} }
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item label={t("filament.fields.color_hex")}>
label={t("filament.fields.color_hex")} <Radio.Group
name={["color_hex"]} onChange={(value) => {
rules={[ setColorType(value.target.value);
{ }}
required: false, defaultValue={colorType}
}, value={colorType}
]} >
getValueFromEvent={(e) => { <Radio.Button value={"single"}>{t("filament.fields.single_color")}</Radio.Button>
return e?.toHex(); <Radio.Button value={"multi"}>{t("filament.fields.multi_color")}</Radio.Button>
}} </Radio.Group>
>
<ColorPicker format="hex" />
</Form.Item> </Form.Item>
{colorType == "single" && (
<Form.Item
name={"color_hex"}
rules={[
{
required: false,
},
]}
getValueFromEvent={(e) => {
return e?.toHex();
}}
>
<ColorPicker format="hex" />
</Form.Item>
)}
{colorType == "multi" && (
<Form.Item
name={"multi_color_direction"}
help={t("filament.fields_help.multi_color_direction")}
rules={[
{
required: true,
},
]}
initialValue={"coaxial"}
>
<Radio.Group>
<Radio.Button value={"coaxial"}>{t("filament.fields.coaxial")}</Radio.Button>
<Radio.Button value={"longitudinal"}>{t("filament.fields.longitudinal")}</Radio.Button>
</Radio.Group>
</Form.Item>
)}
{colorType == "multi" && (
<Form.Item
name={"multi_color_hexes"}
rules={[
{
required: false,
},
]}
>
<MultiColorPicker min={2} max={14} />
</Form.Item>
)}
<Form.Item <Form.Item
label={t("filament.fields.material")} label={t("filament.fields.material")}
help={t("filament.fields_help.material")} help={t("filament.fields_help.material")}