chore: standardize web controls
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<script>
|
||||
import { Input } from "$components/ui/index.js";
|
||||
import { Trash2 } from "$components/ui/icons.js";
|
||||
import { getContext, onMount } from "svelte";
|
||||
import Dialog from "$components/ui/dialog.svelte";
|
||||
@@ -106,7 +107,7 @@
|
||||
<div class="admin-form" data-dialog-content>
|
||||
<div class="admin-dialog-form-section">
|
||||
<AdminField label={at("ad_label_source", {}, "Источник")}>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder="telegram_ads"
|
||||
@@ -118,7 +119,7 @@
|
||||
label={at("ad_label_param", {}, "start-параметр")}
|
||||
hint={at("ad_hint_param", {}, "Передаётся в /start, должен быть уникален")}
|
||||
>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder="ads_summer25"
|
||||
@@ -129,7 +130,7 @@
|
||||
</div>
|
||||
<div class="admin-dialog-form-section">
|
||||
<AdminField label={at("ad_label_cost", {}, "Стоимость, RUB")}>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
step="0.01"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
AdminEmptyState,
|
||||
AdminSelect,
|
||||
} from "$components/patterns/admin/index.js";
|
||||
import { Checkbox } from "$components/ui/index.js";
|
||||
import { Checkbox, ColorInput, FileInput, Input, RangeInput } from "$components/ui/index.js";
|
||||
import { Switch } from "$components/ui/primitives.js";
|
||||
import { getContext, onDestroy, onMount } from "svelte";
|
||||
|
||||
@@ -444,10 +444,9 @@
|
||||
|
||||
<div class="appearance-controls">
|
||||
<section class="appearance-control-card">
|
||||
<input
|
||||
bind:this={logoFileInput}
|
||||
<FileInput
|
||||
bind:element={logoFileInput}
|
||||
class="appearance-file-input"
|
||||
type="file"
|
||||
accept="image/png,image/jpeg,image/gif,image/webp,image/svg+xml,image/x-icon"
|
||||
onchange={handleLogoFileChange}
|
||||
/>
|
||||
@@ -461,7 +460,7 @@
|
||||
{at("appearance_logo_upload_file", {}, "Загрузить файл")}
|
||||
</AdminButton>
|
||||
<div class="appearance-url-row">
|
||||
<input
|
||||
<Input
|
||||
class="input appearance-control"
|
||||
type="url"
|
||||
placeholder="https://example.com/logo.png"
|
||||
@@ -490,7 +489,7 @@
|
||||
<span>{at("appearance_use_emoji_logo", {}, "Использовать emoji-логотип")}</span>
|
||||
</label>
|
||||
<div class="appearance-emoji-grid">
|
||||
<input
|
||||
<Input
|
||||
class="input appearance-control"
|
||||
type="text"
|
||||
maxlength="8"
|
||||
@@ -547,10 +546,9 @@
|
||||
>{at("appearance_use_custom_favicon", {}, "Использовать отдельную favicon")}</span
|
||||
>
|
||||
</label>
|
||||
<input
|
||||
bind:this={faviconFileInput}
|
||||
<FileInput
|
||||
bind:element={faviconFileInput}
|
||||
class="appearance-file-input"
|
||||
type="file"
|
||||
accept="image/png,image/jpeg,image/gif,image/webp,image/svg+xml,image/x-icon,.ico"
|
||||
onchange={handleFaviconFileChange}
|
||||
/>
|
||||
@@ -564,7 +562,7 @@
|
||||
{at("appearance_favicon_upload_file", {}, "Загрузить favicon")}
|
||||
</AdminButton>
|
||||
<div class="appearance-url-row">
|
||||
<input
|
||||
<Input
|
||||
class="input appearance-control"
|
||||
type="url"
|
||||
placeholder="https://example.com/icon.png"
|
||||
@@ -657,18 +655,17 @@
|
||||
</span>
|
||||
<label class="admin-theme-card-option appearance-color-row">
|
||||
<span>{at("appearance_theme_accent", {}, "Accent")}</span>
|
||||
<input
|
||||
class="admin-color"
|
||||
class:is-empty={!isThemeAccentSet(theme)}
|
||||
type="color"
|
||||
<ColorInput
|
||||
class={`admin-color${!isThemeAccentSet(theme) ? " is-empty" : ""}`}
|
||||
value={pickerHex(theme.tokens?.accent)}
|
||||
ariaLabel={at("appearance_theme_accent", {}, "Accent")}
|
||||
title={isThemeAccentSet(theme)
|
||||
? theme.tokens?.accent
|
||||
: at("appearance_theme_accent_empty", {}, "Не задан")}
|
||||
onclick={() => openThemeAccentPicker(theme)}
|
||||
oninput={(event) => setThemeAccent(theme, event.currentTarget.value)}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input appearance-color-text"
|
||||
type="text"
|
||||
placeholder={at("appearance_theme_accent_placeholder", {}, "Не задан")}
|
||||
@@ -693,17 +690,17 @@
|
||||
"Логотип на главной и входе"
|
||||
)}</span
|
||||
>
|
||||
<input
|
||||
<RangeInput
|
||||
class="appearance-logo-scale-range"
|
||||
type="range"
|
||||
min="50"
|
||||
max="300"
|
||||
step="5"
|
||||
ariaLabel={at("appearance_theme_home_logo_scale", {}, "Home logo scale")}
|
||||
value={homeLogoScale(theme)}
|
||||
oninput={(event) => setThemeHomeLogoScale(theme, event.currentTarget.value)}
|
||||
onValueChange={(value) => setThemeHomeLogoScale(theme, value)}
|
||||
/>
|
||||
<span class="appearance-logo-scale-value">
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="50"
|
||||
@@ -814,7 +811,7 @@
|
||||
background: color-mix(in srgb, var(--admin-surface-2) 40%, transparent);
|
||||
}
|
||||
|
||||
.appearance-file-input {
|
||||
:global(.appearance-file-input) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -949,7 +946,7 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.appearance-color-text {
|
||||
:global(.appearance-color-text) {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
@@ -959,7 +956,7 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.appearance-logo-scale-range {
|
||||
:global(.appearance-logo-scale-range) {
|
||||
width: 100%;
|
||||
accent-color: var(--accent);
|
||||
}
|
||||
@@ -971,14 +968,14 @@
|
||||
color: var(--admin-text);
|
||||
}
|
||||
|
||||
.appearance-logo-scale-value .input {
|
||||
:global(.appearance-logo-scale-value .input) {
|
||||
width: 70px;
|
||||
min-height: 32px;
|
||||
padding: 4px 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.admin-color.is-empty {
|
||||
:global(.admin-color.is-empty) {
|
||||
opacity: 0.42;
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
AdminTable,
|
||||
AdminTableSkeleton,
|
||||
} from "$components/patterns/admin/index.js";
|
||||
import { Checkbox, RadioGroup, RadioGroupItem } from "$components/ui/index.js";
|
||||
import { Checkbox, FileInput, RadioGroup, RadioGroupItem } from "$components/ui/index.js";
|
||||
import {
|
||||
CheckCircle2,
|
||||
Database,
|
||||
@@ -178,10 +178,9 @@
|
||||
? at("backups_uploading", {}, "Загрузка...")
|
||||
: at("backups_upload", {}, "Загрузить архив")}
|
||||
</AdminButton>
|
||||
<input
|
||||
bind:this={fileInput}
|
||||
<FileInput
|
||||
bind:element={fileInput}
|
||||
class="backups-file-input"
|
||||
type="file"
|
||||
accept=".zip,application/zip"
|
||||
on:change={uploadSelectedFile}
|
||||
/>
|
||||
@@ -362,7 +361,7 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.backups-file-input {
|
||||
:global(.backups-file-input) {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script>
|
||||
import { Textarea } from "$components/ui/index.js";
|
||||
import { Send } from "$components/ui/icons.js";
|
||||
import { getContext } from "svelte";
|
||||
import { Label } from "$components/ui/primitives.js";
|
||||
@@ -31,12 +32,12 @@
|
||||
<Label.Root class="admin-field-label">
|
||||
<span>{at("broadcast_label_text", {}, "Текст сообщения")}</span>
|
||||
<small>{at("broadcast_hint_text", {}, "Поддерживается HTML-разметка Telegram")}</small>
|
||||
<textarea
|
||||
<Textarea
|
||||
class="admin-textarea"
|
||||
rows="6"
|
||||
value={broadcastText}
|
||||
on:input={(e) => broadcastStore.updateField({ broadcastText: e.target.value })}
|
||||
></textarea>
|
||||
/>
|
||||
</Label.Root>
|
||||
<div style="display:flex; gap:8px; align-items:center;">
|
||||
<AdminButton
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script>
|
||||
import { Input } from "$components/ui/index.js";
|
||||
import { getContext, onMount } from "svelte";
|
||||
import {
|
||||
AdminButton,
|
||||
@@ -31,7 +32,7 @@
|
||||
|
||||
<div class="admin-toolbar admin-toolbar-card">
|
||||
<div class="admin-toolbar-search admin-toolbar-search-actions">
|
||||
<input
|
||||
<Input
|
||||
type="search"
|
||||
class="input"
|
||||
placeholder={at("logs_user_filter_placeholder", {}, "Фильтр по ID пользователя")}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script>
|
||||
import { Input } from "$components/ui/index.js";
|
||||
import { Trash2 } from "$components/ui/icons.js";
|
||||
import { getContext, onMount } from "svelte";
|
||||
import Dialog from "$components/ui/dialog.svelte";
|
||||
@@ -110,7 +111,7 @@
|
||||
<div class="admin-form" data-dialog-content>
|
||||
<div class="admin-dialog-form-section">
|
||||
<AdminField label={at("promo_label_code", {}, "Код")}>
|
||||
<input
|
||||
<Input
|
||||
type="text"
|
||||
class="input"
|
||||
value={promoDraft.code}
|
||||
@@ -122,7 +123,7 @@
|
||||
<div class="admin-dialog-form-section">
|
||||
<div class="admin-form-row-2">
|
||||
<AdminField label={at("promo_label_bonus_days", {}, "Бонус (дней)")}>
|
||||
<input
|
||||
<Input
|
||||
type="number"
|
||||
class="input"
|
||||
min="1"
|
||||
@@ -131,7 +132,7 @@
|
||||
/>
|
||||
</AdminField>
|
||||
<AdminField label={at("promo_label_max_activations", {}, "Макс. активаций")}>
|
||||
<input
|
||||
<Input
|
||||
type="number"
|
||||
class="input"
|
||||
min="1"
|
||||
@@ -141,7 +142,7 @@
|
||||
</AdminField>
|
||||
</div>
|
||||
<AdminField label={at("promo_label_valid_days", {}, "Срок действия (дней от текущего)")}>
|
||||
<input
|
||||
<Input
|
||||
type="number"
|
||||
class="input"
|
||||
min="1"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script>
|
||||
import { ColorInput, FileInput, Input, Textarea } from "$components/ui/index.js";
|
||||
import {
|
||||
Check,
|
||||
ChevronRight,
|
||||
@@ -515,13 +516,13 @@
|
||||
>
|
||||
</div>
|
||||
{:else if field.type === "color"}
|
||||
<input
|
||||
<ColorInput
|
||||
class="admin-color"
|
||||
type="color"
|
||||
value={valueFor(field) || "#00fe7a"}
|
||||
ariaLabel={fieldLabelText(field)}
|
||||
oninput={(e) => settingsStore.markDirty(field.key, e.currentTarget.value)}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="text"
|
||||
value={valueFor(field) || ""}
|
||||
@@ -560,7 +561,7 @@
|
||||
onValueChange={(value) => settingsStore.markDirty(field.key, value)}
|
||||
/>
|
||||
{:else if field.type === "int" || field.type === "float"}
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
step={field.type === "float" ? "0.1" : "1"}
|
||||
@@ -571,19 +572,18 @@
|
||||
oninput={(e) => settingsStore.markDirty(field.key, e.currentTarget.value)}
|
||||
/>
|
||||
{:else if field.type === "text"}
|
||||
<textarea
|
||||
<Textarea
|
||||
class="admin-setting-textarea"
|
||||
rows="4"
|
||||
placeholder={fieldPlaceholderText(field)}
|
||||
value={valueFor(field) ?? ""}
|
||||
oninput={(e) => settingsStore.markDirty(field.key, e.currentTarget.value)}
|
||||
></textarea>
|
||||
/>
|
||||
{:else if field.type === "json"}
|
||||
<div class="admin-json-toolbar">
|
||||
<input
|
||||
<FileInput
|
||||
id={"json-file-" + field.key}
|
||||
class="admin-json-file-input"
|
||||
type="file"
|
||||
accept="application/json,.json"
|
||||
onchange={(event) => handleJsonFile(field, event)}
|
||||
/>
|
||||
@@ -605,16 +605,16 @@
|
||||
</AdminButton>
|
||||
{/if}
|
||||
</div>
|
||||
<textarea
|
||||
<Textarea
|
||||
class="admin-setting-textarea admin-setting-json-textarea"
|
||||
rows="10"
|
||||
spellcheck="false"
|
||||
placeholder={fieldPlaceholderText(field)}
|
||||
value={valueFor(field) ?? ""}
|
||||
oninput={(e) => settingsStore.markDirty(field.key, e.currentTarget.value)}
|
||||
></textarea>
|
||||
/>
|
||||
{:else if field.secret}
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type={revealed ? "text" : "password"}
|
||||
placeholder={secretPlaceholder(field)}
|
||||
@@ -631,7 +631,7 @@
|
||||
{#if revealed}<EyeOff size={13} />{:else}<Eye size={13} />{/if}
|
||||
</AdminButton>
|
||||
{:else}
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder={fieldPlaceholderText(field)}
|
||||
@@ -816,7 +816,7 @@
|
||||
<div class="admin-icon-picker-toolbar">
|
||||
<label class="admin-icon-picker-search">
|
||||
<Search size={15} />
|
||||
<input
|
||||
<Input
|
||||
bind:value={iconPickerSearch}
|
||||
class="input"
|
||||
type="text"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
import { TicketMessageBubble } from "$components/patterns/webapp/index.js";
|
||||
import Dialog from "$components/ui/dialog.svelte";
|
||||
import { Search } from "$components/ui/icons.js";
|
||||
import { ScrollArea, Skeleton } from "$components/ui/index.js";
|
||||
import { Input, ScrollArea, Skeleton } from "$components/ui/index.js";
|
||||
|
||||
export let at = (key) => key;
|
||||
export let initialTicketId = null;
|
||||
@@ -215,7 +215,7 @@
|
||||
<div class="support-admin-toolbar admin-toolbar-card">
|
||||
<label class="support-admin-search">
|
||||
<Search size={16} />
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="search"
|
||||
placeholder={at("support_search", {}, "Поиск")}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script>
|
||||
import { Input } from "$components/ui/index.js";
|
||||
import { Tabs, Switch, Label } from "$components/ui/primitives.js";
|
||||
import Dialog from "$components/ui/dialog.svelte";
|
||||
import { Plus, Save, Trash2, X } from "$components/ui/icons.js";
|
||||
@@ -71,7 +72,7 @@
|
||||
"Латиницей, без пробелов. Используется в платежах и подписках, менять после публикации не рекомендуется"
|
||||
)}</small
|
||||
>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder="standard"
|
||||
@@ -127,7 +128,7 @@
|
||||
<div class="admin-form-row admin-form-row-2">
|
||||
<Label.Root class="admin-field-label">
|
||||
<span>{at("tariff_label_name_ru", {}, "Название · RU")}</span>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder={at("tariff_placeholder_name_ru", {}, "Стандарт")}
|
||||
@@ -136,7 +137,7 @@
|
||||
</Label.Root>
|
||||
<Label.Root class="admin-field-label">
|
||||
<span>{at("tariff_label_name_en", {}, "Название · EN")}</span>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder={at("tariff_placeholder_name_en", {}, "Standard")}
|
||||
@@ -148,7 +149,7 @@
|
||||
<div class="admin-form-row admin-form-row-2">
|
||||
<Label.Root class="admin-field-label">
|
||||
<span>{at("tariff_label_desc_ru", {}, "Описание · RU")}</span>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder={at("tariff_placeholder_desc_ru", {}, "Базовый набор серверов")}
|
||||
@@ -157,7 +158,7 @@
|
||||
</Label.Root>
|
||||
<Label.Root class="admin-field-label">
|
||||
<span>{at("tariff_label_desc_en", {}, "Описание · EN")}</span>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder={at("tariff_placeholder_desc_en", {}, "Base server pool")}
|
||||
@@ -211,7 +212,7 @@
|
||||
"Сколько устройств может одновременно использовать подписку. Пусто — взять значение из .env, 0 — без ограничений"
|
||||
)}</small
|
||||
>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -229,7 +230,7 @@
|
||||
"Сколько GB включено в тариф на каждый месяц. 0 — безлимитный трафика. Сверху можно докупать пакеты на вкладке «Докупки»"
|
||||
)}</small
|
||||
>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -248,7 +249,7 @@
|
||||
"По этому курсу остаток подписки пересчитывается в гигабайты при переходе пользователя с тарифа «Период» на «Трафик»"
|
||||
)}</small
|
||||
>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -287,7 +288,7 @@
|
||||
"Эта строка заменит «Premium-серверы» в кабинете, докупках и карточках лимитов."
|
||||
)}</small
|
||||
>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder={at("tariff_placeholder_premium_name_ru", {}, "Premium-серверы")}
|
||||
@@ -303,7 +304,7 @@
|
||||
"Опционально для английского интерфейса."
|
||||
)}</small
|
||||
>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder={at("tariff_placeholder_premium_name_en", {}, "Premium servers")}
|
||||
@@ -359,7 +360,7 @@
|
||||
"Сколько GB через premium-сквады включено в тариф каждый месяц. 0 или пусто — отдельного premium-лимита нет (premium-нодами можно пользоваться без ограничения)"
|
||||
)}</small
|
||||
>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -409,7 +410,7 @@
|
||||
{/if}
|
||||
{#each tariffDraft.premiumTopupRubRows as row, index}
|
||||
<div class="admin-row-editor-line">
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0.1"
|
||||
@@ -418,7 +419,7 @@
|
||||
bind:value={row.gb}
|
||||
aria-label={at("tariff_col_volume_gb", {}, "Объём premium-пакета в GB")}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -449,7 +450,7 @@
|
||||
{/if}
|
||||
{#each tariffDraft.premiumTopupStarsRows as row, index}
|
||||
<div class="admin-row-editor-line">
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0.1"
|
||||
@@ -458,7 +459,7 @@
|
||||
bind:value={row.gb}
|
||||
aria-label={at("tariff_col_volume_gb", {}, "Объём premium-пакета в GB")}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -533,7 +534,7 @@
|
||||
</div>
|
||||
{#each tariffDraft.periodRows as row, index}
|
||||
<div class="admin-row-editor-line admin-row-editor-6">
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="1"
|
||||
@@ -541,7 +542,7 @@
|
||||
bind:value={row.months}
|
||||
aria-label={at("tariff_col_period_months", {}, "Срок (месяцы)")}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -550,7 +551,7 @@
|
||||
bind:value={row.rub}
|
||||
aria-label={at("tariff_label_price_rub", {}, "Цена в рублях")}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -559,7 +560,7 @@
|
||||
bind:value={row.stars}
|
||||
aria-label={at("tariff_label_price_stars", {}, "Цена в Telegram Stars")}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -568,7 +569,7 @@
|
||||
bind:value={row.referral_inviter}
|
||||
aria-label={at("tariff_label_ref_inviter", {}, "Бонус приглашающему")}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -629,7 +630,7 @@
|
||||
{/if}
|
||||
{#each tariffDraft.trafficRubRows as row, index}
|
||||
<div class="admin-row-editor-line">
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0.1"
|
||||
@@ -638,7 +639,7 @@
|
||||
bind:value={row.gb}
|
||||
aria-label={at("tariff_col_volume_gb", {}, "Объём пакета в GB")}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -669,7 +670,7 @@
|
||||
{/if}
|
||||
{#each tariffDraft.trafficStarsRows as row, index}
|
||||
<div class="admin-row-editor-line">
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0.1"
|
||||
@@ -678,7 +679,7 @@
|
||||
bind:value={row.gb}
|
||||
aria-label={at("tariff_col_volume_gb", {}, "Объём пакета в GB")}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -743,7 +744,7 @@
|
||||
{/if}
|
||||
{#each tariffDraft.topupRubRows as row, index}
|
||||
<div class="admin-row-editor-line">
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0.1"
|
||||
@@ -752,7 +753,7 @@
|
||||
bind:value={row.gb}
|
||||
aria-label={at("tariff_col_volume_gb", {}, "Объём пакета в GB")}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -783,7 +784,7 @@
|
||||
{/if}
|
||||
{#each tariffDraft.topupStarsRows as row, index}
|
||||
<div class="admin-row-editor-line">
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0.1"
|
||||
@@ -792,7 +793,7 @@
|
||||
bind:value={row.gb}
|
||||
aria-label={at("tariff_col_volume_gb", {}, "Объём пакета в GB")}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -867,7 +868,7 @@
|
||||
{/if}
|
||||
{#each tariffDraft.hwidRubRows as row, index}
|
||||
<div class="admin-row-editor-line">
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="1"
|
||||
@@ -880,7 +881,7 @@
|
||||
"Сколько устройств добавляет пакет"
|
||||
)}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -911,7 +912,7 @@
|
||||
{/if}
|
||||
{#each tariffDraft.hwidStarsRows as row, index}
|
||||
<div class="admin-row-editor-line">
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="1"
|
||||
@@ -924,7 +925,7 @@
|
||||
"Сколько устройств добавляет пакет"
|
||||
)}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script>
|
||||
import { Input } from "$components/ui/index.js";
|
||||
import {
|
||||
ChevronRight,
|
||||
RefreshCw,
|
||||
@@ -403,7 +404,7 @@
|
||||
<code>TRIAL_DURATION_DAYS</code>
|
||||
</div>
|
||||
<div class="admin-setting-control">
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -439,7 +440,7 @@
|
||||
<code>TRIAL_TRAFFIC_LIMIT_GB</code>
|
||||
</div>
|
||||
<div class="admin-setting-control">
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -591,7 +592,7 @@
|
||||
onValueChange={handleTrialSquadSelect}
|
||||
/>
|
||||
{/key}
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder={valueForKey("USER_SQUAD_UUIDS", settingsDirty, settingsFieldMap) ||
|
||||
@@ -837,7 +838,7 @@
|
||||
<Switch.Thumb class="admin-switch-thumb" />
|
||||
</Switch.Root>
|
||||
</div>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -845,7 +846,7 @@
|
||||
value={valueForKey(rubKey, settingsDirty, settingsFieldMap)}
|
||||
oninput={(event) => setSetting(rubKey, event.currentTarget.value)}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -853,7 +854,7 @@
|
||||
value={valueForKey(starsKey, settingsDirty, settingsFieldMap)}
|
||||
oninput={(event) => setSetting(starsKey, event.currentTarget.value)}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -861,7 +862,7 @@
|
||||
value={valueForKey(inviterKey, settingsDirty, settingsFieldMap)}
|
||||
oninput={(event) => setSetting(inviterKey, event.currentTarget.value)}
|
||||
/>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -877,7 +878,7 @@
|
||||
<label class="admin-field-label admin-field-label-compact">
|
||||
<span>{at("tariffs_legacy_traffic_packages", {}, "Traffic packages")}</span>
|
||||
<small>{at("tariffs_legacy_traffic_hint", {}, "Format: 10:199,50:799")}</small>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="text"
|
||||
value={valueForKey("TRAFFIC_PACKAGES", settingsDirty, settingsFieldMap)}
|
||||
@@ -889,7 +890,7 @@
|
||||
>{at("tariffs_legacy_stars_traffic_packages", {}, "Traffic packages, Stars")}</span
|
||||
>
|
||||
<small>{at("tariffs_legacy_traffic_hint", {}, "Format: 10:199,50:799")}</small>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="text"
|
||||
value={valueForKey("STARS_TRAFFIC_PACKAGES", settingsDirty, settingsFieldMap)}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script>
|
||||
import { Input, Textarea } from "$components/ui/index.js";
|
||||
import { ChevronRight, Languages, Plus, Search, X } from "$components/ui/icons.js";
|
||||
import { AdminBadge, AdminButton, AdminEmptyState } from "$components/patterns/admin/index.js";
|
||||
import { getContext, onDestroy, onMount } from "svelte";
|
||||
@@ -396,7 +397,7 @@
|
||||
|
||||
{#if expanded}
|
||||
<div class="admin-translation-locale-body" transition:slide={{ duration: 130 }}>
|
||||
<textarea
|
||||
<Textarea
|
||||
class="admin-setting-textarea admin-translation-textarea"
|
||||
rows="3"
|
||||
spellcheck="false"
|
||||
@@ -404,7 +405,7 @@
|
||||
value={localeValue(item, lang, dirtyEntry)}
|
||||
oninput={(event) =>
|
||||
translationsStore.markDirty(lang, item.key, event.currentTarget.value)}
|
||||
></textarea>
|
||||
/>
|
||||
<div class="admin-translation-base">
|
||||
<small>{baseKind(item, lang)}</small>
|
||||
<span title={baseValue(item, lang)}>{baseValue(item, lang) || "-"}</span>
|
||||
@@ -457,7 +458,7 @@
|
||||
<div class="admin-translations-toolbar">
|
||||
<label class="admin-translations-search">
|
||||
<Search size={15} />
|
||||
<input
|
||||
<Input
|
||||
bind:value={search}
|
||||
class="input"
|
||||
type="text"
|
||||
@@ -502,7 +503,7 @@
|
||||
addLanguage();
|
||||
}}
|
||||
>
|
||||
<input
|
||||
<Input
|
||||
bind:value={newLanguageCode}
|
||||
class="input"
|
||||
type="text"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { Label, Separator, Tabs } from "$components/ui/primitives.js";
|
||||
import { Checkbox } from "$components/ui/index.js";
|
||||
import { Checkbox, Input, Textarea } from "$components/ui/index.js";
|
||||
import Dialog from "$components/ui/dialog.svelte";
|
||||
import {
|
||||
AdminBadge,
|
||||
@@ -632,7 +632,7 @@
|
||||
<Label.Root class="admin-field-label admin-extend-field">
|
||||
<span>{at("user_label_extend", {}, "Продлить подписку")}</span>
|
||||
<div class="admin-extend-control">
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="1"
|
||||
@@ -662,7 +662,7 @@
|
||||
<span>{at("user_premium_override_bonus", {}, "Доп. премиум-трафик, GB")}</span
|
||||
>
|
||||
<small>{at("user_premium_override_bonus_hint", {}, "")}</small>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -741,7 +741,7 @@
|
||||
>{at("user_regular_override_bonus", {}, "Доп. основной трафик, GB")}</span
|
||||
>
|
||||
<small>{at("user_regular_override_bonus_hint", {}, "")}</small>
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -837,7 +837,7 @@
|
||||
<Label.Root class="admin-field-label admin-extend-field">
|
||||
<span>{at("user_traffic_grant_gb", {}, "ГБ к выдаче")}</span>
|
||||
<div class="admin-extend-control">
|
||||
<input
|
||||
<Input
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -869,12 +869,12 @@
|
||||
"Поддерживается HTML-разметка Telegram"
|
||||
)}</small
|
||||
>
|
||||
<textarea
|
||||
<Textarea
|
||||
class="admin-textarea"
|
||||
rows="3"
|
||||
placeholder={at("user_placeholder_msg", {}, "Текст сообщения")}
|
||||
bind:value={$usersStore.userMessageDraft}
|
||||
></textarea>
|
||||
/>
|
||||
</Label.Root>
|
||||
<div class="admin-message-actions">
|
||||
<AdminButton
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script>
|
||||
import { Input } from "$components/ui/index.js";
|
||||
import { Label } from "$components/ui/primitives.js";
|
||||
import {
|
||||
AdminBadge,
|
||||
@@ -107,7 +108,7 @@
|
||||
|
||||
<div class="admin-toolbar admin-toolbar-users">
|
||||
<div class="admin-toolbar-search">
|
||||
<input
|
||||
<Input
|
||||
type="search"
|
||||
class="input"
|
||||
placeholder={at("users_search_placeholder", {}, "ID, @username или email")}
|
||||
|
||||
Reference in New Issue
Block a user