chore: compact traffic cards

This commit is contained in:
3252a8
2026-05-28 21:52:38 +03:00
parent 2f192447ce
commit e998b9ddd1
3 changed files with 257 additions and 74 deletions
+1
View File
@@ -12,6 +12,7 @@ export {
ChevronRight,
ChevronsUpDown,
Circle,
CircleQuestionMark,
CircleX,
Coins,
Copy,
+165 -9
View File
@@ -360,6 +360,58 @@ a {
font-weight: 850;
}
.traffic-card-compact {
display: grid;
}
.traffic-card-compact .progress {
margin-top: 8px;
}
.traffic-summary-row {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: baseline;
gap: 8px;
min-width: 0;
line-height: 1.15;
}
.traffic-summary-left,
.traffic-summary-right {
align-items: baseline;
min-width: 0;
gap: 5px;
}
.traffic-summary-left {
display: block;
overflow: hidden;
color: var(--muted);
font-size: 11px;
text-overflow: ellipsis;
white-space: nowrap;
}
.traffic-summary-right {
display: inline-flex;
justify-content: flex-end;
color: var(--text);
font-size: 11px;
font-weight: 850;
text-align: right;
white-space: nowrap;
font-variant-numeric: tabular-nums;
}
.traffic-summary-separator {
color: color-mix(in srgb, var(--muted) 58%, transparent);
}
.traffic-summary-right .traffic-summary-separator {
flex: 0 0 auto;
}
.card-heading {
margin: 0 0 10px;
color: var(--text);
@@ -412,6 +464,9 @@ a {
.traffic-card-depleted .traffic-top span,
.traffic-card-depleted .traffic-top strong,
.traffic-card-depleted .traffic-summary-left,
.traffic-card-depleted .traffic-summary-right,
.traffic-card-depleted .traffic-summary-separator,
.traffic-card-depleted .traffic-meta,
.traffic-card-depleted .traffic-percent {
color: var(--danger-text);
@@ -456,6 +511,7 @@ a {
.premium-traffic-meta {
align-items: flex-start;
margin-top: 5px;
}
.premium-server-dropdown {
@@ -464,23 +520,57 @@ a {
min-width: 0;
}
.premium-server-dropdown summary {
display: inline-flex;
align-items: center;
gap: 6px;
.premium-server-dropdown-inline {
display: grid;
min-width: 0;
min-height: 32px;
margin: -6px -8px;
padding: 6px 8px;
}
.premium-server-dropdown summary {
min-width: 0;
min-height: 26px;
margin: -4px -7px 0;
padding: 4px 7px;
border-radius: 999px;
cursor: pointer;
list-style: none;
-webkit-tap-highlight-color: transparent;
transition:
background 0.16s ease,
color 0.16s ease;
}
.premium-server-dropdown-inline summary {
display: grid;
max-width: 100%;
min-height: 0;
margin: 0;
padding: 0;
}
.premium-server-summary {
grid-template-columns: minmax(0, 1fr) auto;
align-items: baseline;
gap: 8px;
}
.premium-summary-trigger {
display: inline-flex;
align-items: center;
min-width: 0;
gap: 6px;
overflow: hidden;
white-space: nowrap;
}
.premium-server-dropdown summary:focus {
outline: none;
}
.premium-server-dropdown summary:focus-visible {
background: color-mix(in srgb, var(--accent) 12%, transparent);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 22%, transparent);
}
.premium-server-dropdown summary::-webkit-details-marker {
display: none;
}
@@ -491,13 +581,64 @@ a {
white-space: nowrap;
}
.premium-summary-copy {
display: block;
}
.premium-summary-copy {
flex: 0 1 auto;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.premium-server-dropdown svg {
flex: 0 0 auto;
opacity: 0.72;
opacity: 0.82;
}
.premium-server-help-icon {
padding: 1px;
border-radius: 999px;
color: var(--muted);
background: color-mix(in srgb, var(--muted) 10%, transparent);
transition:
color 0.16s ease,
background 0.16s ease,
transform 0.18s ease;
}
.premium-server-dropdown summary:hover .premium-server-help-icon,
.premium-server-dropdown[open] .premium-server-help-icon {
color: var(--accent);
background: color-mix(in srgb, var(--accent) 14%, transparent);
}
.premium-server-list-dropdown {
margin-top: 8px;
display: grid;
grid-template-rows: 0fr;
margin-top: 0;
opacity: 0;
transform: translateY(-2px);
transform-origin: top;
transition:
grid-template-rows 0.22s ease,
margin-top 0.22s ease,
opacity 0.18s ease,
transform 0.22s ease;
}
.premium-server-dropdown[open] .premium-server-list-dropdown {
grid-template-rows: 1fr;
margin-top: 6px;
opacity: 1;
transform: translateY(0);
}
.premium-server-list-dropdown > div {
min-height: 0;
overflow: hidden;
}
.premium-detail-grid {
@@ -2466,6 +2607,15 @@ a {
--screen-gutter: 10px;
}
.traffic-summary-row {
gap: 6px;
}
.traffic-summary-left,
.traffic-summary-right {
font-size: 10px;
}
.period-grid,
.method-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
@@ -2496,6 +2646,12 @@ a {
.motion-height-stage.motion-height-locked {
transition: none !important;
}
.premium-server-dropdown summary,
.premium-server-help-icon,
.premium-server-list-dropdown {
transition: none !important;
}
}
@supports not (color: color-mix(in srgb, #000 50%, #fff)) {
+91 -65
View File
@@ -1,7 +1,7 @@
<script>
import {
CheckCircle2,
ChevronsUpDown,
CircleQuestionMark,
CircleX,
CreditCard,
Database,
@@ -58,6 +58,7 @@
}
function regularTrafficCardClass(sub = subscription) {
return [
"traffic-card-compact",
regularTrafficTopupBarClickable ? "traffic-card-clickable" : "",
regularTrafficDepleted(sub) ? "traffic-card-depleted" : "",
]
@@ -79,6 +80,11 @@
function premiumTitle(sub = subscription) {
return premiumTitleFn(sub, t);
}
function premiumTrafficMetaLabel(sub = subscription) {
return sub?.premium_is_limited
? t("wa_premium_access_limited", {}, "Доступ к premium временно ограничен")
: t("wa_premium_reset_monthly", {}, "Отдельный лимит на месяц");
}
function premiumServerLabels(sub) {
return premiumServerLabelsFn(sub);
}
@@ -166,7 +172,7 @@
</Card>
{#if subscription.active}
<Card class={regularTrafficCardClass(subscription)}>
<Card compact class={regularTrafficCardClass(subscription)}>
{#if regularTrafficTopupBarClickable}
<button
class="card-click-target"
@@ -175,45 +181,58 @@
aria-label={t("wa_add_traffic")}
></button>
{/if}
<div class="traffic-top">
<span>{t("wa_home_traffic_used")}</span>
<strong>{trafficLabel(subscription)}</strong>
<div class="traffic-summary-row">
<span class="traffic-summary-left">
{t("wa_home_traffic_used")}
<span class="traffic-summary-separator" aria-hidden="true">|</span>
{regularTrafficMetaLabel(subscription)}
</span>
<strong class="traffic-summary-right">
<span>{trafficLabel(subscription)}</span>
<span class="traffic-summary-separator" aria-hidden="true">|</span>
<span>{trafficPercent(subscription)}%</span>
</strong>
</div>
<LinearProgress value={trafficPercent(subscription)} label={t("wa_home_traffic_used")} />
<div class="traffic-meta">
<span>{regularTrafficMetaLabel(subscription)}</span>
<span class="traffic-percent">{trafficPercent(subscription)}%</span>
</div>
</Card>
{#if premiumTrafficAvailable(subscription) && subscription?.premium_unlimited_override}
<Card class="premium-traffic-card">
<div class="traffic-top">
<span>{premiumTitle(subscription)}</span>
<strong></strong>
</div>
<div class="traffic-meta premium-traffic-meta">
{#if premiumServerLabels(subscription).length}
<details class="premium-server-dropdown">
<summary>
<span>{t("wa_premium_unlimited", {}, "Безлимит на premium-сервера")}</span>
<ChevronsUpDown size={13} />
</summary>
<div class="premium-server-list premium-server-list-dropdown">
<div>
{#each premiumServerLabels(subscription).slice(0, 8) as label}
<span>{label}</span>
{/each}
</div>
<Card compact class="traffic-card-compact premium-traffic-card">
{#if premiumServerLabels(subscription).length}
<details class="premium-server-dropdown premium-server-dropdown-inline">
<summary class="traffic-summary-row premium-server-summary">
<span class="traffic-summary-left premium-summary-trigger">
<span class="premium-summary-copy">
{premiumTitle(subscription)}
<span class="traffic-summary-separator" aria-hidden="true">|</span>
{t("wa_premium_unlimited", {}, "Безлимит на premium-сервера")}
</span>
<CircleQuestionMark class="premium-server-help-icon" size={15} />
</span>
<strong class="traffic-summary-right"></strong>
</summary>
<div class="premium-server-list premium-server-list-dropdown">
<div>
{#each premiumServerLabels(subscription).slice(0, 8) as label}
<span>{label}</span>
{/each}
</div>
</details>
{:else}
<span>{t("wa_premium_unlimited", {}, "Безлимит на premium-сервера")}</span>
{/if}
</div>
</div>
</details>
{:else}
<div class="traffic-summary-row">
<span class="traffic-summary-left">
{premiumTitle(subscription)}
<span class="traffic-summary-separator" aria-hidden="true">|</span>
{t("wa_premium_unlimited", {}, "Безлимит на premium-сервера")}
</span>
<strong class="traffic-summary-right"></strong>
</div>
{/if}
</Card>
{:else if premiumTrafficAvailable(subscription) && Number(subscription?.premium_limit_bytes || 0) > 0}
<Card
class={`${premiumTrafficTopupBarClickable ? "traffic-card-clickable " : ""}premium-traffic-card${subscription?.premium_is_limited ? " premium-traffic-card-limited" : ""}`}
compact
class={`traffic-card-compact ${premiumTrafficTopupBarClickable ? "traffic-card-clickable " : ""}premium-traffic-card${subscription?.premium_is_limited ? " premium-traffic-card-limited" : ""}`}
>
{#if premiumTrafficTopupBarClickable}
<button
@@ -223,43 +242,50 @@
aria-label={t("wa_add_traffic_premium", { target: premiumTitle(subscription) })}
></button>
{/if}
<div class="traffic-top">
<span>{premiumTitle(subscription)}</span>
<strong>{premiumTrafficLabel(subscription)}</strong>
</div>
{#if premiumServerLabels(subscription).length}
<details class="premium-server-dropdown premium-server-dropdown-inline">
<summary class="traffic-summary-row premium-server-summary">
<span class="traffic-summary-left premium-summary-trigger">
<span class="premium-summary-copy">
{premiumTitle(subscription)}
<span class="traffic-summary-separator" aria-hidden="true">|</span>
{premiumTrafficMetaLabel(subscription)}
</span>
<CircleQuestionMark class="premium-server-help-icon" size={15} />
</span>
<strong class="traffic-summary-right">
<span>{premiumTrafficLabel(subscription)}</span>
<span class="traffic-summary-separator" aria-hidden="true">|</span>
<span>{premiumTrafficPercent(subscription)}%</span>
</strong>
</summary>
<div class="premium-server-list premium-server-list-dropdown">
<div>
{#each premiumServerLabels(subscription).slice(0, 8) as label}
<span>{label}</span>
{/each}
</div>
</div>
</details>
{:else}
<div class="traffic-summary-row">
<span class="traffic-summary-left">
{premiumTitle(subscription)}
<span class="traffic-summary-separator" aria-hidden="true">|</span>
{premiumTrafficMetaLabel(subscription)}
</span>
<strong class="traffic-summary-right">
<span>{premiumTrafficLabel(subscription)}</span>
<span class="traffic-summary-separator" aria-hidden="true">|</span>
<span>{premiumTrafficPercent(subscription)}%</span>
</strong>
</div>
{/if}
<LinearProgress
class="premium-progress"
value={premiumTrafficPercent(subscription)}
label={premiumTitle(subscription)}
/>
<div class="traffic-meta premium-traffic-meta">
{#if premiumServerLabels(subscription).length}
<details class="premium-server-dropdown">
<summary>
<span
>{subscription?.premium_is_limited
? t("wa_premium_access_limited", {}, "Доступ к premium временно ограничен")
: t("wa_premium_reset_monthly", {}, "Отдельный лимит на месяц")}</span
>
<ChevronsUpDown size={13} />
</summary>
<div class="premium-server-list premium-server-list-dropdown">
<div>
{#each premiumServerLabels(subscription).slice(0, 8) as label}
<span>{label}</span>
{/each}
</div>
</div>
</details>
{:else}
<span
>{subscription?.premium_is_limited
? t("wa_premium_access_limited", {}, "Доступ к premium временно ограничен")
: t("wa_premium_reset_monthly", {}, "Отдельный лимит на месяц")}</span
>
{/if}
<span class="traffic-percent">{premiumTrafficPercent(subscription)}%</span>
</div>
</Card>
{/if}
{:else if trialOfferAvailable}