From 4cde7e7d383e13d7ce3fefb1a8dca8102c6dee64 Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Mon, 5 Jan 2026 15:02:52 -0500 Subject: [PATCH] feat(templ): add charts and drawers components --- components/charts.templ | 703 ++++++++++++++++++++++++ components/charts_templ.go | 1003 +++++++++++++++++++++++++++++++++++ components/drawers.templ | 374 +++++++++++++ components/drawers_templ.go | 564 ++++++++++++++++++++ 4 files changed, 2644 insertions(+) create mode 100644 components/charts.templ create mode 100644 components/charts_templ.go create mode 100644 components/drawers.templ create mode 100644 components/drawers_templ.go diff --git a/components/charts.templ b/components/charts.templ new file mode 100644 index 0000000..7c0a0fe --- /dev/null +++ b/components/charts.templ @@ -0,0 +1,703 @@ +package components + +import "encoding/json" + +// OHLCData represents a single candlestick data point +type OHLCData struct { + Date string `json:"date"` + Open float64 `json:"open"` + High float64 `json:"high"` + Low float64 `json:"low"` + Close float64 `json:"close"` +} + +// AreaSeriesData represents time series data for stacked area chart +type AreaSeriesData struct { + Date string `json:"date"` + Industry string `json:"industry"` + Value float64 `json:"value"` +} + +// BubbleData represents data for bubble/circle packing chart +type BubbleData struct { + Name string `json:"name"` + Sector string `json:"sector"` + Value float64 `json:"value"` +} + +// TimeSeriesData represents simple time series data +type TimeSeriesData struct { + Date string `json:"date"` + Value float64 `json:"value"` +} + +// Helper to convert data to JSON string for JS +func toJSON(v interface{}) string { + b, _ := json.Marshal(v) + return string(b) +} + +// RosenCharts global utilities and chart classes +script initRosenCharts() { + window.RosenCharts = { + colors: { + success: 'var(--wa-color-success)', + danger: 'var(--wa-color-danger)', + primary: 'var(--wa-color-primary)', + neutral400: 'var(--wa-color-neutral-400)', + neutral500: 'var(--wa-color-neutral-500)', + neutral600: 'var(--wa-color-neutral-600)', + surfaceAlt: 'var(--wa-color-surface-alt)', + surface: 'var(--wa-color-surface)', + fuchsia: { from: '#f0abfc', to: '#e879f9' }, + purple: { from: '#c4b5fd', to: '#a855f7' }, + blue: { from: '#93c5fd', to: '#3b82f6' }, + sky: { from: '#bae6fd', to: '#38bdf8' }, + orange: { from: '#fed7aa', to: '#fb923c' }, + yellow: { from: '#fef08a', to: '#facc15' }, + emerald: { from: '#6ee7b7', to: '#10b981' }, + red: { from: '#fca5a5', to: '#ef4444' } + }, + formatNumber(value, decimals = 2) { + return new Intl.NumberFormat('en-US', { + minimumFractionDigits: decimals, + maximumFractionDigits: decimals + }).format(value); + }, + formatCurrency(value) { + return new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'USD' + }).format(value); + }, + isDesktop() { + return window.innerWidth > 1024; + }, + createSVG(tag, attrs = {}) { + const el = document.createElementNS('http://www.w3.org/2000/svg', tag); + Object.entries(attrs).forEach(([key, value]) => { + el.setAttribute(key, value); + }); + return el; + }, + createElement(tag, attrs = {}, children = []) { + const el = document.createElement(tag); + Object.entries(attrs).forEach(([key, value]) => { + if (key === 'style' && typeof value === 'object') { + Object.assign(el.style, value); + } else if (key === 'className') { + el.className = value; + } else { + el.setAttribute(key, value); + } + }); + children.forEach(child => { + if (typeof child === 'string') { + el.appendChild(document.createTextNode(child)); + } else if (child) { + el.appendChild(child); + } + }); + return el; + } + }; +} + +// CandleChart initialization script +script initCandleChart(containerId string, dataJSON string) { + const container = document.getElementById(containerId); + if (!container || !window.d3) return; + + const data = JSON.parse(dataJSON); + const RC = window.RosenCharts; + + const options = { + marginTop: 10, + marginRight: 60, + marginBottom: 56, + marginLeft: 30, + height: 288 + }; + + let zoomLevel = 1; + let visibleRange = { start: 0, end: data.length - 1 }; + let mousePosition = null; + let hoverData = null; + + function getVisibleData() { + return data.slice(visibleRange.start, visibleRange.end + 1); + } + + function render() { + container.innerHTML = ''; + container.style.position = 'relative'; + + const visibleData = getVisibleData(); + + // Create scales + const xScale = d3.scaleBand() + .domain(visibleData.map(d => d.date)) + .range([0, 100]) + .padding(0.3); + + const yMin = d3.min(visibleData, d => d.low) * 0.995; + const yMax = d3.max(visibleData, d => d.high) * 1.005; + const yScale = d3.scaleLinear() + .domain([yMin, yMax]) + .range([100, 0]); + + // Legend + const legend = RC.createElement('div', { + style: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + marginBottom: '8px', + padding: '4px 32px', + background: 'var(--wa-color-surface-alt)', + borderRadius: 'var(--wa-radius-s)', + fontSize: 'var(--wa-font-size-xs)' + } + }); + legend.innerHTML = `
Hover over chart to see OHLC data
`; + + // Chart area + const chartArea = RC.createElement('div', { + style: { + position: 'relative', + height: options.height + 'px', + width: '100%' + } + }); + + // Y-axis + const yAxisContainer = RC.createElement('div', { + style: { + position: 'absolute', + height: 'calc(100% - ' + options.marginTop + 'px - ' + options.marginBottom + 'px)', + transform: 'translateY(' + options.marginTop + 'px)', + right: 'calc(' + options.marginRight + 'px - 1rem)', + overflow: 'visible' + } + }); + + const yTicks = yScale.ticks(6); + yTicks.forEach(value => { + const label = RC.createElement('div', { + style: { + position: 'absolute', + right: '0%', + top: yScale(value) + '%', + transform: 'translateY(-50%)', + fontSize: 'var(--wa-font-size-xs)', + fontVariantNumeric: 'tabular-nums', + color: 'var(--wa-color-neutral-400)', + width: '100%', + textAlign: 'right' + } + }, [value.toFixed(2)]); + yAxisContainer.appendChild(label); + }); + + // Chart inner + const chartInner = RC.createElement('div', { + style: { + position: 'absolute', + inset: 0, + height: 'calc(100% - ' + options.marginTop + 'px - ' + options.marginBottom + 'px)', + width: 'calc(100% - ' + options.marginLeft + 'px - ' + options.marginRight + 'px)', + transform: 'translate(' + options.marginLeft + 'px, ' + options.marginTop + 'px)', + overflow: 'visible' + } + }); + + // SVG for grid and wicks + const svg = RC.createSVG('svg', { + viewBox: '0 0 100 100', + preserveAspectRatio: 'none', + style: 'overflow: visible; width: 100%; height: 100%;' + }); + + // Grid lines + yTicks.forEach(value => { + const line = RC.createSVG('line', { + x1: 0, x2: 100, + y1: yScale(value), y2: yScale(value), + stroke: 'var(--wa-color-neutral-200)', + 'stroke-dasharray': '6,5', + 'stroke-width': 0.5, + 'vector-effect': 'non-scaling-stroke' + }); + svg.appendChild(line); + }); + + // Wicks + visibleData.forEach(d => { + const barX = xScale(d.date) + xScale.bandwidth() / 2; + const line = RC.createSVG('line', { + x1: barX, y1: yScale(d.high), + x2: barX, y2: yScale(d.low), + stroke: 'var(--wa-color-neutral-300)', + 'stroke-width': 1, + 'vector-effect': 'non-scaling-stroke' + }); + svg.appendChild(line); + }); + + chartInner.appendChild(svg); + + // Candle bodies + visibleData.forEach(d => { + const barWidth = xScale.bandwidth(); + const barHeight = Math.abs(yScale(d.open) - yScale(d.close)); + const barX = xScale(d.date); + const barY = yScale(Math.max(d.open, d.close)); + const isUp = d.close > d.open; + + const bar = RC.createElement('div', { + style: { + position: 'absolute', + width: barWidth + '%', + height: barHeight + '%', + left: barX + '%', + top: barY + '%', + background: isUp + ? 'linear-gradient(to bottom, #6ee7b7, #10b981)' + : 'linear-gradient(to bottom, #fca5a5, #ef4444)', + borderRadius: '1px' + } + }); + chartInner.appendChild(bar); + }); + + chartArea.appendChild(yAxisContainer); + chartArea.appendChild(chartInner); + + container.appendChild(legend); + container.appendChild(chartArea); + + // Wheel zoom + chartArea.addEventListener('wheel', (e) => { + e.preventDefault(); + const zoomIn = e.deltaY < 0; + const zoomFactor = 1.04; + const newZoomLevel = zoomIn + ? Math.min(zoomLevel * zoomFactor, 20) + : Math.max(zoomLevel / zoomFactor, 1); + + const visibleCount = Math.max(5, Math.floor(data.length / newZoomLevel)); + const newEnd = data.length - 1; + const newStart = Math.max(0, newEnd - visibleCount + 1); + + zoomLevel = newZoomLevel; + visibleRange = { start: newStart, end: newEnd }; + render(); + }, { passive: false }); + } + + render(); +} + +// StackedAreaChart initialization script +script initStackedAreaChart(containerId string, dataJSON string) { + const container = document.getElementById(containerId); + if (!container || !window.d3) return; + + const data = JSON.parse(dataJSON); + const RC = window.RosenCharts; + + const colors = [ + { from: '#f5d0fe', to: '#e879f9', bg: '#e879f9' }, + { from: '#c4b5fd', to: '#a855f7', bg: '#a855f7' }, + { from: '#bfdbfe', to: '#3b82f6', bg: '#3b82f6' }, + { from: '#bae6fd', to: '#38bdf8', bg: '#38bdf8' }, + { from: '#fed7aa', to: '#fb923c', bg: '#fb923c' } + ]; + + container.innerHTML = ''; + container.style.position = 'relative'; + + const parseDate = d3.utcParse('%Y-%m-%d'); + const industries = Array.from(new Set(data.map(d => d.industry))); + + const groupedData = Array.from( + d3.group(data, d => d.date), + ([date, values]) => { + const obj = { date: parseDate(date.split('T')[0]) }; + values.forEach(val => { + obj[val.industry] = val.value || 0; + }); + return obj; + } + ); + + const series = d3.stack().keys(industries)(groupedData); + + // Legend + const legendContainer = RC.createElement('div', { + style: { + display: 'flex', + textAlign: 'center', + gap: '16px', + fontSize: 'var(--wa-font-size-xs)', + overflowX: 'auto', + padding: '0 40px', + marginBottom: '32px' + } + }); + + industries.slice().reverse().forEach((industry, i) => { + const colorIndex = industries.length - 1 - i; + const color = colors[colorIndex % colors.length]; + + const item = RC.createElement('div', { + style: { display: 'flex', gap: '6px', alignItems: 'center' } + }); + + const dot = RC.createElement('div', { + style: { + width: '4px', + height: '16px', + borderRadius: '9999px', + background: color.bg + } + }); + + item.appendChild(dot); + item.appendChild(document.createTextNode(industry)); + legendContainer.appendChild(item); + }); + + // Chart container + const chartContainer = RC.createElement('div', { + style: { + position: 'relative', + height: '256px', + width: '100%' + } + }); + + // Scales + const xScale = d3.scaleUtc() + .domain(d3.extent(groupedData, d => d.date)) + .range([0, 100]); + + const yScale = d3.scaleLinear() + .domain([0, d3.max(series, d => d3.max(d, d => d[1])) || 0]) + .rangeRound([100, 0]); + + // Area generator + const area = d3.area() + .x(d => xScale(d.data.date)) + .y0(d => yScale(d[0])) + .y1(d => yScale(d[1])) + .curve(d3.curveMonotoneX); + + // SVG + const svg = RC.createSVG('svg', { + style: 'position: absolute; inset: 0; z-index: 10; height: 100%; width: 100%; overflow: visible;' + }); + + const innerSvg = RC.createSVG('svg', { + viewBox: '0 0 100 100', + preserveAspectRatio: 'none', + style: 'overflow: visible;' + }); + + // Gradients + const defs = RC.createSVG('defs'); + series.forEach((_, i) => { + const color = colors[i % colors.length]; + const gradient = RC.createSVG('linearGradient', { + id: 'stacked-area-gradient-' + containerId + '-' + i, + x1: 0, x2: 0.5, y1: 0.25, y2: 1 + }); + + const stop1 = RC.createSVG('stop', { offset: '0%', 'stop-color': color.from }); + const stop2 = RC.createSVG('stop', { offset: '80%', 'stop-color': color.to }); + + gradient.appendChild(stop1); + gradient.appendChild(stop2); + defs.appendChild(gradient); + }); + innerSvg.appendChild(defs); + + // Areas + series.forEach((layer, layerIndex) => { + const path = RC.createSVG('path', { + fill: 'url(#stacked-area-gradient-' + containerId + '-' + layerIndex + ')', + d: area(layer), + stroke: '#ccc', + 'stroke-width': '0.05' + }); + innerSvg.appendChild(path); + }); + + svg.appendChild(innerSvg); + chartContainer.appendChild(svg); + + container.appendChild(legendContainer); + container.appendChild(chartContainer); +} + +// BubbleChart initialization script +script initBubbleChart(containerId string, dataJSON string) { + const container = document.getElementById(containerId); + if (!container || !window.d3) return; + + const data = JSON.parse(dataJSON); + const RC = window.RosenCharts; + + const colors = ['#f472b6', '#8b5cf6', '#84cc16', '#38bdf8', '#fb923c']; + + container.innerHTML = ''; + container.style.position = 'relative'; + container.style.width = '100%'; + container.style.aspectRatio = '1'; + container.style.maxWidth = '18rem'; + container.style.margin = '0 auto'; + + const sectors = Array.from(new Set(data.map(d => d.sector))); + const color = d3.scaleOrdinal().domain(sectors).range(colors); + + const pack = d3.pack().size([1000, 1000]).padding(12); + + const root = pack( + d3.hierarchy({ children: data }).sum(d => d.value) + ); + + root.leaves().forEach(d => { + const x = d.x; + const y = d.y; + const r = d.r; + const fillColor = color(d.data.sector); + const name = d.data.name; + const value = d.data.value; + + const bubble = RC.createElement('div', { + style: { + position: 'absolute', + transform: 'translate(-50%, -50%)', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + left: (x / 1000 * 100) + '%', + top: (y / 1000 * 100) + '%', + width: (r * 2 / 1000 * 100) + '%', + height: (r * 2 / 1000 * 100) + '%', + borderRadius: '50%', + backgroundColor: fillColor, + border: '1px solid rgba(255,255,255,0.2)', + cursor: 'default' + }, + title: name + '\n' + d3.format(',d')(value) + }); + + if (value > 1000) { + const nameEl = RC.createElement('div', { + style: { + color: 'white', + textAlign: 'center', + whiteSpace: 'nowrap', + fontSize: (r / 9) + 'px', + lineHeight: (r / 7) + 'px' + } + }, [name]); + + const valueEl = RC.createElement('div', { + style: { + color: 'white', + textAlign: 'center', + whiteSpace: 'nowrap', + opacity: 0.7, + fontSize: (r / 10) + 'px', + lineHeight: (r / 8) + 'px' + } + }, [d3.format(',d')(value)]); + + bubble.appendChild(nameEl); + bubble.appendChild(valueEl); + } + + container.appendChild(bubble); + }); +} + +// SemiFilledAreaChart initialization script +script initSemiFilledAreaChart(containerId string, dataJSON string, lineColor string, areaFromColor string, areaToColor string) { + const container = document.getElementById(containerId); + if (!container || !window.d3) return; + + const data = JSON.parse(dataJSON).map(d => ({ + ...d, + date: new Date(d.date) + })); + const RC = window.RosenCharts; + + container.innerHTML = ''; + container.style.position = 'relative'; + container.style.height = '288px'; + container.style.width = '100%'; + + // Scales + const xScale = d3.scaleTime() + .domain([data[0].date, data[data.length - 1].date]) + .range([0, 100]); + + const yScale = d3.scaleLinear() + .domain([0, d3.max(data, d => d.value) || 0]) + .range([100, 0]); + + // Line generator + const line = d3.line() + .x(d => xScale(d.date)) + .y(d => yScale(d.value)) + .curve(d3.curveMonotoneX); + + // Area generator + const area = d3.area() + .x(d => xScale(d.date)) + .y0(yScale(0)) + .y1(d => yScale(d.value)) + .curve(d3.curveMonotoneX); + + // Chart inner + const chartInner = RC.createElement('div', { + style: { + position: 'absolute', + inset: 0, + height: '100%', + width: '100%', + overflow: 'visible' + } + }); + + // SVG + const svg = RC.createSVG('svg', { + viewBox: '0 0 100 100', + preserveAspectRatio: 'none', + style: 'width: 100%; height: 100%; overflow: visible;' + }); + + // Gradient + const defs = RC.createSVG('defs'); + const gradient = RC.createSVG('linearGradient', { + id: 'semi-filled-gradient-' + containerId, + x1: 0, x2: 0, y1: 0, y2: 1 + }); + + const stop1 = RC.createSVG('stop', { offset: '0%', 'stop-color': areaFromColor }); + const stop2 = RC.createSVG('stop', { offset: '100%', 'stop-color': areaToColor }); + + gradient.appendChild(stop1); + gradient.appendChild(stop2); + defs.appendChild(gradient); + svg.appendChild(defs); + + // Area path + const areaPath = RC.createSVG('path', { + d: area(data), + fill: 'url(#semi-filled-gradient-' + containerId + ')' + }); + svg.appendChild(areaPath); + + // Line path + const linePath = RC.createSVG('path', { + d: line(data), + fill: 'none', + stroke: lineColor, + 'stroke-width': '1.5', + 'vector-effect': 'non-scaling-stroke' + }); + svg.appendChild(linePath); + + chartInner.appendChild(svg); + + // X-axis labels + data.forEach((day, i) => { + if (i % 6 !== 0 || i === 0 || i >= data.length - 3) return; + + const label = RC.createElement('div', { + style: { + position: 'absolute', + left: xScale(day.date) + '%', + top: '90%', + fontSize: 'var(--wa-font-size-xs)', + color: 'var(--wa-color-neutral-500)', + transform: 'translateX(-50%)' + } + }, [day.date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })]); + + chartInner.appendChild(label); + }); + + container.appendChild(chartInner); + + // Y-axis labels + yScale.ticks(8).forEach((value, i) => { + if (i < 1) return; + + const label = RC.createElement('div', { + style: { + position: 'absolute', + top: yScale(value) + '%', + right: '3%', + fontSize: 'var(--wa-font-size-xs)', + fontVariantNumeric: 'tabular-nums', + color: 'var(--wa-color-neutral-400)', + transform: 'translateY(-50%)' + } + }, [value.toString()]); + + container.appendChild(label); + }); +} + +// CandleChart component +templ CandleChart(id string, data []OHLCData) { +
+ @initRosenCharts() + @initCandleChart(id, toJSON(data)) +} + +// StackedAreaChart component +templ StackedAreaChart(id string, data []AreaSeriesData) { +
+ @initRosenCharts() + @initStackedAreaChart(id, toJSON(data)) +} + +// BubbleChart component +templ BubbleChart(id string, data []BubbleData) { +
+ @initRosenCharts() + @initBubbleChart(id, toJSON(data)) +} + +// SemiFilledAreaChart component with customizable colors +templ SemiFilledAreaChart(id string, data []TimeSeriesData) { + @SemiFilledAreaChartWithColors(id, data, "#facc15", "rgba(234, 179, 8, 0.2)", "rgba(234, 179, 8, 0.05)") +} + +// SemiFilledAreaChart with custom colors +templ SemiFilledAreaChartWithColors(id string, data []TimeSeriesData, lineColor string, areaFromColor string, areaToColor string) { +
+ @initRosenCharts() + @initSemiFilledAreaChart(id, toJSON(data), lineColor, areaFromColor, areaToColor) +} + +// Chart card wrapper for consistent styling +templ ChartCard(title string, subtitle string) { + + + { children... } + +} diff --git a/components/charts_templ.go b/components/charts_templ.go new file mode 100644 index 0000000..fea1412 --- /dev/null +++ b/components/charts_templ.go @@ -0,0 +1,1003 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.977 +package components + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +import "encoding/json" + +// OHLCData represents a single candlestick data point +type OHLCData struct { + Date string `json:"date"` + Open float64 `json:"open"` + High float64 `json:"high"` + Low float64 `json:"low"` + Close float64 `json:"close"` +} + +// AreaSeriesData represents time series data for stacked area chart +type AreaSeriesData struct { + Date string `json:"date"` + Industry string `json:"industry"` + Value float64 `json:"value"` +} + +// BubbleData represents data for bubble/circle packing chart +type BubbleData struct { + Name string `json:"name"` + Sector string `json:"sector"` + Value float64 `json:"value"` +} + +// TimeSeriesData represents simple time series data +type TimeSeriesData struct { + Date string `json:"date"` + Value float64 `json:"value"` +} + +// Helper to convert data to JSON string for JS +func toJSON(v interface{}) string { + b, _ := json.Marshal(v) + return string(b) +} + +// RosenCharts global utilities and chart classes +func initRosenCharts() templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_initRosenCharts_9c0e`, + Function: `function __templ_initRosenCharts_9c0e(){window.RosenCharts = { + colors: { + success: 'var(--wa-color-success)', + danger: 'var(--wa-color-danger)', + primary: 'var(--wa-color-primary)', + neutral400: 'var(--wa-color-neutral-400)', + neutral500: 'var(--wa-color-neutral-500)', + neutral600: 'var(--wa-color-neutral-600)', + surfaceAlt: 'var(--wa-color-surface-alt)', + surface: 'var(--wa-color-surface)', + fuchsia: { from: '#f0abfc', to: '#e879f9' }, + purple: { from: '#c4b5fd', to: '#a855f7' }, + blue: { from: '#93c5fd', to: '#3b82f6' }, + sky: { from: '#bae6fd', to: '#38bdf8' }, + orange: { from: '#fed7aa', to: '#fb923c' }, + yellow: { from: '#fef08a', to: '#facc15' }, + emerald: { from: '#6ee7b7', to: '#10b981' }, + red: { from: '#fca5a5', to: '#ef4444' } + }, + formatNumber(value, decimals = 2) { + return new Intl.NumberFormat('en-US', { + minimumFractionDigits: decimals, + maximumFractionDigits: decimals + }).format(value); + }, + formatCurrency(value) { + return new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'USD' + }).format(value); + }, + isDesktop() { + return window.innerWidth > 1024; + }, + createSVG(tag, attrs = {}) { + const el = document.createElementNS('http://www.w3.org/2000/svg', tag); + Object.entries(attrs).forEach(([key, value]) => { + el.setAttribute(key, value); + }); + return el; + }, + createElement(tag, attrs = {}, children = []) { + const el = document.createElement(tag); + Object.entries(attrs).forEach(([key, value]) => { + if (key === 'style' && typeof value === 'object') { + Object.assign(el.style, value); + } else if (key === 'className') { + el.className = value; + } else { + el.setAttribute(key, value); + } + }); + children.forEach(child => { + if (typeof child === 'string') { + el.appendChild(document.createTextNode(child)); + } else if (child) { + el.appendChild(child); + } + }); + return el; + } + }; +}`, + Call: templ.SafeScript(`__templ_initRosenCharts_9c0e`), + CallInline: templ.SafeScriptInline(`__templ_initRosenCharts_9c0e`), + } +} + +// CandleChart initialization script +func initCandleChart(containerId string, dataJSON string) templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_initCandleChart_55d6`, + Function: `function __templ_initCandleChart_55d6(containerId, dataJSON){const container = document.getElementById(containerId); + if (!container || !window.d3) return; + + const data = JSON.parse(dataJSON); + const RC = window.RosenCharts; + + const options = { + marginTop: 10, + marginRight: 60, + marginBottom: 56, + marginLeft: 30, + height: 288 + }; + + let zoomLevel = 1; + let visibleRange = { start: 0, end: data.length - 1 }; + let mousePosition = null; + let hoverData = null; + + function getVisibleData() { + return data.slice(visibleRange.start, visibleRange.end + 1); + } + + function render() { + container.innerHTML = ''; + container.style.position = 'relative'; + + const visibleData = getVisibleData(); + + // Create scales + const xScale = d3.scaleBand() + .domain(visibleData.map(d => d.date)) + .range([0, 100]) + .padding(0.3); + + const yMin = d3.min(visibleData, d => d.low) * 0.995; + const yMax = d3.max(visibleData, d => d.high) * 1.005; + const yScale = d3.scaleLinear() + .domain([yMin, yMax]) + .range([100, 0]); + + // Legend + const legend = RC.createElement('div', { + style: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + marginBottom: '8px', + padding: '4px 32px', + background: 'var(--wa-color-surface-alt)', + borderRadius: 'var(--wa-radius-s)', + fontSize: 'var(--wa-font-size-xs)' + } + }); + legend.innerHTML = ` + "`" + `
Hover over chart to see OHLC data
` + "`" + `; + + // Chart area + const chartArea = RC.createElement('div', { + style: { + position: 'relative', + height: options.height + 'px', + width: '100%' + } + }); + + // Y-axis + const yAxisContainer = RC.createElement('div', { + style: { + position: 'absolute', + height: 'calc(100% - ' + options.marginTop + 'px - ' + options.marginBottom + 'px)', + transform: 'translateY(' + options.marginTop + 'px)', + right: 'calc(' + options.marginRight + 'px - 1rem)', + overflow: 'visible' + } + }); + + const yTicks = yScale.ticks(6); + yTicks.forEach(value => { + const label = RC.createElement('div', { + style: { + position: 'absolute', + right: '0%', + top: yScale(value) + '%', + transform: 'translateY(-50%)', + fontSize: 'var(--wa-font-size-xs)', + fontVariantNumeric: 'tabular-nums', + color: 'var(--wa-color-neutral-400)', + width: '100%', + textAlign: 'right' + } + }, [value.toFixed(2)]); + yAxisContainer.appendChild(label); + }); + + // Chart inner + const chartInner = RC.createElement('div', { + style: { + position: 'absolute', + inset: 0, + height: 'calc(100% - ' + options.marginTop + 'px - ' + options.marginBottom + 'px)', + width: 'calc(100% - ' + options.marginLeft + 'px - ' + options.marginRight + 'px)', + transform: 'translate(' + options.marginLeft + 'px, ' + options.marginTop + 'px)', + overflow: 'visible' + } + }); + + // SVG for grid and wicks + const svg = RC.createSVG('svg', { + viewBox: '0 0 100 100', + preserveAspectRatio: 'none', + style: 'overflow: visible; width: 100%; height: 100%;' + }); + + // Grid lines + yTicks.forEach(value => { + const line = RC.createSVG('line', { + x1: 0, x2: 100, + y1: yScale(value), y2: yScale(value), + stroke: 'var(--wa-color-neutral-200)', + 'stroke-dasharray': '6,5', + 'stroke-width': 0.5, + 'vector-effect': 'non-scaling-stroke' + }); + svg.appendChild(line); + }); + + // Wicks + visibleData.forEach(d => { + const barX = xScale(d.date) + xScale.bandwidth() / 2; + const line = RC.createSVG('line', { + x1: barX, y1: yScale(d.high), + x2: barX, y2: yScale(d.low), + stroke: 'var(--wa-color-neutral-300)', + 'stroke-width': 1, + 'vector-effect': 'non-scaling-stroke' + }); + svg.appendChild(line); + }); + + chartInner.appendChild(svg); + + // Candle bodies + visibleData.forEach(d => { + const barWidth = xScale.bandwidth(); + const barHeight = Math.abs(yScale(d.open) - yScale(d.close)); + const barX = xScale(d.date); + const barY = yScale(Math.max(d.open, d.close)); + const isUp = d.close > d.open; + + const bar = RC.createElement('div', { + style: { + position: 'absolute', + width: barWidth + '%', + height: barHeight + '%', + left: barX + '%', + top: barY + '%', + background: isUp + ? 'linear-gradient(to bottom, #6ee7b7, #10b981)' + : 'linear-gradient(to bottom, #fca5a5, #ef4444)', + borderRadius: '1px' + } + }); + chartInner.appendChild(bar); + }); + + chartArea.appendChild(yAxisContainer); + chartArea.appendChild(chartInner); + + container.appendChild(legend); + container.appendChild(chartArea); + + // Wheel zoom + chartArea.addEventListener('wheel', (e) => { + e.preventDefault(); + const zoomIn = e.deltaY < 0; + const zoomFactor = 1.04; + const newZoomLevel = zoomIn + ? Math.min(zoomLevel * zoomFactor, 20) + : Math.max(zoomLevel / zoomFactor, 1); + + const visibleCount = Math.max(5, Math.floor(data.length / newZoomLevel)); + const newEnd = data.length - 1; + const newStart = Math.max(0, newEnd - visibleCount + 1); + + zoomLevel = newZoomLevel; + visibleRange = { start: newStart, end: newEnd }; + render(); + }, { passive: false }); + } + + render(); +}`, + Call: templ.SafeScript(`__templ_initCandleChart_55d6`, containerId, dataJSON), + CallInline: templ.SafeScriptInline(`__templ_initCandleChart_55d6`, containerId, dataJSON), + } +} + +// StackedAreaChart initialization script +func initStackedAreaChart(containerId string, dataJSON string) templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_initStackedAreaChart_1646`, + Function: `function __templ_initStackedAreaChart_1646(containerId, dataJSON){const container = document.getElementById(containerId); + if (!container || !window.d3) return; + + const data = JSON.parse(dataJSON); + const RC = window.RosenCharts; + + const colors = [ + { from: '#f5d0fe', to: '#e879f9', bg: '#e879f9' }, + { from: '#c4b5fd', to: '#a855f7', bg: '#a855f7' }, + { from: '#bfdbfe', to: '#3b82f6', bg: '#3b82f6' }, + { from: '#bae6fd', to: '#38bdf8', bg: '#38bdf8' }, + { from: '#fed7aa', to: '#fb923c', bg: '#fb923c' } + ]; + + container.innerHTML = ''; + container.style.position = 'relative'; + + const parseDate = d3.utcParse('%Y-%m-%d'); + const industries = Array.from(new Set(data.map(d => d.industry))); + + const groupedData = Array.from( + d3.group(data, d => d.date), + ([date, values]) => { + const obj = { date: parseDate(date.split('T')[0]) }; + values.forEach(val => { + obj[val.industry] = val.value || 0; + }); + return obj; + } + ); + + const series = d3.stack().keys(industries)(groupedData); + + // Legend + const legendContainer = RC.createElement('div', { + style: { + display: 'flex', + textAlign: 'center', + gap: '16px', + fontSize: 'var(--wa-font-size-xs)', + overflowX: 'auto', + padding: '0 40px', + marginBottom: '32px' + } + }); + + industries.slice().reverse().forEach((industry, i) => { + const colorIndex = industries.length - 1 - i; + const color = colors[colorIndex % colors.length]; + + const item = RC.createElement('div', { + style: { display: 'flex', gap: '6px', alignItems: 'center' } + }); + + const dot = RC.createElement('div', { + style: { + width: '4px', + height: '16px', + borderRadius: '9999px', + background: color.bg + } + }); + + item.appendChild(dot); + item.appendChild(document.createTextNode(industry)); + legendContainer.appendChild(item); + }); + + // Chart container + const chartContainer = RC.createElement('div', { + style: { + position: 'relative', + height: '256px', + width: '100%' + } + }); + + // Scales + const xScale = d3.scaleUtc() + .domain(d3.extent(groupedData, d => d.date)) + .range([0, 100]); + + const yScale = d3.scaleLinear() + .domain([0, d3.max(series, d => d3.max(d, d => d[1])) || 0]) + .rangeRound([100, 0]); + + // Area generator + const area = d3.area() + .x(d => xScale(d.data.date)) + .y0(d => yScale(d[0])) + .y1(d => yScale(d[1])) + .curve(d3.curveMonotoneX); + + // SVG + const svg = RC.createSVG('svg', { + style: 'position: absolute; inset: 0; z-index: 10; height: 100%; width: 100%; overflow: visible;' + }); + + const innerSvg = RC.createSVG('svg', { + viewBox: '0 0 100 100', + preserveAspectRatio: 'none', + style: 'overflow: visible;' + }); + + // Gradients + const defs = RC.createSVG('defs'); + series.forEach((_, i) => { + const color = colors[i % colors.length]; + const gradient = RC.createSVG('linearGradient', { + id: 'stacked-area-gradient-' + containerId + '-' + i, + x1: 0, x2: 0.5, y1: 0.25, y2: 1 + }); + + const stop1 = RC.createSVG('stop', { offset: '0%', 'stop-color': color.from }); + const stop2 = RC.createSVG('stop', { offset: '80%', 'stop-color': color.to }); + + gradient.appendChild(stop1); + gradient.appendChild(stop2); + defs.appendChild(gradient); + }); + innerSvg.appendChild(defs); + + // Areas + series.forEach((layer, layerIndex) => { + const path = RC.createSVG('path', { + fill: 'url(#stacked-area-gradient-' + containerId + '-' + layerIndex + ')', + d: area(layer), + stroke: '#ccc', + 'stroke-width': '0.05' + }); + innerSvg.appendChild(path); + }); + + svg.appendChild(innerSvg); + chartContainer.appendChild(svg); + + container.appendChild(legendContainer); + container.appendChild(chartContainer); +}`, + Call: templ.SafeScript(`__templ_initStackedAreaChart_1646`, containerId, dataJSON), + CallInline: templ.SafeScriptInline(`__templ_initStackedAreaChart_1646`, containerId, dataJSON), + } +} + +// BubbleChart initialization script +func initBubbleChart(containerId string, dataJSON string) templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_initBubbleChart_9cee`, + Function: `function __templ_initBubbleChart_9cee(containerId, dataJSON){const container = document.getElementById(containerId); + if (!container || !window.d3) return; + + const data = JSON.parse(dataJSON); + const RC = window.RosenCharts; + + const colors = ['#f472b6', '#8b5cf6', '#84cc16', '#38bdf8', '#fb923c']; + + container.innerHTML = ''; + container.style.position = 'relative'; + container.style.width = '100%'; + container.style.aspectRatio = '1'; + container.style.maxWidth = '18rem'; + container.style.margin = '0 auto'; + + const sectors = Array.from(new Set(data.map(d => d.sector))); + const color = d3.scaleOrdinal().domain(sectors).range(colors); + + const pack = d3.pack().size([1000, 1000]).padding(12); + + const root = pack( + d3.hierarchy({ children: data }).sum(d => d.value) + ); + + root.leaves().forEach(d => { + const x = d.x; + const y = d.y; + const r = d.r; + const fillColor = color(d.data.sector); + const name = d.data.name; + const value = d.data.value; + + const bubble = RC.createElement('div', { + style: { + position: 'absolute', + transform: 'translate(-50%, -50%)', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + left: (x / 1000 * 100) + '%', + top: (y / 1000 * 100) + '%', + width: (r * 2 / 1000 * 100) + '%', + height: (r * 2 / 1000 * 100) + '%', + borderRadius: '50%', + backgroundColor: fillColor, + border: '1px solid rgba(255,255,255,0.2)', + cursor: 'default' + }, + title: name + '\n' + d3.format(',d')(value) + }); + + if (value > 1000) { + const nameEl = RC.createElement('div', { + style: { + color: 'white', + textAlign: 'center', + whiteSpace: 'nowrap', + fontSize: (r / 9) + 'px', + lineHeight: (r / 7) + 'px' + } + }, [name]); + + const valueEl = RC.createElement('div', { + style: { + color: 'white', + textAlign: 'center', + whiteSpace: 'nowrap', + opacity: 0.7, + fontSize: (r / 10) + 'px', + lineHeight: (r / 8) + 'px' + } + }, [d3.format(',d')(value)]); + + bubble.appendChild(nameEl); + bubble.appendChild(valueEl); + } + + container.appendChild(bubble); + }); +}`, + Call: templ.SafeScript(`__templ_initBubbleChart_9cee`, containerId, dataJSON), + CallInline: templ.SafeScriptInline(`__templ_initBubbleChart_9cee`, containerId, dataJSON), + } +} + +// SemiFilledAreaChart initialization script +func initSemiFilledAreaChart(containerId string, dataJSON string, lineColor string, areaFromColor string, areaToColor string) templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_initSemiFilledAreaChart_71b8`, + Function: `function __templ_initSemiFilledAreaChart_71b8(containerId, dataJSON, lineColor, areaFromColor, areaToColor){const container = document.getElementById(containerId); + if (!container || !window.d3) return; + + const data = JSON.parse(dataJSON).map(d => ({ + ...d, + date: new Date(d.date) + })); + const RC = window.RosenCharts; + + container.innerHTML = ''; + container.style.position = 'relative'; + container.style.height = '288px'; + container.style.width = '100%'; + + // Scales + const xScale = d3.scaleTime() + .domain([data[0].date, data[data.length - 1].date]) + .range([0, 100]); + + const yScale = d3.scaleLinear() + .domain([0, d3.max(data, d => d.value) || 0]) + .range([100, 0]); + + // Line generator + const line = d3.line() + .x(d => xScale(d.date)) + .y(d => yScale(d.value)) + .curve(d3.curveMonotoneX); + + // Area generator + const area = d3.area() + .x(d => xScale(d.date)) + .y0(yScale(0)) + .y1(d => yScale(d.value)) + .curve(d3.curveMonotoneX); + + // Chart inner + const chartInner = RC.createElement('div', { + style: { + position: 'absolute', + inset: 0, + height: '100%', + width: '100%', + overflow: 'visible' + } + }); + + // SVG + const svg = RC.createSVG('svg', { + viewBox: '0 0 100 100', + preserveAspectRatio: 'none', + style: 'width: 100%; height: 100%; overflow: visible;' + }); + + // Gradient + const defs = RC.createSVG('defs'); + const gradient = RC.createSVG('linearGradient', { + id: 'semi-filled-gradient-' + containerId, + x1: 0, x2: 0, y1: 0, y2: 1 + }); + + const stop1 = RC.createSVG('stop', { offset: '0%', 'stop-color': areaFromColor }); + const stop2 = RC.createSVG('stop', { offset: '100%', 'stop-color': areaToColor }); + + gradient.appendChild(stop1); + gradient.appendChild(stop2); + defs.appendChild(gradient); + svg.appendChild(defs); + + // Area path + const areaPath = RC.createSVG('path', { + d: area(data), + fill: 'url(#semi-filled-gradient-' + containerId + ')' + }); + svg.appendChild(areaPath); + + // Line path + const linePath = RC.createSVG('path', { + d: line(data), + fill: 'none', + stroke: lineColor, + 'stroke-width': '1.5', + 'vector-effect': 'non-scaling-stroke' + }); + svg.appendChild(linePath); + + chartInner.appendChild(svg); + + // X-axis labels + data.forEach((day, i) => { + if (i % 6 !== 0 || i === 0 || i >= data.length - 3) return; + + const label = RC.createElement('div', { + style: { + position: 'absolute', + left: xScale(day.date) + '%', + top: '90%', + fontSize: 'var(--wa-font-size-xs)', + color: 'var(--wa-color-neutral-500)', + transform: 'translateX(-50%)' + } + }, [day.date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })]); + + chartInner.appendChild(label); + }); + + container.appendChild(chartInner); + + // Y-axis labels + yScale.ticks(8).forEach((value, i) => { + if (i < 1) return; + + const label = RC.createElement('div', { + style: { + position: 'absolute', + top: yScale(value) + '%', + right: '3%', + fontSize: 'var(--wa-font-size-xs)', + fontVariantNumeric: 'tabular-nums', + color: 'var(--wa-color-neutral-400)', + transform: 'translateY(-50%)' + } + }, [value.toString()]); + + container.appendChild(label); + }); +}`, + Call: templ.SafeScript(`__templ_initSemiFilledAreaChart_71b8`, containerId, dataJSON, lineColor, areaFromColor, areaToColor), + CallInline: templ.SafeScriptInline(`__templ_initSemiFilledAreaChart_71b8`, containerId, dataJSON, lineColor, areaFromColor, areaToColor), + } +} + +// CandleChart component +func CandleChart(id string, data []OHLCData) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = initRosenCharts().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = initCandleChart(id, toJSON(data)).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// StackedAreaChart component +func StackedAreaChart(id string, data []AreaSeriesData) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var3 := templ.GetChildren(ctx) + if templ_7745c5c3_Var3 == nil { + templ_7745c5c3_Var3 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = initRosenCharts().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = initStackedAreaChart(id, toJSON(data)).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// BubbleChart component +func BubbleChart(id string, data []BubbleData) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var5 := templ.GetChildren(ctx) + if templ_7745c5c3_Var5 == nil { + templ_7745c5c3_Var5 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = initRosenCharts().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = initBubbleChart(id, toJSON(data)).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// SemiFilledAreaChart component with customizable colors +func SemiFilledAreaChart(id string, data []TimeSeriesData) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var7 := templ.GetChildren(ctx) + if templ_7745c5c3_Var7 == nil { + templ_7745c5c3_Var7 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = SemiFilledAreaChartWithColors(id, data, "#facc15", "rgba(234, 179, 8, 0.2)", "rgba(234, 179, 8, 0.05)").Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// SemiFilledAreaChart with custom colors +func SemiFilledAreaChartWithColors(id string, data []TimeSeriesData, lineColor string, areaFromColor string, areaToColor string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var8 := templ.GetChildren(ctx) + if templ_7745c5c3_Var8 == nil { + templ_7745c5c3_Var8 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = initRosenCharts().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = initSemiFilledAreaChart(id, toJSON(data), lineColor, areaFromColor, areaToColor).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// Chart card wrapper for consistent styling +func ChartCard(title string, subtitle string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var10 := templ.GetChildren(ctx) + if templ_7745c5c3_Var10 == nil { + templ_7745c5c3_Var10 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var11 string + templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(title) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/charts.templ`, Line: 695, Col: 38} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if subtitle != "" { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var12 string + templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(subtitle) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/charts.templ`, Line: 697, Col: 87} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templ_7745c5c3_Var10.Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate diff --git a/components/drawers.templ b/components/drawers.templ new file mode 100644 index 0000000..c6de425 --- /dev/null +++ b/components/drawers.templ @@ -0,0 +1,374 @@ +package components + +// TokenOption represents a token choice in dropdowns +type TokenOption struct { + Symbol string + Name string + Balance string + Color string + Initials string +} + +// DefaultTokenOptions returns the standard token options for drawers +func DefaultTokenOptions() []TokenOption { + return []TokenOption{ + {Symbol: "SNR", Name: "Sonr", Balance: "8,432.50", Color: "linear-gradient(135deg, #17c2ff, #0090ff)", Initials: "S"}, + {Symbol: "ETH", Name: "Ethereum", Balance: "2.847", Color: "#627eea", Initials: "E"}, + {Symbol: "USDC", Name: "USD Coin", Balance: "1,250.00", Color: "#2775ca", Initials: "U"}, + {Symbol: "AVAX", Name: "Avalanche", Balance: "24.83", Color: "#e84142", Initials: "A"}, + } +} + +// ReceiveDrawer component for receiving tokens +templ ReceiveDrawer(tokens []TokenOption, walletAddress string) { + +
+
+ +
+ +
+
+ @drawerStyles() +} + +// SendDrawer component for sending tokens +templ SendDrawer(tokens []TokenOption) { + +
+
+ +
+ +
+
+ @drawerStyles() +} + +// SwapDrawer component for swapping tokens +templ SwapDrawer(tokens []TokenOption) { + +
+
+ +
+ +
+
+ @drawerStyles() + @swapDirectionScript() +} + +// Script to handle swap direction button +script swapDirectionScript() { + document.getElementById('swap-direction-btn')?.addEventListener('click', function() { + this.style.transform = this.style.transform === 'rotate(180deg)' ? '' : 'rotate(180deg)'; + }); +} + +// Drawer-specific styles +templ drawerStyles() { + +} + +// AllDrawers renders all three drawers together for convenience +templ AllDrawers(tokens []TokenOption, walletAddress string) { + @ReceiveDrawer(tokens, walletAddress) + @SendDrawer(tokens) + @SwapDrawer(tokens) +} + +// DrawerTriggerScript provides the JavaScript to wire up drawer triggers +script drawerTriggerScript() { + // Open receive drawer + document.querySelectorAll('[data-drawer-open="receive"]').forEach(el => { + el.addEventListener('click', () => { + document.getElementById('receive-drawer').open = true; + }); + }); + + // Open send drawer + document.querySelectorAll('[data-drawer-open="send"]').forEach(el => { + el.addEventListener('click', () => { + document.getElementById('send-drawer').open = true; + }); + }); + + // Open swap drawer + document.querySelectorAll('[data-drawer-open="swap"]').forEach(el => { + el.addEventListener('click', () => { + document.getElementById('swap-drawer').open = true; + }); + }); +} + +// DrawerTriggers component to initialize drawer triggers +templ DrawerTriggers() { + @drawerTriggerScript() +} diff --git a/components/drawers_templ.go b/components/drawers_templ.go new file mode 100644 index 0000000..530db65 --- /dev/null +++ b/components/drawers_templ.go @@ -0,0 +1,564 @@ +// Code generated by templ - DO NOT EDIT. + +// templ: version: v0.3.977 +package components + +//lint:file-ignore SA4006 This context is only used if a nested component is present. + +import "github.com/a-h/templ" +import templruntime "github.com/a-h/templ/runtime" + +// TokenOption represents a token choice in dropdowns +type TokenOption struct { + Symbol string + Name string + Balance string + Color string + Initials string +} + +// DefaultTokenOptions returns the standard token options for drawers +func DefaultTokenOptions() []TokenOption { + return []TokenOption{ + {Symbol: "SNR", Name: "Sonr", Balance: "8,432.50", Color: "linear-gradient(135deg, #17c2ff, #0090ff)", Initials: "S"}, + {Symbol: "ETH", Name: "Ethereum", Balance: "2.847", Color: "#627eea", Initials: "E"}, + {Symbol: "USDC", Name: "USD Coin", Balance: "1,250.00", Color: "#2775ca", Initials: "U"}, + {Symbol: "AVAX", Name: "Avalanche", Balance: "24.83", Color: "#e84142", Initials: "A"}, + } +} + +// ReceiveDrawer component for receiving tokens +func ReceiveDrawer(tokens []TokenOption, walletAddress string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var1 := templ.GetChildren(ctx) + if templ_7745c5c3_Var1 == nil { + templ_7745c5c3_Var1 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, token := range tokens { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var5 string + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(token.Symbol) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/drawers.templ`, Line: 32, Col: 22} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, " - ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var6 string + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(token.Name) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/drawers.templ`, Line: 32, Col: 39} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "
Scan to receive tokens
Your Wallet Address
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var8 string + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(walletAddress) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/drawers.templ`, Line: 43, Col: 45} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "
Only send SNR tokens to this address. Sending other assets may result in permanent loss.
Close Share Address
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = drawerStyles().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// SendDrawer component for sending tokens +func SendDrawer(tokens []TokenOption) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var10 := templ.GetChildren(ctx) + if templ_7745c5c3_Var10 == nil { + templ_7745c5c3_Var10 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, token := range tokens { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var14 string + templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(token.Symbol) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/drawers.templ`, Line: 75, Col: 22} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, " - ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var15 string + templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(token.Balance) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/drawers.templ`, Line: 75, Col: 42} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, " available") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "
SNR
≈ $0.00 USD MAX
Slow Standard Fast
Estimated Gas ~0.001 SNR ($0.05)
Amount 0.00 SNR
Network Fee ~0.001 SNR
Total 0.001 SNR
Cancel Review Send
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = drawerStyles().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// SwapDrawer component for swapping tokens +func SwapDrawer(tokens []TokenOption) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var16 := templ.GetChildren(ctx) + if templ_7745c5c3_Var16 == nil { + templ_7745c5c3_Var16 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "
You Pay Balance: 2.847 ETH
ETH ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, token := range tokens { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var19 string + templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(token.Symbol) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/drawers.templ`, Line: 159, Col: 24} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
≈ $0.00
25% 50% MAX
You Receive Balance: 1,250.00 USDC
USDC ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + for _, token := range tokens { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, " ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var22 string + templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(token.Symbol) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `components/drawers.templ`, Line: 193, Col: 24} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "
≈ $0.00
Slippage Tolerance 0.1% 0.5% 1% Custom
minutes
Rate 1 ETH = 2,345.00 USDC
Price Impact < 0.01%
Minimum Received 0.00 USDC
Network Fee ~$2.50
Route ETH USDC
Price updates in real-time. Review carefully before confirming.
Cancel Review Swap
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = drawerStyles().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = swapDirectionScript().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// Script to handle swap direction button +func swapDirectionScript() templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_swapDirectionScript_d885`, + Function: `function __templ_swapDirectionScript_d885(){document.getElementById('swap-direction-btn')?.addEventListener('click', function() { + this.style.transform = this.style.transform === 'rotate(180deg)' ? '' : 'rotate(180deg)'; + }); +}`, + Call: templ.SafeScript(`__templ_swapDirectionScript_d885`), + CallInline: templ.SafeScriptInline(`__templ_swapDirectionScript_d885`), + } +} + +// Drawer-specific styles +func drawerStyles() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var23 := templ.GetChildren(ctx) + if templ_7745c5c3_Var23 == nil { + templ_7745c5c3_Var23 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// AllDrawers renders all three drawers together for convenience +func AllDrawers(tokens []TokenOption, walletAddress string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var24 := templ.GetChildren(ctx) + if templ_7745c5c3_Var24 == nil { + templ_7745c5c3_Var24 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = ReceiveDrawer(tokens, walletAddress).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = SendDrawer(tokens).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = SwapDrawer(tokens).Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +// DrawerTriggerScript provides the JavaScript to wire up drawer triggers +func drawerTriggerScript() templ.ComponentScript { + return templ.ComponentScript{ + Name: `__templ_drawerTriggerScript_084e`, + Function: `function __templ_drawerTriggerScript_084e(){// Open receive drawer + document.querySelectorAll('[data-drawer-open="receive"]').forEach(el => { + el.addEventListener('click', () => { + document.getElementById('receive-drawer').open = true; + }); + }); + + // Open send drawer + document.querySelectorAll('[data-drawer-open="send"]').forEach(el => { + el.addEventListener('click', () => { + document.getElementById('send-drawer').open = true; + }); + }); + + // Open swap drawer + document.querySelectorAll('[data-drawer-open="swap"]').forEach(el => { + el.addEventListener('click', () => { + document.getElementById('swap-drawer').open = true; + }); + }); +}`, + Call: templ.SafeScript(`__templ_drawerTriggerScript_084e`), + CallInline: templ.SafeScriptInline(`__templ_drawerTriggerScript_084e`), + } +} + +// DrawerTriggers component to initialize drawer triggers +func DrawerTriggers() templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var25 := templ.GetChildren(ctx) + if templ_7745c5c3_Var25 == nil { + templ_7745c5c3_Var25 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + templ_7745c5c3_Err = drawerTriggerScript().Render(ctx, templ_7745c5c3_Buffer) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil + }) +} + +var _ = templruntime.GeneratedTemplate