Laser Settings
diff --git a/app/projects/[id]/page.tsx b/app/projects/[id]/projects.tsx
similarity index 100%
rename from app/projects/[id]/page.tsx
rename to app/projects/[id]/projects.tsx
diff --git a/app/settings/co2-galvo/[id]/co2-galvo.tsx b/app/settings/co2-galvo/[id]/co2-galvo.tsx
new file mode 100644
index 00000000..1d7afa69
--- /dev/null
+++ b/app/settings/co2-galvo/[id]/co2-galvo.tsx
@@ -0,0 +1,183 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import { useParams } from "next/navigation";
+import Image from "next/image";
+import Markdown from "react-markdown";
+
+export default function CO2GalvoSettingDetailPage() {
+ const { id } = useParams();
+ const [setting, setSetting] = useState(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ fetch(
+ `${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_co2gal/${id}?fields=submission_id,setting_title,uploader,setting_notes,photo.filename_disk,screen.filename_disk,mat.name,mat_coat.name,mat_color.name,mat_opacity.opacity,mat_thickness,source.make,source.model,lens.field_size,lens.focal_length,lens_conf.name,lens_apt.name,lens_exp.name,focus,laser_soft.name,repeat_all,fill_settings,line_settings,raster_settings`
+ )
+ .then((res) => {
+ if (!res.ok) throw new Error("Failed to load");
+ return res.json();
+ })
+ .then((data) => setSetting(data.data))
+ .catch(() => setSetting(null))
+ .finally(() => setLoading(false));
+ }, [id]);
+
+ const formatBoolean = (val) => val ? "Enabled" : val === false ? "Disabled" : "—";
+
+ const renderRepeaterCard = (title, fields, items) => {
+ const filtered = (items || []).filter(item => Object.values(item).some(v => v !== null && v !== ""));
+ if (filtered.length === 0) return null;
+ return (
+
+
{title}
+
+ {filtered.map((item, i) => (
+
+ {fields.map(({ key, label, condition }) => {
+ const value = item[key];
+ if (condition && !condition(item)) return null;
+ return
{label}: {typeof value === "boolean" ? formatBoolean(value) : value || "—"}
;
+ })}
+
+ ))}
+
+
+ );
+ };
+
+ const openSearchInNewTab = (value) => {
+ const url = new URL("/co2-galvo-settings", window.location.origin);
+ url.searchParams.set("query", value);
+ const anchor = document.createElement("a");
+ anchor.href = url.toString();
+ anchor.target = "_blank";
+ anchor.rel = "noopener noreferrer";
+ anchor.click();
+ };
+
+ if (loading) return
Loading setting...
;
+ if (!setting) return
Setting not found.
;
+
+ return (
+
+
+
+
+
+
+ {setting.photo?.filename_disk && (
+
+
+
+ )}
+
+
+
Material
+
Material: openSearchInNewTab(setting.mat?.name)}>{setting.mat?.name || "—"}
+
Coating: openSearchInNewTab(setting.mat_coat?.name)}>{setting.mat_coat?.name || "—"}
+
Color: {setting.mat_color?.name || "—"}
+
Opacity: {setting.mat_opacity?.opacity || "—"}
+
Thickness: {setting.mat_thickness ? `${setting.mat_thickness} mm` : "Not Applicable"}
+
+
+
+
+
Setup
+
Software: {setting.laser_soft?.name || "—"}
+
Repeat All (global): {setting.repeat_all ?? "—"}
+
Focus: {setting.focus ?? "—"} mm
+
-Values Focus Closer | +Values Focus Further
+
+
+
+
Laser
+
Source Make: {setting.source?.make || "—"}
+
Source Model: openSearchInNewTab(setting.source?.model)}>{setting.source?.model || "—"}
+
Lens: openSearchInNewTab(setting.lens?.field_size)}>{setting.lens?.field_size || "—"} mm | {setting.lens?.focal_length || "—"} mm
+
Lens Config: {setting.lens_conf?.name || "—"}
+
Aperture Type: {setting.lens_apt?.name || "—"}
+
Expansion Type: {setting.lens_exp?.name || "—"}
+
+
+
+ {setting.setting_notes && (
+
+
Notes
+ {setting.setting_notes}
+
+ )}
+
+
+
+ {renderRepeaterCard("Fill Settings", [
+ { key: "fill_name", label: "Fill Name" },
+ { key: "power", label: "Power (%)" },
+ { key: "speed", label: "Speed (mm/s)" },
+ { key: "frequency", label: "Frequency (kHz)" },
+ { key: "pulse", label: "Pulse Width (ns)" },
+ { key: "interval", label: "Interval (mm)" },
+ { key: "pass", label: "Passes" },
+ { key: "type", label: "Type" },
+ { key: "angle", label: "Angle (°)" },
+ { key: "auto", label: "Auto-Rotate" },
+ { key: "increment", label: "Increment (°)", condition: (e) => e.auto },
+ { key: "cross", label: "Crosshatch" },
+ { key: "flood", label: "Flood Fill" },
+ { key: "air", label: "Air Assist" },
+ ], setting.fill_settings)}
+
+ {renderRepeaterCard("Line Settings", [
+ { key: "name", label: "Line Name" },
+ { key: "power", label: "Power (%)" },
+ { key: "speed", label: "Speed (mm/s)" },
+ { key: "frequency", label: "Frequency (kHz)" },
+ { key: "pulse", label: "Pulse Width (ns)" },
+ { key: "perf", label: "Perforation Mode" },
+ { key: "cut", label: "Cut (mm)", condition: (e) => e.perf },
+ { key: "skip", label: "Skip (mm)", condition: (e) => e.perf },
+ { key: "wobble", label: "Wobble Mode" },
+ { key: "step", label: "Step (mm)", condition: (e) => e.wobble },
+ { key: "size", label: "Size (mm)", condition: (e) => e.wobble },
+ { key: "pass", label: "Passes" },
+ { key: "air", label: "Air Assist" },
+ ], setting.line_settings)}
+
+ {renderRepeaterCard("Raster Settings", [
+ { key: "name", label: "Raster Name" },
+ { key: "power", label: "Power (%)" },
+ { key: "speed", label: "Speed (mm/s)" },
+ { key: "frequency", label: "Frequency (kHz)" },
+ { key: "pulse", label: "Pulse Width (ns)" },
+ { key: "type", label: "Type" },
+ { key: "dither", label: "Dither" },
+ { key: "halftone_cell", label: "Cell Size (mm)", condition: (e) => e.dither === "halftone" },
+ { key: "halftone_angle", label: "Halftone Angle", condition: (e) => e.dither === "halftone" },
+ { key: "inversion", label: "Image Inverted" },
+ { key: "interval", label: "Interval (mm)" },
+ { key: "dot", label: "Dot-width Adjustment (mm)" },
+ { key: "pass", label: "Passes" },
+ { key: "cross", label: "Crosshatch" },
+ { key: "air", label: "Air Assist" },
+ ], setting.raster_settings)}
+
+ );
+}
+
diff --git a/app/settings/co2-galvo/[id]/page.tsx b/app/settings/co2-galvo/[id]/page.tsx
index 1d7afa69..6e8b4ecb 100644
--- a/app/settings/co2-galvo/[id]/page.tsx
+++ b/app/settings/co2-galvo/[id]/page.tsx
@@ -1,183 +1,5 @@
-"use client";
-
-import { useEffect, useState } from "react";
-import { useParams } from "next/navigation";
-import Image from "next/image";
-import Markdown from "react-markdown";
-
-export default function CO2GalvoSettingDetailPage() {
- const { id } = useParams();
- const [setting, setSetting] = useState(null);
- const [loading, setLoading] = useState(true);
-
- useEffect(() => {
- fetch(
- `${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_co2gal/${id}?fields=submission_id,setting_title,uploader,setting_notes,photo.filename_disk,screen.filename_disk,mat.name,mat_coat.name,mat_color.name,mat_opacity.opacity,mat_thickness,source.make,source.model,lens.field_size,lens.focal_length,lens_conf.name,lens_apt.name,lens_exp.name,focus,laser_soft.name,repeat_all,fill_settings,line_settings,raster_settings`
- )
- .then((res) => {
- if (!res.ok) throw new Error("Failed to load");
- return res.json();
- })
- .then((data) => setSetting(data.data))
- .catch(() => setSetting(null))
- .finally(() => setLoading(false));
- }, [id]);
-
- const formatBoolean = (val) => val ? "Enabled" : val === false ? "Disabled" : "—";
-
- const renderRepeaterCard = (title, fields, items) => {
- const filtered = (items || []).filter(item => Object.values(item).some(v => v !== null && v !== ""));
- if (filtered.length === 0) return null;
- return (
-
-
{title}
-
- {filtered.map((item, i) => (
-
- {fields.map(({ key, label, condition }) => {
- const value = item[key];
- if (condition && !condition(item)) return null;
- return
{label}: {typeof value === "boolean" ? formatBoolean(value) : value || "—"}
;
- })}
-
- ))}
-
-
- );
- };
-
- const openSearchInNewTab = (value) => {
- const url = new URL("/co2-galvo-settings", window.location.origin);
- url.searchParams.set("query", value);
- const anchor = document.createElement("a");
- anchor.href = url.toString();
- anchor.target = "_blank";
- anchor.rel = "noopener noreferrer";
- anchor.click();
- };
-
- if (loading) return
Loading setting...
;
- if (!setting) return
Setting not found.
;
-
- return (
-
-
-
-
-
-
- {setting.photo?.filename_disk && (
-
-
-
- )}
-
-
-
Material
-
Material: openSearchInNewTab(setting.mat?.name)}>{setting.mat?.name || "—"}
-
Coating: openSearchInNewTab(setting.mat_coat?.name)}>{setting.mat_coat?.name || "—"}
-
Color: {setting.mat_color?.name || "—"}
-
Opacity: {setting.mat_opacity?.opacity || "—"}
-
Thickness: {setting.mat_thickness ? `${setting.mat_thickness} mm` : "Not Applicable"}
-
-
-
-
-
Setup
-
Software: {setting.laser_soft?.name || "—"}
-
Repeat All (global): {setting.repeat_all ?? "—"}
-
Focus: {setting.focus ?? "—"} mm
-
-Values Focus Closer | +Values Focus Further
-
-
-
-
Laser
-
Source Make: {setting.source?.make || "—"}
-
Source Model: openSearchInNewTab(setting.source?.model)}>{setting.source?.model || "—"}
-
Lens: openSearchInNewTab(setting.lens?.field_size)}>{setting.lens?.field_size || "—"} mm | {setting.lens?.focal_length || "—"} mm
-
Lens Config: {setting.lens_conf?.name || "—"}
-
Aperture Type: {setting.lens_apt?.name || "—"}
-
Expansion Type: {setting.lens_exp?.name || "—"}
-
-
-
- {setting.setting_notes && (
-
-
Notes
- {setting.setting_notes}
-
- )}
-
-
-
- {renderRepeaterCard("Fill Settings", [
- { key: "fill_name", label: "Fill Name" },
- { key: "power", label: "Power (%)" },
- { key: "speed", label: "Speed (mm/s)" },
- { key: "frequency", label: "Frequency (kHz)" },
- { key: "pulse", label: "Pulse Width (ns)" },
- { key: "interval", label: "Interval (mm)" },
- { key: "pass", label: "Passes" },
- { key: "type", label: "Type" },
- { key: "angle", label: "Angle (°)" },
- { key: "auto", label: "Auto-Rotate" },
- { key: "increment", label: "Increment (°)", condition: (e) => e.auto },
- { key: "cross", label: "Crosshatch" },
- { key: "flood", label: "Flood Fill" },
- { key: "air", label: "Air Assist" },
- ], setting.fill_settings)}
-
- {renderRepeaterCard("Line Settings", [
- { key: "name", label: "Line Name" },
- { key: "power", label: "Power (%)" },
- { key: "speed", label: "Speed (mm/s)" },
- { key: "frequency", label: "Frequency (kHz)" },
- { key: "pulse", label: "Pulse Width (ns)" },
- { key: "perf", label: "Perforation Mode" },
- { key: "cut", label: "Cut (mm)", condition: (e) => e.perf },
- { key: "skip", label: "Skip (mm)", condition: (e) => e.perf },
- { key: "wobble", label: "Wobble Mode" },
- { key: "step", label: "Step (mm)", condition: (e) => e.wobble },
- { key: "size", label: "Size (mm)", condition: (e) => e.wobble },
- { key: "pass", label: "Passes" },
- { key: "air", label: "Air Assist" },
- ], setting.line_settings)}
-
- {renderRepeaterCard("Raster Settings", [
- { key: "name", label: "Raster Name" },
- { key: "power", label: "Power (%)" },
- { key: "speed", label: "Speed (mm/s)" },
- { key: "frequency", label: "Frequency (kHz)" },
- { key: "pulse", label: "Pulse Width (ns)" },
- { key: "type", label: "Type" },
- { key: "dither", label: "Dither" },
- { key: "halftone_cell", label: "Cell Size (mm)", condition: (e) => e.dither === "halftone" },
- { key: "halftone_angle", label: "Halftone Angle", condition: (e) => e.dither === "halftone" },
- { key: "inversion", label: "Image Inverted" },
- { key: "interval", label: "Interval (mm)" },
- { key: "dot", label: "Dot-width Adjustment (mm)" },
- { key: "pass", label: "Passes" },
- { key: "cross", label: "Crosshatch" },
- { key: "air", label: "Air Assist" },
- ], setting.raster_settings)}
-
- );
+// app/settings/co2-galvo/[id]/page.tsx
+import { redirect } from "next/navigation";
+export default function Page({ params }: { params: { id: string } }) {
+ redirect(`/portal/laser-settings?t=co2-galvo&id=${encodeURIComponent(params.id)}`);
}
-
diff --git a/app/settings/co2-gantry/[id]/co2-gantry.tsx b/app/settings/co2-gantry/[id]/co2-gantry.tsx
new file mode 100644
index 00000000..39a26e3f
--- /dev/null
+++ b/app/settings/co2-gantry/[id]/co2-gantry.tsx
@@ -0,0 +1,180 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import { useParams } from "next/navigation";
+import Image from "next/image";
+import Markdown from "react-markdown";
+
+export default function CO2GantrySettingDetailPage() {
+ const { id } = useParams();
+ const [setting, setSetting] = useState(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ if (!id) return;
+
+ fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_co2gan/${id}?fields=submission_id,setting_title,uploader,setting_notes,photo.filename_disk,screen.filename_disk,mat.name,mat_coat.name,mat_color.name,mat_opacity.opacity,mat_thickness,source.make,source.model,laser_soft.name,lens.name,lens_conf.name,focus,repeat_all,fill_settings,line_settings,raster_settings`)
+ .then((res) => {
+ if (!res.ok) throw new Error("Failed to load");
+ return res.json();
+ })
+ .then((data) => {
+ setSetting(data.data);
+ setLoading(false);
+ })
+ .catch(() => setLoading(false));
+ }, [id]);
+
+ const openSearchInNewTab = (value) => {
+ if (!value || typeof window === "undefined") return;
+ const url = new URL("/co2-gantry-settings", window.location.origin);
+ url.searchParams.set("query", value);
+ window.open(url.toString(), "_blank", "noopener,noreferrer");
+ };
+
+ const renderRepeaterCard = (title, fields, data) => {
+ if (!data || !Array.isArray(data) || data.length === 0) return null;
+ return (
+
+
{title}
+ {data.map((item, i) => (
+
+ {fields.map((field) =>
+ field.condition === undefined || field.condition(item) ? (
+
+ {field.label}:{" "}
+ {item[field.key] !== undefined && item[field.key] !== null ? item[field.key].toString() : "—"}
+
+ ) : null
+ )}
+
+ ))}
+
+ );
+ };
+
+ if (loading) return
Loading…
;
+ if (!setting) return
Setting not found.
;
+
+ return (
+
+
+
+
+
+
+ {setting.photo?.filename_disk && (
+
+ )}
+
+
+
+ Material:{" "}
+ openSearchInNewTab(setting.mat?.name)}>
+ {setting.mat?.name || "—"}
+
+
+
+ Coating:{" "}
+ openSearchInNewTab(setting.mat_coat?.name)}>
+ {setting.mat_coat?.name || "—"}
+
+
+
Color: {setting.mat_color?.name || "—"}
+
Opacity: {setting.mat_opacity?.opacity || "—"}
+
Thickness: {setting.mat_thickness ? `${setting.mat_thickness} mm` : "—"}
+
+
+
+
+
+
+
Laser
+
Source Make: {setting.source?.make || "—"}
+
+ Source Model:{" "}
+ openSearchInNewTab(setting.source?.model)}>
+ {setting.source?.model || "—"}
+
+
+
+ Lens:{" "}
+ openSearchInNewTab(setting.lens?.name)}>
+ {setting.lens?.name || "—"}
+
+
+
Lens Config: {setting.lens_conf?.name || "—"}
+
+
+
+
Focus
+
Focus: {setting.focus || "—"}
+
+
+
+
+
Notes
+
+ {setting.setting_notes || "—"}
+
+
+
+
+
+ {renderRepeaterCard("Fill Settings", [
+ { key: "name", label: "Fill Name" },
+ { key: "power", label: "Power (%)" },
+ { key: "speed", label: "Speed (mm/s)" },
+ { key: "interval", label: "Interval (mm)" },
+ { key: "pass", label: "Passes" },
+ { key: "type", label: "Type" },
+ { key: "flood", label: "Flood Fill" },
+ { key: "air", label: "Air Assist" },
+ ], setting.fill_settings)}
+
+ {renderRepeaterCard("Line Settings", [
+ { key: "name", label: "Line Name" },
+ { key: "power", label: "Power (%)" },
+ { key: "speed", label: "Speed (mm/s)" },
+ { key: "perf", label: "Perforation" },
+ { key: "cut", label: "Cut Power Override" },
+ { key: "skip", label: "Skip Pass" },
+ { key: "pass", label: "Passes" },
+ { key: "air", label: "Air Assist" },
+ ], setting.line_settings)}
+
+ {renderRepeaterCard("Raster Settings", [
+ { key: "name", label: "Raster Name" },
+ { key: "power", label: "Power (%)" },
+ { key: "speed", label: "Speed (mm/s)" },
+ { key: "type", label: "Type" },
+ { key: "dither", label: "Dither" },
+ { key: "halftone_cell", label: "Halftone Cell" },
+ { key: "halftone_angle", label: "Angle" },
+ { key: "inversion", label: "Inversion" },
+ { key: "interval", label: "Interval" },
+ { key: "dot", label: "Dot Size" },
+ { key: "pass", label: "Passes" },
+ { key: "air", label: "Air Assist" },
+ ], setting.raster_settings)}
+
+ );
+}
+
diff --git a/app/settings/co2-gantry/[id]/page.tsx b/app/settings/co2-gantry/[id]/page.tsx
index 39a26e3f..07db80f9 100644
--- a/app/settings/co2-gantry/[id]/page.tsx
+++ b/app/settings/co2-gantry/[id]/page.tsx
@@ -1,180 +1,5 @@
-"use client";
-
-import { useEffect, useState } from "react";
-import { useParams } from "next/navigation";
-import Image from "next/image";
-import Markdown from "react-markdown";
-
-export default function CO2GantrySettingDetailPage() {
- const { id } = useParams();
- const [setting, setSetting] = useState(null);
- const [loading, setLoading] = useState(true);
-
- useEffect(() => {
- if (!id) return;
-
- fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_co2gan/${id}?fields=submission_id,setting_title,uploader,setting_notes,photo.filename_disk,screen.filename_disk,mat.name,mat_coat.name,mat_color.name,mat_opacity.opacity,mat_thickness,source.make,source.model,laser_soft.name,lens.name,lens_conf.name,focus,repeat_all,fill_settings,line_settings,raster_settings`)
- .then((res) => {
- if (!res.ok) throw new Error("Failed to load");
- return res.json();
- })
- .then((data) => {
- setSetting(data.data);
- setLoading(false);
- })
- .catch(() => setLoading(false));
- }, [id]);
-
- const openSearchInNewTab = (value) => {
- if (!value || typeof window === "undefined") return;
- const url = new URL("/co2-gantry-settings", window.location.origin);
- url.searchParams.set("query", value);
- window.open(url.toString(), "_blank", "noopener,noreferrer");
- };
-
- const renderRepeaterCard = (title, fields, data) => {
- if (!data || !Array.isArray(data) || data.length === 0) return null;
- return (
-
-
{title}
- {data.map((item, i) => (
-
- {fields.map((field) =>
- field.condition === undefined || field.condition(item) ? (
-
- {field.label}:{" "}
- {item[field.key] !== undefined && item[field.key] !== null ? item[field.key].toString() : "—"}
-
- ) : null
- )}
-
- ))}
-
- );
- };
-
- if (loading) return
Loading…
;
- if (!setting) return
Setting not found.
;
-
- return (
-
-
-
-
-
-
- {setting.photo?.filename_disk && (
-
- )}
-
-
-
- Material:{" "}
- openSearchInNewTab(setting.mat?.name)}>
- {setting.mat?.name || "—"}
-
-
-
- Coating:{" "}
- openSearchInNewTab(setting.mat_coat?.name)}>
- {setting.mat_coat?.name || "—"}
-
-
-
Color: {setting.mat_color?.name || "—"}
-
Opacity: {setting.mat_opacity?.opacity || "—"}
-
Thickness: {setting.mat_thickness ? `${setting.mat_thickness} mm` : "—"}
-
-
-
-
-
-
-
Laser
-
Source Make: {setting.source?.make || "—"}
-
- Source Model:{" "}
- openSearchInNewTab(setting.source?.model)}>
- {setting.source?.model || "—"}
-
-
-
- Lens:{" "}
- openSearchInNewTab(setting.lens?.name)}>
- {setting.lens?.name || "—"}
-
-
-
Lens Config: {setting.lens_conf?.name || "—"}
-
-
-
-
Focus
-
Focus: {setting.focus || "—"}
-
-
-
-
-
Notes
-
- {setting.setting_notes || "—"}
-
-
-
-
-
- {renderRepeaterCard("Fill Settings", [
- { key: "name", label: "Fill Name" },
- { key: "power", label: "Power (%)" },
- { key: "speed", label: "Speed (mm/s)" },
- { key: "interval", label: "Interval (mm)" },
- { key: "pass", label: "Passes" },
- { key: "type", label: "Type" },
- { key: "flood", label: "Flood Fill" },
- { key: "air", label: "Air Assist" },
- ], setting.fill_settings)}
-
- {renderRepeaterCard("Line Settings", [
- { key: "name", label: "Line Name" },
- { key: "power", label: "Power (%)" },
- { key: "speed", label: "Speed (mm/s)" },
- { key: "perf", label: "Perforation" },
- { key: "cut", label: "Cut Power Override" },
- { key: "skip", label: "Skip Pass" },
- { key: "pass", label: "Passes" },
- { key: "air", label: "Air Assist" },
- ], setting.line_settings)}
-
- {renderRepeaterCard("Raster Settings", [
- { key: "name", label: "Raster Name" },
- { key: "power", label: "Power (%)" },
- { key: "speed", label: "Speed (mm/s)" },
- { key: "type", label: "Type" },
- { key: "dither", label: "Dither" },
- { key: "halftone_cell", label: "Halftone Cell" },
- { key: "halftone_angle", label: "Angle" },
- { key: "inversion", label: "Inversion" },
- { key: "interval", label: "Interval" },
- { key: "dot", label: "Dot Size" },
- { key: "pass", label: "Passes" },
- { key: "air", label: "Air Assist" },
- ], setting.raster_settings)}
-
- );
+// app/settings/co2-gantry/[id]/page.tsx
+import { redirect } from "next/navigation";
+export default function Page({ params }: { params: { id: string } }) {
+ redirect(`/portal/laser-settings?t=co2-gantry&id=${encodeURIComponent(params.id)}`);
}
-
diff --git a/app/settings/fiber/[id]/fiber.tsx b/app/settings/fiber/[id]/fiber.tsx
new file mode 100644
index 00000000..a826bd02
--- /dev/null
+++ b/app/settings/fiber/[id]/fiber.tsx
@@ -0,0 +1,179 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import { useParams } from "next/navigation";
+import Image from "next/image";
+import Markdown from "react-markdown";
+
+export default function FiberSettingDetailPage() {
+ const { id } = useParams();
+ const [setting, setSetting] = useState(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ fetch(
+ `${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_fiber/${id}?fields=submission_id,setting_title,uploader,setting_notes,photo.filename_disk,screen.filename_disk,mat.name,mat_coat.name,mat_color.name,mat_opacity.opacity,mat_thickness,source.make,source.model,lens.field_size,lens.focal_length,focus,laser_soft.name,repeat_all,fill_settings,line_settings,raster_settings`
+ )
+ .then((res) => {
+ if (!res.ok) throw new Error("Failed to load");
+ return res.json();
+ })
+ .then((data) => setSetting(data.data))
+ .catch(() => setSetting(null))
+ .finally(() => setLoading(false));
+ }, [id]);
+
+ if (loading) return
Loading setting...
;
+ if (!setting) return
Setting not found.
;
+
+ const formatBoolean = (val) => val ? "Enabled" : val === false ? "Disabled" : "—";
+
+ const renderRepeaterCard = (title, fields, items) => {
+ const filtered = (items || []).filter(item => Object.values(item).some(v => v !== null && v !== ""));
+ if (filtered.length === 0) return null;
+ return (
+
+
{title}
+
+ {filtered.map((item, i) => (
+
+ {fields.map(({ key, label, condition }) => {
+ const value = item[key];
+ if (condition && !condition(item)) return null;
+ return
{label}: {typeof value === "boolean" ? formatBoolean(value) : value || "—"}
;
+ })}
+
+ ))}
+
+
+ );
+ };
+
+ const openSearchInNewTab = (value) => {
+ const url = new URL("/fiber-settings", window.location.origin);
+ url.searchParams.set("query", value);
+ const anchor = document.createElement("a");
+ anchor.href = url.toString();
+ anchor.target = "_blank";
+ anchor.rel = "noopener noreferrer";
+ anchor.click();
+ };
+
+ return (
+
+
+
+
+
+ {setting.photo?.filename_disk && (
+
+
+
+ )}
+
+
+
Material
+
Material: openSearchInNewTab(setting.mat?.name)}>{setting.mat?.name || "—"}
+
Coating: openSearchInNewTab(setting.mat_coat?.name)}>{setting.mat_coat?.name || "—"}
+
Color: {setting.mat_color?.name || "—"}
+
Opacity: {setting.mat_opacity?.opacity || "—"}
+
Thickness: {setting.mat_thickness ? `${setting.mat_thickness} mm` : "Not Applicable"}
+
+
+
+
+
Setup
+
Software: {setting.laser_soft?.name || "—"}
+
Repeat All (global): {setting.repeat_all ?? "—"}
+
Focus: {setting.focus ?? "—"} mm
+
-Values Focus Closer | +Values Focus Further
+
+
+
+
Laser
+
Source Make: {setting.source?.make || "—"}
+
Source Model: openSearchInNewTab(setting.source?.model)}>{setting.source?.model || "—"}
+
Lens: openSearchInNewTab(setting.lens?.field_size)}>{setting.lens?.field_size || "—"} mm | {setting.lens?.focal_length || "—"}
+
+
+
+ {setting.setting_notes && (
+
+
Notes
+ {setting.setting_notes}
+
+ )}
+
+
+
+ {renderRepeaterCard("Fill Settings", [
+ { key: "fill_name", label: "Fill Name" },
+ { key: "power", label: "Power (%)" },
+ { key: "speed", label: "Speed (mm/s)" },
+ { key: "frequency", label: "Frequency (kHz)" },
+ { key: "pulse", label: "Pulse Width (ns)" },
+ { key: "interval", label: "Interval (mm)" },
+ { key: "pass", label: "Passes" },
+ { key: "type", label: "Type" },
+ { key: "angle", label: "Angle (°)" },
+ { key: "auto", label: "Auto-Rotate" },
+ { key: "increment", label: "Increment (°)", condition: (e) => e.auto },
+ { key: "cross", label: "Crosshatch" },
+ { key: "flood", label: "Flood Fill" },
+ { key: "air", label: "Air Assist" },
+ ], setting.fill_settings)}
+
+ {renderRepeaterCard("Line Settings", [
+ { key: "name", label: "Line Name" },
+ { key: "power", label: "Power (%)" },
+ { key: "speed", label: "Speed (mm/s)" },
+ { key: "frequency", label: "Frequency (kHz)" },
+ { key: "pulse", label: "Pulse Width (ns)" },
+ { key: "perf", label: "Perforation Mode" },
+ { key: "cut", label: "Cut (mm)", condition: (e) => e.perf },
+ { key: "skip", label: "Skip (mm)", condition: (e) => e.perf },
+ { key: "wobble", label: "Wobble Mode" },
+ { key: "step", label: "Step (mm)", condition: (e) => e.wobble },
+ { key: "size", label: "Size (mm)", condition: (e) => e.wobble },
+ { key: "pass", label: "Passes" },
+ { key: "air", label: "Air Assist" },
+ ], setting.line_settings)}
+
+ {renderRepeaterCard("Raster Settings", [
+ { key: "name", label: "Raster Name" },
+ { key: "power", label: "Power (%)" },
+ { key: "speed", label: "Speed (mm/s)" },
+ { key: "frequency", label: "Frequency (kHz)" },
+ { key: "pulse", label: "Pulse Width (ns)" },
+ { key: "type", label: "Type" },
+ { key: "dither", label: "Dither" },
+ { key: "halftone_cell", label: "Cell Size (mm)", condition: (e) => e.dither === "halftone" },
+ { key: "halftone_angle", label: "Halftone Angle", condition: (e) => e.dither === "halftone" },
+ { key: "inversion", label: "Image Inverted" },
+ { key: "interval", label: "Interval (mm)" },
+ { key: "dot", label: "Dot-width Adjustment (mm)" },
+ { key: "pass", label: "Passes" },
+ { key: "cross", label: "Crosshatch" },
+ { key: "air", label: "Air Assist" },
+ ], setting.raster_settings)}
+
+ );
+}
+
diff --git a/app/settings/fiber/[id]/page.tsx b/app/settings/fiber/[id]/page.tsx
index a826bd02..03972276 100644
--- a/app/settings/fiber/[id]/page.tsx
+++ b/app/settings/fiber/[id]/page.tsx
@@ -1,179 +1,5 @@
-"use client";
-
-import { useEffect, useState } from "react";
-import { useParams } from "next/navigation";
-import Image from "next/image";
-import Markdown from "react-markdown";
-
-export default function FiberSettingDetailPage() {
- const { id } = useParams();
- const [setting, setSetting] = useState(null);
- const [loading, setLoading] = useState(true);
-
- useEffect(() => {
- fetch(
- `${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_fiber/${id}?fields=submission_id,setting_title,uploader,setting_notes,photo.filename_disk,screen.filename_disk,mat.name,mat_coat.name,mat_color.name,mat_opacity.opacity,mat_thickness,source.make,source.model,lens.field_size,lens.focal_length,focus,laser_soft.name,repeat_all,fill_settings,line_settings,raster_settings`
- )
- .then((res) => {
- if (!res.ok) throw new Error("Failed to load");
- return res.json();
- })
- .then((data) => setSetting(data.data))
- .catch(() => setSetting(null))
- .finally(() => setLoading(false));
- }, [id]);
-
- if (loading) return
Loading setting...
;
- if (!setting) return
Setting not found.
;
-
- const formatBoolean = (val) => val ? "Enabled" : val === false ? "Disabled" : "—";
-
- const renderRepeaterCard = (title, fields, items) => {
- const filtered = (items || []).filter(item => Object.values(item).some(v => v !== null && v !== ""));
- if (filtered.length === 0) return null;
- return (
-
-
{title}
-
- {filtered.map((item, i) => (
-
- {fields.map(({ key, label, condition }) => {
- const value = item[key];
- if (condition && !condition(item)) return null;
- return
{label}: {typeof value === "boolean" ? formatBoolean(value) : value || "—"}
;
- })}
-
- ))}
-
-
- );
- };
-
- const openSearchInNewTab = (value) => {
- const url = new URL("/fiber-settings", window.location.origin);
- url.searchParams.set("query", value);
- const anchor = document.createElement("a");
- anchor.href = url.toString();
- anchor.target = "_blank";
- anchor.rel = "noopener noreferrer";
- anchor.click();
- };
-
- return (
-
-
-
-
-
- {setting.photo?.filename_disk && (
-
-
-
- )}
-
-
-
Material
-
Material: openSearchInNewTab(setting.mat?.name)}>{setting.mat?.name || "—"}
-
Coating: openSearchInNewTab(setting.mat_coat?.name)}>{setting.mat_coat?.name || "—"}
-
Color: {setting.mat_color?.name || "—"}
-
Opacity: {setting.mat_opacity?.opacity || "—"}
-
Thickness: {setting.mat_thickness ? `${setting.mat_thickness} mm` : "Not Applicable"}
-
-
-
-
-
Setup
-
Software: {setting.laser_soft?.name || "—"}
-
Repeat All (global): {setting.repeat_all ?? "—"}
-
Focus: {setting.focus ?? "—"} mm
-
-Values Focus Closer | +Values Focus Further
-
-
-
-
Laser
-
Source Make: {setting.source?.make || "—"}
-
Source Model: openSearchInNewTab(setting.source?.model)}>{setting.source?.model || "—"}
-
Lens: openSearchInNewTab(setting.lens?.field_size)}>{setting.lens?.field_size || "—"} mm | {setting.lens?.focal_length || "—"}
-
-
-
- {setting.setting_notes && (
-
-
Notes
- {setting.setting_notes}
-
- )}
-
-
-
- {renderRepeaterCard("Fill Settings", [
- { key: "fill_name", label: "Fill Name" },
- { key: "power", label: "Power (%)" },
- { key: "speed", label: "Speed (mm/s)" },
- { key: "frequency", label: "Frequency (kHz)" },
- { key: "pulse", label: "Pulse Width (ns)" },
- { key: "interval", label: "Interval (mm)" },
- { key: "pass", label: "Passes" },
- { key: "type", label: "Type" },
- { key: "angle", label: "Angle (°)" },
- { key: "auto", label: "Auto-Rotate" },
- { key: "increment", label: "Increment (°)", condition: (e) => e.auto },
- { key: "cross", label: "Crosshatch" },
- { key: "flood", label: "Flood Fill" },
- { key: "air", label: "Air Assist" },
- ], setting.fill_settings)}
-
- {renderRepeaterCard("Line Settings", [
- { key: "name", label: "Line Name" },
- { key: "power", label: "Power (%)" },
- { key: "speed", label: "Speed (mm/s)" },
- { key: "frequency", label: "Frequency (kHz)" },
- { key: "pulse", label: "Pulse Width (ns)" },
- { key: "perf", label: "Perforation Mode" },
- { key: "cut", label: "Cut (mm)", condition: (e) => e.perf },
- { key: "skip", label: "Skip (mm)", condition: (e) => e.perf },
- { key: "wobble", label: "Wobble Mode" },
- { key: "step", label: "Step (mm)", condition: (e) => e.wobble },
- { key: "size", label: "Size (mm)", condition: (e) => e.wobble },
- { key: "pass", label: "Passes" },
- { key: "air", label: "Air Assist" },
- ], setting.line_settings)}
-
- {renderRepeaterCard("Raster Settings", [
- { key: "name", label: "Raster Name" },
- { key: "power", label: "Power (%)" },
- { key: "speed", label: "Speed (mm/s)" },
- { key: "frequency", label: "Frequency (kHz)" },
- { key: "pulse", label: "Pulse Width (ns)" },
- { key: "type", label: "Type" },
- { key: "dither", label: "Dither" },
- { key: "halftone_cell", label: "Cell Size (mm)", condition: (e) => e.dither === "halftone" },
- { key: "halftone_angle", label: "Halftone Angle", condition: (e) => e.dither === "halftone" },
- { key: "inversion", label: "Image Inverted" },
- { key: "interval", label: "Interval (mm)" },
- { key: "dot", label: "Dot-width Adjustment (mm)" },
- { key: "pass", label: "Passes" },
- { key: "cross", label: "Crosshatch" },
- { key: "air", label: "Air Assist" },
- ], setting.raster_settings)}
-
- );
+// app/settings/fiber/[id]/page.tsx
+import { redirect } from "next/navigation";
+export default function Page({ params }: { params: { id: string } }) {
+ redirect(`/portal/laser-settings?t=fiber&id=${encodeURIComponent(params.id)}`);
}
-
diff --git a/app/settings/fiber/[id]/page.tsx.back b/app/settings/fiber/[id]/page.tsx.back
deleted file mode 100644
index c7916b1b..00000000
--- a/app/settings/fiber/[id]/page.tsx.back
+++ /dev/null
@@ -1,59 +0,0 @@
-"use client";
-
-import { useEffect, useState } from "react";
-import { useParams } from "next/navigation";
-import Image from "next/image";
-import Markdown from "react-markdown";
-
-export default function FiberSettingDetailPage() {
- const { id } = useParams();
- const [setting, setSetting] = useState(null);
- const [loading, setLoading] = useState(true);
-
- useEffect(() => {
- fetch(
- `${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_fiber/${id}?fields=submission_id,setting_title,uploader,setting_notes,photo.filename_disk,mat.name,mat_coat.name,mat_color.name,mat_opacity.opacity,source.model,lens.field_size`
- )
- .then((res) => {
- if (!res.ok) throw new Error("Failed to load");
- return res.json();
- })
- .then((data) => setSetting(data.data))
- .catch(() => setSetting(null))
- .finally(() => setLoading(false));
- }, [id]);
-
- if (loading) return
Loading setting...
;
- if (!setting) return
Setting not found.
;
-
- return (
-
-
{setting.setting_title}
- {setting.photo?.filename_disk && (
-
- )}
-
-
Uploader: {setting.uploader || "—"}
-
Material: {setting.mat?.name || "—"}
-
Coating: {setting.mat_coat?.name || "—"}
-
Color: {setting.mat_color?.name || "—"}
-
Opacity: {setting.mat_opacity?.opacity || "—"}
-
Source Model: {setting.source?.model || "—"}
-
Lens Field Size: {setting.lens?.field_size || "—"}
-
- {setting.setting_notes && (
-
-
Notes
- {setting.setting_notes}
-
- )}
-
- );
-}
-
diff --git a/app/settings/uv/[id]/page.tsx b/app/settings/uv/[id]/page.tsx
index 1d69b7e3..7bea97cd 100644
--- a/app/settings/uv/[id]/page.tsx
+++ b/app/settings/uv/[id]/page.tsx
@@ -1,168 +1,5 @@
-"use client";
-
-import { useEffect, useState } from "react";
-import { useParams } from "next/navigation";
-import Image from "next/image";
-import Markdown from "react-markdown";
-
-export default function UVSettingDetailPage() {
- const { id } = useParams();
- const [setting, setSetting] = useState(null);
- const [loading, setLoading] = useState(true);
-
- useEffect(() => {
- if (!id) return;
- fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_uv/${id}?fields=submission_id,setting_title,uploader,setting_notes,photo.filename_disk,mat.name,mat_coat.name,mat_color.name,mat_opacity.opacity,mat_thickness,source.model,lens.field_size,lens.focal_length,focus,fill_settings,line_settings,raster_settings`)
- .then((res) => {
- if (!res.ok) throw new Error("Failed to load");
- return res.json();
- })
- .then((data) => {
- setSetting(data.data);
- setLoading(false);
- })
- .catch(() => setLoading(false));
- }, [id]);
-
- const openSearchInNewTab = (value) => {
- if (!value || typeof window === "undefined") return;
- const url = new URL("/uv-settings", window.location.origin);
- url.searchParams.set("query", value);
- window.open(url.toString(), "_blank", "noopener,noreferrer");
- };
-
- const renderRepeaterCard = (title, fields, data) => {
- if (!data || !Array.isArray(data) || data.length === 0) return null;
- return (
-
-
{title}
- {data.map((item, i) => (
-
- {fields.map((field) =>
- field.condition === undefined || field.condition(item) ? (
-
- {field.label}:{" "}
- {item[field.key] !== undefined && item[field.key] !== null ? item[field.key].toString() : "—"}
-
- ) : null
- )}
-
- ))}
-
- );
- };
-
- if (loading) return
Loading…
;
- if (!setting) return
Setting not found.
;
-
- return (
-
-
-
-
-
-
- {setting.photo?.filename_disk && (
-
- )}
-
-
-
Material: openSearchInNewTab(setting.mat?.name)}>{setting.mat?.name || "—"}
-
Coating: openSearchInNewTab(setting.mat_coat?.name)}>{setting.mat_coat?.name || "—"}
-
Color: {setting.mat_color?.name || "—"}
-
Opacity: {setting.mat_opacity?.opacity || "—"}
-
Thickness: {setting.mat_thickness ? `${setting.mat_thickness} mm` : "—"}
-
-
-
-
-
-
-
Laser
-
Source Model: openSearchInNewTab(setting.source?.model)}>{setting.source?.model || "—"}
-
Lens: {setting.lens?.field_size || "—"} mm | {setting.lens?.focal_length || "—"} mm
-
-
-
-
Focus
-
Focus: {setting.focus || "—"}
-
-
-
-
-
Notes
-
- {setting.setting_notes || "—"}
-
-
-
-
-
- {renderRepeaterCard("Fill Settings", [
- { key: "name", label: "Fill Name" },
- { key: "speed", label: "Speed (mm/s)" },
- { key: "frequency", label: "Frequency (kHz)" },
- { key: "pulse", label: "Pulse Width (ns)" },
- { key: "interval", label: "Interval (mm)" },
- { key: "pass", label: "Passes" },
- { key: "type", label: "Type" },
- { key: "angle", label: "Angle (°)" },
- { key: "auto", label: "Auto-Rotate" },
- { key: "increment", label: "Increment (°)", condition: (e) => e.auto },
- { key: "cross", label: "Crosshatch" },
- { key: "flood", label: "Flood Fill" },
- { key: "air", label: "Air Assist" },
- ], setting.fill_settings)}
-
- {renderRepeaterCard("Line Settings", [
- { key: "name", label: "Line Name" },
- { key: "speed", label: "Speed (mm/s)" },
- { key: "frequency", label: "Frequency (kHz)" },
- { key: "pulse", label: "Pulse Width (ns)" },
- { key: "perf", label: "Perforation Mode" },
- { key: "cut", label: "Cut Override" },
- { key: "skip", label: "Skip Pass" },
- { key: "wobble", label: "Wobble Enabled" },
- { key: "step", label: "Wobble Step" },
- { key: "size", label: "Wobble Size" },
- { key: "pass", label: "Passes" },
- { key: "air", label: "Air Assist" },
- ], setting.line_settings)}
-
- {renderRepeaterCard("Raster Settings", [
- { key: "name", label: "Raster Name" },
- { key: "speed", label: "Speed (mm/s)" },
- { key: "frequency", label: "Frequency (kHz)" },
- { key: "pulse", label: "Pulse Width (ns)" },
- { key: "type", label: "Type" },
- { key: "dither", label: "Dither" },
- { key: "halftone_cell", label: "Halftone Cell" },
- { key: "halftone_angle", label: "Halftone Angle" },
- { key: "inversion", label: "Invert Colors" },
- { key: "interval", label: "Interval (mm)" },
- { key: "dot", label: "Dot Size" },
- { key: "pass", label: "Passes" },
- { key: "cross", label: "Crosshatch" },
- { key: "air", label: "Air Assist" },
- ], setting.raster_settings)}
-
- );
+// app/settings/uv/[id]/page.tsx
+import { redirect } from "next/navigation";
+export default function Page({ params }: { params: { id: string } }) {
+ redirect(`/portal/laser-settings?t=uv&id=${encodeURIComponent(params.id)}`);
}
-
diff --git a/app/settings/uv/[id]/uv.tsx b/app/settings/uv/[id]/uv.tsx
new file mode 100644
index 00000000..1d69b7e3
--- /dev/null
+++ b/app/settings/uv/[id]/uv.tsx
@@ -0,0 +1,168 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import { useParams } from "next/navigation";
+import Image from "next/image";
+import Markdown from "react-markdown";
+
+export default function UVSettingDetailPage() {
+ const { id } = useParams();
+ const [setting, setSetting] = useState(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ if (!id) return;
+ fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/items/settings_uv/${id}?fields=submission_id,setting_title,uploader,setting_notes,photo.filename_disk,mat.name,mat_coat.name,mat_color.name,mat_opacity.opacity,mat_thickness,source.model,lens.field_size,lens.focal_length,focus,fill_settings,line_settings,raster_settings`)
+ .then((res) => {
+ if (!res.ok) throw new Error("Failed to load");
+ return res.json();
+ })
+ .then((data) => {
+ setSetting(data.data);
+ setLoading(false);
+ })
+ .catch(() => setLoading(false));
+ }, [id]);
+
+ const openSearchInNewTab = (value) => {
+ if (!value || typeof window === "undefined") return;
+ const url = new URL("/uv-settings", window.location.origin);
+ url.searchParams.set("query", value);
+ window.open(url.toString(), "_blank", "noopener,noreferrer");
+ };
+
+ const renderRepeaterCard = (title, fields, data) => {
+ if (!data || !Array.isArray(data) || data.length === 0) return null;
+ return (
+
+
{title}
+ {data.map((item, i) => (
+
+ {fields.map((field) =>
+ field.condition === undefined || field.condition(item) ? (
+
+ {field.label}:{" "}
+ {item[field.key] !== undefined && item[field.key] !== null ? item[field.key].toString() : "—"}
+
+ ) : null
+ )}
+
+ ))}
+
+ );
+ };
+
+ if (loading) return
Loading…
;
+ if (!setting) return
Setting not found.
;
+
+ return (
+
+
+
+
+
+
+ {setting.photo?.filename_disk && (
+
+ )}
+
+
+
Material: openSearchInNewTab(setting.mat?.name)}>{setting.mat?.name || "—"}
+
Coating: openSearchInNewTab(setting.mat_coat?.name)}>{setting.mat_coat?.name || "—"}
+
Color: {setting.mat_color?.name || "—"}
+
Opacity: {setting.mat_opacity?.opacity || "—"}
+
Thickness: {setting.mat_thickness ? `${setting.mat_thickness} mm` : "—"}
+
+
+
+
+
+
+
Laser
+
Source Model: openSearchInNewTab(setting.source?.model)}>{setting.source?.model || "—"}
+
Lens: {setting.lens?.field_size || "—"} mm | {setting.lens?.focal_length || "—"} mm
+
+
+
+
Focus
+
Focus: {setting.focus || "—"}
+
+
+
+
+
Notes
+
+ {setting.setting_notes || "—"}
+
+
+
+
+
+ {renderRepeaterCard("Fill Settings", [
+ { key: "name", label: "Fill Name" },
+ { key: "speed", label: "Speed (mm/s)" },
+ { key: "frequency", label: "Frequency (kHz)" },
+ { key: "pulse", label: "Pulse Width (ns)" },
+ { key: "interval", label: "Interval (mm)" },
+ { key: "pass", label: "Passes" },
+ { key: "type", label: "Type" },
+ { key: "angle", label: "Angle (°)" },
+ { key: "auto", label: "Auto-Rotate" },
+ { key: "increment", label: "Increment (°)", condition: (e) => e.auto },
+ { key: "cross", label: "Crosshatch" },
+ { key: "flood", label: "Flood Fill" },
+ { key: "air", label: "Air Assist" },
+ ], setting.fill_settings)}
+
+ {renderRepeaterCard("Line Settings", [
+ { key: "name", label: "Line Name" },
+ { key: "speed", label: "Speed (mm/s)" },
+ { key: "frequency", label: "Frequency (kHz)" },
+ { key: "pulse", label: "Pulse Width (ns)" },
+ { key: "perf", label: "Perforation Mode" },
+ { key: "cut", label: "Cut Override" },
+ { key: "skip", label: "Skip Pass" },
+ { key: "wobble", label: "Wobble Enabled" },
+ { key: "step", label: "Wobble Step" },
+ { key: "size", label: "Wobble Size" },
+ { key: "pass", label: "Passes" },
+ { key: "air", label: "Air Assist" },
+ ], setting.line_settings)}
+
+ {renderRepeaterCard("Raster Settings", [
+ { key: "name", label: "Raster Name" },
+ { key: "speed", label: "Speed (mm/s)" },
+ { key: "frequency", label: "Frequency (kHz)" },
+ { key: "pulse", label: "Pulse Width (ns)" },
+ { key: "type", label: "Type" },
+ { key: "dither", label: "Dither" },
+ { key: "halftone_cell", label: "Halftone Cell" },
+ { key: "halftone_angle", label: "Halftone Angle" },
+ { key: "inversion", label: "Invert Colors" },
+ { key: "interval", label: "Interval (mm)" },
+ { key: "dot", label: "Dot Size" },
+ { key: "pass", label: "Passes" },
+ { key: "cross", label: "Crosshatch" },
+ { key: "air", label: "Air Assist" },
+ ], setting.raster_settings)}
+
+ );
+}
+