feat(companion): Migrate Companion from admin-v2 to studio-v2 as pure lesson tool
Remove Companion module entirely from admin-v2. Rebuild in studio-v2 as a focused lesson timer (no dashboard mode). Direct flow: start → active → ended. Fix timer bug where lastTickRef reset prevented countdown. Add companion link to Sidebar and i18n translations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,364 +0,0 @@
|
||||
/**
|
||||
* Constants for Companion Module
|
||||
* Phase colors, defaults, and configuration
|
||||
*/
|
||||
|
||||
import { PhaseId, PhaseDurations, Phase, TeacherSettings } from './types'
|
||||
|
||||
// ============================================================================
|
||||
// Phase Colors (Didactic Color Psychology)
|
||||
// ============================================================================
|
||||
|
||||
export const PHASE_COLORS: Record<PhaseId, { hex: string; tailwind: string; gradient: string }> = {
|
||||
einstieg: {
|
||||
hex: '#4A90E2',
|
||||
tailwind: 'bg-blue-500',
|
||||
gradient: 'from-blue-500 to-blue-600',
|
||||
},
|
||||
erarbeitung: {
|
||||
hex: '#F5A623',
|
||||
tailwind: 'bg-orange-500',
|
||||
gradient: 'from-orange-500 to-orange-600',
|
||||
},
|
||||
sicherung: {
|
||||
hex: '#7ED321',
|
||||
tailwind: 'bg-green-500',
|
||||
gradient: 'from-green-500 to-green-600',
|
||||
},
|
||||
transfer: {
|
||||
hex: '#9013FE',
|
||||
tailwind: 'bg-purple-600',
|
||||
gradient: 'from-purple-600 to-purple-700',
|
||||
},
|
||||
reflexion: {
|
||||
hex: '#6B7280',
|
||||
tailwind: 'bg-gray-500',
|
||||
gradient: 'from-gray-500 to-gray-600',
|
||||
},
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Phase Definitions
|
||||
// ============================================================================
|
||||
|
||||
export const PHASE_SHORT_NAMES: Record<PhaseId, string> = {
|
||||
einstieg: 'E',
|
||||
erarbeitung: 'A',
|
||||
sicherung: 'S',
|
||||
transfer: 'T',
|
||||
reflexion: 'R',
|
||||
}
|
||||
|
||||
export const PHASE_DISPLAY_NAMES: Record<PhaseId, string> = {
|
||||
einstieg: 'Einstieg',
|
||||
erarbeitung: 'Erarbeitung',
|
||||
sicherung: 'Sicherung',
|
||||
transfer: 'Transfer',
|
||||
reflexion: 'Reflexion',
|
||||
}
|
||||
|
||||
export const PHASE_DESCRIPTIONS: Record<PhaseId, string> = {
|
||||
einstieg: 'Motivation, Kontext setzen, Vorwissen aktivieren',
|
||||
erarbeitung: 'Hauptinhalt, aktives Lernen, neue Konzepte',
|
||||
sicherung: 'Konsolidierung, Zusammenfassung, Uebungen',
|
||||
transfer: 'Anwendung, neue Kontexte, kreative Aufgaben',
|
||||
reflexion: 'Rueckblick, Selbsteinschaetzung, Ausblick',
|
||||
}
|
||||
|
||||
export const PHASE_ORDER: PhaseId[] = [
|
||||
'einstieg',
|
||||
'erarbeitung',
|
||||
'sicherung',
|
||||
'transfer',
|
||||
'reflexion',
|
||||
]
|
||||
|
||||
// ============================================================================
|
||||
// Default Durations (in minutes)
|
||||
// ============================================================================
|
||||
|
||||
export const DEFAULT_PHASE_DURATIONS: PhaseDurations = {
|
||||
einstieg: 8,
|
||||
erarbeitung: 20,
|
||||
sicherung: 10,
|
||||
transfer: 7,
|
||||
reflexion: 5,
|
||||
}
|
||||
|
||||
export const DEFAULT_LESSON_LENGTH = 45 // minutes (German standard)
|
||||
export const EXTENDED_LESSON_LENGTH = 50 // minutes (with buffer)
|
||||
|
||||
// ============================================================================
|
||||
// Timer Thresholds (in seconds)
|
||||
// ============================================================================
|
||||
|
||||
export const TIMER_WARNING_THRESHOLD = 5 * 60 // 5 minutes = warning (yellow)
|
||||
export const TIMER_CRITICAL_THRESHOLD = 2 * 60 // 2 minutes = critical (red)
|
||||
|
||||
// ============================================================================
|
||||
// SVG Pie Timer Constants
|
||||
// ============================================================================
|
||||
|
||||
export const PIE_TIMER_RADIUS = 42
|
||||
export const PIE_TIMER_CIRCUMFERENCE = 2 * Math.PI * PIE_TIMER_RADIUS // ~263.89
|
||||
export const PIE_TIMER_STROKE_WIDTH = 8
|
||||
export const PIE_TIMER_SIZE = 120 // viewBox size
|
||||
|
||||
// ============================================================================
|
||||
// Timer Color Classes
|
||||
// ============================================================================
|
||||
|
||||
export const TIMER_COLOR_CLASSES = {
|
||||
plenty: 'text-green-500 stroke-green-500',
|
||||
warning: 'text-amber-500 stroke-amber-500',
|
||||
critical: 'text-red-500 stroke-red-500',
|
||||
overtime: 'text-red-600 stroke-red-600 animate-pulse',
|
||||
}
|
||||
|
||||
export const TIMER_BG_COLORS = {
|
||||
plenty: 'bg-green-500/10',
|
||||
warning: 'bg-amber-500/10',
|
||||
critical: 'bg-red-500/10',
|
||||
overtime: 'bg-red-600/20',
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Keyboard Shortcuts
|
||||
// ============================================================================
|
||||
|
||||
export const KEYBOARD_SHORTCUTS = {
|
||||
PAUSE_RESUME: ' ', // Spacebar
|
||||
EXTEND_5MIN: 'e',
|
||||
NEXT_PHASE: 'n',
|
||||
CLOSE_MODAL: 'Escape',
|
||||
SHOW_HELP: '?',
|
||||
} as const
|
||||
|
||||
export const KEYBOARD_SHORTCUT_DESCRIPTIONS: Record<string, string> = {
|
||||
' ': 'Pause/Fortsetzen',
|
||||
'e': '+5 Minuten',
|
||||
'n': 'Naechste Phase',
|
||||
'Escape': 'Modal schliessen',
|
||||
'?': 'Hilfe anzeigen',
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Default Settings
|
||||
// ============================================================================
|
||||
|
||||
export const DEFAULT_TEACHER_SETTINGS: TeacherSettings = {
|
||||
defaultPhaseDurations: DEFAULT_PHASE_DURATIONS,
|
||||
preferredLessonLength: DEFAULT_LESSON_LENGTH,
|
||||
autoAdvancePhases: true,
|
||||
soundNotifications: true,
|
||||
showKeyboardShortcuts: true,
|
||||
highContrastMode: false,
|
||||
onboardingCompleted: false,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// System Templates
|
||||
// ============================================================================
|
||||
|
||||
export const SYSTEM_TEMPLATES = [
|
||||
{
|
||||
templateId: 'standard-45',
|
||||
name: 'Standard (45 Min)',
|
||||
description: 'Klassische Unterrichtsstunde',
|
||||
durations: DEFAULT_PHASE_DURATIONS,
|
||||
isSystemTemplate: true,
|
||||
},
|
||||
{
|
||||
templateId: 'double-90',
|
||||
name: 'Doppelstunde (90 Min)',
|
||||
description: 'Fuer laengere Arbeitsphasen',
|
||||
durations: {
|
||||
einstieg: 10,
|
||||
erarbeitung: 45,
|
||||
sicherung: 15,
|
||||
transfer: 12,
|
||||
reflexion: 8,
|
||||
},
|
||||
isSystemTemplate: true,
|
||||
},
|
||||
{
|
||||
templateId: 'math-focused',
|
||||
name: 'Mathematik-fokussiert',
|
||||
description: 'Lange Erarbeitung und Sicherung',
|
||||
durations: {
|
||||
einstieg: 5,
|
||||
erarbeitung: 25,
|
||||
sicherung: 10,
|
||||
transfer: 5,
|
||||
reflexion: 5,
|
||||
},
|
||||
isSystemTemplate: true,
|
||||
},
|
||||
{
|
||||
templateId: 'language-practice',
|
||||
name: 'Sprachpraxis',
|
||||
description: 'Betont kommunikative Phasen',
|
||||
durations: {
|
||||
einstieg: 10,
|
||||
erarbeitung: 15,
|
||||
sicherung: 8,
|
||||
transfer: 10,
|
||||
reflexion: 7,
|
||||
},
|
||||
isSystemTemplate: true,
|
||||
},
|
||||
]
|
||||
|
||||
// ============================================================================
|
||||
// Suggestion Icons (Lucide icon names)
|
||||
// ============================================================================
|
||||
|
||||
export const SUGGESTION_ICONS = {
|
||||
grading: 'ClipboardCheck',
|
||||
homework: 'BookOpen',
|
||||
planning: 'Calendar',
|
||||
meeting: 'Users',
|
||||
deadline: 'Clock',
|
||||
material: 'FileText',
|
||||
communication: 'MessageSquare',
|
||||
default: 'Lightbulb',
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Priority Colors
|
||||
// ============================================================================
|
||||
|
||||
export const PRIORITY_COLORS = {
|
||||
urgent: {
|
||||
bg: 'bg-red-100',
|
||||
text: 'text-red-700',
|
||||
border: 'border-red-200',
|
||||
dot: 'bg-red-500',
|
||||
},
|
||||
high: {
|
||||
bg: 'bg-orange-100',
|
||||
text: 'text-orange-700',
|
||||
border: 'border-orange-200',
|
||||
dot: 'bg-orange-500',
|
||||
},
|
||||
medium: {
|
||||
bg: 'bg-yellow-100',
|
||||
text: 'text-yellow-700',
|
||||
border: 'border-yellow-200',
|
||||
dot: 'bg-yellow-500',
|
||||
},
|
||||
low: {
|
||||
bg: 'bg-slate-100',
|
||||
text: 'text-slate-700',
|
||||
border: 'border-slate-200',
|
||||
dot: 'bg-slate-400',
|
||||
},
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Event Type Icons & Colors
|
||||
// ============================================================================
|
||||
|
||||
export const EVENT_TYPE_CONFIG = {
|
||||
exam: {
|
||||
icon: 'FileQuestion',
|
||||
color: 'text-red-600',
|
||||
bg: 'bg-red-50',
|
||||
},
|
||||
parent_meeting: {
|
||||
icon: 'Users',
|
||||
color: 'text-blue-600',
|
||||
bg: 'bg-blue-50',
|
||||
},
|
||||
deadline: {
|
||||
icon: 'Clock',
|
||||
color: 'text-amber-600',
|
||||
bg: 'bg-amber-50',
|
||||
},
|
||||
other: {
|
||||
icon: 'Calendar',
|
||||
color: 'text-slate-600',
|
||||
bg: 'bg-slate-50',
|
||||
},
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Storage Keys
|
||||
// ============================================================================
|
||||
|
||||
export const STORAGE_KEYS = {
|
||||
SETTINGS: 'companion_settings',
|
||||
CURRENT_SESSION: 'companion_current_session',
|
||||
ONBOARDING_STATE: 'companion_onboarding',
|
||||
CUSTOM_TEMPLATES: 'companion_custom_templates',
|
||||
LAST_MODE: 'companion_last_mode',
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// API Endpoints (relative to backend)
|
||||
// ============================================================================
|
||||
|
||||
export const API_ENDPOINTS = {
|
||||
DASHBOARD: '/api/state/dashboard',
|
||||
LESSON_START: '/api/classroom/sessions',
|
||||
LESSON_UPDATE: '/api/classroom/sessions', // + /{id}
|
||||
TEMPLATES: '/api/classroom/templates',
|
||||
SETTINGS: '/api/teacher/settings',
|
||||
FEEDBACK: '/api/feedback',
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Helper Functions
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Create default phases array from durations
|
||||
*/
|
||||
export function createDefaultPhases(durations: PhaseDurations = DEFAULT_PHASE_DURATIONS): Phase[] {
|
||||
return PHASE_ORDER.map((phaseId, index) => ({
|
||||
id: phaseId,
|
||||
shortName: PHASE_SHORT_NAMES[phaseId],
|
||||
displayName: PHASE_DISPLAY_NAMES[phaseId],
|
||||
duration: durations[phaseId],
|
||||
status: index === 0 ? 'active' : 'planned',
|
||||
color: PHASE_COLORS[phaseId].hex,
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate total duration from phase durations
|
||||
*/
|
||||
export function calculateTotalDuration(durations: PhaseDurations): number {
|
||||
return Object.values(durations).reduce((sum, d) => sum + d, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get timer color status based on remaining time
|
||||
*/
|
||||
export function getTimerColorStatus(
|
||||
remainingSeconds: number,
|
||||
isOvertime: boolean
|
||||
): 'plenty' | 'warning' | 'critical' | 'overtime' {
|
||||
if (isOvertime) return 'overtime'
|
||||
if (remainingSeconds <= TIMER_CRITICAL_THRESHOLD) return 'critical'
|
||||
if (remainingSeconds <= TIMER_WARNING_THRESHOLD) return 'warning'
|
||||
return 'plenty'
|
||||
}
|
||||
|
||||
/**
|
||||
* Format seconds as MM:SS
|
||||
*/
|
||||
export function formatTime(seconds: number): string {
|
||||
const absSeconds = Math.abs(seconds)
|
||||
const mins = Math.floor(absSeconds / 60)
|
||||
const secs = absSeconds % 60
|
||||
const sign = seconds < 0 ? '-' : ''
|
||||
return `${sign}${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Format minutes as "X Min"
|
||||
*/
|
||||
export function formatMinutes(minutes: number): string {
|
||||
return `${minutes} Min`
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from './types'
|
||||
export * from './constants'
|
||||
@@ -1,329 +0,0 @@
|
||||
/**
|
||||
* TypeScript Types for Companion Module
|
||||
* Migration from Flask companion.py/companion_js.py
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// Phase System
|
||||
// ============================================================================
|
||||
|
||||
export type PhaseId = 'einstieg' | 'erarbeitung' | 'sicherung' | 'transfer' | 'reflexion'
|
||||
|
||||
export interface Phase {
|
||||
id: PhaseId
|
||||
shortName: string // E, A, S, T, R
|
||||
displayName: string
|
||||
duration: number // minutes
|
||||
status: 'planned' | 'active' | 'completed'
|
||||
actualTime?: number // seconds (actual time spent)
|
||||
color: string // hex color
|
||||
}
|
||||
|
||||
export interface PhaseContext {
|
||||
currentPhase: PhaseId
|
||||
phaseDisplayName: string
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Dashboard / Companion Mode
|
||||
// ============================================================================
|
||||
|
||||
export interface CompanionStats {
|
||||
classesCount: number
|
||||
studentsCount: number
|
||||
learningUnitsCreated: number
|
||||
gradesEntered: number
|
||||
}
|
||||
|
||||
export interface Progress {
|
||||
percentage: number
|
||||
completed: number
|
||||
total: number
|
||||
}
|
||||
|
||||
export type SuggestionPriority = 'urgent' | 'high' | 'medium' | 'low'
|
||||
|
||||
export interface Suggestion {
|
||||
id: string
|
||||
title: string
|
||||
description: string
|
||||
priority: SuggestionPriority
|
||||
icon: string // lucide icon name
|
||||
actionTarget: string // navigation path
|
||||
estimatedTime: number // minutes
|
||||
}
|
||||
|
||||
export type EventType = 'exam' | 'parent_meeting' | 'deadline' | 'other'
|
||||
|
||||
export interface UpcomingEvent {
|
||||
id: string
|
||||
title: string
|
||||
date: string // ISO date string
|
||||
type: EventType
|
||||
inDays: number
|
||||
}
|
||||
|
||||
export interface CompanionData {
|
||||
context: PhaseContext
|
||||
stats: CompanionStats
|
||||
phases: Phase[]
|
||||
progress: Progress
|
||||
suggestions: Suggestion[]
|
||||
upcomingEvents: UpcomingEvent[]
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Lesson Mode
|
||||
// ============================================================================
|
||||
|
||||
export type LessonStatus =
|
||||
| 'not_started'
|
||||
| 'in_progress'
|
||||
| 'paused'
|
||||
| 'completed'
|
||||
| 'overtime'
|
||||
|
||||
export interface LessonPhase {
|
||||
phase: PhaseId
|
||||
duration: number // planned duration in minutes
|
||||
status: 'planned' | 'active' | 'completed' | 'skipped'
|
||||
actualTime: number // actual time spent in seconds
|
||||
startedAt?: string // ISO timestamp
|
||||
completedAt?: string // ISO timestamp
|
||||
}
|
||||
|
||||
export interface Homework {
|
||||
id: string
|
||||
title: string
|
||||
description?: string
|
||||
dueDate: string // ISO date
|
||||
attachments?: string[]
|
||||
completed?: boolean
|
||||
}
|
||||
|
||||
export interface Material {
|
||||
id: string
|
||||
title: string
|
||||
type: 'document' | 'video' | 'presentation' | 'link' | 'other'
|
||||
url?: string
|
||||
fileName?: string
|
||||
}
|
||||
|
||||
export interface LessonReflection {
|
||||
rating: number // 1-5 stars
|
||||
notes: string
|
||||
nextSteps: string
|
||||
savedAt?: string
|
||||
}
|
||||
|
||||
export interface LessonSession {
|
||||
sessionId: string
|
||||
classId: string
|
||||
className: string
|
||||
subject: string
|
||||
topic?: string
|
||||
startTime: string // ISO timestamp
|
||||
endTime?: string // ISO timestamp
|
||||
phases: LessonPhase[]
|
||||
totalPlannedDuration: number // minutes
|
||||
currentPhaseIndex: number
|
||||
elapsedTime: number // seconds
|
||||
isPaused: boolean
|
||||
pausedAt?: string
|
||||
pauseDuration: number // total pause time in seconds
|
||||
overtimeMinutes: number
|
||||
status: LessonStatus
|
||||
homeworkList: Homework[]
|
||||
materials: Material[]
|
||||
reflection?: LessonReflection
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Lesson Templates
|
||||
// ============================================================================
|
||||
|
||||
export interface PhaseDurations {
|
||||
einstieg: number
|
||||
erarbeitung: number
|
||||
sicherung: number
|
||||
transfer: number
|
||||
reflexion: number
|
||||
}
|
||||
|
||||
export interface LessonTemplate {
|
||||
templateId: string
|
||||
name: string
|
||||
description?: string
|
||||
subject?: string
|
||||
durations: PhaseDurations
|
||||
isSystemTemplate: boolean
|
||||
createdBy?: string
|
||||
createdAt?: string
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Settings
|
||||
// ============================================================================
|
||||
|
||||
export interface TeacherSettings {
|
||||
defaultPhaseDurations: PhaseDurations
|
||||
preferredLessonLength: number // minutes (default 45)
|
||||
autoAdvancePhases: boolean
|
||||
soundNotifications: boolean
|
||||
showKeyboardShortcuts: boolean
|
||||
highContrastMode: boolean
|
||||
onboardingCompleted: boolean
|
||||
selectedTemplateId?: string
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Timer State
|
||||
// ============================================================================
|
||||
|
||||
export type TimerColorStatus = 'plenty' | 'warning' | 'critical' | 'overtime'
|
||||
|
||||
export interface TimerState {
|
||||
isRunning: boolean
|
||||
isPaused: boolean
|
||||
elapsedSeconds: number
|
||||
remainingSeconds: number
|
||||
totalSeconds: number
|
||||
progress: number // 0-1
|
||||
colorStatus: TimerColorStatus
|
||||
currentPhase: LessonPhase | null
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Forms
|
||||
// ============================================================================
|
||||
|
||||
export interface LessonStartFormData {
|
||||
classId: string
|
||||
subject: string
|
||||
topic?: string
|
||||
templateId?: string
|
||||
customDurations?: PhaseDurations
|
||||
}
|
||||
|
||||
export interface Class {
|
||||
id: string
|
||||
name: string
|
||||
grade: string
|
||||
studentCount: number
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Feedback
|
||||
// ============================================================================
|
||||
|
||||
export type FeedbackType = 'bug' | 'feature' | 'feedback'
|
||||
|
||||
export interface FeedbackSubmission {
|
||||
type: FeedbackType
|
||||
title: string
|
||||
description: string
|
||||
screenshot?: string // base64
|
||||
sessionId?: string
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Onboarding
|
||||
// ============================================================================
|
||||
|
||||
export interface OnboardingStep {
|
||||
step: number
|
||||
title: string
|
||||
description: string
|
||||
completed: boolean
|
||||
}
|
||||
|
||||
export interface OnboardingState {
|
||||
currentStep: number
|
||||
totalSteps: number
|
||||
steps: OnboardingStep[]
|
||||
selectedState?: string // Bundesland
|
||||
selectedSchoolType?: string
|
||||
completed: boolean
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// WebSocket Messages
|
||||
// ============================================================================
|
||||
|
||||
export type WSMessageType =
|
||||
| 'phase_update'
|
||||
| 'timer_tick'
|
||||
| 'overtime_warning'
|
||||
| 'pause_toggle'
|
||||
| 'session_end'
|
||||
| 'sync_request'
|
||||
|
||||
export interface WSMessage {
|
||||
type: WSMessageType
|
||||
payload: {
|
||||
sessionId: string
|
||||
phase?: number
|
||||
elapsed?: number
|
||||
isPaused?: boolean
|
||||
overtimeMinutes?: number
|
||||
[key: string]: unknown
|
||||
}
|
||||
timestamp: string
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// API Responses
|
||||
// ============================================================================
|
||||
|
||||
export interface APIResponse<T> {
|
||||
success: boolean
|
||||
data?: T
|
||||
error?: string
|
||||
message?: string
|
||||
}
|
||||
|
||||
export interface DashboardResponse extends APIResponse<CompanionData> {}
|
||||
|
||||
export interface LessonResponse extends APIResponse<LessonSession> {}
|
||||
|
||||
export interface TemplatesResponse extends APIResponse<{ templates: LessonTemplate[] }> {}
|
||||
|
||||
export interface SettingsResponse extends APIResponse<TeacherSettings> {}
|
||||
|
||||
// ============================================================================
|
||||
// Component Props
|
||||
// ============================================================================
|
||||
|
||||
export type CompanionMode = 'companion' | 'lesson' | 'classic'
|
||||
|
||||
export interface ModeToggleProps {
|
||||
currentMode: CompanionMode
|
||||
onModeChange: (mode: CompanionMode) => void
|
||||
}
|
||||
|
||||
export interface PhaseTimelineProps {
|
||||
phases: Phase[]
|
||||
currentPhaseIndex: number
|
||||
onPhaseClick?: (index: number) => void
|
||||
}
|
||||
|
||||
export interface VisualPieTimerProps {
|
||||
progress: number // 0-1
|
||||
remainingSeconds: number
|
||||
totalSeconds: number
|
||||
colorStatus: TimerColorStatus
|
||||
isPaused: boolean
|
||||
currentPhaseName: string
|
||||
phaseColor: string
|
||||
}
|
||||
|
||||
export interface QuickActionsBarProps {
|
||||
onExtend: (minutes: number) => void
|
||||
onPause: () => void
|
||||
onResume: () => void
|
||||
onSkip: () => void
|
||||
isPaused: boolean
|
||||
isLastPhase: boolean
|
||||
disabled?: boolean
|
||||
}
|
||||
Reference in New Issue
Block a user