fix ccolor one page
This commit is contained in:
@@ -32,6 +32,8 @@ const EditorCanvas = ({ catalogSize }: EditorCanvasProps) => {
|
||||
tool,
|
||||
objects,
|
||||
guides,
|
||||
pages,
|
||||
currentPageId,
|
||||
selectedObjectId,
|
||||
selectedObjectIds,
|
||||
selectedCellId,
|
||||
@@ -40,17 +42,17 @@ const EditorCanvas = ({ catalogSize }: EditorCanvasProps) => {
|
||||
setLayerRef,
|
||||
setGuides,
|
||||
zoom,
|
||||
documentSettings,
|
||||
} = useEditorStore();
|
||||
const currentPage = pages.find((page) => page.id === currentPageId);
|
||||
|
||||
const bgColor =
|
||||
documentSettings.backgroundType === 'color'
|
||||
? documentSettings.backgroundColor
|
||||
currentPage?.backgroundType === 'color'
|
||||
? currentPage.backgroundColor
|
||||
: '#ffffff';
|
||||
|
||||
const [bgImage] = useImage(
|
||||
documentSettings.backgroundType === 'image'
|
||||
? documentSettings.backgroundImageUrl
|
||||
currentPage?.backgroundType === 'image'
|
||||
? (currentPage.backgroundImageUrl || '')
|
||||
: '',
|
||||
);
|
||||
const stageSize = useStageSize(catalogSize);
|
||||
@@ -394,7 +396,7 @@ const EditorCanvas = ({ catalogSize }: EditorCanvasProps) => {
|
||||
fill={bgColor}
|
||||
listening={false}
|
||||
/>
|
||||
{documentSettings.backgroundType === 'image' && bgImage && (
|
||||
{currentPage?.backgroundType === 'image' && bgImage && (
|
||||
<KonvaImage
|
||||
image={bgImage}
|
||||
x={0}
|
||||
|
||||
@@ -27,11 +27,21 @@ const BACKGROUND_TYPE_OPTIONS: { value: BackgroundType; label: string }[] = [
|
||||
]
|
||||
|
||||
const SettingsPanel = () => {
|
||||
const { documentSettings, updateDocumentSettings } = useEditorStore()
|
||||
const {
|
||||
documentSettings,
|
||||
pages,
|
||||
currentPageId,
|
||||
updateDocumentSettings,
|
||||
updateCurrentPageBackground,
|
||||
} = useEditorStore()
|
||||
const colorInputRef = useRef<HTMLInputElement>(null)
|
||||
const { mutateAsync: uploadFile, isPending: imageLoading } = useSingleUpload()
|
||||
const currentPage = pages.find((page) => page.id === currentPageId)
|
||||
const backgroundType = currentPage?.backgroundType ?? 'color'
|
||||
const backgroundColor = currentPage?.backgroundColor ?? '#ffffff'
|
||||
const backgroundImageUrl = currentPage?.backgroundImageUrl ?? ''
|
||||
const [uploadedPreviews, setUploadedPreviews] = useState<string[]>(
|
||||
documentSettings.backgroundImageUrl ? [documentSettings.backgroundImageUrl] : []
|
||||
backgroundImageUrl ? [backgroundImageUrl] : []
|
||||
)
|
||||
|
||||
const {
|
||||
@@ -39,15 +49,13 @@ const SettingsPanel = () => {
|
||||
autoPlay,
|
||||
pageFlipSound,
|
||||
leftToRightFlip,
|
||||
backgroundType,
|
||||
backgroundColor,
|
||||
} = documentSettings
|
||||
|
||||
useEffect(() => {
|
||||
setUploadedPreviews(
|
||||
documentSettings.backgroundImageUrl ? [documentSettings.backgroundImageUrl] : []
|
||||
backgroundImageUrl ? [backgroundImageUrl] : []
|
||||
)
|
||||
}, [documentSettings.backgroundImageUrl])
|
||||
}, [backgroundImageUrl])
|
||||
|
||||
const handleImageFiles = async (files: File[]) => {
|
||||
if (files.length === 0) return
|
||||
@@ -59,7 +67,7 @@ const SettingsPanel = () => {
|
||||
const imageUrl = result?.data?.url
|
||||
if (!imageUrl) return
|
||||
|
||||
updateDocumentSettings({ backgroundImageUrl: imageUrl })
|
||||
updateCurrentPageBackground({ backgroundImageUrl: imageUrl })
|
||||
setUploadedPreviews([imageUrl])
|
||||
} catch {
|
||||
// TODO: show error toast
|
||||
@@ -69,7 +77,7 @@ const SettingsPanel = () => {
|
||||
const handlePreviewChange = (previews: string[]) => {
|
||||
setUploadedPreviews(previews)
|
||||
if (previews.length === 0) {
|
||||
updateDocumentSettings({ backgroundImageUrl: '' })
|
||||
updateCurrentPageBackground({ backgroundImageUrl: '' })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +145,7 @@ const SettingsPanel = () => {
|
||||
<label key={opt.value} className="flex items-center gap-1.5 cursor-pointer select-none">
|
||||
<span className="text-xs text-gray-600">{opt.label}</span>
|
||||
<div
|
||||
onClick={() => updateDocumentSettings({ backgroundType: opt.value })}
|
||||
onClick={() => updateCurrentPageBackground({ backgroundType: opt.value })}
|
||||
className={clx(
|
||||
'w-4 h-4 rounded-full border-2 flex items-center justify-center transition-colors cursor-pointer',
|
||||
backgroundType === opt.value
|
||||
@@ -161,7 +169,7 @@ const SettingsPanel = () => {
|
||||
{PRESET_COLORS.map((color) => (
|
||||
<button
|
||||
key={color}
|
||||
onClick={() => updateDocumentSettings({ backgroundColor: color })}
|
||||
onClick={() => updateCurrentPageBackground({ backgroundColor: color })}
|
||||
className={clx(
|
||||
'w-9 h-9 rounded-xl border-2 transition-all',
|
||||
backgroundColor === color
|
||||
@@ -184,7 +192,7 @@ const SettingsPanel = () => {
|
||||
ref={colorInputRef}
|
||||
type="color"
|
||||
value={backgroundColor}
|
||||
onChange={(e) => updateDocumentSettings({ backgroundColor: e.target.value })}
|
||||
onChange={(e) => updateCurrentPageBackground({ backgroundColor: e.target.value })}
|
||||
className="absolute inset-0 opacity-0 w-full h-full cursor-pointer"
|
||||
/>
|
||||
</button>
|
||||
|
||||
@@ -78,7 +78,6 @@ export const useDrawingHandlers = () => {
|
||||
opacity: defaults.opacity,
|
||||
letterSpacing: defaults.letterSpacing,
|
||||
wordSpacing: defaults.wordSpacing,
|
||||
width: 150,
|
||||
height: defaults.fontSize || 24,
|
||||
};
|
||||
useEditorStore.getState().commitObjectHistoryBeforeChange();
|
||||
|
||||
@@ -84,21 +84,25 @@ const TextShape = ({
|
||||
|
||||
textNode._setTextData();
|
||||
|
||||
const { width: rw, height: rh } = textNode.getClientRect({
|
||||
// اندازهگیری طبیعی متن (بدون width تحمیلی) تا باکس واقعاً دور متن فیت شود.
|
||||
const measureNode = textNode.clone({
|
||||
width: undefined,
|
||||
x: 0,
|
||||
y: 0,
|
||||
});
|
||||
measureNode._setTextData();
|
||||
const { width: rw, height: rh } = measureNode.getClientRect({
|
||||
skipTransform: true,
|
||||
});
|
||||
const measuredWidth = Math.ceil(rw);
|
||||
const h = Math.ceil(rh);
|
||||
const nextWidth = obj.width && obj.width > 0 ? obj.width : measuredWidth;
|
||||
measureNode.destroy();
|
||||
|
||||
// For text alignment to be visible, keep an existing text box width
|
||||
// and only auto-calc width when the object has no width yet.
|
||||
if (
|
||||
nextWidth > 0 &&
|
||||
h > 0 &&
|
||||
(nextWidth !== obj.width || h !== obj.height)
|
||||
) {
|
||||
onUpdate(obj.id, { width: nextWidth, height: h });
|
||||
const nextWidth = Math.max(1, Math.ceil(rw));
|
||||
const nextHeight = Math.max(1, Math.ceil(rh));
|
||||
const widthChanged = Math.abs((obj.width || 0) - nextWidth) > 1;
|
||||
const heightChanged = Math.abs((obj.height || 0) - nextHeight) > 1;
|
||||
|
||||
if (widthChanged || heightChanged) {
|
||||
onUpdate(obj.id, { width: nextWidth, height: nextHeight });
|
||||
}
|
||||
textNode.getLayer()?.batchDraw();
|
||||
};
|
||||
|
||||
@@ -53,6 +53,9 @@ export const createInitialPage = (name: string): Page => ({
|
||||
name,
|
||||
objects: [],
|
||||
guides: [],
|
||||
backgroundType: "color",
|
||||
backgroundColor: "#ffffff",
|
||||
backgroundImageUrl: "",
|
||||
});
|
||||
|
||||
export const reorderByIds = (
|
||||
|
||||
@@ -44,6 +44,11 @@ export type {
|
||||
BackgroundType,
|
||||
} from "./editorStore.types";
|
||||
|
||||
type PageBackgroundSettings = Pick<
|
||||
Page,
|
||||
"backgroundType" | "backgroundColor" | "backgroundImageUrl"
|
||||
>;
|
||||
|
||||
type EditorStoreType = {
|
||||
tool: ToolType;
|
||||
setTool: (tool: ToolType) => void;
|
||||
@@ -134,6 +139,7 @@ type EditorStoreType = {
|
||||
sendObjectBackward: (id: string) => void;
|
||||
documentSettings: DocumentSettings;
|
||||
updateDocumentSettings: (updates: Partial<DocumentSettings>) => void;
|
||||
updateCurrentPageBackground: (updates: Partial<PageBackgroundSettings>) => void;
|
||||
};
|
||||
|
||||
export const useEditorStore = create<EditorStoreType>((set, get) => {
|
||||
@@ -191,6 +197,18 @@ export const useEditorStore = create<EditorStoreType>((set, get) => {
|
||||
set((state) => ({
|
||||
documentSettings: { ...state.documentSettings, ...updates },
|
||||
})),
|
||||
updateCurrentPageBackground: (updates) =>
|
||||
set((state) => {
|
||||
if (!state.currentPageId) return {};
|
||||
const currentPage = state.pages.find((p) => p.id === state.currentPageId);
|
||||
if (!currentPage) return {};
|
||||
const nextPage = { ...currentPage, ...updates };
|
||||
return {
|
||||
pages: state.pages.map((p) =>
|
||||
p.id === state.currentPageId ? nextPage : p,
|
||||
),
|
||||
};
|
||||
}),
|
||||
tool: "select",
|
||||
setTool: (tool) =>
|
||||
set((state) => ({
|
||||
@@ -816,6 +834,9 @@ export const useEditorStore = create<EditorStoreType>((set, get) => {
|
||||
name: `${pageToDuplicate.name} (کپی)`,
|
||||
objects: duplicatedObjects,
|
||||
guides: [...pageToDuplicate.guides],
|
||||
backgroundType: pageToDuplicate.backgroundType,
|
||||
backgroundColor: pageToDuplicate.backgroundColor,
|
||||
backgroundImageUrl: pageToDuplicate.backgroundImageUrl,
|
||||
};
|
||||
|
||||
set((state) => ({
|
||||
@@ -978,11 +999,18 @@ export const useEditorStore = create<EditorStoreType>((set, get) => {
|
||||
},
|
||||
loadPages: (pages, documentSettings) => {
|
||||
if (pages.length === 0) return;
|
||||
const fallbackSettings = documentSettings ?? {};
|
||||
const normalizedPages = pages.map((page) => ({
|
||||
...page,
|
||||
id: isInvalidPageId(page.id) ? createScopedId("page") : page.id,
|
||||
guides: page.guides || [],
|
||||
objects: ensureMissingGroupObjects(page.objects || []),
|
||||
backgroundType:
|
||||
page.backgroundType ?? fallbackSettings.backgroundType ?? "color",
|
||||
backgroundColor:
|
||||
page.backgroundColor ?? fallbackSettings.backgroundColor ?? "#ffffff",
|
||||
backgroundImageUrl:
|
||||
page.backgroundImageUrl ?? fallbackSettings.backgroundImageUrl ?? "",
|
||||
}));
|
||||
const firstPage = normalizedPages[0];
|
||||
const currentSettings = get().documentSettings;
|
||||
|
||||
@@ -80,6 +80,9 @@ export type Page = {
|
||||
name: string;
|
||||
objects: EditorObject[];
|
||||
guides: PageGuide[];
|
||||
backgroundType: BackgroundType;
|
||||
backgroundColor: string;
|
||||
backgroundImageUrl: string;
|
||||
};
|
||||
|
||||
export type DisplayStyle = 'single' | 'double';
|
||||
|
||||
Reference in New Issue
Block a user