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,290 @@
1
+ <div class="heyiam-portfolio parchment" data-render-version="2" data-template="parchment" data-username="{{ user.username }}">
2
+ <a href="#main-content" class="skip-link">Skip to content</a>
3
+
4
+ <div class="page-wrapper">
5
+
6
+ {% if hasProfile %}
7
+ {%- comment -%} Masthead / Title Page {%- endcomment -%}
8
+ <header class="masthead fade-in" role="banner">
9
+ {% if user.photoUrl %}
10
+ <img src="{{ user.photoUrl }}" alt="{{ user.displayName }}" class="masthead__photo" width="120" height="120">
11
+ {% endif %}
12
+ {% if user.displayName != blank %}
13
+ <h1 class="masthead__title">{{ user.displayName }}</h1>
14
+ {% endif %}
15
+ {% if user.bio %}
16
+ <p class="masthead__subtitle">{{ user.bio }}</p>
17
+ {% endif %}
18
+ {% if user.location %}
19
+ <p class="masthead__location">{{ user.location }}</p>
20
+ {% endif %}
21
+ {% if user.email or user.linkedinUrl or user.githubUrl or user.twitterHandle or user.websiteUrl or user.resumeUrl %}
22
+ <div class="masthead__links">
23
+ {% if user.email %}
24
+ <a href="mailto:{{ user.email }}">
25
+ <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>
26
+ {{ user.email }}
27
+ </a>
28
+ {% endif %}
29
+ {% if user.linkedinUrl %}
30
+ <a href="{{ user.linkedinUrl }}" target="_blank" rel="noopener">
31
+ <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>
32
+ LinkedIn
33
+ </a>
34
+ {% endif %}
35
+ {% if user.githubUrl %}
36
+ <a href="{{ user.githubUrl }}" target="_blank" rel="noopener">
37
+ <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>
38
+ GitHub
39
+ </a>
40
+ {% endif %}
41
+ {% if user.twitterHandle %}
42
+ <a href="https://x.com/{{ user.twitterHandle }}" target="_blank" rel="noopener">
43
+ <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>
44
+ @{{ user.twitterHandle }}
45
+ </a>
46
+ {% endif %}
47
+ {% if user.websiteUrl %}
48
+ <a href="{{ user.websiteUrl }}" target="_blank" rel="noopener">{{ user.websiteUrl | stripProtocol }}</a>
49
+ {% endif %}
50
+ {% if user.resumeUrl %}
51
+ <a href="{{ user.resumeUrl }}" target="_blank" rel="noopener">
52
+ <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>
53
+ Resume (PDF)
54
+ </a>
55
+ {% endif %}
56
+ </div>
57
+ {% endif %}
58
+ </header>
59
+ {% endif %}
60
+
61
+ <div class="hr-triple" role="separator">
62
+ <span class="hr-triple-inner"></span>
63
+ </div>
64
+
65
+ {%- comment -%} Aggregate Stats {%- endcomment -%}
66
+ <section class="margin-stats fade-in fade-in-delay-1" aria-label="Portfolio statistics">
67
+ <div class="margin-stat">
68
+ <div class="margin-stat__value">{{ projects.size }}</div>
69
+ <div class="margin-stat__label">Projects</div>
70
+ </div>
71
+ <div class="margin-stat">
72
+ <div class="margin-stat__value">{{ totalSessions }}</div>
73
+ <div class="margin-stat__label">Sessions</div>
74
+ </div>
75
+ {% if efficiencyMultiplier %}
76
+ <div class="margin-stat">
77
+ <div class="margin-stat__label">the author</div>
78
+ <div class="margin-stat__value" style="opacity:0.7">{{ totalDurationMinutes | formatDuration }}</div>
79
+ <div class="margin-stat__label" style="margin-top:0.25rem">the machines</div>
80
+ <div class="margin-stat__value" style="color:var(--parch-accent)">{{ totalAgentDurationMinutes | formatDuration }}</div>
81
+ </div>
82
+ <div class="margin-stat margin-stat--featured">
83
+ <div class="margin-stat__value" style="font-size:1.5rem;color:var(--parch-accent)">{{ efficiencyMultiplier }}&times;</div>
84
+ <div class="margin-stat__label">leverage</div>
85
+ </div>
86
+ {% else %}
87
+ <div class="margin-stat">
88
+ <div class="margin-stat__value">{{ totalDurationMinutes | formatDuration }}</div>
89
+ <div class="margin-stat__label">Time</div>
90
+ </div>
91
+ {% endif %}
92
+ <div class="margin-stat">
93
+ <div class="margin-stat__value">{{ totalLoc | formatLoc }}</div>
94
+ <div class="margin-stat__label">Lines Changed</div>
95
+ </div>
96
+ </section>
97
+
98
+ <div class="hr-triple" role="separator">
99
+ <span class="hr-triple-inner"></span>
100
+ </div>
101
+
102
+ {%- comment -%} Main Content {%- endcomment -%}
103
+ <main id="main-content">
104
+
105
+ {%- comment -%} Chapter I: Works {%- endcomment -%}
106
+ {% if projects.size > 0 %}
107
+ <section aria-label="Projects">
108
+ <h2 class="chapter-heading fade-in fade-in-delay-2">
109
+ <span class="chapter-heading__number">Chapter I</span>
110
+ Works
111
+ </h2>
112
+
113
+ {% for p in projects %}
114
+ <article class="project-card fade-in fade-in-delay-2">
115
+ <span class="project-card__page-number">p. {{ forloop.index }}</span>
116
+ <h3 class="project-card__title">
117
+ <a href="/{{ user.username }}/{{ p.slug }}">{{ p.title }}</a>
118
+ </h3>
119
+ {% if p.narrative %}
120
+ <p class="project-card__narrative">{{ p.narrative }}</p>
121
+ {% endif %}
122
+ {% if p.skills.size > 0 %}
123
+ <div class="project-card__skills">
124
+ {% for skill in p.skills %}
125
+ <span class="skill-tag">{{ skill }}</span>
126
+ {% endfor %}
127
+ </div>
128
+ {% endif %}
129
+ <div class="project-card__meta">
130
+ <span class="project-card__meta-item">{{ p.totalSessions }} session{% if p.totalSessions != 1 %}s{% endif %}</span>
131
+ <span class="project-card__meta-item">{{ p.totalDurationMinutes | formatDuration }}</span>
132
+ <span class="project-card__meta-item">{{ p.totalLoc | localeNumber }} LOC</span>
133
+ </div>
134
+ {% if p.sourceCounts.size > 0 %}
135
+ {% assign pTotalSrc = 0 %}
136
+ {% for src in p.sourceCounts %}
137
+ {% assign pTotalSrc = pTotalSrc | plus: src.count %}
138
+ {% endfor %}
139
+ {% if pTotalSrc > 0 %}
140
+ <div class="source-bar" role="img" aria-label="Source mix">
141
+ {% for src in p.sourceCounts %}
142
+ {% assign pSrcPct = src.count | times: 100.0 | divided_by: pTotalSrc | round %}
143
+ <div class="source-bar__segment{% if forloop.first %} source-bar__segment--claude{% else %} source-bar__segment--cursor{% endif %}" style="width: {{ pSrcPct }}%"></div>
144
+ {% endfor %}
145
+ </div>
146
+ <div class="source-bar__labels">
147
+ {% for src in p.sourceCounts %}
148
+ {% assign pSrcPct = src.count | times: 100.0 | divided_by: pTotalSrc | round %}
149
+ <span>{{ src.tool }} {{ pSrcPct }}%</span>
150
+ {% endfor %}
151
+ </div>
152
+ {% endif %}
153
+ {% endif %}
154
+ </article>
155
+ {% endfor %}
156
+ </section>
157
+
158
+ <div class="hr-triple" role="separator">
159
+ <span class="hr-triple-inner"></span>
160
+ </div>
161
+ {% endif %}
162
+
163
+ {%- comment -%} Chapter II: Skills Compendium {%- endcomment -%}
164
+ {% if allSkills.size > 0 %}
165
+ <section class="skills-overview" aria-label="Skills compendium">
166
+ <h2 class="chapter-heading fade-in fade-in-delay-3">
167
+ <span class="chapter-heading__number">Chapter II</span>
168
+ Skills Compendium
169
+ </h2>
170
+ <div class="skills-grid">
171
+ {% for skill in allSkills %}
172
+ <div class="skills-grid__item">
173
+ <div class="skills-grid__name">{{ skill.name }}</div>
174
+ <div class="skills-grid__count">{{ skill.projectCount }} project{% if skill.projectCount != 1 %}s{% endif %}</div>
175
+ </div>
176
+ {% endfor %}
177
+ </div>
178
+ </section>
179
+
180
+ <div class="hr-triple" role="separator">
181
+ <span class="hr-triple-inner"></span>
182
+ </div>
183
+ {% endif %}
184
+
185
+ {%- comment -%} Chapter III: Recent Activity {%- endcomment -%}
186
+ {% if recentSessions.size > 0 %}
187
+ <section aria-label="Recent activity">
188
+ <h2 class="chapter-heading fade-in fade-in-delay-3">
189
+ <span class="chapter-heading__number">Chapter III</span>
190
+ Recent Activity
191
+ </h2>
192
+ <div style="overflow-x: auto;">
193
+ <table class="activity-table">
194
+ <thead>
195
+ <tr>
196
+ <th scope="col">Date</th>
197
+ <th scope="col">Session</th>
198
+ <th scope="col">Project</th>
199
+ <th scope="col">Duration</th>
200
+ <th scope="col">LOC</th>
201
+ </tr>
202
+ </thead>
203
+ <tbody>
204
+ {% for rs in recentSessions %}
205
+ <tr>
206
+ <td>{% if rs.recordedAt %}{{ rs.recordedAt | formatDateShort }}{% endif %}</td>
207
+ <td>{{ rs.title }}</td>
208
+ <td><span class="activity-table__project">{{ rs.projectTitle | default: rs.projectSlug }}</span></td>
209
+ <td>{{ rs.durationMinutes | formatDuration }}</td>
210
+ <td>{{ rs.locChanged | localeNumber }}</td>
211
+ </tr>
212
+ {% endfor %}
213
+ </tbody>
214
+ </table>
215
+ </div>
216
+ </section>
217
+
218
+ <div class="hr-triple" role="separator">
219
+ <span class="hr-triple-inner"></span>
220
+ </div>
221
+ {% endif %}
222
+
223
+ {%- comment -%} Chapter IV: Source Overview {%- endcomment -%}
224
+ {% if sourceCounts.size > 0 %}
225
+ <section aria-label="Source overview">
226
+ <h2 class="chapter-heading fade-in fade-in-delay-3">
227
+ <span class="chapter-heading__number">Chapter IV</span>
228
+ Source
229
+ </h2>
230
+ {% assign totalPortSrc = 0 %}
231
+ {% for src in sourceCounts %}
232
+ {% assign totalPortSrc = totalPortSrc | plus: src.count %}
233
+ {% endfor %}
234
+ {% if totalPortSrc > 0 %}
235
+ <div class="source-overview">
236
+ {% for src in sourceCounts %}
237
+ {% assign portSrcPct = src.count | times: 100.0 | divided_by: totalPortSrc | round %}
238
+ <div class="source-overview__item">
239
+ <div class="source-overview__value">{{ portSrcPct }}%</div>
240
+ <div class="source-overview__label">{{ src.tool }}</div>
241
+ </div>
242
+ {% endfor %}
243
+ </div>
244
+ <div class="source-overview__bar" style="margin-top: 1rem;">
245
+ <div class="source-overview__bar-track" role="img" aria-label="Overall source mix">
246
+ {% for src in sourceCounts %}
247
+ {% assign portSrcPct = src.count | times: 100.0 | divided_by: totalPortSrc | round %}
248
+ <div class="source-overview__bar-fill--{% if forloop.first %}claude{% else %}cursor{% endif %}" style="width: {{ portSrcPct }}%;"></div>
249
+ {% endfor %}
250
+ </div>
251
+ <div class="source-overview__bar-labels">
252
+ {% for src in sourceCounts %}
253
+ <span>{{ src.tool }}</span>
254
+ {% endfor %}
255
+ </div>
256
+ </div>
257
+ {% endif %}
258
+ </section>
259
+
260
+ <div class="hr-triple" role="separator">
261
+ <span class="hr-triple-inner"></span>
262
+ </div>
263
+ {% endif %}
264
+
265
+ {%- comment -%} Epilogue: About This Collection {%- endcomment -%}
266
+ {% if user.bio %}
267
+ <section class="about-section" aria-label="About this collection">
268
+ <h2 class="chapter-heading fade-in fade-in-delay-3">
269
+ <span class="chapter-heading__number">Epilogue</span>
270
+ About This Collection
271
+ </h2>
272
+ <p class="about-section__text">{{ user.bio }}</p>
273
+ </section>
274
+ {% endif %}
275
+ </main>
276
+
277
+ <div class="hr-triple" role="separator">
278
+ <span class="hr-triple-inner"></span>
279
+ </div>
280
+
281
+ {%- comment -%} Colophon {%- endcomment -%}
282
+ <footer class="colophon" role="contentinfo">
283
+ <div class="colophon__mark" aria-hidden="true">&sect;</div>
284
+ <p>Set in Crimson Pro &amp; IBM Plex Mono</p>
285
+ <p>Composed with AI-assisted development tools</p>
286
+ <p>Published on heyi.am</p>
287
+ </footer>
288
+ </div>
289
+
290
+ </div>
@@ -0,0 +1,289 @@
1
+ <div class="heyiam-project parchment" data-render-version="2" data-template="parchment"{% if sessionBaseUrl %} data-session-base-url="{{ sessionBaseUrl }}"{% endif %} data-username="{{ user.username }}" data-project-slug="{{ project.slug }}">
2
+ <a href="#main-content" class="skip-link">Skip to content</a>
3
+
4
+ <div class="page-wrapper">
5
+
6
+ {%- comment -%} Breadcrumb {%- endcomment -%}
7
+ <div class="breadcrumb" aria-label="Breadcrumb">
8
+ <a href="/{{ user.username }}">{{ user.username }}</a>
9
+ <span class="breadcrumb__sep" aria-hidden="true">/</span>
10
+ <span>{{ project.slug }}</span>
11
+ </div>
12
+
13
+ {%- comment -%} Title Page {%- endcomment -%}
14
+ <header class="title-page fade-in" role="banner">
15
+ <h1 class="title-page__heading" data-editable="title">{{ project.title }}</h1>
16
+ {% if project.repoUrl or project.projectUrl %}
17
+ <div class="title-page__links">
18
+ {% if project.repoUrl %}
19
+ <a href="{{ project.repoUrl }}" target="_blank" rel="noopener noreferrer">{{ project.repoUrl | stripProtocol }}</a>
20
+ {% endif %}
21
+ {% if project.projectUrl %}
22
+ <a href="{{ project.projectUrl }}" target="_blank" rel="noopener noreferrer">{{ project.projectUrl | stripProtocol }}</a>
23
+ {% endif %}
24
+ </div>
25
+ {% endif %}
26
+ </header>
27
+
28
+ {%- comment -%} Screenshot {%- endcomment -%}
29
+ {% if project.screenshotUrl %}
30
+ <figure class="screenshot fade-in fade-in-d1" aria-label="Application screenshot">
31
+ <div class="screenshot__chrome">
32
+ <span class="screenshot__dot" aria-hidden="true"></span>
33
+ <span class="screenshot__dot" aria-hidden="true"></span>
34
+ <span class="screenshot__dot" aria-hidden="true"></span>
35
+ {% if project.projectUrl %}
36
+ <span class="screenshot__bar">{{ project.projectUrl | stripProtocol }}</span>
37
+ {% else %}
38
+ <span class="screenshot__bar">{{ project.slug }}</span>
39
+ {% endif %}
40
+ </div>
41
+ <img src="{{ project.screenshotUrl }}" alt="{{ project.title }} preview" style="width:100%;display:block;">
42
+ </figure>
43
+ {% endif %}
44
+
45
+ <div class="hr-triple" role="separator">
46
+ <span class="hr-triple-inner"></span>
47
+ </div>
48
+
49
+ <main id="main-content">
50
+
51
+ {%- comment -%} Narrative with Drop Cap {%- endcomment -%}
52
+ {% if project.narrative %}
53
+ <section class="narrative fade-in fade-in-d2" aria-label="Project narrative">
54
+ <p>{{ project.narrative }}</p>
55
+ </section>
56
+
57
+ <div class="hr-triple" role="separator">
58
+ <span class="hr-triple-inner"></span>
59
+ </div>
60
+ {% endif %}
61
+
62
+ {%- comment -%} Stats {%- endcomment -%}
63
+ <section class="project-stats fade-in fade-in-d2" aria-label="Project statistics">
64
+ <div class="project-stat">
65
+ <div class="project-stat__value">{{ project.totalSessions }}</div>
66
+ <div class="project-stat__label">Sessions</div>
67
+ </div>
68
+ {% if efficiencyMultiplier %}
69
+ <div class="project-stat">
70
+ <div class="project-stat__label">the author</div>
71
+ <div class="project-stat__value" style="opacity:0.7">{{ project.totalDurationMinutes | formatDuration }}</div>
72
+ <div class="project-stat__label" style="margin-top:0.25rem">the machines</div>
73
+ <div class="project-stat__value" style="color:var(--parch-accent)">{{ project.totalAgentDurationMinutes | formatDuration }}</div>
74
+ </div>
75
+ <div class="project-stat project-stat--featured">
76
+ <div class="project-stat__value" style="font-size:1.5rem;color:var(--parch-accent)">{{ efficiencyMultiplier }}&times;</div>
77
+ <div class="project-stat__label">leverage</div>
78
+ </div>
79
+ {% else %}
80
+ <div class="project-stat">
81
+ <div class="project-stat__value">{{ project.totalDurationMinutes | formatDuration }}</div>
82
+ <div class="project-stat__label">{{ durationLabel }}</div>
83
+ </div>
84
+ {% endif %}
85
+ <div class="project-stat">
86
+ <div class="project-stat__value">{{ project.totalLoc | localeNumber }}</div>
87
+ <div class="project-stat__label">Lines Changed</div>
88
+ </div>
89
+ <div class="project-stat">
90
+ <div class="project-stat__value">{{ project.totalFilesChanged | localeNumber }}</div>
91
+ <div class="project-stat__label">Files</div>
92
+ </div>
93
+ {% if project.totalTokens %}
94
+ <div class="project-stat">
95
+ <div class="project-stat__value">{{ project.totalTokens | formatTokens }}</div>
96
+ <div class="project-stat__label">Tokens</div>
97
+ </div>
98
+ {% endif %}
99
+ </section>
100
+
101
+ <div class="hr-triple" role="separator">
102
+ <span class="hr-triple-inner"></span>
103
+ </div>
104
+
105
+ {%- comment -%} Chapter II: Phases {%- endcomment -%}
106
+ {% if arc.size > 0 %}
107
+ <section aria-label="Project phases">
108
+ <h2 class="chapter-heading fade-in fade-in-d3">
109
+ <span class="chapter-heading__number">Chapter II</span>
110
+ Phases
111
+ </h2>
112
+ <div class="phases">
113
+ {% for item in arc %}
114
+ <div class="phase">
115
+ <div class="phase__number">Phase {{ item.phase }}</div>
116
+ <h3 class="phase__title">{{ item.title }}</h3>
117
+ {% if item.dates %}
118
+ <div class="phase__dates">{{ item.dates }}</div>
119
+ {% endif %}
120
+ <p class="phase__desc">{{ item.description }}</p>
121
+ </div>
122
+ {% endfor %}
123
+ </div>
124
+ </section>
125
+
126
+ <div class="hr-triple" role="separator">
127
+ <span class="hr-triple-inner"></span>
128
+ </div>
129
+ {% endif %}
130
+
131
+ {%- comment -%} Chapter III: Key Decisions {%- endcomment -%}
132
+ {% if arc.size > 0 %}
133
+ <section aria-label="Key decisions">
134
+ <h2 class="chapter-heading fade-in fade-in-d3">
135
+ <span class="chapter-heading__number">Chapter III</span>
136
+ Key Decisions
137
+ </h2>
138
+ <ol class="decisions-list">
139
+ {% for item in arc %}
140
+ <li>{{ item.description }}</li>
141
+ {% endfor %}
142
+ </ol>
143
+ </section>
144
+
145
+ <div class="hr-triple" role="separator">
146
+ <span class="hr-triple-inner"></span>
147
+ </div>
148
+ {% endif %}
149
+
150
+ {%- comment -%} Chapter IV: Skills {%- endcomment -%}
151
+ {% if project.skills.size > 0 %}
152
+ <section class="skills-section" aria-label="Skills used">
153
+ <h2 class="chapter-heading fade-in fade-in-d3">
154
+ <span class="chapter-heading__number">Chapter IV</span>
155
+ Skills
156
+ </h2>
157
+ <div class="skill-list">
158
+ {% for skill in project.skills %}
159
+ <span class="skill-tag">{{ skill }}</span>
160
+ {% endfor %}
161
+ </div>
162
+ </section>
163
+
164
+ <div class="hr-triple" role="separator">
165
+ <span class="hr-triple-inner"></span>
166
+ </div>
167
+ {% endif %}
168
+
169
+ {%- comment -%} Chapter V: Source Breakdown {%- endcomment -%}
170
+ {% if sourceCounts.size > 0 %}
171
+ <section aria-label="Source breakdown">
172
+ <h2 class="chapter-heading fade-in fade-in-d3">
173
+ <span class="chapter-heading__number">Chapter V</span>
174
+ Source
175
+ </h2>
176
+ <div class="source-breakdown">
177
+ <div class="source-bar-container">
178
+ {% assign totalSourceSessions = 0 %}
179
+ {% for src in sourceCounts %}
180
+ {% assign totalSourceSessions = totalSourceSessions | plus: src.count %}
181
+ {% endfor %}
182
+ {% if totalSourceSessions > 0 %}
183
+ <div class="source-bar" role="img" aria-label="Source breakdown">
184
+ {% for src in sourceCounts %}
185
+ {% assign srcPct = src.count | times: 100.0 | divided_by: totalSourceSessions | round %}
186
+ <div class="source-bar__segment{% if forloop.first %} source-bar__segment--claude{% else %} source-bar__segment--cursor{% endif %}" style="width: {{ srcPct }}%"></div>
187
+ {% endfor %}
188
+ </div>
189
+ <div class="source-labels">
190
+ {% for src in sourceCounts %}
191
+ {% assign srcPct = src.count | times: 100.0 | divided_by: totalSourceSessions | round %}
192
+ <span>{{ src.tool }} &mdash; {{ src.count }} session{% if src.count != 1 %}s{% endif %} ({{ srcPct }}%)</span>
193
+ {% endfor %}
194
+ </div>
195
+ {% endif %}
196
+ </div>
197
+ </div>
198
+ </section>
199
+
200
+ <div class="hr-triple" role="separator">
201
+ <span class="hr-triple-inner"></span>
202
+ </div>
203
+ {% endif %}
204
+
205
+ {%- comment -%} Chapter VI: Work Timeline (static table) {%- endcomment -%}
206
+ {% if featuredSessions.size > 0 %}
207
+ <section aria-label="Work timeline">
208
+ <h2 class="chapter-heading fade-in fade-in-d4">
209
+ <span class="chapter-heading__number">Chapter VI</span>
210
+ Work Timeline
211
+ </h2>
212
+ <div style="overflow-x: auto;">
213
+ <table class="timeline-table">
214
+ <thead>
215
+ <tr>
216
+ <th scope="col">#</th>
217
+ <th scope="col">Title</th>
218
+ <th scope="col">Date</th>
219
+ <th scope="col">Duration</th>
220
+ <th scope="col">LOC</th>
221
+ <th scope="col">Source</th>
222
+ </tr>
223
+ </thead>
224
+ <tbody>
225
+ {% for s in featuredSessions %}
226
+ <tr>
227
+ <td>{{ forloop.index }}</td>
228
+ <td>{{ s.title }}</td>
229
+ <td>{% if s.recordedAt %}{{ s.recordedAt | formatDateShort }}{% endif %}</td>
230
+ <td>{{ s.durationMinutes | formatDuration }}</td>
231
+ <td>{{ s.locChanged | localeNumber }}</td>
232
+ <td>{{ s.sourceTool | default: "—" }}</td>
233
+ </tr>
234
+ {% endfor %}
235
+ </tbody>
236
+ </table>
237
+ </div>
238
+ </section>
239
+
240
+ <div class="hr-triple" role="separator">
241
+ <span class="hr-triple-inner"></span>
242
+ </div>
243
+ {% endif %}
244
+
245
+ {%- comment -%} Chapter VII: Featured Sessions {%- endcomment -%}
246
+ {% if featuredSessions.size > 0 %}
247
+ <section class="session-list" aria-label="Featured sessions">
248
+ <h2 class="chapter-heading fade-in fade-in-d4">
249
+ <span class="chapter-heading__number">Chapter VII</span>
250
+ Featured Sessions
251
+ </h2>
252
+
253
+ {% for s in featuredSessions %}
254
+ <article class="session-card">
255
+ <span class="session-card__page">p. {{ forloop.index }}</span>
256
+ <div class="session-card__number">Session {{ forloop.index }}</div>
257
+ <h3 class="session-card__title">
258
+ <a href="{{ sessionBaseUrl }}/{{ s.slug }}{{ sessionSuffix }}">{{ s.title }}</a>
259
+ {% if s.skills.size > 0 %}
260
+ <span class="session-card__tag">{{ s.skills | first }}</span>
261
+ {% endif %}
262
+ </h3>
263
+ <div class="session-card__meta">
264
+ <span>{{ s.durationMinutes | formatDuration }}</span>
265
+ <span>{{ s.locChanged | localeNumber }} LOC</span>
266
+ {% if s.agentSummary %}
267
+ <span>{{ s.agentSummary.agents.size }} agents</span>
268
+ {% endif %}
269
+ </div>
270
+ </article>
271
+ {% endfor %}
272
+ </section>
273
+ {% endif %}
274
+ </main>
275
+
276
+ <div class="hr-triple" role="separator">
277
+ <span class="hr-triple-inner"></span>
278
+ </div>
279
+
280
+ {%- comment -%} Colophon {%- endcomment -%}
281
+ <footer class="colophon" role="contentinfo">
282
+ <div class="colophon__mark" aria-hidden="true">&sect;</div>
283
+ <p>Set in Crimson Pro &amp; IBM Plex Mono</p>
284
+ <p>Composed with AI-assisted development tools</p>
285
+ <p>Published on heyi.am</p>
286
+ </footer>
287
+ </div>
288
+
289
+ </div>