Skip to main content
Glama
northernvariables

FedMCP - Federal Parliamentary Information

TranscriptPanel.tsx5.83 kB
/** * Live transcript/captions panel * Shows real-time text of chamber proceedings */ 'use client'; import { useState, useRef, useEffect } from 'react'; import { Pause, Play, Search } from 'lucide-react'; import { Card } from '@canadagpt/design-system'; // Mock transcript data - will be replaced with real-time API data const MOCK_TRANSCRIPT = [ { id: 1, speaker: 'Hon. Chrystia Freeland', party: 'Liberal', time: '14:32:15', text: 'Mr. Speaker, I rise today to address the critical importance of Bill C-69, the Impact Assessment Act. This legislation represents a significant step forward in our commitment to environmental protection while fostering economic growth.', }, { id: 2, speaker: 'Hon. Pierre Poilievre', party: 'Conservative', time: '14:33:42', text: 'Mr. Speaker, I must respectfully disagree with the Deputy Prime Minister. This bill will impose unnecessary regulatory burdens on Canadian businesses and stifle innovation in our resource sector.', }, { id: 3, speaker: 'Jagmeet Singh', party: 'NDP', time: '14:35:18', text: 'Mr. Speaker, while I appreciate the concerns raised by my colleagues, I believe we must find a balance between environmental stewardship and economic prosperity. The people of Canada deserve nothing less.', }, { id: 4, speaker: 'Yves-François Blanchet', party: 'Bloc Québécois', time: '14:36:55', text: "Monsieur le Président, le Québec a démontré qu'il est possible de protéger l'environnement tout en maintenant une économie forte. Ce projet de loi doit reconnaître les compétences provinciales.", }, ]; export function TranscriptPanel() { const [isAutoScroll, setIsAutoScroll] = useState(true); const [searchQuery, setSearchQuery] = useState(''); const [isSearchExpanded, setIsSearchExpanded] = useState(false); const scrollRef = useRef<HTMLDivElement>(null); // Auto-scroll to bottom when new content arrives useEffect(() => { if (isAutoScroll && scrollRef.current) { scrollRef.current.scrollTop = scrollRef.current.scrollHeight; } }, [isAutoScroll]); const filteredTranscript = MOCK_TRANSCRIPT.filter((item) => searchQuery ? item.text.toLowerCase().includes(searchQuery.toLowerCase()) || item.speaker.toLowerCase().includes(searchQuery.toLowerCase()) : true ); const highlightText = (text: string, query: string) => { if (!query) return text; const regex = new RegExp(`(${query})`, 'gi'); const parts = text.split(regex); return parts.map((part, index) => regex.test(part) ? ( <mark key={index} className="bg-yellow-500/30 text-text-primary"> {part} </mark> ) : ( part ) ); }; return ( <Card className="h-full flex flex-col"> {/* Header */} <div className="flex items-center justify-between mb-3 pb-3 border-b border-border"> <h3 className="text-lg font-semibold text-text-primary"> Live Transcript </h3> <div className="flex items-center gap-2"> {/* Search Toggle Button */} <button onClick={() => setIsSearchExpanded(!isSearchExpanded)} className={`p-2 rounded-lg hover:bg-bg-elevated transition-colors ${ isSearchExpanded ? 'bg-bg-elevated' : '' }`} title="Search transcript" > <Search className={`h-4 w-4 ${searchQuery ? 'text-accent-red' : 'text-text-secondary'}`} /> </button> {/* Auto-scroll Toggle */} <button onClick={() => setIsAutoScroll(!isAutoScroll)} className="p-2 rounded-lg hover:bg-bg-elevated transition-colors" title={isAutoScroll ? 'Pause auto-scroll' : 'Resume auto-scroll'} > {isAutoScroll ? ( <Pause className="h-4 w-4 text-accent-red" /> ) : ( <Play className="h-4 w-4 text-text-secondary" /> )} </button> </div> </div> {/* Collapsible Search */} {isSearchExpanded && ( <div className="relative mb-3"> <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary" /> <input type="text" placeholder="Search transcript..." value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} className="w-full pl-10 pr-4 py-2 bg-bg-elevated border border-border rounded-lg text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-accent-red focus:border-transparent" autoFocus /> </div> )} {/* Transcript Content */} <div ref={scrollRef} className="flex-1 overflow-y-auto space-y-4 pr-2 scrollbar-thin scrollbar-thumb-border scrollbar-track-transparent" > {filteredTranscript.map((item) => ( <div key={item.id} className="p-3 bg-bg-elevated rounded-lg space-y-1" > <div className="flex items-center justify-between"> <div className="flex items-center gap-2"> <span className="text-sm font-medium text-text-primary"> {item.speaker} </span> <span className="text-xs text-text-secondary"> {item.party} </span> </div> <span className="text-xs text-text-secondary font-mono"> {item.time} </span> </div> <p className="text-sm text-text-secondary leading-relaxed"> {highlightText(item.text, searchQuery)} </p> </div> ))} </div> </Card> ); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/northernvariables/FedMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server