Replace keyboard emojis with the app's own lucide icons (quiz reactions, +XP, welcome hand, party popper, streak flame)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 16:47:05 +03:30
parent 22fc870176
commit 50f6ade9f8
5 changed files with 16 additions and 15 deletions

View File

@@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from 'react';
import { Bell, ChevronLeft, Coins, Flame, Star } from 'lucide-react';
import { Bell, ChevronLeft, Coins, Flame, Hand, PartyPopper, Star } from 'lucide-react';
import type { HomeNode } from '@/api';
import { useAppData } from '@/state/AppData';
import { findContinue, unitColor, unitProgress } from '@/state/curriculum';
@@ -39,8 +39,8 @@ export function HomeScreen() {
: !home.units.length
? 'هنوز درسی برای این پایه ثبت نشده.'
: cont
? <>سلام {name}! 👋 وقتشه جزیره‌ی <b>«<MathText text={cont.node.title} />»</b> رو شروع کنی؛ دکمه‌ی <b>شروع</b> رو بزن.</>
: <>آفرین {name}! همه‌ی جزیره‌های این پایه رو تموم کردی 🎉</>;
? <>سلام {name}! <Hand size={15} className="mb-0.5 inline text-[#E8A400]" /> وقتشه جزیره‌ی <b>«<MathText text={cont.node.title} />»</b> رو شروع کنی؛ دکمه‌ی <b>شروع</b> رو بزن.</>
: <>آفرین {name}! همه‌ی جزیره‌های این پایه رو تموم کردی <PartyPopper size={15} className="mb-0.5 inline text-[#E8A400]" /></>;
const stats = [
{ icon: Flame, value: summary?.streak.current ?? 0, label: 'روزِ پیاپی', color: '#FF7A3D', fill: true, to: 'streak' as const },

View File

@@ -1,6 +1,6 @@
import { useState } from 'react';
import { motion } from 'motion/react';
import { Brain, Check, ChevronDown, Lock, Play, Sparkles } from 'lucide-react';
import { Brain, Check, ChevronDown, Lock, PartyPopper, Play, Sparkles } from 'lucide-react';
import { api, type HomeNode, type HomeUnit } from '@/api';
import { useAppData } from '@/state/AppData';
import { findContinue, unitColor, unitProgress } from '@/state/curriculum';
@@ -132,7 +132,7 @@ function UnitCard({
</span>
<span className="min-w-0 flex-1">
<span className="block text-[11px] font-bold" style={{ color }}>
{complete ? 'تموم شد 🎉' : `${toFa(p.total)} جزیره`}
{complete ? <><PartyPopper size={12} className="mb-0.5 ml-1 inline" />تموم شد</> : `${toFa(p.total)} جزیره`}
</span>
<span className="block text-sm font-black leading-6 text-ink"><MathText text={unit.title} /></span>
<span className="mt-1 flex items-center gap-2">

View File

@@ -1,6 +1,6 @@
import { useEffect, useRef, useState } from 'react';
import { AnimatePresence, motion } from 'motion/react';
import { Brain, Check, ChevronLeft, Coins, Flag, Heart, Infinity as InfinityIcon, Star, X } from 'lucide-react';
import { Brain, Check, ChevronLeft, Coins, Compass, Flag, Heart, Infinity as InfinityIcon, Lightbulb, Ruler, Sparkles, Star, Target, ThumbsUp, X, Zap, type LucideIcon } from 'lucide-react';
import { api, ApiError, type AnswerResult, type Hearts, type Question, type ReportReason } from '@/api';
import { useAppData } from '@/state/AppData';
import { findNode, findNodeOfLesson, nextLessonOf, unitColor } from '@/state/curriculum';
@@ -291,7 +291,7 @@ export function QuizScreen({ lessonId, nodeId }: { lessonId?: number; nodeId?: s
transition={{ type: 'spring', stiffness: 400, damping: 14 }}
className="mr-2 inline-block rounded-full bg-[#FFF3C4] px-2 py-0.5 text-[11px] font-black text-[#8A5A00]"
>
+{toFa(answer.xpEarned)} ⭐
+{toFa(answer.xpEarned)} <Star size={11} className="mb-0.5 inline" fill="#E8A400" color="#E8A400" />
</motion.span>
)}
</div>
@@ -430,7 +430,7 @@ function Result({
</div>
<div>
<h2 className="text-2xl font-black text-ink">{result.stars === 3 ? 'عالی بود!' : result.stars === 2 ? 'آفرین!' : 'تموم شد!'}</h2>
{nodeMode && <p className="mt-1 text-sm font-bold" style={{ color }}>این جزیره رو تموم کردی 🏝️</p>}
{nodeMode && <p className="mt-1 text-sm font-bold" style={{ color }}>این جزیره رو تموم کردی</p>}
<p className="mt-1 text-sm text-muted">{toFa(correct)} جوابِ درست از {toFa(total)} سوال</p>
</div>
<div className="flex w-full gap-3">
@@ -520,20 +520,21 @@ function ReportSheet({ open, questionId, onClose }: { open: boolean; questionId:
);
}
/** شکلکِ کوچکِ بعد از جواب؛ هر سوال یکی از مجموعه، با یک تکانِ کوتاه. فقط ایموجی و transform. */
const WIN = ['🧠', '💪', '🎯', '⚡', '🤩'];
const MISS = ['🤔', '💡', '📐'];
/** آیکنِ کوچکِ بعد از جواب (همان خانواده‌ی آیکنِ اپ، نه ایموجیِ کیبورد)؛ هر سوال یکی از مجموعه، با یک تکانِ کوتاه. */
const WIN: [LucideIcon, string][] = [[Brain, '#9B7BFF'], [Zap, '#E8A400'], [Target, '#ED6956'], [ThumbsUp, '#3E9E73'], [Sparkles, '#4C5FD5']];
const MISS: [LucideIcon, string][] = [[Lightbulb, '#E8A400'], [Ruler, '#4C5FD5'], [Compass, '#9B7BFF']];
function Reaction({ correct, seed }: { correct: boolean; seed: number }) {
const set = correct ? WIN : MISS;
const [Icon, color] = set[seed % set.length];
return (
<motion.span
aria-hidden
className="mr-1.5 inline-block"
className="mr-1.5 inline-block align-middle"
initial={{ scale: 0.4, rotate: 0 }}
animate={{ scale: 1, rotate: [0, -14, 14, -8, 8, 0] }}
transition={{ duration: 0.6, ease: 'easeOut' }}
>
{set[seed % set.length]}
<Icon size={18} color={color} strokeWidth={2.4} />
</motion.span>
);
}

View File

@@ -102,7 +102,7 @@ function StreakGoal({ current }: { current: number }) {
return (
<div className="rounded-3xl border border-line bg-[#FFF3E8] px-4 py-3">
<p className="text-sm font-black leading-7 text-ink">
{reached ? `🔥 ${toFa(current)} روزه‌ای! ` : ''}
{reached ? <><Flame size={16} fill="#FF7A3D" className="mb-0.5 ml-1 inline text-orange" />{toFa(current)} روزه‌ای! </> : null}
{next ? `${toFa(next - current)} روز دیگه می‌شه زنجیره‌ی ${toFa(next)} روزه.` : 'از همه‌ی نقطه‌عطف‌ها رد شدی، افسانه‌ای!'}
</p>
{next && (