mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 17:43:47 +00:00
Refactor AdminDashboard and AdminPanel components for improved icon consistency and layout
- Updated icon components in AdminDashboard to use modern, styled icons for better visual consistency. - Replaced existing icons with new versions across various sections, enhancing the overall UI. - Refactored AdminPanel to streamline the structure, introducing grouped sections for better organization. - Improved card layouts and hover effects for a more responsive user experience.
This commit is contained in:
@@ -4,7 +4,7 @@ import { Link } from 'react-router-dom'
|
|||||||
import { statsApi, type DashboardStats, type NodeStatus } from '../api/admin'
|
import { statsApi, type DashboardStats, type NodeStatus } from '../api/admin'
|
||||||
import { useCurrency } from '../hooks/useCurrency'
|
import { useCurrency } from '../hooks/useCurrency'
|
||||||
|
|
||||||
// Icons
|
// Icons - styled like main navigation
|
||||||
const BackIcon = () => (
|
const BackIcon = () => (
|
||||||
<svg className="w-5 h-5 text-dark-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
<svg className="w-5 h-5 text-dark-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
|
||||||
@@ -12,26 +12,45 @@ const BackIcon = () => (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const ServerIcon = () => (
|
const ServerIcon = () => (
|
||||||
<svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M5.25 14.25h13.5m-13.5 0a3 3 0 01-3-3m3 3a3 3 0 100 6h13.5a3 3 0 100-6m-16.5-3a3 3 0 013-3h13.5a3 3 0 013 3m-19.5 0a4.5 4.5 0 01.9-2.7L5.737 5.1a3.375 3.375 0 012.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 01.9 2.7m0 0a3 3 0 01-3 3m0 3h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008zm-3 6h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008z" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M21.75 17.25v-.228a4.5 4.5 0 00-.12-1.03l-2.268-9.64a3.375 3.375 0 00-3.285-2.602H7.923a3.375 3.375 0 00-3.285 2.602l-2.268 9.64a4.5 4.5 0 00-.12 1.03v.228m19.5 0a3 3 0 01-3 3H5.25a3 3 0 01-3-3m19.5 0a3 3 0 00-3-3H5.25a3 3 0 00-3 3m16.5 0h.008v.008h-.008v-.008zm-3 0h.008v.008h-.008v-.008z" />
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
const UsersIcon = () => (
|
const UsersOnlineIcon = () => (
|
||||||
<svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M18 18.72a9.094 9.094 0 003.741-.479 3 3 0 00-4.682-2.72m.94 3.198l.001.031c0 .225-.012.447-.037.666A11.944 11.944 0 0112 21c-2.17 0-4.207-.576-5.963-1.584A6.062 6.062 0 016 18.719m12 0a5.971 5.971 0 00-.941-3.197m0 0A5.995 5.995 0 0012 12.75a5.995 5.995 0 00-5.058 2.772m0 0a3 3 0 00-4.681 2.72 8.986 8.986 0 003.74.477m.94-3.197a5.971 5.971 0 00-.94 3.197M15 6.75a3 3 0 11-6 0 3 3 0 016 0zm6 3a2.25 2.25 0 11-4.5 0 2.25 2.25 0 014.5 0zm-13.5 0a2.25 2.25 0 11-4.5 0 2.25 2.25 0 014.5 0z" />
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
const CurrencyIcon = () => (
|
const WalletIcon = () => (
|
||||||
<svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M2.25 18.75a60.07 60.07 0 0115.797 2.101c.727.198 1.453-.342 1.453-1.096V18.75M3.75 4.5v.75A.75.75 0 013 6h-.75m0 0v-.375c0-.621.504-1.125 1.125-1.125H20.25M2.25 6v9m18-10.5v.75c0 .414.336.75.75.75h.75m-1.5-1.5h.375c.621 0 1.125.504 1.125 1.125v9.75c0 .621-.504 1.125-1.125 1.125h-.375m1.5-1.5H21a.75.75 0 00-.75.75v.75m0 0H3.75m0 0h-.375a1.125 1.125 0 01-1.125-1.125V15m1.5 1.5v-.75A.75.75 0 003 15h-.75M15 10.5a3 3 0 11-6 0 3 3 0 016 0zm3 0h.008v.008H18V10.5zm-12 0h.008v.008H6V10.5z" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M21 12a2.25 2.25 0 00-2.25-2.25H15a3 3 0 11-6 0H5.25A2.25 2.25 0 003 12m18 0v6a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 18v-6m18 0V9M3 12V9m18 0a2.25 2.25 0 00-2.25-2.25H5.25A2.25 2.25 0 003 9m18 0V6a2.25 2.25 0 00-2.25-2.25H5.25A2.25 2.25 0 003 6v3" />
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
const SubscriptionIcon = () => (
|
const ChartBarIcon = () => (
|
||||||
<svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M2.25 8.25h19.5M2.25 9h19.5m-16.5 5.25h6m-6 2.25h3m-3.75 3h15a2.25 2.25 0 002.25-2.25V6.75A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25v10.5A2.25 2.25 0 004.5 19.5z" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 013 19.875v-6.75zM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V8.625zM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V4.125z" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const SparklesIcon = () => (
|
||||||
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09zM18.259 8.715L18 9.75l-.259-1.035a3.375 3.375 0 00-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 002.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 002.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 00-2.456 2.456zM16.894 20.567L16.5 21.75l-.394-1.183a2.25 2.25 0 00-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 001.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 001.423 1.423l1.183.394-1.183.394a2.25 2.25 0 00-1.423 1.423z" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const CubeIcon = () => (
|
||||||
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M21 7.5l-9-5.25L3 7.5m18 0l-9 5.25m9-5.25v9l-9 5.25M3 7.5l9 5.25M3 7.5v9l9 5.25m0-9v9" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const TagIcon = () => (
|
||||||
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M9.568 3H5.25A2.25 2.25 0 003 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 005.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 009.568 3z" />
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M6 6h.008v.008H6V6z" />
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -319,26 +338,26 @@ export default function AdminDashboard() {
|
|||||||
<StatCard
|
<StatCard
|
||||||
title={t('adminDashboard.stats.usersOnline')}
|
title={t('adminDashboard.stats.usersOnline')}
|
||||||
value={stats?.nodes.total_users_online || 0}
|
value={stats?.nodes.total_users_online || 0}
|
||||||
icon={<UsersIcon />}
|
icon={<UsersOnlineIcon />}
|
||||||
color="success"
|
color="success"
|
||||||
/>
|
/>
|
||||||
<StatCard
|
<StatCard
|
||||||
title={t('adminDashboard.stats.activeSubscriptions')}
|
title={t('adminDashboard.stats.activeSubscriptions')}
|
||||||
value={stats?.subscriptions.active || 0}
|
value={stats?.subscriptions.active || 0}
|
||||||
subtitle={`${t('adminDashboard.stats.total')}: ${stats?.subscriptions.total || 0}`}
|
subtitle={`${t('adminDashboard.stats.total')}: ${stats?.subscriptions.total || 0}`}
|
||||||
icon={<SubscriptionIcon />}
|
icon={<SparklesIcon />}
|
||||||
color="accent"
|
color="accent"
|
||||||
/>
|
/>
|
||||||
<StatCard
|
<StatCard
|
||||||
title={t('adminDashboard.stats.incomeToday')}
|
title={t('adminDashboard.stats.incomeToday')}
|
||||||
value={`${formatAmount(stats?.financial.income_today_rubles || 0)} ${currencySymbol}`}
|
value={`${formatAmount(stats?.financial.income_today_rubles || 0)} ${currencySymbol}`}
|
||||||
icon={<CurrencyIcon />}
|
icon={<WalletIcon />}
|
||||||
color="warning"
|
color="warning"
|
||||||
/>
|
/>
|
||||||
<StatCard
|
<StatCard
|
||||||
title={t('adminDashboard.stats.incomeMonth')}
|
title={t('adminDashboard.stats.incomeMonth')}
|
||||||
value={`${formatAmount(stats?.financial.income_month_rubles || 0)} ${currencySymbol}`}
|
value={`${formatAmount(stats?.financial.income_month_rubles || 0)} ${currencySymbol}`}
|
||||||
icon={<CurrencyIcon />}
|
icon={<ChartBarIcon />}
|
||||||
color="info"
|
color="info"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -347,7 +366,9 @@ export default function AdminDashboard() {
|
|||||||
<div className="bg-dark-800/30 backdrop-blur rounded-xl border border-dark-700 p-5">
|
<div className="bg-dark-800/30 backdrop-blur rounded-xl border border-dark-700 p-5">
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<ServerIcon />
|
<div className="p-2.5 rounded-lg bg-accent-500/20 text-accent-400">
|
||||||
|
<ServerIcon />
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-lg font-semibold text-dark-100">{t('adminDashboard.nodes.title')}</h2>
|
<h2 className="text-lg font-semibold text-dark-100">{t('adminDashboard.nodes.title')}</h2>
|
||||||
<p className="text-sm text-dark-400">
|
<p className="text-sm text-dark-400">
|
||||||
@@ -395,7 +416,9 @@ export default function AdminDashboard() {
|
|||||||
{/* Revenue Chart */}
|
{/* Revenue Chart */}
|
||||||
<div className="bg-dark-800/30 backdrop-blur rounded-xl border border-dark-700 p-5">
|
<div className="bg-dark-800/30 backdrop-blur rounded-xl border border-dark-700 p-5">
|
||||||
<div className="flex items-center gap-3 mb-4">
|
<div className="flex items-center gap-3 mb-4">
|
||||||
<CurrencyIcon />
|
<div className="p-2.5 rounded-lg bg-warning-500/20 text-warning-400">
|
||||||
|
<ChartBarIcon />
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-lg font-semibold text-dark-100">{t('adminDashboard.revenue.title')}</h2>
|
<h2 className="text-lg font-semibold text-dark-100">{t('adminDashboard.revenue.title')}</h2>
|
||||||
<p className="text-sm text-dark-400">{t('adminDashboard.revenue.last7Days')}</p>
|
<p className="text-sm text-dark-400">{t('adminDashboard.revenue.last7Days')}</p>
|
||||||
@@ -417,7 +440,9 @@ export default function AdminDashboard() {
|
|||||||
{/* Subscription Stats */}
|
{/* Subscription Stats */}
|
||||||
<div className="bg-dark-800/30 backdrop-blur rounded-xl border border-dark-700 p-5">
|
<div className="bg-dark-800/30 backdrop-blur rounded-xl border border-dark-700 p-5">
|
||||||
<div className="flex items-center gap-3 mb-4">
|
<div className="flex items-center gap-3 mb-4">
|
||||||
<SubscriptionIcon />
|
<div className="p-2.5 rounded-lg bg-accent-500/20 text-accent-400">
|
||||||
|
<SparklesIcon />
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-lg font-semibold text-dark-100">{t('adminDashboard.subscriptions.title')}</h2>
|
<h2 className="text-lg font-semibold text-dark-100">{t('adminDashboard.subscriptions.title')}</h2>
|
||||||
<p className="text-sm text-dark-400">{t('adminDashboard.subscriptions.subtitle')}</p>
|
<p className="text-sm text-dark-400">{t('adminDashboard.subscriptions.subtitle')}</p>
|
||||||
@@ -478,7 +503,9 @@ export default function AdminDashboard() {
|
|||||||
{stats?.servers && (
|
{stats?.servers && (
|
||||||
<div className="bg-dark-800/30 backdrop-blur rounded-xl border border-dark-700 p-5">
|
<div className="bg-dark-800/30 backdrop-blur rounded-xl border border-dark-700 p-5">
|
||||||
<div className="flex items-center gap-3 mb-4">
|
<div className="flex items-center gap-3 mb-4">
|
||||||
<ServerIcon />
|
<div className="p-2.5 rounded-lg bg-info-500/20 text-info-400">
|
||||||
|
<CubeIcon />
|
||||||
|
</div>
|
||||||
<h2 className="text-lg font-semibold text-dark-100">{t('adminDashboard.servers.title')}</h2>
|
<h2 className="text-lg font-semibold text-dark-100">{t('adminDashboard.servers.title')}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||||
@@ -506,7 +533,9 @@ export default function AdminDashboard() {
|
|||||||
{stats?.tariff_stats && stats.tariff_stats.tariffs.length > 0 && (
|
{stats?.tariff_stats && stats.tariff_stats.tariffs.length > 0 && (
|
||||||
<div className="bg-dark-800/30 backdrop-blur rounded-xl border border-dark-700 p-5">
|
<div className="bg-dark-800/30 backdrop-blur rounded-xl border border-dark-700 p-5">
|
||||||
<div className="flex items-center gap-3 mb-4">
|
<div className="flex items-center gap-3 mb-4">
|
||||||
<SubscriptionIcon />
|
<div className="p-2.5 rounded-lg bg-success-500/20 text-success-400">
|
||||||
|
<TagIcon />
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-lg font-semibold text-dark-100">{t('adminDashboard.tariffs.title')}</h2>
|
<h2 className="text-lg font-semibold text-dark-100">{t('adminDashboard.tariffs.title')}</h2>
|
||||||
<p className="text-sm text-dark-400">{t('adminDashboard.tariffs.subtitle')}</p>
|
<p className="text-sm text-dark-400">{t('adminDashboard.tariffs.subtitle')}</p>
|
||||||
|
|||||||
@@ -1,393 +1,331 @@
|
|||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
// Icons - smaller versions for mobile
|
// Modern icons with consistent styling
|
||||||
const TicketIcon = ({ className = "w-8 h-8" }: { className?: string }) => (
|
const ChartBarIcon = () => (
|
||||||
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 013 19.875v-6.75zM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V8.625zM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V4.125z" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const BanknotesIcon = () => (
|
||||||
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M2.25 18.75a60.07 60.07 0 0115.797 2.101c.727.198 1.453-.342 1.453-1.096V18.75M3.75 4.5v.75A.75.75 0 013 6h-.75m0 0v-.375c0-.621.504-1.125 1.125-1.125H20.25M2.25 6v9m18-10.5v.75c0 .414.336.75.75.75h.75m-1.5-1.5h.375c.621 0 1.125.504 1.125 1.125v9.75c0 .621-.504 1.125-1.125 1.125h-.375m1.5-1.5H21a.75.75 0 00-.75.75v.75m0 0H3.75m0 0h-.375a1.125 1.125 0 01-1.125-1.125V15m1.5 1.5v-.75A.75.75 0 003 15h-.75M15 10.5a3 3 0 11-6 0 3 3 0 016 0zm3 0h.008v.008H18V10.5zm-12 0h.008v.008H6V10.5z" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const UsersIcon = () => (
|
||||||
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const ChatBubbleIcon = () => (
|
||||||
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M8.625 12a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H8.25m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H12m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0h-.375M21 12c0 4.556-4.03 8.25-9 8.25a9.764 9.764 0 01-2.555-.337A5.972 5.972 0 015.41 20.97a5.969 5.969 0 01-.474-.065 4.48 4.48 0 00.978-2.025c.09-.457-.133-.901-.467-1.226C3.93 16.178 3 14.189 3 12c0-4.556 4.03-8.25 9-8.25s9 3.694 9 8.25z" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const NoSymbolIcon = () => (
|
||||||
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const CreditCardIcon = () => (
|
||||||
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M2.25 8.25h19.5M2.25 9h19.5m-16.5 5.25h6m-6 2.25h3m-3.75 3h15a2.25 2.25 0 002.25-2.25V6.75A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25v10.5A2.25 2.25 0 004.5 19.5z" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const TicketIcon = () => (
|
||||||
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M16.5 6v.75m0 3v.75m0 3v.75m0 3V18m-9-5.25h5.25M7.5 15h3M3.375 5.25c-.621 0-1.125.504-1.125 1.125v3.026a2.999 2.999 0 010 5.198v3.026c0 .621.504 1.125 1.125 1.125h17.25c.621 0 1.125-.504 1.125-1.125v-3.026a2.999 2.999 0 010-5.198V6.375c0-.621-.504-1.125-1.125-1.125H3.375z" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M16.5 6v.75m0 3v.75m0 3v.75m0 3V18m-9-5.25h5.25M7.5 15h3M3.375 5.25c-.621 0-1.125.504-1.125 1.125v3.026a2.999 2.999 0 010 5.198v3.026c0 .621.504 1.125 1.125 1.125h17.25c.621 0 1.125-.504 1.125-1.125v-3.026a2.999 2.999 0 010-5.198V6.375c0-.621-.504-1.125-1.125-1.125H3.375z" />
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
const CogIcon = ({ className = "w-8 h-8" }: { className?: string }) => (
|
const GiftIcon = () => (
|
||||||
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M21 11.25v8.25a1.5 1.5 0 01-1.5 1.5H5.25a1.5 1.5 0 01-1.5-1.5v-8.25M12 4.875A2.625 2.625 0 109.375 7.5H12m0-2.625V7.5m0-2.625A2.625 2.625 0 1114.625 7.5H12m0 0V21m-8.625-9.75h18c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125h-18c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125z" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const MegaphoneIcon = () => (
|
||||||
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M10.34 15.84c-.688-.06-1.386-.09-2.09-.09H7.5a4.5 4.5 0 110-9h.75c.704 0 1.402-.03 2.09-.09m0 9.18c.253.962.584 1.892.985 2.783.247.55.06 1.21-.463 1.511l-.657.38c-.551.318-1.26.117-1.527-.461a20.845 20.845 0 01-1.44-4.282m3.102.069a18.03 18.03 0 01-.59-4.59c0-1.586.205-3.124.59-4.59m0 9.18a23.848 23.848 0 018.835 2.535M10.34 6.66a23.847 23.847 0 008.835-2.535m0 0A23.74 23.74 0 0018.795 3m.38 1.125a23.91 23.91 0 011.014 5.395m-1.014 8.855c-.118.38-.245.754-.38 1.125m.38-1.125a23.91 23.91 0 001.014-5.395m0-3.46c.495.413.811 1.035.811 1.73 0 .695-.316 1.317-.811 1.73m0-3.46a24.347 24.347 0 010 3.46" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const PaperAirplaneIcon = () => (
|
||||||
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M6 12L3.269 3.126A59.768 59.768 0 0121.485 12 59.77 59.77 0 013.27 20.876L5.999 12zm0 0h7.5" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const SparklesIcon = () => (
|
||||||
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09zM18.259 8.715L18 9.75l-.259-1.035a3.375 3.375 0 00-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 002.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 002.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 00-2.456 2.456zM16.894 20.567L16.5 21.75l-.394-1.183a2.25 2.25 0 00-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 001.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 001.423 1.423l1.183.394-1.183.394a2.25 2.25 0 00-1.423 1.423z" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
const CogIcon = () => (
|
||||||
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z" />
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
const PhoneIcon = ({ className = "w-8 h-8" }: { className?: string }) => (
|
const DevicePhoneMobileIcon = () => (
|
||||||
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M10.5 1.5H8.25A2.25 2.25 0 006 3.75v16.5a2.25 2.25 0 002.25 2.25h7.5A2.25 2.25 0 0018 20.25V3.75a2.25 2.25 0 00-2.25-2.25H13.5m-3 0V3h3V1.5m-3 0h3m-3 18.75h3" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M10.5 1.5H8.25A2.25 2.25 0 006 3.75v16.5a2.25 2.25 0 002.25 2.25h7.5A2.25 2.25 0 0018 20.25V3.75a2.25 2.25 0 00-2.25-2.25H13.5m-3 0V3h3V1.5m-3 0h3m-3 18.75h3" />
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
const WheelIcon = ({ className = "w-8 h-8" }: { className?: string }) => (
|
const ServerStackIcon = () => (
|
||||||
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 3v2.25m6.364.386l-1.591 1.591M21 12h-2.25m-.386 6.364l-1.591-1.591M12 18.75V21m-4.773-4.227l-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z" />
|
|
||||||
</svg>
|
|
||||||
)
|
|
||||||
|
|
||||||
const TariffIcon = ({ className = "w-8 h-8" }: { className?: string }) => (
|
|
||||||
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M2.25 8.25h19.5M2.25 9h19.5m-16.5 5.25h6m-6 2.25h3m-3.75 3h15a2.25 2.25 0 002.25-2.25V6.75A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25v10.5A2.25 2.25 0 004.5 19.5z" />
|
|
||||||
</svg>
|
|
||||||
)
|
|
||||||
|
|
||||||
const ServerIcon = ({ className = "w-8 h-8" }: { className?: string }) => (
|
|
||||||
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M5.25 14.25h13.5m-13.5 0a3 3 0 01-3-3m3 3a3 3 0 100 6h13.5a3 3 0 100-6m-16.5-3a3 3 0 013-3h13.5a3 3 0 013 3m-19.5 0a4.5 4.5 0 01.9-2.7L5.737 5.1a3.375 3.375 0 012.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 01.9 2.7m0 0a3 3 0 01-3 3m0 3h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008zm-3 6h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008z" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M5.25 14.25h13.5m-13.5 0a3 3 0 01-3-3m3 3a3 3 0 100 6h13.5a3 3 0 100-6m-16.5-3a3 3 0 013-3h13.5a3 3 0 013 3m-19.5 0a4.5 4.5 0 01.9-2.7L5.737 5.1a3.375 3.375 0 012.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 01.9 2.7m0 0a3 3 0 01-3 3m0 3h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008zm-3 6h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008z" />
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
const AdminIcon = ({ className = "w-8 h-8" }: { className?: string }) => (
|
const CubeTransparentIcon = () => (
|
||||||
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12.75L11.25 15 15 9.75m-3-7.036A11.959 11.959 0 013.598 6 11.99 11.99 0 003 9.749c0 5.592 3.824 10.29 9 11.623 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285z" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M21 7.5l-2.25-1.313M21 7.5v2.25m0-2.25l-2.25 1.313M3 7.5l2.25-1.313M3 7.5l2.25 1.313M3 7.5v2.25m9 3l2.25-1.313M12 12.75l-2.25-1.313M12 12.75V15m0 6.75l2.25-1.313M12 21.75V19.5m0 2.25l-2.25-1.313m0-16.875L12 2.25l2.25 1.313M21 14.25v2.25l-2.25 1.313m-13.5 0L3 16.5v-2.25" />
|
||||||
</svg>
|
|
||||||
)
|
|
||||||
|
|
||||||
const ChartIcon = ({ className = "w-8 h-8" }: { className?: string }) => (
|
|
||||||
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 013 19.875v-6.75zM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V8.625zM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V4.125z" />
|
|
||||||
</svg>
|
|
||||||
)
|
|
||||||
|
|
||||||
const BanSystemIcon = ({ className = "w-8 h-8" }: { className?: string }) => (
|
|
||||||
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636" />
|
|
||||||
</svg>
|
|
||||||
)
|
|
||||||
|
|
||||||
const BroadcastIcon = ({ className = "w-8 h-8" }: { className?: string }) => (
|
|
||||||
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M10.34 15.84c-.688-.06-1.386-.09-2.09-.09H7.5a4.5 4.5 0 110-9h.75c.704 0 1.402-.03 2.09-.09m0 9.18c.253.962.584 1.892.985 2.783.247.55.06 1.21-.463 1.511l-.657.38c-.551.318-1.26.117-1.527-.461a20.845 20.845 0 01-1.44-4.282m3.102.069a18.03 18.03 0 01-.59-4.59c0-1.586.205-3.124.59-4.59m0 9.18a23.848 23.848 0 018.835 2.535M10.34 6.66a23.847 23.847 0 008.835-2.535m0 0A23.74 23.74 0 0018.795 3m.38 1.125a23.91 23.91 0 011.014 5.395m-1.014 8.855c-.118.38-.245.754-.38 1.125m.38-1.125a23.91 23.91 0 001.014-5.395m0-3.46c.495.413.811 1.035.811 1.73 0 .695-.316 1.317-.811 1.73m0-3.46a24.347 24.347 0 010 3.46" />
|
|
||||||
</svg>
|
|
||||||
)
|
|
||||||
|
|
||||||
const PromocodeIcon = ({ className = "w-8 h-8" }: { className?: string }) => (
|
|
||||||
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M16.5 6v.75m0 3v.75m0 3v.75m0 3V18m-9-5.25h5.25M7.5 15h3M3.375 5.25c-.621 0-1.125.504-1.125 1.125v3.026a2.999 2.999 0 010 5.198v3.026c0 .621.504 1.125 1.125 1.125h17.25c.621 0 1.125-.504 1.125-1.125v-3.026a2.999 2.999 0 010-5.198V6.375c0-.621-.504-1.125-1.125-1.125H3.375z" />
|
|
||||||
</svg>
|
|
||||||
)
|
|
||||||
|
|
||||||
const CampaignIcon = ({ className = "w-8 h-8" }: { className?: string }) => (
|
|
||||||
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M3.75 3v11.25A2.25 2.25 0 006 16.5h2.25M3.75 3h-1.5m1.5 0h16.5m0 0h1.5m-1.5 0v11.25A2.25 2.25 0 0118 16.5h-2.25m-7.5 0h7.5m-7.5 0l-1 3m8.5-3l1 3m0 0l.5 1.5m-.5-1.5h-9.5m0 0l-.5 1.5M9 11.25v1.5M12 9v3.75m3-6v6" />
|
|
||||||
</svg>
|
|
||||||
)
|
|
||||||
|
|
||||||
const UsersIcon = ({ className = "w-8 h-8" }: { className?: string }) => (
|
|
||||||
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z" />
|
|
||||||
</svg>
|
|
||||||
)
|
|
||||||
|
|
||||||
const PaymentsIcon = ({ className = "w-8 h-8" }: { className?: string }) => (
|
|
||||||
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M2.25 18.75a60.07 60.07 0 0115.797 2.101c.727.198 1.453-.342 1.453-1.096V18.75M3.75 4.5v.75A.75.75 0 013 6h-.75m0 0v-.375c0-.621.504-1.125 1.125-1.125H20.25M2.25 6v9m18-10.5v.75c0 .414.336.75.75.75h.75m-1.5-1.5h.375c.621 0 1.125.504 1.125 1.125v9.75c0 .621-.504 1.125-1.125 1.125h-.375m1.5-1.5H21a.75.75 0 00-.75.75v.75m0 0H3.75m0 0h-.375a1.125 1.125 0 01-1.125-1.125V15m1.5 1.5v-.75A.75.75 0 003 15h-.75M15 10.5a3 3 0 11-6 0 3 3 0 016 0zm3 0h.008v.008H18V10.5zm-12 0h.008v.008H6V10.5z" />
|
|
||||||
</svg>
|
|
||||||
)
|
|
||||||
|
|
||||||
const PromoOffersIcon = ({ className = "w-8 h-8" }: { className?: string }) => (
|
|
||||||
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M21 11.25v8.25a1.5 1.5 0 01-1.5 1.5H5.25a1.5 1.5 0 01-1.5-1.5v-8.25M12 4.875A2.625 2.625 0 109.375 7.5H12m0-2.625V7.5m0-2.625A2.625 2.625 0 1114.625 7.5H12m0 0V21m-8.625-9.75h18c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125h-18c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125z" />
|
|
||||||
</svg>
|
|
||||||
)
|
|
||||||
|
|
||||||
const RemnawaveIcon = ({ className = "w-8 h-8" }: { className?: string }) => (
|
|
||||||
<svg className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M5.25 14.25h13.5m-13.5 0a3 3 0 01-3-3m3 3a3 3 0 100 6h13.5a3 3 0 100-6m-16.5-3a3 3 0 013-3h13.5a3 3 0 013 3m-19.5 0a4.5 4.5 0 01.9-2.7L5.737 5.1a3.375 3.375 0 012.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 01.9 2.7m0 0a3 3 0 01-3 3m0 3h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008zm-3 6h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008z" />
|
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
const ChevronRightIcon = () => (
|
const ChevronRightIcon = () => (
|
||||||
<svg className="w-4 h-4 text-dark-500 group-hover:text-dark-300 transition-colors" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
|
<path strokeLinecap="round" strokeLinejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
interface AdminSection {
|
interface AdminItem {
|
||||||
to: string
|
to: string
|
||||||
icon: React.ReactNode
|
icon: React.ReactNode
|
||||||
mobileIcon: React.ReactNode
|
|
||||||
title: string
|
title: string
|
||||||
description: string
|
description: string
|
||||||
color: string
|
|
||||||
bgColor: string
|
|
||||||
textColor: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mobile compact card
|
interface AdminGroup {
|
||||||
function MobileAdminCard({ to, mobileIcon, title, bgColor, textColor }: AdminSection) {
|
id: string
|
||||||
|
title: string
|
||||||
|
icon: string
|
||||||
|
gradient: string
|
||||||
|
borderColor: string
|
||||||
|
iconBg: string
|
||||||
|
iconColor: string
|
||||||
|
items: AdminItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
function AdminCard({ to, icon, title, description, iconBg, iconColor }: AdminItem & { iconBg: string; iconColor: string }) {
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
to={to}
|
to={to}
|
||||||
className="flex flex-col items-center justify-center p-3 bg-dark-800/80 rounded-2xl border border-dark-700/50 hover:border-dark-600 active:scale-95 transition-all duration-150"
|
className="group flex items-center gap-3 p-3 rounded-xl bg-dark-800/40 border border-dark-700/50 hover:bg-dark-800/80 hover:border-dark-600 transition-all duration-200"
|
||||||
>
|
>
|
||||||
<div className={`w-12 h-12 rounded-xl ${bgColor} flex items-center justify-center mb-2`}>
|
<div className={`w-10 h-10 rounded-lg ${iconBg} ${iconColor} flex items-center justify-center shrink-0 group-hover:scale-105 transition-transform`}>
|
||||||
<div className={textColor}>
|
{icon}
|
||||||
{mobileIcon}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<span className="text-xs font-medium text-dark-200 text-center leading-tight">{title}</span>
|
|
||||||
</Link>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Desktop card
|
|
||||||
function DesktopAdminCard({ to, icon, title, description, bgColor, textColor }: AdminSection) {
|
|
||||||
return (
|
|
||||||
<Link
|
|
||||||
to={to}
|
|
||||||
className="group flex items-center gap-4 p-4 bg-dark-800/80 rounded-2xl border border-dark-700/50 hover:border-dark-600 hover:bg-dark-800 transition-all duration-200"
|
|
||||||
>
|
|
||||||
<div className={`w-14 h-14 rounded-xl ${bgColor} flex items-center justify-center shrink-0 group-hover:scale-105 transition-transform`}>
|
|
||||||
<div className={textColor}>
|
|
||||||
{icon}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<h3 className="text-base font-semibold text-dark-100 mb-0.5">{title}</h3>
|
<h3 className="text-sm font-medium text-dark-100 group-hover:text-white transition-colors">{title}</h3>
|
||||||
<p className="text-sm text-dark-400 truncate">{description}</p>
|
<p className="text-xs text-dark-500 truncate">{description}</p>
|
||||||
|
</div>
|
||||||
|
<div className="text-dark-600 group-hover:text-dark-400 transition-colors">
|
||||||
|
<ChevronRightIcon />
|
||||||
</div>
|
</div>
|
||||||
<ChevronRightIcon />
|
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section group definition
|
function GroupSection({ group }: { group: AdminGroup }) {
|
||||||
interface SectionGroup {
|
|
||||||
title: string
|
|
||||||
emoji: string
|
|
||||||
sections: AdminSection[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function AdminPanel() {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
|
|
||||||
// Grouped admin sections
|
|
||||||
const sectionGroups: SectionGroup[] = [
|
|
||||||
{
|
|
||||||
title: 'Аналитика',
|
|
||||||
emoji: '📊',
|
|
||||||
sections: [
|
|
||||||
{
|
|
||||||
to: '/admin/dashboard',
|
|
||||||
icon: <ChartIcon />,
|
|
||||||
mobileIcon: <ChartIcon className="w-6 h-6" />,
|
|
||||||
title: t('admin.nav.dashboard'),
|
|
||||||
description: t('admin.panel.dashboardDesc'),
|
|
||||||
color: 'success',
|
|
||||||
bgColor: 'bg-emerald-500/20',
|
|
||||||
textColor: 'text-emerald-400'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: '/admin/payments',
|
|
||||||
icon: <PaymentsIcon />,
|
|
||||||
mobileIcon: <PaymentsIcon className="w-6 h-6" />,
|
|
||||||
title: t('admin.nav.payments', 'Платежи'),
|
|
||||||
description: t('admin.panel.paymentsDesc', 'Проверка платежей'),
|
|
||||||
color: 'lime',
|
|
||||||
bgColor: 'bg-lime-500/20',
|
|
||||||
textColor: 'text-lime-400'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Пользователи',
|
|
||||||
emoji: '👥',
|
|
||||||
sections: [
|
|
||||||
{
|
|
||||||
to: '/admin/users',
|
|
||||||
icon: <UsersIcon />,
|
|
||||||
mobileIcon: <UsersIcon className="w-6 h-6" />,
|
|
||||||
title: t('admin.nav.users', 'Пользователи'),
|
|
||||||
description: t('admin.panel.usersDesc', 'Управление пользователями'),
|
|
||||||
color: 'indigo',
|
|
||||||
bgColor: 'bg-indigo-500/20',
|
|
||||||
textColor: 'text-indigo-400'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: '/admin/tickets',
|
|
||||||
icon: <TicketIcon />,
|
|
||||||
mobileIcon: <TicketIcon className="w-6 h-6" />,
|
|
||||||
title: t('admin.nav.tickets'),
|
|
||||||
description: t('admin.panel.ticketsDesc'),
|
|
||||||
color: 'warning',
|
|
||||||
bgColor: 'bg-amber-500/20',
|
|
||||||
textColor: 'text-amber-400'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: '/admin/ban-system',
|
|
||||||
icon: <BanSystemIcon />,
|
|
||||||
mobileIcon: <BanSystemIcon className="w-6 h-6" />,
|
|
||||||
title: t('admin.nav.banSystem'),
|
|
||||||
description: t('admin.panel.banSystemDesc'),
|
|
||||||
color: 'error',
|
|
||||||
bgColor: 'bg-red-500/20',
|
|
||||||
textColor: 'text-red-400'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Тарифы и продажи',
|
|
||||||
emoji: '💰',
|
|
||||||
sections: [
|
|
||||||
{
|
|
||||||
to: '/admin/tariffs',
|
|
||||||
icon: <TariffIcon />,
|
|
||||||
mobileIcon: <TariffIcon className="w-6 h-6" />,
|
|
||||||
title: t('admin.nav.tariffs'),
|
|
||||||
description: t('admin.panel.tariffsDesc'),
|
|
||||||
color: 'info',
|
|
||||||
bgColor: 'bg-cyan-500/20',
|
|
||||||
textColor: 'text-cyan-400'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: '/admin/promocodes',
|
|
||||||
icon: <PromocodeIcon />,
|
|
||||||
mobileIcon: <PromocodeIcon className="w-6 h-6" />,
|
|
||||||
title: t('admin.nav.promocodes', 'Промокоды'),
|
|
||||||
description: t('admin.panel.promocodesDesc', 'Управление промокодами'),
|
|
||||||
color: 'violet',
|
|
||||||
bgColor: 'bg-violet-500/20',
|
|
||||||
textColor: 'text-violet-400'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: '/admin/promo-offers',
|
|
||||||
icon: <PromoOffersIcon />,
|
|
||||||
mobileIcon: <PromoOffersIcon className="w-6 h-6" />,
|
|
||||||
title: t('admin.nav.promoOffers', 'Промопредложения'),
|
|
||||||
description: t('admin.panel.promoOffersDesc', 'Персональные скидки и предложения'),
|
|
||||||
color: 'orange',
|
|
||||||
bgColor: 'bg-orange-500/20',
|
|
||||||
textColor: 'text-orange-400'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Маркетинг',
|
|
||||||
emoji: '📣',
|
|
||||||
sections: [
|
|
||||||
{
|
|
||||||
to: '/admin/campaigns',
|
|
||||||
icon: <CampaignIcon />,
|
|
||||||
mobileIcon: <CampaignIcon className="w-6 h-6" />,
|
|
||||||
title: t('admin.nav.campaigns', 'Кампании'),
|
|
||||||
description: t('admin.panel.campaignsDesc', 'Рекламные кампании'),
|
|
||||||
color: 'orange',
|
|
||||||
bgColor: 'bg-orange-500/20',
|
|
||||||
textColor: 'text-orange-400'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: '/admin/broadcasts',
|
|
||||||
icon: <BroadcastIcon />,
|
|
||||||
mobileIcon: <BroadcastIcon className="w-6 h-6" />,
|
|
||||||
title: t('admin.nav.broadcasts'),
|
|
||||||
description: t('admin.panel.broadcastsDesc'),
|
|
||||||
color: 'orange',
|
|
||||||
bgColor: 'bg-orange-500/20',
|
|
||||||
textColor: 'text-orange-400'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: '/admin/wheel',
|
|
||||||
icon: <WheelIcon />,
|
|
||||||
mobileIcon: <WheelIcon className="w-6 h-6" />,
|
|
||||||
title: t('admin.nav.wheel'),
|
|
||||||
description: t('admin.panel.wheelDesc'),
|
|
||||||
color: 'error',
|
|
||||||
bgColor: 'bg-rose-500/20',
|
|
||||||
textColor: 'text-rose-400'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Система',
|
|
||||||
emoji: '⚙️',
|
|
||||||
sections: [
|
|
||||||
{
|
|
||||||
to: '/admin/settings',
|
|
||||||
icon: <CogIcon />,
|
|
||||||
mobileIcon: <CogIcon className="w-6 h-6" />,
|
|
||||||
title: t('admin.nav.settings'),
|
|
||||||
description: t('admin.panel.settingsDesc'),
|
|
||||||
color: 'accent',
|
|
||||||
bgColor: 'bg-blue-500/20',
|
|
||||||
textColor: 'text-blue-400'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: '/admin/apps',
|
|
||||||
icon: <PhoneIcon />,
|
|
||||||
mobileIcon: <PhoneIcon className="w-6 h-6" />,
|
|
||||||
title: t('admin.nav.apps'),
|
|
||||||
description: t('admin.panel.appsDesc'),
|
|
||||||
color: 'success',
|
|
||||||
bgColor: 'bg-teal-500/20',
|
|
||||||
textColor: 'text-teal-400'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: '/admin/servers',
|
|
||||||
icon: <ServerIcon />,
|
|
||||||
mobileIcon: <ServerIcon className="w-6 h-6" />,
|
|
||||||
title: t('admin.nav.servers'),
|
|
||||||
description: t('admin.panel.serversDesc'),
|
|
||||||
color: 'purple',
|
|
||||||
bgColor: 'bg-purple-500/20',
|
|
||||||
textColor: 'text-purple-400'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: '/admin/remnawave',
|
|
||||||
icon: <RemnawaveIcon />,
|
|
||||||
mobileIcon: <RemnawaveIcon className="w-6 h-6" />,
|
|
||||||
title: t('admin.nav.remnawave', 'RemnaWave'),
|
|
||||||
description: t('admin.panel.remnawaveDesc', 'Управление панелью и статистика'),
|
|
||||||
color: 'purple',
|
|
||||||
bgColor: 'bg-purple-500/20',
|
|
||||||
textColor: 'text-purple-400'
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
// Flatten all sections for mobile view
|
|
||||||
const allSections = sectionGroups.flatMap(group => group.sections)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="animate-fade-in">
|
<div className="rounded-2xl border border-dark-700/50 overflow-hidden bg-dark-900/30 backdrop-blur">
|
||||||
{/* Header - compact on mobile */}
|
{/* Group Header */}
|
||||||
<div className="flex items-center gap-3 mb-6">
|
<div className={`px-4 py-3 bg-gradient-to-r ${group.gradient} border-b ${group.borderColor}`}>
|
||||||
<div className="p-2.5 sm:p-3 bg-amber-500/20 rounded-xl">
|
<div className="flex items-center gap-2.5">
|
||||||
<AdminIcon className="w-6 h-6 sm:w-8 sm:h-8 text-amber-400" />
|
<span className="text-lg">{group.icon}</span>
|
||||||
</div>
|
<h2 className="text-sm font-semibold text-dark-100">{group.title}</h2>
|
||||||
<div>
|
|
||||||
<h1 className="text-xl sm:text-2xl font-bold text-dark-100">{t('admin.panel.title')}</h1>
|
|
||||||
<p className="text-sm text-dark-400 hidden sm:block">{t('admin.panel.subtitle')}</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Mobile: Compact grid (all sections) */}
|
{/* Group Items */}
|
||||||
<div className="grid grid-cols-3 gap-3 sm:hidden">
|
<div className="p-2 space-y-1.5">
|
||||||
{allSections.map((section) => (
|
{group.items.map((item) => (
|
||||||
<MobileAdminCard key={section.to} {...section} />
|
<AdminCard
|
||||||
))}
|
key={item.to}
|
||||||
</div>
|
{...item}
|
||||||
|
iconBg={group.iconBg}
|
||||||
{/* Tablet/Desktop: Grouped sections */}
|
iconColor={group.iconColor}
|
||||||
<div className="hidden sm:block space-y-6">
|
/>
|
||||||
{sectionGroups.map((group) => (
|
))}
|
||||||
<div key={group.title}>
|
</div>
|
||||||
{/* Group header */}
|
</div>
|
||||||
<div className="flex items-center gap-2 mb-3">
|
)
|
||||||
<span className="text-xl">{group.emoji}</span>
|
}
|
||||||
<h2 className="text-sm font-semibold text-dark-400 uppercase tracking-wider">{group.title}</h2>
|
|
||||||
</div>
|
export default function AdminPanel() {
|
||||||
|
const { t } = useTranslation()
|
||||||
{/* Group cards */}
|
|
||||||
<div className="grid sm:grid-cols-1 lg:grid-cols-2 gap-3">
|
const groups: AdminGroup[] = [
|
||||||
{group.sections.map((section) => (
|
{
|
||||||
<DesktopAdminCard key={section.to} {...section} />
|
id: 'analytics',
|
||||||
))}
|
title: t('admin.groups.analytics', 'Аналитика'),
|
||||||
</div>
|
icon: '📊',
|
||||||
</div>
|
gradient: 'from-emerald-500/10 to-emerald-500/5',
|
||||||
|
borderColor: 'border-emerald-500/20',
|
||||||
|
iconBg: 'bg-emerald-500/20',
|
||||||
|
iconColor: 'text-emerald-400',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
to: '/admin/dashboard',
|
||||||
|
icon: <ChartBarIcon />,
|
||||||
|
title: t('admin.nav.dashboard'),
|
||||||
|
description: t('admin.panel.dashboardDesc'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/admin/payments',
|
||||||
|
icon: <BanknotesIcon />,
|
||||||
|
title: t('admin.nav.payments', 'Платежи'),
|
||||||
|
description: t('admin.panel.paymentsDesc', 'История и проверка платежей'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'users',
|
||||||
|
title: t('admin.groups.users', 'Пользователи'),
|
||||||
|
icon: '👥',
|
||||||
|
gradient: 'from-blue-500/10 to-blue-500/5',
|
||||||
|
borderColor: 'border-blue-500/20',
|
||||||
|
iconBg: 'bg-blue-500/20',
|
||||||
|
iconColor: 'text-blue-400',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
to: '/admin/users',
|
||||||
|
icon: <UsersIcon />,
|
||||||
|
title: t('admin.nav.users', 'Пользователи'),
|
||||||
|
description: t('admin.panel.usersDesc', 'Управление пользователями'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/admin/tickets',
|
||||||
|
icon: <ChatBubbleIcon />,
|
||||||
|
title: t('admin.nav.tickets'),
|
||||||
|
description: t('admin.panel.ticketsDesc'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/admin/ban-system',
|
||||||
|
icon: <NoSymbolIcon />,
|
||||||
|
title: t('admin.nav.banSystem'),
|
||||||
|
description: t('admin.panel.banSystemDesc'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tariffs',
|
||||||
|
title: t('admin.groups.tariffs', 'Тарифы и продажи'),
|
||||||
|
icon: '💰',
|
||||||
|
gradient: 'from-amber-500/10 to-amber-500/5',
|
||||||
|
borderColor: 'border-amber-500/20',
|
||||||
|
iconBg: 'bg-amber-500/20',
|
||||||
|
iconColor: 'text-amber-400',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
to: '/admin/tariffs',
|
||||||
|
icon: <CreditCardIcon />,
|
||||||
|
title: t('admin.nav.tariffs'),
|
||||||
|
description: t('admin.panel.tariffsDesc'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/admin/promocodes',
|
||||||
|
icon: <TicketIcon />,
|
||||||
|
title: t('admin.nav.promocodes', 'Промокоды'),
|
||||||
|
description: t('admin.panel.promocodesDesc', 'Управление промокодами'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/admin/promo-offers',
|
||||||
|
icon: <GiftIcon />,
|
||||||
|
title: t('admin.nav.promoOffers', 'Промопредложения'),
|
||||||
|
description: t('admin.panel.promoOffersDesc', 'Персональные скидки'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'marketing',
|
||||||
|
title: t('admin.groups.marketing', 'Маркетинг'),
|
||||||
|
icon: '📣',
|
||||||
|
gradient: 'from-rose-500/10 to-rose-500/5',
|
||||||
|
borderColor: 'border-rose-500/20',
|
||||||
|
iconBg: 'bg-rose-500/20',
|
||||||
|
iconColor: 'text-rose-400',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
to: '/admin/campaigns',
|
||||||
|
icon: <MegaphoneIcon />,
|
||||||
|
title: t('admin.nav.campaigns', 'Кампании'),
|
||||||
|
description: t('admin.panel.campaignsDesc', 'Рекламные кампании'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/admin/broadcasts',
|
||||||
|
icon: <PaperAirplaneIcon />,
|
||||||
|
title: t('admin.nav.broadcasts'),
|
||||||
|
description: t('admin.panel.broadcastsDesc'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/admin/wheel',
|
||||||
|
icon: <SparklesIcon />,
|
||||||
|
title: t('admin.nav.wheel'),
|
||||||
|
description: t('admin.panel.wheelDesc'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'system',
|
||||||
|
title: t('admin.groups.system', 'Система'),
|
||||||
|
icon: '⚙️',
|
||||||
|
gradient: 'from-violet-500/10 to-violet-500/5',
|
||||||
|
borderColor: 'border-violet-500/20',
|
||||||
|
iconBg: 'bg-violet-500/20',
|
||||||
|
iconColor: 'text-violet-400',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
to: '/admin/settings',
|
||||||
|
icon: <CogIcon />,
|
||||||
|
title: t('admin.nav.settings'),
|
||||||
|
description: t('admin.panel.settingsDesc'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/admin/apps',
|
||||||
|
icon: <DevicePhoneMobileIcon />,
|
||||||
|
title: t('admin.nav.apps'),
|
||||||
|
description: t('admin.panel.appsDesc'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/admin/servers',
|
||||||
|
icon: <ServerStackIcon />,
|
||||||
|
title: t('admin.nav.servers'),
|
||||||
|
description: t('admin.panel.serversDesc'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/admin/remnawave',
|
||||||
|
icon: <CubeTransparentIcon />,
|
||||||
|
title: t('admin.nav.remnawave', 'RemnaWave'),
|
||||||
|
description: t('admin.panel.remnawaveDesc', 'Управление панелью'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="animate-fade-in space-y-4">
|
||||||
|
{/* Header */}
|
||||||
|
<div className="mb-6">
|
||||||
|
<h1 className="text-2xl font-bold text-dark-100">{t('admin.panel.title')}</h1>
|
||||||
|
<p className="text-sm text-dark-400 mt-1">{t('admin.panel.subtitle')}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Groups Grid */}
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||||
|
{groups.map((group) => (
|
||||||
|
<GroupSection key={group.id} group={group} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user