@git-stats-components/vue 1.0.0 → 1.0.2

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.
package/README.md ADDED
@@ -0,0 +1,272 @@
1
+ # @git-stats-components/vue
2
+
3
+ Beautiful GitHub/GitLab/Bitbucket contribution graphs for Vue 3.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @git-stats-components/vue
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```vue
14
+ <script setup>
15
+ import { ContributionGraph, StatsBreakdown } from '@git-stats-components/vue'
16
+ import '@git-stats-components/vue/style.css'
17
+ </script>
18
+
19
+ <template>
20
+ <div>
21
+ <ContributionGraph data-url="/data/git-stats.json" color-scheme="green" />
22
+ <StatsBreakdown data-url="/data/git-stats.json" />
23
+ </div>
24
+ </template>
25
+ ```
26
+
27
+ ## Components
28
+
29
+ ### ContributionGraph
30
+
31
+ GitHub-style contribution heatmap.
32
+
33
+ **Props:**
34
+
35
+ - `dataUrl` (string) - Path to stats JSON file (default: `/data/git-stats.json`)
36
+ - `profileIndex` (number) - Which profile to display (default: 0)
37
+ - `colorScheme` ('green' | 'blue' | 'purple' | 'orange') - Color theme (default: 'green')
38
+ - `showSettings` (boolean) - Show color scheme dropdown (default: true)
39
+ - `cacheTTL` (number) - Cache duration in milliseconds
40
+
41
+ **Events:**
42
+
43
+ - `@day-click` - Emitted when a day is clicked (`{ date: string, count: number }`)
44
+ - `@color-scheme-change` - Emitted when color scheme changes
45
+
46
+ **Example:**
47
+
48
+ ```vue
49
+ <ContributionGraph
50
+ data-url="/data/git-stats.json"
51
+ :profile-index="0"
52
+ color-scheme="blue"
53
+ :show-settings="true"
54
+ @day-click="handleDayClick"
55
+ @color-scheme-change="handleColorChange"
56
+ />
57
+ ```
58
+
59
+ ### StatsBreakdown
60
+
61
+ Project and commit count statistics.
62
+
63
+ **Props:**
64
+
65
+ - `dataUrl` (string) - Path to stats JSON file
66
+ - `profileIndexes` (number[]) - Which profiles to aggregate (default: [])
67
+ - `experienceData` (ExperienceEntry[]) - Work experience for years calculation
68
+ - `showCustomStat` (boolean) - Show custom stat (default: true)
69
+ - `customStatCalculator` (function) - Custom stat calculation function
70
+
71
+ **Slots:**
72
+
73
+ - `icon-experience` - Custom icon for experience stat
74
+ - `icon-projects` - Custom icon for projects stat
75
+ - `icon-commits` - Custom icon for commits stat
76
+ - `icon-custom` - Custom icon for custom stat
77
+ - `custom-stat-label` - Custom label for custom stat
78
+
79
+ **Example:**
80
+
81
+ ```vue
82
+ <script setup>
83
+ const experienceData = [
84
+ {
85
+ startDate: '2020-01-01',
86
+ endDate: null, // current
87
+ skills: ['JavaScript', 'Vue', 'TypeScript']
88
+ }
89
+ ]
90
+
91
+ function calculatePizzas({ projects, commits, years }) {
92
+ return (projects * 2 + commits * 0.5 + years * 100).toFixed(0)
93
+ }
94
+ </script>
95
+
96
+ <template>
97
+ <StatsBreakdown
98
+ data-url="/data/git-stats.json"
99
+ :experience-data="experienceData"
100
+ :show-custom-stat="true"
101
+ :custom-stat-calculator="calculatePizzas"
102
+ >
103
+ <template #icon-custom>🍕</template>
104
+ <template #custom-stat-label>Pizzas Ordered</template>
105
+ </StatsBreakdown>
106
+ </template>
107
+ ```
108
+
109
+ ## Using the Composable
110
+
111
+ ```vue
112
+ <script setup>
113
+ import { useGitStats } from '@git-stats-components/vue'
114
+
115
+ const { data, loading, error, dataSourceText, lastUpdatedText, isDummy } = useGitStats({
116
+ dataUrl: '/data/git-stats.json',
117
+ cacheTTL: 3600000, // 1 hour
118
+ useStaleCache: true
119
+ })
120
+ </script>
121
+
122
+ <template>
123
+ <div v-if="loading">Loading...</div>
124
+ <div v-else-if="error">Error: {{ error.message }}</div>
125
+ <div v-else>
126
+ <p>{{ dataSourceText }}</p>
127
+ <p>{{ lastUpdatedText }}</p>
128
+ <pre>{{ JSON.stringify(data, null, 2) }}</pre>
129
+ </div>
130
+ </template>
131
+ ```
132
+
133
+ ## TypeScript Support
134
+
135
+ Full TypeScript support with exported types:
136
+
137
+ ```typescript
138
+ import type {
139
+ GitStatsData,
140
+ ColorScheme,
141
+ Platform,
142
+ ExperienceEntry,
143
+ CustomStatCalculator
144
+ } from '@git-stats-components/vue'
145
+
146
+ const colorScheme: ColorScheme = 'green'
147
+
148
+ const experienceData: ExperienceEntry[] = [
149
+ {
150
+ startDate: '2020-01-01',
151
+ endDate: null,
152
+ skills: ['JavaScript', 'Vue', 'TypeScript']
153
+ }
154
+ ]
155
+
156
+ const customCalculator: CustomStatCalculator = ({ projects, commits, years }) => {
157
+ return (projects * 2 + commits * 0.5).toFixed(0)
158
+ }
159
+ ```
160
+
161
+ ## Plugin Usage
162
+
163
+ Register globally in your Vue app:
164
+
165
+ ```typescript
166
+ import { createApp } from 'vue'
167
+ import VueGitStats from '@git-stats-components/vue'
168
+ import '@git-stats-components/vue/style.css'
169
+ import App from './App.vue'
170
+
171
+ const app = createApp(App)
172
+ app.use(VueGitStats)
173
+ app.mount('#app')
174
+ ```
175
+
176
+ Then use without imports:
177
+
178
+ ```vue
179
+ <template>
180
+ <ContributionGraph data-url="/data/git-stats.json" />
181
+ <StatsBreakdown data-url="/data/git-stats.json" />
182
+ </template>
183
+ ```
184
+
185
+ ## Nuxt 3 Usage
186
+
187
+ ```vue
188
+ <!-- pages/index.vue -->
189
+ <script setup lang="ts">
190
+ import { ContributionGraph, StatsBreakdown } from '@git-stats-components/vue'
191
+ import '@git-stats-components/vue/style.css'
192
+
193
+ const experienceData = [
194
+ {
195
+ startDate: '2020-01-01',
196
+ endDate: null,
197
+ skills: ['JavaScript', 'Vue', 'Nuxt']
198
+ }
199
+ ]
200
+ </script>
201
+
202
+ <template>
203
+ <div>
204
+ <ContributionGraph data-url="/data/git-stats.json" />
205
+ <StatsBreakdown data-url="/data/git-stats.json" :experience-data="experienceData" />
206
+ </div>
207
+ </template>
208
+ ```
209
+
210
+ ## Custom Styling
211
+
212
+ Override CSS variables:
213
+
214
+ ```css
215
+ .git-contribution-graph {
216
+ --graph-bg: #0d1117;
217
+ --graph-text: #e6edf3;
218
+ --graph-border: #30363d;
219
+ }
220
+
221
+ /* Or target specific classes */
222
+ .contribution-day.level-4.green {
223
+ background-color: #00ff00 !important;
224
+ }
225
+ ```
226
+
227
+ ## Data Setup
228
+
229
+ ## Quick Setup
230
+
231
+ ### 1. Initialize in your project
232
+
233
+ ```bash
234
+ npx @git-stats-components/vue init
235
+ ```
236
+
237
+ This creates:
238
+ - `git-stats.config.js` - Configuration file
239
+ - `.github/workflows/update-git-stats.yml` - GitHub Action workflow
240
+ - `public/data/` - Directory for stats data
241
+
242
+ ### 2. Configure your profiles
243
+
244
+ Edit `git-stats.config.js`:
245
+
246
+ ```javascript
247
+ export default {
248
+ profiles: [
249
+ {
250
+ username: 'your-github-username',
251
+ platform: 'github',
252
+ tokenSecret: 'GITHUB_TOKEN'
253
+ }
254
+ ],
255
+ dataPath: 'public/data/git-stats.json',
256
+ schedule: '0 2 * * *' // Daily at 2 AM UTC
257
+ }
258
+ ```
259
+
260
+ ### 3. Add GitHub Secrets
261
+
262
+ Go to **Settings → Secrets and variables → Actions** and add your tokens.
263
+
264
+ ### 4. Done!
265
+
266
+ The GitHub Action will fetch your stats daily and save them to the JSON file. Your components will load this data automatically.
267
+
268
+ For more details, see the main [git-stats-components](https://github.com/derekjj/git-stats-components) repository.
269
+
270
+ ## License
271
+
272
+ MIT © Derek Johnston
@@ -633,4 +633,4 @@ export {
633
633
  fe as saveDummyDataToFile,
634
634
  K as useGitStats
635
635
  };
636
- //# sourceMappingURL=vue-git-stats.es.js.map
636
+ //# sourceMappingURL=vue.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vue.es.js","sources":["../../core/src/api/fetchGitStats.ts","../../core/src/utils/generateDummyData.js","../../core/src/index.ts","../src/composables/useGitStats.ts","../src/components/ContributionGraph.vue","../src/components/StatsBreakdown.vue","../src/index.ts"],"sourcesContent":["import type { GitStatsData } from '../types'\r\n\r\nexport async function fetchGitStats(url: string): Promise<GitStatsData> {\r\n\tconst response = await fetch(url)\r\n\tif (!response.ok) {\r\n\t\tthrow new Error(`Failed to fetch git stats: ${response.statusText}`)\r\n\t}\r\n\treturn response.json()\r\n}\r\n","/**\n * Generate realistic dummy data for testing and development\n */\n\n/**\n * Generate dummy contribution data (53 weeks)\n */\nexport function generateDummyContributions() {\n\tconst weeks = []\n\tconst now = new Date()\n\n\t// Get the Sunday that starts the week containing today\n\tconst endDate = new Date(now)\n\tendDate.setDate(endDate.getDate() - endDate.getDay())\n\n\t// Go back exactly 52 weeks\n\tconst startDate = new Date(endDate)\n\tstartDate.setDate(startDate.getDate() - 52 * 7)\n\n\tconst currentDate = new Date(startDate)\n\n\tfor (let week = 0; week < 53; week++) {\n\t\tconst weekData = {\n\t\t\tweekStart: new Date(currentDate).toISOString().split('T')[0],\n\t\t\tcontributionDays: [],\n\t\t}\n\n\t\tfor (let day = 0; day < 7; day++) {\n\t\t\tconst isInFuture = currentDate > now\n\t\t\tconst isWeekend = day === 0 || day === 6\n\n\t\t\t// More realistic pattern: fewer commits on weekends, none in future\n\t\t\tlet dayCount = 0\n\t\t\tif (!isInFuture) {\n\t\t\t\tif (isWeekend) {\n\t\t\t\t\tdayCount =\n\t\t\t\t\t\tMath.random() < 0.3 ? Math.floor(Math.random() * 5) : 0\n\t\t\t\t} else {\n\t\t\t\t\tdayCount = Math.floor(Math.random() * 15)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tweekData.contributionDays.push({\n\t\t\t\tdate: new Date(currentDate).toISOString().split('T')[0],\n\t\t\t\tcontributionCount: dayCount,\n\t\t\t\tweekday: day,\n\t\t\t})\n\t\t\tcurrentDate.setDate(currentDate.getDate() + 1)\n\t\t}\n\n\t\tweeks.push(weekData)\n\t}\n\n\treturn weeks\n}\n\n/**\n * Generate complete dummy stats data\n */\nexport function generateDummyStats(options = {}) {\n\tconst {\n\t\tusername = 'demo-user',\n\t\tplatform = 'github',\n\t\tprojectCount = 30,\n\t\tcommitCount = 2500,\n\t} = options\n\n\tconst contributions = generateDummyContributions()\n\tconst totalContributions = contributions.reduce((total, week) => {\n\t\treturn (\n\t\t\ttotal +\n\t\t\tweek.contributionDays.reduce(\n\t\t\t\t(sum, day) => sum + day.contributionCount,\n\t\t\t\t0\n\t\t\t)\n\t\t)\n\t}, 0)\n\n\treturn {\n\t\tlastUpdated: new Date().toISOString(),\n\t\tprofiles: [\n\t\t\t{\n\t\t\t\tusername,\n\t\t\t\tplatform,\n\t\t\t\tstats: {\n\t\t\t\t\tprojectCount,\n\t\t\t\t\tcommitCount,\n\t\t\t\t\tcontributions: contributions.map((week) => ({\n\t\t\t\t\t\tfirstDay: week.weekStart,\n\t\t\t\t\t\tcontributionDays: week.contributionDays,\n\t\t\t\t\t})),\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\ttotals: {\n\t\t\tprojectCount,\n\t\t\tcommitCount,\n\t\t},\n\t\tmetadata: {\n\t\t\tfetchedAt: Date.now(),\n\t\t\tsource: 'dummy_data',\n\t\t\tisDummy: true,\n\t\t},\n\t}\n}\n\n/**\n * Generate multiple profiles dummy data\n */\nexport function generateMultiProfileDummyStats() {\n\tconst githubProfile = generateDummyStats({\n\t\tusername: 'demo-github',\n\t\tplatform: 'github',\n\t\tprojectCount: 45,\n\t\tcommitCount: 2847,\n\t})\n\n\tconst gitlabProfile = generateDummyStats({\n\t\tusername: 'demo-gitlab',\n\t\tplatform: 'gitlab',\n\t\tprojectCount: 7,\n\t\tcommitCount: 523,\n\t})\n\n\treturn {\n\t\tlastUpdated: new Date().toISOString(),\n\t\tprofiles: [githubProfile.profiles[0], gitlabProfile.profiles[0]],\n\t\ttotals: {\n\t\t\tprojectCount: 45 + 7,\n\t\t\tcommitCount: 2847 + 523,\n\t\t},\n\t\tmetadata: {\n\t\t\tfetchedAt: Date.now(),\n\t\t\tsource: 'dummy_data',\n\t\t\tisDummy: true,\n\t\t},\n\t}\n}\n\n/**\n * Save dummy data to a file (for testing)\n */\nexport function saveDummyDataToFile(filepath = 'dummy-git-stats.json') {\n\tconst data = generateDummyStats()\n\tconst json = JSON.stringify(data, null, '\\t')\n\n\tif (typeof window !== 'undefined') {\n\t\t// Browser environment - trigger download\n\t\tconst blob = new Blob([json], { type: 'application/json' })\n\t\tconst url = URL.createObjectURL(blob)\n\t\tconst a = document.createElement('a')\n\t\ta.href = url\n\t\ta.download = filepath\n\t\ta.click()\n\t\tURL.revokeObjectURL(url)\n\t} else {\n\t\t// Node environment\n\t\ttry {\n\t\t\tconst fs = require('fs')\n\t\t\tfs.writeFileSync(filepath, json)\n\t\t\tconsole.log(`✓ Dummy data saved to ${filepath}`)\n\t\t} catch (err) {\n\t\t\tconsole.error('Failed to save dummy data:', err)\n\t\t}\n\t}\n}\n","// packages/core/src/index.ts\n// Framework-agnostic core logic\n\n// Re-export everything from types\nexport type {\n\tColorScheme,\n\tContributionDay,\n\tContributionWeek,\n\tProfile,\n\tGitStatsData,\n\tExperienceEntry,\n\tDataSource,\n\tPlatform,\n\tProfileStats,\n\tStatsTotals,\n\tStatsMetadata,\n\tCustomStatCalculator,\n\tCustomStatCalculatorParams,\n} from './types/index.js'\n\n// Export API functions\nexport { fetchGitStats as fetchGitStatsAPI } from './api/fetchGitStats.js'\n\n// Export utility functions with explicit imports\nexport {\n\tgenerateDummyStats,\n\tgenerateDummyContributions,\n\tgenerateMultiProfileDummyStats,\n\tsaveDummyDataToFile,\n} from './utils/generateDummyData.js'\n\n// Core data fetching (framework-agnostic)\nimport type { GitStatsData } from './types/index.js'\n\nexport interface FetchOptions {\n\tdataUrl: string\n\tcacheTTL?: number\n\tcacheKey?: string\n\tuseStaleCache?: boolean\n}\n\nexport interface DataResult<T> {\n\tdata: T | null\n\terror: Error | null\n\tsource: 'static' | 'cache' | 'mock' | 'dummy' | null\n\tisDummy: boolean\n}\n\n/**\n * Framework-agnostic data fetcher\n */\nexport async function fetchGitStats(\n\toptions: FetchOptions\n): Promise<DataResult<GitStatsData>> {\n\tconst { dataUrl, cacheKey = 'git_stats_cache', useStaleCache = true } = options\n\n\ttry {\n\t\t// Try static file first\n\t\tconst response = await fetch(dataUrl)\n\t\tif (response.ok) {\n\t\t\tconst data = await response.json()\n\t\t\t// Cache the data\n\t\t\tif (typeof window !== 'undefined') {\n\t\t\t\tlocalStorage.setItem(\n\t\t\t\t\tcacheKey,\n\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t...data,\n\t\t\t\t\t\tcachedAt: Date.now(),\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tdata,\n\t\t\t\terror: null,\n\t\t\t\tsource: 'static',\n\t\t\t\tisDummy: data.metadata?.isDummy === true,\n\t\t\t}\n\t\t}\n\t} catch (err) {\n\t\tconsole.warn('Failed to fetch from static file:', err)\n\t}\n\n\t// Try cache\n\tif (useStaleCache && typeof window !== 'undefined') {\n\t\ttry {\n\t\t\tconst cached = localStorage.getItem(cacheKey)\n\t\t\tif (cached) {\n\t\t\t\tconst data = JSON.parse(cached)\n\t\t\t\treturn {\n\t\t\t\t\tdata,\n\t\t\t\t\terror: null,\n\t\t\t\t\tsource: 'cache',\n\t\t\t\t\tisDummy: data.metadata?.isDummy === true,\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconsole.warn('Failed to load from cache:', err)\n\t\t}\n\t}\n\n\t// Fallback to mock\n\tconst mockData = generateMockData()\n\treturn {\n\t\tdata: mockData,\n\t\terror: null,\n\t\tsource: 'mock',\n\t\tisDummy: false,\n\t}\n}\n\n/**\n * Format last updated time\n */\nexport function formatLastUpdated(dateString: string): string {\n\tconst date = new Date(dateString)\n\tconst now = new Date()\n\tconst diffHours = Math.floor((now.getTime() - date.getTime()) / (1000 * 60 * 60))\n\n\tif (diffHours < 1) return 'just now'\n\tif (diffHours < 24) return `${diffHours} hours ago`\n\n\tconst diffDays = Math.floor(diffHours / 24)\n\tif (diffDays === 1) return 'yesterday'\n\tif (diffDays < 7) return `${diffDays} days ago`\n\n\treturn date.toLocaleDateString('en-US', {\n\t\tmonth: 'short',\n\t\tday: 'numeric',\n\t\tyear: date.getFullYear() !== now.getFullYear() ? 'numeric' : undefined,\n\t})\n}\n\n/**\n * Get contribution level (0-4)\n */\nexport function getContributionLevel(count: number): number {\n\tif (count === 0) return 0\n\tif (count <= 3) return 1\n\tif (count <= 6) return 2\n\tif (count <= 9) return 3\n\treturn 4\n}\n\n/**\n * Calculate years of experience\n */\nexport function calculateYearsExperience(\n\texperienceData: { startDate: string; endDate: string | null; skills?: string[] }[]\n): number {\n\tif (experienceData.length === 0) return 0\n\n\tconst skillExperience: Record<string, number> = {}\n\n\texperienceData.forEach((exp) => {\n\t\tconst end = exp.endDate ? new Date(exp.endDate) : new Date()\n\t\tconst start = new Date(exp.startDate)\n\t\tconst years = (end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24 * 365.25)\n\n\t\texp.skills?.forEach((skill) => {\n\t\t\tif (!skillExperience[skill]) {\n\t\t\t\tskillExperience[skill] = 0\n\t\t\t}\n\t\t\tskillExperience[skill] += years\n\t\t})\n\t})\n\n\treturn Math.max(...Object.values(skillExperience), 0)\n}\n\n// Mock data generator\nfunction generateMockData(): GitStatsData {\n\treturn {\n\t\tlastUpdated: new Date().toISOString(),\n\t\tprofiles: [\n\t\t\t{\n\t\t\t\tusername: 'mockuser',\n\t\t\t\tplatform: 'github',\n\t\t\t\tstats: {\n\t\t\t\t\tprojectCount: 30,\n\t\t\t\t\tcommitCount: 2500,\n\t\t\t\t\tcontributions: [],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\ttotals: {\n\t\t\tprojectCount: 30,\n\t\t\tcommitCount: 2500,\n\t\t},\n\t\tmetadata: {\n\t\t\tsource: 'mock',\n\t\t\tfetchedAt: Date.now(),\n\t\t},\n\t}\n}","import { ref, computed } from 'vue'\r\nimport {\r\n\tfetchGitStats,\r\n\tformatLastUpdated,\r\n\ttype GitStatsData,\r\n\ttype DataSource,\r\n} from '@git-stats-components/core'\r\n\r\nexport interface UseGitStatsConfig {\r\n\tdataUrl?: string\r\n\tcacheTTL?: number\r\n\tuseStaleCache?: boolean\r\n\tcacheKey?: string\r\n}\r\n\r\nexport function useGitStats(config: UseGitStatsConfig = {}) {\r\n\tconst {\r\n\t\tdataUrl = '/data/git-stats.json',\r\n\t\tcacheTTL = 24 * 60 * 60 * 1000,\r\n\t\tuseStaleCache = true,\r\n\t\tcacheKey = 'git_stats_cache',\r\n\t} = config\r\n\r\n\tconst loading = ref(false)\r\n\tconst error = ref<Error | null>(null)\r\n\tconst data = ref<GitStatsData | null>(null)\r\n\tconst dataSource = ref<DataSource | null>(null)\r\n\tconst isDummy = ref(false)\r\n\r\n\t/**\r\n\t * Load data with fallback strategy\r\n\t */\r\n\tasync function loadData(): Promise<GitStatsData | null> {\r\n\t\tloading.value = true\r\n\t\terror.value = null\r\n\r\n\t\ttry {\r\n\t\t\tconst result = await fetchGitStats({\r\n\t\t\t\tdataUrl,\r\n\t\t\t\tcacheTTL,\r\n\t\t\t\tcacheKey,\r\n\t\t\t\tuseStaleCache,\r\n\t\t\t})\r\n\r\n\t\t\tdata.value = result.data\r\n\t\t\terror.value = result.error\r\n\t\t\tdataSource.value = result.source\r\n\t\t\tisDummy.value = result.isDummy\r\n\r\n\t\t\treturn result.data\r\n\t\t} catch (err) {\r\n\t\t\terror.value =\r\n\t\t\t\terr instanceof Error ? err : new Error('Failed to load data')\r\n\t\t\treturn null\r\n\t\t} finally {\r\n\t\t\tloading.value = false\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Format \"last updated\" text\r\n\t */\r\n\tconst lastUpdatedText = computed(() => {\r\n\t\tif (!data.value?.lastUpdated) return ''\r\n\t\treturn formatLastUpdated(data.value.lastUpdated)\r\n\t})\r\n\r\n\t/**\r\n\t * Computed data source display text\r\n\t */\r\n\tconst dataSourceText = computed(() => {\r\n\t\tif (isDummy.value) {\r\n\t\t\treturn '⚠️ Using dummy data for testing'\r\n\t\t}\r\n\r\n\t\tswitch (dataSource.value) {\r\n\t\t\tcase 'static':\r\n\t\t\t\treturn 'Real-time data'\r\n\t\t\tcase 'cache':\r\n\t\t\t\treturn 'Cached data'\r\n\t\t\tcase 'mock':\r\n\t\t\t\treturn 'Sample data'\r\n\t\t\tdefault:\r\n\t\t\t\treturn ''\r\n\t\t}\r\n\t})\r\n\r\n\t// Auto-load on creation\r\n\tloadData()\r\n\r\n\treturn {\r\n\t\tdata,\r\n\t\tloading,\r\n\t\terror,\r\n\t\tdataSource,\r\n\t\tdataSourceText,\r\n\t\tlastUpdatedText,\r\n\t\tisDummy,\r\n\t\tloadData,\r\n\t}\r\n}\r\n","<template>\r\n\t<div class=\"git-contribution-graph\">\r\n\t\t<!-- Header -->\r\n\t\t<div class=\"graph-header\">\r\n\t\t\t<div class=\"header-info\">\r\n\t\t\t\t<h5 class=\"contribution-count\">\r\n\t\t\t\t\t{{ totalContributions.toLocaleString() }} contributions in\r\n\t\t\t\t\tthe last year\r\n\t\t\t\t</h5>\r\n\t\t\t\t<small\r\n\t\t\t\t\tclass=\"data-source-text\"\r\n\t\t\t\t\t:class=\"{ 'is-dummy': isDummy }\"\r\n\t\t\t\t>\r\n\t\t\t\t\t{{ dataSourceText }}\r\n\t\t\t\t</small>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"header-actions\" v-if=\"showSettings\">\r\n\t\t\t\t<button\r\n\t\t\t\t\tclass=\"settings-btn\"\r\n\t\t\t\t\ttype=\"button\"\r\n\t\t\t\t\t@click=\"toggleSettings\"\r\n\t\t\t\t>\r\n\t\t\t\t\t<slot name=\"settings-icon\">⚙️</slot>\r\n\t\t\t\t\tSettings\r\n\t\t\t\t</button>\r\n\t\t\t\t<div v-if=\"settingsOpen\" class=\"settings-dropdown\">\r\n\t\t\t\t\t<button\r\n\t\t\t\t\t\tv-for=\"scheme in colorSchemes\"\r\n\t\t\t\t\t\t:key=\"scheme\"\r\n\t\t\t\t\t\t@click=\"changeColorScheme(scheme)\"\r\n\t\t\t\t\t\tclass=\"settings-item\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t\t{{ scheme }} theme\r\n\t\t\t\t\t</button>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\r\n\t\t<!-- Loading state -->\r\n\t\t<div v-if=\"loading\" class=\"loading-state\">\r\n\t\t\t<div class=\"spinner\"></div>\r\n\t\t\t<span>Loading contributions...</span>\r\n\t\t</div>\r\n\r\n\t\t<!-- Contribution grid -->\r\n\t\t<div v-else class=\"graph-container\">\r\n\t\t\t<div class=\"graph-content-wrapper\">\r\n\t\t\t\t<!-- Month labels -->\r\n\t\t\t\t<div class=\"months-row\">\r\n\t\t\t\t\t<div class=\"month-spacer\"></div>\r\n\t\t\t\t\t<div class=\"months-container\">\r\n\t\t\t\t\t\t<div\r\n\t\t\t\t\t\t\tv-for=\"month in monthLabels\"\r\n\t\t\t\t\t\t\t:key=\"`${month.year}-${month.month}`\"\r\n\t\t\t\t\t\t\tclass=\"month-label\"\r\n\t\t\t\t\t\t\t:style=\"{\r\n\t\t\t\t\t\t\t\tgridColumn: `${month.week + 1} / span 1`,\r\n\t\t\t\t\t\t\t}\"\r\n\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t{{ month.label }}\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\r\n\t\t\t\t<!-- Grid with day labels -->\r\n\t\t\t\t<div class=\"grid-container\">\r\n\t\t\t\t\t<!-- Day labels -->\r\n\t\t\t\t\t<div class=\"day-labels\">\r\n\t\t\t\t\t\t<div class=\"day-label\">Mon</div>\r\n\t\t\t\t\t\t<div class=\"day-label\"></div>\r\n\t\t\t\t\t\t<div class=\"day-label\">Wed</div>\r\n\t\t\t\t\t\t<div class=\"day-label\"></div>\r\n\t\t\t\t\t\t<div class=\"day-label\">Fri</div>\r\n\t\t\t\t\t\t<div class=\"day-label\"></div>\r\n\t\t\t\t\t\t<div class=\"day-label\"></div>\r\n\t\t\t\t\t</div>\r\n\r\n\t\t\t\t\t<!-- Contribution squares -->\r\n\t\t\t\t\t<div class=\"contribution-grid\">\r\n\t\t\t\t\t\t<div\r\n\t\t\t\t\t\t\tv-for=\"week in contributionData\"\r\n\t\t\t\t\t\t\t:key=\"week.weekStart\"\r\n\t\t\t\t\t\t\tclass=\"contribution-week\"\r\n\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t<div\r\n\t\t\t\t\t\t\t\tv-for=\"day in week.days\"\r\n\t\t\t\t\t\t\t\t:key=\"day.date\"\r\n\t\t\t\t\t\t\t\tclass=\"contribution-day\"\r\n\t\t\t\t\t\t\t\t:class=\"getContributionLevel(day.count)\"\r\n\t\t\t\t\t\t\t\t:title=\"getTooltipText(day)\"\r\n\t\t\t\t\t\t\t\t@click=\"onDayClick(day)\"\r\n\t\t\t\t\t\t\t></div>\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Legend -->\r\n\t\t\t<div class=\"graph-footer\">\r\n\t\t\t\t<small class=\"last-updated\" v-if=\"lastUpdatedText\">\r\n\t\t\t\t\tLast updated: {{ lastUpdatedText }}\r\n\t\t\t\t</small>\r\n\t\t\t\t<div class=\"legend\">\r\n\t\t\t\t\t<small class=\"legend-label\">Less</small>\r\n\t\t\t\t\t<div class=\"legend-squares\">\r\n\t\t\t\t\t\t<div class=\"contribution-day level-0\"></div>\r\n\t\t\t\t\t\t<div class=\"contribution-day level-1\"></div>\r\n\t\t\t\t\t\t<div class=\"contribution-day level-2\"></div>\r\n\t\t\t\t\t\t<div class=\"contribution-day level-3\"></div>\r\n\t\t\t\t\t\t<div class=\"contribution-day level-4\"></div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<small class=\"legend-label\">More</small>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from 'vue'\r\nimport { useGitStats } from '../composables/useGitStats'\r\nimport {\r\n\ttype ColorScheme,\r\n\ttype ContributionWeek,\r\n} from '@git-stats-components/core'\r\n\r\ninterface ProcessedWeek {\r\n\tweekStart: string\r\n\tdays: ProcessedDay[]\r\n}\r\n\r\ninterface ProcessedDay {\r\n\tdate: string\r\n\tcount: number\r\n\tweekday: number\r\n}\r\n\r\ninterface MonthLabel {\r\n\tweek: number\r\n\tmonth: number\r\n\tyear: number\r\n\tlabel: string\r\n}\r\n\r\ninterface Props {\r\n\tdataUrl?: string\r\n\tprofileIndex?: number\r\n\tcolorScheme?: ColorScheme\r\n\tshowSettings?: boolean\r\n\tcacheTTL?: number\r\n}\r\n\r\ninterface Emits {\r\n\t(e: 'day-click', data: { date: string; count: number }): void\r\n\t(e: 'color-scheme-change', scheme: ColorScheme): void\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n\tdataUrl: '/data/git-stats.json',\r\n\tprofileIndex: 0,\r\n\tcolorScheme: 'green',\r\n\tshowSettings: true,\r\n\tcacheTTL: 24 * 60 * 60 * 1000,\r\n})\r\n\r\nconst emit = defineEmits<Emits>()\r\n\r\n// Use the shared composable\r\nconst { data, loading, dataSourceText, lastUpdatedText, isDummy } = useGitStats(\r\n\t{\r\n\t\tdataUrl: props.dataUrl,\r\n\t\tcacheTTL: props.cacheTTL,\r\n\t}\r\n)\r\n\r\nconst currentColorScheme = ref<ColorScheme>(props.colorScheme)\r\nconst settingsOpen = ref(false)\r\nconst colorSchemes: ColorScheme[] = ['green', 'blue', 'purple', 'orange']\r\nconst contributionData = ref<ProcessedWeek[]>([])\r\nconst monthLabels = ref<MonthLabel[]>([])\r\n\r\n// Process contribution data when loaded\r\nwatch(\r\n\tdata,\r\n\t(newData) => {\r\n\t\tif (newData?.profiles?.[props.profileIndex]?.stats?.contributions) {\r\n\t\t\tconst contributions =\r\n\t\t\t\tnewData.profiles[props.profileIndex].stats.contributions\r\n\t\t\tif (contributions) {\r\n\t\t\t\tcontributionData.value = processContributions(contributions)\r\n\t\t\t\tgenerateMonthLabels()\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tcontributionData.value = []\r\n\t\t}\r\n\t},\r\n\t{ immediate: true }\r\n)\r\n\r\nconst totalContributions = computed(() => {\r\n\tif (!contributionData.value || contributionData.value.length === 0) {\r\n\t\treturn 0\r\n\t}\r\n\r\n\treturn contributionData.value.reduce((total, week) => {\r\n\t\tif (!week.days || !Array.isArray(week.days)) {\r\n\t\t\treturn total\r\n\t\t}\r\n\t\treturn (\r\n\t\t\ttotal +\r\n\t\t\tweek.days.reduce((weekTotal, day) => {\r\n\t\t\t\treturn weekTotal + (day.count || 0)\r\n\t\t\t}, 0)\r\n\t\t)\r\n\t}, 0)\r\n})\r\n\r\nfunction processContributions(\r\n\tcontributions: ContributionWeek[]\r\n): ProcessedWeek[] {\r\n\tif (!contributions || !Array.isArray(contributions)) {\r\n\t\treturn generateEmptyWeeks()\r\n\t}\r\n\r\n\tconst weeks = contributions.map((week) => ({\r\n\t\tweekStart: week.firstDay || '',\r\n\t\tdays: week.contributionDays.map((day) => ({\r\n\t\t\tdate: day.date || '',\r\n\t\t\tcount: day.contributionCount ?? 0,\r\n\t\t\tweekday: day.weekday || 0,\r\n\t\t})),\r\n\t}))\r\n\r\n\twhile (weeks.length < 53) {\r\n\t\tweeks.push(generateEmptyWeek())\r\n\t}\r\n\r\n\treturn weeks\r\n}\r\n\r\nfunction generateEmptyWeeks(): ProcessedWeek[] {\r\n\tconst weeks: ProcessedWeek[] = []\r\n\tfor (let i = 0; i < 53; i++) {\r\n\t\tweeks.push(generateEmptyWeek())\r\n\t}\r\n\treturn weeks\r\n}\r\n\r\nfunction generateEmptyWeek(): ProcessedWeek {\r\n\tconst days: ProcessedDay[] = []\r\n\tfor (let i = 0; i < 7; i++) {\r\n\t\tdays.push({ date: '', count: 0, weekday: i })\r\n\t}\r\n\treturn { weekStart: '', days }\r\n}\r\n\r\nfunction generateMonthLabels(): void {\r\n\tif (!contributionData.value || contributionData.value.length === 0) {\r\n\t\tmonthLabels.value = []\r\n\t\treturn\r\n\t}\r\n\r\n\tconst monthPositions: MonthLabel[] = []\r\n\tlet lastMonth = -1\r\n\tlet lastYear = -1\r\n\r\n\tcontributionData.value.forEach((week, weekIndex) => {\r\n\t\tif (!week.days || week.days.length === 0) return\r\n\r\n\t\tconst firstDay = week.days[0].date\r\n\t\tif (!firstDay) return\r\n\r\n\t\tconst dateParts = firstDay.split('-')\r\n\t\tif (dateParts.length !== 3) return\r\n\r\n\t\tconst [year, month] = dateParts.map(Number)\r\n\t\tif (isNaN(year) || isNaN(month)) return\r\n\r\n\t\tif (month !== lastMonth || year !== lastYear) {\r\n\t\t\tconst date = new Date(year, month - 1, 1)\r\n\t\t\tmonthPositions.push({\r\n\t\t\t\tweek: weekIndex,\r\n\t\t\t\tmonth: month - 1,\r\n\t\t\t\tyear: year,\r\n\t\t\t\tlabel: date.toLocaleDateString('en-US', { month: 'short' }),\r\n\t\t\t})\r\n\t\t\tlastMonth = month\r\n\t\t\tlastYear = year\r\n\t\t}\r\n\t})\r\n\r\n\tmonthLabels.value = monthPositions\r\n}\r\n\r\nfunction getContributionLevel(count: number): string {\r\n\tconst level = getContributionLevelNumber(count)\r\n\treturn `level-${level} ${currentColorScheme.value}`\r\n}\r\n\r\nfunction getContributionLevelNumber(count: number): number {\r\n\tif (count === 0) return 0\r\n\tif (count <= 3) return 1\r\n\tif (count <= 6) return 2\r\n\tif (count <= 9) return 3\r\n\treturn 4\r\n}\r\n\r\nfunction getTooltipText(day: ProcessedDay): string {\r\n\tif (!day.date) return ''\r\n\r\n\tconst [year, month, dayNum] = day.date.split('-').map(Number)\r\n\tconst date = new Date(year, month - 1, dayNum)\r\n\r\n\tconst formattedDate = date.toLocaleDateString('en-US', {\r\n\t\tweekday: 'short',\r\n\t\tyear: 'numeric',\r\n\t\tmonth: 'short',\r\n\t\tday: 'numeric',\r\n\t})\r\n\r\n\tconst contributionText = day.count === 1 ? 'contribution' : 'contributions'\r\n\treturn `${day.count} ${contributionText} on ${formattedDate}`\r\n}\r\n\r\nfunction onDayClick(day: ProcessedDay): void {\r\n\temit('day-click', { date: day.date, count: day.count })\r\n}\r\n\r\nfunction toggleSettings(): void {\r\n\tsettingsOpen.value = !settingsOpen.value\r\n}\r\n\r\nfunction changeColorScheme(scheme: ColorScheme): void {\r\n\tcurrentColorScheme.value = scheme\r\n\tsettingsOpen.value = false\r\n\temit('color-scheme-change', scheme)\r\n}\r\n</script>\r\n\r\n<style scoped>\r\n.graph-content-wrapper {\r\n\tjustify-items: anchor-center;\r\n}\r\n.git-contribution-graph {\r\n\tfont-family:\r\n\t\t-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica,\r\n\t\tArial, sans-serif;\r\n\tfont-size: 12px;\r\n\tbackground: transparent;\r\n\tcolor: #e6edf3;\r\n\tpadding: 16px;\r\n\tmax-width: 1200px;\r\n\tmargin: 0 auto;\r\n\twidth: 100%;\r\n}\r\n\r\n.graph-header {\r\n\tdisplay: flex;\r\n\tjustify-content: space-between;\r\n\talign-items: center;\r\n\tmargin-bottom: 16px;\r\n}\r\n\r\n.contribution-count {\r\n\tmargin: 0 0 4px 0;\r\n\tfont-size: 16px;\r\n\tfont-weight: 600;\r\n}\r\n\r\n.data-source-text {\r\n\tcolor: #7d8590;\r\n}\r\n\r\n.data-source-text.is-dummy {\r\n\tcolor: #f85149;\r\n\tfont-weight: 600;\r\n\tbackground: rgba(248, 81, 73, 0.1);\r\n\tpadding: 2px 8px;\r\n\tborder-radius: 4px;\r\n}\r\n\r\n.settings-btn {\r\n\tbackground: transparent;\r\n\tborder: 1px solid #30363d;\r\n\tcolor: #7d8590;\r\n\tpadding: 6px 12px;\r\n\tborder-radius: 6px;\r\n\tcursor: pointer;\r\n\tfont-size: 12px;\r\n}\r\n\r\n.settings-btn:hover {\r\n\tbackground: #21262d;\r\n\tcolor: #e6edf3;\r\n}\r\n\r\n.header-actions {\r\n\tposition: relative;\r\n}\r\n\r\n.settings-dropdown {\r\n\tposition: absolute;\r\n\tright: 0;\r\n\ttop: 100%;\r\n\tmargin-top: 4px;\r\n\tbackground: #21262d;\r\n\tborder: 1px solid #30363d;\r\n\tborder-radius: 6px;\r\n\tpadding: 4px;\r\n\tz-index: 10;\r\n\tmin-width: 150px;\r\n}\r\n\r\n.settings-item {\r\n\tdisplay: block;\r\n\twidth: 100%;\r\n\tbackground: transparent;\r\n\tborder: none;\r\n\tcolor: #e6edf3;\r\n\tpadding: 8px 12px;\r\n\ttext-align: left;\r\n\tcursor: pointer;\r\n\tborder-radius: 4px;\r\n}\r\n\r\n.settings-item:hover {\r\n\tbackground: #30363d;\r\n}\r\n\r\n.loading-state {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\tgap: 12px;\r\n\tpadding: 40px;\r\n\tcolor: #7d8590;\r\n}\r\n\r\n.spinner {\r\n\twidth: 20px;\r\n\theight: 20px;\r\n\tborder: 2px solid #30363d;\r\n\tborder-top-color: #58a6ff;\r\n\tborder-radius: 50%;\r\n\tanimation: spin 1s linear infinite;\r\n}\r\n\r\n@keyframes spin {\r\n\tto {\r\n\t\ttransform: rotate(360deg);\r\n\t}\r\n}\r\n\r\n.months-row {\r\n\tdisplay: flex;\r\n\tmargin-bottom: 4px;\r\n}\r\n\r\n.month-spacer {\r\n\twidth: 27px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.months-container {\r\n\tdisplay: grid;\r\n\tgrid-template-columns: repeat(53, 11px);\r\n\tgap: 2px;\r\n\tflex: 1;\r\n\tmargin-left: 3px;\r\n\tmin-width: 0;\r\n}\r\n\r\n.month-label {\r\n\tfont-size: 11px;\r\n\tcolor: #7d8590;\r\n\ttext-align: left;\r\n}\r\n\r\n.grid-container {\r\n\tdisplay: flex;\r\n\tgap: 3px;\r\n\tmin-width: fit-content;\r\n}\r\n\r\n.day-labels {\r\n\tdisplay: flex;\r\n\tflex-direction: column;\r\n\twidth: 24px;\r\n\tgap: 2px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.day-label {\r\n\theight: 11px;\r\n\tfont-size: 9px;\r\n\tcolor: #7d8590;\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n}\r\n\r\n.contribution-grid {\r\n\tdisplay: flex;\r\n\tgap: 2px;\r\n\tflex: 1;\r\n\tmin-width: 0;\r\n}\r\n\r\n.contribution-week {\r\n\tdisplay: flex;\r\n\tflex-direction: column;\r\n\tgap: 2px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.contribution-day {\r\n\twidth: 11px;\r\n\theight: 11px;\r\n\tborder-radius: 2px;\r\n\tcursor: pointer;\r\n\toutline: 1px solid rgba(27, 31, 36, 0.06);\r\n\toutline-offset: -1px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n/* Color schemes */\r\n.contribution-day.level-0.green {\r\n\tbackground-color: #161b22;\r\n}\r\n.contribution-day.level-1.green {\r\n\tbackground-color: #0e4429;\r\n}\r\n.contribution-day.level-2.green {\r\n\tbackground-color: #006d32;\r\n}\r\n.contribution-day.level-3.green {\r\n\tbackground-color: #26a641;\r\n}\r\n.contribution-day.level-4.green {\r\n\tbackground-color: #39d353;\r\n}\r\n\r\n.contribution-day.level-0.blue {\r\n\tbackground-color: #161b22;\r\n}\r\n.contribution-day.level-1.blue {\r\n\tbackground-color: #0a3069;\r\n}\r\n.contribution-day.level-2.blue {\r\n\tbackground-color: #1f6feb;\r\n}\r\n.contribution-day.level-3.blue {\r\n\tbackground-color: #58a6ff;\r\n}\r\n.contribution-day.level-4.blue {\r\n\tbackground-color: #79c0ff;\r\n}\r\n\r\n.contribution-day.level-0.purple {\r\n\tbackground-color: #161b22;\r\n}\r\n.contribution-day.level-1.purple {\r\n\tbackground-color: #3b1e6d;\r\n}\r\n.contribution-day.level-2.purple {\r\n\tbackground-color: #8250df;\r\n}\r\n.contribution-day.level-3.purple {\r\n\tbackground-color: #a475f9;\r\n}\r\n.contribution-day.level-4.purple {\r\n\tbackground-color: #d2a8ff;\r\n}\r\n\r\n.contribution-day.level-0.orange {\r\n\tbackground-color: #161b22;\r\n}\r\n.contribution-day.level-1.orange {\r\n\tbackground-color: #7d2d00;\r\n}\r\n.contribution-day.level-2.orange {\r\n\tbackground-color: #da7b00;\r\n}\r\n.contribution-day.level-3.orange {\r\n\tbackground-color: #ffa348;\r\n}\r\n.contribution-day.level-4.orange {\r\n\tbackground-color: #ffb366;\r\n}\r\n\r\n.contribution-day:hover {\r\n\toutline: 1px solid #c9d1d9;\r\n\toutline-offset: -1px;\r\n}\r\n\r\n.graph-footer {\r\n\tdisplay: flex;\r\n\tjustify-content: space-between;\r\n\talign-items: center;\r\n\tmargin-top: 8px;\r\n}\r\n\r\n.last-updated {\r\n\tcolor: #7d8590;\r\n}\r\n\r\n.legend {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tgap: 4px;\r\n}\r\n\r\n.legend-label {\r\n\tcolor: #7d8590;\r\n}\r\n\r\n.legend-squares {\r\n\tdisplay: flex;\r\n\tgap: 2px;\r\n}\r\n\r\n.legend-squares .contribution-day {\r\n\tcursor: default;\r\n}\r\n\r\n.legend-squares .contribution-day:hover {\r\n\toutline: none;\r\n}\r\n\r\n/* Mobile responsive */\r\n@media (max-width: 768px) {\r\n\t.git-contribution-graph {\r\n\t\tpadding: 12px;\r\n\t\tfont-size: 11px;\r\n\t\toverflow-x: auto;\r\n\t}\r\n\t.months-container {\r\n\t\tgrid-template-columns: repeat(53, 10px);\r\n\t\tgap: 1px;\r\n\t}\r\n\t.grid-container {\r\n\t\tgap: 2px;\r\n\t}\r\n\t.day-labels {\r\n\t\twidth: 20px;\r\n\t}\r\n\t.day-label {\r\n\t\theight: 10px;\r\n\t\tfont-size: 8px;\r\n\t}\r\n\t.contribution-grid {\r\n\t\tgap: 1px;\r\n\t}\r\n\t.contribution-week {\r\n\t\tgap: 1px;\r\n\t}\r\n\t.contribution-day {\r\n\t\twidth: 10px;\r\n\t\theight: 10px;\r\n\t}\r\n\t.settings-btn {\r\n\t\tfont-size: 10px;\r\n\t\tpadding: 4px 8px;\r\n\t}\r\n\t.contribution-count {\r\n\t\tfont-size: 14px;\r\n\t}\r\n}\r\n\r\n@media (max-width: 480px) {\r\n\t.graph-header {\r\n\t\tflex-direction: column;\r\n\t\talign-items: flex-start;\r\n\t\tgap: 8px;\r\n\t}\r\n}\r\n</style>\r\n","<template>\r\n\t<div class=\"git-stats-breakdown\">\r\n\t\t<div class=\"stats-grid\">\r\n\t\t\t<!-- Years Experience -->\r\n\t\t\t<div class=\"stat-card\">\r\n\t\t\t\t<div class=\"stat-icon\">\r\n\t\t\t\t\t<slot name=\"icon-experience\">⏱️</slot>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"stat-content\">\r\n\t\t\t\t\t<div class=\"stat-value\">{{ yearsExperience }}</div>\r\n\t\t\t\t\t<div class=\"stat-label\">Years Experience</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Projects -->\r\n\t\t\t<div class=\"stat-card\">\r\n\t\t\t\t<div class=\"stat-icon\">\r\n\t\t\t\t\t<slot name=\"icon-projects\">📦</slot>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"stat-content\">\r\n\t\t\t\t\t<div v-if=\"loading\" class=\"stat-loading\">\r\n\t\t\t\t\t\t<div class=\"spinner\"></div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div v-else class=\"stat-value\">{{ totalProjects }}</div>\r\n\t\t\t\t\t<div class=\"stat-label\">Projects</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Commits -->\r\n\t\t\t<div class=\"stat-card\">\r\n\t\t\t\t<div class=\"stat-icon\">\r\n\t\t\t\t\t<slot name=\"icon-commits\">💻</slot>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"stat-content\">\r\n\t\t\t\t\t<div v-if=\"loading\" class=\"stat-loading\">\r\n\t\t\t\t\t\t<div class=\"spinner\"></div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div v-else class=\"stat-value\">{{ totalCommits }}</div>\r\n\t\t\t\t\t<div class=\"stat-label\">Commits</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Custom Stat -->\r\n\t\t\t<div class=\"stat-card\" v-if=\"showCustomStat\">\r\n\t\t\t\t<div class=\"stat-icon\">\r\n\t\t\t\t\t<slot name=\"icon-custom\">☕</slot>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"stat-content\">\r\n\t\t\t\t\t<div v-if=\"loading\" class=\"stat-loading\">\r\n\t\t\t\t\t\t<div class=\"spinner\"></div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div v-else class=\"stat-value\">{{ customStatValue }}</div>\r\n\t\t\t\t\t<div class=\"stat-label\">\r\n\t\t\t\t\t\t<slot name=\"custom-stat-label\">Coffee Consumed</slot>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\r\n\t\t<!-- Footer -->\r\n\t\t<div class=\"stats-footer\">\r\n\t\t\t<small v-if=\"dataSourceText\" class=\"data-source\">\r\n\t\t\t\t{{ dataSourceText }}\r\n\t\t\t\t<span v-if=\"lastUpdatedText\"> · {{ lastUpdatedText }}</span>\r\n\t\t\t</small>\r\n\t\t</div>\r\n\t</div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from 'vue'\r\nimport { useGitStats } from '../composables/useGitStats'\r\nimport {\r\n\tcalculateYearsExperience,\r\n\ttype ExperienceEntry,\r\n\ttype CustomStatCalculator,\r\n\ttype CustomStatCalculatorParams,\r\n} from '@git-stats-components/core'\r\n\r\ninterface Props {\r\n\tdataUrl?: string\r\n\tprofileIndexes?: number[]\r\n\texperienceData?: ExperienceEntry[]\r\n\tshowCustomStat?: boolean\r\n\tcustomStatCalculator?: CustomStatCalculator | null\r\n\tcacheTTL?: number\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n\tdataUrl: '/data/git-stats.json',\r\n\tprofileIndexes: () => [],\r\n\texperienceData: () => [],\r\n\tshowCustomStat: true,\r\n\tcustomStatCalculator: null,\r\n\tcacheTTL: 24 * 60 * 60 * 1000,\r\n})\r\n\r\n// Use the shared composable\r\nconst { data, loading, dataSourceText, lastUpdatedText } = useGitStats({\r\n\tdataUrl: props.dataUrl,\r\n\tcacheTTL: props.cacheTTL,\r\n})\r\n\r\nconst totalProjects = ref(0)\r\nconst totalCommits = ref(0)\r\n\r\n// Calculate totals when data loads\r\nwatch(\r\n\tdata,\r\n\t(newData) => {\r\n\t\tif (!newData) return\r\n\r\n\t\t// If profileIndexes specified, sum only those profiles\r\n\t\tif (props.profileIndexes.length > 0) {\r\n\t\t\tlet projects = 0\r\n\t\t\tlet commits = 0\r\n\r\n\t\t\tprops.profileIndexes.forEach((index) => {\r\n\t\t\t\tconst profile = newData.profiles?.[index]\r\n\t\t\t\tif (profile?.stats) {\r\n\t\t\t\t\tprojects += profile.stats.projectCount || 0\r\n\t\t\t\t\tcommits += profile.stats.commitCount || 0\r\n\t\t\t\t}\r\n\t\t\t})\r\n\r\n\t\t\ttotalProjects.value = projects\r\n\t\t\ttotalCommits.value = commits\r\n\t\t} else {\r\n\t\t\t// Use totals from data (aggregates all profiles)\r\n\t\t\ttotalProjects.value = newData.totals?.projectCount || 0\r\n\t\t\ttotalCommits.value = newData.totals?.commitCount || 0\r\n\t\t}\r\n\t},\r\n\t{ immediate: true }\r\n)\r\n\r\n// Calculate years of experience using core utility\r\nconst yearsExperience = computed(() => {\r\n\tconst years = calculateYearsExperience(props.experienceData)\r\n\treturn years.toFixed(1)\r\n})\r\n\r\n// Custom stat calculation\r\nconst customStatValue = computed(() => {\r\n\tif (props.customStatCalculator) {\r\n\t\tconst params: CustomStatCalculatorParams = {\r\n\t\t\tprojects: totalProjects.value,\r\n\t\t\tcommits: totalCommits.value,\r\n\t\t\tyears: parseFloat(yearsExperience.value),\r\n\t\t}\r\n\t\treturn props.customStatCalculator(params)\r\n\t}\r\n\r\n\t// Default: fun coffee calculation\r\n\tconst kA = 1.5\r\n\tconst kB = 1.2\r\n\tconst kC = 1.5\r\n\r\n\tconst cups =\r\n\t\ttotalProjects.value * kA +\r\n\t\ttotalCommits.value * kB +\r\n\t\tparseFloat(yearsExperience.value) * kC\r\n\r\n\treturn cups.toFixed(2)\r\n})\r\n</script>\r\n\r\n<style scoped>\r\n.git-stats-breakdown {\r\n\tfont-family:\r\n\t\t-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica,\r\n\t\tArial, sans-serif;\r\n\tpadding: 40px 20px;\r\n\tmax-width: 1200px;\r\n\tmargin: 0 auto;\r\n}\r\n\r\n.stats-grid {\r\n\tdisplay: grid;\r\n\tgrid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\r\n\tgap: 24px;\r\n\tmargin-bottom: 24px;\r\n}\r\n\r\n.stat-card {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tgap: 16px;\r\n\tpadding: 24px;\r\n\tbackground: rgba(255, 255, 255, 0.05);\r\n\tborder-radius: 12px;\r\n\tborder: 1px solid rgba(255, 255, 255, 0.1);\r\n\ttransition: all 0.3s ease;\r\n}\r\n\r\n.stat-card:hover {\r\n\tbackground: rgba(255, 255, 255, 0.08);\r\n\tborder-color: rgba(255, 255, 255, 0.2);\r\n\ttransform: translateY(-2px);\r\n}\r\n\r\n.stat-icon {\r\n\tfont-size: 48px;\r\n\tline-height: 1;\r\n\topacity: 0.9;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.stat-content {\r\n\tflex: 1;\r\n\tmin-width: 0;\r\n}\r\n\r\n.stat-value {\r\n\tfont-size: 32px;\r\n\tfont-weight: bold;\r\n\tline-height: 1.2;\r\n\tcolor: #e6edf3;\r\n\tmargin-bottom: 4px;\r\n}\r\n\r\n.stat-label {\r\n\tfont-size: 14px;\r\n\tcolor: #7d8590;\r\n\ttext-transform: uppercase;\r\n\tletter-spacing: 0.5px;\r\n}\r\n\r\n.stat-loading {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\theight: 38px;\r\n}\r\n\r\n.spinner {\r\n\twidth: 24px;\r\n\theight: 24px;\r\n\tborder: 3px solid rgba(255, 255, 255, 0.1);\r\n\tborder-top-color: #58a6ff;\r\n\tborder-radius: 50%;\r\n\tanimation: spin 1s linear infinite;\r\n}\r\n\r\n@keyframes spin {\r\n\tto {\r\n\t\ttransform: rotate(360deg);\r\n\t}\r\n}\r\n\r\n.stats-footer {\r\n\tdisplay: flex;\r\n\tflex-direction: column;\r\n\talign-items: center;\r\n\tgap: 8px;\r\n\tpadding-top: 16px;\r\n\tborder-top: 1px solid rgba(255, 255, 255, 0.1);\r\n}\r\n\r\n.data-source {\r\n\tfont-size: 12px;\r\n\tcolor: #7d8590;\r\n\ttext-align: center;\r\n}\r\n\r\n/* Responsive */\r\n@media (max-width: 768px) {\r\n\t.git-stats-breakdown {\r\n\t\tpadding: 20px 12px;\r\n\t}\r\n\t.stats-grid {\r\n\t\tgrid-template-columns: 1fr;\r\n\t\tgap: 16px;\r\n\t}\r\n\t.stat-card {\r\n\t\tpadding: 16px;\r\n\t}\r\n\t.stat-icon {\r\n\t\tfont-size: 36px;\r\n\t}\r\n\t.stat-value {\r\n\t\tfont-size: 24px;\r\n\t}\r\n\t.stat-label {\r\n\t\tfont-size: 12px;\r\n\t}\r\n}\r\n\r\n@media (max-width: 480px) {\r\n\t.stat-card {\r\n\t\tflex-direction: column;\r\n\t\ttext-align: center;\r\n\t}\r\n\t.stat-content {\r\n\t\twidth: 100%;\r\n\t}\r\n}\r\n</style>\r\n","// Main entry point for git-stats-components\n\nimport type { App } from 'vue'\nimport ContributionGraph from './components/ContributionGraph.vue'\nimport StatsBreakdown from './components/StatsBreakdown.vue'\nimport { useGitStats } from './composables/useGitStats'\n\n// Re-export everything from core\nexport * from '@git-stats-components/core'\n\n// Export Vue-specific components and composables\nexport { ContributionGraph, StatsBreakdown, useGitStats }\n\n// Auto-import styles\nimport './styles/index.css'\n\n// Plugin for Vue.use()\nexport interface VueGitStatsPlugin {\n\tinstall: (app: App) => void\n}\n\nconst VueGitStats: VueGitStatsPlugin = {\n\tinstall(app: App) {\n\t\tapp.component('ContributionGraph', ContributionGraph)\n\t\tapp.component('StatsBreakdown', StatsBreakdown)\n\t},\n}\n\n// Export as default for Vue.use()\nexport default VueGitStats\n"],"names":["fetchGitStats","url","__async","response","generateDummyContributions","weeks","now","endDate","startDate","currentDate","week","weekData","day","isInFuture","isWeekend","dayCount","generateDummyStats","options","username","platform","projectCount","commitCount","contributions","total","sum","generateMultiProfileDummyStats","githubProfile","gitlabProfile","saveDummyDataToFile","filepath","data","json","blob","a","err","dataUrl","cacheKey","useStaleCache","__spreadProps","__spreadValues","_a","cached","_b","generateMockData","formatLastUpdated","dateString","date","diffHours","diffDays","getContributionLevel","count","calculateYearsExperience","experienceData","skillExperience","exp","end","start","years","skill","useGitStats","config","cacheTTL","loading","ref","error","dataSource","isDummy","loadData","result","lastUpdatedText","computed","dataSourceText","props","__props","emit","__emit","currentColorScheme","settingsOpen","colorSchemes","contributionData","monthLabels","watch","newData","_c","processContributions","generateMonthLabels","totalContributions","weekTotal","generateEmptyWeeks","generateEmptyWeek","i","days","monthPositions","lastMonth","lastYear","weekIndex","firstDay","dateParts","year","month","getContributionLevelNumber","getTooltipText","dayNum","formattedDate","contributionText","onDayClick","toggleSettings","changeColorScheme","scheme","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_hoisted_4","_toDisplayString","_normalizeClass","_unref","_hoisted_5","_renderSlot","_ctx","_hoisted_6","_Fragment","_renderList","$event","_hoisted_7","_hoisted_8","_cache","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_normalizeStyle","_hoisted_13","_hoisted_14","_hoisted_16","_hoisted_17","totalProjects","totalCommits","projects","commits","index","profile","yearsExperience","customStatValue","params","_hoisted_15","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_createTextVNode","_hoisted_25","VueGitStats","app","ContributionGraph","StatsBreakdown"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
1
  (function(l,t){typeof exports=="object"&&typeof module!="undefined"?t(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],t):(l=typeof globalThis!="undefined"?globalThis:l||self,t(l.VueGitStats={},l.Vue))})(this,function(l,t){"use strict";var zt=Object.defineProperty,Jt=Object.defineProperties;var Kt=Object.getOwnPropertyDescriptors;var Y=Object.getOwnPropertySymbols;var Ht=Object.prototype.hasOwnProperty,Qt=Object.prototype.propertyIsEnumerable;var R=(l,t,k)=>t in l?zt(l,t,{enumerable:!0,configurable:!0,writable:!0,value:k}):l[t]=k,W=(l,t)=>{for(var k in t||(t={}))Ht.call(t,k)&&R(l,k,t[k]);if(Y)for(var k of Y(t))Qt.call(t,k)&&R(l,k,t[k]);return l},q=(l,t)=>Jt(l,Kt(t));var F=(l,t,k)=>new Promise((L,_)=>{var x=D=>{try{N(k.next(D))}catch(V){_(V)}},I=D=>{try{N(k.throw(D))}catch(V){_(V)}},N=D=>D.done?L(D.value):Promise.resolve(D.value).then(x,I);N((k=k.apply(l,t)).next())});function k(o){return F(this,null,function*(){const a=yield fetch(o);if(!a.ok)throw new Error(`Failed to fetch git stats: ${a.statusText}`);return a.json()})}function L(){const o=[],a=new Date,r=new Date(a);r.setDate(r.getDate()-r.getDay());const c=new Date(r);c.setDate(c.getDate()-52*7);const d=new Date(c);for(let p=0;p<53;p++){const m={weekStart:new Date(d).toISOString().split("T")[0],contributionDays:[]};for(let s=0;s<7;s++){const y=d>a,b=s===0||s===6;let u=0;y||(b?u=Math.random()<.3?Math.floor(Math.random()*5):0:u=Math.floor(Math.random()*15)),m.contributionDays.push({date:new Date(d).toISOString().split("T")[0],contributionCount:u,weekday:s}),d.setDate(d.getDate()+1)}o.push(m)}return o}function _(o={}){const{username:a="demo-user",platform:r="github",projectCount:c=30,commitCount:d=2500}=o,p=L();return p.reduce((m,s)=>m+s.contributionDays.reduce((y,b)=>y+b.contributionCount,0),0),{lastUpdated:new Date().toISOString(),profiles:[{username:a,platform:r,stats:{projectCount:c,commitCount:d,contributions:p.map(m=>({firstDay:m.weekStart,contributionDays:m.contributionDays}))}}],totals:{projectCount:c,commitCount:d},metadata:{fetchedAt:Date.now(),source:"dummy_data",isDummy:!0}}}function x(){const o=_({username:"demo-github",platform:"github",projectCount:45,commitCount:2847}),a=_({username:"demo-gitlab",platform:"gitlab",projectCount:7,commitCount:523});return{lastUpdated:new Date().toISOString(),profiles:[o.profiles[0],a.profiles[0]],totals:{projectCount:52,commitCount:3370},metadata:{fetchedAt:Date.now(),source:"dummy_data",isDummy:!0}}}function I(o="dummy-git-stats.json"){const a=_(),r=JSON.stringify(a,null," ");if(typeof window!="undefined"){const c=new Blob([r],{type:"application/json"}),d=URL.createObjectURL(c),p=document.createElement("a");p.href=d,p.download=o,p.click(),URL.revokeObjectURL(d)}else try{require("fs").writeFileSync(o,r),console.log(`✓ Dummy data saved to ${o}`)}catch(c){console.error("Failed to save dummy data:",c)}}function N(o){return F(this,null,function*(){var p,m;const{dataUrl:a,cacheKey:r="git_stats_cache",useStaleCache:c=!0}=o;try{const s=yield fetch(a);if(s.ok){const y=yield s.json();return typeof window!="undefined"&&localStorage.setItem(r,JSON.stringify(q(W({},y),{cachedAt:Date.now()}))),{data:y,error:null,source:"static",isDummy:((p=y.metadata)==null?void 0:p.isDummy)===!0}}}catch(s){console.warn("Failed to fetch from static file:",s)}if(c&&typeof window!="undefined")try{const s=localStorage.getItem(r);if(s){const y=JSON.parse(s);return{data:y,error:null,source:"cache",isDummy:((m=y.metadata)==null?void 0:m.isDummy)===!0}}}catch(s){console.warn("Failed to load from cache:",s)}return{data:z(),error:null,source:"mock",isDummy:!1}})}function D(o){const a=new Date(o),r=new Date,c=Math.floor((r.getTime()-a.getTime())/(1e3*60*60));if(c<1)return"just now";if(c<24)return`${c} hours ago`;const d=Math.floor(c/24);return d===1?"yesterday":d<7?`${d} days ago`:a.toLocaleDateString("en-US",{month:"short",day:"numeric",year:a.getFullYear()!==r.getFullYear()?"numeric":void 0})}function V(o){return o===0?0:o<=3?1:o<=6?2:o<=9?3:4}function O(o){if(o.length===0)return 0;const a={};return o.forEach(r=>{var m;const c=r.endDate?new Date(r.endDate):new Date,d=new Date(r.startDate),p=(c.getTime()-d.getTime())/(1e3*60*60*24*365.25);(m=r.skills)==null||m.forEach(s=>{a[s]||(a[s]=0),a[s]+=p})}),Math.max(...Object.values(a),0)}function z(){return{lastUpdated:new Date().toISOString(),profiles:[{username:"mockuser",platform:"github",stats:{projectCount:30,commitCount:2500,contributions:[]}}],totals:{projectCount:30,commitCount:2500},metadata:{source:"mock",fetchedAt:Date.now()}}}function M(o={}){const{dataUrl:a="/data/git-stats.json",cacheTTL:r=24*60*60*1e3,useStaleCache:c=!0,cacheKey:d="git_stats_cache"}=o,p=t.ref(!1),m=t.ref(null),s=t.ref(null),y=t.ref(null),b=t.ref(!1);function u(){return F(this,null,function*(){p.value=!0,m.value=null;try{const g=yield N({dataUrl:a,cacheTTL:r,cacheKey:d,useStaleCache:c});return s.value=g.data,m.value=g.error,y.value=g.source,b.value=g.isDummy,g.data}catch(g){return m.value=g instanceof Error?g:new Error("Failed to load data"),null}finally{p.value=!1}})}const i=t.computed(()=>{var g;return(g=s.value)!=null&&g.lastUpdated?D(s.value.lastUpdated):""}),S=t.computed(()=>{if(b.value)return"⚠️ Using dummy data for testing";switch(y.value){case"static":return"Real-time data";case"cache":return"Cached data";case"mock":return"Sample data";default:return""}});return u(),{data:s,loading:p,error:m,dataSource:y,dataSourceText:S,lastUpdatedText:i,isDummy:b,loadData:u}}const J={class:"git-contribution-graph"},K={class:"graph-header"},H={class:"header-info"},Q={class:"contribution-count"},X={key:0,class:"header-actions"},Z={key:0,class:"settings-dropdown"},tt=["onClick"],et={key:0,class:"loading-state"},ot={key:1,class:"graph-container"},at={class:"graph-content-wrapper"},nt={class:"months-row"},st={class:"months-container"},rt={class:"grid-container"},lt={class:"contribution-grid"},ct=["title","onClick"],it={class:"graph-footer"},dt={key:0,class:"last-updated"},mt=t.defineComponent({__name:"ContributionGraph",props:{dataUrl:{default:"/data/git-stats.json"},profileIndex:{default:0},colorScheme:{default:"green"},showSettings:{type:Boolean,default:!0},cacheTTL:{default:24*60*60*1e3}},emits:["day-click","color-scheme-change"],setup(o,{emit:a}){const r=o,c=a,{data:d,loading:p,dataSourceText:m,lastUpdatedText:s,isDummy:y}=M({dataUrl:r.dataUrl,cacheTTL:r.cacheTTL}),b=t.ref(r.colorScheme),u=t.ref(!1),i=["green","blue","purple","orange"],S=t.ref([]),g=t.ref([]);t.watch(d,e=>{var n,f,h;if((h=(f=(n=e==null?void 0:e.profiles)==null?void 0:n[r.profileIndex])==null?void 0:f.stats)!=null&&h.contributions){const E=e.profiles[r.profileIndex].stats.contributions;E&&(S.value=v(E),Ot())}else S.value=[]},{immediate:!0});const w=t.computed(()=>!S.value||S.value.length===0?0:S.value.reduce((e,n)=>!n.days||!Array.isArray(n.days)?e:e+n.days.reduce((f,h)=>f+(h.count||0),0),0));function v(e){if(!e||!Array.isArray(e))return C();const n=e.map(f=>({weekStart:f.firstDay||"",days:f.contributionDays.map(h=>{var E;return{date:h.date||"",count:(E=h.contributionCount)!=null?E:0,weekday:h.weekday||0}})}));for(;n.length<53;)n.push(B());return n}function C(){const e=[];for(let n=0;n<53;n++)e.push(B());return e}function B(){const e=[];for(let n=0;n<7;n++)e.push({date:"",count:0,weekday:n});return{weekStart:"",days:e}}function Ot(){if(!S.value||S.value.length===0){g.value=[];return}const e=[];let n=-1,f=-1;S.value.forEach((h,E)=>{if(!h.days||h.days.length===0)return;const j=h.days[0].date;if(!j)return;const U=j.split("-");if(U.length!==3)return;const[T,$]=U.map(Number);if(!(isNaN(T)||isNaN($))&&($!==n||T!==f)){const qt=new Date(T,$-1,1);e.push({week:E,month:$-1,year:T,label:qt.toLocaleDateString("en-US",{month:"short"})}),n=$,f=T}}),g.value=e}function Gt(e){return`level-${At(e)} ${b.value}`}function At(e){return e===0?0:e<=3?1:e<=6?2:e<=9?3:4}function Pt(e){if(!e.date)return"";const[n,f,h]=e.date.split("-").map(Number),j=new Date(n,f-1,h).toLocaleDateString("en-US",{weekday:"short",year:"numeric",month:"short",day:"numeric"}),U=e.count===1?"contribution":"contributions";return`${e.count} ${U} on ${j}`}function Yt(e){c("day-click",{date:e.date,count:e.count})}function Rt(){u.value=!u.value}function Wt(e){b.value=e,u.value=!1,c("color-scheme-change",e)}return(e,n)=>(t.openBlock(),t.createElementBlock("div",J,[t.createElementVNode("div",K,[t.createElementVNode("div",H,[t.createElementVNode("h5",Q,t.toDisplayString(w.value.toLocaleString())+" contributions in the last year ",1),t.createElementVNode("small",{class:t.normalizeClass(["data-source-text",{"is-dummy":t.unref(y)}])},t.toDisplayString(t.unref(m)),3)]),o.showSettings?(t.openBlock(),t.createElementBlock("div",X,[t.createElementVNode("button",{class:"settings-btn",type:"button",onClick:Rt},[t.renderSlot(e.$slots,"settings-icon",{},()=>[n[0]||(n[0]=t.createTextVNode("⚙️",-1))],!0),n[1]||(n[1]=t.createTextVNode(" Settings ",-1))]),u.value?(t.openBlock(),t.createElementBlock("div",Z,[(t.openBlock(),t.createElementBlock(t.Fragment,null,t.renderList(i,f=>t.createElementVNode("button",{key:f,onClick:h=>Wt(f),class:"settings-item"},t.toDisplayString(f)+" theme ",9,tt)),64))])):t.createCommentVNode("",!0)])):t.createCommentVNode("",!0)]),t.unref(p)?(t.openBlock(),t.createElementBlock("div",et,[...n[2]||(n[2]=[t.createElementVNode("div",{class:"spinner"},null,-1),t.createElementVNode("span",null,"Loading contributions...",-1)])])):(t.openBlock(),t.createElementBlock("div",ot,[t.createElementVNode("div",at,[t.createElementVNode("div",nt,[n[3]||(n[3]=t.createElementVNode("div",{class:"month-spacer"},null,-1)),t.createElementVNode("div",st,[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(g.value,f=>(t.openBlock(),t.createElementBlock("div",{key:`${f.year}-${f.month}`,class:"month-label",style:t.normalizeStyle({gridColumn:`${f.week+1} / span 1`})},t.toDisplayString(f.label),5))),128))])]),t.createElementVNode("div",rt,[n[4]||(n[4]=t.createStaticVNode('<div class="day-labels" data-v-f1ff100d><div class="day-label" data-v-f1ff100d>Mon</div><div class="day-label" data-v-f1ff100d></div><div class="day-label" data-v-f1ff100d>Wed</div><div class="day-label" data-v-f1ff100d></div><div class="day-label" data-v-f1ff100d>Fri</div><div class="day-label" data-v-f1ff100d></div><div class="day-label" data-v-f1ff100d></div></div>',1)),t.createElementVNode("div",lt,[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(S.value,f=>(t.openBlock(),t.createElementBlock("div",{key:f.weekStart,class:"contribution-week"},[(t.openBlock(!0),t.createElementBlock(t.Fragment,null,t.renderList(f.days,h=>(t.openBlock(),t.createElementBlock("div",{key:h.date,class:t.normalizeClass(["contribution-day",Gt(h.count)]),title:Pt(h),onClick:E=>Yt(h)},null,10,ct))),128))]))),128))])])]),t.createElementVNode("div",it,[t.unref(s)?(t.openBlock(),t.createElementBlock("small",dt," Last updated: "+t.toDisplayString(t.unref(s)),1)):t.createCommentVNode("",!0),n[5]||(n[5]=t.createStaticVNode('<div class="legend" data-v-f1ff100d><small class="legend-label" data-v-f1ff100d>Less</small><div class="legend-squares" data-v-f1ff100d><div class="contribution-day level-0" data-v-f1ff100d></div><div class="contribution-day level-1" data-v-f1ff100d></div><div class="contribution-day level-2" data-v-f1ff100d></div><div class="contribution-day level-3" data-v-f1ff100d></div><div class="contribution-day level-4" data-v-f1ff100d></div></div><small class="legend-label" data-v-f1ff100d>More</small></div>',1))])]))]))}}),G=(o,a)=>{const r=o.__vccOpts||o;for(const[c,d]of a)r[c]=d;return r},A=G(mt,[["__scopeId","data-v-f1ff100d"]]),ut={class:"git-stats-breakdown"},ft={class:"stats-grid"},pt={class:"stat-card"},yt={class:"stat-icon"},ht={class:"stat-content"},gt={class:"stat-value"},kt={class:"stat-card"},St={class:"stat-icon"},bt={class:"stat-content"},Dt={key:0,class:"stat-loading"},Et={key:1,class:"stat-value"},_t={class:"stat-card"},Ct={class:"stat-icon"},Nt={class:"stat-content"},wt={key:0,class:"stat-loading"},Vt={key:1,class:"stat-value"},Bt={key:0,class:"stat-card"},Tt={class:"stat-icon"},$t={class:"stat-content"},Lt={key:0,class:"stat-loading"},jt={key:1,class:"stat-value"},Ut={class:"stat-label"},Ft={class:"stats-footer"},xt={key:0,class:"data-source"},It={key:0},Mt=t.defineComponent({__name:"StatsBreakdown",props:{dataUrl:{default:"/data/git-stats.json"},profileIndexes:{default:()=>[]},experienceData:{default:()=>[]},showCustomStat:{type:Boolean,default:!0},customStatCalculator:{type:[Function,null],default:null},cacheTTL:{default:24*60*60*1e3}},setup(o){const a=o,{data:r,loading:c,dataSourceText:d,lastUpdatedText:p}=M({dataUrl:a.dataUrl,cacheTTL:a.cacheTTL}),m=t.ref(0),s=t.ref(0);t.watch(r,u=>{var i,S;if(u)if(a.profileIndexes.length>0){let g=0,w=0;a.profileIndexes.forEach(v=>{var B;const C=(B=u.profiles)==null?void 0:B[v];C!=null&&C.stats&&(g+=C.stats.projectCount||0,w+=C.stats.commitCount||0)}),m.value=g,s.value=w}else m.value=((i=u.totals)==null?void 0:i.projectCount)||0,s.value=((S=u.totals)==null?void 0:S.commitCount)||0},{immediate:!0});const y=t.computed(()=>O(a.experienceData).toFixed(1)),b=t.computed(()=>{if(a.customStatCalculator){const w={projects:m.value,commits:s.value,years:parseFloat(y.value)};return a.customStatCalculator(w)}return(m.value*1.5+s.value*1.2+parseFloat(y.value)*1.5).toFixed(2)});return(u,i)=>(t.openBlock(),t.createElementBlock("div",ut,[t.createElementVNode("div",ft,[t.createElementVNode("div",pt,[t.createElementVNode("div",yt,[t.renderSlot(u.$slots,"icon-experience",{},()=>[i[0]||(i[0]=t.createTextVNode("⏱️",-1))],!0)]),t.createElementVNode("div",ht,[t.createElementVNode("div",gt,t.toDisplayString(y.value),1),i[1]||(i[1]=t.createElementVNode("div",{class:"stat-label"},"Years Experience",-1))])]),t.createElementVNode("div",kt,[t.createElementVNode("div",St,[t.renderSlot(u.$slots,"icon-projects",{},()=>[i[2]||(i[2]=t.createTextVNode("📦",-1))],!0)]),t.createElementVNode("div",bt,[t.unref(c)?(t.openBlock(),t.createElementBlock("div",Dt,[...i[3]||(i[3]=[t.createElementVNode("div",{class:"spinner"},null,-1)])])):(t.openBlock(),t.createElementBlock("div",Et,t.toDisplayString(m.value),1)),i[4]||(i[4]=t.createElementVNode("div",{class:"stat-label"},"Projects",-1))])]),t.createElementVNode("div",_t,[t.createElementVNode("div",Ct,[t.renderSlot(u.$slots,"icon-commits",{},()=>[i[5]||(i[5]=t.createTextVNode("💻",-1))],!0)]),t.createElementVNode("div",Nt,[t.unref(c)?(t.openBlock(),t.createElementBlock("div",wt,[...i[6]||(i[6]=[t.createElementVNode("div",{class:"spinner"},null,-1)])])):(t.openBlock(),t.createElementBlock("div",Vt,t.toDisplayString(s.value),1)),i[7]||(i[7]=t.createElementVNode("div",{class:"stat-label"},"Commits",-1))])]),o.showCustomStat?(t.openBlock(),t.createElementBlock("div",Bt,[t.createElementVNode("div",Tt,[t.renderSlot(u.$slots,"icon-custom",{},()=>[i[8]||(i[8]=t.createTextVNode("☕",-1))],!0)]),t.createElementVNode("div",$t,[t.unref(c)?(t.openBlock(),t.createElementBlock("div",Lt,[...i[9]||(i[9]=[t.createElementVNode("div",{class:"spinner"},null,-1)])])):(t.openBlock(),t.createElementBlock("div",jt,t.toDisplayString(b.value),1)),t.createElementVNode("div",Ut,[t.renderSlot(u.$slots,"custom-stat-label",{},()=>[i[10]||(i[10]=t.createTextVNode("Coffee Consumed",-1))],!0)])])])):t.createCommentVNode("",!0)]),t.createElementVNode("div",Ft,[t.unref(d)?(t.openBlock(),t.createElementBlock("small",xt,[t.createTextVNode(t.toDisplayString(t.unref(d))+" ",1),t.unref(p)?(t.openBlock(),t.createElementBlock("span",It," · "+t.toDisplayString(t.unref(p)),1)):t.createCommentVNode("",!0)])):t.createCommentVNode("",!0)])]))}}),P=G(Mt,[["__scopeId","data-v-97689125"]]),vt={install(o){o.component("ContributionGraph",A),o.component("StatsBreakdown",P)}};l.ContributionGraph=A,l.StatsBreakdown=P,l.calculateYearsExperience=O,l.default=vt,l.fetchGitStats=N,l.fetchGitStatsAPI=k,l.formatLastUpdated=D,l.generateDummyContributions=L,l.generateDummyStats=_,l.generateMultiProfileDummyStats=x,l.getContributionLevel=V,l.saveDummyDataToFile=I,l.useGitStats=M,Object.defineProperties(l,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
2
- //# sourceMappingURL=vue-git-stats.umd.js.map
2
+ //# sourceMappingURL=vue.umd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vue.umd.js","sources":["../../core/src/api/fetchGitStats.ts","../../core/src/utils/generateDummyData.js","../../core/src/index.ts","../src/composables/useGitStats.ts","../src/components/ContributionGraph.vue","../src/components/StatsBreakdown.vue","../src/index.ts"],"sourcesContent":["import type { GitStatsData } from '../types'\r\n\r\nexport async function fetchGitStats(url: string): Promise<GitStatsData> {\r\n\tconst response = await fetch(url)\r\n\tif (!response.ok) {\r\n\t\tthrow new Error(`Failed to fetch git stats: ${response.statusText}`)\r\n\t}\r\n\treturn response.json()\r\n}\r\n","/**\n * Generate realistic dummy data for testing and development\n */\n\n/**\n * Generate dummy contribution data (53 weeks)\n */\nexport function generateDummyContributions() {\n\tconst weeks = []\n\tconst now = new Date()\n\n\t// Get the Sunday that starts the week containing today\n\tconst endDate = new Date(now)\n\tendDate.setDate(endDate.getDate() - endDate.getDay())\n\n\t// Go back exactly 52 weeks\n\tconst startDate = new Date(endDate)\n\tstartDate.setDate(startDate.getDate() - 52 * 7)\n\n\tconst currentDate = new Date(startDate)\n\n\tfor (let week = 0; week < 53; week++) {\n\t\tconst weekData = {\n\t\t\tweekStart: new Date(currentDate).toISOString().split('T')[0],\n\t\t\tcontributionDays: [],\n\t\t}\n\n\t\tfor (let day = 0; day < 7; day++) {\n\t\t\tconst isInFuture = currentDate > now\n\t\t\tconst isWeekend = day === 0 || day === 6\n\n\t\t\t// More realistic pattern: fewer commits on weekends, none in future\n\t\t\tlet dayCount = 0\n\t\t\tif (!isInFuture) {\n\t\t\t\tif (isWeekend) {\n\t\t\t\t\tdayCount =\n\t\t\t\t\t\tMath.random() < 0.3 ? Math.floor(Math.random() * 5) : 0\n\t\t\t\t} else {\n\t\t\t\t\tdayCount = Math.floor(Math.random() * 15)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tweekData.contributionDays.push({\n\t\t\t\tdate: new Date(currentDate).toISOString().split('T')[0],\n\t\t\t\tcontributionCount: dayCount,\n\t\t\t\tweekday: day,\n\t\t\t})\n\t\t\tcurrentDate.setDate(currentDate.getDate() + 1)\n\t\t}\n\n\t\tweeks.push(weekData)\n\t}\n\n\treturn weeks\n}\n\n/**\n * Generate complete dummy stats data\n */\nexport function generateDummyStats(options = {}) {\n\tconst {\n\t\tusername = 'demo-user',\n\t\tplatform = 'github',\n\t\tprojectCount = 30,\n\t\tcommitCount = 2500,\n\t} = options\n\n\tconst contributions = generateDummyContributions()\n\tconst totalContributions = contributions.reduce((total, week) => {\n\t\treturn (\n\t\t\ttotal +\n\t\t\tweek.contributionDays.reduce(\n\t\t\t\t(sum, day) => sum + day.contributionCount,\n\t\t\t\t0\n\t\t\t)\n\t\t)\n\t}, 0)\n\n\treturn {\n\t\tlastUpdated: new Date().toISOString(),\n\t\tprofiles: [\n\t\t\t{\n\t\t\t\tusername,\n\t\t\t\tplatform,\n\t\t\t\tstats: {\n\t\t\t\t\tprojectCount,\n\t\t\t\t\tcommitCount,\n\t\t\t\t\tcontributions: contributions.map((week) => ({\n\t\t\t\t\t\tfirstDay: week.weekStart,\n\t\t\t\t\t\tcontributionDays: week.contributionDays,\n\t\t\t\t\t})),\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\ttotals: {\n\t\t\tprojectCount,\n\t\t\tcommitCount,\n\t\t},\n\t\tmetadata: {\n\t\t\tfetchedAt: Date.now(),\n\t\t\tsource: 'dummy_data',\n\t\t\tisDummy: true,\n\t\t},\n\t}\n}\n\n/**\n * Generate multiple profiles dummy data\n */\nexport function generateMultiProfileDummyStats() {\n\tconst githubProfile = generateDummyStats({\n\t\tusername: 'demo-github',\n\t\tplatform: 'github',\n\t\tprojectCount: 45,\n\t\tcommitCount: 2847,\n\t})\n\n\tconst gitlabProfile = generateDummyStats({\n\t\tusername: 'demo-gitlab',\n\t\tplatform: 'gitlab',\n\t\tprojectCount: 7,\n\t\tcommitCount: 523,\n\t})\n\n\treturn {\n\t\tlastUpdated: new Date().toISOString(),\n\t\tprofiles: [githubProfile.profiles[0], gitlabProfile.profiles[0]],\n\t\ttotals: {\n\t\t\tprojectCount: 45 + 7,\n\t\t\tcommitCount: 2847 + 523,\n\t\t},\n\t\tmetadata: {\n\t\t\tfetchedAt: Date.now(),\n\t\t\tsource: 'dummy_data',\n\t\t\tisDummy: true,\n\t\t},\n\t}\n}\n\n/**\n * Save dummy data to a file (for testing)\n */\nexport function saveDummyDataToFile(filepath = 'dummy-git-stats.json') {\n\tconst data = generateDummyStats()\n\tconst json = JSON.stringify(data, null, '\\t')\n\n\tif (typeof window !== 'undefined') {\n\t\t// Browser environment - trigger download\n\t\tconst blob = new Blob([json], { type: 'application/json' })\n\t\tconst url = URL.createObjectURL(blob)\n\t\tconst a = document.createElement('a')\n\t\ta.href = url\n\t\ta.download = filepath\n\t\ta.click()\n\t\tURL.revokeObjectURL(url)\n\t} else {\n\t\t// Node environment\n\t\ttry {\n\t\t\tconst fs = require('fs')\n\t\t\tfs.writeFileSync(filepath, json)\n\t\t\tconsole.log(`✓ Dummy data saved to ${filepath}`)\n\t\t} catch (err) {\n\t\t\tconsole.error('Failed to save dummy data:', err)\n\t\t}\n\t}\n}\n","// packages/core/src/index.ts\n// Framework-agnostic core logic\n\n// Re-export everything from types\nexport type {\n\tColorScheme,\n\tContributionDay,\n\tContributionWeek,\n\tProfile,\n\tGitStatsData,\n\tExperienceEntry,\n\tDataSource,\n\tPlatform,\n\tProfileStats,\n\tStatsTotals,\n\tStatsMetadata,\n\tCustomStatCalculator,\n\tCustomStatCalculatorParams,\n} from './types/index.js'\n\n// Export API functions\nexport { fetchGitStats as fetchGitStatsAPI } from './api/fetchGitStats.js'\n\n// Export utility functions with explicit imports\nexport {\n\tgenerateDummyStats,\n\tgenerateDummyContributions,\n\tgenerateMultiProfileDummyStats,\n\tsaveDummyDataToFile,\n} from './utils/generateDummyData.js'\n\n// Core data fetching (framework-agnostic)\nimport type { GitStatsData } from './types/index.js'\n\nexport interface FetchOptions {\n\tdataUrl: string\n\tcacheTTL?: number\n\tcacheKey?: string\n\tuseStaleCache?: boolean\n}\n\nexport interface DataResult<T> {\n\tdata: T | null\n\terror: Error | null\n\tsource: 'static' | 'cache' | 'mock' | 'dummy' | null\n\tisDummy: boolean\n}\n\n/**\n * Framework-agnostic data fetcher\n */\nexport async function fetchGitStats(\n\toptions: FetchOptions\n): Promise<DataResult<GitStatsData>> {\n\tconst { dataUrl, cacheKey = 'git_stats_cache', useStaleCache = true } = options\n\n\ttry {\n\t\t// Try static file first\n\t\tconst response = await fetch(dataUrl)\n\t\tif (response.ok) {\n\t\t\tconst data = await response.json()\n\t\t\t// Cache the data\n\t\t\tif (typeof window !== 'undefined') {\n\t\t\t\tlocalStorage.setItem(\n\t\t\t\t\tcacheKey,\n\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t...data,\n\t\t\t\t\t\tcachedAt: Date.now(),\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tdata,\n\t\t\t\terror: null,\n\t\t\t\tsource: 'static',\n\t\t\t\tisDummy: data.metadata?.isDummy === true,\n\t\t\t}\n\t\t}\n\t} catch (err) {\n\t\tconsole.warn('Failed to fetch from static file:', err)\n\t}\n\n\t// Try cache\n\tif (useStaleCache && typeof window !== 'undefined') {\n\t\ttry {\n\t\t\tconst cached = localStorage.getItem(cacheKey)\n\t\t\tif (cached) {\n\t\t\t\tconst data = JSON.parse(cached)\n\t\t\t\treturn {\n\t\t\t\t\tdata,\n\t\t\t\t\terror: null,\n\t\t\t\t\tsource: 'cache',\n\t\t\t\t\tisDummy: data.metadata?.isDummy === true,\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconsole.warn('Failed to load from cache:', err)\n\t\t}\n\t}\n\n\t// Fallback to mock\n\tconst mockData = generateMockData()\n\treturn {\n\t\tdata: mockData,\n\t\terror: null,\n\t\tsource: 'mock',\n\t\tisDummy: false,\n\t}\n}\n\n/**\n * Format last updated time\n */\nexport function formatLastUpdated(dateString: string): string {\n\tconst date = new Date(dateString)\n\tconst now = new Date()\n\tconst diffHours = Math.floor((now.getTime() - date.getTime()) / (1000 * 60 * 60))\n\n\tif (diffHours < 1) return 'just now'\n\tif (diffHours < 24) return `${diffHours} hours ago`\n\n\tconst diffDays = Math.floor(diffHours / 24)\n\tif (diffDays === 1) return 'yesterday'\n\tif (diffDays < 7) return `${diffDays} days ago`\n\n\treturn date.toLocaleDateString('en-US', {\n\t\tmonth: 'short',\n\t\tday: 'numeric',\n\t\tyear: date.getFullYear() !== now.getFullYear() ? 'numeric' : undefined,\n\t})\n}\n\n/**\n * Get contribution level (0-4)\n */\nexport function getContributionLevel(count: number): number {\n\tif (count === 0) return 0\n\tif (count <= 3) return 1\n\tif (count <= 6) return 2\n\tif (count <= 9) return 3\n\treturn 4\n}\n\n/**\n * Calculate years of experience\n */\nexport function calculateYearsExperience(\n\texperienceData: { startDate: string; endDate: string | null; skills?: string[] }[]\n): number {\n\tif (experienceData.length === 0) return 0\n\n\tconst skillExperience: Record<string, number> = {}\n\n\texperienceData.forEach((exp) => {\n\t\tconst end = exp.endDate ? new Date(exp.endDate) : new Date()\n\t\tconst start = new Date(exp.startDate)\n\t\tconst years = (end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24 * 365.25)\n\n\t\texp.skills?.forEach((skill) => {\n\t\t\tif (!skillExperience[skill]) {\n\t\t\t\tskillExperience[skill] = 0\n\t\t\t}\n\t\t\tskillExperience[skill] += years\n\t\t})\n\t})\n\n\treturn Math.max(...Object.values(skillExperience), 0)\n}\n\n// Mock data generator\nfunction generateMockData(): GitStatsData {\n\treturn {\n\t\tlastUpdated: new Date().toISOString(),\n\t\tprofiles: [\n\t\t\t{\n\t\t\t\tusername: 'mockuser',\n\t\t\t\tplatform: 'github',\n\t\t\t\tstats: {\n\t\t\t\t\tprojectCount: 30,\n\t\t\t\t\tcommitCount: 2500,\n\t\t\t\t\tcontributions: [],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\ttotals: {\n\t\t\tprojectCount: 30,\n\t\t\tcommitCount: 2500,\n\t\t},\n\t\tmetadata: {\n\t\t\tsource: 'mock',\n\t\t\tfetchedAt: Date.now(),\n\t\t},\n\t}\n}","import { ref, computed } from 'vue'\r\nimport {\r\n\tfetchGitStats,\r\n\tformatLastUpdated,\r\n\ttype GitStatsData,\r\n\ttype DataSource,\r\n} from '@git-stats-components/core'\r\n\r\nexport interface UseGitStatsConfig {\r\n\tdataUrl?: string\r\n\tcacheTTL?: number\r\n\tuseStaleCache?: boolean\r\n\tcacheKey?: string\r\n}\r\n\r\nexport function useGitStats(config: UseGitStatsConfig = {}) {\r\n\tconst {\r\n\t\tdataUrl = '/data/git-stats.json',\r\n\t\tcacheTTL = 24 * 60 * 60 * 1000,\r\n\t\tuseStaleCache = true,\r\n\t\tcacheKey = 'git_stats_cache',\r\n\t} = config\r\n\r\n\tconst loading = ref(false)\r\n\tconst error = ref<Error | null>(null)\r\n\tconst data = ref<GitStatsData | null>(null)\r\n\tconst dataSource = ref<DataSource | null>(null)\r\n\tconst isDummy = ref(false)\r\n\r\n\t/**\r\n\t * Load data with fallback strategy\r\n\t */\r\n\tasync function loadData(): Promise<GitStatsData | null> {\r\n\t\tloading.value = true\r\n\t\terror.value = null\r\n\r\n\t\ttry {\r\n\t\t\tconst result = await fetchGitStats({\r\n\t\t\t\tdataUrl,\r\n\t\t\t\tcacheTTL,\r\n\t\t\t\tcacheKey,\r\n\t\t\t\tuseStaleCache,\r\n\t\t\t})\r\n\r\n\t\t\tdata.value = result.data\r\n\t\t\terror.value = result.error\r\n\t\t\tdataSource.value = result.source\r\n\t\t\tisDummy.value = result.isDummy\r\n\r\n\t\t\treturn result.data\r\n\t\t} catch (err) {\r\n\t\t\terror.value =\r\n\t\t\t\terr instanceof Error ? err : new Error('Failed to load data')\r\n\t\t\treturn null\r\n\t\t} finally {\r\n\t\t\tloading.value = false\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Format \"last updated\" text\r\n\t */\r\n\tconst lastUpdatedText = computed(() => {\r\n\t\tif (!data.value?.lastUpdated) return ''\r\n\t\treturn formatLastUpdated(data.value.lastUpdated)\r\n\t})\r\n\r\n\t/**\r\n\t * Computed data source display text\r\n\t */\r\n\tconst dataSourceText = computed(() => {\r\n\t\tif (isDummy.value) {\r\n\t\t\treturn '⚠️ Using dummy data for testing'\r\n\t\t}\r\n\r\n\t\tswitch (dataSource.value) {\r\n\t\t\tcase 'static':\r\n\t\t\t\treturn 'Real-time data'\r\n\t\t\tcase 'cache':\r\n\t\t\t\treturn 'Cached data'\r\n\t\t\tcase 'mock':\r\n\t\t\t\treturn 'Sample data'\r\n\t\t\tdefault:\r\n\t\t\t\treturn ''\r\n\t\t}\r\n\t})\r\n\r\n\t// Auto-load on creation\r\n\tloadData()\r\n\r\n\treturn {\r\n\t\tdata,\r\n\t\tloading,\r\n\t\terror,\r\n\t\tdataSource,\r\n\t\tdataSourceText,\r\n\t\tlastUpdatedText,\r\n\t\tisDummy,\r\n\t\tloadData,\r\n\t}\r\n}\r\n","<template>\r\n\t<div class=\"git-contribution-graph\">\r\n\t\t<!-- Header -->\r\n\t\t<div class=\"graph-header\">\r\n\t\t\t<div class=\"header-info\">\r\n\t\t\t\t<h5 class=\"contribution-count\">\r\n\t\t\t\t\t{{ totalContributions.toLocaleString() }} contributions in\r\n\t\t\t\t\tthe last year\r\n\t\t\t\t</h5>\r\n\t\t\t\t<small\r\n\t\t\t\t\tclass=\"data-source-text\"\r\n\t\t\t\t\t:class=\"{ 'is-dummy': isDummy }\"\r\n\t\t\t\t>\r\n\t\t\t\t\t{{ dataSourceText }}\r\n\t\t\t\t</small>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"header-actions\" v-if=\"showSettings\">\r\n\t\t\t\t<button\r\n\t\t\t\t\tclass=\"settings-btn\"\r\n\t\t\t\t\ttype=\"button\"\r\n\t\t\t\t\t@click=\"toggleSettings\"\r\n\t\t\t\t>\r\n\t\t\t\t\t<slot name=\"settings-icon\">⚙️</slot>\r\n\t\t\t\t\tSettings\r\n\t\t\t\t</button>\r\n\t\t\t\t<div v-if=\"settingsOpen\" class=\"settings-dropdown\">\r\n\t\t\t\t\t<button\r\n\t\t\t\t\t\tv-for=\"scheme in colorSchemes\"\r\n\t\t\t\t\t\t:key=\"scheme\"\r\n\t\t\t\t\t\t@click=\"changeColorScheme(scheme)\"\r\n\t\t\t\t\t\tclass=\"settings-item\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t\t{{ scheme }} theme\r\n\t\t\t\t\t</button>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\r\n\t\t<!-- Loading state -->\r\n\t\t<div v-if=\"loading\" class=\"loading-state\">\r\n\t\t\t<div class=\"spinner\"></div>\r\n\t\t\t<span>Loading contributions...</span>\r\n\t\t</div>\r\n\r\n\t\t<!-- Contribution grid -->\r\n\t\t<div v-else class=\"graph-container\">\r\n\t\t\t<div class=\"graph-content-wrapper\">\r\n\t\t\t\t<!-- Month labels -->\r\n\t\t\t\t<div class=\"months-row\">\r\n\t\t\t\t\t<div class=\"month-spacer\"></div>\r\n\t\t\t\t\t<div class=\"months-container\">\r\n\t\t\t\t\t\t<div\r\n\t\t\t\t\t\t\tv-for=\"month in monthLabels\"\r\n\t\t\t\t\t\t\t:key=\"`${month.year}-${month.month}`\"\r\n\t\t\t\t\t\t\tclass=\"month-label\"\r\n\t\t\t\t\t\t\t:style=\"{\r\n\t\t\t\t\t\t\t\tgridColumn: `${month.week + 1} / span 1`,\r\n\t\t\t\t\t\t\t}\"\r\n\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t{{ month.label }}\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\r\n\t\t\t\t<!-- Grid with day labels -->\r\n\t\t\t\t<div class=\"grid-container\">\r\n\t\t\t\t\t<!-- Day labels -->\r\n\t\t\t\t\t<div class=\"day-labels\">\r\n\t\t\t\t\t\t<div class=\"day-label\">Mon</div>\r\n\t\t\t\t\t\t<div class=\"day-label\"></div>\r\n\t\t\t\t\t\t<div class=\"day-label\">Wed</div>\r\n\t\t\t\t\t\t<div class=\"day-label\"></div>\r\n\t\t\t\t\t\t<div class=\"day-label\">Fri</div>\r\n\t\t\t\t\t\t<div class=\"day-label\"></div>\r\n\t\t\t\t\t\t<div class=\"day-label\"></div>\r\n\t\t\t\t\t</div>\r\n\r\n\t\t\t\t\t<!-- Contribution squares -->\r\n\t\t\t\t\t<div class=\"contribution-grid\">\r\n\t\t\t\t\t\t<div\r\n\t\t\t\t\t\t\tv-for=\"week in contributionData\"\r\n\t\t\t\t\t\t\t:key=\"week.weekStart\"\r\n\t\t\t\t\t\t\tclass=\"contribution-week\"\r\n\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t<div\r\n\t\t\t\t\t\t\t\tv-for=\"day in week.days\"\r\n\t\t\t\t\t\t\t\t:key=\"day.date\"\r\n\t\t\t\t\t\t\t\tclass=\"contribution-day\"\r\n\t\t\t\t\t\t\t\t:class=\"getContributionLevel(day.count)\"\r\n\t\t\t\t\t\t\t\t:title=\"getTooltipText(day)\"\r\n\t\t\t\t\t\t\t\t@click=\"onDayClick(day)\"\r\n\t\t\t\t\t\t\t></div>\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Legend -->\r\n\t\t\t<div class=\"graph-footer\">\r\n\t\t\t\t<small class=\"last-updated\" v-if=\"lastUpdatedText\">\r\n\t\t\t\t\tLast updated: {{ lastUpdatedText }}\r\n\t\t\t\t</small>\r\n\t\t\t\t<div class=\"legend\">\r\n\t\t\t\t\t<small class=\"legend-label\">Less</small>\r\n\t\t\t\t\t<div class=\"legend-squares\">\r\n\t\t\t\t\t\t<div class=\"contribution-day level-0\"></div>\r\n\t\t\t\t\t\t<div class=\"contribution-day level-1\"></div>\r\n\t\t\t\t\t\t<div class=\"contribution-day level-2\"></div>\r\n\t\t\t\t\t\t<div class=\"contribution-day level-3\"></div>\r\n\t\t\t\t\t\t<div class=\"contribution-day level-4\"></div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<small class=\"legend-label\">More</small>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from 'vue'\r\nimport { useGitStats } from '../composables/useGitStats'\r\nimport {\r\n\ttype ColorScheme,\r\n\ttype ContributionWeek,\r\n} from '@git-stats-components/core'\r\n\r\ninterface ProcessedWeek {\r\n\tweekStart: string\r\n\tdays: ProcessedDay[]\r\n}\r\n\r\ninterface ProcessedDay {\r\n\tdate: string\r\n\tcount: number\r\n\tweekday: number\r\n}\r\n\r\ninterface MonthLabel {\r\n\tweek: number\r\n\tmonth: number\r\n\tyear: number\r\n\tlabel: string\r\n}\r\n\r\ninterface Props {\r\n\tdataUrl?: string\r\n\tprofileIndex?: number\r\n\tcolorScheme?: ColorScheme\r\n\tshowSettings?: boolean\r\n\tcacheTTL?: number\r\n}\r\n\r\ninterface Emits {\r\n\t(e: 'day-click', data: { date: string; count: number }): void\r\n\t(e: 'color-scheme-change', scheme: ColorScheme): void\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n\tdataUrl: '/data/git-stats.json',\r\n\tprofileIndex: 0,\r\n\tcolorScheme: 'green',\r\n\tshowSettings: true,\r\n\tcacheTTL: 24 * 60 * 60 * 1000,\r\n})\r\n\r\nconst emit = defineEmits<Emits>()\r\n\r\n// Use the shared composable\r\nconst { data, loading, dataSourceText, lastUpdatedText, isDummy } = useGitStats(\r\n\t{\r\n\t\tdataUrl: props.dataUrl,\r\n\t\tcacheTTL: props.cacheTTL,\r\n\t}\r\n)\r\n\r\nconst currentColorScheme = ref<ColorScheme>(props.colorScheme)\r\nconst settingsOpen = ref(false)\r\nconst colorSchemes: ColorScheme[] = ['green', 'blue', 'purple', 'orange']\r\nconst contributionData = ref<ProcessedWeek[]>([])\r\nconst monthLabels = ref<MonthLabel[]>([])\r\n\r\n// Process contribution data when loaded\r\nwatch(\r\n\tdata,\r\n\t(newData) => {\r\n\t\tif (newData?.profiles?.[props.profileIndex]?.stats?.contributions) {\r\n\t\t\tconst contributions =\r\n\t\t\t\tnewData.profiles[props.profileIndex].stats.contributions\r\n\t\t\tif (contributions) {\r\n\t\t\t\tcontributionData.value = processContributions(contributions)\r\n\t\t\t\tgenerateMonthLabels()\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tcontributionData.value = []\r\n\t\t}\r\n\t},\r\n\t{ immediate: true }\r\n)\r\n\r\nconst totalContributions = computed(() => {\r\n\tif (!contributionData.value || contributionData.value.length === 0) {\r\n\t\treturn 0\r\n\t}\r\n\r\n\treturn contributionData.value.reduce((total, week) => {\r\n\t\tif (!week.days || !Array.isArray(week.days)) {\r\n\t\t\treturn total\r\n\t\t}\r\n\t\treturn (\r\n\t\t\ttotal +\r\n\t\t\tweek.days.reduce((weekTotal, day) => {\r\n\t\t\t\treturn weekTotal + (day.count || 0)\r\n\t\t\t}, 0)\r\n\t\t)\r\n\t}, 0)\r\n})\r\n\r\nfunction processContributions(\r\n\tcontributions: ContributionWeek[]\r\n): ProcessedWeek[] {\r\n\tif (!contributions || !Array.isArray(contributions)) {\r\n\t\treturn generateEmptyWeeks()\r\n\t}\r\n\r\n\tconst weeks = contributions.map((week) => ({\r\n\t\tweekStart: week.firstDay || '',\r\n\t\tdays: week.contributionDays.map((day) => ({\r\n\t\t\tdate: day.date || '',\r\n\t\t\tcount: day.contributionCount ?? 0,\r\n\t\t\tweekday: day.weekday || 0,\r\n\t\t})),\r\n\t}))\r\n\r\n\twhile (weeks.length < 53) {\r\n\t\tweeks.push(generateEmptyWeek())\r\n\t}\r\n\r\n\treturn weeks\r\n}\r\n\r\nfunction generateEmptyWeeks(): ProcessedWeek[] {\r\n\tconst weeks: ProcessedWeek[] = []\r\n\tfor (let i = 0; i < 53; i++) {\r\n\t\tweeks.push(generateEmptyWeek())\r\n\t}\r\n\treturn weeks\r\n}\r\n\r\nfunction generateEmptyWeek(): ProcessedWeek {\r\n\tconst days: ProcessedDay[] = []\r\n\tfor (let i = 0; i < 7; i++) {\r\n\t\tdays.push({ date: '', count: 0, weekday: i })\r\n\t}\r\n\treturn { weekStart: '', days }\r\n}\r\n\r\nfunction generateMonthLabels(): void {\r\n\tif (!contributionData.value || contributionData.value.length === 0) {\r\n\t\tmonthLabels.value = []\r\n\t\treturn\r\n\t}\r\n\r\n\tconst monthPositions: MonthLabel[] = []\r\n\tlet lastMonth = -1\r\n\tlet lastYear = -1\r\n\r\n\tcontributionData.value.forEach((week, weekIndex) => {\r\n\t\tif (!week.days || week.days.length === 0) return\r\n\r\n\t\tconst firstDay = week.days[0].date\r\n\t\tif (!firstDay) return\r\n\r\n\t\tconst dateParts = firstDay.split('-')\r\n\t\tif (dateParts.length !== 3) return\r\n\r\n\t\tconst [year, month] = dateParts.map(Number)\r\n\t\tif (isNaN(year) || isNaN(month)) return\r\n\r\n\t\tif (month !== lastMonth || year !== lastYear) {\r\n\t\t\tconst date = new Date(year, month - 1, 1)\r\n\t\t\tmonthPositions.push({\r\n\t\t\t\tweek: weekIndex,\r\n\t\t\t\tmonth: month - 1,\r\n\t\t\t\tyear: year,\r\n\t\t\t\tlabel: date.toLocaleDateString('en-US', { month: 'short' }),\r\n\t\t\t})\r\n\t\t\tlastMonth = month\r\n\t\t\tlastYear = year\r\n\t\t}\r\n\t})\r\n\r\n\tmonthLabels.value = monthPositions\r\n}\r\n\r\nfunction getContributionLevel(count: number): string {\r\n\tconst level = getContributionLevelNumber(count)\r\n\treturn `level-${level} ${currentColorScheme.value}`\r\n}\r\n\r\nfunction getContributionLevelNumber(count: number): number {\r\n\tif (count === 0) return 0\r\n\tif (count <= 3) return 1\r\n\tif (count <= 6) return 2\r\n\tif (count <= 9) return 3\r\n\treturn 4\r\n}\r\n\r\nfunction getTooltipText(day: ProcessedDay): string {\r\n\tif (!day.date) return ''\r\n\r\n\tconst [year, month, dayNum] = day.date.split('-').map(Number)\r\n\tconst date = new Date(year, month - 1, dayNum)\r\n\r\n\tconst formattedDate = date.toLocaleDateString('en-US', {\r\n\t\tweekday: 'short',\r\n\t\tyear: 'numeric',\r\n\t\tmonth: 'short',\r\n\t\tday: 'numeric',\r\n\t})\r\n\r\n\tconst contributionText = day.count === 1 ? 'contribution' : 'contributions'\r\n\treturn `${day.count} ${contributionText} on ${formattedDate}`\r\n}\r\n\r\nfunction onDayClick(day: ProcessedDay): void {\r\n\temit('day-click', { date: day.date, count: day.count })\r\n}\r\n\r\nfunction toggleSettings(): void {\r\n\tsettingsOpen.value = !settingsOpen.value\r\n}\r\n\r\nfunction changeColorScheme(scheme: ColorScheme): void {\r\n\tcurrentColorScheme.value = scheme\r\n\tsettingsOpen.value = false\r\n\temit('color-scheme-change', scheme)\r\n}\r\n</script>\r\n\r\n<style scoped>\r\n.graph-content-wrapper {\r\n\tjustify-items: anchor-center;\r\n}\r\n.git-contribution-graph {\r\n\tfont-family:\r\n\t\t-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica,\r\n\t\tArial, sans-serif;\r\n\tfont-size: 12px;\r\n\tbackground: transparent;\r\n\tcolor: #e6edf3;\r\n\tpadding: 16px;\r\n\tmax-width: 1200px;\r\n\tmargin: 0 auto;\r\n\twidth: 100%;\r\n}\r\n\r\n.graph-header {\r\n\tdisplay: flex;\r\n\tjustify-content: space-between;\r\n\talign-items: center;\r\n\tmargin-bottom: 16px;\r\n}\r\n\r\n.contribution-count {\r\n\tmargin: 0 0 4px 0;\r\n\tfont-size: 16px;\r\n\tfont-weight: 600;\r\n}\r\n\r\n.data-source-text {\r\n\tcolor: #7d8590;\r\n}\r\n\r\n.data-source-text.is-dummy {\r\n\tcolor: #f85149;\r\n\tfont-weight: 600;\r\n\tbackground: rgba(248, 81, 73, 0.1);\r\n\tpadding: 2px 8px;\r\n\tborder-radius: 4px;\r\n}\r\n\r\n.settings-btn {\r\n\tbackground: transparent;\r\n\tborder: 1px solid #30363d;\r\n\tcolor: #7d8590;\r\n\tpadding: 6px 12px;\r\n\tborder-radius: 6px;\r\n\tcursor: pointer;\r\n\tfont-size: 12px;\r\n}\r\n\r\n.settings-btn:hover {\r\n\tbackground: #21262d;\r\n\tcolor: #e6edf3;\r\n}\r\n\r\n.header-actions {\r\n\tposition: relative;\r\n}\r\n\r\n.settings-dropdown {\r\n\tposition: absolute;\r\n\tright: 0;\r\n\ttop: 100%;\r\n\tmargin-top: 4px;\r\n\tbackground: #21262d;\r\n\tborder: 1px solid #30363d;\r\n\tborder-radius: 6px;\r\n\tpadding: 4px;\r\n\tz-index: 10;\r\n\tmin-width: 150px;\r\n}\r\n\r\n.settings-item {\r\n\tdisplay: block;\r\n\twidth: 100%;\r\n\tbackground: transparent;\r\n\tborder: none;\r\n\tcolor: #e6edf3;\r\n\tpadding: 8px 12px;\r\n\ttext-align: left;\r\n\tcursor: pointer;\r\n\tborder-radius: 4px;\r\n}\r\n\r\n.settings-item:hover {\r\n\tbackground: #30363d;\r\n}\r\n\r\n.loading-state {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\tgap: 12px;\r\n\tpadding: 40px;\r\n\tcolor: #7d8590;\r\n}\r\n\r\n.spinner {\r\n\twidth: 20px;\r\n\theight: 20px;\r\n\tborder: 2px solid #30363d;\r\n\tborder-top-color: #58a6ff;\r\n\tborder-radius: 50%;\r\n\tanimation: spin 1s linear infinite;\r\n}\r\n\r\n@keyframes spin {\r\n\tto {\r\n\t\ttransform: rotate(360deg);\r\n\t}\r\n}\r\n\r\n.months-row {\r\n\tdisplay: flex;\r\n\tmargin-bottom: 4px;\r\n}\r\n\r\n.month-spacer {\r\n\twidth: 27px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.months-container {\r\n\tdisplay: grid;\r\n\tgrid-template-columns: repeat(53, 11px);\r\n\tgap: 2px;\r\n\tflex: 1;\r\n\tmargin-left: 3px;\r\n\tmin-width: 0;\r\n}\r\n\r\n.month-label {\r\n\tfont-size: 11px;\r\n\tcolor: #7d8590;\r\n\ttext-align: left;\r\n}\r\n\r\n.grid-container {\r\n\tdisplay: flex;\r\n\tgap: 3px;\r\n\tmin-width: fit-content;\r\n}\r\n\r\n.day-labels {\r\n\tdisplay: flex;\r\n\tflex-direction: column;\r\n\twidth: 24px;\r\n\tgap: 2px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.day-label {\r\n\theight: 11px;\r\n\tfont-size: 9px;\r\n\tcolor: #7d8590;\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n}\r\n\r\n.contribution-grid {\r\n\tdisplay: flex;\r\n\tgap: 2px;\r\n\tflex: 1;\r\n\tmin-width: 0;\r\n}\r\n\r\n.contribution-week {\r\n\tdisplay: flex;\r\n\tflex-direction: column;\r\n\tgap: 2px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.contribution-day {\r\n\twidth: 11px;\r\n\theight: 11px;\r\n\tborder-radius: 2px;\r\n\tcursor: pointer;\r\n\toutline: 1px solid rgba(27, 31, 36, 0.06);\r\n\toutline-offset: -1px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n/* Color schemes */\r\n.contribution-day.level-0.green {\r\n\tbackground-color: #161b22;\r\n}\r\n.contribution-day.level-1.green {\r\n\tbackground-color: #0e4429;\r\n}\r\n.contribution-day.level-2.green {\r\n\tbackground-color: #006d32;\r\n}\r\n.contribution-day.level-3.green {\r\n\tbackground-color: #26a641;\r\n}\r\n.contribution-day.level-4.green {\r\n\tbackground-color: #39d353;\r\n}\r\n\r\n.contribution-day.level-0.blue {\r\n\tbackground-color: #161b22;\r\n}\r\n.contribution-day.level-1.blue {\r\n\tbackground-color: #0a3069;\r\n}\r\n.contribution-day.level-2.blue {\r\n\tbackground-color: #1f6feb;\r\n}\r\n.contribution-day.level-3.blue {\r\n\tbackground-color: #58a6ff;\r\n}\r\n.contribution-day.level-4.blue {\r\n\tbackground-color: #79c0ff;\r\n}\r\n\r\n.contribution-day.level-0.purple {\r\n\tbackground-color: #161b22;\r\n}\r\n.contribution-day.level-1.purple {\r\n\tbackground-color: #3b1e6d;\r\n}\r\n.contribution-day.level-2.purple {\r\n\tbackground-color: #8250df;\r\n}\r\n.contribution-day.level-3.purple {\r\n\tbackground-color: #a475f9;\r\n}\r\n.contribution-day.level-4.purple {\r\n\tbackground-color: #d2a8ff;\r\n}\r\n\r\n.contribution-day.level-0.orange {\r\n\tbackground-color: #161b22;\r\n}\r\n.contribution-day.level-1.orange {\r\n\tbackground-color: #7d2d00;\r\n}\r\n.contribution-day.level-2.orange {\r\n\tbackground-color: #da7b00;\r\n}\r\n.contribution-day.level-3.orange {\r\n\tbackground-color: #ffa348;\r\n}\r\n.contribution-day.level-4.orange {\r\n\tbackground-color: #ffb366;\r\n}\r\n\r\n.contribution-day:hover {\r\n\toutline: 1px solid #c9d1d9;\r\n\toutline-offset: -1px;\r\n}\r\n\r\n.graph-footer {\r\n\tdisplay: flex;\r\n\tjustify-content: space-between;\r\n\talign-items: center;\r\n\tmargin-top: 8px;\r\n}\r\n\r\n.last-updated {\r\n\tcolor: #7d8590;\r\n}\r\n\r\n.legend {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tgap: 4px;\r\n}\r\n\r\n.legend-label {\r\n\tcolor: #7d8590;\r\n}\r\n\r\n.legend-squares {\r\n\tdisplay: flex;\r\n\tgap: 2px;\r\n}\r\n\r\n.legend-squares .contribution-day {\r\n\tcursor: default;\r\n}\r\n\r\n.legend-squares .contribution-day:hover {\r\n\toutline: none;\r\n}\r\n\r\n/* Mobile responsive */\r\n@media (max-width: 768px) {\r\n\t.git-contribution-graph {\r\n\t\tpadding: 12px;\r\n\t\tfont-size: 11px;\r\n\t\toverflow-x: auto;\r\n\t}\r\n\t.months-container {\r\n\t\tgrid-template-columns: repeat(53, 10px);\r\n\t\tgap: 1px;\r\n\t}\r\n\t.grid-container {\r\n\t\tgap: 2px;\r\n\t}\r\n\t.day-labels {\r\n\t\twidth: 20px;\r\n\t}\r\n\t.day-label {\r\n\t\theight: 10px;\r\n\t\tfont-size: 8px;\r\n\t}\r\n\t.contribution-grid {\r\n\t\tgap: 1px;\r\n\t}\r\n\t.contribution-week {\r\n\t\tgap: 1px;\r\n\t}\r\n\t.contribution-day {\r\n\t\twidth: 10px;\r\n\t\theight: 10px;\r\n\t}\r\n\t.settings-btn {\r\n\t\tfont-size: 10px;\r\n\t\tpadding: 4px 8px;\r\n\t}\r\n\t.contribution-count {\r\n\t\tfont-size: 14px;\r\n\t}\r\n}\r\n\r\n@media (max-width: 480px) {\r\n\t.graph-header {\r\n\t\tflex-direction: column;\r\n\t\talign-items: flex-start;\r\n\t\tgap: 8px;\r\n\t}\r\n}\r\n</style>\r\n","<template>\r\n\t<div class=\"git-stats-breakdown\">\r\n\t\t<div class=\"stats-grid\">\r\n\t\t\t<!-- Years Experience -->\r\n\t\t\t<div class=\"stat-card\">\r\n\t\t\t\t<div class=\"stat-icon\">\r\n\t\t\t\t\t<slot name=\"icon-experience\">⏱️</slot>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"stat-content\">\r\n\t\t\t\t\t<div class=\"stat-value\">{{ yearsExperience }}</div>\r\n\t\t\t\t\t<div class=\"stat-label\">Years Experience</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Projects -->\r\n\t\t\t<div class=\"stat-card\">\r\n\t\t\t\t<div class=\"stat-icon\">\r\n\t\t\t\t\t<slot name=\"icon-projects\">📦</slot>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"stat-content\">\r\n\t\t\t\t\t<div v-if=\"loading\" class=\"stat-loading\">\r\n\t\t\t\t\t\t<div class=\"spinner\"></div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div v-else class=\"stat-value\">{{ totalProjects }}</div>\r\n\t\t\t\t\t<div class=\"stat-label\">Projects</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Commits -->\r\n\t\t\t<div class=\"stat-card\">\r\n\t\t\t\t<div class=\"stat-icon\">\r\n\t\t\t\t\t<slot name=\"icon-commits\">💻</slot>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"stat-content\">\r\n\t\t\t\t\t<div v-if=\"loading\" class=\"stat-loading\">\r\n\t\t\t\t\t\t<div class=\"spinner\"></div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div v-else class=\"stat-value\">{{ totalCommits }}</div>\r\n\t\t\t\t\t<div class=\"stat-label\">Commits</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Custom Stat -->\r\n\t\t\t<div class=\"stat-card\" v-if=\"showCustomStat\">\r\n\t\t\t\t<div class=\"stat-icon\">\r\n\t\t\t\t\t<slot name=\"icon-custom\">☕</slot>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"stat-content\">\r\n\t\t\t\t\t<div v-if=\"loading\" class=\"stat-loading\">\r\n\t\t\t\t\t\t<div class=\"spinner\"></div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div v-else class=\"stat-value\">{{ customStatValue }}</div>\r\n\t\t\t\t\t<div class=\"stat-label\">\r\n\t\t\t\t\t\t<slot name=\"custom-stat-label\">Coffee Consumed</slot>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\r\n\t\t<!-- Footer -->\r\n\t\t<div class=\"stats-footer\">\r\n\t\t\t<small v-if=\"dataSourceText\" class=\"data-source\">\r\n\t\t\t\t{{ dataSourceText }}\r\n\t\t\t\t<span v-if=\"lastUpdatedText\"> · {{ lastUpdatedText }}</span>\r\n\t\t\t</small>\r\n\t\t</div>\r\n\t</div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from 'vue'\r\nimport { useGitStats } from '../composables/useGitStats'\r\nimport {\r\n\tcalculateYearsExperience,\r\n\ttype ExperienceEntry,\r\n\ttype CustomStatCalculator,\r\n\ttype CustomStatCalculatorParams,\r\n} from '@git-stats-components/core'\r\n\r\ninterface Props {\r\n\tdataUrl?: string\r\n\tprofileIndexes?: number[]\r\n\texperienceData?: ExperienceEntry[]\r\n\tshowCustomStat?: boolean\r\n\tcustomStatCalculator?: CustomStatCalculator | null\r\n\tcacheTTL?: number\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n\tdataUrl: '/data/git-stats.json',\r\n\tprofileIndexes: () => [],\r\n\texperienceData: () => [],\r\n\tshowCustomStat: true,\r\n\tcustomStatCalculator: null,\r\n\tcacheTTL: 24 * 60 * 60 * 1000,\r\n})\r\n\r\n// Use the shared composable\r\nconst { data, loading, dataSourceText, lastUpdatedText } = useGitStats({\r\n\tdataUrl: props.dataUrl,\r\n\tcacheTTL: props.cacheTTL,\r\n})\r\n\r\nconst totalProjects = ref(0)\r\nconst totalCommits = ref(0)\r\n\r\n// Calculate totals when data loads\r\nwatch(\r\n\tdata,\r\n\t(newData) => {\r\n\t\tif (!newData) return\r\n\r\n\t\t// If profileIndexes specified, sum only those profiles\r\n\t\tif (props.profileIndexes.length > 0) {\r\n\t\t\tlet projects = 0\r\n\t\t\tlet commits = 0\r\n\r\n\t\t\tprops.profileIndexes.forEach((index) => {\r\n\t\t\t\tconst profile = newData.profiles?.[index]\r\n\t\t\t\tif (profile?.stats) {\r\n\t\t\t\t\tprojects += profile.stats.projectCount || 0\r\n\t\t\t\t\tcommits += profile.stats.commitCount || 0\r\n\t\t\t\t}\r\n\t\t\t})\r\n\r\n\t\t\ttotalProjects.value = projects\r\n\t\t\ttotalCommits.value = commits\r\n\t\t} else {\r\n\t\t\t// Use totals from data (aggregates all profiles)\r\n\t\t\ttotalProjects.value = newData.totals?.projectCount || 0\r\n\t\t\ttotalCommits.value = newData.totals?.commitCount || 0\r\n\t\t}\r\n\t},\r\n\t{ immediate: true }\r\n)\r\n\r\n// Calculate years of experience using core utility\r\nconst yearsExperience = computed(() => {\r\n\tconst years = calculateYearsExperience(props.experienceData)\r\n\treturn years.toFixed(1)\r\n})\r\n\r\n// Custom stat calculation\r\nconst customStatValue = computed(() => {\r\n\tif (props.customStatCalculator) {\r\n\t\tconst params: CustomStatCalculatorParams = {\r\n\t\t\tprojects: totalProjects.value,\r\n\t\t\tcommits: totalCommits.value,\r\n\t\t\tyears: parseFloat(yearsExperience.value),\r\n\t\t}\r\n\t\treturn props.customStatCalculator(params)\r\n\t}\r\n\r\n\t// Default: fun coffee calculation\r\n\tconst kA = 1.5\r\n\tconst kB = 1.2\r\n\tconst kC = 1.5\r\n\r\n\tconst cups =\r\n\t\ttotalProjects.value * kA +\r\n\t\ttotalCommits.value * kB +\r\n\t\tparseFloat(yearsExperience.value) * kC\r\n\r\n\treturn cups.toFixed(2)\r\n})\r\n</script>\r\n\r\n<style scoped>\r\n.git-stats-breakdown {\r\n\tfont-family:\r\n\t\t-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica,\r\n\t\tArial, sans-serif;\r\n\tpadding: 40px 20px;\r\n\tmax-width: 1200px;\r\n\tmargin: 0 auto;\r\n}\r\n\r\n.stats-grid {\r\n\tdisplay: grid;\r\n\tgrid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\r\n\tgap: 24px;\r\n\tmargin-bottom: 24px;\r\n}\r\n\r\n.stat-card {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tgap: 16px;\r\n\tpadding: 24px;\r\n\tbackground: rgba(255, 255, 255, 0.05);\r\n\tborder-radius: 12px;\r\n\tborder: 1px solid rgba(255, 255, 255, 0.1);\r\n\ttransition: all 0.3s ease;\r\n}\r\n\r\n.stat-card:hover {\r\n\tbackground: rgba(255, 255, 255, 0.08);\r\n\tborder-color: rgba(255, 255, 255, 0.2);\r\n\ttransform: translateY(-2px);\r\n}\r\n\r\n.stat-icon {\r\n\tfont-size: 48px;\r\n\tline-height: 1;\r\n\topacity: 0.9;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.stat-content {\r\n\tflex: 1;\r\n\tmin-width: 0;\r\n}\r\n\r\n.stat-value {\r\n\tfont-size: 32px;\r\n\tfont-weight: bold;\r\n\tline-height: 1.2;\r\n\tcolor: #e6edf3;\r\n\tmargin-bottom: 4px;\r\n}\r\n\r\n.stat-label {\r\n\tfont-size: 14px;\r\n\tcolor: #7d8590;\r\n\ttext-transform: uppercase;\r\n\tletter-spacing: 0.5px;\r\n}\r\n\r\n.stat-loading {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\theight: 38px;\r\n}\r\n\r\n.spinner {\r\n\twidth: 24px;\r\n\theight: 24px;\r\n\tborder: 3px solid rgba(255, 255, 255, 0.1);\r\n\tborder-top-color: #58a6ff;\r\n\tborder-radius: 50%;\r\n\tanimation: spin 1s linear infinite;\r\n}\r\n\r\n@keyframes spin {\r\n\tto {\r\n\t\ttransform: rotate(360deg);\r\n\t}\r\n}\r\n\r\n.stats-footer {\r\n\tdisplay: flex;\r\n\tflex-direction: column;\r\n\talign-items: center;\r\n\tgap: 8px;\r\n\tpadding-top: 16px;\r\n\tborder-top: 1px solid rgba(255, 255, 255, 0.1);\r\n}\r\n\r\n.data-source {\r\n\tfont-size: 12px;\r\n\tcolor: #7d8590;\r\n\ttext-align: center;\r\n}\r\n\r\n/* Responsive */\r\n@media (max-width: 768px) {\r\n\t.git-stats-breakdown {\r\n\t\tpadding: 20px 12px;\r\n\t}\r\n\t.stats-grid {\r\n\t\tgrid-template-columns: 1fr;\r\n\t\tgap: 16px;\r\n\t}\r\n\t.stat-card {\r\n\t\tpadding: 16px;\r\n\t}\r\n\t.stat-icon {\r\n\t\tfont-size: 36px;\r\n\t}\r\n\t.stat-value {\r\n\t\tfont-size: 24px;\r\n\t}\r\n\t.stat-label {\r\n\t\tfont-size: 12px;\r\n\t}\r\n}\r\n\r\n@media (max-width: 480px) {\r\n\t.stat-card {\r\n\t\tflex-direction: column;\r\n\t\ttext-align: center;\r\n\t}\r\n\t.stat-content {\r\n\t\twidth: 100%;\r\n\t}\r\n}\r\n</style>\r\n","// Main entry point for git-stats-components\n\nimport type { App } from 'vue'\nimport ContributionGraph from './components/ContributionGraph.vue'\nimport StatsBreakdown from './components/StatsBreakdown.vue'\nimport { useGitStats } from './composables/useGitStats'\n\n// Re-export everything from core\nexport * from '@git-stats-components/core'\n\n// Export Vue-specific components and composables\nexport { ContributionGraph, StatsBreakdown, useGitStats }\n\n// Auto-import styles\nimport './styles/index.css'\n\n// Plugin for Vue.use()\nexport interface VueGitStatsPlugin {\n\tinstall: (app: App) => void\n}\n\nconst VueGitStats: VueGitStatsPlugin = {\n\tinstall(app: App) {\n\t\tapp.component('ContributionGraph', ContributionGraph)\n\t\tapp.component('StatsBreakdown', StatsBreakdown)\n\t},\n}\n\n// Export as default for Vue.use()\nexport default VueGitStats\n"],"names":["fetchGitStats","url","__async","response","generateDummyContributions","weeks","now","endDate","startDate","currentDate","week","weekData","day","isInFuture","isWeekend","dayCount","generateDummyStats","options","username","platform","projectCount","commitCount","contributions","total","sum","generateMultiProfileDummyStats","githubProfile","gitlabProfile","saveDummyDataToFile","filepath","data","json","blob","a","err","dataUrl","cacheKey","useStaleCache","__spreadProps","__spreadValues","_a","cached","_b","generateMockData","formatLastUpdated","dateString","date","diffHours","diffDays","getContributionLevel","count","calculateYearsExperience","experienceData","skillExperience","exp","end","start","years","skill","useGitStats","config","cacheTTL","loading","ref","error","dataSource","isDummy","loadData","result","lastUpdatedText","computed","dataSourceText","props","__props","emit","__emit","currentColorScheme","settingsOpen","colorSchemes","contributionData","monthLabels","watch","newData","_c","processContributions","generateMonthLabels","totalContributions","weekTotal","generateEmptyWeeks","generateEmptyWeek","i","days","monthPositions","lastMonth","lastYear","weekIndex","firstDay","dateParts","year","month","getContributionLevelNumber","getTooltipText","dayNum","formattedDate","contributionText","onDayClick","toggleSettings","changeColorScheme","scheme","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_hoisted_4","_toDisplayString","_normalizeClass","_unref","_hoisted_5","_renderSlot","_ctx","_hoisted_6","_Fragment","_renderList","$event","_hoisted_7","_hoisted_8","_cache","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_normalizeStyle","_hoisted_13","_hoisted_14","_hoisted_16","_hoisted_17","totalProjects","totalCommits","projects","commits","index","profile","yearsExperience","customStatValue","params","_hoisted_15","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_createTextVNode","_hoisted_25","VueGitStats","app","ContributionGraph","StatsBreakdown"],"mappings":"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"}
package/package.json CHANGED
@@ -1,60 +1,72 @@
1
1
  {
2
- "name": "@git-stats-components/vue",
3
- "version": "1.0.0",
4
- "description": "Beautiful GitHub/GitLab/Bitbucket contribution graphs for Vue 3",
5
- "author": "Derek Johnston",
6
- "license": "MIT",
7
- "type": "module",
8
- "main": "./dist/vue.umd.js",
9
- "module": "./dist/vue.es.js",
10
- "types": "./dist/index.d.ts",
11
- "exports": {
12
- ".": {
13
- "types": "./dist/index.d.ts",
14
- "import": "./dist/vue.es.js",
15
- "require": "./dist/vue.umd.js"
16
- },
17
- "./style.css": "./dist/style.css"
18
- },
19
- "files": [
20
- "dist"
21
- ],
22
- "keywords": [
23
- "vue",
24
- "vue3",
25
- "github",
26
- "gitlab",
27
- "bitbucket",
28
- "contributions",
29
- "stats",
30
- "component"
31
- ],
32
- "scripts": {
33
- "build": "vite build",
34
- "dev": "vite build --watch",
35
- "clean": "rm -rf dist",
36
- "test": "vitest run",
37
- "test:watch": "vitest",
38
- "test:ui": "vitest --ui"
39
- },
40
- "peerDependencies": {
41
- "vue": "^3.3.0"
42
- },
43
- "dependencies": {
44
- "@git-stats-components/core": "^1.0.0"
45
- },
46
- "devDependencies": {
47
- "@vitejs/plugin-vue": "^5.0.0",
48
- "@types/node": "^20.10.6",
49
- "@vue/test-utils": "^2.4.3",
50
- "@testing-library/jest-dom": "^6.1.5",
51
- "jsdom": "^23.0.1",
52
- "typescript": "^5.3.3",
53
- "vite": "^5.0.0",
54
- "vite-plugin-dts": "^3.7.0",
55
- "vitest": "^1.0.4",
56
- "@vitest/ui": "^1.0.4",
57
- "vue": "^3.4.0",
58
- "vue-tsc": "^2.0.0"
59
- }
60
- }
2
+ "name": "@git-stats-components/vue",
3
+ "version": "1.0.2",
4
+ "description": "Beautiful GitHub/GitLab/Bitbucket contribution graphs for Vue 3",
5
+ "author": "Derek Johnston",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "./dist/vue.umd.js",
9
+ "module": "./dist/vue.es.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/vue.es.js",
15
+ "require": "./dist/vue.umd.js"
16
+ },
17
+ "./style.css": "./dist/style.css"
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "README.md",
22
+ "LICENSE"
23
+ ],
24
+ "keywords": [
25
+ "vue",
26
+ "vue3",
27
+ "github",
28
+ "gitlab",
29
+ "bitbucket",
30
+ "contributions",
31
+ "stats",
32
+ "component",
33
+ "git-stats"
34
+ ],
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/derekjj/git-stats-components.git",
38
+ "directory": "packages/vue"
39
+ },
40
+ "bugs": {
41
+ "url": "https://github.com/derekjj/git-stats-components/issues"
42
+ },
43
+ "homepage": "https://github.com/derekjj/git-stats-components/tree/main/packages/vue#readme",
44
+ "peerDependencies": {
45
+ "vue": "^3.3.0"
46
+ },
47
+ "dependencies": {
48
+ "@git-stats-components/core": "^1.0.0"
49
+ },
50
+ "devDependencies": {
51
+ "@vitejs/plugin-vue": "^5.0.0",
52
+ "@types/node": "^20.10.6",
53
+ "@vue/test-utils": "^2.4.3",
54
+ "@testing-library/jest-dom": "^6.1.5",
55
+ "jsdom": "^23.0.1",
56
+ "typescript": "^5.3.3",
57
+ "vite": "^5.0.0",
58
+ "vite-plugin-dts": "^3.7.0",
59
+ "vitest": "^1.0.4",
60
+ "@vitest/ui": "^1.0.4",
61
+ "vue": "^3.4.0",
62
+ "vue-tsc": "^2.0.0"
63
+ },
64
+ "scripts": {
65
+ "build": "vite build",
66
+ "dev": "vite build --watch",
67
+ "clean": "rm -rf dist",
68
+ "test": "vitest run",
69
+ "test:watch": "vitest",
70
+ "test:ui": "vitest --ui"
71
+ }
72
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"vue-git-stats.es.js","sources":["../../core/src/api/fetchGitStats.ts","../../core/src/utils/generateDummyData.js","../../core/src/index.ts","../src/composables/useGitStats.ts","../src/components/ContributionGraph.vue","../src/components/StatsBreakdown.vue","../src/index.ts"],"sourcesContent":["import type { GitStatsData } from '../types'\r\n\r\nexport async function fetchGitStats(url: string): Promise<GitStatsData> {\r\n\tconst response = await fetch(url)\r\n\tif (!response.ok) {\r\n\t\tthrow new Error(`Failed to fetch git stats: ${response.statusText}`)\r\n\t}\r\n\treturn response.json()\r\n}\r\n","/**\n * Generate realistic dummy data for testing and development\n */\n\n/**\n * Generate dummy contribution data (53 weeks)\n */\nexport function generateDummyContributions() {\n\tconst weeks = []\n\tconst now = new Date()\n\n\t// Get the Sunday that starts the week containing today\n\tconst endDate = new Date(now)\n\tendDate.setDate(endDate.getDate() - endDate.getDay())\n\n\t// Go back exactly 52 weeks\n\tconst startDate = new Date(endDate)\n\tstartDate.setDate(startDate.getDate() - 52 * 7)\n\n\tconst currentDate = new Date(startDate)\n\n\tfor (let week = 0; week < 53; week++) {\n\t\tconst weekData = {\n\t\t\tweekStart: new Date(currentDate).toISOString().split('T')[0],\n\t\t\tcontributionDays: [],\n\t\t}\n\n\t\tfor (let day = 0; day < 7; day++) {\n\t\t\tconst isInFuture = currentDate > now\n\t\t\tconst isWeekend = day === 0 || day === 6\n\n\t\t\t// More realistic pattern: fewer commits on weekends, none in future\n\t\t\tlet dayCount = 0\n\t\t\tif (!isInFuture) {\n\t\t\t\tif (isWeekend) {\n\t\t\t\t\tdayCount =\n\t\t\t\t\t\tMath.random() < 0.3 ? Math.floor(Math.random() * 5) : 0\n\t\t\t\t} else {\n\t\t\t\t\tdayCount = Math.floor(Math.random() * 15)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tweekData.contributionDays.push({\n\t\t\t\tdate: new Date(currentDate).toISOString().split('T')[0],\n\t\t\t\tcontributionCount: dayCount,\n\t\t\t\tweekday: day,\n\t\t\t})\n\t\t\tcurrentDate.setDate(currentDate.getDate() + 1)\n\t\t}\n\n\t\tweeks.push(weekData)\n\t}\n\n\treturn weeks\n}\n\n/**\n * Generate complete dummy stats data\n */\nexport function generateDummyStats(options = {}) {\n\tconst {\n\t\tusername = 'demo-user',\n\t\tplatform = 'github',\n\t\tprojectCount = 30,\n\t\tcommitCount = 2500,\n\t} = options\n\n\tconst contributions = generateDummyContributions()\n\tconst totalContributions = contributions.reduce((total, week) => {\n\t\treturn (\n\t\t\ttotal +\n\t\t\tweek.contributionDays.reduce(\n\t\t\t\t(sum, day) => sum + day.contributionCount,\n\t\t\t\t0\n\t\t\t)\n\t\t)\n\t}, 0)\n\n\treturn {\n\t\tlastUpdated: new Date().toISOString(),\n\t\tprofiles: [\n\t\t\t{\n\t\t\t\tusername,\n\t\t\t\tplatform,\n\t\t\t\tstats: {\n\t\t\t\t\tprojectCount,\n\t\t\t\t\tcommitCount,\n\t\t\t\t\tcontributions: contributions.map((week) => ({\n\t\t\t\t\t\tfirstDay: week.weekStart,\n\t\t\t\t\t\tcontributionDays: week.contributionDays,\n\t\t\t\t\t})),\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\ttotals: {\n\t\t\tprojectCount,\n\t\t\tcommitCount,\n\t\t},\n\t\tmetadata: {\n\t\t\tfetchedAt: Date.now(),\n\t\t\tsource: 'dummy_data',\n\t\t\tisDummy: true,\n\t\t},\n\t}\n}\n\n/**\n * Generate multiple profiles dummy data\n */\nexport function generateMultiProfileDummyStats() {\n\tconst githubProfile = generateDummyStats({\n\t\tusername: 'demo-github',\n\t\tplatform: 'github',\n\t\tprojectCount: 45,\n\t\tcommitCount: 2847,\n\t})\n\n\tconst gitlabProfile = generateDummyStats({\n\t\tusername: 'demo-gitlab',\n\t\tplatform: 'gitlab',\n\t\tprojectCount: 7,\n\t\tcommitCount: 523,\n\t})\n\n\treturn {\n\t\tlastUpdated: new Date().toISOString(),\n\t\tprofiles: [githubProfile.profiles[0], gitlabProfile.profiles[0]],\n\t\ttotals: {\n\t\t\tprojectCount: 45 + 7,\n\t\t\tcommitCount: 2847 + 523,\n\t\t},\n\t\tmetadata: {\n\t\t\tfetchedAt: Date.now(),\n\t\t\tsource: 'dummy_data',\n\t\t\tisDummy: true,\n\t\t},\n\t}\n}\n\n/**\n * Save dummy data to a file (for testing)\n */\nexport function saveDummyDataToFile(filepath = 'dummy-git-stats.json') {\n\tconst data = generateDummyStats()\n\tconst json = JSON.stringify(data, null, '\\t')\n\n\tif (typeof window !== 'undefined') {\n\t\t// Browser environment - trigger download\n\t\tconst blob = new Blob([json], { type: 'application/json' })\n\t\tconst url = URL.createObjectURL(blob)\n\t\tconst a = document.createElement('a')\n\t\ta.href = url\n\t\ta.download = filepath\n\t\ta.click()\n\t\tURL.revokeObjectURL(url)\n\t} else {\n\t\t// Node environment\n\t\ttry {\n\t\t\tconst fs = require('fs')\n\t\t\tfs.writeFileSync(filepath, json)\n\t\t\tconsole.log(`✓ Dummy data saved to ${filepath}`)\n\t\t} catch (err) {\n\t\t\tconsole.error('Failed to save dummy data:', err)\n\t\t}\n\t}\n}\n","// packages/core/src/index.ts\n// Framework-agnostic core logic\n\n// Re-export everything from types\nexport type {\n\tColorScheme,\n\tContributionDay,\n\tContributionWeek,\n\tProfile,\n\tGitStatsData,\n\tExperienceEntry,\n\tDataSource,\n\tPlatform,\n\tProfileStats,\n\tStatsTotals,\n\tStatsMetadata,\n\tCustomStatCalculator,\n\tCustomStatCalculatorParams,\n} from './types/index.js'\n\n// Export API functions\nexport { fetchGitStats as fetchGitStatsAPI } from './api/fetchGitStats.js'\n\n// Export utility functions with explicit imports\nexport {\n\tgenerateDummyStats,\n\tgenerateDummyContributions,\n\tgenerateMultiProfileDummyStats,\n\tsaveDummyDataToFile,\n} from './utils/generateDummyData.js'\n\n// Core data fetching (framework-agnostic)\nimport type { GitStatsData } from './types/index.js'\n\nexport interface FetchOptions {\n\tdataUrl: string\n\tcacheTTL?: number\n\tcacheKey?: string\n\tuseStaleCache?: boolean\n}\n\nexport interface DataResult<T> {\n\tdata: T | null\n\terror: Error | null\n\tsource: 'static' | 'cache' | 'mock' | 'dummy' | null\n\tisDummy: boolean\n}\n\n/**\n * Framework-agnostic data fetcher\n */\nexport async function fetchGitStats(\n\toptions: FetchOptions\n): Promise<DataResult<GitStatsData>> {\n\tconst { dataUrl, cacheKey = 'git_stats_cache', useStaleCache = true } = options\n\n\ttry {\n\t\t// Try static file first\n\t\tconst response = await fetch(dataUrl)\n\t\tif (response.ok) {\n\t\t\tconst data = await response.json()\n\t\t\t// Cache the data\n\t\t\tif (typeof window !== 'undefined') {\n\t\t\t\tlocalStorage.setItem(\n\t\t\t\t\tcacheKey,\n\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t...data,\n\t\t\t\t\t\tcachedAt: Date.now(),\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tdata,\n\t\t\t\terror: null,\n\t\t\t\tsource: 'static',\n\t\t\t\tisDummy: data.metadata?.isDummy === true,\n\t\t\t}\n\t\t}\n\t} catch (err) {\n\t\tconsole.warn('Failed to fetch from static file:', err)\n\t}\n\n\t// Try cache\n\tif (useStaleCache && typeof window !== 'undefined') {\n\t\ttry {\n\t\t\tconst cached = localStorage.getItem(cacheKey)\n\t\t\tif (cached) {\n\t\t\t\tconst data = JSON.parse(cached)\n\t\t\t\treturn {\n\t\t\t\t\tdata,\n\t\t\t\t\terror: null,\n\t\t\t\t\tsource: 'cache',\n\t\t\t\t\tisDummy: data.metadata?.isDummy === true,\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconsole.warn('Failed to load from cache:', err)\n\t\t}\n\t}\n\n\t// Fallback to mock\n\tconst mockData = generateMockData()\n\treturn {\n\t\tdata: mockData,\n\t\terror: null,\n\t\tsource: 'mock',\n\t\tisDummy: false,\n\t}\n}\n\n/**\n * Format last updated time\n */\nexport function formatLastUpdated(dateString: string): string {\n\tconst date = new Date(dateString)\n\tconst now = new Date()\n\tconst diffHours = Math.floor((now.getTime() - date.getTime()) / (1000 * 60 * 60))\n\n\tif (diffHours < 1) return 'just now'\n\tif (diffHours < 24) return `${diffHours} hours ago`\n\n\tconst diffDays = Math.floor(diffHours / 24)\n\tif (diffDays === 1) return 'yesterday'\n\tif (diffDays < 7) return `${diffDays} days ago`\n\n\treturn date.toLocaleDateString('en-US', {\n\t\tmonth: 'short',\n\t\tday: 'numeric',\n\t\tyear: date.getFullYear() !== now.getFullYear() ? 'numeric' : undefined,\n\t})\n}\n\n/**\n * Get contribution level (0-4)\n */\nexport function getContributionLevel(count: number): number {\n\tif (count === 0) return 0\n\tif (count <= 3) return 1\n\tif (count <= 6) return 2\n\tif (count <= 9) return 3\n\treturn 4\n}\n\n/**\n * Calculate years of experience\n */\nexport function calculateYearsExperience(\n\texperienceData: { startDate: string; endDate: string | null; skills?: string[] }[]\n): number {\n\tif (experienceData.length === 0) return 0\n\n\tconst skillExperience: Record<string, number> = {}\n\n\texperienceData.forEach((exp) => {\n\t\tconst end = exp.endDate ? new Date(exp.endDate) : new Date()\n\t\tconst start = new Date(exp.startDate)\n\t\tconst years = (end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24 * 365.25)\n\n\t\texp.skills?.forEach((skill) => {\n\t\t\tif (!skillExperience[skill]) {\n\t\t\t\tskillExperience[skill] = 0\n\t\t\t}\n\t\t\tskillExperience[skill] += years\n\t\t})\n\t})\n\n\treturn Math.max(...Object.values(skillExperience), 0)\n}\n\n// Mock data generator\nfunction generateMockData(): GitStatsData {\n\treturn {\n\t\tlastUpdated: new Date().toISOString(),\n\t\tprofiles: [\n\t\t\t{\n\t\t\t\tusername: 'mockuser',\n\t\t\t\tplatform: 'github',\n\t\t\t\tstats: {\n\t\t\t\t\tprojectCount: 30,\n\t\t\t\t\tcommitCount: 2500,\n\t\t\t\t\tcontributions: [],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\ttotals: {\n\t\t\tprojectCount: 30,\n\t\t\tcommitCount: 2500,\n\t\t},\n\t\tmetadata: {\n\t\t\tsource: 'mock',\n\t\t\tfetchedAt: Date.now(),\n\t\t},\n\t}\n}","import { ref, computed } from 'vue'\r\nimport {\r\n\tfetchGitStats,\r\n\tformatLastUpdated,\r\n\ttype GitStatsData,\r\n\ttype DataSource,\r\n} from '@git-stats-components/core'\r\n\r\nexport interface UseGitStatsConfig {\r\n\tdataUrl?: string\r\n\tcacheTTL?: number\r\n\tuseStaleCache?: boolean\r\n\tcacheKey?: string\r\n}\r\n\r\nexport function useGitStats(config: UseGitStatsConfig = {}) {\r\n\tconst {\r\n\t\tdataUrl = '/data/git-stats.json',\r\n\t\tcacheTTL = 24 * 60 * 60 * 1000,\r\n\t\tuseStaleCache = true,\r\n\t\tcacheKey = 'git_stats_cache',\r\n\t} = config\r\n\r\n\tconst loading = ref(false)\r\n\tconst error = ref<Error | null>(null)\r\n\tconst data = ref<GitStatsData | null>(null)\r\n\tconst dataSource = ref<DataSource | null>(null)\r\n\tconst isDummy = ref(false)\r\n\r\n\t/**\r\n\t * Load data with fallback strategy\r\n\t */\r\n\tasync function loadData(): Promise<GitStatsData | null> {\r\n\t\tloading.value = true\r\n\t\terror.value = null\r\n\r\n\t\ttry {\r\n\t\t\tconst result = await fetchGitStats({\r\n\t\t\t\tdataUrl,\r\n\t\t\t\tcacheTTL,\r\n\t\t\t\tcacheKey,\r\n\t\t\t\tuseStaleCache,\r\n\t\t\t})\r\n\r\n\t\t\tdata.value = result.data\r\n\t\t\terror.value = result.error\r\n\t\t\tdataSource.value = result.source\r\n\t\t\tisDummy.value = result.isDummy\r\n\r\n\t\t\treturn result.data\r\n\t\t} catch (err) {\r\n\t\t\terror.value =\r\n\t\t\t\terr instanceof Error ? err : new Error('Failed to load data')\r\n\t\t\treturn null\r\n\t\t} finally {\r\n\t\t\tloading.value = false\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Format \"last updated\" text\r\n\t */\r\n\tconst lastUpdatedText = computed(() => {\r\n\t\tif (!data.value?.lastUpdated) return ''\r\n\t\treturn formatLastUpdated(data.value.lastUpdated)\r\n\t})\r\n\r\n\t/**\r\n\t * Computed data source display text\r\n\t */\r\n\tconst dataSourceText = computed(() => {\r\n\t\tif (isDummy.value) {\r\n\t\t\treturn '⚠️ Using dummy data for testing'\r\n\t\t}\r\n\r\n\t\tswitch (dataSource.value) {\r\n\t\t\tcase 'static':\r\n\t\t\t\treturn 'Real-time data'\r\n\t\t\tcase 'cache':\r\n\t\t\t\treturn 'Cached data'\r\n\t\t\tcase 'mock':\r\n\t\t\t\treturn 'Sample data'\r\n\t\t\tdefault:\r\n\t\t\t\treturn ''\r\n\t\t}\r\n\t})\r\n\r\n\t// Auto-load on creation\r\n\tloadData()\r\n\r\n\treturn {\r\n\t\tdata,\r\n\t\tloading,\r\n\t\terror,\r\n\t\tdataSource,\r\n\t\tdataSourceText,\r\n\t\tlastUpdatedText,\r\n\t\tisDummy,\r\n\t\tloadData,\r\n\t}\r\n}\r\n","<template>\r\n\t<div class=\"git-contribution-graph\">\r\n\t\t<!-- Header -->\r\n\t\t<div class=\"graph-header\">\r\n\t\t\t<div class=\"header-info\">\r\n\t\t\t\t<h5 class=\"contribution-count\">\r\n\t\t\t\t\t{{ totalContributions.toLocaleString() }} contributions in\r\n\t\t\t\t\tthe last year\r\n\t\t\t\t</h5>\r\n\t\t\t\t<small\r\n\t\t\t\t\tclass=\"data-source-text\"\r\n\t\t\t\t\t:class=\"{ 'is-dummy': isDummy }\"\r\n\t\t\t\t>\r\n\t\t\t\t\t{{ dataSourceText }}\r\n\t\t\t\t</small>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"header-actions\" v-if=\"showSettings\">\r\n\t\t\t\t<button\r\n\t\t\t\t\tclass=\"settings-btn\"\r\n\t\t\t\t\ttype=\"button\"\r\n\t\t\t\t\t@click=\"toggleSettings\"\r\n\t\t\t\t>\r\n\t\t\t\t\t<slot name=\"settings-icon\">⚙️</slot>\r\n\t\t\t\t\tSettings\r\n\t\t\t\t</button>\r\n\t\t\t\t<div v-if=\"settingsOpen\" class=\"settings-dropdown\">\r\n\t\t\t\t\t<button\r\n\t\t\t\t\t\tv-for=\"scheme in colorSchemes\"\r\n\t\t\t\t\t\t:key=\"scheme\"\r\n\t\t\t\t\t\t@click=\"changeColorScheme(scheme)\"\r\n\t\t\t\t\t\tclass=\"settings-item\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t\t{{ scheme }} theme\r\n\t\t\t\t\t</button>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\r\n\t\t<!-- Loading state -->\r\n\t\t<div v-if=\"loading\" class=\"loading-state\">\r\n\t\t\t<div class=\"spinner\"></div>\r\n\t\t\t<span>Loading contributions...</span>\r\n\t\t</div>\r\n\r\n\t\t<!-- Contribution grid -->\r\n\t\t<div v-else class=\"graph-container\">\r\n\t\t\t<div class=\"graph-content-wrapper\">\r\n\t\t\t\t<!-- Month labels -->\r\n\t\t\t\t<div class=\"months-row\">\r\n\t\t\t\t\t<div class=\"month-spacer\"></div>\r\n\t\t\t\t\t<div class=\"months-container\">\r\n\t\t\t\t\t\t<div\r\n\t\t\t\t\t\t\tv-for=\"month in monthLabels\"\r\n\t\t\t\t\t\t\t:key=\"`${month.year}-${month.month}`\"\r\n\t\t\t\t\t\t\tclass=\"month-label\"\r\n\t\t\t\t\t\t\t:style=\"{\r\n\t\t\t\t\t\t\t\tgridColumn: `${month.week + 1} / span 1`,\r\n\t\t\t\t\t\t\t}\"\r\n\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t{{ month.label }}\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\r\n\t\t\t\t<!-- Grid with day labels -->\r\n\t\t\t\t<div class=\"grid-container\">\r\n\t\t\t\t\t<!-- Day labels -->\r\n\t\t\t\t\t<div class=\"day-labels\">\r\n\t\t\t\t\t\t<div class=\"day-label\">Mon</div>\r\n\t\t\t\t\t\t<div class=\"day-label\"></div>\r\n\t\t\t\t\t\t<div class=\"day-label\">Wed</div>\r\n\t\t\t\t\t\t<div class=\"day-label\"></div>\r\n\t\t\t\t\t\t<div class=\"day-label\">Fri</div>\r\n\t\t\t\t\t\t<div class=\"day-label\"></div>\r\n\t\t\t\t\t\t<div class=\"day-label\"></div>\r\n\t\t\t\t\t</div>\r\n\r\n\t\t\t\t\t<!-- Contribution squares -->\r\n\t\t\t\t\t<div class=\"contribution-grid\">\r\n\t\t\t\t\t\t<div\r\n\t\t\t\t\t\t\tv-for=\"week in contributionData\"\r\n\t\t\t\t\t\t\t:key=\"week.weekStart\"\r\n\t\t\t\t\t\t\tclass=\"contribution-week\"\r\n\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t<div\r\n\t\t\t\t\t\t\t\tv-for=\"day in week.days\"\r\n\t\t\t\t\t\t\t\t:key=\"day.date\"\r\n\t\t\t\t\t\t\t\tclass=\"contribution-day\"\r\n\t\t\t\t\t\t\t\t:class=\"getContributionLevel(day.count)\"\r\n\t\t\t\t\t\t\t\t:title=\"getTooltipText(day)\"\r\n\t\t\t\t\t\t\t\t@click=\"onDayClick(day)\"\r\n\t\t\t\t\t\t\t></div>\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Legend -->\r\n\t\t\t<div class=\"graph-footer\">\r\n\t\t\t\t<small class=\"last-updated\" v-if=\"lastUpdatedText\">\r\n\t\t\t\t\tLast updated: {{ lastUpdatedText }}\r\n\t\t\t\t</small>\r\n\t\t\t\t<div class=\"legend\">\r\n\t\t\t\t\t<small class=\"legend-label\">Less</small>\r\n\t\t\t\t\t<div class=\"legend-squares\">\r\n\t\t\t\t\t\t<div class=\"contribution-day level-0\"></div>\r\n\t\t\t\t\t\t<div class=\"contribution-day level-1\"></div>\r\n\t\t\t\t\t\t<div class=\"contribution-day level-2\"></div>\r\n\t\t\t\t\t\t<div class=\"contribution-day level-3\"></div>\r\n\t\t\t\t\t\t<div class=\"contribution-day level-4\"></div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<small class=\"legend-label\">More</small>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from 'vue'\r\nimport { useGitStats } from '../composables/useGitStats'\r\nimport {\r\n\ttype ColorScheme,\r\n\ttype ContributionWeek,\r\n} from '@git-stats-components/core'\r\n\r\ninterface ProcessedWeek {\r\n\tweekStart: string\r\n\tdays: ProcessedDay[]\r\n}\r\n\r\ninterface ProcessedDay {\r\n\tdate: string\r\n\tcount: number\r\n\tweekday: number\r\n}\r\n\r\ninterface MonthLabel {\r\n\tweek: number\r\n\tmonth: number\r\n\tyear: number\r\n\tlabel: string\r\n}\r\n\r\ninterface Props {\r\n\tdataUrl?: string\r\n\tprofileIndex?: number\r\n\tcolorScheme?: ColorScheme\r\n\tshowSettings?: boolean\r\n\tcacheTTL?: number\r\n}\r\n\r\ninterface Emits {\r\n\t(e: 'day-click', data: { date: string; count: number }): void\r\n\t(e: 'color-scheme-change', scheme: ColorScheme): void\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n\tdataUrl: '/data/git-stats.json',\r\n\tprofileIndex: 0,\r\n\tcolorScheme: 'green',\r\n\tshowSettings: true,\r\n\tcacheTTL: 24 * 60 * 60 * 1000,\r\n})\r\n\r\nconst emit = defineEmits<Emits>()\r\n\r\n// Use the shared composable\r\nconst { data, loading, dataSourceText, lastUpdatedText, isDummy } = useGitStats(\r\n\t{\r\n\t\tdataUrl: props.dataUrl,\r\n\t\tcacheTTL: props.cacheTTL,\r\n\t}\r\n)\r\n\r\nconst currentColorScheme = ref<ColorScheme>(props.colorScheme)\r\nconst settingsOpen = ref(false)\r\nconst colorSchemes: ColorScheme[] = ['green', 'blue', 'purple', 'orange']\r\nconst contributionData = ref<ProcessedWeek[]>([])\r\nconst monthLabels = ref<MonthLabel[]>([])\r\n\r\n// Process contribution data when loaded\r\nwatch(\r\n\tdata,\r\n\t(newData) => {\r\n\t\tif (newData?.profiles?.[props.profileIndex]?.stats?.contributions) {\r\n\t\t\tconst contributions =\r\n\t\t\t\tnewData.profiles[props.profileIndex].stats.contributions\r\n\t\t\tif (contributions) {\r\n\t\t\t\tcontributionData.value = processContributions(contributions)\r\n\t\t\t\tgenerateMonthLabels()\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tcontributionData.value = []\r\n\t\t}\r\n\t},\r\n\t{ immediate: true }\r\n)\r\n\r\nconst totalContributions = computed(() => {\r\n\tif (!contributionData.value || contributionData.value.length === 0) {\r\n\t\treturn 0\r\n\t}\r\n\r\n\treturn contributionData.value.reduce((total, week) => {\r\n\t\tif (!week.days || !Array.isArray(week.days)) {\r\n\t\t\treturn total\r\n\t\t}\r\n\t\treturn (\r\n\t\t\ttotal +\r\n\t\t\tweek.days.reduce((weekTotal, day) => {\r\n\t\t\t\treturn weekTotal + (day.count || 0)\r\n\t\t\t}, 0)\r\n\t\t)\r\n\t}, 0)\r\n})\r\n\r\nfunction processContributions(\r\n\tcontributions: ContributionWeek[]\r\n): ProcessedWeek[] {\r\n\tif (!contributions || !Array.isArray(contributions)) {\r\n\t\treturn generateEmptyWeeks()\r\n\t}\r\n\r\n\tconst weeks = contributions.map((week) => ({\r\n\t\tweekStart: week.firstDay || '',\r\n\t\tdays: week.contributionDays.map((day) => ({\r\n\t\t\tdate: day.date || '',\r\n\t\t\tcount: day.contributionCount ?? 0,\r\n\t\t\tweekday: day.weekday || 0,\r\n\t\t})),\r\n\t}))\r\n\r\n\twhile (weeks.length < 53) {\r\n\t\tweeks.push(generateEmptyWeek())\r\n\t}\r\n\r\n\treturn weeks\r\n}\r\n\r\nfunction generateEmptyWeeks(): ProcessedWeek[] {\r\n\tconst weeks: ProcessedWeek[] = []\r\n\tfor (let i = 0; i < 53; i++) {\r\n\t\tweeks.push(generateEmptyWeek())\r\n\t}\r\n\treturn weeks\r\n}\r\n\r\nfunction generateEmptyWeek(): ProcessedWeek {\r\n\tconst days: ProcessedDay[] = []\r\n\tfor (let i = 0; i < 7; i++) {\r\n\t\tdays.push({ date: '', count: 0, weekday: i })\r\n\t}\r\n\treturn { weekStart: '', days }\r\n}\r\n\r\nfunction generateMonthLabels(): void {\r\n\tif (!contributionData.value || contributionData.value.length === 0) {\r\n\t\tmonthLabels.value = []\r\n\t\treturn\r\n\t}\r\n\r\n\tconst monthPositions: MonthLabel[] = []\r\n\tlet lastMonth = -1\r\n\tlet lastYear = -1\r\n\r\n\tcontributionData.value.forEach((week, weekIndex) => {\r\n\t\tif (!week.days || week.days.length === 0) return\r\n\r\n\t\tconst firstDay = week.days[0].date\r\n\t\tif (!firstDay) return\r\n\r\n\t\tconst dateParts = firstDay.split('-')\r\n\t\tif (dateParts.length !== 3) return\r\n\r\n\t\tconst [year, month] = dateParts.map(Number)\r\n\t\tif (isNaN(year) || isNaN(month)) return\r\n\r\n\t\tif (month !== lastMonth || year !== lastYear) {\r\n\t\t\tconst date = new Date(year, month - 1, 1)\r\n\t\t\tmonthPositions.push({\r\n\t\t\t\tweek: weekIndex,\r\n\t\t\t\tmonth: month - 1,\r\n\t\t\t\tyear: year,\r\n\t\t\t\tlabel: date.toLocaleDateString('en-US', { month: 'short' }),\r\n\t\t\t})\r\n\t\t\tlastMonth = month\r\n\t\t\tlastYear = year\r\n\t\t}\r\n\t})\r\n\r\n\tmonthLabels.value = monthPositions\r\n}\r\n\r\nfunction getContributionLevel(count: number): string {\r\n\tconst level = getContributionLevelNumber(count)\r\n\treturn `level-${level} ${currentColorScheme.value}`\r\n}\r\n\r\nfunction getContributionLevelNumber(count: number): number {\r\n\tif (count === 0) return 0\r\n\tif (count <= 3) return 1\r\n\tif (count <= 6) return 2\r\n\tif (count <= 9) return 3\r\n\treturn 4\r\n}\r\n\r\nfunction getTooltipText(day: ProcessedDay): string {\r\n\tif (!day.date) return ''\r\n\r\n\tconst [year, month, dayNum] = day.date.split('-').map(Number)\r\n\tconst date = new Date(year, month - 1, dayNum)\r\n\r\n\tconst formattedDate = date.toLocaleDateString('en-US', {\r\n\t\tweekday: 'short',\r\n\t\tyear: 'numeric',\r\n\t\tmonth: 'short',\r\n\t\tday: 'numeric',\r\n\t})\r\n\r\n\tconst contributionText = day.count === 1 ? 'contribution' : 'contributions'\r\n\treturn `${day.count} ${contributionText} on ${formattedDate}`\r\n}\r\n\r\nfunction onDayClick(day: ProcessedDay): void {\r\n\temit('day-click', { date: day.date, count: day.count })\r\n}\r\n\r\nfunction toggleSettings(): void {\r\n\tsettingsOpen.value = !settingsOpen.value\r\n}\r\n\r\nfunction changeColorScheme(scheme: ColorScheme): void {\r\n\tcurrentColorScheme.value = scheme\r\n\tsettingsOpen.value = false\r\n\temit('color-scheme-change', scheme)\r\n}\r\n</script>\r\n\r\n<style scoped>\r\n.graph-content-wrapper {\r\n\tjustify-items: anchor-center;\r\n}\r\n.git-contribution-graph {\r\n\tfont-family:\r\n\t\t-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica,\r\n\t\tArial, sans-serif;\r\n\tfont-size: 12px;\r\n\tbackground: transparent;\r\n\tcolor: #e6edf3;\r\n\tpadding: 16px;\r\n\tmax-width: 1200px;\r\n\tmargin: 0 auto;\r\n\twidth: 100%;\r\n}\r\n\r\n.graph-header {\r\n\tdisplay: flex;\r\n\tjustify-content: space-between;\r\n\talign-items: center;\r\n\tmargin-bottom: 16px;\r\n}\r\n\r\n.contribution-count {\r\n\tmargin: 0 0 4px 0;\r\n\tfont-size: 16px;\r\n\tfont-weight: 600;\r\n}\r\n\r\n.data-source-text {\r\n\tcolor: #7d8590;\r\n}\r\n\r\n.data-source-text.is-dummy {\r\n\tcolor: #f85149;\r\n\tfont-weight: 600;\r\n\tbackground: rgba(248, 81, 73, 0.1);\r\n\tpadding: 2px 8px;\r\n\tborder-radius: 4px;\r\n}\r\n\r\n.settings-btn {\r\n\tbackground: transparent;\r\n\tborder: 1px solid #30363d;\r\n\tcolor: #7d8590;\r\n\tpadding: 6px 12px;\r\n\tborder-radius: 6px;\r\n\tcursor: pointer;\r\n\tfont-size: 12px;\r\n}\r\n\r\n.settings-btn:hover {\r\n\tbackground: #21262d;\r\n\tcolor: #e6edf3;\r\n}\r\n\r\n.header-actions {\r\n\tposition: relative;\r\n}\r\n\r\n.settings-dropdown {\r\n\tposition: absolute;\r\n\tright: 0;\r\n\ttop: 100%;\r\n\tmargin-top: 4px;\r\n\tbackground: #21262d;\r\n\tborder: 1px solid #30363d;\r\n\tborder-radius: 6px;\r\n\tpadding: 4px;\r\n\tz-index: 10;\r\n\tmin-width: 150px;\r\n}\r\n\r\n.settings-item {\r\n\tdisplay: block;\r\n\twidth: 100%;\r\n\tbackground: transparent;\r\n\tborder: none;\r\n\tcolor: #e6edf3;\r\n\tpadding: 8px 12px;\r\n\ttext-align: left;\r\n\tcursor: pointer;\r\n\tborder-radius: 4px;\r\n}\r\n\r\n.settings-item:hover {\r\n\tbackground: #30363d;\r\n}\r\n\r\n.loading-state {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\tgap: 12px;\r\n\tpadding: 40px;\r\n\tcolor: #7d8590;\r\n}\r\n\r\n.spinner {\r\n\twidth: 20px;\r\n\theight: 20px;\r\n\tborder: 2px solid #30363d;\r\n\tborder-top-color: #58a6ff;\r\n\tborder-radius: 50%;\r\n\tanimation: spin 1s linear infinite;\r\n}\r\n\r\n@keyframes spin {\r\n\tto {\r\n\t\ttransform: rotate(360deg);\r\n\t}\r\n}\r\n\r\n.months-row {\r\n\tdisplay: flex;\r\n\tmargin-bottom: 4px;\r\n}\r\n\r\n.month-spacer {\r\n\twidth: 27px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.months-container {\r\n\tdisplay: grid;\r\n\tgrid-template-columns: repeat(53, 11px);\r\n\tgap: 2px;\r\n\tflex: 1;\r\n\tmargin-left: 3px;\r\n\tmin-width: 0;\r\n}\r\n\r\n.month-label {\r\n\tfont-size: 11px;\r\n\tcolor: #7d8590;\r\n\ttext-align: left;\r\n}\r\n\r\n.grid-container {\r\n\tdisplay: flex;\r\n\tgap: 3px;\r\n\tmin-width: fit-content;\r\n}\r\n\r\n.day-labels {\r\n\tdisplay: flex;\r\n\tflex-direction: column;\r\n\twidth: 24px;\r\n\tgap: 2px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.day-label {\r\n\theight: 11px;\r\n\tfont-size: 9px;\r\n\tcolor: #7d8590;\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n}\r\n\r\n.contribution-grid {\r\n\tdisplay: flex;\r\n\tgap: 2px;\r\n\tflex: 1;\r\n\tmin-width: 0;\r\n}\r\n\r\n.contribution-week {\r\n\tdisplay: flex;\r\n\tflex-direction: column;\r\n\tgap: 2px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.contribution-day {\r\n\twidth: 11px;\r\n\theight: 11px;\r\n\tborder-radius: 2px;\r\n\tcursor: pointer;\r\n\toutline: 1px solid rgba(27, 31, 36, 0.06);\r\n\toutline-offset: -1px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n/* Color schemes */\r\n.contribution-day.level-0.green {\r\n\tbackground-color: #161b22;\r\n}\r\n.contribution-day.level-1.green {\r\n\tbackground-color: #0e4429;\r\n}\r\n.contribution-day.level-2.green {\r\n\tbackground-color: #006d32;\r\n}\r\n.contribution-day.level-3.green {\r\n\tbackground-color: #26a641;\r\n}\r\n.contribution-day.level-4.green {\r\n\tbackground-color: #39d353;\r\n}\r\n\r\n.contribution-day.level-0.blue {\r\n\tbackground-color: #161b22;\r\n}\r\n.contribution-day.level-1.blue {\r\n\tbackground-color: #0a3069;\r\n}\r\n.contribution-day.level-2.blue {\r\n\tbackground-color: #1f6feb;\r\n}\r\n.contribution-day.level-3.blue {\r\n\tbackground-color: #58a6ff;\r\n}\r\n.contribution-day.level-4.blue {\r\n\tbackground-color: #79c0ff;\r\n}\r\n\r\n.contribution-day.level-0.purple {\r\n\tbackground-color: #161b22;\r\n}\r\n.contribution-day.level-1.purple {\r\n\tbackground-color: #3b1e6d;\r\n}\r\n.contribution-day.level-2.purple {\r\n\tbackground-color: #8250df;\r\n}\r\n.contribution-day.level-3.purple {\r\n\tbackground-color: #a475f9;\r\n}\r\n.contribution-day.level-4.purple {\r\n\tbackground-color: #d2a8ff;\r\n}\r\n\r\n.contribution-day.level-0.orange {\r\n\tbackground-color: #161b22;\r\n}\r\n.contribution-day.level-1.orange {\r\n\tbackground-color: #7d2d00;\r\n}\r\n.contribution-day.level-2.orange {\r\n\tbackground-color: #da7b00;\r\n}\r\n.contribution-day.level-3.orange {\r\n\tbackground-color: #ffa348;\r\n}\r\n.contribution-day.level-4.orange {\r\n\tbackground-color: #ffb366;\r\n}\r\n\r\n.contribution-day:hover {\r\n\toutline: 1px solid #c9d1d9;\r\n\toutline-offset: -1px;\r\n}\r\n\r\n.graph-footer {\r\n\tdisplay: flex;\r\n\tjustify-content: space-between;\r\n\talign-items: center;\r\n\tmargin-top: 8px;\r\n}\r\n\r\n.last-updated {\r\n\tcolor: #7d8590;\r\n}\r\n\r\n.legend {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tgap: 4px;\r\n}\r\n\r\n.legend-label {\r\n\tcolor: #7d8590;\r\n}\r\n\r\n.legend-squares {\r\n\tdisplay: flex;\r\n\tgap: 2px;\r\n}\r\n\r\n.legend-squares .contribution-day {\r\n\tcursor: default;\r\n}\r\n\r\n.legend-squares .contribution-day:hover {\r\n\toutline: none;\r\n}\r\n\r\n/* Mobile responsive */\r\n@media (max-width: 768px) {\r\n\t.git-contribution-graph {\r\n\t\tpadding: 12px;\r\n\t\tfont-size: 11px;\r\n\t\toverflow-x: auto;\r\n\t}\r\n\t.months-container {\r\n\t\tgrid-template-columns: repeat(53, 10px);\r\n\t\tgap: 1px;\r\n\t}\r\n\t.grid-container {\r\n\t\tgap: 2px;\r\n\t}\r\n\t.day-labels {\r\n\t\twidth: 20px;\r\n\t}\r\n\t.day-label {\r\n\t\theight: 10px;\r\n\t\tfont-size: 8px;\r\n\t}\r\n\t.contribution-grid {\r\n\t\tgap: 1px;\r\n\t}\r\n\t.contribution-week {\r\n\t\tgap: 1px;\r\n\t}\r\n\t.contribution-day {\r\n\t\twidth: 10px;\r\n\t\theight: 10px;\r\n\t}\r\n\t.settings-btn {\r\n\t\tfont-size: 10px;\r\n\t\tpadding: 4px 8px;\r\n\t}\r\n\t.contribution-count {\r\n\t\tfont-size: 14px;\r\n\t}\r\n}\r\n\r\n@media (max-width: 480px) {\r\n\t.graph-header {\r\n\t\tflex-direction: column;\r\n\t\talign-items: flex-start;\r\n\t\tgap: 8px;\r\n\t}\r\n}\r\n</style>\r\n","<template>\r\n\t<div class=\"git-stats-breakdown\">\r\n\t\t<div class=\"stats-grid\">\r\n\t\t\t<!-- Years Experience -->\r\n\t\t\t<div class=\"stat-card\">\r\n\t\t\t\t<div class=\"stat-icon\">\r\n\t\t\t\t\t<slot name=\"icon-experience\">⏱️</slot>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"stat-content\">\r\n\t\t\t\t\t<div class=\"stat-value\">{{ yearsExperience }}</div>\r\n\t\t\t\t\t<div class=\"stat-label\">Years Experience</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Projects -->\r\n\t\t\t<div class=\"stat-card\">\r\n\t\t\t\t<div class=\"stat-icon\">\r\n\t\t\t\t\t<slot name=\"icon-projects\">📦</slot>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"stat-content\">\r\n\t\t\t\t\t<div v-if=\"loading\" class=\"stat-loading\">\r\n\t\t\t\t\t\t<div class=\"spinner\"></div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div v-else class=\"stat-value\">{{ totalProjects }}</div>\r\n\t\t\t\t\t<div class=\"stat-label\">Projects</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Commits -->\r\n\t\t\t<div class=\"stat-card\">\r\n\t\t\t\t<div class=\"stat-icon\">\r\n\t\t\t\t\t<slot name=\"icon-commits\">💻</slot>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"stat-content\">\r\n\t\t\t\t\t<div v-if=\"loading\" class=\"stat-loading\">\r\n\t\t\t\t\t\t<div class=\"spinner\"></div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div v-else class=\"stat-value\">{{ totalCommits }}</div>\r\n\t\t\t\t\t<div class=\"stat-label\">Commits</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Custom Stat -->\r\n\t\t\t<div class=\"stat-card\" v-if=\"showCustomStat\">\r\n\t\t\t\t<div class=\"stat-icon\">\r\n\t\t\t\t\t<slot name=\"icon-custom\">☕</slot>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"stat-content\">\r\n\t\t\t\t\t<div v-if=\"loading\" class=\"stat-loading\">\r\n\t\t\t\t\t\t<div class=\"spinner\"></div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div v-else class=\"stat-value\">{{ customStatValue }}</div>\r\n\t\t\t\t\t<div class=\"stat-label\">\r\n\t\t\t\t\t\t<slot name=\"custom-stat-label\">Coffee Consumed</slot>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\r\n\t\t<!-- Footer -->\r\n\t\t<div class=\"stats-footer\">\r\n\t\t\t<small v-if=\"dataSourceText\" class=\"data-source\">\r\n\t\t\t\t{{ dataSourceText }}\r\n\t\t\t\t<span v-if=\"lastUpdatedText\"> · {{ lastUpdatedText }}</span>\r\n\t\t\t</small>\r\n\t\t</div>\r\n\t</div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from 'vue'\r\nimport { useGitStats } from '../composables/useGitStats'\r\nimport {\r\n\tcalculateYearsExperience,\r\n\ttype ExperienceEntry,\r\n\ttype CustomStatCalculator,\r\n\ttype CustomStatCalculatorParams,\r\n} from '@git-stats-components/core'\r\n\r\ninterface Props {\r\n\tdataUrl?: string\r\n\tprofileIndexes?: number[]\r\n\texperienceData?: ExperienceEntry[]\r\n\tshowCustomStat?: boolean\r\n\tcustomStatCalculator?: CustomStatCalculator | null\r\n\tcacheTTL?: number\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n\tdataUrl: '/data/git-stats.json',\r\n\tprofileIndexes: () => [],\r\n\texperienceData: () => [],\r\n\tshowCustomStat: true,\r\n\tcustomStatCalculator: null,\r\n\tcacheTTL: 24 * 60 * 60 * 1000,\r\n})\r\n\r\n// Use the shared composable\r\nconst { data, loading, dataSourceText, lastUpdatedText } = useGitStats({\r\n\tdataUrl: props.dataUrl,\r\n\tcacheTTL: props.cacheTTL,\r\n})\r\n\r\nconst totalProjects = ref(0)\r\nconst totalCommits = ref(0)\r\n\r\n// Calculate totals when data loads\r\nwatch(\r\n\tdata,\r\n\t(newData) => {\r\n\t\tif (!newData) return\r\n\r\n\t\t// If profileIndexes specified, sum only those profiles\r\n\t\tif (props.profileIndexes.length > 0) {\r\n\t\t\tlet projects = 0\r\n\t\t\tlet commits = 0\r\n\r\n\t\t\tprops.profileIndexes.forEach((index) => {\r\n\t\t\t\tconst profile = newData.profiles?.[index]\r\n\t\t\t\tif (profile?.stats) {\r\n\t\t\t\t\tprojects += profile.stats.projectCount || 0\r\n\t\t\t\t\tcommits += profile.stats.commitCount || 0\r\n\t\t\t\t}\r\n\t\t\t})\r\n\r\n\t\t\ttotalProjects.value = projects\r\n\t\t\ttotalCommits.value = commits\r\n\t\t} else {\r\n\t\t\t// Use totals from data (aggregates all profiles)\r\n\t\t\ttotalProjects.value = newData.totals?.projectCount || 0\r\n\t\t\ttotalCommits.value = newData.totals?.commitCount || 0\r\n\t\t}\r\n\t},\r\n\t{ immediate: true }\r\n)\r\n\r\n// Calculate years of experience using core utility\r\nconst yearsExperience = computed(() => {\r\n\tconst years = calculateYearsExperience(props.experienceData)\r\n\treturn years.toFixed(1)\r\n})\r\n\r\n// Custom stat calculation\r\nconst customStatValue = computed(() => {\r\n\tif (props.customStatCalculator) {\r\n\t\tconst params: CustomStatCalculatorParams = {\r\n\t\t\tprojects: totalProjects.value,\r\n\t\t\tcommits: totalCommits.value,\r\n\t\t\tyears: parseFloat(yearsExperience.value),\r\n\t\t}\r\n\t\treturn props.customStatCalculator(params)\r\n\t}\r\n\r\n\t// Default: fun coffee calculation\r\n\tconst kA = 1.5\r\n\tconst kB = 1.2\r\n\tconst kC = 1.5\r\n\r\n\tconst cups =\r\n\t\ttotalProjects.value * kA +\r\n\t\ttotalCommits.value * kB +\r\n\t\tparseFloat(yearsExperience.value) * kC\r\n\r\n\treturn cups.toFixed(2)\r\n})\r\n</script>\r\n\r\n<style scoped>\r\n.git-stats-breakdown {\r\n\tfont-family:\r\n\t\t-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica,\r\n\t\tArial, sans-serif;\r\n\tpadding: 40px 20px;\r\n\tmax-width: 1200px;\r\n\tmargin: 0 auto;\r\n}\r\n\r\n.stats-grid {\r\n\tdisplay: grid;\r\n\tgrid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\r\n\tgap: 24px;\r\n\tmargin-bottom: 24px;\r\n}\r\n\r\n.stat-card {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tgap: 16px;\r\n\tpadding: 24px;\r\n\tbackground: rgba(255, 255, 255, 0.05);\r\n\tborder-radius: 12px;\r\n\tborder: 1px solid rgba(255, 255, 255, 0.1);\r\n\ttransition: all 0.3s ease;\r\n}\r\n\r\n.stat-card:hover {\r\n\tbackground: rgba(255, 255, 255, 0.08);\r\n\tborder-color: rgba(255, 255, 255, 0.2);\r\n\ttransform: translateY(-2px);\r\n}\r\n\r\n.stat-icon {\r\n\tfont-size: 48px;\r\n\tline-height: 1;\r\n\topacity: 0.9;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.stat-content {\r\n\tflex: 1;\r\n\tmin-width: 0;\r\n}\r\n\r\n.stat-value {\r\n\tfont-size: 32px;\r\n\tfont-weight: bold;\r\n\tline-height: 1.2;\r\n\tcolor: #e6edf3;\r\n\tmargin-bottom: 4px;\r\n}\r\n\r\n.stat-label {\r\n\tfont-size: 14px;\r\n\tcolor: #7d8590;\r\n\ttext-transform: uppercase;\r\n\tletter-spacing: 0.5px;\r\n}\r\n\r\n.stat-loading {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\theight: 38px;\r\n}\r\n\r\n.spinner {\r\n\twidth: 24px;\r\n\theight: 24px;\r\n\tborder: 3px solid rgba(255, 255, 255, 0.1);\r\n\tborder-top-color: #58a6ff;\r\n\tborder-radius: 50%;\r\n\tanimation: spin 1s linear infinite;\r\n}\r\n\r\n@keyframes spin {\r\n\tto {\r\n\t\ttransform: rotate(360deg);\r\n\t}\r\n}\r\n\r\n.stats-footer {\r\n\tdisplay: flex;\r\n\tflex-direction: column;\r\n\talign-items: center;\r\n\tgap: 8px;\r\n\tpadding-top: 16px;\r\n\tborder-top: 1px solid rgba(255, 255, 255, 0.1);\r\n}\r\n\r\n.data-source {\r\n\tfont-size: 12px;\r\n\tcolor: #7d8590;\r\n\ttext-align: center;\r\n}\r\n\r\n/* Responsive */\r\n@media (max-width: 768px) {\r\n\t.git-stats-breakdown {\r\n\t\tpadding: 20px 12px;\r\n\t}\r\n\t.stats-grid {\r\n\t\tgrid-template-columns: 1fr;\r\n\t\tgap: 16px;\r\n\t}\r\n\t.stat-card {\r\n\t\tpadding: 16px;\r\n\t}\r\n\t.stat-icon {\r\n\t\tfont-size: 36px;\r\n\t}\r\n\t.stat-value {\r\n\t\tfont-size: 24px;\r\n\t}\r\n\t.stat-label {\r\n\t\tfont-size: 12px;\r\n\t}\r\n}\r\n\r\n@media (max-width: 480px) {\r\n\t.stat-card {\r\n\t\tflex-direction: column;\r\n\t\ttext-align: center;\r\n\t}\r\n\t.stat-content {\r\n\t\twidth: 100%;\r\n\t}\r\n}\r\n</style>\r\n","// Main entry point for git-stats-components\n\nimport type { App } from 'vue'\nimport ContributionGraph from './components/ContributionGraph.vue'\nimport StatsBreakdown from './components/StatsBreakdown.vue'\nimport { useGitStats } from './composables/useGitStats'\n\n// Re-export everything from core\nexport * from '@git-stats-components/core'\n\n// Export Vue-specific components and composables\nexport { ContributionGraph, StatsBreakdown, useGitStats }\n\n// Auto-import styles\nimport './styles/index.css'\n\n// Plugin for Vue.use()\nexport interface VueGitStatsPlugin {\n\tinstall: (app: App) => void\n}\n\nconst VueGitStats: VueGitStatsPlugin = {\n\tinstall(app: App) {\n\t\tapp.component('ContributionGraph', ContributionGraph)\n\t\tapp.component('StatsBreakdown', StatsBreakdown)\n\t},\n}\n\n// Export as default for Vue.use()\nexport default VueGitStats\n"],"names":["fetchGitStats","url","__async","response","generateDummyContributions","weeks","now","endDate","startDate","currentDate","week","weekData","day","isInFuture","isWeekend","dayCount","generateDummyStats","options","username","platform","projectCount","commitCount","contributions","total","sum","generateMultiProfileDummyStats","githubProfile","gitlabProfile","saveDummyDataToFile","filepath","data","json","blob","a","err","dataUrl","cacheKey","useStaleCache","__spreadProps","__spreadValues","_a","cached","_b","generateMockData","formatLastUpdated","dateString","date","diffHours","diffDays","getContributionLevel","count","calculateYearsExperience","experienceData","skillExperience","exp","end","start","years","skill","useGitStats","config","cacheTTL","loading","ref","error","dataSource","isDummy","loadData","result","lastUpdatedText","computed","dataSourceText","props","__props","emit","__emit","currentColorScheme","settingsOpen","colorSchemes","contributionData","monthLabels","watch","newData","_c","processContributions","generateMonthLabels","totalContributions","weekTotal","generateEmptyWeeks","generateEmptyWeek","i","days","monthPositions","lastMonth","lastYear","weekIndex","firstDay","dateParts","year","month","getContributionLevelNumber","getTooltipText","dayNum","formattedDate","contributionText","onDayClick","toggleSettings","changeColorScheme","scheme","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_hoisted_4","_toDisplayString","_normalizeClass","_unref","_hoisted_5","_renderSlot","_ctx","_hoisted_6","_Fragment","_renderList","$event","_hoisted_7","_hoisted_8","_cache","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_normalizeStyle","_hoisted_13","_hoisted_14","_hoisted_16","_hoisted_17","totalProjects","totalCommits","projects","commits","index","profile","yearsExperience","customStatValue","params","_hoisted_15","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_createTextVNode","_hoisted_25","VueGitStats","app","ContributionGraph","StatsBreakdown"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,SAAsBA,GAAcC,GAAoC;AAAA,SAAAC,EAAA;AACvE,UAAMC,IAAW,MAAM,MAAMF,CAAG;AAChC,QAAI,CAACE,EAAS;AACb,YAAM,IAAI,MAAM,8BAA8BA,EAAS,UAAU,EAAE;AAEpE,WAAOA,EAAS,KAAA;AAAA,EACjB;AAAA;ACDO,SAASC,KAA6B;AAC5C,QAAMC,IAAQ,CAAA,GACRC,IAAM,oBAAI,KAAI,GAGdC,IAAU,IAAI,KAAKD,CAAG;AAC5B,EAAAC,EAAQ,QAAQA,EAAQ,QAAO,IAAKA,EAAQ,OAAM,CAAE;AAGpD,QAAMC,IAAY,IAAI,KAAKD,CAAO;AAClC,EAAAC,EAAU,QAAQA,EAAU,QAAO,IAAK,KAAK,CAAC;AAE9C,QAAMC,IAAc,IAAI,KAAKD,CAAS;AAEtC,WAASE,IAAO,GAAGA,IAAO,IAAIA,KAAQ;AACrC,UAAMC,IAAW;AAAA,MAChB,WAAW,IAAI,KAAKF,CAAW,EAAE,YAAW,EAAG,MAAM,GAAG,EAAE,CAAC;AAAA,MAC3D,kBAAkB,CAAA;AAAA,IACrB;AAEE,aAASG,IAAM,GAAGA,IAAM,GAAGA,KAAO;AACjC,YAAMC,IAAaJ,IAAcH,GAC3BQ,IAAYF,MAAQ,KAAKA,MAAQ;AAGvC,UAAIG,IAAW;AACf,MAAKF,MACAC,IACHC,IACC,KAAK,WAAW,MAAM,KAAK,MAAM,KAAK,WAAW,CAAC,IAAI,IAEvDA,IAAW,KAAK,MAAM,KAAK,OAAM,IAAK,EAAE,IAI1CJ,EAAS,iBAAiB,KAAK;AAAA,QAC9B,MAAM,IAAI,KAAKF,CAAW,EAAE,YAAW,EAAG,MAAM,GAAG,EAAE,CAAC;AAAA,QACtD,mBAAmBM;AAAA,QACnB,SAASH;AAAA,MACb,CAAI,GACDH,EAAY,QAAQA,EAAY,QAAO,IAAK,CAAC;AAAA,IAC9C;AAEA,IAAAJ,EAAM,KAAKM,CAAQ;AAAA,EACpB;AAEA,SAAON;AACR;AAKO,SAASW,EAAmBC,IAAU,IAAI;AAChD,QAAM;AAAA,IACL,UAAAC,IAAW;AAAA,IACX,UAAAC,IAAW;AAAA,IACX,cAAAC,IAAe;AAAA,IACf,aAAAC,IAAc;AAAA,EAChB,IAAKJ,GAEEK,IAAgBlB,GAA0B;AACrB,SAAAkB,EAAc,OAAO,CAACC,GAAOb,MAEtDa,IACAb,EAAK,iBAAiB;AAAA,IACrB,CAACc,GAAKZ,MAAQY,IAAMZ,EAAI;AAAA,IACxB;AAAA,EACJ,GAEI,CAAC,GAEG;AAAA,IACN,cAAa,oBAAI,KAAI,GAAG,YAAW;AAAA,IACnC,UAAU;AAAA,MACT;AAAA,QACC,UAAAM;AAAA,QACA,UAAAC;AAAA,QACA,OAAO;AAAA,UACN,cAAAC;AAAA,UACA,aAAAC;AAAA,UACA,eAAeC,EAAc,IAAI,CAACZ,OAAU;AAAA,YAC3C,UAAUA,EAAK;AAAA,YACf,kBAAkBA,EAAK;AAAA,UAC7B,EAAO;AAAA,QACP;AAAA,MACA;AAAA,IACA;AAAA,IACE,QAAQ;AAAA,MACP,cAAAU;AAAA,MACA,aAAAC;AAAA,IACH;AAAA,IACE,UAAU;AAAA,MACT,WAAW,KAAK,IAAG;AAAA,MACnB,QAAQ;AAAA,MACR,SAAS;AAAA,IACZ;AAAA,EACA;AACA;AAKO,SAASI,KAAiC;AAChD,QAAMC,IAAgBV,EAAmB;AAAA,IACxC,UAAU;AAAA,IACV,UAAU;AAAA,IACV,cAAc;AAAA,IACd,aAAa;AAAA,EACf,CAAE,GAEKW,IAAgBX,EAAmB;AAAA,IACxC,UAAU;AAAA,IACV,UAAU;AAAA,IACV,cAAc;AAAA,IACd,aAAa;AAAA,EACf,CAAE;AAED,SAAO;AAAA,IACN,cAAa,oBAAI,KAAI,GAAG,YAAW;AAAA,IACnC,UAAU,CAACU,EAAc,SAAS,CAAC,GAAGC,EAAc,SAAS,CAAC,CAAC;AAAA,IAC/D,QAAQ;AAAA,MACP,cAAc;AAAA,MACd,aAAa;AAAA,IAChB;AAAA,IACE,UAAU;AAAA,MACT,WAAW,KAAK,IAAG;AAAA,MACnB,QAAQ;AAAA,MACR,SAAS;AAAA,IACZ;AAAA,EACA;AACA;AAKO,SAASC,GAAoBC,IAAW,wBAAwB;AACtE,QAAMC,IAAOd,EAAkB,GACzBe,IAAO,KAAK,UAAUD,GAAM,MAAM,GAAI;AAE5C,MAAI,OAAO,UAAW,aAAa;AAElC,UAAME,IAAO,IAAI,KAAK,CAACD,CAAI,GAAG,EAAE,MAAM,mBAAkB,CAAE,GACpD9B,IAAM,IAAI,gBAAgB+B,CAAI,GAC9BC,IAAI,SAAS,cAAc,GAAG;AACpC,IAAAA,EAAE,OAAOhC,GACTgC,EAAE,WAAWJ,GACbI,EAAE,MAAK,GACP,IAAI,gBAAgBhC,CAAG;AAAA,EACxB;AAEC,QAAI;AAEH,MADW,QAAQ,IAAI,EACpB,cAAc4B,GAAUE,CAAI,GAC/B,QAAQ,IAAI,yBAAyBF,CAAQ,EAAE;AAAA,IAChD,SAASK,GAAK;AACb,cAAQ,MAAM,8BAA8BA,CAAG;AAAA,IAChD;AAEF;AClHA,SAAsBlC,GACrBiB,GACoC;AAAA,SAAAf,EAAA;;AACpC,UAAM,EAAE,SAAAiC,GAAS,UAAAC,IAAW,mBAAmB,eAAAC,IAAgB,OAASpB;AAExE,QAAI;AAEH,YAAMd,IAAW,MAAM,MAAMgC,CAAO;AACpC,UAAIhC,EAAS,IAAI;AAChB,cAAM2B,IAAO,MAAM3B,EAAS,KAAA;AAE5B,eAAI,OAAO,UAAW,eACrB,aAAa;AAAA,UACZiC;AAAA,UACA,KAAK,UAAUE,EAAAC,EAAA,IACXT,IADW;AAAA,YAEd,UAAU,KAAK,IAAA;AAAA,UAAI,EACnB;AAAA,QAAA,GAGI;AAAA,UACN,MAAAA;AAAA,UACA,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,WAASU,IAAAV,EAAK,aAAL,gBAAAU,EAAe,aAAY;AAAA,QAAA;AAAA,MAEtC;AAAA,IACD,SAASN,GAAK;AACb,cAAQ,KAAK,qCAAqCA,CAAG;AAAA,IACtD;AAGA,QAAIG,KAAiB,OAAO,UAAW;AACtC,UAAI;AACH,cAAMI,IAAS,aAAa,QAAQL,CAAQ;AAC5C,YAAIK,GAAQ;AACX,gBAAMX,IAAO,KAAK,MAAMW,CAAM;AAC9B,iBAAO;AAAA,YACN,MAAAX;AAAA,YACA,OAAO;AAAA,YACP,QAAQ;AAAA,YACR,WAASY,IAAAZ,EAAK,aAAL,gBAAAY,EAAe,aAAY;AAAA,UAAA;AAAA,QAEtC;AAAA,MACD,SAASR,GAAK;AACb,gBAAQ,KAAK,8BAA8BA,CAAG;AAAA,MAC/C;AAKD,WAAO;AAAA,MACN,MAFgBS,GAAA;AAAA,MAGhB,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAS;AAAA,IAAA;AAAA,EAEX;AAAA;AAKO,SAASC,GAAkBC,GAA4B;AAC7D,QAAMC,IAAO,IAAI,KAAKD,CAAU,GAC1BvC,wBAAU,KAAA,GACVyC,IAAY,KAAK,OAAOzC,EAAI,QAAA,IAAYwC,EAAK,QAAA,MAAc,MAAO,KAAK,GAAG;AAEhF,MAAIC,IAAY,EAAG,QAAO;AAC1B,MAAIA,IAAY,GAAI,QAAO,GAAGA,CAAS;AAEvC,QAAMC,IAAW,KAAK,MAAMD,IAAY,EAAE;AAC1C,SAAIC,MAAa,IAAU,cACvBA,IAAW,IAAU,GAAGA,CAAQ,cAE7BF,EAAK,mBAAmB,SAAS;AAAA,IACvC,OAAO;AAAA,IACP,KAAK;AAAA,IACL,MAAMA,EAAK,YAAA,MAAkBxC,EAAI,YAAA,IAAgB,YAAY;AAAA,EAAA,CAC7D;AACF;AAKO,SAAS2C,GAAqBC,GAAuB;AAC3D,SAAIA,MAAU,IAAU,IACpBA,KAAS,IAAU,IACnBA,KAAS,IAAU,IACnBA,KAAS,IAAU,IAChB;AACR;AAKO,SAASC,GACfC,GACS;AACT,MAAIA,EAAe,WAAW,EAAG,QAAO;AAExC,QAAMC,IAA0C,CAAA;AAEhD,SAAAD,EAAe,QAAQ,CAACE,MAAQ;;AAC/B,UAAMC,IAAMD,EAAI,UAAU,IAAI,KAAKA,EAAI,OAAO,IAAI,oBAAI,KAAA,GAChDE,IAAQ,IAAI,KAAKF,EAAI,SAAS,GAC9BG,KAASF,EAAI,QAAA,IAAYC,EAAM,cAAc,MAAO,KAAK,KAAK,KAAK;AAEzE,KAAAhB,IAAAc,EAAI,WAAJ,QAAAd,EAAY,QAAQ,CAACkB,MAAU;AAC9B,MAAKL,EAAgBK,CAAK,MACzBL,EAAgBK,CAAK,IAAI,IAE1BL,EAAgBK,CAAK,KAAKD;AAAA,IAC3B;AAAA,EACD,CAAC,GAEM,KAAK,IAAI,GAAG,OAAO,OAAOJ,CAAe,GAAG,CAAC;AACrD;AAGA,SAASV,KAAiC;AACzC,SAAO;AAAA,IACN,cAAa,oBAAI,KAAA,GAAO,YAAA;AAAA,IACxB,UAAU;AAAA,MACT;AAAA,QACC,UAAU;AAAA,QACV,UAAU;AAAA,QACV,OAAO;AAAA,UACN,cAAc;AAAA,UACd,aAAa;AAAA,UACb,eAAe,CAAA;AAAA,QAAC;AAAA,MACjB;AAAA,IACD;AAAA,IAED,QAAQ;AAAA,MACP,cAAc;AAAA,MACd,aAAa;AAAA,IAAA;AAAA,IAEd,UAAU;AAAA,MACT,QAAQ;AAAA,MACR,WAAW,KAAK,IAAA;AAAA,IAAI;AAAA,EACrB;AAEF;AClLO,SAASgB,EAAYC,IAA4B,IAAI;AAC3D,QAAM;AAAA,IACL,SAAAzB,IAAU;AAAA,IACV,UAAA0B,IAAW,KAAK,KAAK,KAAK;AAAA,IAC1B,eAAAxB,IAAgB;AAAA,IAChB,UAAAD,IAAW;AAAA,EAAA,IACRwB,GAEEE,IAAUC,EAAI,EAAK,GACnBC,IAAQD,EAAkB,IAAI,GAC9BjC,IAAOiC,EAAyB,IAAI,GACpCE,IAAaF,EAAuB,IAAI,GACxCG,IAAUH,EAAI,EAAK;AAKzB,WAAeI,IAAyC;AAAA,WAAAjE,EAAA;AACvD,MAAA4D,EAAQ,QAAQ,IAChBE,EAAM,QAAQ;AAEd,UAAI;AACH,cAAMI,IAAS,MAAMpE,GAAc;AAAA,UAClC,SAAAmC;AAAA,UACA,UAAA0B;AAAA,UACA,UAAAzB;AAAA,UACA,eAAAC;AAAA,QAAA,CACA;AAED,eAAAP,EAAK,QAAQsC,EAAO,MACpBJ,EAAM,QAAQI,EAAO,OACrBH,EAAW,QAAQG,EAAO,QAC1BF,EAAQ,QAAQE,EAAO,SAEhBA,EAAO;AAAA,MACf,SAASlC,GAAK;AACb,eAAA8B,EAAM,QACL9B,aAAe,QAAQA,IAAM,IAAI,MAAM,qBAAqB,GACtD;AAAA,MACR,UAAA;AACC,QAAA4B,EAAQ,QAAQ;AAAA,MACjB;AAAA,IACD;AAAA;AAKA,QAAMO,IAAkBC,EAAS,MAAM;;AACtC,YAAK9B,IAAAV,EAAK,UAAL,QAAAU,EAAY,cACVI,GAAkBd,EAAK,MAAM,WAAW,IADV;AAAA,EAEtC,CAAC,GAKKyC,IAAiBD,EAAS,MAAM;AACrC,QAAIJ,EAAQ;AACX,aAAO;AAGR,YAAQD,EAAW,OAAA;AAAA,MAClB,KAAK;AACJ,eAAO;AAAA,MACR,KAAK;AACJ,eAAO;AAAA,MACR,KAAK;AACJ,eAAO;AAAA,MACR;AACC,eAAO;AAAA,IAAA;AAAA,EAEV,CAAC;AAGD,SAAAE,EAAA,GAEO;AAAA,IACN,MAAArC;AAAA,IACA,SAAAgC;AAAA,IACA,OAAAE;AAAA,IACA,YAAAC;AAAA,IACA,gBAAAM;AAAA,IACA,iBAAAF;AAAA,IACA,SAAAH;AAAA,IACA,UAAAC;AAAA,EAAA;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;ACyDA,UAAMK,IAAQC,GAQRC,IAAOC,GAGP,EAAE,MAAA7C,GAAM,SAAAgC,GAAS,gBAAAS,GAAgB,iBAAAF,GAAiB,SAAAH,MAAYP;AAAA,MACnE;AAAA,QACC,SAASa,EAAM;AAAA,QACf,UAAUA,EAAM;AAAA,MAAA;AAAA,IACjB,GAGKI,IAAqBb,EAAiBS,EAAM,WAAW,GACvDK,IAAed,EAAI,EAAK,GACxBe,IAA8B,CAAC,SAAS,QAAQ,UAAU,QAAQ,GAClEC,IAAmBhB,EAAqB,EAAE,GAC1CiB,IAAcjB,EAAkB,EAAE;AAGxC,IAAAkB;AAAA,MACCnD;AAAA,MACA,CAACoD,MAAY;;AACZ,aAAIC,KAAAzC,KAAAF,IAAA0C,KAAA,gBAAAA,EAAS,aAAT,gBAAA1C,EAAoBgC,EAAM,kBAA1B,gBAAA9B,EAAyC,UAAzC,QAAAyC,EAAgD,eAAe;AAClE,gBAAM7D,IACL4D,EAAQ,SAASV,EAAM,YAAY,EAAE,MAAM;AAC5C,UAAIlD,MACHyD,EAAiB,QAAQK,EAAqB9D,CAAa,GAC3D+D,EAAA;AAAA,QAEF;AACC,UAAAN,EAAiB,QAAQ,CAAA;AAAA,MAE3B;AAAA,MACA,EAAE,WAAW,GAAA;AAAA,IAAK;AAGnB,UAAMO,IAAqBhB,EAAS,MAC/B,CAACS,EAAiB,SAASA,EAAiB,MAAM,WAAW,IACzD,IAGDA,EAAiB,MAAM,OAAO,CAACxD,GAAOb,MACxC,CAACA,EAAK,QAAQ,CAAC,MAAM,QAAQA,EAAK,IAAI,IAClCa,IAGPA,IACAb,EAAK,KAAK,OAAO,CAAC6E,GAAW3E,MACrB2E,KAAa3E,EAAI,SAAS,IAC/B,CAAC,GAEH,CAAC,CACJ;AAED,aAASwE,EACR9D,GACkB;AAClB,UAAI,CAACA,KAAiB,CAAC,MAAM,QAAQA,CAAa;AACjD,eAAOkE,EAAA;AAGR,YAAMnF,IAAQiB,EAAc,IAAI,CAACZ,OAAU;AAAA,QAC1C,WAAWA,EAAK,YAAY;AAAA,QAC5B,MAAMA,EAAK,iBAAiB,IAAI,CAACE,MAAA;;AAAS;AAAA,YACzC,MAAMA,EAAI,QAAQ;AAAA,YAClB,QAAO4B,IAAA5B,EAAI,sBAAJ,OAAA4B,IAAyB;AAAA,YAChC,SAAS5B,EAAI,WAAW;AAAA,UAAA;AAAA,SACvB;AAAA,MAAA,EACD;AAEF,aAAOP,EAAM,SAAS;AACrB,QAAAA,EAAM,KAAKoF,GAAmB;AAG/B,aAAOpF;AAAA,IACR;AAEA,aAASmF,IAAsC;AAC9C,YAAMnF,IAAyB,CAAA;AAC/B,eAASqF,IAAI,GAAGA,IAAI,IAAIA;AACvB,QAAArF,EAAM,KAAKoF,GAAmB;AAE/B,aAAOpF;AAAA,IACR;AAEA,aAASoF,IAAmC;AAC3C,YAAME,IAAuB,CAAA;AAC7B,eAASD,IAAI,GAAGA,IAAI,GAAGA;AACtB,QAAAC,EAAK,KAAK,EAAE,MAAM,IAAI,OAAO,GAAG,SAASD,GAAG;AAE7C,aAAO,EAAE,WAAW,IAAI,MAAAC,EAAA;AAAA,IACzB;AAEA,aAASN,IAA4B;AACpC,UAAI,CAACN,EAAiB,SAASA,EAAiB,MAAM,WAAW,GAAG;AACnE,QAAAC,EAAY,QAAQ,CAAA;AACpB;AAAA,MACD;AAEA,YAAMY,IAA+B,CAAA;AACrC,UAAIC,IAAY,IACZC,IAAW;AAEf,MAAAf,EAAiB,MAAM,QAAQ,CAACrE,GAAMqF,MAAc;AACnD,YAAI,CAACrF,EAAK,QAAQA,EAAK,KAAK,WAAW,EAAG;AAE1C,cAAMsF,IAAWtF,EAAK,KAAK,CAAC,EAAE;AAC9B,YAAI,CAACsF,EAAU;AAEf,cAAMC,IAAYD,EAAS,MAAM,GAAG;AACpC,YAAIC,EAAU,WAAW,EAAG;AAE5B,cAAM,CAACC,GAAMC,CAAK,IAAIF,EAAU,IAAI,MAAM;AAC1C,YAAI,QAAMC,CAAI,KAAK,MAAMC,CAAK,OAE1BA,MAAUN,KAAaK,MAASJ,IAAU;AAC7C,gBAAMhD,KAAO,IAAI,KAAKoD,GAAMC,IAAQ,GAAG,CAAC;AACxC,UAAAP,EAAe,KAAK;AAAA,YACnB,MAAMG;AAAA,YACN,OAAOI,IAAQ;AAAA,YACf,MAAAD;AAAA,YACA,OAAOpD,GAAK,mBAAmB,SAAS,EAAE,OAAO,SAAS;AAAA,UAAA,CAC1D,GACD+C,IAAYM,GACZL,IAAWI;AAAA,QACZ;AAAA,MACD,CAAC,GAEDlB,EAAY,QAAQY;AAAA,IACrB;AAEA,aAAS3C,EAAqBC,GAAuB;AAEpD,aAAO,SADOkD,EAA2BlD,CAAK,CACzB,IAAI0B,EAAmB,KAAK;AAAA,IAClD;AAEA,aAASwB,EAA2BlD,GAAuB;AAC1D,aAAIA,MAAU,IAAU,IACpBA,KAAS,IAAU,IACnBA,KAAS,IAAU,IACnBA,KAAS,IAAU,IAChB;AAAA,IACR;AAEA,aAASmD,GAAezF,GAA2B;AAClD,UAAI,CAACA,EAAI,KAAM,QAAO;AAEtB,YAAM,CAACsF,GAAMC,GAAOG,CAAM,IAAI1F,EAAI,KAAK,MAAM,GAAG,EAAE,IAAI,MAAM,GAGtD2F,IAFO,IAAI,KAAKL,GAAMC,IAAQ,GAAGG,CAAM,EAElB,mBAAmB,SAAS;AAAA,QACtD,SAAS;AAAA,QACT,MAAM;AAAA,QACN,OAAO;AAAA,QACP,KAAK;AAAA,MAAA,CACL,GAEKE,IAAmB5F,EAAI,UAAU,IAAI,iBAAiB;AAC5D,aAAO,GAAGA,EAAI,KAAK,IAAI4F,CAAgB,OAAOD,CAAa;AAAA,IAC5D;AAEA,aAASE,GAAW7F,GAAyB;AAC5C,MAAA8D,EAAK,aAAa,EAAE,MAAM9D,EAAI,MAAM,OAAOA,EAAI,OAAO;AAAA,IACvD;AAEA,aAAS8F,KAAuB;AAC/B,MAAA7B,EAAa,QAAQ,CAACA,EAAa;AAAA,IACpC;AAEA,aAAS8B,GAAkBC,GAA2B;AACrD,MAAAhC,EAAmB,QAAQgC,GAC3B/B,EAAa,QAAQ,IACrBH,EAAK,uBAAuBkC,CAAM;AAAA,IACnC;sBA/UCC,EAAA,GAAAC,EAkHM,OAlHNC,IAkHM;AAAA,MAhHLC,EAiCM,OAjCNC,IAiCM;AAAA,QAhCLD,EAWM,OAXNE,IAWM;AAAA,UAVLF,EAGK,MAHLG,IAGKC,EAFD9B,QAAmB,eAAA,KAAmB,oCAE1C,CAAA;AAAA,UACA0B,EAKQ,SAAA;AAAA,YAJP,OAAKK,EAAA,CAAC,oBAAkB,EAAA,YACFC,EAAApD,CAAA,GAAO,CAAA;AAAA,UAAA,KAE1BoD,EAAA/C,CAAA,CAAc,GAAA,CAAA;AAAA,QAAA;QAGeE,EAAA,gBAAlCoC,EAAA,GAAAC,EAmBM,OAnBNS,IAmBM;AAAA,UAlBLP,EAOS,UAAA;AAAA,YANR,OAAM;AAAA,YACN,MAAK;AAAA,YACJ,SAAON;AAAA,UAAA;YAERc,EAAoCC,+BAApC,MAAoC;AAAA,gCAAT,MAAE,EAAA;AAAA,YAAA;8BAAO,cAErC,EAAA;AAAA,UAAA;UACW5C,EAAA,SAAXgC,EAAA,GAAAC,EASM,OATNY,IASM;AAAA,kBARLZ,EAOSa,GAAA,MAAAC,EANS9C,GAAY,CAAtB8B,MADRI,EAOS,UAAA;AAAA,cALP,KAAKJ;AAAA,cACL,SAAK,CAAAiB,MAAElB,GAAkBC,CAAM;AAAA,cAChC,OAAM;AAAA,YAAA,GAEHQ,EAAAR,CAAM,IAAG,WACb,GAAAkB,EAAA;;;;MAMQR,EAAAxD,CAAA,KAAX+C,EAAA,GAAAC,EAGM,OAHNiB,IAGM,CAAA,GAAAC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA;AAAA,QAFLhB,EAA2B,OAAA,EAAtB,OAAM,UAAA,GAAS,MAAA,EAAA;AAAA,QACpBA,EAAqC,cAA/B,4BAAwB,EAAA;AAAA,MAAA,SAI/BH,KAAAC,EAqEM,OArENmB,IAqEM;AAAA,QApELjB,EAiDM,OAjDNkB,IAiDM;AAAA,UA/CLlB,EAcM,OAdNmB,IAcM;AAAA,4BAbLnB,EAAgC,OAAA,EAA3B,OAAM,eAAA,GAAc,MAAA,EAAA;AAAA,YACzBA,EAWM,OAXNoB,IAWM;AAAA,sBAVLtB,EASMa,GAAA,MAAAC,EARW5C,EAAA,OAAW,CAApBmB,YADRW,EASM,OAAA;AAAA,gBAPJ,QAAQX,EAAM,IAAI,IAAIA,EAAM,KAAK;AAAA,gBAClC,OAAM;AAAA,gBACL,OAAKkC,GAAA;AAAA,kBAA4B,YAAA,GAAAlC,EAAM,OAAI,CAAA;AAAA,gBAAA;iBAIzCiB,EAAAjB,EAAM,KAAK,GAAA,CAAA;;;UAMjBa,EA6BM,OA7BNsB,IA6BM;AAAA;YAhBLtB,EAeM,OAfNuB,IAeM;AAAA,sBAdLzB,EAaMa,GAAA,MAAAC,EAZU7C,EAAA,OAAgB,CAAxBrE,YADRoG,EAaM,OAAA;AAAA,gBAXJ,KAAKpG,EAAK;AAAA,gBACX,OAAM;AAAA,cAAA;iBAENmG,EAAA,EAAA,GAAAC,EAOOa,GAAA,MAAAC,EANQlH,EAAK,OAAZE,YADRkG,EAOO,OAAA;AAAA,kBALL,KAAKlG,EAAI;AAAA,kBACV,UAAM,oBACEqC,EAAqBrC,EAAI,KAAK,CAAA,CAAA;AAAA,kBACrC,OAAOyF,GAAezF,CAAG;AAAA,kBACzB,SAAK,CAAAiH,MAAEpB,GAAW7F,CAAG;AAAA,gBAAA;;;;;QAQ3BoG,EAeM,OAfNwB,IAeM;AAAA,UAd6BlB,EAAAjD,CAAA,KAAlCwC,KAAAC,EAEQ,SAFR2B,IAAmD,sBACjCnB,EAAAjD,CAAA,CAAe,GAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACZrC,UAAMG,IAAQC,GAUR,EAAE,MAAA3C,GAAM,SAAAgC,GAAS,gBAAAS,GAAgB,iBAAAF,EAAA,IAAoBV,EAAY;AAAA,MACtE,SAASa,EAAM;AAAA,MACf,UAAUA,EAAM;AAAA,IAAA,CAChB,GAEKkE,IAAgB3E,EAAI,CAAC,GACrB4E,IAAe5E,EAAI,CAAC;AAG1B,IAAAkB;AAAA,MACCnD;AAAA,MACA,CAACoD,MAAY;;AACZ,YAAKA;AAGL,cAAIV,EAAM,eAAe,SAAS,GAAG;AACpC,gBAAIoE,IAAW,GACXC,IAAU;AAEd,YAAArE,EAAM,eAAe,QAAQ,CAACsE,MAAU;;AACvC,oBAAMC,KAAUvG,IAAA0C,EAAQ,aAAR,gBAAA1C,EAAmBsG;AACnC,cAAIC,KAAA,QAAAA,EAAS,UACZH,KAAYG,EAAQ,MAAM,gBAAgB,GAC1CF,KAAWE,EAAQ,MAAM,eAAe;AAAA,YAE1C,CAAC,GAEDL,EAAc,QAAQE,GACtBD,EAAa,QAAQE;AAAA,UACtB;AAEC,YAAAH,EAAc,UAAQlG,IAAA0C,EAAQ,WAAR,gBAAA1C,EAAgB,iBAAgB,GACtDmG,EAAa,UAAQjG,IAAAwC,EAAQ,WAAR,gBAAAxC,EAAgB,gBAAe;AAAA,MAEtD;AAAA,MACA,EAAE,WAAW,GAAA;AAAA,IAAK;AAInB,UAAMsG,IAAkB1E,EAAS,MAClBnB,GAAyBqB,EAAM,cAAc,EAC9C,QAAQ,CAAC,CACtB,GAGKyE,IAAkB3E,EAAS,MAAM;AACtC,UAAIE,EAAM,sBAAsB;AAC/B,cAAM0E,IAAqC;AAAA,UAC1C,UAAUR,EAAc;AAAA,UACxB,SAASC,EAAa;AAAA,UACtB,OAAO,WAAWK,EAAgB,KAAK;AAAA,QAAA;AAExC,eAAOxE,EAAM,qBAAqB0E,CAAM;AAAA,MACzC;AAYA,cAJCR,EAAc,QALJ,MAMVC,EAAa,QALH,MAMV,WAAWK,EAAgB,KAAK,IALtB,KAOC,QAAQ,CAAC;AAAA,IACtB,CAAC;sBAnKAnC,EAAA,GAAAC,EAiEM,OAjENC,IAiEM;AAAA,MAhELC,EAuDM,OAvDNC,IAuDM;AAAA,QArDLD,EAQM,OARNE,IAQM;AAAA,UAPLF,EAEM,OAFNG,IAEM;AAAA,YADLK,EAAsCC,iCAAtC,MAAsC;AAAA,gCAAT,MAAE,EAAA;AAAA,YAAA;;UAEhCT,EAGM,OAHNO,IAGM;AAAA,YAFLP,EAAmD,OAAnDU,IAAmDN,EAAxB4B,EAAA,KAAe,GAAA,CAAA;AAAA,YAC1ChB,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAhB,EAA8C,OAAA,EAAzC,OAAM,gBAAa,oBAAgB,EAAA;AAAA,UAAA;;QAK1CA,EAWM,OAXNc,IAWM;AAAA,UAVLd,EAEM,OAFNe,IAEM;AAAA,YADLP,EAAoCC,+BAApC,MAAoC;AAAA,gCAAT,MAAE,EAAA;AAAA,YAAA;;UAE9BT,EAMM,OANNiB,IAMM;AAAA,YALMX,EAAAxD,CAAA,KAAX+C,EAAA,GAAAC,EAEM,OAFNoB,IAEM,CAAA,GAAAF,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA;AAAA,cADLhB,EAA2B,OAAA,EAAtB,OAAM,UAAA,GAAS,MAAA,EAAA;AAAA,YAAA,cAErBF,EAAwD,OAAxDqB,IAAwDf,EAAtBsB,EAAA,KAAa,GAAA,CAAA;AAAA,YAC/CV,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAhB,EAAsC,OAAA,EAAjC,OAAM,gBAAa,YAAQ,EAAA;AAAA,UAAA;;QAKlCA,EAWM,OAXNoB,IAWM;AAAA,UAVLpB,EAEM,OAFNsB,IAEM;AAAA,YADLd,EAAmCC,8BAAnC,MAAmC;AAAA,gCAAT,MAAE,EAAA;AAAA,YAAA;;UAE7BT,EAMM,OANNuB,IAMM;AAAA,YALMjB,EAAAxD,CAAA,KAAX+C,EAAA,GAAAC,EAEM,OAFNqC,IAEM,CAAA,GAAAnB,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA;AAAA,cADLhB,EAA2B,OAAA,EAAtB,OAAM,UAAA,GAAS,MAAA,EAAA;AAAA,YAAA,cAErBF,EAAuD,OAAvD0B,IAAuDpB,EAArBuB,EAAA,KAAY,GAAA,CAAA;AAAA,YAC9CX,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAAhB,EAAqC,OAAA,EAAhC,OAAM,gBAAa,WAAO,EAAA;AAAA,UAAA;;QAKJvC,EAAA,kBAA7BoC,EAAA,GAAAC,EAaM,OAbN2B,IAaM;AAAA,UAZLzB,EAEM,OAFNoC,IAEM;AAAA,YADL5B,EAAiCC,6BAAjC,MAAiC;AAAA,gCAAR,KAAC,EAAA;AAAA,YAAA;;UAE3BT,EAQM,OARNqC,IAQM;AAAA,YAPM/B,EAAAxD,CAAA,KAAX+C,EAAA,GAAAC,EAEM,OAFNwC,IAEM,CAAA,GAAAtB,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA;AAAA,cADLhB,EAA2B,OAAA,EAAtB,OAAM,UAAA,GAAS,MAAA,EAAA;AAAA,YAAA,cAErBF,EAA0D,OAA1DyC,IAA0DnC,EAAxB6B,EAAA,KAAe,GAAA,CAAA;AAAA,YACjDjC,EAEM,OAFNwC,IAEM;AAAA,cADLhC,EAAqDC,mCAArD,MAAqD;AAAA,oCAAtB,mBAAe,EAAA;AAAA,cAAA;;;;;MAOlDT,EAKM,OALNyC,IAKM;AAAA,QAJQnC,EAAA/C,CAAA,KAAbsC,KAAAC,EAGQ,SAHR4C,IAGQ;AAAA,UAFJC,EAAAvC,EAAAE,EAAA/C,CAAA,CAAc,IAAG,KACpB,CAAA;AAAA,UAAY+C,EAAAjD,CAAA,UAAZyC,EAA4D,QAAA8C,IAA/B,QAAGxC,EAAGE,EAAAjD,CAAA,CAAe,GAAA,CAAA;;;;;oEC1ChDwF,KAAiC;AAAA,EACtC,QAAQC,GAAU;AACjB,IAAAA,EAAI,UAAU,qBAAqBC,EAAiB,GACpDD,EAAI,UAAU,kBAAkBE,EAAc;AAAA,EAC/C;AACD;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"vue-git-stats.umd.js","sources":["../../core/src/api/fetchGitStats.ts","../../core/src/utils/generateDummyData.js","../../core/src/index.ts","../src/composables/useGitStats.ts","../src/components/ContributionGraph.vue","../src/components/StatsBreakdown.vue","../src/index.ts"],"sourcesContent":["import type { GitStatsData } from '../types'\r\n\r\nexport async function fetchGitStats(url: string): Promise<GitStatsData> {\r\n\tconst response = await fetch(url)\r\n\tif (!response.ok) {\r\n\t\tthrow new Error(`Failed to fetch git stats: ${response.statusText}`)\r\n\t}\r\n\treturn response.json()\r\n}\r\n","/**\n * Generate realistic dummy data for testing and development\n */\n\n/**\n * Generate dummy contribution data (53 weeks)\n */\nexport function generateDummyContributions() {\n\tconst weeks = []\n\tconst now = new Date()\n\n\t// Get the Sunday that starts the week containing today\n\tconst endDate = new Date(now)\n\tendDate.setDate(endDate.getDate() - endDate.getDay())\n\n\t// Go back exactly 52 weeks\n\tconst startDate = new Date(endDate)\n\tstartDate.setDate(startDate.getDate() - 52 * 7)\n\n\tconst currentDate = new Date(startDate)\n\n\tfor (let week = 0; week < 53; week++) {\n\t\tconst weekData = {\n\t\t\tweekStart: new Date(currentDate).toISOString().split('T')[0],\n\t\t\tcontributionDays: [],\n\t\t}\n\n\t\tfor (let day = 0; day < 7; day++) {\n\t\t\tconst isInFuture = currentDate > now\n\t\t\tconst isWeekend = day === 0 || day === 6\n\n\t\t\t// More realistic pattern: fewer commits on weekends, none in future\n\t\t\tlet dayCount = 0\n\t\t\tif (!isInFuture) {\n\t\t\t\tif (isWeekend) {\n\t\t\t\t\tdayCount =\n\t\t\t\t\t\tMath.random() < 0.3 ? Math.floor(Math.random() * 5) : 0\n\t\t\t\t} else {\n\t\t\t\t\tdayCount = Math.floor(Math.random() * 15)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tweekData.contributionDays.push({\n\t\t\t\tdate: new Date(currentDate).toISOString().split('T')[0],\n\t\t\t\tcontributionCount: dayCount,\n\t\t\t\tweekday: day,\n\t\t\t})\n\t\t\tcurrentDate.setDate(currentDate.getDate() + 1)\n\t\t}\n\n\t\tweeks.push(weekData)\n\t}\n\n\treturn weeks\n}\n\n/**\n * Generate complete dummy stats data\n */\nexport function generateDummyStats(options = {}) {\n\tconst {\n\t\tusername = 'demo-user',\n\t\tplatform = 'github',\n\t\tprojectCount = 30,\n\t\tcommitCount = 2500,\n\t} = options\n\n\tconst contributions = generateDummyContributions()\n\tconst totalContributions = contributions.reduce((total, week) => {\n\t\treturn (\n\t\t\ttotal +\n\t\t\tweek.contributionDays.reduce(\n\t\t\t\t(sum, day) => sum + day.contributionCount,\n\t\t\t\t0\n\t\t\t)\n\t\t)\n\t}, 0)\n\n\treturn {\n\t\tlastUpdated: new Date().toISOString(),\n\t\tprofiles: [\n\t\t\t{\n\t\t\t\tusername,\n\t\t\t\tplatform,\n\t\t\t\tstats: {\n\t\t\t\t\tprojectCount,\n\t\t\t\t\tcommitCount,\n\t\t\t\t\tcontributions: contributions.map((week) => ({\n\t\t\t\t\t\tfirstDay: week.weekStart,\n\t\t\t\t\t\tcontributionDays: week.contributionDays,\n\t\t\t\t\t})),\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\ttotals: {\n\t\t\tprojectCount,\n\t\t\tcommitCount,\n\t\t},\n\t\tmetadata: {\n\t\t\tfetchedAt: Date.now(),\n\t\t\tsource: 'dummy_data',\n\t\t\tisDummy: true,\n\t\t},\n\t}\n}\n\n/**\n * Generate multiple profiles dummy data\n */\nexport function generateMultiProfileDummyStats() {\n\tconst githubProfile = generateDummyStats({\n\t\tusername: 'demo-github',\n\t\tplatform: 'github',\n\t\tprojectCount: 45,\n\t\tcommitCount: 2847,\n\t})\n\n\tconst gitlabProfile = generateDummyStats({\n\t\tusername: 'demo-gitlab',\n\t\tplatform: 'gitlab',\n\t\tprojectCount: 7,\n\t\tcommitCount: 523,\n\t})\n\n\treturn {\n\t\tlastUpdated: new Date().toISOString(),\n\t\tprofiles: [githubProfile.profiles[0], gitlabProfile.profiles[0]],\n\t\ttotals: {\n\t\t\tprojectCount: 45 + 7,\n\t\t\tcommitCount: 2847 + 523,\n\t\t},\n\t\tmetadata: {\n\t\t\tfetchedAt: Date.now(),\n\t\t\tsource: 'dummy_data',\n\t\t\tisDummy: true,\n\t\t},\n\t}\n}\n\n/**\n * Save dummy data to a file (for testing)\n */\nexport function saveDummyDataToFile(filepath = 'dummy-git-stats.json') {\n\tconst data = generateDummyStats()\n\tconst json = JSON.stringify(data, null, '\\t')\n\n\tif (typeof window !== 'undefined') {\n\t\t// Browser environment - trigger download\n\t\tconst blob = new Blob([json], { type: 'application/json' })\n\t\tconst url = URL.createObjectURL(blob)\n\t\tconst a = document.createElement('a')\n\t\ta.href = url\n\t\ta.download = filepath\n\t\ta.click()\n\t\tURL.revokeObjectURL(url)\n\t} else {\n\t\t// Node environment\n\t\ttry {\n\t\t\tconst fs = require('fs')\n\t\t\tfs.writeFileSync(filepath, json)\n\t\t\tconsole.log(`✓ Dummy data saved to ${filepath}`)\n\t\t} catch (err) {\n\t\t\tconsole.error('Failed to save dummy data:', err)\n\t\t}\n\t}\n}\n","// packages/core/src/index.ts\n// Framework-agnostic core logic\n\n// Re-export everything from types\nexport type {\n\tColorScheme,\n\tContributionDay,\n\tContributionWeek,\n\tProfile,\n\tGitStatsData,\n\tExperienceEntry,\n\tDataSource,\n\tPlatform,\n\tProfileStats,\n\tStatsTotals,\n\tStatsMetadata,\n\tCustomStatCalculator,\n\tCustomStatCalculatorParams,\n} from './types/index.js'\n\n// Export API functions\nexport { fetchGitStats as fetchGitStatsAPI } from './api/fetchGitStats.js'\n\n// Export utility functions with explicit imports\nexport {\n\tgenerateDummyStats,\n\tgenerateDummyContributions,\n\tgenerateMultiProfileDummyStats,\n\tsaveDummyDataToFile,\n} from './utils/generateDummyData.js'\n\n// Core data fetching (framework-agnostic)\nimport type { GitStatsData } from './types/index.js'\n\nexport interface FetchOptions {\n\tdataUrl: string\n\tcacheTTL?: number\n\tcacheKey?: string\n\tuseStaleCache?: boolean\n}\n\nexport interface DataResult<T> {\n\tdata: T | null\n\terror: Error | null\n\tsource: 'static' | 'cache' | 'mock' | 'dummy' | null\n\tisDummy: boolean\n}\n\n/**\n * Framework-agnostic data fetcher\n */\nexport async function fetchGitStats(\n\toptions: FetchOptions\n): Promise<DataResult<GitStatsData>> {\n\tconst { dataUrl, cacheKey = 'git_stats_cache', useStaleCache = true } = options\n\n\ttry {\n\t\t// Try static file first\n\t\tconst response = await fetch(dataUrl)\n\t\tif (response.ok) {\n\t\t\tconst data = await response.json()\n\t\t\t// Cache the data\n\t\t\tif (typeof window !== 'undefined') {\n\t\t\t\tlocalStorage.setItem(\n\t\t\t\t\tcacheKey,\n\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t...data,\n\t\t\t\t\t\tcachedAt: Date.now(),\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tdata,\n\t\t\t\terror: null,\n\t\t\t\tsource: 'static',\n\t\t\t\tisDummy: data.metadata?.isDummy === true,\n\t\t\t}\n\t\t}\n\t} catch (err) {\n\t\tconsole.warn('Failed to fetch from static file:', err)\n\t}\n\n\t// Try cache\n\tif (useStaleCache && typeof window !== 'undefined') {\n\t\ttry {\n\t\t\tconst cached = localStorage.getItem(cacheKey)\n\t\t\tif (cached) {\n\t\t\t\tconst data = JSON.parse(cached)\n\t\t\t\treturn {\n\t\t\t\t\tdata,\n\t\t\t\t\terror: null,\n\t\t\t\t\tsource: 'cache',\n\t\t\t\t\tisDummy: data.metadata?.isDummy === true,\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconsole.warn('Failed to load from cache:', err)\n\t\t}\n\t}\n\n\t// Fallback to mock\n\tconst mockData = generateMockData()\n\treturn {\n\t\tdata: mockData,\n\t\terror: null,\n\t\tsource: 'mock',\n\t\tisDummy: false,\n\t}\n}\n\n/**\n * Format last updated time\n */\nexport function formatLastUpdated(dateString: string): string {\n\tconst date = new Date(dateString)\n\tconst now = new Date()\n\tconst diffHours = Math.floor((now.getTime() - date.getTime()) / (1000 * 60 * 60))\n\n\tif (diffHours < 1) return 'just now'\n\tif (diffHours < 24) return `${diffHours} hours ago`\n\n\tconst diffDays = Math.floor(diffHours / 24)\n\tif (diffDays === 1) return 'yesterday'\n\tif (diffDays < 7) return `${diffDays} days ago`\n\n\treturn date.toLocaleDateString('en-US', {\n\t\tmonth: 'short',\n\t\tday: 'numeric',\n\t\tyear: date.getFullYear() !== now.getFullYear() ? 'numeric' : undefined,\n\t})\n}\n\n/**\n * Get contribution level (0-4)\n */\nexport function getContributionLevel(count: number): number {\n\tif (count === 0) return 0\n\tif (count <= 3) return 1\n\tif (count <= 6) return 2\n\tif (count <= 9) return 3\n\treturn 4\n}\n\n/**\n * Calculate years of experience\n */\nexport function calculateYearsExperience(\n\texperienceData: { startDate: string; endDate: string | null; skills?: string[] }[]\n): number {\n\tif (experienceData.length === 0) return 0\n\n\tconst skillExperience: Record<string, number> = {}\n\n\texperienceData.forEach((exp) => {\n\t\tconst end = exp.endDate ? new Date(exp.endDate) : new Date()\n\t\tconst start = new Date(exp.startDate)\n\t\tconst years = (end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24 * 365.25)\n\n\t\texp.skills?.forEach((skill) => {\n\t\t\tif (!skillExperience[skill]) {\n\t\t\t\tskillExperience[skill] = 0\n\t\t\t}\n\t\t\tskillExperience[skill] += years\n\t\t})\n\t})\n\n\treturn Math.max(...Object.values(skillExperience), 0)\n}\n\n// Mock data generator\nfunction generateMockData(): GitStatsData {\n\treturn {\n\t\tlastUpdated: new Date().toISOString(),\n\t\tprofiles: [\n\t\t\t{\n\t\t\t\tusername: 'mockuser',\n\t\t\t\tplatform: 'github',\n\t\t\t\tstats: {\n\t\t\t\t\tprojectCount: 30,\n\t\t\t\t\tcommitCount: 2500,\n\t\t\t\t\tcontributions: [],\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\ttotals: {\n\t\t\tprojectCount: 30,\n\t\t\tcommitCount: 2500,\n\t\t},\n\t\tmetadata: {\n\t\t\tsource: 'mock',\n\t\t\tfetchedAt: Date.now(),\n\t\t},\n\t}\n}","import { ref, computed } from 'vue'\r\nimport {\r\n\tfetchGitStats,\r\n\tformatLastUpdated,\r\n\ttype GitStatsData,\r\n\ttype DataSource,\r\n} from '@git-stats-components/core'\r\n\r\nexport interface UseGitStatsConfig {\r\n\tdataUrl?: string\r\n\tcacheTTL?: number\r\n\tuseStaleCache?: boolean\r\n\tcacheKey?: string\r\n}\r\n\r\nexport function useGitStats(config: UseGitStatsConfig = {}) {\r\n\tconst {\r\n\t\tdataUrl = '/data/git-stats.json',\r\n\t\tcacheTTL = 24 * 60 * 60 * 1000,\r\n\t\tuseStaleCache = true,\r\n\t\tcacheKey = 'git_stats_cache',\r\n\t} = config\r\n\r\n\tconst loading = ref(false)\r\n\tconst error = ref<Error | null>(null)\r\n\tconst data = ref<GitStatsData | null>(null)\r\n\tconst dataSource = ref<DataSource | null>(null)\r\n\tconst isDummy = ref(false)\r\n\r\n\t/**\r\n\t * Load data with fallback strategy\r\n\t */\r\n\tasync function loadData(): Promise<GitStatsData | null> {\r\n\t\tloading.value = true\r\n\t\terror.value = null\r\n\r\n\t\ttry {\r\n\t\t\tconst result = await fetchGitStats({\r\n\t\t\t\tdataUrl,\r\n\t\t\t\tcacheTTL,\r\n\t\t\t\tcacheKey,\r\n\t\t\t\tuseStaleCache,\r\n\t\t\t})\r\n\r\n\t\t\tdata.value = result.data\r\n\t\t\terror.value = result.error\r\n\t\t\tdataSource.value = result.source\r\n\t\t\tisDummy.value = result.isDummy\r\n\r\n\t\t\treturn result.data\r\n\t\t} catch (err) {\r\n\t\t\terror.value =\r\n\t\t\t\terr instanceof Error ? err : new Error('Failed to load data')\r\n\t\t\treturn null\r\n\t\t} finally {\r\n\t\t\tloading.value = false\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Format \"last updated\" text\r\n\t */\r\n\tconst lastUpdatedText = computed(() => {\r\n\t\tif (!data.value?.lastUpdated) return ''\r\n\t\treturn formatLastUpdated(data.value.lastUpdated)\r\n\t})\r\n\r\n\t/**\r\n\t * Computed data source display text\r\n\t */\r\n\tconst dataSourceText = computed(() => {\r\n\t\tif (isDummy.value) {\r\n\t\t\treturn '⚠️ Using dummy data for testing'\r\n\t\t}\r\n\r\n\t\tswitch (dataSource.value) {\r\n\t\t\tcase 'static':\r\n\t\t\t\treturn 'Real-time data'\r\n\t\t\tcase 'cache':\r\n\t\t\t\treturn 'Cached data'\r\n\t\t\tcase 'mock':\r\n\t\t\t\treturn 'Sample data'\r\n\t\t\tdefault:\r\n\t\t\t\treturn ''\r\n\t\t}\r\n\t})\r\n\r\n\t// Auto-load on creation\r\n\tloadData()\r\n\r\n\treturn {\r\n\t\tdata,\r\n\t\tloading,\r\n\t\terror,\r\n\t\tdataSource,\r\n\t\tdataSourceText,\r\n\t\tlastUpdatedText,\r\n\t\tisDummy,\r\n\t\tloadData,\r\n\t}\r\n}\r\n","<template>\r\n\t<div class=\"git-contribution-graph\">\r\n\t\t<!-- Header -->\r\n\t\t<div class=\"graph-header\">\r\n\t\t\t<div class=\"header-info\">\r\n\t\t\t\t<h5 class=\"contribution-count\">\r\n\t\t\t\t\t{{ totalContributions.toLocaleString() }} contributions in\r\n\t\t\t\t\tthe last year\r\n\t\t\t\t</h5>\r\n\t\t\t\t<small\r\n\t\t\t\t\tclass=\"data-source-text\"\r\n\t\t\t\t\t:class=\"{ 'is-dummy': isDummy }\"\r\n\t\t\t\t>\r\n\t\t\t\t\t{{ dataSourceText }}\r\n\t\t\t\t</small>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"header-actions\" v-if=\"showSettings\">\r\n\t\t\t\t<button\r\n\t\t\t\t\tclass=\"settings-btn\"\r\n\t\t\t\t\ttype=\"button\"\r\n\t\t\t\t\t@click=\"toggleSettings\"\r\n\t\t\t\t>\r\n\t\t\t\t\t<slot name=\"settings-icon\">⚙️</slot>\r\n\t\t\t\t\tSettings\r\n\t\t\t\t</button>\r\n\t\t\t\t<div v-if=\"settingsOpen\" class=\"settings-dropdown\">\r\n\t\t\t\t\t<button\r\n\t\t\t\t\t\tv-for=\"scheme in colorSchemes\"\r\n\t\t\t\t\t\t:key=\"scheme\"\r\n\t\t\t\t\t\t@click=\"changeColorScheme(scheme)\"\r\n\t\t\t\t\t\tclass=\"settings-item\"\r\n\t\t\t\t\t>\r\n\t\t\t\t\t\t{{ scheme }} theme\r\n\t\t\t\t\t</button>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\r\n\t\t<!-- Loading state -->\r\n\t\t<div v-if=\"loading\" class=\"loading-state\">\r\n\t\t\t<div class=\"spinner\"></div>\r\n\t\t\t<span>Loading contributions...</span>\r\n\t\t</div>\r\n\r\n\t\t<!-- Contribution grid -->\r\n\t\t<div v-else class=\"graph-container\">\r\n\t\t\t<div class=\"graph-content-wrapper\">\r\n\t\t\t\t<!-- Month labels -->\r\n\t\t\t\t<div class=\"months-row\">\r\n\t\t\t\t\t<div class=\"month-spacer\"></div>\r\n\t\t\t\t\t<div class=\"months-container\">\r\n\t\t\t\t\t\t<div\r\n\t\t\t\t\t\t\tv-for=\"month in monthLabels\"\r\n\t\t\t\t\t\t\t:key=\"`${month.year}-${month.month}`\"\r\n\t\t\t\t\t\t\tclass=\"month-label\"\r\n\t\t\t\t\t\t\t:style=\"{\r\n\t\t\t\t\t\t\t\tgridColumn: `${month.week + 1} / span 1`,\r\n\t\t\t\t\t\t\t}\"\r\n\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t{{ month.label }}\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\r\n\t\t\t\t<!-- Grid with day labels -->\r\n\t\t\t\t<div class=\"grid-container\">\r\n\t\t\t\t\t<!-- Day labels -->\r\n\t\t\t\t\t<div class=\"day-labels\">\r\n\t\t\t\t\t\t<div class=\"day-label\">Mon</div>\r\n\t\t\t\t\t\t<div class=\"day-label\"></div>\r\n\t\t\t\t\t\t<div class=\"day-label\">Wed</div>\r\n\t\t\t\t\t\t<div class=\"day-label\"></div>\r\n\t\t\t\t\t\t<div class=\"day-label\">Fri</div>\r\n\t\t\t\t\t\t<div class=\"day-label\"></div>\r\n\t\t\t\t\t\t<div class=\"day-label\"></div>\r\n\t\t\t\t\t</div>\r\n\r\n\t\t\t\t\t<!-- Contribution squares -->\r\n\t\t\t\t\t<div class=\"contribution-grid\">\r\n\t\t\t\t\t\t<div\r\n\t\t\t\t\t\t\tv-for=\"week in contributionData\"\r\n\t\t\t\t\t\t\t:key=\"week.weekStart\"\r\n\t\t\t\t\t\t\tclass=\"contribution-week\"\r\n\t\t\t\t\t\t>\r\n\t\t\t\t\t\t\t<div\r\n\t\t\t\t\t\t\t\tv-for=\"day in week.days\"\r\n\t\t\t\t\t\t\t\t:key=\"day.date\"\r\n\t\t\t\t\t\t\t\tclass=\"contribution-day\"\r\n\t\t\t\t\t\t\t\t:class=\"getContributionLevel(day.count)\"\r\n\t\t\t\t\t\t\t\t:title=\"getTooltipText(day)\"\r\n\t\t\t\t\t\t\t\t@click=\"onDayClick(day)\"\r\n\t\t\t\t\t\t\t></div>\r\n\t\t\t\t\t\t</div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Legend -->\r\n\t\t\t<div class=\"graph-footer\">\r\n\t\t\t\t<small class=\"last-updated\" v-if=\"lastUpdatedText\">\r\n\t\t\t\t\tLast updated: {{ lastUpdatedText }}\r\n\t\t\t\t</small>\r\n\t\t\t\t<div class=\"legend\">\r\n\t\t\t\t\t<small class=\"legend-label\">Less</small>\r\n\t\t\t\t\t<div class=\"legend-squares\">\r\n\t\t\t\t\t\t<div class=\"contribution-day level-0\"></div>\r\n\t\t\t\t\t\t<div class=\"contribution-day level-1\"></div>\r\n\t\t\t\t\t\t<div class=\"contribution-day level-2\"></div>\r\n\t\t\t\t\t\t<div class=\"contribution-day level-3\"></div>\r\n\t\t\t\t\t\t<div class=\"contribution-day level-4\"></div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<small class=\"legend-label\">More</small>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\t</div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from 'vue'\r\nimport { useGitStats } from '../composables/useGitStats'\r\nimport {\r\n\ttype ColorScheme,\r\n\ttype ContributionWeek,\r\n} from '@git-stats-components/core'\r\n\r\ninterface ProcessedWeek {\r\n\tweekStart: string\r\n\tdays: ProcessedDay[]\r\n}\r\n\r\ninterface ProcessedDay {\r\n\tdate: string\r\n\tcount: number\r\n\tweekday: number\r\n}\r\n\r\ninterface MonthLabel {\r\n\tweek: number\r\n\tmonth: number\r\n\tyear: number\r\n\tlabel: string\r\n}\r\n\r\ninterface Props {\r\n\tdataUrl?: string\r\n\tprofileIndex?: number\r\n\tcolorScheme?: ColorScheme\r\n\tshowSettings?: boolean\r\n\tcacheTTL?: number\r\n}\r\n\r\ninterface Emits {\r\n\t(e: 'day-click', data: { date: string; count: number }): void\r\n\t(e: 'color-scheme-change', scheme: ColorScheme): void\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n\tdataUrl: '/data/git-stats.json',\r\n\tprofileIndex: 0,\r\n\tcolorScheme: 'green',\r\n\tshowSettings: true,\r\n\tcacheTTL: 24 * 60 * 60 * 1000,\r\n})\r\n\r\nconst emit = defineEmits<Emits>()\r\n\r\n// Use the shared composable\r\nconst { data, loading, dataSourceText, lastUpdatedText, isDummy } = useGitStats(\r\n\t{\r\n\t\tdataUrl: props.dataUrl,\r\n\t\tcacheTTL: props.cacheTTL,\r\n\t}\r\n)\r\n\r\nconst currentColorScheme = ref<ColorScheme>(props.colorScheme)\r\nconst settingsOpen = ref(false)\r\nconst colorSchemes: ColorScheme[] = ['green', 'blue', 'purple', 'orange']\r\nconst contributionData = ref<ProcessedWeek[]>([])\r\nconst monthLabels = ref<MonthLabel[]>([])\r\n\r\n// Process contribution data when loaded\r\nwatch(\r\n\tdata,\r\n\t(newData) => {\r\n\t\tif (newData?.profiles?.[props.profileIndex]?.stats?.contributions) {\r\n\t\t\tconst contributions =\r\n\t\t\t\tnewData.profiles[props.profileIndex].stats.contributions\r\n\t\t\tif (contributions) {\r\n\t\t\t\tcontributionData.value = processContributions(contributions)\r\n\t\t\t\tgenerateMonthLabels()\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tcontributionData.value = []\r\n\t\t}\r\n\t},\r\n\t{ immediate: true }\r\n)\r\n\r\nconst totalContributions = computed(() => {\r\n\tif (!contributionData.value || contributionData.value.length === 0) {\r\n\t\treturn 0\r\n\t}\r\n\r\n\treturn contributionData.value.reduce((total, week) => {\r\n\t\tif (!week.days || !Array.isArray(week.days)) {\r\n\t\t\treturn total\r\n\t\t}\r\n\t\treturn (\r\n\t\t\ttotal +\r\n\t\t\tweek.days.reduce((weekTotal, day) => {\r\n\t\t\t\treturn weekTotal + (day.count || 0)\r\n\t\t\t}, 0)\r\n\t\t)\r\n\t}, 0)\r\n})\r\n\r\nfunction processContributions(\r\n\tcontributions: ContributionWeek[]\r\n): ProcessedWeek[] {\r\n\tif (!contributions || !Array.isArray(contributions)) {\r\n\t\treturn generateEmptyWeeks()\r\n\t}\r\n\r\n\tconst weeks = contributions.map((week) => ({\r\n\t\tweekStart: week.firstDay || '',\r\n\t\tdays: week.contributionDays.map((day) => ({\r\n\t\t\tdate: day.date || '',\r\n\t\t\tcount: day.contributionCount ?? 0,\r\n\t\t\tweekday: day.weekday || 0,\r\n\t\t})),\r\n\t}))\r\n\r\n\twhile (weeks.length < 53) {\r\n\t\tweeks.push(generateEmptyWeek())\r\n\t}\r\n\r\n\treturn weeks\r\n}\r\n\r\nfunction generateEmptyWeeks(): ProcessedWeek[] {\r\n\tconst weeks: ProcessedWeek[] = []\r\n\tfor (let i = 0; i < 53; i++) {\r\n\t\tweeks.push(generateEmptyWeek())\r\n\t}\r\n\treturn weeks\r\n}\r\n\r\nfunction generateEmptyWeek(): ProcessedWeek {\r\n\tconst days: ProcessedDay[] = []\r\n\tfor (let i = 0; i < 7; i++) {\r\n\t\tdays.push({ date: '', count: 0, weekday: i })\r\n\t}\r\n\treturn { weekStart: '', days }\r\n}\r\n\r\nfunction generateMonthLabels(): void {\r\n\tif (!contributionData.value || contributionData.value.length === 0) {\r\n\t\tmonthLabels.value = []\r\n\t\treturn\r\n\t}\r\n\r\n\tconst monthPositions: MonthLabel[] = []\r\n\tlet lastMonth = -1\r\n\tlet lastYear = -1\r\n\r\n\tcontributionData.value.forEach((week, weekIndex) => {\r\n\t\tif (!week.days || week.days.length === 0) return\r\n\r\n\t\tconst firstDay = week.days[0].date\r\n\t\tif (!firstDay) return\r\n\r\n\t\tconst dateParts = firstDay.split('-')\r\n\t\tif (dateParts.length !== 3) return\r\n\r\n\t\tconst [year, month] = dateParts.map(Number)\r\n\t\tif (isNaN(year) || isNaN(month)) return\r\n\r\n\t\tif (month !== lastMonth || year !== lastYear) {\r\n\t\t\tconst date = new Date(year, month - 1, 1)\r\n\t\t\tmonthPositions.push({\r\n\t\t\t\tweek: weekIndex,\r\n\t\t\t\tmonth: month - 1,\r\n\t\t\t\tyear: year,\r\n\t\t\t\tlabel: date.toLocaleDateString('en-US', { month: 'short' }),\r\n\t\t\t})\r\n\t\t\tlastMonth = month\r\n\t\t\tlastYear = year\r\n\t\t}\r\n\t})\r\n\r\n\tmonthLabels.value = monthPositions\r\n}\r\n\r\nfunction getContributionLevel(count: number): string {\r\n\tconst level = getContributionLevelNumber(count)\r\n\treturn `level-${level} ${currentColorScheme.value}`\r\n}\r\n\r\nfunction getContributionLevelNumber(count: number): number {\r\n\tif (count === 0) return 0\r\n\tif (count <= 3) return 1\r\n\tif (count <= 6) return 2\r\n\tif (count <= 9) return 3\r\n\treturn 4\r\n}\r\n\r\nfunction getTooltipText(day: ProcessedDay): string {\r\n\tif (!day.date) return ''\r\n\r\n\tconst [year, month, dayNum] = day.date.split('-').map(Number)\r\n\tconst date = new Date(year, month - 1, dayNum)\r\n\r\n\tconst formattedDate = date.toLocaleDateString('en-US', {\r\n\t\tweekday: 'short',\r\n\t\tyear: 'numeric',\r\n\t\tmonth: 'short',\r\n\t\tday: 'numeric',\r\n\t})\r\n\r\n\tconst contributionText = day.count === 1 ? 'contribution' : 'contributions'\r\n\treturn `${day.count} ${contributionText} on ${formattedDate}`\r\n}\r\n\r\nfunction onDayClick(day: ProcessedDay): void {\r\n\temit('day-click', { date: day.date, count: day.count })\r\n}\r\n\r\nfunction toggleSettings(): void {\r\n\tsettingsOpen.value = !settingsOpen.value\r\n}\r\n\r\nfunction changeColorScheme(scheme: ColorScheme): void {\r\n\tcurrentColorScheme.value = scheme\r\n\tsettingsOpen.value = false\r\n\temit('color-scheme-change', scheme)\r\n}\r\n</script>\r\n\r\n<style scoped>\r\n.graph-content-wrapper {\r\n\tjustify-items: anchor-center;\r\n}\r\n.git-contribution-graph {\r\n\tfont-family:\r\n\t\t-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica,\r\n\t\tArial, sans-serif;\r\n\tfont-size: 12px;\r\n\tbackground: transparent;\r\n\tcolor: #e6edf3;\r\n\tpadding: 16px;\r\n\tmax-width: 1200px;\r\n\tmargin: 0 auto;\r\n\twidth: 100%;\r\n}\r\n\r\n.graph-header {\r\n\tdisplay: flex;\r\n\tjustify-content: space-between;\r\n\talign-items: center;\r\n\tmargin-bottom: 16px;\r\n}\r\n\r\n.contribution-count {\r\n\tmargin: 0 0 4px 0;\r\n\tfont-size: 16px;\r\n\tfont-weight: 600;\r\n}\r\n\r\n.data-source-text {\r\n\tcolor: #7d8590;\r\n}\r\n\r\n.data-source-text.is-dummy {\r\n\tcolor: #f85149;\r\n\tfont-weight: 600;\r\n\tbackground: rgba(248, 81, 73, 0.1);\r\n\tpadding: 2px 8px;\r\n\tborder-radius: 4px;\r\n}\r\n\r\n.settings-btn {\r\n\tbackground: transparent;\r\n\tborder: 1px solid #30363d;\r\n\tcolor: #7d8590;\r\n\tpadding: 6px 12px;\r\n\tborder-radius: 6px;\r\n\tcursor: pointer;\r\n\tfont-size: 12px;\r\n}\r\n\r\n.settings-btn:hover {\r\n\tbackground: #21262d;\r\n\tcolor: #e6edf3;\r\n}\r\n\r\n.header-actions {\r\n\tposition: relative;\r\n}\r\n\r\n.settings-dropdown {\r\n\tposition: absolute;\r\n\tright: 0;\r\n\ttop: 100%;\r\n\tmargin-top: 4px;\r\n\tbackground: #21262d;\r\n\tborder: 1px solid #30363d;\r\n\tborder-radius: 6px;\r\n\tpadding: 4px;\r\n\tz-index: 10;\r\n\tmin-width: 150px;\r\n}\r\n\r\n.settings-item {\r\n\tdisplay: block;\r\n\twidth: 100%;\r\n\tbackground: transparent;\r\n\tborder: none;\r\n\tcolor: #e6edf3;\r\n\tpadding: 8px 12px;\r\n\ttext-align: left;\r\n\tcursor: pointer;\r\n\tborder-radius: 4px;\r\n}\r\n\r\n.settings-item:hover {\r\n\tbackground: #30363d;\r\n}\r\n\r\n.loading-state {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\tgap: 12px;\r\n\tpadding: 40px;\r\n\tcolor: #7d8590;\r\n}\r\n\r\n.spinner {\r\n\twidth: 20px;\r\n\theight: 20px;\r\n\tborder: 2px solid #30363d;\r\n\tborder-top-color: #58a6ff;\r\n\tborder-radius: 50%;\r\n\tanimation: spin 1s linear infinite;\r\n}\r\n\r\n@keyframes spin {\r\n\tto {\r\n\t\ttransform: rotate(360deg);\r\n\t}\r\n}\r\n\r\n.months-row {\r\n\tdisplay: flex;\r\n\tmargin-bottom: 4px;\r\n}\r\n\r\n.month-spacer {\r\n\twidth: 27px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.months-container {\r\n\tdisplay: grid;\r\n\tgrid-template-columns: repeat(53, 11px);\r\n\tgap: 2px;\r\n\tflex: 1;\r\n\tmargin-left: 3px;\r\n\tmin-width: 0;\r\n}\r\n\r\n.month-label {\r\n\tfont-size: 11px;\r\n\tcolor: #7d8590;\r\n\ttext-align: left;\r\n}\r\n\r\n.grid-container {\r\n\tdisplay: flex;\r\n\tgap: 3px;\r\n\tmin-width: fit-content;\r\n}\r\n\r\n.day-labels {\r\n\tdisplay: flex;\r\n\tflex-direction: column;\r\n\twidth: 24px;\r\n\tgap: 2px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.day-label {\r\n\theight: 11px;\r\n\tfont-size: 9px;\r\n\tcolor: #7d8590;\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n}\r\n\r\n.contribution-grid {\r\n\tdisplay: flex;\r\n\tgap: 2px;\r\n\tflex: 1;\r\n\tmin-width: 0;\r\n}\r\n\r\n.contribution-week {\r\n\tdisplay: flex;\r\n\tflex-direction: column;\r\n\tgap: 2px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.contribution-day {\r\n\twidth: 11px;\r\n\theight: 11px;\r\n\tborder-radius: 2px;\r\n\tcursor: pointer;\r\n\toutline: 1px solid rgba(27, 31, 36, 0.06);\r\n\toutline-offset: -1px;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n/* Color schemes */\r\n.contribution-day.level-0.green {\r\n\tbackground-color: #161b22;\r\n}\r\n.contribution-day.level-1.green {\r\n\tbackground-color: #0e4429;\r\n}\r\n.contribution-day.level-2.green {\r\n\tbackground-color: #006d32;\r\n}\r\n.contribution-day.level-3.green {\r\n\tbackground-color: #26a641;\r\n}\r\n.contribution-day.level-4.green {\r\n\tbackground-color: #39d353;\r\n}\r\n\r\n.contribution-day.level-0.blue {\r\n\tbackground-color: #161b22;\r\n}\r\n.contribution-day.level-1.blue {\r\n\tbackground-color: #0a3069;\r\n}\r\n.contribution-day.level-2.blue {\r\n\tbackground-color: #1f6feb;\r\n}\r\n.contribution-day.level-3.blue {\r\n\tbackground-color: #58a6ff;\r\n}\r\n.contribution-day.level-4.blue {\r\n\tbackground-color: #79c0ff;\r\n}\r\n\r\n.contribution-day.level-0.purple {\r\n\tbackground-color: #161b22;\r\n}\r\n.contribution-day.level-1.purple {\r\n\tbackground-color: #3b1e6d;\r\n}\r\n.contribution-day.level-2.purple {\r\n\tbackground-color: #8250df;\r\n}\r\n.contribution-day.level-3.purple {\r\n\tbackground-color: #a475f9;\r\n}\r\n.contribution-day.level-4.purple {\r\n\tbackground-color: #d2a8ff;\r\n}\r\n\r\n.contribution-day.level-0.orange {\r\n\tbackground-color: #161b22;\r\n}\r\n.contribution-day.level-1.orange {\r\n\tbackground-color: #7d2d00;\r\n}\r\n.contribution-day.level-2.orange {\r\n\tbackground-color: #da7b00;\r\n}\r\n.contribution-day.level-3.orange {\r\n\tbackground-color: #ffa348;\r\n}\r\n.contribution-day.level-4.orange {\r\n\tbackground-color: #ffb366;\r\n}\r\n\r\n.contribution-day:hover {\r\n\toutline: 1px solid #c9d1d9;\r\n\toutline-offset: -1px;\r\n}\r\n\r\n.graph-footer {\r\n\tdisplay: flex;\r\n\tjustify-content: space-between;\r\n\talign-items: center;\r\n\tmargin-top: 8px;\r\n}\r\n\r\n.last-updated {\r\n\tcolor: #7d8590;\r\n}\r\n\r\n.legend {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tgap: 4px;\r\n}\r\n\r\n.legend-label {\r\n\tcolor: #7d8590;\r\n}\r\n\r\n.legend-squares {\r\n\tdisplay: flex;\r\n\tgap: 2px;\r\n}\r\n\r\n.legend-squares .contribution-day {\r\n\tcursor: default;\r\n}\r\n\r\n.legend-squares .contribution-day:hover {\r\n\toutline: none;\r\n}\r\n\r\n/* Mobile responsive */\r\n@media (max-width: 768px) {\r\n\t.git-contribution-graph {\r\n\t\tpadding: 12px;\r\n\t\tfont-size: 11px;\r\n\t\toverflow-x: auto;\r\n\t}\r\n\t.months-container {\r\n\t\tgrid-template-columns: repeat(53, 10px);\r\n\t\tgap: 1px;\r\n\t}\r\n\t.grid-container {\r\n\t\tgap: 2px;\r\n\t}\r\n\t.day-labels {\r\n\t\twidth: 20px;\r\n\t}\r\n\t.day-label {\r\n\t\theight: 10px;\r\n\t\tfont-size: 8px;\r\n\t}\r\n\t.contribution-grid {\r\n\t\tgap: 1px;\r\n\t}\r\n\t.contribution-week {\r\n\t\tgap: 1px;\r\n\t}\r\n\t.contribution-day {\r\n\t\twidth: 10px;\r\n\t\theight: 10px;\r\n\t}\r\n\t.settings-btn {\r\n\t\tfont-size: 10px;\r\n\t\tpadding: 4px 8px;\r\n\t}\r\n\t.contribution-count {\r\n\t\tfont-size: 14px;\r\n\t}\r\n}\r\n\r\n@media (max-width: 480px) {\r\n\t.graph-header {\r\n\t\tflex-direction: column;\r\n\t\talign-items: flex-start;\r\n\t\tgap: 8px;\r\n\t}\r\n}\r\n</style>\r\n","<template>\r\n\t<div class=\"git-stats-breakdown\">\r\n\t\t<div class=\"stats-grid\">\r\n\t\t\t<!-- Years Experience -->\r\n\t\t\t<div class=\"stat-card\">\r\n\t\t\t\t<div class=\"stat-icon\">\r\n\t\t\t\t\t<slot name=\"icon-experience\">⏱️</slot>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"stat-content\">\r\n\t\t\t\t\t<div class=\"stat-value\">{{ yearsExperience }}</div>\r\n\t\t\t\t\t<div class=\"stat-label\">Years Experience</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Projects -->\r\n\t\t\t<div class=\"stat-card\">\r\n\t\t\t\t<div class=\"stat-icon\">\r\n\t\t\t\t\t<slot name=\"icon-projects\">📦</slot>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"stat-content\">\r\n\t\t\t\t\t<div v-if=\"loading\" class=\"stat-loading\">\r\n\t\t\t\t\t\t<div class=\"spinner\"></div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div v-else class=\"stat-value\">{{ totalProjects }}</div>\r\n\t\t\t\t\t<div class=\"stat-label\">Projects</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Commits -->\r\n\t\t\t<div class=\"stat-card\">\r\n\t\t\t\t<div class=\"stat-icon\">\r\n\t\t\t\t\t<slot name=\"icon-commits\">💻</slot>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"stat-content\">\r\n\t\t\t\t\t<div v-if=\"loading\" class=\"stat-loading\">\r\n\t\t\t\t\t\t<div class=\"spinner\"></div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div v-else class=\"stat-value\">{{ totalCommits }}</div>\r\n\t\t\t\t\t<div class=\"stat-label\">Commits</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\r\n\t\t\t<!-- Custom Stat -->\r\n\t\t\t<div class=\"stat-card\" v-if=\"showCustomStat\">\r\n\t\t\t\t<div class=\"stat-icon\">\r\n\t\t\t\t\t<slot name=\"icon-custom\">☕</slot>\r\n\t\t\t\t</div>\r\n\t\t\t\t<div class=\"stat-content\">\r\n\t\t\t\t\t<div v-if=\"loading\" class=\"stat-loading\">\r\n\t\t\t\t\t\t<div class=\"spinner\"></div>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t\t<div v-else class=\"stat-value\">{{ customStatValue }}</div>\r\n\t\t\t\t\t<div class=\"stat-label\">\r\n\t\t\t\t\t\t<slot name=\"custom-stat-label\">Coffee Consumed</slot>\r\n\t\t\t\t\t</div>\r\n\t\t\t\t</div>\r\n\t\t\t</div>\r\n\t\t</div>\r\n\r\n\t\t<!-- Footer -->\r\n\t\t<div class=\"stats-footer\">\r\n\t\t\t<small v-if=\"dataSourceText\" class=\"data-source\">\r\n\t\t\t\t{{ dataSourceText }}\r\n\t\t\t\t<span v-if=\"lastUpdatedText\"> · {{ lastUpdatedText }}</span>\r\n\t\t\t</small>\r\n\t\t</div>\r\n\t</div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from 'vue'\r\nimport { useGitStats } from '../composables/useGitStats'\r\nimport {\r\n\tcalculateYearsExperience,\r\n\ttype ExperienceEntry,\r\n\ttype CustomStatCalculator,\r\n\ttype CustomStatCalculatorParams,\r\n} from '@git-stats-components/core'\r\n\r\ninterface Props {\r\n\tdataUrl?: string\r\n\tprofileIndexes?: number[]\r\n\texperienceData?: ExperienceEntry[]\r\n\tshowCustomStat?: boolean\r\n\tcustomStatCalculator?: CustomStatCalculator | null\r\n\tcacheTTL?: number\r\n}\r\n\r\nconst props = withDefaults(defineProps<Props>(), {\r\n\tdataUrl: '/data/git-stats.json',\r\n\tprofileIndexes: () => [],\r\n\texperienceData: () => [],\r\n\tshowCustomStat: true,\r\n\tcustomStatCalculator: null,\r\n\tcacheTTL: 24 * 60 * 60 * 1000,\r\n})\r\n\r\n// Use the shared composable\r\nconst { data, loading, dataSourceText, lastUpdatedText } = useGitStats({\r\n\tdataUrl: props.dataUrl,\r\n\tcacheTTL: props.cacheTTL,\r\n})\r\n\r\nconst totalProjects = ref(0)\r\nconst totalCommits = ref(0)\r\n\r\n// Calculate totals when data loads\r\nwatch(\r\n\tdata,\r\n\t(newData) => {\r\n\t\tif (!newData) return\r\n\r\n\t\t// If profileIndexes specified, sum only those profiles\r\n\t\tif (props.profileIndexes.length > 0) {\r\n\t\t\tlet projects = 0\r\n\t\t\tlet commits = 0\r\n\r\n\t\t\tprops.profileIndexes.forEach((index) => {\r\n\t\t\t\tconst profile = newData.profiles?.[index]\r\n\t\t\t\tif (profile?.stats) {\r\n\t\t\t\t\tprojects += profile.stats.projectCount || 0\r\n\t\t\t\t\tcommits += profile.stats.commitCount || 0\r\n\t\t\t\t}\r\n\t\t\t})\r\n\r\n\t\t\ttotalProjects.value = projects\r\n\t\t\ttotalCommits.value = commits\r\n\t\t} else {\r\n\t\t\t// Use totals from data (aggregates all profiles)\r\n\t\t\ttotalProjects.value = newData.totals?.projectCount || 0\r\n\t\t\ttotalCommits.value = newData.totals?.commitCount || 0\r\n\t\t}\r\n\t},\r\n\t{ immediate: true }\r\n)\r\n\r\n// Calculate years of experience using core utility\r\nconst yearsExperience = computed(() => {\r\n\tconst years = calculateYearsExperience(props.experienceData)\r\n\treturn years.toFixed(1)\r\n})\r\n\r\n// Custom stat calculation\r\nconst customStatValue = computed(() => {\r\n\tif (props.customStatCalculator) {\r\n\t\tconst params: CustomStatCalculatorParams = {\r\n\t\t\tprojects: totalProjects.value,\r\n\t\t\tcommits: totalCommits.value,\r\n\t\t\tyears: parseFloat(yearsExperience.value),\r\n\t\t}\r\n\t\treturn props.customStatCalculator(params)\r\n\t}\r\n\r\n\t// Default: fun coffee calculation\r\n\tconst kA = 1.5\r\n\tconst kB = 1.2\r\n\tconst kC = 1.5\r\n\r\n\tconst cups =\r\n\t\ttotalProjects.value * kA +\r\n\t\ttotalCommits.value * kB +\r\n\t\tparseFloat(yearsExperience.value) * kC\r\n\r\n\treturn cups.toFixed(2)\r\n})\r\n</script>\r\n\r\n<style scoped>\r\n.git-stats-breakdown {\r\n\tfont-family:\r\n\t\t-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica,\r\n\t\tArial, sans-serif;\r\n\tpadding: 40px 20px;\r\n\tmax-width: 1200px;\r\n\tmargin: 0 auto;\r\n}\r\n\r\n.stats-grid {\r\n\tdisplay: grid;\r\n\tgrid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\r\n\tgap: 24px;\r\n\tmargin-bottom: 24px;\r\n}\r\n\r\n.stat-card {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tgap: 16px;\r\n\tpadding: 24px;\r\n\tbackground: rgba(255, 255, 255, 0.05);\r\n\tborder-radius: 12px;\r\n\tborder: 1px solid rgba(255, 255, 255, 0.1);\r\n\ttransition: all 0.3s ease;\r\n}\r\n\r\n.stat-card:hover {\r\n\tbackground: rgba(255, 255, 255, 0.08);\r\n\tborder-color: rgba(255, 255, 255, 0.2);\r\n\ttransform: translateY(-2px);\r\n}\r\n\r\n.stat-icon {\r\n\tfont-size: 48px;\r\n\tline-height: 1;\r\n\topacity: 0.9;\r\n\tflex-shrink: 0;\r\n}\r\n\r\n.stat-content {\r\n\tflex: 1;\r\n\tmin-width: 0;\r\n}\r\n\r\n.stat-value {\r\n\tfont-size: 32px;\r\n\tfont-weight: bold;\r\n\tline-height: 1.2;\r\n\tcolor: #e6edf3;\r\n\tmargin-bottom: 4px;\r\n}\r\n\r\n.stat-label {\r\n\tfont-size: 14px;\r\n\tcolor: #7d8590;\r\n\ttext-transform: uppercase;\r\n\tletter-spacing: 0.5px;\r\n}\r\n\r\n.stat-loading {\r\n\tdisplay: flex;\r\n\talign-items: center;\r\n\tjustify-content: center;\r\n\theight: 38px;\r\n}\r\n\r\n.spinner {\r\n\twidth: 24px;\r\n\theight: 24px;\r\n\tborder: 3px solid rgba(255, 255, 255, 0.1);\r\n\tborder-top-color: #58a6ff;\r\n\tborder-radius: 50%;\r\n\tanimation: spin 1s linear infinite;\r\n}\r\n\r\n@keyframes spin {\r\n\tto {\r\n\t\ttransform: rotate(360deg);\r\n\t}\r\n}\r\n\r\n.stats-footer {\r\n\tdisplay: flex;\r\n\tflex-direction: column;\r\n\talign-items: center;\r\n\tgap: 8px;\r\n\tpadding-top: 16px;\r\n\tborder-top: 1px solid rgba(255, 255, 255, 0.1);\r\n}\r\n\r\n.data-source {\r\n\tfont-size: 12px;\r\n\tcolor: #7d8590;\r\n\ttext-align: center;\r\n}\r\n\r\n/* Responsive */\r\n@media (max-width: 768px) {\r\n\t.git-stats-breakdown {\r\n\t\tpadding: 20px 12px;\r\n\t}\r\n\t.stats-grid {\r\n\t\tgrid-template-columns: 1fr;\r\n\t\tgap: 16px;\r\n\t}\r\n\t.stat-card {\r\n\t\tpadding: 16px;\r\n\t}\r\n\t.stat-icon {\r\n\t\tfont-size: 36px;\r\n\t}\r\n\t.stat-value {\r\n\t\tfont-size: 24px;\r\n\t}\r\n\t.stat-label {\r\n\t\tfont-size: 12px;\r\n\t}\r\n}\r\n\r\n@media (max-width: 480px) {\r\n\t.stat-card {\r\n\t\tflex-direction: column;\r\n\t\ttext-align: center;\r\n\t}\r\n\t.stat-content {\r\n\t\twidth: 100%;\r\n\t}\r\n}\r\n</style>\r\n","// Main entry point for git-stats-components\n\nimport type { App } from 'vue'\nimport ContributionGraph from './components/ContributionGraph.vue'\nimport StatsBreakdown from './components/StatsBreakdown.vue'\nimport { useGitStats } from './composables/useGitStats'\n\n// Re-export everything from core\nexport * from '@git-stats-components/core'\n\n// Export Vue-specific components and composables\nexport { ContributionGraph, StatsBreakdown, useGitStats }\n\n// Auto-import styles\nimport './styles/index.css'\n\n// Plugin for Vue.use()\nexport interface VueGitStatsPlugin {\n\tinstall: (app: App) => void\n}\n\nconst VueGitStats: VueGitStatsPlugin = {\n\tinstall(app: App) {\n\t\tapp.component('ContributionGraph', ContributionGraph)\n\t\tapp.component('StatsBreakdown', StatsBreakdown)\n\t},\n}\n\n// Export as default for Vue.use()\nexport default VueGitStats\n"],"names":["fetchGitStats","url","__async","response","generateDummyContributions","weeks","now","endDate","startDate","currentDate","week","weekData","day","isInFuture","isWeekend","dayCount","generateDummyStats","options","username","platform","projectCount","commitCount","contributions","total","sum","generateMultiProfileDummyStats","githubProfile","gitlabProfile","saveDummyDataToFile","filepath","data","json","blob","a","err","dataUrl","cacheKey","useStaleCache","__spreadProps","__spreadValues","_a","cached","_b","generateMockData","formatLastUpdated","dateString","date","diffHours","diffDays","getContributionLevel","count","calculateYearsExperience","experienceData","skillExperience","exp","end","start","years","skill","useGitStats","config","cacheTTL","loading","ref","error","dataSource","isDummy","loadData","result","lastUpdatedText","computed","dataSourceText","props","__props","emit","__emit","currentColorScheme","settingsOpen","colorSchemes","contributionData","monthLabels","watch","newData","_c","processContributions","generateMonthLabels","totalContributions","weekTotal","generateEmptyWeeks","generateEmptyWeek","i","days","monthPositions","lastMonth","lastYear","weekIndex","firstDay","dateParts","year","month","getContributionLevelNumber","getTooltipText","dayNum","formattedDate","contributionText","onDayClick","toggleSettings","changeColorScheme","scheme","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_hoisted_4","_toDisplayString","_normalizeClass","_unref","_hoisted_5","_renderSlot","_ctx","_hoisted_6","_Fragment","_renderList","$event","_hoisted_7","_hoisted_8","_cache","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_normalizeStyle","_hoisted_13","_hoisted_14","_hoisted_16","_hoisted_17","totalProjects","totalCommits","projects","commits","index","profile","yearsExperience","customStatValue","params","_hoisted_15","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_createTextVNode","_hoisted_25","VueGitStats","app","ContributionGraph","StatsBreakdown"],"mappings":"s5BAEA,SAAsBA,EAAcC,EAAoC,QAAAC,EAAA,sBACvE,MAAMC,EAAW,MAAM,MAAMF,CAAG,EAChC,GAAI,CAACE,EAAS,GACb,MAAM,IAAI,MAAM,8BAA8BA,EAAS,UAAU,EAAE,EAEpE,OAAOA,EAAS,KAAA,CACjB,GCDO,SAASC,GAA6B,CAC5C,MAAMC,EAAQ,CAAA,EACRC,EAAM,IAAI,KAGVC,EAAU,IAAI,KAAKD,CAAG,EAC5BC,EAAQ,QAAQA,EAAQ,QAAO,EAAKA,EAAQ,OAAM,CAAE,EAGpD,MAAMC,EAAY,IAAI,KAAKD,CAAO,EAClCC,EAAU,QAAQA,EAAU,QAAO,EAAK,GAAK,CAAC,EAE9C,MAAMC,EAAc,IAAI,KAAKD,CAAS,EAEtC,QAASE,EAAO,EAAGA,EAAO,GAAIA,IAAQ,CACrC,MAAMC,EAAW,CAChB,UAAW,IAAI,KAAKF,CAAW,EAAE,YAAW,EAAG,MAAM,GAAG,EAAE,CAAC,EAC3D,iBAAkB,CAAA,CACrB,EAEE,QAASG,EAAM,EAAGA,EAAM,EAAGA,IAAO,CACjC,MAAMC,EAAaJ,EAAcH,EAC3BQ,EAAYF,IAAQ,GAAKA,IAAQ,EAGvC,IAAIG,EAAW,EACVF,IACAC,EACHC,EACC,KAAK,SAAW,GAAM,KAAK,MAAM,KAAK,SAAW,CAAC,EAAI,EAEvDA,EAAW,KAAK,MAAM,KAAK,OAAM,EAAK,EAAE,GAI1CJ,EAAS,iBAAiB,KAAK,CAC9B,KAAM,IAAI,KAAKF,CAAW,EAAE,YAAW,EAAG,MAAM,GAAG,EAAE,CAAC,EACtD,kBAAmBM,EACnB,QAASH,CACb,CAAI,EACDH,EAAY,QAAQA,EAAY,QAAO,EAAK,CAAC,CAC9C,CAEAJ,EAAM,KAAKM,CAAQ,CACpB,CAEA,OAAON,CACR,CAKO,SAASW,EAAmBC,EAAU,GAAI,CAChD,KAAM,CACL,SAAAC,EAAW,YACX,SAAAC,EAAW,SACX,aAAAC,EAAe,GACf,YAAAC,EAAc,IAChB,EAAKJ,EAEEK,EAAgBlB,EAA0B,EACrB,OAAAkB,EAAc,OAAO,CAACC,EAAOb,IAEtDa,EACAb,EAAK,iBAAiB,OACrB,CAACc,EAAKZ,IAAQY,EAAMZ,EAAI,kBACxB,CACJ,EAEI,CAAC,EAEG,CACN,YAAa,IAAI,KAAI,EAAG,YAAW,EACnC,SAAU,CACT,CACC,SAAAM,EACA,SAAAC,EACA,MAAO,CACN,aAAAC,EACA,YAAAC,EACA,cAAeC,EAAc,IAAKZ,IAAU,CAC3C,SAAUA,EAAK,UACf,iBAAkBA,EAAK,gBAC7B,EAAO,CACP,CACA,CACA,EACE,OAAQ,CACP,aAAAU,EACA,YAAAC,CACH,EACE,SAAU,CACT,UAAW,KAAK,IAAG,EACnB,OAAQ,aACR,QAAS,EACZ,CACA,CACA,CAKO,SAASI,GAAiC,CAChD,MAAMC,EAAgBV,EAAmB,CACxC,SAAU,cACV,SAAU,SACV,aAAc,GACd,YAAa,IACf,CAAE,EAEKW,EAAgBX,EAAmB,CACxC,SAAU,cACV,SAAU,SACV,aAAc,EACd,YAAa,GACf,CAAE,EAED,MAAO,CACN,YAAa,IAAI,KAAI,EAAG,YAAW,EACnC,SAAU,CAACU,EAAc,SAAS,CAAC,EAAGC,EAAc,SAAS,CAAC,CAAC,EAC/D,OAAQ,CACP,aAAc,GACd,YAAa,IAChB,EACE,SAAU,CACT,UAAW,KAAK,IAAG,EACnB,OAAQ,aACR,QAAS,EACZ,CACA,CACA,CAKO,SAASC,EAAoBC,EAAW,uBAAwB,CACtE,MAAMC,EAAOd,EAAkB,EACzBe,EAAO,KAAK,UAAUD,EAAM,KAAM,GAAI,EAE5C,GAAI,OAAO,QAAW,YAAa,CAElC,MAAME,EAAO,IAAI,KAAK,CAACD,CAAI,EAAG,CAAE,KAAM,kBAAkB,CAAE,EACpD9B,EAAM,IAAI,gBAAgB+B,CAAI,EAC9BC,EAAI,SAAS,cAAc,GAAG,EACpCA,EAAE,KAAOhC,EACTgC,EAAE,SAAWJ,EACbI,EAAE,MAAK,EACP,IAAI,gBAAgBhC,CAAG,CACxB,KAEC,IAAI,CACQ,QAAQ,IAAI,EACpB,cAAc4B,EAAUE,CAAI,EAC/B,QAAQ,IAAI,yBAAyBF,CAAQ,EAAE,CAChD,OAASK,EAAK,CACb,QAAQ,MAAM,6BAA8BA,CAAG,CAChD,CAEF,CClHA,SAAsBlC,EACrBiB,EACoC,QAAAf,EAAA,8BACpC,KAAM,CAAE,QAAAiC,EAAS,SAAAC,EAAW,kBAAmB,cAAAC,EAAgB,IAASpB,EAExE,GAAI,CAEH,MAAMd,EAAW,MAAM,MAAMgC,CAAO,EACpC,GAAIhC,EAAS,GAAI,CAChB,MAAM2B,EAAO,MAAM3B,EAAS,KAAA,EAE5B,OAAI,OAAO,QAAW,aACrB,aAAa,QACZiC,EACA,KAAK,UAAUE,EAAAC,EAAA,GACXT,GADW,CAEd,SAAU,KAAK,IAAA,CAAI,EACnB,CAAA,EAGI,CACN,KAAAA,EACA,MAAO,KACP,OAAQ,SACR,UAASU,EAAAV,EAAK,WAAL,YAAAU,EAAe,WAAY,EAAA,CAEtC,CACD,OAASN,EAAK,CACb,QAAQ,KAAK,oCAAqCA,CAAG,CACtD,CAGA,GAAIG,GAAiB,OAAO,QAAW,YACtC,GAAI,CACH,MAAMI,EAAS,aAAa,QAAQL,CAAQ,EAC5C,GAAIK,EAAQ,CACX,MAAMX,EAAO,KAAK,MAAMW,CAAM,EAC9B,MAAO,CACN,KAAAX,EACA,MAAO,KACP,OAAQ,QACR,UAASY,EAAAZ,EAAK,WAAL,YAAAY,EAAe,WAAY,EAAA,CAEtC,CACD,OAASR,EAAK,CACb,QAAQ,KAAK,6BAA8BA,CAAG,CAC/C,CAKD,MAAO,CACN,KAFgBS,EAAA,EAGhB,MAAO,KACP,OAAQ,OACR,QAAS,EAAA,CAEX,GAKO,SAASC,EAAkBC,EAA4B,CAC7D,MAAMC,EAAO,IAAI,KAAKD,CAAU,EAC1BvC,MAAU,KACVyC,EAAY,KAAK,OAAOzC,EAAI,QAAA,EAAYwC,EAAK,QAAA,IAAc,IAAO,GAAK,GAAG,EAEhF,GAAIC,EAAY,EAAG,MAAO,WAC1B,GAAIA,EAAY,GAAI,MAAO,GAAGA,CAAS,aAEvC,MAAMC,EAAW,KAAK,MAAMD,EAAY,EAAE,EAC1C,OAAIC,IAAa,EAAU,YACvBA,EAAW,EAAU,GAAGA,CAAQ,YAE7BF,EAAK,mBAAmB,QAAS,CACvC,MAAO,QACP,IAAK,UACL,KAAMA,EAAK,YAAA,IAAkBxC,EAAI,YAAA,EAAgB,UAAY,MAAA,CAC7D,CACF,CAKO,SAAS2C,EAAqBC,EAAuB,CAC3D,OAAIA,IAAU,EAAU,EACpBA,GAAS,EAAU,EACnBA,GAAS,EAAU,EACnBA,GAAS,EAAU,EAChB,CACR,CAKO,SAASC,EACfC,EACS,CACT,GAAIA,EAAe,SAAW,EAAG,MAAO,GAExC,MAAMC,EAA0C,CAAA,EAEhD,OAAAD,EAAe,QAASE,GAAQ,OAC/B,MAAMC,EAAMD,EAAI,QAAU,IAAI,KAAKA,EAAI,OAAO,EAAI,IAAI,KAChDE,EAAQ,IAAI,KAAKF,EAAI,SAAS,EAC9BG,GAASF,EAAI,QAAA,EAAYC,EAAM,YAAc,IAAO,GAAK,GAAK,GAAK,SAEzEhB,EAAAc,EAAI,SAAJ,MAAAd,EAAY,QAASkB,GAAU,CACzBL,EAAgBK,CAAK,IACzBL,EAAgBK,CAAK,EAAI,GAE1BL,EAAgBK,CAAK,GAAKD,CAC3B,EACD,CAAC,EAEM,KAAK,IAAI,GAAG,OAAO,OAAOJ,CAAe,EAAG,CAAC,CACrD,CAGA,SAASV,GAAiC,CACzC,MAAO,CACN,YAAa,IAAI,KAAA,EAAO,YAAA,EACxB,SAAU,CACT,CACC,SAAU,WACV,SAAU,SACV,MAAO,CACN,aAAc,GACd,YAAa,KACb,cAAe,CAAA,CAAC,CACjB,CACD,EAED,OAAQ,CACP,aAAc,GACd,YAAa,IAAA,EAEd,SAAU,CACT,OAAQ,OACR,UAAW,KAAK,IAAA,CAAI,CACrB,CAEF,CClLO,SAASgB,EAAYC,EAA4B,GAAI,CAC3D,KAAM,CACL,QAAAzB,EAAU,uBACV,SAAA0B,EAAW,GAAK,GAAK,GAAK,IAC1B,cAAAxB,EAAgB,GAChB,SAAAD,EAAW,iBAAA,EACRwB,EAEEE,EAAUC,EAAAA,IAAI,EAAK,EACnBC,EAAQD,EAAAA,IAAkB,IAAI,EAC9BjC,EAAOiC,EAAAA,IAAyB,IAAI,EACpCE,EAAaF,EAAAA,IAAuB,IAAI,EACxCG,EAAUH,EAAAA,IAAI,EAAK,EAKzB,SAAeI,GAAyC,QAAAjE,EAAA,sBACvD4D,EAAQ,MAAQ,GAChBE,EAAM,MAAQ,KAEd,GAAI,CACH,MAAMI,EAAS,MAAMpE,EAAc,CAClC,QAAAmC,EACA,SAAA0B,EACA,SAAAzB,EACA,cAAAC,CAAA,CACA,EAED,OAAAP,EAAK,MAAQsC,EAAO,KACpBJ,EAAM,MAAQI,EAAO,MACrBH,EAAW,MAAQG,EAAO,OAC1BF,EAAQ,MAAQE,EAAO,QAEhBA,EAAO,IACf,OAASlC,EAAK,CACb,OAAA8B,EAAM,MACL9B,aAAe,MAAQA,EAAM,IAAI,MAAM,qBAAqB,EACtD,IACR,QAAA,CACC4B,EAAQ,MAAQ,EACjB,CACD,GAKA,MAAMO,EAAkBC,EAAAA,SAAS,IAAM,OACtC,OAAK9B,EAAAV,EAAK,QAAL,MAAAU,EAAY,YACVI,EAAkBd,EAAK,MAAM,WAAW,EADV,EAEtC,CAAC,EAKKyC,EAAiBD,EAAAA,SAAS,IAAM,CACrC,GAAIJ,EAAQ,MACX,MAAO,kCAGR,OAAQD,EAAW,MAAA,CAClB,IAAK,SACJ,MAAO,iBACR,IAAK,QACJ,MAAO,cACR,IAAK,OACJ,MAAO,cACR,QACC,MAAO,EAAA,CAEV,CAAC,EAGD,OAAAE,EAAA,EAEO,CACN,KAAArC,EACA,QAAAgC,EACA,MAAAE,EACA,WAAAC,EACA,eAAAM,EACA,gBAAAF,EACA,QAAAH,EACA,SAAAC,CAAA,CAEF,mxBCyDA,MAAMK,EAAQC,EAQRC,EAAOC,EAGP,CAAE,KAAA7C,EAAM,QAAAgC,EAAS,eAAAS,EAAgB,gBAAAF,EAAiB,QAAAH,GAAYP,EACnE,CACC,QAASa,EAAM,QACf,SAAUA,EAAM,QAAA,CACjB,EAGKI,EAAqBb,EAAAA,IAAiBS,EAAM,WAAW,EACvDK,EAAed,EAAAA,IAAI,EAAK,EACxBe,EAA8B,CAAC,QAAS,OAAQ,SAAU,QAAQ,EAClEC,EAAmBhB,EAAAA,IAAqB,EAAE,EAC1CiB,EAAcjB,EAAAA,IAAkB,EAAE,EAGxCkB,EAAAA,MACCnD,EACCoD,GAAY,WACZ,IAAIC,GAAAzC,GAAAF,EAAA0C,GAAA,YAAAA,EAAS,WAAT,YAAA1C,EAAoBgC,EAAM,gBAA1B,YAAA9B,EAAyC,QAAzC,MAAAyC,EAAgD,cAAe,CAClE,MAAM7D,EACL4D,EAAQ,SAASV,EAAM,YAAY,EAAE,MAAM,cACxClD,IACHyD,EAAiB,MAAQK,EAAqB9D,CAAa,EAC3D+D,GAAA,EAEF,MACCN,EAAiB,MAAQ,CAAA,CAE3B,EACA,CAAE,UAAW,EAAA,CAAK,EAGnB,MAAMO,EAAqBhB,EAAAA,SAAS,IAC/B,CAACS,EAAiB,OAASA,EAAiB,MAAM,SAAW,EACzD,EAGDA,EAAiB,MAAM,OAAO,CAACxD,EAAOb,IACxC,CAACA,EAAK,MAAQ,CAAC,MAAM,QAAQA,EAAK,IAAI,EAClCa,EAGPA,EACAb,EAAK,KAAK,OAAO,CAAC6E,EAAW3E,IACrB2E,GAAa3E,EAAI,OAAS,GAC/B,CAAC,EAEH,CAAC,CACJ,EAED,SAASwE,EACR9D,EACkB,CAClB,GAAI,CAACA,GAAiB,CAAC,MAAM,QAAQA,CAAa,EACjD,OAAOkE,EAAA,EAGR,MAAMnF,EAAQiB,EAAc,IAAKZ,IAAU,CAC1C,UAAWA,EAAK,UAAY,GAC5B,KAAMA,EAAK,iBAAiB,IAAKE,GAAA,OAAS,OACzC,KAAMA,EAAI,MAAQ,GAClB,OAAO4B,EAAA5B,EAAI,oBAAJ,KAAA4B,EAAyB,EAChC,QAAS5B,EAAI,SAAW,CAAA,EACvB,CAAA,EACD,EAEF,KAAOP,EAAM,OAAS,IACrBA,EAAM,KAAKoF,GAAmB,EAG/B,OAAOpF,CACR,CAEA,SAASmF,GAAsC,CAC9C,MAAMnF,EAAyB,CAAA,EAC/B,QAASqF,EAAI,EAAGA,EAAI,GAAIA,IACvBrF,EAAM,KAAKoF,GAAmB,EAE/B,OAAOpF,CACR,CAEA,SAASoF,GAAmC,CAC3C,MAAME,EAAuB,CAAA,EAC7B,QAASD,EAAI,EAAGA,EAAI,EAAGA,IACtBC,EAAK,KAAK,CAAE,KAAM,GAAI,MAAO,EAAG,QAASD,EAAG,EAE7C,MAAO,CAAE,UAAW,GAAI,KAAAC,CAAA,CACzB,CAEA,SAASN,IAA4B,CACpC,GAAI,CAACN,EAAiB,OAASA,EAAiB,MAAM,SAAW,EAAG,CACnEC,EAAY,MAAQ,CAAA,EACpB,MACD,CAEA,MAAMY,EAA+B,CAAA,EACrC,IAAIC,EAAY,GACZC,EAAW,GAEff,EAAiB,MAAM,QAAQ,CAACrE,EAAMqF,IAAc,CACnD,GAAI,CAACrF,EAAK,MAAQA,EAAK,KAAK,SAAW,EAAG,OAE1C,MAAMsF,EAAWtF,EAAK,KAAK,CAAC,EAAE,KAC9B,GAAI,CAACsF,EAAU,OAEf,MAAMC,EAAYD,EAAS,MAAM,GAAG,EACpC,GAAIC,EAAU,SAAW,EAAG,OAE5B,KAAM,CAACC,EAAMC,CAAK,EAAIF,EAAU,IAAI,MAAM,EAC1C,GAAI,QAAMC,CAAI,GAAK,MAAMC,CAAK,KAE1BA,IAAUN,GAAaK,IAASJ,GAAU,CAC7C,MAAMhD,GAAO,IAAI,KAAKoD,EAAMC,EAAQ,EAAG,CAAC,EACxCP,EAAe,KAAK,CACnB,KAAMG,EACN,MAAOI,EAAQ,EACf,KAAAD,EACA,MAAOpD,GAAK,mBAAmB,QAAS,CAAE,MAAO,QAAS,CAAA,CAC1D,EACD+C,EAAYM,EACZL,EAAWI,CACZ,CACD,CAAC,EAEDlB,EAAY,MAAQY,CACrB,CAEA,SAAS3C,GAAqBC,EAAuB,CAEpD,MAAO,SADOkD,GAA2BlD,CAAK,CACzB,IAAI0B,EAAmB,KAAK,EAClD,CAEA,SAASwB,GAA2BlD,EAAuB,CAC1D,OAAIA,IAAU,EAAU,EACpBA,GAAS,EAAU,EACnBA,GAAS,EAAU,EACnBA,GAAS,EAAU,EAChB,CACR,CAEA,SAASmD,GAAezF,EAA2B,CAClD,GAAI,CAACA,EAAI,KAAM,MAAO,GAEtB,KAAM,CAACsF,EAAMC,EAAOG,CAAM,EAAI1F,EAAI,KAAK,MAAM,GAAG,EAAE,IAAI,MAAM,EAGtD2F,EAFO,IAAI,KAAKL,EAAMC,EAAQ,EAAGG,CAAM,EAElB,mBAAmB,QAAS,CACtD,QAAS,QACT,KAAM,UACN,MAAO,QACP,IAAK,SAAA,CACL,EAEKE,EAAmB5F,EAAI,QAAU,EAAI,eAAiB,gBAC5D,MAAO,GAAGA,EAAI,KAAK,IAAI4F,CAAgB,OAAOD,CAAa,EAC5D,CAEA,SAASE,GAAW7F,EAAyB,CAC5C8D,EAAK,YAAa,CAAE,KAAM9D,EAAI,KAAM,MAAOA,EAAI,MAAO,CACvD,CAEA,SAAS8F,IAAuB,CAC/B7B,EAAa,MAAQ,CAACA,EAAa,KACpC,CAEA,SAAS8B,GAAkBC,EAA2B,CACrDhC,EAAmB,MAAQgC,EAC3B/B,EAAa,MAAQ,GACrBH,EAAK,sBAAuBkC,CAAM,CACnC,eA/UCC,YAAA,EAAAC,qBAkHM,MAlHNC,EAkHM,CAhHLC,EAAAA,mBAiCM,MAjCNC,EAiCM,CAhCLD,EAAAA,mBAWM,MAXNE,EAWM,CAVLF,qBAGK,KAHLG,EAGKC,kBAFD9B,QAAmB,eAAA,GAAmB,mCAE1C,CAAA,EACA0B,EAAAA,mBAKQ,QAAA,CAJP,MAAKK,EAAAA,eAAA,CAAC,mBAAkB,CAAA,WACFC,EAAAA,MAAApD,CAAA,EAAO,CAAA,CAAA,oBAE1BoD,EAAAA,MAAA/C,CAAA,CAAc,EAAA,CAAA,CAAA,GAGeE,EAAA,cAAlCoC,EAAAA,UAAA,EAAAC,EAAAA,mBAmBM,MAnBNS,EAmBM,CAlBLP,EAAAA,mBAOS,SAAA,CANR,MAAM,eACN,KAAK,SACJ,QAAON,EAAA,GAERc,EAAAA,WAAoCC,4BAApC,IAAoC,+BAAT,KAAE,EAAA,EAAA,oCAAO,aAErC,EAAA,EAAA,GACW5C,EAAA,OAAXgC,EAAAA,UAAA,EAAAC,EAAAA,mBASM,MATNY,EASM,gBARLZ,EAAAA,mBAOSa,EAAAA,SAAA,KAAAC,aANS9C,EAAV8B,GADRI,EAAAA,mBAOS,SAAA,CALP,IAAKJ,EACL,QAAKiB,GAAElB,GAAkBC,CAAM,EAChC,MAAM,eAAA,EAEHQ,EAAAA,gBAAAR,CAAM,EAAG,UACb,EAAAkB,EAAA,wEAMQR,EAAAA,MAAAxD,CAAA,GAAX+C,YAAA,EAAAC,EAAAA,mBAGM,MAHNiB,GAGM,CAAA,GAAAC,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAA,CAFLhB,EAAAA,mBAA2B,MAAA,CAAtB,MAAM,SAAA,EAAS,KAAA,EAAA,EACpBA,EAAAA,mBAAqC,YAA/B,2BAAwB,EAAA,CAAA,OAI/BH,EAAAA,YAAAC,EAAAA,mBAqEM,MArENmB,GAqEM,CApELjB,EAAAA,mBAiDM,MAjDNkB,GAiDM,CA/CLlB,EAAAA,mBAcM,MAdNmB,GAcM,aAbLnB,EAAAA,mBAAgC,MAAA,CAA3B,MAAM,cAAA,EAAc,KAAA,EAAA,GACzBA,EAAAA,mBAWM,MAXNoB,GAWM,kBAVLtB,EAAAA,mBASMa,EAAAA,SAAA,KAAAC,EAAAA,WARW5C,EAAA,MAATmB,kBADRW,EAAAA,mBASM,MAAA,CAPJ,OAAQX,EAAM,IAAI,IAAIA,EAAM,KAAK,GAClC,MAAM,cACL,MAAKkC,EAAAA,eAAA,CAA4B,WAAA,GAAAlC,EAAM,KAAI,CAAA,WAAA,IAIzCiB,kBAAAjB,EAAM,KAAK,EAAA,CAAA,cAMjBa,EAAAA,mBA6BM,MA7BNsB,GA6BM,0ZAhBLtB,EAAAA,mBAeM,MAfNuB,GAeM,kBAdLzB,EAAAA,mBAaMa,EAAAA,SAAA,KAAAC,EAAAA,WAZU7C,EAAA,MAARrE,kBADRoG,EAAAA,mBAaM,MAAA,CAXJ,IAAKpG,EAAK,UACX,MAAM,mBAAA,IAENmG,YAAA,EAAA,EAAAC,EAAAA,mBAOOa,EAAAA,SAAA,KAAAC,EAAAA,WANQlH,EAAK,KAAZE,kBADRkG,EAAAA,mBAOO,MAAA,CALL,IAAKlG,EAAI,KACV,wBAAM,mBACEqC,GAAqBrC,EAAI,KAAK,CAAA,CAAA,EACrC,MAAOyF,GAAezF,CAAG,EACzB,QAAKiH,GAAEpB,GAAW7F,CAAG,CAAA,sCAQ3BoG,EAAAA,mBAeM,MAfNwB,GAeM,CAd6BlB,EAAAA,MAAAjD,CAAA,GAAlCwC,EAAAA,YAAAC,EAAAA,mBAEQ,QAFR2B,GAAmD,oCACjCnB,EAAAA,MAAAjD,CAAA,CAAe,EAAA,CAAA,+mDCZrC,MAAMG,EAAQC,EAUR,CAAE,KAAA3C,EAAM,QAAAgC,EAAS,eAAAS,EAAgB,gBAAAF,CAAA,EAAoBV,EAAY,CACtE,QAASa,EAAM,QACf,SAAUA,EAAM,QAAA,CAChB,EAEKkE,EAAgB3E,EAAAA,IAAI,CAAC,EACrB4E,EAAe5E,EAAAA,IAAI,CAAC,EAG1BkB,EAAAA,MACCnD,EACCoD,GAAY,SACZ,GAAKA,EAGL,GAAIV,EAAM,eAAe,OAAS,EAAG,CACpC,IAAIoE,EAAW,EACXC,EAAU,EAEdrE,EAAM,eAAe,QAASsE,GAAU,OACvC,MAAMC,GAAUvG,EAAA0C,EAAQ,WAAR,YAAA1C,EAAmBsG,GAC/BC,GAAA,MAAAA,EAAS,QACZH,GAAYG,EAAQ,MAAM,cAAgB,EAC1CF,GAAWE,EAAQ,MAAM,aAAe,EAE1C,CAAC,EAEDL,EAAc,MAAQE,EACtBD,EAAa,MAAQE,CACtB,MAECH,EAAc,QAAQlG,EAAA0C,EAAQ,SAAR,YAAA1C,EAAgB,eAAgB,EACtDmG,EAAa,QAAQjG,EAAAwC,EAAQ,SAAR,YAAAxC,EAAgB,cAAe,CAEtD,EACA,CAAE,UAAW,EAAA,CAAK,EAInB,MAAMsG,EAAkB1E,EAAAA,SAAS,IAClBnB,EAAyBqB,EAAM,cAAc,EAC9C,QAAQ,CAAC,CACtB,EAGKyE,EAAkB3E,EAAAA,SAAS,IAAM,CACtC,GAAIE,EAAM,qBAAsB,CAC/B,MAAM0E,EAAqC,CAC1C,SAAUR,EAAc,MACxB,QAASC,EAAa,MACtB,MAAO,WAAWK,EAAgB,KAAK,CAAA,EAExC,OAAOxE,EAAM,qBAAqB0E,CAAM,CACzC,CAYA,OAJCR,EAAc,MALJ,IAMVC,EAAa,MALH,IAMV,WAAWK,EAAgB,KAAK,EALtB,KAOC,QAAQ,CAAC,CACtB,CAAC,gBAnKAnC,YAAA,EAAAC,qBAiEM,MAjENC,GAiEM,CAhELC,EAAAA,mBAuDM,MAvDNC,GAuDM,CArDLD,EAAAA,mBAQM,MARNE,GAQM,CAPLF,EAAAA,mBAEM,MAFNG,GAEM,CADLK,EAAAA,WAAsCC,8BAAtC,IAAsC,+BAAT,KAAE,EAAA,EAAA,QAEhCT,EAAAA,mBAGM,MAHNO,GAGM,CAFLP,EAAAA,mBAAmD,MAAnDU,GAAmDN,EAAAA,gBAAxB4B,EAAA,KAAe,EAAA,CAAA,EAC1ChB,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAhB,EAAAA,mBAA8C,MAAA,CAAzC,MAAM,cAAa,mBAAgB,EAAA,EAAA,KAK1CA,EAAAA,mBAWM,MAXNc,GAWM,CAVLd,EAAAA,mBAEM,MAFNe,GAEM,CADLP,EAAAA,WAAoCC,4BAApC,IAAoC,+BAAT,KAAE,EAAA,EAAA,QAE9BT,EAAAA,mBAMM,MANNiB,GAMM,CALMX,EAAAA,MAAAxD,CAAA,GAAX+C,YAAA,EAAAC,EAAAA,mBAEM,MAFNoB,GAEM,CAAA,GAAAF,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAA,CADLhB,EAAAA,mBAA2B,MAAA,CAAtB,MAAM,SAAA,EAAS,KAAA,EAAA,CAAA,qBAErBF,EAAAA,mBAAwD,MAAxDqB,GAAwDf,EAAAA,gBAAtBsB,EAAA,KAAa,EAAA,CAAA,GAC/CV,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAhB,EAAAA,mBAAsC,MAAA,CAAjC,MAAM,cAAa,WAAQ,EAAA,EAAA,KAKlCA,EAAAA,mBAWM,MAXNoB,GAWM,CAVLpB,EAAAA,mBAEM,MAFNsB,GAEM,CADLd,EAAAA,WAAmCC,2BAAnC,IAAmC,+BAAT,KAAE,EAAA,EAAA,QAE7BT,EAAAA,mBAMM,MANNuB,GAMM,CALMjB,EAAAA,MAAAxD,CAAA,GAAX+C,YAAA,EAAAC,EAAAA,mBAEM,MAFNqC,GAEM,CAAA,GAAAnB,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAA,CADLhB,EAAAA,mBAA2B,MAAA,CAAtB,MAAM,SAAA,EAAS,KAAA,EAAA,CAAA,qBAErBF,EAAAA,mBAAuD,MAAvD0B,GAAuDpB,EAAAA,gBAArBuB,EAAA,KAAY,EAAA,CAAA,GAC9CX,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAhB,EAAAA,mBAAqC,MAAA,CAAhC,MAAM,cAAa,UAAO,EAAA,EAAA,KAKJvC,EAAA,gBAA7BoC,EAAAA,UAAA,EAAAC,EAAAA,mBAaM,MAbN2B,GAaM,CAZLzB,EAAAA,mBAEM,MAFNoC,GAEM,CADL5B,EAAAA,WAAiCC,0BAAjC,IAAiC,+BAAR,IAAC,EAAA,EAAA,QAE3BT,EAAAA,mBAQM,MARNqC,GAQM,CAPM/B,EAAAA,MAAAxD,CAAA,GAAX+C,YAAA,EAAAC,EAAAA,mBAEM,MAFNwC,GAEM,CAAA,GAAAtB,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAA,CADLhB,EAAAA,mBAA2B,MAAA,CAAtB,MAAM,SAAA,EAAS,KAAA,EAAA,CAAA,qBAErBF,EAAAA,mBAA0D,MAA1DyC,GAA0DnC,EAAAA,gBAAxB6B,EAAA,KAAe,EAAA,CAAA,GACjDjC,EAAAA,mBAEM,MAFNwC,GAEM,CADLhC,EAAAA,WAAqDC,gCAArD,IAAqD,iCAAtB,kBAAe,EAAA,EAAA,2CAOlDT,EAAAA,mBAKM,MALNyC,GAKM,CAJQnC,EAAAA,MAAA/C,CAAA,GAAbsC,EAAAA,YAAAC,EAAAA,mBAGQ,QAHR4C,GAGQ,CAFJC,EAAAA,gBAAAvC,EAAAA,gBAAAE,EAAAA,MAAA/C,CAAA,CAAc,EAAG,IACpB,CAAA,EAAY+C,EAAAA,MAAAjD,CAAA,iBAAZyC,EAAAA,mBAA4D,OAAA8C,GAA/B,MAAGxC,EAAAA,gBAAGE,EAAAA,MAAAjD,CAAA,CAAe,EAAA,CAAA,gHC1ChDwF,GAAiC,CACtC,QAAQC,EAAU,CACjBA,EAAI,UAAU,oBAAqBC,CAAiB,EACpDD,EAAI,UAAU,iBAAkBE,CAAc,CAC/C,CACD"}