686f09ed5ca8
give each palette colour one meaning on every page: amber for links, green for additions and success, red for removals and errors, lavender for versions, rose for people; the timeline returns to amber tones (v3.1.14)
- time
- 2026-10-08 00:39 UTC · 5 days ago
- machine
- Junes-MacBook-Pro.local
- agent
- claude-opus-5-5
- session
- vivid kepr palette
- parent
- 34c906a3bdd2
↓ kepr-686f09ed.tar.gzatlas at this save
files changed7 files
package.json+1 −1public/css/kepr.css+28 −34public/js/kepr.js+4 −4src/admin/repos.ts+1 −1src/pages/repo.ts+2 −2tests/releases.test.ts+6 −2tests/version.test.ts+4 −2package.json+1 −1
@@ -1,6 +1,6 @@11 {22 "name": "kepr",3- "version": "3.1.13",3+ "version": "3.1.14",44 "private": true,55 "type": "module",66 "scripts": {public/css/kepr.css+28 −34
@@ -13,7 +13,6 @@1313 --accent: #ffad33;1414 --accent-bright: #ffc966;1515 --accent-dim: #b8741c;16- --accent-flash: #4da3ff;1716 --red: #ff5c4d;1817 --accent-tint-04: rgba(255, 173, 51, 0.04);1918 --accent-tint-12: rgba(255, 173, 51, 0.12);@@ -295,7 +294,7 @@295294 animation: fadeUp 280ms 40ms ease both;296295 }297296 .repo-contributor a:hover {298- color: var(--accent);297+ text-decoration-color: var(--rose);299298 }300299 .repo-desc,301300 .repo-homepage {@@ -326,13 +325,16 @@326325 .lang-badge {327326 font-family: var(--mono);328327 font-size: 0.6875rem;329- color: var(--lavender);328+ color: var(--text-secondary);330329 background: var(--bg-surface);331330 border: 1px solid var(--border);332331 border-radius: 3px;333332 padding: 1px 7px;334333 letter-spacing: 0.02em;335334 }335+.repo-version {336+ color: var(--lavender);337+}336338 .repo-meta {337339 margin: 0;338340 font-size: 0.875rem;@@ -392,7 +394,7 @@392394 max-width: 100%;393395 font-family: var(--mono);394396 font-size: 0.75rem;395- color: var(--sage);397+ color: var(--text-muted);396398 background: var(--bg-surface);397399 border: 1px solid var(--border);398400 border-radius: 3px;@@ -406,11 +408,14 @@406408 color 120ms,407409 border-color 120ms;408410 }409-.repo-steal-btn:hover,410-.repo-steal-btn.copied {411+.repo-steal-btn:hover {411412 color: var(--accent);412413 border-color: var(--accent-dim);413414 }415+.repo-steal-btn.copied {416+ color: var(--sage);417+ border-color: var(--sage);418+}414419 .install-lines {415420 display: flex;416421 flex-direction: column;@@ -448,10 +453,12 @@448453 color: var(--text-faint);449454 letter-spacing: 0.04em;450455 }451-.copy-btn:hover,452-.copy-btn.copied {456+.copy-btn:hover {453457 color: var(--accent);454458 }459+.copy-btn.copied {460+ color: var(--sage);461+}455462 456463 /* ----- sections ----------------------------------------------------------- */457464 @@ -494,7 +501,7 @@494501 .section-label {495502 font-size: 0.6875rem;496503 letter-spacing: 0.12em;497- color: var(--lavender);504+ color: var(--text-secondary);498505 text-transform: uppercase;499506 }500507 .section-count {@@ -1466,7 +1473,7 @@14661473 .release-version {14671474 font-family: "Martian Mono", monospace;14681475 font-size: 1rem;1469- color: var(--accent);1476+ color: var(--lavender);14701477 }14711478 .release-latest .release-version {14721479 font-size: clamp(2rem, 5vw, 3.5rem);@@ -1593,7 +1600,7 @@15931600 color: var(--text-muted);15941601 }15951602 .issue-symbol--open {1596- color: var(--accent);1603+ color: var(--sage);15971604 }15981605 .issue-symbol--closed {15991606 color: var(--text-faint);@@ -1603,7 +1610,7 @@16031610 }16041611 .issue-reporter {16051612 font-size: 0.6875rem;1606- color: var(--text-muted);1613+ color: var(--rose);16071614 overflow-wrap: anywhere;16081615 }16091616 .issues-filter {@@ -1620,7 +1627,7 @@16201627 background: var(--bg-surface);16211628 }16221629 .issue-post--operator {1623- border-color: var(--accent-dim);1630+ border-color: var(--rose);16241631 }16251632 .issue-post-head {16261633 display: flex;@@ -1629,10 +1636,10 @@16291636 margin: 0 0 8px;16301637 }16311638 .issue-author {1632- color: var(--text);1639+ color: var(--rose);16331640 }16341641 .issue-badge {1635- color: var(--accent);1642+ color: var(--rose);16361643 text-transform: uppercase;16371644 letter-spacing: 0.08em;16381645 }@@ -1877,24 +1884,12 @@18771884 font-family: var(--mono);18781885 letter-spacing: 0.03em;18791886 white-space: nowrap;1880- color: var(--accent);1887+ color: var(--accent-dim);18811888 transition:18821889 color 0.2s,18831890 opacity 0.2s,18841891 text-shadow 0.2s;18851892 }1886-.tc-tag:nth-child(5n + 2) {1887- color: var(--red);1888-}1889-.tc-tag:nth-child(5n + 3) {1890- color: var(--sage);1891-}1892-.tc-tag:nth-child(5n + 4) {1893- color: var(--rose);1894-}1895-.tc-tag:nth-child(5n) {1896- color: var(--lavender);1897-}18981893 .tc-tag:hover {18991894 color: var(--accent);19001895 opacity: 1;@@ -2088,7 +2083,7 @@20882083 line-height: 1;20892084 letter-spacing: -0.02em;20902085 text-transform: lowercase;2091- color: var(--text-heading);2086+ color: var(--rose);20922087 user-select: none;20932088 animation: fadeUp 500ms ease both;20942089 }@@ -2108,7 +2103,7 @@21082103 display: block;21092104 font-size: 0.6875rem;21102105 letter-spacing: 0.18em;2111- color: var(--accent);2106+ color: var(--rose);21122107 }21132108 21142109 .profile-portrait-section {@@ -2206,14 +2201,13 @@22062201 opacity: 0.6;22072202 }22082203 .profile-lang-bar rect:nth-child(2) {2209- fill: var(--sage);2204+ fill: var(--accent-bright);22102205 }22112206 .profile-lang-bar rect:nth-child(3) {2212- fill: var(--accent-flash);2213- opacity: 0.45;2207+ fill: var(--accent-dim);22142208 }22152209 .profile-lang-bar rect:nth-child(4) {2216- fill: var(--accent-dim);2210+ fill: var(--text-muted);22172211 }22182212 .profile-lang-labels {22192213 display: flex;public/js/kepr.js+4 −4
@@ -6,14 +6,14 @@66 // Kepr 2's save kinds (canvas.js), first match wins: each dot's colour and strength.77 const KINDS = [88 [/\b(release|version|bump|tag)\b/i, "accent", 1],9- [/\b(fix|bug|patch|issue|crash|error|regress|revert)\b/i, "red", 0.9],10- [/\b(add|new|implement|feat|introduce|wire|support)\b/i, "sage", 1],9+ [/\b(fix|bug|patch|issue|crash|error|regress|revert)\b/i, "accent-dim", 0.8],10+ [/\b(add|new|implement|feat|introduce|wire|support)\b/i, "accent", 1],1111 [1212 /\b(refactor|restructure|reorganize|extract|move|rename|split|cleanup|clean up)\b/i,13- "lavender",13+ "text",1414 0.85,1515 ],16- [/\b(perf|optim|speed|fast|slow|cache|memory|alloc)\b/i, "rose", 0.9],16+ [/\b(perf|optim|speed|fast|slow|cache|memory|alloc)\b/i, "accent", 0.9],1717 [/\b(test|spec|coverage|assert)\b/i, "text-secondary", 0.74],1818 [/\b(doc|readme|comment|example|guide)\b/i, "text-secondary", 0.7],1919 [/\b(polish|style|format|lint|whitespace|typo|wording|copy)\b/i, "text-secondary", 0.66],src/admin/repos.ts+1 −1
@@ -365,7 +365,7 @@365365 const id = `release-${repo}-${release.version}`;366366 return html`<article class="issue-post" id="${id}">367367 <p class="issue-post-head mono">368-${/* this row stays one line: splitting its spans changes the HTML that tests/console.test.ts pins */ ""}${html`<span class="issue-author">${release.version}</span>`}${html`<span>${release.hidden ? "hidden" : "shown"}</span>`}${html`<span>${plural(total, "download")}</span>`}${release.downloads.map(368+${/* this row stays one line: splitting its spans changes the HTML that tests/console.test.ts pins */ ""}${html`<span class="repo-version">${release.version}</span>`}${html`<span>${release.hidden ? "hidden" : "shown"}</span>`}${html`<span>${plural(total, "download")}</span>`}${release.downloads.map(369369 ([platform, n]) => html`<span class="muted">${platform} ${n}</span>`,370370 )}371371 </p>src/pages/repo.ts+2 −2
@@ -139,7 +139,7 @@139139 visibleReleases(ctx.kepr, repo.mirror, name)[0]?.version ||140140 mirrorState(repo.mirror, "declared_version");141141 const meta = [142- version && `v${version}`,142+ version && html`<span class="repo-version">v${version}</span>`,143143 plural(stats.saves, "save"),144144 stats.lines > 0 && plural(stats.lines, "line"),145145 stats.updated !== null && `updated ${relativeTime(stats.updated)}`,@@ -158,7 +158,7 @@158158 (language) => html`<span class="lang-badge">${language}</span>`,159159 )}</div>`160160 }161-<p class="repo-meta">${meta.join(" · ")}</p>161+<p class="repo-meta">${meta.flatMap((part, i) => (i === 0 ? [part] : [" · ", part]))}</p>162162 <div class="repo-tabbar">163163 <nav class="repo-tabs" aria-label="Repository panels">${PANELS.map(164164 ([label, path]) =>tests/releases.test.ts+6 −2
@@ -207,12 +207,16 @@207207 });208208 209209 test("hidden versions don't show, and the repo header names the newest visible release", async () => {210- expect(await (await get("/tool")).text()).toContain("v0.11.0 · ");210+ expect(await (await get("/tool")).text()).toContain(211+ `<span class="repo-version">v0.11.0</span> · `,212+ );211213 const kepr = releaseKepr.get(app);212214 kepr?.run("INSERT INTO release_settings (repo, version, hidden) VALUES ('tool', '0.11.0', 1)");213215 const body = await (await get("/tool/releases")).text();214216 expect(body).not.toContain("0.11.0");215- expect(await (await get("/tool")).text()).toContain("v0.10.0 · ");217+ expect(await (await get("/tool")).text()).toContain(218+ `<span class="repo-version">v0.10.0</span> · `,219+ );216220 kepr?.run("DELETE FROM release_settings");217221 });218222 tests/version.test.ts+4 −2
@@ -81,7 +81,9 @@8181 const inst = await instance(repos.bucketDir);8282 inst.kepr.run("UPDATE repos SET public = 1");8383 const meta = async () =>84- /<p class="repo-meta">([^<]*)<\/p>/.exec(await (await inst.app.request("/app")).text())?.[1];84+ /<p class="repo-meta">(.*?)<\/p>/85+ .exec(await (await inst.app.request("/app")).text())?.[1]86+ ?.replace(/<[^>]+>/g, "");8587 expect(await meta()).toStartWith("v1.2.3 · ");8688 const head = JSON.parse(repos.koh("app", "view", "--json")).head_id as string;8789 await writeRelease(repos.bucketDir, "app", {@@ -107,7 +109,7 @@107109 const inst = await instance(repos.bucketDir);108110 inst.kepr.run("UPDATE repos SET public = 1");109111 const page = await (await inst.app.request("/app")).text();110- const meta = /<p class="repo-meta">([^<]*)<\/p>/.exec(page)?.[1];112+ const meta = /<p class="repo-meta">(.*?)<\/p>/.exec(page)?.[1]?.replace(/<[^>]+>/g, "");111113 expect(meta).toBeDefined();112114 expect(meta).not.toStartWith("v");113115 });