Spaces:
Running
Running
Commit ·
a3025a6
1
Parent(s): f6b1e29
feat: add in-app help guide with ❓ button in top bar
Browse files- HelpModal component renders condensed annotator guide
- Accessible via ❓ Help button in top bar
- Scrollable modal with styled markdown tables
- Covers navigation, tags, validation, and annotation workflow
- app/components/HelpModal.js +110 -0
- app/globals.css +52 -0
- app/page.js +9 -0
app/components/HelpModal.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use client";
|
| 2 |
+
|
| 3 |
+
import { useState, useEffect } from 'react';
|
| 4 |
+
import ReactMarkdown from 'react-markdown';
|
| 5 |
+
import remarkGfm from 'remark-gfm';
|
| 6 |
+
|
| 7 |
+
const GUIDE_CONTENT = `
|
| 8 |
+
## Getting Started
|
| 9 |
+
|
| 10 |
+
1. **Sign in** with your HuggingFace account
|
| 11 |
+
2. Your assigned documents appear in the dropdown
|
| 12 |
+
3. Only accounts in the annotator config will see documents
|
| 13 |
+
|
| 14 |
+
---
|
| 15 |
+
|
| 16 |
+
## Interface Layout
|
| 17 |
+
|
| 18 |
+
| Panel | Purpose |
|
| 19 |
+
|-------|---------|
|
| 20 |
+
| **Left** | PDF viewer — original document page |
|
| 21 |
+
| **Right** | Markdown text with highlighted data mentions |
|
| 22 |
+
|
| 23 |
+
---
|
| 24 |
+
|
| 25 |
+
## Page Navigation
|
| 26 |
+
|
| 27 |
+
| Button | Action |
|
| 28 |
+
|--------|--------|
|
| 29 |
+
| **← Prev / Next →** | Move one page at a time |
|
| 30 |
+
| **⏮ / ⏭** | Jump to page with data mentions |
|
| 31 |
+
| **● green dot** | Current page has mentions |
|
| 32 |
+
|
| 33 |
+
---
|
| 34 |
+
|
| 35 |
+
## Data Mention Colors
|
| 36 |
+
|
| 37 |
+
| Color | Tag | Meaning |
|
| 38 |
+
|-------|-----|---------|
|
| 39 |
+
| 🟢 Green | **Named** | A specific, named dataset |
|
| 40 |
+
| 🟡 Amber | **Descriptive** | Described but not formally named |
|
| 41 |
+
| 🟣 Purple | **Vague** | Unclear or ambiguous reference |
|
| 42 |
+
| ⚪ Gray | **Non-Dataset** | Not actually a dataset |
|
| 43 |
+
|
| 44 |
+
---
|
| 45 |
+
|
| 46 |
+
## Validating Mentions
|
| 47 |
+
|
| 48 |
+
1. Click the **toggle (‹)** to open the side panel
|
| 49 |
+
2. For each mention:
|
| 50 |
+
- ✅ **Correct** — real dataset mention
|
| 51 |
+
- ❌ **Wrong** — false positive
|
| 52 |
+
- **Edit tag** — click the tag badge to change it
|
| 53 |
+
- **Delete** — remove false mentions (click twice to confirm)
|
| 54 |
+
|
| 55 |
+
---
|
| 56 |
+
|
| 57 |
+
## Adding New Annotations
|
| 58 |
+
|
| 59 |
+
1. **Select text** in the markdown preview (click & drag)
|
| 60 |
+
2. Click **✍️ Annotate Selection**
|
| 61 |
+
3. Choose a tag: Named, Descriptive, or Vague
|
| 62 |
+
4. Click **Save Annotation**
|
| 63 |
+
|
| 64 |
+
---
|
| 65 |
+
|
| 66 |
+
## Recommended Workflow
|
| 67 |
+
|
| 68 |
+
1. **Read** the markdown text, reference the PDF for context
|
| 69 |
+
2. **Review** each highlighted mention in the side panel
|
| 70 |
+
3. **Add** any mentions the AI missed via text selection
|
| 71 |
+
4. **Move** to the next page (warning if unvalidated mentions remain)
|
| 72 |
+
|
| 73 |
+
---
|
| 74 |
+
|
| 75 |
+
## Tips
|
| 76 |
+
|
| 77 |
+
- Use **⏮/⏭ jump buttons** to skip pages without mentions
|
| 78 |
+
- Pages without mentions may still have datasets the AI missed
|
| 79 |
+
- Select just the **dataset name**, not surrounding text
|
| 80 |
+
- The **PDF is the source of truth** — markdown may have formatting issues
|
| 81 |
+
`;
|
| 82 |
+
|
| 83 |
+
export default function HelpModal({ isOpen, onClose }) {
|
| 84 |
+
useEffect(() => {
|
| 85 |
+
const handleEsc = (e) => { if (e.key === 'Escape') onClose(); };
|
| 86 |
+
if (isOpen) window.addEventListener('keydown', handleEsc);
|
| 87 |
+
return () => window.removeEventListener('keydown', handleEsc);
|
| 88 |
+
}, [isOpen, onClose]);
|
| 89 |
+
|
| 90 |
+
if (!isOpen) return null;
|
| 91 |
+
|
| 92 |
+
return (
|
| 93 |
+
<div className="modal-overlay help-modal-overlay" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
|
| 94 |
+
<div className="modal-content help-modal-content">
|
| 95 |
+
<div className="modal-header">
|
| 96 |
+
<h3>📖 Annotator Guide</h3>
|
| 97 |
+
<button className="modal-close" onClick={onClose}>×</button>
|
| 98 |
+
</div>
|
| 99 |
+
<div className="modal-body help-modal-body">
|
| 100 |
+
<ReactMarkdown remarkPlugins={[remarkGfm]}>
|
| 101 |
+
{GUIDE_CONTENT}
|
| 102 |
+
</ReactMarkdown>
|
| 103 |
+
</div>
|
| 104 |
+
<div className="modal-footer">
|
| 105 |
+
<button className="btn btn-primary" onClick={onClose}>Got it!</button>
|
| 106 |
+
</div>
|
| 107 |
+
</div>
|
| 108 |
+
</div>
|
| 109 |
+
);
|
| 110 |
+
}
|
app/globals.css
CHANGED
|
@@ -1228,6 +1228,58 @@ h4 {
|
|
| 1228 |
animation: slideUp 0.2s ease;
|
| 1229 |
}
|
| 1230 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1231 |
.modal-header {
|
| 1232 |
display: flex;
|
| 1233 |
justify-content: space-between;
|
|
|
|
| 1228 |
animation: slideUp 0.2s ease;
|
| 1229 |
}
|
| 1230 |
|
| 1231 |
+
.help-modal-content {
|
| 1232 |
+
max-width: 700px;
|
| 1233 |
+
}
|
| 1234 |
+
|
| 1235 |
+
.help-modal-body {
|
| 1236 |
+
max-height: 65vh;
|
| 1237 |
+
overflow-y: auto;
|
| 1238 |
+
font-size: 0.9rem;
|
| 1239 |
+
line-height: 1.6;
|
| 1240 |
+
}
|
| 1241 |
+
|
| 1242 |
+
.help-modal-body h2 {
|
| 1243 |
+
color: #e2e8f0;
|
| 1244 |
+
font-size: 1.1rem;
|
| 1245 |
+
margin-top: 1.2em;
|
| 1246 |
+
}
|
| 1247 |
+
|
| 1248 |
+
.help-modal-body table {
|
| 1249 |
+
width: 100%;
|
| 1250 |
+
border-collapse: collapse;
|
| 1251 |
+
margin: 0.8em 0;
|
| 1252 |
+
font-size: 0.85rem;
|
| 1253 |
+
}
|
| 1254 |
+
|
| 1255 |
+
.help-modal-body th,
|
| 1256 |
+
.help-modal-body td {
|
| 1257 |
+
border: 1px solid var(--border-color);
|
| 1258 |
+
padding: 6px 10px;
|
| 1259 |
+
text-align: left;
|
| 1260 |
+
}
|
| 1261 |
+
|
| 1262 |
+
.help-modal-body th {
|
| 1263 |
+
background-color: #334155;
|
| 1264 |
+
color: #e2e8f0;
|
| 1265 |
+
}
|
| 1266 |
+
|
| 1267 |
+
.help-modal-body hr {
|
| 1268 |
+
border: 0;
|
| 1269 |
+
height: 1px;
|
| 1270 |
+
background: var(--border-color);
|
| 1271 |
+
margin: 16px 0;
|
| 1272 |
+
}
|
| 1273 |
+
|
| 1274 |
+
.help-modal-body ol,
|
| 1275 |
+
.help-modal-body ul {
|
| 1276 |
+
padding-left: 20px;
|
| 1277 |
+
}
|
| 1278 |
+
|
| 1279 |
+
.help-modal-body strong {
|
| 1280 |
+
color: #e2e8f0;
|
| 1281 |
+
}
|
| 1282 |
+
|
| 1283 |
.modal-header {
|
| 1284 |
display: flex;
|
| 1285 |
justify-content: space-between;
|
app/page.js
CHANGED
|
@@ -9,6 +9,7 @@ import AnnotationModal from './components/AnnotationModal';
|
|
| 9 |
import PageNavigator from './components/PageNavigator';
|
| 10 |
import ProgressBar from './components/ProgressBar';
|
| 11 |
import Leaderboard from './components/Leaderboard';
|
|
|
|
| 12 |
|
| 13 |
export default function Home() {
|
| 14 |
const [documents, setDocuments] = useState([]);
|
|
@@ -39,6 +40,7 @@ export default function Home() {
|
|
| 39 |
|
| 40 |
// Leaderboard state
|
| 41 |
const [leaderboardOpen, setLeaderboardOpen] = useState(false);
|
|
|
|
| 42 |
|
| 43 |
const showToast = useCallback((message, type = 'success') => {
|
| 44 |
setToast({ message, type });
|
|
@@ -486,6 +488,12 @@ export default function Home() {
|
|
| 486 |
>
|
| 487 |
🏆 Leaderboard
|
| 488 |
</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 489 |
{annotatorName ? (
|
| 490 |
<span className="user-badge">👤 {annotatorName}</span>
|
| 491 |
) : (
|
|
@@ -574,6 +582,7 @@ export default function Home() {
|
|
| 574 |
)}
|
| 575 |
</div>
|
| 576 |
<Leaderboard isOpen={leaderboardOpen} onClose={() => setLeaderboardOpen(false)} />
|
|
|
|
| 577 |
</div>
|
| 578 |
);
|
| 579 |
}
|
|
|
|
| 9 |
import PageNavigator from './components/PageNavigator';
|
| 10 |
import ProgressBar from './components/ProgressBar';
|
| 11 |
import Leaderboard from './components/Leaderboard';
|
| 12 |
+
import HelpModal from './components/HelpModal';
|
| 13 |
|
| 14 |
export default function Home() {
|
| 15 |
const [documents, setDocuments] = useState([]);
|
|
|
|
| 40 |
|
| 41 |
// Leaderboard state
|
| 42 |
const [leaderboardOpen, setLeaderboardOpen] = useState(false);
|
| 43 |
+
const [helpOpen, setHelpOpen] = useState(false);
|
| 44 |
|
| 45 |
const showToast = useCallback((message, type = 'success') => {
|
| 46 |
setToast({ message, type });
|
|
|
|
| 488 |
>
|
| 489 |
🏆 Leaderboard
|
| 490 |
</button>
|
| 491 |
+
<button
|
| 492 |
+
className="btn-leaderboard"
|
| 493 |
+
onClick={() => setHelpOpen(true)}
|
| 494 |
+
>
|
| 495 |
+
❓ Help
|
| 496 |
+
</button>
|
| 497 |
{annotatorName ? (
|
| 498 |
<span className="user-badge">👤 {annotatorName}</span>
|
| 499 |
) : (
|
|
|
|
| 582 |
)}
|
| 583 |
</div>
|
| 584 |
<Leaderboard isOpen={leaderboardOpen} onClose={() => setLeaderboardOpen(false)} />
|
| 585 |
+
<HelpModal isOpen={helpOpen} onClose={() => setHelpOpen(false)} />
|
| 586 |
</div>
|
| 587 |
);
|
| 588 |
}
|