153 lines
4.1 KiB
TypeScript
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; |