feat(lessons): add lessons from client db
This commit is contained in:
84
src/components/lessons/GrowthComparisonWidget.tsx
Normal file
84
src/components/lessons/GrowthComparisonWidget.tsx
Normal file
@ -0,0 +1,84 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
const GrowthComparisonWidget: React.FC = () => {
|
||||
const [linearRate, setLinearRate] = useState(10); // +10 per step
|
||||
const [expRate, setExpRate] = useState(10); // +10% per step
|
||||
const start = 100;
|
||||
const steps = 10;
|
||||
|
||||
// Generate Data
|
||||
const data = Array.from({ length: steps + 1 }, (_, i) => {
|
||||
return {
|
||||
x: i,
|
||||
lin: start + linearRate * i,
|
||||
exp: start * Math.pow(1 + expRate/100, i)
|
||||
};
|
||||
});
|
||||
|
||||
const maxY = Math.max(data[steps].lin, data[steps].exp);
|
||||
|
||||
// Scales
|
||||
const width = 100;
|
||||
const height = 60;
|
||||
const getX = (i: number) => (i / steps) * width;
|
||||
const getY = (val: number) => height - (val / maxY) * height; // Inverted Y
|
||||
|
||||
const linPath = `M ${data.map(d => `${getX(d.x)},${getY(d.lin)}`).join(' L ')}`;
|
||||
const expPath = `M ${data.map(d => `${getX(d.x)},${getY(d.exp)}`).join(' L ')}`;
|
||||
|
||||
return (
|
||||
<div className="bg-white p-6 rounded-xl shadow-lg border border-slate-200">
|
||||
<div className="grid grid-cols-2 gap-8 mb-6">
|
||||
<div>
|
||||
<label className="text-xs font-bold text-indigo-600 uppercase">Linear Rate (+)</label>
|
||||
<input
|
||||
type="range" min="5" max="50" value={linearRate}
|
||||
onChange={e => setLinearRate(Number(e.target.value))}
|
||||
className="w-full h-2 bg-indigo-100 rounded-lg appearance-none cursor-pointer accent-indigo-600 mt-2"
|
||||
/>
|
||||
<div className="text-right font-mono font-bold text-indigo-700">+{linearRate} / step</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-bold text-rose-600 uppercase">Exponential Rate (%)</label>
|
||||
<input
|
||||
type="range" min="2" max="30" value={expRate}
|
||||
onChange={e => setExpRate(Number(e.target.value))}
|
||||
className="w-full h-2 bg-rose-100 rounded-lg appearance-none cursor-pointer accent-rose-600 mt-2"
|
||||
/>
|
||||
<div className="text-right font-mono font-bold text-rose-700">+{expRate}% / step</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative h-64 w-full bg-slate-50 rounded-lg border border-slate-200 mb-6 overflow-hidden">
|
||||
<svg viewBox={`0 0 ${width} ${height}`} preserveAspectRatio="none" className="w-full h-full p-4 overflow-visible">
|
||||
{/* Grid */}
|
||||
<line x1="0" y1={height} x2={width} y2={height} stroke="#cbd5e1" strokeWidth="0.5" />
|
||||
<line x1="0" y1="0" x2="0" y2={height} stroke="#cbd5e1" strokeWidth="0.5" />
|
||||
|
||||
{/* Paths */}
|
||||
<path d={linPath} fill="none" stroke="#4f46e5" strokeWidth="1" />
|
||||
<path d={expPath} fill="none" stroke="#e11d48" strokeWidth="1" />
|
||||
|
||||
{/* Points */}
|
||||
{data.map((d, i) => (
|
||||
<g key={i}>
|
||||
<circle cx={getX(d.x)} cy={getY(d.lin)} r="1" fill="#4f46e5" />
|
||||
<circle cx={getX(d.x)} cy={getY(d.exp)} r="1" fill="#e11d48" />
|
||||
</g>
|
||||
))}
|
||||
</svg>
|
||||
{/* Labels */}
|
||||
<div className="absolute top-2 right-2 text-xs font-bold bg-white/80 p-2 rounded shadow-sm">
|
||||
<div className="text-indigo-600">Linear Final: {Math.round(data[steps].lin)}</div>
|
||||
<div className="text-rose-600">Exp Final: {Math.round(data[steps].exp)}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="text-sm text-slate-500">
|
||||
Exponential growth eventually overtakes Linear growth, even if the linear rate seems larger at first!
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default GrowthComparisonWidget;
|
||||
Reference in New Issue
Block a user