Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/BloomBrowserUI/react_components/TopBar/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
kGreyOnDarkColor,
} from "../../bloomMaterialUITheme";
import { ScopedCssBaseline } from "@mui/material";
import { TopBarContextMenu } from "./TopBarContextMenu";

export type WorkspaceTabId = "collection" | "edit" | "publish";

Expand Down Expand Up @@ -71,6 +72,7 @@ export const TopBar: React.FunctionComponent = () => {
"workspace",
"tabs",
);
const topBarRef = React.useRef<HTMLDivElement>(null);

const tabStates = state.tabStates ?? defaultWorkspaceTabState.tabStates;
const activeTab = React.useMemo((): WorkspaceTabId => {
Expand Down Expand Up @@ -110,6 +112,7 @@ export const TopBar: React.FunctionComponent = () => {
CssBaseline would apply everywhere. */
<ScopedCssBaseline>
<div
ref={topBarRef}
css={css`
background-color: ${getColorForTab(activeTab)};
padding-top: 2px;
Expand All @@ -120,6 +123,7 @@ export const TopBar: React.FunctionComponent = () => {
>
<BloomTabs tabStates={tabStates} selectTab={handleSelectTab} />
<TopBarControls activeTab={activeTab} />
<TopBarContextMenu targetRef={topBarRef} />
</div>
</ScopedCssBaseline>
);
Expand Down
211 changes: 211 additions & 0 deletions src/BloomBrowserUI/react_components/TopBar/TopBarContextMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
import * as React from "react";
import { css } from "@emotion/react";
import { getBoolean, post, postBoolean, postJson } from "../../utils/bloomApi";
import Menu from "@mui/material/Menu";
import Divider from "@mui/material/Divider";
import {
LocalizableMenuItem,
LocalizableSelectableMenuItem,
} from "../localizableMenuItem";
import { useMountEffect } from "../../utils/useMountEffect";

interface ITopBarContextMenuPoint {
clientX: number;
clientY: number;
}

interface ITopBarContextMenuItem {
label: string;
enabled?: boolean;
selected?: boolean;
onClick?: () => void;
}

export const TopBarContextMenu: React.FunctionComponent<{
targetRef: React.RefObject<HTMLDivElement>;
}> = (props) => {
const [menuPoint, setMenuPoint] = React.useState<ITopBarContextMenuPoint>();
const [currentlyMeasuring, setCurrentlyMeasuring] = React.useState(false);
const [alwaysMeasurePerformance, setAlwaysMeasurePerformance] =
React.useState(false);
const [isMeddlingWithNewFiles, setIsMeddlingWithNewFiles] =
React.useState(false);
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.

const onClose = React.useCallback(() => {
setMenuPoint(undefined);
}, []);

useMountEffect(() => {
Comment thread
andrew-polk marked this conversation as resolved.
// CurrentlyMeasuring is only turned on from this menu, so local state can own it
// once we establish the initial persisted setting. (No need to ask the back end.)
getBoolean("app/alwaysMeasurePerformance", (value) => {
setAlwaysMeasurePerformance(value);
if (value) {
setCurrentlyMeasuring(true);
}
});
// Even though this is only controlled from this menu, meddling could be turned on
// and then Bloom could restart or reload a collection. So we do need to ask
// the back end for the current value.
getBoolean("app/isMeddlingWithNewFiles", (value) => {
setIsMeddlingWithNewFiles(value);
});

const target = props.targetRef.current;
if (!target) {
return;
}

const handleTopBarContextMenu = (event: MouseEvent) => {
// Don't block the Ctrl+RightClick context menu
if (event.ctrlKey) {
return;
}

event.preventDefault();
event.stopPropagation();

setMenuPoint({
clientX: event.clientX,
clientY: event.clientY,
});
};

target.addEventListener("contextmenu", handleTopBarContextMenu);

return () => {
target.removeEventListener("contextmenu", handleTopBarContextMenu);
};
});

function handleResizeWindow(width: number, height: number) {
postJson("app/resizeWindow", {
width,
height,
});
}

const menuItems = React.useMemo<ITopBarContextMenuItem[]>(() => {
return [
{
label: "1024 x 586 Low-end netbook with windows Task bar",
onClick: () => {
handleResizeWindow(1024, 586);
},
},
{ label: "-" },
{
label: "800 x 600",
onClick: () => {
handleResizeWindow(800, 600);
},
},
{
label: "1024 x 600",
onClick: () => {
handleResizeWindow(1024, 600);
},
},
{
label: "1024 x 768",
onClick: () => {
handleResizeWindow(1024, 768);
},
},
{ label: "-" },
{
label: "Always Measure Performance",
selected: alwaysMeasurePerformance,
onClick: () => {
const newValue = !alwaysMeasurePerformance;
postBoolean("app/alwaysMeasurePerformance", newValue);
setAlwaysMeasurePerformance(newValue);
if (newValue) {
setCurrentlyMeasuring(true);
}
},
},
{
label: currentlyMeasuring
? "Currently Measuring Performance"
: "Start Measuring Performance",
enabled: !currentlyMeasuring,
onClick: () => {
post("app/startMeasuringPerformance");
setCurrentlyMeasuring(true);
},
},
{
label: "Show Performance Page",
enabled: currentlyMeasuring,
onClick: () => {
post("app/showPerformancePage");
},
},
{
label: isMeddlingWithNewFiles
? "Stop Meddling with New Files"
: "Meddle with New Files",
onClick: () => {
const newValue = !isMeddlingWithNewFiles;
postBoolean("app/isMeddlingWithNewFiles", newValue);
setIsMeddlingWithNewFiles(newValue);
},
},
];
}, [alwaysMeasurePerformance, currentlyMeasuring, isMeddlingWithNewFiles]);

return (
<Menu
keepMounted={true}
open={!!menuPoint}
onClose={onClose}
anchorReference="anchorPosition"
anchorPosition={
menuPoint
? {
top: menuPoint.clientY,
left: menuPoint.clientX,
}
: undefined
}
slotProps={{
paper: {
css: css`
min-width: 220px;
max-width: 440px;
`,
},
}}
>
{menuItems.map((item, index) => {
if (item.label === "-") {
return <Divider key={`separator-${index}`} />;
}

const commonProps = {
key: `${item.label ?? index}`,
english: item.label,
l10nId: null,
onClick: () => {
item.onClick?.();
onClose();
},
disabled: item.enabled === false,
};

return item.selected !== undefined ? (
<LocalizableSelectableMenuItem
{...commonProps}
selected={item.selected}
/>
) : (
<LocalizableMenuItem
{...commonProps}
hasLeadingIconSpace={true}
/>
);
})}
</Menu>
);
};
6 changes: 6 additions & 0 deletions src/BloomBrowserUI/utils/useMountEffect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { useEffect } from "react";

export function useMountEffect(effect: () => void | (() => void)) {
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(effect, []);
}
108 changes: 0 additions & 108 deletions src/BloomExe/Shell.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading