Now only using one status box
This commit is contained in:
+123
-15
@@ -2,12 +2,34 @@ import * as React from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import MatchSizes from "./MatchSizes";
|
||||
import MatchProperties from "./MatchProperties";
|
||||
import { makeStyles, Text, Subtitle1, tokens, Theme } from "@fluentui/react-components";
|
||||
import { makeStyles, Text, Subtitle1, tokens, Theme, Spinner } from "@fluentui/react-components";
|
||||
import { ShapeUnionRegular, SquareRegular, InfoRegular } from "@fluentui/react-icons";
|
||||
|
||||
interface AppProps {
|
||||
title: string;
|
||||
}
|
||||
|
||||
export type StatusType = "info" | "success" | "warning" | "error";
|
||||
|
||||
export interface StatusContextType {
|
||||
statusMessage: string;
|
||||
setStatusMessage: (message: string) => void;
|
||||
statusType: StatusType;
|
||||
setStatusType: (type: StatusType) => void;
|
||||
isProcessing: boolean;
|
||||
setIsProcessing: (processing: boolean) => void;
|
||||
}
|
||||
|
||||
export const StatusContext = React.createContext<StatusContextType | undefined>(undefined);
|
||||
|
||||
export const useStatusContext = () => {
|
||||
const context = React.useContext(StatusContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useStatusContext must be used within a StatusProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
const useStyles = makeStyles({
|
||||
root: {
|
||||
display: "flex",
|
||||
@@ -18,8 +40,35 @@ const useStyles = makeStyles({
|
||||
backgroundColor: tokens.colorNeutralBackground1,
|
||||
overflow: "auto",
|
||||
},
|
||||
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",
|
||||
},
|
||||
section: {
|
||||
marginBottom: "24px",
|
||||
marginBottom: "4px",
|
||||
padding: "12px",
|
||||
borderRadius: "8px",
|
||||
backgroundColor: tokens.colorNeutralBackground2,
|
||||
@@ -47,6 +96,11 @@ const App: React.FC<AppProps> = () => {
|
||||
const styles = useStyles();
|
||||
const [theme, setTheme] = useState<string>("light");
|
||||
|
||||
// Status state
|
||||
const [statusMessage, setStatusMessage] = useState("");
|
||||
const [statusType, setStatusType] = useState<StatusType>("info");
|
||||
const [isProcessing, setIsProcessing] = useState(false);
|
||||
|
||||
// Check if macOS is in dark mode (would need to be expanded in production)
|
||||
useEffect(() => {
|
||||
// In a real implementation, we would listen to Office theme changes
|
||||
@@ -54,21 +108,75 @@ const App: React.FC<AppProps> = () => {
|
||||
setTheme(prefersDarkMode ? "dark" : "light");
|
||||
}, []);
|
||||
|
||||
// Auto-clear success messages after 5 seconds
|
||||
useEffect(() => {
|
||||
let timer: number;
|
||||
if (statusType === "success" && statusMessage) {
|
||||
timer = window.setTimeout(() => {
|
||||
setStatusMessage("");
|
||||
}, 5000);
|
||||
}
|
||||
return () => {
|
||||
if (timer) clearTimeout(timer);
|
||||
};
|
||||
}, [statusMessage, statusType]);
|
||||
|
||||
const getStatusIcon = () => {
|
||||
switch (statusType) {
|
||||
case "success":
|
||||
return <ShapeUnionRegular className={styles.statusIcon} />;
|
||||
case "warning":
|
||||
return <SquareRegular className={styles.statusIcon} />;
|
||||
case "error":
|
||||
return <InfoRegular className={styles.statusIcon} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.root} data-theme={theme}>
|
||||
<div className={styles.section}>
|
||||
<Subtitle1 block className={styles.sectionTitle}>
|
||||
Shape Tools
|
||||
</Subtitle1>
|
||||
<MatchSizes />
|
||||
<div style={{ marginTop: "8px" }}></div>
|
||||
<MatchProperties />
|
||||
<StatusContext.Provider value={{
|
||||
statusMessage,
|
||||
setStatusMessage,
|
||||
statusType,
|
||||
setStatusType,
|
||||
isProcessing,
|
||||
setIsProcessing
|
||||
}}>
|
||||
<div className={styles.root} data-theme={theme}>
|
||||
<div className={styles.section}>
|
||||
<Subtitle1 block className={styles.sectionTitle}>
|
||||
Shape Tools
|
||||
</Subtitle1>
|
||||
<MatchSizes />
|
||||
<div style={{ marginTop: "8px" }}></div>
|
||||
<MatchProperties />
|
||||
</div>
|
||||
|
||||
{/* Status message area at the bottom */}
|
||||
{isProcessing && (
|
||||
<div className={styles.statusContainer}>
|
||||
<div className={styles.statusText}>
|
||||
<Spinner size="tiny" style={{ marginRight: "8px" }} />
|
||||
Processing...
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isProcessing && statusMessage && (
|
||||
<div className={`${styles.statusContainer} ${styles[`${statusType}Status`]}`}>
|
||||
<div className={styles.statusText}>
|
||||
{getStatusIcon()}
|
||||
{statusMessage}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={styles.footer}>
|
||||
<Text size={100}>Edison • v1.0.0</Text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.footer}>
|
||||
<Text size={100}>Edison • v1.0.0</Text>
|
||||
</div>
|
||||
</div>
|
||||
</StatusContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -2,16 +2,12 @@ import * as React from "react";
|
||||
import {
|
||||
Button,
|
||||
makeStyles,
|
||||
Text,
|
||||
Spinner,
|
||||
tokens
|
||||
} from "@fluentui/react-components";
|
||||
import {
|
||||
ColorRegular,
|
||||
SquareRegular,
|
||||
ShapeUnionRegular,
|
||||
InfoRegular
|
||||
ColorRegular
|
||||
} from "@fluentui/react-icons";
|
||||
import { useStatusContext } from "./App";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
container: {
|
||||
@@ -62,9 +58,11 @@ const useStyles = makeStyles({
|
||||
|
||||
export const MatchProperties: React.FC = () => {
|
||||
const styles = useStyles();
|
||||
const [statusMessage, setStatusMessage] = React.useState("");
|
||||
const [statusType, setStatusType] = React.useState<"info" | "success" | "warning" | "error">("info");
|
||||
const [isProcessing, setIsProcessing] = React.useState(false);
|
||||
const {
|
||||
statusMessage, setStatusMessage,
|
||||
statusType, setStatusType,
|
||||
isProcessing, setIsProcessing
|
||||
} = useStatusContext();
|
||||
|
||||
const matchPropertiesToFirstSelected = async () => {
|
||||
setIsProcessing(true);
|
||||
@@ -245,12 +243,7 @@ export const MatchProperties: React.FC = () => {
|
||||
setStatusType("error");
|
||||
}
|
||||
|
||||
// Auto-clear success message after 5 seconds
|
||||
setTimeout(() => {
|
||||
if (statusType === "success") {
|
||||
setStatusMessage("");
|
||||
}
|
||||
}, 5000);
|
||||
// Timeout is handled in App.tsx now
|
||||
});
|
||||
} catch (error) {
|
||||
setStatusMessage(`Error: ${error.message}`);
|
||||
@@ -261,19 +254,6 @@ export const MatchProperties: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusIcon = () => {
|
||||
switch (statusType) {
|
||||
case "success":
|
||||
return <ShapeUnionRegular className={styles.statusIcon} />;
|
||||
case "warning":
|
||||
return <SquareRegular className={styles.statusIcon} />;
|
||||
case "error":
|
||||
return <InfoRegular className={styles.statusIcon} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.buttonGroup}>
|
||||
@@ -287,24 +267,6 @@ export const MatchProperties: React.FC = () => {
|
||||
Match Properties
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{isProcessing && (
|
||||
<div className={styles.statusContainer}>
|
||||
<div className={styles.statusText}>
|
||||
<Spinner size="tiny" style={{ marginRight: "8px" }} />
|
||||
Applying properties...
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isProcessing && statusMessage && (
|
||||
<div className={`${styles.statusContainer} ${styles[`${statusType}Status`]}`}>
|
||||
<div className={styles.statusText}>
|
||||
{getStatusIcon()}
|
||||
{statusMessage}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -5,18 +5,15 @@ import {
|
||||
Text,
|
||||
Tooltip,
|
||||
InfoLabel,
|
||||
Spinner,
|
||||
tokens,
|
||||
Card
|
||||
} from "@fluentui/react-components";
|
||||
import {
|
||||
ArrowFitInRegular,
|
||||
ArrowSortDownRegular,
|
||||
ArrowSortUpRegular,
|
||||
SquareRegular,
|
||||
ShapeUnionRegular,
|
||||
InfoRegular
|
||||
ArrowSortUpRegular
|
||||
} from "@fluentui/react-icons";
|
||||
import { useStatusContext } from "./App";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
container: {
|
||||
@@ -67,9 +64,11 @@ const useStyles = makeStyles({
|
||||
|
||||
export const MatchSizes: React.FC = () => {
|
||||
const styles = useStyles();
|
||||
const [statusMessage, setStatusMessage] = React.useState("");
|
||||
const [statusType, setStatusType] = React.useState<"info" | "success" | "warning" | "error">("info");
|
||||
const [isProcessing, setIsProcessing] = React.useState(false);
|
||||
const {
|
||||
statusMessage, setStatusMessage,
|
||||
statusType, setStatusType,
|
||||
isProcessing, setIsProcessing
|
||||
} = useStatusContext();
|
||||
|
||||
const matchSizeToFirstSelected = async () => {
|
||||
setIsProcessing(true);
|
||||
@@ -109,12 +108,7 @@ export const MatchSizes: React.FC = () => {
|
||||
setStatusMessage(`Resized ${shapes.items.length - 1} shapes to match the first selected shape.`);
|
||||
setStatusType("success");
|
||||
|
||||
// Auto-clear success message after 5 seconds
|
||||
setTimeout(() => {
|
||||
if (statusType === "success") {
|
||||
setStatusMessage("");
|
||||
}
|
||||
}, 5000);
|
||||
// Timeout is handled in App.tsx now
|
||||
});
|
||||
} catch (error) {
|
||||
setStatusMessage(`Error: ${error.message}`);
|
||||
@@ -126,19 +120,6 @@ export const MatchSizes: React.FC = () => {
|
||||
};
|
||||
|
||||
|
||||
const getStatusIcon = () => {
|
||||
switch (statusType) {
|
||||
case "success":
|
||||
return <ShapeUnionRegular className={styles.statusIcon} />;
|
||||
case "warning":
|
||||
return <SquareRegular className={styles.statusIcon} />;
|
||||
case "error":
|
||||
return <InfoRegular className={styles.statusIcon} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.buttonGroup}>
|
||||
@@ -152,25 +133,6 @@ export const MatchSizes: React.FC = () => {
|
||||
Match Sizes
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{isProcessing && (
|
||||
<div className={styles.statusContainer}>
|
||||
<div className={styles.statusText}>
|
||||
<Spinner size="tiny" style={{ marginRight: "8px" }} />
|
||||
Resizing shapes...
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isProcessing && statusMessage && (
|
||||
<div className={`${styles.statusContainer} ${styles[`${statusType}Status`]}`}>
|
||||
<div className={styles.statusText}>
|
||||
{getStatusIcon()}
|
||||
{statusMessage}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user