File size: 13,478 Bytes
42ee5bf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44453a0
42ee5bf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Data Experiments</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap">
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.2/marked.min.js" integrity="sha384-/TQbtLCAerC3jgaim+N78RZSDYV7ryeoBCVqTuzRrFec2akfBkHS7ACQ3PQhvMVi" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.1.6/purify.min.js" integrity="sha384-+VfUPEb0PdtChMwmBcBmykRMDd+v6D/oFmB3rZM/puCMDYcIvF968OimRh4KQY9a" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<style>
/* Layout: a status strip, a filter bar, then one section per status with a grid of project cards; access guides open in a side reader. */
:root {
  --bg: #f3f5f8; --panel: #ffffff; --ink: #16202c; --muted: #5d6a7b; --rule: #dde2ea; --accent: #2a5bd7;
  --bld: #8a5a00; --bld-bg: #fff2d1; --plt: #6a3fc4; --plt-bg: #f0e9fd; --run: #1d64d8; --run-bg: #e3edff;
  --don: #18794b; --don-bg: #e2f5ea; --code-bg: #eef1f5; --pau: #8b4a3c; --pau-bg: #fbe9e4;
  --sft: #0b6e74; --sft-bg: #ddf3f2;
  --sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, Menlo, Consolas, monospace;
}
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) {
  --bg: #0f141b; --panel: #161d27; --ink: #e4e9f1; --muted: #98a4b6; --rule: #283241; --accent: #7ea6ff;
  --bld: #f0c35a; --bld-bg: #2d2412; --plt: #b99cf7; --plt-bg: #241b38; --run: #7fb0ff; --run-bg: #14233d;
  --don: #6fd39d; --don-bg: #11281d; --code-bg: #1d2633; --pau: #f0a08c; --pau-bg: #2e1a15;
  --sft: #5fd4d0; --sft-bg: #0f2a2a; color-scheme: dark } }
:root[data-theme="dark"] {
  --bg: #0f141b; --panel: #161d27; --ink: #e4e9f1; --muted: #98a4b6; --rule: #283241; --accent: #7ea6ff;
  --bld: #f0c35a; --bld-bg: #2d2412; --plt: #b99cf7; --plt-bg: #241b38; --run: #7fb0ff; --run-bg: #14233d;
  --don: #6fd39d; --don-bg: #11281d; --code-bg: #1d2633; --pau: #f0a08c; --pau-bg: #2e1a15;
  --sft: #5fd4d0; --sft-bg: #0f2a2a; color-scheme: dark }
body { background: var(--bg); color: var(--ink); font: 15px/1.5 var(--sans);
  padding-left: max(16px, env(safe-area-inset-left, 0px)); padding-right: max(16px, env(safe-area-inset-right, 0px)); padding-block: 26px 56px; }
main { max-width: 1180px; margin: 0 auto; display: flex; flex-direction: column; gap: 26px; }
h1, h2, h3 { margin: 0; text-wrap: balance; font-weight: 600; }
h1 { font-size: 1.85rem; line-height: 1.15; letter-spacing: -0.01em; }
h2 { font-size: 1.05rem; display: flex; align-items: center; gap: 10px; }
h3 { font-size: 1.02rem; line-height: 1.3; }
p { margin: 0; max-width: 72ch; }
.lede { color: var(--muted); }
.strip { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr)); gap: 10px; }
.stat { background: var(--panel); border: 1px solid var(--rule); border-radius: 10px; padding: 12px 14px; display: flex; flex-direction: column; gap: 2px;
  cursor: pointer; text-align: left; font: inherit; color: inherit; }
.stat b { font: 600 1.6rem/1.1 var(--mono); font-variant-numeric: tabular-nums; }
.stat span { font-size: .78rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.stat small { font-size: .78rem; line-height: 1.35; color: var(--muted); margin-top: 4px; }
.stat[aria-pressed="true"] { outline: 2px solid var(--accent); outline-offset: -1px; }
.stat.building b { color: var(--bld); } .stat.pilot_ready b { color: var(--plt); } .stat.prod_running b { color: var(--run); } .stat.prod_done b { color: var(--don); }
.stat.prod_paused b { color: var(--pau); } .stat.sft b { color: var(--sft); }
.bar { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.bar input { font: inherit; color: var(--ink); background: var(--panel); border: 1px solid var(--rule); border-radius: 8px; padding: 7px 10px; min-width: 0; flex: 1 1 220px; max-width: 360px; }
.bar .note { color: var(--muted); font-size: .85rem; }
button:focus-visible, input:focus-visible, a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
section { display: flex; flex-direction: column; gap: 12px; }
.count { font: 500 .8rem var(--mono); color: var(--muted); }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr)); gap: 14px; }
.card { background: var(--panel); border: 1px solid var(--rule); border-radius: 12px; padding: 16px; display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.top { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; }
.pill { flex: none; font: 600 .72rem var(--sans); text-transform: uppercase; letter-spacing: .06em; padding: 3px 9px; border-radius: 999px; white-space: nowrap; display: inline-flex; align-items: center; gap: 6px; }
.pill.building { background: var(--bld-bg); color: var(--bld); } .pill.pilot_ready { background: var(--plt-bg); color: var(--plt); }
.pill.prod_running { background: var(--run-bg); color: var(--run); } .pill.prod_done { background: var(--don-bg); color: var(--don); }
.pill.prod_paused { background: var(--pau-bg); color: var(--pau); }
.sftrow { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: .84rem; }
.sftbadge { font: 600 .74rem var(--sans); text-transform: uppercase; letter-spacing: .06em; padding: 3px 9px; border-radius: 999px; background: var(--sft-bg); color: var(--sft); }
.sftrow .who { color: var(--muted); }
.sftrow .sftnote { flex-basis: 100%; color: var(--ink); overflow-wrap: anywhere; }
.sftrow button { font: 500 .8rem var(--sans); color: var(--sft); background: transparent; border: 1px solid var(--rule); border-radius: 999px; padding: 3px 10px; cursor: pointer; }
.sftrow button:hover { border-color: var(--sft); }
.sftrow input { font: inherit; font-size: .85rem; color: var(--ink); background: var(--bg); border: 1px solid var(--rule); border-radius: 8px; padding: 5px 8px; flex: 1 1 200px; min-width: 0; }
.sftrow .err { flex-basis: 100%; color: var(--pau); }
.dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.pill.prod_running .dot { animation: pulse 1.6s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) { .pill.prod_running .dot { animation: none; } }
.desc { font-size: .95rem; line-height: 1.45; }
.type { color: var(--muted); font-size: .86rem; }
.size { font: 500 .9rem var(--mono); font-variant-numeric: tabular-nums; }
.prog { display: flex; flex-direction: column; gap: 4px; }
.track { height: 8px; background: var(--code-bg); border-radius: 999px; overflow: hidden; }
.fill { height: 100%; background: var(--run); border-radius: 999px; }
.prog .lbl { font: .8rem var(--mono); color: var(--muted); font-variant-numeric: tabular-nums; }
.links { display: flex; flex-wrap: wrap; gap: 8px; }
.links a, .links button { font: 500 .82rem var(--sans); color: var(--accent); background: transparent; border: 1px solid var(--rule); border-radius: 999px; padding: 4px 11px; text-decoration: none; cursor: pointer; }
.links a:hover, .links button:hover { border-color: var(--accent); }
.loc { display: flex; gap: 8px; align-items: center; min-width: 0; }
.loc code { font: .78rem var(--mono); background: var(--code-bg); padding: 3px 7px; border-radius: 6px; overflow-wrap: anywhere; min-width: 0; }
.loc button { flex: none; font: .75rem var(--sans); color: var(--muted); background: transparent; border: 1px solid var(--rule); border-radius: 6px; padding: 2px 8px; cursor: pointer; }
.kv { display: grid; grid-template-columns: auto 1fr; gap: 3px 10px; font-size: .86rem; }
.kv dt { color: var(--muted); } .kv dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.foot { font-size: .78rem; color: var(--muted); border-top: 1px solid var(--rule); padding-top: 8px; }
.empty { background: var(--panel); border: 1px dashed var(--rule); border-radius: 12px; padding: 22px; color: var(--muted); }
.howto { background: var(--panel); border: 1px solid var(--rule); border-radius: 12px; padding: 16px; display: flex; flex-direction: column; gap: 8px; }
.howto code { font: .82rem var(--mono); background: var(--code-bg); padding: 1px 5px; border-radius: 4px; }
.reader { position: fixed; inset: 0; background: color-mix(in srgb, var(--ink) 35%, transparent); display: flex; justify-content: flex-end; z-index: 20; }
.reader[hidden] { display: none !important; }
.sheet { background: var(--panel); width: min(860px, 100%); height: 100%; display: flex; flex-direction: column; border-left: 1px solid var(--rule);
  padding-top: env(safe-area-inset-top, 0px); padding-bottom: env(safe-area-inset-bottom, 0px); padding-right: env(safe-area-inset-right, 0px); }
.sheet header { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 14px 18px; border-bottom: 1px solid var(--rule); }
.sheet header .path { font: .78rem var(--mono); color: var(--muted); overflow-wrap: anywhere; }
.sheet header button { font: 500 .85rem var(--sans); color: var(--ink); background: var(--bg); border: 1px solid var(--rule); border-radius: 8px; padding: 6px 12px; cursor: pointer; flex: none; }
.md { overflow: auto; padding: 18px 22px 40px; line-height: 1.6; }
.md h1 { font-size: 1.4rem; margin: .2em 0 .6em; } .md h2 { font-size: 1.15rem; margin: 1.3em 0 .5em; display: block; } .md h3 { font-size: 1rem; margin: 1.1em 0 .4em; }
.md p, .md ul, .md ol { margin: .5em 0; max-width: 78ch; }
.md table { border-collapse: collapse; font-size: .88rem; display: block; overflow-x: auto; max-width: 100%; margin: .7em 0; }
.md th, .md td { border: 1px solid var(--rule); padding: 5px 9px; text-align: left; vertical-align: top; }
.md th { background: var(--code-bg); font-weight: 600; }
.md code { font: .85em var(--mono); background: var(--code-bg); padding: 1px 5px; border-radius: 4px; }
.md pre { background: var(--code-bg); padding: 12px 14px; border-radius: 8px; overflow-x: auto; }
.md pre code { background: none; padding: 0; }
.md a { color: var(--accent); }
.md blockquote { border-left: 3px solid var(--rule); margin: .6em 0; padding: .1em 0 .1em 12px; color: var(--muted); }

.who-am-i { color: var(--muted); font-size: .82rem; }
.who-am-i a { color: var(--accent); margin-left: 6px; }
.gate { border: 1px solid var(--rule); border-radius: 12px; background: var(--panel); padding: 20px 22px; display: flex; flex-direction: column; gap: 8px; max-width: 640px; }
.gate h2 { margin: 0; font-size: 1.15rem; }
.gate p { margin: 0; }
.gate a.signin { display: inline-block; font-weight: 600; color: var(--panel); background: var(--accent); text-decoration: none; padding: 8px 14px; border-radius: 9px; }
.build { font: .72rem var(--mono); color: var(--muted); }
</style>
</head>
<body>
<main>
  <header style="display:flex;flex-direction:column;gap:8px">
    <h1>Data Experiments</h1>
    <p class="lede">Every data type we are building, piloting or producing: what it is, where it stands, the pilot to listen to, and how to get the production data. Sessions keep their own rows up to date.</p>
    <span class="who-am-i"><span id="me"></span> <a id="signout" href="/logout" hidden>Sign out</a></span>
  </header>

  <div class="gate" id="gate" hidden>
    <h2 id="gtitle">Sign in to see the projects</h2>
    <p id="gtext">This dashboard is for the Extrian team and invited collaborators. Sign in with your Hugging Face account; a free one works.</p>
    <p><a class="signin" id="signin" href="/login">Sign in with Hugging Face</a></p>
    <p class="note" id="gnote">No access after signing in? Ask the dashboard owner to add your email or Hugging Face username.</p>
  </div>

  <div class="strip" id="strip"></div>

  <div class="bar">
    <input id="q" type="search" placeholder="Search titles, data types, locations" aria-label="Search projects">
    <span class="note" id="status">Loading projects…</span>
  </div>

  <div id="sections" style="display:flex;flex-direction:column;gap:26px">
    <div class="empty" id="empty">Projects will appear here as each session adds its row. Nothing has loaded yet.</div>
  </div>

  <div class="howto">
    <h2>Add or update a project</h2>
    <p>Each project is one JSON record under <code>projects/&lt;slug&gt;</code>, with access guides under <code>docs/&lt;id&gt;</code>. A session updates its own record with <code>python dataops/experiments_db.py</code>, and this page picks it up within a minute. Full instructions, fields and examples are in <code>DATA_EXPERIMENTS_DASHBOARD.md</code> at the root of the data-processing-tts repo.</p>
    <p>Trained on a dataset? Press <b>Mark SFT done</b> on its card and add a note (the run name or result). Anyone signed in can mark or undo it; everyone sees who marked it and when.</p>
    <span class="build">build dc86eb14</span>
  </div>
</main>

<div class="reader" id="reader" hidden>
  <div class="sheet" role="dialog" aria-modal="true" aria-labelledby="rtitle">
    <header>
      <div style="display:flex;flex-direction:column;gap:2px;min-width:0"><b id="rtitle"></b><span class="path" id="rpath"></span></div>
      <button type="button" id="rclose">Close</button>
    </header>
    <div class="md" id="rbody"></div>
  </div>
</div>
<script src="/app.js"></script>
</body>
</html>