Skip to content

Commit b1a8ced

Browse files
committed
plugin system for sidebar panels
1 parent fffd3e9 commit b1a8ced

6 files changed

Lines changed: 43 additions & 8 deletions

File tree

src/components/Editor/Project/Project.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const Project = (props) => {
2222
withProjectbar = true,
2323
withSidebar = true,
2424
sidebarOptions = [],
25+
plugins = [],
2526
} = props;
2627
const saving = useSelector((state) => state.editor.saving);
2728
const autosave = useSelector((state) => state.editor.lastSaveAutosave);
@@ -59,7 +60,7 @@ const Project = (props) => {
5960
"proj-container--wc": webComponent,
6061
})}
6162
>
62-
{withSidebar && <Sidebar options={sidebarOptions} />}
63+
{withSidebar && <Sidebar options={sidebarOptions} plugins={plugins} />}
6364
<div className="project-wrapper" ref={containerRef}>
6465
{withProjectbar && <ProjectBar nameEditable={nameEditable} />}
6566
{!loading && (

src/components/Menus/Sidebar/Sidebar.jsx

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ import { MOBILE_MEDIA_QUERY } from "../../../utils/mediaQueryBreakpoints";
2323
import FileIcon from "../../../utils/FileIcon";
2424
import DownloadPanel from "./DownloadPanel/DownloadPanel";
2525
import InstructionsPanel from "./InstructionsPanel/InstructionsPanel";
26+
import SidebarPanel from "./SidebarPanel";
2627

27-
const Sidebar = ({ options = [] }) => {
28+
const Sidebar = ({ options = [], plugins = [] }) => {
2829
const { t } = useTranslation();
2930

3031
let menuOptions = [
@@ -79,6 +80,22 @@ const Sidebar = ({ options = [] }) => {
7980
},
8081
].filter((option) => options.includes(option.name));
8182

83+
let pluginMenuOptions = plugins.map((plugin) => {
84+
return {
85+
name: plugin.name,
86+
icon: plugin.icon,
87+
title: plugin.title,
88+
position: plugin.position || "top",
89+
panel: () => (
90+
<SidebarPanel heading={plugin.heading} Button={plugin.button}>
91+
{plugin.panel()}
92+
</SidebarPanel>
93+
),
94+
};
95+
});
96+
97+
menuOptions = [...menuOptions, ...pluginMenuOptions];
98+
8299
const isMobile = useMediaQuery({ query: MOBILE_MEDIA_QUERY });
83100
const projectImages = useSelector((state) => state.editor.project.image_list);
84101
const instructionsSteps = useSelector(
@@ -103,17 +120,23 @@ const Sidebar = ({ options = [] }) => {
103120
removeOption("instructions", instructionsSteps);
104121
}
105122

123+
const autoOpenPlugin = plugins?.find((plugin) => plugin.autoOpen);
124+
106125
const [option, setOption] = useState(
107-
instructionsEditable || instructionsSteps ? "instructions" : "file",
126+
autoOpenPlugin
127+
? autoOpenPlugin.name
128+
: instructionsEditable || instructionsSteps
129+
? "instructions"
130+
: "file",
108131
);
109132

110133
const hasInstructions = instructionsSteps && instructionsSteps.length > 0;
111134

112135
useEffect(() => {
113-
if (instructionsEditable || hasInstructions) {
136+
if (!autoOpenPlugin && (instructionsEditable || hasInstructions)) {
114137
setOption("instructions");
115138
}
116-
}, [instructionsEditable, hasInstructions]);
139+
}, [autoOpenPlugin, instructionsEditable, hasInstructions]);
117140

118141
const toggleOption = (newOption) => {
119142
if (option !== newOption) {

src/components/Mobile/MobileProject/MobileProject.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { useTranslation } from "react-i18next";
1414
import Sidebar from "../../Menus/Sidebar/Sidebar";
1515
import { showSidebar } from "../../../redux/EditorSlice";
1616

17-
const MobileProject = ({ withSidebar, sidebarOptions = [] }) => {
17+
const MobileProject = ({ withSidebar, sidebarOptions = [], plugins = [] }) => {
1818
const projectType = useSelector((state) => state.editor.project.project_type);
1919
const sidebarShowing = useSelector((state) => state.editor.sidebarShowing);
2020
const codeRunTriggered = useSelector(
@@ -48,7 +48,7 @@ const MobileProject = ({ withSidebar, sidebarOptions = [] }) => {
4848
>
4949
{withSidebar && (
5050
<TabPanel>
51-
<Sidebar options={sidebarOptions} />
51+
<Sidebar options={sidebarOptions} plugins={plugins} />
5252
</TabPanel>
5353
)}
5454
<TabPanel>

src/components/WebComponentProject/WebComponentProject.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const WebComponentProject = ({
3535
outputOnly = false,
3636
outputPanels = ["text", "visual"],
3737
outputSplitView = false,
38+
plugins = [],
3839
}) => {
3940
const loading = useSelector((state) => state.editor.loading);
4041
const project = useSelector((state) => state.editor.project);
@@ -145,13 +146,15 @@ const WebComponentProject = ({
145146
<MobileProject
146147
withSidebar={withSidebar}
147148
sidebarOptions={sidebarOptions}
149+
plugins={plugins}
148150
/>
149151
) : (
150152
<Project
151153
nameEditable={nameEditable}
152154
withProjectbar={withProjectbar}
153155
withSidebar={withSidebar}
154156
sidebarOptions={sidebarOptions}
157+
plugins={plugins}
155158
/>
156159
))}
157160
{outputOnly && (

src/containers/WebComponentLoader.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const WebComponentLoader = (props) => {
4747
outputOnly = false,
4848
outputPanels = ["text", "visual"],
4949
outputSplitView = false,
50+
plugins = [],
5051
projectNameEditable = false,
5152
reactAppApiEndpoint = process.env.REACT_APP_API_ENDPOINT,
5253
readOnly = false,
@@ -227,6 +228,7 @@ const WebComponentLoader = (props) => {
227228
outputPanels={outputPanels}
228229
outputSplitView={outputSplitView}
229230
editableInstructions={editableInstructions}
231+
plugins={plugins}
230232
/>
231233
{errorModalShowing && <ErrorModal />}
232234
{newFileModalShowing && <NewFileModal />}

src/web-component.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class WebComponent extends HTMLElement {
2727
mountPoint;
2828
componentAttributes = {};
2929
componentProperties = {};
30+
plugins = [];
3031

3132
connectedCallback() {
3233
if (!this.shadowRoot) {
@@ -112,6 +113,11 @@ class WebComponent extends HTMLElement {
112113
this.mountReactApp();
113114
}
114115

116+
setPlugins(plugins) {
117+
this.plugins = plugins;
118+
this.mountReactApp();
119+
}
120+
115121
get editorCode() {
116122
const state = store.getState();
117123
return state.editor.project.components[0]?.content;
@@ -177,7 +183,7 @@ class WebComponent extends HTMLElement {
177183
<React.StrictMode>
178184
<Provider store={store}>
179185
<BrowserRouter>
180-
<WebComponentLoader {...this.reactProps()} />
186+
<WebComponentLoader plugins={this.plugins} {...this.reactProps()} />
181187
</BrowserRouter>
182188
</Provider>
183189
</React.StrictMode>,

0 commit comments

Comments
 (0)