@@ -124,7 +124,12 @@ <h1 class="headline">One-Line Embed: AI Chat Dashboard</h1>
124124 {
125125 "imports" : {
126126 "@renderify/ir" : "../../packages/ir/dist/ir.esm.js" ,
127- "@renderify/security" : "../../packages/security/dist/security.esm.js"
127+ "@renderify/security" : "../../packages/security/dist/security.esm.js" ,
128+ "es-module-lexer" : "https://ga.jspm.io/npm:es-module-lexer@1.7.0/dist/lexer.js" ,
129+ "preact" : "https://ga.jspm.io/npm:preact@10.28.3/dist/preact.module.js" ,
130+ "preact/hooks" : "https://ga.jspm.io/npm:preact@10.28.3/hooks/dist/hooks.module.js" ,
131+ "preact/jsx-runtime" : "https://ga.jspm.io/npm:preact@10.28.3/jsx-runtime/dist/jsxRuntime.module.js" ,
132+ "preact-render-to-string" : "https://ga.jspm.io/npm:preact-render-to-string@6.6.5/dist/index.module.js"
128133 }
129134 }
130135 </ script >
@@ -138,10 +143,10 @@ <h1 class="headline">One-Line Embed: AI Chat Dashboard</h1>
138143 root : { type : "text" , value : "loading" } ,
139144 capabilities : {
140145 domWrite : true ,
141- allowedModules : [ "preact" , "preact/hooks" , "recharts" ] ,
146+ allowedModules : [ "preact" , "preact/hooks" ] ,
142147 maxExecutionMs : 5000 ,
143148 } ,
144- imports : [ "preact" , "preact/hooks" , "recharts" ] ,
149+ imports : [ "preact" , "preact/hooks" ] ,
145150 moduleManifest : {
146151 preact : {
147152 resolvedUrl : "https://ga.jspm.io/npm:preact@10.28.3/dist/preact.module.js" ,
@@ -155,30 +160,6 @@ <h1 class="headline">One-Line Embed: AI Chat Dashboard</h1>
155160 resolvedUrl : "https://ga.jspm.io/npm:preact@10.28.3/jsx-runtime/dist/jsxRuntime.module.js" ,
156161 signer : "examples" ,
157162 } ,
158- recharts : {
159- resolvedUrl : "https://ga.jspm.io/npm:recharts@3.3.0/es6/index.js" ,
160- signer : "examples" ,
161- } ,
162- react : {
163- resolvedUrl : "https://ga.jspm.io/npm:preact@10.28.3/compat/dist/compat.module.js" ,
164- signer : "examples" ,
165- } ,
166- "react-dom" : {
167- resolvedUrl : "https://ga.jspm.io/npm:preact@10.28.3/compat/dist/compat.module.js" ,
168- signer : "examples" ,
169- } ,
170- "react-dom/client" : {
171- resolvedUrl : "https://ga.jspm.io/npm:preact@10.28.3/compat/dist/compat.module.js" ,
172- signer : "examples" ,
173- } ,
174- "react/jsx-runtime" : {
175- resolvedUrl : "https://ga.jspm.io/npm:preact@10.28.3/jsx-runtime/dist/jsxRuntime.module.js" ,
176- signer : "examples" ,
177- } ,
178- "react/jsx-dev-runtime" : {
179- resolvedUrl : "https://ga.jspm.io/npm:preact@10.28.3/jsx-runtime/dist/jsxRuntime.module.js" ,
180- signer : "examples" ,
181- } ,
182163 } ,
183164 source : {
184165 language : "tsx" ,
@@ -187,7 +168,6 @@ <h1 class="headline">One-Line Embed: AI Chat Dashboard</h1>
187168 code : [
188169 "import { h } from 'preact';" ,
189170 "import { useMemo, useState } from 'preact/hooks';" ,
190- "import { ResponsiveContainer, LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip } from 'recharts';" ,
191171 "" ,
192172 "export default function Dashboard() {" ,
193173 " const [metric, setMetric] = useState('revenue');" ,
@@ -198,6 +178,17 @@ <h1 class="headline">One-Line Embed: AI Chat Dashboard</h1>
198178 " { day: 'Thu', revenue: 222, users: 74 }," ,
199179 " { day: 'Fri', revenue: 261, users: 91 }," ,
200180 " ], []);" ,
181+ " const key = metric === 'revenue' ? 'revenue' : 'users';" ,
182+ " const width = 560;" ,
183+ " const height = 280;" ,
184+ " const pad = 28;" ,
185+ " const max = Math.max(...data.map((entry) => entry[key]));" ,
186+ " const points = data.map((entry, index) => {" ,
187+ " const x = pad + (index * (width - pad * 2)) / Math.max(1, data.length - 1);" ,
188+ " const y = height - pad - (entry[key] / Math.max(1, max)) * (height - pad * 2);" ,
189+ " return { x, y, day: entry.day, value: entry[key] };" ,
190+ " });" ,
191+ " const polyline = points.map((point) => `${point.x},${point.y}`).join(' ');" ,
201192 " return (" ,
202193 " <section style={{ fontFamily: 'IBM Plex Sans, sans-serif' }}>" ,
203194 " <h2 style={{ margin: '0 0 6px' }}>Revenue Assistant Dashboard</h2>" ,
@@ -206,16 +197,24 @@ <h1 class="headline">One-Line Embed: AI Chat Dashboard</h1>
206197 " <button type='button' onClick={() => setMetric('revenue')}>Revenue</button>" ,
207198 " <button type='button' onClick={() => setMetric('users')}>Users</button>" ,
208199 " </div>" ,
209- " <div style={{ width: '100%', height: 280 }}>" ,
210- " <ResponsiveContainer>" ,
211- " <LineChart data={data}>" ,
212- " <CartesianGrid strokeDasharray='3 3' />" ,
213- " <XAxis dataKey='day' />" ,
214- " <YAxis />" ,
215- " <Tooltip />" ,
216- " <Line type='monotone' dataKey={metric} stroke={metric === 'revenue' ? '#0f766e' : '#1d4ed8'} strokeWidth={3} />" ,
217- " </LineChart>" ,
218- " </ResponsiveContainer>" ,
200+ " <div style={{ overflowX: 'auto' }}>" ,
201+ " <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`} role='img' aria-label='Metric chart'>" ,
202+ " <line x1={pad} y1={height - pad} x2={width - pad} y2={height - pad} stroke='#d1d8e6' />" ,
203+ " <line x1={pad} y1={pad} x2={pad} y2={height - pad} stroke='#d1d8e6' />" ,
204+ " <polyline" ,
205+ " fill='none'" ,
206+ " stroke={metric === 'revenue' ? '#0f766e' : '#1d4ed8'}" ,
207+ " strokeWidth={3}" ,
208+ " points={polyline}" ,
209+ " />" ,
210+ " {points.map((point) => (" ,
211+ " <g key={point.day}>" ,
212+ " <circle cx={point.x} cy={point.y} r={4} fill={metric === 'revenue' ? '#0f766e' : '#1d4ed8'} />" ,
213+ " <text x={point.x} y={height - 8} textAnchor='middle' fontSize='11' fill='#5c6f88'>{point.day}</text>" ,
214+ " <text x={point.x} y={point.y - 10} textAnchor='middle' fontSize='11' fill='#2a3f58'>{point.value}</text>" ,
215+ " </g>" ,
216+ " ))}" ,
217+ " </svg>" ,
219218 " </div>" ,
220219 " <p style={{ marginBottom: 0 }}>Current metric: <strong>{metric}</strong></p>" ,
221220 " </section>" ,
0 commit comments