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,217 @@
1
+ <div class="heyiam-portfolio signal" data-render-version="2" data-template="signal" data-username="{{ user.username }}">
2
+
3
+ <a href="#main" class="skip-link">Skip to content</a>
4
+
5
+ {%- comment -%} Dashboard Strip {%- endcomment -%}
6
+ <section class="dashboard-strip" aria-label="Portfolio statistics">
7
+ <div class="container">
8
+ <div class="stats-grid">
9
+ <div class="stat-cell">
10
+ <div class="stat-value" data-animate data-target="{{ projects.size }}">0</div>
11
+ <div class="stat-label">Projects</div>
12
+ </div>
13
+ <div class="stat-cell">
14
+ <div class="stat-value" data-animate data-target="{{ totalSessions }}">0</div>
15
+ <div class="stat-label">Sessions</div>
16
+ </div>
17
+ {% if efficiencyMultiplier %}
18
+ <div class="stat-cell--leverage-group">
19
+ <div class="stat-cell">
20
+ <div class="stat-value">{{ totalDurationMinutes | formatDuration }}</div>
21
+ <div class="stat-label">You</div>
22
+ </div>
23
+ <div class="stat-cell">
24
+ <div class="stat-value green">{{ totalAgentDurationMinutes | formatDuration }}</div>
25
+ <div class="stat-label">Agents</div>
26
+ </div>
27
+ <div class="stat-cell">
28
+ <div class="stat-value green">{{ efficiencyMultiplier }}</div>
29
+ <div class="stat-label">Multi</div>
30
+ </div>
31
+ </div>
32
+ {% else %}
33
+ <div class="stat-cell">
34
+ <div class="stat-value">{{ totalDurationMinutes | formatDuration }}</div>
35
+ <div class="stat-label">Time</div>
36
+ </div>
37
+ {% endif %}
38
+ <div class="stat-cell">
39
+ <div class="stat-value" data-animate data-target="{{ totalLoc }}">0</div>
40
+ <div class="stat-label">Lines Changed</div>
41
+ </div>
42
+ </div>
43
+ </div>
44
+ </section>
45
+
46
+ {%- comment -%} Main Content {%- endcomment -%}
47
+ <main id="main" class="container">
48
+
49
+ {% if hasProfile %}
50
+ {%- comment -%} Identity {%- endcomment -%}
51
+ <section class="identity fade-in" aria-label="Developer identity">
52
+ <div class="identity-profile">
53
+ {% if user.photoUrl %}
54
+ <img src="{{ user.photoUrl }}" alt="{{ user.displayName }}" class="identity-photo" width="100" height="100" data-portfolio-field="photoBase64"{% unless user.photoUrl %} data-portfolio-empty="true"{% endunless %}>
55
+ {% endif %}
56
+ <div class="identity-details">
57
+ <div class="identity-top">
58
+ <div>
59
+ {% if user.displayName != blank %}
60
+ <h1 data-portfolio-field="displayName">{{ user.displayName }}</h1>
61
+ {% endif %}
62
+ {% if user.bio != blank %}
63
+ <p class="identity-bio" data-portfolio-field="bio">{{ user.bio }}</p>
64
+ {% endif %}
65
+ {% if user.location != blank %}
66
+ <p class="identity-location" data-portfolio-field="location">{{ user.location }}</p>
67
+ {% endif %}
68
+ </div>
69
+ {% if user.status != blank %}
70
+ <div class="identity-status" aria-label="Status: {{ user.status }}">
71
+ <span class="status-dot" aria-hidden="true"></span>
72
+ {{ user.status }}
73
+ </div>
74
+ {% endif %}
75
+ </div>
76
+ {% if user.email or user.linkedinUrl or user.githubUrl or user.twitterHandle or user.websiteUrl %}
77
+ <ul class="identity-contact" aria-label="Contact and social links">
78
+ <li data-portfolio-field="email"{% unless user.email %} data-portfolio-empty="true"{% endunless %}><a href="{% if user.email %}mailto:{{ user.email }}{% endif %}"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m2 4 10 8 10-8"/></svg>{{ user.email }}</a></li>
79
+ <li data-portfolio-field="linkedinUrl"{% unless user.linkedinUrl %} data-portfolio-empty="true"{% endunless %}><a href="{% if user.linkedinUrl %}{{ user.linkedinUrl }}{% endif %}"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><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>
80
+ <li data-portfolio-field="githubUrl"{% unless user.githubUrl %} data-portfolio-empty="true"{% endunless %}><a href="{% if user.githubUrl %}{{ user.githubUrl }}{% endif %}"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><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>
81
+ <li data-portfolio-field="twitterHandle"{% unless user.twitterHandle %} data-portfolio-empty="true"{% endunless %}><a href="{% if user.twitterHandle %}https://x.com/{{ user.twitterHandle }}{% endif %}"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><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>
82
+ <li data-portfolio-field="websiteUrl"{% unless user.websiteUrl %} data-portfolio-empty="true"{% endunless %}><a href="{% if user.websiteUrl %}{{ user.websiteUrl }}{% endif %}"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 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>
83
+ </ul>
84
+ {% endif %}
85
+ {% if user.resumeUrl %}
86
+ <a href="{{ user.resumeUrl }}" class="identity-resume"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><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>Download Resume</a>
87
+ {% endif %}
88
+ </div>
89
+ </div>
90
+ </section>
91
+ {% endif %}
92
+
93
+ {%- comment -%} Projects Table {%- endcomment -%}
94
+ {% if projects.size > 0 %}
95
+ <section class="fade-in" aria-label="Projects">
96
+ <div class="section-header">
97
+ <h2>Projects</h2>
98
+ <span class="section-tag">{{ projects.size }} total</span>
99
+ <div class="section-line" aria-hidden="true"></div>
100
+ </div>
101
+ <div class="project-table-wrap" role="region" aria-label="Projects table" tabindex="0">
102
+ <table class="project-table">
103
+ <thead>
104
+ <tr>
105
+ <th scope="col">Project</th>
106
+ <th scope="col">Sessions</th>
107
+ <th scope="col">Hours</th>
108
+ <th scope="col">LOC</th>
109
+ <th scope="col">Source Mix</th>
110
+ <th scope="col">Skills</th>
111
+ </tr>
112
+ </thead>
113
+ <tbody>
114
+ {% for p in projects %}
115
+ <tr>
116
+ <td>
117
+ <div class="project-name"><a href="/{{ user.username }}/{{ p.slug }}">{{ p.title }}</a></div>
118
+ {% if p.narrative != blank %}
119
+ <div class="project-narrative">{{ p.narrative }}</div>
120
+ {% endif %}
121
+ </td>
122
+ <td class="stat-mono">{{ p.totalSessions }}</td>
123
+ <td class="stat-mono">{{ p.totalDurationMinutes | formatDuration }}</td>
124
+ <td class="stat-mono stat-green">{{ p.totalLoc | localeNumber }}</td>
125
+ <td class="source-bar-wrap">
126
+ {% if p.sourceCounts.size > 0 %}
127
+ {% assign pTotalSrc = 0 %}
128
+ {% for src in p.sourceCounts %}
129
+ {% assign pTotalSrc = pTotalSrc | plus: src.count %}
130
+ {% endfor %}
131
+ {% if pTotalSrc > 0 %}
132
+ <div class="source-bar">
133
+ {% for src in p.sourceCounts %}
134
+ {% assign pSrcPct = src.count | times: 100.0 | divided_by: pTotalSrc | round %}
135
+ <div class="segment-{{ src.tool | downcase }}" style="width: {{ pSrcPct }}%;" aria-label="{{ src.tool }} {{ pSrcPct }}%"></div>
136
+ {% endfor %}
137
+ </div>
138
+ <div class="source-legend">
139
+ {% for src in p.sourceCounts %}
140
+ {% assign pSrcPct = src.count | times: 100.0 | divided_by: pTotalSrc | round %}
141
+ <span><span class="dot-{{ src.tool | downcase }}" aria-hidden="true">&#9632;</span> {{ pSrcPct }}%</span>
142
+ {% endfor %}
143
+ </div>
144
+ {% endif %}
145
+ {% endif %}
146
+ </td>
147
+ <td>
148
+ {% if p.skills.size > 0 %}
149
+ <div class="skill-badges">
150
+ {% for skill in p.skills %}
151
+ <span class="skill-badge strong">{{ skill }}</span>
152
+ {% endfor %}
153
+ </div>
154
+ {% endif %}
155
+ </td>
156
+ </tr>
157
+ {% endfor %}
158
+ </tbody>
159
+ </table>
160
+ </div>
161
+ </section>
162
+ {% endif %}
163
+
164
+ {%- comment -%} Overall Source Breakdown {%- endcomment -%}
165
+ {% if sourceCounts.size > 0 %}
166
+ {% assign totalSourceSessions = 0 %}
167
+ {% for src in sourceCounts %}
168
+ {% assign totalSourceSessions = totalSourceSessions | plus: src.count %}
169
+ {% endfor %}
170
+ {% if totalSourceSessions > 0 %}
171
+ <section class="source-breakdown fade-in" aria-label="Source breakdown">
172
+ <h3>Source Breakdown — All Projects</h3>
173
+ <div class="source-stacked-bar" role="img" aria-label="Source breakdown">
174
+ {% for src in sourceCounts %}
175
+ {% assign srcPct = src.count | times: 100.0 | divided_by: totalSourceSessions | round %}
176
+ <div class="seg seg-{{ src.tool | downcase }}" style="flex-basis: {{ srcPct }}%;">{{ srcPct }}%</div>
177
+ {% endfor %}
178
+ </div>
179
+ <div class="source-breakdown-legend">
180
+ {% for src in sourceCounts %}
181
+ <div class="legend-item">
182
+ <div class="legend-dot {{ src.tool | downcase }}" aria-hidden="true"></div>
183
+ <span>{{ src.tool }} — {{ src.count }} sessions</span>
184
+ </div>
185
+ {% endfor %}
186
+ </div>
187
+ </section>
188
+ {% endif %}
189
+ {% endif %}
190
+
191
+ {%- comment -%} Skills Summary {%- endcomment -%}
192
+ {% if allSkills.size > 0 %}
193
+ <section class="skills-summary fade-in" aria-label="Skills overview">
194
+ <div class="section-header">
195
+ <h2>Skills</h2>
196
+ <span class="section-tag">Status Board</span>
197
+ <div class="section-line" aria-hidden="true"></div>
198
+ </div>
199
+ <div class="skills-grid">
200
+ {% for skill in allSkills %}
201
+ <span class="skill-badge strong">{{ skill }}</span>
202
+ {% endfor %}
203
+ </div>
204
+ </section>
205
+ {% endif %}
206
+
207
+ </main>
208
+
209
+ {%- comment -%} Footer {%- endcomment -%}
210
+ <footer class="footer">
211
+ <div class="container">
212
+ signal template &middot; heyi.am
213
+ </div>
214
+ </footer>
215
+
216
+
217
+ </div>
@@ -0,0 +1,278 @@
1
+ <div class="heyiam-project signal" data-render-version="2" data-template="signal"{% if sessionBaseUrl %} data-session-base-url="{{ sessionBaseUrl }}"{% endif %} data-username="{{ user.username }}" data-project-slug="{{ project.slug }}">
2
+
3
+ <a href="#main" class="skip-link">Skip to content</a>
4
+
5
+ {%- comment -%} Breadcrumb {%- endcomment -%}
6
+ <div class="container">
7
+ <nav class="breadcrumb" aria-label="Breadcrumb">
8
+ <a href="/{{ user.username }}">{{ user.username }}</a>
9
+ <span class="sep" aria-hidden="true">/</span>
10
+ <span aria-current="page">{{ project.slug }}</span>
11
+ </nav>
12
+ </div>
13
+
14
+ {%- comment -%} Dashboard Strip {%- endcomment -%}
15
+ <section class="dashboard-strip" aria-label="Project statistics">
16
+ <div class="container">
17
+ <div class="stats-grid stats-grid--6">
18
+ <div class="stat-cell">
19
+ <div class="stat-value" data-animate data-target="{{ project.totalSessions }}">0</div>
20
+ <div class="stat-label">Sessions</div>
21
+ </div>
22
+ {% if efficiencyMultiplier %}
23
+ <div class="stat-cell--leverage-group">
24
+ <div class="stat-cell">
25
+ <div class="stat-value">{{ project.totalDurationMinutes | formatDuration }}</div>
26
+ <div class="stat-label">You</div>
27
+ </div>
28
+ <div class="stat-cell">
29
+ <div class="stat-value green">{{ project.totalAgentDurationMinutes | formatDuration }}</div>
30
+ <div class="stat-label">Agents</div>
31
+ </div>
32
+ <div class="stat-cell">
33
+ <div class="stat-value green">{{ efficiencyMultiplier }}</div>
34
+ <div class="stat-label">Multi</div>
35
+ </div>
36
+ </div>
37
+ {% else %}
38
+ <div class="stat-cell">
39
+ <div class="stat-value">{{ project.totalDurationMinutes | formatDuration }}</div>
40
+ <div class="stat-label">Time</div>
41
+ </div>
42
+ {% endif %}
43
+ <div class="stat-cell">
44
+ <div class="stat-value green" data-animate data-target="{{ project.totalLoc }}">0</div>
45
+ <div class="stat-label">LOC</div>
46
+ </div>
47
+ <div class="stat-cell">
48
+ <div class="stat-value" data-animate data-target="{{ project.totalFilesChanged }}">0</div>
49
+ <div class="stat-label">Files</div>
50
+ </div>
51
+ {% if project.totalTokens %}
52
+ <div class="stat-cell">
53
+ <div class="stat-value">{{ project.totalTokens | formatTokens }}</div>
54
+ <div class="stat-label">Tokens</div>
55
+ </div>
56
+ {% endif %}
57
+ </div>
58
+ </div>
59
+ </section>
60
+
61
+ {%- comment -%} Main Content {%- endcomment -%}
62
+ <main id="main" class="container">
63
+
64
+ {%- comment -%} Project Header {%- endcomment -%}
65
+ <section class="project-header fade-in" aria-label="Project header">
66
+ <div class="project-header-top">
67
+ <div>
68
+ <h1 data-editable="title">{{ project.title }}</h1>
69
+ {% if project.repoUrl or project.projectUrl %}
70
+ <div class="project-links">
71
+ {% if project.repoUrl %}
72
+ <a href="{{ project.repoUrl }}" target="_blank" rel="noopener">{{ project.repoUrl | stripProtocol }}</a>
73
+ {% endif %}
74
+ {% if project.projectUrl %}
75
+ <a href="{{ project.projectUrl }}" target="_blank" rel="noopener">{{ project.projectUrl | stripProtocol }}</a>
76
+ {% endif %}
77
+ </div>
78
+ {% endif %}
79
+ </div>
80
+ </div>
81
+ {% if sourceCounts.size > 0 %}
82
+ {% assign totalSourceSessions = 0 %}
83
+ {% for src in sourceCounts %}
84
+ {% assign totalSourceSessions = totalSourceSessions | plus: src.count %}
85
+ {% endfor %}
86
+ {% if totalSourceSessions > 0 %}
87
+ <div class="source-bar-section">
88
+ <div class="source-stacked-bar" role="img" aria-label="Source breakdown">
89
+ {% for src in sourceCounts %}
90
+ {% assign srcPct = src.count | times: 100.0 | divided_by: totalSourceSessions | round %}
91
+ <div class="seg-{{ src.tool | downcase }}" style="width: {{ srcPct }}%;"></div>
92
+ {% endfor %}
93
+ </div>
94
+ <div class="source-legend">
95
+ {% for src in sourceCounts %}
96
+ {% assign srcPct = src.count | times: 100.0 | divided_by: totalSourceSessions | round %}
97
+ <span><span class="swatch {{ src.tool | downcase }}" aria-hidden="true"></span> {{ src.tool }} {{ srcPct }}%</span>
98
+ {% endfor %}
99
+ </div>
100
+ </div>
101
+ {% endif %}
102
+ {% endif %}
103
+ </section>
104
+
105
+ {%- comment -%} Screenshot {%- endcomment -%}
106
+ {% if project.screenshotUrl %}
107
+ <section class="fade-in" aria-label="Project screenshot" style="padding-top: 24px;">
108
+ <div class="screenshot">
109
+ <div class="screenshot-chrome">
110
+ <div class="chrome-dot" aria-hidden="true"></div>
111
+ <div class="chrome-dot" aria-hidden="true"></div>
112
+ <div class="chrome-dot" aria-hidden="true"></div>
113
+ {% if project.projectUrl %}
114
+ <span class="chrome-url">{{ project.projectUrl | stripProtocol }}</span>
115
+ {% endif %}
116
+ </div>
117
+ <div class="screenshot-body">
118
+ <img src="{{ project.screenshotUrl }}" alt="{{ project.title }} screenshot">
119
+ </div>
120
+ </div>
121
+ </section>
122
+ {% endif %}
123
+
124
+ {%- comment -%} Narrative {%- endcomment -%}
125
+ {% if project.narrative != blank %}
126
+ <section class="narrative fade-in" aria-label="Project narrative">
127
+ <div class="section-header">
128
+ <h2>Narrative</h2>
129
+ <div class="section-line" aria-hidden="true"></div>
130
+ </div>
131
+ <p>{{ project.narrative }}</p>
132
+ </section>
133
+ {% endif %}
134
+
135
+ {%- comment -%} Work Timeline (CSS-only horizontal bars) {%- endcomment -%}
136
+ {% if featuredSessions.size > 0 %}
137
+ <section class="fade-in" aria-label="Work timeline">
138
+ <div class="section-header">
139
+ <h2>Work Timeline</h2>
140
+ <span class="section-tag">{{ featuredSessions.size }} sessions</span>
141
+ <div class="section-line" aria-hidden="true"></div>
142
+ </div>
143
+ <div class="timeline-wrap" role="region" aria-label="Scrollable work timeline" tabindex="0">
144
+ <div class="timeline">
145
+ {% assign maxDur = 1 %}
146
+ {% for s in featuredSessions %}
147
+ {% if s.durationMinutes > maxDur %}
148
+ {% assign maxDur = s.durationMinutes %}
149
+ {% endif %}
150
+ {% endfor %}
151
+ {% for s in featuredSessions %}
152
+ <div class="timeline-bar">
153
+ <div class="timeline-stat">{{ s.durationMinutes }}m</div>
154
+ {% assign barHeight = s.durationMinutes | times: 100 | divided_by: maxDur %}
155
+ <div class="timeline-fill {{ s.sourceTool | downcase }}" style="height: {{ barHeight }}px;" aria-label="Session {{ forloop.index }}: {{ s.durationMinutes }} minutes, {{ s.sourceTool }}"></div>
156
+ <div class="timeline-label">{{ s.recordedAt | formatDateShort }}</div>
157
+ </div>
158
+ {% endfor %}
159
+ </div>
160
+ </div>
161
+ </section>
162
+ {% endif %}
163
+
164
+ {%- comment -%} Phases {%- endcomment -%}
165
+ {% if arc.size > 0 %}
166
+ <section class="fade-in" aria-label="Project phases">
167
+ <div class="section-header">
168
+ <h2>Phases</h2>
169
+ <span class="section-tag">{{ arc.size }} arcs</span>
170
+ <div class="section-line" aria-hidden="true"></div>
171
+ </div>
172
+ <div class="phases">
173
+ {% for item in arc %}
174
+ <div class="phase-card">
175
+ <div class="phase-number">Phase {{ item.phase }}</div>
176
+ <div class="phase-name">{{ item.title }}</div>
177
+ {% if item.dates != blank %}
178
+ <div class="phase-dates">{{ item.dates }}</div>
179
+ {% endif %}
180
+ <div class="phase-desc">{{ item.description }}</div>
181
+ </div>
182
+ {% endfor %}
183
+ </div>
184
+ </section>
185
+ {% endif %}
186
+
187
+ {%- comment -%} Sessions Table {%- endcomment -%}
188
+ {% if featuredSessions.size > 0 %}
189
+ <section class="fade-in" aria-label="Sessions list">
190
+ <div class="section-header">
191
+ <h2>Sessions</h2>
192
+ <span class="section-tag">{{ featuredSessions.size }} total</span>
193
+ <div class="section-line" aria-hidden="true"></div>
194
+ </div>
195
+ <div class="session-table-wrap" role="region" aria-label="Sessions table" tabindex="0">
196
+ <table class="session-table" aria-label="All sessions for {{ project.title }}">
197
+ <thead>
198
+ <tr>
199
+ <th scope="col">#</th>
200
+ <th scope="col">Title</th>
201
+ <th scope="col">Date</th>
202
+ <th scope="col">Duration</th>
203
+ <th scope="col">LOC</th>
204
+ <th scope="col">Source</th>
205
+ <th scope="col">Agents</th>
206
+ </tr>
207
+ </thead>
208
+ <tbody>
209
+ {% for s in featuredSessions %}
210
+ <tr>
211
+ <td class="stat-mono">{{ forloop.index }}</td>
212
+ <td><a href="{{ sessionBaseUrl }}/{{ s.slug }}{{ sessionSuffix }}" class="session-title-link">{{ s.title }}</a></td>
213
+ <td class="stat-mono">{{ s.recordedAt | formatDateShort }}</td>
214
+ <td class="stat-mono">{{ s.durationMinutes | formatDuration }}</td>
215
+ <td class="stat-mono stat-green">{{ s.locChanged | localeNumber }}</td>
216
+ <td><span class="source-tag {{ s.sourceTool | downcase }}">{{ s.sourceTool }}</span></td>
217
+ <td>
218
+ {% if s.agentSessions.size > 0 %}
219
+ <div class="agent-dots" aria-label="{{ s.agentSessions.size }} agents">
220
+ {% for agent in s.agentSessions %}
221
+ <span class="agent-dot" style="background: {{ agent.color | default: 'var(--fg-dim)' }};" title="{{ agent.role }}"></span>
222
+ {% endfor %}
223
+ </div>
224
+ {% else %}
225
+ <span class="stat-mono" style="font-size: 10px;">&mdash;</span>
226
+ {% endif %}
227
+ </td>
228
+ </tr>
229
+ {% endfor %}
230
+ </tbody>
231
+ </table>
232
+ </div>
233
+ </section>
234
+ {% endif %}
235
+
236
+ {%- comment -%} Key Decisions {%- endcomment -%}
237
+ {% if arc.size > 0 %}
238
+ <section class="fade-in" aria-label="Key decisions">
239
+ <div class="section-header">
240
+ <h2>Key Decisions</h2>
241
+ <span class="section-tag">{{ arc.size }} calls</span>
242
+ <div class="section-line" aria-hidden="true"></div>
243
+ </div>
244
+ <ol class="decisions-list">
245
+ {% for item in arc %}
246
+ <li>{{ item.description }}</li>
247
+ {% endfor %}
248
+ </ol>
249
+ </section>
250
+ {% endif %}
251
+
252
+ {%- comment -%} Skills {%- endcomment -%}
253
+ {% if project.skills.size > 0 %}
254
+ <section class="fade-in" aria-label="Skills">
255
+ <div class="section-header">
256
+ <h2>Skills</h2>
257
+ <span class="section-tag">{{ project.skills.size }} technologies</span>
258
+ <div class="section-line" aria-hidden="true"></div>
259
+ </div>
260
+ <div class="skill-badges">
261
+ {% for skill in project.skills %}
262
+ <span class="skill-badge strong">{{ skill }}</span>
263
+ {% endfor %}
264
+ </div>
265
+ </section>
266
+ {% endif %}
267
+
268
+ </main>
269
+
270
+ {%- comment -%} Footer {%- endcomment -%}
271
+ <footer class="footer">
272
+ <div class="container">
273
+ signal template &middot; heyi.am
274
+ </div>
275
+ </footer>
276
+
277
+
278
+ </div>