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

  1. ✅ Phase 1: Implement 5 core templates (split, header/content/footer, dashboard, 2-col, 3-col)
  2. ⏳ Phase 2: Visual template selector with live previews
  3. ⏳ Phase 3: Flutter renderer (separate package)
  4. ⏳ Phase 4: Advanced custom templates (if needed)

Next Steps: Update canvas.types.ts with new schema, implement template rendering logic.