Created
June 13, 2025 16:46
-
-
Save manzyuk/f6ba0f74a8de58c1f947adb4b4ae50cc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<body style="margin: 0"> | |
<div id="root"></div> | |
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script> | |
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script> | |
<script src="https://unpkg.com/@babel/[email protected]/babel.js"></script> | |
<script src="https://unpkg.com/@babel/[email protected]/babel.js"></script> | |
<script type="text/babel"> | |
const items = [ | |
{ id: 1, label: "Item 1", details: "Details for item 1" }, | |
{ id: 2, label: "Item 2", details: "Details for item 2" }, | |
{ id: 3, label: "Item 3", details: "Details for item 3" }, | |
]; | |
function SlidingPanelList() { | |
const [selected, setSelected] = React.useState(null); | |
const [panelVisible, setPanelVisible] = React.useState(false); | |
const [nextState, setNextState] = React.useState({ | |
nextSelected: null, | |
nextPanelVisible: false, | |
}); | |
const panelRef = React.useRef(); | |
const handleTransformTransitionEnd = (e) => { | |
if (e.propertyName !== "transform") { | |
return; | |
} | |
const { nextSelected, nextPanelVisible } = nextState; | |
setSelected(nextSelected); | |
setPanelVisible(nextPanelVisible); | |
}; | |
React.useEffect(() => { | |
if (panelRef.current) { | |
panelRef.current.addEventListener( | |
"transitionend", | |
handleTransformTransitionEnd | |
); | |
} | |
return () => { | |
if (panelRef.current) { | |
panelRef.current.removeEventListener( | |
"transitionend", | |
handleTransformTransitionEnd | |
); | |
} | |
}; | |
}); | |
const handleClick = (id) => { | |
if (selected === id) { | |
setPanelVisible(false); | |
setNextState({ nextSelected: null, nextPanelVisible: false }); | |
} else if (selected !== null) { | |
setPanelVisible(false); | |
setNextState({ nextSelected: id, nextPanelVisible: true }); | |
} else { | |
setPanelVisible(true); | |
setNextState({ nextSelected: id, nextPanelVisible: true }); | |
} | |
}; | |
const panelItem = items.find((item) => item.id === selected); | |
return ( | |
<div style={{ display: "flex", height: 400 }}> | |
<ul | |
style={{ | |
width: "100%", | |
borderRight: "1px solid #ccc", | |
margin: 0, | |
padding: 0, | |
listStyle: "none", | |
}} | |
> | |
{items.map((item) => ( | |
<li | |
key={item.id} | |
style={{ | |
padding: 16, | |
cursor: "pointer", | |
background: selected === item.id ? "#f0f0f0" : undefined, | |
}} | |
onClick={() => handleClick(item.id)} | |
> | |
{item.label} | |
</li> | |
))} | |
</ul> | |
<div | |
style={{ | |
width: "20%", | |
position: "relative", | |
overflow: "visible", | |
}} | |
> | |
<div | |
ref={panelRef} | |
style={{ | |
position: "absolute", | |
top: 0, | |
right: 0, | |
width: "100%", | |
height: "100%", | |
background: "#fff", | |
boxShadow: "-2px 0 8px rgba(0,0,0,0.1)", | |
transform: panelVisible | |
? "translateX(0)" | |
: "translateX(100%)", | |
transition: "transform 0.3s cubic-bezier(.4,0,.2,1)", | |
pointerEvents: panelVisible ? "auto" : "none", | |
// opacity: panelVisible ? 1 : 0, | |
}} | |
> | |
{panelItem && ( | |
<div style={{ padding: 24 }}> | |
<h3>{panelItem.label}</h3> | |
<p>{panelItem.details}</p> | |
</div> | |
)} | |
</div> | |
</div> | |
</div> | |
); | |
} | |
ReactDOM.render(<SlidingPanelList />, document.getElementById("root")); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment