ElementsPanel.tsx 5.17 KB
import React from "react";
import type { ElementLibraryCategory, ElementType } from "../../../types/labelTemplate";

/** 左侧标签库:四类分组(与产品图一致);打印时输入项可带 config 以正确显示为 input */
const ELEMENT_CATEGORIES: {
  title: ElementLibraryCategory;
  subtitle?: string;
  items: { label: string; type: ElementType; config?: Record<string, unknown> }[];
}[] = [
  {
    title: "Template",
    items: [
      { label: "Text", type: "TEXT_STATIC" },
      { label: "QR Code", type: "QRCODE" },
      { label: "Barcode", type: "BARCODE" },
      { label: "Blank Space", type: "BLANK" },
      { label: "Price", type: "TEXT_PRICE" },
      { label: "Image", type: "IMAGE" },
      { label: "Logo", type: "IMAGE" },
    ],
  },
  {
    title: "Label",
    items: [
      { label: "Label Name", type: "TEXT_PRODUCT" },
      { label: "Text", type: "TEXT_STATIC" },
      { label: "QR Code", type: "QRCODE" },
      { label: "Barcode", type: "BARCODE" },
      { label: "Nutrition Facts", type: "NUTRITION" },
      { label: "Price", type: "TEXT_PRICE" },
      { label: "Duration Date", type: "DATE" },
      { label: "Duration Time", type: "TIME" },
      { label: "Duration", type: "DURATION" },
      { label: "Image", type: "IMAGE" },
      { label: "Label Type", type: "TEXT_STATIC" },
      { label: "How-to", type: "TEXT_STATIC" },
      { label: "Expiration Alert", type: "TEXT_STATIC" },
    ],
  },
  {
    title: "Auto-generated",
    items: [
      { label: "Company", type: "TEXT_STATIC" },
      { label: "Employee", type: "TEXT_STATIC" },
      { label: "Current Date", type: "DATE" },
      { label: "Current Time", type: "TIME" },
      { label: "Label ID", type: "TEXT_STATIC" },
    ],
  },
  {
    title: "Print input",
    subtitle: "Click to add to canvas",
    items: [
      { label: "Text", type: "TEXT_STATIC", config: { inputType: "text" } },
      { label: "Weight", type: "WEIGHT" },
      { label: "Number", type: "TEXT_STATIC", config: { inputType: "number", text: "0" } },
      { label: "Date & Time", type: "DATE", config: { inputType: "datetime", format: "YYYY-MM-DD HH:mm" } },
      {
        label: "Multiple Options",
        type: "TEXT_STATIC",
        config: {
          inputType: "options",
          multipleOptionId: "",
          selectedOptionValues: [],
          text: "Text",
          fontFamily: "Arial",
          fontSize: 14,
          fontWeight: "normal",
          textAlign: "left",
        },
      },
    ],
  },
];

interface ElementsPanelProps {
  onAddElement: (
    type: ElementType,
    configOverride: Partial<Record<string, unknown>> | undefined,
    libraryCategory: ElementLibraryCategory,
    paletteItemLabel: string,
  ) => void;
}

function sectionSurfaceStyle(title: string): React.CSSProperties {
  const t = title.trim().toLowerCase();
  if (t === "template") {
    return {
      backgroundColor: "#dbeafe",
      border: "1px solid #93c5fd",
      borderRadius: 8,
      padding: 8,
    };
  }
  if (t === "label") {
    return {
      backgroundColor: "#e0f2fe",
      border: "1px solid #7dd3fc",
      borderRadius: 8,
      padding: 8,
    };
  }
  if (t === "auto-generated") {
    return {
      backgroundColor: "#ede9fe",
      border: "1px solid #c4b5fd",
      borderRadius: 8,
      padding: 8,
    };
  }
  if (t === "print input") {
    return {
      backgroundColor: "#ffedd5",
      border: "1px solid #fdba74",
      borderRadius: 8,
      padding: 8,
    };
  }
  return {
    backgroundColor: "#f1f5f9",
    border: "1px solid #cbd5e1",
    borderRadius: 8,
    padding: 8,
  };
}

/**
 * 左侧元素库。纵向滚动由父级(index 左侧列容器)的 overflow-y:auto 负责,
 * 避免预编译 CSS 缺少 min-h-0 / flex-1 时内层滚动高度为 0 导致底部橙色区被裁切。
 */
export function ElementsPanel({ onAddElement }: ElementsPanelProps) {
  return (
    <div className="border-r border-slate-200 bg-slate-50">
      <div
        className="border-b border-slate-200 px-2 py-2 text-sm font-semibold text-slate-800"
        style={{ backgroundColor: "#eff6ff", borderBottomColor: "#93c5fd" }}
      >
        Elements
      </div>
      <div className="p-2 space-y-3">
        {ELEMENT_CATEGORIES.map((cat) => (
          <div key={cat.title} style={sectionSurfaceStyle(cat.title)}>
            <div className="px-2 py-1 text-xs font-medium uppercase tracking-wide text-gray-600">{cat.title}</div>
            {cat.subtitle ? (
              <div className="px-2 py-0.5 text-[10px] text-gray-400">{cat.subtitle}</div>
            ) : null}
            <div className="mt-0.5 grid grid-cols-2 gap-1">
              {cat.items.map((item, i) => (
                <button
                  key={`${cat.title}-${item.label}-${i}`}
                  type="button"
                  onClick={() => onAddElement(item.type, item.config, cat.title, item.label)}
                  className="items-start justify-start whitespace-normal break-words rounded border border-transparent px-2 py-1.5 text-left text-xs leading-snug hover:border-gray-200 hover:bg-gray-100"
                >
                  {item.label}
                </button>
              ))}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}