PLATFORM AGNOSTIC LAYOUTS
Ecosistema completo para organización y gestión de contenido con interfaces espaciales
*# Platform-Agnostic Layout System
Goal: Create a layout system that works identically on Web (CSS Grid) and Flutter (native widgets)
Core Principle: Template-Based Layouts
Strategy: Define layouts as templates with named regions, not raw CSS/Flutter code.
Layout Templates (Root-Level Only)
1. Split View (Sidebar + Main)
Use Case: Dashboard, admin panels, documentation sites
Web (CSS Grid):
display: grid;
grid-template-columns: 300px 1fr;
grid-template-rows: 1fr;
grid-template-areas: "sidebar main";
Flutter Equivalent:
Row(
children: [
Container(
width: 300, // Fixed sidebar
child: sidebarWidget,
),
Expanded(
child: mainWidget, // Flexible main area
),
],
)
JSON Schema:
{
"layout": "template",
"template": "split-sidebar",
"config": {
"sidebarWidth": "300px",
"gap": "0px"
},
"regions": [
{
"name": "sidebar",
"type": "container",
"children": []
},
{
"name": "main",
"type": "container",
"children": []
}
]
}
2. Header/Content/Footer
Use Case: Traditional page layout
Web (CSS Grid):
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header"
"content"
"footer";
Flutter Equivalent:
Column(
children: [
headerWidget, // auto height
Expanded(
child: contentWidget, // fills remaining space
),
footerWidget, // auto height
],
)
JSON Schema:
{
"layout": "template",
"template": "header-content-footer",
"config": {
"gap": "0px"
},
"regions": [
{
"name": "header",
"type": "container",
"flex": false,
"children": []
},
{
"name": "content",
"type": "container",
"flex": true,
"children": []
},
{
"name": "footer",
"type": "container",
"flex": false,
"children": []
}
]
}
3. Dashboard (Sidebar + Header + Main + Aside)
Use Case: Complex admin dashboards
Web (CSS Grid):
display: grid;
grid-template-columns: 250px 1fr 300px;
grid-template-rows: 60px 1fr;
grid-template-areas:
"header header header"
"sidebar main aside";
Flutter Equivalent:
Column(
children: [
Container(
height: 60,
child: headerWidget, // Spans full width
),
Expanded(
child: Row(
children: [
Container(
width: 250,
child: sidebarWidget,
),
Expanded(
child: mainWidget,
),
Container(
width: 300,
child: asideWidget,
),
],
),
),
],
)
JSON Schema:
{
"layout": "template",
"template": "dashboard",
"config": {
"headerHeight": "60px",
"sidebarWidth": "250px",
"asideWidth": "300px",
"gap": "0px"
},
"regions": [
{
"name": "header",
"type": "container",
"span": "full",
"children": []
},
{
"name": "sidebar",
"type": "container",
"children": []
},
{
"name": "main",
"type": "container",
"flex": true,
"children": []
},
{
"name": "aside",
"type": "container",
"children": []
}
]
}
4. Two-Column Equal Split
Use Case: Compare views, split editing
Web (CSS Grid):
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr;
grid-template-areas: "left right";
gap: 16px;
Flutter Equivalent:
Row(
children: [
Expanded(
flex: 1,
child: leftWidget,
),
SizedBox(width: 16), // gap
Expanded(
flex: 1,
child: rightWidget,
),
],
)
JSON Schema:
{
"layout": "template",
"template": "two-column-equal",
"config": {
"gap": "16px"
},
"regions": [
{
"name": "left",
"type": "container",
"flex": 1,
"children": []
},
{
"name": "right",
"type": "container",
"flex": 1,
"children": []
}
]
}
5. Three-Column Equal Split
Use Case: Multi-panel views
Web (CSS Grid):
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr;
gap: 16px;
Flutter Equivalent:
Row(
children: [
Expanded(flex: 1, child: column1Widget),
SizedBox(width: 16),
Expanded(flex: 1, child: column2Widget),
SizedBox(width: 16),
Expanded(flex: 1, child: column3Widget),
],
)
JSON Schema:
{
"layout": "template",
"template": "three-column-equal",
"config": {
"gap": "16px"
},
"regions": [
{
"name": "column1",
"type": "container",
"flex": 1,
"children": []
},
{
"name": "column2",
"type": "container",
"flex": 1,
"children": []
},
{
"name": "column3",
"type": "container",
"flex": 1,
"children": []
}
]
}
Nested Content Layouts (Inside Regions)
For content INSIDE template regions, use simple Flexbox:
Vertical Stack
Web: flex-direction: column
Flutter: Column(children: [...])
Horizontal Row
Web: flex-direction: row
Flutter: Row(children: [...])
Wrapped Cards
Web: flex-direction: row; flex-wrap: wrap
Flutter: Wrap(children: [...])
Centered Content
Web: justify-content: center; align-items: center
Flutter: Center(child: ...)
Updated Type Definitions
export type LayoutTemplate =
| 'split-sidebar' // Sidebar (fixed) + Main (flex)
| 'header-content-footer' // Header (auto) + Content (flex) + Footer (auto)
| 'dashboard' // Header + Sidebar + Main + Aside
| 'two-column-equal' // 1fr 1fr
| 'three-column-equal' // 1fr 1fr 1fr
| 'custom'; // Advanced: manual grid definition
export interface CanvasSection {
id: string;
label: string;
type: 'region' | 'container';
// Root-level: Template-based
layout?: 'template' | 'flexbox';
template?: LayoutTemplate;
// Template regions
regions?: TemplateRegion[];
// Nested content: Simple flexbox
flex?: FlexConfig;
// Content & children
content?: ContentConfig;
children: CanvasSection[];
styles?: SectionStyles;
}
export interface TemplateRegion {
name: string; // 'sidebar', 'main', 'header', etc.
type: 'container';
flex?: boolean | number; // true = Expanded, number = flex value
width?: string; // Fixed width (e.g., '300px')
height?: string; // Fixed height (e.g., '60px')
span?: 'full'; // Span full width
children: CanvasSection[];
}
export interface TemplateConfig {
// Split Sidebar
sidebarWidth?: string;
// Dashboard
headerHeight?: string;
asideWidth?: string;
// All templates
gap?: string;
}
Platform Rendering Logic
Web (CSS Grid)
function renderTemplateWeb(section: CanvasSection): CSSProperties {
const template = TEMPLATE_DEFINITIONS[section.template!];
return {
display: 'grid',
gridTemplateColumns: template.columns,
gridTemplateRows: template.rows,
gridTemplateAreas: template.areas,
gap: section.config?.gap || '0px'
};
}
Flutter (Widget Tree)
Widget buildTemplate(CanvasSection section) {
switch (section.template) {
case 'split-sidebar':
return Row(
children: [
Container(
width: parseWidth(section.config.sidebarWidth),
child: buildRegion(section.regions[0]),
),
Expanded(
child: buildRegion(section.regions[1]),
),
],
);
// ... other templates
}
}
Benefits of This Approach
✅ Platform Agnostic: Same JSON works on Web, Flutter, React Native
✅ Predictable: Fixed templates = predictable behavior
✅ Simple for Users: Visual template picker, not CSS/Flutter code
✅ Type-Safe: Strong TypeScript types, validated schemas
✅ AI-Trainable: Templates are learnable patterns
✅ Maintainable: One source of truth for all platforms
Implementation Priority
- ✅ Phase 1: Implement 5 core templates (split, header/content/footer, dashboard, 2-col, 3-col)
- ⏳ Phase 2: Visual template selector with live previews
- ⏳ Phase 3: Flutter renderer (separate package)
- ⏳ Phase 4: Advanced custom templates (if needed)
Next Steps: Update canvas.types.ts with new schema, implement template rendering logic.