/* ============================================================
screen_stories.jsx — Home: weekly pulse + swipeable Stories
============================================================ */
/* ---------- mini sparkline (animated draw) ---------- */
function Spark({ color = 'var(--amber)', w = 120, h = 40 }) {
const pts = [6, 9, 7, 12, 10, 16, 14, 20, 24];
const max = Math.max(...pts), min = Math.min(...pts);
const d = pts.map((p, i) => {
const x = (i / (pts.length - 1)) * w;
const y = h - ((p - min) / (max - min)) * (h - 6) - 3;
return `${i === 0 ? 'M' : 'L'}${x.toFixed(1)} ${y.toFixed(1)}`;
}).join(' ');
return (
);
}
/* ---------- story card content by type ---------- */
function StoryContent({ s, lang, t, go, onClose }) {
const valueNum = useCountUp(s.value || s.delta || (s.big ? +s.big : 0), 1100, true);
return (
{tr(s.kicker, lang)}
{s.type === 'value' && (
{tr(s.title, lang)}
{fmtSum(valueNum)}
{t.perMonth}
+{s.trend}% {t.thisWeek}
)}
{s.type === 'watchers' && (
{valueNum}
{tr(s.title, lang)}
{[0,1,2,3,4].map(i => (
))}
)}
{s.type === 'demand' && (
{tr(s.title, lang)}
{[40, 52, 48, 66, 72, 88, 100].map((h, i) => (
= 5 ? 'linear-gradient(var(--amber-soft),var(--amber))' : 'rgba(255,255,255,.18)',
animation: `barGrow .6s var(--ease-out) ${0.3 + i*0.07}s both` }} />
))}
+{s.delta}%
)}
{s.type === 'role' && (
{s.match}
{tr(s.title, lang)}
{brandName(s.company)}
)}
{s.type === 'gap' && (
)}
{s.type === 'progress' && (
{tr(s.title, lang)}
{[0,1,2,3,4].map(i => (
))}
)}
{tr(s.sub, lang)}
{(s.type === 'role' || s.type === 'watchers' || s.type === 'gap') && (
)}
);
}
/* ---------- fullscreen story viewer ---------- */
function StoryViewer({ start, onClose, lang, t, go }) {
const [i, setI] = useState(start || 0);
const [paused, setPaused] = useState(false);
const [prog, setProg] = useState(0);
const raf = useRef(null);
const last = useRef(0);
const DUR = 5200;
useEffect(() => { setProg(0); last.current = 0; }, [i]);
useEffect(() => {
const tick = (ts) => {
if (!last.current) last.current = ts;
const dt = ts - last.current; last.current = ts;
if (!paused) {
setProg(p => {
const n = p + dt / DUR;
if (n >= 1) {
if (i < STORIES.length - 1) { setI(i + 1); return 0; }
else { setTimeout(onClose, 0); return 1; }
}
return n;
});
}
raf.current = requestAnimationFrame(tick);
};
raf.current = requestAnimationFrame(tick);
return () => cancelAnimationFrame(raf.current);
}, [i, paused]);
const s = STORIES[i];
const next = () => { if (i < STORIES.length - 1) setI(i + 1); else onClose(); };
const prev = () => { if (i > 0) setI(i - 1); else setProg(0); };
return (
{/* decorative glow */}
{/* progress bars */}
{STORIES.map((_, k) => (
))}
{/* header */}
{/* tap zones */}
setPaused(true)} onPointerUp={() => setPaused(false)} onPointerLeave={() => setPaused(false)}>
);
}
/* ---------- story rail bubble ---------- */
function StoryBubble({ s, lang, onOpen, seen }) {
const label = { value: { ru: 'Неделя', uz: 'Hafta' }, watchers: { ru: 'Тебя ищут', uz: 'Qidirishyapti' }, demand: { ru: 'Спрос', uz: 'Talab' }, role: { ru: 'Роль', uz: 'Rol' }, gap: { ru: 'Шаг', uz: 'Qadam' }, progress: { ru: 'Рост', uz: 'Rivoj' } }[s.type];
const icon = { value: 'trend', watchers: 'eye', demand: 'spark', role: 'briefcase', gap: 'fire', progress: 'trend' }[s.type];
return (
);
}
/* ---------- home screen ---------- */
function StoriesScreen({ lang, theme, setLang, setTheme, t, go, status }) {
const [viewer, setViewer] = useState(null); // start index or null
const [seen, setSeen] = useState([]);
const hero = STORIES[0];
const heroVal = useCountUp(hero.value, 1100, true);
const open = (k) => { setViewer(k); setSeen(p => [...new Set([...p, k])]); };
return (
{viewer !== null &&
setViewer(null)} lang={lang} t={t} go={go} />}
}
t={t}
/>
{/* story rail */}
{STORIES.map((s, k) => open(k)} seen={seen.includes(k)} />)}
{/* pulse hero */}
{/* feed cards */}
open(1)} icon="eye" color="var(--indigo-500)" delay={.08}
big="14" title={t.seen} sub={tr(STORIES[1].sub, lang)} lang={lang} />
open(2)} icon="trend" color="var(--good)" delay={.14}
big="+12%" title={t.demand} sub={tr(STORIES[2].sub, lang)} lang={lang} />
{ setViewer(null); go('jobs'); }} icon="briefcase" color="var(--amber-deep)" delay={.2}
big="92%" title={tr({ ru: 'Новая роль · SMM-менеджер', uz: 'Yangi rol · SMM menejer' }, lang)} sub={tr(STORIES[3].sub, lang)} lang={lang} />
{/* who viewed you */}
{/* companies hiring rail */}
{t.companiesHiring}
{VIEWERS.map(b => (
))}
);
}
function FeedCard({ icon, color, big, title, sub, onClick, delay = 0 }) {
return (
);
}
Object.assign(window, { StoriesScreen, StoryViewer });