diff --git a/packages/twenty-front/src/modules/page-layout/PageLayoutMainContent.tsx b/packages/twenty-front/src/modules/page-layout/PageLayoutMainContent.tsx
new file mode 100644
index 0000000000..9bea1d4e26
--- /dev/null
+++ b/packages/twenty-front/src/modules/page-layout/PageLayoutMainContent.tsx
@@ -0,0 +1,31 @@
+import { PageLayoutContent } from '@/page-layout/components/PageLayoutContent';
+import { PageLayoutContentProvider } from '@/page-layout/contexts/PageLayoutContentContext';
+import { useCurrentPageLayoutOrThrow } from '@/page-layout/hooks/useCurrentPageLayoutOrThrow';
+import { getTabLayoutMode } from '@/page-layout/utils/getTabLayoutMode';
+
+type PageLayoutMainContentProps = {
+ tabId: string;
+};
+
+export const PageLayoutMainContent = ({
+ tabId,
+}: PageLayoutMainContentProps) => {
+ const { currentPageLayout } = useCurrentPageLayoutOrThrow();
+
+ const activeTab = currentPageLayout.tabs.find((tab) => tab.id === tabId);
+ const layoutMode = getTabLayoutMode({
+ tab: activeTab,
+ pageLayoutType: currentPageLayout.type,
+ });
+
+ return (
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutCanvasViewer.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutCanvasViewer.tsx
index 18e4d76f17..0840a58c76 100644
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutCanvasViewer.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutCanvasViewer.tsx
@@ -1,7 +1,7 @@
import { WidgetRenderer } from '@/page-layout/widgets/components/WidgetRenderer';
import styled from '@emotion/styled';
import { isDefined } from 'twenty-shared/utils';
-import { PageLayoutType, type PageLayoutWidget } from '~/generated/graphql';
+import { type PageLayoutWidget } from '~/generated/graphql';
const StyledCanvasContainer = styled.div`
display: grid;
@@ -23,11 +23,7 @@ export const PageLayoutCanvasViewer = ({
return (
-
+
);
};
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutContent.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutContent.tsx
index 49ecde4f6e..32c3e8876d 100644
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutContent.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutContent.tsx
@@ -2,30 +2,29 @@ import { PageLayoutCanvasViewer } from '@/page-layout/components/PageLayoutCanva
import { PageLayoutGridLayout } from '@/page-layout/components/PageLayoutGridLayout';
import { PageLayoutVerticalListEditor } from '@/page-layout/components/PageLayoutVerticalListEditor';
import { PageLayoutVerticalListViewer } from '@/page-layout/components/PageLayoutVerticalListViewer';
+import { usePageLayoutContentContext } from '@/page-layout/contexts/PageLayoutContentContext';
import { useCurrentPageLayout } from '@/page-layout/hooks/useCurrentPageLayout';
import { useReorderPageLayoutWidgets } from '@/page-layout/hooks/useReorderPageLayoutWidgets';
import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState';
+import { useIsInPinnedTab } from '@/page-layout/widgets/hooks/useIsInPinnedTab';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import styled from '@emotion/styled';
import { isDefined } from 'twenty-shared/utils';
import { FeatureFlagKey } from '~/generated/graphql';
-const StyledContainer = styled.div`
+const StyledContainer = styled.div<{ isInPinnedTab: boolean }>`
background: ${({ theme }) => theme.background.primary};
box-sizing: border-box;
flex: 1;
min-height: 100%;
position: relative;
- padding: ${({ theme }) => theme.spacing(2)};
width: 100%;
+ padding: ${({ theme, isInPinnedTab }) =>
+ isInPinnedTab ? 0 : theme.spacing(2)};
`;
-type PageLayoutContentProps = {
- tabId: string;
-};
-
-export const PageLayoutContent = ({ tabId }: PageLayoutContentProps) => {
+export const PageLayoutContent = () => {
const isRecordPageEnabled = useIsFeatureEnabled(
FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_ENABLED,
);
@@ -35,18 +34,21 @@ export const PageLayoutContent = ({ tabId }: PageLayoutContentProps) => {
);
const { currentPageLayout } = useCurrentPageLayout();
+ const { tabId } = usePageLayoutContentContext();
+
const { reorderWidgets } = useReorderPageLayoutWidgets(tabId);
const activeTab = currentPageLayout?.tabs.find((tab) => tab.id === tabId);
+ const { layoutMode } = usePageLayoutContentContext();
+ const { isInPinnedTab } = useIsInPinnedTab();
+
if (!isDefined(currentPageLayout) || !isDefined(activeTab)) {
return null;
}
- const isCanvasLayout =
- isRecordPageEnabled && activeTab.layoutMode === 'canvas';
- const isVerticalList =
- isRecordPageEnabled && activeTab.layoutMode === 'vertical-list';
+ const isCanvasLayout = isRecordPageEnabled && layoutMode === 'canvas';
+ const isVerticalList = isRecordPageEnabled && layoutMode === 'vertical-list';
if (isCanvasLayout) {
return ;
@@ -54,7 +56,7 @@ export const PageLayoutContent = ({ tabId }: PageLayoutContentProps) => {
if (isVerticalList) {
return (
-
+
{isPageLayoutInEditMode ? (
{
{item.type === 'placeholder' ? (
) : (
-
+
)}
))}
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutLeftPanel.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutLeftPanel.tsx
index bf44f8c08b..db2df23925 100644
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutLeftPanel.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutLeftPanel.tsx
@@ -1,6 +1,8 @@
import { SummaryCard } from '@/object-record/record-show/components/SummaryCard';
import { PageLayoutContent } from '@/page-layout/components/PageLayoutContent';
+import { PageLayoutContentProvider } from '@/page-layout/contexts/PageLayoutContentContext';
import { useCurrentPageLayout } from '@/page-layout/hooks/useCurrentPageLayout';
+import { getTabLayoutMode } from '@/page-layout/utils/getTabLayoutMode';
import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord';
import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer';
@@ -21,6 +23,15 @@ export const PageLayoutLeftPanel = ({
return null;
}
+ const pinnedTab = currentPageLayout.tabs.find(
+ (tab) => tab.id === pinnedLeftTabId,
+ );
+
+ const layoutMode = getTabLayoutMode({
+ tab: pinnedTab,
+ pageLayoutType: currentPageLayout.type,
+ });
+
return (
-
+
+
+
);
};
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx
index cb52dba85d..75a6e18977 100644
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutRendererContent.tsx
@@ -1,4 +1,5 @@
-import { PageLayoutContent } from '@/page-layout/components/PageLayoutContent';
+import { useNavigatePageLayoutCommandMenu } from '@/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu';
+import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import { PageLayoutLeftPanel } from '@/page-layout/components/PageLayoutLeftPanel';
import { PageLayoutTabHeader } from '@/page-layout/components/PageLayoutTabHeader';
import { PageLayoutTabList } from '@/page-layout/components/PageLayoutTabList';
@@ -6,6 +7,7 @@ import { PageLayoutTabListEffect } from '@/page-layout/components/PageLayoutTabL
import { useCreatePageLayoutTab } from '@/page-layout/hooks/useCreatePageLayoutTab';
import { useCurrentPageLayout } from '@/page-layout/hooks/useCurrentPageLayout';
import { useReorderPageLayoutTabs } from '@/page-layout/hooks/useReorderPageLayoutTabs';
+import { PageLayoutMainContent } from '@/page-layout/PageLayoutMainContent';
import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState';
import { pageLayoutTabSettingsOpenTabIdComponentState } from '@/page-layout/states/pageLayoutTabSettingsOpenTabIdComponentState';
import { getTabListInstanceIdFromPageLayoutId } from '@/page-layout/utils/getTabListInstanceIdFromPageLayoutId';
@@ -18,8 +20,6 @@ import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
-import { useNavigatePageLayoutCommandMenu } from '@/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu';
-import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
import styled from '@emotion/styled';
import { isDefined } from 'twenty-shared/utils';
@@ -124,7 +124,7 @@ export const PageLayoutRendererContent = () => {
defaultEnableXScroll={false}
>
{isDefined(activeTabId) && (
-
+
)}
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListEditor.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListEditor.tsx
index 88f72d52ff..1309f2be56 100644
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListEditor.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListEditor.tsx
@@ -9,7 +9,7 @@ import {
type DropResult,
} from '@hello-pangea/dnd';
import { useId } from 'react';
-import { PageLayoutType, type PageLayoutWidget } from '~/generated/graphql';
+import { type PageLayoutWidget } from '~/generated/graphql';
const StyledVerticalListContainer = styled.div`
display: flex;
@@ -67,11 +67,7 @@ export const PageLayoutVerticalListEditor = ({
>
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
-
+
)}
diff --git a/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListViewer.tsx b/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListViewer.tsx
index f3da18ae92..b33c198696 100644
--- a/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListViewer.tsx
+++ b/packages/twenty-front/src/modules/page-layout/components/PageLayoutVerticalListViewer.tsx
@@ -1,6 +1,6 @@
import { WidgetRenderer } from '@/page-layout/widgets/components/WidgetRenderer';
import styled from '@emotion/styled';
-import { PageLayoutType, type PageLayoutWidget } from '~/generated/graphql';
+import { type PageLayoutWidget } from '~/generated/graphql';
const StyledVerticalListContainer = styled.div`
display: flex;
@@ -19,11 +19,7 @@ export const PageLayoutVerticalListViewer = ({
{widgets.map((widget) => (
-
+
))}
diff --git a/packages/twenty-front/src/modules/page-layout/contexts/PageLayoutContentContext.ts b/packages/twenty-front/src/modules/page-layout/contexts/PageLayoutContentContext.ts
new file mode 100644
index 0000000000..589dcdddd2
--- /dev/null
+++ b/packages/twenty-front/src/modules/page-layout/contexts/PageLayoutContentContext.ts
@@ -0,0 +1,12 @@
+import { type PageLayoutTabLayoutMode } from '@/page-layout/types/PageLayoutTabLayoutMode';
+import { createRequiredContext } from '~/utils/createRequiredContext';
+
+export type PageLayoutContentContextType = {
+ tabId: string;
+ layoutMode: PageLayoutTabLayoutMode;
+};
+
+export const [PageLayoutContentProvider, usePageLayoutContentContext] =
+ createRequiredContext(
+ 'PageLayoutContentContext',
+ );
diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useCurrentPageLayoutOrThrow.ts b/packages/twenty-front/src/modules/page-layout/hooks/useCurrentPageLayoutOrThrow.ts
new file mode 100644
index 0000000000..6d3e720027
--- /dev/null
+++ b/packages/twenty-front/src/modules/page-layout/hooks/useCurrentPageLayoutOrThrow.ts
@@ -0,0 +1,12 @@
+import { useCurrentPageLayout } from '@/page-layout/hooks/useCurrentPageLayout';
+import { isDefined } from 'twenty-shared/utils';
+
+export const useCurrentPageLayoutOrThrow = () => {
+ const { currentPageLayout } = useCurrentPageLayout();
+
+ if (!isDefined(currentPageLayout)) {
+ throw new Error('No current page layout found');
+ }
+
+ return { currentPageLayout };
+};
diff --git a/packages/twenty-front/src/modules/page-layout/utils/assertPageLayoutTabHasDefinedLayoutModeOrThrow.ts b/packages/twenty-front/src/modules/page-layout/utils/assertPageLayoutTabHasDefinedLayoutModeOrThrow.ts
new file mode 100644
index 0000000000..e6e7da68b7
--- /dev/null
+++ b/packages/twenty-front/src/modules/page-layout/utils/assertPageLayoutTabHasDefinedLayoutModeOrThrow.ts
@@ -0,0 +1,15 @@
+import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab';
+import { isNonEmptyString } from '@sniptt/guards';
+
+type AssertPageLayoutTabHasDefinedLayoutModeOrThrow = (
+ tab: PageLayoutTab | undefined,
+) => asserts tab is PageLayoutTab & {
+ layoutMode: NonNullable;
+};
+
+export const assertPageLayoutTabHasDefinedLayoutModeOrThrow: AssertPageLayoutTabHasDefinedLayoutModeOrThrow =
+ (tab) => {
+ if (!isNonEmptyString(tab?.layoutMode)) {
+ throw new Error('Tab layout mode is not defined');
+ }
+ };
diff --git a/packages/twenty-front/src/modules/page-layout/utils/getTabLayoutMode.ts b/packages/twenty-front/src/modules/page-layout/utils/getTabLayoutMode.ts
new file mode 100644
index 0000000000..3fb1398837
--- /dev/null
+++ b/packages/twenty-front/src/modules/page-layout/utils/getTabLayoutMode.ts
@@ -0,0 +1,22 @@
+import { type PageLayoutTab } from '@/page-layout/types/PageLayoutTab';
+import { type PageLayoutTabLayoutMode } from '@/page-layout/types/PageLayoutTabLayoutMode';
+import { assertPageLayoutTabHasDefinedLayoutModeOrThrow } from '@/page-layout/utils/assertPageLayoutTabHasDefinedLayoutModeOrThrow';
+import { PageLayoutType } from '~/generated/graphql';
+
+type GetTabLayoutModeParams = {
+ tab: PageLayoutTab | undefined;
+ pageLayoutType: PageLayoutType;
+};
+
+export const getTabLayoutMode = ({
+ tab,
+ pageLayoutType,
+}: GetTabLayoutModeParams): PageLayoutTabLayoutMode => {
+ if (pageLayoutType === PageLayoutType.RECORD_PAGE) {
+ assertPageLayoutTabHasDefinedLayoutModeOrThrow(tab);
+
+ return tab.layoutMode;
+ }
+
+ return 'grid';
+};
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetPlaceholder.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetPlaceholder.tsx
index 7691b3cdea..e01196316c 100644
--- a/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetPlaceholder.tsx
+++ b/packages/twenty-front/src/modules/page-layout/widgets/components/WidgetPlaceholder.tsx
@@ -1,8 +1,11 @@
import { useNavigatePageLayoutCommandMenu } from '@/command-menu/pages/page-layout/hooks/useNavigatePageLayoutCommandMenu';
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
+import { usePageLayoutContentContext } from '@/page-layout/contexts/PageLayoutContentContext';
+import { useCurrentPageLayoutOrThrow } from '@/page-layout/hooks/useCurrentPageLayoutOrThrow';
import { useSetIsPageLayoutInEditMode } from '@/page-layout/hooks/useSetIsPageLayoutInEditMode';
import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext';
import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState';
+import { useIsInPinnedTab } from '@/page-layout/widgets/hooks/useIsInPinnedTab';
import { WidgetCard } from '@/page-layout/widgets/widget-card/components/WidgetCard';
import { WidgetCardHeader } from '@/page-layout/widgets/widget-card/components/WidgetCardHeader';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
@@ -17,7 +20,6 @@ import {
AnimatedPlaceholderEmptyTitle,
EMPTY_PLACEHOLDER_TRANSITION_PROPS,
} from 'twenty-ui/layout';
-import { PageLayoutType } from '~/generated/graphql';
export const WidgetPlaceholder = () => {
const pageLayoutId = useAvailableComponentInstanceIdOrThrow(
@@ -33,6 +35,10 @@ export const WidgetPlaceholder = () => {
const { navigatePageLayoutCommandMenu } = useNavigatePageLayoutCommandMenu();
+ const { currentPageLayout } = useCurrentPageLayoutOrThrow();
+ const { layoutMode } = usePageLayoutContentContext();
+ const { isInPinnedTab } = useIsInPinnedTab();
+
const handleClick = () => {
if (!isPageLayoutInEditMode) {
setIsPageLayoutInEditMode(true);
@@ -44,11 +50,12 @@ export const WidgetPlaceholder = () => {
return (
{
+export const WidgetRenderer = ({ widget }: WidgetRendererProps) => {
const theme = useTheme();
const { deletePageLayoutWidget } = useDeletePageLayoutWidget();
const { handleEditWidget } = useEditPageLayoutWidget();
@@ -49,6 +45,13 @@ export const WidgetRenderer = ({
const { hasAccess, restriction } = useWidgetPermissions(widget);
+ const { layoutMode } = usePageLayoutContentContext();
+ const { isInPinnedTab } = useIsInPinnedTab();
+
+ const { currentPageLayout } = useCurrentPageLayoutOrThrow();
+
+ const showHeader = layoutMode !== 'canvas' && !isInPinnedTab;
+
const handleClick = () => {
handleEditWidget({
widgetId: widget.id,
@@ -73,15 +76,16 @@ export const WidgetRenderer = ({
return (
- {layoutMode !== 'canvas' && (
+ {showHeader && (
{hasAccess && }
- {!hasAccess && pageLayoutType === PageLayoutType.DASHBOARD && (
+ {!hasAccess && currentPageLayout.type === PageLayoutType.DASHBOARD && (
= {
title: 'Modules/PageLayout/Widgets/WidgetPlaceholder',
component: WidgetPlaceholder,
@@ -19,11 +37,29 @@ const meta: Meta = {
generatedMockObjectMetadataItems,
);
snapshot.set(shouldAppBeLoadingState, false);
+ snapshot.set(
+ pageLayoutPersistedComponentState.atomFamily({
+ instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID,
+ }),
+ mockPageLayout,
+ );
};
return (
-
+
+
+
+
+
);
},
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/components/__stories__/WidgetRenderer.stories.tsx b/packages/twenty-front/src/modules/page-layout/widgets/components/__stories__/WidgetRenderer.stories.tsx
index d0846812d2..f34c7b7b02 100644
--- a/packages/twenty-front/src/modules/page-layout/widgets/components/__stories__/WidgetRenderer.stories.tsx
+++ b/packages/twenty-front/src/modules/page-layout/widgets/components/__stories__/WidgetRenderer.stories.tsx
@@ -12,9 +12,15 @@ import { ApolloCoreClientContext } from '@/object-metadata/contexts/ApolloCoreCl
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { shouldAppBeLoadingState } from '@/object-metadata/states/shouldAppBeLoadingState';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
-import { PageLayoutTestWrapper } from '@/page-layout/hooks/__tests__/PageLayoutTestWrapper';
+import { PageLayoutContentProvider } from '@/page-layout/contexts/PageLayoutContentContext';
+import {
+ PAGE_LAYOUT_TEST_INSTANCE_ID,
+ PageLayoutTestWrapper,
+} from '@/page-layout/hooks/__tests__/PageLayoutTestWrapper';
+import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState';
import { WidgetRenderer } from '@/page-layout/widgets/components/WidgetRenderer';
import { generateGroupByQuery } from '@/page-layout/widgets/graph/utils/generateGroupByQuery';
+import { LayoutRenderingProvider } from '@/ui/layout/contexts/LayoutRenderingContext';
import {
GraphOrderBy,
GraphType,
@@ -124,6 +130,21 @@ const meta: Meta = {
generatedMockObjectMetadataItems,
);
snapshot.set(shouldAppBeLoadingState, false);
+ snapshot.set(
+ pageLayoutPersistedComponentState.atomFamily({
+ instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID,
+ }),
+ {
+ id: PAGE_LAYOUT_TEST_INSTANCE_ID,
+ name: 'Mock Page Layout',
+ type: PageLayoutType.DASHBOARD,
+ objectMetadataId: companyObjectMetadataItem.id,
+ tabs: [],
+ createdAt: '2024-01-01T00:00:00Z',
+ updatedAt: '2024-01-01T00:00:00Z',
+ deletedAt: null,
+ },
+ );
};
return (
@@ -131,7 +152,26 @@ const meta: Meta = {
-
+
+
+
+
+
@@ -183,11 +223,7 @@ export const WithNumberChart: Story = {
},
render: (args) => (
-
+
),
};
@@ -222,11 +258,7 @@ export const WithGaugeChart: Story = {
},
render: (args) => (
-
+
),
};
@@ -264,11 +296,7 @@ export const WithBarChart: Story = {
},
render: (args) => (
-
+
),
};
@@ -310,11 +338,7 @@ export const SmallWidget: Story = {
},
render: (args) => (
-
+
),
};
@@ -359,11 +383,7 @@ export const MediumWidget: Story = {
},
render: (args) => (
-
+
),
};
@@ -408,11 +428,7 @@ export const LargeWidget: Story = {
},
render: (args) => (
-
+
),
};
@@ -454,11 +470,7 @@ export const WideWidget: Story = {
},
render: (args) => (
-
+
),
};
@@ -503,11 +515,7 @@ export const TallWidget: Story = {
},
render: (args) => (
-
+
),
};
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/hooks/useIsInPinnedTab.ts b/packages/twenty-front/src/modules/page-layout/widgets/hooks/useIsInPinnedTab.ts
new file mode 100644
index 0000000000..d8bccf0404
--- /dev/null
+++ b/packages/twenty-front/src/modules/page-layout/widgets/hooks/useIsInPinnedTab.ts
@@ -0,0 +1,24 @@
+import { usePageLayoutContentContext } from '@/page-layout/contexts/PageLayoutContentContext';
+import { useCurrentPageLayoutOrThrow } from '@/page-layout/hooks/useCurrentPageLayoutOrThrow';
+import { getTabsByDisplayMode } from '@/page-layout/utils/getTabsByDisplayMode';
+import { useLayoutRenderingContext } from '@/ui/layout/contexts/LayoutRenderingContext';
+import { isDefined } from 'twenty-shared/utils';
+import { useIsMobile } from 'twenty-ui/utilities';
+
+export const useIsInPinnedTab = () => {
+ const isMobile = useIsMobile();
+
+ const { tabId } = usePageLayoutContentContext();
+ const { isInRightDrawer } = useLayoutRenderingContext();
+ const { currentPageLayout } = useCurrentPageLayoutOrThrow();
+
+ const { pinnedLeftTab } = getTabsByDisplayMode({
+ pageLayout: currentPageLayout,
+ isMobile,
+ isInRightDrawer,
+ });
+
+ return {
+ isInPinnedTab: isDefined(pinnedLeftTab) && pinnedLeftTab.id === tabId,
+ };
+};
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 36426fb33d..22d88eddc2 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
@@ -14,6 +14,7 @@ export type WidgetCardProps = {
onClick?: () => void;
isEditing: boolean;
isDragging: boolean;
+ isInPinnedTab: boolean;
className?: string;
onMouseEnter?: () => void;
onMouseLeave?: () => void;
@@ -23,6 +24,7 @@ const StyledWidgetCard = styled.div<{
onClick?: () => void;
pageLayoutType: PageLayoutType;
layoutMode: PageLayoutTabLayoutMode;
+ isInPinnedTab: boolean;
isPageLayoutInEditMode: boolean;
isEditing: boolean;
isDragging: boolean;
@@ -41,6 +43,7 @@ const StyledWidgetCard = styled.div<{
isPageLayoutInEditMode,
isEditing,
isDragging,
+ isInPinnedTab,
onClick,
}) => {
if (layoutMode === 'canvas') {
@@ -50,7 +53,7 @@ const StyledWidgetCard = styled.div<{
}
switch (pageLayoutType) {
- case PageLayoutType.DASHBOARD:
+ case PageLayoutType.DASHBOARD: {
return css`
background: ${theme.background.secondary};
border: 1px solid ${theme.border.color.light};
@@ -85,8 +88,9 @@ const StyledWidgetCard = styled.div<{
border: 1px solid ${theme.color.blue} !important;
`}
`;
+ }
- case PageLayoutType.RECORD_PAGE:
+ case PageLayoutType.RECORD_PAGE: {
return css`
background: ${theme.background.primary};
border: 1px solid transparent;
@@ -120,10 +124,20 @@ const StyledWidgetCard = styled.div<{
${theme.background.secondary};
border: 1px solid ${theme.color.blue} !important;
`}
+
+ ${isInPinnedTab &&
+ !isPageLayoutInEditMode &&
+ css`
+ border: none;
+ padding: 0;
+ border-radius: 0;
+ background: ${theme.background.secondary};
+ `}
`;
+ }
default:
- return '';
+ return undefined;
}
}}
`;
@@ -135,6 +149,7 @@ export const WidgetCard = ({
onClick,
isEditing,
isDragging,
+ isInPinnedTab,
className,
onMouseEnter,
onMouseLeave,
@@ -151,6 +166,7 @@ export const WidgetCard = ({
isPageLayoutInEditMode={isPageLayoutInEditMode}
isEditing={isEditing}
isDragging={isDragging}
+ isInPinnedTab={isInPinnedTab}
className={className}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardContent.tsx b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardContent.tsx
index 2f848a465e..731d6dabe5 100644
--- a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardContent.tsx
+++ b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/WidgetCardContent.tsx
@@ -7,6 +7,8 @@ import { type PageLayoutType } from '~/generated/graphql';
export type WidgetCardContentProps = {
children?: ReactNode;
pageLayoutType: PageLayoutType;
+ isInPinnedTab: boolean;
+ isPageLayoutInEditMode: boolean;
layoutMode: PageLayoutTabLayoutMode;
className?: string;
};
@@ -20,7 +22,13 @@ const StyledWidgetCardContent = styled.div`
box-sizing: border-box;
padding: ${({ theme }) => theme.spacing(2)};
- ${({ theme, pageLayoutType, layoutMode }) => {
+ ${({
+ theme,
+ pageLayoutType,
+ layoutMode,
+ isPageLayoutInEditMode,
+ isInPinnedTab,
+ }) => {
if (layoutMode === 'canvas') {
return css`
padding: 0;
@@ -32,6 +40,13 @@ const StyledWidgetCardContent = styled.div`
return css`
border: 1px solid ${theme.border.color.medium};
border-radius: ${theme.border.radius.md};
+
+ ${isInPinnedTab &&
+ !isPageLayoutInEditMode &&
+ css`
+ border: none;
+ padding: 0;
+ `}
`;
default:
diff --git a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/__stories__/WidgetCard.stories.tsx b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/__stories__/WidgetCard.stories.tsx
index b42003bf3c..798c0ed5b7 100644
--- a/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/__stories__/WidgetCard.stories.tsx
+++ b/packages/twenty-front/src/modules/page-layout/widgets/widget-card/components/__stories__/WidgetCard.stories.tsx
@@ -73,6 +73,7 @@ export const Default: Story = {
args: {
pageLayoutType: PageLayoutType.DASHBOARD,
layoutMode: 'grid',
+ isInPinnedTab: false,
isEditing: false,
isDragging: false,
},
@@ -80,6 +81,7 @@ export const Default: Story = {
@@ -92,6 +94,8 @@ export const Default: Story = {
Widget
@@ -119,7 +123,9 @@ export const Catalog: CatalogStory = {
name: 'contextVariant',
values: [
'Record Page - Default',
+ 'Record Page - Default - Pinned',
'Record Page - Restriction',
+ 'Record Page - Restriction - Pinned',
'Dashboard - Default',
'Dashboard - Restriction',
],
@@ -128,11 +134,13 @@ export const Catalog: CatalogStory = {
? PageLayoutType.RECORD_PAGE
: PageLayoutType.DASHBOARD;
const hasRestriction = contextName.includes('Restriction');
+ const isInPinnedTab = contextName.includes('Pinned');
return {
pageLayoutType,
contextVariant: contextName,
hasRestriction,
+ isInPinnedTab,
};
},
},
@@ -171,7 +179,9 @@ export const Catalog: CatalogStory = {
const isReadMode = args.state === 'Read Mode';
const pageLayoutType = args.pageLayoutType || PageLayoutType.DASHBOARD;
const layoutMode = args.layoutMode || 'grid';
+ const isInPinnedTab = args.isInPinnedTab || false;
const hasRestriction = args.hasRestriction || false;
+ const isPageLayoutInEditMode = false;
return (
@@ -182,6 +192,7 @@ export const Catalog: CatalogStory = {
isEditing={args.isEditing ?? false}
pageLayoutType={pageLayoutType}
layoutMode={layoutMode}
+ isInPinnedTab={isInPinnedTab}
>
= {
Widget