heyiam 0.2.28 → 0.3.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.
Files changed (177) hide show
  1. package/README.md +45 -0
  2. package/dist/config.js +10 -1
  3. package/dist/db.js +1 -2
  4. package/dist/export.js +40 -25
  5. package/dist/format-utils.js +5 -0
  6. package/dist/index.js +168 -0
  7. package/dist/mount.js +300 -102
  8. package/dist/parsers/claude.js +2 -28
  9. package/dist/parsers/codex.js +2 -26
  10. package/dist/parsers/cursor.js +2 -26
  11. package/dist/parsers/duration.js +35 -0
  12. package/dist/parsers/gemini.js +2 -20
  13. package/dist/parsers/types.js +0 -1
  14. package/dist/public/assets/index-BZ65TU_Y.js +40 -0
  15. package/dist/public/assets/index-CqCaW2cb.css +1 -0
  16. package/dist/public/index.html +2 -2
  17. package/dist/redact.js +4 -104
  18. package/dist/render/build-render-data.js +9 -2
  19. package/dist/render/index.js +32 -5
  20. package/dist/render/liquid.js +147 -7
  21. package/dist/render/mock-data.js +303 -0
  22. package/dist/render/templates/aurora/portfolio.liquid +204 -0
  23. package/dist/render/templates/aurora/project.liquid +260 -0
  24. package/dist/render/templates/aurora/session.liquid +223 -0
  25. package/dist/render/templates/aurora/styles.css +1178 -0
  26. package/dist/render/templates/bauhaus/portfolio.liquid +179 -0
  27. package/dist/render/templates/bauhaus/project.liquid +300 -0
  28. package/dist/render/templates/bauhaus/session.liquid +333 -0
  29. package/dist/render/templates/bauhaus/styles.css +1641 -0
  30. package/dist/render/templates/blueprint/portfolio.liquid +167 -0
  31. package/dist/render/templates/blueprint/project.liquid +286 -0
  32. package/dist/render/templates/blueprint/session.liquid +248 -0
  33. package/dist/render/templates/blueprint/styles.css +1285 -0
  34. package/dist/render/templates/canvas/portfolio.liquid +215 -0
  35. package/dist/render/templates/canvas/project.liquid +235 -0
  36. package/dist/render/templates/canvas/session.liquid +223 -0
  37. package/dist/render/templates/canvas/styles.css +1436 -0
  38. package/dist/render/templates/carbon/portfolio.liquid +170 -0
  39. package/dist/render/templates/carbon/project.liquid +249 -0
  40. package/dist/render/templates/carbon/session.liquid +190 -0
  41. package/dist/render/templates/carbon/styles.css +1091 -0
  42. package/dist/render/templates/chalk/portfolio.liquid +199 -0
  43. package/dist/render/templates/chalk/project.liquid +245 -0
  44. package/dist/render/templates/chalk/session.liquid +215 -0
  45. package/dist/render/templates/chalk/styles.css +1157 -0
  46. package/dist/render/templates/circuit/portfolio.liquid +162 -0
  47. package/dist/render/templates/circuit/project.liquid +247 -0
  48. package/dist/render/templates/circuit/session.liquid +205 -0
  49. package/dist/render/templates/circuit/styles.css +1403 -0
  50. package/dist/render/templates/cosmos/portfolio.liquid +232 -0
  51. package/dist/render/templates/cosmos/project.liquid +327 -0
  52. package/dist/render/templates/cosmos/session.liquid +239 -0
  53. package/dist/render/templates/cosmos/styles.css +1151 -0
  54. package/dist/render/templates/daylight/portfolio.liquid +217 -0
  55. package/dist/render/templates/daylight/project.liquid +229 -0
  56. package/dist/render/templates/daylight/session.liquid +219 -0
  57. package/dist/render/templates/daylight/styles.css +1311 -0
  58. package/dist/render/templates/editorial/portfolio.liquid +126 -0
  59. package/dist/render/templates/editorial/project.liquid +202 -0
  60. package/dist/render/templates/editorial/session.liquid +171 -0
  61. package/dist/render/templates/editorial/styles.css +822 -0
  62. package/dist/render/templates/ember/portfolio.liquid +318 -0
  63. package/dist/render/templates/ember/project.liquid +232 -0
  64. package/dist/render/templates/ember/session.liquid +202 -0
  65. package/dist/render/templates/ember/styles.css +1283 -0
  66. package/dist/render/templates/glacier/portfolio.liquid +271 -0
  67. package/dist/render/templates/glacier/project.liquid +288 -0
  68. package/dist/render/templates/glacier/session.liquid +217 -0
  69. package/dist/render/templates/glacier/styles.css +1200 -0
  70. package/dist/render/templates/grid/portfolio.liquid +265 -0
  71. package/dist/render/templates/grid/project.liquid +306 -0
  72. package/dist/render/templates/grid/session.liquid +260 -0
  73. package/dist/render/templates/grid/styles.css +1441 -0
  74. package/dist/render/templates/kinetic/portfolio.liquid +170 -0
  75. package/dist/render/templates/kinetic/project.liquid +242 -0
  76. package/dist/render/templates/kinetic/session.liquid +228 -0
  77. package/dist/render/templates/kinetic/styles.css +944 -0
  78. package/dist/render/templates/meridian/portfolio.liquid +255 -0
  79. package/dist/render/templates/meridian/project.liquid +376 -0
  80. package/dist/render/templates/meridian/session.liquid +298 -0
  81. package/dist/render/templates/meridian/styles.css +1369 -0
  82. package/dist/render/templates/minimal/portfolio.liquid +71 -0
  83. package/dist/render/templates/minimal/project.liquid +154 -0
  84. package/dist/render/templates/minimal/session.liquid +140 -0
  85. package/dist/render/templates/minimal/styles.css +525 -0
  86. package/dist/render/templates/mono/portfolio.liquid +291 -0
  87. package/dist/render/templates/mono/project.liquid +275 -0
  88. package/dist/render/templates/mono/session.liquid +276 -0
  89. package/dist/render/templates/mono/styles.css +1016 -0
  90. package/dist/render/templates/neon/portfolio.liquid +217 -0
  91. package/dist/render/templates/neon/project.liquid +225 -0
  92. package/dist/render/templates/neon/session.liquid +195 -0
  93. package/dist/render/templates/neon/styles.css +1265 -0
  94. package/dist/render/templates/noir/portfolio.liquid +137 -0
  95. package/dist/render/templates/noir/project.liquid +220 -0
  96. package/dist/render/templates/noir/session.liquid +241 -0
  97. package/dist/render/templates/noir/styles.css +1223 -0
  98. package/dist/render/templates/obsidian/portfolio.liquid +257 -0
  99. package/dist/render/templates/obsidian/project.liquid +280 -0
  100. package/dist/render/templates/obsidian/session.liquid +241 -0
  101. package/dist/render/templates/obsidian/styles.css +1401 -0
  102. package/dist/render/templates/paper/portfolio.liquid +267 -0
  103. package/dist/render/templates/paper/project.liquid +235 -0
  104. package/dist/render/templates/paper/session.liquid +271 -0
  105. package/dist/render/templates/paper/styles.css +1509 -0
  106. package/dist/render/templates/parallax/portfolio.liquid +305 -0
  107. package/dist/render/templates/parallax/project.liquid +275 -0
  108. package/dist/render/templates/parallax/session.liquid +295 -0
  109. package/dist/render/templates/parallax/styles.css +1874 -0
  110. package/dist/render/templates/parchment/portfolio.liquid +290 -0
  111. package/dist/render/templates/parchment/project.liquid +289 -0
  112. package/dist/render/templates/parchment/session.liquid +346 -0
  113. package/dist/render/templates/parchment/styles.css +1397 -0
  114. package/dist/render/templates/partials/_beats.liquid +16 -0
  115. package/dist/render/templates/partials/_breadcrumb.liquid +9 -0
  116. package/dist/render/templates/partials/_footer.liquid +7 -0
  117. package/dist/render/templates/partials/_growth-chart.liquid +7 -0
  118. package/dist/render/templates/partials/_key-decisions.liquid +20 -0
  119. package/dist/render/templates/partials/_links.liquid +16 -0
  120. package/dist/render/templates/partials/_narrative.liquid +8 -0
  121. package/dist/render/templates/partials/_phases.liquid +20 -0
  122. package/dist/render/templates/partials/_portfolio-header.liquid +20 -0
  123. package/dist/render/templates/partials/_portfolio-projects.liquid +16 -0
  124. package/dist/render/templates/partials/_portfolio-stats.liquid +19 -0
  125. package/dist/render/templates/partials/_qa.liquid +13 -0
  126. package/dist/render/templates/partials/_screenshot.liquid +15 -0
  127. package/dist/render/templates/partials/_session-cards.liquid +30 -0
  128. package/dist/render/templates/partials/_session-header.liquid +39 -0
  129. package/dist/render/templates/partials/_session-sidebar.liquid +30 -0
  130. package/dist/render/templates/partials/_skills.liquid +12 -0
  131. package/dist/render/templates/partials/_source-breakdown.liquid +22 -0
  132. package/dist/render/templates/partials/_stats.liquid +38 -0
  133. package/dist/render/templates/partials/_work-timeline.liquid +7 -0
  134. package/dist/render/templates/project.liquid +7 -4
  135. package/dist/render/templates/radar/portfolio.liquid +233 -0
  136. package/dist/render/templates/radar/project.liquid +278 -0
  137. package/dist/render/templates/radar/session.liquid +300 -0
  138. package/dist/render/templates/radar/styles.css +1049 -0
  139. package/dist/render/templates/showcase/portfolio.liquid +231 -0
  140. package/dist/render/templates/showcase/project.liquid +237 -0
  141. package/dist/render/templates/showcase/session.liquid +210 -0
  142. package/dist/render/templates/showcase/styles.css +1279 -0
  143. package/dist/render/templates/signal/portfolio.liquid +227 -0
  144. package/dist/render/templates/signal/project.liquid +278 -0
  145. package/dist/render/templates/signal/session.liquid +282 -0
  146. package/dist/render/templates/signal/styles.css +1395 -0
  147. package/dist/render/templates/strata/portfolio.liquid +192 -0
  148. package/dist/render/templates/strata/project.liquid +282 -0
  149. package/dist/render/templates/strata/session.liquid +261 -0
  150. package/dist/render/templates/strata/styles.css +1350 -0
  151. package/dist/render/templates/styles.css +1190 -0
  152. package/dist/render/templates/terminal/portfolio.liquid +118 -0
  153. package/dist/render/templates/terminal/project.liquid +161 -0
  154. package/dist/render/templates/terminal/session.liquid +145 -0
  155. package/dist/render/templates/terminal/styles.css +492 -0
  156. package/dist/render/templates/verdant/portfolio.liquid +333 -0
  157. package/dist/render/templates/verdant/project.liquid +309 -0
  158. package/dist/render/templates/verdant/session.liquid +237 -0
  159. package/dist/render/templates/verdant/styles.css +1257 -0
  160. package/dist/render/templates/zen/portfolio.liquid +136 -0
  161. package/dist/render/templates/zen/project.liquid +187 -0
  162. package/dist/render/templates/zen/session.liquid +203 -0
  163. package/dist/render/templates/zen/styles.css +1207 -0
  164. package/dist/render/templates.js +90 -0
  165. package/dist/routes/context.js +15 -10
  166. package/dist/routes/enhance.js +17 -40
  167. package/dist/routes/export.js +14 -4
  168. package/dist/routes/preview.js +480 -108
  169. package/dist/routes/projects.js +11 -19
  170. package/dist/routes/publish.js +15 -17
  171. package/dist/routes/settings.js +94 -1
  172. package/dist/routes/sse.js +9 -0
  173. package/dist/server.js +8 -2
  174. package/dist/settings.js +17 -9
  175. package/package.json +2 -4
  176. package/dist/public/assets/index-B_d6DlEI.js +0 -21
  177. package/dist/public/assets/index-Dalqz2mC.css +0 -1
@@ -0,0 +1,217 @@
1
+ <div class="heyiam-portfolio neon" data-render-version="2" data-template="neon" data-username="{{ user.username }}">
2
+
3
+ <div class="grid-bg" aria-hidden="true"></div>
4
+
5
+ {%- comment -%} Hero {%- endcomment -%}
6
+ {% if hasProfile %}
7
+ <section class="hero fade-in" aria-label="Profile">
8
+ {% if user.photoUrl %}
9
+ <img src="{{ user.photoUrl }}" alt="{{ user.displayName }}" class="hero-photo portfolio-photo">
10
+ {% endif %}
11
+ {% if user.displayName != blank %}
12
+ <h1>{{ user.displayName }}</h1>
13
+ {% endif %}
14
+ {% if user.bio != blank %}
15
+ <p class="hero-bio portfolio-bio">{{ user.bio }}</p>
16
+ {% endif %}
17
+ {% if user.location != blank %}
18
+ <p class="hero-location portfolio-location">{{ user.location }}</p>
19
+ {% endif %}
20
+ {% if user.email or user.linkedinUrl or user.githubUrl or user.twitterHandle or user.websiteUrl or user.resumeUrl %}
21
+ <ul class="hero-links" aria-label="Contact and social links">
22
+ {% if user.email %}
23
+ <li><a href="mailto:{{ user.email }}"><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>{{ user.email }}</a></li>
24
+ {% endif %}
25
+ {% if user.linkedinUrl %}
26
+ <li><a href="{{ user.linkedinUrl }}" 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>
27
+ {% endif %}
28
+ {% if user.githubUrl %}
29
+ <li><a href="{{ user.githubUrl }}" 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>
30
+ {% endif %}
31
+ {% if user.twitterHandle %}
32
+ <li><a href="https://x.com/{{ user.twitterHandle }}" 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>@{{ user.twitterHandle }}</a></li>
33
+ {% endif %}
34
+ {% if user.websiteUrl %}
35
+ <li><a href="{{ user.websiteUrl }}" target="_blank" rel="noopener"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>{{ user.websiteUrl | stripProtocol }}</a></li>
36
+ {% endif %}
37
+ {% if user.resumeUrl %}
38
+ <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>
39
+ {% endif %}
40
+ </ul>
41
+ {% endif %}
42
+ </section>
43
+ {% endif %}
44
+
45
+ {%- comment -%} Aggregate Stats {%- endcomment -%}
46
+ <section class="stats-section fade-in" aria-label="Aggregate statistics">
47
+ <div class="stats-grid">
48
+ <div class="stat-card" role="figure" aria-label="{{ projects.size }} projects">
49
+ <div class="stat-value pink" data-target="{{ projects.size }}">0</div>
50
+ <div class="stat-label">Projects</div>
51
+ </div>
52
+ <div class="stat-card" role="figure" aria-label="{{ totalSessions }} sessions">
53
+ <div class="stat-value cyan" data-target="{{ totalSessions }}">0</div>
54
+ <div class="stat-label">Sessions</div>
55
+ </div>
56
+ <div class="stat-card" role="figure" aria-label="{{ totalLoc }} lines changed">
57
+ <div class="stat-value cyan" data-target="{{ totalLoc }}" data-format="comma">0</div>
58
+ <div class="stat-label">Lines Changed</div>
59
+ </div>
60
+ {% if efficiencyMultiplier %}
61
+ <div class="stat-card" role="figure" aria-label="{{ efficiencyMultiplier }} leverage">
62
+ <div class="stat-value pink">{{ efficiencyMultiplier }}</div>
63
+ <div class="stat-label">Leverage</div>
64
+ </div>
65
+ {% else %}
66
+ <div class="stat-card" role="figure" aria-label="{{ totalDurationMinutes | formatDuration }} total time">
67
+ <div class="stat-value pink">{{ totalDurationMinutes | formatDuration }}</div>
68
+ <div class="stat-label">Total Time</div>
69
+ </div>
70
+ {% endif %}
71
+ </div>
72
+ </section>
73
+
74
+ {%- comment -%} Leverage {%- endcomment -%}
75
+ {% if efficiencyMultiplier %}
76
+ <section class="fade-in" aria-label="AI leverage" role="figure">
77
+ <div class="neon-leverage">
78
+ <div class="neon-leverage__multi">{{ efficiencyMultiplier }}</div>
79
+ <div class="neon-leverage__context">{{ totalDurationMinutes | formatDuration }} you &middot; <span>{{ totalAgentDurationMinutes | formatDuration }} agents</span></div>
80
+ {% assign totalCombined = totalDurationMinutes | plus: totalAgentDurationMinutes %}
81
+ {% if totalCombined > 0 %}
82
+ {% assign humanPct = totalDurationMinutes | times: 100 | divided_by: totalCombined %}
83
+ {% assign agentPct = 100 | minus: humanPct %}
84
+ <div class="neon-leverage__bar"><div class="neon-leverage__human" style="width:{{ humanPct }}%"></div><div class="neon-leverage__agent" style="width:{{ agentPct }}%"></div></div>
85
+ {% endif %}
86
+ </div>
87
+ </section>
88
+ {% endif %}
89
+
90
+ {%- comment -%} Projects {%- endcomment -%}
91
+ {% if projects.size > 0 %}
92
+ <section class="projects-section" aria-label="Projects">
93
+ <h2 class="section-heading">Projects</h2>
94
+
95
+ {% for p in projects %}
96
+ <article class="project-card fade-in">
97
+ <a href="/{{ user.username }}/{{ p.slug }}" class="project-title">{{ p.title }}</a>
98
+ {% if p.narrative != blank %}
99
+ <p class="project-narrative">{{ p.narrative | truncate: 120 }}</p>
100
+ {% endif %}
101
+ {% if p.skills.size > 0 %}
102
+ <ul class="skills-list" aria-label="Skills used in {{ p.title }}">
103
+ {% for skill in p.skills %}
104
+ <li class="skill-chip">{{ skill }}</li>
105
+ {% endfor %}
106
+ </ul>
107
+ {% endif %}
108
+ <div class="project-meta">
109
+ <span>{{ p.totalSessions }} session{% if p.totalSessions != 1 %}s{% endif %}</span>
110
+ <span>{{ p.totalDurationMinutes | formatDuration }}</span>
111
+ <span>{{ p.totalLoc | localeNumber }} LOC</span>
112
+ </div>
113
+ {% if p.sourceCounts.size > 0 %}
114
+ {% assign pTotalSource = 0 %}
115
+ {% for src in p.sourceCounts %}
116
+ {% assign pTotalSource = pTotalSource | plus: src.count %}
117
+ {% endfor %}
118
+ <div class="source-bar-container">
119
+ <div class="source-bar-label">Source mix</div>
120
+ <div class="source-bar" role="img">
121
+ {% for src in p.sourceCounts %}
122
+ {% if pTotalSource > 0 %}
123
+ {% assign pSrcPct = src.count | times: 100.0 | divided_by: pTotalSource | round %}
124
+ {% endif %}
125
+ <div class="{% if forloop.first %}claude{% else %}cursor{% endif %}" style="width: 0%" data-width="{{ pSrcPct }}"></div>
126
+ {% endfor %}
127
+ </div>
128
+ <div class="source-legend">
129
+ {% for src in p.sourceCounts %}
130
+ {% if pTotalSource > 0 %}
131
+ {% assign pSrcPctDisplay = src.count | times: 100.0 | divided_by: pTotalSource | round %}
132
+ {% endif %}
133
+ <span class="{% if forloop.first %}claude-label{% else %}cursor-label{% endif %}">{{ src.tool }} {{ pSrcPctDisplay }}%</span>
134
+ {% endfor %}
135
+ </div>
136
+ </div>
137
+ {% endif %}
138
+ </article>
139
+ {% endfor %}
140
+ </section>
141
+ {% endif %}
142
+
143
+ {%- comment -%} Contribution Overview {%- endcomment -%}
144
+ {% if sourceCounts.size > 0 %}
145
+ <section class="chart-section fade-in" aria-label="Contribution overview">
146
+ <h2 class="section-heading">Contribution Overview</h2>
147
+ <div class="contrib-chart">
148
+ <div style="display: flex; align-items: flex-end; gap: 2rem; justify-content: center; padding: 1.5rem 1rem;">
149
+ {% assign maxSourceCount = 0 %}
150
+ {% for src in sourceCounts %}
151
+ {% if src.count > maxSourceCount %}{% assign maxSourceCount = src.count %}{% endif %}
152
+ {% endfor %}
153
+ {% for src in sourceCounts %}
154
+ <div style="display: flex; flex-direction: column; align-items: center; gap: 0.5rem;">
155
+ {% if maxSourceCount > 0 %}
156
+ {% assign barHeight = src.count | times: 120 | divided_by: maxSourceCount %}
157
+ {% else %}
158
+ {% assign barHeight = 0 %}
159
+ {% endif %}
160
+ <div style="font-family: var(--font-mono); font-size: 0.75rem; color: {% if forloop.first %}var(--neon-pink){% else %}var(--neon-cyan){% endif %};">{{ src.count }}</div>
161
+ <div style="width: 80px; height: {{ barHeight }}px; background: {% if forloop.first %}var(--neon-pink){% else %}var(--neon-cyan){% endif %}; border-radius: 4px 4px 0 0; min-height: 8px;"></div>
162
+ <div style="font-family: var(--font-mono); font-size: 0.75rem; color: var(--neon-muted);">{{ src.tool }}</div>
163
+ </div>
164
+ {% endfor %}
165
+ </div>
166
+ <div class="chart-legend">
167
+ {% for src in sourceCounts %}
168
+ <span class="{% if forloop.first %}pink-label{% else %}cyan-label{% endif %}">{{ src.tool }} sessions</span>
169
+ {% endfor %}
170
+ </div>
171
+ </div>
172
+ </section>
173
+ {% endif %}
174
+
175
+ {%- comment -%} All Skills {%- endcomment -%}
176
+ {% assign allSkills = '' %}
177
+ {% for p in projects %}
178
+ {% for skill in p.skills %}
179
+ {% unless allSkills contains skill %}
180
+ {% if allSkills != '' %}{% assign allSkills = allSkills | append: ',' %}{% endif %}
181
+ {% assign allSkills = allSkills | append: skill %}
182
+ {% endunless %}
183
+ {% endfor %}
184
+ {% endfor %}
185
+ {% assign skillsArray = allSkills | split: ',' %}
186
+ {% if skillsArray.size > 0 %}
187
+ <section class="all-skills-section fade-in" aria-label="All skills across projects">
188
+ <h2 class="section-heading">All Skills</h2>
189
+ <ul class="skills-grid">
190
+ {% for skill in skillsArray %}
191
+ <li class="skill-chip">{{ skill }}</li>
192
+ {% endfor %}
193
+ </ul>
194
+ </section>
195
+ {% endif %}
196
+
197
+ {%- comment -%} Recent Activity {%- endcomment -%}
198
+ {% if recentSessions.size > 0 %}
199
+ <section class="activity-section fade-in" aria-label="Recent activity timeline">
200
+ <h2 class="section-heading">Recent Activity</h2>
201
+ <ol class="activity-list">
202
+ {% for s in recentSessions %}
203
+ <li class="activity-item">
204
+ {% if s.recordedAt %}
205
+ <div class="activity-date">{{ s.recordedAt | formatDate }}</div>
206
+ {% endif %}
207
+ <div class="activity-title"><a href="/{{ user.username }}/{{ s.projectSlug }}/{{ s.slug }}">{{ s.title }}</a></div>
208
+ <div class="activity-detail">{{ s.projectTitle }} &middot; {{ s.durationMinutes | formatDuration }} &middot; {{ s.locChanged | localeNumber }} LOC</div>
209
+ </li>
210
+ {% endfor %}
211
+ </ol>
212
+ </section>
213
+ {% endif %}
214
+
215
+ {%- comment -%} Scroll + counter animations {%- endcomment -%}
216
+
217
+ </div>
@@ -0,0 +1,225 @@
1
+ <div class="heyiam-project neon" data-render-version="2" data-template="neon"{% if sessionBaseUrl %} data-session-base-url="{{ sessionBaseUrl }}"{% endif %} data-username="{{ user.username }}" data-project-slug="{{ project.slug }}">
2
+
3
+ <div class="grid-bg" aria-hidden="true"></div>
4
+
5
+ <div class="container">
6
+
7
+ {%- comment -%} Breadcrumb {%- endcomment -%}
8
+ <div class="breadcrumb" aria-label="Breadcrumb">
9
+ <a href="/{{ user.username }}">{{ user.username }}</a> /
10
+ <span>{{ project.slug }}</span>
11
+ </div>
12
+
13
+ {%- comment -%} Project Header {%- endcomment -%}
14
+ <header class="project-header fade-in">
15
+ <h1 data-editable="title">{{ project.title }}</h1>
16
+ {% if project.repoUrl or project.projectUrl %}
17
+ <div class="project-links">
18
+ {% if project.repoUrl %}
19
+ <a href="{{ project.repoUrl }}" target="_blank" rel="noopener">{{ project.repoUrl | stripProtocol }}</a>
20
+ {% endif %}
21
+ {% if project.projectUrl %}
22
+ <a href="{{ project.projectUrl }}" target="_blank" rel="noopener">{{ project.projectUrl | stripProtocol }}</a>
23
+ {% endif %}
24
+ </div>
25
+ {% endif %}
26
+ </header>
27
+
28
+ {%- comment -%} Screenshot {%- endcomment -%}
29
+ {% if project.screenshotUrl %}
30
+ <div class="screenshot fade-in browser-chrome" role="img" aria-label="{{ project.title }} screenshot">
31
+ <div class="screenshot-chrome">
32
+ <span class="screenshot-dot"></span>
33
+ <span class="screenshot-dot"></span>
34
+ <span class="screenshot-dot"></span>
35
+ </div>
36
+ <img src="{{ project.screenshotUrl }}" alt="{{ project.title }} screenshot" class="screenshot-img">
37
+ </div>
38
+ {% endif %}
39
+
40
+ {%- comment -%} Narrative {%- endcomment -%}
41
+ {% if project.narrative != blank %}
42
+ <section class="narrative fade-in" aria-label="Project narrative">
43
+ <p>{{ project.narrative }}</p>
44
+ </section>
45
+ {% endif %}
46
+
47
+ {%- comment -%} Stats {%- endcomment -%}
48
+ <section class="fade-in" aria-label="Project statistics">
49
+ <div class="stats-row">
50
+ <div class="stat-item" role="figure" aria-label="{{ project.totalSessions }} sessions">
51
+ <div class="value" data-target="{{ project.totalSessions }}">0</div>
52
+ <div class="label">Sessions</div>
53
+ </div>
54
+ <div class="stat-item" role="figure" aria-label="{{ project.totalLoc }} lines of code">
55
+ <div class="value" data-target="{{ project.totalLoc }}" data-format="comma">0</div>
56
+ <div class="label">LOC</div>
57
+ </div>
58
+ <div class="stat-item" role="figure" aria-label="{{ project.totalFilesChanged }} files">
59
+ <div class="value" data-target="{{ project.totalFilesChanged }}">0</div>
60
+ <div class="label">Files</div>
61
+ </div>
62
+ {% if project.totalTokens %}
63
+ <div class="stat-item" role="figure" aria-label="{{ project.totalTokens | formatTokens }} tokens">
64
+ <div class="value">{{ project.totalTokens | formatTokens }}</div>
65
+ <div class="label">Tokens</div>
66
+ </div>
67
+ {% endif %}
68
+ {% if efficiencyMultiplier %}
69
+ <div class="stat-item" role="figure" aria-label="{{ efficiencyMultiplier }} leverage">
70
+ <div class="value">{{ efficiencyMultiplier }}</div>
71
+ <div class="label">Leverage</div>
72
+ </div>
73
+ {% else %}
74
+ <div class="stat-item" role="figure" aria-label="{{ project.totalDurationMinutes | formatDuration }} duration">
75
+ <div class="value">{{ project.totalDurationMinutes | formatDuration }}</div>
76
+ <div class="label">{{ durationLabel }}</div>
77
+ </div>
78
+ {% endif %}
79
+ </div>
80
+ </section>
81
+
82
+ {%- comment -%} Leverage {%- endcomment -%}
83
+ {% if efficiencyMultiplier %}
84
+ <section class="fade-in" aria-label="AI leverage" role="figure">
85
+ <div class="neon-leverage">
86
+ <div class="neon-leverage__multi">{{ efficiencyMultiplier }}</div>
87
+ <div class="neon-leverage__context">{{ project.totalDurationMinutes | formatDuration }} you &middot; <span>{{ project.totalAgentDurationMinutes | formatDuration }} agents</span></div>
88
+ {% assign totalCombined = project.totalDurationMinutes | plus: project.totalAgentDurationMinutes %}
89
+ {% if totalCombined > 0 %}
90
+ {% assign humanPct = project.totalDurationMinutes | times: 100 | divided_by: totalCombined %}
91
+ {% assign agentPct = 100 | minus: humanPct %}
92
+ <div class="neon-leverage__bar"><div class="neon-leverage__human" style="width:{{ humanPct }}%"></div><div class="neon-leverage__agent" style="width:{{ agentPct }}%"></div></div>
93
+ {% endif %}
94
+ </div>
95
+ </section>
96
+ {% endif %}
97
+
98
+ {%- comment -%} Work Timeline Chart (CSS-only) {%- endcomment -%}
99
+ {% if featuredSessions.size > 0 %}
100
+ {% assign maxDuration = 1 %}
101
+ {% for s in featuredSessions %}
102
+ {% if s.durationMinutes > maxDuration %}
103
+ {% assign maxDuration = s.durationMinutes %}
104
+ {% endif %}
105
+ {% endfor %}
106
+ <section class="timeline-section fade-in" aria-label="Work timeline">
107
+ <h2 class="section-heading">Work Timeline</h2>
108
+ <div class="timeline-chart" role="img" aria-label="Session durations chart showing {{ featuredSessions.size }} sessions">
109
+ {% for s in featuredSessions %}
110
+ <div class="timeline-row">
111
+ <span class="timeline-num">{{ forloop.index }}</span>
112
+ <div class="timeline-bar-track">
113
+ {% assign barPct = s.durationMinutes | times: 100 | divided_by: maxDuration %}
114
+ <div class="timeline-bar {% if s.sourceTool == 'Cursor' %}cursor{% else %}claude{% endif %}" data-width="{{ barPct }}" title="{{ s.title }}">{{ s.title }}</div>
115
+ </div>
116
+ <span class="timeline-duration">{{ s.durationMinutes }}m</span>
117
+ </div>
118
+ {% endfor %}
119
+ </div>
120
+ </section>
121
+ {% endif %}
122
+
123
+ {%- comment -%} Phases {%- endcomment -%}
124
+ {% if arc.size > 0 %}
125
+ <section class="phases-section fade-in" aria-label="Project phases">
126
+ <h2 class="section-heading">Phases</h2>
127
+ <ol class="phase-list">
128
+ {% for item in arc %}
129
+ <li class="phase-item">
130
+ <span class="phase-num">{{ item.phase }}</span>
131
+ <div>
132
+ <div class="phase-name">{{ item.title }}</div>
133
+ {% if item.dates %}
134
+ <div class="phase-dates">{{ item.dates }}</div>
135
+ {% endif %}
136
+ <div class="phase-desc">{{ item.description }}</div>
137
+ </div>
138
+ </li>
139
+ {% endfor %}
140
+ </ol>
141
+ </section>
142
+ {% endif %}
143
+
144
+ {%- comment -%} Skills {%- endcomment -%}
145
+ {% if project.skills.size > 0 %}
146
+ <section class="skills-section fade-in" aria-label="Technologies used">
147
+ <h2 class="section-heading">Skills</h2>
148
+ <ul class="skills-list">
149
+ {% for skill in project.skills %}
150
+ <li class="skill-chip">{{ skill }}</li>
151
+ {% endfor %}
152
+ </ul>
153
+ </section>
154
+ {% endif %}
155
+
156
+ {%- comment -%} Key Decisions {%- endcomment -%}
157
+ {% if arc.size > 0 %}
158
+ <section class="decisions-section fade-in" aria-label="Key decisions">
159
+ <h2 class="section-heading">Key Decisions</h2>
160
+ <ol class="decision-list">
161
+ {% for item in arc %}
162
+ <li class="decision-item">{{ item.description }}</li>
163
+ {% endfor %}
164
+ </ol>
165
+ </section>
166
+ {% endif %}
167
+
168
+ {%- comment -%} Source Breakdown {%- endcomment -%}
169
+ {% if sourceCounts.size > 0 %}
170
+ <section class="source-section fade-in" aria-label="Source breakdown">
171
+ <h2 class="section-heading">Source Breakdown</h2>
172
+ {% assign totalSourceSessions = 0 %}
173
+ {% for src in sourceCounts %}
174
+ {% assign totalSourceSessions = totalSourceSessions | plus: src.count %}
175
+ {% endfor %}
176
+ <div class="source-bar-container">
177
+ <div class="source-bar" role="img">
178
+ {% for src in sourceCounts %}
179
+ {% if totalSourceSessions > 0 %}
180
+ {% assign srcPct = src.count | times: 100.0 | divided_by: totalSourceSessions | round %}
181
+ {% endif %}
182
+ <div class="{% if forloop.first %}claude{% else %}cursor{% endif %}" style="width: {{ srcPct }}%"></div>
183
+ {% endfor %}
184
+ </div>
185
+ <div class="source-legend">
186
+ {% for src in sourceCounts %}
187
+ {% if totalSourceSessions > 0 %}
188
+ {% assign srcPctDisplay = src.count | times: 100.0 | divided_by: totalSourceSessions | round %}
189
+ {% endif %}
190
+ <span class="{% if forloop.first %}claude-label{% else %}cursor-label{% endif %}">{{ src.tool }} {{ srcPctDisplay }}% ({{ src.count }} session{% if src.count != 1 %}s{% endif %})</span>
191
+ {% endfor %}
192
+ </div>
193
+ </div>
194
+ </section>
195
+ {% endif %}
196
+
197
+ {%- comment -%} Featured Sessions {%- endcomment -%}
198
+ {% if featuredSessions.size > 0 %}
199
+ <section class="sessions-section fade-in" aria-label="Featured sessions">
200
+ <h2 class="section-heading">Featured Sessions</h2>
201
+ <div class="session-grid">
202
+ {% for s in featuredSessions %}
203
+ <article class="session-card">
204
+ <a href="{{ sessionBaseUrl }}/{{ s.slug }}{{ sessionSuffix }}">{{ s.title }}</a>
205
+ <div class="session-card-meta">
206
+ <span>{{ s.durationMinutes | formatDuration }}</span>
207
+ <span>{{ s.locChanged | localeNumber }} LOC</span>
208
+ {% if s.agentSummary %}
209
+ <span>{{ s.agentSummary.agents.size }} agents</span>
210
+ {% endif %}
211
+ </div>
212
+ {% if s.skills.size > 0 %}
213
+ <span class="session-tag">{{ s.skills | first }}</span>
214
+ {% endif %}
215
+ </article>
216
+ {% endfor %}
217
+ </div>
218
+ </section>
219
+ {% endif %}
220
+
221
+ </div>
222
+
223
+ {%- comment -%} Animations {%- endcomment -%}
224
+
225
+ </div>
@@ -0,0 +1,195 @@
1
+ <div class="heyiam-session neon" data-render-version="2" data-template="neon">
2
+
3
+ <div class="grid-bg" aria-hidden="true"></div>
4
+
5
+ <div class="container">
6
+
7
+ {%- comment -%} Breadcrumb {%- endcomment -%}
8
+ <div class="breadcrumb" aria-label="Breadcrumb">
9
+ <a href="/{{ user.username }}">{{ user.username }}</a>
10
+ {% if projectSlug %}
11
+ / <a href="/{{ user.username }}/{{ projectSlug }}">{{ projectSlug }}</a>
12
+ {% endif %}
13
+ / <span>{{ session.title }}</span>
14
+ </div>
15
+
16
+ {%- comment -%} Session Header {%- endcomment -%}
17
+ <header class="session-header fade-in">
18
+ <h1>{{ session.title }}</h1>
19
+ <div class="session-meta-row">
20
+ {% if session.recordedAt %}
21
+ <span>{{ session.recordedAt | formatDate }}</span>
22
+ {% endif %}
23
+ {% if session.sourceTool %}
24
+ <span class="source-badge">{{ session.sourceTool }}</span>
25
+ {% endif %}
26
+ <span>{{ session.durationMinutes | formatDuration }}{% if session.wallClockMinutes %} ({{ session.wallClockMinutes | formatDuration }} wall){% endif %}</span>
27
+ <span>{{ session.turns }} turns</span>
28
+ </div>
29
+ <div class="session-stats-grid">
30
+ <div class="session-stat" role="figure" aria-label="{{ session.durationMinutes }} minutes duration">
31
+ <div class="value" data-target="{{ session.durationMinutes }}">0</div>
32
+ <div class="label">Minutes</div>
33
+ </div>
34
+ <div class="session-stat" role="figure" aria-label="{{ session.locChanged }} lines of code">
35
+ <div class="value" data-target="{{ session.locChanged }}">0</div>
36
+ <div class="label">LOC</div>
37
+ </div>
38
+ <div class="session-stat" role="figure" aria-label="{{ session.turns }} turns">
39
+ <div class="value" data-target="{{ session.turns }}">0</div>
40
+ <div class="label">Turns</div>
41
+ </div>
42
+ <div class="session-stat" role="figure" aria-label="{{ session.filesChanged }} files changed">
43
+ <div class="value" data-target="{{ session.filesChanged }}">0</div>
44
+ <div class="label">Files</div>
45
+ </div>
46
+ </div>
47
+ </header>
48
+
49
+ {%- comment -%} Dev Take {%- endcomment -%}
50
+ {% if session.devTake != blank %}
51
+ <div class="dev-take fade-in">
52
+ <div class="dev-take-label">Dev Take</div>
53
+ <p>{{ session.devTake }}</p>
54
+ </div>
55
+ {% endif %}
56
+
57
+ {%- comment -%} Main Content + Sidebar {%- endcomment -%}
58
+ <div class="content-grid">
59
+
60
+ {%- comment -%} Main Column {%- endcomment -%}
61
+ <div>
62
+
63
+ {%- comment -%} Narrative {%- endcomment -%}
64
+ {% if session.narrative != blank %}
65
+ <section class="fade-in" aria-label="Session narrative" style="margin-bottom: 2.5rem;">
66
+ <h2 class="section-heading">Narrative</h2>
67
+ <p style="color: var(--neon-text-secondary); font-size: 0.9375rem; line-height: 1.7;">{{ session.narrative }}</p>
68
+ </section>
69
+ {% endif %}
70
+
71
+ {%- comment -%} Highlights {%- endcomment -%}
72
+ {% if session.highlights.size > 0 %}
73
+ <section class="fade-in" aria-label="Session highlights" style="margin-bottom: 2.5rem;">
74
+ <h2 class="section-heading">Highlights</h2>
75
+ <ul class="highlights-list" style="list-style: none; padding: 0;">
76
+ {% for h in session.highlights %}
77
+ <li style="font-size: 0.875rem; color: var(--neon-text-secondary); line-height: 1.7; padding: 0.375rem 0; border-bottom: 1px solid rgba(244, 114, 182, 0.08);">{{ h }}</li>
78
+ {% endfor %}
79
+ </ul>
80
+ </section>
81
+ {% endif %}
82
+
83
+ {%- comment -%} Execution Path (Beats) {%- endcomment -%}
84
+ {% if session.beats.size > 0 %}
85
+ <section class="beats-section fade-in" aria-label="Execution path">
86
+ <h2 class="section-heading">Execution Path</h2>
87
+ <ol class="beats-list beat-list">
88
+ {% for beat in session.beats %}
89
+ <li class="beat-item">
90
+ <div class="beat-title">{{ beat.title }}</div>
91
+ <div class="beat-desc">{{ beat.body }}</div>
92
+ </li>
93
+ {% endfor %}
94
+ </ol>
95
+ </section>
96
+ {% endif %}
97
+
98
+ {%- comment -%} Q&A {%- endcomment -%}
99
+ {% if session.qaPairs.size > 0 %}
100
+ <section class="qa-section fade-in" aria-label="Questions and answers">
101
+ <h2 class="section-heading">Q&amp;A</h2>
102
+ {% for qa in session.qaPairs %}
103
+ <article class="qa-item qa-pair">
104
+ <div class="qa-question">{{ qa.question }}</div>
105
+ <div class="qa-answer">{{ qa.answer }}</div>
106
+ </article>
107
+ {% endfor %}
108
+ </section>
109
+ {% endif %}
110
+
111
+ {%- comment -%} Agent Summary {%- endcomment -%}
112
+ {% if session.agentSummary %}
113
+ <section class="agents-section fade-in" aria-label="Agent summary">
114
+ <h2 class="section-heading">Agent Summary</h2>
115
+ {% assign maxAgentLoc = 0 %}
116
+ {% for agent in session.agentSummary.agents %}
117
+ {% if agent.loc_changed > maxAgentLoc %}
118
+ {% assign maxAgentLoc = agent.loc_changed %}
119
+ {% endif %}
120
+ {% endfor %}
121
+ <div class="agent-chart" role="img" aria-label="Agent contributions chart">
122
+ {% for agent in session.agentSummary.agents %}
123
+ <div class="agent-row">
124
+ <span class="agent-name">{{ agent.role }}</span>
125
+ <div class="agent-bar-track">
126
+ {% if maxAgentLoc > 0 %}
127
+ {% assign barPct = agent.loc_changed | times: 100 | divided_by: maxAgentLoc %}
128
+ {% else %}
129
+ {% assign barPct = 0 %}
130
+ {% endif %}
131
+ {% assign agent_css_classes = 'backend,qa,frontend,security,reviewer' | split: ',' %}
132
+ {% assign colorIdx = forloop.index0 | modulo: 5 %}
133
+ <div class="agent-bar {{ agent_css_classes[colorIdx] }}" data-width="{{ barPct }}" title="{{ agent.duration_minutes }}m, {{ agent.loc_changed }} LOC"></div>
134
+ </div>
135
+ <span class="agent-duration">{{ agent.duration_minutes }}m</span>
136
+ </div>
137
+ {% endfor %}
138
+ </div>
139
+ </section>
140
+ {% endif %}
141
+
142
+ </div>
143
+
144
+ {%- comment -%} Sidebar {%- endcomment -%}
145
+ <aside class="sidebar" aria-label="Session details">
146
+
147
+ {%- comment -%} Tools Used {%- endcomment -%}
148
+ {% if session.toolBreakdown.size > 0 %}
149
+ <div class="sidebar-card">
150
+ <h3 class="sidebar-heading">Tools Used</h3>
151
+ <table class="tools-table tool-list" aria-label="Tool usage counts">
152
+ <tbody>
153
+ {% for t in session.toolBreakdown %}
154
+ <tr><td>{{ t.tool }}</td><td>{{ t.count }}</td></tr>
155
+ {% endfor %}
156
+ </tbody>
157
+ </table>
158
+ </div>
159
+ {% endif %}
160
+
161
+ {%- comment -%} Files Changed {%- endcomment -%}
162
+ {% if session.topFiles.size > 0 %}
163
+ <div class="sidebar-card">
164
+ <h3 class="sidebar-heading">Files Changed</h3>
165
+ <ul class="files-list file-list" aria-label="Files modified in this session">
166
+ {% for f in session.topFiles %}
167
+ <li class="file-item">
168
+ <span class="file-name" title="{{ f.path }}">{{ f.path }}</span>
169
+ <span class="file-diff">+{{ f.additions }}{% if f.deletions > 0 %} <span style="color: #ef4444;">-{{ f.deletions }}</span>{% endif %}</span>
170
+ </li>
171
+ {% endfor %}
172
+ </ul>
173
+ </div>
174
+ {% endif %}
175
+
176
+ {%- comment -%} Skills {%- endcomment -%}
177
+ {% if session.skills.size > 0 %}
178
+ <div class="sidebar-card">
179
+ <h3 class="sidebar-heading">Skills</h3>
180
+ <ul class="sidebar-skills" aria-label="Technologies used in this session">
181
+ {% for skill in session.skills %}
182
+ <li class="sidebar-skill">{{ skill }}</li>
183
+ {% endfor %}
184
+ </ul>
185
+ </div>
186
+ {% endif %}
187
+
188
+ </aside>
189
+
190
+ </div>
191
+ </div>
192
+
193
+ {%- comment -%} Animations {%- endcomment -%}
194
+
195
+ </div>