system HF Staff commited on
Commit
58fcc33
·
verified ·
1 Parent(s): ee84667

Bootstrap automatic contribution interface

Browse files
Files changed (5) hide show
  1. README.md +8 -3
  2. app.js +87 -0
  3. catalog.json +1 -0
  4. index.html +55 -17
  5. style.css +51 -26
README.md CHANGED
@@ -1,10 +1,15 @@
1
  ---
2
  title: Gene Embeddings Staging
3
- emoji: 🌍
4
  colorFrom: blue
5
- colorTo: gray
6
  sdk: static
 
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
1
  ---
2
  title: Gene Embeddings Staging
3
+ emoji: 🧬
4
  colorFrom: blue
5
+ colorTo: indigo
6
  sdk: static
7
+ app_file: index.html
8
  pinned: false
9
+ datasets:
10
+ - embeddingsSSRF/gene_embeddings_staging
11
  ---
12
 
13
+ # Gene Embeddings Staging Catalog
14
+
15
+ A static catalog of approved gene embeddings. Community additions are automatically validated against the published technical policy before appearing here.
app.js ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (() => {
2
+ "use strict";
3
+ const GITHUB_CONTRIBUTING = "https://github.com/DanielTabaresLopez/Gene-Embeddings-Contributions/blob/main/CONTRIBUTING.md";
4
+ const DATASET_BASE = "https://huggingface.co/datasets/embeddingsSSRF/gene_embeddings_staging/tree/main/";
5
+
6
+ const grid = document.getElementById("grid");
7
+ const search = document.getElementById("search");
8
+ const category = document.getElementById("category");
9
+ const dialog = document.getElementById("detail-dialog");
10
+ const detail = document.getElementById("detail-content");
11
+ let catalog = [];
12
+
13
+ document.getElementById("contribute-link").href = GITHUB_CONTRIBUTING;
14
+ document.getElementById("contribute-link-bottom").href = GITHUB_CONTRIBUTING;
15
+ document.getElementById("close-detail").addEventListener("click", () => dialog.close());
16
+
17
+ const escapeHtml = (value) => {
18
+ const div = document.createElement("div");
19
+ div.textContent = value ?? "";
20
+ return div.innerHTML;
21
+ };
22
+
23
+ function render() {
24
+ const term = search.value.trim().toLowerCase();
25
+ const selected = category.value;
26
+ const items = catalog.filter((item) => {
27
+ if (selected !== "All" && item.category !== selected) return false;
28
+ const haystack = `${item.name} ${item.category} ${item.modality} ${item.algorithm} ${item.description}`.toLowerCase();
29
+ return !term || haystack.includes(term);
30
+ });
31
+ document.getElementById("result-count").textContent = `${items.length} of ${catalog.length} embedding sets`;
32
+ grid.innerHTML = "";
33
+ items.forEach((item) => {
34
+ const card = document.createElement("button");
35
+ card.className = "card";
36
+ card.innerHTML = `
37
+ <span class="badge">${escapeHtml(item.category)}</span>
38
+ <h3>${escapeHtml(item.name)}</h3>
39
+ <p>${escapeHtml(item.description || "No description provided.")}</p>
40
+ <div class="metrics">
41
+ <span><strong>${Number(item.n_genes).toLocaleString()}</strong> genes</span>
42
+ <span><strong>${Number(item.n_dims).toLocaleString()}</strong> dims</span>
43
+ <span><strong>${item.coverage_pct}%</strong> coverage</span>
44
+ </div>`;
45
+ card.addEventListener("click", () => openDetail(item));
46
+ grid.appendChild(card);
47
+ });
48
+ }
49
+
50
+ function openDetail(item) {
51
+ const path = item.dataset_path || `data/embeddings/${item.id}`;
52
+ detail.innerHTML = `
53
+ <p class="badge">${escapeHtml(item.category)}</p>
54
+ <h2>${escapeHtml(item.name)}</h2>
55
+ <p>${escapeHtml(item.description || "")}</p>
56
+ <div class="detail-grid">
57
+ <div><strong>${Number(item.n_genes).toLocaleString()}</strong>genes</div>
58
+ <div><strong>${Number(item.n_dims).toLocaleString()}</strong>dimensions</div>
59
+ <div><strong>${item.coverage_pct}%</strong>coverage</div>
60
+ </div>
61
+ <p><b>Modality:</b> ${escapeHtml(item.modality || "—")}</p>
62
+ <p><b>Method:</b> ${escapeHtml(item.algorithm || "—")}</p>
63
+ <p><b>QC:</b> ${escapeHtml(item.qc_status || "legacy package")}</p>
64
+ <p><b>License:</b> ${escapeHtml(item.license || "see package metadata")}</p>
65
+ <a class="button primary" href="${DATASET_BASE}${encodeURI(path)}" target="_blank" rel="noopener">Open package files</a>`;
66
+ dialog.showModal();
67
+ }
68
+
69
+ async function init() {
70
+ const response = await fetch("catalog.json", { cache: "no-store" });
71
+ if (!response.ok) throw new Error(`Could not load catalog.json (${response.status})`);
72
+ catalog = await response.json();
73
+ const categories = [...new Set(catalog.map((item) => item.category))].sort();
74
+ categories.forEach((value) => category.add(new Option(value, value)));
75
+ document.getElementById("stat-count").textContent = catalog.length.toLocaleString();
76
+ document.getElementById("stat-genes").textContent = Math.max(...catalog.map((item) => Number(item.n_genes) || 0)).toLocaleString();
77
+ const dims = catalog.map((item) => Number(item.n_dims) || 0);
78
+ document.getElementById("stat-dims").textContent = `${Math.min(...dims).toLocaleString()}–${Math.max(...dims).toLocaleString()}`;
79
+ render();
80
+ }
81
+
82
+ search.addEventListener("input", render);
83
+ category.addEventListener("change", render);
84
+ init().catch((error) => {
85
+ grid.innerHTML = `<p>Catalog failed to load: ${escapeHtml(error.message)}</p>`;
86
+ });
87
+ })();
catalog.json ADDED
@@ -0,0 +1 @@
 
 
1
+ []
index.html CHANGED
@@ -1,19 +1,57 @@
1
  <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
  <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Gene Embeddings</title>
7
+ <link rel="stylesheet" href="style.css" />
8
+ </head>
9
+ <body>
10
+ <header class="hero">
11
+ <div class="hero-inner">
12
+ <p class="eyebrow">Unified human gene representations</p>
13
+ <h1>Gene Embeddings</h1>
14
+ <p class="lead">Browse standardized gene-level representations across sequence, expression, literature, pathway, network, regulatory, knowledge-graph, and single-cell modalities.</p>
15
+ <div class="actions">
16
+ <a class="button primary" id="contribute-link" href="#">Contribute an embedding</a>
17
+ <a class="button" href="https://huggingface.co/datasets/embeddingsSSRF/gene_embeddings_staging" target="_blank" rel="noopener">Open Dataset</a>
18
+ </div>
19
+ <p class="notice">Community contributions are automatically checked for compliance with the technical policy. Inclusion is not independent scientific or legal endorsement.</p>
20
+ </div>
21
+ </header>
22
+
23
+ <main>
24
+ <section class="stats" aria-label="Catalog summary">
25
+ <article><strong id="stat-count">—</strong><span>embedding sets</span></article>
26
+ <article><strong id="stat-genes">—</strong><span>maximum genes</span></article>
27
+ <article><strong id="stat-dims">—</strong><span>dimension range</span></article>
28
+ </section>
29
+
30
+ <section class="controls">
31
+ <input id="search" type="search" placeholder="Search names, modalities, or methods" aria-label="Search catalog" />
32
+ <select id="category" aria-label="Filter by category"><option value="All">All categories</option></select>
33
+ </section>
34
+
35
+ <p id="result-count" class="result-count"></p>
36
+ <section id="grid" class="grid" aria-live="polite"></section>
37
+
38
+ <section class="contribute" id="contribute">
39
+ <h2>Automatic contribution workflow</h2>
40
+ <ol>
41
+ <li>Put <code>embeddings.npz</code>, <code>genes.tsv</code>, <code>metadata.json</code>, and <code>README.md</code> in a public Hugging Face Dataset.</li>
42
+ <li>Freeze the candidate at a full commit SHA.</li>
43
+ <li>Add one submission YAML through a GitHub Pull Request.</li>
44
+ <li>GitHub validates the frozen package. A strict PASS is merged and published automatically.</li>
45
+ </ol>
46
+ <a class="button primary" id="contribute-link-bottom" href="#">Open contribution instructions</a>
47
+ </section>
48
+ </main>
49
+
50
+ <dialog id="detail-dialog">
51
+ <button id="close-detail" class="close" aria-label="Close">×</button>
52
+ <div id="detail-content"></div>
53
+ </dialog>
54
+
55
+ <script src="app.js"></script>
56
+ </body>
57
  </html>
style.css CHANGED
@@ -1,28 +1,53 @@
1
- body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
 
 
 
 
 
 
 
4
  }
5
-
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
9
- }
10
-
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
- }
17
-
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
- }
25
-
26
- .card p:last-child {
27
- margin-bottom: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  }
 
1
+ :root {
2
+ --ink: #172033;
3
+ --muted: #647089;
4
+ --line: #dbe2ee;
5
+ --paper: #ffffff;
6
+ --wash: #f4f7fb;
7
+ --brand: #3157d5;
8
+ --brand-dark: #213c9d;
9
+ --success: #167c5a;
10
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
11
  }
12
+ * { box-sizing: border-box; }
13
+ body { margin: 0; color: var(--ink); background: var(--wash); }
14
+ a { color: inherit; }
15
+ .hero { background: linear-gradient(135deg, #182858, #3157d5 62%, #5a80ef); color: white; }
16
+ .hero-inner { max-width: 1160px; margin: auto; padding: 72px 24px 58px; }
17
+ .eyebrow { text-transform: uppercase; letter-spacing: .14em; font-weight: 700; font-size: .78rem; opacity: .8; }
18
+ h1 { font-size: clamp(2.5rem, 7vw, 5.2rem); line-height: .98; margin: 12px 0 20px; }
19
+ .lead { max-width: 800px; font-size: 1.15rem; line-height: 1.65; color: #e9efff; }
20
+ .actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }
21
+ .button { display: inline-flex; align-items: center; justify-content: center; padding: 12px 17px; border-radius: 10px; border: 1px solid currentColor; text-decoration: none; font-weight: 700; }
22
+ .hero .button { color: white; }
23
+ .hero .button.primary { background: white; color: var(--brand-dark); border-color: white; }
24
+ .notice { max-width: 850px; font-size: .88rem; color: #d6e0ff; margin-top: 20px; }
25
+ main { max-width: 1160px; margin: auto; padding: 0 24px 70px; }
26
+ .stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-top: -28px; }
27
+ .stats article { background: var(--paper); border: 1px solid var(--line); border-radius: 15px; padding: 22px; box-shadow: 0 8px 28px rgba(31, 47, 88, .08); }
28
+ .stats strong { display: block; font-size: 2rem; }
29
+ .stats span { color: var(--muted); }
30
+ .controls { display: grid; grid-template-columns: 1fr 260px; gap: 12px; margin: 38px 0 12px; }
31
+ input, select { width: 100%; padding: 13px 14px; border: 1px solid var(--line); border-radius: 10px; background: var(--paper); font: inherit; }
32
+ .result-count { color: var(--muted); }
33
+ .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; }
34
+ .card { text-align: left; border: 1px solid var(--line); background: var(--paper); border-radius: 15px; padding: 19px; cursor: pointer; transition: transform .15s ease, box-shadow .15s ease; }
35
+ .card:hover { transform: translateY(-2px); box-shadow: 0 10px 30px rgba(31,47,88,.10); }
36
+ .card h3 { margin: 0 0 9px; font-size: 1.05rem; }
37
+ .card p { color: var(--muted); line-height: 1.5; min-height: 4.5em; }
38
+ .badge { display: inline-block; border-radius: 999px; background: #e8edff; color: var(--brand-dark); padding: 5px 9px; font-size: .75rem; font-weight: 700; }
39
+ .metrics { display: flex; gap: 12px; flex-wrap: wrap; border-top: 1px solid var(--line); padding-top: 13px; font-size: .83rem; color: var(--muted); }
40
+ .metrics strong { color: var(--ink); }
41
+ .contribute { margin-top: 54px; padding: 30px; background: var(--paper); border: 1px solid var(--line); border-radius: 16px; }
42
+ .contribute li { margin: 10px 0; line-height: 1.55; }
43
+ .contribute .button.primary { background: var(--brand); color: white; border-color: var(--brand); }
44
+ dialog { width: min(720px, calc(100vw - 32px)); border: 0; border-radius: 16px; padding: 28px; box-shadow: 0 30px 100px rgba(0,0,0,.3); }
45
+ dialog::backdrop { background: rgba(12,20,40,.55); }
46
+ .close { float: right; border: 0; background: none; font-size: 2rem; cursor: pointer; }
47
+ .detail-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin: 18px 0; }
48
+ .detail-grid div { background: var(--wash); border-radius: 10px; padding: 13px; }
49
+ .detail-grid strong { display: block; font-size: 1.2rem; }
50
+ @media (max-width: 720px) {
51
+ .stats, .controls { grid-template-columns: 1fr; }
52
+ .hero-inner { padding-top: 48px; }
53
  }