@@ -4,17 +4,15 @@ import Select from "@/components/Select";
|
||||
import ColorPicker from "@/components/ColorPicker";
|
||||
import { useEditorStore } from "@/pages/editor/store/editorStore";
|
||||
import { useTextDefaultsStore } from "@/pages/editor/store/textDefaultsStore";
|
||||
import {
|
||||
getDefaultFontWeight,
|
||||
getFontFamilyOptions,
|
||||
getFontWeightOptions,
|
||||
hasMultipleFontWeights,
|
||||
} from "@/pages/editor/utils/fonts";
|
||||
import { getFontFamily } from "@/pages/editor/utils/fontFamily";
|
||||
|
||||
const fontOptions = [
|
||||
{ label: "ایرانسل", value: "1" },
|
||||
{ label: "فونت 2", value: "2" },
|
||||
];
|
||||
|
||||
const fontWeightOptions = [
|
||||
{ label: "Bold", value: "bold" },
|
||||
{ label: "Normal", value: "normal" },
|
||||
{ label: "Light", value: "300" },
|
||||
];
|
||||
const fontOptions = getFontFamilyOptions();
|
||||
|
||||
|
||||
type TextFormState = {
|
||||
@@ -55,11 +53,45 @@ const TextInstruction: FC = () => {
|
||||
|
||||
const [formState, setFormState] = useState<TextFormState>(baseValues);
|
||||
|
||||
const fontWeightOptions = useMemo(
|
||||
() => getFontWeightOptions(formState.fontFamily),
|
||||
[formState.fontFamily],
|
||||
);
|
||||
|
||||
const selectedFontFamily = useMemo(
|
||||
() => getFontFamily(formState.fontFamily),
|
||||
[formState.fontFamily],
|
||||
);
|
||||
|
||||
const showWeightSelect = hasMultipleFontWeights(formState.fontFamily);
|
||||
|
||||
useEffect(() => {
|
||||
setFormState(baseValues);
|
||||
}, [baseValues]);
|
||||
|
||||
const handleChange = (field: keyof TextFormState, value: string | number) => {
|
||||
if (field === "fontFamily") {
|
||||
const nextFontId = String(value);
|
||||
const nextWeightOptions = getFontWeightOptions(nextFontId);
|
||||
const nextWeight = nextWeightOptions.some((w) => w.value === formState.fontWeight)
|
||||
? formState.fontWeight
|
||||
: getDefaultFontWeight(nextFontId);
|
||||
|
||||
if (isEditing && selectedObject) {
|
||||
const newState = { ...formState, fontFamily: nextFontId, fontWeight: nextWeight };
|
||||
setFormState(newState);
|
||||
useEditorStore.getState().commitObjectHistoryBeforeChange();
|
||||
updateObject(selectedObject.id, {
|
||||
fontFamily: nextFontId,
|
||||
fontWeight: nextWeight,
|
||||
});
|
||||
} else {
|
||||
setFormState((prev) => ({ ...prev, fontFamily: nextFontId, fontWeight: nextWeight }));
|
||||
updateDefaults({ fontFamily: nextFontId, fontWeight: nextWeight });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEditing && selectedObject) {
|
||||
// اعمال تغییرات به صورت لایو
|
||||
const newState = { ...formState, [field]: value };
|
||||
@@ -105,20 +137,24 @@ const TextInstruction: FC = () => {
|
||||
label="فونت"
|
||||
value={formState.fontFamily}
|
||||
onChange={(e) => handleChange("fontFamily", e.target.value)}
|
||||
style={{ fontFamily: selectedFontFamily }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 mt-4">
|
||||
<Select
|
||||
label="وزن"
|
||||
items={fontWeightOptions}
|
||||
value={formState.fontWeight}
|
||||
onChange={(e) => handleChange("fontWeight", e.target.value)}
|
||||
/>
|
||||
{showWeightSelect && (
|
||||
<Select
|
||||
label="وزن"
|
||||
items={fontWeightOptions}
|
||||
value={formState.fontWeight}
|
||||
onChange={(e) => handleChange("fontWeight", e.target.value)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Input
|
||||
type="number"
|
||||
label="سایز"
|
||||
className={showWeightSelect ? "" : "flex-1"}
|
||||
value={Math.round(formState.fontSize)}
|
||||
onChange={(e) => {
|
||||
const numValue = parseInt(e.target.value) || 0;
|
||||
|
||||
@@ -17,8 +17,8 @@ type TextDefaultsStoreType = {
|
||||
|
||||
export const useTextDefaultsStore = create<TextDefaultsStoreType>((set) => ({
|
||||
defaults: {
|
||||
fontFamily: "1",
|
||||
fontWeight: "bold",
|
||||
fontFamily: "irancell",
|
||||
fontWeight: "600",
|
||||
fontSize: 16,
|
||||
fill: "#000000",
|
||||
opacity: 100,
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
const FONT_FAMILY_MAP: Record<string, string> = {
|
||||
"1": "irancell",
|
||||
"2": "irancell",
|
||||
};
|
||||
import { getEditorFont } from "@/pages/editor/utils/fonts";
|
||||
|
||||
/** Maps editor font option ids to CSS font-family names. */
|
||||
/** Maps editor font ids to CSS font-family names. */
|
||||
export const getFontFamily = (fontFamily?: string): string => {
|
||||
return FONT_FAMILY_MAP[fontFamily || "1"] || fontFamily || "irancell";
|
||||
const font = getEditorFont(fontFamily);
|
||||
return font?.cssFamily ?? fontFamily ?? "editor-irancell";
|
||||
};
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import fontsCatalog from "@/assets/fonts/irancell/fonts-editor/fonts.json";
|
||||
|
||||
export type FontWeightOption = {
|
||||
value: string;
|
||||
label: string;
|
||||
};
|
||||
|
||||
export type EditorFont = {
|
||||
id: string;
|
||||
label: string;
|
||||
cssFamily: string;
|
||||
category: "persian" | "english";
|
||||
defaultWeight: string;
|
||||
weights: FontWeightOption[];
|
||||
};
|
||||
|
||||
const LEGACY_FONT_ID_MAP: Record<string, string> = {
|
||||
"1": "irancell",
|
||||
"2": "irancell",
|
||||
byekan: "yekan",
|
||||
bzarbd: "bzar",
|
||||
"bkoodak-bold": "bkoodak",
|
||||
};
|
||||
|
||||
const fonts = fontsCatalog.fonts as EditorFont[];
|
||||
const fontById = new Map(fonts.map((font) => [font.id, font]));
|
||||
|
||||
export const EDITOR_FONTS = fonts;
|
||||
|
||||
export const getEditorFont = (fontId?: string): EditorFont | undefined => {
|
||||
const normalizedId = LEGACY_FONT_ID_MAP[fontId || ""] || fontId;
|
||||
return fontById.get(normalizedId || "irancell") ?? fontById.get("irancell");
|
||||
};
|
||||
|
||||
export const getFontFamilyOptions = () =>
|
||||
fonts.map((font) => ({
|
||||
label: font.label,
|
||||
value: font.id,
|
||||
}));
|
||||
|
||||
export const getFontWeightOptions = (fontId?: string): FontWeightOption[] => {
|
||||
const font = getEditorFont(fontId);
|
||||
return font?.weights ?? [{ value: "400", label: "Regular" }];
|
||||
};
|
||||
|
||||
export const getDefaultFontWeight = (fontId?: string): string => {
|
||||
const font = getEditorFont(fontId);
|
||||
return font?.defaultWeight ?? "400";
|
||||
};
|
||||
|
||||
export const hasMultipleFontWeights = (fontId?: string): boolean =>
|
||||
getFontWeightOptions(fontId).length > 1;
|
||||
@@ -1,18 +1,14 @@
|
||||
import { getFontFamily } from "@/pages/editor/utils/fontFamily";
|
||||
|
||||
/** CSS font-weight values that match irancell @font-face declarations. */
|
||||
/** CSS font-weight values for canvas/Konva text rendering. */
|
||||
export const getCssFontWeight = (fontWeight?: string): number => {
|
||||
if (!fontWeight || fontWeight === "normal") return 300;
|
||||
if (fontWeight === "bold" || fontWeight === "bolder") return 600;
|
||||
if (!fontWeight || fontWeight === "normal") return 400;
|
||||
if (fontWeight === "bold" || fontWeight === "bolder") return 700;
|
||||
|
||||
const n = parseInt(fontWeight, 10);
|
||||
if (!Number.isNaN(n)) {
|
||||
if (n >= 600) return 600;
|
||||
if (n <= 200) return 200;
|
||||
return 300;
|
||||
}
|
||||
if (!Number.isNaN(n)) return n;
|
||||
|
||||
return 300;
|
||||
return 400;
|
||||
};
|
||||
|
||||
/** Konva.Text uses `fontStyle: bold` (canvas keyword), not numeric weight. */
|
||||
|
||||
Reference in New Issue
Block a user