Skip to content

Commit f019fcc

Browse files
authored
fix(ui): keep home actions visible on short viewports (#452)
## Summary - Make the folder selection home screen scroll vertically when short viewports cannot fit the primary action column. - Cap the recent folders/server list to the measured action column height on desktop so it scrolls internally instead of stretching the layout. - Use a focused home layout stylesheet with equal-width desktop columns. ## Validation - npm run typecheck --workspace @codenomad/ui - npm run build --workspace @codenomad/ui ## Notes - Build still emits existing warnings about virtua JSX import source and large chunks; unrelated to this change.
1 parent 9a6450c commit f019fcc

5 files changed

Lines changed: 113 additions & 12 deletions

File tree

packages/ui/src/components/folder-selection-view.tsx

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ const FolderSelectionView: Component<FolderSelectionViewProps> = (props) => {
6666
const [serverDialogError, setServerDialogError] = createSignal<string | null>(null)
6767
const [isSavingServer, setIsSavingServer] = createSignal(false)
6868
const [connectingServerId, setConnectingServerId] = createSignal<string | null>(null)
69+
let homeRootRef: HTMLDivElement | undefined
70+
let actionsColumnRef: HTMLDivElement | undefined
6971
let recentListRef: HTMLDivElement | undefined
7072

7173
type LanguageOption = { value: Locale; label: string }
@@ -242,6 +244,28 @@ const FolderSelectionView: Component<FolderSelectionViewProps> = (props) => {
242244
})
243245
})
244246

247+
onMount(() => {
248+
const syncActionsHeight = () => {
249+
if (!homeRootRef || !actionsColumnRef) return
250+
const height = actionsColumnRef.getBoundingClientRect().height
251+
homeRootRef.style.setProperty("--folder-home-actions-height", `${Math.ceil(height)}px`)
252+
}
253+
254+
syncActionsHeight()
255+
window.addEventListener("resize", syncActionsHeight)
256+
257+
let observer: ResizeObserver | undefined
258+
if (typeof ResizeObserver !== "undefined" && actionsColumnRef) {
259+
observer = new ResizeObserver(syncActionsHeight)
260+
observer.observe(actionsColumnRef)
261+
}
262+
263+
onCleanup(() => {
264+
window.removeEventListener("resize", syncActionsHeight)
265+
observer?.disconnect()
266+
})
267+
})
268+
245269
function dropTargetBlocked() {
246270
return isLoading() || isFolderBrowserOpen() || settingsOpen()
247271
}
@@ -552,15 +576,15 @@ const FolderSelectionView: Component<FolderSelectionViewProps> = (props) => {
552576
return (
553577
<>
554578
<div
555-
class="flex h-screen w-full items-start justify-center overflow-hidden py-6 px-4 sm:px-6 relative"
556-
style="background-color: var(--surface-secondary)"
579+
class="folder-home-root flex w-full items-start justify-center py-6 px-4 sm:px-6 relative"
580+
ref={(el) => (homeRootRef = el)}
557581
onDragEnter={folderDrop.bind.onDragEnter}
558582
onDragOver={folderDrop.bind.onDragOver}
559583
onDragLeave={folderDrop.bind.onDragLeave}
560584
onDrop={folderDrop.bind.onDrop}
561585
>
562586
<div
563-
class="w-full max-w-5xl h-full px-4 sm:px-8 pb-2 flex flex-col overflow-hidden"
587+
class="folder-home-shell w-full max-w-5xl px-4 sm:px-8 pb-2 flex flex-col"
564588
aria-busy={isLoading() ? "true" : "false"}
565589
>
566590
<div class="absolute top-4" style="inset-inline-start: 1.5rem;">
@@ -640,9 +664,9 @@ const FolderSelectionView: Component<FolderSelectionViewProps> = (props) => {
640664
</button>
641665
</Show>
642666
</div>
643-
<div class="mb-6 text-center shrink-0">
667+
<div class="folder-home-hero text-center shrink-0">
644668
<div class="mb-3 flex justify-center">
645-
<img src={codeNomadLogo} alt={t("folderSelection.logoAlt")} class="h-32 w-auto sm:h-48" loading="lazy" />
669+
<img src={codeNomadLogo} alt={t("folderSelection.logoAlt")} class="folder-home-logo w-auto" loading="lazy" />
646670
</div>
647671
<h1 class="mb-2 text-3xl font-semibold text-primary">CodeNomad</h1>
648672
<div class="mt-3 flex justify-center gap-2">
@@ -694,11 +718,11 @@ const FolderSelectionView: Component<FolderSelectionViewProps> = (props) => {
694718
</div>
695719
</div>
696720

697-
<div class="flex-1 min-h-0 overflow-hidden flex flex-col gap-4">
698-
<div class="flex-1 min-h-0 overflow-hidden flex flex-col lg:flex-row gap-4">
721+
<div class="folder-home-content flex-1 min-h-0 flex flex-col gap-4">
722+
<div class="folder-home-main flex-1 gap-4">
699723
{/* Right column: recent folders */}
700-
<div class="order-1 lg:order-2 flex flex-col gap-4 flex-1 min-h-0 overflow-hidden">
701-
<div class="panel flex flex-col flex-1 min-h-0">
724+
<div class="folder-home-list-column order-1 lg:order-2 flex flex-col gap-4 flex-1 min-h-0">
725+
<div class="folder-home-list-panel panel flex flex-col flex-1">
702726
<div class="panel-header !gap-0 !p-0">
703727
<div class={`grid ${canUseRemoteServerWindows() ? "grid-cols-2" : "grid-cols-1"} gap-0 overflow-hidden border border-base rounded-t-lg rounded-b-none`}>
704728
<button
@@ -930,7 +954,10 @@ const FolderSelectionView: Component<FolderSelectionViewProps> = (props) => {
930954
</div>
931955

932956
{/* Left column: version + browse + advanced settings */}
933-
<div class="order-2 lg:order-1 flex flex-col gap-4 flex-1 min-h-0">
957+
<div
958+
class="folder-home-actions-column order-2 lg:order-1 flex flex-col gap-4 flex-1"
959+
ref={(el) => (actionsColumnRef = el)}
960+
>
934961
<div class="panel shrink-0">
935962
<div class="panel-header hidden sm:block">
936963
<h2 class="panel-title">{t("folderSelection.actions.title")}</h2>

packages/ui/src/styles/components/folder-drop.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.folder-drop-overlay {
2-
position: absolute;
2+
position: fixed;
33
inset: 0;
44
z-index: 40;
55
display: flex;
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
.folder-home-root {
2+
height: 100dvh;
3+
overflow-x: hidden;
4+
overflow-y: auto;
5+
background-color: var(--surface-secondary);
6+
}
7+
8+
.folder-home-shell {
9+
min-height: 100%;
10+
}
11+
12+
.folder-home-hero {
13+
margin-bottom: 1.5rem;
14+
}
15+
16+
.folder-home-logo {
17+
height: 8rem;
18+
}
19+
20+
.folder-home-content,
21+
.folder-home-main,
22+
.folder-home-list-column,
23+
.folder-home-actions-column {
24+
overflow: visible;
25+
}
26+
27+
.folder-home-main {
28+
display: flex;
29+
flex-direction: column;
30+
min-height: max-content;
31+
}
32+
33+
.folder-home-actions-column {
34+
min-height: max-content;
35+
}
36+
37+
.folder-home-list-panel {
38+
min-height: 16rem;
39+
}
40+
41+
@media (min-width: 1024px) {
42+
.folder-home-main {
43+
display: grid;
44+
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
45+
align-items: start;
46+
}
47+
48+
.folder-home-list-column,
49+
.folder-home-actions-column {
50+
min-width: 0;
51+
}
52+
53+
.folder-home-list-panel {
54+
height: var(--folder-home-actions-height, auto);
55+
max-height: var(--folder-home-actions-height, none);
56+
}
57+
}
58+
59+
@media (min-width: 640px) and (min-height: 721px) {
60+
.folder-home-logo {
61+
height: 12rem;
62+
}
63+
}
64+
65+
@media (max-height: 720px) and (min-width: 1024px) {
66+
.folder-home-hero {
67+
margin-bottom: var(--space-md);
68+
}
69+
70+
.folder-home-logo {
71+
height: 8rem;
72+
}
73+
}

packages/ui/src/styles/components/folder-loading.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* Folder loading overlay */
22
.folder-loading-overlay {
3-
position: absolute;
3+
position: fixed;
44
inset: 0;
55
background-color: var(--folder-overlay-bg);
66
display: flex;

packages/ui/src/styles/controls.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
@import "./components/buttons.css";
22
@import "./components/badges.css";
3+
@import "./components/folder-home.css";
34
@import "./components/folder-drop.css";
45
@import "./components/folder-loading.css";
56
@import "./components/dropdown.css";

0 commit comments

Comments
 (0)