From 0e58510541529236652e8412b85dde66d0f42f46 Mon Sep 17 00:00:00 2001 From: Greg Shear Date: Fri, 26 Jun 2026 14:58:03 -0400 Subject: [PATCH 1/2] Navigation and content-layout redesign (rebased onto main) Squashed rebase of greg/dash/nav onto main. Reworks the app shell: - Collapsible left sidebar nav; user menu, help menu, Agent Skills, and the dark-mode toggle relocated into the sidebar - New content header / PageContainer layout, CompanyMark when collapsed - Theme updates: rounded buttons/icon-buttons, drawer/list overrides, lucide icons (iconoir retained as a dependency) - Per-page create buttons restored on captures/collections/materializations; admin tenant selector kept - Connector settings page removed Reconciled with work merged to main since this branch diverged: the AgentSkills PR (#1975/#1985) and the i18n-deprecation refactor (#2009). ListItemLink keeps main's named-export + deprecated-wrapper pattern and active-route highlighting (useMatch), with a separate onClick prop for action items. The AgentSkills toast retains main's #1985 docs-open hide behavior. --- package-lock.json | 6 +- src/app/Layout.tsx | 45 +-- src/components/AgentSkills/HeaderPill.tsx | 83 ++---- src/components/AgentSkills/Toast.tsx | 61 ++-- src/components/AgentSkills/shared.ts | 28 -- src/components/content/types.ts | 5 +- src/components/graphics/CompanyLogo.tsx | 4 +- src/components/graphics/CompanyMark.tsx | 22 ++ src/components/menus/HelpMenu.tsx | 33 ++- src/components/navigation/ListItemLink.tsx | 64 +++-- src/components/navigation/Navigation.tsx | 285 +++++++++++++------ src/components/navigation/PageTitle.tsx | 2 +- src/components/navigation/TopBar.tsx | 46 +-- src/components/shared/ChipList/Wrapper.tsx | 2 - src/components/shared/Error/Instructions.tsx | 4 +- src/components/shared/Error/Message.tsx | 4 +- src/components/shared/Error/index.tsx | 5 +- src/components/shared/PageContainer.tsx | 61 +++- src/components/shared/UserAvatar.tsx | 4 +- src/components/tables/Collections/index.tsx | 93 +++--- src/components/tables/EntityTable/index.tsx | 10 +- src/context/Theme.tsx | 70 ++++- src/icons/CheckSquare.tsx | 9 +- src/icons/EditOff.tsx | 9 +- src/lang/en-US/Captures.ts | 2 +- src/lang/en-US/Navigation.ts | 11 +- src/lang/en-US/RouteTitles.ts | 8 +- src/utils/workflow-utils.ts | 2 +- 28 files changed, 550 insertions(+), 428 deletions(-) create mode 100644 src/components/graphics/CompanyMark.tsx diff --git a/package-lock.json b/package-lock.json index 8a2370e4f1..5946ea87ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11595,9 +11595,9 @@ "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" }, "node_modules/iconoir-react": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/iconoir-react/-/iconoir-react-7.11.0.tgz", - "integrity": "sha512-uvTKtnHYwbbTsmQ6HCcliYd50WK0GbjP497RwdISxKzfS01x4cK1Mn/F2mT/t2roSaJQ0I+KnHxMcyvmNMXWsQ==", + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/iconoir-react/-/iconoir-react-7.11.1.tgz", + "integrity": "sha512-uUdoKZ5SvvleMWf+mJWbAxLt5WaEcvBAU3YmO5Ho+JA5JLxBKntT0KNXpJqQArq7b5DxiN5xobIVoDBIPAvA/w==", "license": "MIT", "funding": { "type": "opencollective", diff --git a/src/app/Layout.tsx b/src/app/Layout.tsx index fa58df8c80..adbe0c14d5 100644 --- a/src/app/Layout.tsx +++ b/src/app/Layout.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; -import { Box, Toolbar, useMediaQuery, useTheme } from '@mui/material'; +import { Box, useMediaQuery, useTheme } from '@mui/material'; import { useShallow } from 'zustand/react/shallow'; @@ -8,8 +8,9 @@ import { ReflexContainer, ReflexElement, ReflexSplitter } from 'react-reflex'; import { Outlet } from 'react-router'; import { useLocalStorage } from 'react-use'; -import { Toast } from 'src/components/AgentSkills/Toast'; +import { AgentSkillsToast } from 'src/components/AgentSkills/Toast'; import Navigation from 'src/components/navigation/Navigation'; +import Topbar from 'src/components/navigation/TopBar'; import ErrorBoundryWrapper from 'src/components/shared/ErrorBoundryWrapper'; import PageContainer from 'src/components/shared/PageContainer'; import DocsSidePanel from 'src/components/sidePanelDocs/SidePanel'; @@ -75,38 +76,44 @@ function AppLayout() { }; return ( - - - + + `grid-template-columns ${t.transitions.duration.shortest}ms`, + }} + > + + - + - + + + - + - - + diff --git a/src/components/AgentSkills/HeaderPill.tsx b/src/components/AgentSkills/HeaderPill.tsx index b15bf6e35c..fec0ad1a40 100644 --- a/src/components/AgentSkills/HeaderPill.tsx +++ b/src/components/AgentSkills/HeaderPill.tsx @@ -1,21 +1,17 @@ import { Box, Link, Paper, Tooltip, Typography, useTheme } from '@mui/material'; -import { usePostHog } from '@posthog/react'; import { NavArrowRight } from 'iconoir-react'; import { useIntl } from 'react-intl'; import { AGENT_SKILLS_URL, - BG_GRADIENT, - GRADIENT, LINK_COLOR, SECONDARY_TEXT_COLOR, SHIMMER_STYLES, - useAgentSkillsStore, } from 'src/components/AgentSkills/shared'; import { SparkleIcon } from 'src/components/AgentSkills/SparkleIcon'; -function TooltipContent({ onClick }: { onClick: () => void }) { +function TooltipContent() { const theme = useTheme(); const mode = theme.palette.mode; const intl = useIntl(); @@ -23,7 +19,6 @@ function TooltipContent({ onClick }: { onClick: () => void }) { return ( void }) { {intl.formatMessage({ id: 'agentSkills.cta', })} - + ); } -export function HeaderPill() { - const theme = useTheme(); - const mode = theme.palette.mode; - const intl = useIntl(); - const postHog = usePostHog(); - const toastDismissed = useAgentSkillsStore((s) => s.toastDismissed); +interface HeaderPillProps { + isOpen?: boolean; +} - if (!toastDismissed) { - return null; - } +export function HeaderPill({ isOpen = true }: HeaderPillProps) { + const intl = useIntl(); return ( { - postHog.capture('AgentSkills:Click', { - source: 'popover', - }); - window.open( - AGENT_SKILLS_URL, - '_blank', - 'noopener,noreferrer' - ); - }} - /> - } - placement="bottom-end" + title={} + placement={isOpen ? 'bottom-start' : 'right'} enterDelay={200} - leaveDelay={150} + leaveDelay={100} slotProps={{ tooltip: { sx: { @@ -131,51 +109,36 @@ export function HeaderPill() { target="_blank" rel="noopener noreferrer" underline="none" - onClick={() => - postHog.capture('AgentSkills:Click', { - source: 'pill', - }) - } sx={{ - 'display': 'inline-flex', + 'display': 'flex', + 'width': '100%', 'alignItems': 'center', + 'justifyContent': 'flex-start', 'gap': 1, - 'height': 36, - 'px': '14px', - 'pl': '10px', + 'py': '6px', + 'px': '10px', 'borderRadius': '999px', - 'background': BG_GRADIENT[mode], - 'border': '1px solid rgba(46,100,235,0.22)', 'fontSize': 13, 'fontWeight': 600, - 'transition': 'transform 200ms ease', + 'cursor': 'pointer', + 'transition': + 'background 180ms ease, transform 180ms ease, box-shadow 180ms ease', '&:hover': { background: 'linear-gradient(135deg, rgba(46,100,235,0.14) 0%, rgba(54,197,176,0.16) 100%)', - borderColor: 'rgba(46,100,235,0.42)', boxShadow: '0 6px 16px -6px rgba(46,100,235,0.35)', transform: 'translateY(-1px)', }, }} > - - - + /> s.toastDismissed); - const dismissToast = useAgentSkillsStore((s) => s.dismissToast); + const [dismissed, setDismissed] = useLocalStorage( + LocalStorageKeys.AGENT_SKILLS_TOAST_DISMISSED, + false + ); - // If the docs panel is open just hide the toast. That way it cannot cover up - // the cookie consent banner in the docs. - if (toastDismissed || docsPanelOpen) { + // Hide the toast while the docs panel is open so it cannot cover the + // cookie-consent banner that renders inside the docs. + if (dismissed || docsPanelOpen) { return null; } const handleClick = () => { - postHog.capture('AgentSkills:Click', { source: 'toast' }); window.open(AGENT_SKILLS_URL, '_blank', 'noopener,noreferrer'); }; @@ -71,13 +69,13 @@ export function Toast({ docsPanelOpen }: ToastProps) { 'display': 'block', 'animation': `${toastIn} 750ms cubic-bezier(.2,.9,.25,1) 1s both`, 'transition': 'transform 200ms ease, box-shadow 200ms ease', - 'zIndex': toastIndex, + 'zIndex': 1200, '&:hover': { transform: 'translateY(-2px)', boxShadow: '0 1px 2px rgba(15, 23, 42, 0.04), 0 18px 40px -8px rgba(15, 23, 42, 0.22), 0 36px 80px -12px rgba(46, 100, 235, 0.28)', }, - '&:hover .cta-arrow': { + '&:hover .est-toast-cta-arrow': { transform: 'translateX(3px)', }, }} @@ -113,7 +111,7 @@ export function Toast({ docsPanelOpen }: ToastProps) { }} > @@ -127,21 +125,22 @@ export function Toast({ docsPanelOpen }: ToastProps) { mb: 0.5, }} > - + > + {intl.formatMessage({ id: 'agentSkills.badge' })} + {intl.formatMessage({ id: 'agentSkills.cta' })} @@ -211,10 +207,7 @@ export function Toast({ docsPanelOpen }: ToastProps) { size="small" onClick={(e) => { e.stopPropagation(); - postHog.capture('AgentSkills:Click', { - source: 'dismiss', - }); - dismissToast(); + setDismissed(true); }} aria-label={intl.formatMessage({ id: 'agentSkills.dismiss', @@ -227,7 +220,7 @@ export function Toast({ docsPanelOpen }: ToastProps) { '&:hover': { color: '#475569', background: 'none' }, }} > - + diff --git a/src/components/AgentSkills/shared.ts b/src/components/AgentSkills/shared.ts index e1b0495ada..c78e2e6fee 100644 --- a/src/components/AgentSkills/shared.ts +++ b/src/components/AgentSkills/shared.ts @@ -1,33 +1,5 @@ -import type { PersistOptions } from 'zustand/middleware'; - import { keyframes } from '@mui/material'; -import { create } from 'zustand'; -import { persist } from 'zustand/middleware'; - -import { LocalStorageKeys } from 'src/utils/localStorage-utils'; - -interface AgentSkillsState { - toastDismissed: boolean; - dismissToast: () => void; -} - -// v0 - {"state":{"toastDismissed":false},"version":0} -const persistOptions: PersistOptions = { - name: LocalStorageKeys.AGENT_SKILLS_TOAST_DISMISSED, - version: 0, -}; - -export const useAgentSkillsStore = create()( - persist( - (set) => ({ - toastDismissed: false, - dismissToast: () => set({ toastDismissed: true }), - }), - persistOptions - ) -); - export const AGENT_SKILLS_URL = 'https://docs.estuary.dev/guides/agent-skills/'; export const GRADIENT = { diff --git a/src/components/content/types.ts b/src/components/content/types.ts index f2106ea87e..7006f240d7 100644 --- a/src/components/content/types.ts +++ b/src/components/content/types.ts @@ -1,5 +1,4 @@ -import type { SxProps } from '@mui/material'; -import type { ExternalLinkOptions } from 'src/components/shared/ExternalLink'; +import type { SxProps, Theme } from '@mui/material'; export interface SingleLineCodeProps { value: any; @@ -11,6 +10,6 @@ export interface SingleLineCodeProps { export interface MessageWithLinkProps { messageID: string; link?: string; - linkOptions?: ExternalLinkOptions; + linkOptions?: { sx?: SxProps }; intlValues?: any; } diff --git a/src/components/graphics/CompanyLogo.tsx b/src/components/graphics/CompanyLogo.tsx index 0be8ed03a3..2645d90f94 100644 --- a/src/components/graphics/CompanyLogo.tsx +++ b/src/components/graphics/CompanyLogo.tsx @@ -12,8 +12,8 @@ function CompanyLogo() { return ( {intl.formatMessage({ ); diff --git a/src/components/graphics/CompanyMark.tsx b/src/components/graphics/CompanyMark.tsx new file mode 100644 index 0000000000..eeace76cea --- /dev/null +++ b/src/components/graphics/CompanyMark.tsx @@ -0,0 +1,22 @@ +import { useTheme } from '@mui/material'; + +import { useIntl } from 'react-intl'; + +import darkMark from 'src/images/pictorial-marks/pictorial-mark__multi-blue.png'; +import lightMark from 'src/images/pictorial-marks/pictorial-mark__white.png'; + +function CompanyMark() { + const intl = useIntl(); + const theme = useTheme(); + + return ( + {intl.formatMessage({ + ); +} + +export default CompanyMark; diff --git a/src/components/menus/HelpMenu.tsx b/src/components/menus/HelpMenu.tsx index c1855ce0a8..eff64c1f6e 100644 --- a/src/components/menus/HelpMenu.tsx +++ b/src/components/menus/HelpMenu.tsx @@ -1,18 +1,31 @@ -import { HelpCircle } from 'iconoir-react'; +import { Menu } from '@mui/material'; + import { FormattedMessage, useIntl } from 'react-intl'; -import IconMenu from 'src/components/menus/IconMenu'; import ExternalLinkMenuItem from 'src/components/shared/ExternalLinkMenuItem'; -function HelpMenu() { +interface HelpMenuProps { + anchorEl: HTMLElement | null; + onClose: () => void; +} + +export function HelpMenu({ anchorEl, onClose }: HelpMenuProps) { const intl = useIntl(); return ( - } - identifier="help-menu" - tooltip={intl.formatMessage({ id: 'helpMenu.tooltip' })} + - + ); } - -export default HelpMenu; diff --git a/src/components/navigation/ListItemLink.tsx b/src/components/navigation/ListItemLink.tsx index c55533c5db..ac872306a1 100644 --- a/src/components/navigation/ListItemLink.tsx +++ b/src/components/navigation/ListItemLink.tsx @@ -1,6 +1,7 @@ -import type { ReactElement } from 'react'; +import type { MouseEvent, ReactNode } from 'react'; import { + Badge, ListItemButton, ListItemIcon, ListItemText, @@ -11,41 +12,48 @@ import { useIntl } from 'react-intl'; import { Link, useMatch, useResolvedPath } from 'react-router-dom'; interface Props { - icon: ReactElement; + icon: ReactNode; title: string; - link: string; + link?: string; + onClick?: (event: MouseEvent) => void; + isOpen?: boolean; + badgeContent?: number; + tooltipDelay?: number; } -export const ListItemLink = ({ icon, title, link }: Props) => { - const resolved = useResolvedPath(link); - const selected = Boolean( - useMatch({ - path: resolved.pathname, - end: false, // `end: false` matches nested routes e.g. `/admin/billing` - }) - ); +export const ListItemLink = ({ + icon, + title, + link, + onClick, + isOpen, + badgeContent, + tooltipDelay, +}: Props) => { + // Hooks must run unconditionally; for action items (no `link`) the resolved + // match is ignored because `selected` is gated on `link` being present. + const resolved = useResolvedPath(link ?? ''); + const match = useMatch({ path: resolved.pathname, end: false }); + const selected = Boolean(link) && Boolean(match); return (
  • - + - theme.palette.text.primary, - }} - > - {icon} - + {icon ? ( + + {icon} + + ) : null} diff --git a/src/components/navigation/Navigation.tsx b/src/components/navigation/Navigation.tsx index 82ef0714bd..b7bf12c17b 100644 --- a/src/components/navigation/Navigation.tsx +++ b/src/components/navigation/Navigation.tsx @@ -1,31 +1,45 @@ -//TODO (UI / UX) - These icons are not final +import React from 'react'; + import { Box, + Divider, List, ListItemButton, ListItemIcon, ListItemText, + Menu, + MenuItem, Stack, - Toolbar, - Tooltip, + Typography, useTheme, } from '@mui/material'; import MuiDrawer, { drawerClasses } from '@mui/material/Drawer'; +import { useShallow } from 'zustand/react/shallow'; + import { CloudDownload, CloudUpload, DatabaseScript, FastArrowLeft, + HalfMoon, + HelpCircle, HomeSimple, + LogOut, + MoreHoriz, Settings, + SunLight, } from 'iconoir-react'; -import { useIntl } from 'react-intl'; +import { FormattedMessage, useIntl } from 'react-intl'; import { authenticatedRoutes } from 'src/app/routes'; +import { HeaderPill } from 'src/components/AgentSkills/HeaderPill'; +import { HelpMenu } from 'src/components/menus/HelpMenu'; import ListItemLink from 'src/components/navigation/ListItemLink'; -import ModeSwitch from 'src/components/navigation/ModeSwitch'; -import { paperBackground } from 'src/context/Theme'; +import UserAvatar from 'src/components/shared/UserAvatar'; +import { supabaseClient } from 'src/context/GlobalProviders'; +import { useColorMode } from 'src/context/Theme'; +import { useUserStore } from 'src/context/User/useUserContextStore'; interface NavigationProps { open: boolean; @@ -36,6 +50,18 @@ interface NavigationProps { const Navigation = ({ open, width, onNavigationToggle }: NavigationProps) => { const intl = useIntl(); const theme = useTheme(); + const colorMode = useColorMode(); + + const userDetails = useUserStore(useShallow((state) => state.userDetails)); + + const [menuAnchor, setMenuAnchor] = React.useState( + null + ); + const menuOpen = Boolean(menuAnchor); + + const [helpAnchor, setHelpAnchor] = React.useState( + null + ); const openNavigation = () => { onNavigationToggle(true); @@ -55,109 +81,202 @@ const Navigation = ({ open, width, onNavigationToggle }: NavigationProps) => { sx={{ [`& .${drawerClasses.paper}`]: { boxSizing: 'border-box', + position: 'static', + height: '100%', transition: (paperTheme) => `${paperTheme.transitions.duration.shortest}ms`, width, - border: 0, - background: paperBackground[theme.palette.mode], }, transition: (drawerTheme) => `${drawerTheme.transitions.duration.shortest}ms`, width, }} > - - - - - } - title={authenticatedRoutes.home.title} - link={authenticatedRoutes.home.path} - /> - } - title={authenticatedRoutes.captures.title} - link={authenticatedRoutes.captures.path} - /> - } - title={authenticatedRoutes.collections.title} - link={authenticatedRoutes.collections.path} - /> - } - title={authenticatedRoutes.materializations.title} - link={authenticatedRoutes.materializations.path} - /> - } - title={authenticatedRoutes.admin.title} - link={authenticatedRoutes.admin.path} - /> - - + + } + title={authenticatedRoutes.home.title} + link={authenticatedRoutes.home.path} + isOpen={open} + /> + } + title={authenticatedRoutes.captures.title} + link={authenticatedRoutes.captures.path} + isOpen={open} + /> + } + title={authenticatedRoutes.collections.title} + link={authenticatedRoutes.collections.path} + isOpen={open} + /> + } + title={authenticatedRoutes.materializations.title} + link={authenticatedRoutes.materializations.path} + isOpen={open} + /> + } + title={authenticatedRoutes.admin.title} + link={authenticatedRoutes.admin.path} + isOpen={open} + /> + - - + - - - - + + + } + title="helpMenu.tooltip" + onClick={(e) => setHelpAnchor(e.currentTarget)} + isOpen={open} + /> + setHelpAnchor(null)} + /> + + - - - + /> + } + title="navigation.collapse" + onClick={openNavigation} + isOpen={open} + /> + {userDetails ? ( + <> + setMenuAnchor(e.currentTarget)} + sx={{ mx: 1, my: 0.25 }} + > + + - - + + setMenuAnchor(null)} + onClick={() => setMenuAnchor(null)} + anchorOrigin={{ + horizontal: 'left', + vertical: 'top', + }} + transformOrigin={{ + horizontal: 'left', + vertical: 'bottom', + }} + > + + + + {userDetails.userName ?? + userDetails.email} + + + {userDetails.email} + + + + + + + colorMode.toggleColorMode()} + > + + {theme.palette.mode === 'dark' ? ( + + ) : ( + + )} + + + + + + { + void supabaseClient.auth.signOut(); + }} + > + + + + + + + + ) : null} diff --git a/src/components/navigation/PageTitle.tsx b/src/components/navigation/PageTitle.tsx index ac16c3db5f..a41d158e4b 100644 --- a/src/components/navigation/PageTitle.tsx +++ b/src/components/navigation/PageTitle.tsx @@ -25,7 +25,7 @@ function PageTitle() { alignItems: 'baseline', }} > - + diff --git a/src/components/navigation/TopBar.tsx b/src/components/navigation/TopBar.tsx index 5d35e1a122..b8e09a4b91 100644 --- a/src/components/navigation/TopBar.tsx +++ b/src/components/navigation/TopBar.tsx @@ -1,54 +1,34 @@ -import { Divider, Stack, Toolbar } from '@mui/material'; +import { Stack, Toolbar } from '@mui/material'; import MuiAppBar from '@mui/material/AppBar'; -import { useTheme } from '@mui/material/styles'; -import { HeaderPill } from 'src/components/AgentSkills/HeaderPill'; import CompanyLogo from 'src/components/graphics/CompanyLogo'; -import HelpMenu from 'src/components/menus/HelpMenu'; -import UserMenu from 'src/components/menus/UserMenu'; -import PageTitle from 'src/components/navigation/PageTitle'; +import CompanyMark from 'src/components/graphics/CompanyMark'; import SidePanelDocsOpenButton from 'src/components/sidePanelDocs/OpenButton'; import { UpdateAlert } from 'src/components/UpdateAlert'; -import { zIndexIncrement } from 'src/context/Theme'; -const Topbar = () => { - const theme = useTheme(); +interface TopbarProps { + navigationOpen?: boolean; +} +const Topbar = ({ navigationOpen = true }: TopbarProps) => { return ( - + + {navigationOpen ? : } + } > - - - - - - - - - - - - - diff --git a/src/components/shared/ChipList/Wrapper.tsx b/src/components/shared/ChipList/Wrapper.tsx index 59a973f9e4..236c35c16b 100644 --- a/src/components/shared/ChipList/Wrapper.tsx +++ b/src/components/shared/ChipList/Wrapper.tsx @@ -8,7 +8,6 @@ import { Box, styled, Tooltip } from '@mui/material'; import { useIntl } from 'react-intl'; import LinkWrapper from 'src/components/shared/LinkWrapper'; -import { underlineTextSx } from 'src/context/Theme'; import { OutlinedChip } from 'src/styledComponents/chips/OutlinedChip'; import { stripPathing } from 'src/utils/misc-utils'; @@ -60,7 +59,6 @@ function ChipWrapper({ if (val.link) { chipSX = { ...chipSX, - ...underlineTextSx, color: (theme) => theme.palette.primary.main, }; } diff --git a/src/components/shared/Error/Instructions.tsx b/src/components/shared/Error/Instructions.tsx index 12ead47d6e..47058b7be1 100644 --- a/src/components/shared/Error/Instructions.tsx +++ b/src/components/shared/Error/Instructions.tsx @@ -1,4 +1,4 @@ -import type { ExternalLinkOptions } from 'src/components/shared/ExternalLink'; +import type { SxProps, Theme } from '@mui/material'; import { Stack, Typography } from '@mui/material'; @@ -9,7 +9,7 @@ import { showAsTechnicalDifficulties } from 'src/services/shared'; interface Props { message: string; - linkOptions?: ExternalLinkOptions; + linkOptions?: { sx?: SxProps }; } // We will only show special messaging for errors that are can actually tell the user diff --git a/src/components/shared/Error/Message.tsx b/src/components/shared/Error/Message.tsx index 16c6221461..98edd238e4 100644 --- a/src/components/shared/Error/Message.tsx +++ b/src/components/shared/Error/Message.tsx @@ -1,5 +1,5 @@ +import type { SxProps, Theme } from '@mui/material'; import type { ErrorDetails } from 'src/components/shared/Error/types'; -import type { ExternalLinkOptions } from 'src/components/shared/ExternalLink'; import { Box, Stack, Typography } from '@mui/material'; @@ -15,7 +15,7 @@ import { CustomEvents } from 'src/services/types'; interface Props { error?: ErrorDetails; - linkOptions?: ExternalLinkOptions; + linkOptions?: { sx?: SxProps }; } const FALLBACK = 'error.fallBack'; diff --git a/src/components/shared/Error/index.tsx b/src/components/shared/Error/index.tsx index b1c8e3c691..9bc4577df9 100644 --- a/src/components/shared/Error/index.tsx +++ b/src/components/shared/Error/index.tsx @@ -1,7 +1,6 @@ -import type { AlertColor } from '@mui/material'; +import type { AlertColor, SxProps, Theme } from '@mui/material'; import type { ReactNode } from 'react'; import type { ErrorDetails } from 'src/components/shared/Error/types'; -import type { ExternalLinkOptions } from 'src/components/shared/ExternalLink'; import { AlertTitle, Box } from '@mui/material'; @@ -15,7 +14,7 @@ export interface ErrorProps { error?: ErrorDetails; hideIcon?: boolean; hideTitle?: boolean; - linkOptions?: ExternalLinkOptions; + linkOptions?: { sx?: SxProps }; noAlertBox?: boolean; severity?: AlertColor; cta?: ReactNode; diff --git a/src/components/shared/PageContainer.tsx b/src/components/shared/PageContainer.tsx index a331571946..22e7846c6e 100644 --- a/src/components/shared/PageContainer.tsx +++ b/src/components/shared/PageContainer.tsx @@ -3,22 +3,31 @@ import type { Notification } from 'src/stores/NotificationStore'; import { useEffect, useMemo, useState } from 'react'; -import { Container, Paper, Snackbar, useTheme } from '@mui/material'; +import { Box, Paper, Snackbar, Typography, useTheme } from '@mui/material'; + +import { useIntl } from 'react-intl'; -import Topbar from 'src/components/navigation/TopBar'; import AlertBox from 'src/components/shared/AlertBox'; import { paperBackground } from 'src/context/Theme'; import useNotificationStore, { notificationStoreSelectors, } from 'src/stores/NotificationStore'; +import { useTopBarStore } from 'src/stores/TopBar/Store'; interface Props { children: ReactNode | ReactNode[]; hideBackground?: boolean; + navigationOpen?: boolean; } -function PageContainer({ children, hideBackground }: Props) { +function PageContainer({ + children, + hideBackground, + navigationOpen = true, +}: Props) { + const intl = useIntl(); const theme = useTheme(); + const header = useTopBarStore((state) => state.header); const notification = useNotificationStore( notificationStoreSelectors.notification @@ -77,10 +86,12 @@ function PageContainer({ children, hideBackground }: Props) { }, [notification]); return ( - {notification && alertBody ? ( @@ -112,20 +123,50 @@ function PageContainer({ children, hideBackground }: Props) { ) : null} - + {header ? ( + + + {intl.formatMessage({ id: header })} + + + ) : null} + `padding ${t.transitions.duration.shortest}ms`, + py: 2, + flex: 1, + minHeight: 0, + overflow: 'auto', + overscrollBehavior: 'none', width: '100%', + mb: 1, boxShadow: boxShadowMixin, - borderRadius: 3, + borderRadius: header ? '0 0 16px 16px' : 8, background: backgroundMixin, }} > {children} - + ); } diff --git a/src/components/shared/UserAvatar.tsx b/src/components/shared/UserAvatar.tsx index e45708c816..440fc24903 100644 --- a/src/components/shared/UserAvatar.tsx +++ b/src/components/shared/UserAvatar.tsx @@ -1,5 +1,7 @@ import { Avatar } from '@mui/material'; +import defaultAvatar from 'src/images/user.png'; + interface Props { avatarUrl: string | null; userName: string | null; @@ -14,7 +16,7 @@ function UserAvatar({ avatarUrl, size, userName, userEmail }: Props) { return ( - - + + ( + + )} + rowsPerPage={rowsPerPage} + setRowsPerPage={setRowsPerPage} + pagination={pagination} + setPagination={setPagination} + searchQuery={searchQuery} + setSearchQuery={setSearchQuery} + sortDirection={sortDirection} + setSortDirection={setSortDirection} + columnToSort={columnToSort} + setColumnToSort={setColumnToSort} + header={ENTITY_SETTINGS.collection.table.headerIntlKey} + filterLabel={ENTITY_SETTINGS.collection.table.filterIntlKey} + showEntityStatus selectableTableStoreName={selectableTableStoreName} - > - ( - - )} - rowsPerPage={rowsPerPage} - setRowsPerPage={setRowsPerPage} - pagination={pagination} - setPagination={setPagination} - searchQuery={searchQuery} - setSearchQuery={setSearchQuery} - sortDirection={sortDirection} - setSortDirection={setSortDirection} - columnToSort={columnToSort} - setColumnToSort={setColumnToSort} - header={ENTITY_SETTINGS.collection.table.headerIntlKey} - filterLabel={ - ENTITY_SETTINGS.collection.table.filterIntlKey - } - showEntityStatus - selectableTableStoreName={selectableTableStoreName} - showToolbar - toolbar={ - - } - /> - - - + showToolbar + toolbar={ + + } + /> + + ); } diff --git a/src/components/tables/EntityTable/index.tsx b/src/components/tables/EntityTable/index.tsx index cf04214274..d244efea66 100644 --- a/src/components/tables/EntityTable/index.tsx +++ b/src/components/tables/EntityTable/index.tsx @@ -245,13 +245,7 @@ function EntityTable({ {hideHeaderAndFooter || (!showToolbar && hideFilter && !ExportComponent) ? null : ( - - - {showToolbar ? ( - - ) : null} - </Stack> - + <Box> <Toolbar disableGutters sx={{ @@ -297,7 +291,7 @@ function EntityTable({ </Box> )} - <Box sx={hideHeaderAndFooter ? {} : { mb: 2, mx: 2 }}> + <Box sx={hideHeaderAndFooter ? {} : { mb: 2 }}> <TableContainer component={Box}> <Table size="small" diff --git a/src/context/Theme.tsx b/src/context/Theme.tsx index 62174da645..07f1cc692c 100644 --- a/src/context/Theme.tsx +++ b/src/context/Theme.tsx @@ -94,7 +94,7 @@ declare module '@mui/material/Typography' { // Navigation Width export enum NavWidths { MOBILE = 0, - RAIL = 48, + RAIL = 54, FULL = 200, } @@ -702,20 +702,11 @@ export const jsonFormsPadding: SxProps<Theme> = { }, }; -export const underlineTextSx: SxProps<Theme> = { - 'textDecoration': 'underline', - '&:hover, &:focus': { - textDecoration: 'underline', - }, -}; - // Used to make buttons look like a normal(ish) link export const linkButtonSx: SxProps<Theme> = { - ...underlineTextSx, px: 1, py: 0, fontWeight: 500, - zIndex: headerLinkIndex, }; // Light is an RGB translation of #E1E9F4; Light is an RGB translation of #F7F9FC. @@ -990,6 +981,11 @@ const themeSettings = createTheme({ }, }, }, + MuiLink: { + defaultProps: { + underline: 'hover', + }, + }, MuiButton: { defaultProps: { variant: 'contained', @@ -998,11 +994,19 @@ const themeSettings = createTheme({ styleOverrides: { root: { fontSize: 14, - borderRadius: 4, + borderRadius: 8, textTransform: 'none', }, }, }, + MuiIconButton: { + styleOverrides: { + root: { + fontSize: 14, + borderRadius: 8, + }, + }, + }, MuiCheckbox: { defaultProps: { icon: <Square style={{ fontSize: 14 }} />, @@ -1148,17 +1152,53 @@ const ThemeProvider = ({ children }: BaseComponentProps) => { }, }, MuiAppBar: { + defaultProps: { + position: 'static' as const, + elevation: 0, + }, styleOverrides: { root: { - background: - palette.mode === 'dark' - ? sample_grey[800] - : 'white', + background: palette.background?.default, boxShadow: 'none', color: palette.text?.primary, }, }, }, + MuiDrawer: { + styleOverrides: { + paper: { + background: palette.background?.default, + border: 0, + }, + }, + }, + MuiListItemButton: { + styleOverrides: { + root: { + gap: 8, + whiteSpace: 'nowrap', + padding: '6px 10px', + borderRadius: 8, + }, + }, + }, + MuiListItemIcon: { + styleOverrides: { + root: { + minWidth: 'auto', + color: 'inherit', + }, + }, + }, + MuiListItemText: { + styleOverrides: { + primary: { + fontSize: 13, + overflow: 'hidden', + textOverflow: 'ellipsis', + }, + }, + }, MuiDialog: { styleOverrides: { paper: { diff --git a/src/icons/CheckSquare.tsx b/src/icons/CheckSquare.tsx index 0b2714290d..afdeb80d2a 100644 --- a/src/icons/CheckSquare.tsx +++ b/src/icons/CheckSquare.tsx @@ -1,16 +1,9 @@ import React from 'react'; -import { IconoirContext } from 'iconoir-react'; - function SvgCheckSquare( - passedProps: React.SVGProps<SVGSVGElement>, + props: React.SVGProps<SVGSVGElement>, svgRef?: React.Ref<SVGSVGElement> ) { - const context = React.useContext(IconoirContext); - const props = { - ...context, - ...passedProps, - }; return ( <svg diff --git a/src/icons/EditOff.tsx b/src/icons/EditOff.tsx index cdb4f285d9..6ef218bba5 100644 --- a/src/icons/EditOff.tsx +++ b/src/icons/EditOff.tsx @@ -1,16 +1,9 @@ import React from 'react'; -import { IconoirContext } from 'iconoir-react'; - function SvgEditOff( - passedProps: React.SVGProps<SVGSVGElement>, + props: React.SVGProps<SVGSVGElement>, svgRef?: React.Ref<SVGSVGElement> ) { - const context = React.useContext(IconoirContext); - const props = { - ...context, - ...passedProps, - }; return ( <svg diff --git a/src/lang/en-US/Captures.ts b/src/lang/en-US/Captures.ts index 20e35f423e..61402d7e77 100644 --- a/src/lang/en-US/Captures.ts +++ b/src/lang/en-US/Captures.ts @@ -4,7 +4,7 @@ import { RouteTitles } from 'src/lang/en-US/RouteTitles'; export const Captures: Record<string, string> = { 'captureTable.header': `Captures`, - 'capturesTable.title': `Your Captures`, + 'capturesTable.title': `Captures`, 'capturesTable.cta.new': `New Capture`, 'capturesTable.filterLabel': `Filter captures`, 'capturesTable.delete.removeCollectionsOption': `Delete all collections associated with this capture. Collections used by active tasks will be skipped.`, diff --git a/src/lang/en-US/Navigation.ts b/src/lang/en-US/Navigation.ts index 304f759a81..177e937ea7 100644 --- a/src/lang/en-US/Navigation.ts +++ b/src/lang/en-US/Navigation.ts @@ -2,15 +2,15 @@ import { CommonMessages } from 'src/lang/en-US/CommonMessages'; import { CTAs } from 'src/lang/en-US/CTAs'; export const Navigation: Record<string, string> = { - 'navigation.toggle.ariaLabel': `Toggle Navigation`, - 'navigation.expand': `Expand Navigation`, - 'navigation.collapse': `Collapse Navigation`, + 'navigation.toggle.ariaLabel': `Toggle Sidebar`, + 'navigation.expand': `Expand`, + 'navigation.collapse': `Collapse`, // Header 'mainMenu.tooltip': `Open Main Menu`, 'helpMenu.ariaLabel': `Open Help Menu`, - 'helpMenu.tooltip': `Helpful Links`, + 'helpMenu.tooltip': `Help`, 'helpMenu.docs': `Docs`, 'helpMenu.docs.link': `https://docs.estuary.dev/`, 'helpMenu.slack': `Estuary Slack`, @@ -27,7 +27,8 @@ export const Navigation: Record<string, string> = { 'accountMenu.tooltip': `My Account`, 'accountMenu.emailVerified': `verified`, - 'modeSwitch.label': `Toggle Color Mode`, + 'modeSwitch.darkLabel': `Dark Mode`, + 'modeSwitch.lightLabel': `Light Mode`, 'updateAlert.cta': `Update`, 'updateAlert.title': `Dashboard Updated`, diff --git a/src/lang/en-US/RouteTitles.ts b/src/lang/en-US/RouteTitles.ts index 64c4469df1..17711a8011 100644 --- a/src/lang/en-US/RouteTitles.ts +++ b/src/lang/en-US/RouteTitles.ts @@ -1,19 +1,19 @@ import { CommonMessages } from 'src/lang/en-US/CommonMessages'; export const RouteTitles: Record<string, string> = { - 'routeTitle.home': `Welcome`, + 'routeTitle.home': `Overview`, 'routeTitle.dashboard': `Dashboard`, 'routeTitle.admin': `Admin`, 'routeTitle.admin.accessGrants': `Access Grants`, 'routeTitle.admin.api': `CLI - API`, 'routeTitle.admin.billing': `Billing`, 'routeTitle.admin.settings': `Settings`, - 'routeTitle.captureCreate': `Create Capture`, + 'routeTitle.captureCreate': `New Capture`, 'routeTitle.captureDetails': `Capture Details`, 'routeTitle.captureEdit': `Edit Capture`, 'routeTitle.captures': `${CommonMessages['terms.sources']}`, 'routeTitle.collections': `Collections`, - 'routeTitle.collectionCreate': `Create Transformation`, + 'routeTitle.collectionCreate': `New Transformation`, 'routeTitle.collectionDetails': `Collection Details`, 'routeTitle.dataPlaneAuthReq': `Data Plane Authorization Checkpoint`, 'routeTitle.directives': `Directives`, @@ -23,7 +23,7 @@ export const RouteTitles: Record<string, string> = { 'routeTitle.loginLoading': `Checking Credentials`, 'routeTitle.noGrants': `Signed Up`, 'routeTitle.legal': `Legal`, - 'routeTitle.materializationCreate': `Create Materialization`, + 'routeTitle.materializationCreate': `New Materialization`, 'routeTitle.materializationDetails': `Materialization Details`, 'routeTitle.materializationEdit': `Edit Materialization`, 'routeTitle.materializations': `${CommonMessages['terms.destinations']}`, diff --git a/src/utils/workflow-utils.ts b/src/utils/workflow-utils.ts index 859d2c5f2e..c3434e9f34 100644 --- a/src/utils/workflow-utils.ts +++ b/src/utils/workflow-utils.ts @@ -43,7 +43,7 @@ export const getBackfillCounter = (binding: any): number => { }; export const getSourceOrTarget = (binding: any) => { - return Object.hasOwn(binding ?? {}, 'source') + return Object.hasOwn(binding ?? {}, '3source') ? binding.source : Object.hasOwn(binding ?? {}, 'target') ? binding.target From 0aa045d522a2dcb2b66459a324891af12a2e220a Mon Sep 17 00:00:00 2001 From: Greg Shear <greg@estuary.dev> Date: Fri, 26 Jun 2026 16:36:32 -0400 Subject: [PATCH 2/2] Align navigation/layout chrome with the agent2 redesign Adopt the agent2 layout shell without the Copilot assistant. - Delete TopBar and drop its grid row from Layout (gridTemplateRows auto 1fr -> 1fr). - Pad the content column with the top strip the top bar used to occupy, so the docs side panel stays top-aligned with the page content and the header lines up with the first sidebar nav item below the logo header. - Move the brand into the sidebar header: full CompanyLogo when expanded, CompanyMark when collapsed, left-anchored so the mark does not jump as the drawer width animates on collapse. - Move the docs open button onto the trailing edge of the PageContainer content header; the header shows the bold page title. UpdateAlert is intentionally orphaned for now. It previously lived in the TopBar, and agent2 only renders it inside the Copilot status bar, which this branch does not include. Keep dash/nav's in-table title removal (EntityTable, Collections); the content header shows the page title, so the in-table title would otherwise duplicate it. Revert the unrelated changes to main: UserAvatar default image, the ExternalLink type decoupling in Error/content, and the icon-context changes in CheckSquare/EditOff. Keep ChipList/Wrapper as-is because its underline removal is coupled to this branch's Theme cleanup (underlineTextSx is no longer exported). --- src/app/Layout.tsx | 13 +++---- src/components/content/types.ts | 5 ++- src/components/navigation/Navigation.tsx | 18 +++++++++ src/components/navigation/TopBar.tsx | 39 -------------------- src/components/shared/Error/Instructions.tsx | 4 +- src/components/shared/Error/Message.tsx | 4 +- src/components/shared/Error/index.tsx | 5 ++- src/components/shared/PageContainer.tsx | 7 +++- src/components/shared/UserAvatar.tsx | 4 +- src/icons/CheckSquare.tsx | 9 ++++- src/icons/EditOff.tsx | 9 ++++- 11 files changed, 57 insertions(+), 60 deletions(-) delete mode 100644 src/components/navigation/TopBar.tsx diff --git a/src/app/Layout.tsx b/src/app/Layout.tsx index adbe0c14d5..e89f78caa3 100644 --- a/src/app/Layout.tsx +++ b/src/app/Layout.tsx @@ -10,7 +10,6 @@ import { useLocalStorage } from 'react-use'; import { AgentSkillsToast } from 'src/components/AgentSkills/Toast'; import Navigation from 'src/components/navigation/Navigation'; -import Topbar from 'src/components/navigation/TopBar'; import ErrorBoundryWrapper from 'src/components/shared/ErrorBoundryWrapper'; import PageContainer from 'src/components/shared/PageContainer'; import DocsSidePanel from 'src/components/sidePanelDocs/SidePanel'; @@ -80,16 +79,12 @@ function AppLayout() { sx={{ display: 'grid', gridTemplateColumns: `${navigationWidth}px 1fr`, - gridTemplateRows: 'auto 1fr', + gridTemplateRows: '1fr', height: '100vh', transition: (t) => `grid-template-columns ${t.transitions.duration.shortest}ms`, }} > - <Box sx={{ gridColumn: '1 / -1' }}> - <Topbar navigationOpen={navigationOpen} /> - </Box> - <Navigation open={navigationOpen} width={navigationWidth} @@ -98,7 +93,11 @@ function AppLayout() { <AgentSkillsToast docsPanelOpen={displaySidePanel} /> - <Box sx={{ overflow: 'hidden', minWidth: 0 }}> + {/* Top strip the removed top bar used to occupy. Padding the whole + content column (not just PageContainer) keeps the docs side panel + top-aligned with the page content, and lines the breadcrumb bar up + with the first sidebar nav item below the logo header. */} + <Box sx={{ overflow: 'hidden', minWidth: 0, pt: 6 }}> <ReflexContainer orientation="vertical"> <ReflexElement className="left-pane" diff --git a/src/components/content/types.ts b/src/components/content/types.ts index 7006f240d7..f2106ea87e 100644 --- a/src/components/content/types.ts +++ b/src/components/content/types.ts @@ -1,4 +1,5 @@ -import type { SxProps, Theme } from '@mui/material'; +import type { SxProps } from '@mui/material'; +import type { ExternalLinkOptions } from 'src/components/shared/ExternalLink'; export interface SingleLineCodeProps { value: any; @@ -10,6 +11,6 @@ export interface SingleLineCodeProps { export interface MessageWithLinkProps { messageID: string; link?: string; - linkOptions?: { sx?: SxProps<Theme> }; + linkOptions?: ExternalLinkOptions; intlValues?: any; } diff --git a/src/components/navigation/Navigation.tsx b/src/components/navigation/Navigation.tsx index b7bf12c17b..945f931f47 100644 --- a/src/components/navigation/Navigation.tsx +++ b/src/components/navigation/Navigation.tsx @@ -34,6 +34,8 @@ import { FormattedMessage, useIntl } from 'react-intl'; import { authenticatedRoutes } from 'src/app/routes'; import { HeaderPill } from 'src/components/AgentSkills/HeaderPill'; +import CompanyLogo from 'src/components/graphics/CompanyLogo'; +import CompanyMark from 'src/components/graphics/CompanyMark'; import { HelpMenu } from 'src/components/menus/HelpMenu'; import ListItemLink from 'src/components/navigation/ListItemLink'; import UserAvatar from 'src/components/shared/UserAvatar'; @@ -98,6 +100,22 @@ const Navigation = ({ open, width, onNavigationToggle }: NavigationProps) => { overflowX: 'hidden', }} > + <Box + sx={{ + display: 'flex', + alignItems: 'center', + // Left-anchor the brand in both states. The drawer + // animates its width on collapse; centering would fling + // the mark toward the middle of the still-wide rail and + // snap it back as the width settles. + justifyContent: 'flex-start', + height: 48, + px: 2, + }} + > + {open ? <CompanyLogo /> : <CompanyMark />} + </Box> + <List aria-label={intl.formatMessage({ id: 'navigation.toggle.ariaLabel', diff --git a/src/components/navigation/TopBar.tsx b/src/components/navigation/TopBar.tsx deleted file mode 100644 index b8e09a4b91..0000000000 --- a/src/components/navigation/TopBar.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { Stack, Toolbar } from '@mui/material'; -import MuiAppBar from '@mui/material/AppBar'; - -import CompanyLogo from 'src/components/graphics/CompanyLogo'; -import CompanyMark from 'src/components/graphics/CompanyMark'; -import SidePanelDocsOpenButton from 'src/components/sidePanelDocs/OpenButton'; -import { UpdateAlert } from 'src/components/UpdateAlert'; - -interface TopbarProps { - navigationOpen?: boolean; -} - -const Topbar = ({ navigationOpen = true }: TopbarProps) => { - return ( - <MuiAppBar> - <Toolbar - variant="dense" - sx={{ - pl: '19px !important', - minHeight: 48, - justifyContent: 'space-between', - }} - > - {navigationOpen ? <CompanyLogo /> : <CompanyMark />} - - <Stack - direction="row" - spacing={2} - sx={{ alignItems: 'center' }} - > - <UpdateAlert /> - <SidePanelDocsOpenButton /> - </Stack> - </Toolbar> - </MuiAppBar> - ); -}; - -export default Topbar; diff --git a/src/components/shared/Error/Instructions.tsx b/src/components/shared/Error/Instructions.tsx index 47058b7be1..12ead47d6e 100644 --- a/src/components/shared/Error/Instructions.tsx +++ b/src/components/shared/Error/Instructions.tsx @@ -1,4 +1,4 @@ -import type { SxProps, Theme } from '@mui/material'; +import type { ExternalLinkOptions } from 'src/components/shared/ExternalLink'; import { Stack, Typography } from '@mui/material'; @@ -9,7 +9,7 @@ import { showAsTechnicalDifficulties } from 'src/services/shared'; interface Props { message: string; - linkOptions?: { sx?: SxProps<Theme> }; + linkOptions?: ExternalLinkOptions; } // We will only show special messaging for errors that are can actually tell the user diff --git a/src/components/shared/Error/Message.tsx b/src/components/shared/Error/Message.tsx index 98edd238e4..16c6221461 100644 --- a/src/components/shared/Error/Message.tsx +++ b/src/components/shared/Error/Message.tsx @@ -1,5 +1,5 @@ -import type { SxProps, Theme } from '@mui/material'; import type { ErrorDetails } from 'src/components/shared/Error/types'; +import type { ExternalLinkOptions } from 'src/components/shared/ExternalLink'; import { Box, Stack, Typography } from '@mui/material'; @@ -15,7 +15,7 @@ import { CustomEvents } from 'src/services/types'; interface Props { error?: ErrorDetails; - linkOptions?: { sx?: SxProps<Theme> }; + linkOptions?: ExternalLinkOptions; } const FALLBACK = 'error.fallBack'; diff --git a/src/components/shared/Error/index.tsx b/src/components/shared/Error/index.tsx index 9bc4577df9..b1c8e3c691 100644 --- a/src/components/shared/Error/index.tsx +++ b/src/components/shared/Error/index.tsx @@ -1,6 +1,7 @@ -import type { AlertColor, SxProps, Theme } from '@mui/material'; +import type { AlertColor } from '@mui/material'; import type { ReactNode } from 'react'; import type { ErrorDetails } from 'src/components/shared/Error/types'; +import type { ExternalLinkOptions } from 'src/components/shared/ExternalLink'; import { AlertTitle, Box } from '@mui/material'; @@ -14,7 +15,7 @@ export interface ErrorProps { error?: ErrorDetails; hideIcon?: boolean; hideTitle?: boolean; - linkOptions?: { sx?: SxProps<Theme> }; + linkOptions?: ExternalLinkOptions; noAlertBox?: boolean; severity?: AlertColor; cta?: ReactNode; diff --git a/src/components/shared/PageContainer.tsx b/src/components/shared/PageContainer.tsx index 22e7846c6e..cad256ce1e 100644 --- a/src/components/shared/PageContainer.tsx +++ b/src/components/shared/PageContainer.tsx @@ -8,6 +8,7 @@ import { Box, Paper, Snackbar, Typography, useTheme } from '@mui/material'; import { useIntl } from 'react-intl'; import AlertBox from 'src/components/shared/AlertBox'; +import SidePanelDocsOpenButton from 'src/components/sidePanelDocs/OpenButton'; import { paperBackground } from 'src/context/Theme'; import useNotificationStore, { notificationStoreSelectors, @@ -144,12 +145,16 @@ function PageContainer({ <Typography sx={{ fontWeight: 'bold' }}> {intl.formatMessage({ id: header })} </Typography> + + <Box sx={{ ml: 'auto' }}> + <SidePanelDocsOpenButton /> + </Box> </Paper> ) : null} <Paper sx={{ - px: navigationOpen ? 1 : 5, + px: navigationOpen ? 1 : { xs: 1, md: 5 }, transition: (t) => `padding ${t.transitions.duration.shortest}ms`, py: 2, diff --git a/src/components/shared/UserAvatar.tsx b/src/components/shared/UserAvatar.tsx index 440fc24903..e45708c816 100644 --- a/src/components/shared/UserAvatar.tsx +++ b/src/components/shared/UserAvatar.tsx @@ -1,7 +1,5 @@ import { Avatar } from '@mui/material'; -import defaultAvatar from 'src/images/user.png'; - interface Props { avatarUrl: string | null; userName: string | null; @@ -16,7 +14,7 @@ function UserAvatar({ avatarUrl, size, userName, userEmail }: Props) { return ( <Avatar - src={avatarUrl || defaultAvatar} + src={avatarUrl ?? ''} sx={{ fontSize: avatarSize / 1.5, height: avatarSize, diff --git a/src/icons/CheckSquare.tsx b/src/icons/CheckSquare.tsx index afdeb80d2a..0b2714290d 100644 --- a/src/icons/CheckSquare.tsx +++ b/src/icons/CheckSquare.tsx @@ -1,9 +1,16 @@ import React from 'react'; +import { IconoirContext } from 'iconoir-react'; + function SvgCheckSquare( - props: React.SVGProps<SVGSVGElement>, + passedProps: React.SVGProps<SVGSVGElement>, svgRef?: React.Ref<SVGSVGElement> ) { + const context = React.useContext(IconoirContext); + const props = { + ...context, + ...passedProps, + }; return ( <svg diff --git a/src/icons/EditOff.tsx b/src/icons/EditOff.tsx index 6ef218bba5..cdb4f285d9 100644 --- a/src/icons/EditOff.tsx +++ b/src/icons/EditOff.tsx @@ -1,9 +1,16 @@ import React from 'react'; +import { IconoirContext } from 'iconoir-react'; + function SvgEditOff( - props: React.SVGProps<SVGSVGElement>, + passedProps: React.SVGProps<SVGSVGElement>, svgRef?: React.Ref<SVGSVGElement> ) { + const context = React.useContext(IconoirContext); + const props = { + ...context, + ...passedProps, + }; return ( <svg