diff --git a/src/assets/stylesheets/Project.scss b/src/assets/stylesheets/Project.scss
index 207b2b318..5da294adb 100644
--- a/src/assets/stylesheets/Project.scss
+++ b/src/assets/stylesheets/Project.scss
@@ -1,4 +1,5 @@
@use "./ScratchContainer";
+@use "./sizes" as *;
.proj {
display: flex;
@@ -34,7 +35,7 @@
flex-direction: row;
overflow-y: hidden;
- --resize-handle-size: 16px;
+ --resize-handle-size: #{$resize-handle-size};
gap: var(--resize-handle-size);
margin-block-start: var(--editor-margin-block-start, var(--space-2));
diff --git a/src/assets/stylesheets/Sidebar.scss b/src/assets/stylesheets/Sidebar.scss
index d2d5d3307..4b87f4b63 100644
--- a/src/assets/stylesheets/Sidebar.scss
+++ b/src/assets/stylesheets/Sidebar.scss
@@ -1,6 +1,12 @@
@use "@raspberrypifoundation/design-system-core/scss/mixins/typography";
@use "./rpf_design_system/mixins" as *;
-@use "./breakpoints" as *;
+@use "./sizes" as *;
+
+$sidebar-min-width: 350px;
+$block-editor-min-width: 1024px;
+$small-sidebar-breakpoint: calc(
+ $sidebar-min-width + $block-editor-min-width + $resize-handle-size
+);
/* Sidebar */
.sidebar {
@@ -28,7 +34,7 @@
margin: var(--space-1-5);
display: var(--editor-logo-display, inherit);
- @include unique-max-width($stacked-editor-max-width) {
+ @include unique-max-width($small-sidebar-breakpoint) {
block-size: var(--space-4);
inline-size: var(--space-4);
margin: var(--space-1) var(--space-0-5);
@@ -87,7 +93,7 @@
padding: var(--space-1);
border: 1px solid transparent;
- @include unique-max-width($stacked-editor-max-width) {
+ @include unique-max-width($small-sidebar-breakpoint) {
padding: var(--space-0-5);
}
@@ -108,7 +114,7 @@
block-size: 60px;
background-color: var(--sidebar-panel-background);
- @include unique-max-width($stacked-editor-max-width) {
+ @include unique-max-width($small-sidebar-breakpoint) {
inset-block: -4px -1px;
inset-inline-end: -8px;
block-size: 40px;
@@ -136,7 +142,7 @@
margin: 0;
}
- @include unique-max-width($stacked-editor-max-width) {
+ @include unique-max-width($small-sidebar-breakpoint) {
&.btn {
min-block-size: 32px;
min-inline-size: 32px;
diff --git a/src/assets/stylesheets/_breakpoints.scss b/src/assets/stylesheets/_breakpoints.scss
deleted file mode 100644
index ac07cac02..000000000
--- a/src/assets/stylesheets/_breakpoints.scss
+++ /dev/null
@@ -1 +0,0 @@
-$stacked-editor-max-width: 1146px;
diff --git a/src/assets/stylesheets/_sizes.scss b/src/assets/stylesheets/_sizes.scss
new file mode 100644
index 000000000..f0d8f32a3
--- /dev/null
+++ b/src/assets/stylesheets/_sizes.scss
@@ -0,0 +1 @@
+$resize-handle-size: 16px;
diff --git a/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.test.jsx b/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.test.jsx
index 218233655..0ab6cd50c 100644
--- a/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.test.jsx
+++ b/src/components/Menus/Sidebar/InstructionsPanel/InstructionsPanel.test.jsx
@@ -558,6 +558,7 @@ describe("When instructions are not editable", () => {
renderWithProviders(, {
preloadedState: {
editor: {
+ project: {},
instructionsEditable: false,
},
instructions: {
diff --git a/src/components/Menus/Sidebar/SettingsPanel/SettingsPanel.test.jsx b/src/components/Menus/Sidebar/SettingsPanel/SettingsPanel.test.jsx
index dca618836..c69ba9863 100644
--- a/src/components/Menus/Sidebar/SettingsPanel/SettingsPanel.test.jsx
+++ b/src/components/Menus/Sidebar/SettingsPanel/SettingsPanel.test.jsx
@@ -13,6 +13,7 @@ describe("Settings panel", () => {
const mockStore = configureStore(middlewares);
const initialState = {
editor: {
+ project: {},
isThemeable: true,
},
};
@@ -46,6 +47,7 @@ describe("Settings panel", () => {
const mockStore = configureStore(middlewares);
const initialState = {
editor: {
+ project: {},
isThemeable: false,
},
};
diff --git a/src/components/Menus/Sidebar/SidebarPanel.jsx b/src/components/Menus/Sidebar/SidebarPanel.jsx
index 4b4ff8b9b..b0c1712d1 100644
--- a/src/components/Menus/Sidebar/SidebarPanel.jsx
+++ b/src/components/Menus/Sidebar/SidebarPanel.jsx
@@ -1,11 +1,9 @@
import React, { useContext, useState } from "react";
import ResizableWithHandle from "../../../utils/ResizableWithHandle";
+import { useSelector } from "react-redux";
import classNames from "classnames";
import PropTypes from "prop-types";
-import {
- MOBILE_MEDIA_QUERY,
- SMALL_SCREEN_MEDIA_QUERY,
-} from "../../../utils/mediaQueryBreakpoints";
+import { MOBILE_MEDIA_QUERY } from "../../../utils/mediaQueryBreakpoints";
import { useMediaQuery } from "react-responsive";
import {
SidebarActiveOptionContext,
@@ -15,6 +13,20 @@ import {
const MIN_WIDTH = "280px";
+export const SMALL_SIDEBAR_PROJECT_TYPE_BREAKPOINTS = {
+ code_editor_scratch: "(max-width: 1430px)",
+};
+
+export const SMALL_SIDEBAR_PROJECT_TYPE = "(max-width: 1146px)";
+
+export const sidebarStartingWidth = (projectType, defaultWidth) => {
+ const breakpoint =
+ SMALL_SIDEBAR_PROJECT_TYPE_BREAKPOINTS[projectType] ||
+ SMALL_SIDEBAR_PROJECT_TYPE;
+
+ return window.matchMedia(breakpoint).matches ? MIN_WIDTH : defaultWidth;
+};
+
const SidebarPanel = (props) => {
const {
children,
@@ -26,6 +38,7 @@ const SidebarPanel = (props) => {
panelRef,
defaultWidth = "320px",
} = props;
+ const projectType = useSelector((state) => state.editor.project.project_type);
const activeOption = useContext(SidebarActiveOptionContext);
const tabpanelProps = activeOption
? {
@@ -36,10 +49,8 @@ const SidebarPanel = (props) => {
}
: {};
const isMobile = useMediaQuery({ query: MOBILE_MEDIA_QUERY });
- const [initialWidth] = useState(() =>
- window.matchMedia(SMALL_SCREEN_MEDIA_QUERY).matches
- ? MIN_WIDTH
- : defaultWidth,
+ const [initialWidth] = useState(
+ sidebarStartingWidth(projectType, defaultWidth),
);
const buttonsIsEmptyArray =
diff --git a/src/components/Menus/Sidebar/SidebarPanel.test.jsx b/src/components/Menus/Sidebar/SidebarPanel.test.jsx
index 38b30ca3a..56e61635a 100644
--- a/src/components/Menus/Sidebar/SidebarPanel.test.jsx
+++ b/src/components/Menus/Sidebar/SidebarPanel.test.jsx
@@ -1,32 +1,38 @@
import React from "react";
-import { render, screen } from "@testing-library/react";
-import SidebarPanel from "./SidebarPanel";
-import { SMALL_SCREEN_MEDIA_QUERY } from "../../../utils/mediaQueryBreakpoints";
+import { screen } from "@testing-library/react";
+import { renderWithProviders } from "../../../utils/renderWithProviders";
+import SidebarPanel, {
+ SMALL_SIDEBAR_PROJECT_TYPE,
+ SMALL_SIDEBAR_PROJECT_TYPE_BREAKPOINTS,
+} from "./SidebarPanel";
const Footer = () =>
footer
;
-beforeEach(() => {
- render(
-
- some content
- ,
- );
-});
-
test("Renders heading", () => {
+ renderWithProviders(
+ some content,
+ );
expect(screen.queryByText("heading")).toBeInTheDocument();
});
test("Renders content", () => {
+ renderWithProviders(
+ some content,
+ );
expect(screen.queryByText("some content")).toBeInTheDocument();
});
test("Renders footer", () => {
+ renderWithProviders(
+
+ some content
+ ,
+ );
expect(screen.queryByText("footer")).toBeInTheDocument();
});
test("Renders a single button", () => {
- render(
+ renderWithProviders(
button]}>
some content
,
@@ -35,7 +41,7 @@ test("Renders a single button", () => {
});
test("Renders arbitrary header content", () => {
- render(
+ renderWithProviders(
a link}>
some content
,
@@ -44,7 +50,7 @@ test("Renders arbitrary header content", () => {
});
test("Renders header content alongside buttons", () => {
- render(
+ renderWithProviders(
button]}
@@ -58,7 +64,7 @@ test("Renders header content alongside buttons", () => {
});
test("Renders multiple buttons", () => {
- render(
+ renderWithProviders(
{
describe("Default width", () => {
const originalMatchMedia = window.matchMedia;
- const mockSmallScreen = (matches) => {
+ const mockMatchingMediaQuery = (matchingQuery) => {
window.matchMedia = (query) => ({
...originalMatchMedia(query),
- matches: matches && query === SMALL_SCREEN_MEDIA_QUERY,
+ matches: query === matchingQuery,
});
};
@@ -88,27 +94,68 @@ describe("Default width", () => {
});
test("Uses the default width on larger screens", () => {
- mockSmallScreen(false);
- render(some content);
- const panel = screen.getAllByTestId("sidebar__panel").at(-1);
- expect(panel).toHaveStyle({ width: "320px" });
+ mockMatchingMediaQuery(null);
+ renderWithProviders(
+ some content,
+ );
+ expect(screen.getByTestId("sidebar__panel")).toHaveStyle({
+ width: "320px",
+ });
});
test("Uses the minimum width on smaller screens", () => {
- mockSmallScreen(true);
- render(some content);
- const panel = screen.getAllByTestId("sidebar__panel").at(-1);
- expect(panel).toHaveStyle({ width: "280px" });
+ mockMatchingMediaQuery(SMALL_SIDEBAR_PROJECT_TYPE);
+ renderWithProviders(
+ some content,
+ );
+ expect(screen.getByTestId("sidebar__panel")).toHaveStyle({
+ width: "280px",
+ });
+ });
+
+ test("Uses the minimum width sooner for project types that need more room", () => {
+ mockMatchingMediaQuery(
+ SMALL_SIDEBAR_PROJECT_TYPE_BREAKPOINTS.code_editor_scratch,
+ );
+ renderWithProviders(
+ some content,
+ {
+ preloadedState: {
+ editor: { project: { project_type: "code_editor_scratch" } },
+ },
+ },
+ );
+ expect(screen.getByTestId("sidebar__panel")).toHaveStyle({
+ width: "280px",
+ });
+ });
+
+ test("Uses the default width at that same size for other project types", () => {
+ mockMatchingMediaQuery(
+ SMALL_SIDEBAR_PROJECT_TYPE_BREAKPOINTS.code_editor_scratch,
+ );
+ renderWithProviders(
+ some content,
+ {
+ preloadedState: {
+ editor: { project: { project_type: "python" } },
+ },
+ },
+ );
+ expect(screen.getByTestId("sidebar__panel")).toHaveStyle({
+ width: "320px",
+ });
});
test("Keeps its width when the screen size changes", () => {
- mockSmallScreen(true);
- const { rerender } = render(
+ mockMatchingMediaQuery(SMALL_SIDEBAR_PROJECT_TYPE);
+ const { rerender } = renderWithProviders(
some content,
);
- mockSmallScreen(false);
+ mockMatchingMediaQuery(null);
rerender(some content);
- const panel = screen.getAllByTestId("sidebar__panel").at(-1);
- expect(panel).toHaveStyle({ width: "280px" });
+ expect(screen.getByTestId("sidebar__panel")).toHaveStyle({
+ width: "280px",
+ });
});
});
diff --git a/src/utils/mediaQueryBreakpoints.js b/src/utils/mediaQueryBreakpoints.js
index 6f60bb927..1da98634b 100644
--- a/src/utils/mediaQueryBreakpoints.js
+++ b/src/utils/mediaQueryBreakpoints.js
@@ -1,4 +1,2 @@
export const MOBILE_BREAKPOINT = "600px";
export const MOBILE_MEDIA_QUERY = `(max-width: ${MOBILE_BREAKPOINT})`;
-export const SMALL_SCREEN_BREAKPOINT = "1146px";
-export const SMALL_SCREEN_MEDIA_QUERY = `(max-width: ${SMALL_SCREEN_BREAKPOINT})`;