Refine routing rule controls and responsive layout
This commit is contained in:
@@ -19,6 +19,7 @@ import { operationBlocked } from '../../state/operations.js';
|
||||
import { ConfirmationDialog } from '../../ui/ConfirmationDialog.js';
|
||||
import { Drawer } from '../../ui/Drawer.js';
|
||||
import { RailAction } from '../../ui/RailAction.js';
|
||||
import { Tooltip } from '../../ui/Tooltip.js';
|
||||
import {
|
||||
beginRuleReorder,
|
||||
crossedRuleIndex,
|
||||
@@ -760,19 +761,26 @@ function RuleOutboundPicker({
|
||||
disabled?: boolean;
|
||||
onChange: (value: RouteRule['outbound']) => void;
|
||||
}) {
|
||||
return <div className="client-rule-outbound" role="group" aria-label={`Маршрут правила ${index + 1}`}>
|
||||
{([['vpn', 'VPN'], ['direct', 'Напрямую']] as const).map(([outbound, label]) => (
|
||||
<button
|
||||
type="button"
|
||||
key={outbound}
|
||||
aria-pressed={value === outbound}
|
||||
disabled={disabled}
|
||||
onClick={() => onChange(outbound)}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
))}
|
||||
</div>;
|
||||
const direct = value === 'direct';
|
||||
const label = direct ? 'Напрямую' : 'VPN';
|
||||
return <span className="client-rule-outbound client-tooltip-anchor">
|
||||
<button
|
||||
className={direct ? 'is-direct' : 'is-vpn'}
|
||||
type="button"
|
||||
aria-label={`Маршрут правила ${index + 1}: ${label}. Переключить на ${direct ? 'VPN' : 'Напрямую'}`}
|
||||
aria-pressed={direct}
|
||||
disabled={disabled}
|
||||
onClick={() => onChange(direct ? 'vpn' : 'direct')}
|
||||
>
|
||||
{direct ? <svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M4 12h15M14 7l5 5-5 5" />
|
||||
</svg> : <svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M12 3 19 6v5c0 4.4-2.8 8-7 10-4.2-2-7-5.6-7-10V6l7-3Z" />
|
||||
<path d="m9 12 2 2 4-4" />
|
||||
</svg>}
|
||||
</button>
|
||||
<Tooltip>{label}</Tooltip>
|
||||
</span>;
|
||||
}
|
||||
|
||||
export function RoutingToggle({
|
||||
@@ -899,7 +907,11 @@ export function RoutingPanel({ feature, statusSlot }: { feature: RoutingFeature;
|
||||
</span>
|
||||
<section className="client-local-rules-group" aria-labelledby="local-rules-list-title">
|
||||
<span id="local-rules-list-title">Правила</span>
|
||||
<div className="client-local-rules-list">
|
||||
<div
|
||||
className={`client-local-rules-list${draftRules.length > 1 ? ' has-order-flow' : ''}`}
|
||||
role="list"
|
||||
aria-label="Правила применяются сверху вниз"
|
||||
>
|
||||
{feature.rules.map((rule, index) => {
|
||||
const [status, statusLabel] = localRuleStatus(
|
||||
rule,
|
||||
@@ -916,6 +928,7 @@ export function RoutingPanel({ feature, statusSlot }: { feature: RoutingFeature;
|
||||
className={`client-local-rule client-deletable-row is-${status}${rule.enabled ? '' : ' is-disabled'}${rule.removing ? ' is-removing' : ''}${lifted ? ' is-dragging' : ''}`}
|
||||
key={rule._key}
|
||||
data-rule-key={rule._key}
|
||||
role="listitem"
|
||||
style={{ viewTransitionName: rule.removing ? 'none' : rule._key }}
|
||||
inert={rule.removing ? true : undefined}
|
||||
>
|
||||
@@ -974,6 +987,20 @@ export function RoutingPanel({ feature, statusSlot }: { feature: RoutingFeature;
|
||||
value={rule.value}
|
||||
onChange={(event) => feature.change(index, 'value', event.target.value)}
|
||||
/>
|
||||
<RuleOutboundPicker
|
||||
value={rule.outbound}
|
||||
index={index}
|
||||
disabled={editorDisabled}
|
||||
onChange={(outbound) => feature.change(index, 'outbound', outbound)}
|
||||
/>
|
||||
<span
|
||||
className="client-local-rule-status client-tooltip-anchor"
|
||||
role="status"
|
||||
aria-label={`Состояние правила: ${statusLabel}`}
|
||||
>
|
||||
<span className="client-rule-status-dot" aria-hidden="true" />
|
||||
<Tooltip>{statusLabel}</Tooltip>
|
||||
</span>
|
||||
<button
|
||||
className="client-row-delete"
|
||||
type="button"
|
||||
@@ -988,15 +1015,6 @@ export function RoutingPanel({ feature, statusSlot }: { feature: RoutingFeature;
|
||||
aria-hidden="true"
|
||||
onAnimationEnd={() => feature.finishRemove(rule._key)}
|
||||
/>
|
||||
<div className="client-local-rule-meta">
|
||||
<RuleOutboundPicker
|
||||
value={rule.outbound}
|
||||
index={index}
|
||||
disabled={editorDisabled}
|
||||
onChange={(outbound) => feature.change(index, 'outbound', outbound)}
|
||||
/>
|
||||
<span className="client-local-rule-status" role="status">{statusLabel}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user