token-larper 1.8.1 → 1.9.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "token-larper",
3
- "version": "1.8.1",
3
+ "version": "1.9.0",
4
4
  "description": "Token Larper — Multi-Harness AI Coding Usage & Cost Telemetry Dashboard powered by ccusage",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,9 +1,10 @@
1
1
  import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
- import { AlertTriangle, Heart, Moon, Power, RefreshCw, Search, Settings, Sun } from "lucide-react";
2
+ import { AlertTriangle, Moon, Power, RefreshCw, Search, Settings, Sun } from "lucide-react";
3
3
  import type { DashboardPayload, HarnessId, StartupConfig } from "../types.ts";
4
4
  import { OTHER_SERIES, SERIES_SLOTS, seriesColor, type SeriesInfo } from "./charts.tsx";
5
5
  import { DashboardProvider, type Dashboard } from "./context.tsx";
6
6
  import { DateRangePicker } from "./components/DateRangePicker.tsx";
7
+ import { AppFooter } from "./components/AppFooter.tsx";
7
8
  import { Logo } from "./components/Logo.tsx";
8
9
  import { RankChip } from "./components/RankChip.tsx";
9
10
  import { SettingsDialog } from "./components/SettingsDialog.tsx";
@@ -553,14 +554,7 @@ export function App() {
553
554
  {view.id === "rank" && <Rank />}
554
555
  </main>
555
556
 
556
- <footer className="credit">
557
- <span>
558
- Made with <Heart size={12} aria-label="love" className="credit-heart" /> by{" "}
559
- <a href="https://github.com/YarooqH" target="_blank" rel="noreferrer">qray</a>
560
- </span>
561
- <span aria-hidden="true">·</span>
562
- <a href="https://github.com/YarooqH/token-larper" target="_blank" rel="noreferrer">Source on GitHub</a>
563
- </footer>
557
+ <AppFooter />
564
558
 
565
559
  {showSettings && (
566
560
  <SettingsDialog
@@ -0,0 +1,47 @@
1
+ import React from "react";
2
+
3
+ const JOKES = [
4
+ "Tokens were harmed in the making.",
5
+ "The context window remembers.",
6
+ "One more prompt. Famous last words.",
7
+ "Your cache misses have been noted.",
8
+ "The bill has entered the chat.",
9
+ "This footer also cost tokens.",
10
+ "The tokens know what they did.",
11
+ ] as const;
12
+
13
+ const LAST_JOKE_KEY = "token-larper-last-footer-joke";
14
+
15
+ function pickJoke(): string {
16
+ let previous = -1;
17
+ try {
18
+ const saved = sessionStorage.getItem(LAST_JOKE_KEY);
19
+ if (saved !== null) previous = Number(saved);
20
+ } catch {
21
+ // The footer still works when storage is unavailable.
22
+ }
23
+
24
+ const choices = JOKES.map((_, index) => index).filter((index) => index !== previous);
25
+ const index = choices[Math.floor(Math.random() * choices.length)]!;
26
+ try { sessionStorage.setItem(LAST_JOKE_KEY, String(index)); } catch {}
27
+ return JOKES[index];
28
+ }
29
+
30
+ const joke = pickJoke();
31
+
32
+ export function AppFooter() {
33
+ return (
34
+ <footer className="app-footer">
35
+ <span>Made by <a href="https://github.com/YarooqH" target="_blank" rel="noopener noreferrer">qray</a></span>
36
+ <span className="footer-separator" aria-hidden="true">·</span>
37
+ <span>{joke}</span>
38
+ <span className="footer-separator" aria-hidden="true">·</span>
39
+ <a className="footer-source" href="https://github.com/YarooqH/token-larper" target="_blank" rel="noopener noreferrer">
40
+ <svg width="13" height="13" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
41
+ <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.23.48-2.69-1.08-2.69-1.08-.36-.92-.89-1.16-.89-1.16-.73-.5.06-.49.06-.49.81.06 1.24.83 1.24.83.72 1.23 1.88.88 2.34.67.07-.52.28-.88.51-1.08-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.22 2.2.82a7.65 7.65 0 0 1 4.01 0c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.28.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.08-.01 1.95-.01 2.21 0 .21.15.46.55.38A8.02 8.02 0 0 0 16 8c0-4.42-3.58-8-8-8Z" />
42
+ </svg>
43
+ <span>Source on GitHub</span>
44
+ </a>
45
+ </footer>
46
+ );
47
+ }
@@ -310,9 +310,32 @@ img { display: block; }
310
310
 
311
311
  .app {
312
312
  max-width: 1240px;
313
+ min-height: 100vh;
314
+ display: flex;
315
+ flex-direction: column;
313
316
  margin: 0 auto;
314
- padding: 0 32px 72px;
317
+ padding: 0 32px 24px;
318
+ }
319
+
320
+ .app-footer {
321
+ display: flex;
322
+ align-items: center;
323
+ justify-content: center;
324
+ flex-wrap: wrap;
325
+ column-gap: 8px;
326
+ row-gap: 4px;
327
+ margin-top: auto;
328
+ padding-top: 64px;
329
+ color: var(--text-3);
330
+ font-size: 11px;
331
+ line-height: 1.5;
332
+ text-align: center;
315
333
  }
334
+ .app-footer a { color: var(--text-2); text-decoration: none; }
335
+ .app-footer a:hover { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
336
+ .app-footer a:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; border-radius: 2px; }
337
+ .footer-source { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
338
+ .footer-separator { color: var(--text-3); }
316
339
 
317
340
  .topbar {
318
341
  display: flex;
@@ -1161,10 +1184,6 @@ html[data-theme="dark"] .toggle.on .toggle-knob { background: var(--accent-ink);
1161
1184
 
1162
1185
  /* ---------- Credit ---------- */
1163
1186
 
1164
- .credit { display: flex; justify-content: center; flex-wrap: wrap; gap: 6px 10px; margin-top: 48px; color: var(--text-3); font-size: 12px; }
1165
- .credit a { color: inherit; text-decoration: underline; text-decoration-color: var(--border-strong); text-underline-offset: 3px; }
1166
- .credit a:hover { color: var(--text); text-decoration-color: currentColor; }
1167
- .credit-heart { vertical-align: -1px; color: var(--accent); fill: currentColor; }
1168
1187
 
1169
1188
  /* ---------- Splash screens ---------- */
1170
1189
 
@@ -1329,7 +1348,8 @@ html[data-theme="dark"] .toggle.on .toggle-knob { background: var(--accent-ink);
1329
1348
  @media (max-width: 700px) {
1330
1349
  .update-banner { flex-wrap: wrap; }
1331
1350
  .update-banner-actions { width: 100%; justify-content: flex-end; }
1332
- .app { padding: 0 16px 48px; }
1351
+ .app { padding: 0 16px 24px; }
1352
+ .app-footer { padding-top: 48px; }
1333
1353
  .topbar { margin: 0 -16px; padding: 12px 16px; }
1334
1354
  .updated { display: none; }
1335
1355
  .filters { margin: 0 -16px 16px; padding: 8px 16px 10px; }