style: convert UI palette to clean clinical hospital theme

This commit is contained in:
2026-09-05 14:17:24 -07:00
parent 39829b79d3
commit e681f066bb
13 changed files with 785 additions and 824 deletions
+56 -57
View File
@@ -1,7 +1,7 @@
'use client';
import React, { useState, useEffect } from 'react';
import { Mic, MicOff, Sparkles, Volume2, Play, Pause, RotateCcw, CheckCircle2, AlertCircle } from 'lucide-react';
import { Mic, MicOff, Sparkles, Volume2, CheckCircle2, ShieldCheck } from 'lucide-react';
import { SAMPLE_AUDIO_PRESETS } from '@/lib/mock-data';
interface AmbientAudioRecorderProps {
@@ -27,7 +27,6 @@ export const AmbientAudioRecorder: React.FC<AmbientAudioRecorderProps> = ({
const [liveTranscript, setLiveTranscript] = useState('');
const [showAppliedToast, setShowAppliedToast] = useState(false);
// Timer simulation
useEffect(() => {
let interval: any = null;
if (isRecording) {
@@ -44,8 +43,7 @@ export const AmbientAudioRecorder: React.FC<AmbientAudioRecorderProps> = ({
if (!isRecording) {
setIsRecording(true);
setRecordingSeconds(0);
setLiveTranscript('Listening to ambient doctor-patient dialogue in operatory...');
// Simulate live ambient audio transcription
setLiveTranscript('Hospital ambient listener active. Recording operatory encounter...');
setTimeout(() => {
setLiveTranscript(selectedPreset.audioTranscript);
}, 2500);
@@ -87,48 +85,48 @@ export const AmbientAudioRecorder: React.FC<AmbientAudioRecorderProps> = ({
};
return (
<div className="bg-gradient-to-br from-slate-900 via-slate-900 to-teal-950/40 border border-teal-500/30 rounded-2xl p-5 shadow-2xl text-slate-100">
<div className="bg-white border border-slate-200 rounded-xl p-5 shadow-xs text-slate-800">
{/* Top Banner */}
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 pb-4 border-b border-slate-800">
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 pb-4 border-b border-slate-100">
<div>
<div className="flex items-center gap-2">
<span className="p-1.5 rounded-lg bg-teal-500/20 text-teal-400 border border-teal-500/30">
<span className="p-1.5 rounded-lg bg-sky-50 text-sky-700 border border-sky-100">
<Sparkles className="w-4 h-4" />
</span>
<h3 className="font-semibold text-white text-base tracking-tight">
Mediusa Ambient Clinical AI Scribe
<h3 className="font-bold text-slate-900 text-base tracking-tight">
Ambient Clinical Medical Scribe
</h3>
<span className="text-[11px] font-semibold px-2 py-0.5 rounded-full bg-indigo-500/20 text-indigo-300 border border-indigo-500/30">
Powered by gpt-5.4-mini Clinical Engine
<span className="text-[11px] font-bold px-2.5 py-0.5 rounded-full bg-sky-100 text-sky-800 border border-sky-200">
Clinical Intelligence Engine (gpt-5.4-mini)
</span>
</div>
<p className="text-xs text-slate-400 mt-1">
Zero typing required. Scribe listens to ambient doctor-patient encounter and converts conversational dialogue into compliant SOAP + CPT/ICD-10 codes.
<p className="text-xs text-slate-500 mt-1">
Hands-free documentation. Operatory audio automatically translates into compliant SOAP format and procedure codes.
</p>
</div>
{/* Recording Status / Mic Button */}
<div className="flex items-center gap-3">
{isRecording && (
<div className="flex items-center gap-2 text-xs font-mono font-semibold text-red-400 animate-pulse">
<span className="w-2.5 h-2.5 rounded-full bg-red-500" />
LIVE {formatTime(recordingSeconds)}
<div className="flex items-center gap-2 text-xs font-mono font-bold text-red-600 animate-pulse">
<span className="w-2.5 h-2.5 rounded-full bg-red-600" />
RECORDING {formatTime(recordingSeconds)}
</div>
)}
<button
type="button"
onClick={toggleRecording}
className={`px-4 py-2 rounded-xl text-xs font-bold flex items-center gap-2 transition-all shadow-lg ${
className={`px-4 py-2 rounded-lg text-xs font-bold flex items-center gap-2 transition shadow-xs ${
isRecording
? 'bg-red-500/20 text-red-400 border border-red-500/50 hover:bg-red-500/30'
: 'bg-teal-500 hover:bg-teal-400 text-slate-950 shadow-teal-500/20'
? 'bg-red-50 text-red-700 border border-red-200 hover:bg-red-100'
: 'bg-sky-700 hover:bg-sky-800 text-white'
}`}
>
{isRecording ? (
<>
<MicOff className="w-4 h-4" />
Stop Listening
Stop Recording
</>
) : (
<>
@@ -140,20 +138,21 @@ export const AmbientAudioRecorder: React.FC<AmbientAudioRecorderProps> = ({
</div>
</div>
{/* Waveform Graphic Animation */}
<div className="mt-4 p-4 bg-slate-950/60 rounded-xl border border-slate-800/80">
{/* Hospital Audio Monitor Waveform */}
<div className="mt-4 p-4 bg-slate-900 rounded-lg border border-slate-800 text-slate-100">
<div className="flex items-center justify-between mb-2">
<span className="text-[11px] font-semibold text-slate-400 uppercase tracking-wider flex items-center gap-1.5">
<Volume2 className="w-3.5 h-3.5 text-teal-400" />
Operatory Ambient Stream
<span className="text-xs font-bold text-slate-300 uppercase tracking-wider flex items-center gap-1.5">
<Volume2 className="w-3.5 h-3.5 text-sky-400" />
Medical Audio Feed
</span>
<span className="text-[10px] text-slate-500 font-mono">
44.1kHz 24-bit HIPAA Speech Encryption
<span className="text-[10px] text-slate-400 font-mono flex items-center gap-1">
<ShieldCheck className="w-3 h-3 text-emerald-400" />
HIPAA BAA End-to-End Encryption
</span>
</div>
{/* Dynamic Animated Bars */}
<div className="h-10 flex items-center justify-center gap-1">
<div className="h-9 flex items-center justify-center gap-1">
{[
12, 28, 45, 18, 62, 85, 40, 92, 70, 30, 80, 65, 45, 90, 35, 75, 55, 20, 68, 88,
42, 78, 52, 22, 60, 95, 38, 72, 58, 25, 48, 82, 32, 64, 44, 15,
@@ -162,11 +161,11 @@ export const AmbientAudioRecorder: React.FC<AmbientAudioRecorderProps> = ({
key={i}
className={`w-1 rounded-full transition-all duration-150 ${
isRecording
? 'bg-gradient-to-t from-teal-500 to-emerald-300 animate-pulse'
: 'bg-slate-800'
? 'bg-sky-400 animate-pulse'
: 'bg-slate-700'
}`}
style={{
height: isRecording ? `${Math.max(10, (height * (1 + (i % 3) * 0.2)) % 40)}px` : '6px',
height: isRecording ? `${Math.max(8, (height * (1 + (i % 3) * 0.2)) % 36)}px` : '4px',
animationDelay: `${(i * 40) % 600}ms`,
}}
/>
@@ -178,8 +177,8 @@ export const AmbientAudioRecorder: React.FC<AmbientAudioRecorderProps> = ({
<div className="grid grid-cols-1 md:grid-cols-12 gap-4 mt-4">
{/* Left 4 Cols: Presets */}
<div className="md:col-span-4 flex flex-col gap-2">
<label className="text-[11px] font-semibold text-slate-400 uppercase tracking-wider">
Clinical Encounter Presets (1-Click Demo)
<label className="text-xs font-bold text-slate-700 uppercase tracking-wider">
Clinical Encounter Presets
</label>
<div className="space-y-2">
{SAMPLE_AUDIO_PRESETS.map((preset) => (
@@ -187,14 +186,14 @@ export const AmbientAudioRecorder: React.FC<AmbientAudioRecorderProps> = ({
key={preset.id}
type="button"
onClick={() => handleSelectPreset(preset)}
className={`w-full text-left p-2.5 rounded-xl border transition text-xs ${
className={`w-full text-left p-3 rounded-lg border transition text-xs ${
selectedPreset.id === preset.id
? 'bg-slate-800 border-teal-500/60 text-white shadow-sm'
: 'bg-slate-900/60 border-slate-800 text-slate-400 hover:bg-slate-800/40 hover:text-slate-200'
? 'bg-sky-50/80 border-sky-300 text-sky-950 font-medium shadow-2xs'
: 'bg-slate-50 border-slate-200 text-slate-600 hover:bg-slate-100 hover:text-slate-900'
}`}
>
<div className="font-semibold text-slate-200 truncate">{preset.title}</div>
<div className="text-[10px] text-teal-400 mt-0.5">Encounter Duration: {preset.duration}</div>
<div className="font-bold text-slate-900 truncate">{preset.title}</div>
<div className="text-[11px] text-sky-700 mt-0.5">Length: {preset.duration}</div>
</button>
))}
</div>
@@ -203,50 +202,50 @@ export const AmbientAudioRecorder: React.FC<AmbientAudioRecorderProps> = ({
type="button"
onClick={handleSynthesizeSoap}
disabled={isProcessingAI}
className="mt-3 w-full py-2.5 px-4 rounded-xl text-xs font-bold bg-gradient-to-r from-teal-500 to-emerald-500 hover:from-teal-400 hover:to-emerald-400 text-slate-950 shadow-lg shadow-teal-500/20 transition flex items-center justify-center gap-2 disabled:opacity-50"
className="mt-2 w-full py-2.5 px-4 rounded-lg text-xs font-bold bg-sky-700 hover:bg-sky-800 text-white shadow-xs transition flex items-center justify-center gap-2 disabled:opacity-50"
>
{isProcessingAI ? (
<>
<span className="w-3.5 h-3.5 border-2 border-slate-950 border-t-transparent rounded-full animate-spin" />
AI Extracting SOAP...
<span className="w-3.5 h-3.5 border-2 border-white border-t-transparent rounded-full animate-spin" />
Structuring Medical Note...
</>
) : (
<>
<Sparkles className="w-4 h-4 text-slate-950" />
Extract SOAP &amp; Auto-Codes
<Sparkles className="w-4 h-4 text-white" />
Synthesize Note &amp; Auto-Codes
</>
)}
</button>
</div>
{/* Right 8 Cols: Dialogue Transcript */}
<div className="md:col-span-8 bg-slate-950/70 border border-slate-800 rounded-xl p-3.5 flex flex-col justify-between">
<div className="md:col-span-8 bg-slate-50 border border-slate-200 rounded-lg p-3.5 flex flex-col justify-between">
<div>
<div className="flex items-center justify-between pb-2 border-b border-slate-800 text-xs">
<span className="font-semibold text-slate-300">Encounter Dialogue Feed</span>
<span className="text-[10px] text-teal-400/90 font-mono">Live Whisper Stream</span>
<div className="flex items-center justify-between pb-2 border-b border-slate-200 text-xs">
<span className="font-bold text-slate-800">Transcript Log</span>
<span className="text-[11px] text-slate-500 font-mono">Live Operatory Mic</span>
</div>
<p className="text-xs text-slate-300 whitespace-pre-line mt-2 font-mono leading-relaxed max-h-[160px] overflow-y-auto pr-1">
<p className="text-xs text-slate-700 whitespace-pre-line mt-2 font-mono leading-relaxed max-h-[160px] overflow-y-auto pr-1">
{liveTranscript || selectedPreset.audioTranscript}
</p>
</div>
<div className="mt-3 pt-2 border-t border-slate-800/80 flex items-center justify-between text-[11px] text-slate-400">
<span className="flex items-center gap-1 text-teal-400">
<CheckCircle2 className="w-3.5 h-3.5" />
Auto-detects Subluxations, VAS score, CPT 98940, ICD-10 M99.0x
<div className="mt-3 pt-2 border-t border-slate-200 flex items-center justify-between text-xs text-slate-500">
<span className="flex items-center gap-1 text-sky-800 font-medium">
<CheckCircle2 className="w-3.5 h-3.5 text-sky-700" />
Auto-extracts SOAP, CPT 98940, ICD-10 M99.0x
</span>
<span className="text-slate-500">HIPAA BAA Compliant</span>
<span className="text-slate-400">Speech-to-Text v2.4</span>
</div>
</div>
</div>
{showAppliedToast && (
<div className="mt-3 p-3 bg-emerald-500/20 border border-emerald-500/40 rounded-xl text-xs text-emerald-300 flex items-center justify-between animate-in fade-in slide-in-from-top-2 duration-200">
<div className="flex items-center gap-2">
<CheckCircle2 className="w-4 h-4 text-emerald-400" />
<div className="mt-3 p-3 bg-emerald-50 border border-emerald-200 rounded-lg text-xs text-emerald-800 flex items-center justify-between animate-in fade-in duration-200">
<div className="flex items-center gap-2 font-medium">
<CheckCircle2 className="w-4 h-4 text-emerald-600" />
<span>
<strong>Success!</strong> Encounter conversation extracted into Subjective, Objective, Assessment, Plan, Spine segments, and Billing codes.
<strong>Note Populated:</strong> Subjective, Objective, Assessment, Plan, Vertebrae listings, and Billing codes auto-synced.
</span>
</div>
</div>