got working toggle tabs! I don't like HeadlessUI's Tabs, they don't appear to support programmatic opening
This commit is contained in:
@@ -65,8 +65,13 @@ const IdeHeader = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-16 w-full bg-ch-gray-900 flex justify-between items-center text-lg">
|
<div className="h-16 w-full bg-ch-gray-900 flex justify-between items-center text-lg">
|
||||||
{_projectId ? (
|
<div className="h-full text-gray-300 flex items-center">
|
||||||
<div className="h-full text-gray-300 flex items-center">
|
<div className="w-14 h-16 flex items-center justify-center bg-ch-gray-900">
|
||||||
|
<Link to={routes.home()}>
|
||||||
|
<Svg className="w-12 p-0.5" name="favicon" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
{_projectId && <>
|
||||||
<span className="bg-ch-gray-700 h-full grid grid-flow-col-dense items-center gap-2 px-4">
|
<span className="bg-ch-gray-700 h-full grid grid-flow-col-dense items-center gap-2 px-4">
|
||||||
<Gravatar
|
<Gravatar
|
||||||
image={project?.user?.image || projectOwnerImage}
|
image={project?.user?.image || projectOwnerImage}
|
||||||
@@ -87,10 +92,8 @@ const IdeHeader = ({
|
|||||||
canEdit={canEdit}
|
canEdit={canEdit}
|
||||||
shouldRouteToIde={!projectTitle}
|
shouldRouteToIde={!projectTitle}
|
||||||
/>
|
/>
|
||||||
</div>
|
</>}
|
||||||
) : (
|
</div>
|
||||||
<div />
|
|
||||||
)}
|
|
||||||
<div className="text-gray-200 grid grid-flow-col-dense gap-4 mr-4 items-center">
|
<div className="text-gray-200 grid grid-flow-col-dense gap-4 mr-4 items-center">
|
||||||
{canEdit && !projectTitle && (
|
{canEdit && !projectTitle && (
|
||||||
<CaptureButton
|
<CaptureButton
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
import { ReactNode, useState } from 'react'
|
||||||
import { Link, routes } from '@redwoodjs/router'
|
import { Link, routes } from '@redwoodjs/router'
|
||||||
import { Tab } from '@headlessui/react'
|
import { Tab } from '@headlessui/react'
|
||||||
import Svg, { SvgNames } from 'src/components/Svg/Svg'
|
import Svg, { SvgNames } from 'src/components/Svg/Svg'
|
||||||
import { ReactNode } from 'react'
|
|
||||||
|
|
||||||
interface SidebarConfigType {
|
interface SidebarConfigType {
|
||||||
name: string,
|
name: string,
|
||||||
@@ -15,13 +15,13 @@ const sidebarTopConfig : SidebarConfigType[] = [
|
|||||||
name: 'Files',
|
name: 'Files',
|
||||||
icon: 'files',
|
icon: 'files',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
panel: () => { <h2>Some Files!</h2> },
|
panel: <h2>Some Files!</h2>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'GitHub',
|
name: 'GitHub',
|
||||||
icon: 'github',
|
icon: 'github',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
panel: () => { <h2>Le GitHub Integration™️</h2> },
|
panel: <h2>Le GitHub Integration™️</h2>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Visibility',
|
name: 'Visibility',
|
||||||
@@ -40,42 +40,74 @@ const sidebarBottomConfig : SidebarConfigType[] = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const IdeSideBar = () => {
|
const combinedConfig = [
|
||||||
|
...sidebarTopConfig,
|
||||||
|
...sidebarBottomConfig,
|
||||||
|
]
|
||||||
|
|
||||||
|
function TabToggle({ item, className = "", active, onChange, onClick }) {
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex flex-col justify-between">
|
<label
|
||||||
<div className="w-14 h-16 flex items-center justify-center bg-ch-gray-900">
|
key={'tab-'+item.name}
|
||||||
<Link to={routes.home()}>
|
className={`tabToggle${item.disabled ? ' disabled' : ''}${active ? ' active' : ''} ${className}`}>
|
||||||
<Svg className="w-12 p-0.5" name="favicon" />
|
<input name="sidebar-tabs"
|
||||||
</Link>
|
type="radio"
|
||||||
</div>
|
disabled={item.disabled}
|
||||||
<Tab.Group vertical>
|
value={ item.name }
|
||||||
<Tab.List className="h-full flex flex-col justify-between">
|
onChange={ onChange }
|
||||||
<div>
|
onClick={ onClick }
|
||||||
{ sidebarTopConfig.map(topItem => (
|
className="visually-hidden"
|
||||||
<Tab disabled={topItem.disabled}
|
/>
|
||||||
key={'tab-'+topItem.name}
|
<Svg name={item.icon} className="w-8 mx-auto"/>
|
||||||
className="text-gray-300 p-3 pb-6 flex justify-center">
|
</label>
|
||||||
<Svg name={topItem.icon} className="w-8 mx-auto"/>
|
)
|
||||||
</Tab>
|
}
|
||||||
|
|
||||||
|
const IdeSideBar = () => {
|
||||||
|
const [selectedTab, setSelectedTab] = useState("")
|
||||||
|
const [lastOpen, setLastOpen] = useState("")
|
||||||
|
|
||||||
|
function onTabClick(name) {
|
||||||
|
return function() {
|
||||||
|
if (selectedTab === name) {
|
||||||
|
setLastOpen(selectedTab)
|
||||||
|
setSelectedTab("")
|
||||||
|
} else if (selectedTab === "" && lastOpen === name) {
|
||||||
|
setSelectedTab(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="flex h-full bg-ch-gray-700">
|
||||||
|
<fieldset className="h-full flex flex-col justify-between border-r-2 border-ch-gray-900">
|
||||||
|
<div>
|
||||||
|
{ sidebarTopConfig.map((topItem, i) => (
|
||||||
|
<TabToggle
|
||||||
|
item={topItem}
|
||||||
|
active={ selectedTab === topItem.name }
|
||||||
|
onChange={ () => setSelectedTab(topItem.name) }
|
||||||
|
onClick={ onTabClick(topItem.name) }
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{ sidebarBottomConfig.map(bottomItem => (
|
{ sidebarBottomConfig.map((bottomItem, i) => (
|
||||||
<Tab disabled={bottomItem.disabled}
|
<TabToggle
|
||||||
key={'tab-'+bottomItem.name}
|
item={bottomItem}
|
||||||
className="text-gray-300 p-3 pb-6 flex justify-center">
|
active={ selectedTab === bottomItem.name }
|
||||||
<Svg name={bottomItem.icon} className="w-8 mx-auto" />
|
onChange={ () => setSelectedTab(bottomItem.name) }
|
||||||
</Tab>
|
onClick={ onTabClick(bottomItem.name) }
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</Tab.List>
|
</fieldset>
|
||||||
<Tab.Panels>
|
{ combinedConfig.find(item => item.name === selectedTab)?.panel && (
|
||||||
{ ([...sidebarTopConfig, ...sidebarBottomConfig]).map(item => item.panel && (
|
<div className="w-56 h-full bg-ch-gray-700 py-4 px-2 text-ch-gray-300 border-t-2 border-ch-gray-900">
|
||||||
<Tab.Panel key={'panel-'+item.name}>{ item.panel }</Tab.Panel>
|
{ combinedConfig.find(item => item.name === selectedTab).panel }
|
||||||
)) }
|
</div>
|
||||||
</Tab.Panels>
|
) }
|
||||||
</Tab.Group>
|
</section>
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,15 +24,17 @@ const IdeWrapper = ({ cadPackage }: Props) => {
|
|||||||
useIdeInit(cadPackage, project?.code || state?.code)
|
useIdeInit(cadPackage, project?.code || state?.code)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full flex">
|
<div className="h-full flex flex-col">
|
||||||
<div className="w-14 bg-ch-gray-700 flex-shrink-0">
|
<nav className="flex">
|
||||||
<IdeSideBar />
|
|
||||||
</div>
|
|
||||||
<div className="h-full flex flex-grow flex-col">
|
|
||||||
<nav className="flex">
|
|
||||||
<IdeHeader handleRender={onRender} />
|
<IdeHeader handleRender={onRender} />
|
||||||
</nav>
|
</nav>
|
||||||
<IdeContainer />
|
<div className="h-full flex flex-grow bg-ch-gray-900">
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<IdeSideBar />
|
||||||
|
</div>
|
||||||
|
<div className="h-full flex flex-grow">
|
||||||
|
<IdeContainer />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,6 +17,29 @@
|
|||||||
body {
|
body {
|
||||||
font-family: 'Fira Sans', ui-sans-serif, system-ui, -apple-system, system-ui, "Segoe UI", "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
font-family: 'Fira Sans', ui-sans-serif, system-ui, -apple-system, system-ui, "Segoe UI", "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* https://www.a11yproject.com/posts/2013-01-11-how-to-hide-content/ */
|
||||||
|
.visually-hidden {
|
||||||
|
clip: rect(0 0 0 0);
|
||||||
|
clip-path: inset(50%);
|
||||||
|
height: 1px;
|
||||||
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer components {
|
||||||
|
.tabToggle {
|
||||||
|
@apply text-ch-gray-300 p-3 mb-3 flex justify-center;
|
||||||
|
}
|
||||||
|
.tabToggle.active {
|
||||||
|
@apply bg-ch-pink-800 text-ch-pink-300 bg-opacity-30;
|
||||||
|
}
|
||||||
|
.tabToggle.disabled {
|
||||||
|
@apply text-ch-gray-550 cursor-not-allowed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user