diff --git a/public/translations/en-US.json b/public/translations/en-US.json
index a73e8f6b1..62c0ef274 100644
--- a/public/translations/en-US.json
+++ b/public/translations/en-US.json
@@ -308,8 +308,10 @@
},
"sidebar": {
"collapse": "Collapse sidebar",
+ "collapseInstructions": "Collapse project instructions",
"download": "Download project",
"expand": "Expand sidebar",
+ "expandInstructions": "Open project instructions",
"file": "Project files",
"images": "Image gallery",
"settings": "Settings",
@@ -355,4 +357,4 @@
"common": {
"or": "or"
}
-}
\ No newline at end of file
+}
diff --git a/public/translations/en.json b/public/translations/en.json
index 0ecc5f9e4..178693e70 100644
--- a/public/translations/en.json
+++ b/public/translations/en.json
@@ -308,8 +308,10 @@
},
"sidebar": {
"collapse": "Collapse sidebar",
+ "collapseInstructions": "Collapse project instructions",
"download": "Download project",
"expand": "Expand sidebar",
+ "expandInstructions": "Open project instructions",
"file": "Project files",
"images": "Image gallery",
"settings": "Settings",
diff --git a/src/assets/stylesheets/Project.scss b/src/assets/stylesheets/Project.scss
index d9fe8c518..3323ef8f3 100644
--- a/src/assets/stylesheets/Project.scss
+++ b/src/assets/stylesheets/Project.scss
@@ -50,6 +50,32 @@
overflow: hidden;
}
+ .project-bar-row {
+ display: flex;
+ align-items: stretch;
+ gap: var(--project-wrapper-grid-gap, #{$space-0-5});
+
+ .project-bar {
+ flex: 1 1 auto;
+ min-inline-size: 0;
+ }
+ }
+
+ .project-bar-row__expand {
+ display: flex;
+ align-items: center;
+ flex-shrink: 0;
+ box-sizing: border-box;
+ padding: $space-0-5;
+ border-radius: $space-0-5;
+ background-color: var(--editor-color-layer-3);
+ border: 1px solid var(--editor-color-outline);
+
+ .rpf-button {
+ border: none;
+ }
+ }
+
.proj-editor-wrapper {
display: flex;
flex: 0 1 auto;
diff --git a/src/assets/stylesheets/Sidebar.scss b/src/assets/stylesheets/Sidebar.scss
index 916669c3a..14ec3dea3 100644
--- a/src/assets/stylesheets/Sidebar.scss
+++ b/src/assets/stylesheets/Sidebar.scss
@@ -122,9 +122,41 @@
.sidebar__panel-heading {
margin: 0;
+ min-inline-size: 0;
@include font-size-1-5(regular);
}
+.sidebar__panel-heading-row {
+ display: flex;
+ align-items: center;
+ gap: var(--space-0-5);
+
+ .rpf-button {
+ border: none;
+ }
+}
+
+.sidebar__panel-collapse {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+ flex-shrink: 0;
+ margin: 0;
+ border: 1px solid var(--sidebar-border);
+ border-radius: var(--space-1);
+ padding: var(--space-1);
+ color: var(--editor-color-text);
+
+ svg {
+ margin: 0;
+ }
+
+ &:hover {
+ background-color: var(--sidebar-option-hover);
+ }
+}
+
.sidebar__panel-header {
display: flex;
flex-direction: column;
diff --git a/src/components/Editor/Project/Project.jsx b/src/components/Editor/Project/Project.jsx
index a99fe0c36..bbb61fd5f 100644
--- a/src/components/Editor/Project/Project.jsx
+++ b/src/components/Editor/Project/Project.jsx
@@ -10,6 +10,7 @@ import { showSavedMessage } from "../../../utils/Notifications";
import ProjectBar from "../../ProjectBar/ProjectBar";
import ScratchProjectBar from "../../ProjectBar/ScratchProjectBar";
import Sidebar from "../../Menus/Sidebar/Sidebar";
+import SidebarExpandButton from "../../Menus/Sidebar/SidebarExpandButton";
import EditorInput from "../EditorInput/EditorInput";
import ResizableWithHandle from "../../../utils/ResizableWithHandle";
import { useContainerMinWidth } from "../../../hooks/useContainerMinWidth";
@@ -69,12 +70,20 @@ const Project = (props) => {
/>
)}
- {withProjectbar &&
- (isCodeEditorScratchProject ? (
-
- ) : (
-
- ))}
+ {withProjectbar && (
+
+ {withSidebar && (
+
+ )}
+ {isCodeEditorScratchProject ? (
+
+ ) : (
+
+ )}
+
+ )}
{!loading && !isCodeEditorScratchProject && (
{
+const InstructionsPanel = ({ toggleOption, isMobile }) => {
const [tabIndex, setTabIndex] = useState(0);
const [showRemoveStepModal, setShowRemoveStepModal] = useState(false);
const [removeScope, setRemoveScope] = useState(REMOVE_CURRENT_STEP);
@@ -110,11 +110,31 @@ const InstructionsPanel = () => {
const panelRef = useRef(null);
+ const collapsePanel = () => {
+ toggleOption("instructions");
+ if (window.plausible) {
+ window.plausible("Collapse file pane");
+ }
+ };
+
return (
}
+ iconOnly
+ text={t("sidebar.collapseInstructions")}
+ onClick={collapsePanel}
+ size="small"
+ type="tertiary"
+ />
+ ) : undefined
+ }
buttons={
instructionsEditable && !hasInstructions
? [
diff --git a/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.test.jsx b/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.test.jsx
index 218233655..090723285 100644
--- a/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.test.jsx
+++ b/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.test.jsx
@@ -42,6 +42,44 @@ const selectRemoveModalScope = (scope) =>
fireEvent.click(removeModalScopeRadio(scope));
});
+describe("The panel header collapse button", () => {
+ const renderPanel = (props = {}) =>
+ renderWithProviders(, {
+ preloadedState: {
+ editor: {
+ project: { instructions: [{ markdown_content: "instructions" }] },
+ instructionsEditable: true,
+ },
+ instructions: { permitOverride: true, currentStepPosition: 0 },
+ },
+ });
+
+ test("is not rendered when the panel cannot be toggled", () => {
+ renderPanel();
+
+ expect(
+ screen.queryByTitle("sidebar.collapseInstructions"),
+ ).not.toBeInTheDocument();
+ });
+
+ test("is not rendered on mobile", () => {
+ renderPanel({ toggleOption: vi.fn(), isMobile: true });
+
+ expect(
+ screen.queryByTitle("sidebar.collapseInstructions"),
+ ).not.toBeInTheDocument();
+ });
+
+ test("closes the instructions panel when clicked", () => {
+ const toggleOption = vi.fn();
+ renderPanel({ toggleOption });
+
+ fireEvent.click(screen.getByTitle("sidebar.collapseInstructions"));
+
+ expect(toggleOption).toHaveBeenCalledWith("instructions");
+ });
+});
+
describe("When instructionsEditable changes from false to true", () => {
test("does not leave the rendered preview above the edit/view tabs", () => {
const { container, store } = renderWithProviders(, {
diff --git a/src/components/Menus/Sidebar/Sidebar.jsx b/src/components/Menus/Sidebar/Sidebar.jsx
index 79d3157b0..0605b4a00 100644
--- a/src/components/Menus/Sidebar/Sidebar.jsx
+++ b/src/components/Menus/Sidebar/Sidebar.jsx
@@ -212,6 +212,8 @@ const Sidebar = ({
} else if (!optionIsAvailable) {
setOption(nextDefaultOption);
dispatch(setSidebarOption(nextDefaultOption));
+ } else {
+ setOption(selectedSidebarOption);
}
}, [dispatch, nextDefaultOption, optionIsAvailable, selectedSidebarOption]);
@@ -245,7 +247,7 @@ const Sidebar = ({
>
)}
diff --git a/src/components/Menus/Sidebar/SidebarBar.jsx b/src/components/Menus/Sidebar/SidebarBar.jsx
index 78c38f655..4bbeff0a7 100644
--- a/src/components/Menus/Sidebar/SidebarBar.jsx
+++ b/src/components/Menus/Sidebar/SidebarBar.jsx
@@ -16,7 +16,7 @@ import { MOBILE_MEDIA_QUERY } from "../../../utils/mediaQueryBreakpoints";
const SidebarBar = (props) => {
const {
menuOptions,
- option,
+ activeOption,
toggleOption,
instructions = false,
allowMobileView = true,
@@ -59,7 +59,7 @@ const SidebarBar = (props) => {
};
const collapsePopOut = () => {
- toggleOption(option);
+ toggleOption(activeOption);
if (window.plausible) {
window.plausible("Collapse file pane");
}
@@ -81,7 +81,7 @@ const SidebarBar = (props) => {
return (
@@ -95,7 +95,7 @@ const SidebarBar = (props) => {
key={i}
Icon={menuOption.icon}
title={menuOption.title}
- isActive={option === menuOption.name}
+ isActive={activeOption === menuOption.name}
toggleOption={toggleOption}
name={menuOption.name}
/>
@@ -107,13 +107,13 @@ const SidebarBar = (props) => {
key={i}
Icon={menuOption.icon}
title={menuOption.title}
- isActive={option === menuOption.name}
+ isActive={activeOption === menuOption.name}
toggleOption={toggleOption}
name={menuOption.name}
/>
))}
{!isMobile &&
- (option ? (
+ (activeOption ? (