Initial commit: Velocity-OS migration

This commit is contained in:
2026-05-01 12:32:19 +05:30
commit 407af828d4
283 changed files with 207782 additions and 0 deletions

View File

@@ -0,0 +1,92 @@
import { useEffect, useRef } from 'react';
import { motion } from 'framer-motion';
/**
* QDRing
* Animated SVG arc representing the Qualification Desire score (0100).
* Color: green (≥70), amber (4069), red (<40).
* Animates from 0 to score on mount; smooth spring on value change.
*/
interface QDRingProps {
score: number;
size?: number; // diameter in px (default 64)
strokeWidth?: number;
color?: string; // overrides semantic color if provided
showLabel?: boolean;
}
export function QDRing({
score,
size = 64,
strokeWidth = 4,
color,
showLabel = false,
}: QDRingProps) {
const clampedScore = Math.max(0, Math.min(100, score));
const r = (size - strokeWidth) / 2;
const cx = size / 2;
const cy = size / 2;
const circumference = 2 * Math.PI * r;
// Arc: 0% = full stroke-dashoffset (hidden), 100% = 0 offset (full)
const offset = circumference * (1 - clampedScore / 100);
// Semantic color
const arcColor = color ?? (
clampedScore >= 70 ? 'var(--color-green)' :
clampedScore >= 40 ? 'var(--color-amber)' :
'var(--color-red)'
);
return (
<svg
width={size}
height={size}
viewBox={`0 0 ${size} ${size}`}
role="img"
aria-label={`QD Score: ${clampedScore}`}
style={{ transform: 'rotate(-90deg)' }} // Start arc at top
>
{/* Track */}
<circle
cx={cx} cy={cy} r={r}
fill="none"
stroke="rgba(255,255,255,0.08)"
strokeWidth={strokeWidth}
/>
{/* Animated arc */}
<motion.circle
cx={cx} cy={cy} r={r}
fill="none"
stroke={arcColor}
strokeWidth={strokeWidth}
strokeLinecap="round"
strokeDasharray={circumference}
initial={{ strokeDashoffset: circumference }}
animate={{ strokeDashoffset: offset }}
transition={{ duration: 0.8, ease: [0.4, 0, 0.2, 1] }}
style={{
filter: `drop-shadow(0 0 4px ${arcColor})`,
}}
/>
{/* Optional center label (shown rotated back) */}
{showLabel && (
<text
x={cx} y={cy}
textAnchor="middle"
dominantBaseline="middle"
fill={arcColor}
fontSize={size * 0.22}
fontWeight="700"
fontFamily="var(--font-sans)"
style={{ transform: `rotate(90deg)`, transformOrigin: `${cx}px ${cy}px` }}
>
{clampedScore}
</text>
)}
</svg>
);
}