diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetRenderer.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetRenderer.tsx index 5766ad54d6..00dfa75930 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetRenderer.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetRenderer.tsx @@ -9,6 +9,7 @@ import { pageLayoutResizingWidgetIdComponentState } from '@/page-layout/states/p import { type PageLayoutWidget } from '@/page-layout/types/PageLayoutWidget'; import { PageLayoutWidgetForbiddenDisplay } from '@/page-layout/widgets/components/PageLayoutWidgetForbiddenDisplay'; import { WidgetContentRenderer } from '@/page-layout/widgets/components/WidgetContentRenderer'; +import { useIsCurrentWidgetLastOfTab } from '@/page-layout/widgets/hooks/useIsCurrentWidgetLastOfTab'; import { useIsInPinnedTab } from '@/page-layout/widgets/hooks/useIsInPinnedTab'; import { useWidgetActions } from '@/page-layout/widgets/hooks/useWidgetActions'; import { useWidgetPermissions } from '@/page-layout/widgets/hooks/useWidgetPermissions'; @@ -67,6 +68,8 @@ export const WidgetRenderer = ({ widget }: WidgetRendererProps) => { const { currentPageLayout } = useCurrentPageLayoutOrThrow(); + const isLastWidget = useIsCurrentWidgetLastOfTab(widget.id); + // TODO: when we have more widgets without headers, we should use a more generic approach to hide the header // each widget type could have metadata (e.g., hasHeader: boolean or headerMode: 'always' | 'editOnly' | 'never') const isRichTextWidget = widget.type === WidgetType.STANDALONE_RICH_TEXT; @@ -119,6 +122,7 @@ export const WidgetRenderer = ({ widget }: WidgetRendererProps) => { isEditing={isEditing} isDragging={isDragging} isResizing={isResizing} + isLastWidget={isLastWidget} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} data-widget-id={widget.id} diff --git a/packages/twenty-front/src/modules/page-layout/widgets/hooks/useIsCurrentWidgetLastOfTab.ts b/packages/twenty-front/src/modules/page-layout/widgets/hooks/useIsCurrentWidgetLastOfTab.ts new file mode 100644 index 0000000000..3d9b25e6e7 --- /dev/null +++ b/packages/twenty-front/src/modules/page-layout/widgets/hooks/useIsCurrentWidgetLastOfTab.ts @@ -0,0 +1,44 @@ +import { useCurrentPageLayout } from '@/page-layout/hooks/useCurrentPageLayout'; +import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; +import { buildWidgetVisibilityContext } from '@/page-layout/utils/buildWidgetVisibilityContext'; +import { filterVisibleWidgets } from '@/page-layout/utils/filterVisibleWidgets'; +import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext'; +import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; +import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { isDefined } from 'twenty-shared/utils'; + +export const useIsCurrentWidgetLastOfTab = (widgetId: string): boolean => { + const { currentPageLayout } = useCurrentPageLayout(); + const isMobile = useIsMobile(); + const { isInRightDrawer } = useLayoutRenderingContext(); + const isPageLayoutInEditMode = useRecoilComponentValue( + isPageLayoutInEditModeComponentState, + ); + + if (!isDefined(currentPageLayout)) { + return false; + } + + const tab = currentPageLayout.tabs.find((tab) => + tab.widgets.some((widget) => widget.id === widgetId), + ); + + if (!isDefined(tab)) { + return false; + } + + const visibleWidgets = isPageLayoutInEditMode + ? tab.widgets + : filterVisibleWidgets({ + widgets: tab.widgets, + context: buildWidgetVisibilityContext({ isMobile, isInRightDrawer }), + }); + + if (visibleWidgets.length === 0) { + return false; + } + + const lastWidget = visibleWidgets.at(-1); + + return lastWidget?.id === widgetId; +}; diff --git a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCard.tsx b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCard.tsx index 7dee5c9b5b..364c980022 100644 --- a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCard.tsx +++ b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCard.tsx @@ -11,6 +11,7 @@ const StyledWidgetCard = styled.div<{ isDragging: boolean; isResizing: boolean; headerLess?: boolean; + isLastWidget?: boolean; }>` box-sizing: border-box; display: flex; @@ -28,6 +29,7 @@ const StyledWidgetCard = styled.div<{ isResizing, onClick, headerLess, + isLastWidget, }) => { if (variant === 'dashboard' && !isEditable) { return css` @@ -80,7 +82,10 @@ const StyledWidgetCard = styled.div<{ return css` background: ${theme.background.secondary}; padding: ${theme.spacing(2)}; - border-bottom: 1px solid ${theme.border.color.light}; + ${isLastWidget !== true && + css` + border-bottom: 1px solid ${theme.border.color.light}; + `} `; }