@stacksjs/ts-analytics 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +361 -0
  4. package/bin/cli.ts +169 -0
  5. package/dist/Analytics.d.ts +558 -0
  6. package/dist/api.d.ts +109 -0
  7. package/dist/batching.d.ts +93 -0
  8. package/dist/chunk-2mx7fq49.js +4 -0
  9. package/dist/chunk-3z29508k.js +204 -0
  10. package/dist/chunk-deephkz6.js +56 -0
  11. package/dist/chunk-j261vgyp.js +305 -0
  12. package/dist/chunk-xga17tz7.js +207 -0
  13. package/dist/config.d.ts +132 -0
  14. package/dist/dashboard/components/index.d.ts +80 -0
  15. package/dist/dashboard/composables/useAnalytics.d.ts +99 -0
  16. package/dist/dashboard/index.d.ts +110 -0
  17. package/dist/dashboard/types/index.d.ts +144 -0
  18. package/dist/dashboard/utils/index.d.ts +81 -0
  19. package/dist/dynamodb.d.ts +86 -0
  20. package/dist/funnels.d.ts +104 -0
  21. package/dist/geolocation.d.ts +96 -0
  22. package/dist/index.d.ts +371 -0
  23. package/dist/index.js +10211 -0
  24. package/dist/infrastructure/cdk.d.ts +60 -0
  25. package/dist/infrastructure/cloudformation.d.ts +44 -0
  26. package/dist/infrastructure/index.d.ts +45 -0
  27. package/dist/infrastructure/setup.d.ts +133 -0
  28. package/dist/integrations/cloudflare.d.ts +76 -0
  29. package/dist/integrations/hono.d.ts +60 -0
  30. package/dist/integrations/index.d.ts +24 -0
  31. package/dist/integrations/nuxt.d.ts +7 -0
  32. package/dist/integrations/nuxt.js +42 -0
  33. package/dist/integrations/runtime/use-ts-analytics.d.ts +18 -0
  34. package/dist/integrations/runtime/use-ts-analytics.js +17 -0
  35. package/dist/integrations/stx.d.ts +88 -0
  36. package/dist/integrations/stx.js +18 -0
  37. package/dist/lib/crypto-random.d.ts +4 -0
  38. package/dist/lib/salt.d.ts +16 -0
  39. package/dist/local.d.ts +56 -0
  40. package/dist/model-connector.d.ts +145 -0
  41. package/dist/models/AggregatedStats.d.ts +9 -0
  42. package/dist/models/CampaignStats.d.ts +9 -0
  43. package/dist/models/Conversion.d.ts +11 -0
  44. package/dist/models/CustomEvent.d.ts +11 -0
  45. package/dist/models/DeviceStats.d.ts +9 -0
  46. package/dist/models/EventStats.d.ts +9 -0
  47. package/dist/models/GeoStats.d.ts +9 -0
  48. package/dist/models/Goal.d.ts +9 -0
  49. package/dist/models/GoalStats.d.ts +9 -0
  50. package/dist/models/PageStats.d.ts +11 -0
  51. package/dist/models/PageView.d.ts +13 -0
  52. package/dist/models/RealtimeStats.d.ts +9 -0
  53. package/dist/models/ReferrerStats.d.ts +9 -0
  54. package/dist/models/Session.d.ts +11 -0
  55. package/dist/models/Site.d.ts +11 -0
  56. package/dist/models/index.d.ts +28 -0
  57. package/dist/models/types.d.ts +60 -0
  58. package/dist/sqs-buffering.d.ts +243 -0
  59. package/dist/stacks-integration.d.ts +159 -0
  60. package/dist/tracking-script.d.ts +71 -0
  61. package/dist/tracking.d.ts +17 -0
  62. package/dist/tracking.js +26 -0
  63. package/dist/types.d.ts +595 -0
  64. package/dist/utils/geolocation.d.ts +111 -0
  65. package/dist/utils/user-agent.d.ts +17 -0
  66. package/dist/version.d.ts +7 -0
  67. package/package.json +119 -0
  68. package/src/Analytics.ts +3349 -0
  69. package/src/api.ts +1286 -0
  70. package/src/assets/crosswind.css +2220 -0
  71. package/src/batching.ts +452 -0
  72. package/src/components/dashboard/index.ts +18 -0
  73. package/src/config.ts +456 -0
  74. package/src/dashboard/Dashboard.stx +1517 -0
  75. package/src/dashboard/components/AlertCard.stx +177 -0
  76. package/src/dashboard/components/AnalyticsDashboard.stx +354 -0
  77. package/src/dashboard/components/AnimatedNumber.stx +86 -0
  78. package/src/dashboard/components/BarChart.stx +220 -0
  79. package/src/dashboard/components/BrowserBreakdown.stx +98 -0
  80. package/src/dashboard/components/BrowsersTable.stx +125 -0
  81. package/src/dashboard/components/CampaignBreakdown.stx +163 -0
  82. package/src/dashboard/components/CampaignTable.stx +238 -0
  83. package/src/dashboard/components/CountryList.stx +101 -0
  84. package/src/dashboard/components/DataTable.stx +226 -0
  85. package/src/dashboard/components/DateRangePicker.stx +77 -0
  86. package/src/dashboard/components/DeviceBreakdown.stx +94 -0
  87. package/src/dashboard/components/DevicesTable.stx +163 -0
  88. package/src/dashboard/components/DonutChart.stories.ts +55 -0
  89. package/src/dashboard/components/DonutChart.stx +157 -0
  90. package/src/dashboard/components/EmptyState.stx +90 -0
  91. package/src/dashboard/components/EngagementMetrics.stx +183 -0
  92. package/src/dashboard/components/EventsSection.stx +192 -0
  93. package/src/dashboard/components/FilterBar.stx +104 -0
  94. package/src/dashboard/components/FullAnalyticsDashboard.stx +455 -0
  95. package/src/dashboard/components/FunnelChart.stx +142 -0
  96. package/src/dashboard/components/GeoTable.stx +337 -0
  97. package/src/dashboard/components/GoalsPanel.stx +109 -0
  98. package/src/dashboard/components/Header.stx +39 -0
  99. package/src/dashboard/components/HeatmapChart.stx +140 -0
  100. package/src/dashboard/components/LiveActivityFeed.stx +172 -0
  101. package/src/dashboard/components/MetricComparison.stx +106 -0
  102. package/src/dashboard/components/MiniStats.stx +96 -0
  103. package/src/dashboard/components/OSBreakdown.stx +124 -0
  104. package/src/dashboard/components/PageDetailCard.stx +102 -0
  105. package/src/dashboard/components/PagesTable.stx +127 -0
  106. package/src/dashboard/components/ProgressRing.stx +89 -0
  107. package/src/dashboard/components/RealtimeCounter.stories.ts +45 -0
  108. package/src/dashboard/components/RealtimeCounter.stx +46 -0
  109. package/src/dashboard/components/ReferrersTable.stx +180 -0
  110. package/src/dashboard/components/SparklineChart.stx +160 -0
  111. package/src/dashboard/components/StatCard.stories.ts +58 -0
  112. package/src/dashboard/components/StatCard.stx +90 -0
  113. package/src/dashboard/components/SummaryStats.stx +81 -0
  114. package/src/dashboard/components/TabNav.stx +66 -0
  115. package/src/dashboard/components/ThemeSwitcher.stx +124 -0
  116. package/src/dashboard/components/TimeSeriesChart.stx +106 -0
  117. package/src/dashboard/components/TopList.stories.ts +58 -0
  118. package/src/dashboard/components/TopList.stx +74 -0
  119. package/src/dashboard/components/TrendIndicator.stx +84 -0
  120. package/src/dashboard/components/heatmap/ClickHeatmap.stx +264 -0
  121. package/src/dashboard/components/heatmap/ElementClickList.stx +125 -0
  122. package/src/dashboard/components/heatmap/HeatmapControls.stx +125 -0
  123. package/src/dashboard/components/heatmap/HeatmapLegend.stx +69 -0
  124. package/src/dashboard/components/heatmap/PageHeatmap.stx +264 -0
  125. package/src/dashboard/components/heatmap/ScrollHeatmap.stx +127 -0
  126. package/src/dashboard/components/heatmap/index.ts +12 -0
  127. package/src/dashboard/components/index.ts +86 -0
  128. package/src/dashboard/composables/useAnalytics.ts +465 -0
  129. package/src/dashboard/demo/DemoApp.stx +370 -0
  130. package/src/dashboard/demo/index.ts +8 -0
  131. package/src/dashboard/demo/mockData.ts +234 -0
  132. package/src/dashboard/index.ts +117 -0
  133. package/src/dashboard/stx-shim.d.ts +4 -0
  134. package/src/dashboard/types/index.ts +203 -0
  135. package/src/dashboard/utils/index.ts +426 -0
  136. package/src/dynamodb.ts +344 -0
  137. package/src/funnels.ts +534 -0
  138. package/src/geolocation.ts +515 -0
  139. package/src/handlers/alerts.ts +328 -0
  140. package/src/handlers/annotations.ts +128 -0
  141. package/src/handlers/api-keys.ts +240 -0
  142. package/src/handlers/auth.ts +1020 -0
  143. package/src/handlers/authz.ts +137 -0
  144. package/src/handlers/collect.ts +724 -0
  145. package/src/handlers/data.ts +625 -0
  146. package/src/handlers/experiments.ts +138 -0
  147. package/src/handlers/funnels.ts +216 -0
  148. package/src/handlers/goals.ts +218 -0
  149. package/src/handlers/heatmaps.ts +272 -0
  150. package/src/handlers/index.ts +56 -0
  151. package/src/handlers/lib/read-cache.ts +63 -0
  152. package/src/handlers/misc.ts +486 -0
  153. package/src/handlers/oauth.ts +233 -0
  154. package/src/handlers/performance.ts +388 -0
  155. package/src/handlers/sessions.ts +413 -0
  156. package/src/handlers/sharing.ts +198 -0
  157. package/src/handlers/stats.ts +1368 -0
  158. package/src/handlers/team.ts +161 -0
  159. package/src/handlers/uptime.ts +283 -0
  160. package/src/handlers/views.ts +390 -0
  161. package/src/handlers/webhooks.ts +226 -0
  162. package/src/heatmap/index.ts +32 -0
  163. package/src/heatmap/tracking-script.ts +452 -0
  164. package/src/heatmap/types.ts +79 -0
  165. package/src/index.ts +387 -0
  166. package/src/infrastructure/cdk.ts +496 -0
  167. package/src/infrastructure/cloudformation.ts +595 -0
  168. package/src/infrastructure/index.ts +48 -0
  169. package/src/infrastructure/setup.ts +611 -0
  170. package/src/integrations/cloudflare.ts +732 -0
  171. package/src/integrations/hono.ts +589 -0
  172. package/src/integrations/index.ts +27 -0
  173. package/src/integrations/nuxt.ts +78 -0
  174. package/src/integrations/runtime/use-ts-analytics.ts +32 -0
  175. package/src/integrations/stx.ts +138 -0
  176. package/src/jobs/index.ts +127 -0
  177. package/src/lib/crypto-random.ts +41 -0
  178. package/src/lib/ddb-errors.ts +20 -0
  179. package/src/lib/dynamodb.ts +216 -0
  180. package/src/lib/email.ts +38 -0
  181. package/src/lib/ga-import.ts +471 -0
  182. package/src/lib/ga4-api.ts +244 -0
  183. package/src/lib/goals.ts +205 -0
  184. package/src/lib/index.ts +6 -0
  185. package/src/lib/ingest-counters.ts +123 -0
  186. package/src/lib/log.ts +36 -0
  187. package/src/lib/membership.ts +98 -0
  188. package/src/lib/plans.ts +90 -0
  189. package/src/lib/quota.ts +46 -0
  190. package/src/lib/rate-limit.ts +27 -0
  191. package/src/lib/rollups.ts +472 -0
  192. package/src/lib/salt.ts +97 -0
  193. package/src/lib/scheduler.ts +97 -0
  194. package/src/lib/significance.ts +66 -0
  195. package/src/lib/site-retention.ts +56 -0
  196. package/src/local.ts +360 -0
  197. package/src/model-connector.ts +616 -0
  198. package/src/models/AggregatedStats.ts +162 -0
  199. package/src/models/CampaignStats.ts +141 -0
  200. package/src/models/Conversion.ts +135 -0
  201. package/src/models/CustomEvent.ts +123 -0
  202. package/src/models/DeviceStats.ts +105 -0
  203. package/src/models/EventStats.ts +108 -0
  204. package/src/models/GeoStats.ts +112 -0
  205. package/src/models/Goal.ts +105 -0
  206. package/src/models/GoalStats.ts +106 -0
  207. package/src/models/PageStats.ts +152 -0
  208. package/src/models/PageView.ts +277 -0
  209. package/src/models/RealtimeStats.ts +96 -0
  210. package/src/models/ReferrerStats.ts +115 -0
  211. package/src/models/Session.ts +235 -0
  212. package/src/models/Site.ts +115 -0
  213. package/src/models/index.ts +50 -0
  214. package/src/models/orm/index.ts +2043 -0
  215. package/src/models/types.ts +71 -0
  216. package/src/router.ts +521 -0
  217. package/src/sqs-buffering.ts +806 -0
  218. package/src/stacks-integration.ts +527 -0
  219. package/src/tracking-script.ts +944 -0
  220. package/src/tracking.ts +27 -0
  221. package/src/types/analytics.ts +219 -0
  222. package/src/types/api.ts +75 -0
  223. package/src/types/bun-router.d.ts +15 -0
  224. package/src/types/dashboard.ts +62 -0
  225. package/src/types/index.ts +66 -0
  226. package/src/types/stx.d.ts +27 -0
  227. package/src/types/window.d.ts +101 -0
  228. package/src/types.ts +911 -0
  229. package/src/utils/cache.ts +148 -0
  230. package/src/utils/date.ts +118 -0
  231. package/src/utils/filters.ts +71 -0
  232. package/src/utils/geolocation.ts +323 -0
  233. package/src/utils/index.ts +9 -0
  234. package/src/utils/response.ts +180 -0
  235. package/src/utils/timezone-country.ts +242 -0
  236. package/src/utils/user-agent.ts +110 -0
  237. package/src/version.ts +7 -0
@@ -0,0 +1,370 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Analytics Dashboard Demo App
4
+ *
5
+ * Showcases all 31 dashboard components with mock data.
6
+ */
7
+ import { computed, onMounted, onUnmounted, ref } from 'vue'
8
+ import {
9
+ AlertCard,
10
+ AnimatedNumber,
11
+ AnalyticsDashboard,
12
+ BarChart,
13
+ BrowserBreakdown,
14
+ CampaignBreakdown,
15
+ CountryList,
16
+ DataTable,
17
+ DateRangePicker,
18
+ DeviceBreakdown,
19
+ DonutChart,
20
+ EmptyState,
21
+ EngagementMetrics,
22
+ FilterBar,
23
+ FunnelChart,
24
+ GoalsPanel,
25
+ HeatmapChart,
26
+ LiveActivityFeed,
27
+ MetricComparison,
28
+ MiniStats,
29
+ OSBreakdown,
30
+ PageDetailCard,
31
+ ProgressRing,
32
+ RealtimeCounter,
33
+ SparklineChart,
34
+ StatCard,
35
+ ThemeSwitcher,
36
+ TimeSeriesChart,
37
+ TopList,
38
+ TrendIndicator,
39
+ } from '../components'
40
+ import { mockData } from './mockData'
41
+
42
+ // Theme state
43
+ const isDark = ref(false)
44
+
45
+ // Date range state
46
+ const dateRange = ref({
47
+ start: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
48
+ end: new Date(),
49
+ })
50
+
51
+ // Active section for navigation
52
+ const activeSection = ref('overview')
53
+
54
+ // Realtime simulation
55
+ const realtimeCount = ref(42)
56
+ const activities = ref(mockData.activities)
57
+
58
+ let realtimeInterval: ReturnType<typeof setInterval> | null = null
59
+
60
+ onMounted(() => {
61
+ // Simulate realtime updates
62
+ realtimeInterval = setInterval(() => {
63
+ realtimeCount.value = Math.floor(Math.random() * 50) + 20
64
+
65
+ // Add random activity
66
+ if (Math.random() > 0.5) {
67
+ const types = ['pageview', 'event', 'conversion', 'session_start'] as const
68
+ const newActivity = {
69
+ id: `act-${Date.now()}`,
70
+ type: types[Math.floor(Math.random() * types.length)],
71
+ page: mockData.pages[Math.floor(Math.random() * mockData.pages.length)],
72
+ country: mockData.countries[Math.floor(Math.random() * mockData.countries.length)].name,
73
+ countryCode: mockData.countries[Math.floor(Math.random() * mockData.countries.length)].code,
74
+ device: (['desktop', 'mobile', 'tablet'] as const)[Math.floor(Math.random() * 3)],
75
+ timestamp: new Date(),
76
+ }
77
+ activities.value = [newActivity, ...activities.value.slice(0, 19)]
78
+ }
79
+ }, 3000)
80
+ })
81
+
82
+ onUnmounted(() => {
83
+ if (realtimeInterval) clearInterval(realtimeInterval)
84
+ })
85
+
86
+ const sections = [
87
+ { id: 'overview', label: 'Overview' },
88
+ { id: 'charts', label: 'Charts' },
89
+ { id: 'breakdowns', label: 'Breakdowns' },
90
+ { id: 'tables', label: 'Tables & Lists' },
91
+ { id: 'engagement', label: 'Engagement' },
92
+ { id: 'utilities', label: 'Utilities' },
93
+ ]
94
+
95
+ function handleDateChange(range: { start: Date, end: Date }) {
96
+ dateRange.value = range
97
+ }
98
+ </script>
99
+
100
+ <template>
101
+ <div class="min-h-screen" x-class="isDark ? 'dark bg-gray-900' : 'bg-gray-50'">
102
+ <!-- Header -->
103
+ <header class="sticky top-0 z-50 bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700">
104
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
105
+ <div class="flex items-center justify-between h-16">
106
+ <div class="flex items-center gap-4">
107
+ <h1 class="text-xl font-bold text-gray-900 dark:text-white">
108
+ Analytics Dashboard Demo
109
+ </h1>
110
+ <span class="px-2 py-1 text-xs font-medium bg-primary-100 text-primary-700 rounded-full">
111
+ 31 Components
112
+ </span>
113
+ </div>
114
+ <div class="flex items-center gap-4">
115
+ <DateRangePicker
116
+ :start="dateRange.start"
117
+ :end="dateRange.end"
118
+ @change="handleDateChange"
119
+ />
120
+ <ThemeSwitcher v-model="isDark" />
121
+ </div>
122
+ </div>
123
+ </div>
124
+ </header>
125
+
126
+ <!-- Navigation -->
127
+ <nav class="bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700">
128
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
129
+ <div class="flex gap-4 overflow-x-auto py-3">
130
+ <button
131
+ v-for="section in sections"
132
+ :key="section.id"
133
+ class="px-4 py-2 text-sm font-medium rounded-lg whitespace-nowrap transition-colors"
134
+ x-class="activeSection === section.id
135
+ ? 'bg-primary-100 text-primary-700 dark:bg-primary-900 dark:text-primary-300'
136
+ : 'text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700'"
137
+ @click="activeSection = section.id"
138
+ >
139
+ {{ section.label }}
140
+ </button>
141
+ </div>
142
+ </div>
143
+ </nav>
144
+
145
+ <!-- Main Content -->
146
+ <main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
147
+ <!-- Overview Section -->
148
+ <section v-show="activeSection === 'overview'" class="space-y-8">
149
+ <h2 class="text-lg font-semibold text-gray-900 dark:text-white">Overview Components</h2>
150
+
151
+ <!-- Realtime Counter -->
152
+ <div class="grid grid-cols-1 lg:grid-cols-4 gap-6">
153
+ <RealtimeCounter :count="realtimeCount" label="Active Visitors" />
154
+ </div>
155
+
156
+ <!-- Stat Cards -->
157
+ <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
158
+ <StatCard
159
+ v-for="stat in mockData.stats"
160
+ :key="stat.label"
161
+ :label="stat.label"
162
+ x-value="stat.value"
163
+ :change="stat.change"
164
+ :icon="stat.icon"
165
+ />
166
+ </div>
167
+
168
+ <!-- Mini Stats -->
169
+ <MiniStats :stats="mockData.miniStats" />
170
+
171
+ <!-- Animated Numbers -->
172
+ <div class="card p-6">
173
+ <h3 class="text-sm font-medium text-gray-900 dark:text-white mb-4">Animated Numbers</h3>
174
+ <div class="flex gap-8">
175
+ <div>
176
+ <div class="text-3xl font-bold text-gray-900 dark:text-white">
177
+ <AnimatedNumber x-value="12847" format="compact" />
178
+ </div>
179
+ <div class="text-sm text-gray-500">Total Users</div>
180
+ </div>
181
+ <div>
182
+ <div class="text-3xl font-bold text-green-600">
183
+ <AnimatedNumber x-value="0.0847" format="percentage" />
184
+ </div>
185
+ <div class="text-sm text-gray-500">Conversion Rate</div>
186
+ </div>
187
+ <div>
188
+ <div class="text-3xl font-bold text-primary-600">
189
+ <AnimatedNumber x-value="48293" format="currency" />
190
+ </div>
191
+ <div class="text-sm text-gray-500">Revenue</div>
192
+ </div>
193
+ </div>
194
+ </div>
195
+
196
+ <!-- Metric Comparison -->
197
+ <MetricComparison
198
+ :metrics="mockData.comparisonMetrics"
199
+ title="Period Comparison"
200
+ />
201
+ </section>
202
+
203
+ <!-- Charts Section -->
204
+ <section v-show="activeSection === 'charts'" class="space-y-8">
205
+ <h2 class="text-lg font-semibold text-gray-900 dark:text-white">Chart Components</h2>
206
+
207
+ <!-- Time Series -->
208
+ <TimeSeriesChart
209
+ :data="mockData.timeSeries"
210
+ title="Visitors Over Time"
211
+ x-height="300"
212
+ />
213
+
214
+ <!-- Chart Grid -->
215
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
216
+ <DonutChart
217
+ :data="mockData.donutData"
218
+ title="Traffic Sources"
219
+ />
220
+ <BarChart
221
+ :data="mockData.barData"
222
+ title="Top Pages"
223
+ />
224
+ </div>
225
+
226
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
227
+ <FunnelChart
228
+ :steps="mockData.funnelSteps"
229
+ title="Conversion Funnel"
230
+ />
231
+ <HeatmapChart
232
+ :data="mockData.heatmapData"
233
+ title="Activity by Hour"
234
+ />
235
+ </div>
236
+
237
+ <!-- Sparklines -->
238
+ <div class="card p-6">
239
+ <h3 class="text-sm font-medium text-gray-900 dark:text-white mb-4">Sparkline Charts</h3>
240
+ <div class="grid grid-cols-2 lg:grid-cols-4 gap-6">
241
+ <div v-for="spark in mockData.sparklines" :key="spark.label">
242
+ <div class="text-sm text-gray-500 mb-1">{{ spark.label }}</div>
243
+ <SparklineChart :data="spark.data" :color="spark.color" x-height="40" />
244
+ </div>
245
+ </div>
246
+ </div>
247
+
248
+ <!-- Progress Rings -->
249
+ <div class="card p-6">
250
+ <h3 class="text-sm font-medium text-gray-900 dark:text-white mb-4">Progress Rings</h3>
251
+ <div class="flex gap-8">
252
+ <ProgressRing x-value="0.75" label="Goal Progress" :size="100" />
253
+ <ProgressRing x-value="0.42" label="Bounce Rate" color="#ef4444" :size="100" />
254
+ <ProgressRing x-value="0.91" label="Uptime" color="#10b981" :size="100" />
255
+ </div>
256
+ </div>
257
+ </section>
258
+
259
+ <!-- Breakdowns Section -->
260
+ <section v-show="activeSection === 'breakdowns'" class="space-y-8">
261
+ <h2 class="text-lg font-semibold text-gray-900 dark:text-white">Breakdown Components</h2>
262
+
263
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
264
+ <DeviceBreakdown :data="mockData.devices" />
265
+ <BrowserBreakdown :browsers="mockData.browsers" />
266
+ <OSBreakdown :data="mockData.operatingSystems" />
267
+ </div>
268
+
269
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
270
+ <CountryList :countries="mockData.countryList" />
271
+ <CampaignBreakdown :campaigns="mockData.campaigns" />
272
+ </div>
273
+ </section>
274
+
275
+ <!-- Tables Section -->
276
+ <section v-show="activeSection === 'tables'" class="space-y-8">
277
+ <h2 class="text-lg font-semibold text-gray-900 dark:text-white">Table & List Components</h2>
278
+
279
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
280
+ <TopList
281
+ :items="mockData.topPages"
282
+ title="Top Pages"
283
+ value-label="Views"
284
+ />
285
+ <TopList
286
+ :items="mockData.topReferrers"
287
+ title="Top Referrers"
288
+ value-label="Visitors"
289
+ />
290
+ </div>
291
+
292
+ <DataTable
293
+ :columns="mockData.tableColumns"
294
+ :rows="mockData.tableRows"
295
+ title="Detailed Analytics"
296
+ />
297
+
298
+ <PageDetailCard :page="mockData.pageDetail" />
299
+ </section>
300
+
301
+ <!-- Engagement Section -->
302
+ <section v-show="activeSection === 'engagement'" class="space-y-8">
303
+ <h2 class="text-lg font-semibold text-gray-900 dark:text-white">Engagement Components</h2>
304
+
305
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
306
+ <GoalsPanel :goals="mockData.goals" />
307
+ <EngagementMetrics :metrics="mockData.engagementMetrics" />
308
+ </div>
309
+
310
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
311
+ <LiveActivityFeed :activities="activities" />
312
+ <AlertCard
313
+ v-for="alert in mockData.alerts"
314
+ :key="alert.id"
315
+ :title="alert.title"
316
+ :message="alert.message"
317
+ :type="alert.type"
318
+ :timestamp="alert.timestamp"
319
+ />
320
+ </div>
321
+ </section>
322
+
323
+ <!-- Utilities Section -->
324
+ <section v-show="activeSection === 'utilities'" class="space-y-8">
325
+ <h2 class="text-lg font-semibold text-gray-900 dark:text-white">Utility Components</h2>
326
+
327
+ <!-- Filter Bar -->
328
+ <FilterBar
329
+ :filters="mockData.filters"
330
+ @change="(f) => console.log('Filters changed:', f)"
331
+ />
332
+
333
+ <!-- Trend Indicators -->
334
+ <div class="card p-6">
335
+ <h3 class="text-sm font-medium text-gray-900 dark:text-white mb-4">Trend Indicators</h3>
336
+ <div class="flex gap-8">
337
+ <TrendIndicator x-value="0.15" label="vs last week" />
338
+ <TrendIndicator x-value="-0.08" label="vs last month" />
339
+ <TrendIndicator x-value="0" label="vs yesterday" />
340
+ </div>
341
+ </div>
342
+
343
+ <!-- Empty States -->
344
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
345
+ <EmptyState
346
+ title="No data available"
347
+ message="Start tracking to see your analytics data here."
348
+ icon="chart"
349
+ />
350
+ <EmptyState
351
+ title="No visitors yet"
352
+ message="Share your site to start getting visitors."
353
+ icon="users"
354
+ />
355
+ <EmptyState
356
+ title="No goals configured"
357
+ message="Set up conversion goals to track success."
358
+ icon="target"
359
+ action-label="Create Goal"
360
+ @action="() => console.log('Create goal clicked')"
361
+ />
362
+ </div>
363
+ </section>
364
+ </main>
365
+ </div>
366
+ </template>
367
+
368
+ <style>
369
+ @import 'uno.css';
370
+ </style>
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Analytics Dashboard Demo
3
+ *
4
+ * Demo application showcasing all 31 dashboard components.
5
+ */
6
+
7
+ export { default as DemoApp } from './DemoApp.stx'
8
+ export { mockData } from './mockData'
@@ -0,0 +1,234 @@
1
+ /**
2
+ * Mock Data for Dashboard Demo
3
+ *
4
+ * Realistic sample data for showcasing all dashboard components.
5
+ */
6
+
7
+ export const mockData = {
8
+ // Stat Cards
9
+ stats: [
10
+ { label: 'Total Visitors', value: 24847, change: 0.12, icon: 'users' },
11
+ { label: 'Page Views', value: 89234, change: 0.08, icon: 'eye' },
12
+ { label: 'Bounce Rate', value: '42.3%', change: -0.05, icon: 'arrow-down' },
13
+ { label: 'Avg. Duration', value: '3m 24s', change: 0.15, icon: 'clock' },
14
+ ],
15
+
16
+ // Mini Stats
17
+ miniStats: [
18
+ { label: 'Sessions', value: 12847, change: 0.08 },
19
+ { label: 'Users', value: 8234, change: 0.12 },
20
+ { label: 'New Users', value: 3421, change: 0.24 },
21
+ { label: 'Events', value: 45892, change: -0.03 },
22
+ ],
23
+
24
+ // Comparison Metrics
25
+ comparisonMetrics: [
26
+ { label: 'Visitors', current: 24847, previous: 22134, format: 'number' as const },
27
+ { label: 'Bounce Rate', current: 0.423, previous: 0.456, format: 'percentage' as const, inverse: true },
28
+ { label: 'Avg. Duration', current: 204000, previous: 178000, format: 'duration' as const },
29
+ { label: 'Conversions', current: 847, previous: 723, format: 'number' as const },
30
+ ],
31
+
32
+ // Time Series
33
+ timeSeries: Array.from({ length: 30 }, (_, i) => {
34
+ const date = new Date()
35
+ date.setDate(date.getDate() - (29 - i))
36
+ return {
37
+ date: date.toISOString().slice(0, 10),
38
+ visitors: Math.floor(Math.random() * 500) + 800,
39
+ pageViews: Math.floor(Math.random() * 1500) + 2000,
40
+ }
41
+ }),
42
+
43
+ // Donut Chart
44
+ donutData: [
45
+ { label: 'Direct', value: 4234, color: '#3b82f6' },
46
+ { label: 'Organic Search', value: 3456, color: '#10b981' },
47
+ { label: 'Social', value: 2134, color: '#8b5cf6' },
48
+ { label: 'Referral', value: 1234, color: '#f59e0b' },
49
+ { label: 'Email', value: 567, color: '#ef4444' },
50
+ ],
51
+
52
+ // Bar Chart
53
+ barData: [
54
+ { label: '/home', value: 12847 },
55
+ { label: '/products', value: 8923 },
56
+ { label: '/about', value: 5634 },
57
+ { label: '/blog', value: 4521 },
58
+ { label: '/contact', value: 2134 },
59
+ ],
60
+
61
+ // Funnel Steps
62
+ funnelSteps: [
63
+ { label: 'Visitors', value: 10000, color: '#3b82f6' },
64
+ { label: 'Product Views', value: 6500, color: '#8b5cf6' },
65
+ { label: 'Add to Cart', value: 3200, color: '#f59e0b' },
66
+ { label: 'Checkout', value: 1800, color: '#10b981' },
67
+ { label: 'Purchase', value: 850, color: '#ef4444' },
68
+ ],
69
+
70
+ // Heatmap Data (7 days x 24 hours)
71
+ heatmapData: Array.from({ length: 7 }, (_, day) =>
72
+ Array.from({ length: 24 }, (_, hour) => ({
73
+ day,
74
+ hour,
75
+ value: Math.floor(Math.random() * 100),
76
+ }))).flat(),
77
+
78
+ // Sparklines
79
+ sparklines: [
80
+ { label: 'Visitors', data: Array.from({ length: 14 }, () => Math.floor(Math.random() * 100) + 50), color: '#3b82f6' },
81
+ { label: 'Conversions', data: Array.from({ length: 14 }, () => Math.floor(Math.random() * 30) + 10), color: '#10b981' },
82
+ { label: 'Bounce Rate', data: Array.from({ length: 14 }, () => Math.floor(Math.random() * 20) + 30), color: '#ef4444' },
83
+ { label: 'Duration', data: Array.from({ length: 14 }, () => Math.floor(Math.random() * 60) + 120), color: '#8b5cf6' },
84
+ ],
85
+
86
+ // Device Breakdown
87
+ devices: [
88
+ { type: 'desktop', count: 12847, percentage: 0.52 },
89
+ { type: 'mobile', count: 9234, percentage: 0.37 },
90
+ { type: 'tablet', count: 2766, percentage: 0.11 },
91
+ ],
92
+
93
+ // Browser Breakdown
94
+ browsers: [
95
+ { name: 'Chrome', count: 14523, percentage: 0.58, icon: 'chrome' },
96
+ { name: 'Safari', count: 5234, percentage: 0.21, icon: 'safari' },
97
+ { name: 'Firefox', count: 2847, percentage: 0.11, icon: 'firefox' },
98
+ { name: 'Edge', count: 1823, percentage: 0.07, icon: 'edge' },
99
+ { name: 'Other', count: 420, percentage: 0.03, icon: 'globe' },
100
+ ],
101
+
102
+ // OS Breakdown
103
+ operatingSystems: [
104
+ { name: 'Windows', count: 10234, percentage: 0.41 },
105
+ { name: 'macOS', count: 7823, percentage: 0.31 },
106
+ { name: 'iOS', count: 4234, percentage: 0.17 },
107
+ { name: 'Android', count: 2134, percentage: 0.09 },
108
+ { name: 'Linux', count: 422, percentage: 0.02 },
109
+ ],
110
+
111
+ // Country List
112
+ countryList: [
113
+ { name: 'United States', code: 'US', visitors: 8234, percentage: 0.33 },
114
+ { name: 'United Kingdom', code: 'GB', visitors: 3456, percentage: 0.14 },
115
+ { name: 'Germany', code: 'DE', visitors: 2847, percentage: 0.11 },
116
+ { name: 'France', code: 'FR', visitors: 2134, percentage: 0.09 },
117
+ { name: 'Canada', code: 'CA', visitors: 1823, percentage: 0.07 },
118
+ { name: 'Australia', code: 'AU', visitors: 1234, percentage: 0.05 },
119
+ { name: 'Japan', code: 'JP', visitors: 987, percentage: 0.04 },
120
+ { name: 'Brazil', code: 'BR', visitors: 756, percentage: 0.03 },
121
+ ],
122
+
123
+ // Campaigns
124
+ campaigns: [
125
+ { name: 'Summer Sale', source: 'google', medium: 'cpc', visitors: 3456, conversions: 234, conversionRate: 0.068, revenue: 12340 },
126
+ { name: 'Newsletter', source: 'email', medium: 'email', visitors: 2134, conversions: 187, conversionRate: 0.088, revenue: 8923 },
127
+ { name: 'Social Launch', source: 'facebook', medium: 'social', visitors: 1823, conversions: 98, conversionRate: 0.054, revenue: 4521 },
128
+ { name: 'Retargeting', source: 'google', medium: 'display', visitors: 1234, conversions: 76, conversionRate: 0.062, revenue: 3456 },
129
+ ],
130
+
131
+ // Top Pages
132
+ topPages: [
133
+ { name: '/home', value: 12847, change: 0.12 },
134
+ { name: '/products', value: 8923, change: 0.08 },
135
+ { name: '/products/widget', value: 5634, change: 0.24 },
136
+ { name: '/about', value: 4521, change: -0.05 },
137
+ { name: '/blog', value: 3847, change: 0.15 },
138
+ { name: '/contact', value: 2134, change: 0.03 },
139
+ { name: '/pricing', value: 1823, change: 0.18 },
140
+ { name: '/docs', value: 1456, change: 0.09 },
141
+ ],
142
+
143
+ // Top Referrers
144
+ topReferrers: [
145
+ { name: 'google.com', value: 8234, change: 0.15 },
146
+ { name: 'twitter.com', value: 3456, change: 0.22 },
147
+ { name: 'facebook.com', value: 2847, change: -0.08 },
148
+ { name: 'linkedin.com', value: 1823, change: 0.12 },
149
+ { name: 'reddit.com', value: 1234, change: 0.45 },
150
+ { name: 'github.com', value: 987, change: 0.08 },
151
+ ],
152
+
153
+ // Table Data
154
+ tableColumns: [
155
+ { key: 'page', label: 'Page', sortable: true },
156
+ { key: 'visitors', label: 'Visitors', sortable: true, align: 'right' as const },
157
+ { key: 'pageViews', label: 'Page Views', sortable: true, align: 'right' as const },
158
+ { key: 'bounceRate', label: 'Bounce Rate', sortable: true, align: 'right' as const },
159
+ { key: 'avgDuration', label: 'Avg. Duration', sortable: true, align: 'right' as const },
160
+ ],
161
+ tableRows: [
162
+ { page: '/home', visitors: 12847, pageViews: 24532, bounceRate: '38.2%', avgDuration: '2m 45s' },
163
+ { page: '/products', visitors: 8923, pageViews: 15234, bounceRate: '42.1%', avgDuration: '3m 12s' },
164
+ { page: '/about', visitors: 5634, pageViews: 7823, bounceRate: '52.3%', avgDuration: '1m 34s' },
165
+ { page: '/blog', visitors: 4521, pageViews: 12847, bounceRate: '35.6%', avgDuration: '4m 56s' },
166
+ { page: '/contact', visitors: 2134, pageViews: 3456, bounceRate: '48.7%', avgDuration: '1m 23s' },
167
+ ],
168
+
169
+ // Page Detail
170
+ pageDetail: {
171
+ path: '/products/widget-pro',
172
+ title: 'Widget Pro - Premium Analytics Widget',
173
+ pageViews: 12847,
174
+ uniquePageViews: 8923,
175
+ avgTimeOnPage: 234000,
176
+ bounceRate: 0.382,
177
+ exitRate: 0.456,
178
+ entrances: 5634,
179
+ exits: 5823,
180
+ change: 0.15,
181
+ },
182
+
183
+ // Goals
184
+ goals: [
185
+ { id: '1', name: 'Sign Up', conversions: 847, conversionRate: 0.034, value: 8470, target: 1000 },
186
+ { id: '2', name: 'Purchase', conversions: 234, conversionRate: 0.0094, value: 23400, target: 300 },
187
+ { id: '3', name: 'Newsletter', conversions: 1234, conversionRate: 0.05, value: 0, target: 1500 },
188
+ { id: '4', name: 'Contact Form', conversions: 456, conversionRate: 0.018, value: 0, target: 500 },
189
+ ],
190
+
191
+ // Engagement Metrics
192
+ engagementMetrics: {
193
+ avgSessionDuration: 234000,
194
+ pagesPerSession: 3.4,
195
+ bounceRate: 0.423,
196
+ returningVisitors: 0.34,
197
+ newVisitors: 0.66,
198
+ engagedSessions: 0.72,
199
+ },
200
+
201
+ // Live Activity
202
+ activities: [
203
+ { id: '1', type: 'pageview' as const, page: '/products', country: 'United States', countryCode: 'US', device: 'desktop' as const, timestamp: new Date() },
204
+ { id: '2', type: 'conversion' as const, eventName: 'Sign Up', country: 'Germany', countryCode: 'DE', device: 'mobile' as const, timestamp: new Date(Date.now() - 15000), value: 10 },
205
+ { id: '3', type: 'event' as const, eventName: 'Add to Cart', country: 'United Kingdom', countryCode: 'GB', device: 'tablet' as const, timestamp: new Date(Date.now() - 30000) },
206
+ { id: '4', type: 'session_start' as const, country: 'France', countryCode: 'FR', device: 'desktop' as const, timestamp: new Date(Date.now() - 45000) },
207
+ { id: '5', type: 'pageview' as const, page: '/blog/analytics-tips', country: 'Canada', countryCode: 'CA', device: 'mobile' as const, timestamp: new Date(Date.now() - 60000) },
208
+ ],
209
+
210
+ // Alerts
211
+ alerts: [
212
+ { id: '1', title: 'Traffic Spike', message: 'Visitor count increased by 150% in the last hour.', type: 'success' as const, timestamp: new Date() },
213
+ { id: '2', title: 'High Bounce Rate', message: '/landing page has 75% bounce rate today.', type: 'warning' as const, timestamp: new Date(Date.now() - 3600000) },
214
+ ],
215
+
216
+ // Filters
217
+ filters: [
218
+ { id: 'device', label: 'Device', options: ['All', 'Desktop', 'Mobile', 'Tablet'], value: 'All' },
219
+ { id: 'country', label: 'Country', options: ['All', 'United States', 'United Kingdom', 'Germany'], value: 'All' },
220
+ { id: 'source', label: 'Source', options: ['All', 'Direct', 'Organic', 'Social', 'Referral'], value: 'All' },
221
+ ],
222
+
223
+ // Helper arrays
224
+ pages: ['/home', '/products', '/about', '/blog', '/contact', '/pricing', '/docs'],
225
+ countries: [
226
+ { name: 'United States', code: 'US' },
227
+ { name: 'United Kingdom', code: 'GB' },
228
+ { name: 'Germany', code: 'DE' },
229
+ { name: 'France', code: 'FR' },
230
+ { name: 'Canada', code: 'CA' },
231
+ ],
232
+ }
233
+
234
+ export default mockData