Skip to content

Commit 8d2f2a0

Browse files
authored
Merge pull request #13 from yoanbernabeu/improve-mobile
feat: enhance mobile layout responsiveness and configuration
2 parents 8ff80ab + 85a9741 commit 8d2f2a0

File tree

7 files changed

+110
-42
lines changed

7 files changed

+110
-42
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ dist-ssr
1313
*.local
1414
supabase/.temp/
1515
.supabase-config.json
16+
.temp/
1617

1718
# Editor directories and files
1819
.vscode/*

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ public
55
package-lock.json
66

77

8+

components/Builder.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
GRID_VERSION,
1919
} from '../services/storageService';
2020
import { getSocialPlatformOption, buildSocialUrl, formatFollowerCount } from '../socialPlatforms';
21+
import { getMobileLayout, MOBILE_GRID_CONFIG } from '../utils/mobileLayout';
2122
import {
2223
Download,
2324
Layout,
@@ -1671,27 +1672,26 @@ const Builder: React.FC<BuilderProps> = ({ onBack }) => {
16711672
</div>
16721673
)}
16731674
</div>
1674-
{/* Grid Section - Matches export's mobile layout: single column, stacked blocks */}
1675+
{/* Grid Section - Mobile layout: 2 columns adaptive */}
16751676
<div className="p-4 relative z-10">
16761677
<div
1677-
className="grid gap-5 pb-8"
1678+
className="grid pb-8"
16781679
style={{
1679-
gridTemplateColumns: '1fr',
1680-
gridAutoRows: '64px',
1681-
gridAutoFlow: 'dense',
1680+
gridTemplateColumns: `repeat(${MOBILE_GRID_CONFIG.columns}, 1fr)`,
1681+
gridAutoRows: `${MOBILE_GRID_CONFIG.rowHeight}px`,
1682+
gap: `${MOBILE_GRID_CONFIG.gap}px`,
16821683
}}
16831684
>
16841685
{sortedMobileBlocks.map((block) => {
1685-
// In mobile export, blocks stack vertically in a single column
1686-
// grid-column: auto, grid-row: auto (CSS resets positioning)
1687-
// Row span is preserved
1686+
// Calculate mobile layout based on desktop dimensions
1687+
const mobileLayout = getMobileLayout(block);
16881688
return (
16891689
<div
16901690
key={block.id}
16911691
className="pointer-events-none"
16921692
style={{
1693-
gridColumn: 'auto',
1694-
gridRow: 'auto',
1693+
gridColumn: `span ${mobileLayout.colSpan}`,
1694+
gridRow: `span ${mobileLayout.rowSpan}`,
16951695
}}
16961696
>
16971697
<Block

components/PreviewPage.tsx

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { AvatarStyle, SavedBento } from '../types';
33
import { getBento, getOrCreateActiveBento, setActiveBentoId } from '../services/storageService';
44
import Block from './Block';
55
import { buildSocialUrl, formatFollowerCount, getSocialPlatformOption } from '../socialPlatforms';
6+
import { getMobileLayout, MOBILE_GRID_CONFIG } from '../utils/mobileLayout';
67

78
const PreviewPage: React.FC = () => {
89
const [bento, setBento] = useState<SavedBento | null>(null);
@@ -233,33 +234,46 @@ const PreviewPage: React.FC = () => {
233234
)}
234235
</div>
235236

236-
{/* Single Column Grid */}
237+
{/* Mobile Grid - 2 columns adaptive */}
237238
<div className="p-4">
238239
<div
239-
className="grid gap-5 pb-8"
240-
style={{ gridTemplateColumns: '1fr', gridAutoRows: '64px' }}
240+
className="grid pb-8"
241+
style={{
242+
gridTemplateColumns: `repeat(${MOBILE_GRID_CONFIG.columns}, 1fr)`,
243+
gridAutoRows: `${MOBILE_GRID_CONFIG.rowHeight}px`,
244+
gap: `${MOBILE_GRID_CONFIG.gap}px`,
245+
}}
241246
>
242-
{sortedBlocks.map((block) => (
243-
<div key={block.id} style={{ gridRow: `span ${block.rowSpan}` }}>
244-
<Block
245-
block={{ ...block, gridColumn: undefined, gridRow: undefined }}
246-
isSelected={false}
247-
isDragTarget={false}
248-
isDragging={false}
249-
enableResize={false}
250-
isResizing={false}
251-
onResizeStart={undefined}
252-
onEdit={() => {}}
253-
onDelete={() => {}}
254-
onDragStart={() => {}}
255-
onDragEnter={() => {}}
256-
onDragEnd={() => {}}
257-
onDrop={() => {}}
258-
enableTiltEffect={true}
259-
previewMode={true}
260-
/>
261-
</div>
262-
))}
247+
{sortedBlocks.map((block) => {
248+
const mobileLayout = getMobileLayout(block);
249+
return (
250+
<div
251+
key={block.id}
252+
style={{
253+
gridColumn: `span ${mobileLayout.colSpan}`,
254+
gridRow: `span ${mobileLayout.rowSpan}`,
255+
}}
256+
>
257+
<Block
258+
block={{ ...block, gridColumn: undefined, gridRow: undefined }}
259+
isSelected={false}
260+
isDragTarget={false}
261+
isDragging={false}
262+
enableResize={false}
263+
isResizing={false}
264+
onResizeStart={undefined}
265+
onEdit={() => {}}
266+
onDelete={() => {}}
267+
onDragStart={() => {}}
268+
onDragEnter={() => {}}
269+
onDragEnd={() => {}}
270+
onDrop={() => {}}
271+
enableTiltEffect={true}
272+
previewMode={true}
273+
/>
274+
</div>
275+
);
276+
})}
263277
</div>
264278
</div>
265279
</div>

services/export/templates/app/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { generateBlockComponent } from './blockComponent';
1212
import {
1313
generateDesktopLayout,
1414
generateMobileLayout,
15+
generateMobileLayoutHelper,
1516
generateFooter,
1617
generateBackgroundBlur,
1718
} from './layouts';
@@ -81,7 +82,7 @@ ${generateBlockComponent()}
8182
const profile = ${profileJson}
8283
const blocks: BlockData[] = ${blocksJson}
8384
${generateAnalyticsHook(analyticsId)}
84-
85+
${generateMobileLayoutHelper()}
8586
// Sort blocks for mobile
8687
const sortedBlocks = [...blocks].sort((a, b) => {
8788
const aRow = a.gridRow ?? 999

services/export/templates/app/layouts.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,23 @@ export const generateDesktopLayout = (params: LayoutParams): string => `
5050
</div>
5151
</div>`;
5252

53+
// Mobile grid configuration constants
54+
export const MOBILE_GRID_CONFIG = {
55+
columns: 2,
56+
rowHeight: 80,
57+
gap: 12,
58+
} as const;
59+
60+
export const generateMobileLayoutHelper = (): string => `
61+
// Mobile layout helper - calculates responsive grid spans
62+
const getMobileLayout = (block: BlockData) => ({
63+
colSpan: block.colSpan >= 5 ? 2 : 1,
64+
rowSpan: block.colSpan >= 3 && block.colSpan < 5 ? Math.max(block.rowSpan, 2) : block.rowSpan
65+
})
66+
`;
67+
5368
export const generateMobileLayout = (params: LayoutParams): string => `
54-
{/* Mobile Layout */}
69+
{/* Mobile Layout - 2 columns adaptive */}
5570
<div className="lg:hidden">
5671
<div className="p-4 pt-8 flex flex-col items-center text-center">
5772
<div className="w-24 h-24 mb-4 overflow-hidden bg-gray-100" style={avatarStyle}>
@@ -80,12 +95,15 @@ export const generateMobileLayout = (params: LayoutParams): string => `
8095
}
8196
</div>
8297
<div className="p-4">
83-
<div className="grid gap-5" style={{ gridTemplateColumns: '1fr', gridAutoRows: '64px' }}>
84-
{sortedBlocks.map(block => (
85-
<div key={block.id} style={{ gridRow: \`span \${block.rowSpan}\` }}>
86-
<Block block={{ ...block, gridColumn: undefined, gridRow: undefined }} />
87-
</div>
88-
))}
98+
<div className="grid" style={{ gridTemplateColumns: 'repeat(${MOBILE_GRID_CONFIG.columns}, 1fr)', gridAutoRows: '${MOBILE_GRID_CONFIG.rowHeight}px', gap: '${MOBILE_GRID_CONFIG.gap}px' }}>
99+
{sortedBlocks.map(block => {
100+
const mobile = getMobileLayout(block)
101+
return (
102+
<div key={block.id} style={{ gridColumn: \`span \${mobile.colSpan}\`, gridRow: \`span \${mobile.rowSpan}\` }}>
103+
<Block block={{ ...block, gridColumn: undefined, gridRow: undefined }} />
104+
</div>
105+
)
106+
})}
89107
</div>
90108
</div>
91109
</div>`;

utils/mobileLayout.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Mobile layout utilities for responsive grid conversion
2+
import { BlockData } from '../types';
3+
4+
/**
5+
* Calculates the mobile grid layout for a block based on its desktop dimensions.
6+
*
7+
* Rules:
8+
* - Desktop colSpan 1-4 → Mobile 1 column (50% width)
9+
* - Desktop colSpan 5-9 → Mobile 2 columns (100% width)
10+
* - Medium blocks (colSpan 3-4) get minimum 2 rowSpan for better proportions
11+
*/
12+
export const getMobileLayout = (block: BlockData): { colSpan: number; rowSpan: number } => {
13+
// Large blocks (more than half of 9-col grid) → full width
14+
const mobileColSpan = block.colSpan >= 5 ? 2 : 1;
15+
16+
// Medium blocks that become narrow need more height
17+
const mobileRowSpan =
18+
block.colSpan >= 3 && block.colSpan < 5 ? Math.max(block.rowSpan, 2) : block.rowSpan;
19+
20+
return {
21+
colSpan: mobileColSpan,
22+
rowSpan: mobileRowSpan,
23+
};
24+
};
25+
26+
/**
27+
* Mobile grid configuration constants
28+
*/
29+
export const MOBILE_GRID_CONFIG = {
30+
columns: 2,
31+
rowHeight: 80, // px per row
32+
gap: 12, // px between items
33+
} as const;

0 commit comments

Comments
 (0)