mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-29 18:13:47 +00:00
fix(theme): readable text on any operator palette + admin consistency pass
Контраст-аудит (WCAG-обход всех текстовых узлов, 4 палитры × юзер+админ страницы) показал системные провалы читаемости: вторичный текст 1.5-2.5 на светлой/кастомных темах, статусные цвета 1.3-1.6, белый текст на светлых акцентах 1.9. Корневые фиксы: - useThemeColors: контраст-кламп производных серых токенов — dark-400/ champagne-600 (вторичный текст) держат >=5.0 к поверхности, dark-500/ champagne-500 (подсказки) >=3.8; палитры с достаточным контрастом рендерятся байт-в-байт как раньше - --color-on-accent/-success/-warning/-error: чёрный или белый текст по фактической яркости цвета оператора; text-white на accent-заливках заменён на text-on-accent (135 мест + variant примитива Button + .btn-primary) - .light: статусные текстовые оттенки *-300/400 ремапятся на тёмные *-700 (жёлтая «Админка» 1.26 -> 3.8+, зелёные суммы 1.4 -> 3.4+, бейджи состояний) Замер после: операторская тёмная палитра — 0 нарушений (всё >=4.5), худшие точки остальных подняты с 1.26-1.6 до 3.2+. Консистентность: - заголовки админ-страниц приведены к text-xl font-bold text-dark-100 (были 18/20/24/30px и 600/700 вперемешку) - «Создать FAQ»: warning-500/80+белый -> warning-500+text-on-warning - formatTraffic: единицы из i18n (убран микс «GB»/«ГБ» на одном экране) - categoryCanvas -> categoryCANVAS в локалях (битый ключ на настройках) - «Управление сквадами» -> «Управление локациями» (юзерский экран) - мин-макс сумм на выборе метода: dark-600 -> dark-400 - неактивные пункты нижнего нава: dark-500 -> dark-400
This commit is contained in:
@@ -545,7 +545,7 @@ export default function AdminAuditLog() {
|
||||
handleExport();
|
||||
}}
|
||||
disabled={exporting}
|
||||
className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
>
|
||||
<DownloadIcon />
|
||||
<span className="hidden sm:inline">
|
||||
@@ -614,7 +614,7 @@ export default function AdminAuditLog() {
|
||||
<span
|
||||
className={`flex h-4 w-4 items-center justify-center rounded border text-xs ${
|
||||
isSelected
|
||||
? 'border-accent-500 bg-accent-500 text-white'
|
||||
? 'border-accent-500 bg-accent-500 text-on-accent'
|
||||
: 'border-dark-500 bg-dark-800'
|
||||
}`}
|
||||
>
|
||||
@@ -734,7 +734,7 @@ export default function AdminAuditLog() {
|
||||
<div className="mt-4 flex items-center gap-3">
|
||||
<button
|
||||
onClick={handleApplyFilters}
|
||||
className="rounded-lg bg-accent-500 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-accent-600"
|
||||
className="rounded-lg bg-accent-500 px-4 py-2 text-sm font-medium text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
{t('admin.auditLog.filters.apply')}
|
||||
</button>
|
||||
|
||||
@@ -702,7 +702,7 @@ export default function AdminBroadcastCreate() {
|
||||
onClick={() => toggleButton(button.key)}
|
||||
className={`rounded-lg px-3 py-2 text-sm transition-colors ${
|
||||
selectedButtons.includes(button.key)
|
||||
? 'bg-accent-500 text-white'
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'border border-dark-700 bg-dark-800 text-dark-300 hover:bg-dark-700'
|
||||
}`}
|
||||
>
|
||||
@@ -770,7 +770,7 @@ export default function AdminBroadcastCreate() {
|
||||
onClick={() => setNewButtonActionType('callback')}
|
||||
className={`flex-1 rounded-lg px-3 py-2 text-sm transition-colors ${
|
||||
newButtonActionType === 'callback'
|
||||
? 'bg-accent-500 text-white'
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'border border-dark-700 bg-dark-800 text-dark-300 hover:bg-dark-700'
|
||||
}`}
|
||||
>
|
||||
@@ -781,7 +781,7 @@ export default function AdminBroadcastCreate() {
|
||||
onClick={() => setNewButtonActionType('url')}
|
||||
className={`flex-1 rounded-lg px-3 py-2 text-sm transition-colors ${
|
||||
newButtonActionType === 'url'
|
||||
? 'bg-accent-500 text-white'
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'border border-dark-700 bg-dark-800 text-dark-300 hover:bg-dark-700'
|
||||
}`}
|
||||
>
|
||||
|
||||
@@ -155,7 +155,7 @@ export default function AdminBroadcastDetail() {
|
||||
<p className="text-dark-400">{t('admin.broadcasts.notFound')}</p>
|
||||
<button
|
||||
onClick={() => navigate('/admin/broadcasts')}
|
||||
className="rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600"
|
||||
className="rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
{t('common.back')}
|
||||
</button>
|
||||
|
||||
@@ -117,7 +117,7 @@ export default function AdminBroadcasts() {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => navigate('/admin/broadcasts/create')}
|
||||
className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600"
|
||||
className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
<PlusIcon />
|
||||
<span className="hidden sm:inline">{t('admin.broadcasts.create')}</span>
|
||||
|
||||
@@ -79,7 +79,9 @@ function ServerSelector({
|
||||
>
|
||||
<div
|
||||
className={`flex h-5 w-5 items-center justify-center rounded ${
|
||||
selected.includes(server.squad_uuid) ? 'bg-accent-500 text-white' : 'bg-dark-600'
|
||||
selected.includes(server.squad_uuid)
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-600'
|
||||
}`}
|
||||
>
|
||||
{selected.includes(server.squad_uuid) && <CheckIcon />}
|
||||
|
||||
@@ -79,7 +79,9 @@ function ServerSelector({
|
||||
>
|
||||
<div
|
||||
className={`flex h-5 w-5 items-center justify-center rounded ${
|
||||
selected.includes(server.squad_uuid) ? 'bg-accent-500 text-white' : 'bg-dark-600'
|
||||
selected.includes(server.squad_uuid)
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-600'
|
||||
}`}
|
||||
>
|
||||
{selected.includes(server.squad_uuid) && <CheckIcon />}
|
||||
|
||||
@@ -136,7 +136,7 @@ export default function AdminCampaigns() {
|
||||
</div>
|
||||
<button
|
||||
onClick={() => navigate('/admin/campaigns/create')}
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600"
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
<PlusIcon />
|
||||
{t('admin.campaigns.createButton')}
|
||||
|
||||
@@ -424,7 +424,7 @@ function AddChannelForm({
|
||||
<button
|
||||
onClick={handleSubmit}
|
||||
disabled={!channelId.trim() || isLoading}
|
||||
className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-sm text-white transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-sm text-on-accent transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
<CheckIcon />
|
||||
{t('admin.channelSubscriptions.form.submit')}
|
||||
@@ -499,7 +499,7 @@ function EditChannelForm({
|
||||
<button
|
||||
onClick={handleSubmit}
|
||||
disabled={isLoading}
|
||||
className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-sm text-white transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-sm text-on-accent transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
<CheckIcon />
|
||||
{t('admin.channelSubscriptions.form.save')}
|
||||
@@ -641,7 +641,7 @@ export default function AdminChannelSubscriptions() {
|
||||
<button
|
||||
onClick={() => setShowAddForm(true)}
|
||||
aria-label={t('admin.channelSubscriptions.addChannel')}
|
||||
className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600"
|
||||
className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
<PlusIcon />
|
||||
<span className="hidden sm:inline">{t('admin.channelSubscriptions.addChannel')}</span>
|
||||
|
||||
@@ -442,7 +442,7 @@ function TemplateEditor({
|
||||
<button
|
||||
onClick={() => saveMutation.mutate()}
|
||||
disabled={!isDirty || saveMutation.isPending}
|
||||
className="inline-flex items-center justify-center gap-1.5 rounded-lg bg-accent-500 px-3 py-2.5 text-sm font-medium text-white transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-40 sm:px-4 sm:py-2"
|
||||
className="inline-flex items-center justify-center gap-1.5 rounded-lg bg-accent-500 px-3 py-2.5 text-sm font-medium text-on-accent transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-40 sm:px-4 sm:py-2"
|
||||
>
|
||||
<SaveIcon className="h-4 w-4" />
|
||||
{saveMutation.isPending ? t('common.loading') : t('common.save')}
|
||||
|
||||
@@ -1027,7 +1027,7 @@ export default function AdminInfoPageEditor() {
|
||||
<button
|
||||
onClick={handleSave}
|
||||
disabled={saveMutation.isPending || !slug.trim()}
|
||||
className="min-h-[44px] rounded-lg bg-accent-500 px-6 py-2.5 text-sm font-medium text-white transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
className="min-h-[44px] rounded-lg bg-accent-500 px-6 py-2.5 text-sm font-medium text-on-accent transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
{saveMutation.isPending ? t('admin.infoPages.saving') : t('admin.infoPages.save')}
|
||||
</button>
|
||||
@@ -1108,7 +1108,7 @@ export default function AdminInfoPageEditor() {
|
||||
className={cn(
|
||||
'min-h-[44px] rounded-lg px-4 py-2.5 text-sm font-medium transition-colors',
|
||||
displayMode === mode
|
||||
? 'bg-accent-500 text-white'
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-700 text-dark-300 hover:bg-dark-600 hover:text-dark-100',
|
||||
)}
|
||||
>
|
||||
@@ -1136,7 +1136,7 @@ export default function AdminInfoPageEditor() {
|
||||
pageType === pt
|
||||
? pt === 'faq'
|
||||
? 'bg-warning-500 text-white'
|
||||
: 'bg-accent-500 text-white'
|
||||
: 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-700 text-dark-300 hover:bg-dark-600 hover:text-dark-100',
|
||||
)}
|
||||
>
|
||||
@@ -1194,7 +1194,7 @@ export default function AdminInfoPageEditor() {
|
||||
className={cn(
|
||||
'min-h-[44px] rounded-lg px-4 py-2.5 text-sm font-medium transition-colors',
|
||||
activeLocale === loc
|
||||
? 'bg-accent-500 text-white'
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-700 text-dark-300 hover:bg-dark-600 hover:text-dark-100',
|
||||
)}
|
||||
>
|
||||
@@ -1415,7 +1415,7 @@ export default function AdminInfoPageEditor() {
|
||||
<button
|
||||
onClick={handleSave}
|
||||
disabled={saveMutation.isPending || !slug.trim()}
|
||||
className="min-h-[44px] w-full rounded-lg bg-accent-500 py-3 text-sm font-medium text-white transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
className="min-h-[44px] w-full rounded-lg bg-accent-500 py-3 text-sm font-medium text-on-accent transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
{saveMutation.isPending ? t('admin.infoPages.saving') : t('admin.infoPages.save')}
|
||||
</button>
|
||||
|
||||
@@ -238,7 +238,7 @@ export default function AdminInfoPages() {
|
||||
haptic.buttonPress();
|
||||
navigate('/admin/info-pages/create?type=faq');
|
||||
}}
|
||||
className="flex min-h-[44px] items-center gap-2 rounded-lg bg-warning-500/80 px-4 py-2.5 text-white transition-colors hover:bg-warning-500"
|
||||
className="flex min-h-[44px] items-center gap-2 rounded-lg bg-warning-500 px-4 py-2.5 text-on-warning transition-colors hover:bg-warning-400"
|
||||
aria-label={t('admin.infoPages.createFaq')}
|
||||
>
|
||||
<PlusIcon />
|
||||
@@ -249,7 +249,7 @@ export default function AdminInfoPages() {
|
||||
haptic.buttonPress();
|
||||
navigate('/admin/info-pages/create');
|
||||
}}
|
||||
className="flex min-h-[44px] items-center gap-2 rounded-lg bg-accent-500 px-4 py-2.5 text-white transition-colors hover:bg-accent-600"
|
||||
className="flex min-h-[44px] items-center gap-2 rounded-lg bg-accent-500 px-4 py-2.5 text-on-accent transition-colors hover:bg-accent-600"
|
||||
aria-label={t('admin.infoPages.create')}
|
||||
>
|
||||
<PlusIcon />
|
||||
@@ -268,7 +268,7 @@ export default function AdminInfoPages() {
|
||||
className={cn(
|
||||
'min-h-[44px] rounded-lg px-4 py-2.5 text-sm font-medium transition-colors',
|
||||
activeFilter === tab
|
||||
? 'bg-accent-500 text-white'
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-700 text-dark-300 hover:bg-dark-600 hover:text-dark-100',
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -588,7 +588,7 @@ export default function AdminLandingEditor() {
|
||||
<button
|
||||
onClick={handleSubmit}
|
||||
disabled={isPending || !slug || !Object.values(title).some((v) => v.trim())}
|
||||
className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-sm text-white transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-sm text-on-accent transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
>
|
||||
{isPending && (
|
||||
<div className="h-4 w-4 animate-spin rounded-full border-2 border-white/30 border-t-white" />
|
||||
|
||||
@@ -423,7 +423,7 @@ export default function AdminLandings() {
|
||||
)}
|
||||
<button
|
||||
onClick={() => navigate('/admin/landings/create')}
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600"
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
<PlusIcon />
|
||||
{t('admin.landings.create')}
|
||||
|
||||
@@ -49,7 +49,7 @@ function DisplayModeSelector({
|
||||
className={cn(
|
||||
'min-h-[44px] rounded-lg px-4 py-2.5 text-sm font-medium transition-colors',
|
||||
value === mode
|
||||
? 'bg-accent-500 text-white'
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-700 text-dark-300 hover:bg-dark-600 hover:text-dark-100',
|
||||
disabled && 'cursor-not-allowed opacity-50',
|
||||
)}
|
||||
@@ -87,7 +87,7 @@ function LanguageTabs({
|
||||
className={cn(
|
||||
'min-h-[44px] rounded-lg px-4 py-2.5 text-sm font-medium uppercase transition-colors',
|
||||
active === lang
|
||||
? 'bg-accent-500 text-white'
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-700 text-dark-300 hover:bg-dark-600 hover:text-dark-100',
|
||||
)}
|
||||
>
|
||||
@@ -221,7 +221,7 @@ function DocumentEditor({
|
||||
<button
|
||||
onClick={() => saveMutation.mutate()}
|
||||
disabled={saveMutation.isPending}
|
||||
className="min-h-[44px] rounded-lg bg-accent-500 px-6 py-2.5 text-sm font-medium text-white transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
className="min-h-[44px] rounded-lg bg-accent-500 px-6 py-2.5 text-sm font-medium text-on-accent transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
>
|
||||
{saveMutation.isPending ? t('admin.legalPages.saving') : t('admin.legalPages.save')}
|
||||
</button>
|
||||
@@ -321,7 +321,7 @@ function RulesEditor({ onDirtyChange }: { onDirtyChange: (dirty: boolean) => voi
|
||||
<button
|
||||
onClick={() => saveMutation.mutate()}
|
||||
disabled={saveMutation.isPending}
|
||||
className="min-h-[44px] rounded-lg bg-accent-500 px-6 py-2.5 text-sm font-medium text-white transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
className="min-h-[44px] rounded-lg bg-accent-500 px-6 py-2.5 text-sm font-medium text-on-accent transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
>
|
||||
{saveMutation.isPending ? t('admin.legalPages.saving') : t('admin.legalPages.save')}
|
||||
</button>
|
||||
@@ -604,7 +604,7 @@ function FaqEditor({ onDirtyChange }: { onDirtyChange: (dirty: boolean) => void
|
||||
<button
|
||||
onClick={() => createMutation.mutate()}
|
||||
disabled={createMutation.isPending}
|
||||
className="flex min-h-[44px] items-center gap-2 rounded-lg bg-accent-500 px-4 py-2.5 text-sm font-medium text-white transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
className="flex min-h-[44px] items-center gap-2 rounded-lg bg-accent-500 px-4 py-2.5 text-sm font-medium text-on-accent transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
>
|
||||
<PlusIcon />
|
||||
<span className="hidden sm:inline">{t('admin.legalPages.addQuestion')}</span>
|
||||
@@ -669,7 +669,7 @@ export default function AdminLegalPages() {
|
||||
className={cn(
|
||||
'min-h-[44px] rounded-lg px-4 py-2.5 text-sm font-medium transition-colors',
|
||||
activeTab === tab
|
||||
? 'bg-accent-500 text-white'
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-700 text-dark-300 hover:bg-dark-600 hover:text-dark-100',
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -273,7 +273,7 @@ export default function AdminNews() {
|
||||
haptic.buttonPress();
|
||||
navigate('/admin/news/create');
|
||||
}}
|
||||
className="flex min-h-[44px] items-center gap-2 rounded-lg bg-accent-500 px-4 py-2.5 text-white transition-colors hover:bg-accent-600"
|
||||
className="flex min-h-[44px] items-center gap-2 rounded-lg bg-accent-500 px-4 py-2.5 text-on-accent transition-colors hover:bg-accent-600"
|
||||
aria-label={t('news.admin.create')}
|
||||
>
|
||||
<PlusIcon />
|
||||
|
||||
@@ -558,7 +558,7 @@ export default function AdminNewsCreate() {
|
||||
<button
|
||||
onClick={handleSave}
|
||||
disabled={saveMutation.isPending || !title.trim() || !slug.trim() || !selectedCategory}
|
||||
className="min-h-[44px] rounded-lg bg-accent-500 px-6 py-2.5 text-sm font-medium text-white transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
className="min-h-[44px] rounded-lg bg-accent-500 px-6 py-2.5 text-sm font-medium text-on-accent transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
{saveMutation.isPending ? t('news.admin.saving') : t('news.admin.save')}
|
||||
</button>
|
||||
@@ -912,7 +912,7 @@ export default function AdminNewsCreate() {
|
||||
<button
|
||||
onClick={handleSave}
|
||||
disabled={saveMutation.isPending || !title.trim() || !slug.trim() || !selectedCategory}
|
||||
className="min-h-[44px] w-full rounded-lg bg-accent-500 py-3 text-sm font-medium text-white transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
className="min-h-[44px] w-full rounded-lg bg-accent-500 py-3 text-sm font-medium text-on-accent transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
{saveMutation.isPending ? t('news.admin.saving') : t('news.admin.save')}
|
||||
</button>
|
||||
|
||||
@@ -68,7 +68,7 @@ export default function AdminPartnerCampaignAssign() {
|
||||
</div>
|
||||
<button
|
||||
onClick={() => navigate(`/admin/campaigns/create?partnerId=${userId}`)}
|
||||
className="mt-2 w-full rounded-lg bg-accent-500 px-4 py-3 font-medium text-white transition-colors hover:bg-accent-600"
|
||||
className="mt-2 w-full rounded-lg bg-accent-500 px-4 py-3 font-medium text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
{t('admin.partnerDetail.campaigns.createNew')}
|
||||
</button>
|
||||
|
||||
@@ -90,7 +90,7 @@ export default function AdminPartnerCommission() {
|
||||
Number(commissionValue) < 1 ||
|
||||
Number(commissionValue) > 100
|
||||
}
|
||||
className="flex-1 rounded-lg bg-accent-500 px-4 py-3 font-medium text-white transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
className="flex-1 rounded-lg bg-accent-500 px-4 py-3 font-medium text-on-accent transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
>
|
||||
{updateMutation.isPending ? t('common.saving') : t('common.save')}
|
||||
</button>
|
||||
|
||||
@@ -301,7 +301,9 @@ export default function AdminPaymentMethodEdit() {
|
||||
<span className="text-sm">{opt.name}</span>
|
||||
<div
|
||||
className={`flex h-5 w-5 items-center justify-center rounded ${
|
||||
enabled ? 'bg-accent-500 text-white' : 'border border-dark-600 bg-dark-700'
|
||||
enabled
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'border border-dark-600 bg-dark-700'
|
||||
}`}
|
||||
>
|
||||
{enabled && <CheckIcon />}
|
||||
@@ -493,7 +495,7 @@ export default function AdminPaymentMethodEdit() {
|
||||
<span>{group.name}</span>
|
||||
<div
|
||||
className={`flex h-4 w-4 items-center justify-center rounded ${
|
||||
selected ? 'bg-accent-500 text-white' : 'border border-dark-600'
|
||||
selected ? 'bg-accent-500 text-on-accent' : 'border border-dark-600'
|
||||
}`}
|
||||
>
|
||||
{selected && <CheckIcon />}
|
||||
|
||||
@@ -218,7 +218,7 @@ export default function AdminPaymentMethods() {
|
||||
</button>
|
||||
)}
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-dark-50">{t('admin.paymentMethods.title')}</h1>
|
||||
<h1 className="text-xl font-bold text-dark-100">{t('admin.paymentMethods.title')}</h1>
|
||||
<p className="text-sm text-dark-400">{t('admin.paymentMethods.description')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -184,7 +184,7 @@ export default function AdminPayments() {
|
||||
</button>
|
||||
)}
|
||||
<div>
|
||||
<h1 className="text-xl font-semibold text-dark-100">{t('admin.payments.title')}</h1>
|
||||
<h1 className="text-xl font-bold text-dark-100">{t('admin.payments.title')}</h1>
|
||||
<p className="text-sm text-dark-400">{t('admin.payments.description')}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -239,7 +239,7 @@ export default function AdminPayments() {
|
||||
onClick={() => setStatusFilter(option.value)}
|
||||
className={`rounded-lg px-3 py-1.5 text-sm transition-all ${
|
||||
statusFilter === option.value
|
||||
? 'bg-accent-500 text-white'
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-800 text-dark-300 hover:bg-dark-700'
|
||||
}`}
|
||||
>
|
||||
@@ -256,7 +256,7 @@ export default function AdminPayments() {
|
||||
onClick={() => handlePeriodChange(option.value)}
|
||||
className={`rounded-lg px-3 py-1.5 text-sm transition-all ${
|
||||
periodFilter === option.value
|
||||
? 'bg-accent-500 text-white'
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-800 text-dark-300 hover:bg-dark-700'
|
||||
}`}
|
||||
>
|
||||
@@ -267,7 +267,7 @@ export default function AdminPayments() {
|
||||
onClick={() => handlePeriodChange('custom')}
|
||||
className={`flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm transition-all ${
|
||||
periodFilter === 'custom'
|
||||
? 'bg-accent-500 text-white'
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-800 text-dark-300 hover:bg-dark-700'
|
||||
}`}
|
||||
>
|
||||
|
||||
@@ -269,7 +269,7 @@ export default function AdminPinnedMessages() {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => navigate('/admin/pinned-messages/create')}
|
||||
className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600"
|
||||
className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
<PlusIcon />
|
||||
<span className="hidden sm:inline">{t('admin.pinnedMessages.create')}</span>
|
||||
|
||||
@@ -228,7 +228,7 @@ export default function AdminPolicies() {
|
||||
<PermissionGate permission="roles:create">
|
||||
<button
|
||||
onClick={() => navigate('/admin/policies/create')}
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600"
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
<PlusIcon />
|
||||
{t('admin.policies.createPolicy')}
|
||||
|
||||
@@ -757,7 +757,7 @@ export default function AdminPolicyEdit() {
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSaving}
|
||||
className="rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
className="rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
>
|
||||
{isSaving ? t('admin.policies.form.saving') : t('admin.policies.form.save')}
|
||||
</button>
|
||||
|
||||
@@ -65,7 +65,7 @@ export default function AdminPromoGroups() {
|
||||
</div>
|
||||
<button
|
||||
onClick={() => navigate('/admin/promo-groups/create')}
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600"
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
<PlusIcon />
|
||||
{t('admin.promoGroups.addGroup')}
|
||||
|
||||
@@ -199,7 +199,7 @@ export default function AdminPromoOfferSend() {
|
||||
<div className="flex justify-center gap-3">
|
||||
<button
|
||||
onClick={() => navigate('/admin/promo-offers')}
|
||||
className="rounded-lg bg-accent-500 px-6 py-2 text-white transition-colors hover:bg-accent-600"
|
||||
className="rounded-lg bg-accent-500 px-6 py-2 text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
{t('admin.promoOffers.backToList')}
|
||||
</button>
|
||||
@@ -441,7 +441,7 @@ export default function AdminPromoOfferSend() {
|
||||
{selectedTemplate.message_text}
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<span className="inline-block rounded-lg bg-accent-500 px-4 py-2 text-sm text-white">
|
||||
<span className="inline-block rounded-lg bg-accent-500 px-4 py-2 text-sm text-on-accent">
|
||||
{selectedTemplate.button_text}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -93,7 +93,7 @@ export default function AdminPromoOffers() {
|
||||
</div>
|
||||
<button
|
||||
onClick={() => navigate('/admin/promo-offers/send')}
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600"
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
<SendIcon />
|
||||
{t('admin.promoOffers.sendButton')}
|
||||
|
||||
@@ -124,7 +124,7 @@ export default function AdminPromocodeStats() {
|
||||
</div>
|
||||
<button
|
||||
onClick={() => navigate(`/admin/promocodes/${id}/edit`)}
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600"
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
<EditIcon />
|
||||
{t('admin.promocodes.modal.edit')}
|
||||
|
||||
@@ -102,13 +102,13 @@ export default function AdminPromocodes() {
|
||||
</button>
|
||||
)}
|
||||
<div>
|
||||
<h1 className="text-xl font-semibold text-dark-100">{t('admin.promocodes.title')}</h1>
|
||||
<h1 className="text-xl font-bold text-dark-100">{t('admin.promocodes.title')}</h1>
|
||||
<p className="text-sm text-dark-400">{t('admin.promocodes.subtitle')}</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => navigate('/admin/promocodes/create')}
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600"
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
<PlusIcon />
|
||||
{t('admin.promocodes.addPromocode')}
|
||||
|
||||
@@ -432,7 +432,7 @@ export default function AdminRoleAssign() {
|
||||
<button
|
||||
type="submit"
|
||||
disabled={assignMutation.isPending || !selectedUser || !selectedRoleId}
|
||||
className="flex items-center gap-2 rounded-lg bg-accent-500 px-5 py-2 text-white transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
className="flex items-center gap-2 rounded-lg bg-accent-500 px-5 py-2 text-on-accent transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
>
|
||||
{assignMutation.isPending
|
||||
? t('admin.roleAssign.assigning')
|
||||
|
||||
@@ -514,7 +514,7 @@ export default function AdminRoleEdit() {
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSaving}
|
||||
className="rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
className="rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
>
|
||||
{isSaving ? t('admin.roles.form.saving') : t('admin.roles.form.save')}
|
||||
</button>
|
||||
|
||||
@@ -81,7 +81,7 @@ export default function AdminRoles() {
|
||||
<PermissionGate permission="roles:create">
|
||||
<button
|
||||
onClick={() => navigate('/admin/roles/create')}
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600"
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
<PlusIcon />
|
||||
{t('admin.roles.createRole')}
|
||||
|
||||
@@ -76,7 +76,7 @@ export default function AdminServers() {
|
||||
<button
|
||||
onClick={() => syncMutation.mutate()}
|
||||
disabled={syncMutation.isPending}
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
>
|
||||
<SyncIcon />
|
||||
{syncMutation.isPending ? t('admin.servers.syncing') : t('admin.servers.sync')}
|
||||
|
||||
@@ -248,7 +248,7 @@ export default function AdminSettings() {
|
||||
<BackIcon />
|
||||
</button>
|
||||
)}
|
||||
<h1 className="text-lg font-bold text-dark-100">{t('admin.settings.title')}</h1>
|
||||
<h1 className="text-xl font-bold text-dark-100">{t('admin.settings.title')}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<SettingsTreeSidebar
|
||||
|
||||
@@ -661,7 +661,7 @@ export default function AdminTariffCreate() {
|
||||
!selectedExternalSquad
|
||||
? isDaily
|
||||
? 'bg-warning-500 text-white'
|
||||
: 'bg-accent-500 text-white'
|
||||
: 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-600'
|
||||
}`}
|
||||
>
|
||||
@@ -691,7 +691,7 @@ export default function AdminTariffCreate() {
|
||||
isSelected
|
||||
? isDaily
|
||||
? 'bg-warning-500 text-white'
|
||||
: 'bg-accent-500 text-white'
|
||||
: 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-600'
|
||||
}`}
|
||||
>
|
||||
@@ -740,7 +740,7 @@ export default function AdminTariffCreate() {
|
||||
isSelected
|
||||
? isDaily
|
||||
? 'bg-warning-500 text-white'
|
||||
: 'bg-accent-500 text-white'
|
||||
: 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-600'
|
||||
}`}
|
||||
>
|
||||
@@ -1055,7 +1055,7 @@ export default function AdminTariffCreate() {
|
||||
isSelected
|
||||
? isDaily
|
||||
? 'bg-warning-500 text-white'
|
||||
: 'bg-accent-500 text-white'
|
||||
: 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-600'
|
||||
}`}
|
||||
>
|
||||
|
||||
@@ -307,7 +307,7 @@ export default function AdminTariffs() {
|
||||
</button>
|
||||
)}
|
||||
<div>
|
||||
<h1 className="text-xl font-semibold text-dark-100">{t('admin.tariffs.title')}</h1>
|
||||
<h1 className="text-xl font-bold text-dark-100">{t('admin.tariffs.title')}</h1>
|
||||
<p className="text-sm text-dark-400">{t('admin.tariffs.subtitle')}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -328,7 +328,7 @@ export default function AdminTariffs() {
|
||||
)}
|
||||
<button
|
||||
onClick={() => navigate('/admin/tariffs/create')}
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600"
|
||||
className="flex items-center justify-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
<PlusIcon />
|
||||
{t('admin.tariffs.create')}
|
||||
|
||||
@@ -272,9 +272,7 @@ export default function AdminTickets() {
|
||||
<BackIcon />
|
||||
</button>
|
||||
)}
|
||||
<h1 className="text-2xl font-bold text-dark-50 sm:text-3xl">
|
||||
{t('admin.tickets.title')}
|
||||
</h1>
|
||||
<h1 className="text-xl font-bold text-dark-100">{t('admin.tickets.title')}</h1>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => navigate('/admin/tickets/settings')}
|
||||
|
||||
@@ -740,7 +740,7 @@ export default function AdminUserDetail() {
|
||||
<p className="text-dark-400">{t('admin.users.notFound')}</p>
|
||||
<button
|
||||
onClick={() => navigate('/admin/users')}
|
||||
className="rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600"
|
||||
className="rounded-lg bg-accent-500 px-4 py-2 text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
{t('common.back')}
|
||||
</button>
|
||||
|
||||
@@ -364,7 +364,7 @@ export default function AdminWithdrawalDetail() {
|
||||
<button
|
||||
onClick={() => completeMutation.mutate()}
|
||||
disabled={completeMutation.isPending}
|
||||
className="w-full rounded-lg bg-accent-500 px-4 py-3 font-medium text-white transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
className="w-full rounded-lg bg-accent-500 px-4 py-3 font-medium text-on-accent transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
>
|
||||
{completeMutation.isPending
|
||||
? t('admin.withdrawals.detail.completing')
|
||||
|
||||
@@ -81,7 +81,7 @@ export default function AdminWithdrawals() {
|
||||
onClick={() => setStatusFilter(filter)}
|
||||
className={`whitespace-nowrap rounded-lg px-4 py-2 text-sm font-medium transition-colors ${
|
||||
statusFilter === filter
|
||||
? 'bg-accent-500 text-white'
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-800/40 text-dark-400 hover:bg-dark-700/50 hover:text-dark-200'
|
||||
}`}
|
||||
>
|
||||
|
||||
@@ -58,7 +58,7 @@ export default function AutoLogin() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigate('/login', { replace: true })}
|
||||
className="rounded-xl bg-accent-500 px-6 py-2.5 text-sm font-medium text-white transition-colors hover:bg-accent-400"
|
||||
className="rounded-xl bg-accent-500 px-6 py-2.5 text-sm font-medium text-on-accent transition-colors hover:bg-accent-400"
|
||||
>
|
||||
{t('auth.login', 'Login')}
|
||||
</button>
|
||||
|
||||
@@ -340,7 +340,7 @@ export default function Balance() {
|
||||
{translatedDesc || method.description}
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-3 text-xs text-dark-600">
|
||||
<div className="mt-3 text-xs text-dark-400">
|
||||
{formatAmount(method.min_amount_kopeks / 100, 0)} {t('common.rangeTo', 'to')}{' '}
|
||||
{formatAmount(method.max_amount_kopeks / 100, 0)} {currencySymbol}
|
||||
</div>
|
||||
|
||||
@@ -318,7 +318,7 @@ export default function Dashboard() {
|
||||
) : (
|
||||
<Link
|
||||
to="/subscription/purchase"
|
||||
className="flex w-full items-center justify-center gap-2 rounded-2xl bg-accent-500 p-3.5 text-sm font-semibold text-white transition-colors hover:bg-accent-600"
|
||||
className="flex w-full items-center justify-center gap-2 rounded-2xl bg-accent-500 p-3.5 text-sm font-semibold text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
<span className="text-base">+</span>{' '}
|
||||
{t('subscriptions.browsePlans', 'Посмотреть тарифы и купить подписку')}
|
||||
@@ -381,7 +381,7 @@ export default function Dashboard() {
|
||||
)}
|
||||
<Link
|
||||
to="/subscription/purchase"
|
||||
className="flex w-full items-center justify-center gap-2 rounded-2xl bg-accent-500 p-3.5 text-sm font-semibold text-white transition-colors hover:bg-accent-600"
|
||||
className="flex w-full items-center justify-center gap-2 rounded-2xl bg-accent-500 p-3.5 text-sm font-semibold text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
<span className="text-base">+</span>{' '}
|
||||
{t('subscriptions.browsePlans', 'Посмотреть тарифы и купить подписку')}
|
||||
|
||||
@@ -189,7 +189,7 @@ export default function GiftClaim() {
|
||||
'flex w-full items-center justify-center gap-2 rounded-xl px-4 py-3 text-sm font-bold transition-all active:scale-[0.98]',
|
||||
copied
|
||||
? 'bg-success-500/20 text-success-400'
|
||||
: 'bg-accent-500 text-white hover:bg-accent-400',
|
||||
: 'bg-accent-500 text-on-accent hover:bg-accent-400',
|
||||
)}
|
||||
>
|
||||
{copied ? <CheckIcon className="h-4 w-4" /> : <CopyIcon className="h-4 w-4" />}
|
||||
@@ -264,7 +264,7 @@ export default function GiftClaim() {
|
||||
{gift.bot_claim_link && (
|
||||
<a
|
||||
href={gift.bot_claim_link}
|
||||
className="flex w-full items-center justify-center gap-2 rounded-xl bg-accent-500 px-6 py-3.5 text-sm font-bold text-white shadow-lg shadow-accent-500/25 transition-all hover:bg-accent-400 active:scale-[0.98]"
|
||||
className="flex w-full items-center justify-center gap-2 rounded-xl bg-accent-500 px-6 py-3.5 text-sm font-bold text-on-accent shadow-lg shadow-accent-500/25 transition-all hover:bg-accent-400 active:scale-[0.98]"
|
||||
>
|
||||
{t('landing.giftClaim.activateTelegram', 'Activate in Telegram')}
|
||||
</a>
|
||||
@@ -303,7 +303,7 @@ export default function GiftClaim() {
|
||||
className={cn(
|
||||
'flex w-full items-center justify-center gap-2 rounded-xl px-6 py-3.5 text-sm font-bold transition-all',
|
||||
isValidEmail(email) && !claimMutation.isPending
|
||||
? 'bg-accent-500 text-white hover:bg-accent-400 active:scale-[0.98]'
|
||||
? 'bg-accent-500 text-on-accent hover:bg-accent-400 active:scale-[0.98]'
|
||||
: 'cursor-not-allowed bg-dark-800 text-dark-500',
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -156,7 +156,7 @@ function CodeOnlySuccessState({
|
||||
'flex w-full items-center justify-center gap-2 rounded-xl px-4 py-3.5 text-sm font-bold transition-all duration-200 active:scale-[0.98]',
|
||||
copied
|
||||
? 'bg-success-500/20 text-success-400'
|
||||
: 'bg-accent-500 text-white shadow-lg shadow-accent-500/25 hover:bg-accent-400',
|
||||
: 'bg-accent-500 text-on-accent shadow-lg shadow-accent-500/25 hover:bg-accent-400',
|
||||
)}
|
||||
>
|
||||
{copied ? (
|
||||
@@ -236,7 +236,7 @@ function DeliveredState({
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigate('/')}
|
||||
className="flex w-full items-center justify-center rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-accent-400"
|
||||
className="flex w-full items-center justify-center rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-on-accent transition-colors hover:bg-accent-400"
|
||||
>
|
||||
{t('gift.backToDashboard', 'Back to dashboard')}
|
||||
</button>
|
||||
@@ -303,7 +303,7 @@ function PendingActivationState({
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigate('/')}
|
||||
className="flex w-full items-center justify-center rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-accent-400"
|
||||
className="flex w-full items-center justify-center rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-on-accent transition-colors hover:bg-accent-400"
|
||||
>
|
||||
{t('gift.backToDashboard', 'Back to dashboard')}
|
||||
</button>
|
||||
@@ -335,7 +335,7 @@ function FailedState() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigate('/gift')}
|
||||
className="flex w-full items-center justify-center rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-accent-400"
|
||||
className="flex w-full items-center justify-center rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-on-accent transition-colors hover:bg-accent-400"
|
||||
>
|
||||
{t('gift.tryAgain', 'Try again')}
|
||||
</button>
|
||||
@@ -372,7 +372,7 @@ function PollErrorState() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigate('/')}
|
||||
className="flex w-full items-center justify-center rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-accent-400"
|
||||
className="flex w-full items-center justify-center rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-on-accent transition-colors hover:bg-accent-400"
|
||||
>
|
||||
{t('gift.backToDashboard', 'Back to dashboard')}
|
||||
</button>
|
||||
@@ -406,7 +406,7 @@ function PollTimedOutState({ onRetry }: { onRetry: () => void }) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={onRetry}
|
||||
className="rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-accent-400"
|
||||
className="rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-on-accent transition-colors hover:bg-accent-400"
|
||||
>
|
||||
{t('gift.retry', 'Retry')}
|
||||
</button>
|
||||
@@ -436,7 +436,7 @@ function NoTokenState() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigate('/gift')}
|
||||
className="rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-accent-400"
|
||||
className="rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-on-accent transition-colors hover:bg-accent-400"
|
||||
>
|
||||
{t('gift.backToGift', 'Go back')}
|
||||
</button>
|
||||
|
||||
@@ -231,7 +231,7 @@ function PeriodCard({
|
||||
<span
|
||||
className={cn(
|
||||
'rounded-md px-2 py-0.5 text-xs font-bold',
|
||||
isSelected ? 'bg-white/20 text-white' : 'bg-accent-500/20 text-accent-400',
|
||||
isSelected ? 'bg-white/20 text-on-accent' : 'bg-accent-500/20 text-accent-400',
|
||||
)}
|
||||
>
|
||||
-{period.discount_percent}%
|
||||
@@ -366,7 +366,7 @@ function PaymentMethodCard({
|
||||
className={cn(
|
||||
'rounded-xl px-4 py-2 text-sm font-medium transition-all duration-200',
|
||||
selectedSubOption === opt.id
|
||||
? 'bg-accent-500 text-white shadow-sm shadow-accent-500/25'
|
||||
? 'bg-accent-500 text-on-accent shadow-sm shadow-accent-500/25'
|
||||
: 'bg-dark-800/50 text-dark-300 hover:bg-dark-700/50',
|
||||
)}
|
||||
>
|
||||
@@ -716,7 +716,7 @@ function BuyTabContent({
|
||||
className={cn(
|
||||
'flex w-full items-center justify-center gap-2 rounded-2xl px-6 py-4 text-base font-semibold transition-all duration-200',
|
||||
canSubmit && !purchaseMutation.isPending
|
||||
? 'bg-accent-500 text-white shadow-lg shadow-accent-500/25 hover:bg-accent-400 hover:shadow-accent-500/40 active:scale-[0.98]'
|
||||
? 'bg-accent-500 text-on-accent shadow-lg shadow-accent-500/25 hover:bg-accent-400 hover:shadow-accent-500/40 active:scale-[0.98]'
|
||||
: 'cursor-not-allowed bg-dark-800 text-dark-500',
|
||||
)}
|
||||
>
|
||||
@@ -833,7 +833,7 @@ function ActivateTabContent({ initialCode }: { initialCode?: string | null }) {
|
||||
className={cn(
|
||||
'w-full max-w-sm rounded-2xl px-6 py-4 text-base font-semibold transition-all duration-200',
|
||||
code.trim() && !activateMutation.isPending
|
||||
? 'bg-accent-500 text-white shadow-lg shadow-accent-500/25 hover:bg-accent-400 active:scale-[0.98]'
|
||||
? 'bg-accent-500 text-on-accent shadow-lg shadow-accent-500/25 hover:bg-accent-400 active:scale-[0.98]'
|
||||
: 'cursor-not-allowed bg-dark-800 text-dark-500',
|
||||
)}
|
||||
>
|
||||
@@ -962,7 +962,7 @@ function SentGiftCard({ gift }: { gift: SentGift }) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleShare}
|
||||
className="flex w-full items-center justify-center gap-2 rounded-xl bg-accent-500 px-4 py-3 text-sm font-bold uppercase tracking-wider text-white transition-colors hover:bg-accent-400 active:scale-[0.98]"
|
||||
className="flex w-full items-center justify-center gap-2 rounded-xl bg-accent-500 px-4 py-3 text-sm font-bold uppercase tracking-wider text-on-accent transition-colors hover:bg-accent-400 active:scale-[0.98]"
|
||||
>
|
||||
<ExportIcon className="h-4 w-4" />
|
||||
{t('gift.shareGift')}
|
||||
@@ -1243,7 +1243,7 @@ export default function GiftSubscription() {
|
||||
className={cn(
|
||||
'flex-1 rounded-xl px-3 py-2.5 text-sm font-medium transition-all duration-200',
|
||||
activeTab === tab.id
|
||||
? 'bg-accent-500 text-white shadow-sm'
|
||||
? 'bg-accent-500 text-on-accent shadow-sm'
|
||||
: 'text-dark-400 hover:text-dark-200',
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -838,7 +838,7 @@ export default function Info() {
|
||||
onClick={() => setActiveTab(tab.id)}
|
||||
className={`flex min-h-[44px] shrink-0 items-center gap-2 rounded-lg px-4 py-2.5 text-sm font-medium transition-colors ${
|
||||
activeTab === tab.id
|
||||
? 'bg-accent-500 text-white'
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'bg-dark-800 text-dark-300 hover:bg-dark-700'
|
||||
}`}
|
||||
>
|
||||
|
||||
@@ -583,7 +583,7 @@ export default function Login() {
|
||||
type="button"
|
||||
className={`flex-1 rounded-md py-2 text-sm font-medium transition-all ${
|
||||
authMode === 'login'
|
||||
? 'bg-accent-500 text-white'
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'text-dark-400 hover:text-dark-200'
|
||||
}`}
|
||||
onClick={() => setAuthMode('login')}
|
||||
@@ -594,7 +594,7 @@ export default function Login() {
|
||||
type="button"
|
||||
className={`flex-1 rounded-md py-2 text-sm font-medium transition-all ${
|
||||
authMode === 'register'
|
||||
? 'bg-accent-500 text-white'
|
||||
? 'bg-accent-500 text-on-accent'
|
||||
: 'text-dark-400 hover:text-dark-200'
|
||||
}`}
|
||||
onClick={() => setAuthMode('register')}
|
||||
|
||||
@@ -268,7 +268,7 @@ function SuccessState({
|
||||
href={botLink}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex w-full items-center justify-center gap-2 rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-accent-400"
|
||||
className="flex w-full items-center justify-center gap-2 rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-on-accent transition-colors hover:bg-accent-400"
|
||||
>
|
||||
{t('landing.openBot')}
|
||||
</a>
|
||||
@@ -492,7 +492,7 @@ function GiftPendingActivationState({
|
||||
href={botLink}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex w-full items-center justify-center gap-2 rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-accent-400"
|
||||
className="flex w-full items-center justify-center gap-2 rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-on-accent transition-colors hover:bg-accent-400"
|
||||
>
|
||||
{t('landing.openBot')}
|
||||
</a>
|
||||
@@ -545,7 +545,7 @@ function PollTimedOutState({ onRetry }: { onRetry: () => void }) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={onRetry}
|
||||
className="rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-accent-400"
|
||||
className="rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-on-accent transition-colors hover:bg-accent-400"
|
||||
>
|
||||
{t('common.retry', 'Retry')}
|
||||
</button>
|
||||
@@ -641,7 +641,7 @@ function GiftLinkShareState({
|
||||
'flex w-full items-center justify-center gap-2 rounded-xl px-4 py-3.5 text-sm font-bold transition-all duration-200 active:scale-[0.98]',
|
||||
copied
|
||||
? 'bg-success-500/20 text-success-400'
|
||||
: 'bg-accent-500 text-white shadow-lg shadow-accent-500/25 hover:bg-accent-400',
|
||||
: 'bg-accent-500 text-on-accent shadow-lg shadow-accent-500/25 hover:bg-accent-400',
|
||||
)}
|
||||
>
|
||||
{copied ? (
|
||||
|
||||
@@ -122,7 +122,7 @@ function PeriodTabs({
|
||||
className={cn(
|
||||
'whitespace-nowrap rounded-full px-4 py-2 text-sm font-medium transition-all duration-200',
|
||||
selectedDays === period.days
|
||||
? 'bg-accent-500 text-white shadow-lg shadow-accent-500/25'
|
||||
? 'bg-accent-500 text-on-accent shadow-lg shadow-accent-500/25'
|
||||
: 'bg-dark-800/50 text-dark-300 hover:bg-dark-700/50 hover:text-dark-100',
|
||||
)}
|
||||
>
|
||||
@@ -409,7 +409,7 @@ function PaymentMethodCard({
|
||||
className={cn(
|
||||
'rounded-xl px-4 py-2 text-sm font-medium transition-all duration-200',
|
||||
selectedSubOption === opt.id
|
||||
? 'bg-accent-500 text-white shadow-sm shadow-accent-500/25'
|
||||
? 'bg-accent-500 text-on-accent shadow-sm shadow-accent-500/25'
|
||||
: 'bg-dark-800/50 text-dark-300 hover:bg-dark-700/50 hover:text-dark-100',
|
||||
)}
|
||||
>
|
||||
@@ -583,7 +583,7 @@ function SummaryCard({
|
||||
className={cn(
|
||||
'flex w-full items-center justify-center gap-2 rounded-2xl px-6 py-4 text-base font-semibold transition-all duration-200',
|
||||
canSubmit && !isSubmitting
|
||||
? 'bg-accent-500 text-white shadow-lg shadow-accent-500/25 hover:bg-accent-400 hover:shadow-accent-500/40 active:scale-[0.98]'
|
||||
? 'bg-accent-500 text-on-accent shadow-lg shadow-accent-500/25 hover:bg-accent-400 hover:shadow-accent-500/40 active:scale-[0.98]'
|
||||
: 'cursor-not-allowed bg-dark-800 text-dark-500',
|
||||
)}
|
||||
>
|
||||
@@ -629,7 +629,7 @@ function SummaryCard({
|
||||
className={cn(
|
||||
'flex w-full items-center justify-center gap-2 rounded-2xl px-6 py-4 text-base font-semibold transition-all duration-200',
|
||||
canSubmit && !isSubmitting
|
||||
? 'bg-accent-500 text-white shadow-lg shadow-accent-500/25 hover:bg-accent-400 hover:shadow-accent-500/40 active:scale-[0.98]'
|
||||
? 'bg-accent-500 text-on-accent shadow-lg shadow-accent-500/25 hover:bg-accent-400 hover:shadow-accent-500/40 active:scale-[0.98]'
|
||||
: 'cursor-not-allowed bg-dark-800 text-dark-500',
|
||||
)}
|
||||
>
|
||||
@@ -734,7 +734,7 @@ function DiscountBanner({
|
||||
<div className="flex flex-col items-center gap-4 px-5 py-5 sm:flex-row sm:justify-between">
|
||||
{/* Left: badge + text */}
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="shrink-0 rounded-full bg-accent-500 px-3 py-1 text-sm font-bold text-white shadow-lg shadow-accent-500/25">
|
||||
<span className="shrink-0 rounded-full bg-accent-500 px-3 py-1 text-sm font-bold text-on-accent shadow-lg shadow-accent-500/25">
|
||||
-{discount.percent}%
|
||||
</span>
|
||||
{discount.badge_text && (
|
||||
|
||||
@@ -226,7 +226,7 @@ export default function RenewSubscription() {
|
||||
<button
|
||||
onClick={() => handleRenew(selectedPeriod)}
|
||||
disabled={renewMutation.isPending}
|
||||
className="w-full rounded-2xl bg-accent-500 py-3.5 text-base font-semibold text-white transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
className="w-full rounded-2xl bg-accent-500 py-3.5 text-base font-semibold text-on-accent transition-colors hover:bg-accent-600 disabled:opacity-50"
|
||||
>
|
||||
{renewMutation.isPending
|
||||
? t('common.processing', 'Обработка...')
|
||||
|
||||
@@ -515,7 +515,7 @@ export default function Subscription() {
|
||||
</p>
|
||||
<button
|
||||
onClick={() => navigate('/subscriptions')}
|
||||
className="rounded-xl bg-accent-500 px-6 py-2.5 text-sm font-medium text-white"
|
||||
className="rounded-xl bg-accent-500 px-6 py-2.5 text-sm font-medium text-on-accent"
|
||||
>
|
||||
{t('subscription.backToList', 'Мои подписки')}
|
||||
</button>
|
||||
|
||||
@@ -121,7 +121,7 @@ export default function SubscriptionPurchase() {
|
||||
</p>
|
||||
<button
|
||||
onClick={() => refetchOptions()}
|
||||
className="rounded-xl bg-accent-500 px-6 py-2 text-sm font-medium text-white transition-colors hover:bg-accent-600"
|
||||
className="rounded-xl bg-accent-500 px-6 py-2 text-sm font-medium text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
{t('common.retry')}
|
||||
</button>
|
||||
@@ -322,7 +322,7 @@ export default function SubscriptionPurchase() {
|
||||
</p>
|
||||
<button
|
||||
onClick={() => refetchOptions()}
|
||||
className="rounded-xl bg-accent-500 px-6 py-2 text-sm font-medium text-white transition-colors hover:bg-accent-600"
|
||||
className="rounded-xl bg-accent-500 px-6 py-2 text-sm font-medium text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
{t('common.retry')}
|
||||
</button>
|
||||
|
||||
@@ -35,7 +35,7 @@ function EmptyState({ onBuy }: { onBuy: () => void }) {
|
||||
</p>
|
||||
<button
|
||||
onClick={onBuy}
|
||||
className="rounded-xl bg-accent-500 px-8 py-3 text-sm font-medium text-white transition-colors hover:bg-accent-600"
|
||||
className="rounded-xl bg-accent-500 px-8 py-3 text-sm font-medium text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
{t('subscriptions.buy', 'Купить подписку')}
|
||||
</button>
|
||||
@@ -135,7 +135,7 @@ export default function Subscriptions() {
|
||||
{!isLoading && subscriptions.length > 0 && !hasActivePaid && (
|
||||
<button
|
||||
onClick={() => navigate('/subscription/purchase')}
|
||||
className="flex w-full items-center justify-center gap-2 rounded-2xl bg-accent-500 p-3.5 text-sm font-semibold text-white transition-colors hover:bg-accent-600"
|
||||
className="flex w-full items-center justify-center gap-2 rounded-2xl bg-accent-500 p-3.5 text-sm font-semibold text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
<PlusIcon className="h-5 w-5" />
|
||||
{t('subscriptions.browsePlans', 'Посмотреть тарифы и купить подписку')}
|
||||
@@ -171,7 +171,7 @@ export default function Subscriptions() {
|
||||
(Telegram-баг #605056/#605063). */}
|
||||
<button
|
||||
onClick={() => navigate('/subscription/purchase')}
|
||||
className="flex w-full items-center justify-center gap-2 rounded-xl bg-accent-500 px-6 py-3 text-sm font-semibold text-white transition-colors hover:bg-accent-600"
|
||||
className="flex w-full items-center justify-center gap-2 rounded-xl bg-accent-500 px-6 py-3 text-sm font-semibold text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
<PlusIcon className="h-5 w-5" />
|
||||
{t('subscriptions.browsePlans', 'Посмотреть тарифы и купить подписку')}
|
||||
|
||||
@@ -507,7 +507,7 @@ export default function TopUpAmount() {
|
||||
? 'cursor-not-allowed bg-dark-700 text-dark-500'
|
||||
: isStarsMethod
|
||||
? 'bg-gradient-to-r from-yellow-500 to-orange-500 text-white shadow-lg shadow-yellow-500/25 hover:from-yellow-400 hover:to-orange-400 active:from-yellow-600 active:to-orange-600'
|
||||
: 'bg-accent-500 text-white shadow-lg shadow-accent-500/25 transition-colors hover:bg-accent-400 active:bg-accent-600'
|
||||
: 'bg-accent-500 text-on-accent shadow-lg shadow-accent-500/25 transition-colors hover:bg-accent-400 active:bg-accent-600'
|
||||
}`}
|
||||
>
|
||||
{isPending ? (
|
||||
|
||||
@@ -82,7 +82,7 @@ export default function TopUpMethodSelect() {
|
||||
{translatedDesc || method.description}
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-3 text-xs text-dark-600">
|
||||
<div className="mt-3 text-xs text-dark-400">
|
||||
{formatAmount(method.min_amount_kopeks / 100, 0)} –{' '}
|
||||
{formatAmount(method.max_amount_kopeks / 100, 0)} {currencySymbol}
|
||||
</div>
|
||||
|
||||
@@ -85,7 +85,7 @@ function SuccessState({ amountKopeks }: { amountKopeks: number | null }) {
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleGoToBalance}
|
||||
className="flex w-full items-center justify-center gap-2 rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-accent-400"
|
||||
className="flex w-full items-center justify-center gap-2 rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-on-accent transition-colors hover:bg-accent-400"
|
||||
>
|
||||
{t('balance.topUpResult.goToBalance')}
|
||||
</button>
|
||||
@@ -162,7 +162,7 @@ function TimeoutState({ onRetry, onGoBack }: { onRetry: () => void; onGoBack: ()
|
||||
<button
|
||||
type="button"
|
||||
onClick={onRetry}
|
||||
className="w-full rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-white transition-colors hover:bg-accent-400"
|
||||
className="w-full rounded-xl bg-accent-500 px-6 py-3 text-sm font-medium text-on-accent transition-colors hover:bg-accent-400"
|
||||
>
|
||||
{t('common.retry')}
|
||||
</button>
|
||||
|
||||
@@ -632,7 +632,7 @@ export default function Wheel() {
|
||||
</button>
|
||||
<button
|
||||
onClick={handleDirectStarsPay}
|
||||
className="rounded-lg bg-accent-500 px-4 py-2.5 text-sm font-medium text-white transition-colors hover:bg-accent-600"
|
||||
className="rounded-lg bg-accent-500 px-4 py-2.5 text-sm font-medium text-on-accent transition-colors hover:bg-accent-600"
|
||||
>
|
||||
{t('wheel.payStars', { count: config.spin_cost_stars ?? 0 })}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user