Merge pull request #507 from Irev-Dev/sidebar-tray

Sidebar tray
This commit was merged in pull request #507.
This commit is contained in:
Kurt Hutten
2021-09-18 16:22:13 +10:00
committed by GitHub
14 changed files with 513 additions and 176 deletions

View File

@@ -13,7 +13,7 @@
]
},
"dependencies": {
"@headlessui/react": "^1.0.0",
"@headlessui/react": "^1.4.1",
"@heroicons/react": "^1.0.4",
"@material-ui/core": "^4.11.0",
"@monaco-editor/react": "^4.0.11",

View File

@@ -34,9 +34,16 @@ const EditorMenu = () => {
))}
</div>
<button
className="text-ch-gray-300 h-full cursor-not-allowed"
className="text-ch-gray-300 h-full"
aria-label="editor settings"
disabled
onClick={() =>
thunkDispatch((dispatch) =>
dispatch({
type: 'settingsButtonClicked',
payload: ['Settings', 'editor'],
})
)
}
>
<Svg name="gear" className="w-6 p-px" />
</button>

View File

@@ -42,19 +42,40 @@ const ELEMENT_MAP = {
}
const TOOLBAR_MAP = {
Editor: (
Editor: () => (
<div className="w-full">
<EditorMenu />
</div>
),
Viewer: (
Viewer: (thunkDispatch) => (
<div>
<PanelToolbar panelName="Viewer" />
<PanelToolbar
panelName="Viewer"
onClick={() =>
thunkDispatch((dispatch) =>
dispatch({
type: 'settingsButtonClicked',
payload: ['Settings', 'viewer'],
})
)
}
/>
</div>
),
Console: (
Console: (thunkDispatch) => (
<div>
<PanelToolbar panelName="Console" showTopGradient />
<PanelToolbar
panelName="Console"
showTopGradient
onClick={() =>
thunkDispatch((dispatch) =>
dispatch({
type: 'settingsButtonClicked',
payload: ['Settings', 'console'],
})
)
}
/>
</div>
),
}
@@ -74,7 +95,7 @@ const IdeContainer = () => {
return (
<MosaicWindow
path={path}
renderToolbar={() => TOOLBAR_MAP[id]}
renderToolbar={() => TOOLBAR_MAP[id](thunkDispatch)}
className={`${id.toLowerCase()} ${id.toLowerCase()}-tile`}
>
{id === 'Viewer' ? (

View File

@@ -68,32 +68,37 @@ const IdeHeader = ({
return (
<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">
<span className="bg-ch-gray-700 h-full grid grid-flow-col-dense items-center gap-2 px-4">
<Gravatar
image={project?.user?.image || projectOwnerImage}
className="w-10"
/>
<Link
to={routes.user({
userName: _projectOwner,
})}
>
{_projectOwner}
</Link>
</span>
<EditableProjectTitle
id={_projectId}
userName={_projectOwner}
projectTitle={project?.title || projectTitle}
canEdit={canEdit}
shouldRouteToIde={!projectTitle}
/>
<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>
) : (
<div />
)}
{_projectId && (
<>
<span className="bg-ch-gray-700 h-full grid grid-flow-col-dense items-center gap-2 px-4">
<Gravatar
image={project?.user?.image || projectOwnerImage}
className="w-10"
/>
<Link
to={routes.user({
userName: _projectOwner,
})}
>
{_projectOwner}
</Link>
</span>
<EditableProjectTitle
id={_projectId}
userName={_projectOwner}
projectTitle={project?.title || projectTitle}
canEdit={canEdit}
shouldRouteToIde={!projectTitle}
/>
</>
)}
</div>
<div className="text-gray-200 grid grid-flow-col-dense gap-4 mr-4 items-center">
{!children ? (
<DefaultTopButtons

View File

@@ -1,22 +1,84 @@
import { Link, routes } from '@redwoodjs/router'
import { useState } from 'react'
import Svg from 'src/components/Svg/Svg'
import {
sidebarTopConfig,
sidebarBottomConfig,
sidebarCombinedConfig,
} from './sidebarConfig'
import { useIdeContext } from 'src/helpers/hooks/useIdeContext'
function TabToggle({ item, className = '', active, onChange, onClick }) {
return (
<label
className={`tabToggle${item.disabled ? ' disabled' : ''}${
active ? ' active' : ''
} ${className}`}
>
<input
name="sidebar-tabs"
type="radio"
disabled={item.disabled}
value={item.name}
onChange={onChange}
onClick={onClick}
className="sr-only"
/>
<Svg name={item.icon} className="w-8 mx-auto" />
</label>
)
}
const IdeSideBar = () => {
const { state, thunkDispatch } = useIdeContext()
function onTabClick(name) {
return function () {
thunkDispatch({ type: 'settingsButtonClicked', payload: [name] })
}
}
const selectedTab = React.useMemo(
() => sidebarCombinedConfig.find((item) => item.name === state.sideTray[0]),
[state.sideTray]
)
return (
<div className="h-full flex flex-col justify-between">
<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>
<button
className="text-gray-300 p-3 pb-6 flex justify-center cursor-not-allowed"
aria-label="IDE settings"
disabled
>
<Svg name="gear" />
</button>
</div>
<section className="flex h-full bg-ch-gray-900">
<fieldset className="h-full flex flex-col justify-between bg-ch-gray-700">
<div>
{sidebarTopConfig.map((topItem, i) => (
<TabToggle
item={topItem}
active={state.sideTray[0] === topItem.name}
onChange={() => onTabClick(topItem.name)}
onClick={onTabClick(topItem.name)}
key={'tab-' + i}
/>
))}
</div>
<div>
{sidebarBottomConfig.map((bottomItem, i) => (
<TabToggle
item={bottomItem}
active={state.sideTray[0] === bottomItem.name}
onChange={() => onTabClick(bottomItem.name)}
onClick={onTabClick(bottomItem.name)}
key={'tab-' + (sidebarTopConfig.length + i)}
/>
))}
</div>
</fieldset>
{selectedTab?.panel && (
<div
className="w-56 bg-ch-gray-900 text-ch-gray-300 border border-ch-pink-800 border-opacity-30"
style={{ height: 'calc(100% - 6px)', margin: '3px' }}
>
<h2 className="flex items-center h-9 px-4 bg-ch-pink-800 bg-opacity-30">
{selectedTab.name}
</h2>
{selectedTab.panel}
</div>
)}
</section>
)
}

View File

@@ -0,0 +1,156 @@
import React, { ReactNode } from 'react'
import { SvgNames } from 'src/components/Svg/Svg'
import { useIdeContext } from 'src/helpers/hooks/useIdeContext'
interface SidebarConfigType {
name: string
icon: SvgNames
disabled: boolean
panel: ReactNode | null
}
export const sidebarTopConfig: SidebarConfigType[] = [
{
name: 'Files',
icon: 'files',
disabled: false,
panel: (
<article className="px-2 py-4">
<p>
<em>Coming Soon</em>
</p>
<hr className="my-4" />
<p>
We're working on multi-file support in tandem with the GitHub
integration.
</p>
</article>
),
},
{
name: 'GitHub',
icon: 'github',
disabled: false,
panel: (
<article className="px-2 py-4">
<p>
<em>Coming Soon</em>
</p>
<hr className="my-4" />
<p>
This integration will allow you to sync a project with a GitHub repo
and push changes back to it as a commit!
</p>
</article>
),
},
{
name: 'Visibility',
icon: 'eye',
disabled: true,
panel: null,
},
]
const DiscordLink = () => (
<a className="underline text-ch-pink-300"
href="https://discord.gg/SD7zFRNjGH"
target="_blank"
rel="noreferrer"
>
Discord
</a>
)
const settingsConfig = [
{
title: 'Editor',
name: 'editor',
open: false,
content: (
<div className="p-2">
<p>
<em>Coming Soon</em>
</p>
<hr className="my-2" />
<p className="p-2">
We're building configuration settings for the Viewer pane now. Join us on <DiscordLink/> if you want to lend a hand!
</p>
</div>
),
},
{
title: 'Viewer',
name: 'viewer',
open: false,
content: (
<div className="p-2">
<p>
<em>Coming Soon</em>
</p>
<hr className="my-2" />
<p className="p-2">
We're building configuration settings for the Viewer pane now. Join us on <DiscordLink/> if you want to lend a hand!
</p>
</div>
),
},
{
title: 'Console',
name: 'console',
open: false,
content: (
<div className="p-2">
<p>
<em>Coming Soon</em>
</p>
<hr className="my-2" />
<p className="p-2">
We're building configuration settings for the Viewer pane now. Join us on <DiscordLink/> if you want to lend a hand!
</p>
</div>
),
},
]
export const sidebarBottomConfig: SidebarConfigType[] = [
{
name: 'Settings',
icon: 'gear',
disabled: false,
panel: <SettingsMenu parentName="Settings" />,
},
]
export const sidebarCombinedConfig = [
...sidebarTopConfig,
...sidebarBottomConfig,
]
function SettingsMenu({ parentName }: { parentName: string }) {
const { state, thunkDispatch } = useIdeContext()
return (
<article className="">
{settingsConfig.map((item) => (
<details
key={'settings-tray-' + item.name}
open={state.sideTray.slice(-1)[0] === item.name}
onClick={(e) => {
e.preventDefault()
thunkDispatch((dispatch) =>
dispatch({
type: 'settingsButtonClicked',
payload: [parentName, item.name],
})
)
}}
>
<summary className="px-2 py-2 bg-ch-pink-800 bg-opacity-10 my-px cursor-pointer">
{item.title}
</summary>
{item.content}
</details>
))}
</article>
)
}

View File

@@ -30,16 +30,18 @@ const IdeWrapper = ({ cadPackage }: Props) => {
}
return (
<div className="h-full flex">
<div className="h-full flex flex-col">
<ShortcutsModalContext.Provider value={shortcutModalContextValues}>
<div className="w-16 bg-ch-gray-700 flex-shrink-0">
<IdeSideBar />
</div>
<div className="h-full flex flex-grow flex-col">
<nav className="flex">
<IdeHeader handleRender={onRender} />
</nav>
<IdeContainer />
<nav className="flex">
<IdeHeader handleRender={onRender} />
</nav>
<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>
</ShortcutsModalContext.Provider>
</div>

View File

@@ -1,4 +1,4 @@
import { useContext } from 'react'
import { MouseEventHandler, useContext } from 'react'
import { MosaicWindowContext } from 'react-mosaic-component'
import Svg from 'src/components/Svg/Svg'
import OpenscadStaticImageMessage from 'src/components/OpenscadStaticImageMessage/OpenscadStaticImageMessage'
@@ -6,9 +6,11 @@ import OpenscadStaticImageMessage from 'src/components/OpenscadStaticImageMessag
const PanelToolbar = ({
panelName,
showTopGradient,
onClick,
}: {
panelName: 'Viewer' | 'Console'
showTopGradient?: boolean
onClick?: MouseEventHandler
}) => {
const { mosaicWindowActions } = useContext(MosaicWindowContext)
return (
@@ -19,9 +21,13 @@ const PanelToolbar = ({
<div className="absolute top-0 right-0 flex items-center h-9">
{panelName === 'Viewer' && <OpenscadStaticImageMessage />}
<button
className="bg-ch-gray-760 text-ch-gray-300 px-3 rounded-bl-lg h-full cursor-not-allowed"
className={
'bg-ch-gray-760 text-ch-gray-300 px-3 rounded-bl-lg h-full ' +
(!onClick ? 'cursor-not-allowed' : '')
}
aria-label={`${panelName} settings`}
disabled
onClick={onClick}
disabled={!onClick}
>
<Svg name="gear" className="w-7 p-0.5" />
</button>

View File

@@ -70,12 +70,6 @@ const ProjectProfile = ({
<>
<div className="h-screen flex flex-col text-lg font-fira-sans">
<div className="flex">
<Link
to={routes.home()}
className="w-16 h-16 flex items-center justify-center bg-ch-gray-900"
>
<Svg className="w-12" name="favicon" />
</Link>
<IdeHeader
handleRender={() => {}}
projectTitle={project?.title}

View File

@@ -9,12 +9,15 @@ export type SvgNames =
| 'dots-vertical'
| 'drag-grid'
| 'exclamation-circle'
| 'eye'
| 'favicon'
| 'files'
| 'flag'
| 'floppy-disk'
| 'fork'
| 'fork-new'
| 'gear'
| 'github'
| 'lightbulb'
| 'logout'
| 'mac-cmd-key'
@@ -176,6 +179,23 @@ const Svg = ({
/>
</svg>
),
eye: (
<svg viewBox="0 0 34 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M33.6281 10.3992C33.9385 10.0498 33.9385 9.53738 33.6281 9.18801C31.7613 7.08739 25.0664 0.242065 17.0935 0.242065C9.12069 0.242065 2.42579 7.08739 0.559031 9.18801C0.248552 9.53738 0.248552 10.0498 0.559031 10.3992C2.42579 12.4998 9.12069 19.3451 17.0935 19.3451C25.0664 19.3451 31.7613 12.4998 33.6281 10.3992ZM17.0935 17.7936C21.5118 17.7936 25.0935 14.2119 25.0935 9.79359C25.0935 5.37532 21.5118 1.7936 17.0935 1.7936C12.6753 1.7936 9.09354 5.37532 9.09354 9.79359C9.09354 14.2119 12.6753 17.7936 17.0935 17.7936Z"
fill="currentColor"
/>
<ellipse
cx="17.0932"
cy="9.79354"
rx="4.31588"
ry="4.31588"
fill="currentColor"
/>
</svg>
),
favicon: (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2667 2667">
<defs>
@@ -275,6 +295,22 @@ const Svg = ({
</g>
</svg>
),
files: (
<svg viewBox="0 0 30 33" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4.54121 6.31592C3.23314 6.31592 2.17274 7.37633 2.17274 8.6844V28.6849C2.17274 29.9929 3.23314 31.0534 4.54121 31.0534H19.2784C20.5865 31.0534 21.6469 29.9929 21.6469 28.6849V26.342H23.2259V28.6849C23.2259 30.865 21.4585 32.6323 19.2784 32.6323H4.54121C2.36109 32.6323 0.59375 30.865 0.59375 28.6849V8.6844C0.59375 6.50428 2.36109 4.73694 4.54121 4.73694H8.50454V6.31592H4.54121Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M20.871 0H11.699C9.95489 0 8.54102 1.41387 8.54102 3.15797V23.1584C8.54102 24.9025 9.95489 26.3164 11.699 26.3164H26.4362C28.1803 26.3164 29.5942 24.9025 29.5942 23.1584V8.90104L20.871 0ZM26.6096 8.11155L21.6605 3.0615V5.74308C21.6605 7.05115 22.7209 8.11155 24.029 8.11155H26.6096ZM20.0815 1.57898H11.699C10.8269 1.57898 10.12 2.28592 10.12 3.15797V23.1584C10.12 24.0305 10.8269 24.7374 11.699 24.7374H26.4362C27.3082 24.7374 28.0152 24.0305 28.0152 23.1584V9.69054H24.029C21.8489 9.69054 20.0815 7.9232 20.0815 5.74308V1.57898Z"
fill="currentColor"
/>
</svg>
),
flag: (
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -356,6 +392,16 @@ const Svg = ({
/>
</svg>
),
github: (
<svg viewBox="0 0 35 34" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M17.0938 0.632324C7.70125 0.632324 0.09375 8.23982 0.09375 17.6323C0.09375 25.1548 4.96 31.5086 11.7175 33.7611C12.5675 33.9098 12.8862 33.3998 12.8862 32.9536C12.8862 32.5498 12.865 31.2111 12.865 29.7873C8.59375 30.5736 7.48875 28.7461 7.14875 27.7898C6.9575 27.3011 6.12875 25.7923 5.40625 25.3886C4.81125 25.0698 3.96125 24.2836 5.385 24.2623C6.72375 24.2411 7.68 25.4948 7.99875 26.0048C9.52875 28.5761 11.9725 27.8536 12.95 27.4073C13.0988 26.3023 13.545 25.5586 14.0337 25.1336C10.2513 24.7086 6.29875 23.2423 6.29875 16.7398C6.29875 14.8911 6.9575 13.3611 8.04125 12.1711C7.87125 11.7461 7.27625 10.0036 8.21125 7.66607C8.21125 7.66607 9.635 7.21983 12.8862 9.40858C14.2463 9.02608 15.6913 8.83482 17.1363 8.83482C18.5813 8.83482 20.0263 9.02608 21.3863 9.40858C24.6375 7.19858 26.0613 7.66607 26.0613 7.66607C26.9963 10.0036 26.4013 11.7461 26.2313 12.1711C27.315 13.3611 27.9737 14.8698 27.9737 16.7398C27.9737 23.2636 24 24.7086 20.2175 25.1336C20.8337 25.6648 21.365 26.6848 21.365 28.2786C21.365 30.5523 21.3438 32.3798 21.3438 32.9536C21.3438 33.3998 21.6625 33.9311 22.5125 33.7611C29.2275 31.5086 34.0938 25.1336 34.0938 17.6323C34.0938 8.23982 26.4862 0.632324 17.0938 0.632324Z"
fill="currentColor"
/>
</svg>
),
lightbulb: (
<svg
xmlns="http://www.w3.org/2000/svg"

View File

@@ -53,12 +53,6 @@ const UserProfile = ({
<>
<div className="md:h-screen flex flex-col text-lg font-fira-sans">
<div className="flex">
<Link
to={routes.home()}
className="w-16 h-16 flex items-center justify-center bg-ch-gray-900"
>
<Svg className="w-12" name="favicon" />
</Link>
<IdeHeader
handleRender={() => {}}
projectOwner={user?.userName}

View File

@@ -115,6 +115,7 @@ export interface State {
viewerSize: { width: number; height: number }
isLoading: boolean
threeInstance: RootState
sideTray: string[] // could probably be an array of a union type
}
const code = ''
@@ -146,103 +147,133 @@ export const initialState: State = {
viewerSize: { width: 0, height: 0 },
isLoading: false,
threeInstance: null,
sideTray: [],
}
export const useIdeState = (): [State, (actionOrThunk: any) => any] => {
const reducer = (state: State, { type, payload }): State => {
switch (type) {
case 'initIde':
return {
...state,
code:
payload.code ||
// localStorage.getItem(makeCodeStoreKey(payload.cadPackage)) ||
initCodeMap[payload.cadPackage] ||
'',
ideType: payload.cadPackage,
}
case 'updateCode':
return { ...state, code: payload }
case 'healthyRender':
const customizerParams: CadhubParams[] = payload?.customizerParams
?.length
? payload.customizerParams
: state.customizerParams
const currentParameters = {}
customizerParams.forEach((param) => {
currentParameters[param.name] =
typeof state?.currentParameters?.[param.name] !== 'undefined'
? state?.currentParameters?.[param.name]
: param.initial
})
return {
...state,
objectData: {
...state.objectData,
type: payload.objectData?.type,
data: payload.objectData?.data,
},
customizerParams,
currentParameters,
consoleMessages: payload.message
? [...state.consoleMessages, payload.message]
: payload.message,
isLoading: false,
}
case 'errorRender':
return {
...state,
consoleMessages: payload.message
? [...state.consoleMessages, payload.message]
: payload.message,
isLoading: false,
}
case 'setCurrentCustomizerParams':
if (!Object.keys(payload || {}).length) return state
return {
...state,
currentParameters: payload,
}
case 'setLayout':
return {
...state,
layout: payload.message,
}
case 'updateCamera':
return {
...state,
camera: payload.camera,
}
case 'updateViewerSize':
return {
...state,
viewerSize: payload.viewerSize,
}
case 'setLoading':
return {
...state,
isLoading: true,
}
case 'resetLoading':
return {
...state,
isLoading: false,
}
case 'resetLayout':
return {
...state,
layout: initialLayout,
}
case 'setThreeInstance':
return {
...state,
threeInstance: payload,
}
default:
return state
}
}
const reducer = (state: State, { type, payload }): State => {
switch (type) {
case 'initIde':
return {
...state,
code:
payload.code ||
// localStorage.getItem(makeCodeStoreKey(payload.cadPackage)) ||
initCodeMap[payload.cadPackage] ||
'',
ideType: payload.cadPackage,
}
case 'updateCode':
return { ...state, code: payload }
case 'healthyRender':
const customizerParams: CadhubParams[] = payload?.customizerParams?.length
? payload.customizerParams
: state.customizerParams
const currentParameters = {}
customizerParams.forEach((param) => {
currentParameters[param.name] =
typeof state?.currentParameters?.[param.name] !== 'undefined'
? state?.currentParameters?.[param.name]
: param.initial
})
return {
...state,
objectData: {
...state.objectData,
type: payload.objectData?.type,
data: payload.objectData?.data,
},
customizerParams,
currentParameters,
consoleMessages: payload.message
? [...state.consoleMessages, payload.message]
: payload.message,
isLoading: false,
}
case 'errorRender':
return {
...state,
consoleMessages: payload.message
? [...state.consoleMessages, payload.message]
: payload.message,
isLoading: false,
}
case 'setCurrentCustomizerParams':
if (!Object.keys(payload || {}).length) return state
return {
...state,
currentParameters: payload,
}
case 'setLayout':
return {
...state,
layout: payload.message,
}
case 'updateCamera':
return {
...state,
camera: payload.camera,
}
case 'updateViewerSize':
return {
...state,
viewerSize: payload.viewerSize,
}
case 'setLoading':
return {
...state,
isLoading: true,
}
case 'resetLoading':
return {
...state,
isLoading: false,
}
case 'resetLayout':
return {
...state,
layout: initialLayout,
}
case 'setThreeInstance':
return {
...state,
threeInstance: payload,
}
case 'settingsButtonClicked':
const isReClick =
state.sideTray.length &&
state.sideTray.length === payload.length &&
state.sideTray.every((original, index) => original === payload[index])
const payloadInOriginal =
payload.length && state.sideTray.indexOf(payload[0])
const isAncestorClick =
state.sideTray.length &&
state.sideTray.length > payload.length &&
payloadInOriginal >= 0 &&
payload.every(
(incoming, i) => incoming === state.sideTray[i + payloadInOriginal]
)
if (isReClick) {
return {
...state,
sideTray: state.sideTray.slice(0, -1),
}
} else if (isAncestorClick) {
return {
...state,
sideTray: state.sideTray.slice(0, payload.length * -1 - 1),
}
}
return {
...state,
sideTray: payload,
}
default:
return state
}
}
export const useIdeState = (): [State, (actionOrThunk: any) => any] => {
const [state, dispatch] = useReducer(reducer, initialState)
mutableState = state
const getState = (): State => mutableState

View File

@@ -18,17 +18,30 @@
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";
}
/* custom scrollbar */
.ch-scrollbar::-webkit-scrollbar {
@apply w-3;
@apply w-3;
}
.ch-scrollbar::-webkit-scrollbar-track {
@apply bg-ch-gray-700;
}
.ch-scrollbar::-webkit-scrollbar-thumb {
@apply bg-ch-pink-800 bg-opacity-30 hover:bg-opacity-60;
@apply bg-ch-pink-800 bg-opacity-30 hover:bg-opacity-60;
}
}
@layer components {
.tabToggle {
@apply text-ch-gray-300 p-3 mb-1 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;
}
}

View File

@@ -2007,10 +2007,10 @@
resolved "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.0.0.tgz"
integrity sha512-WEezM1FWztfbzqIUbsDzFRVMxSoLy3HugVcux6KDDtTqzPsLE8NDRHfXvev66aH1i2oOKKar3/XDjbvh/OUBdg==
"@headlessui/react@^1.0.0":
version "1.2.0"
resolved "https://registry.npmjs.org/@headlessui/react/-/react-1.2.0.tgz"
integrity sha512-19DkLz8gDgbi+WvkoTzi9vs0NK9TJf94vbYhMzB4LYJo03Kili0gmvXT9CiKZoxXZ7YAvy/b1U1oQKEnjWrqxw==
"@headlessui/react@^1.4.1":
version "1.4.1"
resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.4.1.tgz#0a8dbb20e1d63dcea55bfc3ab1b87637aaac7777"
integrity sha512-gL6Ns5xQM57cZBzX6IVv6L7nsam8rDEpRhs5fg28SN64ikfmuuMgunc+Rw5C1cMScnvFM+cz32ueVrlSFEVlSg==
"@heroicons/react@^1.0.4":
version "1.0.4"