[a11y] re-enable and fix all failing plan tests (#7753)

* enable planning a11y tests

* Fix all a11y failing tests

* drive-by: missed clean

* test: attempt to fix parallelization

* split the test 3 ways

* lint

---------

Co-authored-by: Hill, John (ARC-TI)[KBR Wyle Services, LLC] <john.c.hill@nasa.gov>
This commit is contained in:
Rukmini Bose (Ruki) 2024-06-21 16:37:36 -07:00 committed by GitHub
parent a5770817cc
commit 554f77c42f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 463 additions and 370 deletions

View File

@ -8,8 +8,8 @@ executors:
- image: mcr.microsoft.com/playwright:v1.44.0-focal
environment:
NODE_ENV: development # Needed to ensure 'dist' folder created and devDependencies installed
PERCY_POSTINSTALL_BROWSER: 'true' # Needed to store the percy browser in cache deps
PERCY_LOGLEVEL: 'debug' # Enable DEBUG level logging for Percy (Issue: https://github.com/nasa/openmct/issues/5742)
PERCY_POSTINSTALL_BROWSER: "true" # Needed to store the percy browser in cache deps
PERCY_LOGLEVEL: "debug" # Enable DEBUG level logging for Percy (Issue: https://github.com/nasa/openmct/issues/5742)
PERCY_PARALLEL_TOTAL: 2
ubuntu:
machine:
@ -17,7 +17,7 @@ executors:
docker_layer_caching: true
commands:
build_and_install:
description: 'All steps used to build and install.'
description: "All steps used to build and install."
parameters:
node-version:
type: string
@ -27,7 +27,7 @@ commands:
node-version: << parameters.node-version >>
- node/install-packages
generate_and_store_version_and_filesystem_artifacts:
description: 'Track important packages and files'
description: "Track important packages and files"
steps:
- run: |
[[ $EUID -ne 0 ]] && (sudo mkdir -p /tmp/artifacts && sudo chmod 777 /tmp/artifacts) || (mkdir -p /tmp/artifacts && chmod 777 /tmp/artifacts)
@ -38,7 +38,7 @@ commands:
- store_artifacts:
path: /tmp/artifacts/
generate_e2e_code_cov_report:
description: 'Generate e2e code coverage artifacts and publish to codecov.io. Needed to that we can ignore the exit code status of the npm run test'
description: "Generate e2e code coverage artifacts and publish to codecov.io. Needed to that we can ignore the exit code status of the npm run test"
parameters:
suite:
type: string
@ -102,7 +102,7 @@ jobs:
node-version: lts/hydrogen
- when: #Only install chrome-beta when running the 'full' suite to save $$$
condition:
equal: ['full', <<parameters.suite>>]
equal: ["full", <<parameters.suite>>]
steps:
- run: npx playwright install chrome-beta
- run:
@ -230,7 +230,7 @@ jobs:
steps:
- build_and_install:
node-version: lts/iron
- run: npm run test:e2e:visual:<<parameters.suite>>
- run: SHARD="$((${CIRCLE_NODE_INDEX}+1))"; npm run test:e2e:visual:<<parameters.suite>> -- --shard=${SHARD}/${CIRCLE_NODE_TOTAL}
- store_test_results:
path: test-results/results.xml
- store_artifacts:
@ -282,7 +282,7 @@ workflows:
- e2e-couchdb
triggers:
- schedule:
cron: '0 0 * * *'
cron: "0 0 * * *"
filters:
branches:
only:

View File

@ -24,91 +24,15 @@ import percySnapshot from '@percy/playwright';
import fs from 'fs';
import { createDomainObjectWithDefaults, createPlanFromJSON } from '../../appActions.js';
import { test } from '../../avpFixtures.js';
import { scanForA11yViolations, test } from '../../avpFixtures.js';
import { VISUAL_FIXED_URL } from '../../constants.js';
import {
createTimelistWithPlanAndSetActivityInProgress,
getFirstActivity,
setBoundsToSpanAllActivities,
setDraftStatusForPlan
} from '../../helper/planningUtils.js';
const examplePlanSmall1 = JSON.parse(
fs.readFileSync(new URL('../../test-data/examplePlans/ExamplePlan_Small1.json', import.meta.url))
);
import { setBoundsToSpanAllActivities, setDraftStatusForPlan } from '../../helper/planningUtils.js';
const examplePlanSmall2 = JSON.parse(
fs.readFileSync(new URL('../../test-data/examplePlans/ExamplePlan_Small2.json', import.meta.url))
);
test.describe('Visual - Timelist progress bar @clock', () => {
const firstActivity = getFirstActivity(examplePlanSmall1);
test.use({
clockOptions: {
now: firstActivity.end + 10000,
shouldAdvanceTime: true
}
});
test.beforeEach(async ({ page }) => {
await createTimelistWithPlanAndSetActivityInProgress(page, examplePlanSmall1);
await page.getByLabel('Click to collapse items').click();
});
test('progress pie is full', async ({ page, theme }) => {
// Progress pie is completely full and doesn't update if now is greater than the end time
await percySnapshot(page, `Time List with Activity in Progress (theme: ${theme})`);
});
});
test.describe('Visual - Planning', () => {
test.beforeEach(async ({ page }) => {
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
});
test('Plan View', async ({ page, theme }) => {
const plan = await createPlanFromJSON(page, {
name: 'Plan Visual Test',
json: examplePlanSmall2
});
await setBoundsToSpanAllActivities(page, examplePlanSmall2, plan.url);
await percySnapshot(page, `Plan View (theme: ${theme})`);
});
test('Resize Plan View @2p', async ({ browser, theme }) => {
// need to set viewport to null to allow for resizing
const newContext = await browser.newContext({
viewport: null
});
const newPage = await newContext.newPage();
await newPage.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
const plan = await createPlanFromJSON(newPage, {
name: 'Plan Visual Test',
json: examplePlanSmall2
});
await setBoundsToSpanAllActivities(newPage, examplePlanSmall2, plan.url);
// resize the window
await newPage.setViewportSize({ width: 800, height: 600 });
await percySnapshot(newPage, `Plan View resized (theme: ${theme})`);
});
test('Plan View w/ draft status', async ({ page, theme }) => {
const plan = await createPlanFromJSON(page, {
name: 'Plan Visual Test (Draft)',
json: examplePlanSmall2
});
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
await setDraftStatusForPlan(page, plan);
await setBoundsToSpanAllActivities(page, examplePlanSmall2, plan.url);
await percySnapshot(page, `Plan View w/ draft status (theme: ${theme})`);
});
});
test.describe('Visual - Gantt Chart', () => {
test.describe('Visual - Gantt Chart @a11y', () => {
test.beforeEach(async ({ page }) => {
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
});
@ -178,8 +102,7 @@ test.describe('Visual - Gantt Chart', () => {
);
});
});
// FIXME: https://github.com/nasa/openmct/issues/7421
// Currently has contrast failures
// test.afterEach(async ({ page }, testInfo) => {
// await scanForA11yViolations(page, testInfo.title);
// });
test.afterEach(async ({ page }, testInfo) => {
await scanForA11yViolations(page, testInfo.title);
});

View File

@ -0,0 +1,59 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2024, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
import percySnapshot from '@percy/playwright';
import fs from 'fs';
import { scanForA11yViolations, test } from '../../avpFixtures.js';
import {
createTimelistWithPlanAndSetActivityInProgress,
getFirstActivity
} from '../../helper/planningUtils.js';
const examplePlanSmall1 = JSON.parse(
fs.readFileSync(new URL('../../test-data/examplePlans/ExamplePlan_Small1.json', import.meta.url))
);
test.describe('Visual - Timelist progress bar @clock @a11y', () => {
const firstActivity = getFirstActivity(examplePlanSmall1);
test.use({
clockOptions: {
now: firstActivity.end + 10000,
shouldAdvanceTime: true
}
});
test.beforeEach(async ({ page }) => {
await createTimelistWithPlanAndSetActivityInProgress(page, examplePlanSmall1);
await page.getByLabel('Click to collapse items').click();
});
test('progress pie is full', async ({ page, theme }) => {
// Progress pie is completely full and doesn't update if now is greater than the end time
await percySnapshot(page, `Time List with Activity in Progress (theme: ${theme})`);
});
});
test.afterEach(async ({ page }, testInfo) => {
await scanForA11yViolations(page, testInfo.title);
});

View File

@ -0,0 +1,113 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2024, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
import percySnapshot from '@percy/playwright';
import fs from 'fs';
import { createPlanFromJSON } from '../../appActions.js';
import { scanForA11yViolations, test } from '../../avpFixtures.js';
import { VISUAL_FIXED_URL } from '../../constants.js';
import {
createTimelistWithPlanAndSetActivityInProgress,
getFirstActivity,
setBoundsToSpanAllActivities,
setDraftStatusForPlan
} from '../../helper/planningUtils.js';
const examplePlanSmall1 = JSON.parse(
fs.readFileSync(new URL('../../test-data/examplePlans/ExamplePlan_Small1.json', import.meta.url))
);
const examplePlanSmall2 = JSON.parse(
fs.readFileSync(new URL('../../test-data/examplePlans/ExamplePlan_Small2.json', import.meta.url))
);
test.describe('Visual - Timelist progress bar @clock @a11y', () => {
const firstActivity = getFirstActivity(examplePlanSmall1);
test.use({
clockOptions: {
now: firstActivity.end + 10000,
shouldAdvanceTime: true
}
});
test.beforeEach(async ({ page }) => {
await createTimelistWithPlanAndSetActivityInProgress(page, examplePlanSmall1);
await page.getByLabel('Click to collapse items').click();
});
test('progress pie is full', async ({ page, theme }) => {
// Progress pie is completely full and doesn't update if now is greater than the end time
await percySnapshot(page, `Time List with Activity in Progress (theme: ${theme})`);
});
});
test.describe('Visual - Plan View @a11y', () => {
test.beforeEach(async ({ page }) => {
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
});
test('Plan View', async ({ page, theme }) => {
const plan = await createPlanFromJSON(page, {
name: 'Plan Visual Test',
json: examplePlanSmall2
});
await setBoundsToSpanAllActivities(page, examplePlanSmall2, plan.url);
await percySnapshot(page, `Plan View (theme: ${theme})`);
});
test('Resize Plan View @2p', async ({ browser, theme }) => {
// need to set viewport to null to allow for resizing
const newContext = await browser.newContext({
viewport: null
});
const newPage = await newContext.newPage();
await newPage.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
const plan = await createPlanFromJSON(newPage, {
name: 'Plan Visual Test',
json: examplePlanSmall2
});
await setBoundsToSpanAllActivities(newPage, examplePlanSmall2, plan.url);
// resize the window
await newPage.setViewportSize({ width: 800, height: 600 });
await percySnapshot(newPage, `Plan View resized (theme: ${theme})`);
});
test('Plan View w/ draft status', async ({ page, theme }) => {
const plan = await createPlanFromJSON(page, {
name: 'Plan Visual Test (Draft)',
json: examplePlanSmall2
});
await page.goto(VISUAL_FIXED_URL, { waitUntil: 'domcontentloaded' });
await setDraftStatusForPlan(page, plan);
await setBoundsToSpanAllActivities(page, examplePlanSmall2, plan.url);
await percySnapshot(page, `Plan View w/ draft status (theme: ${theme})`);
});
});
test.afterEach(async ({ page }, testInfo) => {
await scanForA11yViolations(page, testInfo.title);
});

View File

@ -96,7 +96,7 @@
"webpack-merge": "5.10.0"
},
"scripts": {
"clean": "rm -rf ./dist ./node_modules ./coverage ./html-test-results ./test-results ./.nyc_output",
"clean": "rm -rf ./dist ./node_modules ./coverage ./html-test-results ./e2e/test-results ./.nyc_output ./e2e/.nyc_output",
"start": "npx webpack serve --config ./.webpack/webpack.dev.mjs",
"start:prod": "npx webpack serve --config ./.webpack/webpack.prod.mjs",
"start:coverage": "npx webpack serve --config ./.webpack/webpack.coverage.mjs",
@ -161,4 +161,4 @@
"keywords": [
"nasa"
]
}
}

View File

@ -20,240 +20,240 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
.c-timelist {
& .nowMarker.hasCurrent {
height: 2px;
position: absolute;
z-index: 10;
background: cyan;
width: 100%;
& .nowMarker.hasCurrent {
height: 2px;
position: absolute;
z-index: 10;
background: cyan;
width: 100%;
}
.c-list-item {
/* Compact Time Lists; is a <tr> element */
@mixin sSelected($bgColor, $fgColor) {
&[s-selected] {
background: $bgColor !important;
border: 1px solid $colorSelectedFg !important;
color: $fgColor !important;
}
}
.c-list-item {
/* Compact Time Lists; is a <tr> element */
@mixin sSelected($bgColor, $fgColor) {
&[s-selected] {
background: $bgColor !important;
border: 1px solid $colorSelectedFg !important;
color: $fgColor !important;
}
}
td {
$p: $interiorMarginSm;
padding-top: $p;
padding-bottom: $p;
}
&.--is-past {
@include sSelected(transparent, $colorPastFgEm);
}
&.--is-current {
@include sSelected($colorCurrentBg, $colorCurrentFgEm);
background-color: $colorCurrentBg;
border-top: 1px solid $colorCurrentBorder !important;
color: $colorCurrentFgEm;
}
&.--is-future {
@include sSelected($colorFutureBg, $colorFutureFgEm);
background-color: $colorFutureBg;
border-top-color: $colorFutureBorder !important;
color: $colorFutureFgEm;
}
&.--is-in-progress {
@include sSelected($colorInProgressBg, $colorInProgressFgEm);
background-color: $colorInProgressBg;
}
&__value {
&.--duration {
width: 5%;
}
}
td {
$p: $interiorMarginSm;
padding-top: $p;
padding-bottom: $p;
}
&.--is-past {
@include sSelected(transparent, $colorPastFgEm);
}
&.--is-current {
@include sSelected($colorCurrentBg, $colorCurrentFgEm);
background-color: $colorCurrentBg;
border-top: 1px solid $colorCurrentBorder !important;
color: $colorCurrentFgEm;
}
&.--is-future {
@include sSelected($colorFutureBg, $colorFutureFgEm);
background-color: $colorFutureBg;
border-top-color: $colorFutureBorder !important;
color: $colorFutureFgEm;
}
&.--is-in-progress {
@include sSelected($colorInProgressBg, $colorInProgressFgEm);
background-color: $colorInProgressBg;
}
&__value {
&.--duration {
width: 5%;
}
}
}
}
/**************************************************** LARGE TIME LIST */
@mixin styleTliEm($colorEm) {
// Styles emphasized elements within c-tli.
.c-tli {
&__duration,
&__title,
&__time-hero-time {
color: $colorEm;
}
// Styles emphasized elements within c-tli.
.c-tli {
&__duration,
&__title,
&__time-hero-time {
color: $colorEm;
}
}
}
@mixin showTliGraphic($wGraphic) {
.c-tli__graphic {
&__#{$wGraphic} {
display: block;
}
.c-tli__graphic {
&__#{$wGraphic} {
display: block;
}
}
}
.c-timelist--large {
$textSm: 0.8em;
$textLg: 1.3em;
$textSm: 0.8em;
$textLg: 1.3em;
margin-right: $interiorMargin; // fend off from scrollbar
margin-right: $interiorMargin; // fend off from scrollbar
> * + * {
margin-top: $interiorMarginSm;
> * + * {
margin-top: $interiorMarginSm;
}
.c-tli {
// TODO: add styles for various activity statuses
$baseBg: $colorPastBg;
$baseFg: $colorPastFg;
$baseFgEm: $colorPastFgEm;
background: $baseBg;
color: $baseFg;
border-radius: $basicCr;
display: grid;
padding: $interiorMargin;
grid-template-columns: min-content 3fr 40px 1fr;
grid-column-gap: $interiorMargin;
&[s-selected] {
box-shadow: inset rgba($colorSelectedFg, 0.8) 0 0 0 1px;
color: $colorSelectedFg !important;
@include styleTliEm($colorSelectedFg);
}
.c-tli {
// TODO: add styles for various activity statuses
$baseBg: $colorPastBg;
$baseFg: $colorPastFg;
$baseFgEm: $colorPastFgEm;
@include styleTliEm($baseFgEm);
background: $baseBg;
color: $baseFg;
border-radius: $basicCr;
display: grid;
padding: $interiorMargin;
grid-template-columns: min-content 3fr 40px 1fr;
grid-column-gap: $interiorMargin;
&__activity-color {
align-items: start;
display: flex;
padding-top: 1px;
}
&[s-selected] {
box-shadow: inset rgba($colorSelectedFg, 0.8) 0 0 0 1px;
color: $colorSelectedFg !important;
&__activity-color-swatch {
$d: 16px;
border-radius: 50%;
box-shadow: rgba(black, 0.3) 0 0 2px 1px;
width: $d;
height: $d;
}
@include styleTliEm($colorSelectedFg);
&__title-and-bounds {
> * + * {
margin-top: $interiorMargin;
}
}
&__bounds {
display: flex;
flex-wrap: wrap;
align-items: center;
> * {
margin-right: $interiorMargin;
white-space: nowrap;
}
&.--has-duration {
.c-tli__start-time {
display: flex;
align-items: start;
&:after {
content: $glyph-icon-play;
font-family: symbolsfont;
font-size: 0.7em;
display: block;
margin-left: $interiorMargin;
margin-top: 2px;
}
}
}
}
@include styleTliEm($baseFgEm);
&__title {
font-size: $textLg;
}
&__activity-color {
align-items: start;
display: flex;
padding-top: 1px;
&__time-hero {
display: flex;
align-items: center;
justify-content: end;
}
&__time-hero-context-and-time {
align-items: center;
flex-wrap: wrap;
display: flex;
justify-content: end;
text-align: right;
> * + * {
margin-left: $interiorMargin;
}
}
&__time-hero-context {
font-size: $textSm;
text-transform: uppercase;
}
&__time-hero-time {
display: flex;
align-items: center;
font-size: $textLg;
white-space: nowrap;
&:before {
display: block;
font-family: symbolsfont;
font-size: 0.7em;
margin-right: 3px;
}
&.--is-countdown {
&:before {
content: $glyph-icon-minus;
}
}
&__activity-color-swatch {
$d: 16px;
border-radius: 50%;
box-shadow: rgba(black, 0.3) 0 0 2px 1px;
width: $d;
height: $d;
&.--is-countup {
&:before {
content: $glyph-icon-plus;
}
}
}
&__title-and-bounds {
> * + * {
margin-top: $interiorMargin;
}
&__graphic {
display: flex;
fill: $baseFg;
align-items: center;
svg {
> * {
display: none;
}
}
}
&__bounds {
display: flex;
flex-wrap: wrap;
align-items: center;
&.--is-current {
background-color: $colorCurrentBg;
color: $colorCurrentFg;
@include styleTliEm($colorCurrentFgEm);
}
> * {
margin-right: $interiorMargin;
white-space: nowrap;
}
&.--is-future {
background-color: $colorFutureBg;
color: $colorFutureFg;
@include styleTliEm($colorFutureFgEm);
}
&.--has-duration {
.c-tli__start-time {
display: flex;
align-items: start;
&:after {
content: $glyph-icon-play;
font-family: symbolsfont;
font-size: 0.7em;
display: block;
margin-left: $interiorMargin;
margin-top: 2px;
}
}
}
}
&__title {
font-size: $textLg;
}
&__time-hero {
display: flex;
align-items: center;
justify-content: end;
}
&__time-hero-context-and-time {
align-items: center;
flex-wrap: wrap;
display: flex;
justify-content: end;
text-align: right;
> * + * {
margin-left: $interiorMargin;
}
}
&__time-hero-context {
font-size: $textSm;
text-transform: uppercase;
}
&__time-hero-time {
display: flex;
align-items: center;
font-size: $textLg;
white-space: nowrap;
&:before {
display: block;
font-family: symbolsfont;
font-size: 0.7em;
margin-right: 3px;
}
&.--is-countdown {
&:before {
content: $glyph-icon-minus;
}
}
&.--is-countup {
&:before {
content: $glyph-icon-plus;
}
}
}
&__graphic {
display: flex;
fill: $baseFg;
align-items: center;
svg {
> * {
display: none;
}
}
}
&.--is-current {
background-color: $colorCurrentBg;
color: $colorCurrentFg;
@include styleTliEm($colorCurrentFgEm);
}
&.--is-future {
background-color: $colorFutureBg;
color: $colorFutureFg;
@include styleTliEm($colorFutureFgEm);
}
/************************************ ACTIVITY STATE STYLES */
/*
/************************************ ACTIVITY STATE STYLES */
/*
- 'In Progress' : itemState.inProgress
- 'Running Long' : itemState.inProgress && now > end datetime
- 'Overdue' : itemState.notStarted && now > start datetime
@ -263,85 +263,83 @@
- 'Ends' : itemState.inProgress && now > start datetime && now < end datetime
- 'Completed', 'Aborted', 'Skipped' : itemState.<that state>
*/
&.--is-not-started {
}
&.--is-in-progress {
@include showTliGraphic('pie');
background-color: $colorInProgressBg;
color: $colorInProgressFg;
}
&.--is-running-long {
@include showTliGraphic('alert-triangle');
background-color: $colorInProgressBg;
color: $colorInProgressFg;
}
&.--is-overdue,
&.--is-incomplete {
@include showTliGraphic('alert-triangle');
}
&.--is-completed {
@include showTliGraphic('check');
}
&.--is-aborted {
@include showTliGraphic('circle-slash');
}
&.--is-skipped {
@include showTliGraphic('skipped');
}
&__check {
// Overrides?
}
&__alert-triangle {
// Overrides?
}
&__circle-slash {
// Overrides?
}
&.--is-not-started {
}
&.--is-in-progress {
@include showTliGraphic('pie');
background-color: $colorInProgressBg;
color: $colorInProgressFg;
}
&.--is-running-long {
@include showTliGraphic('alert-triangle');
background-color: $colorInProgressBg;
color: $colorInProgressFg;
}
&.--is-overdue,
&.--is-incomplete {
@include showTliGraphic('alert-triangle');
}
&.--is-completed {
@include showTliGraphic('check');
}
&.--is-aborted {
@include showTliGraphic('circle-slash');
}
&.--is-skipped {
@include showTliGraphic('skipped');
}
&__check {
// Overrides?
}
&__alert-triangle {
// Overrides?
}
&__circle-slash {
// Overrides?
}
}
}
.c-svg-progress {
&__bg {
fill: rgba(black, 0.2);
}
&__bg {
fill: rgba(black, 0.2);
}
&__ticks {
fill: none;
stroke: $colorInProgressFg;
stroke-width: 6;
}
&__ticks {
fill: none;
stroke: $colorInProgressFg;
stroke-width: 6;
}
&__progress {
fill: $colorInProgressFgEm;
transform: translateX(50%) translateY(50%);
}
&__progress {
fill: $colorInProgressFgEm;
transform: translateX(50%) translateY(50%);
}
&__sweep-hand {
animation-name: sweep-hand;
animation-duration: 10s;
animation-iteration-count: infinite;
animation-timing-function: steps(12);
fill: $colorInProgressFg;
transform-origin: center;
}
&__sweep-hand {
animation-name: sweep-hand;
animation-duration: 10s;
animation-iteration-count: infinite;
animation-timing-function: steps(12);
fill: $colorInProgressFg;
transform-origin: center;
}
}
@keyframes sweep-hand {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}

View File

@ -130,7 +130,7 @@ $bodySize: 100%;
// Object labels
$objectLabelTypeIconOpacity: 0.8; //JOHN
$objectLabelNameColorFg: lighten($colorBodyFg, 10%);
$objectLabelNameColorFg: lighten($colorBodyFg, 20%);
// Layout
$shellMainPad: 4px 0;
@ -168,7 +168,7 @@ $colorDiagnostic: #a4b442;
$colorDiagnosticFg: #39461a;
$colorCommand: #3693bd;
$colorCommandFg: #fff;
$colorInfo: #2294a2;
$colorInfo: #198290;
$colorInfoFg: #fff;
$colorOk: #33cc33;
$colorOkFg: #fff;
@ -471,7 +471,7 @@ $colorPastBg: #444;
$colorPastFg: pushBack($colorBodyFg, 10%);
$colorPastFgEm: $colorBodyFg;
$colorCurrentBg: #666;
$colorCurrentFg: $colorBodyFg;
$colorCurrentFg: pullForward($colorBodyFg, 10%);
$colorCurrentFgEm: $colorBodyFgEm;
$colorCurrentBorder: $colorBodyBg;
$colorFutureBg: $colorPastBg;