heyiam 0.2.29 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -0
- package/dist/auth.js +29 -3
- package/dist/config.js +10 -1
- package/dist/db.js +0 -1
- package/dist/export.js +124 -27
- package/dist/format-utils.js +5 -0
- package/dist/github.js +381 -0
- package/dist/index.js +168 -0
- package/dist/mount.js +300 -102
- package/dist/parsers/claude.js +2 -28
- package/dist/parsers/codex.js +2 -26
- package/dist/parsers/cursor.js +2 -26
- package/dist/parsers/duration.js +35 -0
- package/dist/parsers/gemini.js +2 -20
- package/dist/parsers/index.js +22 -3
- package/dist/parsers/types.js +0 -1
- package/dist/public/assets/index-Coilyhtr.css +1 -0
- package/dist/public/assets/index-D0noVMFu.js +44 -0
- package/dist/public/index.html +2 -2
- package/dist/redact.js +4 -104
- package/dist/render/build-render-data.js +9 -2
- package/dist/render/index.js +32 -5
- package/dist/render/liquid.js +147 -7
- package/dist/render/mock-data.js +303 -0
- package/dist/render/templates/aurora/portfolio.liquid +192 -0
- package/dist/render/templates/aurora/project.liquid +260 -0
- package/dist/render/templates/aurora/session.liquid +223 -0
- package/dist/render/templates/aurora/styles.css +1184 -0
- package/dist/render/templates/bauhaus/portfolio.liquid +169 -0
- package/dist/render/templates/bauhaus/project.liquid +300 -0
- package/dist/render/templates/bauhaus/session.liquid +333 -0
- package/dist/render/templates/bauhaus/styles.css +1645 -0
- package/dist/render/templates/blueprint/portfolio.liquid +153 -0
- package/dist/render/templates/blueprint/project.liquid +286 -0
- package/dist/render/templates/blueprint/session.liquid +248 -0
- package/dist/render/templates/blueprint/styles.css +1289 -0
- package/dist/render/templates/canvas/portfolio.liquid +203 -0
- package/dist/render/templates/canvas/project.liquid +235 -0
- package/dist/render/templates/canvas/session.liquid +223 -0
- package/dist/render/templates/canvas/styles.css +1440 -0
- package/dist/render/templates/carbon/portfolio.liquid +160 -0
- package/dist/render/templates/carbon/project.liquid +249 -0
- package/dist/render/templates/carbon/session.liquid +190 -0
- package/dist/render/templates/carbon/styles.css +1097 -0
- package/dist/render/templates/chalk/portfolio.liquid +189 -0
- package/dist/render/templates/chalk/project.liquid +245 -0
- package/dist/render/templates/chalk/session.liquid +215 -0
- package/dist/render/templates/chalk/styles.css +1161 -0
- package/dist/render/templates/circuit/portfolio.liquid +152 -0
- package/dist/render/templates/circuit/project.liquid +247 -0
- package/dist/render/templates/circuit/session.liquid +205 -0
- package/dist/render/templates/circuit/styles.css +1409 -0
- package/dist/render/templates/cosmos/portfolio.liquid +222 -0
- package/dist/render/templates/cosmos/project.liquid +327 -0
- package/dist/render/templates/cosmos/session.liquid +239 -0
- package/dist/render/templates/cosmos/styles.css +1157 -0
- package/dist/render/templates/daylight/portfolio.liquid +207 -0
- package/dist/render/templates/daylight/project.liquid +229 -0
- package/dist/render/templates/daylight/session.liquid +219 -0
- package/dist/render/templates/daylight/styles.css +1315 -0
- package/dist/render/templates/editorial/portfolio.liquid +110 -0
- package/dist/render/templates/editorial/project.liquid +202 -0
- package/dist/render/templates/editorial/session.liquid +171 -0
- package/dist/render/templates/editorial/styles.css +826 -0
- package/dist/render/templates/ember/portfolio.liquid +306 -0
- package/dist/render/templates/ember/project.liquid +232 -0
- package/dist/render/templates/ember/session.liquid +202 -0
- package/dist/render/templates/ember/styles.css +1289 -0
- package/dist/render/templates/glacier/portfolio.liquid +261 -0
- package/dist/render/templates/glacier/project.liquid +288 -0
- package/dist/render/templates/glacier/session.liquid +217 -0
- package/dist/render/templates/glacier/styles.css +1204 -0
- package/dist/render/templates/grid/portfolio.liquid +255 -0
- package/dist/render/templates/grid/project.liquid +306 -0
- package/dist/render/templates/grid/session.liquid +260 -0
- package/dist/render/templates/grid/styles.css +1445 -0
- package/dist/render/templates/kinetic/portfolio.liquid +158 -0
- package/dist/render/templates/kinetic/project.liquid +242 -0
- package/dist/render/templates/kinetic/session.liquid +228 -0
- package/dist/render/templates/kinetic/styles.css +948 -0
- package/dist/render/templates/meridian/portfolio.liquid +243 -0
- package/dist/render/templates/meridian/project.liquid +376 -0
- package/dist/render/templates/meridian/session.liquid +298 -0
- package/dist/render/templates/meridian/styles.css +1375 -0
- package/dist/render/templates/minimal/portfolio.liquid +71 -0
- package/dist/render/templates/minimal/project.liquid +154 -0
- package/dist/render/templates/minimal/session.liquid +140 -0
- package/dist/render/templates/minimal/styles.css +529 -0
- package/dist/render/templates/mono/portfolio.liquid +281 -0
- package/dist/render/templates/mono/project.liquid +275 -0
- package/dist/render/templates/mono/session.liquid +276 -0
- package/dist/render/templates/mono/styles.css +1022 -0
- package/dist/render/templates/neon/portfolio.liquid +207 -0
- package/dist/render/templates/neon/project.liquid +225 -0
- package/dist/render/templates/neon/session.liquid +195 -0
- package/dist/render/templates/neon/styles.css +1271 -0
- package/dist/render/templates/noir/portfolio.liquid +137 -0
- package/dist/render/templates/noir/project.liquid +220 -0
- package/dist/render/templates/noir/session.liquid +241 -0
- package/dist/render/templates/noir/styles.css +1229 -0
- package/dist/render/templates/obsidian/portfolio.liquid +247 -0
- package/dist/render/templates/obsidian/project.liquid +280 -0
- package/dist/render/templates/obsidian/session.liquid +241 -0
- package/dist/render/templates/obsidian/styles.css +1407 -0
- package/dist/render/templates/paper/portfolio.liquid +257 -0
- package/dist/render/templates/paper/project.liquid +235 -0
- package/dist/render/templates/paper/session.liquid +271 -0
- package/dist/render/templates/paper/styles.css +1513 -0
- package/dist/render/templates/parallax/portfolio.liquid +295 -0
- package/dist/render/templates/parallax/project.liquid +275 -0
- package/dist/render/templates/parallax/session.liquid +295 -0
- package/dist/render/templates/parallax/styles.css +1880 -0
- package/dist/render/templates/parchment/portfolio.liquid +280 -0
- package/dist/render/templates/parchment/project.liquid +289 -0
- package/dist/render/templates/parchment/session.liquid +346 -0
- package/dist/render/templates/parchment/styles.css +1401 -0
- package/dist/render/templates/partials/_beats.liquid +16 -0
- package/dist/render/templates/partials/_breadcrumb.liquid +9 -0
- package/dist/render/templates/partials/_footer.liquid +7 -0
- package/dist/render/templates/partials/_growth-chart.liquid +7 -0
- package/dist/render/templates/partials/_key-decisions.liquid +20 -0
- package/dist/render/templates/partials/_links.liquid +16 -0
- package/dist/render/templates/partials/_narrative.liquid +8 -0
- package/dist/render/templates/partials/_phases.liquid +20 -0
- package/dist/render/templates/partials/_portfolio-header.liquid +20 -0
- package/dist/render/templates/partials/_portfolio-projects.liquid +16 -0
- package/dist/render/templates/partials/_portfolio-stats.liquid +19 -0
- package/dist/render/templates/partials/_qa.liquid +13 -0
- package/dist/render/templates/partials/_screenshot.liquid +15 -0
- package/dist/render/templates/partials/_session-cards.liquid +30 -0
- package/dist/render/templates/partials/_session-header.liquid +39 -0
- package/dist/render/templates/partials/_session-sidebar.liquid +30 -0
- package/dist/render/templates/partials/_skills.liquid +12 -0
- package/dist/render/templates/partials/_source-breakdown.liquid +22 -0
- package/dist/render/templates/partials/_stats.liquid +38 -0
- package/dist/render/templates/partials/_work-timeline.liquid +7 -0
- package/dist/render/templates/project.liquid +7 -4
- package/dist/render/templates/radar/portfolio.liquid +223 -0
- package/dist/render/templates/radar/project.liquid +278 -0
- package/dist/render/templates/radar/session.liquid +300 -0
- package/dist/render/templates/radar/styles.css +1055 -0
- package/dist/render/templates/showcase/portfolio.liquid +221 -0
- package/dist/render/templates/showcase/project.liquid +237 -0
- package/dist/render/templates/showcase/session.liquid +210 -0
- package/dist/render/templates/showcase/styles.css +1284 -0
- package/dist/render/templates/signal/portfolio.liquid +217 -0
- package/dist/render/templates/signal/project.liquid +278 -0
- package/dist/render/templates/signal/session.liquid +282 -0
- package/dist/render/templates/signal/styles.css +1401 -0
- package/dist/render/templates/strata/portfolio.liquid +180 -0
- package/dist/render/templates/strata/project.liquid +282 -0
- package/dist/render/templates/strata/session.liquid +261 -0
- package/dist/render/templates/strata/styles.css +1354 -0
- package/dist/render/templates/styles.css +1190 -0
- package/dist/render/templates/terminal/portfolio.liquid +102 -0
- package/dist/render/templates/terminal/project.liquid +161 -0
- package/dist/render/templates/terminal/session.liquid +145 -0
- package/dist/render/templates/terminal/styles.css +497 -0
- package/dist/render/templates/verdant/portfolio.liquid +321 -0
- package/dist/render/templates/verdant/project.liquid +309 -0
- package/dist/render/templates/verdant/session.liquid +237 -0
- package/dist/render/templates/verdant/styles.css +1261 -0
- package/dist/render/templates/zen/portfolio.liquid +124 -0
- package/dist/render/templates/zen/project.liquid +187 -0
- package/dist/render/templates/zen/session.liquid +203 -0
- package/dist/render/templates/zen/styles.css +1211 -0
- package/dist/render/templates.js +90 -0
- package/dist/routes/auth.js +7 -3
- package/dist/routes/context.js +17 -10
- package/dist/routes/delete.js +195 -0
- package/dist/routes/enhance.js +57 -40
- package/dist/routes/export.js +14 -4
- package/dist/routes/github.js +254 -0
- package/dist/routes/index.js +2 -0
- package/dist/routes/portfolio-render-data.js +160 -0
- package/dist/routes/preview.js +555 -108
- package/dist/routes/projects.js +61 -24
- package/dist/routes/publish.js +320 -31
- package/dist/routes/settings.js +194 -1
- package/dist/routes/sse.js +9 -0
- package/dist/search.js +6 -0
- package/dist/server.js +11 -3
- package/dist/settings.js +112 -9
- package/package.json +3 -4
- package/dist/public/assets/index-CC9G8EF1.js +0 -21
- package/dist/public/assets/index-Dalqz2mC.css +0 -1
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock data for template previews.
|
|
3
|
+
*
|
|
4
|
+
* Used by the template browser to render Liquid templates with
|
|
5
|
+
* representative data when no static mockup HTML exists.
|
|
6
|
+
*/
|
|
7
|
+
export function getMockPortfolioData() {
|
|
8
|
+
return {
|
|
9
|
+
user: {
|
|
10
|
+
username: 'alexchen',
|
|
11
|
+
accent: '#084471',
|
|
12
|
+
displayName: 'Alex Chen',
|
|
13
|
+
bio: 'Full-stack engineer who ships fast and thinks deeply. I build tools that make developers more productive — from CLI utilities to AI-powered code assistants.',
|
|
14
|
+
location: 'San Francisco, CA',
|
|
15
|
+
status: 'active',
|
|
16
|
+
email: 'alex@example.com',
|
|
17
|
+
phone: '+1 (555) 123-4567',
|
|
18
|
+
photoUrl: '/preview/template-assets/headshot-man-1-400.jpg',
|
|
19
|
+
githubUrl: 'https://github.com/alexchen',
|
|
20
|
+
linkedinUrl: 'https://linkedin.com/in/alexchen',
|
|
21
|
+
twitterHandle: 'alexchendev',
|
|
22
|
+
websiteUrl: 'https://alexchen.dev',
|
|
23
|
+
resumeUrl: '#',
|
|
24
|
+
},
|
|
25
|
+
projects: [
|
|
26
|
+
{
|
|
27
|
+
slug: 'budgetwise',
|
|
28
|
+
title: 'BudgetWise',
|
|
29
|
+
narrative: 'A personal finance tracker with AI-powered categorization. Built the Prisma schema, REST API, and React dashboard in a single sprint using Claude as a coding partner.',
|
|
30
|
+
totalSessions: 8,
|
|
31
|
+
totalLoc: 3200,
|
|
32
|
+
totalDurationMinutes: 480,
|
|
33
|
+
totalAgentDurationMinutes: 2064,
|
|
34
|
+
totalFilesChanged: 45,
|
|
35
|
+
skills: ['TypeScript', 'React', 'Prisma', 'Node.js'],
|
|
36
|
+
sourceCounts: [{ tool: 'claude', count: 5 }, { tool: 'cursor', count: 3 }],
|
|
37
|
+
publishedCount: 6,
|
|
38
|
+
sessions: [
|
|
39
|
+
{ date: '2026-02-10T10:00:00Z', loc: 420, durationMinutes: 65 },
|
|
40
|
+
{ date: '2026-02-15T14:00:00Z', loc: 680, durationMinutes: 90 },
|
|
41
|
+
{ date: '2026-02-22T09:00:00Z', loc: 350, durationMinutes: 55 },
|
|
42
|
+
{ date: '2026-03-01T11:00:00Z', loc: 550, durationMinutes: 75 },
|
|
43
|
+
{ date: '2026-03-08T16:00:00Z', loc: 280, durationMinutes: 40 },
|
|
44
|
+
{ date: '2026-03-15T10:00:00Z', loc: 400, durationMinutes: 60 },
|
|
45
|
+
{ date: '2026-03-22T13:00:00Z', loc: 320, durationMinutes: 50 },
|
|
46
|
+
{ date: '2026-04-02T09:00:00Z', loc: 200, durationMinutes: 45 },
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
slug: 'shellhook',
|
|
51
|
+
title: 'ShellHook',
|
|
52
|
+
narrative: 'Git hooks manager that auto-installs and shares hooks across teams. Zero config, works with any shell, supports pre-commit, pre-push, and custom triggers.',
|
|
53
|
+
totalSessions: 5,
|
|
54
|
+
totalLoc: 1800,
|
|
55
|
+
totalDurationMinutes: 300,
|
|
56
|
+
totalAgentDurationMinutes: 900,
|
|
57
|
+
totalFilesChanged: 22,
|
|
58
|
+
skills: ['Rust', 'Shell', 'Git'],
|
|
59
|
+
sourceCounts: [{ tool: 'claude', count: 3 }, { tool: 'cursor', count: 2 }],
|
|
60
|
+
publishedCount: 4,
|
|
61
|
+
sessions: [
|
|
62
|
+
{ date: '2026-02-18T11:00:00Z', loc: 380, durationMinutes: 70 },
|
|
63
|
+
{ date: '2026-03-03T15:00:00Z', loc: 450, durationMinutes: 65 },
|
|
64
|
+
{ date: '2026-03-12T10:00:00Z', loc: 320, durationMinutes: 55 },
|
|
65
|
+
{ date: '2026-03-28T14:00:00Z', loc: 400, durationMinutes: 60 },
|
|
66
|
+
{ date: '2026-04-05T09:00:00Z', loc: 250, durationMinutes: 50 },
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
slug: 'pixelboard',
|
|
71
|
+
title: 'PixelBoard',
|
|
72
|
+
narrative: 'Collaborative pixel art canvas with real-time sync. WebSocket-based with conflict-free replicated data types for seamless multi-user editing.',
|
|
73
|
+
totalSessions: 12,
|
|
74
|
+
totalLoc: 4500,
|
|
75
|
+
totalDurationMinutes: 720,
|
|
76
|
+
totalAgentDurationMinutes: 2160,
|
|
77
|
+
totalFilesChanged: 60,
|
|
78
|
+
skills: ['TypeScript', 'WebSocket', 'Canvas API', 'Redis'],
|
|
79
|
+
sourceCounts: [{ tool: 'claude', count: 8 }, { tool: 'cursor', count: 4 }],
|
|
80
|
+
publishedCount: 8,
|
|
81
|
+
sessions: [
|
|
82
|
+
{ date: '2026-02-08T09:00:00Z', loc: 300, durationMinutes: 50 },
|
|
83
|
+
{ date: '2026-02-12T14:00:00Z', loc: 420, durationMinutes: 65 },
|
|
84
|
+
{ date: '2026-02-19T11:00:00Z', loc: 380, durationMinutes: 55 },
|
|
85
|
+
{ date: '2026-02-26T16:00:00Z', loc: 500, durationMinutes: 80 },
|
|
86
|
+
{ date: '2026-03-05T10:00:00Z', loc: 350, durationMinutes: 60 },
|
|
87
|
+
{ date: '2026-03-10T13:00:00Z', loc: 280, durationMinutes: 45 },
|
|
88
|
+
{ date: '2026-03-17T09:00:00Z', loc: 450, durationMinutes: 70 },
|
|
89
|
+
{ date: '2026-03-22T15:00:00Z', loc: 520, durationMinutes: 75 },
|
|
90
|
+
{ date: '2026-03-29T11:00:00Z', loc: 400, durationMinutes: 60 },
|
|
91
|
+
{ date: '2026-04-01T14:00:00Z', loc: 350, durationMinutes: 55 },
|
|
92
|
+
{ date: '2026-04-03T10:00:00Z', loc: 300, durationMinutes: 50 },
|
|
93
|
+
{ date: '2026-04-05T16:00:00Z', loc: 250, durationMinutes: 55 },
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
totalDurationMinutes: 1500,
|
|
98
|
+
totalAgentDurationMinutes: 5124,
|
|
99
|
+
totalLoc: 9500,
|
|
100
|
+
totalSessions: 25,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
export function getMockProjectData() {
|
|
104
|
+
return {
|
|
105
|
+
user: { username: 'alexchen', accent: '#084471' },
|
|
106
|
+
project: {
|
|
107
|
+
slug: 'budgetwise',
|
|
108
|
+
title: 'BudgetWise',
|
|
109
|
+
narrative: 'A personal finance tracker with AI-powered transaction categorization. What started as a weekend project grew into a full-stack app with a Prisma-backed API, React dashboard, and ML-powered category suggestions. The key insight was treating each transaction as a classification problem — the model learns from your corrections and gets smarter over time.',
|
|
110
|
+
repoUrl: 'https://github.com/alexchen/budgetwise',
|
|
111
|
+
projectUrl: 'https://budgetwise.app',
|
|
112
|
+
timeline: [],
|
|
113
|
+
skills: ['TypeScript', 'React', 'Prisma', 'Node.js', 'PostgreSQL', 'TailwindCSS'],
|
|
114
|
+
totalSessions: 8,
|
|
115
|
+
totalLoc: 3200,
|
|
116
|
+
totalDurationMinutes: 480,
|
|
117
|
+
totalAgentDurationMinutes: 2064,
|
|
118
|
+
totalFilesChanged: 45,
|
|
119
|
+
totalTokens: 1250000,
|
|
120
|
+
},
|
|
121
|
+
sessions: [
|
|
122
|
+
{
|
|
123
|
+
token: 'session-1',
|
|
124
|
+
slug: 'prisma-schema-setup',
|
|
125
|
+
title: 'Set up Prisma schema and migrations',
|
|
126
|
+
devTake: 'Got the data model right on the first try — accounts, transactions, categories, and budget rules.',
|
|
127
|
+
durationMinutes: 65,
|
|
128
|
+
wallClockMinutes: 87,
|
|
129
|
+
turns: 18,
|
|
130
|
+
locChanged: 420,
|
|
131
|
+
linesAdded: 350,
|
|
132
|
+
linesDeleted: 70,
|
|
133
|
+
filesChanged: 8,
|
|
134
|
+
skills: ['Prisma', 'PostgreSQL'],
|
|
135
|
+
recordedAt: '2026-03-15T10:00:00Z',
|
|
136
|
+
sourceTool: 'claude',
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
token: 'session-2',
|
|
140
|
+
slug: 'rest-api-endpoints',
|
|
141
|
+
title: 'Build REST API with Express',
|
|
142
|
+
devTake: 'CRUD endpoints for transactions and categories. Added pagination and filtering.',
|
|
143
|
+
durationMinutes: 90,
|
|
144
|
+
wallClockMinutes: 115,
|
|
145
|
+
turns: 24,
|
|
146
|
+
locChanged: 680,
|
|
147
|
+
linesAdded: 520,
|
|
148
|
+
linesDeleted: 160,
|
|
149
|
+
filesChanged: 12,
|
|
150
|
+
skills: ['TypeScript', 'Node.js'],
|
|
151
|
+
recordedAt: '2026-03-16T14:00:00Z',
|
|
152
|
+
sourceTool: 'claude',
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
token: 'session-3',
|
|
156
|
+
slug: 'react-dashboard',
|
|
157
|
+
title: 'React dashboard with charts',
|
|
158
|
+
devTake: 'Built the spending breakdown and monthly trend charts. Used Recharts for visualization.',
|
|
159
|
+
durationMinutes: 75,
|
|
160
|
+
wallClockMinutes: 92,
|
|
161
|
+
turns: 20,
|
|
162
|
+
locChanged: 550,
|
|
163
|
+
linesAdded: 480,
|
|
164
|
+
linesDeleted: 70,
|
|
165
|
+
filesChanged: 10,
|
|
166
|
+
skills: ['React', 'TailwindCSS'],
|
|
167
|
+
recordedAt: '2026-03-17T09:00:00Z',
|
|
168
|
+
sourceTool: 'claude',
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
token: 'session-4',
|
|
172
|
+
slug: 'ai-categorization',
|
|
173
|
+
title: 'AI-powered transaction categorization',
|
|
174
|
+
devTake: 'The classifier learns from user corrections. Accuracy jumped from 60% to 92% after 50 labeled transactions.',
|
|
175
|
+
durationMinutes: 120,
|
|
176
|
+
wallClockMinutes: 155,
|
|
177
|
+
turns: 35,
|
|
178
|
+
locChanged: 800,
|
|
179
|
+
linesAdded: 600,
|
|
180
|
+
linesDeleted: 200,
|
|
181
|
+
filesChanged: 15,
|
|
182
|
+
skills: ['TypeScript', 'ML'],
|
|
183
|
+
recordedAt: '2026-03-18T11:00:00Z',
|
|
184
|
+
sourceTool: 'claude',
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
sessionBaseUrl: '#',
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/** Full session objects for chart rendering — includes children for multi-agent display. */
|
|
191
|
+
export function getMockFullSessions() {
|
|
192
|
+
return [
|
|
193
|
+
{
|
|
194
|
+
id: 'session-1', slug: 'prisma-schema-setup', title: 'Set up Prisma schema and migrations',
|
|
195
|
+
date: '2026-03-15T10:00:00Z', durationMinutes: 65, wallClockMinutes: 87, turns: 18,
|
|
196
|
+
linesOfCode: 420, filesChanged: 8, status: 'enhanced', source: 'claude',
|
|
197
|
+
projectName: 'BudgetWise', skills: ['Prisma', 'PostgreSQL'], rawLog: [],
|
|
198
|
+
children: [
|
|
199
|
+
{ sessionId: 'sub-1a', role: 'backend-dev', durationMinutes: 40, linesOfCode: 280, date: '2026-03-15T10:05:00Z' },
|
|
200
|
+
{ sessionId: 'sub-1b', role: 'code-reviewer', durationMinutes: 15, linesOfCode: 0, date: '2026-03-15T10:30:00Z' },
|
|
201
|
+
],
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
id: 'session-2', slug: 'rest-api-endpoints', title: 'Build REST API with Express',
|
|
205
|
+
date: '2026-03-16T14:00:00Z', durationMinutes: 90, wallClockMinutes: 115, turns: 24,
|
|
206
|
+
linesOfCode: 680, filesChanged: 12, status: 'enhanced', source: 'claude',
|
|
207
|
+
projectName: 'BudgetWise', skills: ['TypeScript', 'Node.js'], rawLog: [],
|
|
208
|
+
children: [
|
|
209
|
+
{ sessionId: 'sub-2a', role: 'backend-dev', durationMinutes: 55, linesOfCode: 450, date: '2026-03-16T14:05:00Z' },
|
|
210
|
+
{ sessionId: 'sub-2b', role: 'qa-engineer', durationMinutes: 20, linesOfCode: 120, date: '2026-03-16T14:40:00Z' },
|
|
211
|
+
{ sessionId: 'sub-2c', role: 'security-engineer', durationMinutes: 10, linesOfCode: 30, date: '2026-03-16T15:00:00Z' },
|
|
212
|
+
],
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
id: 'session-3', slug: 'react-dashboard', title: 'React dashboard with charts',
|
|
216
|
+
date: '2026-03-17T09:00:00Z', durationMinutes: 75, wallClockMinutes: 92, turns: 20,
|
|
217
|
+
linesOfCode: 550, filesChanged: 10, status: 'enhanced', source: 'claude',
|
|
218
|
+
projectName: 'BudgetWise', skills: ['React', 'TailwindCSS'], rawLog: [],
|
|
219
|
+
children: [
|
|
220
|
+
{ sessionId: 'sub-3a', role: 'frontend-dev', durationMinutes: 50, linesOfCode: 380, date: '2026-03-17T09:05:00Z' },
|
|
221
|
+
{ sessionId: 'sub-3b', role: 'ux-designer', durationMinutes: 15, linesOfCode: 80, date: '2026-03-17T09:35:00Z' },
|
|
222
|
+
],
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
id: 'session-4', slug: 'ai-categorization', title: 'AI-powered transaction categorization',
|
|
226
|
+
date: '2026-03-18T11:00:00Z', durationMinutes: 120, wallClockMinutes: 155, turns: 35,
|
|
227
|
+
linesOfCode: 800, filesChanged: 15, status: 'enhanced', source: 'claude',
|
|
228
|
+
projectName: 'BudgetWise', skills: ['TypeScript', 'ML'], rawLog: [],
|
|
229
|
+
children: [
|
|
230
|
+
{ sessionId: 'sub-4a', role: 'backend-dev', durationMinutes: 70, linesOfCode: 500, date: '2026-03-18T11:05:00Z' },
|
|
231
|
+
{ sessionId: 'sub-4b', role: 'qa-engineer', durationMinutes: 25, linesOfCode: 150, date: '2026-03-18T11:50:00Z' },
|
|
232
|
+
{ sessionId: 'sub-4c', role: 'code-reviewer', durationMinutes: 15, linesOfCode: 0, date: '2026-03-18T12:15:00Z' },
|
|
233
|
+
],
|
|
234
|
+
},
|
|
235
|
+
];
|
|
236
|
+
}
|
|
237
|
+
export function getMockProjectArc() {
|
|
238
|
+
return [
|
|
239
|
+
{ phase: 1, title: 'Foundation', description: 'Set up Prisma schema, database migrations, and seed data. Established the core data model for accounts, transactions, and categories.' },
|
|
240
|
+
{ phase: 2, title: 'API & Data Layer', description: 'Built RESTful endpoints with Express. Added pagination, filtering, and input validation. Connected to PostgreSQL via Prisma client.' },
|
|
241
|
+
{ phase: 3, title: 'Frontend Dashboard', description: 'Created React components for spending breakdown, monthly trends, and budget tracking. Used Recharts for interactive visualizations.' },
|
|
242
|
+
{ phase: 4, title: 'AI Categorization', description: 'Trained a transaction classifier that learns from user corrections. Achieved 92% accuracy after 50 labeled examples using embeddings-based similarity.' },
|
|
243
|
+
];
|
|
244
|
+
}
|
|
245
|
+
export function getMockSessionData() {
|
|
246
|
+
return {
|
|
247
|
+
user: { username: 'alexchen', accent: '#084471' },
|
|
248
|
+
projectSlug: 'budgetwise',
|
|
249
|
+
session: {
|
|
250
|
+
token: 'session-1',
|
|
251
|
+
title: 'Set up Prisma schema and migrations',
|
|
252
|
+
devTake: 'Got the data model right on the first try — accounts, transactions, categories, and budget rules. The key was thinking about the relationships upfront instead of iterating.',
|
|
253
|
+
context: 'Starting the BudgetWise project from scratch. Need a solid data foundation before building the API.',
|
|
254
|
+
narrative: 'Started by mapping out the core entities: Users own Accounts, Accounts have Transactions, Transactions belong to Categories, and Categories can be nested. Added a BudgetRule model to track monthly spending limits per category. The Prisma schema came together cleanly — the main design decision was whether to use a single Transaction table with a type enum or separate Income/Expense tables. Went with the enum approach for query simplicity.',
|
|
255
|
+
durationMinutes: 65,
|
|
256
|
+
wallClockMinutes: 87,
|
|
257
|
+
turns: 18,
|
|
258
|
+
filesChanged: 8,
|
|
259
|
+
locChanged: 420,
|
|
260
|
+
skills: ['Prisma', 'PostgreSQL', 'TypeScript'],
|
|
261
|
+
beats: [
|
|
262
|
+
{ stepNumber: 1, title: 'Project scaffolding', body: 'Initialized the repo with TypeScript, ESLint, and Prisma CLI.' },
|
|
263
|
+
{ stepNumber: 2, title: 'Core schema design', body: 'Defined User, Account, Transaction, Category, and BudgetRule models with proper relations.' },
|
|
264
|
+
{ stepNumber: 3, title: 'Migration and seed', body: 'Generated the initial migration and wrote seed data for testing.' },
|
|
265
|
+
{ stepNumber: 4, title: 'Type generation', body: 'Generated TypeScript types from the Prisma schema for type-safe queries.' },
|
|
266
|
+
],
|
|
267
|
+
qaPairs: [
|
|
268
|
+
{ question: 'Why Prisma over raw SQL?', answer: 'Type safety and migration management. The generated client catches schema drift at compile time.' },
|
|
269
|
+
{ question: 'How do nested categories work?', answer: 'Self-referential relation — each Category has an optional parentId. Queries use recursive CTEs for the full tree.' },
|
|
270
|
+
],
|
|
271
|
+
highlights: [
|
|
272
|
+
'Clean separation between financial and budget models',
|
|
273
|
+
'Self-referential categories enable unlimited nesting depth',
|
|
274
|
+
'Seed script generates realistic test data',
|
|
275
|
+
],
|
|
276
|
+
toolBreakdown: [
|
|
277
|
+
{ tool: 'Read', count: 15 },
|
|
278
|
+
{ tool: 'Write', count: 12 },
|
|
279
|
+
{ tool: 'Edit', count: 8 },
|
|
280
|
+
{ tool: 'Bash', count: 6 },
|
|
281
|
+
{ tool: 'Grep', count: 4 },
|
|
282
|
+
],
|
|
283
|
+
topFiles: [
|
|
284
|
+
{ path: 'prisma/schema.prisma', additions: 120, deletions: 0 },
|
|
285
|
+
{ path: 'src/db/seed.ts', additions: 85, deletions: 0 },
|
|
286
|
+
{ path: 'src/types/models.ts', additions: 65, deletions: 0 },
|
|
287
|
+
{ path: 'prisma/migrations/001_init/migration.sql', additions: 95, deletions: 0 },
|
|
288
|
+
{ path: 'src/db/client.ts', additions: 25, deletions: 0 },
|
|
289
|
+
],
|
|
290
|
+
recordedAt: '2026-03-15T10:00:00Z',
|
|
291
|
+
sourceTool: 'claude',
|
|
292
|
+
template: 'case-study',
|
|
293
|
+
agentSummary: {
|
|
294
|
+
is_orchestrated: true,
|
|
295
|
+
agents: [
|
|
296
|
+
{ role: 'backend-dev', duration_minutes: 35, loc_changed: 250 },
|
|
297
|
+
{ role: 'code-reviewer', duration_minutes: 18, loc_changed: 0 },
|
|
298
|
+
{ role: 'qa-engineer', duration_minutes: 12, loc_changed: 80 },
|
|
299
|
+
],
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
<div class="heyiam-portfolio aurora" data-render-version="2" data-template="aurora" data-username="{{ user.username }}">
|
|
2
|
+
|
|
3
|
+
{% if hasProfile %}
|
|
4
|
+
{%- comment -%} Aurora Header {%- endcomment -%}
|
|
5
|
+
<header class="aurora-header" role="banner">
|
|
6
|
+
<div class="aurora-hero fade-up">
|
|
7
|
+
<div class="hero-photo-wrap">
|
|
8
|
+
<img src="{{ user.photoUrl }}" alt="{{ user.displayName }}" class="hero-photo portfolio-photo" data-portfolio-field="photoBase64"{% unless user.photoUrl %} data-portfolio-empty="true"{% endunless %}>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="aurora-hero-content">
|
|
11
|
+
{% if user.displayName != blank %}
|
|
12
|
+
<h1 data-portfolio-field="displayName">{{ user.displayName }}</h1>
|
|
13
|
+
{% endif %}
|
|
14
|
+
{% if user.location %}
|
|
15
|
+
<div class="aurora-hero-location portfolio-location">
|
|
16
|
+
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z" stroke-linecap="round" stroke-linejoin="round"/><circle cx="12" cy="9" r="2.5"/></svg>
|
|
17
|
+
<span data-portfolio-field="location">{{ user.location }}</span>
|
|
18
|
+
</div>
|
|
19
|
+
{% endif %}
|
|
20
|
+
{% if user.bio %}
|
|
21
|
+
<p class="aurora-hero-bio portfolio-bio" data-portfolio-field="bio">{{ user.bio }}</p>
|
|
22
|
+
{% endif %}
|
|
23
|
+
<ul class="aurora-hero-links" aria-label="Contact and social links">
|
|
24
|
+
<li data-portfolio-field="email"{% unless user.email %} data-portfolio-empty="true"{% endunless %}><a href="{% if user.email %}mailto:{{ user.email }}{% endif %}"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m2 4 10 8 10-8"/></svg><span data-portfolio-text>{{ user.email }}</span></a></li>
|
|
25
|
+
<li data-portfolio-field="linkedinUrl"{% unless user.linkedinUrl %} data-portfolio-empty="true"{% endunless %}><a href="{% if user.linkedinUrl %}{{ user.linkedinUrl }}{% endif %}" target="_blank" rel="noopener"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M20.5 2h-17A1.5 1.5 0 002 3.5v17A1.5 1.5 0 003.5 22h17a1.5 1.5 0 001.5-1.5v-17A1.5 1.5 0 0020.5 2zM8 19H5v-9h3zM6.5 8.25A1.75 1.75 0 118.3 6.5a1.78 1.78 0 01-1.8 1.75zM19 19h-3v-4.74c0-1.42-.6-1.93-1.38-1.93A1.74 1.74 0 0013 14.19V19h-3v-9h2.9v1.3a3.11 3.11 0 012.7-1.4c1.55 0 3.36.86 3.36 3.66z"/></svg>LinkedIn</a></li>
|
|
26
|
+
<li data-portfolio-field="githubUrl"{% unless user.githubUrl %} data-portfolio-empty="true"{% endunless %}><a href="{% if user.githubUrl %}{{ user.githubUrl }}{% endif %}" target="_blank" rel="noopener"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>GitHub</a></li>
|
|
27
|
+
<li data-portfolio-field="twitterHandle"{% unless user.twitterHandle %} data-portfolio-empty="true"{% endunless %}><a href="{% if user.twitterHandle %}https://x.com/{{ user.twitterHandle }}{% endif %}" target="_blank" rel="noopener"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg><span data-portfolio-text>{% if user.twitterHandle %}@{{ user.twitterHandle }}{% endif %}</span></a></li>
|
|
28
|
+
<li data-portfolio-field="websiteUrl"{% unless user.websiteUrl %} data-portfolio-empty="true"{% endunless %}><a href="{% if user.websiteUrl %}{{ user.websiteUrl }}{% endif %}" target="_blank" rel="noopener"><span data-portfolio-text>{{ user.websiteUrl | stripProtocol }}</span></a></li>
|
|
29
|
+
{% if user.resumeUrl %}
|
|
30
|
+
<li><a href="{{ user.resumeUrl }}" download><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="12" y1="18" x2="12" y2="12"/><polyline points="9 15 12 18 15 15"/></svg>Resume (PDF)</a></li>
|
|
31
|
+
{% endif %}
|
|
32
|
+
</ul>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div class="aurora-hero-stats fade-up">
|
|
37
|
+
<div class="aurora-hero-stats-inner">
|
|
38
|
+
<span><strong>{{ projects.size }}</strong> projects</span>
|
|
39
|
+
<span><strong>{{ totalSessions }}</strong> sessions</span>
|
|
40
|
+
<span><strong>{{ totalLoc | formatLoc }}</strong> LOC</span>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</header>
|
|
44
|
+
{% endif %}
|
|
45
|
+
|
|
46
|
+
{%- comment -%} Stats Grid {%- endcomment -%}
|
|
47
|
+
<section class="aurora-stats" aria-label="Portfolio statistics">
|
|
48
|
+
<div class="aurora-stat fade-up">
|
|
49
|
+
<div class="aurora-stat-number">{{ projects.size }}</div>
|
|
50
|
+
<div class="aurora-stat-label">Projects</div>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="aurora-stat fade-up">
|
|
53
|
+
<div class="aurora-stat-number">{{ totalSessions }}</div>
|
|
54
|
+
<div class="aurora-stat-label">Sessions</div>
|
|
55
|
+
</div>
|
|
56
|
+
<div class="aurora-stat fade-up">
|
|
57
|
+
<div class="aurora-stat-number">{{ totalLoc | formatLoc }}</div>
|
|
58
|
+
<div class="aurora-stat-label">Lines Changed</div>
|
|
59
|
+
</div>
|
|
60
|
+
{% if efficiencyMultiplier %}
|
|
61
|
+
<div class="aurora-stat fade-up">
|
|
62
|
+
<div class="aurora-stat-number">{{ efficiencyMultiplier }}</div>
|
|
63
|
+
<div class="aurora-stat-label">Leverage</div>
|
|
64
|
+
</div>
|
|
65
|
+
{% else %}
|
|
66
|
+
<div class="aurora-stat fade-up">
|
|
67
|
+
<div class="aurora-stat-number">{{ totalDurationMinutes | formatDuration }}</div>
|
|
68
|
+
<div class="aurora-stat-label">Total Time</div>
|
|
69
|
+
</div>
|
|
70
|
+
{% endif %}
|
|
71
|
+
</section>
|
|
72
|
+
|
|
73
|
+
{%- comment -%} Leverage {%- endcomment -%}
|
|
74
|
+
{% if efficiencyMultiplier %}
|
|
75
|
+
<section class="aurora-leverage-section fade-up" aria-label="AI leverage" role="figure">
|
|
76
|
+
<div class="aurora-leverage-section__multi">{{ efficiencyMultiplier }}</div>
|
|
77
|
+
<div class="aurora-leverage-section__context">{{ totalDurationMinutes | formatDuration }} you · <strong>{{ totalAgentDurationMinutes | formatDuration }}</strong> agents</div>
|
|
78
|
+
{% assign totalCombined = totalDurationMinutes | plus: totalAgentDurationMinutes %}
|
|
79
|
+
{% if totalCombined > 0 %}
|
|
80
|
+
{% assign humanPct = totalDurationMinutes | times: 100 | divided_by: totalCombined | round %}
|
|
81
|
+
{% assign agentPct = 100 | minus: humanPct %}
|
|
82
|
+
<div class="aurora-leverage-section__bar"><div class="aurora-leverage-section__bar-human" style="width:{{ humanPct }}%"></div><div class="aurora-leverage-section__bar-agent" style="width:{{ agentPct }}%"></div></div>
|
|
83
|
+
{% endif %}
|
|
84
|
+
</section>
|
|
85
|
+
{% endif %}
|
|
86
|
+
|
|
87
|
+
{%- comment -%} Projects {%- endcomment -%}
|
|
88
|
+
{% if projects.size > 0 %}
|
|
89
|
+
<section class="aurora-section" aria-label="Projects">
|
|
90
|
+
<h2 class="aurora-section-title fade-up">Projects</h2>
|
|
91
|
+
<div class="aurora-projects">
|
|
92
|
+
{% for p in projects %}
|
|
93
|
+
<a href="/{{ user.username }}/{{ p.slug }}" class="aurora-card project-card fade-up">
|
|
94
|
+
<div class="aurora-card-header">
|
|
95
|
+
<h3>{{ p.title }}</h3>
|
|
96
|
+
</div>
|
|
97
|
+
{% if p.narrative %}
|
|
98
|
+
<p class="aurora-card-narrative">{{ p.narrative | truncate: 120 }}</p>
|
|
99
|
+
{% endif %}
|
|
100
|
+
<div class="aurora-card-stats">
|
|
101
|
+
<span>{{ p.totalSessions }} sessions</span>
|
|
102
|
+
<span>{{ p.totalDurationMinutes | formatDuration }}</span>
|
|
103
|
+
<span>{{ p.totalLoc | localeNumber }} LOC</span>
|
|
104
|
+
</div>
|
|
105
|
+
{% if p.skills.size > 0 %}
|
|
106
|
+
<div class="aurora-tags">
|
|
107
|
+
{% for skill in p.skills %}
|
|
108
|
+
<span class="aurora-tag">{{ skill }}</span>
|
|
109
|
+
{% endfor %}
|
|
110
|
+
</div>
|
|
111
|
+
{% endif %}
|
|
112
|
+
{% if p.sourceCounts.size > 0 %}
|
|
113
|
+
{% assign pTotalSrc = 0 %}
|
|
114
|
+
{% for src in p.sourceCounts %}{% assign pTotalSrc = pTotalSrc | plus: src.count %}{% endfor %}
|
|
115
|
+
{% if pTotalSrc > 0 %}
|
|
116
|
+
<div class="aurora-source-bar">
|
|
117
|
+
<div class="aurora-source-track" role="img" aria-label="Source breakdown for {{ p.title }}">
|
|
118
|
+
{% for src in p.sourceCounts %}
|
|
119
|
+
{% assign srcPct = src.count | times: 100.0 | divided_by: pTotalSrc | round %}
|
|
120
|
+
<div class="aurora-source-fill-{{ src.tool | downcase | replace: ' ', '-' }}" style="width: {{ srcPct }}%"></div>
|
|
121
|
+
{% endfor %}
|
|
122
|
+
</div>
|
|
123
|
+
<div class="aurora-source-labels">
|
|
124
|
+
{% for src in p.sourceCounts %}
|
|
125
|
+
{% assign srcPct = src.count | times: 100.0 | divided_by: pTotalSrc | round %}
|
|
126
|
+
<span><span class="aurora-source-dot aurora-source-dot--{{ src.tool | downcase | replace: ' ', '-' }}"></span>{{ src.tool }} {{ srcPct }}%</span>
|
|
127
|
+
{% endfor %}
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
{% endif %}
|
|
131
|
+
{% endif %}
|
|
132
|
+
</a>
|
|
133
|
+
{% endfor %}
|
|
134
|
+
</div>
|
|
135
|
+
</section>
|
|
136
|
+
{% endif %}
|
|
137
|
+
|
|
138
|
+
{%- comment -%} Activity Heatmap {%- endcomment -%}
|
|
139
|
+
{% if activityByDay.size > 0 %}
|
|
140
|
+
<section class="aurora-activity fade-up" aria-label="Activity overview">
|
|
141
|
+
<h2 class="aurora-section-title">Activity</h2>
|
|
142
|
+
<div class="aurora-activity-grid">
|
|
143
|
+
<div class="aurora-activity-rows" role="img" aria-label="Activity heatmap showing coding sessions over time">
|
|
144
|
+
{% for day in activityByDay %}
|
|
145
|
+
{% assign mod = forloop.index0 | modulo: 5 %}
|
|
146
|
+
{% if mod == 0 %}<div class="aurora-activity-week">{% endif %}
|
|
147
|
+
{% if day.count >= 4 %}{% assign level = 4 %}
|
|
148
|
+
{% elsif day.count >= 3 %}{% assign level = 3 %}
|
|
149
|
+
{% elsif day.count >= 2 %}{% assign level = 2 %}
|
|
150
|
+
{% elsif day.count >= 1 %}{% assign level = 1 %}
|
|
151
|
+
{% else %}{% assign level = 0 %}{% endif %}
|
|
152
|
+
<div class="aurora-activity-cell" data-level="{{ level }}" title="{{ day.date }}: {{ day.count }} sessions"></div>
|
|
153
|
+
{% assign mod1 = forloop.index | modulo: 5 %}
|
|
154
|
+
{% if mod1 == 0 or forloop.last %}</div>{% endif %}
|
|
155
|
+
{% endfor %}
|
|
156
|
+
</div>
|
|
157
|
+
<div class="aurora-activity-legend">
|
|
158
|
+
<span>Less</span>
|
|
159
|
+
<div class="aurora-activity-legend-cell" data-level="0"></div>
|
|
160
|
+
<div class="aurora-activity-legend-cell" data-level="1"></div>
|
|
161
|
+
<div class="aurora-activity-legend-cell" data-level="2"></div>
|
|
162
|
+
<div class="aurora-activity-legend-cell" data-level="3"></div>
|
|
163
|
+
<div class="aurora-activity-legend-cell" data-level="4"></div>
|
|
164
|
+
<span>More</span>
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
167
|
+
</section>
|
|
168
|
+
{% endif %}
|
|
169
|
+
|
|
170
|
+
{%- comment -%} Skills Summary {%- endcomment -%}
|
|
171
|
+
{% if allSkills.size > 0 %}
|
|
172
|
+
<section class="aurora-skills-summary fade-up" aria-label="Top skills">
|
|
173
|
+
<h2 class="aurora-section-title">Top Skills</h2>
|
|
174
|
+
<div class="aurora-skills-grid">
|
|
175
|
+
{% for skill in topSkills %}
|
|
176
|
+
<div class="aurora-skill-card">
|
|
177
|
+
<span class="aurora-skill-name">{{ skill.name }}</span>
|
|
178
|
+
<span class="aurora-skill-count">{{ skill.projectCount }} project{% if skill.projectCount != 1 %}s{% endif %}</span>
|
|
179
|
+
</div>
|
|
180
|
+
{% endfor %}
|
|
181
|
+
</div>
|
|
182
|
+
</section>
|
|
183
|
+
{% endif %}
|
|
184
|
+
|
|
185
|
+
{%- comment -%} Footer {%- endcomment -%}
|
|
186
|
+
<footer class="aurora-footer">
|
|
187
|
+
<p>Built with <a href="https://heyi.am">heyi.am</a></p>
|
|
188
|
+
</footer>
|
|
189
|
+
|
|
190
|
+
{%- comment -%} Fade-up animation {%- endcomment -%}
|
|
191
|
+
|
|
192
|
+
</div>
|