Subscription store, paywall on locked units, profile subscription bar, Tadrisino branding

- Store opens with two choices (subscription / question packs); 3- and 6-month cards
  show per-month price and saving.
- Units that need a subscription show a crown badge and open the store; a 402 from
  the quiz goes there too. «ادامه بده» skips locked units.
- Profile: subscription card with an animated days-left bar (planDurationDays).
- BrandMark (SVG) on splash, home header and footer; copyright footer; floating math
  glyphs on splash. CSS transform/opacity only; honours reduced motion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-10 01:19:09 +03:30
parent 8879b42b1c
commit a8a5351862
15 changed files with 320 additions and 71 deletions

View File

@@ -0,0 +1,13 @@
import { toFa } from '@/lib/format';
import { BrandMark } from '@/components/BrandMark';
/** امضای تدریسینو پایینِ صفحه‌ها: نشان، نام و حقِ نشر، کوچک و کم‌رنگ. */
export function BrandFooter() {
return (
<footer className="flex flex-col items-center gap-1 pb-4 pt-3 text-center">
<BrandMark size={24} tone="dark" />
<span className="text-[10px] text-muted">ریاضی، قدم‌به‌قدم، از روی کتابِ درسی</span>
<span className="text-[10px] text-faint">© {toFa(1405)} تدریسینو · همه‌ی حقوق محفوظ است</span>
</footer>
);
}

View File

@@ -0,0 +1,23 @@
/**
* نشانِ تدریسینو: یک کاشیِ گرد با «π» و جرقه‌ی کوچکِ چشمک‌زن، کنارِ نامِ تدریسینو.
* خودِ SVG است (بی‌فایلِ تصویر)، پس در هر اندازه تیز است و چیزی دانلود نمی‌شود.
*/
export function BrandMark({ size = 28, tone = 'light', withName = true }: { size?: number; tone?: 'light' | 'dark'; withName?: boolean }) {
const ink = tone === 'light' ? '#fff' : '#3C3F8F';
return (
<span className="inline-flex items-center gap-1.5" aria-label="تدریسینو">
<svg width={size} height={size} viewBox="0 0 32 32" aria-hidden="true">
<defs>
<linearGradient id="bm-g" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stopColor="#FF9A5C" />
<stop offset="1" stopColor="#ED6956" />
</linearGradient>
</defs>
<rect x="1" y="1" width="30" height="30" rx="9" fill="url(#bm-g)" stroke={tone === 'light' ? 'rgba(255,255,255,.55)' : 'none'} />
<path d="M9 11.5h14M12.5 11.5v10M19 11.5v8.2c0 1.2.7 1.8 1.8 1.8" stroke="#fff" strokeWidth="2.6" strokeLinecap="round" fill="none" />
<path className="spark" d="M25 4.5l.9 1.9 1.9.9-1.9.9-.9 1.9-.9-1.9-1.9-.9 1.9-.9z" fill="#FFD23F" />
</svg>
{withName && <span className="font-black tracking-tight" style={{ color: ink, fontSize: size * 0.62 }}>تدریسینو</span>}
</span>
);
}