enzostvs's picture
enzostvs HF Staff
Update components/editor-icons/comps/icons/icon-selected.tsx
6d85e41 verified
import classNames from "classnames";
import {
faChevronDown,
faChevronRight,
faTrash,
faCaretDown,
faCaretUp,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { ListItem } from "components/editor-icons/comps/list/list-item";
import {
Icons as ICONS,
IconCustomIcon,
IconCustomText,
} from "components/svg/icons";
import { IconItem, IconType } from "@/types/editor";
import { ColorPicker } from "components/color-picker";
import { Range } from "components/range";
import { Input } from "components/input";
import { Switch } from "@/components/switch";
import { PremiumOverlay } from "@/components/premium/overlay";
import { FormattedMessage, useIntl } from "react-intl";
import { Label } from "@/components/label";
export const IconSelected = ({
index,
totalIcons,
icon,
current,
setCurrent,
onDelete,
onChange,
onChangeOrder,
}: {
index: number;
totalIcons: number;
icon: IconType;
current?: number | null;
setCurrent: (index: number | null) => void;
onDelete: (index: number) => void;
onChange: (idnex: number, icon: IconType) => void;
onChangeOrder: (index: number, value: number) => void;
}) => {
const findIcon: any = icon?.custom_text?.enabled
? IconCustomText
: icon?.image
? IconCustomIcon
: ICONS?.find((i: IconItem) => icon.component === i.name);
const handleChange = (index: number, icon: any) => {
onChange(index, icon);
};
const intl = useIntl();
return (
<div className="flex items-center justify-start gap-3 w-full">
<div
className={classNames(
"bg-dark-600 w-full rounded-lg pl-4 py-4 pr-6 group cursor-pointer transition-all border-2 border-dark-600 duration-200 hover:border-blue",
{
"!border-blue": current === index,
}
)}
>
<div
className="tracking-wider flex items-center justify-between gap-4"
onClick={() => setCurrent(current === index ? null : index)}
>
<div className="flex items-center justify-start gap-4">
<div className="w-10">
{icon?.image ? (
<div className="flex items-center justify-center p-2 cursor-pointer rounded-lg relative group border border-dark-200 border-solid">
<img
src={icon?.image}
className="w-full h-full object-contain"
/>
</div>
) : (
<ListItem
icon={findIcon}
fill={findIcon?.defaultColor ?? "#fff"}
tooltip={false}
hoverable={false}
onSelect={() => {}}
/>
)}
</div>
<div>
<p className="text-white font-semibold">
<FormattedMessage id={findIcon?.name} />
</p>
<p className="text-xs text-dark-200">
{findIcon?.tags?.join(", ")}
</p>
</div>
</div>
<div className="flex items-center justify-end gap-4">
<div
className="bg-danger bg-opacity-60 rounded-lg text-white hover:bg-opacity-100 cursor-pointer w-8 h-8 flex items-center justify-center"
onClick={(e: any) => {
e.preventDefault();
e.stopPropagation();
onDelete(index);
}}
>
<FontAwesomeIcon icon={faTrash} className="w-4" />
</div>
<div className="flex items-center justify-end">
<FontAwesomeIcon
icon={current === index ? faChevronDown : faChevronRight}
className="text-dark-100 transition-all duration-200 w-3"
/>
</div>
</div>
</div>
{current === index && (
<div className="border-t border-dark-400 pt-3 mt-4 grid grid-cols-2 gap-4">
<div className="col-span-2">
<Label className="mb-1">
<FormattedMessage id="iconsEditor.editor.customisation.positions" />
</Label>
<div className="grid grid-cols-2 gap-x-6 gap-y-3">
<div className="gap-4 w-full col-span-2 grid grid-cols-3">
<div className="flex items-center gap-3 col-span-2">
<p className="font-semibold uppercase text-dark-200 text-xs">
X
</p>
<Range
value={icon?.position?.x ?? 0}
max={
icon?.custom_text?.enabled
? 1000
: icon?.position?.xPath ?? undefined
}
onChange={(value) => {
const newIcon = {
...icon,
position: { ...icon.position, x: Number(value) },
};
handleChange(index, newIcon);
}}
/>
</div>
<Input
value={icon?.position?.x}
type="number"
placeholder={intl.formatMessage({
id: "iconsEditor.editor.customisation.positions.x",
})}
className="bg-dark-500 rounded px-2 py-2 text-sm text-white placeholder-dark-200"
onChange={(newX) => {
let x: number = Number(newX);
if (x > 100) x = 100;
const newIcon = {
...icon,
position: { ...icon.position, x: x },
};
handleChange(index, newIcon);
}}
/>
</div>
<div className="gap-4 w-full col-span-2 grid grid-cols-3">
<div className="flex items-center gap-3 col-span-2">
<p className="font-semibold uppercase text-dark-200 text-xs">
Y
</p>
<Range
value={icon?.position?.y ?? 0}
max={
icon?.custom_text?.enabled
? 1000
: icon?.position?.yPath ?? undefined
}
onChange={(value) => {
const newIcon = {
...icon,
position: { ...icon.position, y: Number(value) },
};
handleChange(index, newIcon);
}}
/>
</div>
<Input
value={icon?.position?.y}
type="number"
placeholder={intl.formatMessage({
id: "iconsEditor.editor.customisation.positions.y",
})}
className="bg-dark-500 rounded px-2 py-2 text-sm text-white placeholder-dark-200"
onChange={(newY) => {
let y = Number(newY);
if (y > 100) y = 100;
const newIcon = {
...icon,
position: { ...icon.position, y: y },
};
handleChange(index, newIcon);
}}
/>
</div>
<div className="gap-4 w-full col-span-2 grid grid-cols-3">
<div className="flex items-center gap-3 col-span-2">
<p className="font-semibold uppercase text-dark-200 text-xs">
Z
</p>
<Range
value={icon?.position?.angle ?? 0}
max={360}
onChange={(value) => {
const newIcon = {
...icon,
position: { ...icon.position, angle: Number(value) },
};
handleChange(index, newIcon);
}}
/>
</div>
<Input
value={icon?.position?.angle}
placeholder={intl.formatMessage({
id: "iconsEditor.editor.customisation.angle",
})}
type="number"
className="bg-dark-500 rounded px-2 py-2 text-sm text-white placeholder-dark-200"
onChange={(newAngle) => {
let angle = Number(newAngle);
if (angle > 360) angle = 360;
const newIcon = {
...icon,
position: { ...icon.position, angle: angle },
};
handleChange(index, newIcon);
}}
/>
</div>
{!icon?.custom_text?.enabled && (
<div className="gap-4 w-full col-span-2 grid grid-cols-3">
<div className="flex items-center gap-3 col-span-2">
<p className="font-semibold uppercase text-dark-200 text-xs">
<FormattedMessage id="iconsEditor.editor.customisation.scale" />
</p>
<Range
value={icon?.position?.scale ?? 1}
min={0}
max={2}
step={0.1}
onChange={(value) => {
const newIcon = {
...icon,
position: {
...icon.position,
scale: Number(value),
},
};
handleChange(index, newIcon);
}}
/>
</div>
<Input
value={
icon?.position?.scale
? icon?.position?.scale * 100
: undefined
}
type="number"
placeholder={intl.formatMessage({
id: "iconsEditor.editor.customisation.scale",
})}
className="bg-dark-500 rounded px-2 py-2 text-sm text-white placeholder-dark-200"
onChange={(newScale) => {
let scale = Number(newScale);
if (scale > 100) scale = 100;
const newIcon = {
...icon,
position: {
...icon.position,
scale: Math.trunc(scale) / 100,
},
};
handleChange(index, newIcon);
}}
/>
</div>
)}
</div>
</div>
{!icon?.image && (
<div className="col-span-2">
<Label className="!mb-2.5">
<FormattedMessage
id="iconsEditor.editor.customisation.gradientColor"
values={{
span: (t) => (
<span className="text-xs opacity-40">{t}</span>
),
}}
/>
</Label>
<ColorPicker
data={icon}
value={icon?.stringColor ?? icon?.colour}
onChange={(c: any, datas) => {
let newIcon = { ...icon, stringColor: c };
if (c.includes("gradient")) {
const { colors, degrees } = datas;
const gradientType = c?.startsWith("linear")
? "linearGradient"
: "radialGradient";
const angle = c?.startsWith("linear")
? c?.replace("linear-gradient(", "")?.split("deg")?.[0]
: 90;
newIcon["gradient"] = {
...newIcon.gradient,
enabled: true,
colours: colors,
angle,
type: gradientType,
};
} else {
newIcon = {
...newIcon,
colour: c,
gradient: {
...icon?.gradient,
enabled: false,
},
};
}
handleChange(index, newIcon);
}}
/>
</div>
)}
{icon?.custom_text?.enabled && (
<>
<div className="col-span-2">
<Label className="!mb-2.5">
<FormattedMessage id="iconsEditor.editor.customisation.customText" />
</Label>
<div className="grid grid-cols-2 gap-5">
<div>
<p className="font-semibold uppercase text-dark-200 text-xs mb-2">
<FormattedMessage id="iconsEditor.editor.customisation.customText.text" />
</p>
<input
type="text"
className="bg-dark-500 w-full rounded px-4 py-2 text-sm text-white placeholder-dark-200 outline-none border-none"
placeholder="10"
value={icon?.custom_text?.text}
onChange={({ target }) => {
const newIcon = {
...icon,
custom_text: {
...icon.custom_text,
text: target.value,
},
};
handleChange(index, newIcon);
}}
/>
</div>
<div>
<p className="font-semibold uppercase text-dark-200 text-xs mb-2">
<FormattedMessage id="iconsEditor.editor.customisation.customText.fontSize" />
</p>
<input
type="number"
className="bg-dark-500 w-full rounded px-4 py-2 text-sm text-white placeholder-dark-200 outline-none border-none"
placeholder="10"
value={icon?.custom_text?.size}
onChange={({ target }) => {
const newIcon = {
...icon,
custom_text: {
...icon.custom_text,
size: Number(target.value),
},
};
handleChange(index, newIcon);
}}
/>
</div>
</div>
</div>
</>
)}
<div className="relative col-span-2 grid grid-cols-2 gap-4">
{!icon?.image && (
<div>
<Label className="!mb-2.5">
<FormattedMessage id="iconsEditor.editor.customisation.border" />
</Label>
<div className="flex items-start justify-start gap-5">
<div className="w-full">
<p className="font-semibold uppercase text-dark-200 text-xs mb-2">
<FormattedMessage id="iconsEditor.editor.customisation.width" />
</p>
<input
type="number"
className="bg-dark-500 w-full rounded px-4 py-2 text-sm text-white placeholder-dark-200 outline-none border-none"
placeholder={
intl.formatMessage({
id: "iconsEditor.editor.customisation.width",
}) + "...px"
}
min={0}
value={icon?.border?.width}
onChange={({ target }) => {
const newIcon = {
...icon,
border: {
...icon.border,
width: target?.value
? Number(target.value)
: undefined,
},
};
handleChange(index, newIcon);
}}
/>
</div>
<div>
<p className="font-semibold uppercase text-dark-200 text-xs mb-2">
<FormattedMessage id="iconsEditor.editor.customisation.color" />
</p>
<ColorPicker
value={icon?.border?.colour}
gradients={false}
onChange={(c: any) => {
const newIcon = {
...icon,
border: {
...icon.border,
colour: c,
},
};
handleChange(index, newIcon);
}}
/>
</div>
</div>
</div>
)}
<div className="col-span-2">
<div className="flex items-center justify-start gap-3 mb-2.5 ">
<Label className="!mb-0">
<FormattedMessage id="iconsEditor.editor.customisation.shadow" />
</Label>
<Switch
value={icon?.shadow?.enabled}
onChange={(enabled: boolean) => {
const newIcon = {
...icon,
shadow: {
...icon.shadow,
enabled,
},
};
handleChange(index, newIcon);
}}
/>
</div>
{icon?.shadow?.enabled && (
<div className="gap-5 grid grid-cols-2">
<div className="w-full">
<p className="font-semibold uppercase text-dark-200 text-xs mb-2">
X
</p>
<input
type="number"
className="bg-dark-500 w-full rounded px-4 py-2 text-sm text-white placeholder-dark-200 outline-none border-none"
placeholder={intl.formatMessage({
id: "iconsEditor.editor.customisation.shadow.x.placeholder",
})}
min={0}
value={icon?.shadow?.position?.x}
onChange={({ target }) => {
const newIcon = {
...icon,
shadow: {
...icon.shadow,
position: {
...icon?.shadow?.position,
x: target?.value
? Number(target.value)
: undefined,
},
},
};
handleChange(index, newIcon);
}}
/>
</div>
<div className="w-full">
<p className="font-semibold uppercase text-dark-200 text-xs mb-2">
Y
</p>
<input
type="number"
className="bg-dark-500 w-full rounded px-4 py-2 text-sm text-white placeholder-dark-200 outline-none border-none"
placeholder={intl.formatMessage({
id: "iconsEditor.editor.customisation.shadow.y.placeholder",
})}
min={0}
value={icon?.shadow?.position?.y}
onChange={({ target }) => {
const newIcon = {
...icon,
shadow: {
...icon.shadow,
position: {
...icon?.shadow?.position,
y: target?.value
? Number(target.value)
: undefined,
},
},
};
handleChange(index, newIcon);
}}
/>
</div>
<div className="w-full">
<p className="font-semibold uppercase text-dark-200 text-xs mb-2">
<FormattedMessage id="iconsEditor.editor.customisation.shadow.blur" />
</p>
<input
type="number"
className="bg-dark-500 w-full rounded px-4 py-2 text-sm text-white placeholder-dark-200 outline-none border-none"
placeholder={intl.formatMessage({
id: "iconsEditor.editor.customisation.shadow.blur.placeholder",
})}
min={0}
value={icon?.shadow?.position?.blur}
onChange={({ target }) => {
const newIcon = {
...icon,
shadow: {
...icon.shadow,
position: {
...icon?.shadow?.position,
blur: target?.value
? Number(target.value)
: undefined,
},
},
};
handleChange(index, newIcon);
}}
/>
</div>
<div>
<p className="font-semibold uppercase text-dark-200 text-xs mb-2">
<FormattedMessage id="iconsEditor.editor.customisation.color" />
</p>
<ColorPicker
value={icon?.shadow?.colour}
gradients={false}
onChange={(c: any) => {
const newIcon = {
...icon,
shadow: {
...icon.shadow,
colour: c,
},
};
handleChange(index, newIcon);
}}
/>
</div>
</div>
)}
</div>
</div>
</div>
)}
</div>
{totalIcons > 1 && (
<div className="flex flex-col gap-0.5">
{index !== 0 && (
<FontAwesomeIcon
icon={faCaretUp}
className="text-dark-200 cursor-pointer hover:text-white w-3"
onClick={() => onChangeOrder(index, index - 1)}
/>
)}
{index !== totalIcons - 1 && (
<FontAwesomeIcon
icon={faCaretDown}
className="text-dark-200 cursor-pointer hover:text-white w-3"
onClick={() => onChangeOrder(index, index + 1)}
/>
)}
</div>
)}
</div>
);
};