This commit is contained in:
nabijonovdavronbek619@gmail.com
2026-04-06 15:43:51 +05:00
parent 89c5552c4e
commit 27b1510842
23 changed files with 1871 additions and 26 deletions

View File

@@ -0,0 +1,49 @@
import React from 'react';
import { FileSearch, BrainCircuit, ArrowRight } from 'lucide-react';
import type { CabinetSection } from '../../lib/types';
interface CtaCardsProps {
onNavigate: (section: CabinetSection) => void;
}
export const CtaCards: React.FC<CtaCardsProps> = ({ onNavigate }) => (
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{/* Plagiat */}
<button
onClick={() => onNavigate('plagiat')}
className="group relative overflow-hidden rounded-2xl bg-linear-to-br from-blue-500 to-blue-600 p-6 text-left shadow-md hover:shadow-xl transition-all duration-200 hover:-translate-y-0.5 active:translate-y-0 active:shadow-md"
>
<div className="absolute right-3 top-3 opacity-10 pointer-events-none">
<FileSearch size={72} className="text-white" />
</div>
<FileSearch size={26} className="text-white mb-4" />
<h3 className="text-white font-semibold text-base mb-1">
Plagiat tekshiruvi
</h3>
<p className="text-blue-100 text-sm mb-4 leading-relaxed">
Hujjatingizni originallik uchun tekshiring
</p>
<span className="inline-flex items-center gap-1.5 text-white text-xs font-medium bg-white/20 rounded-lg px-3 py-1.5 group-hover:bg-white/30 transition-colors">
Yuborish <ArrowRight size={12} />
</span>
</button>
{/* SI */}
<button
onClick={() => onNavigate('si')}
className="group relative overflow-hidden rounded-2xl bg-linear-to-br from-violet-500 to-violet-600 p-6 text-left shadow-md hover:shadow-xl transition-all duration-200 hover:-translate-y-0.5 active:translate-y-0 active:shadow-md"
>
<div className="absolute right-3 top-3 opacity-10 pointer-events-none">
<BrainCircuit size={72} className="text-white" />
</div>
<BrainCircuit size={26} className="text-white mb-4" />
<h3 className="text-white font-semibold text-base mb-1">SI detektor</h3>
<p className="text-violet-100 text-sm mb-4 leading-relaxed">
Matnni sun&apos;iy intellekt uchun tekshiring
</p>
<span className="inline-flex items-center gap-1.5 text-white text-xs font-medium bg-white/20 rounded-lg px-3 py-1.5 group-hover:bg-white/30 transition-colors">
Yuborish <ArrowRight size={12} />
</span>
</button>
</div>
);

View File

@@ -0,0 +1,128 @@
import React from 'react';
import {
MODULE_CATEGORIES,
MODULE_STATS,
TAG_STYLES,
type ModuleTag,
} from '../../lib/modules';
// ─── Module stats mini-cards ───────────────────────────────────────────────────
const ModuleStats: React.FC = () => (
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
{[
{ value: MODULE_STATS.total, label: 'Jami modullar' },
{ value: MODULE_STATS.freeInternet, label: 'Bepul internet manbalari' },
{ value: MODULE_STATS.aiModules, label: 'AI tahlil modullari' },
{ value: MODULE_STATS.categories, label: 'Kategoriya' },
].map(({ value, label }) => (
<div
key={label}
className="bg-slate-50 border border-slate-100 rounded-xl px-4 py-3"
>
<p className="text-2xl font-bold text-slate-900 tabular-nums leading-none">
{value}
</p>
<p className="text-xs text-slate-500 mt-1">{label}</p>
</div>
))}
</div>
);
// ─── Tag badge ─────────────────────────────────────────────────────────────────
const Tag: React.FC<{ tag: ModuleTag }> = ({ tag }) => (
<span
className={`inline-block text-[10px] font-semibold px-2 py-0.5 rounded-full ${TAG_STYLES[tag]}`}
>
{tag}
</span>
);
// ─── Category divider ──────────────────────────────────────────────────────────
const CategoryHeader: React.FC<{ label: string }> = ({ label }) => (
<div className="flex items-center gap-3 my-5">
<div className="flex-1 h-px bg-slate-100" />
<span className="text-[11px] font-semibold tracking-widest text-slate-400 uppercase whitespace-nowrap">
{label}
</span>
<div className="flex-1 h-px bg-slate-100" />
</div>
);
// ─── Single module card ────────────────────────────────────────────────────────
interface ModuleCardProps {
name: string;
desc: string;
tags: ModuleTag[];
index: number;
}
const ModuleCard: React.FC<ModuleCardProps> = ({ name, desc, tags, index }) => (
<div className="bg-white border border-slate-100 rounded-xl p-4 flex items-start gap-3 hover:border-slate-200 hover:shadow-sm transition-all duration-150">
{/* Index number */}
<span className="w-6 h-6 rounded-full bg-slate-100 flex items-center justify-center text-[10px] font-semibold text-slate-500 shrink-0 mt-0.5">
{index}
</span>
<div className="min-w-0 flex-1">
<p className="text-sm font-semibold text-slate-800 leading-snug mb-1 truncate">
{name}
</p>
<p className="text-xs text-slate-500 leading-relaxed mb-2.5">{desc}</p>
<div className="flex flex-wrap gap-1.5">
{tags.map((tag) => (
<Tag key={tag} tag={tag} />
))}
</div>
</div>
</div>
);
// ─── Modules section ───────────────────────────────────────────────────────────
export const ModulesSection: React.FC = () => {
// running counter across all categories
let counter = 0;
return (
<div>
<div className="flex items-center justify-between mb-4">
<div>
<h3 className="text-sm font-semibold text-slate-800">
Tekshiruv modullari
</h3>
<p className="text-xs text-slate-400 mt-0.5">
Plagiat aniqlashda foydalaniladigan barcha manbalar
</p>
</div>
<span className="text-xs text-slate-400 bg-slate-100 px-2.5 py-1 rounded-lg font-medium">
{MODULE_STATS.total} ta modul
</span>
</div>
<ModuleStats />
{MODULE_CATEGORIES.map((cat) => (
<div key={cat.label}>
<CategoryHeader label={cat.label} />
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-3">
{cat.modules.map((mod) => {
counter += 1;
return (
<ModuleCard
key={mod.name}
name={mod.name}
desc={mod.desc}
tags={mod.tags}
index={counter}
/>
);
})}
</div>
</div>
))}
</div>
);
};

View File

@@ -0,0 +1,81 @@
import React from 'react';
import { TrendingUp, Calendar, Tag, Wallet } from 'lucide-react';
import type { CabinetStats } from '../../lib/types';
// ─── Single stat card ──────────────────────────────────────────────────────────
interface StatCardProps {
icon: React.ElementType;
label: string;
value: string;
sub?: string;
iconColor: string;
iconBg: string;
}
const StatCard: React.FC<StatCardProps> = ({
icon: Icon,
label,
value,
sub,
iconColor,
iconBg,
}) => (
<div className="bg-white rounded-2xl border border-slate-100 p-5 shadow-sm hover:shadow-md transition-shadow duration-200">
<div
className={`w-10 h-10 rounded-xl flex items-center justify-center mb-4 ${iconBg}`}
>
<Icon size={18} className={iconColor} />
</div>
<p className="text-2xl font-bold text-slate-900 tabular-nums">{value}</p>
<p className="text-xs text-slate-500 mt-0.5">{label}</p>
{sub && <p className="text-[11px] text-slate-400 mt-1">{sub}</p>}
</div>
);
// ─── Grid ──────────────────────────────────────────────────────────────────────
interface StatsCardsProps {
stats: CabinetStats;
}
export const StatsCards: React.FC<StatsCardsProps> = ({ stats }) => {
const discountPct = Math.round(
(stats.discountUsed / stats.discountTotal) * 100,
);
return (
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
<StatCard
icon={TrendingUp}
label="Jami tekshiruvlar"
value={String(stats.total)}
iconColor="text-blue-600"
iconBg="bg-blue-50"
/>
<StatCard
icon={Calendar}
label="Bu oy"
value={String(stats.thisMonth)}
sub={`${stats.discountUsed}/${stats.discountTotal} ta hujjat`}
iconColor="text-emerald-600"
iconBg="bg-emerald-50"
/>
<StatCard
icon={Tag}
label="Chegirma holati"
value={`${discountPct}%`}
sub={`${stats.discountUsed}/${stats.discountTotal} ta ishlatilgan`}
iconColor="text-amber-600"
iconBg="bg-amber-50"
/>
<StatCard
icon={Wallet}
label="Balans"
value={`${stats.balance.toLocaleString()} ${stats.currency}`}
iconColor="text-violet-600"
iconBg="bg-violet-50"
/>
</div>
);
};

View File

@@ -0,0 +1,41 @@
import React from 'react';
import { CtaCards } from './CtaCards';
import { StatsCards } from './StatsCards';
import { ModulesSection } from './ModulesSection';
import type { CabinetSection, CabinetStats } from '../../lib/types';
interface DashboardProps {
stats: CabinetStats;
onNavigate: (section: CabinetSection) => void;
userName: string;
}
export const Dashboard: React.FC<DashboardProps> = ({
stats,
onNavigate,
userName,
}) => (
<div className="space-y-6">
<div>
<h2 className="text-xl font-bold text-slate-900">
Xush kelibsiz, {userName} 👋
</h2>
<p className="text-sm text-slate-500 mt-0.5">
Shaxsiy kabinetingizga xush kelibsiz
</p>
</div>
<StatsCards stats={stats} />
<div>
<h3 className="text-xs font-semibold text-slate-400 uppercase tracking-widest mb-3">
Tezkor harakatlar
</h3>
<CtaCards onNavigate={onNavigate} />
</div>
<div className="border-t border-slate-100 pt-6">
<ModulesSection />
</div>
</div>
);