Skip to content

Commit 09f52cf

Browse files
committed
feat: implement DynamicMinHeight component for responsive layout
- Added a new `DynamicMinHeight` component to calculate and set the minimum height dynamically based on header and onboarding banner heights. - Replaced static height calculations in the layout with the new component to enhance responsiveness. - Updated `OnboardingTracker` component to include an ID for the onboarding banner, allowing for accurate height calculations.
1 parent 2edbeb9 commit 09f52cf

File tree

3 files changed

+59
-15
lines changed

3 files changed

+59
-15
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
'use client';
2+
3+
import { cn } from '@comp/ui/cn';
4+
import { useEffect, useMemo, useRef, useState } from 'react';
5+
6+
interface DynamicMinHeightProps {
7+
children: React.ReactNode;
8+
className?: string;
9+
}
10+
11+
export function DynamicMinHeight({ children, className }: DynamicMinHeightProps) {
12+
const containerRef = useRef<HTMLDivElement | null>(null);
13+
const [offsetPx, setOffsetPx] = useState<number>(0);
14+
15+
useEffect(() => {
16+
const headerEl = document.querySelector('header.sticky') as HTMLElement | null;
17+
const bannerEl = document.getElementById('onboarding-banner') as HTMLElement | null;
18+
19+
const compute = () => {
20+
const header = headerEl?.offsetHeight ?? 0;
21+
const banner = bannerEl?.offsetHeight ?? 0;
22+
// Add 1px border for each element like the server calculation did
23+
const extra = 0; // borders already included in offsetHeight
24+
setOffsetPx(header + banner + extra);
25+
};
26+
27+
compute();
28+
29+
const resizeObserver = new ResizeObserver(() => compute());
30+
if (headerEl) resizeObserver.observe(headerEl);
31+
if (bannerEl) resizeObserver.observe(bannerEl);
32+
33+
const onResize = () => compute();
34+
window.addEventListener('resize', onResize);
35+
36+
return () => {
37+
resizeObserver.disconnect();
38+
window.removeEventListener('resize', onResize);
39+
};
40+
}, []);
41+
42+
const style = useMemo(() => ({ minHeight: `calc(100vh - ${offsetPx}px)` }), [offsetPx]);
43+
44+
return (
45+
<div
46+
ref={containerRef}
47+
className={cn('textured-background mx-auto px-4 py-4', className)}
48+
style={style}
49+
>
50+
{children}
51+
</div>
52+
);
53+
}

apps/app/src/app/(app)/[orgId]/components/OnboardingTracker.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,10 @@ export const OnboardingTracker = ({ onboarding }: { onboarding: Onboarding }) =>
197197
}
198198

199199
return (
200-
<Card className="w-full overflow-hidden rounded-none border-x-0 border-t-0">
200+
<Card
201+
id="onboarding-banner"
202+
className="w-full overflow-hidden rounded-none border-x-0 border-t-0"
203+
>
201204
<CardContent className="bg-background flex flex-col items-center justify-center">
202205
<div className="w-full pt-4">{renderStatusContent()}</div>
203206
</CardContent>

apps/app/src/app/(app)/[orgId]/layout.tsx

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import dynamic from 'next/dynamic';
1111
import { cookies, headers } from 'next/headers';
1212
import { redirect } from 'next/navigation';
1313
import { Suspense } from 'react';
14+
import { DynamicMinHeight } from './components/DynamicMinHeight';
1415
import { OnboardingTracker } from './components/OnboardingTracker';
1516

1617
const HotKeys = dynamic(() => import('@/components/hot-keys').then((mod) => mod.HotKeys), {
@@ -57,8 +58,6 @@ export default async function Layout({
5758
},
5859
});
5960

60-
console.log('member', member);
61-
6261
if (!member) {
6362
// User doesn't have access to this organization
6463
return redirect('/auth/unauthorized');
@@ -80,12 +79,6 @@ export default async function Layout({
8079
},
8180
});
8281

83-
const isOnboardingRunning = !!onboarding?.triggerJobId && !onboarding.triggerJobCompleted;
84-
const navbarHeight = 53 + 1; // 1 for border
85-
const onboardingHeight = 132 + 1; // 1 for border
86-
87-
const pixelsOffset = isOnboardingRunning ? navbarHeight + onboardingHeight : navbarHeight;
88-
8982
return (
9083
<TriggerTokenProvider
9184
triggerJobId={onboarding?.triggerJobId || undefined}
@@ -95,12 +88,7 @@ export default async function Layout({
9588
<AnimatedLayout sidebar={<Sidebar organization={organization} />} isCollapsed={isCollapsed}>
9689
{onboarding?.triggerJobId && <OnboardingTracker onboarding={onboarding} />}
9790
<Header />
98-
<div
99-
className="textured-background mx-auto px-4 py-4"
100-
style={{ minHeight: `calc(100vh - ${pixelsOffset}px)` }}
101-
>
102-
{children}
103-
</div>
91+
<DynamicMinHeight>{children}</DynamicMinHeight>
10492
<AssistantSheet />
10593
<Suspense fallback={null}>
10694
<CheckoutCompleteDialog orgId={organization.id} />

0 commit comments

Comments
 (0)