Skip to content

Commit 163b522

Browse files
authored
Merge pull request #3745 from liam-hq/ux/adjustable-panel-width
✨ Implement adjustable panel width for SessionDetailPage
2 parents 820d9fa + 6815cc7 commit 163b522

File tree

10 files changed

+222
-67
lines changed

10 files changed

+222
-67
lines changed

.changeset/hot-moles-watch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@liam-hq/erd-core": patch
3+
---
4+
5+
🚸 Disable ERD resize handle when the left pane is closed to prevent accidental resizing and layout conflicts

.claude/commands/commit.md

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,65 @@ Examples of bad commit messages:
2323
- 🐛 Fixed a typo in the welcome message
2424
- 📝 Updated README.md with new installation instructions
2525

26-
## Common Gitmoji Reference
26+
## Gitmoji Reference
2727

28-
- ✨ New feature
29-
- 🐛 Bug fix
30-
- 💥 Breaking change
31-
- ⚡ Performance improvement
32-
- ♻️ Code improvement
33-
- 🔧 Configuration/options
28+
### Frequently Used
29+
- 🚸 `:children_crossing:` - Improve user experience / usability
30+
-`:sparkles:` - Introduce new features
31+
- 🐛 `:bug:` - Fix a bug
32+
- ♻️ `:recycle:` - Refactor code
33+
-`:zap:` - Improve performance
34+
- 💄 `:lipstick:` - Add or update the UI and style files
35+
- 🎨 `:art:` - Improve structure / format of the code
36+
- 📝 `:memo:` - Add or update documentation
37+
- 🔧 `:wrench:` - Add or update configuration files
3438

35-
For the complete list, visit [gitmoji.dev](https://gitmoji.dev/).
39+
### Testing & Quality
40+
-`:white_check_mark:` - Add, update, or pass tests
41+
- 🚨 `:rotating_light:` - Fix compiler / linter warnings
42+
- 🧪 `:test_tube:` - Add a failing test
43+
- 🥅 `:goal_net:` - Catch errors
44+
45+
### Critical Changes
46+
- 🚑 `:ambulance:` - Critical hotfix
47+
- 💥 `:boom:` - Introduce breaking changes
48+
- 🔒 `:lock:` - Fix security or privacy issues
49+
50+
### Dependencies & CI/CD
51+
-`:heavy_plus_sign:` - Add a dependency
52+
-`:heavy_minus_sign:` - Remove a dependency
53+
- ⬆️ `:arrow_up:` - Upgrade dependencies
54+
- ⬇️ `:arrow_down:` - Downgrade dependencies
55+
- 💚 `:green_heart:` - Fix CI Build
56+
- 👷 `:construction_worker:` - Add or update CI build system
57+
58+
### Code Management
59+
- 🔥 `:fire:` - Remove code or files
60+
- ⚰️ `:coffin:` - Remove dead code
61+
- 🚚 `:truck:` - Move or rename resources (e.g.: files, paths, routes)
62+
-`:rewind:` - Revert changes
63+
- 🔀 `:twisted_rightwards_arrows:` - Merge branches
64+
65+
### Work in Progress
66+
- 🚧 `:construction:` - Work in progress
67+
- 🩹 `:adhesive_bandage:` - Simple fix for a non-critical issue
68+
69+
### Types & Database
70+
- 🏷️ `:label:` - Add or update types
71+
- 🗃️ `:card_file_box:` - Perform database related changes
72+
73+
### Accessibility & i18n
74+
-`:wheelchair:` - Improve accessibility
75+
- 🌐 `:globe_with_meridians:` - Internationalization and localization
76+
77+
### Other Useful
78+
- 🚀 `:rocket:` - Deploy stuff
79+
- 🔖 `:bookmark:` - Release / Version tags
80+
- 📱 `:iphone:` - Work on responsive design
81+
- 💫 `:dizzy:` - Add or update animations and transitions
82+
- ✏️ `:pencil2:` - Fix typos
83+
- 🙈 `:see_no_evil:` - Add or update a .gitignore file
84+
- 🔊 `:loud_sound:` - Add or update logs
85+
- 🔇 `:mute:` - Remove logs
86+
87+
For the complete list, run `gitmoji list` or visit [gitmoji.dev](https://gitmoji.dev/).

frontend/apps/app/components/PublicSessionDetailPage/PublicSessionDetailPage.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { ReactElement } from 'react'
55
import { safeParse } from 'valibot'
66
import { createPublicServerClient } from '../../libs/db/server'
77
import { PublicLayout } from '../PublicLayout'
8+
import { DEFAULT_PANEL_SIZES } from '../SessionDetailPage/constants'
89
import { ViewModeProvider } from '../SessionDetailPage/contexts/ViewModeContext'
910
import { SessionDetailPageClient } from '../SessionDetailPage/SessionDetailPageClient'
1011
import { buildPrevSchema } from '../SessionDetailPage/services/buildPrevSchema/server/buildPrevSchema'
@@ -136,6 +137,7 @@ export const PublicSessionDetailPage = async ({
136137
initialIsPublic={true}
137138
initialArtifact={initialArtifact}
138139
senderName="Guest"
140+
panelSizes={DEFAULT_PANEL_SIZES}
139141
/>
140142
</ViewModeProvider>
141143
</PublicLayout>

frontend/apps/app/components/SessionDetailPage/SessionDetailPage.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ import { type Artifact, artifactSchema } from '@liam-hq/artifact'
88
import type { Schema } from '@liam-hq/schema'
99
import { schemaSchema } from '@liam-hq/schema'
1010
import { err, ok, type Result } from 'neverthrow'
11+
import { cookies } from 'next/headers'
1112
import type { FC } from 'react'
1213
import { safeParse } from 'valibot'
1314
import { checkPublicShareStatus } from '../../features/public-share/actions'
1415
import { createClient } from '../../libs/db/server'
16+
import { DEFAULT_PANEL_SIZES, PANEL_LAYOUT_COOKIE_NAME } from './constants'
1517
import { ViewModeProvider } from './contexts/ViewModeContext'
1618
import { SessionDetailPageClient } from './SessionDetailPageClient'
1719
import { getBuildingSchema } from './services/buildingSchema/server/getBuildingSchema'
@@ -148,6 +150,17 @@ export const SessionDetailPage: FC<Props> = async ({
148150
const { isPublic: initialIsPublic } =
149151
await checkPublicShareStatus(designSessionId)
150152

153+
const cookieStore = await cookies()
154+
const layoutCookie = cookieStore.get(PANEL_LAYOUT_COOKIE_NAME)
155+
const panelSizes = (() => {
156+
if (!layoutCookie) return DEFAULT_PANEL_SIZES
157+
try {
158+
const sizes = JSON.parse(layoutCookie.value)
159+
if (Array.isArray(sizes) && sizes.length >= 2) return sizes
160+
} catch {}
161+
return DEFAULT_PANEL_SIZES
162+
})()
163+
151164
return (
152165
<ViewModeProvider mode="private">
153166
<SessionDetailPageClient
@@ -162,6 +175,7 @@ export const SessionDetailPage: FC<Props> = async ({
162175
initialIsPublic={initialIsPublic}
163176
initialWorkflowError={workflowError}
164177
senderName={senderName}
178+
panelSizes={panelSizes}
165179
/>
166180
</ViewModeProvider>
167181
)

frontend/apps/app/components/SessionDetailPage/SessionDetailPage.module.css renamed to frontend/apps/app/components/SessionDetailPage/SessionDetailPageClient.module.css

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,32 @@
66
}
77

88
.columns {
9-
display: grid;
109
width: 100%;
1110
height: 100%;
12-
transition: grid-template-columns var(--default-animation-duration)
13-
var(--default-timing-function);
14-
}
15-
16-
.oneColumn {
17-
grid-template-columns: 46rem 0fr;
18-
justify-content: center;
19-
}
20-
21-
.twoColumns {
22-
grid-template-columns: 23rem 1fr;
2311
}
2412

2513
.outputSection {
2614
min-height: 0;
2715
border-left: solid 1px var(--pane-border);
2816
overflow: hidden;
17+
height: 100%;
2918
}
3019

3120
.chatSection {
3221
min-height: 0;
22+
height: 100%;
23+
}
24+
25+
.columns[data-layout='one-column'] .chatSection {
26+
display: flex;
27+
justify-content: center;
28+
}
29+
30+
.chatWrapper {
31+
width: auto;
32+
height: 100%;
33+
}
34+
35+
.columns[data-layout='one-column'] .chatWrapper {
36+
width: 46rem;
3337
}

frontend/apps/app/components/SessionDetailPage/SessionDetailPageClient.tsx

Lines changed: 77 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,28 @@ import {
66
} from '@langchain/core/messages'
77
import type { Artifact } from '@liam-hq/artifact'
88
import type { Schema } from '@liam-hq/schema'
9-
import clsx from 'clsx'
9+
import {
10+
ResizableHandle,
11+
ResizablePanel,
12+
ResizablePanelGroup,
13+
} from '@liam-hq/ui'
1014
import { type FC, useCallback, useEffect, useRef, useState } from 'react'
15+
import { setCookieJson } from '../../libs/utils/cookie'
1116
import { Chat } from './components/Chat'
1217
import { Output } from './components/Output'
1318
import { useRealtimeArtifact } from './components/Output/components/Artifact/hooks/useRealtimeArtifact'
1419
import { OUTPUT_TABS, type OutputTabValue } from './components/Output/constants'
20+
import { PANEL_LAYOUT_COOKIE_NAME } from './constants'
1521
import { useRealtimeVersionsWithSchema } from './hooks/useRealtimeVersionsWithSchema'
1622
import { useStream } from './hooks/useStream'
1723
import { SQL_REVIEW_COMMENTS } from './mock'
18-
import styles from './SessionDetailPage.module.css'
24+
import styles from './SessionDetailPageClient.module.css'
1925
import type { Version } from './types'
2026
import { determineWorkflowAction } from './utils/determineWorkflowAction'
2127
import { getWorkflowInProgress } from './utils/workflowStorage'
2228

29+
const COOKIE_MAX_AGE = 60 * 60 * 24 * 7
30+
2331
type Props = {
2432
buildingSchemaId: string
2533
designSessionId: string
@@ -32,6 +40,7 @@ type Props = {
3240
initialWorkflowError?: string | null
3341
initialArtifact: Artifact | null
3442
senderName: string
43+
panelSizes: number[]
3544
}
3645

3746
// Determine the initial active tab based on available data
@@ -71,10 +80,12 @@ export const SessionDetailPageClient: FC<Props> = ({
7180
initialWorkflowError,
7281
initialArtifact,
7382
senderName,
83+
panelSizes,
7484
}) => {
7585
const [activeTab, setActiveTab] = useState<OutputTabValue | undefined>(
7686
determineInitialTab(initialArtifact, initialVersions),
7787
)
88+
const [isResizing, setIsResizing] = useState(false)
7889

7990
const {
8091
versions,
@@ -123,6 +134,13 @@ export const SessionDetailPageClient: FC<Props> = ({
123134
senderName,
124135
})
125136

137+
const handleLayoutChange = useCallback((sizes: number[]) => {
138+
setCookieJson(PANEL_LAYOUT_COOKIE_NAME, sizes, {
139+
path: '/',
140+
maxAge: COOKIE_MAX_AGE,
141+
})
142+
}, [])
143+
126144
// Combine streaming error with workflow errors
127145
const combinedError = error || initialWorkflowError
128146
// Track if initial workflow has been triggered to prevent multiple executions
@@ -165,47 +183,66 @@ export const SessionDetailPageClient: FC<Props> = ({
165183

166184
return (
167185
<div className={styles.container}>
168-
<div
169-
className={clsx(
170-
styles.columns,
171-
shouldShowOutputSection ? styles.twoColumns : styles.oneColumn,
172-
)}
186+
<ResizablePanelGroup
187+
direction="horizontal"
188+
className={styles.columns}
189+
data-layout={shouldShowOutputSection ? 'two-columns' : 'one-column'}
190+
onLayout={handleLayoutChange}
173191
>
174-
<div className={styles.chatSection}>
175-
<Chat
176-
schemaData={displayedSchema}
177-
messages={messages}
178-
isWorkflowRunning={isStreaming}
179-
onSendMessage={(content: string) =>
180-
start({
181-
userInput: content,
182-
designSessionId,
183-
isDeepModelingEnabled,
184-
})
185-
}
186-
onNavigate={setActiveTab}
187-
error={combinedError}
188-
/>
189-
</div>
190-
{shouldShowOutputSection && (
191-
<div className={styles.outputSection}>
192-
<Output
193-
designSessionId={designSessionId}
194-
schema={displayedSchema}
195-
prevSchema={prevSchema}
196-
sqlReviewComments={SQL_REVIEW_COMMENTS}
197-
versions={versions}
198-
selectedVersion={selectedVersion}
199-
onSelectedVersionChange={handleVersionChange}
200-
activeTab={activeTab}
201-
onTabChange={setActiveTab}
202-
initialIsPublic={initialIsPublic}
203-
artifact={artifact}
204-
artifactError={artifactError}
205-
/>
192+
<ResizablePanel
193+
defaultSize={panelSizes[0]}
194+
minSize={22}
195+
maxSize={70}
196+
isResizing={isResizing}
197+
>
198+
<div className={styles.chatSection}>
199+
<div className={styles.chatWrapper}>
200+
<Chat
201+
schemaData={displayedSchema}
202+
messages={messages}
203+
isWorkflowRunning={isStreaming}
204+
onSendMessage={(content: string) =>
205+
start({
206+
userInput: content,
207+
designSessionId,
208+
isDeepModelingEnabled,
209+
})
210+
}
211+
onNavigate={setActiveTab}
212+
error={combinedError}
213+
/>
214+
</div>
206215
</div>
216+
</ResizablePanel>
217+
{shouldShowOutputSection && (
218+
<>
219+
<ResizableHandle onDragging={(e) => setIsResizing(e)} />
220+
<ResizablePanel
221+
defaultSize={panelSizes[1]}
222+
minSize={30}
223+
maxSize={78}
224+
isResizing={isResizing}
225+
>
226+
<div className={styles.outputSection}>
227+
<Output
228+
designSessionId={designSessionId}
229+
schema={displayedSchema}
230+
prevSchema={prevSchema}
231+
sqlReviewComments={SQL_REVIEW_COMMENTS}
232+
versions={versions}
233+
selectedVersion={selectedVersion}
234+
onSelectedVersionChange={handleVersionChange}
235+
activeTab={activeTab}
236+
onTabChange={setActiveTab}
237+
initialIsPublic={initialIsPublic}
238+
artifact={artifact}
239+
artifactError={artifactError}
240+
/>
241+
</div>
242+
</ResizablePanel>
243+
</>
207244
)}
208-
</div>
245+
</ResizablePanelGroup>
209246
</div>
210247
)
211248
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const PANEL_LAYOUT_COOKIE_NAME = 'session-panels:layout'
2+
export const DEFAULT_PANEL_SIZES = [22, 78]

frontend/apps/app/eslint-suppressions.json

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,6 @@
5959
"count": 3
6060
}
6161
},
62-
"components/SessionDetailPage/SessionDetailPage.module.css": {
63-
"css-modules-kit/no-unused-class-names": {
64-
"count": 6
65-
}
66-
},
6762
"features/sessions/components/GitHubSessionForm/ProjectsDropdown/ProjectsDropdown.module.css": {
6863
"css-modules-kit/no-unused-class-names": {
6964
"count": 5
@@ -94,4 +89,4 @@
9489
"count": 1
9590
}
9691
}
97-
}
92+
}

0 commit comments

Comments
 (0)