Refine subscription panel layout and feedback
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
export const HARBOR_VERSIONS = Object.freeze({
|
export const HARBOR_VERSIONS = Object.freeze({
|
||||||
macClient: '0.23.3',
|
macClient: '0.23.4',
|
||||||
gatewayClient: '0.24.3',
|
gatewayClient: '0.24.4',
|
||||||
gatewayBackend: '0.24.0',
|
gatewayBackend: '0.24.0',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -46,18 +46,6 @@ interface SubscriptionFeatureOptions {
|
|||||||
onDismissError: () => void;
|
onDismissError: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function operationText(key: OperationKey) {
|
|
||||||
return ({
|
|
||||||
profileAdd: 'Добавляем подписку…',
|
|
||||||
profileRename: 'Переименовываем подписку…',
|
|
||||||
profileSelect: 'Сохраняем выбор сервера…',
|
|
||||||
profileActivate: 'Переключаем подписку…',
|
|
||||||
profileRefresh: 'Обновляем подписку…',
|
|
||||||
profileDelete: 'Удаляем подписку…',
|
|
||||||
serverApply: 'Применяем сервер…',
|
|
||||||
} as Partial<Record<OperationKey, string>>)[key] || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function profileServer(profile: ProfileSnapshot | undefined, serverId: string) {
|
function profileServer(profile: ProfileSnapshot | undefined, serverId: string) {
|
||||||
return profile?.servers.find((server) => server.id === serverId) || null;
|
return profile?.servers.find((server) => server.id === serverId) || null;
|
||||||
}
|
}
|
||||||
@@ -99,11 +87,6 @@ export function useSubscriptionFeature({
|
|||||||
: isSubscriptionUrlValid(normalizedUrl) ? 'valid' : 'invalid';
|
: isSubscriptionUrlValid(normalizedUrl) ? 'valid' : 'invalid';
|
||||||
const deleteProfile = profiles.find((profile) => profile.id === deleteId) || null;
|
const deleteProfile = profiles.find((profile) => profile.id === deleteId) || null;
|
||||||
const deleteStopsVpn = connected && selection.appliedProfileId === deleteId;
|
const deleteStopsVpn = connected && selection.appliedProfileId === deleteId;
|
||||||
const activeOperation = (Object.entries(operations) as Array<[
|
|
||||||
OperationKey,
|
|
||||||
OperationRegistrySnapshot[OperationKey],
|
|
||||||
]>).find(([, operation]) => operation?.status === 'running');
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const ids = new Set(profiles.map((profile) => profile.id));
|
const ids = new Set(profiles.map((profile) => profile.id));
|
||||||
setExpanded((current) => current.filter((id) => ids.has(id)));
|
setExpanded((current) => current.filter((id) => ids.has(id)));
|
||||||
@@ -220,7 +203,6 @@ export function useSubscriptionFeature({
|
|||||||
addError,
|
addError,
|
||||||
deleteProfile,
|
deleteProfile,
|
||||||
deleteStopsVpn,
|
deleteStopsVpn,
|
||||||
activeOperation,
|
|
||||||
refreshingIds,
|
refreshingIds,
|
||||||
revealVersions,
|
revealVersions,
|
||||||
panelRef,
|
panelRef,
|
||||||
@@ -301,9 +283,7 @@ function AddProfileForm({ feature }: { feature: SubscriptionFeatureController })
|
|||||||
onChange={(event) => feature.setUrl(event.target.value)}
|
onChange={(event) => feature.setUrl(event.target.value)}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<div className="client-profile-form-status" role="status">
|
{message && <div className="client-profile-form-status" role="status">{message}</div>}
|
||||||
{message || '\u00a0'}
|
|
||||||
</div>
|
|
||||||
<div className="client-profile-form-actions">
|
<div className="client-profile-form-actions">
|
||||||
{feature.profiles.length > 0 && <button type="button" onClick={feature.cancelAdd}>Отмена</button>}
|
{feature.profiles.length > 0 && <button type="button" onClick={feature.cancelAdd}>Отмена</button>}
|
||||||
<button
|
<button
|
||||||
@@ -482,9 +462,6 @@ export function SubscriptionPanel({
|
|||||||
onClick={feature.close}
|
onClick={feature.close}
|
||||||
>×</button>
|
>×</button>
|
||||||
</header>
|
</header>
|
||||||
<div className={`client-profiles-operation${feature.activeOperation ? ' is-active' : ''}`} role="status">
|
|
||||||
{feature.activeOperation ? operationText(feature.activeOperation[0]) : '\u00a0'}
|
|
||||||
</div>
|
|
||||||
{statusSlot}
|
{statusSlot}
|
||||||
<div className="client-profile-list">
|
<div className="client-profile-list">
|
||||||
{feature.profiles.map((profile) => <ProfileGroup
|
{feature.profiles.map((profile) => <ProfileGroup
|
||||||
|
|||||||
@@ -618,17 +618,16 @@
|
|||||||
|
|
||||||
.client-profile-body .client-server-row {
|
.client-profile-body .client-server-row {
|
||||||
grid-template-columns: minmax(0, 1fr) 64px;
|
grid-template-columns: minmax(0, 1fr) 64px;
|
||||||
min-height: 52px;
|
min-height: 44px;
|
||||||
border-bottom: 1px solid var(--client-border);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-body .client-server-row.is-selected {
|
.client-profile-body .client-server-row.is-selected {
|
||||||
background: color-mix(in oklch, var(--client-accent) 5%, transparent);
|
background: color-mix(in oklch, var(--client-accent) 2%, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-body .client-server-row .client-server {
|
.client-profile-body .client-server-row .client-server {
|
||||||
grid-column: 1;
|
grid-column: 1;
|
||||||
min-height: 51px;
|
min-height: 44px;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 18px minmax(0, 1fr) auto;
|
grid-template-columns: 18px minmax(0, 1fr) auto;
|
||||||
place-items: center start;
|
place-items: center start;
|
||||||
@@ -636,6 +635,7 @@
|
|||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
border: 0;
|
border: 0;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
animation: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-body .client-server-row .client-server::before {
|
.client-profile-body .client-server-row .client-server::before {
|
||||||
|
|||||||
@@ -60,54 +60,17 @@
|
|||||||
letter-spacing: 0.02em;
|
letter-spacing: 0.02em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profiles-operation {
|
|
||||||
min-height: 22px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-top: 8px;
|
|
||||||
color: var(--client-muted);
|
|
||||||
font-size: 9px;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.client-profiles-operation.is-active::before {
|
|
||||||
content: '';
|
|
||||||
width: 7px;
|
|
||||||
height: 7px;
|
|
||||||
border: 1px solid currentColor;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.client-profile-list {
|
.client-profile-list {
|
||||||
margin-top: 8px;
|
margin-top: 2px;
|
||||||
border-top: 1px solid var(--client-border);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-group {
|
.client-profile-group {
|
||||||
position: relative;
|
position: relative;
|
||||||
border-bottom: 1px solid var(--client-border);
|
padding: 2px 0;
|
||||||
animation: client-profile-group-in 520ms cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
||||||
}
|
|
||||||
|
|
||||||
.client-profile-group.is-active {
|
|
||||||
background: color-mix(in oklch, var(--client-accent) 3%, transparent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.client-profile-group.is-active .client-profile-title strong,
|
|
||||||
.client-profile-group.is-active .client-profile-selected-server {
|
|
||||||
color: var(--client-accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes client-profile-group-in {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
filter: blur(5px);
|
|
||||||
transform: translateY(8px);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-header {
|
.client-profile-header {
|
||||||
min-height: 72px;
|
min-height: 54px;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1fr) auto 36px 36px;
|
grid-template-columns: minmax(0, 1fr) auto 36px 36px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -116,11 +79,11 @@
|
|||||||
|
|
||||||
.client-profile-disclosure {
|
.client-profile-disclosure {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
min-height: 56px;
|
min-height: 48px;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 18px minmax(0, 1fr);
|
grid-template-columns: 18px minmax(0, 1fr);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 6px 0;
|
padding: 4px 0 4px 8px;
|
||||||
border: 0;
|
border: 0;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--client-text);
|
color: var(--client-text);
|
||||||
@@ -143,7 +106,7 @@
|
|||||||
.client-profile-title {
|
.client-profile-title {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 4px;
|
gap: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-title > span {
|
.client-profile-title > span {
|
||||||
@@ -172,10 +135,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-title em {
|
.client-profile-title em {
|
||||||
padding: 3px 6px;
|
padding: 0;
|
||||||
border: 1px solid color-mix(in oklch, var(--client-accent) 30%, transparent);
|
|
||||||
border-radius: 3px;
|
|
||||||
background: color-mix(in oklch, var(--client-accent) 8%, transparent);
|
|
||||||
color: var(--client-accent);
|
color: var(--client-accent);
|
||||||
font-size: 7px;
|
font-size: 7px;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
@@ -225,11 +185,19 @@
|
|||||||
|
|
||||||
.client-profile-refresh:hover:not(:disabled),
|
.client-profile-refresh:hover:not(:disabled),
|
||||||
.client-profile-refresh:focus-visible,
|
.client-profile-refresh:focus-visible,
|
||||||
.client-profile-delete:hover:not(:disabled),
|
.client-profile-delete:hover:not(:disabled) {
|
||||||
.client-profile-delete:focus-visible {
|
|
||||||
color: var(--client-accent);
|
color: var(--client-accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.client-profile-delete,
|
||||||
|
.client-profile-delete:focus-visible {
|
||||||
|
color: oklch(0.62 0.16 28);
|
||||||
|
}
|
||||||
|
|
||||||
|
.client-profile-delete:hover:not(:disabled) {
|
||||||
|
color: oklch(0.7 0.18 28);
|
||||||
|
}
|
||||||
|
|
||||||
.client-profile-refresh:hover:not(:disabled) svg,
|
.client-profile-refresh:hover:not(:disabled) svg,
|
||||||
.client-profile-refresh:focus-visible:not(.is-refreshing) svg {
|
.client-profile-refresh:focus-visible:not(.is-refreshing) svg {
|
||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
@@ -255,21 +223,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-body {
|
.client-profile-body {
|
||||||
max-height: 3200px;
|
|
||||||
padding: 0 0 4px;
|
padding: 0 0 4px;
|
||||||
overflow: hidden;
|
|
||||||
opacity: 1;
|
|
||||||
visibility: visible;
|
|
||||||
transition: max-height 560ms cubic-bezier(0.16, 1, 0.3, 1), opacity 260ms ease, padding 420ms ease, visibility 0s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-body[aria-hidden='true'] {
|
.client-profile-body[aria-hidden='true'] {
|
||||||
max-height: 0;
|
display: none;
|
||||||
padding-top: 0;
|
|
||||||
padding-bottom: 0;
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
transition: max-height 420ms cubic-bezier(0.16, 1, 0.3, 1), opacity 180ms ease, padding 320ms ease, visibility 0s 420ms;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-body .client-servers {
|
.client-profile-body .client-servers {
|
||||||
@@ -279,14 +237,13 @@
|
|||||||
|
|
||||||
.client-profile-selected-server {
|
.client-profile-selected-server {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 52px;
|
min-height: 44px;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 18px minmax(0, 1fr) auto;
|
grid-template-columns: 18px minmax(0, 1fr) auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-top: 1px solid var(--client-border);
|
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--client-text);
|
color: var(--client-text);
|
||||||
font: inherit;
|
font: inherit;
|
||||||
@@ -319,7 +276,7 @@
|
|||||||
|
|
||||||
.client-profile-selected-server:hover,
|
.client-profile-selected-server:hover,
|
||||||
.client-profile-selected-server:focus-visible {
|
.client-profile-selected-server:focus-visible {
|
||||||
background: color-mix(in oklch, var(--client-accent) 5%, transparent);
|
background: color-mix(in oklch, var(--client-accent) 2%, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-selected-server:focus-visible {
|
.client-profile-selected-server:focus-visible {
|
||||||
@@ -341,17 +298,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.client-subscription-sheet > .client-profile-add {
|
.client-subscription-sheet > .client-profile-add {
|
||||||
margin-top: 12px;
|
margin-top: 8px;
|
||||||
border-bottom: 0;
|
|
||||||
animation: client-profile-add-in 520ms cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes client-profile-add-in {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
filter: blur(5px);
|
|
||||||
transform: translateY(8px);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-activate {
|
.client-profile-activate {
|
||||||
@@ -365,13 +312,12 @@
|
|||||||
|
|
||||||
.client-profile-add-trigger {
|
.client-profile-add-trigger {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 24px;
|
margin-top: 10px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-server-hint,
|
.client-profile-server-hint,
|
||||||
.client-profile-local-status,
|
.client-profile-local-status {
|
||||||
.client-profile-form-status {
|
|
||||||
min-height: 18px;
|
min-height: 18px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: var(--client-muted);
|
color: var(--client-muted);
|
||||||
@@ -388,8 +334,7 @@
|
|||||||
.client-profile-add {
|
.client-profile-add {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
padding: 16px 0 20px;
|
padding: 10px 0 4px;
|
||||||
border-bottom: 1px solid var(--client-border);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-add label {
|
.client-profile-add label {
|
||||||
@@ -405,8 +350,9 @@
|
|||||||
.client-profile-add input {
|
.client-profile-add input {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
padding: 0 10px;
|
padding: 0 2px;
|
||||||
border: 1px solid var(--client-border);
|
border: 0;
|
||||||
|
border-bottom: 1px solid color-mix(in oklch, var(--client-border) 72%, transparent);
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@@ -415,11 +361,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-add input:focus {
|
.client-profile-add input:focus {
|
||||||
border: 1px solid var(--client-accent);
|
border-bottom-color: var(--client-accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-add input[aria-invalid='true'] {
|
.client-profile-add input[aria-invalid='true'] {
|
||||||
border: 1px solid oklch(0.68 0.15 28);
|
border-bottom-color: oklch(0.68 0.15 28);
|
||||||
}
|
}
|
||||||
|
|
||||||
.client-profile-form-actions {
|
.client-profile-form-actions {
|
||||||
@@ -487,12 +433,10 @@
|
|||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
.client-profile-chevron,
|
.client-profile-chevron,
|
||||||
.client-profile-body,
|
|
||||||
.client-profile-refresh,
|
.client-profile-refresh,
|
||||||
.client-profile-refresh svg,
|
.client-profile-refresh svg,
|
||||||
.client-profile-delete-lid,
|
.client-profile-delete-lid,
|
||||||
.client-profile-group,
|
.client-profile-group {
|
||||||
.client-subscription-sheet > .client-profile-add {
|
|
||||||
transition: none;
|
transition: none;
|
||||||
animation: none;
|
animation: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ test('server picker starts simple and reveals advanced controls on demand', () =
|
|||||||
assert.match(picker, /\.slice\(0, SIMPLE_SERVER_LIMIT\)/);
|
assert.match(picker, /\.slice\(0, SIMPLE_SERVER_LIMIT\)/);
|
||||||
assert.match(picker, /\{selected && <ServerRow/);
|
assert.match(picker, /\{selected && <ServerRow/);
|
||||||
assert.match(styles, /\.client-profile-body \.client-server-row \{[\s\S]*?grid-template-columns: minmax\(0, 1fr\) 64px;/);
|
assert.match(styles, /\.client-profile-body \.client-server-row \{[\s\S]*?grid-template-columns: minmax\(0, 1fr\) 64px;/);
|
||||||
assert.match(styles, /\.client-profile-body \.client-server-row\.is-selected \{[\s\S]*?background: color-mix\(in oklch, var\(--client-accent\) 5%, transparent\);/);
|
assert.match(styles, /\.client-profile-body \.client-server-row\.is-selected \{[\s\S]*?background: color-mix\(in oklch, var\(--client-accent\) 2%, transparent\);/);
|
||||||
assert.match(styles, /\.client-profile-body \.client-server-check-label \{[\s\S]*?display: inline;/);
|
assert.match(styles, /\.client-profile-body \.client-server-check-label \{[\s\S]*?display: inline;/);
|
||||||
assert.doesNotMatch(styles, /\.client-profile-body \.client-server-check::after/);
|
assert.doesNotMatch(styles, /\.client-profile-body \.client-server-check::after/);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -36,26 +36,26 @@ const expectedImports = [
|
|||||||
const sha256 = (value) => crypto.createHash('sha256').update(value).digest('hex');
|
const sha256 = (value) => crypto.createHash('sha256').update(value).digest('hex');
|
||||||
const acceptedLedger = {
|
const acceptedLedger = {
|
||||||
counts: {
|
counts: {
|
||||||
cascadeEdges: 792,
|
cascadeEdges: 790,
|
||||||
customProperties: 31,
|
customProperties: 31,
|
||||||
declarations: 2977,
|
declarations: 2941,
|
||||||
important: 0,
|
important: 0,
|
||||||
keyframes: 51,
|
keyframes: 49,
|
||||||
media: 13,
|
media: 13,
|
||||||
rules: 910,
|
rules: 906,
|
||||||
variableReferences: 338,
|
variableReferences: 328,
|
||||||
},
|
},
|
||||||
hashes: {
|
hashes: {
|
||||||
cascadeEdges: 'f83d896540885ddaf09e55551a2f1ba5b587dcebfc285cc305efe80136154d93',
|
cascadeEdges: '1f4fd4cc495ac8d430f0d3891a7d63db34ee44313b4f865b58de7c587378b261',
|
||||||
customProperties: 'c7dd331e4bad898c450568999d8c9c6837e275a79c365c7680e143026fde4545',
|
customProperties: 'c7dd331e4bad898c450568999d8c9c6837e275a79c365c7680e143026fde4545',
|
||||||
declarations: '14728723e4a95d6031b60eb39c0864da0ccc061e24798091cd093b6354a5d906',
|
declarations: 'c17ab95f3bccd3fca26b2707f07e5298deda0f6343e80d77dbc5df8e97ef0ecb',
|
||||||
duplicateKeyframes: '4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945',
|
duplicateKeyframes: '4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945',
|
||||||
duplicateSelectors: 'c0ec5c96e48cd2ceed32aa5050383bcf29c3c0b8f1b440ed6883435e3e9b964d',
|
duplicateSelectors: 'c0ec5c96e48cd2ceed32aa5050383bcf29c3c0b8f1b440ed6883435e3e9b964d',
|
||||||
keyframes: '9e87e997d0b776462ac3e495c7ced584871a5d9512226e5008eb84b4d311530a',
|
keyframes: 'bde9c628dc86cb8a4299d5397eb7a81c5fbc9481136a073130991d3182d0799d',
|
||||||
ruleDeclarationSequences: 'eac60ada2de39eff87713f71f5ca533cd831ee7d400d27eaa09562c29dfbfadd',
|
ruleDeclarationSequences: 'a0e34d9639e87e77a2a095503196f4472a95ac875e398908f184b64b5bf5feba',
|
||||||
selectors: 'e79f61996bcd2a806828406c0a626e87d60112f1b24264d60b8670f9b8f831af',
|
selectors: '7051c489e7dac8bd04f3cdeb44bda8c069793cff4232ea730d40a19545ea0475',
|
||||||
variableReferences: '5c56197ab72968fc007f333c0cc58f90b6ec90465d6273bc757b7c77503dd26e',
|
variableReferences: '37d0cec8ffda35b4b3823322c0e21802ad0d3252258deade0e2124bdc6eb6ca0',
|
||||||
witnesses: '7066589e7b69a5b3c728ff70430a8d6d3c6c6d562cea91377244c0754e18b8da',
|
witnesses: '1b0e3d6fb35dde7acd7b3597f290c2e8b2f25ca569e74b047457121967affc6f',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ test('tokens, shared primitives, and feature styles have one explicit owner', ()
|
|||||||
|
|
||||||
test('accepted stylesheet has pinned declaration, selector, keyframe, variable, and cascade ledgers', () => {
|
test('accepted stylesheet has pinned declaration, selector, keyframe, variable, and cascade ledgers', () => {
|
||||||
const witnesses = readStyleWitnesses(root);
|
const witnesses = readStyleWitnesses(root);
|
||||||
assert.equal(witnesses.length, 735);
|
assert.equal(witnesses.length, 734);
|
||||||
assert.equal(witnesses.filter((witness) => witness.unknown || witness.ancestorUnknown).length, 0);
|
assert.equal(witnesses.filter((witness) => witness.unknown || witness.ancestorUnknown).length, 0);
|
||||||
const ledger = createStyleLedger(readStyleSource(root), { witnesses });
|
const ledger = createStyleLedger(readStyleSource(root), { witnesses });
|
||||||
assert.deepEqual(ledger.counts, acceptedLedger.counts);
|
assert.deepEqual(ledger.counts, acceptedLedger.counts);
|
||||||
@@ -306,8 +306,8 @@ test('main owns one public stylesheet and the regrouped production CSS is determ
|
|||||||
assert.equal((main.match(/import ['"][^'"]+\.css['"]/g) || []).length, 1);
|
assert.equal((main.match(/import ['"][^'"]+\.css['"]/g) || []).length, 1);
|
||||||
|
|
||||||
const assets = fs.readdirSync(path.join(root, 'dist/assets')).filter((file) => file.endsWith('.css'));
|
const assets = fs.readdirSync(path.join(root, 'dist/assets')).filter((file) => file.endsWith('.css'));
|
||||||
assert.deepEqual(assets, ['index-pEpt1ReD.css']);
|
assert.deepEqual(assets, ['index-hHmAphe7.css']);
|
||||||
const built = fs.readFileSync(path.join(root, 'dist/assets', assets[0]));
|
const built = fs.readFileSync(path.join(root, 'dist/assets', assets[0]));
|
||||||
assert.equal(built.byteLength, 111837);
|
assert.equal(built.byteLength, 110356);
|
||||||
assert.equal(sha256(built), 'f797af224ecae5e0435c7fb165cc158a237d11654c48a8cb287b32b2230e6b0c');
|
assert.equal(sha256(built), '67a5df63d5ee0624c0e58f7fc9751c279a0c009c37abc8ef77567892c93da931');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -87,7 +87,8 @@ test('validation rejection parser preserves structured errors and normalizes non
|
|||||||
test('feature keeps exact slots, truthy closes and subscription DOM order', () => {
|
test('feature keeps exact slots, truthy closes and subscription DOM order', () => {
|
||||||
assert.match(feature, /const host = new URL\(normalizedUrl\)\.hostname;[\s\S]*if \(!await onAdd\(label, normalizedUrl\)\) return;[\s\S]*resetAdd\(\)/);
|
assert.match(feature, /const host = new URL\(normalizedUrl\)\.hostname;[\s\S]*if \(!await onAdd\(label, normalizedUrl\)\) return;[\s\S]*resetAdd\(\)/);
|
||||||
assert.match(feature, /if \(!await onForget\(deleteProfile\.id, deleteStopsVpn \? 'stop-and-delete' : 'delete'\)\) return;[\s\S]*setDeleteId\(''\)/);
|
assert.match(feature, /if \(!await onForget\(deleteProfile\.id, deleteStopsVpn \? 'stop-and-delete' : 'delete'\)\) return;[\s\S]*setDeleteId\(''\)/);
|
||||||
assert.match(feature, /client-profiles-operation[\s\S]*\{statusSlot\}[\s\S]*client-profile-list[\s\S]*feature\.adding[\s\S]*AddProfileForm[\s\S]*client-profile-add-trigger/);
|
assert.match(feature, /\{statusSlot\}[\s\S]*client-profile-list[\s\S]*feature\.adding[\s\S]*AddProfileForm[\s\S]*client-profile-add-trigger/);
|
||||||
|
assert.doesNotMatch(feature, /client-profiles-operation|activeOperation|operationText/);
|
||||||
assert.doesNotMatch(feature, /client-profiles-current|aria-label="Добавить подписку"/);
|
assert.doesNotMatch(feature, /client-profiles-current|aria-label="Добавить подписку"/);
|
||||||
assert.match(feature, /const drawerOpen = feature\.open && feature\.profiles\.length > 0/);
|
assert.match(feature, /const drawerOpen = feature\.open && feature\.profiles\.length > 0/);
|
||||||
assert.match(feature, /feature\.profiles\.length === 0 && <div className="client-form client-subscription-first-run"/);
|
assert.match(feature, /feature\.profiles\.length === 0 && <div className="client-form client-subscription-first-run"/);
|
||||||
|
|||||||
Reference in New Issue
Block a user