Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions field-logic/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions field-logic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"astro": "^5.16.16",
"dexie": "^4.3.0",
"idb": "^8.0.3",
"nanostores": "^1.1.0",
"react": "^19.2.4",
Expand Down
6 changes: 3 additions & 3 deletions field-logic/src/components/SurveyWizard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import { SurveyEngine } from '../lib/engine';
import type { SurveyDefinition, SurveyNode } from '../lib/types';
import { SurveyEngine } from '../lib/SurveyEngine';
import type { SurveyDefinition, SurveyNode } from '../types/schema';
import '../styles/main.css';

interface Props {
Expand Down Expand Up @@ -30,7 +30,7 @@ export const SurveyWizard: React.FC<Props> = ({ definition }) => {
return;
}

const nextNode = engine.next(inputValue);
const nextNode = engine.submitAnswer(inputValue);
setCurrentNode(nextNode);
setInputValue(null); // Reset input for next question
};
Expand Down
111 changes: 55 additions & 56 deletions field-logic/src/components/TranscriptViewer.tsx
Original file line number Diff line number Diff line change
@@ -1,74 +1,73 @@
import React from 'react';
import React from "react";

interface TranscriptSegment {
start: number;
end: number;
text: string;
confidence: number;
flagged?: boolean;
start: number;
end: number;
text: string;
confidence: number;
flagged?: boolean;
}

interface TranscriptData {
meta: {
file: string;
duration: number;
engine: string;
};
segments: TranscriptSegment[];
meta: {
file: string;
duration: number;
engine: string;
};
segments: TranscriptSegment[];
}

interface Props {
data: TranscriptData;
data: TranscriptData;
}

export const TranscriptViewer: React.FC<Props> = ({ data }) => {
const handleDeepLink = (e: React.MouseEvent, start: number) => {
e.preventDefault();
const file = data.meta.file;
// Construct custom protocol link
const url = `fieldlogic://open?file=${file}&t=${start}`;
window.location.href = url;
};
const handleDeepLink = (e: React.MouseEvent, start: number) => {
e.preventDefault();
const file = data.meta.file;
// Construct custom protocol link
const url = `fieldlogic://open?file=${file}&t=${start}`;
window.location.href = url;
};

return (
<div className="transcript-viewer" style={{ maxWidth: '800px', margin: '0 auto', fontFamily: 'monospace' }}>
<h2>Transcription Review: {data.meta.file}</h2>
return (
<div className="transcript-viewer">
<h2>Transcription Review: {data.meta.file}</h2>

<div className="segments">
{data.segments.map((seg, idx) => (
<div
key={idx}
style={{
padding: '8px',
borderBottom: '1px solid #eee',
backgroundColor: seg.confidence < 0.6 ? '#fef3c7' : 'transparent'
}}
>
<span style={{ color: '#64748b', marginRight: '10px', userSelect: 'none' }}>
[{new Date(seg.start * 1000).toISOString().substr(14, 5)}]
</span>
<div className="segments">
{data.segments.map((seg, idx) => (
<div
key={idx}
className={`segment-item ${seg.confidence < 0.6 ? "low-confidence" : ""}`}
>
<span className="segment-timestamp">
[{new Date(seg.start * 1000).toISOString().substr(14, 5)}]
</span>

<span style={{ marginRight: '10px' }}>{seg.text}</span>
<span className="segment-text">{seg.text}</span>

<div style={{ float: 'right' }}>
{/* Primary: In-browser audio (mock) */}
<button onClick={() => console.log('Seek audio to', seg.start)} style={{ marginRight: '5px' }}>
â–¶
</button>
<div className="segment-actions">
{/* Primary: In-browser audio (mock) */}
<button
onClick={() => console.log("Seek audio to", seg.start)}
className="action-btn"
>
â–¶
</button>

{/* Secondary: VLC Deep Link */}
<a
href="#"
onClick={(e) => handleDeepLink(e, seg.start)}
title="Open in VLC"
style={{ textDecoration: 'none' }}
>
🚀
</a>
</div>
</div>
))}
{/* Secondary: VLC Deep Link */}
<a
href="#"
onClick={(e) => handleDeepLink(e, seg.start)}
title="Open in VLC"
className="deep-link"
>
🚀
</a>
</div>
</div>
);
</div>
))}
</div>
</div>
);
};
58 changes: 54 additions & 4 deletions field-logic/src/styles/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@
--radius-lg: 1rem;
--radius-md: 0.5rem;
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--shadow-lg:
0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
}

body {
font-family: 'Inter', system-ui, -apple-system, sans-serif;
font-family:
"Inter",
system-ui,
-apple-system,
sans-serif;
background-color: var(--color-bg);
color: var(--color-text);
margin: 0;
Expand Down Expand Up @@ -120,6 +125,51 @@ button:disabled {
}

@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

/* TranscriptViewer Styles */
.transcript-viewer {
max-width: 800px;
margin: 0 auto;
font-family: monospace;
}

.transcript-viewer .segment-item {
padding: 8px;
border-bottom: 1px solid #eee;
background-color: transparent;
}

.transcript-viewer .segment-item.low-confidence {
background-color: #fef3c7;
}

.transcript-viewer .segment-timestamp {
color: var(--color-text-muted);
margin-right: 10px;
user-select: none;
}

.transcript-viewer .segment-text {
margin-right: 10px;
}

.transcript-viewer .segment-actions {
float: right;
}

.transcript-viewer .action-btn {
margin-right: 5px;
}

.transcript-viewer .deep-link {
text-decoration: none;
}