fix(twenty-front): match loading skeleton menu width to the nav drawer (#21278)

## What

On the very first load (full browser refresh), the navigation skeleton
didn't match the real `NavigationDrawer` width: it rendered an 8px-wider
panel (an 8px wrapper padding on top of the 220px animated container)
and right-aligned 204/196px item rows, so the menu visibly shifted and
resized once the app finished loading.

This makes every navigation skeleton mirror the real drawer geometry: a
single `NAVIGATION_DRAWER_CONSTRAINTS.default`-wide (220px), border-box
panel with the drawer's own padding, left-aligned, and skeleton bars
that fill the content width like the real nav items (`width: 100%`). The
same fill-width fix is applied to the in-drawer section skeletons so
every navigation skeleton matches the real menu width.

## Verification

- `tsgo` typecheck, `oxlint`, and `oxfmt` all clean on the changed
files.

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
This commit is contained in:
Félix Malfait
2026-06-08 18:38:17 +02:00
committed by GitHub
parent c596a5e342
commit cd13457a4a
6 changed files with 54 additions and 25 deletions
@@ -7,31 +7,36 @@ import { NAVIGATION_DRAWER_CONSTRAINTS } from '@/ui/layout/resizable-panel/const
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { MainNavigationDrawerItemsSkeletonLoader } from '~/loading/components/MainNavigationDrawerItemsSkeletonLoader';
import { useContext } from 'react';
import { ThemeContext } from 'twenty-ui-deprecated/theme-constants';
import {
ThemeContext,
themeCssVariables,
} from 'twenty-ui-deprecated/theme-constants';
const StyledAnimatedContainer = styled(motion.div)`
align-items: center;
box-sizing: border-box;
display: flex;
justify-content: end;
flex-direction: column;
flex-shrink: 0;
height: 100%;
overflow: hidden;
padding: ${themeCssVariables.spacing[3]} 0 ${themeCssVariables.spacing[4]}
${themeCssVariables.spacing[2]};
`;
const StyledItemsContainer = styled.div`
align-items: center;
display: flex;
flex-direction: column;
gap: 14px;
height: calc(100dvh - 32px);
margin-bottom: auto;
max-width: 204px;
min-width: 204px;
min-height: 0;
overflow-y: auto;
width: 100%;
`;
const StyledSkeletonContainer = styled.div`
align-items: center;
display: flex;
flex-direction: column;
gap: 32px;
width: 100%;
`;
const StyledSkeletonTitleContainer = styled.div`
@@ -41,9 +46,7 @@ const StyledSkeletonTitleContainer = styled.div`
gap: 10px;
height: 32px;
justify-content: center;
max-width: 196px;
min-width: 196px;
width: 100%;
`;
export const LeftPanelSkeletonLoader = () => {
@@ -1,4 +1,5 @@
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { css } from '@linaria/core';
import { styled } from '@linaria/react';
import { useContext } from 'react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
@@ -6,12 +7,15 @@ import { ThemeContext } from 'twenty-ui-deprecated/theme-constants';
const StyledSkeletonContainer = styled.div`
align-items: flex-start;
display: flex;
flex-direction: column;
gap: 6px;
max-width: 196px;
min-width: 196px;
width: 100%;
`;
const fillSkeletonContainer = css`
display: block;
width: 100%;
`;
export const MainNavigationDrawerItemsSkeletonLoader = ({
@@ -38,7 +42,7 @@ export const MainNavigationDrawerItemsSkeletonLoader = ({
{Array.from({ length }).map((_, index) => (
<Skeleton
key={index}
width={196}
containerClassName={fillSkeletonContainer}
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
/>
))}
@@ -28,7 +28,6 @@ const StyledContainer = styled.div`
const StyledLeftPanelWrapper = styled.div`
flex-shrink: 0;
padding: 12px 0 12px 8px;
`;
export const UserOrMetadataLoader = () => {
@@ -1,4 +1,5 @@
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { css } from '@linaria/core';
import { styled } from '@linaria/react';
import { useContext } from 'react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
@@ -19,6 +20,12 @@ const StyledSkeletonColumn = styled.div`
display: flex;
flex-direction: column;
gap: ${themeCssVariables.spacing[1]};
width: 100%;
`;
const fillSkeletonContainer = css`
display: block;
width: 100%;
`;
export const NavigationMenuItemSkeletonLoader = () => {
@@ -36,11 +43,11 @@ export const NavigationMenuItemSkeletonLoader = () => {
/>
<StyledSkeletonColumn>
<Skeleton
width={196}
containerClassName={fillSkeletonContainer}
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
/>
<Skeleton
width={196}
containerClassName={fillSkeletonContainer}
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
/>
</StyledSkeletonColumn>
@@ -1,4 +1,5 @@
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { css } from '@linaria/core';
import { styled } from '@linaria/react';
import { useContext } from 'react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
@@ -8,11 +9,18 @@ import {
} from 'twenty-ui-deprecated/theme-constants';
const StyledSkeletonColumn = styled.div`
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: ${themeCssVariables.spacing[1]};
height: 76px;
padding-left: ${themeCssVariables.spacing[1]};
width: 100%;
`;
const fillSkeletonContainer = css`
display: block;
width: 100%;
`;
export const NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader: React.FC =
@@ -26,15 +34,15 @@ export const NavigationDrawerSectionForObjectMetadataItemsSkeletonLoader: React.
>
<StyledSkeletonColumn>
<Skeleton
width={196}
containerClassName={fillSkeletonContainer}
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
/>
<Skeleton
width={196}
containerClassName={fillSkeletonContainer}
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
/>
<Skeleton
width={196}
containerClassName={fillSkeletonContainer}
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
/>
</StyledSkeletonColumn>
@@ -1,5 +1,6 @@
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection';
import { css } from '@linaria/core';
import { styled } from '@linaria/react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { themeCssVariables } from 'twenty-ui-deprecated/theme-constants';
@@ -13,10 +14,17 @@ const StyledTitleSkeleton = styled.div`
`;
const StyledRowsContainer = styled.div`
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: ${themeCssVariables.spacing[1]};
padding-left: ${themeCssVariables.spacing[1]};
width: 100%;
`;
const fillSkeletonContainer = css`
display: block;
width: 100%;
`;
export const NavigationDrawerWorkspaceSectionSkeletonLoader = () => {
@@ -35,15 +43,15 @@ export const NavigationDrawerWorkspaceSectionSkeletonLoader = () => {
</StyledTitleSkeleton>
<StyledRowsContainer>
<Skeleton
width={196}
containerClassName={fillSkeletonContainer}
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
/>
<Skeleton
width={196}
containerClassName={fillSkeletonContainer}
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
/>
<Skeleton
width={196}
containerClassName={fillSkeletonContainer}
height={SKELETON_LOADER_HEIGHT_SIZES.standard.s}
/>
</StyledRowsContainer>