heyiam 0.2.29 → 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-CC9G8EF1.js +0 -21
- package/dist/public/assets/index-Dalqz2mC.css +0 -1
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
<div class="heyiam-portfolio radar" data-render-version="2" data-template="radar" data-username="{{ user.username }}">
|
|
2
|
+
|
|
3
|
+
{% if hasProfile %}
|
|
4
|
+
{%- comment -%} Header {%- endcomment -%}
|
|
5
|
+
<section class="radar-section" aria-label="Profile">
|
|
6
|
+
<div class="portfolio-header">
|
|
7
|
+
{% if user.photoUrl %}
|
|
8
|
+
<img src="{{ user.photoUrl }}" alt="{{ user.displayName }}" class="portfolio-photo">
|
|
9
|
+
{% endif %}
|
|
10
|
+
<div class="portfolio-info">
|
|
11
|
+
{% if user.displayName != blank %}
|
|
12
|
+
<h1 class="portfolio-name">{{ user.displayName }}</h1>
|
|
13
|
+
{% endif %}
|
|
14
|
+
<div class="portfolio-handle">@{{ user.username }}</div>
|
|
15
|
+
{% if user.bio != blank %}
|
|
16
|
+
<div class="portfolio-bio">{{ user.bio }}</div>
|
|
17
|
+
{% endif %}
|
|
18
|
+
{% if user.location != blank %}
|
|
19
|
+
<div class="portfolio-location">
|
|
20
|
+
<svg viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z"/><circle cx="12" cy="10" r="3"/></svg>
|
|
21
|
+
{{ user.location }}
|
|
22
|
+
</div>
|
|
23
|
+
{% endif %}
|
|
24
|
+
{% if user.email != blank or user.linkedinUrl != blank or user.githubUrl != blank or user.twitterHandle != blank or user.websiteUrl != blank or user.resumeUrl != blank %}
|
|
25
|
+
<div class="contact-row">
|
|
26
|
+
{% if user.email != blank %}
|
|
27
|
+
<a href="mailto:{{ user.email }}"><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>
|
|
28
|
+
{% endif %}
|
|
29
|
+
{% if user.linkedinUrl != blank %}
|
|
30
|
+
<a href="{{ user.linkedinUrl }}" target="_blank" rel="noopener"><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>
|
|
31
|
+
{% endif %}
|
|
32
|
+
{% if user.githubUrl != blank %}
|
|
33
|
+
<a href="{{ user.githubUrl }}" target="_blank" rel="noopener"><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>
|
|
34
|
+
{% endif %}
|
|
35
|
+
{% if user.twitterHandle != blank %}
|
|
36
|
+
<a href="https://x.com/{{ user.twitterHandle }}" target="_blank" rel="noopener"><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>
|
|
37
|
+
{% endif %}
|
|
38
|
+
{% if user.websiteUrl != blank %}
|
|
39
|
+
<a href="{{ user.websiteUrl }}" target="_blank" rel="noopener">{{ user.websiteUrl | stripProtocol }}</a>
|
|
40
|
+
{% endif %}
|
|
41
|
+
{% if user.resumeUrl != blank %}
|
|
42
|
+
<a href="{{ user.resumeUrl }}" class="resume-btn"><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> Resume (PDF)</a>
|
|
43
|
+
{% endif %}
|
|
44
|
+
</div>
|
|
45
|
+
{% endif %}
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</section>
|
|
49
|
+
{% endif %}
|
|
50
|
+
|
|
51
|
+
{%- comment -%} Aggregate Stats {%- endcomment -%}
|
|
52
|
+
<section class="radar-section" aria-label="Aggregate statistics" id="stats-section">
|
|
53
|
+
<div class="radar-label">Metrics</div>
|
|
54
|
+
<div class="portfolio-stats">
|
|
55
|
+
<div class="portfolio-stat">
|
|
56
|
+
<div class="portfolio-stat__value">{{ projects.size }}</div>
|
|
57
|
+
<div class="portfolio-stat__label">Projects</div>
|
|
58
|
+
</div>
|
|
59
|
+
<div class="portfolio-stat">
|
|
60
|
+
<div class="portfolio-stat__value">{{ totalSessions }}</div>
|
|
61
|
+
<div class="portfolio-stat__label">Sessions</div>
|
|
62
|
+
</div>
|
|
63
|
+
<div class="portfolio-stat">
|
|
64
|
+
<div class="portfolio-stat__value">{{ totalDurationMinutes | formatDuration }}</div>
|
|
65
|
+
<div class="portfolio-stat__label">You</div>
|
|
66
|
+
</div>
|
|
67
|
+
{% if totalAgentDurationMinutes %}
|
|
68
|
+
<div class="portfolio-stat portfolio-stat--cyan">
|
|
69
|
+
<div class="portfolio-stat__value">{{ totalAgentDurationMinutes | formatDuration }}</div>
|
|
70
|
+
<div class="portfolio-stat__label">Agents</div>
|
|
71
|
+
</div>
|
|
72
|
+
{% endif %}
|
|
73
|
+
{% if efficiencyMultiplier %}
|
|
74
|
+
<div class="portfolio-stat portfolio-stat--cyan">
|
|
75
|
+
<div class="portfolio-stat__value">{{ efficiencyMultiplier }}</div>
|
|
76
|
+
<div class="portfolio-stat__label">Multiplier</div>
|
|
77
|
+
</div>
|
|
78
|
+
{% endif %}
|
|
79
|
+
<div class="portfolio-stat">
|
|
80
|
+
<div class="portfolio-stat__value">{{ totalLoc | formatLoc }}</div>
|
|
81
|
+
<div class="portfolio-stat__label">LOC</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</section>
|
|
85
|
+
|
|
86
|
+
{%- comment -%} Projects {%- endcomment -%}
|
|
87
|
+
{% if projects.size > 0 %}
|
|
88
|
+
<section class="radar-section" aria-label="Projects">
|
|
89
|
+
<div class="radar-label">Projects</div>
|
|
90
|
+
<div class="portfolio-projects">
|
|
91
|
+
{% for p in projects %}
|
|
92
|
+
<a class="portfolio-card" href="/{{ user.username }}/{{ p.slug }}">
|
|
93
|
+
<div class="portfolio-card__bar portfolio-card__bar--cyan"></div>
|
|
94
|
+
<div class="portfolio-card__title">{{ p.title }}</div>
|
|
95
|
+
{% if p.narrative != blank %}
|
|
96
|
+
<div class="portfolio-card__desc">{{ p.narrative }}</div>
|
|
97
|
+
{% endif %}
|
|
98
|
+
<div class="portfolio-card__meta">{{ p.totalSessions }} sessions · {{ p.totalDurationMinutes | formatDuration }} · {{ p.totalLoc | formatLoc }} LOC</div>
|
|
99
|
+
{% if p.skills.size > 0 %}
|
|
100
|
+
<div class="portfolio-card__skills">
|
|
101
|
+
{% for skill in p.skills %}
|
|
102
|
+
<span class="chip">{{ skill }}</span>
|
|
103
|
+
{% endfor %}
|
|
104
|
+
</div>
|
|
105
|
+
{% endif %}
|
|
106
|
+
{% if p.sourceCounts.size > 0 %}
|
|
107
|
+
<div class="source-mix" aria-label="Source mix: {% for sc in p.sourceCounts %}{{ sc.tool }} {% assign pct = sc.count | times: 100 | divided_by: p.totalSessions %}{{ pct }}%{% unless forloop.last %}, {% endunless %}{% endfor %}">
|
|
108
|
+
{% for sc in p.sourceCounts %}
|
|
109
|
+
{% assign pct = sc.count | times: 100 | divided_by: p.totalSessions %}
|
|
110
|
+
<div class="source-mix__segment--{{ sc.tool | downcase | replace: ' ', '-' }}" style="width: {{ pct }}%"></div>
|
|
111
|
+
{% endfor %}
|
|
112
|
+
</div>
|
|
113
|
+
{% endif %}
|
|
114
|
+
</a>
|
|
115
|
+
{% endfor %}
|
|
116
|
+
</div>
|
|
117
|
+
</section>
|
|
118
|
+
{% endif %}
|
|
119
|
+
|
|
120
|
+
{%- comment -%} All Skills {%- endcomment -%}
|
|
121
|
+
{% assign allSkills = "" %}
|
|
122
|
+
{% for p in projects %}
|
|
123
|
+
{% for skill in p.skills %}
|
|
124
|
+
{% unless allSkills contains skill %}
|
|
125
|
+
{% if allSkills != "" %}{% assign allSkills = allSkills | append: "|||" %}{% endif %}
|
|
126
|
+
{% assign allSkills = allSkills | append: skill %}
|
|
127
|
+
{% endunless %}
|
|
128
|
+
{% endfor %}
|
|
129
|
+
{% endfor %}
|
|
130
|
+
{% if allSkills != "" %}
|
|
131
|
+
<section class="radar-section" aria-label="Technologies">
|
|
132
|
+
<div class="radar-label">Technologies</div>
|
|
133
|
+
<div class="chip-list">
|
|
134
|
+
{% assign skillArray = allSkills | split: "|||" %}
|
|
135
|
+
{% for skill in skillArray %}
|
|
136
|
+
<span class="chip">{{ skill }}</span>
|
|
137
|
+
{% endfor %}
|
|
138
|
+
</div>
|
|
139
|
+
</section>
|
|
140
|
+
{% endif %}
|
|
141
|
+
|
|
142
|
+
{%- comment -%} Activity Chart {%- endcomment -%}
|
|
143
|
+
{% if activityByMonth.size > 0 %}
|
|
144
|
+
<section class="radar-section" aria-label="Activity overview" id="activity-chart-section">
|
|
145
|
+
<div class="radar-label">Activity</div>
|
|
146
|
+
<div style="background: var(--surface-lowest); border: 1px solid var(--ghost); border-radius: var(--radius-sm); padding: 1rem; overflow: hidden;">
|
|
147
|
+
{% assign maxSessions = 0 %}
|
|
148
|
+
{% for m in activityByMonth %}
|
|
149
|
+
{% if m.sessions > maxSessions %}{% assign maxSessions = m.sessions %}{% endif %}
|
|
150
|
+
{% endfor %}
|
|
151
|
+
<svg viewBox="0 0 820 160" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Activity chart showing sessions per month">
|
|
152
|
+
<line x1="48" y1="10" x2="48" y2="130" stroke="rgba(34,211,238,0.08)" stroke-width="1"/>
|
|
153
|
+
<line x1="48" y1="130" x2="800" y2="130" stroke="rgba(34,211,238,0.08)" stroke-width="1"/>
|
|
154
|
+
<line x1="48" y1="90" x2="800" y2="90" stroke="rgba(34,211,238,0.04)" stroke-width="1" stroke-dasharray="4 4"/>
|
|
155
|
+
<line x1="48" y1="50" x2="800" y2="50" stroke="rgba(34,211,238,0.04)" stroke-width="1" stroke-dasharray="4 4"/>
|
|
156
|
+
{% assign barWidth = 750 | divided_by: activityByMonth.size %}
|
|
157
|
+
{% for m in activityByMonth %}
|
|
158
|
+
{% if maxSessions > 0 %}
|
|
159
|
+
{% assign barHeight = m.sessions | times: 100 | divided_by: maxSessions %}
|
|
160
|
+
{% else %}
|
|
161
|
+
{% assign barHeight = 0 %}
|
|
162
|
+
{% endif %}
|
|
163
|
+
{% assign barY = 130 | minus: barHeight %}
|
|
164
|
+
{% assign barX = forloop.index0 | times: barWidth | plus: 60 %}
|
|
165
|
+
{% assign barW = barWidth | minus: 20 %}
|
|
166
|
+
<rect class="wt-bar" x="{{ barX }}" y="{{ barY }}" width="{{ barW }}" height="{{ barHeight }}" rx="2" fill="#22d3ee" opacity="0.7"/>
|
|
167
|
+
{% assign labelX = barX | plus: barW | divided_by: 2 | plus: barX | divided_by: 2 %}
|
|
168
|
+
<text x="{{ barX }}" y="146" fill="#64748b" font-family="'IBM Plex Mono', monospace" font-size="8" dx="{{ barW | divided_by: 2 }}">{{ m.month }}</text>
|
|
169
|
+
{% assign valueY = barY | minus: 4 %}
|
|
170
|
+
<text x="{{ barX }}" y="{{ valueY }}" fill="#64748b" font-family="'IBM Plex Mono', monospace" font-size="7" dx="{{ barW | divided_by: 2 }}">{{ m.sessions }}</text>
|
|
171
|
+
{% endfor %}
|
|
172
|
+
</svg>
|
|
173
|
+
</div>
|
|
174
|
+
</section>
|
|
175
|
+
{% endif %}
|
|
176
|
+
|
|
177
|
+
{%- comment -%} Footer {%- endcomment -%}
|
|
178
|
+
<section class="radar-section" aria-label="Footer" data-radar-section="footer">
|
|
179
|
+
<footer class="radar-footer">
|
|
180
|
+
<div class="radar-footer__text">Built with heyi.am</div>
|
|
181
|
+
</footer>
|
|
182
|
+
</section>
|
|
183
|
+
|
|
184
|
+
{%- comment -%} Radar Floating Nav {%- endcomment -%}
|
|
185
|
+
<nav class="radar-nav" aria-label="Section navigation">
|
|
186
|
+
<div class="radar-nav__ring"></div>
|
|
187
|
+
<div class="radar-nav__sweep"></div>
|
|
188
|
+
<div class="radar-nav__center"></div>
|
|
189
|
+
</nav>
|
|
190
|
+
<script>
|
|
191
|
+
(function() {
|
|
192
|
+
'use strict';
|
|
193
|
+
var nav = document.querySelector('.radar-nav');
|
|
194
|
+
if (!nav) return;
|
|
195
|
+
var sections = document.querySelectorAll('.radar-section');
|
|
196
|
+
var dots = [];
|
|
197
|
+
sections.forEach(function(sec, i) {
|
|
198
|
+
sec.setAttribute('data-radar-section', i);
|
|
199
|
+
var label = sec.getAttribute('aria-label') || 'Section ' + (i + 1);
|
|
200
|
+
var btn = document.createElement('button');
|
|
201
|
+
btn.className = 'radar-nav__dot';
|
|
202
|
+
btn.setAttribute('data-radar-dot', i);
|
|
203
|
+
btn.setAttribute('aria-label', 'Navigate to ' + label);
|
|
204
|
+
nav.appendChild(btn);
|
|
205
|
+
dots.push(btn);
|
|
206
|
+
});
|
|
207
|
+
var total = dots.length;
|
|
208
|
+
dots.forEach(function(dot, i) {
|
|
209
|
+
var angle = (i / total) * 2 * Math.PI - Math.PI / 2;
|
|
210
|
+
var r = 54;
|
|
211
|
+
dot.style.left = (60 + r * Math.cos(angle) - 3) + 'px';
|
|
212
|
+
dot.style.top = (60 + r * Math.sin(angle) - 3) + 'px';
|
|
213
|
+
});
|
|
214
|
+
var observer = new IntersectionObserver(function(entries) {
|
|
215
|
+
entries.forEach(function(entry) {
|
|
216
|
+
var idx = entry.target.getAttribute('data-radar-section');
|
|
217
|
+
var dot = nav.querySelector('[data-radar-dot="' + idx + '"]');
|
|
218
|
+
if (dot) dot.classList.toggle('radar-nav__dot--active', entry.isIntersecting);
|
|
219
|
+
});
|
|
220
|
+
}, { threshold: 0.3 });
|
|
221
|
+
sections.forEach(function(s) { observer.observe(s); });
|
|
222
|
+
dots.forEach(function(dot) {
|
|
223
|
+
dot.addEventListener('click', function() {
|
|
224
|
+
var idx = this.getAttribute('data-radar-dot');
|
|
225
|
+
var target = document.querySelector('[data-radar-section="' + idx + '"]');
|
|
226
|
+
if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
})();
|
|
230
|
+
</script>
|
|
231
|
+
|
|
232
|
+
</div>
|
|
233
|
+
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
<div class="heyiam-project radar" data-render-version="2" data-template="radar"{% if sessionBaseUrl %} data-session-base-url="{{ sessionBaseUrl }}"{% endif %} data-username="{{ user.username }}" data-project-slug="{{ project.slug }}">
|
|
2
|
+
|
|
3
|
+
{%- comment -%} Breadcrumb {%- endcomment -%}
|
|
4
|
+
<nav class="radar-breadcrumb" aria-label="Breadcrumb">
|
|
5
|
+
<a href="/{{ user.username }}">{{ user.username }}</a>
|
|
6
|
+
<span class="radar-breadcrumb__sep">/</span>
|
|
7
|
+
<span>{{ project.slug }}</span>
|
|
8
|
+
</nav>
|
|
9
|
+
|
|
10
|
+
{%- comment -%} Title {%- endcomment -%}
|
|
11
|
+
<section class="radar-section" aria-label="Project title">
|
|
12
|
+
<h1 class="radar-title" data-editable="title">{{ project.title }}</h1>
|
|
13
|
+
</section>
|
|
14
|
+
|
|
15
|
+
{%- comment -%} Links {%- endcomment -%}
|
|
16
|
+
{% if project.repoUrl or project.projectUrl %}
|
|
17
|
+
<section class="radar-section" style="margin-bottom: 2rem;" aria-label="Project links">
|
|
18
|
+
<div class="radar-links">
|
|
19
|
+
{% if project.repoUrl %}
|
|
20
|
+
<a class="radar-link" href="{{ project.repoUrl }}" target="_blank" rel="noopener">
|
|
21
|
+
<svg viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
|
|
22
|
+
{{ project.repoUrl | stripProtocol }}
|
|
23
|
+
</a>
|
|
24
|
+
{% endif %}
|
|
25
|
+
{% if project.projectUrl %}
|
|
26
|
+
<a class="radar-link" href="{{ project.projectUrl }}" target="_blank" rel="noopener">
|
|
27
|
+
<svg viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round"><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>
|
|
28
|
+
{{ project.projectUrl | stripProtocol }}
|
|
29
|
+
</a>
|
|
30
|
+
{% endif %}
|
|
31
|
+
</div>
|
|
32
|
+
</section>
|
|
33
|
+
{% endif %}
|
|
34
|
+
|
|
35
|
+
{%- comment -%} Screenshot {%- endcomment -%}
|
|
36
|
+
{% if project.screenshotUrl %}
|
|
37
|
+
<section class="radar-section" aria-label="Project screenshot">
|
|
38
|
+
<div class="browser-chrome">
|
|
39
|
+
<div class="browser-chrome__bar">
|
|
40
|
+
<div class="browser-chrome__dot browser-chrome__dot--red"></div>
|
|
41
|
+
<div class="browser-chrome__dot browser-chrome__dot--yellow"></div>
|
|
42
|
+
<div class="browser-chrome__dot browser-chrome__dot--green"></div>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="browser-chrome__viewport">
|
|
45
|
+
<img src="{{ project.screenshotUrl }}" alt="{{ project.title }} screenshot" style="width: 100%; height: 100%; object-fit: cover;">
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</section>
|
|
49
|
+
{% endif %}
|
|
50
|
+
|
|
51
|
+
{%- comment -%} Narrative {%- endcomment -%}
|
|
52
|
+
{% if project.narrative != blank %}
|
|
53
|
+
<section class="radar-section" aria-label="Project narrative">
|
|
54
|
+
<div class="radar-narrative">
|
|
55
|
+
{{ project.narrative }}
|
|
56
|
+
</div>
|
|
57
|
+
</section>
|
|
58
|
+
{% endif %}
|
|
59
|
+
|
|
60
|
+
{%- comment -%} Stats {%- endcomment -%}
|
|
61
|
+
<section class="radar-section" aria-label="Project statistics" id="stats-section">
|
|
62
|
+
<div class="radar-label">Metrics</div>
|
|
63
|
+
<div class="stat-grid">
|
|
64
|
+
<div class="stat-card">
|
|
65
|
+
<div class="stat-card__label">Sessions</div>
|
|
66
|
+
<div class="stat-card__value">{{ project.totalSessions }}</div>
|
|
67
|
+
</div>
|
|
68
|
+
<div class="stat-card">
|
|
69
|
+
<div class="stat-card__label">You</div>
|
|
70
|
+
<div class="stat-card__value">{{ project.totalDurationMinutes | formatDuration }}</div>
|
|
71
|
+
</div>
|
|
72
|
+
{% if project.totalAgentDurationMinutes %}
|
|
73
|
+
<div class="stat-card stat-card--cyan">
|
|
74
|
+
<div class="stat-card__label">Agents</div>
|
|
75
|
+
<div class="stat-card__value">{{ project.totalAgentDurationMinutes | formatDuration }}</div>
|
|
76
|
+
</div>
|
|
77
|
+
{% endif %}
|
|
78
|
+
{% if efficiencyMultiplier %}
|
|
79
|
+
<div class="stat-card stat-card--cyan">
|
|
80
|
+
<div class="stat-card__label">Multiplier</div>
|
|
81
|
+
<div class="stat-card__value">{{ efficiencyMultiplier }}</div>
|
|
82
|
+
</div>
|
|
83
|
+
{% endif %}
|
|
84
|
+
<div class="stat-card">
|
|
85
|
+
<div class="stat-card__label">Lines Changed</div>
|
|
86
|
+
<div class="stat-card__value">{{ project.totalLoc | formatLoc }}</div>
|
|
87
|
+
</div>
|
|
88
|
+
<div class="stat-card">
|
|
89
|
+
<div class="stat-card__label">Files Changed</div>
|
|
90
|
+
<div class="stat-card__value">{{ project.totalFilesChanged | localeNumber }}</div>
|
|
91
|
+
</div>
|
|
92
|
+
{% if project.totalTokens %}
|
|
93
|
+
<div class="stat-card">
|
|
94
|
+
<div class="stat-card__label">Tokens</div>
|
|
95
|
+
<div class="stat-card__value">{{ project.totalTokens | formatTokens }}</div>
|
|
96
|
+
</div>
|
|
97
|
+
{% endif %}
|
|
98
|
+
</div>
|
|
99
|
+
</section>
|
|
100
|
+
|
|
101
|
+
{%- comment -%} Work Timeline — React component with radar accent {%- endcomment -%}
|
|
102
|
+
{% if sessionsJson != blank %}
|
|
103
|
+
<section class="radar-section" aria-label="Work timeline">
|
|
104
|
+
<div class="radar-label">Work Timeline</div>
|
|
105
|
+
<div class="chart-card">
|
|
106
|
+
<div data-work-timeline data-sessions='{{ sessionsJson | raw }}'></div>
|
|
107
|
+
</div>
|
|
108
|
+
</section>
|
|
109
|
+
{% endif %}
|
|
110
|
+
|
|
111
|
+
{%- comment -%} Lines Changed — React component with radar variant + dual positive {%- endcomment -%}
|
|
112
|
+
{% if sessionsJson != blank %}
|
|
113
|
+
<section class="radar-section" aria-label="Lines changed">
|
|
114
|
+
<div class="radar-label">Lines Changed</div>
|
|
115
|
+
<div class="chart-card">
|
|
116
|
+
<div data-growth-chart data-variant="radar" data-project-slug="{{ project.slug }}" data-total-loc="{{ project.totalLoc }}" data-total-files="{{ project.totalFilesChanged }}" data-sessions='{{ growthJson | raw }}'></div>
|
|
117
|
+
</div>
|
|
118
|
+
</section>
|
|
119
|
+
{% endif %}
|
|
120
|
+
|
|
121
|
+
{%- comment -%} Two-Column: Key Decisions + Source Breakdown {%- endcomment -%}
|
|
122
|
+
{% if arc.size > 0 or sourceCounts.size > 0 %}
|
|
123
|
+
<section class="radar-section" aria-label="Key decisions and source breakdown">
|
|
124
|
+
<div class="two-col">
|
|
125
|
+
{% if arc.size > 0 %}
|
|
126
|
+
<div>
|
|
127
|
+
<div class="radar-label">Key Decisions</div>
|
|
128
|
+
<ul class="decision-list">
|
|
129
|
+
{% for item in arc %}
|
|
130
|
+
<li class="decision-item">
|
|
131
|
+
<div class="decision-bullet">
|
|
132
|
+
<div>
|
|
133
|
+
<div class="decision-title">{{ item.title }}</div>
|
|
134
|
+
{% if item.description != blank %}
|
|
135
|
+
<div class="decision-desc">{{ item.description }}</div>
|
|
136
|
+
{% endif %}
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</li>
|
|
140
|
+
{% endfor %}
|
|
141
|
+
</ul>
|
|
142
|
+
</div>
|
|
143
|
+
{% endif %}
|
|
144
|
+
{% if sourceCounts.size > 0 %}
|
|
145
|
+
<div>
|
|
146
|
+
<div class="radar-label">Source Breakdown</div>
|
|
147
|
+
<table class="source-table">
|
|
148
|
+
<thead>
|
|
149
|
+
<tr>
|
|
150
|
+
<th>Tool</th>
|
|
151
|
+
<th style="text-align: right;">Sessions</th>
|
|
152
|
+
</tr>
|
|
153
|
+
</thead>
|
|
154
|
+
<tbody>
|
|
155
|
+
{% for src in sourceCounts %}
|
|
156
|
+
<tr><td>{{ src.tool }}</td><td>{{ src.count }} ({{ src.count | times: 100.0 | divided_by: project.totalSessions | round }}%)</td></tr>
|
|
157
|
+
{% endfor %}
|
|
158
|
+
</tbody>
|
|
159
|
+
</table>
|
|
160
|
+
</div>
|
|
161
|
+
{% endif %}
|
|
162
|
+
</div>
|
|
163
|
+
</section>
|
|
164
|
+
{% endif %}
|
|
165
|
+
|
|
166
|
+
{%- comment -%} Phase Timeline {%- endcomment -%}
|
|
167
|
+
{% if arc.size > 0 %}
|
|
168
|
+
<section class="radar-section" aria-label="Project phases">
|
|
169
|
+
<div class="radar-label">Phases</div>
|
|
170
|
+
<div class="phase-timeline">
|
|
171
|
+
<div class="phase-timeline__line"></div>
|
|
172
|
+
{% for phase in arc %}
|
|
173
|
+
<div class="phase-timeline__item">
|
|
174
|
+
<div class="phase-timeline__dot"></div>
|
|
175
|
+
<div class="phase-timeline__title">{{ phase.phase }}. {{ phase.title }}</div>
|
|
176
|
+
{% if phase.dates != blank %}
|
|
177
|
+
<div class="phase-timeline__dates">{{ phase.dates }}</div>
|
|
178
|
+
{% endif %}
|
|
179
|
+
{% if phase.description != blank %}
|
|
180
|
+
<div class="phase-timeline__desc">{{ phase.description }}</div>
|
|
181
|
+
{% endif %}
|
|
182
|
+
</div>
|
|
183
|
+
{% endfor %}
|
|
184
|
+
</div>
|
|
185
|
+
</section>
|
|
186
|
+
{% endif %}
|
|
187
|
+
|
|
188
|
+
{%- comment -%} Skills {%- endcomment -%}
|
|
189
|
+
{% if project.skills.size > 0 %}
|
|
190
|
+
<section class="radar-section" aria-label="Technologies used">
|
|
191
|
+
<div class="radar-label">Technologies</div>
|
|
192
|
+
<div class="chip-list">
|
|
193
|
+
{% for skill in project.skills %}
|
|
194
|
+
<span class="chip">{{ skill }}</span>
|
|
195
|
+
{% endfor %}
|
|
196
|
+
</div>
|
|
197
|
+
</section>
|
|
198
|
+
{% endif %}
|
|
199
|
+
|
|
200
|
+
{%- comment -%} Featured Sessions {%- endcomment -%}
|
|
201
|
+
{% if featuredSessions.size > 0 %}
|
|
202
|
+
<section class="radar-section" aria-label="Featured sessions">
|
|
203
|
+
<div class="section-header">
|
|
204
|
+
<div class="radar-label" style="margin-bottom: 0;">Sessions</div>
|
|
205
|
+
<div class="section-header__meta">{{ project.totalSessions }} total</div>
|
|
206
|
+
</div>
|
|
207
|
+
<div class="session-grid">
|
|
208
|
+
{% for s in featuredSessions %}
|
|
209
|
+
<a class="session-card" href="{{ sessionBaseUrl }}/{{ s.slug }}{{ sessionSuffix }}">
|
|
210
|
+
<div class="session-card__bar session-card__bar--cyan"></div>
|
|
211
|
+
<div class="session-card__title">{{ s.title }}</div>
|
|
212
|
+
<div class="session-card__meta">{{ s.durationMinutes | formatDuration }} · {{ s.locChanged | formatLoc }} LOC{% if s.agentSummary %} · {{ s.agentSummary.agents.size }} agent{% if s.agentSummary.agents.size != 1 %}s{% endif %}{% else %} · {{ s.turns }} turns{% endif %}</div>
|
|
213
|
+
{% if s.skills.size > 0 %}
|
|
214
|
+
<span class="session-card__tag">{{ s.skills[0] }}</span>
|
|
215
|
+
{% endif %}
|
|
216
|
+
</a>
|
|
217
|
+
{% endfor %}
|
|
218
|
+
</div>
|
|
219
|
+
</section>
|
|
220
|
+
{% endif %}
|
|
221
|
+
|
|
222
|
+
{%- comment -%} Footer {%- endcomment -%}
|
|
223
|
+
<section class="radar-section" aria-label="Footer" data-radar-section="footer">
|
|
224
|
+
<footer class="radar-footer">
|
|
225
|
+
<div class="radar-footer__text">Built with heyi.am</div>
|
|
226
|
+
</footer>
|
|
227
|
+
</section>
|
|
228
|
+
|
|
229
|
+
{%- comment -%} Radar Floating Nav {%- endcomment -%}
|
|
230
|
+
<nav class="radar-nav" aria-label="Section navigation">
|
|
231
|
+
<div class="radar-nav__ring"></div>
|
|
232
|
+
<div class="radar-nav__sweep"></div>
|
|
233
|
+
<div class="radar-nav__center"></div>
|
|
234
|
+
</nav>
|
|
235
|
+
<script>
|
|
236
|
+
(function() {
|
|
237
|
+
'use strict';
|
|
238
|
+
var nav = document.querySelector('.radar-nav');
|
|
239
|
+
if (!nav) return;
|
|
240
|
+
var sections = document.querySelectorAll('.radar-section');
|
|
241
|
+
var dots = [];
|
|
242
|
+
sections.forEach(function(sec, i) {
|
|
243
|
+
sec.setAttribute('data-radar-section', i);
|
|
244
|
+
var label = sec.getAttribute('aria-label') || 'Section ' + (i + 1);
|
|
245
|
+
var btn = document.createElement('button');
|
|
246
|
+
btn.className = 'radar-nav__dot';
|
|
247
|
+
btn.setAttribute('data-radar-dot', i);
|
|
248
|
+
btn.setAttribute('aria-label', 'Navigate to ' + label);
|
|
249
|
+
nav.appendChild(btn);
|
|
250
|
+
dots.push(btn);
|
|
251
|
+
});
|
|
252
|
+
var total = dots.length;
|
|
253
|
+
dots.forEach(function(dot, i) {
|
|
254
|
+
var angle = (i / total) * 2 * Math.PI - Math.PI / 2;
|
|
255
|
+
var r = 54;
|
|
256
|
+
dot.style.left = (60 + r * Math.cos(angle) - 3) + 'px';
|
|
257
|
+
dot.style.top = (60 + r * Math.sin(angle) - 3) + 'px';
|
|
258
|
+
});
|
|
259
|
+
var observer = new IntersectionObserver(function(entries) {
|
|
260
|
+
entries.forEach(function(entry) {
|
|
261
|
+
var idx = entry.target.getAttribute('data-radar-section');
|
|
262
|
+
var dot = nav.querySelector('[data-radar-dot="' + idx + '"]');
|
|
263
|
+
if (dot) dot.classList.toggle('radar-nav__dot--active', entry.isIntersecting);
|
|
264
|
+
});
|
|
265
|
+
}, { threshold: 0.3 });
|
|
266
|
+
sections.forEach(function(s) { observer.observe(s); });
|
|
267
|
+
dots.forEach(function(dot) {
|
|
268
|
+
dot.addEventListener('click', function() {
|
|
269
|
+
var idx = this.getAttribute('data-radar-dot');
|
|
270
|
+
var target = document.querySelector('[data-radar-section="' + idx + '"]');
|
|
271
|
+
if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
})();
|
|
275
|
+
</script>
|
|
276
|
+
|
|
277
|
+
</div>
|
|
278
|
+
|