Files
powerpoint-toolbox/src/taskpane/components/RoundImage.tsx
T

153 lines
4.1 KiB
TypeScript

import * as React from "react";
import {
Button,
makeStyles,
tokens
} from "@fluentui/react-components";
import {
CircleRegular
} from "@fluentui/react-icons";
import { useStatusContext } from "./App";
const useStyles = makeStyles({
container: {
display: "flex",
flexDirection: "column",
width: "100%",
},
buttonGroup: {
display: "flex",
flexDirection: "column",
gap: "8px",
marginBottom: "2px",
},
actionButton: {
justifyContent: "flex-start",
transitionProperty: "all",
transitionDuration: "200ms",
transitionTimingFunction: "cubic-bezier(0.33, 0, 0.67, 1)",
},
statusContainer: {
marginTop: "4px",
padding: "8px 12px",
fontSize: "13px",
borderRadius: "6px",
backgroundColor: "#f3f2f1", // Light gray background
transition: "all 0.3s ease",
},
successStatus: {
backgroundColor: "#DFF6DD", // Light green background
color: "#107C10", // Green text
},
warningStatus: {
backgroundColor: "#FFF4CE", // Light yellow background
color: "#797673", // Dark gray text
},
errorStatus: {
backgroundColor: "#FDE7E9", // Light red background
color: "#A80000", // Red text
},
statusIcon: {
marginRight: "8px",
},
statusText: {
display: "flex",
alignItems: "center",
},
});
export const RoundImage: React.FC = () => {
const styles = useStyles();
const {
statusMessage, setStatusMessage,
statusType, setStatusType,
isProcessing, setIsProcessing
} = useStatusContext();
const convertToRoundImage = async () => {
setIsProcessing(true);
try {
await PowerPoint.run(async (context) => {
// Get the selected shapes
const shapes = context.presentation.getSelectedShapes();
shapes.load("items");
await context.sync();
if (shapes.items.length === 0) {
setStatusMessage("No shapes are selected. Please select an image.");
setStatusType("warning");
return;
}
// Get the first selected shape
const shape = shapes.items[0];
// Load essential properties
shape.load(["type"]);
await context.sync();
// Ensure the shape is a picture
if (shape.type !== PowerPoint.ShapeType.image) {
setStatusMessage("Please select an image.");
setStatusType("warning");
return;
}
// Load current dimensions to maintain aspect ratio
shape.load(["width", "height", "left", "top", "id"]);
await context.sync();
// Store current dimensions
const width = shape.width;
const height = shape.height;
const slide = context.presentation.getSelectedSlides().getItemAt(0);
const maskShape = slide.shapes.addGeometricShape("Ellipse" as any);
maskShape.load(["width", "height", "left", "top", "id"]);
await context.sync();
maskShape.left = shape.left;
maskShape.top = shape.top + 1; // TODO: Why + 1
maskShape.width = shape.width;
maskShape.height = shape.height;
maskShape.fill.setSolidColor("red");
maskShape.lineFormat.visible = false;
setStatusMessage("Created mask shape. Please select both the image and the oval, then use the 'Merge Shapes > Intersect' command in PowerPoint.");
setStatusType("warning");
slide.setSelectedShapes([shape.id, maskShape.id]);
// Ensure we maintain the same size
shape.width = width;
shape.height = height;
await context.sync();
});
} catch (error) {
setStatusMessage(`Error: ${error.message}`);
setStatusType("error");
console.error("Main error:", error);
} finally {
setIsProcessing(false);
}
};
return (
<div className={styles.container}>
<div className={styles.buttonGroup}>
<Button
appearance="primary"
className={styles.actionButton}
onClick={convertToRoundImage}
icon={<CircleRegular />}
disabled={isProcessing}
>
Round Image
</Button>
</div>
</div>
);
};
export default RoundImage;