Optimize AlignmentButtons component with improved documentation, code structure, and performance

This commit is contained in:
2025-03-22 19:37:54 +01:00
parent 9bb1bf2cdb
commit b76b34a332
+135 -149
View File
@@ -1,3 +1,10 @@
/**
* @file AlignmentButtons.tsx
* @description Component that provides functionality to align selected shapes
* in PowerPoint presentations. Supports horizontal alignment (left, center, right)
* and vertical alignment (top, middle, bottom).
*/
import * as React from "react";
import {
Button,
@@ -14,6 +21,35 @@ import {
import { useStatusContext } from "./App";
import { useCommonStyles } from "./commonStyles";
/**
* Configuration constants for alignment positions
*/
const ALIGNMENT_CONFIG = {
// Horizontal alignment positions
HORIZONTAL: {
LEFT: 81.1,
CENTER: 480, // Center point of slide
RIGHT: 879.75
},
// Vertical alignment positions
VERTICAL: {
TOP: 136.75,
MIDDLE: 321, // Middle point of slide
BOTTOM: 505.25
},
// Warning message when no shapes are selected
NO_SELECTION_WARNING: "No shapes are selected. Please select shapes first."
};
/**
* Alignment types for horizontal and vertical alignment
*/
type HorizontalAlignmentType = 'left' | 'center' | 'right';
type VerticalAlignmentType = 'top' | 'middle' | 'bottom';
/**
* Component-specific styles
*/
const useStyles = makeStyles({
alignmentGrid: {
display: "grid",
@@ -31,16 +67,41 @@ const useStyles = makeStyles({
}
});
/**
* AlignmentButtons component provides UI and functionality to align
* selected shapes in PowerPoint presentations.
*
* @returns React component
*/
export const AlignmentButtons: React.FC = () => {
const styles = useStyles();
const commonStyles = useCommonStyles();
const {
statusMessage, setStatusMessage,
statusType, setStatusType,
isProcessing, setIsProcessing
setStatusMessage,
setStatusType,
isProcessing,
setIsProcessing
} = useStatusContext();
const alignLeft = async () => {
/**
* Handles errors and updates the status message
*
* @param error - The error object
* @param operation - The operation being performed (for logging)
*/
const handleError = (error: any, operation: string): void => {
setStatusMessage(`Error: ${error.message || "Unknown error occurred"}`);
setStatusType("error");
console.error(`${operation} error:`, error);
setIsProcessing(false);
};
/**
* Generic function to handle horizontal alignment of shapes
*
* @param alignmentType - The type of horizontal alignment to apply
*/
const handleHorizontalAlignment = async (alignmentType: HorizontalAlignmentType): Promise<void> => {
setIsProcessing(true);
try {
await PowerPoint.run(async (context) => {
@@ -51,31 +112,45 @@ export const AlignmentButtons: React.FC = () => {
// Check if shapes are selected
if (shapes.items.length === 0) {
setStatusMessage("No shapes are selected. Please select shapes first.");
setStatusMessage(ALIGNMENT_CONFIG.NO_SELECTION_WARNING);
setStatusType("warning");
return;
}
// Set alignment for all shapes at once
// Set alignment for all shapes at once based on alignment type
shapes.items.forEach(shape => {
shape.left = 81.1;
switch (alignmentType) {
case 'left':
shape.left = ALIGNMENT_CONFIG.HORIZONTAL.LEFT;
break;
case 'center':
shape.left = ALIGNMENT_CONFIG.HORIZONTAL.CENTER - (shape.width / 2);
break;
case 'right':
shape.left = ALIGNMENT_CONFIG.HORIZONTAL.RIGHT - shape.width;
break;
}
});
// Single sync after all updates
await context.sync();
setStatusMessage("Objects aligned to left.");
setStatusMessage(`Objects aligned to ${alignmentType}.`);
setStatusType("success");
});
} catch (error) {
setStatusMessage(`Error: ${error.message}`);
setStatusType("error");
console.error("Align left error:", error);
handleError(error, `Align ${alignmentType}`);
} finally {
setIsProcessing(false);
}
};
const alignCenter = async () => {
/**
* Generic function to handle vertical alignment of shapes
*
* @param alignmentType - The type of vertical alignment to apply
*/
const handleVerticalAlignment = async (alignmentType: VerticalAlignmentType): Promise<void> => {
setIsProcessing(true);
try {
await PowerPoint.run(async (context) => {
@@ -86,168 +161,79 @@ export const AlignmentButtons: React.FC = () => {
// Check if shapes are selected
if (shapes.items.length === 0) {
setStatusMessage("No shapes are selected. Please select shapes first.");
setStatusMessage(ALIGNMENT_CONFIG.NO_SELECTION_WARNING);
setStatusType("warning");
return;
}
// Set alignment for all shapes at once
// Set alignment for all shapes at once based on alignment type
shapes.items.forEach(shape => {
shape.left = 480 - (shape.width / 2);
switch (alignmentType) {
case 'top':
shape.top = ALIGNMENT_CONFIG.VERTICAL.TOP;
break;
case 'middle':
shape.top = ALIGNMENT_CONFIG.VERTICAL.MIDDLE - (shape.height / 2);
break;
case 'bottom':
shape.top = ALIGNMENT_CONFIG.VERTICAL.BOTTOM - shape.height;
break;
}
});
// Single sync after all updates
await context.sync();
setStatusMessage("Objects aligned to center.");
setStatusMessage(`Objects aligned to ${alignmentType}.`);
setStatusType("success");
});
} catch (error) {
setStatusMessage(`Error: ${error.message}`);
setStatusType("error");
console.error("Align center error:", error);
handleError(error, `Align ${alignmentType}`);
} finally {
setIsProcessing(false);
}
};
const alignRight = async () => {
setIsProcessing(true);
try {
await PowerPoint.run(async (context) => {
// Get the selected shapes
const shapes = context.presentation.getSelectedShapes();
shapes.load("items");
await context.sync();
// Check if shapes are selected
if (shapes.items.length === 0) {
setStatusMessage("No shapes are selected. Please select shapes first.");
setStatusType("warning");
return;
}
// Set alignment for all shapes at once
shapes.items.forEach(shape => {
shape.left = 879.75 - shape.width;
});
// Single sync after all updates
await context.sync();
setStatusMessage("Objects aligned to right.");
setStatusType("success");
});
} catch (error) {
setStatusMessage(`Error: ${error.message}`);
setStatusType("error");
console.error("Align right error:", error);
} finally {
setIsProcessing(false);
}
/**
* Aligns selected shapes to the left edge of the slide
*/
const alignLeft = async (): Promise<void> => {
await handleHorizontalAlignment('left');
};
const alignTop = async () => {
setIsProcessing(true);
try {
await PowerPoint.run(async (context) => {
// Get the selected shapes
const shapes = context.presentation.getSelectedShapes();
shapes.load("items");
await context.sync();
// Check if shapes are selected
if (shapes.items.length === 0) {
setStatusMessage("No shapes are selected. Please select shapes first.");
setStatusType("warning");
return;
}
// Set alignment for all shapes at once
shapes.items.forEach(shape => {
shape.top = 136.75;
});
// Single sync after all updates
await context.sync();
setStatusMessage("Objects aligned to top.");
setStatusType("success");
});
} catch (error) {
setStatusMessage(`Error: ${error.message}`);
setStatusType("error");
console.error("Align top error:", error);
} finally {
setIsProcessing(false);
}
/**
* Aligns selected shapes to the horizontal center of the slide
*/
const alignCenter = async (): Promise<void> => {
await handleHorizontalAlignment('center');
};
const alignMiddle = async () => {
setIsProcessing(true);
try {
await PowerPoint.run(async (context) => {
// Get the selected shapes
const shapes = context.presentation.getSelectedShapes();
shapes.load("items");
await context.sync();
// Check if shapes are selected
if (shapes.items.length === 0) {
setStatusMessage("No shapes are selected. Please select shapes first.");
setStatusType("warning");
return;
}
// Set alignment for all shapes at once
shapes.items.forEach(shape => {
shape.top = 321 - (shape.height / 2);
});
// Single sync after all updates
await context.sync();
setStatusMessage("Objects aligned to middle.");
setStatusType("success");
});
} catch (error) {
setStatusMessage(`Error: ${error.message}`);
setStatusType("error");
console.error("Align middle error:", error);
} finally {
setIsProcessing(false);
}
/**
* Aligns selected shapes to the right edge of the slide
*/
const alignRight = async (): Promise<void> => {
await handleHorizontalAlignment('right');
};
const alignBottom = async () => {
setIsProcessing(true);
try {
await PowerPoint.run(async (context) => {
// Get the selected shapes
const shapes = context.presentation.getSelectedShapes();
shapes.load("items");
await context.sync();
/**
* Aligns selected shapes to the top edge of the slide
*/
const alignTop = async (): Promise<void> => {
await handleVerticalAlignment('top');
};
// Check if shapes are selected
if (shapes.items.length === 0) {
setStatusMessage("No shapes are selected. Please select shapes first.");
setStatusType("warning");
return;
}
/**
* Aligns selected shapes to the vertical middle of the slide
*/
const alignMiddle = async (): Promise<void> => {
await handleVerticalAlignment('middle');
};
// Set alignment for all shapes at once
shapes.items.forEach(shape => {
shape.top = 505.25 - shape.height;
});
// Single sync after all updates
await context.sync();
setStatusMessage("Objects aligned to bottom.");
setStatusType("success");
});
} catch (error) {
setStatusMessage(`Error: ${error.message}`);
setStatusType("error");
console.error("Align bottom error:", error);
} finally {
setIsProcessing(false);
}
/**
* Aligns selected shapes to the bottom edge of the slide
*/
const alignBottom = async (): Promise<void> => {
await handleVerticalAlignment('bottom');
};
return (