Complex Workflows
This guide demonstrates advanced patterns and real-world examples of complex dynamic design workflows in Canvelete (opens in a new tab). Learn how to combine multiple dynamic elements, data sources, and conditional logic to create sophisticated, data-driven designs.
Multi-Source Dashboard Workflow
Scenario: Executive Dashboard
Create a comprehensive dashboard that pulls data from multiple APIs and displays different visualizations based on user role and permissions.
Data Sources Configuration
{
"dataSources": {
"salesData": {
"type": "api",
"url": "https://api.company.com/sales/summary",
"refreshInterval": 300000,
"headers": {"Authorization": "Bearer {{userToken}}"}
},
"userMetrics": {
"type": "api",
"url": "https://api.company.com/users/metrics",
"refreshInterval": 600000
},
"realTimeEvents": {
"type": "websocket",
"url": "wss://api.company.com/events",
"events": ["sale", "signup", "error"]
}
},
"computed": {
"totalRevenue": "{{salesData.monthly.reduce((sum, month) => sum + month.revenue, 0)}}",
"growthRate": "{{((salesData.currentMonth.revenue - salesData.previousMonth.revenue) / salesData.previousMonth.revenue * 100).toFixed(1)}}",
"conversionRate": "{{(salesData.conversions / userMetrics.visitors * 100).toFixed(2)}}",
"isPerformingWell": "{{growthRate > 5 && conversionRate > 2.5}}"
}
}Dynamic Dashboard Template
"<div class='dashboard {{user.role}} {{isPerformingWell ? 'positive' : 'needs-attention'}}'>
<!-- Header with role-based content -->
<header class='dashboard-header'>
<h1>{{user.role === 'executive' ? 'Executive' : 'Sales'}} Dashboard</h1>
<div class='last-updated'>
Last updated: {{salesData.lastUpdated | fromNow}}
</div>
</header>
<!-- KPI Cards with conditional styling -->
<div class='kpi-grid'>
{{#each kpiCards}}
<div class='kpi-card {{this.trend}}' style='--accent-color: {{this.color}}'>
<div class='kpi-header'>
<h3>{{this.title}}</h3>
{{#if (hasPermission user.permissions this.requiredPermission)}}
<button class='drill-down' data-metric='{{this.id}}'>Details</button>
{{/if}}
</div>
<div class='kpi-value'>
{{#if this.type === 'currency'}}
{{this.value | currency}}
{{else if this.type === 'percentage'}}
{{this.value}}%
{{else}}
{{this.value | number}}
{{/if}}
</div>
<div class='kpi-change {{this.change >= 0 ? 'positive' : 'negative'}}'>
{{this.change >= 0 ? 'â' : 'â'}} {{Math.abs(this.change)}}%
</div>
</div>
{{/each}}
</div>
<!-- Conditional chart sections based on role -->
{{#if (includes ['executive', 'manager'] user.role)}}
<div class='charts-section'>
<div class='chart-container'>
<h2>Revenue Trend</h2>
{{#if salesData.monthly.length > 0}}
<canvas id='revenue-chart' data-values='{{JSON.stringify(salesData.monthly)}}'></canvas>
{{else}}
<div class='no-data'>No revenue data available</div>
{{/if}}
</div>
{{#if user.role === 'executive'}}
<div class='chart-container'>
<h2>Department Performance</h2>
<div class='department-grid'>
{{#each salesData.departments}}
<div class='department-card {{this.performance}}'>
<h4>{{this.name}}</h4>
<div class='performance-indicator' style='width: {{this.score}}%'></div>
<span>{{this.score}}% of target</span>
</div>
{{/each}}
</div>
</div>
{{/if}}
</div>
{{/if}}
<!-- Real-time events feed -->
{{#if realTimeEvents.length > 0}}
<div class='events-feed'>
<h2>Live Activity</h2>
<div class='events-list'>
{{#each (slice realTimeEvents 0 10)}}
<div class='event-item {{this.type}}'>
<span class='event-time'>{{this.timestamp | time}}</span>
<span class='event-description'>
{{#if this.type === 'sale'}}
đ° Sale: {{this.amount | currency}} - {{this.product}}
{{else if this.type === 'signup'}}
đ¤ New user: {{this.userEmail}}
{{else if this.type === 'error'}}
â ī¸ Error: {{this.message}}
{{/if}}
</span>
</div>
{{/each}}
</div>
</div>
{{/if}}
</div>"E-commerce Product Catalog Workflow
Scenario: Dynamic Product Showcase
Create a product catalog that adapts to user preferences, inventory levels, and promotional campaigns.
Complex Data Structure
{
"products": [
{
"id": "prod-001",
"name": "Wireless Headphones Pro",
"category": "electronics",
"price": 299.99,
"salePrice": 249.99,
"inventory": 15,
"rating": 4.7,
"reviews": 1247,
"images": [
"https://example.com/headphones-1.jpg",
"https://example.com/headphones-2.jpg"
],
"features": ["noise-cancelling", "wireless", "long-battery"],
"variants": [
{"color": "black", "stock": 8},
{"color": "white", "stock": 7}
],
"promotion": {
"type": "flash-sale",
"endTime": "2024-01-20T23:59:59Z",
"discount": 17
}
}
],
"user": {
"preferences": {
"categories": ["electronics", "books"],
"priceRange": {"min": 0, "max": 500},
"brands": ["sony", "apple", "samsung"]
},
"browsingHistory": ["prod-001", "prod-045"],
"cart": {"items": [], "total": 0},
"wishlist": ["prod-001"]
},
"computed": {
"filteredProducts": "{{products.filter(p => user.preferences.categories.includes(p.category) && p.price <= user.preferences.priceRange.max)}}",
"recommendedProducts": "{{products.filter(p => user.browsingHistory.includes(p.id) || user.preferences.brands.includes(p.brand))}}",
"flashSaleProducts": "{{products.filter(p => p.promotion && p.promotion.type === 'flash-sale' && new Date(p.promotion.endTime) > new Date())}}",
"lowStockProducts": "{{products.filter(p => p.inventory > 0 && p.inventory <= 5)}}"
}
}Dynamic Product Grid Template
"<div class='product-catalog'>
<!-- Flash sale banner -->
{{#if flashSaleProducts.length > 0}}
<div class='flash-sale-banner'>
<h2>⥠Flash Sale - Limited Time!</h2>
<div class='countdown' data-end='{{flashSaleProducts[0].promotion.endTime}}'>
Ends in: <span class='time-remaining'></span>
</div>
</div>
{{/if}}
<!-- Personalized recommendations -->
{{#if recommendedProducts.length > 0}}
<section class='recommendations'>
<h2>Recommended for You</h2>
<div class='product-grid recommended'>
{{#each (slice recommendedProducts 0 4)}}
{{> productCard this context='recommendation'}}
{{/each}}
</div>
</section>
{{/if}}
<!-- Main product grid with filters -->
<section class='main-catalog'>
<div class='catalog-header'>
<h2>All Products ({{filteredProducts.length}})</h2>
<div class='filters'>
<!-- Dynamic filter controls -->
</div>
</div>
<div class='product-grid main'>
{{#each filteredProducts}}
{{> productCard this context='catalog'}}
{{/each}}
</div>
</section>
</div>
<!-- Product Card Partial Template -->
{{#*inline 'productCard'}}
<div class='product-card {{context}} {{#if this.promotion}}on-sale{{/if}} {{#if (lte this.inventory 5)}}low-stock{{/if}}'>
<!-- Product image with conditional badges -->
<div class='product-image'>
<img src='{{this.images[0]}}' alt='{{this.name}}' loading='lazy'>
<!-- Conditional badges -->
{{#if this.promotion}}
<div class='sale-badge'>
{{this.promotion.discount}}% OFF
</div>
{{/if}}
{{#if (includes user.wishlist this.id)}}
<div class='wishlist-badge'>â¤ī¸</div>
{{/if}}
{{#if (lte this.inventory 5)}}
<div class='stock-badge'>Only {{this.inventory}} left!</div>
{{/if}}
</div>
<!-- Product info -->
<div class='product-info'>
<h3 class='product-name'>{{this.name}}</h3>
<!-- Dynamic pricing -->
<div class='pricing'>
{{#if this.salePrice}}
<span class='sale-price'>{{this.salePrice | currency}}</span>
<span class='original-price'>{{this.price | currency}}</span>
<span class='savings'>Save {{((this.price - this.salePrice) / this.price * 100).toFixed(0)}}%</span>
{{else}}
<span class='price'>{{this.price | currency}}</span>
{{/if}}
</div>
<!-- Rating and reviews -->
{{#if this.rating}}
<div class='rating'>
<div class='stars' style='--rating: {{this.rating}}'>â
â
â
â
â
</div>
<span class='review-count'>({{this.reviews}} reviews)</span>
</div>
{{/if}}
<!-- Variant selection -->
{{#if this.variants.length > 1}}
<div class='variants'>
{{#each this.variants}}
<button class='variant-option {{#unless this.stock}}out-of-stock{{/unless}}'
data-variant='{{this.color}}'
{{#unless this.stock}}disabled{{/unless}}>
{{this.color | titlecase}}
{{#unless this.stock}}(Out of Stock){{/unless}}
</button>
{{/each}}
</div>
{{/if}}
<!-- Action buttons -->
<div class='product-actions'>
{{#if (gt this.inventory 0)}}
<button class='add-to-cart' data-product='{{this.id}}'>
Add to Cart
</button>
{{else}}
<button class='notify-restock' data-product='{{this.id}}'>
Notify When Available
</button>
{{/if}}
<button class='wishlist-toggle {{#if (includes user.wishlist this.id)}}active{{/if}}'
data-product='{{this.id}}'>
{{#if (includes user.wishlist this.id)}}â¤ī¸{{else}}đ¤{{/if}}
</button>
</div>
</div>
</div>
{{/inline}}"Social Media Content Generator Workflow
Scenario: Multi-Platform Post Creation
Generate social media posts optimized for different platforms with dynamic content adaptation.
Platform-Specific Configuration
{
"platforms": {
"twitter": {
"maxLength": 280,
"supportsImages": true,
"supportsVideo": true,
"hashtagLimit": 2,
"mentionLimit": 10
},
"instagram": {
"maxLength": 2200,
"supportsImages": true,
"supportsVideo": true,
"hashtagLimit": 30,
"aspectRatios": ["1:1", "4:5", "16:9"]
},
"linkedin": {
"maxLength": 3000,
"supportsImages": true,
"supportsVideo": true,
"professionalTone": true
}
},
"content": {
"type": "product-launch",
"product": {
"name": "EcoSmart Water Bottle",
"features": ["BPA-free", "Temperature control", "Smart tracking"],
"price": 49.99,
"launchDate": "2024-02-01"
},
"campaign": {
"hashtags": ["#EcoSmart", "#SustainableLiving", "#Innovation", "#WaterBottle", "#EcoFriendly"],
"mentions": ["@EcoSmartTech", "@SustainabilityNow"],
"callToAction": "Order now and get 20% off!"
}
},
"computed": {
"shortDescription": "{{content.product.name}} - {{content.product.features.slice(0, 2).join(' & ')}}",
"platformHashtags": "{{platform => content.campaign.hashtags.slice(0, platforms[platform].hashtagLimit || content.campaign.hashtags.length)}}",
"adaptedContent": "{{platform => adaptContentForPlatform(content, platforms[platform])}}"
}
}Multi-Platform Template Generator
"{{#each platforms as |config platform|}}
<div class='platform-post {{platform}}'>
<div class='platform-header'>
<h3>{{platform | titlecase}} Post</h3>
<div class='character-count'>
<span class='current'>{{(adaptedContent platform).length}}</span>
<span class='max'>/{{config.maxLength}}</span>
</div>
</div>
<div class='post-content'>
<!-- Platform-specific content adaptation -->
{{#if platform === 'twitter'}}
{{> twitterPost config}}
{{else if platform === 'instagram'}}
{{> instagramPost config}}
{{else if platform === 'linkedin'}}
{{> linkedinPost config}}
{{/if}}
</div>
<!-- Media preview -->
{{#if config.supportsImages}}
<div class='media-preview'>
<img src='{{content.product.image}}' alt='{{content.product.name}}'>
{{#if platform === 'instagram'}}
<div class='aspect-ratio-options'>
{{#each config.aspectRatios}}
<button class='aspect-option' data-ratio='{{this}}'>{{this}}</button>
{{/each}}
</div>
{{/if}}
</div>
{{/if}}
<!-- Engagement predictions -->
<div class='engagement-prediction'>
<div class='metric'>
<span class='label'>Predicted Reach:</span>
<span class='value'>{{predictEngagement platform 'reach'}}</span>
</div>
<div class='metric'>
<span class='label'>Engagement Rate:</span>
<span class='value'>{{predictEngagement platform 'engagement'}}%</span>
</div>
</div>
</div>
{{/each}}
<!-- Platform-specific templates -->
{{#*inline 'twitterPost'}}
<div class='twitter-content'>
đ Introducing {{content.product.name}}!
{{#each (slice content.product.features 0 2)}}
â
{{this}}
{{/each}}
{{#if (lt (calculateLength twitterContent) 200)}}
Starting at ${{content.product.price}}
{{/if}}
{{content.campaign.callToAction}}
{{#each (platformHashtags 'twitter')}}{{this}} {{/each}}
{{#each (slice content.campaign.mentions 0 2)}}{{this}} {{/each}}
</div>
{{/inline}}
{{#*inline 'instagramPost'}}
<div class='instagram-content'>
⨠Meet the {{content.product.name}} â¨
The future of hydration is here! Our latest innovation combines:
{{#each content.product.features}}
đ {{this}}
{{/each}}
Perfect for the eco-conscious lifestyle you've been building. đ
{{content.campaign.callToAction}}
Link in bio! đ
---
{{#each (platformHashtags 'instagram')}}{{this}} {{/each}}
{{#each content.campaign.mentions}}{{this}} {{/each}}
</div>
{{/inline}}
{{#*inline 'linkedinPost'}}
<div class='linkedin-content'>
We're excited to announce the launch of {{content.product.name}}, a breakthrough in sustainable hydration technology.
In today's environmentally conscious market, consumers are seeking products that align with their values. Our new {{content.product.name}} addresses this need by offering:
{{#each content.product.features}}
âĸ {{this}}
{{/each}}
This launch represents our continued commitment to innovation and sustainability in the consumer goods sector.
{{content.campaign.callToAction}}
What are your thoughts on sustainable product innovation? Share your perspective in the comments.
{{#each (slice (platformHashtags 'linkedin') 0 5)}}{{this}} {{/each}}
</div>
{{/inline}}"Event-Driven Dynamic Layouts
Scenario: Real-Time Conference Dashboard
Create a conference dashboard that updates in real-time based on event data, attendee interactions, and schedule changes.
Event Data Structure
{
"conference": {
"name": "TechConf 2024",
"startDate": "2024-03-15T09:00:00Z",
"endDate": "2024-03-17T18:00:00Z",
"timezone": "America/New_York"
},
"sessions": [
{
"id": "session-001",
"title": "The Future of AI",
"speaker": "Dr. Jane Smith",
"startTime": "2024-03-15T10:00:00Z",
"endTime": "2024-03-15T11:00:00Z",
"room": "Main Hall",
"capacity": 500,
"registered": 487,
"status": "live",
"tags": ["AI", "Machine Learning", "Future Tech"]
}
],
"attendee": {
"id": "att-123",
"name": "John Doe",
"registeredSessions": ["session-001", "session-003"],
"preferences": ["AI", "Web Development"],
"currentLocation": "Main Hall"
},
"realTimeData": {
"currentAttendance": 450,
"networkingMatches": 12,
"livePolls": [
{
"sessionId": "session-001",
"question": "What's the most exciting AI development?",
"responses": {"GPT": 45, "Computer Vision": 32, "Robotics": 23}
}
]
},
"computed": {
"currentSession": "{{sessions.find(s => new Date(s.startTime) <= new Date() && new Date(s.endTime) > new Date())}}",
"upcomingSession": "{{sessions.find(s => new Date(s.startTime) > new Date()).sort((a,b) => new Date(a.startTime) - new Date(b.startTime))[0]}}",
"personalizedRecommendations": "{{sessions.filter(s => s.tags.some(tag => attendee.preferences.includes(tag)) && !attendee.registeredSessions.includes(s.id))}}",
"isSessionFull": "{{session => session.registered >= session.capacity * 0.95}}"
}
}Dynamic Conference Dashboard
"<div class='conference-dashboard' data-attendee='{{attendee.id}}'>
<!-- Real-time status header -->
<header class='dashboard-header'>
<div class='conference-info'>
<h1>{{conference.name}}</h1>
<div class='live-status'>
{{#if currentSession}}
<span class='live-indicator'>đ´ LIVE</span>
<span class='current-session'>{{currentSession.title}}</span>
{{else}}
<span class='between-sessions'>Between Sessions</span>
{{/if}}
</div>
</div>
<div class='attendee-info'>
<span class='welcome'>Welcome, {{attendee.name}}</span>
<div class='quick-stats'>
<span class='stat'>
<span class='label'>Registered:</span>
<span class='value'>{{attendee.registeredSessions.length}}</span>
</span>
<span class='stat'>
<span class='label'>Networking:</span>
<span class='value'>{{realTimeData.networkingMatches}}</span>
</span>
</div>
</div>
</header>
<!-- Current session focus -->
{{#if currentSession}}
<section class='current-session-focus'>
<div class='session-header'>
<h2>{{currentSession.title}}</h2>
<div class='session-meta'>
<span class='speaker'>{{currentSession.speaker}}</span>
<span class='room'>{{currentSession.room}}</span>
<span class='time'>
{{currentSession.startTime | time}} - {{currentSession.endTime | time}}
</span>
</div>
</div>
<!-- Live attendance and capacity -->
<div class='attendance-info'>
<div class='attendance-bar'>
<div class='fill' style='width: {{(realTimeData.currentAttendance / currentSession.capacity * 100)}}%'></div>
</div>
<span class='attendance-text'>
{{realTimeData.currentAttendance}} / {{currentSession.capacity}} attendees
{{#if (isSessionFull currentSession)}}
<span class='full-indicator'>Nearly Full!</span>
{{/if}}
</span>
</div>
<!-- Live polls if available -->
{{#each realTimeData.livePolls}}
{{#if (eq this.sessionId ../currentSession.id)}}
<div class='live-poll'>
<h3>Live Poll: {{this.question}}</h3>
<div class='poll-results'>
{{#each this.responses}}
<div class='poll-option'>
<span class='option-name'>{{@key}}</span>
<div class='option-bar'>
<div class='fill' style='width: {{(this / (sum ../this.responses) * 100)}}%'></div>
</div>
<span class='option-count'>{{this}}</span>
</div>
{{/each}}
</div>
</div>
{{/if}}
{{/each}}
<!-- Session actions -->
<div class='session-actions'>
{{#if (includes attendee.registeredSessions currentSession.id)}}
{{#if (eq attendee.currentLocation currentSession.room)}}
<button class='action-btn checked-in'>â Checked In</button>
{{else}}
<button class='action-btn check-in' data-session='{{currentSession.id}}'>
Check In to {{currentSession.room}}
</button>
{{/if}}
{{else}}
{{#if (isSessionFull currentSession)}}
<button class='action-btn full' disabled>Session Full</button>
{{else}}
<button class='action-btn register' data-session='{{currentSession.id}}'>
Join Session
</button>
{{/if}}
{{/if}}
<button class='action-btn networking' data-session='{{currentSession.id}}'>
Find Networking Opportunities
</button>
</div>
</section>
{{/if}}
<!-- Upcoming sessions -->
<section class='upcoming-sessions'>
<h2>Your Schedule</h2>
<div class='session-timeline'>
{{#each (filter sessions s => includes attendee.registeredSessions s.id)}}
<div class='timeline-item {{#if (eq this.id currentSession.id)}}current{{/if}}'>
<div class='time-marker'>
{{this.startTime | time}}
</div>
<div class='session-card'>
<h3>{{this.title}}</h3>
<p class='speaker'>{{this.speaker}}</p>
<p class='room'>{{this.room}}</p>
{{#if (eq this.status 'cancelled')}}
<div class='status-badge cancelled'>Cancelled</div>
{{else if (eq this.status 'moved')}}
<div class='status-badge moved'>Room Changed</div>
{{else if (isSessionFull this)}}
<div class='status-badge full'>Nearly Full</div>
{{/if}}
</div>
</div>
{{/each}}
</div>
</section>
<!-- Personalized recommendations -->
{{#if personalizedRecommendations.length > 0}}
<section class='recommendations'>
<h2>Recommended for You</h2>
<div class='recommendation-grid'>
{{#each (slice personalizedRecommendations 0 3)}}
<div class='recommendation-card'>
<h3>{{this.title}}</h3>
<p class='speaker'>{{this.speaker}}</p>
<div class='match-tags'>
{{#each this.tags}}
{{#if (includes ../attendee.preferences this)}}
<span class='tag matched'>{{this}}</span>
{{else}}
<span class='tag'>{{this}}</span>
{{/if}}
{{/each}}
</div>
<div class='recommendation-actions'>
<button class='register-btn' data-session='{{this.id}}'>
Add to Schedule
</button>
<span class='availability'>
{{this.capacity - this.registered}} spots left
</span>
</div>
</div>
{{/each}}
</div>
</section>
{{/if}}
<!-- Real-time notifications -->
<div class='notification-center'>
{{#if notifications.length > 0}}
{{#each notifications}}
<div class='notification {{this.type}}'>
<span class='notification-icon'>
{{#if (eq this.type 'session-starting')}}â°
{{else if (eq this.type 'room-change')}}đ
{{else if (eq this.type 'networking')}}đ¤
{{else}}âšī¸{{/if}}
</span>
<span class='notification-text'>{{this.message}}</span>
<button class='dismiss-btn' data-notification='{{this.id}}'>Ã</button>
</div>
{{/each}}
{{/if}}
</div>
</div>"Best Practices for Complex Workflows
1. Data Architecture
- Normalize data structures: Keep related data together
- Use computed properties: For expensive calculations
- Implement caching: For frequently accessed data
- Plan for real-time updates: Design with live data in mind
2. Template Organization
- Use partials: Break complex templates into reusable components
- Implement template inheritance: Share common layouts
- Organize by feature: Group related templates together
- Document complex logic: Explain non-obvious template decisions
3. Performance Optimization
- Lazy load sections: Only render visible content
- Batch data updates: Group multiple changes together
- Use efficient filters: Optimize data transformations
- Monitor render times: Track template performance
4. Error Handling
- Graceful degradation: Handle missing data elegantly
- Provide fallbacks: Always have backup content
- Log errors: Track template failures
- Test edge cases: Verify behavior with unusual data
5. Maintainability
- Use consistent patterns: Establish team conventions
- Keep logic simple: Move complex operations to computed properties
- Version templates: Track changes over time
- Document workflows: Explain the overall system design
These complex workflows demonstrate how Canvelete's dynamic elements can be combined to create sophisticated, data-driven applications that adapt to user needs and real-time conditions.