Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import React, { useState, useEffect } from 'react';
- import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
- // Constants
- const CONFIG = {
- CENTER: { X: 250, Y: 250 },
- RADIUS: { OUTER: 180, INNER: 80 },
- HOURS: Array.from({ length: 24 }, (_, i) => i),
- REGIONS: ['Europe', 'North America', 'Asia', 'Australia'],
- TASK_TYPES: {
- 'general': 'General Use',
- 'coding': 'Programming & Development',
- 'writing': 'Content Writing',
- 'translation': 'Translation Tasks',
- 'analysis': 'Data Analysis'
- }
- };
- // Performance calculation utilities
- const getPerformanceScore = (hour, region, taskType = 'general') => {
- let adjustedHour = hour;
- const offsets = { 'North America': -5, 'Europe': 1, 'Asia': 8, 'Australia': 10 };
- adjustedHour = (hour + (offsets[region] || 0) + 24) % 24;
- let baseScore = 0.7;
- // Upravené časové pásma na základe diskusie
- const timeRanges = {
- 'deep_night': { hours: [1, 5], score: 0.98 }, // Najlepší výkon (2am PST)
- 'early_morning': { hours: [5, 8], score: 0.85 }, // Stále dobrý výkon
- 'morning_peak': { hours: [8, 12], score: 0.3 }, // Najhoršia špička (8am US)
- 'afternoon': { hours: [12, 17], score: 0.35 }, // Vysoká záťaž
- 'evening': { hours: [17, 20], score: 0.65 }, // Zlepšenie po práci
- 'night': { hours: [20, 24], score: 0.8 }, // Postupné zlepšovanie
- 'midnight': { hours: [0, 1], score: 0.9 } // Prechod do najlepšieho výkonu
- };
- Object.values(timeRanges).forEach(({ hours, score }) => {
- if (adjustedHour >= hours[0] && adjustedHour < hours[1]) {
- baseScore = score;
- }
- });
- // Vylepšené modifikátory na základe používateľských skúseností
- const taskModifiers = {
- 'coding': adjustedHour >= 1 && adjustedHour < 5 ? 0.1 :
- adjustedHour >= 8 && adjustedHour < 17 ? -0.15 : -0.05, // Výrazný rozdiel v noci
- 'writing': adjustedHour >= 9 && adjustedHour < 17 ? -0.1 :
- adjustedHour >= 0 && adjustedHour < 5 ? 0.05 : 0, // Lepšie v noci
- 'translation': adjustedHour >= 0 && adjustedHour < 5 ? 0.02 : 0, // Mierne lepšie v noci
- 'analysis': adjustedHour >= 0 && adjustedHour < 5 ? 0.08 :
- adjustedHour >= 8 && adjustedHour < 17 ? -0.08 : 0, // Analytické úlohy
- 'general': 0
- };
- return Math.min(1, Math.max(0, baseScore + (taskModifiers[taskType] || 0)));
- };
- const ClaudePerformanceHeatmap = () => {
- // Add custom animation styles
- useEffect(() => {
- const style = document.createElement('style');
- style.textContent = `
- @keyframes peak-performance {
- 0% { opacity: 0.05; transform: scale(1); }
- 50% { opacity: 0.2; transform: scale(1.02); }
- 100% { opacity: 0.05; transform: scale(1); }
- }
- .animate-peak-performance {
- animation: peak-performance 4s cubic-bezier(0.4, 0, 0.6, 1) infinite;
- }
- @keyframes pulse-slow {
- 0% { opacity: 0; transform: scale(1); }
- 50% { opacity: 0.3; transform: scale(1.02); }
- 100% { opacity: 0; transform: scale(1); }
- }
- @keyframes pulse-glow {
- 0% { filter: brightness(1); }
- 50% { filter: brightness(1.3); }
- 100% { filter: brightness(1); }
- }
- @keyframes status-pulse {
- 0% { transform: scale(0.95); opacity: 0.8; }
- 50% { transform: scale(1.05); opacity: 1; }
- 100% { transform: scale(0.95); opacity: 0.8; }
- }
- .animate-pulse-slow {
- animation: pulse-slow 3s cubic-bezier(0.4, 0, 0.6, 1) infinite;
- }
- .animate-pulse-glow {
- animation: pulse-glow 3s cubic-bezier(0.4, 0, 0.6, 1) infinite;
- }
- .animate-status {
- animation: status-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
- }
- `;
- document.head.appendChild(style);
- return () => document.head.removeChild(style);
- }, []);
- const [selectedRegion, setSelectedRegion] = useState('Europe');
- const [selectedTask, setSelectedTask] = useState('general');
- const [hoveredSegment, setHoveredSegment] = useState(null);
- const [tooltipPosition, setTooltipPosition] = useState({ x: 0, y: 0 });
- const [showTooltip, setShowTooltip] = useState(false);
- const [currentTime, setCurrentTime] = useState(new Date());
- const [userTimezone] = useState(Intl.DateTimeFormat().resolvedOptions().timeZone);
- useEffect(() => {
- const timer = setInterval(() => setCurrentTime(new Date()), 60000);
- return () => clearInterval(timer);
- }, []);
- const getCurrentLoadStatus = (region) => {
- const hour = currentTime.getHours();
- const performance = getPerformanceScore(hour, region);
- if (performance >= 0.8) return {
- status: 'Low Load',
- color: '#22c55e',
- message: 'Optimal time for complex tasks'
- };
- if (performance >= 0.6) return {
- status: 'Moderate',
- color: '#eab308',
- message: 'Good for most tasks'
- };
- return {
- status: 'High Load',
- color: '#ef4444',
- message: 'Peak Hours - Expect Delays'
- };
- };
- const generateSegments = () => {
- const currentHour = currentTime.getHours();
- return CONFIG.HOURS.map(hour => {
- const startAngle = (hour * 15 - 90) * (Math.PI / 180);
- const endAngle = ((hour + 1) * 15 - 90) * (Math.PI / 180);
- const performance = getPerformanceScore(hour, selectedRegion, selectedTask);
- const getPoint = (radius, angle) => ({
- x: CONFIG.CENTER.X + radius * Math.cos(angle),
- y: CONFIG.CENTER.Y + radius * Math.sin(angle)
- });
- const start = getPoint(CONFIG.RADIUS.INNER, startAngle);
- const end = getPoint(CONFIG.RADIUS.INNER, endAngle);
- const outerStart = getPoint(CONFIG.RADIUS.OUTER, startAngle);
- const outerEnd = getPoint(CONFIG.RADIUS.OUTER, endAngle);
- const path = [
- `M ${start.x} ${start.y}`,
- `L ${outerStart.x} ${outerStart.y}`,
- `A ${CONFIG.RADIUS.OUTER} ${CONFIG.RADIUS.OUTER} 0 0 1 ${outerEnd.x} ${outerEnd.y}`,
- `L ${end.x} ${end.y}`,
- `A ${CONFIG.RADIUS.INNER} ${CONFIG.RADIUS.INNER} 0 0 0 ${start.x} ${start.y}`,
- 'Z'
- ].join(' ');
- return (
- <g key={hour}>
- {/* Peak Performance Marker */}
- {currentHour === hour && (
- <path
- d={path}
- fill="white"
- opacity="0.2"
- className="animate-pulse-slow"
- />
- )}
- {getPerformanceScore(hour, selectedRegion, selectedTask) > 0.95 && (
- <path
- d={path}
- fill="white"
- opacity="0.1"
- className="animate-peak-performance"
- />
- )}
- <path
- d={path}
- fill={performance >= 0.8 ? '#22c55e' : performance >= 0.6 ? '#eab308' : '#ef4444'}
- opacity={hoveredSegment === hour ? 1 : currentHour === hour ? 0.9 : 0.7}
- className={currentHour === hour ? 'animate-pulse-glow' : ''}
- onMouseEnter={(e) => {
- setHoveredSegment(hour);
- setShowTooltip(true);
- const rect = e.currentTarget.getBoundingClientRect();
- setTooltipPosition({
- x: rect.left + (rect.width / 2),
- y: rect.top - 10
- });
- }}
- onMouseLeave={() => {
- setHoveredSegment(null);
- setShowTooltip(false);
- }}
- />
- <text
- x={CONFIG.CENTER.X + (CONFIG.RADIUS.OUTER + 30) * Math.cos((hour * 15 - 90) * (Math.PI / 180))}
- y={CONFIG.CENTER.Y + (CONFIG.RADIUS.OUTER + 30) * Math.sin((hour * 15 - 90) * (Math.PI / 180))}
- fill="#9ca3af"
- textAnchor="middle"
- dominantBaseline="middle"
- fontSize="12"
- >
- {`${hour}:00`}
- </text>
- </g>
- );
- });
- };
- const loadStatus = getCurrentLoadStatus(selectedRegion);
- return (
- <div className="min-h-screen bg-gray-950 p-4">
- <Card className="w-full max-w-3xl mx-auto bg-gray-900 border-gray-800">
- <CardHeader>
- <CardTitle className="text-gray-100">Claude AI Performance Heatmap</CardTitle>
- </CardHeader>
- <CardContent>
- <div className="flex flex-col items-center gap-4 mb-6">
- <div className="flex items-center gap-4">
- <select
- value={selectedRegion}
- onChange={(e) => setSelectedRegion(e.target.value)}
- className="bg-gray-800 text-gray-100 p-2 rounded border border-gray-700"
- >
- {CONFIG.REGIONS.map(region => (
- <option key={region} value={region}>{region}</option>
- ))}
- </select>
- <select
- value={selectedTask}
- onChange={(e) => setSelectedTask(e.target.value)}
- className="bg-gray-800 text-gray-100 p-2 rounded border border-gray-700"
- >
- {Object.entries(CONFIG.TASK_TYPES).map(([key, label]) => (
- <option key={key} value={key}>{label}</option>
- ))}
- </select>
- <div
- className="flex items-center gap-2 px-3 py-1.5 rounded-full transition-all duration-700"
- style={{
- backgroundColor: `${loadStatus.color}15`,
- border: `1px solid ${loadStatus.color}`,
- boxShadow: `0 0 10px ${loadStatus.color}25`
- }}
- >
- <div
- className="relative"
- >
- <div
- className="w-2 h-2 rounded-full transition-colors duration-700"
- style={{ backgroundColor: loadStatus.color }}
- />
- <div
- className="absolute top-0 left-0 w-2 h-2 rounded-full animate-status"
- style={{
- backgroundColor: loadStatus.color,
- }}
- />
- </div>
- <span
- className="text-sm font-medium transition-colors duration-700"
- style={{ color: loadStatus.color }}
- >
- {loadStatus.status}
- </span>
- </div>
- </div>
- <p className="text-gray-400 text-sm">{loadStatus.message}</p>
- <p className="text-gray-500 text-xs">Your timezone: {userTimezone}</p>
- <button
- onClick={() => {
- const bestHour = CONFIG.HOURS.reduce((best, hour) => {
- return getPerformanceScore(hour, selectedRegion, selectedTask) >
- getPerformanceScore(best, selectedRegion, selectedTask) ? hour : best;
- }, 0);
- setHoveredSegment(bestHour);
- setShowTooltip(true);
- }}
- className="px-4 py-2 bg-gray-800 hover:bg-gray-700 text-gray-200 rounded-full transition-colors text-sm"
- >
- Find Best Time
- </button>
- </div>
- <div className="relative w-full flex justify-center">
- <svg viewBox="-50 -50 600 600" className="w-full max-w-2xl">
- <g>
- {generateSegments()}
- <circle
- cx={CONFIG.CENTER.X}
- cy={CONFIG.CENTER.Y}
- r={CONFIG.RADIUS.INNER - 10}
- className="fill-gray-950"
- />
- <text
- x={CONFIG.CENTER.X}
- y={CONFIG.CENTER.Y - 10}
- textAnchor="middle"
- className="fill-gray-300 text-xl"
- >
- {currentTime.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
- </text>
- <text
- x={CONFIG.CENTER.X}
- y={CONFIG.CENTER.Y + 15}
- textAnchor="middle"
- className="fill-gray-500 text-sm"
- >
- {userTimezone}
- </text>
- </g>
- </svg>
- {showTooltip && hoveredSegment !== null && (
- <div
- className="absolute bg-gray-800 text-gray-100 p-2 rounded shadow-lg border border-gray-700 text-sm"
- style={{
- left: tooltipPosition.x,
- top: tooltipPosition.y,
- transform: 'translate(-50%, -100%)'
- }}
- >
- <div>Time: {hoveredSegment}:00</div>
- <div>Performance: {Math.round(getPerformanceScore(hoveredSegment, selectedRegion, selectedTask) * 100)}%</div>
- </div>
- )}
- </div>
- <div className="mt-6 flex items-center justify-center gap-4 text-sm">
- <span className="text-red-500">Lower Performance</span>
- <div className="w-32 h-2 bg-gradient-to-r from-red-500 via-yellow-500 to-green-500 rounded" />
- <span className="text-green-500">Higher Performance</span>
- </div>
- </CardContent>
- </Card>
- </div>
- );
- };
- export default ClaudePerformanceHeatmap;
Advertisement
Add Comment
Please, Sign In to add comment