@git-stats-components/vue 1.0.0

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.
@@ -0,0 +1,3 @@
1
+ export * from './vue/src/index'
2
+ import VueGitStats from './vue/src/index'
3
+ export default VueGitStats
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .graph-content-wrapper[data-v-f1ff100d]{justify-items:anchor-center}.git-contribution-graph[data-v-f1ff100d]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Noto Sans,Helvetica,Arial,sans-serif;font-size:12px;background:transparent;color:#e6edf3;padding:16px;max-width:1200px;margin:0 auto;width:100%}.graph-header[data-v-f1ff100d]{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.contribution-count[data-v-f1ff100d]{margin:0 0 4px;font-size:16px;font-weight:600}.data-source-text[data-v-f1ff100d]{color:#7d8590}.data-source-text.is-dummy[data-v-f1ff100d]{color:#f85149;font-weight:600;background:#f851491a;padding:2px 8px;border-radius:4px}.settings-btn[data-v-f1ff100d]{background:transparent;border:1px solid #30363d;color:#7d8590;padding:6px 12px;border-radius:6px;cursor:pointer;font-size:12px}.settings-btn[data-v-f1ff100d]:hover{background:#21262d;color:#e6edf3}.header-actions[data-v-f1ff100d]{position:relative}.settings-dropdown[data-v-f1ff100d]{position:absolute;right:0;top:100%;margin-top:4px;background:#21262d;border:1px solid #30363d;border-radius:6px;padding:4px;z-index:10;min-width:150px}.settings-item[data-v-f1ff100d]{display:block;width:100%;background:transparent;border:none;color:#e6edf3;padding:8px 12px;text-align:left;cursor:pointer;border-radius:4px}.settings-item[data-v-f1ff100d]:hover{background:#30363d}.loading-state[data-v-f1ff100d]{display:flex;align-items:center;justify-content:center;gap:12px;padding:40px;color:#7d8590}.spinner[data-v-f1ff100d]{width:20px;height:20px;border:2px solid #30363d;border-top-color:#58a6ff;border-radius:50%;animation:spin-f1ff100d 1s linear infinite}@keyframes spin-f1ff100d{to{transform:rotate(360deg)}}.months-row[data-v-f1ff100d]{display:flex;margin-bottom:4px}.month-spacer[data-v-f1ff100d]{width:27px;flex-shrink:0}.months-container[data-v-f1ff100d]{display:grid;grid-template-columns:repeat(53,11px);gap:2px;flex:1;margin-left:3px;min-width:0}.month-label[data-v-f1ff100d]{font-size:11px;color:#7d8590;text-align:left}.grid-container[data-v-f1ff100d]{display:flex;gap:3px;min-width:fit-content}.day-labels[data-v-f1ff100d]{display:flex;flex-direction:column;width:24px;gap:2px;flex-shrink:0}.day-label[data-v-f1ff100d]{height:11px;font-size:9px;color:#7d8590;display:flex;align-items:center}.contribution-grid[data-v-f1ff100d]{display:flex;gap:2px;flex:1;min-width:0}.contribution-week[data-v-f1ff100d]{display:flex;flex-direction:column;gap:2px;flex-shrink:0}.contribution-day[data-v-f1ff100d]{width:11px;height:11px;border-radius:2px;cursor:pointer;outline:1px solid rgba(27,31,36,.06);outline-offset:-1px;flex-shrink:0}.contribution-day.level-0.green[data-v-f1ff100d]{background-color:#161b22}.contribution-day.level-1.green[data-v-f1ff100d]{background-color:#0e4429}.contribution-day.level-2.green[data-v-f1ff100d]{background-color:#006d32}.contribution-day.level-3.green[data-v-f1ff100d]{background-color:#26a641}.contribution-day.level-4.green[data-v-f1ff100d]{background-color:#39d353}.contribution-day.level-0.blue[data-v-f1ff100d]{background-color:#161b22}.contribution-day.level-1.blue[data-v-f1ff100d]{background-color:#0a3069}.contribution-day.level-2.blue[data-v-f1ff100d]{background-color:#1f6feb}.contribution-day.level-3.blue[data-v-f1ff100d]{background-color:#58a6ff}.contribution-day.level-4.blue[data-v-f1ff100d]{background-color:#79c0ff}.contribution-day.level-0.purple[data-v-f1ff100d]{background-color:#161b22}.contribution-day.level-1.purple[data-v-f1ff100d]{background-color:#3b1e6d}.contribution-day.level-2.purple[data-v-f1ff100d]{background-color:#8250df}.contribution-day.level-3.purple[data-v-f1ff100d]{background-color:#a475f9}.contribution-day.level-4.purple[data-v-f1ff100d]{background-color:#d2a8ff}.contribution-day.level-0.orange[data-v-f1ff100d]{background-color:#161b22}.contribution-day.level-1.orange[data-v-f1ff100d]{background-color:#7d2d00}.contribution-day.level-2.orange[data-v-f1ff100d]{background-color:#da7b00}.contribution-day.level-3.orange[data-v-f1ff100d]{background-color:#ffa348}.contribution-day.level-4.orange[data-v-f1ff100d]{background-color:#ffb366}.contribution-day[data-v-f1ff100d]:hover{outline:1px solid #c9d1d9;outline-offset:-1px}.graph-footer[data-v-f1ff100d]{display:flex;justify-content:space-between;align-items:center;margin-top:8px}.last-updated[data-v-f1ff100d]{color:#7d8590}.legend[data-v-f1ff100d]{display:flex;align-items:center;gap:4px}.legend-label[data-v-f1ff100d]{color:#7d8590}.legend-squares[data-v-f1ff100d]{display:flex;gap:2px}.legend-squares .contribution-day[data-v-f1ff100d]{cursor:default}.legend-squares .contribution-day[data-v-f1ff100d]:hover{outline:none}@media (max-width: 768px){.git-contribution-graph[data-v-f1ff100d]{padding:12px;font-size:11px;overflow-x:auto}.months-container[data-v-f1ff100d]{grid-template-columns:repeat(53,10px);gap:1px}.grid-container[data-v-f1ff100d]{gap:2px}.day-labels[data-v-f1ff100d]{width:20px}.day-label[data-v-f1ff100d]{height:10px;font-size:8px}.contribution-grid[data-v-f1ff100d],.contribution-week[data-v-f1ff100d]{gap:1px}.contribution-day[data-v-f1ff100d]{width:10px;height:10px}.settings-btn[data-v-f1ff100d]{font-size:10px;padding:4px 8px}.contribution-count[data-v-f1ff100d]{font-size:14px}}@media (max-width: 480px){.graph-header[data-v-f1ff100d]{flex-direction:column;align-items:flex-start;gap:8px}}.git-stats-breakdown[data-v-97689125]{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Noto Sans,Helvetica,Arial,sans-serif;padding:40px 20px;max-width:1200px;margin:0 auto}.stats-grid[data-v-97689125]{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:24px;margin-bottom:24px}.stat-card[data-v-97689125]{display:flex;align-items:center;gap:16px;padding:24px;background:#ffffff0d;border-radius:12px;border:1px solid rgba(255,255,255,.1);transition:all .3s ease}.stat-card[data-v-97689125]:hover{background:#ffffff14;border-color:#fff3;transform:translateY(-2px)}.stat-icon[data-v-97689125]{font-size:48px;line-height:1;opacity:.9;flex-shrink:0}.stat-content[data-v-97689125]{flex:1;min-width:0}.stat-value[data-v-97689125]{font-size:32px;font-weight:700;line-height:1.2;color:#e6edf3;margin-bottom:4px}.stat-label[data-v-97689125]{font-size:14px;color:#7d8590;text-transform:uppercase;letter-spacing:.5px}.stat-loading[data-v-97689125]{display:flex;align-items:center;justify-content:center;height:38px}.spinner[data-v-97689125]{width:24px;height:24px;border:3px solid rgba(255,255,255,.1);border-top-color:#58a6ff;border-radius:50%;animation:spin-97689125 1s linear infinite}@keyframes spin-97689125{to{transform:rotate(360deg)}}.stats-footer[data-v-97689125]{display:flex;flex-direction:column;align-items:center;gap:8px;padding-top:16px;border-top:1px solid rgba(255,255,255,.1)}.data-source[data-v-97689125]{font-size:12px;color:#7d8590;text-align:center}@media (max-width: 768px){.git-stats-breakdown[data-v-97689125]{padding:20px 12px}.stats-grid[data-v-97689125]{grid-template-columns:1fr;gap:16px}.stat-card[data-v-97689125]{padding:16px}.stat-icon[data-v-97689125]{font-size:36px}.stat-value[data-v-97689125]{font-size:24px}.stat-label[data-v-97689125]{font-size:12px}}@media (max-width: 480px){.stat-card[data-v-97689125]{flex-direction:column;text-align:center}.stat-content[data-v-97689125]{width:100%}}:root{--vgs-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;--vgs-border-radius: 6px;--vgs-spacing: 16px}.git-contribution-graph *,.git-stats-breakdown *{box-sizing:border-box}.vgs-loading{display:flex;align-items:center;justify-content:center;padding:40px}.vgs-error{color:#f85149;padding:16px;border:1px solid #f85149;border-radius:var(--vgs-border-radius);background:#f851491a}
@@ -0,0 +1,67 @@
1
+ import { ColorScheme } from '../../../core/src';
2
+
3
+ interface Props {
4
+ dataUrl?: string;
5
+ profileIndex?: number;
6
+ colorScheme?: ColorScheme;
7
+ showSettings?: boolean;
8
+ cacheTTL?: number;
9
+ }
10
+ declare function __VLS_template(): {
11
+ "settings-icon"?(_: {}): any;
12
+ };
13
+ declare const __VLS_component: import('vue').DefineComponent<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<Props>, {
14
+ dataUrl: string;
15
+ profileIndex: number;
16
+ colorScheme: string;
17
+ showSettings: boolean;
18
+ cacheTTL: number;
19
+ }>>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
20
+ "day-click": (data: {
21
+ date: string;
22
+ count: number;
23
+ }) => void;
24
+ "color-scheme-change": (scheme: ColorScheme) => void;
25
+ }, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<Props>, {
26
+ dataUrl: string;
27
+ profileIndex: number;
28
+ colorScheme: string;
29
+ showSettings: boolean;
30
+ cacheTTL: number;
31
+ }>>> & Readonly<{
32
+ "onDay-click"?: ((data: {
33
+ date: string;
34
+ count: number;
35
+ }) => any) | undefined;
36
+ "onColor-scheme-change"?: ((scheme: ColorScheme) => any) | undefined;
37
+ }>, {
38
+ dataUrl: string;
39
+ cacheTTL: number;
40
+ profileIndex: number;
41
+ colorScheme: ColorScheme;
42
+ showSettings: boolean;
43
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
44
+ declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, ReturnType<typeof __VLS_template>>;
45
+ export default _default;
46
+ type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
47
+ type __VLS_TypePropsToRuntimeProps<T> = {
48
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
49
+ type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
50
+ } : {
51
+ type: import('vue').PropType<T[K]>;
52
+ required: true;
53
+ };
54
+ };
55
+ type __VLS_WithDefaults<P, D> = {
56
+ [K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
57
+ default: D[K];
58
+ }> : P[K];
59
+ };
60
+ type __VLS_Prettify<T> = {
61
+ [K in keyof T]: T[K];
62
+ } & {};
63
+ type __VLS_WithTemplateSlots<T, S> = T & {
64
+ new (): {
65
+ $slots: S;
66
+ };
67
+ };
@@ -0,0 +1,63 @@
1
+ import { ExperienceEntry, CustomStatCalculator } from '../../../core/src';
2
+
3
+ interface Props {
4
+ dataUrl?: string;
5
+ profileIndexes?: number[];
6
+ experienceData?: ExperienceEntry[];
7
+ showCustomStat?: boolean;
8
+ customStatCalculator?: CustomStatCalculator | null;
9
+ cacheTTL?: number;
10
+ }
11
+ declare function __VLS_template(): {
12
+ "icon-experience"?(_: {}): any;
13
+ "icon-projects"?(_: {}): any;
14
+ "icon-commits"?(_: {}): any;
15
+ "icon-custom"?(_: {}): any;
16
+ "custom-stat-label"?(_: {}): any;
17
+ };
18
+ declare const __VLS_component: import('vue').DefineComponent<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<Props>, {
19
+ dataUrl: string;
20
+ profileIndexes: () => never[];
21
+ experienceData: () => never[];
22
+ showCustomStat: boolean;
23
+ customStatCalculator: null;
24
+ cacheTTL: number;
25
+ }>>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToRuntimeProps<Props>, {
26
+ dataUrl: string;
27
+ profileIndexes: () => never[];
28
+ experienceData: () => never[];
29
+ showCustomStat: boolean;
30
+ customStatCalculator: null;
31
+ cacheTTL: number;
32
+ }>>> & Readonly<{}>, {
33
+ dataUrl: string;
34
+ cacheTTL: number;
35
+ profileIndexes: number[];
36
+ experienceData: ExperienceEntry[];
37
+ showCustomStat: boolean;
38
+ customStatCalculator: CustomStatCalculator | null;
39
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
40
+ declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, ReturnType<typeof __VLS_template>>;
41
+ export default _default;
42
+ type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
43
+ type __VLS_TypePropsToRuntimeProps<T> = {
44
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
45
+ type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
46
+ } : {
47
+ type: import('vue').PropType<T[K]>;
48
+ required: true;
49
+ };
50
+ };
51
+ type __VLS_WithDefaults<P, D> = {
52
+ [K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_Prettify<P[K] & {
53
+ default: D[K];
54
+ }> : P[K];
55
+ };
56
+ type __VLS_Prettify<T> = {
57
+ [K in keyof T]: T[K];
58
+ } & {};
59
+ type __VLS_WithTemplateSlots<T, S> = T & {
60
+ new (): {
61
+ $slots: S;
62
+ };
63
+ };
@@ -0,0 +1,74 @@
1
+ import { GitStatsData, DataSource } from '../../../core/src';
2
+
3
+ export interface UseGitStatsConfig {
4
+ dataUrl?: string;
5
+ cacheTTL?: number;
6
+ useStaleCache?: boolean;
7
+ cacheKey?: string;
8
+ }
9
+ export declare function useGitStats(config?: UseGitStatsConfig): {
10
+ data: import('vue').Ref<{
11
+ lastUpdated: string;
12
+ profiles: {
13
+ username: string;
14
+ platform: import('../../../core/src').Platform;
15
+ stats: {
16
+ projectCount: number;
17
+ commitCount: number;
18
+ contributions?: {
19
+ firstDay: string;
20
+ contributionDays: {
21
+ date: string;
22
+ contributionCount: number;
23
+ weekday: number;
24
+ }[];
25
+ }[] | undefined;
26
+ };
27
+ }[];
28
+ totals: {
29
+ projectCount: number;
30
+ commitCount: number;
31
+ };
32
+ metadata: {
33
+ fetchedAt: number;
34
+ source: string;
35
+ isDummy?: boolean | undefined;
36
+ };
37
+ cachedAt?: number | undefined;
38
+ } | null, GitStatsData | {
39
+ lastUpdated: string;
40
+ profiles: {
41
+ username: string;
42
+ platform: import('../../../core/src').Platform;
43
+ stats: {
44
+ projectCount: number;
45
+ commitCount: number;
46
+ contributions?: {
47
+ firstDay: string;
48
+ contributionDays: {
49
+ date: string;
50
+ contributionCount: number;
51
+ weekday: number;
52
+ }[];
53
+ }[] | undefined;
54
+ };
55
+ }[];
56
+ totals: {
57
+ projectCount: number;
58
+ commitCount: number;
59
+ };
60
+ metadata: {
61
+ fetchedAt: number;
62
+ source: string;
63
+ isDummy?: boolean | undefined;
64
+ };
65
+ cachedAt?: number | undefined;
66
+ } | null>;
67
+ loading: import('vue').Ref<boolean, boolean>;
68
+ error: import('vue').Ref<Error | null, Error | null>;
69
+ dataSource: import('vue').Ref<DataSource | null, DataSource | null>;
70
+ dataSourceText: import('vue').ComputedRef<"" | "⚠️ Using dummy data for testing" | "Real-time data" | "Cached data" | "Sample data">;
71
+ lastUpdatedText: import('vue').ComputedRef<string>;
72
+ isDummy: import('vue').Ref<boolean, boolean>;
73
+ loadData: () => Promise<GitStatsData | null>;
74
+ };
@@ -0,0 +1,12 @@
1
+ import { App } from 'vue';
2
+ import { default as ContributionGraph } from './components/ContributionGraph.vue';
3
+ import { default as StatsBreakdown } from './components/StatsBreakdown.vue';
4
+ import { useGitStats } from './composables/useGitStats';
5
+
6
+ export * from '../../core/src';
7
+ export { ContributionGraph, StatsBreakdown, useGitStats };
8
+ export interface VueGitStatsPlugin {
9
+ install: (app: App) => void;
10
+ }
11
+ declare const VueGitStats: VueGitStatsPlugin;
12
+ export default VueGitStats;
@@ -0,0 +1,14 @@
1
+ import { Ref, ComputedRef } from 'vue';
2
+ import { GitStatsData, DataSource } from '../../core/src';
3
+
4
+ export interface UseGitStatsReturn {
5
+ data: Ref<GitStatsData | null>;
6
+ loading: Ref<boolean>;
7
+ error: Ref<Error | null>;
8
+ dataSource: Ref<DataSource | null>;
9
+ dataSourceText: ComputedRef<string>;
10
+ lastUpdatedText: ComputedRef<string>;
11
+ isDummy: Ref<boolean>;
12
+ loadData: () => Promise<GitStatsData | null>;
13
+ cacheData: (data: GitStatsData) => void;
14
+ }
@@ -0,0 +1,636 @@
1
+ var nt = Object.defineProperty, rt = Object.defineProperties;
2
+ var it = Object.getOwnPropertyDescriptors;
3
+ var P = Object.getOwnPropertySymbols;
4
+ var lt = Object.prototype.hasOwnProperty, ct = Object.prototype.propertyIsEnumerable;
5
+ var V = (e, t, a) => t in e ? nt(e, t, { enumerable: !0, configurable: !0, writable: !0, value: a }) : e[t] = a, R = (e, t) => {
6
+ for (var a in t || (t = {}))
7
+ lt.call(t, a) && V(e, a, t[a]);
8
+ if (P)
9
+ for (var a of P(t))
10
+ ct.call(t, a) && V(e, a, t[a]);
11
+ return e;
12
+ }, Y = (e, t) => rt(e, it(t));
13
+ var M = (e, t, a) => new Promise((i, l) => {
14
+ var f = (u) => {
15
+ try {
16
+ o(a.next(u));
17
+ } catch (b) {
18
+ l(b);
19
+ }
20
+ }, d = (u) => {
21
+ try {
22
+ o(a.throw(u));
23
+ } catch (b) {
24
+ l(b);
25
+ }
26
+ }, o = (u) => u.done ? i(u.value) : Promise.resolve(u.value).then(f, d);
27
+ o((a = a.apply(e, t)).next());
28
+ });
29
+ import { ref as S, computed as I, defineComponent as q, watch as z, createElementBlock as y, openBlock as h, createElementVNode as r, createCommentVNode as L, toDisplayString as D, normalizeClass as W, unref as k, renderSlot as j, createTextVNode as C, Fragment as O, renderList as A, normalizeStyle as dt, createStaticVNode as J } from "vue";
30
+ function de(e) {
31
+ return M(this, null, function* () {
32
+ const t = yield fetch(e);
33
+ if (!t.ok)
34
+ throw new Error(`Failed to fetch git stats: ${t.statusText}`);
35
+ return t.json();
36
+ });
37
+ }
38
+ function ut() {
39
+ const e = [], t = /* @__PURE__ */ new Date(), a = new Date(t);
40
+ a.setDate(a.getDate() - a.getDay());
41
+ const i = new Date(a);
42
+ i.setDate(i.getDate() - 52 * 7);
43
+ const l = new Date(i);
44
+ for (let f = 0; f < 53; f++) {
45
+ const d = {
46
+ weekStart: new Date(l).toISOString().split("T")[0],
47
+ contributionDays: []
48
+ };
49
+ for (let o = 0; o < 7; o++) {
50
+ const u = l > t, b = o === 0 || o === 6;
51
+ let m = 0;
52
+ u || (b ? m = Math.random() < 0.3 ? Math.floor(Math.random() * 5) : 0 : m = Math.floor(Math.random() * 15)), d.contributionDays.push({
53
+ date: new Date(l).toISOString().split("T")[0],
54
+ contributionCount: m,
55
+ weekday: o
56
+ }), l.setDate(l.getDate() + 1);
57
+ }
58
+ e.push(d);
59
+ }
60
+ return e;
61
+ }
62
+ function G(e = {}) {
63
+ const {
64
+ username: t = "demo-user",
65
+ platform: a = "github",
66
+ projectCount: i = 30,
67
+ commitCount: l = 2500
68
+ } = e, f = ut();
69
+ return f.reduce((d, o) => d + o.contributionDays.reduce(
70
+ (u, b) => u + b.contributionCount,
71
+ 0
72
+ ), 0), {
73
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
74
+ profiles: [
75
+ {
76
+ username: t,
77
+ platform: a,
78
+ stats: {
79
+ projectCount: i,
80
+ commitCount: l,
81
+ contributions: f.map((d) => ({
82
+ firstDay: d.weekStart,
83
+ contributionDays: d.contributionDays
84
+ }))
85
+ }
86
+ }
87
+ ],
88
+ totals: {
89
+ projectCount: i,
90
+ commitCount: l
91
+ },
92
+ metadata: {
93
+ fetchedAt: Date.now(),
94
+ source: "dummy_data",
95
+ isDummy: !0
96
+ }
97
+ };
98
+ }
99
+ function ue() {
100
+ const e = G({
101
+ username: "demo-github",
102
+ platform: "github",
103
+ projectCount: 45,
104
+ commitCount: 2847
105
+ }), t = G({
106
+ username: "demo-gitlab",
107
+ platform: "gitlab",
108
+ projectCount: 7,
109
+ commitCount: 523
110
+ });
111
+ return {
112
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
113
+ profiles: [e.profiles[0], t.profiles[0]],
114
+ totals: {
115
+ projectCount: 52,
116
+ commitCount: 3370
117
+ },
118
+ metadata: {
119
+ fetchedAt: Date.now(),
120
+ source: "dummy_data",
121
+ isDummy: !0
122
+ }
123
+ };
124
+ }
125
+ function fe(e = "dummy-git-stats.json") {
126
+ const t = G(), a = JSON.stringify(t, null, " ");
127
+ if (typeof window != "undefined") {
128
+ const i = new Blob([a], { type: "application/json" }), l = URL.createObjectURL(i), f = document.createElement("a");
129
+ f.href = l, f.download = e, f.click(), URL.revokeObjectURL(l);
130
+ } else
131
+ try {
132
+ require("fs").writeFileSync(e, a), console.log(`✓ Dummy data saved to ${e}`);
133
+ } catch (i) {
134
+ console.error("Failed to save dummy data:", i);
135
+ }
136
+ }
137
+ function ft(e) {
138
+ return M(this, null, function* () {
139
+ var f, d;
140
+ const { dataUrl: t, cacheKey: a = "git_stats_cache", useStaleCache: i = !0 } = e;
141
+ try {
142
+ const o = yield fetch(t);
143
+ if (o.ok) {
144
+ const u = yield o.json();
145
+ return typeof window != "undefined" && localStorage.setItem(
146
+ a,
147
+ JSON.stringify(Y(R({}, u), {
148
+ cachedAt: Date.now()
149
+ }))
150
+ ), {
151
+ data: u,
152
+ error: null,
153
+ source: "static",
154
+ isDummy: ((f = u.metadata) == null ? void 0 : f.isDummy) === !0
155
+ };
156
+ }
157
+ } catch (o) {
158
+ console.warn("Failed to fetch from static file:", o);
159
+ }
160
+ if (i && typeof window != "undefined")
161
+ try {
162
+ const o = localStorage.getItem(a);
163
+ if (o) {
164
+ const u = JSON.parse(o);
165
+ return {
166
+ data: u,
167
+ error: null,
168
+ source: "cache",
169
+ isDummy: ((d = u.metadata) == null ? void 0 : d.isDummy) === !0
170
+ };
171
+ }
172
+ } catch (o) {
173
+ console.warn("Failed to load from cache:", o);
174
+ }
175
+ return {
176
+ data: yt(),
177
+ error: null,
178
+ source: "mock",
179
+ isDummy: !1
180
+ };
181
+ });
182
+ }
183
+ function mt(e) {
184
+ const t = new Date(e), a = /* @__PURE__ */ new Date(), i = Math.floor((a.getTime() - t.getTime()) / (1e3 * 60 * 60));
185
+ if (i < 1) return "just now";
186
+ if (i < 24) return `${i} hours ago`;
187
+ const l = Math.floor(i / 24);
188
+ return l === 1 ? "yesterday" : l < 7 ? `${l} days ago` : t.toLocaleDateString("en-US", {
189
+ month: "short",
190
+ day: "numeric",
191
+ year: t.getFullYear() !== a.getFullYear() ? "numeric" : void 0
192
+ });
193
+ }
194
+ function me(e) {
195
+ return e === 0 ? 0 : e <= 3 ? 1 : e <= 6 ? 2 : e <= 9 ? 3 : 4;
196
+ }
197
+ function vt(e) {
198
+ if (e.length === 0) return 0;
199
+ const t = {};
200
+ return e.forEach((a) => {
201
+ var d;
202
+ const i = a.endDate ? new Date(a.endDate) : /* @__PURE__ */ new Date(), l = new Date(a.startDate), f = (i.getTime() - l.getTime()) / (1e3 * 60 * 60 * 24 * 365.25);
203
+ (d = a.skills) == null || d.forEach((o) => {
204
+ t[o] || (t[o] = 0), t[o] += f;
205
+ });
206
+ }), Math.max(...Object.values(t), 0);
207
+ }
208
+ function yt() {
209
+ return {
210
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
211
+ profiles: [
212
+ {
213
+ username: "mockuser",
214
+ platform: "github",
215
+ stats: {
216
+ projectCount: 30,
217
+ commitCount: 2500,
218
+ contributions: []
219
+ }
220
+ }
221
+ ],
222
+ totals: {
223
+ projectCount: 30,
224
+ commitCount: 2500
225
+ },
226
+ metadata: {
227
+ source: "mock",
228
+ fetchedAt: Date.now()
229
+ }
230
+ };
231
+ }
232
+ function K(e = {}) {
233
+ const {
234
+ dataUrl: t = "/data/git-stats.json",
235
+ cacheTTL: a = 24 * 60 * 60 * 1e3,
236
+ useStaleCache: i = !0,
237
+ cacheKey: l = "git_stats_cache"
238
+ } = e, f = S(!1), d = S(null), o = S(null), u = S(null), b = S(!1);
239
+ function m() {
240
+ return M(this, null, function* () {
241
+ f.value = !0, d.value = null;
242
+ try {
243
+ const g = yield ft({
244
+ dataUrl: t,
245
+ cacheTTL: a,
246
+ cacheKey: l,
247
+ useStaleCache: i
248
+ });
249
+ return o.value = g.data, d.value = g.error, u.value = g.source, b.value = g.isDummy, g.data;
250
+ } catch (g) {
251
+ return d.value = g instanceof Error ? g : new Error("Failed to load data"), null;
252
+ } finally {
253
+ f.value = !1;
254
+ }
255
+ });
256
+ }
257
+ const c = I(() => {
258
+ var g;
259
+ return (g = o.value) != null && g.lastUpdated ? mt(o.value.lastUpdated) : "";
260
+ }), _ = I(() => {
261
+ if (b.value)
262
+ return "⚠️ Using dummy data for testing";
263
+ switch (u.value) {
264
+ case "static":
265
+ return "Real-time data";
266
+ case "cache":
267
+ return "Cached data";
268
+ case "mock":
269
+ return "Sample data";
270
+ default:
271
+ return "";
272
+ }
273
+ });
274
+ return m(), {
275
+ data: o,
276
+ loading: f,
277
+ error: d,
278
+ dataSource: u,
279
+ dataSourceText: _,
280
+ lastUpdatedText: c,
281
+ isDummy: b,
282
+ loadData: m
283
+ };
284
+ }
285
+ const ht = { class: "git-contribution-graph" }, pt = { class: "graph-header" }, gt = { class: "header-info" }, bt = { class: "contribution-count" }, _t = {
286
+ key: 0,
287
+ class: "header-actions"
288
+ }, kt = {
289
+ key: 0,
290
+ class: "settings-dropdown"
291
+ }, Dt = ["onClick"], St = {
292
+ key: 0,
293
+ class: "loading-state"
294
+ }, wt = {
295
+ key: 1,
296
+ class: "graph-container"
297
+ }, Ct = { class: "graph-content-wrapper" }, $t = { class: "months-row" }, Tt = { class: "months-container" }, jt = { class: "grid-container" }, Lt = { class: "contribution-grid" }, Ut = ["title", "onClick"], xt = { class: "graph-footer" }, Ft = {
298
+ key: 0,
299
+ class: "last-updated"
300
+ }, It = /* @__PURE__ */ q({
301
+ __name: "ContributionGraph",
302
+ props: {
303
+ dataUrl: { default: "/data/git-stats.json" },
304
+ profileIndex: { default: 0 },
305
+ colorScheme: { default: "green" },
306
+ showSettings: { type: Boolean, default: !0 },
307
+ cacheTTL: { default: 24 * 60 * 60 * 1e3 }
308
+ },
309
+ emits: ["day-click", "color-scheme-change"],
310
+ setup(e, { emit: t }) {
311
+ const a = e, i = t, { data: l, loading: f, dataSourceText: d, lastUpdatedText: o, isDummy: u } = K(
312
+ {
313
+ dataUrl: a.dataUrl,
314
+ cacheTTL: a.cacheTTL
315
+ }
316
+ ), b = S(a.colorScheme), m = S(!1), c = ["green", "blue", "purple", "orange"], _ = S([]), g = S([]);
317
+ z(
318
+ l,
319
+ (s) => {
320
+ var n, v, p;
321
+ if ((p = (v = (n = s == null ? void 0 : s.profiles) == null ? void 0 : n[a.profileIndex]) == null ? void 0 : v.stats) != null && p.contributions) {
322
+ const w = s.profiles[a.profileIndex].stats.contributions;
323
+ w && (_.value = B(w), Q());
324
+ } else
325
+ _.value = [];
326
+ },
327
+ { immediate: !0 }
328
+ );
329
+ const T = I(() => !_.value || _.value.length === 0 ? 0 : _.value.reduce((s, n) => !n.days || !Array.isArray(n.days) ? s : s + n.days.reduce((v, p) => v + (p.count || 0), 0), 0));
330
+ function B(s) {
331
+ if (!s || !Array.isArray(s))
332
+ return $();
333
+ const n = s.map((v) => ({
334
+ weekStart: v.firstDay || "",
335
+ days: v.contributionDays.map((p) => {
336
+ var w;
337
+ return {
338
+ date: p.date || "",
339
+ count: (w = p.contributionCount) != null ? w : 0,
340
+ weekday: p.weekday || 0
341
+ };
342
+ })
343
+ }));
344
+ for (; n.length < 53; )
345
+ n.push(U());
346
+ return n;
347
+ }
348
+ function $() {
349
+ const s = [];
350
+ for (let n = 0; n < 53; n++)
351
+ s.push(U());
352
+ return s;
353
+ }
354
+ function U() {
355
+ const s = [];
356
+ for (let n = 0; n < 7; n++)
357
+ s.push({ date: "", count: 0, weekday: n });
358
+ return { weekStart: "", days: s };
359
+ }
360
+ function Q() {
361
+ if (!_.value || _.value.length === 0) {
362
+ g.value = [];
363
+ return;
364
+ }
365
+ const s = [];
366
+ let n = -1, v = -1;
367
+ _.value.forEach((p, w) => {
368
+ if (!p.days || p.days.length === 0) return;
369
+ const E = p.days[0].date;
370
+ if (!E) return;
371
+ const N = E.split("-");
372
+ if (N.length !== 3) return;
373
+ const [x, F] = N.map(Number);
374
+ if (!(isNaN(x) || isNaN(F)) && (F !== n || x !== v)) {
375
+ const ot = new Date(x, F - 1, 1);
376
+ s.push({
377
+ week: w,
378
+ month: F - 1,
379
+ year: x,
380
+ label: ot.toLocaleDateString("en-US", { month: "short" })
381
+ }), n = F, v = x;
382
+ }
383
+ }), g.value = s;
384
+ }
385
+ function X(s) {
386
+ return `level-${Z(s)} ${b.value}`;
387
+ }
388
+ function Z(s) {
389
+ return s === 0 ? 0 : s <= 3 ? 1 : s <= 6 ? 2 : s <= 9 ? 3 : 4;
390
+ }
391
+ function tt(s) {
392
+ if (!s.date) return "";
393
+ const [n, v, p] = s.date.split("-").map(Number), E = new Date(n, v - 1, p).toLocaleDateString("en-US", {
394
+ weekday: "short",
395
+ year: "numeric",
396
+ month: "short",
397
+ day: "numeric"
398
+ }), N = s.count === 1 ? "contribution" : "contributions";
399
+ return `${s.count} ${N} on ${E}`;
400
+ }
401
+ function et(s) {
402
+ i("day-click", { date: s.date, count: s.count });
403
+ }
404
+ function at() {
405
+ m.value = !m.value;
406
+ }
407
+ function st(s) {
408
+ b.value = s, m.value = !1, i("color-scheme-change", s);
409
+ }
410
+ return (s, n) => (h(), y("div", ht, [
411
+ r("div", pt, [
412
+ r("div", gt, [
413
+ r("h5", bt, D(T.value.toLocaleString()) + " contributions in the last year ", 1),
414
+ r("small", {
415
+ class: W(["data-source-text", { "is-dummy": k(u) }])
416
+ }, D(k(d)), 3)
417
+ ]),
418
+ e.showSettings ? (h(), y("div", _t, [
419
+ r("button", {
420
+ class: "settings-btn",
421
+ type: "button",
422
+ onClick: at
423
+ }, [
424
+ j(s.$slots, "settings-icon", {}, () => [
425
+ n[0] || (n[0] = C("⚙️", -1))
426
+ ], !0),
427
+ n[1] || (n[1] = C(" Settings ", -1))
428
+ ]),
429
+ m.value ? (h(), y("div", kt, [
430
+ (h(), y(O, null, A(c, (v) => r("button", {
431
+ key: v,
432
+ onClick: (p) => st(v),
433
+ class: "settings-item"
434
+ }, D(v) + " theme ", 9, Dt)), 64))
435
+ ])) : L("", !0)
436
+ ])) : L("", !0)
437
+ ]),
438
+ k(f) ? (h(), y("div", St, [...n[2] || (n[2] = [
439
+ r("div", { class: "spinner" }, null, -1),
440
+ r("span", null, "Loading contributions...", -1)
441
+ ])])) : (h(), y("div", wt, [
442
+ r("div", Ct, [
443
+ r("div", $t, [
444
+ n[3] || (n[3] = r("div", { class: "month-spacer" }, null, -1)),
445
+ r("div", Tt, [
446
+ (h(!0), y(O, null, A(g.value, (v) => (h(), y("div", {
447
+ key: `${v.year}-${v.month}`,
448
+ class: "month-label",
449
+ style: dt({
450
+ gridColumn: `${v.week + 1} / span 1`
451
+ })
452
+ }, D(v.label), 5))), 128))
453
+ ])
454
+ ]),
455
+ r("div", jt, [
456
+ n[4] || (n[4] = J('<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)),
457
+ r("div", Lt, [
458
+ (h(!0), y(O, null, A(_.value, (v) => (h(), y("div", {
459
+ key: v.weekStart,
460
+ class: "contribution-week"
461
+ }, [
462
+ (h(!0), y(O, null, A(v.days, (p) => (h(), y("div", {
463
+ key: p.date,
464
+ class: W(["contribution-day", X(p.count)]),
465
+ title: tt(p),
466
+ onClick: (w) => et(p)
467
+ }, null, 10, Ut))), 128))
468
+ ]))), 128))
469
+ ])
470
+ ])
471
+ ]),
472
+ r("div", xt, [
473
+ k(o) ? (h(), y("small", Ft, " Last updated: " + D(k(o)), 1)) : L("", !0),
474
+ n[5] || (n[5] = J('<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))
475
+ ])
476
+ ]))
477
+ ]));
478
+ }
479
+ }), H = (e, t) => {
480
+ const a = e.__vccOpts || e;
481
+ for (const [i, l] of t)
482
+ a[i] = l;
483
+ return a;
484
+ }, Et = /* @__PURE__ */ H(It, [["__scopeId", "data-v-f1ff100d"]]), Nt = { class: "git-stats-breakdown" }, Mt = { class: "stats-grid" }, Ot = { class: "stat-card" }, At = { class: "stat-icon" }, Bt = { class: "stat-content" }, Gt = { class: "stat-value" }, Pt = { class: "stat-card" }, Vt = { class: "stat-icon" }, Rt = { class: "stat-content" }, Yt = {
485
+ key: 0,
486
+ class: "stat-loading"
487
+ }, Wt = {
488
+ key: 1,
489
+ class: "stat-value"
490
+ }, Jt = { class: "stat-card" }, qt = { class: "stat-icon" }, zt = { class: "stat-content" }, Kt = {
491
+ key: 0,
492
+ class: "stat-loading"
493
+ }, Ht = {
494
+ key: 1,
495
+ class: "stat-value"
496
+ }, Qt = {
497
+ key: 0,
498
+ class: "stat-card"
499
+ }, Xt = { class: "stat-icon" }, Zt = { class: "stat-content" }, te = {
500
+ key: 0,
501
+ class: "stat-loading"
502
+ }, ee = {
503
+ key: 1,
504
+ class: "stat-value"
505
+ }, ae = { class: "stat-label" }, se = { class: "stats-footer" }, oe = {
506
+ key: 0,
507
+ class: "data-source"
508
+ }, ne = { key: 0 }, re = /* @__PURE__ */ q({
509
+ __name: "StatsBreakdown",
510
+ props: {
511
+ dataUrl: { default: "/data/git-stats.json" },
512
+ profileIndexes: { default: () => [] },
513
+ experienceData: { default: () => [] },
514
+ showCustomStat: { type: Boolean, default: !0 },
515
+ customStatCalculator: { type: [Function, null], default: null },
516
+ cacheTTL: { default: 24 * 60 * 60 * 1e3 }
517
+ },
518
+ setup(e) {
519
+ const t = e, { data: a, loading: i, dataSourceText: l, lastUpdatedText: f } = K({
520
+ dataUrl: t.dataUrl,
521
+ cacheTTL: t.cacheTTL
522
+ }), d = S(0), o = S(0);
523
+ z(
524
+ a,
525
+ (m) => {
526
+ var c, _;
527
+ if (m)
528
+ if (t.profileIndexes.length > 0) {
529
+ let g = 0, T = 0;
530
+ t.profileIndexes.forEach((B) => {
531
+ var U;
532
+ const $ = (U = m.profiles) == null ? void 0 : U[B];
533
+ $ != null && $.stats && (g += $.stats.projectCount || 0, T += $.stats.commitCount || 0);
534
+ }), d.value = g, o.value = T;
535
+ } else
536
+ d.value = ((c = m.totals) == null ? void 0 : c.projectCount) || 0, o.value = ((_ = m.totals) == null ? void 0 : _.commitCount) || 0;
537
+ },
538
+ { immediate: !0 }
539
+ );
540
+ const u = I(() => vt(t.experienceData).toFixed(1)), b = I(() => {
541
+ if (t.customStatCalculator) {
542
+ const T = {
543
+ projects: d.value,
544
+ commits: o.value,
545
+ years: parseFloat(u.value)
546
+ };
547
+ return t.customStatCalculator(T);
548
+ }
549
+ return (d.value * 1.5 + o.value * 1.2 + parseFloat(u.value) * 1.5).toFixed(2);
550
+ });
551
+ return (m, c) => (h(), y("div", Nt, [
552
+ r("div", Mt, [
553
+ r("div", Ot, [
554
+ r("div", At, [
555
+ j(m.$slots, "icon-experience", {}, () => [
556
+ c[0] || (c[0] = C("⏱️", -1))
557
+ ], !0)
558
+ ]),
559
+ r("div", Bt, [
560
+ r("div", Gt, D(u.value), 1),
561
+ c[1] || (c[1] = r("div", { class: "stat-label" }, "Years Experience", -1))
562
+ ])
563
+ ]),
564
+ r("div", Pt, [
565
+ r("div", Vt, [
566
+ j(m.$slots, "icon-projects", {}, () => [
567
+ c[2] || (c[2] = C("📦", -1))
568
+ ], !0)
569
+ ]),
570
+ r("div", Rt, [
571
+ k(i) ? (h(), y("div", Yt, [...c[3] || (c[3] = [
572
+ r("div", { class: "spinner" }, null, -1)
573
+ ])])) : (h(), y("div", Wt, D(d.value), 1)),
574
+ c[4] || (c[4] = r("div", { class: "stat-label" }, "Projects", -1))
575
+ ])
576
+ ]),
577
+ r("div", Jt, [
578
+ r("div", qt, [
579
+ j(m.$slots, "icon-commits", {}, () => [
580
+ c[5] || (c[5] = C("💻", -1))
581
+ ], !0)
582
+ ]),
583
+ r("div", zt, [
584
+ k(i) ? (h(), y("div", Kt, [...c[6] || (c[6] = [
585
+ r("div", { class: "spinner" }, null, -1)
586
+ ])])) : (h(), y("div", Ht, D(o.value), 1)),
587
+ c[7] || (c[7] = r("div", { class: "stat-label" }, "Commits", -1))
588
+ ])
589
+ ]),
590
+ e.showCustomStat ? (h(), y("div", Qt, [
591
+ r("div", Xt, [
592
+ j(m.$slots, "icon-custom", {}, () => [
593
+ c[8] || (c[8] = C("☕", -1))
594
+ ], !0)
595
+ ]),
596
+ r("div", Zt, [
597
+ k(i) ? (h(), y("div", te, [...c[9] || (c[9] = [
598
+ r("div", { class: "spinner" }, null, -1)
599
+ ])])) : (h(), y("div", ee, D(b.value), 1)),
600
+ r("div", ae, [
601
+ j(m.$slots, "custom-stat-label", {}, () => [
602
+ c[10] || (c[10] = C("Coffee Consumed", -1))
603
+ ], !0)
604
+ ])
605
+ ])
606
+ ])) : L("", !0)
607
+ ]),
608
+ r("div", se, [
609
+ k(l) ? (h(), y("small", oe, [
610
+ C(D(k(l)) + " ", 1),
611
+ k(f) ? (h(), y("span", ne, " · " + D(k(f)), 1)) : L("", !0)
612
+ ])) : L("", !0)
613
+ ])
614
+ ]));
615
+ }
616
+ }), ie = /* @__PURE__ */ H(re, [["__scopeId", "data-v-97689125"]]), ve = {
617
+ install(e) {
618
+ e.component("ContributionGraph", Et), e.component("StatsBreakdown", ie);
619
+ }
620
+ };
621
+ export {
622
+ Et as ContributionGraph,
623
+ ie as StatsBreakdown,
624
+ vt as calculateYearsExperience,
625
+ ve as default,
626
+ ft as fetchGitStats,
627
+ de as fetchGitStatsAPI,
628
+ mt as formatLastUpdated,
629
+ ut as generateDummyContributions,
630
+ G as generateDummyStats,
631
+ ue as generateMultiProfileDummyStats,
632
+ me as getContributionLevel,
633
+ fe as saveDummyDataToFile,
634
+ K as useGitStats
635
+ };
636
+ //# sourceMappingURL=vue-git-stats.es.js.map
@@ -0,0 +1 @@
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":"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"}
@@ -0,0 +1,2 @@
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
@@ -0,0 +1 @@
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":"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"}
package/package.json ADDED
@@ -0,0 +1,60 @@
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
+ }