diff --git a/client/public/locales/en/common.json b/client/public/locales/en/common.json
index d0ff6d4..5bd92a3 100644
--- a/client/public/locales/en/common.json
+++ b/client/public/locales/en/common.json
@@ -204,6 +204,10 @@
"settings_extruder_temp": "Extruder Temp",
"settings_bed_temp": "Bed Temp",
"color_hex": "Color",
+ "single_color": "Single",
+ "multi_color": "Multi",
+ "coaxial": "Coextruded",
+ "longitudinal": "Longitudinal",
"external_id": "External ID",
"spools": "Show Spools"
},
@@ -213,7 +217,8 @@
"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.",
"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": {
"create": "Create Filament",
diff --git a/client/src/components/multiColorPicker.tsx b/client/src/components/multiColorPicker.tsx
new file mode 100644
index 0000000..64581b8
--- /dev/null
+++ b/client/src/components/multiColorPicker.tsx
@@ -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) => (
+ (props.min ?? 0) ? (
+
+ {
+ // Remove this picker
+ if (props.onChange) {
+ props.onChange(values.filter((v, i) => i !== idx).join(","));
+ }
+ }}
+ />
+
+ ) : (
+ <>>
+ )
+ }
+ >
+ {
+ if (props.onChange) {
+ newHex = newHex.replace("#", "");
+ props.onChange(values.map((v, i) => (i === idx ? newHex : v)).join(","));
+ }
+ }}
+ />
+
+ ));
+
+ return (
+ <>
+
+ {pickers}
+ {values.length < (props.max ?? Infinity) && (
+ }
+ onClick={() => {
+ if (props.onChange) {
+ props.onChange(values.concat(generateRandomColor()).join(","));
+ }
+ }}
+ />
+ )}
+
+ >
+ );
+}
diff --git a/client/src/pages/filaments/create.tsx b/client/src/pages/filaments/create.tsx
index f930aaf..964139c 100644
--- a/client/src/pages/filaments/create.tsx
+++ b/client/src/pages/filaments/create.tsx
@@ -1,7 +1,7 @@
import React from "react";
import { HttpError, IResourceComponentsProps, useInvalidate, useTranslate } from "@refinedev/core";
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 { numberFormatter, numberParser } from "../../utils/parsing";
import { IVendor } from "../vendors/model";
@@ -16,6 +16,7 @@ import { ExternalFilament, useGetExternalDBFilaments } from "../../utils/queryEx
import { formatFilamentLabel } from "../spools/functions";
import { FilamentImportModal } from "../../components/filamentImportModal";
import { getOrCreateVendorFromExternal } from "../vendors/functions";
+import { MultiColorPicker } from "../../components/multiColorPicker";
dayjs.extend(utc);
@@ -33,6 +34,7 @@ export const FilamentCreate: React.FC("single");
const { form, formProps, formLoading, onFinish, redirect } = useForm<
IFilament,
@@ -160,20 +162,62 @@ export const FilamentCreate: React.FC
- {
- return e?.toHex();
- }}
- >
-
+
+ {
+ setColorType(value.target.value);
+ }}
+ defaultValue={colorType}
+ value={colorType}
+ >
+ {t("filament.fields.single_color")}
+ {t("filament.fields.multi_color")}
+
+ {colorType == "single" && (
+ {
+ return e?.toHex();
+ }}
+ >
+
+
+ )}
+ {colorType == "multi" && (
+
+
+ {t("filament.fields.coaxial")}
+ {t("filament.fields.longitudinal")}
+
+
+ )}
+ {colorType == "multi" && (
+
+
+
+ )}