diff --git a/apps/web/src/app/app.tsx b/apps/web/src/app/app.tsx index d7839423518dc80024f9e73bb07ec2e3f7ec6776..152e17855f8f4041d5c9f1fb0c74ac2a97fb8c1f 100644 --- a/apps/web/src/app/app.tsx +++ b/apps/web/src/app/app.tsx @@ -78,37 +78,41 @@ export function App(props: App) { <aside className="h-auto w-auto"> <Navbar /> </aside> - <main className="flex w-screen h-[calc(100%-4.2rem)] flex-row"> + <main className="grow flex flex-row"> <Sidebar onTab={(tab) => setTab(tab)} /> <Resizable divisorSize={3} horizontal={true} defaultProportion={0.33}> {tab !== undefined ? ( - <div className="flex-1 border overflow-hidden w-full h-full"> - <div className="relative flex items-center justify-between z-[2] py-0 px-2 bg-secondary-100 border-b"> - <h1 className="text-xs font-semibold text-secondary-800">{tab}</h1> - <ControlContainer> - <TooltipProvider delayDuration={100}> - {tab === 'Schema' && ( - <Tooltip> - <TooltipTrigger asChild> - <Button type="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={() => {}} /> - </TooltipTrigger> - <TooltipContent side={'bottom'}> - <p>Fit to screen</p> - </TooltipContent> - </Tooltip> - )} - {tab === 'Search' && ( - <Tooltip> - <TooltipTrigger asChild> - <Button type="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={() => {}} /> - </TooltipTrigger> - <TooltipContent side={'bottom'}> - <p>Mock icon</p> - </TooltipContent> - </Tooltip> - )} - </TooltipProvider> - </ControlContainer> + <div className="flex flex-col border w-full h-full bg-light"> + <div className="sticky shrink-0 top-0 flex items-stretch justify-between h-7 bg-secondary-100 border-b border-secondary-200 max-w-full"> + <div className="flex items-center"> + <h1 className="text-xs font-semibold text-secondary-600 px-2">{tab}</h1> + </div> + <div className="shrink-0 sticky right-0 px-0.5 ml-auto items-center flex"> + <ControlContainer> + <TooltipProvider delayDuration={100}> + {tab === 'Schema' && ( + <Tooltip> + <TooltipTrigger asChild> + <Button type="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={() => {}} /> + </TooltipTrigger> + <TooltipContent side={'bottom'}> + <p>Fit to screen</p> + </TooltipContent> + </Tooltip> + )} + {tab === 'Search' && ( + <Tooltip> + <TooltipTrigger asChild> + <Button type="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={() => {}} /> + </TooltipTrigger> + <TooltipContent side={'bottom'}> + <p>Mock icon</p> + </TooltipContent> + </Tooltip> + )} + </TooltipProvider> + </ControlContainer> + </div> </div> {tab === 'Search' && <Searchbar />} {tab === 'Schema' && <Schema auth={authCheck} />} @@ -116,19 +120,16 @@ export function App(props: App) { ) : null} <div className="h-full w-full flex-grow"> <Resizable divisorSize={3} horizontal={false}> - <div className="w-full h-full border"> - <VisualizationPanel - manager={manager} - fullSize={() => { - setVisFullSize(!visFullSize); - tab === undefined && setTab('Schema'); - tab !== undefined && setTab(undefined); - }} - /> - </div> - <div className="w-full h-full border"> - <QueryBuilder onRunQuery={runQuery} /> - </div> + <VisualizationPanel + manager={manager} + fullSize={() => { + setVisFullSize(!visFullSize); + tab === undefined && setTab('Schema'); + tab !== undefined && setTab(undefined); + }} + /> + + <QueryBuilder onRunQuery={runQuery} /> </Resizable> </div> </Resizable> diff --git a/apps/web/src/components/navbar/DatabaseManagement/dbConnectionSelector.tsx b/apps/web/src/components/navbar/DatabaseManagement/dbConnectionSelector.tsx index e592fa58e40071f0d4c34bdb7a2b7687f0f8356c..b6cd67af0f0d1c801b4dcc248083542449130f59 100644 --- a/apps/web/src/components/navbar/DatabaseManagement/dbConnectionSelector.tsx +++ b/apps/web/src/components/navbar/DatabaseManagement/dbConnectionSelector.tsx @@ -71,7 +71,7 @@ export default function DatabaseSelector({}) { }, [connecting]); return ( - <div className="menu-walkthrough ml-4"> + <div className="menu-walkthrough"> <TooltipProvider delayDuration={1000}> {settingsMenuOpen !== undefined && ( <SettingsForm @@ -86,8 +86,9 @@ export default function DatabaseSelector({}) { }} /> )} - <DropdownContainer ref={dbSelectionMenuRef} className="w-[20rem]"> + <DropdownContainer ref={dbSelectionMenuRef} className="w-[18rem]"> <DropdownButton + size="md" disabled={connecting || authCache.authorized === false || !!authCache.roomID} title={ <div className="flex items-center"> @@ -98,12 +99,14 @@ export default function DatabaseSelector({}) { </> ) : session.currentSaveState && session.currentSaveState in session.saveStates && session.currentSaveState !== nilUUID ? ( <div className="flex items-center"> - <Icon component={<StorageOutlined />} size={20} /> - <div className="absolute bottom-0 left-0 transform translate-x-2 -translate-y-2"> + <div className="relative self-center"> + <Icon component={<StorageOutlined />} size={20} /> + <div - className={`h-2 w-2 rounded-full ${session.testedSaveState[session.currentSaveState] === DatabaseStatus.tested ? 'bg-success-500' : 'bg-danger-500'}`} + className={`absolute bottom-0 left-0 h-2 w-2 border border-light rounded-full ${session.testedSaveState[session.currentSaveState] === DatabaseStatus.tested ? 'bg-success-500' : 'bg-danger-500'}`} /> </div> + <p className="ml-2 truncate">{session.saveStates[session.currentSaveState].name}</p> </div> ) : session.saveStates === undefined ? ( diff --git a/apps/web/src/components/navbar/navbar.tsx b/apps/web/src/components/navbar/navbar.tsx index 68cbbf0235b03c29a9bcd982026529a5f9e5a5ca..d00e1be1fd3bd25d6017d82ad954de7d277fe194 100644 --- a/apps/web/src/components/navbar/navbar.tsx +++ b/apps/web/src/components/navbar/navbar.tsx @@ -39,69 +39,65 @@ export const Navbar = () => { const buildInfo = import.meta.env.GRAPHPOLARIS_VERSION; return ( - <div className="w-full h-auto px-5"> - <div className="navbar flex items-center justify-between w-auto gap-2 xl:gap-10"> - <div> - <a href="https://graphpolaris.com/" target="_blank" className="w-[10rem] md:w-fit shrink-0 text-dark"> - <GpLogo className="w-48" /> - </a> - <DatabaseSelector /> - </div> + <nav className="w-full px-4 h-12 flex flex-row items-center gap-2 md:gap-3 lg:gap-4"> + <a href="https://graphpolaris.com/" target="_blank" className="shrink-0 text-dark"> + <GpLogo className="h-7" /> + </a> + <DatabaseSelector /> - <div> - <div className="w-fit" ref={dropdownRef}> - <div - className="relative inline-flex items-center justify-center w-8 h-8 overflow-hidden bg-secondary-500 rounded-full hover:bg-secondary-600 transition-colors duration-150 ease-in-out cursor-pointer" - onClick={() => setMenuOpen(!menuOpen)} - > - <span className="font-medium text-light">{authCache.username?.slice(0, 2).toUpperCase()}</span> - </div> + <div className="ml-auto"> + <div className="w-fit" ref={dropdownRef}> + <div + className="relative inline-flex items-center justify-center w-8 h-8 overflow-hidden bg-secondary-500 rounded-full hover:bg-secondary-600 transition-colors duration-150 ease-in-out cursor-pointer" + onClick={() => setMenuOpen(!menuOpen)} + > + <span className="font-medium text-light">{authCache.username?.slice(0, 2).toUpperCase()}</span> + </div> - {menuOpen && ( - <DropdownItemContainer className="w-56" align="right-7"> - <div className="p-2 text-sm border-b"> - <h2 className="font-bold">user: {authCache.username}</h2> - <h3 className="text-xs break-words">session: {authCache.sessionID}</h3> - </div> + {menuOpen && ( + <DropdownItemContainer className="w-56" align="right-3"> + <div className="p-2 text-sm border-b"> + <h2 className="font-bold">user: {authCache.username}</h2> + <h3 className="text-xs break-words">session: {authCache.sessionID}</h3> + </div> - {authCache.authorized ? ( - <> - <DropdownItem - value="Share" - onClick={() => { - auth.newShareRoom(); - }} - /> - <DropdownItem - value="Advanced" - submenu={ - <> - <DropdownItem value="TBD" onClick={() => {}} /> - </> - } - /> - <DropdownItem value="Settings" onClick={() => {}} /> - <DropdownItem value="Log out" onClick={() => {}} /> - </> - ) : ( - <> - <DropdownItem value="Login" onClick={() => {}} /> - </> - )} + {authCache.authorized ? ( + <> + <DropdownItem + value="Share" + onClick={() => { + auth.newShareRoom(); + }} + /> + <DropdownItem + value="Advanced" + submenu={ + <> + <DropdownItem value="TBD" onClick={() => {}} /> + </> + } + /> + <DropdownItem value="Settings" onClick={() => {}} /> + <DropdownItem value="Log out" onClick={() => {}} /> + </> + ) : ( + <> + <DropdownItem value="Login" onClick={() => {}} /> + </> + )} - {authCache?.roomID && ( - <div className="p-2 border-b"> - <h3 className="text-xs break-words">Share ID: {authCache.roomID}</h3> - </div> - )} - <div className="p-2 border-t"> - <h3 className="text-xs">Version: {buildInfo}</h3> + {authCache?.roomID && ( + <div className="p-2 border-b"> + <h3 className="text-xs break-words">Share ID: {authCache.roomID}</h3> </div> - </DropdownItemContainer> - )} - </div> + )} + <div className="p-2 border-t"> + <h3 className="text-xs">Version: {buildInfo}</h3> + </div> + </DropdownItemContainer> + )} </div> </div> - </div> + </nav> ); }; diff --git a/apps/web/src/main.css b/apps/web/src/main.css index 3f399b3f961b6ae85d44cc03a59abbb9448bb1d6..b05311668417118d4d3585830d420c70004e5f31 100644 --- a/apps/web/src/main.css +++ b/apps/web/src/main.css @@ -16,7 +16,7 @@ html * { html, body { - @apply font-sans bg-light text-dark; + @apply font-sans bg-secondary-50 text-dark; } .panel { diff --git a/libs/config/tailwind.config.js b/libs/config/tailwind.config.js index 05385a971cb17f52be606dcc02cf7c381d9b0aef..a6e1334dedafdf03c975f19f4e378c99fade6bc4 100644 --- a/libs/config/tailwind.config.js +++ b/libs/config/tailwind.config.js @@ -37,6 +37,9 @@ export default { mono: ['Roboto Mono', ...defaultTheme.fontFamily.mono], }, extend: { + borderColor: { + DEFAULT: 'hsl(var(--clr-sec--200) / <alpha-value>)', + }, colors: tailwindColors, animation: { openmenu: 'openmenu 0.3s ease-out', diff --git a/libs/shared/lib/components/color-mode/index.tsx b/libs/shared/lib/components/color-mode/index.tsx index 24a32b5b396868e75ec9c4f82cb93bdda3fea9be..6b43428c1cd5d6e231f7f5b6d999e21f19f58968 100644 --- a/libs/shared/lib/components/color-mode/index.tsx +++ b/libs/shared/lib/components/color-mode/index.tsx @@ -45,7 +45,7 @@ const ColorMode = () => { <TooltipProvider delayDuration={0}> <Tooltip> <TooltipTrigger asChild> - <Button variant="ghost" iconComponent={iconComponent} onClick={toggleTheme} /> + <Button variant="ghost" size="sm" iconComponent={iconComponent} onClick={toggleTheme} /> </TooltipTrigger> <TooltipContent side={'right'}> <p>{`Switch to ${theme === 'dark-mode' ? 'light' : 'dark'}-mode`}</p> diff --git a/libs/shared/lib/querybuilder/panel/querybuilder.tsx b/libs/shared/lib/querybuilder/panel/querybuilder.tsx index 18e481c38cbbc669961702bf67031170c8eb58b5..534da6f04177c32f30e6c5068172b0ad5fa09ccf 100644 --- a/libs/shared/lib/querybuilder/panel/querybuilder.tsx +++ b/libs/shared/lib/querybuilder/panel/querybuilder.tsx @@ -434,137 +434,141 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { }, [queryBuilderSettings]); return ( - <div ref={reactFlowWrapper} className="h-full w-full"> + <div ref={reactFlowWrapper} className="h-full w-full flex flex-col"> <QuerySettingsDialog open={toggleSettings === 'settings'} onClose={() => setToggleSettings(undefined)} /> <QueryMLDialog open={toggleSettings === 'ml'} onClose={() => setToggleSettings(undefined)} /> - <div className="relative flex items-center justify-between z-[2] py-0 px-2 bg-secondary-100 border-b"> - <h1 className="text-xs font-semibold text-secondary-800">Query builder</h1> - <ControlContainer> - <TooltipProvider delayDuration={0}> - <Tooltip> - <TooltipTrigger asChild> - <Button type="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={fitView} /> - </TooltipTrigger> - <TooltipContent side={'bottom'}> - <p>Fit to screen</p> - </TooltipContent> - </Tooltip> - <Tooltip> - <TooltipTrigger asChild> - <Button type="secondary" variant="ghost" size="xs" iconComponent={<Delete />} onClick={() => clearAllNodes()} /> - </TooltipTrigger> - <TooltipContent side={'bottom'}> - <p>Clear query panel</p> - </TooltipContent> - </Tooltip> - <Tooltip> - <TooltipTrigger asChild> - <Button - type="secondary" - variant="ghost" - size="xs" - iconComponent={<CameraAlt />} - onClick={(event) => { - event.stopPropagation(); - }} - /> - </TooltipTrigger> - <TooltipContent side={'bottom'}> - <p>Capture screen</p> - </TooltipContent> - </Tooltip> - <Tooltip> - <TooltipTrigger asChild> - <Button - type="secondary" - variant="ghost" - size="xs" - iconComponent={<ImportExport />} - onClick={(event) => { - event.stopPropagation(); - applyLayout(); - }} - /> - </TooltipTrigger> - <TooltipContent side={'bottom'}> - <p>Layouts</p> - </TooltipContent> - </Tooltip> - <Tooltip> - <TooltipTrigger asChild> - <Button - type="secondary" - variant="ghost" - size="xs" - iconComponent={<Settings />} - additionalClasses="query-settings" - onClick={(event) => { - event.stopPropagation(); - if (toggleSettings === 'settings') setToggleSettings(undefined); - else setToggleSettings('settings'); - }} - /> - </TooltipTrigger> - <TooltipContent side={'bottom'} disabled={toggleSettings === 'settings'}> - <p>Query builder settings</p> - </TooltipContent> - </Tooltip> - <Tooltip> - <TooltipTrigger asChild> - <Button - type="secondary" - variant="ghost" - size="xs" - iconComponent={<Cached />} - onClick={(event) => { - event.stopPropagation(); - if (props.onRunQuery) props.onRunQuery(); - }} - /> - </TooltipTrigger> - <TooltipContent side={'bottom'}> - <p>Rerun query</p> - </TooltipContent> - </Tooltip> - <Tooltip> - <TooltipTrigger asChild> - <Button - type="secondary" - variant="ghost" - size="xs" - iconComponent={<Difference />} - onClick={(event) => { - event.stopPropagation(); - if (toggleSettings === 'logic') setToggleSettings(undefined); - else setToggleSettings('logic'); - }} - /> - </TooltipTrigger> - <TooltipContent side={'bottom'} disabled={toggleSettings === 'logic'}> - <p>Logic settings</p> - </TooltipContent> - </Tooltip> - <Tooltip> - <TooltipTrigger asChild> - <Button - type="secondary" - variant="ghost" - size="xs" - iconComponent={<Lightbulb />} - onClick={(event) => { - event.stopPropagation(); - if (toggleSettings === 'ml') setToggleSettings(undefined); - else setToggleSettings('ml'); - }} - /> - </TooltipTrigger> - <TooltipContent side={'bottom'} disabled={toggleSettings === 'ml'}> - <p>Machine learning</p> - </TooltipContent> - </Tooltip> - </TooltipProvider> - </ControlContainer> + <div className="sticky shrink-0 top-0 flex items-stretch justify-between h-7 bg-secondary-100 border-b border-secondary-200 max-w-full"> + <div className="flex items-center"> + <h1 className="text-xs font-semibold text-secondary-600 px-2">Query builder</h1> + </div> + <div className="shrink-0 sticky right-0 px-0.5 ml-auto items-center flex"> + <ControlContainer> + <TooltipProvider delayDuration={0}> + <Tooltip> + <TooltipTrigger asChild> + <Button type="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={fitView} /> + </TooltipTrigger> + <TooltipContent side={'bottom'}> + <p>Fit to screen</p> + </TooltipContent> + </Tooltip> + <Tooltip> + <TooltipTrigger asChild> + <Button type="secondary" variant="ghost" size="xs" iconComponent={<Delete />} onClick={() => clearAllNodes()} /> + </TooltipTrigger> + <TooltipContent side={'bottom'}> + <p>Clear query panel</p> + </TooltipContent> + </Tooltip> + <Tooltip> + <TooltipTrigger asChild> + <Button + type="secondary" + variant="ghost" + size="xs" + iconComponent={<CameraAlt />} + onClick={(event) => { + event.stopPropagation(); + }} + /> + </TooltipTrigger> + <TooltipContent side={'bottom'}> + <p>Capture screen</p> + </TooltipContent> + </Tooltip> + <Tooltip> + <TooltipTrigger asChild> + <Button + type="secondary" + variant="ghost" + size="xs" + iconComponent={<ImportExport />} + onClick={(event) => { + event.stopPropagation(); + applyLayout(); + }} + /> + </TooltipTrigger> + <TooltipContent side={'bottom'}> + <p>Layouts</p> + </TooltipContent> + </Tooltip> + <Tooltip> + <TooltipTrigger asChild> + <Button + type="secondary" + variant="ghost" + size="xs" + iconComponent={<Settings />} + additionalClasses="query-settings" + onClick={(event) => { + event.stopPropagation(); + if (toggleSettings === 'settings') setToggleSettings(undefined); + else setToggleSettings('settings'); + }} + /> + </TooltipTrigger> + <TooltipContent side={'bottom'} disabled={toggleSettings === 'settings'}> + <p>Query builder settings</p> + </TooltipContent> + </Tooltip> + <Tooltip> + <TooltipTrigger asChild> + <Button + type="secondary" + variant="ghost" + size="xs" + iconComponent={<Cached />} + onClick={(event) => { + event.stopPropagation(); + if (props.onRunQuery) props.onRunQuery(); + }} + /> + </TooltipTrigger> + <TooltipContent side={'bottom'}> + <p>Rerun query</p> + </TooltipContent> + </Tooltip> + <Tooltip> + <TooltipTrigger asChild> + <Button + type="secondary" + variant="ghost" + size="xs" + iconComponent={<Difference />} + onClick={(event) => { + event.stopPropagation(); + if (toggleSettings === 'logic') setToggleSettings(undefined); + else setToggleSettings('logic'); + }} + /> + </TooltipTrigger> + <TooltipContent side={'bottom'} disabled={toggleSettings === 'logic'}> + <p>Logic settings</p> + </TooltipContent> + </Tooltip> + <Tooltip> + <TooltipTrigger asChild> + <Button + type="secondary" + variant="ghost" + size="xs" + iconComponent={<Lightbulb />} + onClick={(event) => { + event.stopPropagation(); + if (toggleSettings === 'ml') setToggleSettings(undefined); + else setToggleSettings('ml'); + }} + /> + </TooltipTrigger> + <TooltipContent side={'bottom'} disabled={toggleSettings === 'ml'}> + <p>Machine learning</p> + </TooltipContent> + </Tooltip> + </TooltipProvider> + </ControlContainer> + </div> </div> <Dialog @@ -652,7 +656,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { export const QueryBuilder = (props: QueryBuilderProps) => { return ( - <div className="query-panel flex w-full h-full"> + <div className="query-panel flex w-full h-full border bg-light"> <ReactFlowProvider> <QueryBuilderInner {...props} /> </ReactFlowProvider> diff --git a/libs/shared/lib/schema/panel/schema.tsx b/libs/shared/lib/schema/panel/schema.tsx index 954a301b0a8fb01985be9e50fdd1f97b7943d943..ed516ccec0282e724c46b9d5dd2f803ddb0735ac 100644 --- a/libs/shared/lib/schema/panel/schema.tsx +++ b/libs/shared/lib/schema/panel/schema.tsx @@ -16,7 +16,7 @@ import SelfEdge from '../pills/edges/self-edge'; import { EntityNode } from '../pills/nodes/entity/entity-node'; import { RelationNode } from '../pills/nodes/relation/relation-node'; import { SchemaDialog } from './schemaDialog'; -import { ExpandMore, ArrowRight } from '@mui/icons-material'; +import { KeyboardArrowDown, KeyboardArrowRight } from '@mui/icons-material'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../components/tooltip'; import { FormControl } from '../../components'; import Input from '../../components/inputs'; @@ -114,37 +114,38 @@ export const Schema = (props: Props) => { <p className="text-sm">No Elements</p> ) : ( <ReactFlowProvider> - <div className="h-[calc(100%-.8rem)] w-full"> - <ReactFlow - snapGrid={[10, 10]} - snapToGrid - onlyRenderVisibleElements={false} - nodesDraggable={true} - nodeTypes={nodeTypes} - edgeTypes={edgeTypes} - connectionLineComponent={ConnectionDragLine} - onNodesChange={onNodesChange} - onEdgesChange={onEdgesChange} - nodes={nodes} - edges={edges} - onInit={(reactFlowInstance) => { - reactFlowInstanceRef.current = reactFlowInstance; - onInit(reactFlowInstance); - }} - proOptions={{ hideAttribution: true }} - ></ReactFlow> - </div> + <ReactFlow + snapGrid={[10, 10]} + snapToGrid + onlyRenderVisibleElements={false} + nodesDraggable={true} + nodeTypes={nodeTypes} + edgeTypes={edgeTypes} + connectionLineComponent={ConnectionDragLine} + onNodesChange={onNodesChange} + onEdgesChange={onEdgesChange} + nodes={nodes} + edges={edges} + onInit={(reactFlowInstance) => { + reactFlowInstanceRef.current = reactFlowInstance; + onInit(reactFlowInstance); + }} + proOptions={{ hideAttribution: true }} + ></ReactFlow> </ReactFlowProvider> )} - <div className="relative bottom-0"> - <div className="w-full py-0 px-2 bg-secondary-50 cursor-pointer border-y flex" onClick={() => setExpanded(!expanded)}> + <div> + <div + className="w-full py-0 px-2 bg-secondary-50 cursor-pointer border-y flex items-center gap-1" + onClick={() => setExpanded(!expanded)} + > <Button - size="2xs" + size="xs" variant="ghost" - iconComponent={expanded ? <ExpandMore /> : <ArrowRight />} + iconComponent={expanded ? <KeyboardArrowDown /> : <KeyboardArrowRight />} onClick={() => setExpanded(!expanded)} /> - <span className="text-xs font-semibold text-secondary-800 ml-2">Schema settings</span> + <span className="text-xs font-semibold text-secondary-600">Schema settings</span> </div> {expanded && ( <div className="h-full w-full overflow-y-auto"> diff --git a/libs/shared/lib/sidebar/index.tsx b/libs/shared/lib/sidebar/index.tsx index f84d036317dc7e5d73ca2cc6bdbc99ba402c82af..0738ebcb971df32767abfccfbe883f38e6d51564 100644 --- a/libs/shared/lib/sidebar/index.tsx +++ b/libs/shared/lib/sidebar/index.tsx @@ -21,33 +21,33 @@ export function Sidebar({ onTab }: { onTab: (tab: SideNavTab) => void }) { return ( <div className="info-panel w-fit h-full flex flex-shrink"> <TooltipProvider delayDuration={100}> - <div className="w-12 flex flex-col items-center justify-between"> - <div className="flex flex-col items-center justify-between"> - {tabs.map((t) => ( - <Tooltip key={t.name}> - <TooltipTrigger> - <Button - type="secondary" - variant="ghost" - size="md" - iconComponent={t.icon} - onClick={() => { - if (tab === t.name) { - onTab(undefined); - setTab(undefined); - } else { - onTab(t.name); - setTab(t.name); - } - }} - additionalClasses={tab === t.name ? 'bg-secondary-100' : ''} - /> - </TooltipTrigger> - <TooltipContent side={'right'}>{t.name}</TooltipContent> - </Tooltip> - ))} + <div className="w-11 flex flex-col items-center"> + {tabs.map((t) => ( + <Tooltip key={t.name}> + <TooltipTrigger> + <Button + type="secondary" + variant="ghost" + size="sm" + iconComponent={t.icon} + onClick={() => { + if (tab === t.name) { + onTab(undefined); + setTab(undefined); + } else { + onTab(t.name); + setTab(t.name); + } + }} + additionalClasses={tab === t.name ? 'bg-secondary-100' : ''} + /> + </TooltipTrigger> + <TooltipContent side={'right'}>{t.name}</TooltipContent> + </Tooltip> + ))} + <div className="mt-auto mb-2"> + <ColorMode /> </div> - <ColorMode /> </div> </TooltipProvider> </div> diff --git a/libs/shared/lib/vis/components/bar.tsx b/libs/shared/lib/vis/components/bar.tsx index 42abaaeb3344c4f672dcf705f430b4e43691db55..b948e288d09f338c12a8837ef2fa3c94f32d0cc9 100644 --- a/libs/shared/lib/vis/components/bar.tsx +++ b/libs/shared/lib/vis/components/bar.tsx @@ -29,41 +29,39 @@ export default function VisualizationBar({ manager, fullSize }: Props) { }; return ( - <div> - <div className="sticky top-0 flex items-center justify-between z-[2] py-0 px-2 bg-secondary-100 border-b"> - <div className="flex divide-x"> - <div className="flex items-center"> - <h1 className="text-xs font-semibold text-secondary-600 mr-4">Visualization</h1> - </div> - <div className="flex justify-between w-full divide-x"> - {manager.tabs.map((visId: string) => { - const isActive = manager.active === visId; - return ( - <div - key={visId} - className={`flex items-center px-2 cursor-pointer border-seconday-200 border-b-2 -mb-[1px] ${isActive && 'border-b-primary-500'} ${!isActive && 'border-b-transparent hover:bg-secondary-200 transition-colors duration-150 ease-in-out'}`} - onClick={() => manager.changeActive(visId)} - onDragStart={(e) => handleDragStart(e, visId)} - onDragOver={(e) => handleDragOver(e)} - onDrop={(e) => handleDrop(e, visId)} - draggable - > - <p className={`text-xs text-secondary-500 font-semibold mr-1 ${isActive && 'text-secondary-950'}`}>{visId}</p> - <Button - type="secondary" - variant="ghost" - rounded - size="2xs" - iconComponent={<Close />} - onClick={(e) => { - e.stopPropagation(); - manager.deleteVisualization(visId); - }} - /> - </div> - ); - })} - </div> + <div className="sticky shrink-0 top-0 flex items-stretch justify-between h-7 bg-secondary-100 border-b border-secondary-200 max-w-full"> + <div className="flex items-center"> + <h1 className="text-xs font-semibold text-secondary-600 px-2">Visualization</h1> + </div> + <div className="flex items-stretch divide-x divide-secondary-200 border-x border-secondary-200"> + {manager.tabs.map((visId: string) => { + const isActive = manager.active === visId; + return ( + <div + key={visId} + className={`flex items-center pl-2 pr-1 gap-1 cursor-pointer relative border-secondary-200 before:content-[''] before:absolute before:left-0 before:bottom-0 before:-mb-px before:h-[2px] before:w-full ${isActive && 'before:bg-primary-500'} ${!isActive && 'before:bg-transparent hover:before:bg-secondary-300 hover:bg-secondary-200'}`} + onClick={() => manager.changeActive(visId)} + onDragStart={(e) => handleDragStart(e, visId)} + onDragOver={(e) => handleDragOver(e)} + onDrop={(e) => handleDrop(e, visId)} + draggable + > + <p className={`text-xs text-secondary-500 font-semibold ${isActive && 'text-secondary-950'}`}>{visId}</p> + <Button + type="secondary" + variant="ghost" + rounded + size="2xs" + iconComponent={<Close />} + onClick={(e) => { + e.stopPropagation(); + manager.deleteVisualization(visId); + }} + /> + </div> + ); + })} + <div className="items-center px-0.5"> <DropdownMenu.Root> <DropdownMenu.Trigger> <TooltipProvider delayDuration={0}> @@ -94,6 +92,8 @@ export default function VisualizationBar({ manager, fullSize }: Props) { </DropdownMenu.Portal> </DropdownMenu.Root> </div> + </div> + <div className="shrink-0 sticky right-0 px-0.5 ml-auto items-center flex"> <ControlContainer> <TooltipProvider delayDuration={0}> <Tooltip> diff --git a/libs/shared/lib/vis/components/config/panel.tsx b/libs/shared/lib/vis/components/config/panel.tsx index 99142b43a8d8fb13565e48b1a9bdc2a9001d8bf6..fa5abf24ed4788bce0fc5f5ce20b1c876ec056a5 100644 --- a/libs/shared/lib/vis/components/config/panel.tsx +++ b/libs/shared/lib/vis/components/config/panel.tsx @@ -17,7 +17,7 @@ export function ConfigPanel({ manager }: Props) { const buildInfo = import.meta.env.GRAPHPOLARIS_VERSION; return ( - <div className="w-full h-full flex flex-col border justify-between"> + <div className="w-full h-full flex flex-col border justify-between bg-light"> <div> {manager.active ? ( <> diff --git a/libs/shared/lib/vis/components/panel.tsx b/libs/shared/lib/vis/components/panel.tsx index fdcb3c7828f9c752764f776ee8e374b773b9f0cb..fe5e6b2d0d94901fefb2091bc7b86f1f0f32916a 100644 --- a/libs/shared/lib/vis/components/panel.tsx +++ b/libs/shared/lib/vis/components/panel.tsx @@ -16,13 +16,13 @@ export const VisualizationPanel = ({ manager, fullSize }: { manager: Visualizati } else if (manager.tabs.length === 0) { return <Recommender onClick={(id: string) => manager.changeActive(id)} />; } - return <div className="w-full h-full">{manager.renderComponent()}</div>; + return <div className="w-full h-full flex">{manager.renderComponent()}</div>; }; return ( - <div className="vis-panel h-full w-full"> + <div className="vis-panel h-full w-full flex flex-col border bg-light"> <VisualizationBar manager={manager} fullSize={fullSize} /> - <div className="h-full w-full overflow-y-auto" style={graphQueryResult.nodes.length === 0 ? { overflow: 'hidden' } : {}}> + <div className="grow overflow-y-auto" style={graphQueryResult.nodes.length === 0 ? { overflow: 'hidden' } : {}}> {renderContent()} </div> </div> diff --git a/libs/shared/lib/vis/visualizations/rawjsonvis/rawjsonvis.tsx b/libs/shared/lib/vis/visualizations/rawjsonvis/rawjsonvis.tsx index 5bb20b18f23a8d2568d0b78d6a4a280bc83c5940..45c4ddda71b7143ef8e8e24fea01cc0e2a811a35 100644 --- a/libs/shared/lib/vis/visualizations/rawjsonvis/rawjsonvis.tsx +++ b/libs/shared/lib/vis/visualizations/rawjsonvis/rawjsonvis.tsx @@ -25,19 +25,17 @@ export const RawJSONVis = React.memo(({ data, configuration }: VisualizationProp console.log(configuration); return ( - <div className="overflow-y-auto"> - <ReactJSONView - src={data} - collapsed={1} - quotesOnKeys={false} - style={{ padding: '20px' }} - theme={configuration.theme} - iconStyle={configuration.iconStyle} - displayDataTypes={configuration.displayDataTypes} - displayObjectSize={configuration.displayObjectSize} - enableClipboard={configuration.enableClipboard} - /> - </div> + <ReactJSONView + src={data} + collapsed={1} + quotesOnKeys={false} + style={{ padding: '20px', flexGrow: 1 }} + theme={configuration.theme} + iconStyle={configuration.iconStyle} + displayDataTypes={configuration.displayDataTypes} + displayObjectSize={configuration.displayObjectSize} + enableClipboard={configuration.enableClipboard} + /> ); });