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.
- package/README.md +45 -0
- package/dist/config.js +10 -1
- package/dist/db.js +1 -2
- package/dist/export.js +40 -25
- package/dist/format-utils.js +5 -0
- package/dist/index.js +168 -0
- package/dist/mount.js +300 -102
- package/dist/parsers/claude.js +2 -28
- package/dist/parsers/codex.js +2 -26
- package/dist/parsers/cursor.js +2 -26
- package/dist/parsers/duration.js +35 -0
- package/dist/parsers/gemini.js +2 -20
- package/dist/parsers/types.js +0 -1
- package/dist/public/assets/index-BZ65TU_Y.js +40 -0
- package/dist/public/assets/index-CqCaW2cb.css +1 -0
- package/dist/public/index.html +2 -2
- package/dist/redact.js +4 -104
- package/dist/render/build-render-data.js +9 -2
- package/dist/render/index.js +32 -5
- package/dist/render/liquid.js +147 -7
- package/dist/render/mock-data.js +303 -0
- package/dist/render/templates/aurora/portfolio.liquid +204 -0
- package/dist/render/templates/aurora/project.liquid +260 -0
- package/dist/render/templates/aurora/session.liquid +223 -0
- package/dist/render/templates/aurora/styles.css +1178 -0
- package/dist/render/templates/bauhaus/portfolio.liquid +179 -0
- package/dist/render/templates/bauhaus/project.liquid +300 -0
- package/dist/render/templates/bauhaus/session.liquid +333 -0
- package/dist/render/templates/bauhaus/styles.css +1641 -0
- package/dist/render/templates/blueprint/portfolio.liquid +167 -0
- package/dist/render/templates/blueprint/project.liquid +286 -0
- package/dist/render/templates/blueprint/session.liquid +248 -0
- package/dist/render/templates/blueprint/styles.css +1285 -0
- package/dist/render/templates/canvas/portfolio.liquid +215 -0
- package/dist/render/templates/canvas/project.liquid +235 -0
- package/dist/render/templates/canvas/session.liquid +223 -0
- package/dist/render/templates/canvas/styles.css +1436 -0
- package/dist/render/templates/carbon/portfolio.liquid +170 -0
- package/dist/render/templates/carbon/project.liquid +249 -0
- package/dist/render/templates/carbon/session.liquid +190 -0
- package/dist/render/templates/carbon/styles.css +1091 -0
- package/dist/render/templates/chalk/portfolio.liquid +199 -0
- package/dist/render/templates/chalk/project.liquid +245 -0
- package/dist/render/templates/chalk/session.liquid +215 -0
- package/dist/render/templates/chalk/styles.css +1157 -0
- package/dist/render/templates/circuit/portfolio.liquid +162 -0
- package/dist/render/templates/circuit/project.liquid +247 -0
- package/dist/render/templates/circuit/session.liquid +205 -0
- package/dist/render/templates/circuit/styles.css +1403 -0
- package/dist/render/templates/cosmos/portfolio.liquid +232 -0
- package/dist/render/templates/cosmos/project.liquid +327 -0
- package/dist/render/templates/cosmos/session.liquid +239 -0
- package/dist/render/templates/cosmos/styles.css +1151 -0
- package/dist/render/templates/daylight/portfolio.liquid +217 -0
- package/dist/render/templates/daylight/project.liquid +229 -0
- package/dist/render/templates/daylight/session.liquid +219 -0
- package/dist/render/templates/daylight/styles.css +1311 -0
- package/dist/render/templates/editorial/portfolio.liquid +126 -0
- package/dist/render/templates/editorial/project.liquid +202 -0
- package/dist/render/templates/editorial/session.liquid +171 -0
- package/dist/render/templates/editorial/styles.css +822 -0
- package/dist/render/templates/ember/portfolio.liquid +318 -0
- package/dist/render/templates/ember/project.liquid +232 -0
- package/dist/render/templates/ember/session.liquid +202 -0
- package/dist/render/templates/ember/styles.css +1283 -0
- package/dist/render/templates/glacier/portfolio.liquid +271 -0
- package/dist/render/templates/glacier/project.liquid +288 -0
- package/dist/render/templates/glacier/session.liquid +217 -0
- package/dist/render/templates/glacier/styles.css +1200 -0
- package/dist/render/templates/grid/portfolio.liquid +265 -0
- package/dist/render/templates/grid/project.liquid +306 -0
- package/dist/render/templates/grid/session.liquid +260 -0
- package/dist/render/templates/grid/styles.css +1441 -0
- package/dist/render/templates/kinetic/portfolio.liquid +170 -0
- package/dist/render/templates/kinetic/project.liquid +242 -0
- package/dist/render/templates/kinetic/session.liquid +228 -0
- package/dist/render/templates/kinetic/styles.css +944 -0
- package/dist/render/templates/meridian/portfolio.liquid +255 -0
- package/dist/render/templates/meridian/project.liquid +376 -0
- package/dist/render/templates/meridian/session.liquid +298 -0
- package/dist/render/templates/meridian/styles.css +1369 -0
- package/dist/render/templates/minimal/portfolio.liquid +71 -0
- package/dist/render/templates/minimal/project.liquid +154 -0
- package/dist/render/templates/minimal/session.liquid +140 -0
- package/dist/render/templates/minimal/styles.css +525 -0
- package/dist/render/templates/mono/portfolio.liquid +291 -0
- package/dist/render/templates/mono/project.liquid +275 -0
- package/dist/render/templates/mono/session.liquid +276 -0
- package/dist/render/templates/mono/styles.css +1016 -0
- package/dist/render/templates/neon/portfolio.liquid +217 -0
- package/dist/render/templates/neon/project.liquid +225 -0
- package/dist/render/templates/neon/session.liquid +195 -0
- package/dist/render/templates/neon/styles.css +1265 -0
- package/dist/render/templates/noir/portfolio.liquid +137 -0
- package/dist/render/templates/noir/project.liquid +220 -0
- package/dist/render/templates/noir/session.liquid +241 -0
- package/dist/render/templates/noir/styles.css +1223 -0
- package/dist/render/templates/obsidian/portfolio.liquid +257 -0
- package/dist/render/templates/obsidian/project.liquid +280 -0
- package/dist/render/templates/obsidian/session.liquid +241 -0
- package/dist/render/templates/obsidian/styles.css +1401 -0
- package/dist/render/templates/paper/portfolio.liquid +267 -0
- package/dist/render/templates/paper/project.liquid +235 -0
- package/dist/render/templates/paper/session.liquid +271 -0
- package/dist/render/templates/paper/styles.css +1509 -0
- package/dist/render/templates/parallax/portfolio.liquid +305 -0
- package/dist/render/templates/parallax/project.liquid +275 -0
- package/dist/render/templates/parallax/session.liquid +295 -0
- package/dist/render/templates/parallax/styles.css +1874 -0
- package/dist/render/templates/parchment/portfolio.liquid +290 -0
- package/dist/render/templates/parchment/project.liquid +289 -0
- package/dist/render/templates/parchment/session.liquid +346 -0
- package/dist/render/templates/parchment/styles.css +1397 -0
- package/dist/render/templates/partials/_beats.liquid +16 -0
- package/dist/render/templates/partials/_breadcrumb.liquid +9 -0
- package/dist/render/templates/partials/_footer.liquid +7 -0
- package/dist/render/templates/partials/_growth-chart.liquid +7 -0
- package/dist/render/templates/partials/_key-decisions.liquid +20 -0
- package/dist/render/templates/partials/_links.liquid +16 -0
- package/dist/render/templates/partials/_narrative.liquid +8 -0
- package/dist/render/templates/partials/_phases.liquid +20 -0
- package/dist/render/templates/partials/_portfolio-header.liquid +20 -0
- package/dist/render/templates/partials/_portfolio-projects.liquid +16 -0
- package/dist/render/templates/partials/_portfolio-stats.liquid +19 -0
- package/dist/render/templates/partials/_qa.liquid +13 -0
- package/dist/render/templates/partials/_screenshot.liquid +15 -0
- package/dist/render/templates/partials/_session-cards.liquid +30 -0
- package/dist/render/templates/partials/_session-header.liquid +39 -0
- package/dist/render/templates/partials/_session-sidebar.liquid +30 -0
- package/dist/render/templates/partials/_skills.liquid +12 -0
- package/dist/render/templates/partials/_source-breakdown.liquid +22 -0
- package/dist/render/templates/partials/_stats.liquid +38 -0
- package/dist/render/templates/partials/_work-timeline.liquid +7 -0
- package/dist/render/templates/project.liquid +7 -4
- package/dist/render/templates/radar/portfolio.liquid +233 -0
- package/dist/render/templates/radar/project.liquid +278 -0
- package/dist/render/templates/radar/session.liquid +300 -0
- package/dist/render/templates/radar/styles.css +1049 -0
- package/dist/render/templates/showcase/portfolio.liquid +231 -0
- package/dist/render/templates/showcase/project.liquid +237 -0
- package/dist/render/templates/showcase/session.liquid +210 -0
- package/dist/render/templates/showcase/styles.css +1279 -0
- package/dist/render/templates/signal/portfolio.liquid +227 -0
- package/dist/render/templates/signal/project.liquid +278 -0
- package/dist/render/templates/signal/session.liquid +282 -0
- package/dist/render/templates/signal/styles.css +1395 -0
- package/dist/render/templates/strata/portfolio.liquid +192 -0
- package/dist/render/templates/strata/project.liquid +282 -0
- package/dist/render/templates/strata/session.liquid +261 -0
- package/dist/render/templates/strata/styles.css +1350 -0
- package/dist/render/templates/styles.css +1190 -0
- package/dist/render/templates/terminal/portfolio.liquid +118 -0
- package/dist/render/templates/terminal/project.liquid +161 -0
- package/dist/render/templates/terminal/session.liquid +145 -0
- package/dist/render/templates/terminal/styles.css +492 -0
- package/dist/render/templates/verdant/portfolio.liquid +333 -0
- package/dist/render/templates/verdant/project.liquid +309 -0
- package/dist/render/templates/verdant/session.liquid +237 -0
- package/dist/render/templates/verdant/styles.css +1257 -0
- package/dist/render/templates/zen/portfolio.liquid +136 -0
- package/dist/render/templates/zen/project.liquid +187 -0
- package/dist/render/templates/zen/session.liquid +203 -0
- package/dist/render/templates/zen/styles.css +1207 -0
- package/dist/render/templates.js +90 -0
- package/dist/routes/context.js +15 -10
- package/dist/routes/enhance.js +17 -40
- package/dist/routes/export.js +14 -4
- package/dist/routes/preview.js +480 -108
- package/dist/routes/projects.js +11 -19
- package/dist/routes/publish.js +15 -17
- package/dist/routes/settings.js +94 -1
- package/dist/routes/sse.js +9 -0
- package/dist/server.js +8 -2
- package/dist/settings.js +17 -9
- package/package.json +2 -4
- package/dist/public/assets/index-B_d6DlEI.js +0 -21
- package/dist/public/assets/index-Dalqz2mC.css +0 -1
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
<div class="heyiam-portfolio ember" data-render-version="2" data-template="ember" data-username="{{ user.username }}">
|
|
2
|
+
|
|
3
|
+
{%- comment -%} Hero: Asymmetric Split {%- endcomment -%}
|
|
4
|
+
{% if hasProfile %}
|
|
5
|
+
<section class="hero ember-section" aria-label="Profile">
|
|
6
|
+
<div class="hero-split">
|
|
7
|
+
<div class="hero-content">
|
|
8
|
+
{% if user.displayName != blank %}
|
|
9
|
+
<h1 class="hero-name">{{ user.displayName }}</h1>
|
|
10
|
+
{% endif %}
|
|
11
|
+
{% if user.location %}
|
|
12
|
+
<p class="hero-location">{{ user.location }}</p>
|
|
13
|
+
{% endif %}
|
|
14
|
+
{% if user.bio %}
|
|
15
|
+
<p class="hero-bio">{{ user.bio }}</p>
|
|
16
|
+
{% endif %}
|
|
17
|
+
<ul class="hero-contact" aria-label="Contact and social links">
|
|
18
|
+
{% if user.email %}
|
|
19
|
+
<li><a href="mailto:{{ user.email }}"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m2 4 10 8 10-8"/></svg>{{ user.email }}</a></li>
|
|
20
|
+
{% endif %}
|
|
21
|
+
{% if user.linkedinUrl %}
|
|
22
|
+
<li><a href="{{ user.linkedinUrl }}" target="_blank" rel="noopener"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M20.5 2h-17A1.5 1.5 0 002 3.5v17A1.5 1.5 0 003.5 22h17a1.5 1.5 0 001.5-1.5v-17A1.5 1.5 0 0020.5 2zM8 19H5v-9h3zM6.5 8.25A1.75 1.75 0 118.3 6.5a1.78 1.78 0 01-1.8 1.75zM19 19h-3v-4.74c0-1.42-.6-1.93-1.38-1.93A1.74 1.74 0 0013 14.19V19h-3v-9h2.9v1.3a3.11 3.11 0 012.7-1.4c1.55 0 3.36.86 3.36 3.66z"/></svg>LinkedIn</a></li>
|
|
23
|
+
{% endif %}
|
|
24
|
+
{% if user.githubUrl %}
|
|
25
|
+
<li><a href="{{ user.githubUrl }}" target="_blank" rel="noopener"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>GitHub</a></li>
|
|
26
|
+
{% endif %}
|
|
27
|
+
{% if user.twitterHandle %}
|
|
28
|
+
<li><a href="https://x.com/{{ user.twitterHandle }}" target="_blank" rel="noopener"><svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>@{{ user.twitterHandle }}</a></li>
|
|
29
|
+
{% endif %}
|
|
30
|
+
{% if user.websiteUrl %}
|
|
31
|
+
<li><a href="{{ user.websiteUrl }}" target="_blank" rel="noopener">{{ user.websiteUrl | stripProtocol }}</a></li>
|
|
32
|
+
{% endif %}
|
|
33
|
+
{% if user.phone %}
|
|
34
|
+
<li><a href="tel:{{ user.phone }}">{{ user.phone }}</a></li>
|
|
35
|
+
{% endif %}
|
|
36
|
+
</ul>
|
|
37
|
+
{% if user.resumeUrl %}
|
|
38
|
+
<a href="{{ user.resumeUrl }}" class="hero-resume-btn"><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>Download Resume</a>
|
|
39
|
+
{% endif %}
|
|
40
|
+
</div>
|
|
41
|
+
{% if user.photoUrl %}
|
|
42
|
+
<div class="hero-photo-order hero-photo-wrapper">
|
|
43
|
+
<img src="{{ user.photoUrl }}" alt="{{ user.displayName }}" class="hero-photo" width="350" height="440" loading="eager">
|
|
44
|
+
</div>
|
|
45
|
+
{% endif %}
|
|
46
|
+
</div>
|
|
47
|
+
</section>
|
|
48
|
+
{% endif %}
|
|
49
|
+
|
|
50
|
+
{%- comment -%} Stats {%- endcomment -%}
|
|
51
|
+
<section class="ember-section" aria-label="Aggregate statistics">
|
|
52
|
+
<div class="stats-bar" role="list">
|
|
53
|
+
<div class="stat-cell" role="listitem">
|
|
54
|
+
<span class="stat-value ember-glow">{{ projects.size }}</span>
|
|
55
|
+
<span class="stat-label">Projects</span>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="stat-cell" role="listitem">
|
|
58
|
+
<span class="stat-value ember-glow">{{ totalSessions }}</span>
|
|
59
|
+
<span class="stat-label">Sessions</span>
|
|
60
|
+
</div>
|
|
61
|
+
<div class="stat-cell" role="listitem">
|
|
62
|
+
<span class="stat-value ember-glow">{{ totalLoc | localeNumber }}</span>
|
|
63
|
+
<span class="stat-label">Lines Changed</span>
|
|
64
|
+
</div>
|
|
65
|
+
<div class="stat-cell" role="listitem">
|
|
66
|
+
<span class="stat-value ember-glow">{{ totalDurationMinutes | formatDuration }}</span>
|
|
67
|
+
<span class="stat-label">{{ durationLabel }}</span>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
</section>
|
|
71
|
+
|
|
72
|
+
{%- comment -%} Leverage {%- endcomment -%}
|
|
73
|
+
{% if efficiencyMultiplier %}
|
|
74
|
+
<section class="ember-section" aria-label="AI leverage" role="figure">
|
|
75
|
+
<div class="ember-leverage">
|
|
76
|
+
<div class="ember-leverage__main">
|
|
77
|
+
<span class="ember-leverage__multi">{{ efficiencyMultiplier }}</span>
|
|
78
|
+
<div class="ember-leverage__detail">
|
|
79
|
+
<span>{{ totalDurationMinutes | formatDuration }} <small>you</small></span>
|
|
80
|
+
<span style="color:var(--accent)">{{ totalAgentDurationMinutes | formatDuration }} <small>agents</small></span>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
{% assign totalCombined = totalDurationMinutes | plus: totalAgentDurationMinutes %}
|
|
84
|
+
{% if totalCombined > 0 %}
|
|
85
|
+
{% assign agentPct = totalAgentDurationMinutes | times: 100 | divided_by: totalCombined %}
|
|
86
|
+
<div class="ember-leverage__bar"><div class="ember-leverage__fill" style="width:{{ agentPct }}%"></div></div>
|
|
87
|
+
{% endif %}
|
|
88
|
+
</div>
|
|
89
|
+
</section>
|
|
90
|
+
{% endif %}
|
|
91
|
+
|
|
92
|
+
{%- comment -%} Projects {%- endcomment -%}
|
|
93
|
+
{% if projects.size > 0 %}
|
|
94
|
+
<section class="ember-section" aria-label="Projects">
|
|
95
|
+
<h2 class="section-header"><span class="ember-icon" aria-hidden="true"></span>Projects</h2>
|
|
96
|
+
<div class="projects-grid">
|
|
97
|
+
{% for p in projects %}
|
|
98
|
+
<a href="/{{ user.username }}/{{ p.slug }}" class="project-card" aria-label="{{ p.title }} project">
|
|
99
|
+
<div class="project-card-header">
|
|
100
|
+
<h3 class="project-card-title">{{ p.title }}</h3>
|
|
101
|
+
<span class="project-card-arrow" aria-hidden="true">→</span>
|
|
102
|
+
</div>
|
|
103
|
+
{% if p.narrative %}
|
|
104
|
+
<p class="project-card-narrative">{{ p.narrative }}</p>
|
|
105
|
+
{% endif %}
|
|
106
|
+
{% if p.skills.size > 0 %}
|
|
107
|
+
<div class="project-card-skills">
|
|
108
|
+
{% for skill in p.skills %}
|
|
109
|
+
<span class="skill-chip">{{ skill }}</span>
|
|
110
|
+
{% endfor %}
|
|
111
|
+
</div>
|
|
112
|
+
{% endif %}
|
|
113
|
+
<div class="project-card-stats">
|
|
114
|
+
<span>{{ p.totalSessions }} session{% if p.totalSessions != 1 %}s{% endif %}</span>
|
|
115
|
+
<span>{{ p.totalDurationMinutes | formatDuration }}</span>
|
|
116
|
+
<span>{{ p.totalLoc | localeNumber }} LOC</span>
|
|
117
|
+
</div>
|
|
118
|
+
{% if p.sourceCounts.size > 0 %}
|
|
119
|
+
{% assign pTotalSrc = 0 %}
|
|
120
|
+
{% for src in p.sourceCounts %}{% assign pTotalSrc = pTotalSrc | plus: src.count %}{% endfor %}
|
|
121
|
+
{% if pTotalSrc > 0 %}
|
|
122
|
+
<div class="source-bar" role="img" aria-label="Source breakdown">
|
|
123
|
+
{% for src in p.sourceCounts %}
|
|
124
|
+
{% assign pSrcPct = src.count | times: 100.0 | divided_by: pTotalSrc | round %}
|
|
125
|
+
<div class="source-bar-segment{% if forloop.first %} claude{% else %} cursor{% endif %}" style="width: {{ pSrcPct }}%"></div>
|
|
126
|
+
{% endfor %}
|
|
127
|
+
</div>
|
|
128
|
+
<div class="source-legend">
|
|
129
|
+
{% for src in p.sourceCounts %}
|
|
130
|
+
{% assign pSrcPct = src.count | times: 100.0 | divided_by: pTotalSrc | round %}
|
|
131
|
+
<span><span class="source-legend-dot{% if forloop.first %} claude{% else %} cursor{% endif %}" aria-hidden="true"></span>{{ src.tool }} {{ pSrcPct }}%</span>
|
|
132
|
+
{% endfor %}
|
|
133
|
+
</div>
|
|
134
|
+
{% endif %}
|
|
135
|
+
{% endif %}
|
|
136
|
+
</a>
|
|
137
|
+
{% endfor %}
|
|
138
|
+
</div>
|
|
139
|
+
</section>
|
|
140
|
+
{% endif %}
|
|
141
|
+
|
|
142
|
+
{%- comment -%} Activity {%- endcomment -%}
|
|
143
|
+
{% if activityByMonth.size > 0 %}
|
|
144
|
+
{% assign maxSessions = 0 %}
|
|
145
|
+
{% for m in activityByMonth %}
|
|
146
|
+
{% if m.sessions > maxSessions %}{% assign maxSessions = m.sessions %}{% endif %}
|
|
147
|
+
{% endfor %}
|
|
148
|
+
<section class="activity-section ember-section" aria-label="Session activity">
|
|
149
|
+
<h2 class="section-header"><span class="ember-icon" aria-hidden="true"></span>Session Activity</h2>
|
|
150
|
+
<div class="activity-chart" role="img" aria-label="Monthly session activity bar chart">
|
|
151
|
+
{% for m in activityByMonth %}
|
|
152
|
+
{% if maxSessions > 0 %}
|
|
153
|
+
{% assign barPct = m.sessions | times: 100 | divided_by: maxSessions %}
|
|
154
|
+
{% else %}
|
|
155
|
+
{% assign barPct = 0 %}
|
|
156
|
+
{% endif %}
|
|
157
|
+
<div class="activity-bar" style="height: {{ barPct }}%" data-label="{{ m.month }}"></div>
|
|
158
|
+
{% endfor %}
|
|
159
|
+
</div>
|
|
160
|
+
<div class="activity-labels">
|
|
161
|
+
{% for m in activityByMonth %}
|
|
162
|
+
<span>{{ m.month }}</span>
|
|
163
|
+
{% endfor %}
|
|
164
|
+
</div>
|
|
165
|
+
</section>
|
|
166
|
+
{% endif %}
|
|
167
|
+
|
|
168
|
+
{%- comment -%} Growth Line Chart {%- endcomment -%}
|
|
169
|
+
{% if activityByDay.size > 0 %}
|
|
170
|
+
{% assign cumLoc = 0 %}
|
|
171
|
+
{% assign maxCumLoc = 0 %}
|
|
172
|
+
{% for d in activityByDay %}
|
|
173
|
+
{% assign cumLoc = cumLoc | plus: d.loc %}
|
|
174
|
+
{% if cumLoc > maxCumLoc %}{% assign maxCumLoc = cumLoc %}{% endif %}
|
|
175
|
+
{% endfor %}
|
|
176
|
+
<section class="ember-section" aria-label="Cumulative lines of code" style="margin-top: 2.5rem;">
|
|
177
|
+
<h2 class="section-header"><span class="ember-icon" aria-hidden="true"></span>Growth</h2>
|
|
178
|
+
<div style="background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.5rem;">
|
|
179
|
+
<svg viewBox="0 0 500 180" width="100%" height="180" role="img" aria-label="Cumulative LOC growth line chart">
|
|
180
|
+
<line x1="40" y1="20" x2="40" y2="150" stroke="rgba(250,245,240,0.06)" stroke-width="1"/>
|
|
181
|
+
<line x1="40" y1="150" x2="480" y2="150" stroke="rgba(250,245,240,0.06)" stroke-width="1"/>
|
|
182
|
+
<line x1="40" y1="117.5" x2="480" y2="117.5" stroke="rgba(250,245,240,0.04)" stroke-width="1" stroke-dasharray="4,4"/>
|
|
183
|
+
<line x1="40" y1="85" x2="480" y2="85" stroke="rgba(250,245,240,0.04)" stroke-width="1" stroke-dasharray="4,4"/>
|
|
184
|
+
<line x1="40" y1="52.5" x2="480" y2="52.5" stroke="rgba(250,245,240,0.04)" stroke-width="1" stroke-dasharray="4,4"/>
|
|
185
|
+
<line x1="40" y1="20" x2="480" y2="20" stroke="rgba(250,245,240,0.04)" stroke-width="1" stroke-dasharray="4,4"/>
|
|
186
|
+
<text x="35" y="154" fill="rgba(250,245,240,0.4)" font-family="JetBrains Mono, monospace" font-size="10" text-anchor="end">0</text>
|
|
187
|
+
{% if maxCumLoc > 0 %}
|
|
188
|
+
{% assign yLabel2 = maxCumLoc | divided_by: 2 %}
|
|
189
|
+
<text x="35" y="88" fill="rgba(250,245,240,0.4)" font-family="JetBrains Mono, monospace" font-size="10" text-anchor="end">{{ yLabel2 | formatLoc }}</text>
|
|
190
|
+
<text x="35" y="24" fill="rgba(250,245,240,0.4)" font-family="JetBrains Mono, monospace" font-size="10" text-anchor="end">{{ maxCumLoc | formatLoc }}</text>
|
|
191
|
+
{% endif %}
|
|
192
|
+
<defs>
|
|
193
|
+
<linearGradient id="emberGradFill" x1="0" y1="0" x2="0" y2="1">
|
|
194
|
+
<stop offset="0%" stop-color="#f97316" stop-opacity="0.15"/>
|
|
195
|
+
<stop offset="100%" stop-color="#f97316" stop-opacity="0.01"/>
|
|
196
|
+
</linearGradient>
|
|
197
|
+
<linearGradient id="emberGradLine" x1="0" y1="0" x2="1" y2="0">
|
|
198
|
+
<stop offset="0%" stop-color="#f97316"/>
|
|
199
|
+
<stop offset="100%" stop-color="#ef4444"/>
|
|
200
|
+
</linearGradient>
|
|
201
|
+
</defs>
|
|
202
|
+
{% assign fillPath = "M 40 150" %}
|
|
203
|
+
{% assign polyPoints = "" %}
|
|
204
|
+
{% assign cumLoc = 0 %}
|
|
205
|
+
{% assign dayCount = activityByDay.size | minus: 1 %}
|
|
206
|
+
{% assign lastPx = 40 %}
|
|
207
|
+
{% for d in activityByDay %}
|
|
208
|
+
{% assign cumLoc = cumLoc | plus: d.loc %}
|
|
209
|
+
{% if dayCount > 0 %}
|
|
210
|
+
{% assign px = forloop.index0 | times: 440 | divided_by: dayCount | plus: 40 %}
|
|
211
|
+
{% else %}
|
|
212
|
+
{% assign px = 260 %}
|
|
213
|
+
{% endif %}
|
|
214
|
+
{% if maxCumLoc > 0 %}
|
|
215
|
+
{% assign pyOff = cumLoc | times: 130 | divided_by: maxCumLoc %}
|
|
216
|
+
{% assign py = 150 | minus: pyOff %}
|
|
217
|
+
{% else %}
|
|
218
|
+
{% assign py = 150 %}
|
|
219
|
+
{% endif %}
|
|
220
|
+
{% assign fillPath = fillPath | append: " L " | append: px | append: " " | append: py %}
|
|
221
|
+
{% assign polyPoints = polyPoints | append: px | append: "," | append: py | append: " " %}
|
|
222
|
+
{% assign lastPx = px %}
|
|
223
|
+
{% endfor %}
|
|
224
|
+
{% assign fillPath = fillPath | append: " L " | append: lastPx | append: " 150 Z" %}
|
|
225
|
+
<path d="{{ fillPath }}" fill="url(#emberGradFill)"/>
|
|
226
|
+
<polyline points="{{ polyPoints }}" fill="none" stroke="url(#emberGradLine)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
227
|
+
{% assign cumLoc = 0 %}
|
|
228
|
+
{% for d in activityByDay %}
|
|
229
|
+
{% assign cumLoc = cumLoc | plus: d.loc %}
|
|
230
|
+
{% if dayCount > 0 %}
|
|
231
|
+
{% assign px = forloop.index0 | times: 440 | divided_by: dayCount | plus: 40 %}
|
|
232
|
+
{% else %}
|
|
233
|
+
{% assign px = 260 %}
|
|
234
|
+
{% endif %}
|
|
235
|
+
{% if maxCumLoc > 0 %}
|
|
236
|
+
{% assign pyOff = cumLoc | times: 130 | divided_by: maxCumLoc %}
|
|
237
|
+
{% assign py = 150 | minus: pyOff %}
|
|
238
|
+
{% else %}
|
|
239
|
+
{% assign py = 150 %}
|
|
240
|
+
{% endif %}
|
|
241
|
+
<circle cx="{{ px }}" cy="{{ py }}" r="4" fill="var(--bg)" stroke="#f97316" stroke-width="2"/>
|
|
242
|
+
{% endfor %}
|
|
243
|
+
</svg>
|
|
244
|
+
</div>
|
|
245
|
+
</section>
|
|
246
|
+
{% endif %}
|
|
247
|
+
|
|
248
|
+
{%- comment -%} Skills Overview {%- endcomment -%}
|
|
249
|
+
{% if allSkills.size > 0 %}
|
|
250
|
+
<section class="ember-section" aria-label="Skills overview">
|
|
251
|
+
<h2 class="section-header"><span class="ember-icon" aria-hidden="true"></span>Skills</h2>
|
|
252
|
+
<div style="background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.5rem;">
|
|
253
|
+
<div style="display: flex; flex-wrap: wrap; gap: 8px;">
|
|
254
|
+
{% for skill in allSkills %}
|
|
255
|
+
<span class="skill-chip">{{ skill.name }}</span>
|
|
256
|
+
{% endfor %}
|
|
257
|
+
</div>
|
|
258
|
+
{% if topSkills.size > 0 %}
|
|
259
|
+
<div style="margin-top: 1.25rem; display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem;">
|
|
260
|
+
{% assign maxSkillCount = topSkills[0].projectCount %}
|
|
261
|
+
{% for skill in topSkills %}
|
|
262
|
+
<div>
|
|
263
|
+
<div style="font-family: var(--font-mono); font-size: 11px; color: var(--text-muted); margin-bottom: 6px;">{{ skill.name }}</div>
|
|
264
|
+
<div style="height: 6px; background: var(--surface-high); border-radius: 3px; overflow: hidden;">
|
|
265
|
+
{% if maxSkillCount > 0 %}
|
|
266
|
+
{% assign skillPct = skill.projectCount | times: 100 | divided_by: maxSkillCount %}
|
|
267
|
+
{% else %}
|
|
268
|
+
{% assign skillPct = 0 %}
|
|
269
|
+
{% endif %}
|
|
270
|
+
<div style="width: {{ skillPct }}%; height: 100%; background: linear-gradient(90deg, var(--accent), var(--accent-secondary)); border-radius: 3px;"></div>
|
|
271
|
+
</div>
|
|
272
|
+
</div>
|
|
273
|
+
{% endfor %}
|
|
274
|
+
</div>
|
|
275
|
+
{% endif %}
|
|
276
|
+
</div>
|
|
277
|
+
</section>
|
|
278
|
+
{% endif %}
|
|
279
|
+
|
|
280
|
+
{%- comment -%} Source Overview {%- endcomment -%}
|
|
281
|
+
{% if sourceCounts.size > 0 %}
|
|
282
|
+
<section class="ember-section" aria-label="Overall source breakdown">
|
|
283
|
+
<h2 class="section-header"><span class="ember-icon" aria-hidden="true"></span>Source Breakdown</h2>
|
|
284
|
+
<div style="background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.5rem;">
|
|
285
|
+
<div style="display: grid; grid-template-columns: repeat({{ sourceCounts.size }}, 1fr); gap: 1.5rem;">
|
|
286
|
+
{% for src in sourceCounts %}
|
|
287
|
+
{% if totalSourceSessions > 0 %}
|
|
288
|
+
{% assign srcPct = src.count | times: 100 | divided_by: totalSourceSessions %}
|
|
289
|
+
{% else %}
|
|
290
|
+
{% assign srcPct = 0 %}
|
|
291
|
+
{% endif %}
|
|
292
|
+
<div style="text-align: center; padding: 1rem; background: {% if forloop.first %}var(--accent-glow){% else %}var(--border-subtle){% endif %}; border-radius: var(--radius-sm); border: 1px solid {% if forloop.first %}var(--accent-border){% else %}var(--border-subtle){% endif %};">
|
|
293
|
+
<div style="font-family: var(--font-display); font-size: 1.5rem; font-weight: 700; color: {% if forloop.first %}var(--accent){% else %}var(--text-secondary){% endif %};">{{ srcPct }}%</div>
|
|
294
|
+
<div style="font-family: var(--font-mono); font-size: 11px; color: var(--text-muted); margin-top: 4px;">{{ src.tool }}</div>
|
|
295
|
+
<div style="font-family: var(--font-mono); font-size: 11px; color: var(--text-faint); margin-top: 2px;">{{ src.count }} sessions</div>
|
|
296
|
+
</div>
|
|
297
|
+
{% endfor %}
|
|
298
|
+
</div>
|
|
299
|
+
{% if totalSourceSessions > 0 %}
|
|
300
|
+
<div style="margin-top: 1rem; height: 8px; background: var(--surface-high); border-radius: 4px; overflow: hidden; display: flex;">
|
|
301
|
+
{% for src in sourceCounts %}
|
|
302
|
+
{% assign srcPct = src.count | times: 100 | divided_by: totalSourceSessions %}
|
|
303
|
+
<div style="width: {{ srcPct }}%; height: 100%; background: {% if forloop.first %}linear-gradient(90deg, var(--accent), var(--accent-secondary)){% else %}var(--text-muted){% endif %};"></div>
|
|
304
|
+
{% endfor %}
|
|
305
|
+
</div>
|
|
306
|
+
{% endif %}
|
|
307
|
+
</div>
|
|
308
|
+
</section>
|
|
309
|
+
{% endif %}
|
|
310
|
+
|
|
311
|
+
{%- comment -%} Footer {%- endcomment -%}
|
|
312
|
+
<footer class="footer">
|
|
313
|
+
<p>Built with <a href="https://heyi.am">heyi.am</a></p>
|
|
314
|
+
</footer>
|
|
315
|
+
|
|
316
|
+
{%- comment -%} Section fade-in animation {%- endcomment -%}
|
|
317
|
+
|
|
318
|
+
</div>
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
<div class="heyiam-project ember" data-render-version="2" data-template="ember"{% if sessionBaseUrl %} data-session-base-url="{{ sessionBaseUrl }}"{% endif %} data-username="{{ user.username }}" data-project-slug="{{ project.slug }}">
|
|
2
|
+
|
|
3
|
+
{%- comment -%} Breadcrumb {%- endcomment -%}
|
|
4
|
+
<div class="breadcrumb ember-section" aria-label="Breadcrumb">
|
|
5
|
+
<a href="/{{ user.username }}">{{ user.username }}</a><span class="sep">/</span><span aria-current="page">{{ project.slug }}</span>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
{%- comment -%} Header {%- endcomment -%}
|
|
9
|
+
<header class="project-header ember-section">
|
|
10
|
+
<h1 class="project-title" data-editable="title">{{ project.title }}</h1>
|
|
11
|
+
{% if project.repoUrl or project.projectUrl %}
|
|
12
|
+
<div class="project-links">
|
|
13
|
+
{% if project.repoUrl %}
|
|
14
|
+
<a href="{{ project.repoUrl }}" target="_blank" rel="noopener">{{ project.repoUrl | stripProtocol }}</a>
|
|
15
|
+
{% endif %}
|
|
16
|
+
{% if project.projectUrl %}
|
|
17
|
+
<a href="{{ project.projectUrl }}" target="_blank" rel="noopener">{{ project.projectUrl | stripProtocol }}</a>
|
|
18
|
+
{% endif %}
|
|
19
|
+
</div>
|
|
20
|
+
{% endif %}
|
|
21
|
+
</header>
|
|
22
|
+
|
|
23
|
+
{%- comment -%} Screenshot {%- endcomment -%}
|
|
24
|
+
{% if project.screenshotUrl %}
|
|
25
|
+
<section class="ember-section" aria-label="Project screenshot">
|
|
26
|
+
<div class="screenshot-frame">
|
|
27
|
+
<div class="screenshot-chrome">
|
|
28
|
+
<span class="screenshot-dot" aria-hidden="true"></span>
|
|
29
|
+
<span class="screenshot-dot" aria-hidden="true"></span>
|
|
30
|
+
<span class="screenshot-dot" aria-hidden="true"></span>
|
|
31
|
+
{% if project.projectUrl %}
|
|
32
|
+
<span class="screenshot-url">{{ project.projectUrl | stripProtocol }}</span>
|
|
33
|
+
{% endif %}
|
|
34
|
+
</div>
|
|
35
|
+
<img src="{{ project.screenshotUrl }}" alt="{{ project.title }} screenshot" style="width: 100%; display: block;">
|
|
36
|
+
</div>
|
|
37
|
+
</section>
|
|
38
|
+
{% endif %}
|
|
39
|
+
|
|
40
|
+
{%- comment -%} Stats {%- endcomment -%}
|
|
41
|
+
<section class="ember-section" aria-label="Project statistics">
|
|
42
|
+
<div class="stats-grid" role="list">
|
|
43
|
+
<div class="stat-cell" role="listitem">
|
|
44
|
+
<span class="stat-value">{{ project.totalSessions }}</span>
|
|
45
|
+
<span class="stat-label">Sessions</span>
|
|
46
|
+
</div>
|
|
47
|
+
<div class="stat-cell" role="listitem">
|
|
48
|
+
<span class="stat-value">{{ project.totalLoc | localeNumber }}</span>
|
|
49
|
+
<span class="stat-label">LOC</span>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="stat-cell" role="listitem">
|
|
52
|
+
<span class="stat-value">{{ project.totalFilesChanged }}</span>
|
|
53
|
+
<span class="stat-label">Files</span>
|
|
54
|
+
</div>
|
|
55
|
+
{% if project.totalTokens %}
|
|
56
|
+
<div class="stat-cell" role="listitem">
|
|
57
|
+
<span class="stat-value">{{ project.totalTokens | formatTokens }}</span>
|
|
58
|
+
<span class="stat-label">Tokens</span>
|
|
59
|
+
</div>
|
|
60
|
+
{% endif %}
|
|
61
|
+
<div class="stat-cell" role="listitem">
|
|
62
|
+
<span class="stat-value">{{ project.totalDurationMinutes | formatDuration }}</span>
|
|
63
|
+
<span class="stat-label">{{ durationLabel }}</span>
|
|
64
|
+
</div>
|
|
65
|
+
{% if efficiencyMultiplier %}
|
|
66
|
+
<div class="stat-cell" role="listitem">
|
|
67
|
+
<span class="stat-value" style="color: var(--accent);">{{ efficiencyMultiplier }}</span>
|
|
68
|
+
<span class="stat-label">Leverage</span>
|
|
69
|
+
</div>
|
|
70
|
+
{% endif %}
|
|
71
|
+
</div>
|
|
72
|
+
</section>
|
|
73
|
+
|
|
74
|
+
{%- comment -%} Leverage {%- endcomment -%}
|
|
75
|
+
{% if efficiencyMultiplier %}
|
|
76
|
+
<section class="ember-section" aria-label="AI leverage" role="figure">
|
|
77
|
+
<div class="ember-leverage">
|
|
78
|
+
<div class="ember-leverage__main">
|
|
79
|
+
<span class="ember-leverage__multi">{{ efficiencyMultiplier }}</span>
|
|
80
|
+
<div class="ember-leverage__detail">
|
|
81
|
+
<span>{{ project.totalDurationMinutes | formatDuration }} <small>you</small></span>
|
|
82
|
+
<span style="color:var(--accent)">{{ project.totalAgentDurationMinutes | formatDuration }} <small>agents</small></span>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
{% assign totalCombined = project.totalDurationMinutes | plus: project.totalAgentDurationMinutes %}
|
|
86
|
+
{% if totalCombined > 0 %}
|
|
87
|
+
{% assign agentPct = project.totalAgentDurationMinutes | times: 100 | divided_by: totalCombined %}
|
|
88
|
+
<div class="ember-leverage__bar"><div class="ember-leverage__fill" style="width:{{ agentPct }}%"></div></div>
|
|
89
|
+
{% endif %}
|
|
90
|
+
</div>
|
|
91
|
+
</section>
|
|
92
|
+
{% endif %}
|
|
93
|
+
|
|
94
|
+
{%- comment -%} Narrative {%- endcomment -%}
|
|
95
|
+
{% if project.narrative %}
|
|
96
|
+
<section class="ember-section" aria-label="Project narrative">
|
|
97
|
+
<h2 class="section-header"><span class="ember-icon" aria-hidden="true"></span>Narrative</h2>
|
|
98
|
+
<div class="narrative">
|
|
99
|
+
<p>{{ project.narrative }}</p>
|
|
100
|
+
</div>
|
|
101
|
+
</section>
|
|
102
|
+
{% endif %}
|
|
103
|
+
|
|
104
|
+
{%- comment -%} Work Timeline Chart (CSS-only bars) {%- endcomment -%}
|
|
105
|
+
{% if featuredSessions.size > 0 %}
|
|
106
|
+
<section class="ember-section" aria-label="Session timeline">
|
|
107
|
+
<h2 class="section-header"><span class="ember-icon" aria-hidden="true"></span>Work Timeline</h2>
|
|
108
|
+
<div class="timeline-chart">
|
|
109
|
+
{% assign maxLoc = 1 %}
|
|
110
|
+
{% for s in featuredSessions %}
|
|
111
|
+
{% if s.locChanged > maxLoc %}{% assign maxLoc = s.locChanged %}{% endif %}
|
|
112
|
+
{% endfor %}
|
|
113
|
+
<div class="chart-bars" role="img" aria-label="Bar chart of lines changed per session for {{ project.title }}">
|
|
114
|
+
{% for s in featuredSessions %}
|
|
115
|
+
{% if maxLoc > 0 %}{% assign barPct = s.locChanged | times: 100 | divided_by: maxLoc %}{% else %}{% assign barPct = 0 %}{% endif %}
|
|
116
|
+
<div class="chart-bar-group">
|
|
117
|
+
<div class="chart-bar" style="height: {{ barPct }}%">
|
|
118
|
+
<span class="chart-bar-value">{{ s.locChanged }} LOC</span>
|
|
119
|
+
</div>
|
|
120
|
+
<span class="chart-bar-label">S{{ forloop.index }}</span>
|
|
121
|
+
</div>
|
|
122
|
+
{% endfor %}
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</section>
|
|
126
|
+
{% endif %}
|
|
127
|
+
|
|
128
|
+
{%- comment -%} Phases {%- endcomment -%}
|
|
129
|
+
{% if arc.size > 0 %}
|
|
130
|
+
<section class="ember-section" aria-label="Project phases">
|
|
131
|
+
<h2 class="section-header"><span class="ember-icon" aria-hidden="true"></span>Phases</h2>
|
|
132
|
+
<div class="phases">
|
|
133
|
+
{% for item in arc %}
|
|
134
|
+
<div class="phase-item">
|
|
135
|
+
<div class="phase-dot" aria-hidden="true"></div>
|
|
136
|
+
<div class="phase-title">{{ item.title }}</div>
|
|
137
|
+
{% if item.dates %}
|
|
138
|
+
<div class="phase-dates">{{ item.dates }}</div>
|
|
139
|
+
{% endif %}
|
|
140
|
+
<div class="phase-desc">{{ item.description }}</div>
|
|
141
|
+
</div>
|
|
142
|
+
{% endfor %}
|
|
143
|
+
</div>
|
|
144
|
+
</section>
|
|
145
|
+
{% endif %}
|
|
146
|
+
|
|
147
|
+
{%- comment -%} Skills {%- endcomment -%}
|
|
148
|
+
{% if project.skills.size > 0 %}
|
|
149
|
+
<section class="ember-section" aria-label="Technologies used">
|
|
150
|
+
<h2 class="section-header"><span class="ember-icon" aria-hidden="true"></span>Skills</h2>
|
|
151
|
+
<div class="skills-list">
|
|
152
|
+
{% for skill in project.skills %}
|
|
153
|
+
<span class="skill-chip">{{ skill }}</span>
|
|
154
|
+
{% endfor %}
|
|
155
|
+
</div>
|
|
156
|
+
</section>
|
|
157
|
+
{% endif %}
|
|
158
|
+
|
|
159
|
+
{%- comment -%} Key Decisions {%- endcomment -%}
|
|
160
|
+
{% if arc.size > 0 %}
|
|
161
|
+
<section class="ember-section" aria-label="Key decisions">
|
|
162
|
+
<h2 class="section-header"><span class="ember-icon" aria-hidden="true"></span>Key Decisions</h2>
|
|
163
|
+
<ol class="decisions-list">
|
|
164
|
+
{% for item in arc %}
|
|
165
|
+
<li>{{ item.description }}</li>
|
|
166
|
+
{% endfor %}
|
|
167
|
+
</ol>
|
|
168
|
+
</section>
|
|
169
|
+
{% endif %}
|
|
170
|
+
|
|
171
|
+
{%- comment -%} Source Breakdown {%- endcomment -%}
|
|
172
|
+
{% if sourceCounts.size > 0 %}
|
|
173
|
+
<section class="ember-section" aria-label="Source breakdown">
|
|
174
|
+
<h2 class="section-header"><span class="ember-icon" aria-hidden="true"></span>Source Breakdown</h2>
|
|
175
|
+
<div class="source-breakdown">
|
|
176
|
+
<div class="source-bar-container">
|
|
177
|
+
{% assign totalSourceSessions = 0 %}
|
|
178
|
+
{% for src in sourceCounts %}
|
|
179
|
+
{% assign totalSourceSessions = totalSourceSessions | plus: src.count %}
|
|
180
|
+
{% endfor %}
|
|
181
|
+
{% if totalSourceSessions > 0 %}
|
|
182
|
+
<div class="source-bar">
|
|
183
|
+
{% for src in sourceCounts %}
|
|
184
|
+
{% assign srcPct = src.count | times: 100.0 | divided_by: totalSourceSessions | round %}
|
|
185
|
+
<div class="source-bar-segment{% if forloop.first %} claude{% else %} cursor{% endif %}" style="width: {{ srcPct }}%"></div>
|
|
186
|
+
{% endfor %}
|
|
187
|
+
</div>
|
|
188
|
+
<div class="source-labels">
|
|
189
|
+
{% for src in sourceCounts %}
|
|
190
|
+
{% assign srcPct = src.count | times: 100.0 | divided_by: totalSourceSessions | round %}
|
|
191
|
+
<span><span class="source-legend-dot{% if forloop.first %} claude{% else %} cursor{% endif %}" aria-hidden="true"></span>{{ src.tool }} {{ srcPct }}% ({{ src.count }} session{% if src.count != 1 %}s{% endif %})</span>
|
|
192
|
+
{% endfor %}
|
|
193
|
+
</div>
|
|
194
|
+
{% endif %}
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
</section>
|
|
198
|
+
{% endif %}
|
|
199
|
+
|
|
200
|
+
{%- comment -%} Featured Sessions {%- endcomment -%}
|
|
201
|
+
{% if featuredSessions.size > 0 %}
|
|
202
|
+
<section class="ember-section" aria-label="Featured sessions">
|
|
203
|
+
<h2 class="section-header"><span class="ember-icon" aria-hidden="true"></span>Featured Sessions</h2>
|
|
204
|
+
<div class="sessions-grid">
|
|
205
|
+
{% for s in featuredSessions %}
|
|
206
|
+
<a href="{{ sessionBaseUrl }}/{{ s.slug }}{{ sessionSuffix }}" class="session-card">
|
|
207
|
+
<div class="session-card-number">#{{ forloop.index }}</div>
|
|
208
|
+
<h3 class="session-card-title">{{ s.title }}</h3>
|
|
209
|
+
<div class="session-card-meta">
|
|
210
|
+
<span>{{ s.durationMinutes | formatDuration }}</span>
|
|
211
|
+
<span>{{ s.locChanged | localeNumber }} LOC</span>
|
|
212
|
+
{% if s.agentSummary %}
|
|
213
|
+
<span>{{ s.agentSummary.agents.size }} agent{% if s.agentSummary.agents.size != 1 %}s{% endif %}</span>
|
|
214
|
+
{% endif %}
|
|
215
|
+
</div>
|
|
216
|
+
{% if s.skills.size > 0 %}
|
|
217
|
+
<span class="session-card-tag">{{ s.skills | first }}</span>
|
|
218
|
+
{% endif %}
|
|
219
|
+
</a>
|
|
220
|
+
{% endfor %}
|
|
221
|
+
</div>
|
|
222
|
+
</section>
|
|
223
|
+
{% endif %}
|
|
224
|
+
|
|
225
|
+
{%- comment -%} Footer {%- endcomment -%}
|
|
226
|
+
<footer class="footer">
|
|
227
|
+
<p>Built with <a href="https://heyi.am">heyi.am</a></p>
|
|
228
|
+
</footer>
|
|
229
|
+
|
|
230
|
+
{%- comment -%} Section fade-in animation {%- endcomment -%}
|
|
231
|
+
|
|
232
|
+
</div>
|