diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index af7a4149..ec52f43a 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -79,3 +79,10 @@ Chartifact consists of several interoperating modules: - There is a sandboxed runtime that securely renders documents available at https://microsoft.github.io/chartifact/view - The url above can accept a `load` parameter to specify the document to render, for example https://microsoft.github.io/chartifact/view/?load=https://raw.githubusercontent.com/microsoft/chartifact/562d086/packages/web-deploy/json/sales-dashboard.idoc.json - **ALWAYS provide a preview link when creating or modifying examples** - include the preview link in PR comments and descriptions automatically so examples can be tested immediately without being asked. + +## Schema Validation + +- **IMPORTANT**: All JSON documents must validate against the JSON schema at `docs/schema/idoc_v1.json` or conform to the TypeScript declaration at `docs/schema/idoc_v1.d.ts` +- Valid `PageElement` types are only: strings (markdown) or specific interactive elements (`chart`, `checkbox`, `dropdown`, `image`, `mermaid`, `presets`, `slider`, `tabulator`, `textbox`) +- **NO** `"type": "group"` elements are allowed within `elements` arrays - only use `ElementGroup` at the top level in the `groups` array +- Test JSON validity before committing changes diff --git a/docs/assets/examples/markdown/why-chartifact.idoc.md b/docs/assets/examples/markdown/why-chartifact.idoc.md index 0d7edf49..a37ca4e7 100644 --- a/docs/assets/examples/markdown/why-chartifact.idoc.md +++ b/docs/assets/examples/markdown/why-chartifact.idoc.md @@ -15,6 +15,53 @@ "name": "calculatedWorth", "value": "1000", "update": "format(interactiveValue, ',')" + }, + { + "name": "formatCapabilities", + "update": "data('formatCapabilities')" + }, + { + "name": "excelVsLiveData", + "update": "data('excelVsLiveData')" + } + ], + "data": [ + { + "name": "documentFormats", + "values": [ + {"format": "PDF", "capability": "Portable", "score": 95, "interactive": false}, + {"format": "PDF", "capability": "Human-editable", "score": 10, "interactive": false}, + {"format": "PDF", "capability": "Interactive", "score": 5, "interactive": false}, + {"format": "HTML", "capability": "Portable", "score": 40, "interactive": true}, + {"format": "HTML", "capability": "Human-editable", "score": 30, "interactive": true}, + {"format": "HTML", "capability": "Interactive", "score": 95, "interactive": true}, + {"format": "Markdown", "capability": "Portable", "score": 70, "interactive": false}, + {"format": "Markdown", "capability": "Human-editable", "score": 90, "interactive": false}, + {"format": "Markdown", "capability": "Interactive", "score": 20, "interactive": false}, + {"format": "Chartifact", "capability": "Portable", "score": 85, "interactive": true}, + {"format": "Chartifact", "capability": "Human-editable", "score": 85, "interactive": true}, + {"format": "Chartifact", "capability": "Interactive", "score": 90, "interactive": true} + ] + }, + { + "name": "formatCapabilities", + "source": "documentFormats", + "transform": [ + { + "type": "aggregate", + "groupby": ["format"], + "ops": ["mean"], + "fields": ["score"], + "as": ["avgScore"] + } + ] + }, + { + "name": "excelVsLiveData", + "values": [ + {"approach": "Excel Screenshot", "update_frequency": "Manual", "interactivity": "None", "data_freshness": "Stale", "effort_to_update": "High"}, + {"approach": "Live Chart", "update_frequency": "Real-time", "interactivity": "Full", "data_freshness": "Current", "effort_to_update": "None"} + ] } ] } @@ -30,7 +77,7 @@ body { scroll-snap-type: y mandatory; } #slide3 { background: linear-gradient(135deg, #2980b9 0%, #2c3e50 100%); color: white; } #slide4 { background: linear-gradient(135deg, #27ae60 0%, #2980b9 100%); color: white; } #slide5 { background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%); color: white; } -#slide6 { background: linear-gradient(135deg, #f39c12 0%, #e67e22 100%); color: white; justify-content: center; } +#slide6 { background: linear-gradient(135deg, #f39c12 0%, #e67e22 100%); color: white; justify-content: center; min-width: 0; overflow: hidden; } #slide7 { background: linear-gradient(135deg, #16a085 0%, #27ae60 100%); color: white; } #slide8 { background: linear-gradient(135deg, #2c3e50 0%, #8e44ad 100%); color: white; text-align: center; justify-content: center; } h1 { font-size: 2.5em; margin: 0.3em 0; font-weight: 300; line-height: 1.2; } @@ -39,6 +86,12 @@ h3 { font-size: 1.6em; margin: 0.5em 0; font-weight: 400; line-height: 1.2; } p, li { font-size: 1.2em; line-height: 1.5; margin: 0.5em 0; } ul, ol { margin: 0.5em 0; padding-left: 1.5em; } li { margin: 0.3em 0; } +.tabulator { max-width: 100%; overflow: auto; margin: 20px 0; border-radius: 8px; } +.tabulator .tabulator-table { min-width: fit-content; } +.tabulator .tabulator-header { background: rgba(255,255,255,0.9); color: #333; } +.tabulator .tabulator-cell { background: rgba(255,255,255,0.8); color: #333; } +.vega-embed { margin: 20px auto; } +.vega-embed .vega-actions { display: none; } @media (max-width: 768px) { .group { padding: 2em 1em; } h1 { font-size: 2em; } h2 { font-size: 1.6em; } h3 { font-size: 1.3em; } p, li { font-size: 1em; line-height: 1.4; } ul, ol { padding-left: 1em; } } @media (max-width: 480px) { .group { padding: 1.5em 0.8em; } h1 { font-size: 1.8em; } h2 { font-size: 1.4em; } h3 { font-size: 1.2em; } p, li { font-size: 0.9em; line-height: 1.3; } ul, ol { padding-left: 0.8em; } li { margin: 0.2em 0; } } ``` @@ -103,7 +156,9 @@ li { margin: 0.3em 0; } ::: ::: group {#slide6} -## π Interactive Content is Exponentially More Valuable +## π Stop Pasting Chart Images from Excel! +### Make them live charts from live data instead + ### If a picture is worth 1,000 words... # {{calculatedWorth}} ### Then an interactive is worth **{{calculatedWorth}}** words @@ -119,6 +174,92 @@ step: 1000 ``` +### π Document Format Capabilities + + +```json vega-lite +{ + "$schema": "https://vega.github.io/schema/vega-lite/v6.json", + "width": 300, + "height": 300, + "data": { + "name": "formatCapabilities" + }, + "mark": { + "type": "arc", + "innerRadius": 50, + "stroke": "white", + "strokeWidth": 3 + }, + "encoding": { + "theta": { + "field": "avgScore", + "type": "quantitative", + "title": "Capability Score" + }, + "color": { + "field": "format", + "type": "nominal", + "scale": { + "range": ["#e74c3c", "#f39c12", "#27ae60", "#3498db"] + }, + "legend": { + "orient": "right", + "title": "Document Format" + } + }, + "tooltip": [ + {"field": "format", "type": "nominal", "title": "Format"}, + {"field": "avgScore", "type": "quantitative", "title": "Average Score", "format": ".1f"} + ] + } +} +``` + + +### π Excel Screenshots vs Live Data + + +```json tabulator +{ + "dataSourceName": "excelVsLiveData", + "variableId": "excelComparisonTable", + "editable": true, + "tabulatorOptions": { + "layout": "fitColumns", + "maxHeight": "200px", + "columns": [ + { + "title": "Approach", + "field": "approach", + "editor": "input" + }, + { + "title": "Updates", + "field": "update_frequency", + "editor": "input" + }, + { + "title": "Interactive", + "field": "interactivity", + "editor": "input" + }, + { + "title": "Data Freshness", + "field": "data_freshness", + "editor": "input" + }, + { + "title": "Effort", + "field": "effort_to_update", + "editor": "input" + } + ] + } +} +``` + + ### β‘ This slide proves the point - you just experienced it! ::: ::: group {#slide7} diff --git a/packages/web-deploy/json/why-chartifact.idoc.json b/packages/web-deploy/json/why-chartifact.idoc.json index ace13a3b..8696d089 100644 --- a/packages/web-deploy/json/why-chartifact.idoc.json +++ b/packages/web-deploy/json/why-chartifact.idoc.json @@ -11,7 +11,7 @@ "#slide3 { background: linear-gradient(135deg, #2980b9 0%, #2c3e50 100%); color: white; }", "#slide4 { background: linear-gradient(135deg, #27ae60 0%, #2980b9 100%); color: white; }", "#slide5 { background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%); color: white; }", - "#slide6 { background: linear-gradient(135deg, #f39c12 0%, #e67e22 100%); color: white; justify-content: center; }", + "#slide6 { background: linear-gradient(135deg, #f39c12 0%, #e67e22 100%); color: white; justify-content: flex-start; }", "#slide7 { background: linear-gradient(135deg, #16a085 0%, #27ae60 100%); color: white; }", "#slide8 { background: linear-gradient(135deg, #2c3e50 0%, #8e44ad 100%); color: white; text-align: center; justify-content: center; }", "h1 { font-size: 2.5em; margin: 0.3em 0; font-weight: 300; line-height: 1.2; }", @@ -20,30 +20,81 @@ "p, li { font-size: 1.2em; line-height: 1.5; margin: 0.5em 0; }", "ul, ol { margin: 0.5em 0; padding-left: 1.5em; }", "li { margin: 0.3em 0; }", + ".tabulator { max-width: 100%; overflow: auto; margin: 20px 0; border-radius: 8px; min-width: 0; }", + ".tabulator .tabulator-table { min-width: fit-content; }", + ".tabulator .tabulator-header { background: rgba(255,255,255,0.9); color: #333; }", + ".tabulator .tabulator-cell { background: rgba(255,255,255,0.8); color: #333; }", + ".vega-embed { margin: 20px auto; }", + ".vega-embed .vega-actions { display: none; }", "@media (max-width: 768px) { .group { padding: 2em 1em; } h1 { font-size: 2em; } h2 { font-size: 1.6em; } h3 { font-size: 1.3em; } p, li { font-size: 1em; line-height: 1.4; } ul, ol { padding-left: 1em; } }", "@media (max-width: 480px) { .group { padding: 1.5em 0.8em; } h1 { font-size: 1.8em; } h2 { font-size: 1.4em; } h3 { font-size: 1.2em; } p, li { font-size: 0.9em; line-height: 1.3; } ul, ol { padding-left: 0.8em; } li { margin: 0.2em 0; } }" ] }, - "variables": [ - { - "variableId": "interactiveValue", - "type": "number", - "initialValue": 1000 - }, + "dataLoaders": [ { - "variableId": "calculatedWorth", - "type": "string", - "initialValue": "1000", - "calculation": { - "vegaExpression": "format(interactiveValue, ',')" - } - }, + "dataSourceName": "chartData", + "type": "inline", + "format": "json", + "content": [ + {"category": "Excel Screenshots", "value": 25}, + {"category": "Live Charts", "value": 35}, + {"category": "Static Images", "value": 20}, + {"category": "Interactive Data", "value": 20} + ] + } + ], + "variables": [ { "variableId": "currentYear", "type": "number", "initialValue": 2025 + }, + { + "variableId": "editableChartData", + "type": "object", + "isArray": true, + "initialValue": [] } ], + "resources": { + "charts": { + "dataVisualizationChart": { + "$schema": "https://vega.github.io/schema/vega-lite/v6.json", + "width": 250, + "height": 250, + "data": { + "name": "editableChartData" + }, + "mark": { + "type": "arc", + "innerRadius": 40, + "stroke": "white", + "strokeWidth": 2 + }, + "encoding": { + "theta": { + "field": "value", + "type": "quantitative" + }, + "color": { + "field": "category", + "type": "nominal", + "scale": { + "range": ["#e74c3c", "#3498db", "#95a5a6", "#27ae60"] + }, + "legend": { + "orient": "bottom", + "title": "Data Visualization Types" + } + }, + "tooltip": [ + {"field": "category", "type": "nominal", "title": "Type"}, + {"field": "value", "type": "quantitative", "title": "Usage %"} + ] + } + } + } + }, "groups": [ { "groupId": "slide1", @@ -115,19 +166,53 @@ { "groupId": "slide6", "elements": [ - "## π Interactive Content is Exponentially More Valuable", - "### If a picture is worth 1,000 words...", - "# {{calculatedWorth}}", - "### Then an interactive is worth **{{calculatedWorth}}** words", + "## π Stop Pasting Chart Images from Excel!", + "### Make them live charts from live data instead", + "", + "**The Problem:**", + "- Screenshots become stale immediately", + "- No interaction or exploration", + "- Manual updates required", + "- Data context lost", + "", + "**The Solution:**", + "- Live data connections", + "- Interactive exploration", + "- Automatic updates", + "- Rich context preserved", + "", + "### β‘ Experience the difference below:", + "", + "### π Live Data Visualization", { - "type": "slider", - "variableId": "interactiveValue", - "label": "Adjust the multiplier", - "min": 1000, - "max": 100000, - "step": 1000 + "type": "chart", + "chartKey": "dataVisualizationChart" }, - "### β‘ This slide proves the point - you just experienced it!" + "", + "### π Editable Data Source", + "**Try editing the values in the table below and watch the chart update in real-time!**", + { + "type": "tabulator", + "variableId": "editableChartData", + "dataSourceName": "chartData", + "editable": true, + "tabulatorOptions": { + "layout": "fitColumns", + "maxHeight": "180px", + "columns": [ + { + "title": "Category", + "field": "category", + "editor": "input" + }, + { + "title": "Value", + "field": "value", + "editor": "number" + } + ] + } + } ] }, {