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.
Files changed (186) hide show
  1. package/README.md +45 -0
  2. package/dist/auth.js +29 -3
  3. package/dist/config.js +10 -1
  4. package/dist/db.js +0 -1
  5. package/dist/export.js +124 -27
  6. package/dist/format-utils.js +5 -0
  7. package/dist/github.js +381 -0
  8. package/dist/index.js +168 -0
  9. package/dist/mount.js +300 -102
  10. package/dist/parsers/claude.js +2 -28
  11. package/dist/parsers/codex.js +2 -26
  12. package/dist/parsers/cursor.js +2 -26
  13. package/dist/parsers/duration.js +35 -0
  14. package/dist/parsers/gemini.js +2 -20
  15. package/dist/parsers/index.js +22 -3
  16. package/dist/parsers/types.js +0 -1
  17. package/dist/public/assets/index-Coilyhtr.css +1 -0
  18. package/dist/public/assets/index-D0noVMFu.js +44 -0
  19. package/dist/public/index.html +2 -2
  20. package/dist/redact.js +4 -104
  21. package/dist/render/build-render-data.js +9 -2
  22. package/dist/render/index.js +32 -5
  23. package/dist/render/liquid.js +147 -7
  24. package/dist/render/mock-data.js +303 -0
  25. package/dist/render/templates/aurora/portfolio.liquid +192 -0
  26. package/dist/render/templates/aurora/project.liquid +260 -0
  27. package/dist/render/templates/aurora/session.liquid +223 -0
  28. package/dist/render/templates/aurora/styles.css +1184 -0
  29. package/dist/render/templates/bauhaus/portfolio.liquid +169 -0
  30. package/dist/render/templates/bauhaus/project.liquid +300 -0
  31. package/dist/render/templates/bauhaus/session.liquid +333 -0
  32. package/dist/render/templates/bauhaus/styles.css +1645 -0
  33. package/dist/render/templates/blueprint/portfolio.liquid +153 -0
  34. package/dist/render/templates/blueprint/project.liquid +286 -0
  35. package/dist/render/templates/blueprint/session.liquid +248 -0
  36. package/dist/render/templates/blueprint/styles.css +1289 -0
  37. package/dist/render/templates/canvas/portfolio.liquid +203 -0
  38. package/dist/render/templates/canvas/project.liquid +235 -0
  39. package/dist/render/templates/canvas/session.liquid +223 -0
  40. package/dist/render/templates/canvas/styles.css +1440 -0
  41. package/dist/render/templates/carbon/portfolio.liquid +160 -0
  42. package/dist/render/templates/carbon/project.liquid +249 -0
  43. package/dist/render/templates/carbon/session.liquid +190 -0
  44. package/dist/render/templates/carbon/styles.css +1097 -0
  45. package/dist/render/templates/chalk/portfolio.liquid +189 -0
  46. package/dist/render/templates/chalk/project.liquid +245 -0
  47. package/dist/render/templates/chalk/session.liquid +215 -0
  48. package/dist/render/templates/chalk/styles.css +1161 -0
  49. package/dist/render/templates/circuit/portfolio.liquid +152 -0
  50. package/dist/render/templates/circuit/project.liquid +247 -0
  51. package/dist/render/templates/circuit/session.liquid +205 -0
  52. package/dist/render/templates/circuit/styles.css +1409 -0
  53. package/dist/render/templates/cosmos/portfolio.liquid +222 -0
  54. package/dist/render/templates/cosmos/project.liquid +327 -0
  55. package/dist/render/templates/cosmos/session.liquid +239 -0
  56. package/dist/render/templates/cosmos/styles.css +1157 -0
  57. package/dist/render/templates/daylight/portfolio.liquid +207 -0
  58. package/dist/render/templates/daylight/project.liquid +229 -0
  59. package/dist/render/templates/daylight/session.liquid +219 -0
  60. package/dist/render/templates/daylight/styles.css +1315 -0
  61. package/dist/render/templates/editorial/portfolio.liquid +110 -0
  62. package/dist/render/templates/editorial/project.liquid +202 -0
  63. package/dist/render/templates/editorial/session.liquid +171 -0
  64. package/dist/render/templates/editorial/styles.css +826 -0
  65. package/dist/render/templates/ember/portfolio.liquid +306 -0
  66. package/dist/render/templates/ember/project.liquid +232 -0
  67. package/dist/render/templates/ember/session.liquid +202 -0
  68. package/dist/render/templates/ember/styles.css +1289 -0
  69. package/dist/render/templates/glacier/portfolio.liquid +261 -0
  70. package/dist/render/templates/glacier/project.liquid +288 -0
  71. package/dist/render/templates/glacier/session.liquid +217 -0
  72. package/dist/render/templates/glacier/styles.css +1204 -0
  73. package/dist/render/templates/grid/portfolio.liquid +255 -0
  74. package/dist/render/templates/grid/project.liquid +306 -0
  75. package/dist/render/templates/grid/session.liquid +260 -0
  76. package/dist/render/templates/grid/styles.css +1445 -0
  77. package/dist/render/templates/kinetic/portfolio.liquid +158 -0
  78. package/dist/render/templates/kinetic/project.liquid +242 -0
  79. package/dist/render/templates/kinetic/session.liquid +228 -0
  80. package/dist/render/templates/kinetic/styles.css +948 -0
  81. package/dist/render/templates/meridian/portfolio.liquid +243 -0
  82. package/dist/render/templates/meridian/project.liquid +376 -0
  83. package/dist/render/templates/meridian/session.liquid +298 -0
  84. package/dist/render/templates/meridian/styles.css +1375 -0
  85. package/dist/render/templates/minimal/portfolio.liquid +71 -0
  86. package/dist/render/templates/minimal/project.liquid +154 -0
  87. package/dist/render/templates/minimal/session.liquid +140 -0
  88. package/dist/render/templates/minimal/styles.css +529 -0
  89. package/dist/render/templates/mono/portfolio.liquid +281 -0
  90. package/dist/render/templates/mono/project.liquid +275 -0
  91. package/dist/render/templates/mono/session.liquid +276 -0
  92. package/dist/render/templates/mono/styles.css +1022 -0
  93. package/dist/render/templates/neon/portfolio.liquid +207 -0
  94. package/dist/render/templates/neon/project.liquid +225 -0
  95. package/dist/render/templates/neon/session.liquid +195 -0
  96. package/dist/render/templates/neon/styles.css +1271 -0
  97. package/dist/render/templates/noir/portfolio.liquid +137 -0
  98. package/dist/render/templates/noir/project.liquid +220 -0
  99. package/dist/render/templates/noir/session.liquid +241 -0
  100. package/dist/render/templates/noir/styles.css +1229 -0
  101. package/dist/render/templates/obsidian/portfolio.liquid +247 -0
  102. package/dist/render/templates/obsidian/project.liquid +280 -0
  103. package/dist/render/templates/obsidian/session.liquid +241 -0
  104. package/dist/render/templates/obsidian/styles.css +1407 -0
  105. package/dist/render/templates/paper/portfolio.liquid +257 -0
  106. package/dist/render/templates/paper/project.liquid +235 -0
  107. package/dist/render/templates/paper/session.liquid +271 -0
  108. package/dist/render/templates/paper/styles.css +1513 -0
  109. package/dist/render/templates/parallax/portfolio.liquid +295 -0
  110. package/dist/render/templates/parallax/project.liquid +275 -0
  111. package/dist/render/templates/parallax/session.liquid +295 -0
  112. package/dist/render/templates/parallax/styles.css +1880 -0
  113. package/dist/render/templates/parchment/portfolio.liquid +280 -0
  114. package/dist/render/templates/parchment/project.liquid +289 -0
  115. package/dist/render/templates/parchment/session.liquid +346 -0
  116. package/dist/render/templates/parchment/styles.css +1401 -0
  117. package/dist/render/templates/partials/_beats.liquid +16 -0
  118. package/dist/render/templates/partials/_breadcrumb.liquid +9 -0
  119. package/dist/render/templates/partials/_footer.liquid +7 -0
  120. package/dist/render/templates/partials/_growth-chart.liquid +7 -0
  121. package/dist/render/templates/partials/_key-decisions.liquid +20 -0
  122. package/dist/render/templates/partials/_links.liquid +16 -0
  123. package/dist/render/templates/partials/_narrative.liquid +8 -0
  124. package/dist/render/templates/partials/_phases.liquid +20 -0
  125. package/dist/render/templates/partials/_portfolio-header.liquid +20 -0
  126. package/dist/render/templates/partials/_portfolio-projects.liquid +16 -0
  127. package/dist/render/templates/partials/_portfolio-stats.liquid +19 -0
  128. package/dist/render/templates/partials/_qa.liquid +13 -0
  129. package/dist/render/templates/partials/_screenshot.liquid +15 -0
  130. package/dist/render/templates/partials/_session-cards.liquid +30 -0
  131. package/dist/render/templates/partials/_session-header.liquid +39 -0
  132. package/dist/render/templates/partials/_session-sidebar.liquid +30 -0
  133. package/dist/render/templates/partials/_skills.liquid +12 -0
  134. package/dist/render/templates/partials/_source-breakdown.liquid +22 -0
  135. package/dist/render/templates/partials/_stats.liquid +38 -0
  136. package/dist/render/templates/partials/_work-timeline.liquid +7 -0
  137. package/dist/render/templates/project.liquid +7 -4
  138. package/dist/render/templates/radar/portfolio.liquid +223 -0
  139. package/dist/render/templates/radar/project.liquid +278 -0
  140. package/dist/render/templates/radar/session.liquid +300 -0
  141. package/dist/render/templates/radar/styles.css +1055 -0
  142. package/dist/render/templates/showcase/portfolio.liquid +221 -0
  143. package/dist/render/templates/showcase/project.liquid +237 -0
  144. package/dist/render/templates/showcase/session.liquid +210 -0
  145. package/dist/render/templates/showcase/styles.css +1284 -0
  146. package/dist/render/templates/signal/portfolio.liquid +217 -0
  147. package/dist/render/templates/signal/project.liquid +278 -0
  148. package/dist/render/templates/signal/session.liquid +282 -0
  149. package/dist/render/templates/signal/styles.css +1401 -0
  150. package/dist/render/templates/strata/portfolio.liquid +180 -0
  151. package/dist/render/templates/strata/project.liquid +282 -0
  152. package/dist/render/templates/strata/session.liquid +261 -0
  153. package/dist/render/templates/strata/styles.css +1354 -0
  154. package/dist/render/templates/styles.css +1190 -0
  155. package/dist/render/templates/terminal/portfolio.liquid +102 -0
  156. package/dist/render/templates/terminal/project.liquid +161 -0
  157. package/dist/render/templates/terminal/session.liquid +145 -0
  158. package/dist/render/templates/terminal/styles.css +497 -0
  159. package/dist/render/templates/verdant/portfolio.liquid +321 -0
  160. package/dist/render/templates/verdant/project.liquid +309 -0
  161. package/dist/render/templates/verdant/session.liquid +237 -0
  162. package/dist/render/templates/verdant/styles.css +1261 -0
  163. package/dist/render/templates/zen/portfolio.liquid +124 -0
  164. package/dist/render/templates/zen/project.liquid +187 -0
  165. package/dist/render/templates/zen/session.liquid +203 -0
  166. package/dist/render/templates/zen/styles.css +1211 -0
  167. package/dist/render/templates.js +90 -0
  168. package/dist/routes/auth.js +7 -3
  169. package/dist/routes/context.js +17 -10
  170. package/dist/routes/delete.js +195 -0
  171. package/dist/routes/enhance.js +57 -40
  172. package/dist/routes/export.js +14 -4
  173. package/dist/routes/github.js +254 -0
  174. package/dist/routes/index.js +2 -0
  175. package/dist/routes/portfolio-render-data.js +160 -0
  176. package/dist/routes/preview.js +555 -108
  177. package/dist/routes/projects.js +61 -24
  178. package/dist/routes/publish.js +320 -31
  179. package/dist/routes/settings.js +194 -1
  180. package/dist/routes/sse.js +9 -0
  181. package/dist/search.js +6 -0
  182. package/dist/server.js +11 -3
  183. package/dist/settings.js +112 -9
  184. package/package.json +3 -4
  185. package/dist/public/assets/index-CC9G8EF1.js +0 -21
  186. package/dist/public/assets/index-Dalqz2mC.css +0 -1
@@ -0,0 +1,257 @@
1
+ <div class="heyiam-portfolio paper" data-render-version="2" data-template="paper" data-username="{{ user.username }}">
2
+
3
+ {% if hasProfile %}
4
+ {%- comment -%} Masthead {%- endcomment -%}
5
+ <header class="masthead fade-in fade-in-d1" role="banner">
6
+ {% if user.displayName != blank %}
7
+ <h1 class="masthead__title" data-portfolio-field="displayName">{{ user.displayName }}</h1>
8
+ {% endif %}
9
+ {% if user.bio %}
10
+ <p class="masthead__edition">A Developer Portfolio</p>
11
+ {% endif %}
12
+ <hr class="masthead__rule" aria-hidden="true">
13
+ {% if user.location %}
14
+ <p class="masthead__dateline">{{ user.location }}</p>
15
+ {% endif %}
16
+ </header>
17
+ {% endif %}
18
+
19
+ <main id="main-content">
20
+ {% if hasProfile %}
21
+ {%- comment -%} Byline / Bio {%- endcomment -%}
22
+ <section class="byline fade-in fade-in-d2" aria-label="About">
23
+ {% if user.photoUrl %}
24
+ <img src="{{ user.photoUrl }}" alt="{{ user.displayName }}" class="byline__photo portfolio-photo" width="100" height="130" data-portfolio-field="photoBase64"{% unless user.photoUrl %} data-portfolio-empty="true"{% endunless %}>
25
+ {% endif %}
26
+ {% if user.displayName != blank %}<p class="byline__name">By {{ user.displayName }}</p>{% endif %}
27
+ {% if user.location %}
28
+ <p class="byline__location portfolio-location" data-portfolio-field="location">{{ user.location }}</p>
29
+ {% endif %}
30
+ {% if user.bio %}
31
+ <p class="byline__bio portfolio-bio" data-portfolio-field="bio">{{ user.bio }}</p>
32
+ {% endif %}
33
+ <div class="byline__links">
34
+ <a href="{% if user.email %}mailto:{{ user.email }}{% endif %}" data-portfolio-field="email"{% unless user.email %} data-portfolio-empty="true"{% endunless %}>
35
+ <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>
36
+ {{ user.email }}
37
+ </a>
38
+ <a href="{% if user.linkedinUrl %}{{ user.linkedinUrl }}{% endif %}" target="_blank" rel="noopener" data-portfolio-field="linkedinUrl"{% unless user.linkedinUrl %} data-portfolio-empty="true"{% endunless %}>
39
+ <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>
40
+ LinkedIn
41
+ </a>
42
+ <a href="{% if user.githubUrl %}{{ user.githubUrl }}{% endif %}" target="_blank" rel="noopener" data-portfolio-field="githubUrl"{% unless user.githubUrl %} data-portfolio-empty="true"{% endunless %}>
43
+ <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>
44
+ GitHub
45
+ </a>
46
+ <a href="{% if user.twitterHandle %}https://x.com/{{ user.twitterHandle }}{% endif %}" target="_blank" rel="noopener" data-portfolio-field="twitterHandle"{% unless user.twitterHandle %} data-portfolio-empty="true"{% endunless %}>
47
+ <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>
48
+ @{{ user.twitterHandle }}
49
+ </a>
50
+ <a href="{% if user.websiteUrl %}{{ user.websiteUrl }}{% endif %}" target="_blank" rel="noopener" data-portfolio-field="websiteUrl"{% unless user.websiteUrl %} data-portfolio-empty="true"{% endunless %}>{{ user.websiteUrl | stripProtocol }}</a>
51
+ {% if user.resumeUrl %}
52
+ <a href="{{ user.resumeUrl }}" download>
53
+ <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>
54
+ Resume (PDF)
55
+ </a>
56
+ {% endif %}
57
+ </div>
58
+ </section>
59
+ {% endif %}
60
+
61
+ {%- comment -%} Aggregate Stats {%- endcomment -%}
62
+ <section class="stats-section fade-in fade-in-d3" aria-label="Portfolio statistics">
63
+ <h2 class="stats-section__heading">Portfolio at a Glance</h2>
64
+ <table class="stats-table" role="table">
65
+ <thead>
66
+ <tr>
67
+ <th scope="col">Metric</th>
68
+ <th scope="col">Value</th>
69
+ </tr>
70
+ </thead>
71
+ <tbody>
72
+ <tr>
73
+ <td>Projects</td>
74
+ <td>{{ projects.size }}</td>
75
+ </tr>
76
+ <tr>
77
+ <td>Sessions</td>
78
+ <td>{{ totalSessions }}</td>
79
+ </tr>
80
+ <tr>
81
+ <td>Lines Changed</td>
82
+ <td>{{ totalLoc | formatLoc }}</td>
83
+ </tr>
84
+ </tbody>
85
+ </table>
86
+
87
+ <h3 class="section-label" style="margin-top:1.5rem">Working Pattern</h3>
88
+ <table class="stats-table" role="table">
89
+ <tbody>
90
+ {% if efficiencyMultiplier %}
91
+ <tr><td>You</td><td class="stat-value">{{ totalDurationMinutes | formatDuration }}</td></tr>
92
+ <tr><td>Agents</td><td class="stat-value" style="font-weight:600">{{ totalAgentDurationMinutes | formatDuration }}</td></tr>
93
+ <tr class="multiplier-row"><td colspan="2" class="stat-value" style="font-size:1.25rem">{{ efficiencyMultiplier }} multiplier</td></tr>
94
+ {% else %}
95
+ <tr><td>Total Time</td><td class="stat-value">{{ totalDurationMinutes | formatDuration }}</td></tr>
96
+ {% endif %}
97
+ </tbody>
98
+ </table>
99
+ </section>
100
+
101
+ {%- comment -%} Ornamental break {%- endcomment -%}
102
+ <div class="dingbat" aria-hidden="true">&#8226; &#8226; &#8226;</div>
103
+
104
+ {%- comment -%} Projects {%- endcomment -%}
105
+ {% if projects.size > 0 %}
106
+ <section class="projects-section fade-in fade-in-d4" aria-label="Projects">
107
+ <h2 class="projects-section__heading">Selected Works</h2>
108
+ <p class="projects-section__subheading">
109
+ {{ projects.size }} project{% if projects.size != 1 %}s{% endif %}, {{ totalSessions }} sessions
110
+ </p>
111
+
112
+ <div class="projects-columns">
113
+ {% for p in projects %}
114
+ <article class="project-card fade-in fade-in-d{{ forloop.index | plus: 4 }}">
115
+ <p class="project-card__number">Project {{ forloop.index }}</p>
116
+ <h3 class="project-card__headline">
117
+ <a href="/{{ user.username }}/{{ p.slug }}">{{ p.title }}</a>
118
+ </h3>
119
+ {% if p.narrative %}
120
+ <p class="project-card__narrative">{{ p.narrative | truncate: 120 }}</p>
121
+ {% endif %}
122
+ <p class="project-card__meta">
123
+ <span>{{ p.totalSessions }} sessions</span>
124
+ <span>{{ p.totalDurationMinutes | formatDuration }}</span>
125
+ <span>{{ p.totalLoc | localeNumber }} LOC</span>
126
+ </p>
127
+ {% if p.sourceCounts.size > 0 %}
128
+ {% assign pTotalSrc = 0 %}
129
+ {% for src in p.sourceCounts %}
130
+ {% assign pTotalSrc = pTotalSrc | plus: src.count %}
131
+ {% endfor %}
132
+ {% if pTotalSrc > 0 %}
133
+ <div class="project-card__source-bar" role="img" aria-label="Source distribution">
134
+ {% for src in p.sourceCounts %}
135
+ {% assign pSrcPct = src.count | times: 100.0 | divided_by: pTotalSrc | round %}
136
+ <div class="project-card__source-bar-fill" style="width: {{ pSrcPct }}%"></div>
137
+ {% endfor %}
138
+ </div>
139
+ <p class="project-card__source">
140
+ {% for src in p.sourceCounts %}
141
+ {% assign pSrcPct = src.count | times: 100.0 | divided_by: pTotalSrc | round %}
142
+ {% if forloop.first == false %} &middot; {% endif %}{{ src.tool }} {{ pSrcPct }}%
143
+ {% endfor %}
144
+ </p>
145
+ {% endif %}
146
+ {% endif %}
147
+ {% if p.skills.size > 0 %}
148
+ <div class="project-card__skills" aria-label="Skills used in {{ p.title }}">
149
+ {% for skill in p.skills %}
150
+ <span class="skill-tag chip">{{ skill }}</span>
151
+ {% endfor %}
152
+ </div>
153
+ {% endif %}
154
+ </article>
155
+ {% endfor %}
156
+ </div>
157
+ </section>
158
+ {% endif %}
159
+
160
+ <hr class="section-rule">
161
+
162
+ {%- comment -%} Recent Activity {%- endcomment -%}
163
+ {% if projects.size > 0 %}
164
+ <section class="activity-section fade-in fade-in-d8" aria-label="Recent activity">
165
+ <h2 class="section-label">Recent Activity</h2>
166
+ <div class="table-scroll">
167
+ <table class="activity-table" role="table">
168
+ <thead>
169
+ <tr>
170
+ <th scope="col">Project</th>
171
+ <th scope="col">Sessions</th>
172
+ <th scope="col" class="text-right">Hours</th>
173
+ <th scope="col" class="text-right">LOC</th>
174
+ </tr>
175
+ </thead>
176
+ <tbody>
177
+ {% for p in projects %}
178
+ <tr>
179
+ <td><a href="/{{ user.username }}/{{ p.slug }}">{{ p.title }}</a></td>
180
+ <td>{{ p.totalSessions }}</td>
181
+ <td class="text-right">{{ p.totalDurationMinutes | formatDuration }}</td>
182
+ <td class="text-right">{{ p.totalLoc | localeNumber }}</td>
183
+ </tr>
184
+ {% endfor %}
185
+ </tbody>
186
+ </table>
187
+ </div>
188
+ </section>
189
+ {% endif %}
190
+
191
+ {%- comment -%} Source Summary {%- endcomment -%}
192
+ {% if sourceCounts.size > 0 %}
193
+ {% assign totalSourceSessions = 0 %}
194
+ {% for src in sourceCounts %}
195
+ {% assign totalSourceSessions = totalSourceSessions | plus: src.count %}
196
+ {% endfor %}
197
+ {% if totalSourceSessions > 0 %}
198
+ <section class="source-summary fade-in fade-in-d9" aria-label="Overall source breakdown">
199
+ <h2 class="section-label">Source Distribution</h2>
200
+ <div class="source-bar" role="img" aria-label="Aggregate source distribution across all projects">
201
+ {% for src in sourceCounts %}
202
+ {% assign srcPct = src.count | times: 100.0 | divided_by: totalSourceSessions | round %}
203
+ <div class="source-bar__segment source-bar__segment--{% if forloop.first %}dark{% else %}light{% endif %}" style="flex: {{ srcPct }};"></div>
204
+ {% endfor %}
205
+ </div>
206
+ <div class="source-labels">
207
+ {% for src in sourceCounts %}
208
+ {% assign srcPct = src.count | times: 100.0 | divided_by: totalSourceSessions | round %}
209
+ <span>
210
+ <span class="source-label__swatch source-label__swatch--{% if forloop.first %}dark{% else %}light{% endif %}"></span>
211
+ {{ src.tool }} {{ srcPct }}%
212
+ </span>
213
+ {% endfor %}
214
+ </div>
215
+ </section>
216
+ {% endif %}
217
+ {% endif %}
218
+
219
+ {%- comment -%} Aggregate Skills {%- endcomment -%}
220
+ {% assign allSkills = '' %}
221
+ {% for p in projects %}
222
+ {% for skill in p.skills %}
223
+ {% unless allSkills contains skill %}
224
+ {% if allSkills != '' %}{% assign allSkills = allSkills | append: '|||' %}{% endif %}
225
+ {% assign allSkills = allSkills | append: skill %}
226
+ {% endunless %}
227
+ {% endfor %}
228
+ {% endfor %}
229
+ {% assign skillList = allSkills | split: '|||' %}
230
+ {% if skillList.size > 0 %}
231
+ <section class="aggregate-skills fade-in fade-in-d10" aria-label="All skills">
232
+ <h2 class="section-label">Technologies Used</h2>
233
+ <div class="aggregate-skills__list">
234
+ {% for skill in skillList %}
235
+ <span class="skill-tag chip">{{ skill }}</span>
236
+ {% endfor %}
237
+ </div>
238
+ </section>
239
+ {% endif %}
240
+
241
+ {%- comment -%} Colophon {%- endcomment -%}
242
+ <section class="colophon fade-in fade-in-d10" aria-label="Colophon">
243
+ <p class="colophon__text">
244
+ Built with AI-assisted development tools.
245
+ Every session recorded, every decision documented.
246
+ </p>
247
+ </section>
248
+ </main>
249
+
250
+ {%- comment -%} Footer {%- endcomment -%}
251
+ <footer class="page-footer" role="contentinfo">
252
+ <p class="page-footer__text">
253
+ Published on <a href="https://heyi.am">heyi.am</a> &mdash; Paper Template
254
+ </p>
255
+ </footer>
256
+
257
+ </div>
@@ -0,0 +1,235 @@
1
+ <div class="heyiam-project paper" data-render-version="2" data-template="paper"{% if sessionBaseUrl %} data-session-base-url="{{ sessionBaseUrl }}"{% endif %} data-username="{{ user.username }}" data-project-slug="{{ project.slug }}">
2
+
3
+ {%- comment -%} Masthead {%- endcomment -%}
4
+ <header class="masthead fade-in fade-in-d1" role="banner">
5
+ <h1 class="masthead__title"><a href="/{{ user.username }}">{{ user.username }}</a></h1>
6
+ </header>
7
+
8
+ <main id="main-content">
9
+ {%- comment -%} Breadcrumb {%- endcomment -%}
10
+ <nav class="breadcrumb" aria-label="Breadcrumb">
11
+ <a href="/{{ user.username }}">{{ user.username }}</a>
12
+ <span class="breadcrumb__separator">/</span>
13
+ <span aria-current="page">{{ project.slug }}</span>
14
+ </nav>
15
+
16
+ {%- comment -%} Article Header {%- endcomment -%}
17
+ <header class="article-header fade-in fade-in-d2">
18
+ <p class="article-header__kicker">Project Report</p>
19
+ <h2 class="article-header__headline" data-editable="title">{{ project.title }}</h2>
20
+ {% if project.repoUrl or project.projectUrl %}
21
+ <p class="article-header__links">
22
+ {% if project.repoUrl %}
23
+ <a href="{{ project.repoUrl }}" target="_blank" rel="noopener">{{ project.repoUrl | stripProtocol }}</a>
24
+ {% endif %}
25
+ {% if project.repoUrl and project.projectUrl %}
26
+ &middot;
27
+ {% endif %}
28
+ {% if project.projectUrl %}
29
+ <a href="{{ project.projectUrl }}" target="_blank" rel="noopener">{{ project.projectUrl | stripProtocol }}</a>
30
+ {% endif %}
31
+ </p>
32
+ {% endif %}
33
+ </header>
34
+
35
+ {%- comment -%} Screenshot {%- endcomment -%}
36
+ {% if project.screenshotUrl %}
37
+ <figure class="screenshot fade-in fade-in-d3" role="img" aria-label="{{ project.title }} screenshot">
38
+ <div class="screenshot__chrome browser-chrome">
39
+ <span class="screenshot__dot"></span>
40
+ <span class="screenshot__dot"></span>
41
+ <span class="screenshot__dot"></span>
42
+ {% if project.projectUrl %}
43
+ <span class="screenshot__url">{{ project.projectUrl | stripProtocol }}</span>
44
+ {% endif %}
45
+ </div>
46
+ <div class="screenshot__body">
47
+ <img src="{{ project.screenshotUrl }}" alt="{{ project.title }} screenshot" style="width:100%;height:100%;object-fit:cover;">
48
+ </div>
49
+ </figure>
50
+ {% endif %}
51
+
52
+ {%- comment -%} Narrative {%- endcomment -%}
53
+ {% if project.narrative %}
54
+ <section class="narrative fade-in fade-in-d3" aria-label="Project narrative">
55
+ <p>{{ project.narrative }}</p>
56
+ </section>
57
+ {% endif %}
58
+
59
+ {%- comment -%} Stats {%- endcomment -%}
60
+ <section class="stats-section fade-in fade-in-d4" aria-label="Project statistics">
61
+ <h2 class="section-label">Project Data</h2>
62
+ <table class="stats-table" role="table">
63
+ <thead>
64
+ <tr>
65
+ <th scope="col">Metric</th>
66
+ <th scope="col">Value</th>
67
+ </tr>
68
+ </thead>
69
+ <tbody>
70
+ <tr><td>Sessions</td><td>{{ project.totalSessions }}</td></tr>
71
+ <tr><td>Lines Changed</td><td>{{ project.totalLoc | localeNumber }}</td></tr>
72
+ <tr><td>Files Changed</td><td>{{ project.totalFilesChanged }}</td></tr>
73
+ {% if project.totalTokens %}
74
+ <tr><td>Total Tokens</td><td>{{ project.totalTokens | formatTokens }}</td></tr>
75
+ {% endif %}
76
+ </tbody>
77
+ </table>
78
+
79
+ <h3 class="section-label" style="margin-top:1.5rem">Working Pattern</h3>
80
+ <table class="stats-table" role="table">
81
+ <tbody>
82
+ {% if efficiencyMultiplier %}
83
+ <tr><td>My time</td><td class="stat-value">{{ project.totalDurationMinutes | formatDuration }}</td></tr>
84
+ <tr><td>Agent time</td><td class="stat-value" style="font-weight:600">{{ project.totalAgentDurationMinutes | formatDuration }}</td></tr>
85
+ <tr class="multiplier-row"><td colspan="2" class="stat-value" style="font-size:1.25rem">{{ efficiencyMultiplier }} multiplier</td></tr>
86
+ {% else %}
87
+ <tr><td>Total time</td><td class="stat-value">{{ project.totalDurationMinutes | formatDuration }}</td></tr>
88
+ {% endif %}
89
+ </tbody>
90
+ </table>
91
+ </section>
92
+
93
+ {%- comment -%} Work Timeline Table {%- endcomment -%}
94
+ {% if featuredSessions.size > 0 %}
95
+ <section class="timeline-section fade-in fade-in-d5" aria-label="Work timeline">
96
+ <h2 class="section-label">Work Timeline</h2>
97
+ <div class="table-scroll">
98
+ <table class="timeline-table" role="table">
99
+ <thead>
100
+ <tr>
101
+ <th scope="col">#</th>
102
+ <th scope="col">Title</th>
103
+ <th scope="col">Date</th>
104
+ <th scope="col" class="text-right">Duration</th>
105
+ <th scope="col" class="text-right">LOC</th>
106
+ <th scope="col">Source</th>
107
+ {% if featuredSessions[0].agentSummary %}
108
+ <th scope="col" class="text-right">Agents</th>
109
+ {% endif %}
110
+ </tr>
111
+ </thead>
112
+ <tbody>
113
+ {% for s in featuredSessions %}
114
+ <tr>
115
+ <td>{{ forloop.index }}</td>
116
+ <td>{{ s.title }}</td>
117
+ <td>{{ s.recordedAt | formatDateShort }}</td>
118
+ <td class="text-right">{{ s.durationMinutes | formatDuration }}</td>
119
+ <td class="text-right">{{ s.locChanged | localeNumber }}</td>
120
+ <td>{{ s.sourceTool }}</td>
121
+ {% if s.agentSummary %}
122
+ <td class="text-right">{{ s.agentSummary.agents.size }}</td>
123
+ {% endif %}
124
+ </tr>
125
+ {% endfor %}
126
+ </tbody>
127
+ </table>
128
+ </div>
129
+ </section>
130
+ {% endif %}
131
+
132
+ {%- comment -%} Phases (arc) {%- endcomment -%}
133
+ {% if arc.size > 0 %}
134
+ <section class="phases-section fade-in fade-in-d5" aria-label="Project phases">
135
+ <h2 class="section-label">Project Arc</h2>
136
+ <ol class="phases-list" role="list">
137
+ {% for item in arc %}
138
+ <li class="phase-item">
139
+ <span class="phase-item__dateline">{% if item.dates %}{{ item.dates }}{% else %}Phase {{ item.phase }}{% endif %}</span>
140
+ <div class="phase-item__content">
141
+ <h3 class="phase-item__name">{{ item.title }}</h3>
142
+ <p class="phase-item__description">{{ item.description }}</p>
143
+ </div>
144
+ </li>
145
+ {% endfor %}
146
+ </ol>
147
+ </section>
148
+ {% endif %}
149
+
150
+ {%- comment -%} Key Decisions {%- endcomment -%}
151
+ {% if arc.size > 0 %}
152
+ <section class="decisions-section fade-in fade-in-d5" aria-label="Key decisions">
153
+ <h2 class="section-label">Key Decisions</h2>
154
+ <ol class="decisions-list" role="list">
155
+ {% for item in arc %}
156
+ <li class="decision-item">{{ item.description }}</li>
157
+ {% endfor %}
158
+ </ol>
159
+ </section>
160
+ {% endif %}
161
+
162
+ {%- comment -%} Skills {%- endcomment -%}
163
+ {% if project.skills.size > 0 %}
164
+ <section class="skills-section fade-in fade-in-d6" aria-label="Technologies used">
165
+ <h2 class="section-label">Technologies</h2>
166
+ <div class="skills-list">
167
+ {% for skill in project.skills %}
168
+ <span class="skill-tag chip">{{ skill }}</span>
169
+ {% endfor %}
170
+ </div>
171
+ </section>
172
+ {% endif %}
173
+
174
+ {%- comment -%} Source Breakdown {%- endcomment -%}
175
+ {% if sourceCounts.size > 0 %}
176
+ <section class="source-section fade-in fade-in-d6" aria-label="Source breakdown">
177
+ <h2 class="section-label">Source Breakdown</h2>
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 distribution">
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="flex: {{ 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>
193
+ <span class="source-label__swatch{% if forloop.first %} source-label__swatch--claude{% else %} source-label__swatch--cursor{% endif %}"></span>
194
+ {{ src.tool }} {{ srcPct }}%
195
+ </span>
196
+ {% endfor %}
197
+ </div>
198
+ {% endif %}
199
+ </section>
200
+ {% endif %}
201
+
202
+ {%- comment -%} Featured Sessions {%- endcomment -%}
203
+ {% if featuredSessions.size > 0 %}
204
+ <section class="sessions-section fade-in fade-in-d8" aria-label="Featured sessions">
205
+ <h2 class="section-label">Featured Sessions</h2>
206
+ <div class="sessions-columns">
207
+ {% for s in featuredSessions %}
208
+ <article class="session-card">
209
+ <p class="session-card__number">Session {{ forloop.index }}</p>
210
+ <h3 class="session-card__headline">
211
+ <a href="{{ sessionBaseUrl }}/{{ s.slug }}{{ sessionSuffix }}">{{ s.title }}</a>
212
+ {% if s.skills.size > 0 %}
213
+ <span class="session-card__tag">{{ s.skills | first }}</span>
214
+ {% endif %}
215
+ </h3>
216
+ <p class="session-card__meta">
217
+ <span>{{ s.durationMinutes | formatDuration }}</span>
218
+ <span>{{ s.locChanged | localeNumber }} LOC</span>
219
+ {% if s.agentSummary %}
220
+ <span>{{ s.agentSummary.agents.size }} agents</span>
221
+ {% endif %}
222
+ </p>
223
+ </article>
224
+ {% endfor %}
225
+ </div>
226
+ </section>
227
+ {% endif %}
228
+ </main>
229
+
230
+ {%- comment -%} Footer {%- endcomment -%}
231
+ <footer class="page-footer" role="contentinfo">
232
+ <p class="page-footer__text">Published on <a href="https://heyi.am">heyi.am</a> &mdash; Paper Template</p>
233
+ </footer>
234
+
235
+ </div>