diff --git a/src/taskpane/components/ConfidentialButtons.tsx b/src/taskpane/components/ConfidentialButtons.tsx
new file mode 100644
index 00000000..748dc747
--- /dev/null
+++ b/src/taskpane/components/ConfidentialButtons.tsx
@@ -0,0 +1,277 @@
+import * as React from "react";
+import {
+ Button,
+ makeStyles
+} from "@fluentui/react-components";
+import {
+ ShieldLockRegular,
+ DismissRegular
+} from "@fluentui/react-icons";
+import { useStatusContext } from "./App";
+import { useCommonStyles } from "./commonStyles";
+
+const useStyles = makeStyles({
+ buttonGrid: {
+ display: "grid",
+ gridTemplateColumns: "repeat(2, 1fr)",
+ gap: "8px",
+ width: "100%"
+ },
+ confidentialButton: {
+ width: "100%",
+ minWidth: 0,
+ padding: "8px 4px",
+ "& span": {
+ justifyContent: "center"
+ }
+ }
+});
+
+export const ConfidentialButtons: React.FC = () => {
+ const styles = useStyles();
+ const commonStyles = useCommonStyles();
+ const {
+ statusMessage, setStatusMessage,
+ statusType, setStatusType,
+ isProcessing, setIsProcessing
+ } = useStatusContext();
+
+ const addConfidentialMarking = async () => {
+ setIsProcessing(true);
+ try {
+ await PowerPoint.run(async (context) => {
+ try {
+ // Get all slides in the presentation
+ const slides = context.presentation.slides;
+ slides.load("items");
+ await context.sync();
+
+ // Get a reference slide to determine dimensions
+ // Since we can't access presentation width/height directly
+ if (slides.items.length === 0) {
+ setStatusMessage("No slides found in the presentation.");
+ setStatusType("warning");
+ return;
+ }
+
+ // Get dimensions from the first slide
+ const firstSlide = slides.items[0];
+
+ // Standard PowerPoint slide dimensions (in points)
+ // We'll use these as fallbacks and adjust if we can get actual dimensions
+ let slideWidth = 960; // Default slide width (10 inches * 72 points)
+ let slideHeight = 540; // Default slide height (7.5 inches * 72 points)
+
+ // Process counter
+ let processedSlides = 0;
+ let errorSlides = 0;
+
+ // Process each slide
+ for (let i = 0; i < slides.items.length; i++) {
+ try {
+ const slide = slides.items[i];
+
+ const positionFromTop = slideHeight - 23;
+
+ // Create the textbox - make sure it spans the full width of the slide
+ // This is important for proper centering
+ const textBox = slide.shapes.addTextBox("");
+
+ // Make it span most of the width of the slide (90% centered)
+ // This ensures we have room for the text to be centered
+ const textBoxWidth = slideWidth * 1; // 0.9
+ textBox.left = (slideWidth - textBoxWidth) / 2; // Center it horizontally
+ textBox.top = positionFromTop;
+ textBox.width = textBoxWidth;
+ textBox.height = 25; // Smaller height for footer text
+
+ console.log("Starting PowerPoint add-in execution.");
+ console.log(textBox.left);
+ console.log(textBox.top);
+ console.log(textBox.width);
+ console.log(textBox.height);
+ await context.sync();
+
+ // Load textFrame to set text properties
+ textBox.load("textFrame");
+ await context.sync();
+
+ if (textBox.textFrame) {
+ // Load textRange to set text and properties
+ textBox.textFrame.load("textRange");
+ await context.sync();
+
+ // Need to load font and paragraphFormat
+ textBox.textFrame.textRange.load("font,paragraphFormat");
+ await context.sync();
+
+ // Set font properties
+ try {
+ // Ensure the font is loaded properly before setting properties
+ textBox.textFrame.textRange.font.load();
+ await context.sync();
+
+ // Set font properties exactly as in the VBA code
+ textBox.textFrame.textRange.font.name = "Inter";
+ textBox.textFrame.textRange.font.size = 8;
+ textBox.textFrame.textRange.paragraphFormat.horizontalAlignment = "Center"
+
+ // Set the color to RGB(218, 19, 53)
+ // Different APIs may need different color formats
+ textBox.textFrame.textRange.font.color = "#DA1335";
+
+ // Set the text
+ textBox.textFrame.textRange.text = "– Confidential –";
+ } catch (fontError) {
+ console.error("Error setting font properties:", fontError);
+ // Even if we can't set the font properties exactly, continue with default font
+ }
+
+ // Add a name/tag to the shape for identification
+ textBox.name = "ConfidentialMarking";
+
+ await context.sync();
+ processedSlides++;
+ }
+ } catch (slideError) {
+ console.error(`Error processing slide ${i+1}:`, slideError);
+ errorSlides++;
+ // Continue to the next slide
+ continue;
+ }
+ }
+
+ // Report results
+ if (processedSlides > 0) {
+ setStatusMessage(`Added confidential marking to ${processedSlides} slides.`);
+ setStatusType("success");
+ } else if (errorSlides > 0) {
+ setStatusMessage(`Failed to add markings. Errors on ${errorSlides} slides.`);
+ setStatusType("error");
+ } else {
+ setStatusMessage("No slides found to add confidential marking.");
+ setStatusType("warning");
+ }
+
+ } catch (innerError) {
+ console.error("Inner error:", innerError);
+ throw innerError; // Re-throw to outer catch
+ }
+ });
+ } catch (error) {
+ setStatusMessage(`Error: ${error.message}`);
+ setStatusType("error");
+ console.error("Add confidential error:", error);
+ } finally {
+ setIsProcessing(false);
+ }
+ };
+
+ const removeConfidentialMarking = async () => {
+ setIsProcessing(true);
+ try {
+ await PowerPoint.run(async (context) => {
+ try {
+ // Get all slides in the presentation
+ const slides = context.presentation.slides;
+ slides.load("items");
+ await context.sync();
+
+ if (slides.items.length === 0) {
+ setStatusMessage("No slides found in the presentation.");
+ setStatusType("warning");
+ return;
+ }
+
+ // Process counter
+ let processedSlides = 0;
+ let errorSlides = 0;
+ let removedCount = 0;
+
+ // Process each slide
+ for (let i = 0; i < slides.items.length; i++) {
+ try {
+ const slide = slides.items[i];
+
+ // Load all shapes on the slide
+ slide.shapes.load("items");
+ await context.sync();
+
+ // Find shapes with name "ConfidentialMarking"
+ for (let j = 0; j < slide.shapes.items.length; j++) {
+ const shape = slide.shapes.items[j];
+ shape.load("name");
+ await context.sync();
+
+ if (shape.name === "ConfidentialMarking") {
+ // Delete the confidential marking shape
+ shape.delete();
+ removedCount++;
+ }
+ }
+
+ await context.sync();
+ processedSlides++;
+ } catch (slideError) {
+ console.error(`Error processing slide ${i+1}:`, slideError);
+ errorSlides++;
+ // Continue to the next slide
+ continue;
+ }
+ }
+
+ // Report results
+ if (removedCount > 0) {
+ setStatusMessage(`Removed ${removedCount} confidential markings from ${processedSlides} slides.`);
+ setStatusType("success");
+ } else if (errorSlides > 0) {
+ setStatusMessage(`Failed to remove markings. Errors on ${errorSlides} slides.`);
+ setStatusType("error");
+ } else {
+ setStatusMessage("No confidential markings found to remove.");
+ setStatusType("info");
+ }
+
+ } catch (innerError) {
+ console.error("Inner error:", innerError);
+ throw innerError; // Re-throw to outer catch
+ }
+ });
+ } catch (error) {
+ setStatusMessage(`Error: ${error.message}`);
+ setStatusType("error");
+ console.error("Remove confidential error:", error);
+ } finally {
+ setIsProcessing(false);
+ }
+ };
+
+ return (
+
+
+ }
+ disabled={isProcessing}
+ title="Add Confidential"
+ >
+ Add Confidential
+
+ }
+ disabled={isProcessing}
+ title="Remove Confidential"
+ >
+ Remove Confidential
+
+
+
+ );
+};
+
+export default ConfidentialButtons;
\ No newline at end of file
diff --git a/src/taskpane/components/DraftButtons.tsx b/src/taskpane/components/DraftButtons.tsx
new file mode 100644
index 00000000..313994ab
--- /dev/null
+++ b/src/taskpane/components/DraftButtons.tsx
@@ -0,0 +1,103 @@
+import * as React from "react";
+import {
+ Button,
+ makeStyles
+} from "@fluentui/react-components";
+import {
+ Edit24Regular,
+ DismissRegular
+} from "@fluentui/react-icons";
+import { useStatusContext } from "./App";
+import { useCommonStyles } from "./commonStyles";
+
+const useStyles = makeStyles({
+ buttonGrid: {
+ display: "grid",
+ gridTemplateColumns: "repeat(2, 1fr)",
+ gap: "8px",
+ width: "100%"
+ },
+ draftButton: {
+ width: "100%",
+ minWidth: 0,
+ padding: "8px 4px",
+ "& span": {
+ justifyContent: "center"
+ }
+ }
+});
+
+export const DraftButtons: React.FC = () => {
+ const styles = useStyles();
+ const commonStyles = useCommonStyles();
+ const {
+ statusMessage, setStatusMessage,
+ statusType, setStatusType,
+ isProcessing, setIsProcessing
+ } = useStatusContext();
+
+ const addDraftWatermark = async () => {
+ setIsProcessing(true);
+ try {
+ await PowerPoint.run(async (context) => {
+ const shapes = context.presentation.getSelectedShapes();
+ // Implementation will go here
+ setStatusMessage("Added draft watermark to slides.");
+ setStatusType("success");
+ });
+ } catch (error) {
+ setStatusMessage(`Error: ${error.message}`);
+ setStatusType("error");
+ console.error("Add draft watermark error:", error);
+ } finally {
+ setIsProcessing(false);
+ }
+ };
+
+ const removeDraftWatermark = async () => {
+ setIsProcessing(true);
+ try {
+ await PowerPoint.run(async (context) => {
+ const shapes = context.presentation.getSelectedShapes();
+ // Implementation will go here
+ setStatusMessage("Removed draft watermarks from slides.");
+ setStatusType("success");
+ });
+ } catch (error) {
+ setStatusMessage(`Error: ${error.message}`);
+ setStatusType("error");
+ console.error("Remove draft watermark error:", error);
+ } finally {
+ setIsProcessing(false);
+ }
+ };
+
+ return (
+
+
+ }
+ disabled={isProcessing}
+ title="Add Draft"
+ >
+ Add Draft
+
+ }
+ disabled={isProcessing}
+ title="Remove Draft"
+ >
+ Remove Draft
+
+
+
+ );
+};
+
+export default DraftButtons;
\ No newline at end of file