Added DataOptions sidebar.
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import React, {useCallback, useEffect, useState} from 'react';
|
||||
import * as ReactDOM from 'react-dom/client';
|
||||
import {
|
||||
SidebarButtonToggleStyle,
|
||||
SidebarCloseButtonStyle, SidebarDataOptionsStyle,
|
||||
SidebarHeaderStyle,
|
||||
SidebarStyle,
|
||||
} from "./data-options.style.js";
|
||||
import {isClickOutside, isEscHit} from "../responsive-button/ResponsiveButton.jsx";
|
||||
|
||||
function DataOptions(props = {}) {
|
||||
props.rootAttributes = props.rootAttributes ?? {};
|
||||
|
||||
const initialState = {dataName: 'default', data: {}, dataOptions: []};
|
||||
const [state, setState] = useState(initialState);
|
||||
const updateState = (update) => setState(Object.assign({}, state, update));
|
||||
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
|
||||
useEffect(async () => {
|
||||
const data = await fetchDataOptions(state.dataName);
|
||||
updateState(data);
|
||||
}, []);
|
||||
|
||||
const handleCloseSidebarEscEvent = useCallback((e) => {
|
||||
if (isEscHit(e)) {
|
||||
(() => {
|
||||
closeSidebar()
|
||||
})();
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(async () => {
|
||||
document.addEventListener("keydown", handleCloseSidebarEscEvent);
|
||||
|
||||
// Unsubscribe from ESC listener.
|
||||
return () => {
|
||||
document.removeEventListener("keydown", handleCloseSidebarEscEvent);
|
||||
}
|
||||
}, [handleCloseSidebarEscEvent]);
|
||||
|
||||
const handleBlur = async (e) => await isClickOutside(e) ? closeSidebar() : null;
|
||||
|
||||
return <>
|
||||
<SidebarButtonToggleStyle onClick={() => openSidebar()} title="Open a Sidebar with Data Options">#</SidebarButtonToggleStyle>
|
||||
|
||||
<SidebarStyle className={sidebarOpen ? 'active sidebar-active' : ''} tabIndex='0' onBlur={handleBlur}>
|
||||
<SidebarHeaderStyle>
|
||||
<SidebarCloseButtonStyle onClick={() => closeSidebar()}></SidebarCloseButtonStyle>
|
||||
</SidebarHeaderStyle>
|
||||
|
||||
{state.dataOptions && !!state.dataOptions.length &&
|
||||
<SidebarDataOptionsStyle>
|
||||
<label htmlFor="data-options">Data Options</label>
|
||||
|
||||
<select name="data" id="data-options" onChange={(e) => changeDataOption(e)} value={state.dataName}>
|
||||
{state.dataOptions.map((item) => {
|
||||
const isSelected = state.dataName === item;
|
||||
return <option value={item} selected={isSelected}>{item}</option>
|
||||
})}
|
||||
</select>
|
||||
</SidebarDataOptionsStyle>
|
||||
}
|
||||
|
||||
{state.data &&
|
||||
<pre>{JSON.stringify(state.data, null, 2)}</pre>
|
||||
}
|
||||
</SidebarStyle>
|
||||
</>;
|
||||
|
||||
function openSidebar() {
|
||||
setSidebarOpen(true);
|
||||
setTimeout(() => document.querySelector('.sidebar-active').focus());
|
||||
}
|
||||
|
||||
function closeSidebar() {
|
||||
setSidebarOpen(false);
|
||||
}
|
||||
|
||||
async function changeDataOption(e) {
|
||||
const optionName = e.target.value;
|
||||
props.rootAttributes.previewFrame.src = window.devTool.previewFrameUrl + '?data=' + optionName;
|
||||
|
||||
const dataOption = await fetchDataOptions(optionName);
|
||||
updateState({data: dataOption.data, dataName: optionName})
|
||||
}
|
||||
|
||||
async function fetchDataOptions(name = 'default') {
|
||||
const queryParameters = new URLSearchParams({name});
|
||||
const response = await fetch(`/data?${queryParameters}`);
|
||||
return await response.json();
|
||||
}
|
||||
}
|
||||
|
||||
export function setupDataOptions(rootAttributes) {
|
||||
// INIT
|
||||
const wrapper = document.createElement('div');
|
||||
document.querySelector('.page_toolbar__left').prepend(wrapper)
|
||||
|
||||
const root = ReactDOM.createRoot(wrapper);
|
||||
const html = (<DataOptions rootAttributes={rootAttributes}/>);
|
||||
root.render(html);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
export const SidebarStyle = styled.div`
|
||||
--sidebarWidth: 300px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: calc(var(--sidebarWidth) * -1);
|
||||
width: var(--sidebarWidth);
|
||||
background-color: #E2E8F0;
|
||||
border-right: 1px solid #CBD5E0;
|
||||
padding: 0 0.75rem;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
transition: left .2s ease-in-out, visibility .2s ease-in-out;
|
||||
visibility: hidden;
|
||||
color: #333;
|
||||
|
||||
&.active {
|
||||
left: 0;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
pre {
|
||||
overflow-x: auto;
|
||||
padding: 0.5rem;
|
||||
background-color: #EDF2F7;
|
||||
border-radius: 4px;
|
||||
color: #333;
|
||||
border: 1px solid #cbd5e0;
|
||||
}
|
||||
`;
|
||||
|
||||
export const SidebarHeaderStyle = styled.header`
|
||||
min-height: 34px;
|
||||
padding: 0.5rem 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
`;
|
||||
|
||||
export const SidebarButtonToggleStyle = styled.button`
|
||||
--size: 1.5rem;
|
||||
cursor: pointer;
|
||||
border: 0;
|
||||
background-image: url("/scripts/dist/toolbar/images/icon-json.svg");
|
||||
background-repeat: no-repeat;
|
||||
background-size: calc(var(--size) - 0.15rem);
|
||||
background-position: center center;
|
||||
background-color: initial;
|
||||
font-size: 1px;
|
||||
color: rgba(0, 0, 0, 0);
|
||||
line-height: 1;
|
||||
display: block;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
border-radius: 0.25rem;
|
||||
outline: none;
|
||||
`;
|
||||
|
||||
export const SidebarCloseButtonStyle = styled.button`
|
||||
--size: 1.5rem;
|
||||
cursor: pointer;
|
||||
border: 0;
|
||||
background-image: url("/scripts/dist/toolbar/images/icon-close.svg");
|
||||
background-repeat: no-repeat;
|
||||
background-size: calc(var(--size) - 0.15rem);
|
||||
background-position: center center;
|
||||
background-color: initial;
|
||||
font-size: 1px;
|
||||
color: rgba(0, 0, 0, 0);
|
||||
line-height: 1;
|
||||
display: block;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
border-radius: 0.25rem;
|
||||
outline: none;
|
||||
`;
|
||||
|
||||
export const SidebarDataOptionsStyle = styled.div`
|
||||
margin-top: 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
|
||||
select {
|
||||
flex: 1 1;
|
||||
display: block;
|
||||
appearance: none;
|
||||
border: 1px solid #cbd5e0;
|
||||
padding: 0.5rem;
|
||||
color: #333;
|
||||
border-radius: 4px;
|
||||
|
||||
background-color: #edf2f7;
|
||||
background-image: url("/scripts/dist/toolbar/images/icon-dropdown-arrow.svg");
|
||||
background-position: right 0.75rem center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 0.5rem;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48" fill="#21252d">
|
||||
<path
|
||||
d="M12.45 38.7 9.3 35.55 20.85 24 9.3 12.5l3.15-3.2L24 20.8 35.55 9.3l3.15 3.2L27.2 24l11.5 11.55-3.15 3.15L24 27.2Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 218 B |
@@ -0,0 +1,7 @@
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 330 330" style="enable-background:new 0 0 330 330;" xml:space="preserve">
|
||||
<path id="XMLID_225_" d="M325.607,79.393c-5.857-5.857-15.355-5.858-21.213,0.001l-139.39,139.393L25.607,79.393
|
||||
c-5.857-5.857-15.355-5.858-21.213,0.001c-5.858,5.858-5.858,15.355,0,21.213l150.004,150c2.813,2.813,6.628,4.393,10.606,4.393
|
||||
s7.794-1.581,10.606-4.394l149.996-150C331.465,94.749,331.465,85.251,325.607,79.393z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 553 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48" fill="#21252d">
|
||||
<path
|
||||
d="M28.6 40.75V36.2h4.75q1.2 0 2.05-.825.85-.825.85-2.075v-3.85q0-1.8 1.075-3.225T40.15 24.2v-.4q-1.75-.55-2.825-2-1.075-1.45-1.075-3.3v-3.85q0-1.2-.85-2.05-.85-.85-2.05-.85H28.6V7.2h5.95q2.6 0 4.425 1.825Q40.8 10.85 40.8 13.5v3.85q0 1.2.825 2.05.825.85 2.075.85h1.1v7.5h-1.1q-1.25 0-2.075.85-.825.85-.825 2.05v3.85q0 2.65-1.825 4.45-1.825 1.8-4.425 1.8Zm-15.1 0q-2.7 0-4.475-1.8-1.775-1.8-1.775-4.45v-3.85q0-1.2-.85-2.05-.85-.85-2.05-.85h-1.1v-7.5h1.1q1.2 0 2.05-.85.85-.85.85-2.05V13.5q0-2.65 1.8-4.475Q10.85 7.2 13.5 7.2h5.95v4.55H14.7q-1.25 0-2.075.85-.825.85-.825 2.05v3.85q0 1.85-1.1 3.3-1.1 1.45-2.85 2v.4q1.75.6 2.85 2.025 1.1 1.425 1.1 3.225v3.85q0 1.25.825 2.075.825.825 2.075.825h4.75v4.55Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 803 B |
Reference in New Issue
Block a user