Improve startup animation and traffic chart headroom
Build and Deploy Gateway / build-and-push (push) Successful in 13s
Build and Deploy Gateway / deploy (push) Successful in 7s

This commit is contained in:
2026-08-07 22:03:18 +03:00
parent fbf22e0b88
commit b2a2ed7104
6 changed files with 54 additions and 19 deletions
+16 -6
View File
@@ -16,6 +16,8 @@ const AUTO_REFRESH_MS = 15_000;
const DEVICE_MOVE_MS = 520;
const COPY_FEEDBACK_MS = 800;
const TRAFFIC_DELTA_MS = 2_200;
const TRAFFIC_CHART_HEADROOM = 10;
const trafficChartY = (ratio) => 100 - ratio * (100 - TRAFFIC_CHART_HEADROOM);
function Tooltip({ children }) {
return <span className="client-tooltip" role="tooltip">{children}</span>;
@@ -62,8 +64,8 @@ function TrafficChart({ samples, scale, capacity, routeLabel, pinned }) {
x: (firstSlot + index) * 100 / Math.max(1, capacity - 1),
gateway,
proxy,
gatewayY: 100 - trafficScaleRatio(gateway, max, scale) * 100,
proxyY: 100 - trafficScaleRatio(proxy, max, scale) * 100,
gatewayY: trafficChartY(trafficScaleRatio(gateway, max, scale)),
proxyY: trafficChartY(trafficScaleRatio(proxy, max, scale)),
};
});
const previous = points.slice(0, -1);
@@ -108,7 +110,15 @@ function TrafficChart({ samples, scale, capacity, routeLabel, pinned }) {
document.body,
);
return <span className="client-device-traffic-chart" role="img" aria-label={`История трафика, шкала ${scale === 'log' ? 'логарифмическая' : 'линейная'}, максимум ${formatByteString(max)}`}>
return <span
className="client-device-traffic-chart"
role="img"
aria-label={`История трафика, шкала ${scale === 'log' ? 'логарифмическая' : 'линейная'}, максимум ${formatByteString(max)}`}
style={{
'--traffic-chart-top': `${TRAFFIC_CHART_HEADROOM}%`,
'--traffic-chart-mid': `${(100 + TRAFFIC_CHART_HEADROOM) / 2}%`,
}}
>
{pinned && max > 0n && <span className="client-device-traffic-axis" aria-hidden="true">
<span className="is-max">{formatByteString(max)}</span>
<span className="is-mid">{formatByteString(mid)}</span>
@@ -117,8 +127,8 @@ function TrafficChart({ samples, scale, capacity, routeLabel, pinned }) {
<span className="client-device-traffic-plot" onPointerMove={trackPointer} onPointerLeave={() => setHovered(null)}>
<svg viewBox="0 0 100 100" preserveAspectRatio="none" aria-hidden="true">
{pinned && <g className="client-device-traffic-grid">
<line x1="0" x2="100" y1="0" y2="0" />
<line x1="0" x2="100" y1="50" y2="50" />
<line x1="0" x2="100" y1={TRAFFIC_CHART_HEADROOM} y2={TRAFFIC_CHART_HEADROOM} />
<line x1="0" x2="100" y1={(100 + TRAFFIC_CHART_HEADROOM) / 2} y2={(100 + TRAFFIC_CHART_HEADROOM) / 2} />
<line x1="0" x2="100" y1="100" y2="100" />
</g>}
<g className="client-device-traffic-lines" style={{ '--sample-count': Math.max(1, capacity) }}>
@@ -165,7 +175,7 @@ function TrafficChart({ samples, scale, capacity, routeLabel, pinned }) {
</circle>}
</g>
{hovered && <g className="client-device-traffic-cursor">
<line x1={hovered.x} x2={hovered.x} y1="0" y2="100" />
<line x1={hovered.x} x2={hovered.x} y1={TRAFFIC_CHART_HEADROOM} y2="100" />
<circle className="is-gateway" cx={hovered.x} cy={hovered.gatewayY} r="2" />
{hovered.proxy > 0n && <circle className="is-proxy" cx={hovered.x} cy={hovered.proxyY} r="2" />}
</g>}