initial
@@ -0,0 +1,13 @@
|
||||
import './admin.scss';
|
||||
|
||||
import './scripts/onboarding';
|
||||
|
||||
function importAll( r ) {
|
||||
r.keys().forEach( r );
|
||||
}
|
||||
|
||||
importAll(
|
||||
require.context( '../components/', true, /\/script\.js$/ ),
|
||||
require.context( '../components/', true, /\/_style\.scss$/ ),
|
||||
require.context( '../includes/core/settings/', true, /\/field\.js$/ )
|
||||
);
|
||||
@@ -0,0 +1,342 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
@import "./styles/admin-color-scheme";
|
||||
@import "./styles/animations";
|
||||
|
||||
.vrts-list-table-page {
|
||||
|
||||
tbody {
|
||||
background-color: #f6f7f9;
|
||||
}
|
||||
|
||||
tr {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid $gray-10;
|
||||
|
||||
&:where(:not(.column-title)) > * {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-testing-status {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
margin: 0;
|
||||
|
||||
&--paused {
|
||||
color: $alert-red;
|
||||
}
|
||||
|
||||
&--running {
|
||||
color: $alert-green;
|
||||
}
|
||||
|
||||
&--waiting {
|
||||
color: #f97b06;
|
||||
}
|
||||
}
|
||||
|
||||
// .test-run-row {
|
||||
// background-color: #fff;
|
||||
// border: 1px solid $gray-10;
|
||||
|
||||
// &[data-unread] {
|
||||
// background-color: #FCFCFC;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
.vrts-test-runs-list-table:not(.vrts-test-runs-list-queue-table) {
|
||||
|
||||
.test-run-row[data-has-alerts] {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
td {
|
||||
|
||||
> div,
|
||||
strong {
|
||||
align-self: flex-start;
|
||||
|
||||
@media (min-width: 783px) {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&.column-title {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&.column-trigger,
|
||||
&.column-status {
|
||||
|
||||
@media (max-width: 782px) {
|
||||
padding-block: 10px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.column-vrts_testing_status {
|
||||
width: 3.5rem;
|
||||
|
||||
.vrts-status {
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.vrts-icon-status {
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
margin: 3px 10px 0 3px;
|
||||
background: $gray-700;
|
||||
vertical-align: top;
|
||||
|
||||
&--paused {
|
||||
background: $alert-red;
|
||||
}
|
||||
|
||||
&--running {
|
||||
background: $alert-green;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-metabox-notice {
|
||||
background: #fff;
|
||||
border: 1px solid $gray-10;
|
||||
border-left-width: 4px;
|
||||
padding: 12px;
|
||||
|
||||
&-is-info {
|
||||
border-left-color: $blue-50;
|
||||
}
|
||||
|
||||
&-is-error {
|
||||
border-left-color: $red-50;
|
||||
}
|
||||
|
||||
&-is-success {
|
||||
border-left-color: $alert-green;
|
||||
}
|
||||
|
||||
+ .vrts-metabox-notice {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
> :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
> :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-test-run-trigger {
|
||||
display: inline-block;
|
||||
border-radius: 32px;
|
||||
padding: 4px 10px;
|
||||
font-size: 13px;
|
||||
background: rgba(192, 192, 192, 0.15);
|
||||
color: $gray-80;
|
||||
|
||||
&--api {
|
||||
background: rgba(224, 84, 6, 0.15);
|
||||
color: #ae4204;
|
||||
}
|
||||
|
||||
&--scheduled {
|
||||
background: rgba(106, 26, 185, 0.1);
|
||||
color: #591b98;
|
||||
}
|
||||
|
||||
&--manual {
|
||||
background: rgba(5, 116, 206, 0.1);
|
||||
color: #045495;
|
||||
|
||||
}
|
||||
|
||||
&--update {
|
||||
background: rgba(200, 11, 147, 0.1);
|
||||
color: #a51d7f;
|
||||
}
|
||||
|
||||
&-notes {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-tooltip {
|
||||
position: relative;
|
||||
|
||||
&-icon {
|
||||
color: $blue-50;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&::before {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: currentcolor;
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
display: block;
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
padding: 0.5rem;
|
||||
width: 240px;
|
||||
z-index: 1000002;
|
||||
top: -10px;
|
||||
right: 20px;
|
||||
}
|
||||
|
||||
&-content-inner {
|
||||
display: block;
|
||||
background: #000;
|
||||
border-radius: 2px;
|
||||
color: #f0f0f0;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
padding: 0.725rem;
|
||||
|
||||
a {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover &-content {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-testing-toogle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
|
||||
.vrts-tooltip {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-action-button {
|
||||
display: grid !important;
|
||||
grid-template-columns: max-content max-content;
|
||||
|
||||
&__icons {
|
||||
position: relative;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
display: flex;
|
||||
transition: opacity 0.3s;
|
||||
grid-row: 1 / 1;
|
||||
grid-column: 1 / 1;
|
||||
}
|
||||
|
||||
&__info {
|
||||
grid-row: 1 / 1;
|
||||
grid-column: 2 / 3;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&__spinner {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 1;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: all 0.3s;
|
||||
|
||||
svg {
|
||||
overflow: visible;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
circle {
|
||||
stroke-width: 1.5px;
|
||||
stroke: $gray-5;
|
||||
}
|
||||
|
||||
path {
|
||||
stroke-width: 1.5px;
|
||||
animation: 1.4s linear 0s infinite normal both paused vrts-rotate;
|
||||
}
|
||||
}
|
||||
|
||||
&[data-vrts-loading="true"] {
|
||||
|
||||
.vrts-action-button__icon {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.vrts-action-button__spinner {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
|
||||
path {
|
||||
animation-play-state: running;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&[data-vrts-action-state="primary"] {
|
||||
|
||||
[data-vrts-action-state-secondary] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&[data-vrts-action-state="secondary"] {
|
||||
|
||||
[data-vrts-action-state-primary] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-gradient-loader {
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: calc(100% - 1px);
|
||||
background: linear-gradient(90deg, #ddd, #fff, #ddd);
|
||||
background-size: 200% 100%;
|
||||
animation: vrts-shimmer 1.5s linear paused infinite;
|
||||
transition: opacity 0.2s, visibility 0.2s;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
z-index: 10;
|
||||
|
||||
[data-vrts-loading="true"] > & {
|
||||
opacity: 0.6;
|
||||
visibility: visible;
|
||||
animation-play-state: running;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import './editor.scss';
|
||||
|
||||
function importAll( r ) {
|
||||
r.keys().forEach( r );
|
||||
}
|
||||
|
||||
importAll( require.context( '../editor/plugins/', true, /\/index\.js$/ ) );
|
||||
@@ -0,0 +1,113 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
@import "./styles/admin-color-scheme";
|
||||
@import "./styles/animations";
|
||||
|
||||
.vrts_post_options_metabox {
|
||||
|
||||
figcaption {
|
||||
|
||||
> :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
> :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.figure {
|
||||
margin: 0;
|
||||
|
||||
&-link {
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&-title {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
&-image {
|
||||
aspect-ratio: 16/9;
|
||||
border: solid 1px #bfbfbf;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center top;
|
||||
}
|
||||
|
||||
.howto {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.settings {
|
||||
margin: 1.5rem 0;
|
||||
|
||||
&-title {
|
||||
margin-bottom: 0.5rem;
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
label {
|
||||
text-transform: none;
|
||||
color: rgb(117, 117, 117);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-testing-status {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
margin-bottom: 0;
|
||||
|
||||
&--paused {
|
||||
color: $alert-red;
|
||||
}
|
||||
|
||||
&--waiting {
|
||||
color: #f97b06;
|
||||
}
|
||||
|
||||
&--running {
|
||||
color: $alert-green;
|
||||
}
|
||||
|
||||
&-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
margin: 1.5rem 0;
|
||||
|
||||
> :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
> :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.dashicons {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 5px;
|
||||
font-size: 0.75rem;
|
||||
color: $gray-700;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="17" height="24" viewBox="0 0 17 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.2818 14.1615L9.7663 19.677V0H7.53028V19.677L1.86568 14.1615L0.375 15.6522L8.57376 24L16.7725 15.6522L15.2818 14.1615Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 258 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="17" height="24" viewBox="0 0 17 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.69064 0.5L0.833496 8.5L2.26207 9.92857L7.69064 4.64286V23.5H9.8335V4.64286L15.1192 9.92857L16.5478 8.5L8.69064 0.5Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 255 B |
@@ -0,0 +1,4 @@
|
||||
|
||||
<svg width="6" height="12" viewBox="0 0 6 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.95385 9.72248L2.23269 6.00132L5.95385 2.28017L5.20962 0.791707L0 6.00132L5.20962 11.2109L5.95385 9.72248Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 244 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="21" height="24" viewBox="0 0 21 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.5 3C7.5 2.17031 6.82969 1.5 6 1.5C5.17031 1.5 4.5 2.17031 4.5 3V6H1.5C0.670312 6 0 6.67031 0 7.5C0 8.32969 0.670312 9 1.5 9H6C6.82969 9 7.5 8.32969 7.5 7.5V3ZM1.5 15C0.670312 15 0 15.6703 0 16.5C0 17.3297 0.670312 18 1.5 18H4.5V21C4.5 21.8297 5.17031 22.5 6 22.5C6.82969 22.5 7.5 21.8297 7.5 21V16.5C7.5 15.6703 6.82969 15 6 15H1.5ZM16.5 3C16.5 2.17031 15.8297 1.5 15 1.5C14.1703 1.5 13.5 2.17031 13.5 3V7.5C13.5 8.32969 14.1703 9 15 9H19.5C20.3297 9 21 8.32969 21 7.5C21 6.67031 20.3297 6 19.5 6H16.5V3ZM15 15C14.1703 15 13.5 15.6703 13.5 16.5V21C13.5 21.8297 14.1703 22.5 15 22.5C15.8297 22.5 16.5 21.8297 16.5 21V18H19.5C20.3297 18 21 17.3297 21 16.5C21 15.6703 20.3297 15 19.5 15H15Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 827 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="19" height="18" viewBox="0 0 19 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.10755 1.25781L15.6425 5.14772C15.8084 5.25563 15.9392 5.3976 16.0347 5.57361C16.13 5.74962 16.1777 5.93685 16.1777 6.13532V13.9812C16.1777 14.3571 16.0475 14.6754 15.787 14.9358C15.5265 15.1963 15.2083 15.3266 14.8324 15.3266H3.38274C3.00678 15.3266 2.68856 15.1963 2.42807 14.9358C2.16759 14.6754 2.03735 14.3571 2.03735 13.9812V6.13532C2.03735 5.93685 2.08505 5.74962 2.18043 5.57361C2.27594 5.3976 2.40668 5.25563 2.57264 5.14772L9.10755 1.25781ZM9.10755 9.48435L14.9125 6.02368L9.10755 2.56301L3.30255 6.02368L9.10755 9.48435ZM9.10755 10.7895L3.1537 7.23157V13.9812C3.1537 14.048 3.17516 14.1029 3.21808 14.1458C3.26099 14.1888 3.31588 14.2102 3.38274 14.2102H14.8324C14.8992 14.2102 14.9541 14.1888 14.997 14.1458C15.0399 14.1029 15.0614 14.048 15.0614 13.9812V7.23157L9.10755 10.7895Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 930 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="19" height="18" viewBox="0 0 19 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.38249 14.5829C3.00653 14.5829 2.68831 14.4526 2.42783 14.1922C2.16735 13.9317 2.03711 13.6135 2.03711 13.2375V4.76481C2.03711 4.38885 2.16735 4.07063 2.42783 3.81015C2.68831 3.54967 3.00653 3.41943 3.38249 3.41943H10.8419C10.8067 3.60548 10.7878 3.79036 10.7854 3.97406C10.783 4.15777 10.7971 4.345 10.8276 4.53577H3.26788L9.1073 8.25693L11.7951 6.5424C11.9258 6.66545 12.0649 6.77634 12.2122 6.87508C12.3597 6.97381 12.5141 7.06182 12.6753 7.13909L9.1073 9.41625L3.15346 5.60914V13.2375C3.15346 13.3044 3.17491 13.3592 3.21783 13.4022C3.26075 13.4451 3.31564 13.4665 3.38249 13.4665H14.8321C14.899 13.4665 14.9539 13.4451 14.9968 13.4022C15.0397 13.3592 15.0611 13.3044 15.0611 13.2375V7.5313C15.2749 7.48355 15.4736 7.4206 15.6573 7.34245C15.8409 7.26418 16.0143 7.1683 16.1775 7.05481V13.2375C16.1775 13.6135 16.0473 13.9317 15.7868 14.1922C15.5263 14.4526 15.2081 14.5829 14.8321 14.5829H3.38249ZM14.3169 6.12452C13.7492 6.12452 13.2662 5.92531 12.8679 5.5269C12.4695 5.12849 12.2703 4.64548 12.2703 4.07788C12.2703 3.51016 12.4695 3.02709 12.8679 2.62868C13.2662 2.23039 13.7492 2.03125 14.3169 2.03125C14.8846 2.03125 15.3676 2.23039 15.7659 2.62868C16.1643 3.02709 16.3636 3.51016 16.3636 4.07788C16.3636 4.64548 16.1643 5.12849 15.7659 5.5269C15.3676 5.92531 14.8846 6.12452 14.3169 6.12452Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="21" height="24" viewBox="0 0 21 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1.5 1.5C0.670312 1.5 0 2.17031 0 3V7.5C0 8.32969 0.670312 9 1.5 9C2.32969 9 3 8.32969 3 7.5V4.5H6C6.82969 4.5 7.5 3.82969 7.5 3C7.5 2.17031 6.82969 1.5 6 1.5H1.5ZM3 16.5C3 15.6703 2.32969 15 1.5 15C0.670312 15 0 15.6703 0 16.5V21C0 21.8297 0.670312 22.5 1.5 22.5H6C6.82969 22.5 7.5 21.8297 7.5 21C7.5 20.1703 6.82969 19.5 6 19.5H3V16.5ZM15 1.5C14.1703 1.5 13.5 2.17031 13.5 3C13.5 3.82969 14.1703 4.5 15 4.5H18V7.5C18 8.32969 18.6703 9 19.5 9C20.3297 9 21 8.32969 21 7.5V3C21 2.17031 20.3297 1.5 19.5 1.5H15ZM21 16.5C21 15.6703 20.3297 15 19.5 15C18.6703 15 18 15.6703 18 16.5V19.5H15C14.1703 19.5 13.5 20.1703 13.5 21C13.5 21.8297 14.1703 22.5 15 22.5H19.5C20.3297 22.5 21 21.8297 21 21V16.5Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 824 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.43627 2.69941C4.87225 2.5812 5.53414 2.47266 6.49519 2.47266C7.47028 2.47266 8.28227 2.63804 9.04284 2.79296L9.05806 2.79606C9.82804 2.95288 11.5466 3.0979 12.407 3.0979C13.3082 3.0979 13.8976 3.04673 14.2535 2.99826C14.4312 2.97405 14.55 2.95061 14.6197 2.93479C14.6546 2.92688 14.6771 2.9209 14.6884 2.91771L14.6968 2.91527C14.8587 2.86242 15.0363 2.88968 15.175 2.98897C15.3155 3.08959 15.3989 3.25182 15.3989 3.42467V10.051C15.3989 10.2804 15.2529 10.4843 15.0358 10.5582L14.8631 10.051C15.0358 10.5582 15.0358 10.5582 15.0358 10.5582L15.0339 10.5589L15.0317 10.5596L15.0268 10.5612L15.0142 10.5652C15.0046 10.5682 14.9925 10.5718 14.9778 10.5759C14.9484 10.5841 14.9085 10.5945 14.857 10.6062C14.754 10.6296 14.6041 10.6584 14.3981 10.6864C13.9864 10.7425 13.3478 10.7959 12.407 10.7959C11.4319 10.7959 9.61997 10.6305 8.8594 10.4756L8.84418 10.4725C8.07419 10.3157 7.35557 10.1706 6.49519 10.1706C5.61427 10.1706 5.0482 10.2702 4.71671 10.3601C4.55104 10.405 4.44374 10.4475 4.38464 10.4742C4.35506 10.4876 4.33741 10.4971 4.33043 10.501L4.3284 10.5021C4.16589 10.6063 3.95942 10.6151 3.78824 10.5244C3.613 10.4315 3.50342 10.2493 3.50342 10.051V3.42467C3.50342 3.24697 3.59151 3.08083 3.73861 2.98112L4.03927 3.42467C3.73861 2.98112 3.73861 2.98112 3.73861 2.98112L3.73984 2.98029L3.74114 2.97942L3.7439 2.97758L3.75014 2.9735L3.7655 2.96381C3.77703 2.9567 3.79117 2.94834 3.80806 2.93891C3.84185 2.92005 3.88656 2.89699 3.94332 2.87134C4.05689 2.82002 4.2182 2.75854 4.43627 2.69941ZM4.57511 3.77577V9.29035C5.00877 9.18671 5.63104 9.09895 6.49519 9.09895C7.47028 9.09895 8.28227 9.26434 9.04284 9.41925L9.05806 9.42235C9.82804 9.57918 11.5466 9.7242 12.407 9.7242C13.3082 9.7242 13.8976 9.67302 14.2535 9.62456C14.2793 9.62104 14.3039 9.61754 14.3272 9.61408V4.06948C13.9144 4.122 13.2955 4.16959 12.407 4.16959C11.4319 4.16959 9.61997 4.0042 8.8594 3.84929L8.84418 3.84619C8.07419 3.68937 7.35557 3.54435 6.49519 3.54435C5.61427 3.54435 5.0482 3.64389 4.71671 3.73376C4.66363 3.74815 4.61654 3.7623 4.57511 3.77577Z" fill="currentColor"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.57169 8.65918V16.6355H3.5L3.50319 8.65918H4.57169Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.43627 2.69941C4.87225 2.5812 5.53414 2.47266 6.49519 2.47266C7.47028 2.47266 8.28227 2.63804 9.04284 2.79296L9.05806 2.79606C9.82804 2.95288 11.5466 3.0979 12.407 3.0979C13.3082 3.0979 13.8976 3.04673 14.2535 2.99826C14.4312 2.97405 14.55 2.95061 14.6197 2.93479C14.6546 2.92688 14.6771 2.9209 14.6884 2.91771L14.6968 2.91527C14.8587 2.86242 15.0363 2.88968 15.175 2.98897C15.3155 3.08959 15.3989 3.25182 15.3989 3.42467V10.051C15.3989 10.2804 15.2529 10.4843 15.0358 10.5582L14.8631 10.051C15.0358 10.5582 15.0358 10.5582 15.0358 10.5582L15.0339 10.5589L15.0317 10.5596L15.0268 10.5612L15.0142 10.5652C15.0046 10.5682 14.9925 10.5718 14.9778 10.5759C14.9484 10.5841 14.9085 10.5945 14.857 10.6062C14.754 10.6296 14.6041 10.6584 14.3981 10.6864C13.9864 10.7425 13.3478 10.7959 12.407 10.7959C11.4319 10.7959 9.61997 10.6305 8.8594 10.4756L8.84418 10.4725C8.07419 10.3157 7.35557 10.1706 6.49519 10.1706C5.61427 10.1706 5.0482 10.2702 4.71671 10.3601C4.55104 10.405 4.44374 10.4475 4.38464 10.4742C4.35506 10.4876 4.33741 10.4971 4.33043 10.501L4.3284 10.5021C4.16589 10.6063 3.95942 10.6151 3.78824 10.5244C3.613 10.4315 3.50342 10.2493 3.50342 10.051V3.42467C3.50342 3.24697 3.59151 3.08083 3.73861 2.98112L4.03927 3.42467C3.73861 2.98112 3.73861 2.98112 3.73861 2.98112L3.73984 2.98029L3.74114 2.97942L3.7439 2.97758L3.75014 2.9735L3.7655 2.96381C3.77703 2.9567 3.79117 2.94834 3.80806 2.93891C3.84185 2.92005 3.88656 2.89699 3.94332 2.87134C4.05689 2.82002 4.2182 2.75854 4.43627 2.69941ZM4.57511 3.77577V9.29035C5.00877 9.18671 5.63104 9.09895 6.49519 9.09895C7.47028 9.09895 8.28227 9.26434 9.04284 9.41925L9.05806 9.42235C9.82804 9.57918 11.5466 9.7242 12.407 9.7242C13.3082 9.7242 13.8976 9.67302 14.2535 9.62456C14.2793 9.62104 14.3039 9.61754 14.3272 9.61408V4.06948C13.9144 4.122 13.2955 4.16959 12.407 4.16959C11.4319 4.16959 9.61997 4.0042 8.8594 3.84929L8.84418 3.84619C8.07419 3.68937 7.35557 3.54435 6.49519 3.54435C5.61427 3.54435 5.0482 3.64389 4.71671 3.73376C4.66363 3.74815 4.61654 3.7623 4.57511 3.77577Z" fill="#B32D2E"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.57169 8.65918V16.6355H3.5L3.50319 8.65918H4.57169Z" fill="#B32D2E"/>
|
||||
<path d="M4.12842 9.55604V3.46766C4.17448 3.45279 4.22684 3.43716 4.28585 3.42128C4.65442 3.32206 5.28379 3.21216 6.26323 3.21216C7.21984 3.21216 8.01883 3.37227 8.87493 3.54541L8.89185 3.54883C9.73748 3.71986 11.7521 3.90246 12.8362 3.90246C13.8241 3.90246 14.5122 3.84991 14.9712 3.79193V9.91346C14.9453 9.91728 14.9179 9.92114 14.8892 9.92503C14.4935 9.97853 13.8382 10.035 12.8362 10.035C11.8796 10.035 9.96882 9.87492 9.11273 9.70178L9.09581 9.69835C8.25018 9.52732 7.34738 9.34473 6.26323 9.34473C5.30244 9.34473 4.61058 9.44162 4.12842 9.55604Z" fill="#B32D2E"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="25" height="25" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.75244 9.73359H11.0428V8.44324H9.75244V9.73359ZM9.75244 13.6046H11.0428V12.3142H9.75244V13.6046ZM9.75244 17.4755H11.0428V16.1852H9.75244V17.4755ZM13.6234 8.44324V9.73359H14.9138V8.44324H13.6234ZM13.6234 13.6046H14.9138V12.3142H13.6234V13.6046ZM13.6234 17.4755H14.9138V16.1852H13.6234V17.4755Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 431 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.7393 10.5191L10.9035 9.68332C11.0151 9.06697 10.8393 8.51283 10.376 8.0209C9.91286 7.52908 9.34445 7.33899 8.6708 7.45063L7.83503 6.61486C8.00297 6.53944 8.1752 6.48288 8.35171 6.44517C8.52822 6.40747 8.72141 6.38861 8.93128 6.38861C9.77573 6.38861 10.4926 6.6832 11.0817 7.27238C11.6709 7.86157 11.9655 8.57839 11.9655 9.42284C11.9655 9.63271 11.9467 9.82832 11.9089 10.0097C11.8712 10.1909 11.8147 10.3607 11.7393 10.5191ZM14.1065 12.8348L13.285 12.0649C13.7564 11.7051 14.175 11.3113 14.5409 10.8834C14.9068 10.4555 15.22 9.96861 15.4805 9.42284C14.8603 8.17005 13.9703 7.17464 12.8106 6.43661C11.6508 5.69858 10.3577 5.32957 8.93128 5.32957C8.57157 5.32957 8.21806 5.35438 7.87075 5.40399C7.52344 5.45361 7.18234 5.52803 6.84743 5.62726L5.98022 4.76005C6.45057 4.573 6.93097 4.43513 7.42142 4.34644C7.91187 4.25763 8.41515 4.21322 8.93128 4.21322C10.6754 4.21322 12.2483 4.69412 13.6499 5.65592C15.0515 6.61771 16.0739 7.87335 16.717 9.42284C16.4413 10.0878 16.0852 10.7085 15.6487 11.2849C15.2121 11.8612 14.698 12.3778 14.1065 12.8348ZM14.7076 17.14L11.6965 14.1515C11.3148 14.2928 10.8918 14.4083 10.4276 14.4979C9.9634 14.5876 9.46464 14.6325 8.93128 14.6325C7.18234 14.6325 5.60947 14.1516 4.21267 13.1898C2.81575 12.228 1.79336 10.9723 1.14551 9.42284C1.42025 8.76544 1.77519 8.15219 2.21032 7.5831C2.64544 7.01389 3.12442 6.52034 3.64724 6.10245L1.58628 4.01861L2.3707 3.23438L15.4919 16.3555L14.7076 17.14ZM4.43166 6.88669C4.03846 7.19964 3.65605 7.57584 3.28443 8.01531C2.91281 8.45466 2.61201 8.92383 2.38205 9.42284C3.00224 10.6756 3.89222 11.671 5.05198 12.4091C6.21173 13.1471 7.50484 13.5161 8.93128 13.5161C9.27003 13.5161 9.60735 13.4875 9.94325 13.4302C10.279 13.373 10.5638 13.3139 10.7976 13.2528L9.8558 12.2881C9.72891 12.3396 9.58198 12.3806 9.41503 12.4111C9.24807 12.4417 9.08682 12.4571 8.93128 12.4571C8.08682 12.4571 7.37001 12.1625 6.78082 11.5733C6.19164 10.9841 5.89705 10.2673 5.89705 9.42284C5.89705 9.27213 5.91237 9.11448 5.94301 8.94988C5.97352 8.78528 6.01451 8.63476 6.06599 8.49832L4.43166 6.88669Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.23096 13.5C5.81846 13.5 5.46537 13.3531 5.17171 13.0592C4.87787 12.7656 4.73096 12.4125 4.73096 12C4.73096 11.5875 4.87787 11.2344 5.17171 10.9408C5.46537 10.6469 5.81846 10.5 6.23096 10.5C6.64346 10.5 6.99662 10.6469 7.29046 10.9408C7.58412 11.2344 7.73096 11.5875 7.73096 12C7.73096 12.4125 7.58412 12.7656 7.29046 13.0592C6.99662 13.3531 6.64346 13.5 6.23096 13.5ZM12.0002 13.5C11.5877 13.5 11.2346 13.3531 10.941 13.0592C10.6471 12.7656 10.5002 12.4125 10.5002 12C10.5002 11.5875 10.6471 11.2344 10.941 10.9408C11.2346 10.6469 11.5877 10.5 12.0002 10.5C12.4127 10.5 12.7658 10.6469 13.0595 10.9408C13.3533 11.2344 13.5002 11.5875 13.5002 12C13.5002 12.4125 13.3533 12.7656 13.0595 13.0592C12.7658 13.3531 12.4127 13.5 12.0002 13.5ZM17.7695 13.5C17.357 13.5 17.0038 13.3531 16.71 13.0592C16.4163 12.7656 16.2695 12.4125 16.2695 12C16.2695 11.5875 16.4163 11.2344 16.71 10.9408C17.0038 10.6469 17.357 10.5 17.7695 10.5C18.182 10.5 18.535 10.6469 18.8287 10.9408C19.1225 11.2344 19.2695 11.5875 19.2695 12C19.2695 12.4125 19.1225 12.7656 18.8287 13.0592C18.535 13.3531 18.182 13.5 17.7695 13.5Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg viewBox="0 0 100 100" width="16" height="16" xmlns="http://www.w3.org/2000/svg" role="presentation" focusable="false">
|
||||
<circle cx="50" cy="50" r="50" vector-effect="non-scaling-stroke" fill="none"></circle>
|
||||
<path d="m 50 0 a 50 50 0 0 1 50 50" vector-effect="non-scaling-stroke" fill="none" stroke="currentColor" stroke-linecap="round" transform-origin="50 50"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 383 B |
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20" style="enable-background:new 0 0 20 20" xml:space="preserve"><path fill="black" d="M10.66 19a8.906 8.906 0 0 0 4.914-1.903H10.66V19zm0-3.194h6.254a9.27 9.27 0 0 0 1.236-1.935h-7.49v1.935zm0-3.226h7.992c.188-.63.305-1.279.348-1.936h-8.34v1.936zm7.992-5.16H10.66v1.936H19a8.772 8.772 0 0 0-.348-1.936zm-1.738-3.226H10.66V6.13h7.49v-.001a9.365 9.365 0 0 0-1.236-1.935zM10.66 1v1.904h4.914A8.913 8.913 0 0 0 10.66 1zM1 10a9.047 9.047 0 0 0 2.423 6.145 9.018 9.018 0 0 0 5.949 2.854V1a9.016 9.016 0 0 0-5.949 2.854A9.049 9.049 0 0 0 1 10z"/></svg>
|
||||
|
After Width: | Height: | Size: 626 B |
@@ -0,0 +1 @@
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" viewBox="0 0 245 136" style="enable-background:new 0 0 245 136" xml:space="preserve"><style>.st4{fill:#ababab}</style><path d="M0 0h245v136H0V0z" style="fill:#f6f7f7"/><defs><path id="SVGID_1_" d="M0 0h245v136H0z"/></defs><clipPath id="SVGID_00000075871332272239653010000001685538545955086748_"><use xlink:href="#SVGID_1_" style="overflow:visible"/></clipPath><g style="clip-path:url(#SVGID_00000075871332272239653010000001685538545955086748_)"><defs><filter id="Adobe_OpacityMaskFilter" filterUnits="userSpaceOnUse" x="0" y="27.8" width="245" height=".4"><feColorMatrix values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0"/></filter></defs><mask maskUnits="userSpaceOnUse" x="0" y="27.8" width="245" height=".4" id="c_00000131339708796536986220000018336221103987946920_"><path d="M0 0h245v28H0V0z" style="fill:#fff;filter:url(#Adobe_OpacityMaskFilter)"/></mask><path d="M245 27.8H0v.4h245v-.4z" style="mask:url(#c_00000131339708796536986220000018336221103987946920_);fill:#bfbfbf"/><path class="st4" d="M19 6c5 0 9 4 9 9s-4 9-9 9-9-4-9-9 4-9 9-9zM139 16h27v8h-27v-8zm-33 0h25v8h-25v-8zM10 45h96v16H10V45z"/><path d="M139.1 45.2h95.7v82.7h-95.7V45.2z" style="fill:#e6e6e6;stroke:#a1a1a1;stroke-width:.3"/><path class="st4" d="M10 84h96v9H10v-9zm0-12h96v7H10v-7zm0 25h48v9H10v-9z"/><path d="M11 117.1h30c.5 0 .9.4.9.9v9c0 .5-.4.9-.9.9H11c-.5 0-.9-.4-.9-.9v-9c0-.5.4-.9.9-.9z" style="fill:#ababab;stroke:#8e8e8e;stroke-width:.2"/><path class="st4" d="M173 16h27v8h-27v-8zm35 0h27v8h-27v-8z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,38 @@
|
||||
export default function Dropdown( $dropdown ) {
|
||||
const $dropdownOpen = $dropdown.querySelector(
|
||||
'[data-vrts-dropdown-open]'
|
||||
);
|
||||
|
||||
const toggleContent = ( e ) => {
|
||||
const $el = e.currentTarget;
|
||||
const controls = $el.getAttribute( 'aria-controls' );
|
||||
const $controls = document.getElementById( controls );
|
||||
const isExpanded = $el.getAttribute( 'aria-expanded' ) === 'true';
|
||||
|
||||
$el.setAttribute( 'aria-expanded', ! isExpanded );
|
||||
$controls.setAttribute( 'aria-hidden', isExpanded );
|
||||
};
|
||||
|
||||
const closeDropdown = ( e ) => {
|
||||
if (
|
||||
$dropdown &&
|
||||
$dropdown !== e.target &&
|
||||
! $dropdown.contains( e.target )
|
||||
) {
|
||||
$dropdownOpen.setAttribute( 'aria-expanded', false );
|
||||
document
|
||||
.getElementById( $dropdownOpen.getAttribute( 'aria-controls' ) )
|
||||
.setAttribute( 'aria-hidden', true );
|
||||
}
|
||||
};
|
||||
|
||||
$dropdownOpen?.addEventListener( 'click', toggleContent );
|
||||
|
||||
// Close dropdown when clicking outside of it.
|
||||
document.addEventListener( 'click', closeDropdown );
|
||||
|
||||
return () => {
|
||||
$dropdownOpen?.removeEventListener( 'click', toggleContent );
|
||||
document.removeEventListener( 'click', closeDropdown );
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
import { resolveSelect, dispatch } from '@wordpress/data';
|
||||
import { store as coreStore } from '@wordpress/core-data';
|
||||
import { driver } from 'driver.js';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
import '../styles/onboarding.scss';
|
||||
|
||||
if ( window.vrts_admin_vars.onboarding ) {
|
||||
const isHighlight = window.vrts_admin_vars.onboarding.steps.length === 1;
|
||||
const onboarding = driver( {
|
||||
overlayColor: 'rgba(44, 51, 56, 0.35)',
|
||||
stageRadius: 0,
|
||||
stagePadding: 0,
|
||||
popoverOffset: 20,
|
||||
allowClose: false,
|
||||
showProgress: ! isHighlight,
|
||||
popoverClass: isHighlight
|
||||
? 'vrts-onboarding-nonblocking'
|
||||
: 'vrts-onboarding',
|
||||
disableActiveInteraction: false,
|
||||
progressText: __(
|
||||
'{{current}} of {{total}}',
|
||||
'visual-regression-tests'
|
||||
),
|
||||
prevBtnText: __( 'Previous', 'visual-regression-tests' ),
|
||||
nextBtnText: __( 'Next', 'visual-regression-tests' ),
|
||||
doneBtnText: __( 'Got it!', 'visual-regression-tests' ),
|
||||
onPopoverRender: ( popover, { config, state } ) => {
|
||||
const steps = config.steps;
|
||||
const hasNextStep = steps[ state.activeIndex + 1 ];
|
||||
|
||||
config.stagePadding =
|
||||
window.vrts_admin_vars.onboarding.steps[ state.activeIndex ]
|
||||
.padding || 0;
|
||||
|
||||
popover.previousButton.classList.add(
|
||||
'button',
|
||||
'button-secondary',
|
||||
'button-large'
|
||||
);
|
||||
|
||||
popover.nextButton.classList.add(
|
||||
'button',
|
||||
'button-primary',
|
||||
'button-large'
|
||||
);
|
||||
|
||||
if ( ! hasNextStep ) {
|
||||
popover.nextButton.classList.add(
|
||||
'driver-popover-success-btn'
|
||||
);
|
||||
}
|
||||
|
||||
if ( isHighlight ) {
|
||||
popover.previousButton.setAttribute( 'hidden', true );
|
||||
}
|
||||
},
|
||||
onNextClick: ( element, step, { config, state } ) => {
|
||||
const steps = config.steps;
|
||||
const hasNextStep = steps[ state.activeIndex + 1 ];
|
||||
|
||||
if ( ! hasNextStep ) {
|
||||
onboarding.destroy();
|
||||
} else {
|
||||
onboarding.moveNext();
|
||||
}
|
||||
},
|
||||
onCloseClick: () => {
|
||||
onboarding.destroy();
|
||||
},
|
||||
onDestroyed: () => {
|
||||
window.removeEventListener( 'keyup', onKeyup );
|
||||
},
|
||||
steps: window.vrts_admin_vars.onboarding.steps.map( ( step ) => {
|
||||
return {
|
||||
element: step.element,
|
||||
popover: {
|
||||
title: step.title,
|
||||
description: step.description,
|
||||
side: step.side || 'left',
|
||||
align: step.align || 'start',
|
||||
},
|
||||
};
|
||||
} ),
|
||||
} );
|
||||
|
||||
const onKeyup = ( event ) => {
|
||||
if ( event.key === 'Escape' ) {
|
||||
onboarding.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener( 'keyup', onKeyup );
|
||||
|
||||
onboarding.drive();
|
||||
saveOnboarding();
|
||||
}
|
||||
|
||||
async function saveOnboarding() {
|
||||
const {
|
||||
currentUserId,
|
||||
onboarding: { id: onboardingId },
|
||||
} = window.vrts_admin_vars;
|
||||
|
||||
const userData = await resolveSelect( coreStore ).getEntityRecord(
|
||||
'root',
|
||||
'user',
|
||||
currentUserId
|
||||
);
|
||||
|
||||
const onboarding = userData.vrts_onboarding || {};
|
||||
const completed = onboarding.completed || [];
|
||||
|
||||
return dispatch( coreStore ).saveEntityRecord( 'root', 'user', {
|
||||
id: currentUserId,
|
||||
vrts_onboarding: {
|
||||
...onboarding,
|
||||
completed: [ ...completed, onboardingId ].filter(
|
||||
( value, index, self ) => self.indexOf( value ) === index
|
||||
),
|
||||
},
|
||||
} );
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
class RelativeTimeElement extends window.HTMLElement {
|
||||
// constructor (element) {
|
||||
// this.element = element
|
||||
// // get date from utc timestamp
|
||||
|
||||
// // this.time = new Date( element.getAttribute( 'time' ) );
|
||||
// // this.update();
|
||||
// }
|
||||
|
||||
// observe attribute time
|
||||
static get observedAttributes() {
|
||||
return [ 'time' ];
|
||||
}
|
||||
|
||||
// update time when attribute time changes
|
||||
attributeChangedCallback( name, oldValue, newValue ) {
|
||||
if ( name === 'time' ) {
|
||||
this.time = new Date( newValue );
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
|
||||
// connectedCallback() {
|
||||
// this.time = new Date( this.getAttribute( 'time' ) );
|
||||
// this.update();
|
||||
// }
|
||||
|
||||
update() {
|
||||
this.innerText = `${ extractDate( this.time ) } at ${ extractTime(
|
||||
this.time
|
||||
) }`;
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define( 'vrts-relative-time', RelativeTimeElement );
|
||||
|
||||
function extractDate( inputDate ) {
|
||||
const { __ } = wp.i18n;
|
||||
const today = new Date();
|
||||
// Set the time to midnight for an accurate date comparison
|
||||
today.setHours( 0, 0, 0, 0 );
|
||||
|
||||
// Create a Date object for the input date
|
||||
const comparisonDate = new Date( inputDate );
|
||||
comparisonDate.setHours( 0, 0, 0, 0 );
|
||||
|
||||
// Calculate the difference in days
|
||||
const difference = ( comparisonDate - today ) / ( 1000 * 3600 * 24 );
|
||||
|
||||
// Determine if the date is today, tomorrow, or yesterday
|
||||
if ( difference === 0 ) {
|
||||
return __( 'Today', 'visual-regression-testing' );
|
||||
} else if ( difference === 1 ) {
|
||||
return __( 'Tomorrow', 'visual-regression-testing' );
|
||||
} else if ( difference === -1 ) {
|
||||
return __( 'Yesterday', 'visual-regression-testing' );
|
||||
}
|
||||
return dateFormat( inputDate, 'D, Y/m/d' );
|
||||
}
|
||||
|
||||
function extractTime( inputDate ) {
|
||||
return dateFormat( inputDate, 'g:i a' );
|
||||
}
|
||||
|
||||
// format date like in php date_format
|
||||
function dateFormat( date, format ) {
|
||||
const pad = ( number ) => ( number < 10 ? `0${ number }` : number );
|
||||
const dayNames = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]; // abbreviated day names
|
||||
const d = pad( date.getDate() );
|
||||
const m = pad( date.getMonth() + 1 );
|
||||
const y = date.getFullYear();
|
||||
const Y = date.getFullYear();
|
||||
const H = date.getHours();
|
||||
const i = pad( date.getMinutes() );
|
||||
const s = date.getSeconds();
|
||||
const g = date.getHours() % 12 || 12;
|
||||
const a = date.getHours() >= 12 ? 'pm' : 'am';
|
||||
const D = dayNames[ date.getDay() ]; // get the abbreviated day name
|
||||
|
||||
return format
|
||||
.replace( 'd', d )
|
||||
.replace( 'm', m )
|
||||
.replace( 'y', y )
|
||||
.replace( 'Y', Y )
|
||||
.replace( 'H', H )
|
||||
.replace( 'i', i )
|
||||
.replace( 's', s )
|
||||
.replace( 'g', g )
|
||||
.replace( 'a', a )
|
||||
.replace( 'D', D ); // replace capital D with day name
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
export default function Tabs( $element ) {
|
||||
const $tabs = $element.querySelectorAll( '[role="tab"]' );
|
||||
const $panels = $element.querySelectorAll( '[role="tabpanel"]' );
|
||||
|
||||
const toggleContent = function () {
|
||||
if ( this.getAttribute( 'aria-selected' ) === 'false' ) {
|
||||
$panels.forEach( ( item ) => {
|
||||
item.setAttribute( 'hidden', true );
|
||||
} );
|
||||
|
||||
$tabs.forEach( ( item ) => {
|
||||
item.setAttribute( 'aria-selected', false );
|
||||
} );
|
||||
|
||||
this.setAttribute( 'aria-selected', 'true' );
|
||||
|
||||
const currentTab = this.getAttribute( 'aria-controls' );
|
||||
const tabContent = document.getElementById( currentTab );
|
||||
tabContent.removeAttribute( 'hidden' );
|
||||
}
|
||||
};
|
||||
|
||||
$tabs.forEach( ( item ) => {
|
||||
item.addEventListener( 'click', toggleContent );
|
||||
} );
|
||||
|
||||
return () => {
|
||||
$tabs.forEach( ( item ) => {
|
||||
item.removeEventListener( 'click', toggleContent );
|
||||
} );
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,554 @@
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Customized version of wp-includes/js/wplink.js
|
||||
*/
|
||||
|
||||
( function ( $, wpLinkL10n, wp ) {
|
||||
let editor,
|
||||
searchTimer,
|
||||
River,
|
||||
Query,
|
||||
correctedURL,
|
||||
emailRegexp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,63}$/i,
|
||||
urlRegexp = /^(https?|ftp):\/\/[A-Z0-9.-]+\.[A-Z]{2,63}[^ "]*$/i,
|
||||
inputs = {},
|
||||
rivers = {},
|
||||
isTouch = 'ontouchend' in document;
|
||||
|
||||
window.wpLink = {
|
||||
timeToTriggerRiver: 150,
|
||||
minRiverAJAXDuration: 200,
|
||||
riverBottomThreshold: 5,
|
||||
keySensitivity: 100,
|
||||
lastSearch: '',
|
||||
textarea: '',
|
||||
modalOpen: false,
|
||||
|
||||
init() {
|
||||
inputs.wrap = $( '#wp-link-wrap' );
|
||||
inputs.dialog = $( '#wp-link' );
|
||||
inputs.backdrop = $( '#wp-link-backdrop' );
|
||||
inputs.submit = $( '#wp-link-submit' );
|
||||
inputs.close = $( '#wp-link-close' );
|
||||
|
||||
// Input.
|
||||
inputs.url = $( '#wp-link-url' );
|
||||
inputs.url_post_id = $( '#wp-link-id' );
|
||||
inputs.nonce = $( '#_ajax_linking_nonce' );
|
||||
inputs.search = $( '#wp-link-search' );
|
||||
|
||||
// Build rivers.
|
||||
rivers.search = new River( $( '#search-results' ) );
|
||||
rivers.recent = new River( $( '#most-recent-results' ) );
|
||||
rivers.elements = inputs.dialog.find( '.query-results' );
|
||||
|
||||
// Get search notice text.
|
||||
inputs.queryNotice = $( '#query-notice-message' );
|
||||
inputs.queryNoticeTextDefault = inputs.queryNotice.find(
|
||||
'.query-notice-default'
|
||||
);
|
||||
inputs.queryNoticeTextHint =
|
||||
inputs.queryNotice.find( '.query-notice-hint' );
|
||||
|
||||
// Bind event handlers.
|
||||
inputs.dialog.on( 'keydown', wpLink.keydown );
|
||||
inputs.dialog.on( 'keyup', wpLink.keyup );
|
||||
|
||||
inputs.close
|
||||
.add( inputs.backdrop )
|
||||
.add( '#wp-link-cancel button' )
|
||||
.on( 'click', function ( event ) {
|
||||
event.preventDefault();
|
||||
wpLink.close();
|
||||
} );
|
||||
|
||||
rivers.elements.on( 'river-select', wpLink.updateFields );
|
||||
|
||||
// Display 'hint' message when search field or 'query-results' box are focused.
|
||||
inputs.search
|
||||
.on( 'focus.wplink', function () {
|
||||
inputs.queryNoticeTextDefault.hide();
|
||||
inputs.queryNoticeTextHint
|
||||
.removeClass( 'screen-reader-text' )
|
||||
.show();
|
||||
} )
|
||||
.on( 'blur.wplink', function () {
|
||||
inputs.queryNoticeTextDefault.show();
|
||||
inputs.queryNoticeTextHint
|
||||
.addClass( 'screen-reader-text' )
|
||||
.hide();
|
||||
} );
|
||||
|
||||
inputs.search.on( 'keyup input', function ( event ) {
|
||||
window.clearTimeout( searchTimer );
|
||||
searchTimer = window.setTimeout( function () {
|
||||
wpLink.searchInternalLinks();
|
||||
}, 500 );
|
||||
} );
|
||||
|
||||
inputs.search.on( 'keypress', function ( event ) {
|
||||
if ( event.key === 'Enter' || event.keyCode === 13 ) {
|
||||
event.preventDefault();
|
||||
inputs.search.trigger( 'keyup input' );
|
||||
}
|
||||
} );
|
||||
|
||||
inputs.url.on( 'paste', function () {
|
||||
setTimeout( wpLink.correctURL, 0 );
|
||||
} );
|
||||
|
||||
inputs.url.on( 'blur', wpLink.correctURL );
|
||||
},
|
||||
|
||||
// If URL wasn't corrected last time and doesn't start with http:, https:, ? # or /, prepend http://.
|
||||
correctURL() {
|
||||
const url = inputs.url.val().trim();
|
||||
|
||||
if (
|
||||
url &&
|
||||
correctedURL !== url &&
|
||||
! /^(?:[a-z]+:|#|\?|\.|\/)/.test( url )
|
||||
) {
|
||||
inputs.url.val( 'http://' + url );
|
||||
correctedURL = url;
|
||||
}
|
||||
},
|
||||
|
||||
open( url, text ) {
|
||||
let ed,
|
||||
$body = $( document.body );
|
||||
|
||||
$body.addClass( 'modal-open' );
|
||||
wpLink.modalOpen = true;
|
||||
|
||||
inputs.wrap.show();
|
||||
inputs.backdrop.show();
|
||||
|
||||
wpLink.refresh( url, text );
|
||||
|
||||
$( document ).trigger( 'wplink-open', inputs.wrap );
|
||||
},
|
||||
|
||||
refresh( url, text ) {
|
||||
let linkText = '';
|
||||
|
||||
// Refresh rivers (clear links, check visibility).
|
||||
rivers.search.refresh();
|
||||
rivers.recent.refresh();
|
||||
|
||||
// For the Text editor the "Link text" field is always shown.
|
||||
if ( ! inputs.wrap.hasClass( 'has-text-field' ) ) {
|
||||
inputs.wrap.addClass( 'has-text-field' );
|
||||
}
|
||||
|
||||
if ( document.selection ) {
|
||||
// Old IE.
|
||||
linkText = document.selection.createRange().text || text || '';
|
||||
} else if (
|
||||
typeof this.textarea.selectionStart !== 'undefined' &&
|
||||
this.textarea.selectionStart !== this.textarea.selectionEnd
|
||||
) {
|
||||
// W3C.
|
||||
text =
|
||||
this.textarea.value.substring(
|
||||
this.textarea.selectionStart,
|
||||
this.textarea.selectionEnd
|
||||
) ||
|
||||
text ||
|
||||
'';
|
||||
}
|
||||
|
||||
wpLink.setDefaultValues();
|
||||
|
||||
if ( isTouch ) {
|
||||
// Close the onscreen keyboard.
|
||||
inputs.url.trigger( 'focus' ).trigger( 'blur' );
|
||||
} else {
|
||||
/*
|
||||
* Focus the URL field and highlight its contents.
|
||||
* If this is moved above the selection changes,
|
||||
* IE will show a flashing cursor over the dialog.
|
||||
*/
|
||||
window.setTimeout( function () {
|
||||
inputs.url[ 0 ].select();
|
||||
inputs.url.trigger( 'focus' );
|
||||
} );
|
||||
}
|
||||
|
||||
// Load the most recent results if this is the first time opening the panel.
|
||||
if ( ! rivers.recent.ul.children().length ) {
|
||||
rivers.recent.ajax();
|
||||
}
|
||||
|
||||
correctedURL = inputs.url.val().replace( /^http:\/\//, '' );
|
||||
},
|
||||
|
||||
close( reset ) {
|
||||
$( document.body ).removeClass( 'modal-open' );
|
||||
wpLink.modalOpen = false;
|
||||
|
||||
inputs.backdrop.hide();
|
||||
inputs.wrap.hide();
|
||||
|
||||
correctedURL = false;
|
||||
|
||||
$( document ).trigger( 'wplink-close', inputs.wrap );
|
||||
},
|
||||
|
||||
updateFields( e, li ) {
|
||||
inputs.url.val( li.children( '.item-permalink' ).val() );
|
||||
inputs.url_post_id.val( li.children( '.item-id' ).val() );
|
||||
},
|
||||
|
||||
setDefaultValues() {
|
||||
// Empty the search field and swap the "rivers".
|
||||
inputs.search.val( '' );
|
||||
wpLink.searchInternalLinks();
|
||||
},
|
||||
|
||||
searchInternalLinks() {
|
||||
let waiting,
|
||||
search = inputs.search.val() || '',
|
||||
minInputLength = parseInt( wpLinkL10n.minInputLength, 10 ) || 3;
|
||||
|
||||
if ( search.length >= minInputLength ) {
|
||||
rivers.recent.hide();
|
||||
rivers.search.show();
|
||||
|
||||
// Don't search if the keypress didn't change the title.
|
||||
if ( wpLink.lastSearch == search ) return;
|
||||
|
||||
wpLink.lastSearch = search;
|
||||
waiting = inputs.search
|
||||
.parent()
|
||||
.find( '.spinner' )
|
||||
.addClass( 'is-active' );
|
||||
|
||||
rivers.search.change( search );
|
||||
rivers.search.ajax( function () {
|
||||
waiting.removeClass( 'is-active' );
|
||||
} );
|
||||
} else {
|
||||
rivers.search.hide();
|
||||
rivers.recent.show();
|
||||
}
|
||||
},
|
||||
|
||||
next() {
|
||||
rivers.search.next();
|
||||
rivers.recent.next();
|
||||
},
|
||||
|
||||
prev() {
|
||||
rivers.search.prev();
|
||||
rivers.recent.prev();
|
||||
},
|
||||
|
||||
keydown( event ) {
|
||||
let fn, id;
|
||||
|
||||
// Escape key.
|
||||
if ( 27 === event.keyCode ) {
|
||||
wpLink.close();
|
||||
event.stopImmediatePropagation();
|
||||
// Tab key.
|
||||
} else if ( 9 === event.keyCode ) {
|
||||
id = event.target.id;
|
||||
|
||||
// wp-link-submit must always be the last focusable element in the dialog.
|
||||
// Following focusable elements will be skipped on keyboard navigation.
|
||||
if ( id === 'wp-link-submit' && ! event.shiftKey ) {
|
||||
inputs.close.trigger( 'focus' );
|
||||
event.preventDefault();
|
||||
} else if ( id === 'wp-link-close' && event.shiftKey ) {
|
||||
inputs.submit.trigger( 'focus' );
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
// Up Arrow and Down Arrow keys.
|
||||
if (
|
||||
event.shiftKey ||
|
||||
( 38 !== event.keyCode && 40 !== event.keyCode )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
document.activeElement &&
|
||||
( document.activeElement.id === 'link-title-field' ||
|
||||
document.activeElement.id === 'url-field' )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Up Arrow key.
|
||||
fn = 38 === event.keyCode ? 'prev' : 'next';
|
||||
clearInterval( wpLink.keyInterval );
|
||||
wpLink[ fn ]();
|
||||
wpLink.keyInterval = setInterval(
|
||||
wpLink[ fn ],
|
||||
wpLink.keySensitivity
|
||||
);
|
||||
event.preventDefault();
|
||||
},
|
||||
|
||||
keyup( event ) {
|
||||
// Up Arrow and Down Arrow keys.
|
||||
if ( 38 === event.keyCode || 40 === event.keyCode ) {
|
||||
clearInterval( wpLink.keyInterval );
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
|
||||
delayedCallback( func, delay ) {
|
||||
let timeoutTriggered, funcTriggered, funcArgs, funcContext;
|
||||
|
||||
if ( ! delay ) return func;
|
||||
|
||||
setTimeout( function () {
|
||||
if ( funcTriggered ) return func.apply( funcContext, funcArgs );
|
||||
// Otherwise, wait.
|
||||
timeoutTriggered = true;
|
||||
}, delay );
|
||||
|
||||
return function () {
|
||||
if ( timeoutTriggered ) return func.apply( this, arguments );
|
||||
// Otherwise, wait.
|
||||
funcArgs = arguments;
|
||||
funcContext = this;
|
||||
funcTriggered = true;
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
River = function ( element, search ) {
|
||||
const self = this;
|
||||
this.element = element;
|
||||
this.ul = element.children( 'ul' );
|
||||
this.contentHeight = element.children( '#link-selector-height' );
|
||||
this.waiting = element.find( '.river-waiting' );
|
||||
|
||||
this.change( search );
|
||||
this.refresh();
|
||||
|
||||
$( '#wp-link .query-results, #wp-link #link-selector' ).on(
|
||||
'scroll',
|
||||
function () {
|
||||
self.maybeLoad();
|
||||
}
|
||||
);
|
||||
element.on( 'click', 'li', function ( event ) {
|
||||
self.select( $( this ), event );
|
||||
} );
|
||||
};
|
||||
|
||||
$.extend( River.prototype, {
|
||||
refresh() {
|
||||
this.deselect();
|
||||
this.visible = this.element.is( ':visible' );
|
||||
},
|
||||
show() {
|
||||
if ( ! this.visible ) {
|
||||
this.deselect();
|
||||
this.element.show();
|
||||
this.visible = true;
|
||||
}
|
||||
},
|
||||
hide() {
|
||||
this.element.hide();
|
||||
this.visible = false;
|
||||
},
|
||||
// Selects a list item and triggers the river-select event.
|
||||
select( li, event ) {
|
||||
let liHeight, elHeight, liTop, elTop;
|
||||
|
||||
if ( li.hasClass( 'unselectable' ) || li == this.selected ) return;
|
||||
|
||||
this.deselect();
|
||||
this.selected = li.addClass( 'selected' );
|
||||
// Make sure the element is visible.
|
||||
liHeight = li.outerHeight();
|
||||
elHeight = this.element.height();
|
||||
liTop = li.position().top;
|
||||
elTop = this.element.scrollTop();
|
||||
|
||||
if ( liTop < 0 )
|
||||
// Make first visible element.
|
||||
this.element.scrollTop( elTop + liTop );
|
||||
else if ( liTop + liHeight > elHeight )
|
||||
// Make last visible element.
|
||||
this.element.scrollTop( elTop + liTop - elHeight + liHeight );
|
||||
|
||||
// Trigger the river-select event.
|
||||
this.element.trigger( 'river-select', [ li, event, this ] );
|
||||
|
||||
// Focus submit button.
|
||||
inputs.submit.focus();
|
||||
},
|
||||
deselect() {
|
||||
if ( this.selected ) this.selected.removeClass( 'selected' );
|
||||
this.selected = false;
|
||||
},
|
||||
prev() {
|
||||
if ( ! this.visible ) return;
|
||||
|
||||
let to;
|
||||
if ( this.selected ) {
|
||||
to = this.selected.prev( 'li' );
|
||||
if ( to.length ) this.select( to );
|
||||
}
|
||||
},
|
||||
next() {
|
||||
if ( ! this.visible ) return;
|
||||
|
||||
const to = this.selected
|
||||
? this.selected.next( 'li' )
|
||||
: $( 'li:not(.unselectable):first', this.element );
|
||||
if ( to.length ) this.select( to );
|
||||
},
|
||||
ajax( callback ) {
|
||||
const self = this,
|
||||
delay = this.query.page == 1 ? 0 : wpLink.minRiverAJAXDuration,
|
||||
response = wpLink.delayedCallback( function (
|
||||
results,
|
||||
params
|
||||
) {
|
||||
self.process( results, params );
|
||||
if ( callback ) callback( results, params );
|
||||
},
|
||||
delay );
|
||||
|
||||
this.query.ajax( response );
|
||||
},
|
||||
change( search ) {
|
||||
if ( this.query && this._search == search ) return;
|
||||
|
||||
this._search = search;
|
||||
this.query = new Query( search );
|
||||
this.element.scrollTop( 0 );
|
||||
},
|
||||
process( results, params ) {
|
||||
let list = '',
|
||||
alt = true,
|
||||
classes = '',
|
||||
firstPage = params.page == 1;
|
||||
|
||||
if ( ! results ) {
|
||||
if ( firstPage ) {
|
||||
list +=
|
||||
'<li class="unselectable no-matches-found"><span class="item-title"><em>' +
|
||||
wpLinkL10n.noMatchesFound +
|
||||
'</em></span></li>';
|
||||
}
|
||||
} else {
|
||||
$.each( results, function () {
|
||||
classes = alt ? 'alternate' : '';
|
||||
classes += this.title ? '' : ' no-title';
|
||||
classes +=
|
||||
this.run_tests_status
|
||||
? ' vrts-tests--active'
|
||||
: '';
|
||||
list += classes ? '<li class="' + classes + '">' : '<li>';
|
||||
|
||||
if ( ! this.run_tests_status ) {
|
||||
list +=
|
||||
'<input type="hidden" class="item-permalink" value="' +
|
||||
this.permalink +
|
||||
'" />';
|
||||
list +=
|
||||
'<input type="hidden" class="item-id" value="' +
|
||||
this.ID +
|
||||
'" />';
|
||||
}
|
||||
list += '<span class="item-title"><strong>';
|
||||
list += this.title ? this.title : wpLinkL10n.noTitle;
|
||||
list += '</strong><br><span class="item-permalink">';
|
||||
list += this.permalink
|
||||
? this.permalink
|
||||
: wpLinkL10n.noTitle;
|
||||
list += '</span>';
|
||||
list +=
|
||||
'</span><span class="item-info">' +
|
||||
this.info +
|
||||
'</span></li>';
|
||||
alt = ! alt;
|
||||
} );
|
||||
}
|
||||
|
||||
this.ul[ firstPage ? 'html' : 'append' ]( list );
|
||||
},
|
||||
maybeLoad() {
|
||||
const self = this,
|
||||
el = this.element,
|
||||
bottom = el.scrollTop() + el.height();
|
||||
|
||||
if (
|
||||
! this.query.ready() ||
|
||||
bottom <
|
||||
this.contentHeight.height() - wpLink.riverBottomThreshold
|
||||
)
|
||||
return;
|
||||
|
||||
setTimeout( function () {
|
||||
const newTop = el.scrollTop(),
|
||||
newBottom = newTop + el.height();
|
||||
|
||||
if (
|
||||
! self.query.ready() ||
|
||||
newBottom <
|
||||
self.contentHeight.height() -
|
||||
wpLink.riverBottomThreshold
|
||||
)
|
||||
return;
|
||||
|
||||
self.waiting.addClass( 'is-active' );
|
||||
el.scrollTop( newTop + self.waiting.outerHeight() );
|
||||
|
||||
self.ajax( function () {
|
||||
self.waiting.removeClass( 'is-active' );
|
||||
} );
|
||||
}, wpLink.timeToTriggerRiver );
|
||||
},
|
||||
} );
|
||||
|
||||
Query = function ( search ) {
|
||||
this.page = 1;
|
||||
this.allLoaded = false;
|
||||
this.querying = false;
|
||||
this.search = search;
|
||||
};
|
||||
|
||||
$.extend( Query.prototype, {
|
||||
ready() {
|
||||
return ! ( this.querying || this.allLoaded );
|
||||
},
|
||||
ajax( callback ) {
|
||||
const self = this,
|
||||
query = {
|
||||
action: 'wp-link-ajax',
|
||||
vrts_filter_query: true,
|
||||
page: this.page,
|
||||
_ajax_linking_nonce: inputs.nonce.val(),
|
||||
};
|
||||
|
||||
if ( this.search ) query.search = this.search;
|
||||
|
||||
this.querying = true;
|
||||
|
||||
$.post(
|
||||
window.ajaxurl,
|
||||
query,
|
||||
function ( r ) {
|
||||
self.page++;
|
||||
self.querying = false;
|
||||
self.allLoaded = ! r;
|
||||
callback( r, query );
|
||||
},
|
||||
'json'
|
||||
);
|
||||
},
|
||||
} );
|
||||
|
||||
$( wpLink.init );
|
||||
} )( jQuery, window.wpLinkL10n, window.wp );
|
||||
@@ -0,0 +1,39 @@
|
||||
:root {
|
||||
--vrts-admin-theme-color: #2271b1;
|
||||
}
|
||||
|
||||
.admin-color-fresh {
|
||||
--vrts-admin-theme-color: #1e8cbe;
|
||||
}
|
||||
|
||||
.admin-color-modern {
|
||||
--vrts-admin-theme-color: #3858e9;
|
||||
}
|
||||
|
||||
.admin-color-light {
|
||||
--vrts-admin-theme-color: #04a4cc;
|
||||
}
|
||||
|
||||
.admin-color-blue {
|
||||
--vrts-admin-theme-color: #e1a948;
|
||||
}
|
||||
|
||||
.admin-color-coffee {
|
||||
--vrts-admin-theme-color: #c7a589;
|
||||
}
|
||||
|
||||
.admin-color-ectoplasm {
|
||||
--vrts-admin-theme-color: #a3b745;
|
||||
}
|
||||
|
||||
.admin-color-midnight {
|
||||
--vrts-admin-theme-color: #dd362d;
|
||||
}
|
||||
|
||||
.admin-color-ocean {
|
||||
--vrts-admin-theme-color: #9ebaa0;
|
||||
}
|
||||
|
||||
.admin-color-sunrise {
|
||||
--vrts-admin-theme-color: #dd823b;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
@keyframes vrts-fade-in {
|
||||
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes vrts-slide-up {
|
||||
|
||||
from {
|
||||
transform: translateY(20px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes vrts-rotate {
|
||||
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes vrts-shimmer {
|
||||
|
||||
0% {
|
||||
background-position: 100% 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: -100% 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes vrts-scale-up-down {
|
||||
|
||||
from,
|
||||
to {
|
||||
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
}
|
||||
|
||||
0% {
|
||||
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
|
||||
20% {
|
||||
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
transform: scale3d(1.5, 1.5, 1.5);
|
||||
}
|
||||
|
||||
40% {
|
||||
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
transform: scale3d(0.7, 0.7, 0.7);
|
||||
}
|
||||
|
||||
60% {
|
||||
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
transform: scale3d(1.3, 1.3, 1.3);
|
||||
}
|
||||
|
||||
80% {
|
||||
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
transform: scale3d(0.8, 0.8, 0.8);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes vrts-color-highlight {
|
||||
|
||||
25% {
|
||||
background-color: rgba(32, 113, 177, 0.2);
|
||||
}
|
||||
|
||||
75% {
|
||||
background-color: rgba(32, 113, 177, 0.2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
.driver {
|
||||
|
||||
&-no-interaction {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&-overlay {
|
||||
animation: vrts-fade-in 0.2s ease-in-out;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&-popover {
|
||||
all: unset;
|
||||
animation: vrts-fade-in 0.2s;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
color: #1e1e1e;
|
||||
line-height: 1.5;
|
||||
padding: 15px;
|
||||
border-radius: 2px;
|
||||
min-width: 250px;
|
||||
max-width: 345px;
|
||||
box-shadow: 2px 2px 8px 4px rgba(30, 30, 30, 0.12);
|
||||
z-index: 100099;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
&-popover-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.5;
|
||||
padding-right: 25px;
|
||||
}
|
||||
|
||||
&-popover-description {
|
||||
font-size: 0.8125rem;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
&-popover-close-btn {
|
||||
all: unset;
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
right: 7px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
display: block !important;
|
||||
background-image: url('data:image/svg+xml,<svg width="11" height="10" viewBox="0 0 11 10" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10.2564 1.41L6.71644 4.95L10.2564 8.49L8.84645 9.9L5.30645 6.37L1.77644 9.9L0.356445 8.48L3.88645 4.95L0.356445 1.42L1.77644 0L5.30645 3.53L8.84645 0L10.2564 1.41Z" fill="%23757575"/></svg>'); // stylelint-disable-line
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
border-radius: 3px;
|
||||
font-size: 0;
|
||||
z-index: 1;
|
||||
transition: background-color 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: #f6f7f7;
|
||||
}
|
||||
}
|
||||
|
||||
&-popover-footer {
|
||||
margin-top: 15px;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
&-popover-navigation-btns {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-left: auto;
|
||||
|
||||
.button-secondary[disabled] {
|
||||
border-color: #2271b1 !important;
|
||||
color: #2271b1 !important;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.button-secondary,
|
||||
.button-secondary[disabled] {
|
||||
background: transparent !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-popover-prev-btn,
|
||||
&-popover-next-btn {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
&[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-popover-prev-btn::before,
|
||||
&-popover-next-btn:not(.driver-popover-success-btn)::after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 12px;
|
||||
height: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center 52%;
|
||||
}
|
||||
|
||||
&-popover-prev-btn::before {
|
||||
// stylelint-disable-next-line
|
||||
background-image: url('data:image/svg+xml,<svg width="12" height="10" viewBox="0 0 12 10" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M11.0572 4.34922V5.64922H3.25723L5.85723 8.24922L5.20723 9.54922L0.657227 4.99922L5.20723 0.449219L5.85723 1.74922L3.25723 4.34922H11.0572Z" fill="%232271B1"/></svg>');
|
||||
}
|
||||
|
||||
// stylelint-disable-next-line
|
||||
&-popover-next-btn::after {
|
||||
// stylelint-disable-next-line
|
||||
background-image: url('data:image/svg+xml,<svg width="12" height="10" viewBox="0 0 12 10" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0.657227 5.64922V4.34922H8.45723L5.85723 1.74922L6.50723 0.449219L11.0572 4.99922L6.50723 9.54922L5.85723 8.24922L8.45723 5.64922H0.657227Z" fill="white"/></svg>');
|
||||
}
|
||||
|
||||
&-popover-progress-text {
|
||||
font-size: 0.75rem;
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
&-popover-arrow {
|
||||
content: "";
|
||||
position: absolute;
|
||||
border: 8px solid #fff;
|
||||
|
||||
&-none,
|
||||
&-side-over,
|
||||
&-side-center {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-side-left {
|
||||
left: 100%;
|
||||
border-right-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
&-side-right {
|
||||
right: 100%;
|
||||
border-left-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
&-side-top {
|
||||
top: 100%;
|
||||
border-right-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
border-left-color: transparent;
|
||||
}
|
||||
|
||||
&-side-bottom {
|
||||
bottom: 100%;
|
||||
border-left-color: transparent;
|
||||
border-top-color: transparent;
|
||||
border-right-color: transparent;
|
||||
}
|
||||
|
||||
&-side-left.driver-popover-arrow-align-start,
|
||||
&-side-right.driver-popover-arrow-align-start {
|
||||
top: 8px;
|
||||
}
|
||||
|
||||
&-side-top.driver-popover-arrow-align-start,
|
||||
&-side-bottom.driver-popover-arrow-align-start {
|
||||
left: 8px;
|
||||
}
|
||||
|
||||
&-align-end.driver-popover-arrow-side-left,
|
||||
&-align-end.driver-popover-arrow-side-right {
|
||||
bottom: 8px;
|
||||
}
|
||||
|
||||
&-side-top.driver-popover-arrow-align-end,
|
||||
&-side-bottom.driver-popover-arrow-align-end {
|
||||
right: 8px;
|
||||
}
|
||||
|
||||
&-side-left.driver-popover-arrow-align-center,
|
||||
&-side-right.driver-popover-arrow-align-center {
|
||||
top: 50%;
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
&-side-top.driver-popover-arrow-align-center,
|
||||
&-side-bottom.driver-popover-arrow-align-center {
|
||||
left: 50%;
|
||||
margin-left: -5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-onboarding-nonblocking ~ .driver-overlay {
|
||||
display: none;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<?php return array('dependencies' => array('wp-core-data', 'wp-data', 'wp-i18n'), 'version' => '9954b94a5bbe9fa829ac');
|
||||
@@ -0,0 +1 @@
|
||||
:root{--vrts-admin-theme-color:#2271b1}.admin-color-fresh{--vrts-admin-theme-color:#1e8cbe}.admin-color-modern{--vrts-admin-theme-color:#3858e9}.admin-color-light{--vrts-admin-theme-color:#04a4cc}.admin-color-blue{--vrts-admin-theme-color:#e1a948}.admin-color-coffee{--vrts-admin-theme-color:#c7a589}.admin-color-ectoplasm{--vrts-admin-theme-color:#a3b745}.admin-color-midnight{--vrts-admin-theme-color:#dd362d}.admin-color-ocean{--vrts-admin-theme-color:#9ebaa0}.admin-color-sunrise{--vrts-admin-theme-color:#dd823b}@keyframes vrts-fade-in{0%{opacity:0}to{opacity:1}}@keyframes vrts-slide-up{0%{transform:translateY(20px)}}@keyframes vrts-rotate{0%{transform:rotate(0deg)}to{transform:rotate(-1turn)}}@keyframes vrts-shimmer{0%{background-position:0% 0}to{background-position:200% 0}}@keyframes vrts-scale-up-down{0%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{animation-timing-function:cubic-bezier(.215,.61,.355,1);transform:scaleX(1)}20%{animation-timing-function:cubic-bezier(.215,.61,.355,1);transform:scale3d(1.5,1.5,1.5)}40%{animation-timing-function:cubic-bezier(.215,.61,.355,1);transform:scale3d(.7,.7,.7)}60%{animation-timing-function:cubic-bezier(.215,.61,.355,1);transform:scale3d(1.3,1.3,1.3)}80%{animation-timing-function:cubic-bezier(.215,.61,.355,1);transform:scale3d(.8,.8,.8)}to{transform:scaleX(1)}}@keyframes vrts-color-highlight{25%{background-color:rgba(32,113,177,.2)}75%{background-color:rgba(32,113,177,.2)}}.vrts_post_options_metabox figcaption>:first-child{margin-top:0}.vrts_post_options_metabox figcaption>:last-child{margin-bottom:0}.vrts_post_options_metabox .figure{margin:0}.vrts_post_options_metabox .figure-link{box-shadow:none;outline:none}.vrts_post_options_metabox .figure-title{margin-bottom:.5rem}.vrts_post_options_metabox .figure-image{aspect-ratio:16/9;border:1px solid #bfbfbf;height:100%;-o-object-fit:cover;object-fit:cover;-o-object-position:center top;object-position:center top;width:100%}.vrts_post_options_metabox .figure .howto{margin-top:.5rem}.vrts_post_options_metabox .settings{margin:1.5rem 0}.vrts_post_options_metabox .settings-title{align-items:center;display:flex;gap:.5rem;justify-content:space-between;margin-bottom:.5rem}.vrts_post_options_metabox .settings label{color:#757575;font-size:12px;text-transform:none}.vrts_post_options_metabox .settings textarea{margin-top:.5rem;width:100%}.vrts-testing-status{display:flex;gap:1rem;justify-content:space-between;margin-bottom:0;position:relative}.vrts-testing-status--paused{color:#d94f4f}.vrts-testing-status--waiting{color:#f97b06}.vrts-testing-status--running{color:#4ab866}.vrts-testing-status-wrapper{display:flex;flex-direction:column;gap:5px;margin:1.5rem 0}.vrts-testing-status-wrapper>:first-child{margin-top:0}.vrts-testing-status-wrapper>:last-child{margin-bottom:0}.vrts-testing-status-wrapper .dashicons{display:none}.vrts-testing-status-info{color:#757575;display:flex;font-size:.75rem;gap:5px;justify-content:space-between}
|
||||
@@ -0,0 +1 @@
|
||||
<?php return array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-edit-post', 'wp-element', 'wp-i18n', 'wp-plugins', 'wp-primitives'), 'version' => 'b11c5fa792b4960a1004');
|
||||
@@ -0,0 +1 @@
|
||||
:root{--vrts-admin-theme-color:#2271b1}.admin-color-fresh{--vrts-admin-theme-color:#1e8cbe}.admin-color-modern{--vrts-admin-theme-color:#3858e9}.admin-color-light{--vrts-admin-theme-color:#04a4cc}.admin-color-blue{--vrts-admin-theme-color:#e1a948}.admin-color-coffee{--vrts-admin-theme-color:#c7a589}.admin-color-ectoplasm{--vrts-admin-theme-color:#a3b745}.admin-color-midnight{--vrts-admin-theme-color:#dd362d}.admin-color-ocean{--vrts-admin-theme-color:#9ebaa0}.admin-color-sunrise{--vrts-admin-theme-color:#dd823b}@keyframes vrts-fade-in{0%{opacity:0}to{opacity:1}}@keyframes vrts-slide-up{0%{transform:translateY(20px)}}@keyframes vrts-rotate{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes vrts-shimmer{0%{background-position:100% 0}to{background-position:-100% 0}}@keyframes vrts-scale-up-down{0%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{animation-timing-function:cubic-bezier(.215,.61,.355,1);transform:scaleX(1)}20%{animation-timing-function:cubic-bezier(.215,.61,.355,1);transform:scale3d(1.5,1.5,1.5)}40%{animation-timing-function:cubic-bezier(.215,.61,.355,1);transform:scale3d(.7,.7,.7)}60%{animation-timing-function:cubic-bezier(.215,.61,.355,1);transform:scale3d(1.3,1.3,1.3)}80%{animation-timing-function:cubic-bezier(.215,.61,.355,1);transform:scale3d(.8,.8,.8)}to{transform:scaleX(1)}}@keyframes vrts-color-highlight{25%{background-color:rgba(32,113,177,.2)}75%{background-color:rgba(32,113,177,.2)}}.vrts_post_options_metabox figcaption>:first-child{margin-top:0}.vrts_post_options_metabox figcaption>:last-child{margin-bottom:0}.vrts_post_options_metabox .figure{margin:0}.vrts_post_options_metabox .figure-link{box-shadow:none;outline:none}.vrts_post_options_metabox .figure-title{margin-bottom:.5rem}.vrts_post_options_metabox .figure-image{aspect-ratio:16/9;border:1px solid #bfbfbf;height:100%;-o-object-fit:cover;object-fit:cover;-o-object-position:center top;object-position:center top;width:100%}.vrts_post_options_metabox .figure .howto{margin-top:.5rem}.vrts_post_options_metabox .settings{margin:1.5rem 0}.vrts_post_options_metabox .settings-title{align-items:center;display:flex;gap:.5rem;justify-content:space-between;margin-bottom:.5rem}.vrts_post_options_metabox .settings label{color:#757575;font-size:12px;text-transform:none}.vrts_post_options_metabox .settings textarea{margin-top:.5rem;width:100%}.vrts-testing-status{display:flex;gap:1rem;justify-content:space-between;margin-bottom:0;position:relative}.vrts-testing-status--paused{color:#d94f4f}.vrts-testing-status--waiting{color:#f97b06}.vrts-testing-status--running{color:#4ab866}.vrts-testing-status-wrapper{display:flex;flex-direction:column;gap:5px;margin:1.5rem 0}.vrts-testing-status-wrapper>:first-child{margin-top:0}.vrts-testing-status-wrapper>:last-child{margin-bottom:0}.vrts-testing-status-wrapper .dashicons{display:none}.vrts-testing-status-info{color:#757575;display:flex;font-size:.75rem;gap:5px;justify-content:space-between}
|
||||
@@ -0,0 +1 @@
|
||||
function getColoredPixelsWithLimit(t,a,e="left"){const o=new Set;for(let i=0;i<t.data.length;i+=4){const n=t.data[i],d=t.data[i+1],l=t.data[i+2],s=t.data[i+3];if(255===n&&0===d&&0===l&&255===s){const n=i/4%t.width;("left"===e?n<a:n>a)&&o.add(Math.floor(i/4/t.width))}}return Array.from(o)}self.onmessage=function(t){if("analyzeImage"===t.data?.action){const{imageData:a}=t.data,e=getColoredPixelsWithLimit(a,0,"right");self.postMessage({action:"analyzedImage",coloredPixels:e})}};
|
||||
@@ -0,0 +1,194 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
@import "@wordpress/base-styles/mixins";
|
||||
@import "@wordpress/base-styles/breakpoints";
|
||||
@import "@wordpress/base-styles/variables";
|
||||
@import "@wordpress/base-styles/default-custom-properties";
|
||||
|
||||
.vrts-admin-header {
|
||||
box-sizing: border-box;
|
||||
background: $white;
|
||||
border-bottom: 1px solid $light-gray-500;
|
||||
margin-left: -20px;
|
||||
padding-left: 20px;
|
||||
padding-top: 0;
|
||||
height: 54px;
|
||||
display: flex;
|
||||
gap: 25px;
|
||||
|
||||
@media (max-width: $break-small) {
|
||||
height: calc(54px + 46px);
|
||||
padding-top: 46px;
|
||||
}
|
||||
|
||||
@media (max-width: $break-medium) {
|
||||
margin-left: -10px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
+ #wpbody {
|
||||
|
||||
@media (max-width: 600px) {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__logo {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
|
||||
&-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
||||
svg {
|
||||
|
||||
path {
|
||||
fill: $gray-700;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-text {
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
|
||||
@media (max-width: $break-medium) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__navigation {
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
|
||||
@media (max-width: $break-medium) {
|
||||
gap: 20px;
|
||||
overflow: auto;
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-item {
|
||||
display: flex;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&-link {
|
||||
position: relative;
|
||||
padding: 16px 20px;
|
||||
text-decoration: none;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
background: var(--vrts-admin-theme-color);
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
[aria-current="true"] & {
|
||||
border-bottom-color: var(--vrts-admin-theme-color);
|
||||
font-weight: 600;
|
||||
|
||||
&::after {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: var(--vrts-admin-theme-color);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
box-shadow: inset 0 0 0 2px var(--vrts-admin-theme-color);
|
||||
}
|
||||
|
||||
// required to match the color scheme
|
||||
&:not(:hover):not(:focus) {
|
||||
color: $gray-text;
|
||||
}
|
||||
}
|
||||
|
||||
&-button {
|
||||
align-self: center;
|
||||
border: 1px solid var(--vrts-admin-theme-color);
|
||||
border-radius: 50px;
|
||||
padding: 8px 14px;
|
||||
margin-left: 20px;
|
||||
color: var(--vrts-admin-theme-color);
|
||||
text-decoration: none;
|
||||
|
||||
&::after {
|
||||
content: attr(title);
|
||||
position: relative;
|
||||
display: block;
|
||||
font-weight: 700;
|
||||
height: 1px;
|
||||
color: transparent;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
[aria-current="true"] & {
|
||||
border: 1px solid var(--vrts-admin-theme-color);
|
||||
background: rgba(var(--vrts-admin-theme-color--rgb), 0.1);
|
||||
font-weight: initial;
|
||||
}
|
||||
|
||||
@media (max-width: $break-medium) {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 2px var(--vrts-admin-theme-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.update-plugins {
|
||||
background-color: $alert-red;
|
||||
border-radius: 9px;
|
||||
box-sizing: border-box;
|
||||
color: $white;
|
||||
display: inline-block;
|
||||
font-size: 11px;
|
||||
height: 18px;
|
||||
line-height: 1.6;
|
||||
margin: 0 0 -1px 0;
|
||||
min-width: 18px;
|
||||
padding: 0 5px;
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
|
||||
&::after {
|
||||
display: block;
|
||||
content: attr(title);
|
||||
font-weight: 700;
|
||||
height: 1px;
|
||||
color: transparent;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<nav class="vrts-admin-header">
|
||||
<a class="vrts-admin-header__logo" href="<?php echo esc_url( Url_Helpers::get_page_url( 'tests' ) ); ?>">
|
||||
<span class="vrts-admin-header__logo-icon"><?php vrts()->logo(); ?></span>
|
||||
<h2 class="vrts-admin-header__logo-text"><?php echo esc_html( $data['plugin_name'] ); ?></h2>
|
||||
</a>
|
||||
<ul class="vrts-admin-header__navigation">
|
||||
<?php
|
||||
$allowed_html_into_text = [
|
||||
'span' => [
|
||||
'class' => [],
|
||||
'title' => [],
|
||||
],
|
||||
];
|
||||
$allowed_html_into_title = [];
|
||||
foreach ( $data['menu_items'] as $menu_item ) {
|
||||
printf(
|
||||
'<li class="vrts-admin-header__navigation-item" aria-current="%1$s"><a class="vrts-admin-header__navigation-%5$s" href="%2$s" title="%3$s">%4$s</a></li>',
|
||||
! empty( $menu_item['is_active'] ) ? 'true' : 'false',
|
||||
esc_url( $menu_item['url'] ),
|
||||
wp_kses( $menu_item['text'], $allowed_html_into_title ),
|
||||
wp_kses( $menu_item['text'], $allowed_html_into_text ),
|
||||
esc_attr( strpos( $menu_item['url'], 'vrts-upgrade' ) !== false ? 'button' : 'link' )
|
||||
);
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</nav>
|
||||
@@ -0,0 +1,27 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
|
||||
.vrts-notice {
|
||||
padding-bottom: 0.75em;
|
||||
|
||||
p,
|
||||
form {
|
||||
display: inline;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.admin-notice-button {
|
||||
border: 0;
|
||||
margin-bottom: 2px;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
min-height: 19px;
|
||||
line-height: 1;
|
||||
border-radius: 0;
|
||||
text-decoration: underline;
|
||||
|
||||
&:hover {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
switch ( $data['view'] ) {
|
||||
case 'connection_failed':
|
||||
$template = __DIR__ . '/views/admin-notification-connection-failed.php';
|
||||
break;
|
||||
|
||||
case 'get_started':
|
||||
$template = __DIR__ . '/views/admin-notification-get-started.php';
|
||||
break;
|
||||
|
||||
case 'new_test_added':
|
||||
$template = __DIR__ . '/views/admin-notification-new-test-added.php';
|
||||
break;
|
||||
|
||||
case 'new_test_failed':
|
||||
$template = __DIR__ . '/views/admin-notification-new-test-failed.php';
|
||||
break;
|
||||
|
||||
case 'new_tests_added':
|
||||
$template = __DIR__ . '/views/admin-notification-new-tests-added.php';
|
||||
break;
|
||||
|
||||
case 'plugin_activated':
|
||||
$template = __DIR__ . '/views/admin-notification-plugin-activated.php';
|
||||
break;
|
||||
|
||||
case 'settings_saved':
|
||||
$template = __DIR__ . '/views/admin-notification-settings-saved.php';
|
||||
break;
|
||||
|
||||
case 'license_added':
|
||||
$template = __DIR__ . '/views/admin-notification-license-added.php';
|
||||
break;
|
||||
|
||||
case 'license_not_added':
|
||||
$template = __DIR__ . '/views/admin-notification-license-not-added.php';
|
||||
break;
|
||||
|
||||
case 'test_disabled':
|
||||
$template = __DIR__ . '/views/admin-notification-test-disabled.php';
|
||||
break;
|
||||
|
||||
case 'test_started':
|
||||
$template = __DIR__ . '/views/admin-notification-test-started.php';
|
||||
break;
|
||||
|
||||
case 'test_failed':
|
||||
$template = __DIR__ . '/views/admin-notification-test-failed.php';
|
||||
break;
|
||||
|
||||
case 'unlock_more_tests':
|
||||
$template = __DIR__ . '/views/admin-notification-unlock-more-tests.php';
|
||||
break;
|
||||
|
||||
default:
|
||||
$template = '';
|
||||
break;
|
||||
}//end switch
|
||||
|
||||
if ( file_exists( $template ) ) {
|
||||
include $template;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/* global jQuery, ajaxurl */
|
||||
|
||||
import 'scripts/relative-time-element';
|
||||
|
||||
jQuery( document ).ready( function ( $ ) {
|
||||
$( document ).on( 'click', '.vrts-notice .notice-dismiss', ( event ) => {
|
||||
if ( ajaxurl ) {
|
||||
const nonce =
|
||||
event.target.parentElement.querySelector( '#_wpnonce' ).value;
|
||||
const view = event.target.parentElement.dataset.view;
|
||||
|
||||
const data = {
|
||||
action: 'vrts_admin_notice_dismiss',
|
||||
url: ajaxurl,
|
||||
security: nonce,
|
||||
view,
|
||||
};
|
||||
|
||||
$.ajax( {
|
||||
type: 'POST',
|
||||
url: ajaxurl,
|
||||
data,
|
||||
} );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
@@ -0,0 +1,8 @@
|
||||
<div class="vrts-notice notice notice-error" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<h3><?php esc_html_e( 'Connection failed', 'visual-regression-tests' ); ?></h3>
|
||||
<p><?php esc_html_e( 'Something went wrong while trying to connect to the external service.', 'visual-regression-tests' ); ?></p>
|
||||
<form id="form-retry-connection" method="post">
|
||||
<?php wp_nonce_field( 'vrts_retry_connection_nonce' ); ?>
|
||||
<?php submit_button( esc_attr__( 'Retry connection', 'visual-regression-tests' ), 'admin-notice-button', 'submit_retry_connection', false ); ?>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,5 @@
|
||||
<div class="vrts-notice notice notice-info is-dismissible" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'Let’s get started!', 'visual-regression-tests' ); ?></h3>
|
||||
<p><?php esc_html_e( 'Click “Add New“ to create a Visual Regression Test for your Website and find issues before others do.', 'visual-regression-tests' ); ?></p>
|
||||
</div>
|
||||
@@ -0,0 +1,5 @@
|
||||
<div class="vrts-notice notice notice-success" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'License activated!', 'visual-regression-tests' ); ?></h3>
|
||||
<p><?php esc_html_e( 'Enjoy your upgraded features for seamless visual testing.', 'visual-regression-tests' ); ?></p>
|
||||
</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
<div class="vrts-notice notice notice-error" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'Invalid License Key', 'visual-regression-tests' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %1$s, %2$s: link wrapper. */
|
||||
esc_html__( 'We could not verify the license key you entered. Please check for typos and try again. If the issue persists, %1$scontact us%2$s for assistance. We’re here to help!', 'visual-regression-tests' ),
|
||||
'<a href="https://vrts.app/contact/" target="_blank">',
|
||||
'</a>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
@@ -0,0 +1,13 @@
|
||||
<div class="vrts-notice notice notice-success" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'Test added successfully', 'visual-regression-tests' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: the title of the page. */
|
||||
esc_html__( 'Tests will be run for the following page: %s', 'visual-regression-tests' ),
|
||||
esc_html( $data['page_title'] )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<div class="vrts-notice notice notice-error is-dismissable" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<h3><?php esc_html_e( 'Ready for an Upgrade?', 'visual-regression-tests' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
'%1$s <a href="%2$s" title="%3$s">%3$s</a>',
|
||||
esc_html__( 'Looks like you need a bigger plan to add more tests.', 'visual-regression-tests' ),
|
||||
esc_url( Url_Helpers::get_page_url( 'upgrade' ) ),
|
||||
esc_html__( 'Upgrade here!', 'visual-regression-tests' )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
@@ -0,0 +1,13 @@
|
||||
<div class="vrts-notice notice notice-success" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'Tests added successfully', 'visual-regression-tests' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: the title of the page. */
|
||||
esc_html__( 'Tests will be run for the following pages: %s', 'visual-regression-tests' ),
|
||||
esc_html( $data['page_titles'] )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<div class="notice updated is-dismissible" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<p>
|
||||
<strong><?php esc_html_e( 'VRTs Plugin successfully activated!', 'visual-regression-tests' ); ?></strong>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %1$s, %2$s and %3$s, %4$s: link wrapper. */
|
||||
esc_html__( 'Start to %1$sconfigure tests%2$s, or check the customization options in the %3$splugin settings%4$s.', 'visual-regression-tests' ),
|
||||
'<a href="' . esc_url( Url_Helpers::get_page_url( 'tests' ) ) . '">',
|
||||
'</a>',
|
||||
'<a href="' . esc_url( Url_Helpers::get_page_url( 'settings' ) ) . '">',
|
||||
'</a>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
@@ -0,0 +1,5 @@
|
||||
<div class="vrts-notice notice notice-success" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'Settings saved', 'visual-regression-tests' ); ?></h3>
|
||||
<p><?php esc_html_e( 'Changes have been saved successfully.', 'visual-regression-tests' ); ?></p>
|
||||
</div>
|
||||
@@ -0,0 +1,18 @@
|
||||
<div class="vrts-notice notice notice-error" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'Test disabled successfully', 'visual-regression-tests' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: the title of the page. */
|
||||
esc_html__( 'No more tests will be run for the following page: %s', 'visual-regression-tests' ),
|
||||
esc_html( $data['page_title'] )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<form id="form-undo-test" method="post">
|
||||
<input type="hidden" name="post_id" value="<?php echo esc_attr( $data['post_id'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_page_tests_nonce' ); ?>
|
||||
<?php submit_button( esc_attr__( 'Undo', 'visual-regression-tests' ), 'admin-notice-button', 'submit_add_new_test', false ); ?>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,5 @@
|
||||
<div class="vrts-notice notice notice-error" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'Test couldn’t be started', 'visual-regression-tests' ); ?></h3>
|
||||
<p><?php esc_html_e( 'A Test is already in progress. Please wait for the current Test to finish, then try again.', 'visual-regression-tests' ); ?></p>
|
||||
</div>
|
||||
@@ -0,0 +1,6 @@
|
||||
<div class="vrts-notice notice notice-info" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<?php wp_nonce_field( 'vrts_admin_notice_nonce' ); ?>
|
||||
<h3><?php esc_html_e( 'Testing has started 🚀', 'visual-regression-tests' ); ?></h3>
|
||||
<p><?php esc_html_e( 'New screenshots are being taken and compared with the previous version.', 'visual-regression-tests' ); ?></p><br>
|
||||
<p><?php esc_html_e( 'This may take a moment. You’ll receive an email if any visual changes are detected.', 'visual-regression-tests' ); ?></p>
|
||||
</div>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<div class="vrts-notice notice notice-info" data-view="<?php echo esc_attr( $data['view'] ); ?>">
|
||||
<h3><?php esc_html_e( 'Unlock more tests', 'visual-regression-tests' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
'%s %s',
|
||||
sprintf(
|
||||
/* translators: %1$s, %2$s: number of tests. */
|
||||
esc_html__( 'Good work! You have added %1$s of %2$s available tests.', 'visual-regression-tests' ),
|
||||
intval( $data['total_tests'] ) - intval( $data['remaining_tests'] ),
|
||||
intval( $data['total_tests'] )
|
||||
),
|
||||
sprintf(
|
||||
/* translators: %1$s, %2$s: link wrapper. */
|
||||
esc_html__( 'Upgrade %1$shere%2$s to add more tests to your website!', 'visual-regression-tests' ),
|
||||
'<a href="' . esc_url( Url_Helpers::get_page_url( 'upgrade' ) ) . '">',
|
||||
'</a>'
|
||||
)
|
||||
)
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
@@ -0,0 +1,129 @@
|
||||
.vrts-alert-actions {
|
||||
display: block;
|
||||
position: relative;
|
||||
|
||||
&__trigger {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
padding: 0.5rem;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
content: "";
|
||||
background: #f6f7f7;
|
||||
border-radius: 2px;
|
||||
opacity: 0;
|
||||
z-index: -1;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus-visible,
|
||||
&[aria-expanded="true"] {
|
||||
|
||||
&::before {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__dropdown {
|
||||
position: absolute;
|
||||
top: calc(100% - 5px);
|
||||
right: 0;
|
||||
background: #fff;
|
||||
border: 1px solid #c3c4c7;
|
||||
box-shadow: 0 3px 28px 0 rgba(0, 0, 0, 0.15);
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
min-width: 200px;
|
||||
transform: translateY(-4px);
|
||||
will-change: transform, opacity, visibility;
|
||||
transition: all 0.15s;
|
||||
|
||||
&[aria-hidden="false"] {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__dropdown-action {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
white-space: nowrap;
|
||||
padding: 12px 15px;
|
||||
width: 100%;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition: color 0.2s;
|
||||
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
color: var(--vrts-admin-theme-color);
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
&__modal {
|
||||
|
||||
.vrts-modal__content {
|
||||
max-width: 450px;
|
||||
}
|
||||
|
||||
.vrts-modal__content-inner {
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
&-action {
|
||||
margin-top: 10px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
&-action-success {
|
||||
color: #00a32a;
|
||||
font-size: 0.75rem;
|
||||
margin-left: 0.5rem;
|
||||
display: none;
|
||||
|
||||
&.is-active {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.spinner {
|
||||
margin: 0;
|
||||
display: none;
|
||||
|
||||
&.is-active {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
border-color: #ccc;
|
||||
}
|
||||
|
||||
.description {
|
||||
color: #757575;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<vrts-alert-actions class="vrts-alert-actions">
|
||||
<button type="button" data-vrts-dropdown-open class="vrts-alert-actions__trigger" aria-expanded="false" aria-controls="vrts-alert-actions-dropdown">
|
||||
<?php vrts()->icon( 'more-horizontal' ); ?>
|
||||
</button>
|
||||
<div id="vrts-alert-actions-dropdown" class="vrts-alert-actions__dropdown" aria-hidden="true">
|
||||
<button data-vrts-loading="false" data-vrts-action-state="<?php echo esc_attr( $data['alert']->is_false_positive ? 'secondary' : 'primary' ); ?>" data-vrts-alert-id="<?php echo esc_attr( $data['alert']->id ); ?>" data-vrts-alert-action="false-positive" class="vrts-alert-actions__dropdown-action vrts-action-button">
|
||||
<span class="vrts-action-button__icons">
|
||||
<span class="vrts-action-button__icon" data-vrts-action-state-primary><?php vrts()->icon( 'flag-outline' ); ?></span>
|
||||
<span class="vrts-action-button__icon" data-vrts-action-state-secondary><?php vrts()->icon( 'flag' ); ?></span>
|
||||
<span class="vrts-action-button__spinner"><?php vrts()->icon( 'spinner' ); ?></span>
|
||||
</span>
|
||||
<span class="vrts-action-button__info" data-vrts-action-state-primary><?php esc_html_e( 'Flag as false positive', 'visual-regression-tests' ); ?></span>
|
||||
<span class="vrts-action-button__info" data-vrts-action-state-secondary><?php esc_html_e( 'Unflag as false positive', 'visual-regression-tests' ); ?></span>
|
||||
</button>
|
||||
<button data-vrts-loading="false" data-vrts-action-state="<?php echo esc_attr( $data['alert']->alert_state ? 'secondary' : 'primary' ); ?>" data-vrts-alert-id="<?php echo esc_attr( $data['alert']->id ); ?>" data-vrts-alert-action="read-status" class="vrts-alert-actions__dropdown-action vrts-action-button">
|
||||
<span class="vrts-action-button__icons">
|
||||
<span class="vrts-action-button__icon" data-vrts-action-state-secondary><?php vrts()->icon( 'email-unread' ); ?></span>
|
||||
<span class="vrts-action-button__icon" data-vrts-action-state-primary><?php vrts()->icon( 'email-read' ); ?></span>
|
||||
<span class="vrts-action-button__spinner"><?php vrts()->icon( 'spinner' ); ?></span>
|
||||
</span>
|
||||
<span class="vrts-action-button__info" data-vrts-action-state-primary><?php esc_html_e( 'Mark as read', 'visual-regression-tests' ); ?></span>
|
||||
<span class="vrts-action-button__info" data-vrts-action-state-secondary><?php esc_html_e( 'Mark as unread', 'visual-regression-tests' ); ?></span>
|
||||
</button>
|
||||
<button type="button" class="vrts-alert-actions__dropdown-action" data-a11y-dialog-show="vrts-modal-hide-elements">
|
||||
<?php vrts()->icon( 'hidden' ); ?>
|
||||
<?php esc_html_e( 'Hide elements', 'visual-regression-tests' ); ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<vrts-modal id="vrts-modal-hide-elements" class="vrts-modal vrts-alert-actions__modal" aria-hidden="true">
|
||||
<div class="vrts-modal__overlay" data-a11y-dialog-hide></div>
|
||||
<div class="vrts-modal__content" role="document">
|
||||
<button type="button" class="vrts-modal__close" data-a11y-dialog-hide aria-label="<?php esc_attr_e( 'Close', 'visual-regression-tests' ); ?>"></button>
|
||||
<h2 class="vrts-modal__title">
|
||||
<?php vrts()->icon( 'hidden' ); ?>
|
||||
<?php esc_html_e( 'Hide elements', 'visual-regression-tests' ); ?>
|
||||
</h2>
|
||||
<div class="vrts-modal__content-inner">
|
||||
<form data-vrts-hide-elements-form action="<?php echo esc_url( Url_Helpers::get_page_url( 'runs' ) ); ?>" method="put">
|
||||
<input type="hidden" name="post_id" value="<?php echo esc_attr( $data['alert']->post_id ); ?>">
|
||||
<input type="hidden" name="test_id" value="<?php echo esc_attr( $data['test_settings']['test_id'] ); ?>">
|
||||
<textarea class="widefat" name="hide_css_selectors" placeholder="<?php esc_html_e( 'e.g.: .lottie, #ads', 'visual-regression-tests' ); ?>" rows="4"><?php echo esc_html( $data['test_settings']['hide_css_selectors'] ); ?></textarea>
|
||||
<p class="description"><?php esc_html_e( 'Hide elements on snapshots to exclude them from comparisons.', 'visual-regression-tests' ); ?></p>
|
||||
<div class="vrts-alert-actions__modal-action">
|
||||
<button type="submit" class="button button-primary"><?php esc_html_e( 'Save Changes', 'visual-regression-tests' ); ?></button>
|
||||
<span class="spinner"></span>
|
||||
<span class="vrts-alert-actions__modal-action-success"><?php esc_html_e( 'Saved successfully.', 'visual-regression-tests' ); ?></span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</vrts-modal>
|
||||
</vrts-alert-actions>
|
||||
@@ -0,0 +1,198 @@
|
||||
import Dropdown from '../../assets/scripts/dropdown';
|
||||
|
||||
class VrtsAlertActions extends window.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.dropdown = null;
|
||||
this.setAsReadTimeout = null;
|
||||
this.resolveElements();
|
||||
this.bindFunctions();
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
resolveElements() {
|
||||
this.$actionButtons = this.querySelectorAll(
|
||||
'[data-vrts-alert-action]'
|
||||
);
|
||||
this.$hideElementsForm = this.querySelector(
|
||||
'[data-vrts-hide-elements-form]'
|
||||
);
|
||||
this.$hideElementsModal = document.getElementById(
|
||||
'vrts-modal-hide-elements'
|
||||
);
|
||||
this.$spinner = this.querySelector( '.spinner' );
|
||||
this.$success = this.querySelector(
|
||||
'.vrts-alert-actions__modal-action-success'
|
||||
);
|
||||
}
|
||||
|
||||
bindFunctions() {
|
||||
this.onActionClick = this.onActionClick.bind( this );
|
||||
this.onHideElementsFormSubmit =
|
||||
this.onHideElementsFormSubmit.bind( this );
|
||||
this.onHideElementsModalClose =
|
||||
this.onHideElementsModalClose.bind( this );
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.$actionButtons.forEach( ( item ) => {
|
||||
item.addEventListener( 'click', this.onActionClick );
|
||||
} );
|
||||
this.$hideElementsForm.addEventListener(
|
||||
'submit',
|
||||
this.onHideElementsFormSubmit
|
||||
);
|
||||
this.$hideElementsModal.addEventListener(
|
||||
'hide',
|
||||
this.onHideElementsModalClose
|
||||
);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.dropdown = Dropdown( this );
|
||||
this.setAsReadOnView();
|
||||
}
|
||||
|
||||
setAsReadOnView() {
|
||||
this.$actionButtons.forEach( ( action ) => {
|
||||
const isReadStatusAction =
|
||||
action.getAttribute( 'data-vrts-alert-action' ) ===
|
||||
'read-status';
|
||||
const isUnread =
|
||||
action.getAttribute( 'data-vrts-action-state' ) === 'primary';
|
||||
|
||||
if ( isReadStatusAction && isUnread ) {
|
||||
this.setAsReadTimeout = setTimeout( () => {
|
||||
action.click();
|
||||
}, 1000 );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
onHideElementsFormSubmit( e ) {
|
||||
e.preventDefault();
|
||||
const $form = e.currentTarget;
|
||||
const formData = new window.FormData( $form );
|
||||
const postId = formData.get( 'post_id' );
|
||||
|
||||
this.$spinner.classList.add( 'is-active' );
|
||||
this.$success.classList.remove( 'is-active' );
|
||||
|
||||
fetch( `${ window.vrts_admin_vars.rest_url }/tests/post/${ postId }`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'X-WP-Nonce': window.vrts_admin_vars.rest_nonce,
|
||||
},
|
||||
body: new URLSearchParams( formData ),
|
||||
} )
|
||||
.then( ( response ) => {
|
||||
return response.json();
|
||||
} )
|
||||
.then( () => {
|
||||
this.$spinner.classList.remove( 'is-active' );
|
||||
this.$success.classList.add( 'is-active' );
|
||||
} );
|
||||
}
|
||||
|
||||
onHideElementsModalClose() {
|
||||
this.$success.classList.remove( 'is-active' );
|
||||
}
|
||||
|
||||
onActionClick( e ) {
|
||||
const $el = e.currentTarget;
|
||||
const isLoading = $el.getAttribute( 'data-vrts-loading' ) === 'true';
|
||||
const state = $el.getAttribute( 'data-vrts-action-state' );
|
||||
const isPrimary = state === 'primary';
|
||||
|
||||
if ( isLoading ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const action = $el.getAttribute( 'data-vrts-alert-action' );
|
||||
const id = $el.getAttribute( 'data-vrts-alert-id' );
|
||||
|
||||
this.handleAction( action, $el, id, isPrimary );
|
||||
}
|
||||
|
||||
handleAction( action, $el, id, shouldSetAction ) {
|
||||
const restEndpoint = `${ window.vrts_admin_vars.rest_url }/alerts/${ id }/${ action }`;
|
||||
const method = shouldSetAction ? 'POST' : 'DELETE';
|
||||
|
||||
let loadingElapsedTime = 0;
|
||||
let interval = null;
|
||||
|
||||
const timeout = setTimeout( () => {
|
||||
$el.setAttribute( 'data-vrts-loading', 'true' );
|
||||
const loadingStartTime = window.Date.now();
|
||||
interval = setInterval( () => {
|
||||
loadingElapsedTime = window.Date.now() - loadingStartTime;
|
||||
}, 50 );
|
||||
}, 200 );
|
||||
|
||||
fetch( restEndpoint, {
|
||||
method,
|
||||
headers: {
|
||||
'X-WP-Nonce': window.vrts_admin_vars.rest_nonce,
|
||||
},
|
||||
} )
|
||||
.then( ( response ) => {
|
||||
return response.json();
|
||||
} )
|
||||
.then( () => {
|
||||
const loadingTimeoutTime =
|
||||
loadingElapsedTime > 0
|
||||
? Math.abs( loadingElapsedTime - 400 )
|
||||
: 0;
|
||||
|
||||
setTimeout( () => {
|
||||
$el.setAttribute( 'data-vrts-loading', 'false' );
|
||||
|
||||
$el.setAttribute(
|
||||
'data-vrts-action-state',
|
||||
shouldSetAction ? 'secondary' : 'primary'
|
||||
);
|
||||
|
||||
const $alert = document.getElementById(
|
||||
`vrts-alert-${ id }`
|
||||
);
|
||||
|
||||
if ( $alert ) {
|
||||
if ( 'false-positive' === action ) {
|
||||
$alert.setAttribute(
|
||||
'data-vrts-false-positive',
|
||||
shouldSetAction ? 'true' : 'false'
|
||||
);
|
||||
}
|
||||
|
||||
if ( 'read-status' === action ) {
|
||||
$alert.setAttribute(
|
||||
'data-vrts-state',
|
||||
shouldSetAction ? 'read' : 'unread'
|
||||
);
|
||||
}
|
||||
}
|
||||
}, loadingTimeoutTime );
|
||||
|
||||
clearTimeout( timeout );
|
||||
clearInterval( interval );
|
||||
} );
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.dropdown?.();
|
||||
clearTimeout( this.setAsReadTimeout );
|
||||
this.$actionButtons?.forEach( ( item ) => {
|
||||
item.removeEventListener( 'click', this.onActionClick );
|
||||
} );
|
||||
this.$hideElementsForm?.removeEventListener(
|
||||
'submit',
|
||||
this.onHideElementsFormSubmit
|
||||
);
|
||||
this.$hideElementsModal?.removeEventListener(
|
||||
'hide',
|
||||
this.onHideElementsModalClose
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define( 'vrts-alert-actions', VrtsAlertActions );
|
||||
@@ -0,0 +1,300 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
@import "@wordpress/base-styles/breakpoints";
|
||||
|
||||
.vrts-comparisons {
|
||||
--vrts-comparisons-slider-position: 50%;
|
||||
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
border-top: 0;
|
||||
margin-bottom: 0;
|
||||
|
||||
&__header {
|
||||
background-color: $white;
|
||||
z-index: 1;
|
||||
gap: 1rem;
|
||||
|
||||
&:has(vrts-modal:not([aria-hidden="true"])) {
|
||||
z-index: 999999;
|
||||
}
|
||||
|
||||
@media (min-width: 850px) {
|
||||
position: sticky;
|
||||
top: calc(62px + var(--wp-admin--admin-bar--height));
|
||||
|
||||
[data-vrts-fullscreen="true"] & {
|
||||
top: 62px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
display: -webkit-box;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
max-block-size: calc(13px * 1.4);
|
||||
white-space: initial;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
&__info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: 0.25rem;
|
||||
z-index: 1;
|
||||
|
||||
> *:not(:last-child) {
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
right: -0.5px;
|
||||
content: "";
|
||||
display: block;
|
||||
width: 1px;
|
||||
height: 1rem;
|
||||
background: $gray-10;
|
||||
margin-left: 0.75rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__difference {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #b32d2e;
|
||||
padding-right: 0.75rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__expand-button {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
@media (max-width: 667px) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
content: "";
|
||||
background: #f6f7f7;
|
||||
border-radius: 2px;
|
||||
opacity: 0;
|
||||
z-index: -1;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
|
||||
&::before {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
height: 14px;
|
||||
width: auto;
|
||||
|
||||
&:last-child {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
[data-vrts-fullscreen="true"] & {
|
||||
|
||||
svg:first-child {
|
||||
display: none;
|
||||
}
|
||||
|
||||
svg:last-child {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, max-content));
|
||||
justify-content: center;
|
||||
gap: 0.25rem;
|
||||
padding: 15px;
|
||||
|
||||
@container (max-width: 600px) {
|
||||
gap: 0;
|
||||
grid-template-columns: repeat(2, minmax(0, max-content));
|
||||
}
|
||||
|
||||
&-container {
|
||||
container-type: inline-size;
|
||||
}
|
||||
}
|
||||
|
||||
&__figure {
|
||||
margin: 0;
|
||||
position: relative;
|
||||
border: solid 1px #{$gray-lighten-20};
|
||||
min-height: 100px;
|
||||
|
||||
&-image {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@container (max-width: 600px) {
|
||||
|
||||
&[data-vrts-comparisons-slot="comparison"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__diff-inidicator {
|
||||
box-sizing: border-box;
|
||||
background: #f0f0f1;
|
||||
border-block: 1px solid transparent;
|
||||
height: 100%;
|
||||
image-rendering: pixelated;
|
||||
width: 4px;
|
||||
|
||||
@container (max-width: 600px) {
|
||||
margin-left: -9.5px;
|
||||
}
|
||||
}
|
||||
|
||||
&__slider {
|
||||
--vrts-comparisons-slider-height: 100%;
|
||||
|
||||
position: relative;
|
||||
display: grid;
|
||||
align-items: start;
|
||||
border: solid 1px #{$gray-lighten-20};
|
||||
overflow: clip;
|
||||
|
||||
.vrts-comparisons__figure {
|
||||
grid-column: 1 / 1;
|
||||
grid-row: 1 / 1;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
[data-vrts-comparisons-slot="base"] {
|
||||
clip-path: inset(0 calc(100% - var(--vrts-comparisons-slider-position)) 0 0);
|
||||
}
|
||||
|
||||
[data-vrts-comparisons-slot="target"] {
|
||||
clip-path: inset(0 0 0 var(--vrts-comparisons-slider-position));
|
||||
}
|
||||
|
||||
&:has(input:focus-visible) {
|
||||
|
||||
.vrts-comparisons__slider-handle svg {
|
||||
outline: 2px solid var(--vrts-admin-theme-color);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__slider-handle {
|
||||
--vrts-comparisons-offset: calc(62px + 42px);
|
||||
--vrts-comparisons-handle-size: 32px;
|
||||
--vrts-comparisons-handle-offest: 20px;
|
||||
--vrts-comparisons-slider-centered: calc(100% / var(--vrts-comparisons-slider-aspect-ratio) / 2 - var(--vrts-comparisons-handle-size) / 2);
|
||||
--vrts-comparisons-viewport-centered: calc(((100vh - var(--wp-admin--admin-bar--height) - 56px - 15px - var(--vrts-comparisons-offset)) / 2 - var(--vrts-comparisons-handle-size) / 2) + 15%);
|
||||
|
||||
box-sizing: border-box;
|
||||
position: sticky;
|
||||
top: calc((var(--vrts-comparisons-handle-size) / 2) + 10%);
|
||||
width: 100%;
|
||||
height: calc(var(--vrts-comparisons-handle-size) + 10px);
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
grid-column: 1 / 1;
|
||||
grid-row: 1 / 1;
|
||||
margin-block: var(--vrts-comparisons-handle-offest);
|
||||
margin-block-start: max(var(--vrts-comparisons-handle-offest), min(var(--vrts-comparisons-slider-centered), var(--vrts-comparisons-viewport-centered)));
|
||||
|
||||
@media (min-width: 851px) {
|
||||
top: calc(var(--wp-admin--admin-bar--height) + var(--vrts-comparisons-offset) + (var(--vrts-comparisons-handle-size) / 2) + 10%);
|
||||
}
|
||||
|
||||
[data-vrts-fullscreen="true"] & {
|
||||
top: calc(var(--vrts-comparisons-offset) + (var(--vrts-comparisons-handle-size) / 2) + 10%);
|
||||
}
|
||||
|
||||
svg { // stylelint-disable-line no-descending-specificity
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(var(--vrts-comparisons-slider-position) - (var(--vrts-comparisons-handle-size) / 2));
|
||||
width: var(--vrts-comparisons-handle-size);
|
||||
height: var(--vrts-comparisons-handle-size);
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
border: 1px solid var(--vrts-admin-theme-color);
|
||||
color: var(--vrts-admin-theme-color);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
&__slider-divider {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(var(--vrts-comparisons-slider-position) - 0.5px);
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
background: var(--vrts-admin-theme-color);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
&__slider-divider-clone {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(var(--vrts-comparisons-slider-position) - 0.5px);
|
||||
width: 0;
|
||||
height: 100%;
|
||||
border-left: 1px dashed #c3c4c7;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
&__slider-control {
|
||||
appearance: none;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
opacity: 0;
|
||||
|
||||
&::-webkit-slider-runnable-track {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&::-webkit-slider-thumb {
|
||||
appearance: none;
|
||||
height: 100%;
|
||||
width: 56px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Image_Helpers;
|
||||
|
||||
?>
|
||||
|
||||
<vrts-comparisons class="vrts-comparisons postbox">
|
||||
<div class="vrts-comparisons__header postbox-header">
|
||||
<div class="vrts-comparisons__title"><?php echo esc_html( get_the_title( $data['alert']->post_id ) ); ?></div>
|
||||
<div class="vrts-comparisons__info">
|
||||
<div class="vrts-comparisons__difference">
|
||||
<?php /* translators: %s: the count of pixels with a visual difference. */ ?>
|
||||
<?php echo esc_html( sprintf( __( '%spx Difference', 'visual-regression-tests' ), esc_html( number_format_i18n( ceil( $data['alert']->differences ) ) ) ) ); ?>
|
||||
</div>
|
||||
<button type="button" title="<?php esc_html_e( 'Expand', 'visual-regression-tests' ); ?>" class="vrts-comparisons__expand-button" data-vrts-fullscreen-open>
|
||||
<?php vrts()->icon( 'expand' ); ?>
|
||||
<?php vrts()->icon( 'compress' ); ?>
|
||||
</button>
|
||||
<?php vrts()->component( 'alert-actions', $data ); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="vrts-comparisons__content-container">
|
||||
<div class="vrts-comparisons__content">
|
||||
<figure class="vrts-comparisons__figure" data-vrts-comparisons-slot="comparison">
|
||||
<img class="vrts-comparisons__figure-image" <?php echo wp_kses_post( Image_Helpers::alert_image_hwstring( $data['alert'] ) ); ?> crossorigin="anonymous" src="<?php echo esc_url( Image_Helpers::get_screenshot_url( $data['alert'], 'comparison' ) ); ?>" alt="<?php esc_attr_e( 'Difference', 'visual-regression-tests' ); ?>" />
|
||||
<span class="vrts-comparisons__slider-divider-clone"></span>
|
||||
</figure>
|
||||
<canvas class="vrts-comparisons__diff-inidicator" data-vrts-comparisons-diff-inidicator></canvas>
|
||||
<div class="vrts-comparisons__slider" style="--vrts-comparisons-slider-aspect-ratio: <?php echo esc_attr( Image_Helpers::alert_image_aspect_ratio( $data['alert'] ) ); ?>">
|
||||
<figure class="vrts-comparisons__figure" data-vrts-comparisons-slot="base">
|
||||
<img class="vrts-comparisons__figure-image" <?php echo wp_kses_post( Image_Helpers::alert_image_hwstring( $data['alert'] ) ); ?> crossorigin="anonymous" src="<?php echo esc_url( Image_Helpers::get_screenshot_url( $data['alert'], 'base' ) ); ?>" alt="<?php esc_attr_e( 'Snapshot', 'visual-regression-tests' ); ?>" />
|
||||
</figure>
|
||||
<figure class="vrts-comparisons__figure" data-vrts-comparisons-slot="target">
|
||||
<img class="vrts-comparisons__figure-image" <?php echo wp_kses_post( Image_Helpers::alert_image_hwstring( $data['alert'] ) ); ?> crossorigin="anonymous" src="<?php echo esc_url( Image_Helpers::get_screenshot_url( $data['alert'], 'target' ) ); ?>" alt="<?php esc_attr_e( 'Screenshot', 'visual-regression-tests' ); ?>" />
|
||||
</figure>
|
||||
<span class="vrts-comparisons__slider-divider"></span>
|
||||
<div class="vrts-comparisons__slider-handle">
|
||||
<?php vrts()->icon( 'grip-dots' ); ?>
|
||||
</div>
|
||||
<input type="range" step="0.078125" class="vrts-comparisons__slider-control" data-vrts-comparisons-slider-control>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="vrts-gradient-loader"></span>
|
||||
</vrts-comparisons>
|
||||
@@ -0,0 +1,163 @@
|
||||
class VrtsComparisons extends window.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.resolveElements();
|
||||
this.bindFunctions();
|
||||
this.bindEvents();
|
||||
this.init();
|
||||
}
|
||||
|
||||
resolveElements() {
|
||||
this.$content = document.querySelector( '[data-vrts-fullscreen]' );
|
||||
this.$fullscreen = this.querySelector( '[data-vrts-fullscreen-open]' );
|
||||
this.$control = this.querySelector(
|
||||
'[data-vrts-comparisons-slider-control]'
|
||||
);
|
||||
this.$diffIndicator = this.querySelector(
|
||||
'[data-vrts-comparisons-diff-inidicator]'
|
||||
);
|
||||
this.$comparison = this.querySelector(
|
||||
'[data-vrts-comparisons-slot="comparison"] img'
|
||||
);
|
||||
}
|
||||
|
||||
bindFunctions() {
|
||||
this.onFullscreenToggle = this.onFullscreenToggle.bind( this );
|
||||
this.onControlChange = this.onControlChange.bind( this );
|
||||
this.onFullScreenChange = this.onFullScreenChange.bind( this );
|
||||
this.onLoadComparison = this.onLoadComparison.bind( this );
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.$fullscreen.addEventListener( 'click', this.onFullscreenToggle );
|
||||
this.$control.addEventListener( 'input', this.onControlChange );
|
||||
document.addEventListener(
|
||||
'fullscreenchange',
|
||||
this.onFullScreenChange
|
||||
);
|
||||
}
|
||||
|
||||
init() {
|
||||
this.worker = new window.Worker(
|
||||
new URL( 'worker.js', import.meta.url )
|
||||
);
|
||||
this.worker.onmessage = this.onWorkerMessage.bind( this );
|
||||
if ( this.$comparison.complete ) {
|
||||
this.onLoadComparison();
|
||||
} else {
|
||||
this.$comparison.onload = this.onLoadComparison;
|
||||
}
|
||||
}
|
||||
|
||||
onLoadComparison() {
|
||||
const imageData = this.createOffscreenCanvarImageData(
|
||||
this.$comparison
|
||||
);
|
||||
this.worker.postMessage( {
|
||||
action: 'analyzeImage',
|
||||
imageData,
|
||||
} );
|
||||
}
|
||||
|
||||
createOffscreenCanvarImageData( image ) {
|
||||
const canvas = new window.OffscreenCanvas(
|
||||
image.naturalWidth,
|
||||
image.naturalHeight
|
||||
);
|
||||
const ctx = canvas.getContext( '2d' );
|
||||
ctx.drawImage( image, 0, 0 );
|
||||
return ctx.getImageData( 0, 0, canvas.width, canvas.height );
|
||||
}
|
||||
|
||||
requestFullscreen( element ) {
|
||||
if ( element.requestFullscreen ) {
|
||||
element.requestFullscreen();
|
||||
} else if ( element.webkitRequestFullscreen ) {
|
||||
element.webkitRequestFullscreen();
|
||||
} else if ( element.msRequestFullscreen ) {
|
||||
element.msRequestFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
exitFullscreen() {
|
||||
if ( document.exitFullscreen ) {
|
||||
document.exitFullscreen();
|
||||
} else if ( document.webkitExitFullscreen ) {
|
||||
document.webkitExitFullscreen();
|
||||
} else if ( document.msExitFullscreen ) {
|
||||
document.msExitFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
getFullscreenElement() {
|
||||
return (
|
||||
document.fullscreenElement ||
|
||||
document.webkitFullscreenElement ||
|
||||
document.msFullscreenElement
|
||||
);
|
||||
}
|
||||
|
||||
onFullscreenToggle( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
if ( this.getFullscreenElement() === this.$content ) {
|
||||
this.exitFullscreen();
|
||||
} else {
|
||||
this.requestFullscreen( this.$content );
|
||||
}
|
||||
}
|
||||
|
||||
onFullScreenChange() {
|
||||
this.$content.setAttribute(
|
||||
'data-vrts-fullscreen',
|
||||
this.getFullscreenElement() === this.$content
|
||||
);
|
||||
}
|
||||
|
||||
onControlChange( e ) {
|
||||
this.style.setProperty(
|
||||
'--vrts-comparisons-slider-position',
|
||||
`${ e.target.value }%`
|
||||
);
|
||||
}
|
||||
|
||||
onWorkerMessage( e ) {
|
||||
if ( e.data?.action === 'analyzedImage' ) {
|
||||
this.highlightPixels( e.data.coloredPixels );
|
||||
}
|
||||
}
|
||||
|
||||
highlightPixels( pixels ) {
|
||||
const ctx = this.$diffIndicator.getContext( '2d' );
|
||||
this.$diffIndicator.width = this.$comparison.naturalWidth;
|
||||
this.$diffIndicator.height = this.$comparison.naturalHeight;
|
||||
ctx.clearRect(
|
||||
0,
|
||||
0,
|
||||
this.$comparison.naturalWidth,
|
||||
this.$comparison.naturalHeight
|
||||
);
|
||||
ctx.fillStyle = '#cc1818';
|
||||
pixels.forEach( ( y ) => {
|
||||
ctx.fillRect( 0, y - 2, ctx.canvas.width, 3 );
|
||||
} );
|
||||
}
|
||||
|
||||
connectedCallback() {}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.$fullscreen?.removeEventListener(
|
||||
'click',
|
||||
this.onFullscreenToggle
|
||||
);
|
||||
this.$control?.removeEventListener( 'input', this.onControlChange );
|
||||
document.removeEventListener(
|
||||
'fullscreenchange',
|
||||
this.onFullScreenChange
|
||||
);
|
||||
this.worker?.terminate();
|
||||
this.worker = null;
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define( 'vrts-comparisons', VrtsComparisons );
|
||||
@@ -0,0 +1,30 @@
|
||||
/* global self */
|
||||
function getColoredPixelsWithLimit( imageData, xLimit, direction = 'left' ) {
|
||||
const coloredPixels = new Set();
|
||||
for ( let i = 0; i < imageData.data.length; i += 4 ) {
|
||||
const r = imageData.data[ i ];
|
||||
const g = imageData.data[ i + 1 ];
|
||||
const b = imageData.data[ i + 2 ];
|
||||
const a = imageData.data[ i + 3 ];
|
||||
if ( r === 255 && g === 0 && b === 0 && a === 255 ) {
|
||||
const x = ( i / 4 ) % imageData.width;
|
||||
if ( direction === 'left' ? x < xLimit : x > xLimit ) {
|
||||
// push x and y coordinates
|
||||
coloredPixels.add( Math.floor( i / 4 / imageData.width ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
return Array.from( coloredPixels );
|
||||
}
|
||||
|
||||
self.onmessage = function ( e ) {
|
||||
if ( e.data?.action === 'analyzeImage' ) {
|
||||
const { imageData } = e.data;
|
||||
const coloredPixels = getColoredPixelsWithLimit(
|
||||
imageData,
|
||||
0,
|
||||
'right'
|
||||
);
|
||||
self.postMessage( { action: 'analyzedImage', coloredPixels } );
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Date_Time_Helpers;
|
||||
use Vrts\Core\Utilities\String_Helpers;
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
use Vrts\Models\Test_Run;
|
||||
|
||||
?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html lang="en" dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Title</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="x-apple-disable-message-reformatting" />
|
||||
<meta content="telephone=no" name="format-detection">
|
||||
|
||||
<!--[if !mso]><!-->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<!--<![endif]-->
|
||||
|
||||
<!--[if gte mso 9]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
<o:AllowPNG />
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
|
||||
<style>
|
||||
table,
|
||||
tr,
|
||||
td {
|
||||
border-collapse: separate;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--[if mso]>
|
||||
<style type="text/css">
|
||||
v\:* {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
}
|
||||
o\:* {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
}
|
||||
w\:* {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
}
|
||||
.ExternalClass {
|
||||
width: 100%;
|
||||
}
|
||||
table {
|
||||
mso-table-lspace: 0pt;
|
||||
mso-table-rspace: 0pt;
|
||||
}
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
.ReadMsgBody {
|
||||
width: 100%;
|
||||
}
|
||||
a {
|
||||
background: transparent !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
li {
|
||||
text-align: -webkit-match-parent;
|
||||
display: list-item;
|
||||
text-indent: -1em;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
margin-left: 1em !important;
|
||||
}
|
||||
|
||||
p {
|
||||
text-indent: 0;
|
||||
}
|
||||
</style>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body style="width:100%;height:100%;padding:0;Margin:0">
|
||||
<table border="0" cellspacing="0" width="100%" bgcolor="#ffffff" style="background-color: #ffffff; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<td style="padding: 20px;">
|
||||
<p style="font-size: 14px; line-height: 16px; color: #2C3338; display: block; mso-line-height-rule: exactly"><?php esc_html_e( 'Howdy 👋', 'visual-regression-tests' ); ?></p>
|
||||
<p style="font-size: 14px; line-height: 16px; color: #2C3338; display: block; mso-line-height-rule: exactly; margin: 0"><?php esc_html_e( "We've detected visual changes on your website.", 'visual-regression-tests' ); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0" cellspacing="0" bgcolor="#ffffff" style="background-color: #ffffff; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<td width="1"></td>
|
||||
<td width="280" style="padding: 0 20px;">
|
||||
<table cellpadding="0" cellspacing="0" border="0" role="presentation" style="width: 100%; border-spacing: 0; background-color: #F6F7FB;">
|
||||
<tr><td style="padding: 0 15px;">
|
||||
<table cellpadding="0" cellspacing="0" border="0" role="presentation" style="width: 100%; border-spacing: 0; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<td style="border-bottom: 1px dashed #c3c4c7; padding: 12px 0">
|
||||
<center>
|
||||
<table cellpadding="0" cellspacing="0" border="0" style="border-spacing: 0; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<td width="22" style="padding-right: 8px;">
|
||||
<img width="22" height="22" src="<?php echo esc_url( vrts()->get_plugin_url( 'assets/images/vrts-logo.png' ) ); ?>" alt="Logo">
|
||||
</td>
|
||||
<td width="100">
|
||||
<p style="font-size: 16px; line-height: 20px; color: #2C3338; display: block; margin: 0; mso-line-height-rule: exactly;"><strong><?php esc_html_e( 'VRTs Plugin', 'visual-regression-tests' ); ?></strong></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
<table cellpadding="0" cellspacing="0" border="0" style="width: 100%; border-spacing: 0; padding-top: 10px; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<td style="text-align: center">
|
||||
<p style="font-size: 14px; line-height: 20px; color: #2C3338; display: block; margin: 0; mso-line-height-rule: exactly"><?php esc_html_e( 'Test Receipt', 'visual-regression-tests' ); ?></p>
|
||||
<a style="font-size: 11px; line-height: 16px; display: block; padding-top: 4px; mso-line-height-rule: exactly" href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php echo esc_html( home_url( '/' ) ); ?></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border-bottom: 1px dashed #c3c4c7; padding: 12px 0; text-align: center;">
|
||||
<p style="font-size: 11px; line-height: 16px; color: #2C3338; display: block; margin: 0; mso-line-height-rule: exactly">
|
||||
<span style="padding-right: 10px">
|
||||
<?php
|
||||
// translators: %s: the run number.
|
||||
printf( esc_html__( 'Run #%s', 'visual-regression-tests' ), esc_html( $data['run']->id ) );
|
||||
?>
|
||||
</span>
|
||||
<?php echo wp_kses( Date_Time_Helpers::get_formatted_date_time( $data['run']->finished_at ), [ 'time' => [ 'datetime' => true ] ] ); ?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border-bottom: 1px dashed #c3c4c7; padding: 12px 0;">
|
||||
<table cellpadding="0" cellspacing="0" border="0" style="width: 100%; border-spacing: 0; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<th style="font-size: 12px; padding-bottom: 4px; line-height: 16px; color: #2C3338; mso-line-height-rule: exactly; text-align: left;">Pages</th>
|
||||
<th style="font-size: 12px; padding-bottom: 4px; line-height: 16px; color: #2C3338; mso-line-height-rule: exactly; text-align: right;">Difference</th>
|
||||
</tr>
|
||||
<?php
|
||||
|
||||
foreach ( $data['tests'] as $test ) :
|
||||
$alert = array_values( array_filter( $data['alerts'], static function( $alert ) use ( $test ) {
|
||||
return $alert->post_id === $test['post_id'];
|
||||
} ) );
|
||||
$difference = $alert ? ceil( $alert[0]->differences ) : 0;
|
||||
?>
|
||||
<tr>
|
||||
<td style="padding-top: 2px; padding-bottom: 2px; vertical-align: top; font-size: 12px; line-height: 16px; color: #2C3338; mso-line-height-rule: exactly; text-align: left;">
|
||||
<?php if ( $test['permalink'] ) : ?>
|
||||
<a style="color: #2C3338; text-decoration: none" href="<?php echo esc_url( $test['permalink'] ); ?>"><?php echo esc_html( String_Helpers::truncate( Url_Helpers::make_relative( $test['permalink'] ), 30 ) ); ?></a>
|
||||
<?php else : ?>
|
||||
N/A
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td style="padding-top: 2px; padding-bottom: 2px; vertical-align: top; font-size: 12px; line-height: 16px; color: #2C3338; mso-line-height-rule: exactly; text-align: right;">
|
||||
<?php $difference_url = $difference ? Url_Helpers::get_alert_page( $alert[0]->id, $data['run']->id ) : Url_Helpers::get_alerts_page( $data['run']->id ); ?>
|
||||
<a style="color: #2C3338; text-decoration: none" href="<?php echo esc_url( $difference_url ); ?>">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s. Test run receipt diff in pixels */
|
||||
esc_html_x( '%spx', 'test run receipt difference', 'visual-regression-tests' ),
|
||||
esc_html( number_format_i18n( $difference ) )
|
||||
);
|
||||
?>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border-bottom: 1px dashed #c3c4c7; padding: 12px 0;">
|
||||
<table cellpadding="0" cellspacing="0" border="0" style="width: 100%; border-spacing: 0; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<th style="font-size: 14px; padding-bottom: 4px; line-height: 16px; color: #2C3338; mso-line-height-rule: exactly; text-align: left;">Total</th>
|
||||
<th style="font-size: 14px; padding-bottom: 4px; line-height: 16px; color: #2C3338; mso-line-height-rule: exactly; text-align: right;">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s. Number of tests */
|
||||
esc_html( _n( '%s Test', '%s Tests', count( $data['tests'] ), 'visual-regression-tests' ) ), count( $data['tests'] )
|
||||
); ?>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-top: 2px; padding-bottom: 2px; vertical-align: top; font-size: 12px; line-height: 16px; color: #4ab866; mso-line-height-rule: exactly; text-align: left;"><?php esc_html_e( 'Passed', 'visual-regression-tests' ); ?></td>
|
||||
<td style="padding-top: 2px; padding-bottom: 2px; vertical-align: top; font-size: 12px; line-height: 16px; color: #4ab866; mso-line-height-rule: exactly; text-align: right;"><?php echo esc_html( count( $data['tests'] ) - count( $data['alerts'] ) ); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-top: 2px; padding-bottom: 2px; vertical-align: top; font-size: 12px; line-height: 16px; color: #b32d2e; mso-line-height-rule: exactly; text-align: left;"><?php esc_html_e( 'Changes Detected', 'visual-regression-tests' ); ?></td>
|
||||
<td style="padding-top: 2px; padding-bottom: 2px; vertical-align: top; font-size: 12px; line-height: 16px; color: #b32d2e; mso-line-height-rule: exactly; text-align: right;"><?php echo esc_html( count( $data['alerts'] ) ); ?></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border-bottom: 1px dashed #c3c4c7; padding: 12px 0; font-size: 11px; line-height: 16px; color: #2C3338; mso-line-height-rule: exactly;">
|
||||
<table>
|
||||
<tr>
|
||||
<td><?php esc_html_e( 'Trigger', 'visual-regression-tests' ); ?></td>
|
||||
<td style="padding-left: 5px;">
|
||||
<table cellpadding="0" cellspacing="0" border="0" role="presentation" bgcolor="#f0e8f8" width="100.00%" style="border-radius: 100px; background-color: <?php echo Test_Run::get_trigger_background_color( $data['run'] ); ?>; width: 100%; border-spacing: 0; border-collapse: separate; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<p style="font-size: 12px; font-weight: 400; line-height: 16px; color: <?php echo Test_Run::get_trigger_text_color( $data['run'] ); ?>; mso-line-height-alt: 16px; margin: 0; padding: 4px 10px"><?php echo esc_html( Test_Run::get_trigger_title( $data['run'] ) ); ?></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php
|
||||
$trigger_note = Test_Run::get_trigger_note( $data['run'] );
|
||||
if ( ! empty( $trigger_note ) ) : ?>
|
||||
<span style="color: #757575;">
|
||||
<?php echo esc_html( $trigger_note ); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-top: 12px; padding-bottom: 8px; text-align: center">
|
||||
<p style="font-size: 13px; line-height: 16px; text-transform: uppercase; color: #2C3338; display: block; margin: 0; mso-line-height-rule: exactly"><strong><?php esc_html_e( 'Test Completed!', 'visual-regression-tests' ); ?></strong></p>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="1" style="padding-bottom: 12px;">
|
||||
<table cellpadding="0" cellspacing="0" border="0" role="presentation" bgcolor="#1954ed" width="100.00%" style="border-radius: 2px; background-color: #1954ed; width: 100%; border-spacing: 0; border-collapse: separate; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<td align="center" valign="middle" style="padding: 8px 24px;">
|
||||
<a href="<?php echo Url_Helpers::get_test_run_page( $data['run'] ); ?>" style="font-size: 14px; font-weight: 600; color: white; margin: 0; padding: 0; line-height: 20px; mso-line-height-alt: 20px; text-decoration: none; display: block;"><?php esc_html_e( 'View Details', 'visual-regression-tests' ); ?></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table border="0" cellspacing="0" width="100%" bgcolor="#ffffff" style="background-color: #ffffff; font-family: 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif, Tahoma, system-ui;">
|
||||
<tr>
|
||||
<td style="padding: 20px 20px;">
|
||||
<p style="font-size: 14px; line-height: 16px; color: #2C3338; display: block; mso-line-height-rule: exactly; margin: 0"><?php esc_html_e( 'Your VRTs squad! 🚀', 'visual-regression-tests' ); ?></p>
|
||||
<p style="font-size: 14px; line-height: 16px; color: #2C3338; display: block; mso-line-height-rule: exactly">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: Home URL */
|
||||
wp_kses_post( 'This alert was sent by the VRTs plugin on %s.', 'visual-regression-tests' ),
|
||||
'<a href="' . esc_url( home_url() ) .'">' . esc_html( home_url() ) . '</a>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,98 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
|
||||
#vrts_post_options_metabox { // stylelint-disable-line selector-id-pattern
|
||||
|
||||
figcaption {
|
||||
|
||||
> :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
> :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.figure {
|
||||
margin: 0;
|
||||
|
||||
&-link {
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&-title {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
&-image {
|
||||
aspect-ratio: 16/9;
|
||||
border: solid 1px #bfbfbf;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center top;
|
||||
}
|
||||
|
||||
.howto {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-testing-status {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
margin-bottom: 0;
|
||||
|
||||
&--paused {
|
||||
color: $alert-red;
|
||||
}
|
||||
|
||||
&--waiting {
|
||||
color: #f97b06;
|
||||
}
|
||||
|
||||
&--running {
|
||||
color: $alert-green;
|
||||
}
|
||||
|
||||
&-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
margin: 1.5rem 0;
|
||||
|
||||
> * {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dashicons {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 5px;
|
||||
font-size: 0.75rem;
|
||||
color: $gray-700;
|
||||
}
|
||||
}
|
||||
|
||||
.settings {
|
||||
|
||||
&-title {
|
||||
margin-bottom: 0.5rem;
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
if ( ! $data['is_connected'] ) {
|
||||
include_once __DIR__ . '/metabox-notifications/metabox-notification-connection-failed.php';
|
||||
return;
|
||||
}
|
||||
?>
|
||||
|
||||
<?php wp_nonce_field( $data['nonce'], $data['nonce'] ); ?>
|
||||
<p class="vrts-testing-toogle">
|
||||
<?php if ( 0 === intval( $data['remaining_tests'] ) && ! $data['run_tests_checked'] ) { ?>
|
||||
<input class="widefat" type="checkbox" id="<?php echo esc_attr( $data['field_test_status_key'] ); ?>" value="0" disabled />
|
||||
<?php } else { ?>
|
||||
<input class="widefat" type="checkbox" name="<?php echo esc_attr( $data['field_test_status_key'] ); ?>" id="<?php echo esc_attr( $data['field_test_status_key'] ); ?>" <?php checked( $data['run_tests_checked'] ); ?> value="1" />
|
||||
<?php } ?>
|
||||
<label for="<?php echo esc_attr( $data['field_test_status_key'] ); ?>"><strong><?php esc_html_e( 'Add to VRTs', 'visual-regression-tests' ); ?></strong></label>
|
||||
<span class="vrts-tooltip">
|
||||
<span class="vrts-tooltip-icon dashicons dashicons-info-outline"></span>
|
||||
<span class="vrts-tooltip-content">
|
||||
<span class="vrts-tooltip-content-inner">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %1$s, %2$s: link wrapper. */
|
||||
wp_kses_post( __( 'Add this page to your Visual Regression Tests for consistent checks to ensure no visual changes go unnoticed. Explore the %1$sTests page%2$s in the VRTs plugin for an overview of all tests and their status.', 'visual-regression-tests' ) ),
|
||||
'<a href="' . esc_url( $data['plugin_url'] ) . '">',
|
||||
'</a>'
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<?php
|
||||
|
||||
// Notification: New Test added.
|
||||
if ( true === $data['is_new_test'] ) {
|
||||
include_once __DIR__ . '/metabox-notifications/metabox-notification-new-test-added.php';
|
||||
} elseif ( 1 === intval( $data['remaining_tests'] ) ) {
|
||||
// Notification: Unlock more tests.
|
||||
include_once __DIR__ . '/metabox-notifications/metabox-notification-unlock-more-tests.php';
|
||||
} elseif ( 0 === intval( $data['remaining_tests'] ) ) {
|
||||
// Notification: Unlock more tests.
|
||||
include_once __DIR__ . '/metabox-notifications/metabox-notification-upgrade-required.php';
|
||||
}
|
||||
?>
|
||||
|
||||
<?php
|
||||
// Display details only when "Run Tests" checkbox is active.
|
||||
if ( $data['run_tests_checked'] ) {
|
||||
$test_status = $data['test_status'];
|
||||
$screenshot = $data['screenshot'];
|
||||
?>
|
||||
<div class="vrts-testing-status-wrapper">
|
||||
<p class="vrts-testing-status">
|
||||
<span><?php esc_html_e( 'Test Status', 'visual-regression-tests' ); ?></span>
|
||||
<strong class="vrts-testing-status--<?php echo esc_attr( $test_status['class'] ); ?>"><?php echo wp_kses_post( $test_status['text'] ); ?></strong>
|
||||
</p>
|
||||
<p class="vrts-testing-status-info">
|
||||
<?php echo wp_kses_post( $test_status['instructions'] ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="vrts-testing-status-wrapper">
|
||||
<p class="vrts-testing-status">
|
||||
<span><?php esc_html_e( 'Snapshot', 'visual-regression-tests' ); ?></span>
|
||||
<span class="vrts-testing-status-info">
|
||||
<?php
|
||||
$text = in_array( $screenshot['status'], [ 'paused', 'waiting' ], true ) ? $screenshot['text'] : $screenshot['instructions'];
|
||||
echo wp_kses_post( $text );
|
||||
?>
|
||||
</span>
|
||||
</p>
|
||||
<figure class="figure">
|
||||
<?php echo wp_kses_post( $screenshot['screenshot'] ); ?>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="settings">
|
||||
<input name="test_id" type="hidden" value="<?php echo esc_html( $data['test_settings']['test_id'] ); ?>"/>
|
||||
<label for="vrts-hide-css-selectors" class="settings-title">
|
||||
<span><?php esc_html_e( 'Hide elements from VRTs', 'visual-regression-tests' ); ?></span>
|
||||
<span class="vrts-tooltip">
|
||||
<span class="vrts-tooltip-icon dashicons dashicons-info-outline"></span>
|
||||
<span class="vrts-tooltip-content">
|
||||
<span class="vrts-tooltip-content-inner">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %1$s, %2$s: link wrapper. */
|
||||
esc_html__( 'Exclude elements on this page: Add %1$sCSS selectors%2$s (as comma separated list) to exclude elements from VRTs when a new snapshot gets created.', 'visual-regression-tests' ),
|
||||
'<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors" target="_blank">',
|
||||
'</a>'
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<textarea id="vrts-hide-css-selectors" name="hide_css_selectors" placeholder="<?php esc_html_e( 'e.g.: .lottie, #ads', 'visual-regression-tests' ); ?>" rows="4"><?php echo esc_html( $data['test_settings']['hide_css_selectors'] ); ?></textarea>
|
||||
</div>
|
||||
<?php }//end if
|
||||
?>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<div class="vrts-metabox-notice vrts-metabox-notice-is-error">
|
||||
<p><strong><?php esc_html_e( 'Connection failed', 'visual-regression-tests' ); ?></strong></p>
|
||||
<p><?php esc_html_e( 'Something went wrong while trying to connect to the external service.', 'visual-regression-tests' ); ?></p>
|
||||
<p><a href="<?php echo esc_attr( Url_Helpers::get_page_url( 'tests' ) ); ?>"><?php esc_html_e( 'Go to plugin page', 'visual-regression-tests' ); ?></a></p>
|
||||
</div>
|
||||
@@ -0,0 +1,12 @@
|
||||
<div class="vrts-metabox-notice vrts-metabox-notice-is-success">
|
||||
<p><strong><?php esc_html_e( 'You have added a new test', 'visual-regression-tests' ); ?></strong></p>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: page title. */
|
||||
esc_html__( 'The Visual Regression Test for the page %s has been added!', 'visual-regression-tests' ),
|
||||
'<strong>' . esc_html( get_the_title( $data['post_id'] ) ) . '</strong>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<div class="vrts-metabox-notice vrts-metabox-notice-is-info">
|
||||
<p><strong><?php esc_html_e( 'Unlock more tests', 'visual-regression-tests' ); ?></strong></p>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
'%s %s',
|
||||
sprintf(
|
||||
/* translators: %1$s, %2$s: number of tests. */
|
||||
esc_html__( 'Good work! You have added %1$s of %2$s available tests.', 'visual-regression-tests' ),
|
||||
intval( $data['total_tests'] ) - intval( $data['remaining_tests'] ),
|
||||
intval( $data['total_tests'] )
|
||||
),
|
||||
sprintf(
|
||||
/* translators: %1$s, %2$s: link wrapper. */
|
||||
esc_html__( 'Upgrade %1$shere%2$s to add more tests to your website!', 'visual-regression-tests' ),
|
||||
'<a href="' . esc_url( Url_Helpers::get_page_url( 'upgrade' ) ) . '" target="_blank">',
|
||||
'</a>'
|
||||
)
|
||||
)
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<div class="vrts-metabox-notice vrts-metabox-notice-is-error">
|
||||
<p><strong><?php esc_html_e( 'Ready for an Upgrade?', 'visual-regression-tests' ); ?></strong></p>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
'%1$s <a href="%2$s" target="_blank" title="%3$s">%3$s</a>',
|
||||
esc_html__( 'Looks like you need a bigger plan to add more tests.', 'visual-regression-tests' ),
|
||||
esc_url( Url_Helpers::get_page_url( 'upgrade' ) ),
|
||||
esc_html__( 'Upgrade here!', 'visual-regression-tests' )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
@@ -0,0 +1,83 @@
|
||||
.vrts-modal {
|
||||
animation: vrts-fade-in 200ms both;
|
||||
display: flex;
|
||||
padding: 15px;
|
||||
outline: 0;
|
||||
z-index: 9999999999;
|
||||
|
||||
&[aria-hidden="true"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&,
|
||||
&__overlay {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
&__overlay {
|
||||
background-color: rgba(44, 51, 56, 0.35);
|
||||
}
|
||||
|
||||
&__content {
|
||||
animation: vrts-fade-in 300ms both, vrts-slide-up 300ms both;
|
||||
background-color: #fff;
|
||||
box-shadow: 2px 2px 8px 4px rgba(30, 30, 30, 0.12);
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: auto;
|
||||
max-height: min(calc(100vh - 40px), 620px);
|
||||
min-width: 250px;
|
||||
max-width: 345px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
z-index: 99999;
|
||||
|
||||
&-inner {
|
||||
flex: 1 1 auto;
|
||||
overflow: auto;
|
||||
padding: 10px 15px 15px;
|
||||
}
|
||||
}
|
||||
|
||||
&__close {
|
||||
all: unset;
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
right: 7px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
display: block !important;
|
||||
background-image: url('data:image/svg+xml,<svg width="11" height="10" viewBox="0 0 11 10" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10.2564 1.41L6.71644 4.95L10.2564 8.49L8.84645 9.9L5.30645 6.37L1.77644 9.9L0.356445 8.48L3.88645 4.95L0.356445 1.42L1.77644 0L5.30645 3.53L8.84645 0L10.2564 1.41Z" fill="%23757575"/></svg>'); // stylelint-disable-line
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
border-radius: 3px;
|
||||
font-size: 0;
|
||||
z-index: 1;
|
||||
transition: background-color 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: #f6f7f7;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--vrts-admin-theme-color);
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin: 0;
|
||||
padding: 15px 45px 0 15px;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import A11yDialog from 'a11y-dialog';
|
||||
|
||||
class VrtsModal extends window.HTMLElement {
|
||||
connectedCallback() {
|
||||
this.modal = new A11yDialog( this );
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.modal.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define( 'vrts-modal', VrtsModal );
|
||||
@@ -0,0 +1,66 @@
|
||||
.vrts-settings {
|
||||
display: block;
|
||||
|
||||
h1 {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
form h2 {
|
||||
font-weight: 400;
|
||||
font-size: 20px;
|
||||
|
||||
span {
|
||||
display: block;
|
||||
margin-top: 0.75rem;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
fieldset {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
input {
|
||||
|
||||
&[readonly] {
|
||||
border-color: #8c8f94;
|
||||
background-color: #fff;
|
||||
color: #2c3338;
|
||||
}
|
||||
}
|
||||
|
||||
.form-table {
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 0 24px 24px 0;
|
||||
}
|
||||
|
||||
td fieldset label {
|
||||
margin: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
&__pro-label {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 11px;
|
||||
line-height: 1;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
color: #fff;
|
||||
background: #757575;
|
||||
border-radius: 35px;
|
||||
}
|
||||
|
||||
&__modal {
|
||||
|
||||
&-info {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
?>
|
||||
<vrts-settings class="wrap vrts-settings">
|
||||
<h1><?php echo esc_html( $data['title'] ); ?></h1>
|
||||
<form method="post" action="options.php">
|
||||
<?php
|
||||
settings_fields( $data['settings_fields'] );
|
||||
do_settings_sections( $data['settings_sections'] );
|
||||
submit_button();
|
||||
?>
|
||||
</form>
|
||||
<vrts-modal id="vrts-modal-pro-settings" class="vrts-modal vrts-settings__modal" aria-hidden="true">
|
||||
<div class="vrts-modal__overlay" data-a11y-dialog-hide></div>
|
||||
<div class="vrts-modal__content" role="document">
|
||||
<button type="button" class="vrts-modal__close" data-a11y-dialog-hide aria-label="<?php esc_attr_e( 'Close', 'visual-regression-tests' ); ?>"></button>
|
||||
<h2 class="vrts-modal__title">
|
||||
<?php esc_html_e( '🚀 Go Pro for more testing power!', 'visual-regression-tests' ); ?>
|
||||
</h2>
|
||||
<div class="vrts-modal__content-inner">
|
||||
<p class="vrts-settings__modal-info"><?php esc_html_e( 'Upgrade your plan and unlock automatic testing after updates, plus more tools like manual testing to keep your sites running smoothly.', 'visual-regression-tests' ); ?></p>
|
||||
<a href="<?php echo esc_url( Url_Helpers::get_page_url( 'upgrade' ) ); ?>" class="button button-primary vrts-settings__modal-link"><?php esc_html_e( 'Unlock Now', 'visual-regression-tests' ); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</vrts-modal>
|
||||
</vrts-settings>
|
||||
@@ -0,0 +1,36 @@
|
||||
class VrtsSettings extends window.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.resolveElements();
|
||||
this.bindFunctions();
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
resolveElements() {
|
||||
this.$proSettingsCheckboxes = this.querySelectorAll(
|
||||
'[data-a11y-dialog-show] input[type="checkbox"]'
|
||||
);
|
||||
}
|
||||
|
||||
bindFunctions() {
|
||||
this.onCheckboxChange = this.onCheckboxChange.bind( this );
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.$proSettingsCheckboxes?.forEach( ( item ) => {
|
||||
item.addEventListener( 'change', this.onCheckboxChange );
|
||||
} );
|
||||
}
|
||||
|
||||
onCheckboxChange( e ) {
|
||||
e.preventDefault();
|
||||
e.currentTarget.checked = ! e.currentTarget.checked;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.$proSettingsCheckboxes?.forEach( ( item ) => {
|
||||
item.removeEventListener( 'change', this.onCheckboxChange );
|
||||
} );
|
||||
}
|
||||
}
|
||||
window.customElements.define( 'vrts-settings', VrtsSettings );
|
||||
@@ -0,0 +1,206 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
|
||||
.vrts-test-run-alerts {
|
||||
|
||||
&__heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #f0f0f1;
|
||||
padding: 0;
|
||||
height: 62px;
|
||||
overflow: hidden;
|
||||
transition: box-shadow 0.2s;
|
||||
|
||||
&[data-is-sticky="true"] {
|
||||
box-shadow: 0 1px 0 0 $gray-10;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
> * {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
@media (min-width: 851px) {
|
||||
padding: 0 20px;
|
||||
position: sticky;
|
||||
top: -0.1px;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
&-link {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
min-height: 30px;
|
||||
transition: color 0.2s;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
left: -15px;
|
||||
right: -15px;
|
||||
bottom: -5px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: $blue-50;
|
||||
}
|
||||
|
||||
&--button {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__list {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
padding: 0 10px 10px 10px;
|
||||
margin: 0 -10px;
|
||||
overflow-x: scroll;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
@media (min-width: 851px) {
|
||||
flex-direction: column;
|
||||
overflow: visible;
|
||||
padding: 0 20px;
|
||||
margin: 0 0 20px 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__card {
|
||||
box-sizing: border-box;
|
||||
background: #fff;
|
||||
border: 1px solid $gray-10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 0 auto;
|
||||
transition: all 0.1s;
|
||||
box-shadow: inset 0 0 0 1px transparent;
|
||||
width: 60%;
|
||||
|
||||
@media (min-width: 480px) {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
@media (min-width: 851px) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:has([data-vrts-state="read"]) {
|
||||
background: #f6f7f9;
|
||||
}
|
||||
|
||||
&:has(:hover),
|
||||
&:has([data-vrts-current="true"]) {
|
||||
border-color: var(--vrts-admin-theme-color);
|
||||
box-shadow: inset 0 0 0 1px var(--vrts-admin-theme-color);
|
||||
}
|
||||
|
||||
&:has([data-vrts-current="false"]:focus-visible) {
|
||||
border-color: $gray-20;
|
||||
box-shadow: inset 0 0 0 1px $gray-20;
|
||||
}
|
||||
|
||||
&-link {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
padding: 10px 10px 0 10px;
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-figure {
|
||||
position: relative;
|
||||
background: #f6f7f7;
|
||||
border: 1px solid $gray-5;
|
||||
aspect-ratio: 1 / 1.15;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-flag {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
visibility: hidden;
|
||||
|
||||
[data-vrts-false-positive="true"] & {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
&-image {
|
||||
position: absolute;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
&-title-inner,
|
||||
&-path {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3125rem;
|
||||
color: $gray-70;
|
||||
font-weight: 700;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 4px;
|
||||
text-decoration: none;
|
||||
|
||||
[data-vrts-state="read"] & {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
[data-vrts-state="unread"] &::after {
|
||||
content: "";
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: var(--vrts-admin-theme-color);
|
||||
border-radius: 50%;
|
||||
flex: 0 0 auto;
|
||||
margin-top: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
&-path {
|
||||
padding: 10px;
|
||||
margin-top: -10px;
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid $gray-20;
|
||||
outline-offset: -8px;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Models\Alert;
|
||||
use Vrts\Core\Utilities\Image_Helpers;
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
$unread_alerts = Alert::get_unread_count_by_test_run_ids( $data['run']->id );
|
||||
$unread_count = $unread_alerts[0]->count ?? 0;
|
||||
$unred_runs_count = Alert::get_total_items_grouped_by_test_run();
|
||||
$current_alert_id = isset( $data['alert']->id ) ? $data['alert']->id : 0;
|
||||
|
||||
?>
|
||||
<vrts-test-run-alerts
|
||||
class="vrts-test-run-alerts"
|
||||
data-vrts-current-alert="<?php echo esc_attr( $current_alert_id ? $current_alert_id : 'false' ); ?>"
|
||||
data-vrts-unread-runs="<?php echo esc_attr( $unred_runs_count ); ?>">
|
||||
<div class="vrts-test-run-alerts__heading">
|
||||
<a href="<?php echo esc_url( Url_Helpers::get_page_url( 'runs' ) ); ?>" class="vrts-test-run-alerts__heading-link">
|
||||
<?php vrts()->icon( 'chevron-left' ); ?>
|
||||
<?php esc_html_e( 'All Runs', 'visual-regression-tests' ); ?>
|
||||
</a>
|
||||
<?php if ( $data['alerts'] ) : ?>
|
||||
<button data-vrts-loading="false" data-vrts-action-state="<?php echo esc_attr( $unread_count > 0 ? 'primary' : 'secondary' ); ?>" data-vrts-test-run-id="<?php echo esc_attr( $data['run']->id ); ?>" data-vrts-test-run-action="read-status" class="vrts-test-run-alerts__heading-link vrts-test-run-alerts__heading-link--button vrts-action-button">
|
||||
<span class="vrts-action-button__icons">
|
||||
<span class="vrts-action-button__icon" data-vrts-action-state-secondary><?php vrts()->icon( 'email-unread' ); ?></span>
|
||||
<span class="vrts-action-button__icon" data-vrts-action-state-primary><?php vrts()->icon( 'email-read' ); ?></span>
|
||||
<span class="vrts-action-button__spinner"><?php vrts()->icon( 'spinner' ); ?></span>
|
||||
</span>
|
||||
<span class="vrts-action-button__info" data-vrts-action-state-primary><?php esc_html_e( 'Mark all as read', 'visual-regression-tests' ); ?></span>
|
||||
<span class="vrts-action-button__info" data-vrts-action-state-secondary><?php esc_html_e( 'Mark all as unread', 'visual-regression-tests' ); ?></span>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if ( $data['alerts'] ) : ?>
|
||||
<div class="vrts-test-run-alerts__list">
|
||||
<?php
|
||||
foreach ( $data['alerts'] as $alert ) :
|
||||
$test = null;
|
||||
foreach ( $data['tests'] as $some_test ) {
|
||||
if ( $some_test['post_id'] === $alert->post_id ) {
|
||||
$test = $some_test;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$alert_link = add_query_arg( [
|
||||
'run_id' => $data['run']->id,
|
||||
'alert_id' => $alert->id,
|
||||
], Url_Helpers::get_page_url( 'runs' ) );
|
||||
|
||||
$alert_permalink = '';
|
||||
$alert_post_title = '';
|
||||
if ( $test ) {
|
||||
$alert_permalink = $test['permalink'];
|
||||
$alert_post_title = $test['post_title'];
|
||||
}
|
||||
if ( ! $alert_permalink ) {
|
||||
$alert_permalink = get_permalink( $alert->post_id );
|
||||
}
|
||||
if ( ! $alert_post_title ) {
|
||||
$alert_post_title = get_the_title( $alert->post_id ) ?: 'N/A';
|
||||
}
|
||||
$alert_relative_permalink = Url_Helpers::make_relative( $alert_permalink );
|
||||
|
||||
?>
|
||||
<div class="vrts-test-run-alerts__card">
|
||||
<a
|
||||
id="vrts-alert-<?php echo esc_attr( $alert->id ); ?>"
|
||||
href="<?php echo esc_url( $alert_link ); ?>"
|
||||
class="vrts-test-run-alerts__card-link"
|
||||
data-vrts-alert="<?php echo esc_attr( $alert->id ); ?>"
|
||||
data-vrts-current="<?php echo esc_attr( $current_alert_id === $alert->id ? 'true' : 'false' ); ?>"
|
||||
data-vrts-state="<?php echo esc_attr( intval( $alert->alert_state ) === 0 ? 'unread' : 'read' ); ?>"
|
||||
data-vrts-false-positive="<?php echo esc_attr( $alert->is_false_positive ? 'true' : 'false' ); ?>">
|
||||
<figure class="vrts-test-run-alerts__card-figure">
|
||||
<img class="vrts-test-run-alerts__card-image" src="<?php echo esc_url( Image_Helpers::get_screenshot_url( $alert, 'comparison', 'preview' ) ); ?>" alt="<?php esc_attr_e( 'Difference', 'visual-regression-tests' ); ?>">
|
||||
<span class="vrts-test-run-alerts__card-flag"><?php vrts()->icon( 'flag' ); ?></span>
|
||||
</figure>
|
||||
<span class="vrts-test-run-alerts__card-title">
|
||||
<span class="vrts-test-run-alerts__card-title-inner"><?php echo esc_html( $alert_post_title ); ?></span>
|
||||
</span>
|
||||
</a>
|
||||
<a href="<?php echo esc_url( get_permalink( $alert->post_id ) ); ?>" target="_blank" class="vrts-test-run-alerts__card-path"><?php echo esc_html( $alert_relative_permalink ); ?></a>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php vrts()->component( 'test-run-receipt', $data ); ?>
|
||||
<script>
|
||||
const urlParams = new URLSearchParams( window.location.search );
|
||||
const currentAlertId = urlParams.get( 'alert_id' );
|
||||
|
||||
if ( currentAlertId ) {
|
||||
const $sidebar = document.querySelector(
|
||||
'.vrts-test-run-page__sidebar'
|
||||
);
|
||||
|
||||
let $alert = document.getElementById(
|
||||
`vrts-alert-${ currentAlertId }`
|
||||
);
|
||||
|
||||
let offsetTop = 0;
|
||||
|
||||
while ( $alert && $alert !== $sidebar ) {
|
||||
offsetTop += $alert.offsetTop;
|
||||
$alert = $alert.offsetParent;
|
||||
}
|
||||
|
||||
if ( $alert ) {
|
||||
$sidebar.scrollTo( {
|
||||
left: 0,
|
||||
top: offsetTop - 82,
|
||||
} );
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</vrts-test-run-alerts>
|
||||
@@ -0,0 +1,297 @@
|
||||
class VrtsTestRunAlerts extends window.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.resolveElements();
|
||||
this.bindFunctions();
|
||||
this.bindEvents();
|
||||
this.unreadAlerts = new Set();
|
||||
this.initialUnreadAlerts = 0;
|
||||
this.unreadRuns = parseInt(
|
||||
this.getAttribute( 'data-vrts-unread-runs' ),
|
||||
10
|
||||
);
|
||||
}
|
||||
|
||||
resolveElements() {
|
||||
this.$heading = this.querySelector( '.vrts-test-run-alerts__heading' );
|
||||
this.$alerts = this.querySelectorAll( '[data-vrts-alert]' );
|
||||
this.$actionButtons = this.querySelectorAll(
|
||||
'[data-vrts-test-run-action]'
|
||||
);
|
||||
|
||||
this.$runsMenuItems = [
|
||||
document.querySelector(
|
||||
'.vrts-admin-header [href*="page=vrts-runs"]'
|
||||
),
|
||||
document.querySelector(
|
||||
'#adminmenu .menu-top[href*="page=vrts"] .wp-menu-name'
|
||||
),
|
||||
document.querySelector(
|
||||
'#adminmenu .wp-submenu a[href*="page=vrts-runs"]'
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
bindFunctions() {
|
||||
this.handleAlertClick = this.handleAlertClick.bind( this );
|
||||
this.handleActionClick = this.handleActionClick.bind( this );
|
||||
this.updateRunsCount = this.updateRunsCount.bind( this );
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.$alerts?.forEach( ( item ) => {
|
||||
item.addEventListener( 'click', this.handleAlertClick );
|
||||
} );
|
||||
this.$actionButtons?.forEach( ( item ) => {
|
||||
item.addEventListener( 'click', this.handleActionClick );
|
||||
} );
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.checkHeadingSticky();
|
||||
this.checkReadStatusChange();
|
||||
|
||||
this.$alerts.forEach( ( item ) => {
|
||||
const isUnread =
|
||||
item.getAttribute( 'data-vrts-state' ) === 'unread';
|
||||
if ( isUnread ) {
|
||||
this.unreadAlerts.add( item.getAttribute( 'data-vrts-alert' ) );
|
||||
}
|
||||
} );
|
||||
|
||||
this.initialUnreadAlerts = this.unreadAlerts.size;
|
||||
}
|
||||
|
||||
checkHeadingSticky() {
|
||||
const checkIsSticky = ( entries ) => {
|
||||
const isSticky = ! entries[ 0 ].isIntersecting;
|
||||
this.$heading.setAttribute( 'data-is-sticky', isSticky );
|
||||
};
|
||||
|
||||
const observer = new window.IntersectionObserver( checkIsSticky, {
|
||||
root: document,
|
||||
threshold: [ 1 ],
|
||||
} );
|
||||
|
||||
observer.observe( this.$heading );
|
||||
}
|
||||
|
||||
checkReadStatusChange() {
|
||||
const observer = new window.MutationObserver( ( mutations ) => {
|
||||
mutations.forEach( ( mutation ) => {
|
||||
if (
|
||||
mutation.type === 'attributes' &&
|
||||
mutation.attributeName === 'data-vrts-state'
|
||||
) {
|
||||
const id =
|
||||
mutation.target.getAttribute( 'data-vrts-alert' );
|
||||
const state =
|
||||
mutation.target.getAttribute( 'data-vrts-state' );
|
||||
|
||||
if ( id === 'receipt' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'unread' === state ) {
|
||||
this.unreadAlerts.add( id );
|
||||
} else {
|
||||
this.unreadAlerts.delete( id );
|
||||
}
|
||||
|
||||
this.querySelector(
|
||||
'[data-vrts-test-run-action="read-status"]'
|
||||
).setAttribute(
|
||||
'data-vrts-action-state',
|
||||
this.unreadAlerts.size > 0 ? 'primary' : 'secondary'
|
||||
);
|
||||
|
||||
this.updateRunsCount( this.unreadAlerts.size );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
||||
this.$alerts.forEach( ( item ) => {
|
||||
observer.observe( item, {
|
||||
attributes: true,
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
updateRunsCount( unreadAlerts ) {
|
||||
let unreadRuns = this.unreadRuns;
|
||||
|
||||
if ( unreadAlerts > 0 && this.initialUnreadAlerts === 0 ) {
|
||||
unreadRuns += 1;
|
||||
} else if ( unreadAlerts === 0 && this.initialUnreadAlerts > 0 ) {
|
||||
unreadRuns -= 1;
|
||||
}
|
||||
|
||||
this.$runsMenuItems.forEach( ( item ) => {
|
||||
if ( item ) {
|
||||
item.querySelector( '.update-plugins' )?.remove();
|
||||
item.textContent = item.textContent.replace( /\u00A0/g, '' );
|
||||
|
||||
if ( unreadRuns > 0 ) {
|
||||
const $count = document.createElement( 'span' );
|
||||
const nbsp = document.createTextNode( '\u00A0' );
|
||||
$count.classList.add( 'update-plugins' );
|
||||
$count.textContent = unreadRuns;
|
||||
|
||||
item.appendChild( nbsp );
|
||||
item.appendChild( $count );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
handleAlertClick( e ) {
|
||||
e.preventDefault();
|
||||
const $el = e.currentTarget;
|
||||
const isCurrent = $el.getAttribute( 'data-vrts-current' ) === 'true';
|
||||
|
||||
if ( isCurrent ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const href = $el.getAttribute( 'href' );
|
||||
const $content =
|
||||
document.querySelector( 'vrts-comparisons' ) ||
|
||||
document.querySelector( 'vrts-test-run-success' );
|
||||
const $pagination = document.querySelector(
|
||||
'vrts-test-run-pagination'
|
||||
);
|
||||
|
||||
this.$alerts.forEach( ( item ) => {
|
||||
item.setAttribute( 'data-vrts-current', 'false' );
|
||||
} );
|
||||
|
||||
$el.setAttribute( 'data-vrts-current', 'true' );
|
||||
|
||||
const timeout = setTimeout( () => {
|
||||
$content.setAttribute( 'data-vrts-loading', 'true' );
|
||||
}, 200 );
|
||||
|
||||
fetch( href )
|
||||
.then( ( response ) => {
|
||||
return response.text();
|
||||
} )
|
||||
.then( ( data ) => {
|
||||
const parser = new window.DOMParser();
|
||||
const $html = parser.parseFromString( data, 'text/html' );
|
||||
|
||||
const $newContent =
|
||||
$html.querySelector( 'vrts-comparisons' ) ||
|
||||
$html.querySelector( 'vrts-test-run-success' );
|
||||
const $newPagination = $html.querySelector(
|
||||
'vrts-test-run-pagination'
|
||||
);
|
||||
|
||||
window.history.replaceState( {}, '', href );
|
||||
|
||||
this.scrollTo( $content.offsetTop - 62 );
|
||||
|
||||
if ( $newContent ) {
|
||||
$content.replaceWith( $newContent );
|
||||
}
|
||||
|
||||
if ( $newPagination ) {
|
||||
$pagination.replaceWith( $newPagination );
|
||||
}
|
||||
|
||||
clearTimeout( timeout );
|
||||
} );
|
||||
}
|
||||
|
||||
handleActionClick( e ) {
|
||||
const $el = e.currentTarget;
|
||||
const isLoading = $el.getAttribute( 'data-vrts-loading' ) === 'true';
|
||||
const state = $el.getAttribute( 'data-vrts-action-state' );
|
||||
const isPrimary = state === 'primary';
|
||||
|
||||
if ( isLoading ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const action = $el.getAttribute( 'data-vrts-test-run-action' );
|
||||
const id = $el.getAttribute( 'data-vrts-test-run-id' );
|
||||
|
||||
this.handleAction( action, $el, id, isPrimary );
|
||||
}
|
||||
|
||||
handleAction( action, $el, id, shouldSetAction ) {
|
||||
const restEndpoint = `${ window.vrts_admin_vars.rest_url }/test-runs/${ id }/${ action }`;
|
||||
const method = shouldSetAction ? 'POST' : 'DELETE';
|
||||
|
||||
let loadingElapsedTime = 0;
|
||||
let interval = null;
|
||||
|
||||
const timeout = setTimeout( () => {
|
||||
$el.setAttribute( 'data-vrts-loading', 'true' );
|
||||
const loadingStartTime = window.Date.now();
|
||||
interval = setInterval( () => {
|
||||
loadingElapsedTime = window.Date.now() - loadingStartTime;
|
||||
}, 50 );
|
||||
}, 200 );
|
||||
|
||||
fetch( restEndpoint, {
|
||||
method,
|
||||
headers: {
|
||||
'X-WP-Nonce': window.vrts_admin_vars.rest_nonce,
|
||||
},
|
||||
} )
|
||||
.then( ( response ) => {
|
||||
return response.json();
|
||||
} )
|
||||
.then( () => {
|
||||
const loadingTimeoutTime =
|
||||
loadingElapsedTime > 0
|
||||
? Math.abs( loadingElapsedTime - 400 )
|
||||
: 0;
|
||||
|
||||
setTimeout( () => {
|
||||
$el.setAttribute( 'data-vrts-loading', 'false' );
|
||||
$el.setAttribute(
|
||||
'data-vrts-action-state',
|
||||
shouldSetAction ? 'secondary' : 'primary'
|
||||
);
|
||||
|
||||
const $alerts =
|
||||
document.querySelectorAll( '[data-vrts-alert]' );
|
||||
|
||||
$alerts.forEach( ( item ) => {
|
||||
item.setAttribute(
|
||||
'data-vrts-state',
|
||||
shouldSetAction ? 'read' : 'unread'
|
||||
);
|
||||
} );
|
||||
}, loadingTimeoutTime );
|
||||
|
||||
clearTimeout( timeout );
|
||||
clearInterval( interval );
|
||||
} );
|
||||
}
|
||||
|
||||
scrollTo( offset ) {
|
||||
const $el =
|
||||
document.fullscreenElement ||
|
||||
document.webkitFullscreenElement ||
|
||||
document.msFullscreenElement ||
|
||||
window;
|
||||
|
||||
$el.scrollTo( {
|
||||
top: offset,
|
||||
behavior: 'smooth',
|
||||
} );
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.$alerts?.forEach( ( item ) => {
|
||||
item.removeEventListener( 'click', this.handleAlertClick );
|
||||
} );
|
||||
this.$actionButtons?.forEach( ( item ) => {
|
||||
item.removeEventListener( 'click', this.handleActionClick );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define( 'vrts-test-run-alerts', VrtsTestRunAlerts );
|
||||
@@ -0,0 +1,44 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
|
||||
.vrts-test-run-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
@media (max-width: 700px) {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
> * {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
min-width: 0;
|
||||
flex-shrink: 0;
|
||||
|
||||
&:not(:last-child)::after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 1px;
|
||||
height: 1rem;
|
||||
background: $gray-10;
|
||||
}
|
||||
}
|
||||
|
||||
&__trigger {
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.vrts-test-run-trigger-notes {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
display: -webkit-box;
|
||||
color: $gray-40;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
max-block-size: calc(13px * 1.4);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: initial;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Date_Time_Helpers;
|
||||
use Vrts\Models\Test_Run;
|
||||
|
||||
$trigger_note = Test_Run::get_trigger_note( $data );
|
||||
|
||||
?>
|
||||
<div class="vrts-test-run-info">
|
||||
<strong>
|
||||
<?php
|
||||
// translators: %s: the run number.
|
||||
printf( esc_html__( 'Run #%s', 'visual-regression-tests' ), esc_html( $data->id ) );
|
||||
?>
|
||||
</strong>
|
||||
<?php echo wp_kses( Date_Time_Helpers::get_formatted_relative_date_time( $data->finished_at ), [ 'time' => [ 'datetime' => true ] ] ); ?>
|
||||
<span class="vrts-test-run-info__trigger">
|
||||
<span class="vrts-test-run-trigger vrts-test-run-trigger--<?php echo esc_attr( $data->trigger ); ?>">
|
||||
<?php echo esc_html( Test_Run::get_trigger_title( $data ) ); ?>
|
||||
</span>
|
||||
<?php if ( ! empty( $trigger_note ) ) : ?>
|
||||
<span class="vrts-test-run-trigger-notes" title="<?php echo esc_attr( $trigger_note ); ?>">
|
||||
<?php echo esc_html( $trigger_note ); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
</div>
|
||||
@@ -0,0 +1,128 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
@import "@wordpress/base-styles/mixins";
|
||||
@import "@wordpress/base-styles/breakpoints";
|
||||
@import "@wordpress/base-styles/variables";
|
||||
@import "@wordpress/base-styles/default-custom-properties";
|
||||
|
||||
.vrts-test-run-wrap {
|
||||
|
||||
#wpfooter {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#wpbody-content {
|
||||
padding-bottom: 0;
|
||||
|
||||
@media (min-width: 851px) {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-test-run-page {
|
||||
--vrts-test-run-page-offset: 54px; // our header height
|
||||
|
||||
display: flex;
|
||||
margin-right: 10px;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
|
||||
@media (min-width: 851px) {
|
||||
gap: 20px;
|
||||
flex-direction: row;
|
||||
margin-left: -20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
&__sidebar {
|
||||
order: 2;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: linear-gradient(to right, #{$gray-10} 1px, transparent 1px);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: $gray-20;
|
||||
}
|
||||
|
||||
@media (min-width: 851px) {
|
||||
order: -1;
|
||||
width: 280px;
|
||||
position: sticky;
|
||||
top: var(--wp-admin--admin-bar--height);
|
||||
height: calc(100vh - var(--wp-admin--admin-bar--height) - var(--vrts-test-run-page-offset));
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
flex: 1;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 20px;
|
||||
|
||||
&[data-vrts-fullscreen="true"] {
|
||||
overflow: auto;
|
||||
padding: 0 20px 20px 20px;
|
||||
background-color: #f0f0f1;
|
||||
}
|
||||
|
||||
@media (min-width: 851px) {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
&-heading {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
column-gap: 2rem;
|
||||
row-gap: 1rem;
|
||||
padding: 1rem 0;
|
||||
border-bottom: 1px solid $gray-10;
|
||||
|
||||
@media (min-width: 851px) {
|
||||
box-sizing: border-box;
|
||||
flex-wrap: nowrap;
|
||||
position: sticky;
|
||||
top: var(--wp-admin--admin-bar--height);
|
||||
height: 62px;
|
||||
padding: 0;
|
||||
background: #f0f0f1;
|
||||
z-index: 1;
|
||||
|
||||
[data-vrts-fullscreen="true"] & {
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-navigation-info {
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.25rem;
|
||||
margin-top: 1rem;
|
||||
color: #757575;
|
||||
|
||||
@media (min-width: 851px) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
svg {
|
||||
color: $gray-70;
|
||||
background: $gray-5;
|
||||
border-radius: 3px;
|
||||
padding: 5px;
|
||||
width: 0.75rem;
|
||||
height: 0.75rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<vrts-test-run-page class="vrts-test-run-page">
|
||||
<div class="vrts-test-run-page__sidebar">
|
||||
<?php vrts()->component( 'test-run-alerts', $data ); ?>
|
||||
</div>
|
||||
<div class="vrts-test-run-page__content" data-vrts-fullscreen="false">
|
||||
<div class="vrts-test-run-page__content-heading">
|
||||
<?php vrts()->component( 'test-run-info', $data['run'] ); ?>
|
||||
<?php
|
||||
vrts()->component( 'test-run-pagination', [
|
||||
'run' => $data['run'],
|
||||
'pagination' => $data['pagination'],
|
||||
'is_receipt' => $data['is_receipt'],
|
||||
] );
|
||||
?>
|
||||
</div>
|
||||
<?php if ( $data['alerts'] && ! $data['is_receipt'] ) : ?>
|
||||
<?php
|
||||
vrts()->component( 'comparisons', [
|
||||
'alert' => $data['alert'],
|
||||
'test_settings' => $data['test_settings'],
|
||||
] );
|
||||
?>
|
||||
<div class="vrts-test-run-page__content-navigation-info">
|
||||
<?php esc_html_e( 'Navigate with arrow keys', 'visual-regression-tests' ); ?>
|
||||
<?php vrts()->icon( 'arrow-up' ); ?>
|
||||
<?php vrts()->icon( 'arrow-down' ); ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<?php
|
||||
vrts()->component( 'test-run-success', [
|
||||
'run' => $data['run'],
|
||||
'is_receipt' => $data['is_receipt'],
|
||||
] );
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</vrts-test-run-page>
|
||||
@@ -0,0 +1,50 @@
|
||||
class VrtsTestRunPage extends window.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.bindFunctions();
|
||||
this.bindEvents();
|
||||
this.isScrolling = false;
|
||||
}
|
||||
|
||||
bindFunctions() {
|
||||
this.onScroll = this.onScroll.bind( this );
|
||||
this.setOffset = this.setOffset.bind( this );
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
document.addEventListener( 'scroll', this.onScroll );
|
||||
}
|
||||
|
||||
onScroll() {
|
||||
if ( ! this.isScrolling ) {
|
||||
this.isScrolling = true;
|
||||
window.requestAnimationFrame( this.setOffset );
|
||||
}
|
||||
}
|
||||
|
||||
setOffset() {
|
||||
const offset = Math.max( 0, this.offset - window.scrollY );
|
||||
|
||||
this.style.setProperty(
|
||||
'--vrts-test-run-page-offset',
|
||||
`${ offset }px`
|
||||
);
|
||||
|
||||
this.isScrolling = false;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
const rect = this.getBoundingClientRect();
|
||||
const adminBarHeight =
|
||||
document.getElementById( 'wpadminbar' ).offsetHeight;
|
||||
this.offset = rect.top + window.scrollY - adminBarHeight;
|
||||
|
||||
this.setOffset();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
document.removeEventListener( 'scroll', this.onScroll );
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define( 'vrts-test-run-page', VrtsTestRunPage );
|
||||
@@ -0,0 +1,22 @@
|
||||
.vrts-test-run-pagination {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
align-items: center;
|
||||
|
||||
&__text {
|
||||
white-space: nowrap;
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
vertical-align: baseline;
|
||||
min-width: 30px;
|
||||
min-height: 30px;
|
||||
margin: 0;
|
||||
padding: 0 4px;
|
||||
font-size: 16px;
|
||||
line-height: 1.625;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
|
||||
// don't show pagination if there is no previous or next alert.
|
||||
if ( 0 === $data['pagination']['total'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
?>
|
||||
<vrts-test-run-pagination class="vrts-test-run-pagination">
|
||||
<span class="screen-reader-text"><?php esc_html_e( 'Current Page', 'visual-regression-tests' ); ?></span>
|
||||
<span class="vrts-test-run-pagination__text">
|
||||
<?php
|
||||
if ( $data['is_receipt'] ) {
|
||||
esc_html_e( 'Test Receipt', 'visual-regression-tests' );
|
||||
} else {
|
||||
printf(
|
||||
/* translators: %d: pages. */
|
||||
esc_html_x( 'Alert %1$d of %2$d', 'e.g. Alert 1 of 2', 'visual-regression-tests' ),
|
||||
esc_html( $data['pagination']['current'] ),
|
||||
esc_html( $data['pagination']['total'] )
|
||||
);
|
||||
}
|
||||
?>
|
||||
</span>
|
||||
<a data-vrts-pagination="prev" data-vrts-alert-id="<?php echo esc_attr( $data['pagination']['prev_alert_id'] ); ?>" class="button <?php echo ( 0 === $data['pagination']['prev_alert_id'] ) ? 'button-disabled' : ''; ?>"
|
||||
<?php echo ( 0 !== $data['pagination']['prev_alert_id'] ) ? 'href="' . esc_url( Url_Helpers::get_alert_page( $data['pagination']['prev_alert_id'], $data['run']->id ) ) . '"' : ''; ?>>
|
||||
<span class="screen-reader-text"><?php esc_html_e( 'Previous alert', 'visual-regression-tests' ); ?></span>
|
||||
<span aria-hidden="true">‹</span>
|
||||
</a>
|
||||
<a data-vrts-pagination="next" data-vrts-alert-id="<?php echo esc_attr( $data['pagination']['next_alert_id'] ); ?>" class="button <?php echo ( 0 === $data['pagination']['next_alert_id'] ) ? 'button-disabled' : ''; ?>"
|
||||
<?php echo ( 0 !== $data['pagination']['next_alert_id'] ) ? 'href="' . esc_url( Url_Helpers::get_alert_page( $data['pagination']['next_alert_id'], $data['run']->id ) ) . '"' : ''; ?>>
|
||||
<span class="screen-reader-text"><?php esc_html_e( 'Next alert', 'visual-regression-tests' ); ?></span>
|
||||
<span aria-hidden="true">›</span>
|
||||
</a>
|
||||
</vrts-test-run-pagination>
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
class VrtsTestRunPagination extends window.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.resolveElements();
|
||||
this.bindFunctions();
|
||||
this.bindEvents();
|
||||
}
|
||||
|
||||
resolveElements() {
|
||||
this.$alerts = document.querySelectorAll( '[data-vrts-alert]' );
|
||||
this.$buttons = this.querySelectorAll( '.button' );
|
||||
}
|
||||
|
||||
bindFunctions() {
|
||||
this.handleClick = this.handleClick.bind( this );
|
||||
this.handleKeyDown = this.handleKeyDown.bind( this );
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.$buttons?.forEach( ( item ) => {
|
||||
item.addEventListener( 'click', this.handleClick );
|
||||
} );
|
||||
|
||||
document.addEventListener( 'keydown', this.handleKeyDown );
|
||||
}
|
||||
|
||||
handleClick( e ) {
|
||||
e.preventDefault();
|
||||
const $el = e.currentTarget;
|
||||
const nextAlertId = $el.getAttribute( 'data-vrts-alert-id' );
|
||||
let $nextAlert = document.getElementById(
|
||||
`vrts-alert-${ nextAlertId }`
|
||||
);
|
||||
|
||||
if ( ! $nextAlert ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const href = $el.getAttribute( 'href' );
|
||||
const $content =
|
||||
document.querySelector( 'vrts-comparisons' ) ||
|
||||
document.querySelector( 'vrts-test-run-success' );
|
||||
const $sidebar = document.querySelector(
|
||||
'.vrts-test-run-page__sidebar'
|
||||
);
|
||||
|
||||
this.$alerts.forEach( ( item ) => {
|
||||
item.setAttribute( 'data-vrts-current', 'false' );
|
||||
} );
|
||||
|
||||
$nextAlert.setAttribute( 'data-vrts-current', 'true' );
|
||||
|
||||
let loadingElapsedTime = 0;
|
||||
let interval = null;
|
||||
|
||||
const timeout = setTimeout( () => {
|
||||
$content.setAttribute( 'data-vrts-loading', 'true' );
|
||||
const loadingStartTime = window.Date.now();
|
||||
interval = setInterval( () => {
|
||||
loadingElapsedTime = window.Date.now() - loadingStartTime;
|
||||
}, 50 );
|
||||
}, 200 );
|
||||
|
||||
let offsetTop = 0;
|
||||
|
||||
while ( $nextAlert && $nextAlert !== $sidebar ) {
|
||||
offsetTop += $nextAlert.offsetTop;
|
||||
$nextAlert = $nextAlert.offsetParent;
|
||||
}
|
||||
|
||||
$sidebar.scrollTo( {
|
||||
top: offsetTop - 82,
|
||||
behavior: 'smooth',
|
||||
} );
|
||||
|
||||
fetch( href )
|
||||
.then( ( response ) => {
|
||||
return response.text();
|
||||
} )
|
||||
.then( ( data ) => {
|
||||
const parser = new window.DOMParser();
|
||||
const $html = parser.parseFromString( data, 'text/html' );
|
||||
|
||||
const $newContent =
|
||||
$html.querySelector( 'vrts-comparisons' ) ||
|
||||
$html.querySelector( 'vrts-test-run-success' );
|
||||
const $newPagination = $html.querySelector(
|
||||
'vrts-test-run-pagination'
|
||||
);
|
||||
|
||||
window.history.replaceState( {}, '', href );
|
||||
|
||||
this.scrollTo( $content.offsetTop - 62 );
|
||||
|
||||
const loadingTimeoutTime =
|
||||
loadingElapsedTime > 0
|
||||
? Math.abs( loadingElapsedTime - 400 )
|
||||
: 0;
|
||||
|
||||
setTimeout( () => {
|
||||
if ( $newContent ) {
|
||||
$content.replaceWith( $newContent );
|
||||
}
|
||||
|
||||
if ( $newPagination ) {
|
||||
this.replaceWith( $newPagination );
|
||||
}
|
||||
}, loadingTimeoutTime );
|
||||
|
||||
clearTimeout( timeout );
|
||||
clearInterval( interval );
|
||||
} );
|
||||
}
|
||||
|
||||
handleKeyDown( e ) {
|
||||
if ( e.key === 'ArrowUp' ) {
|
||||
e.preventDefault();
|
||||
this.querySelector( '[data-vrts-pagination="prev"]' ).click();
|
||||
}
|
||||
|
||||
if ( e.key === 'ArrowDown' ) {
|
||||
e.preventDefault();
|
||||
this.querySelector( '[data-vrts-pagination="next"]' ).click();
|
||||
}
|
||||
}
|
||||
|
||||
scrollTo( offset ) {
|
||||
const $el =
|
||||
document.fullscreenElement ||
|
||||
document.webkitFullscreenElement ||
|
||||
document.msFullscreenElement ||
|
||||
window;
|
||||
|
||||
$el.scrollTo( {
|
||||
top: offset,
|
||||
behavior: 'smooth',
|
||||
} );
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.$buttons?.forEach( ( item ) => {
|
||||
item.removeEventListener( 'click', this.handleClick );
|
||||
} );
|
||||
|
||||
document.removeEventListener( 'keydown', this.handleKeyDown );
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define(
|
||||
'vrts-test-run-pagination',
|
||||
VrtsTestRunPagination
|
||||
);
|
||||
@@ -0,0 +1,205 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
|
||||
.vrts-test-run-receipt {
|
||||
position: relative;
|
||||
padding: 0 12px;
|
||||
margin: 30px auto 30px auto;
|
||||
background-color: #f6f7fb;
|
||||
box-shadow: 0 0 6px 2px rgba(0, 0, 0, 0.07);
|
||||
max-width: 280px;
|
||||
transition: box-shadow 0.2s;
|
||||
|
||||
@media (min-width: 851px) {
|
||||
max-width: 100%;
|
||||
margin: 8px 20px 20px;
|
||||
}
|
||||
|
||||
&:has(.vrts-test-run-receipt__link:hover),
|
||||
&:has(.vrts-test-run-receipt__link:focus-visible) {
|
||||
box-shadow: 0 0 6px 2px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
--vrts-test-run-receipt-mask: radial-gradient(10px at top, #0000 97%, #000) 50% / 18.5px 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 100%;
|
||||
content: "";
|
||||
mask: var(--vrts-test-run-receipt-mask);
|
||||
display: block;
|
||||
height: 10px;
|
||||
background: inherit;
|
||||
}
|
||||
|
||||
&::after {
|
||||
--vrts-test-run-receipt-mask: radial-gradient(10px at bottom, #0000 97%, #000) 50% / 18.5px 100%;
|
||||
bottom: -10px;
|
||||
}
|
||||
|
||||
> * {
|
||||
padding: 12px 0;
|
||||
|
||||
&:where(:not(:last-child)) {
|
||||
border-bottom: 1px dashed #c3c4c7;
|
||||
}
|
||||
}
|
||||
|
||||
> svg {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
&__link {
|
||||
display: block;
|
||||
border: none;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
|
||||
&:focus {
|
||||
outline: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding-top: 20px;
|
||||
|
||||
&-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
justify-content: center;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
|
||||
svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
||||
path {
|
||||
fill: #2c3338;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-info {
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
gap: 2px;
|
||||
|
||||
a {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__info {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
column-gap: 10px;
|
||||
justify-content: center;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
&__pages-status,
|
||||
&__total {
|
||||
line-height: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
|
||||
&-heading,
|
||||
&-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
&-heading {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
&-row {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
a {
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
display: -webkit-box;
|
||||
color: inherit;
|
||||
max-block-size: 16px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-decoration: none;
|
||||
white-space: initial;
|
||||
word-break: break-all;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__total {
|
||||
border-top: 1px dashed #c3c4c7;
|
||||
margin-top: 2px;
|
||||
|
||||
&-heading {
|
||||
font-size: 14px;
|
||||
|
||||
> :first-child {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
|
||||
&-row {
|
||||
font-size: 12px;
|
||||
|
||||
&--success {
|
||||
color: #4ab866;
|
||||
}
|
||||
|
||||
&--failed {
|
||||
color: #b32d2e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__trigger {
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
|
||||
.vrts-test-run-trigger {
|
||||
font-size: inherit;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
&-notes {
|
||||
color: #757575;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Core\Utilities\Date_Time_Helpers;
|
||||
use Vrts\Core\Utilities\Url_Helpers;
|
||||
use Vrts\Models\Test_Run;
|
||||
|
||||
$trigger_note = Test_Run::get_trigger_note( $data['run'] );
|
||||
|
||||
?>
|
||||
|
||||
<div class="vrts-test-run-receipt">
|
||||
<?php if ( $data['alerts'] ) : ?>
|
||||
<a id="vrts-alert-receipt" class="vrts-test-run-receipt__link" data-vrts-alert="receipt" href="<?php echo esc_url( Url_Helpers::get_alert_page( 'receipt', $data['run']->id ) ); ?>"></a>
|
||||
<?php endif; ?>
|
||||
<div class="vrts-test-run-receipt__header">
|
||||
<div class="vrts-test-run-receipt__header-logo">
|
||||
<?php vrts()->logo(); ?>
|
||||
<?php esc_html_e( 'VRTs Plugin', 'visual-regression-tests' ); ?>
|
||||
</div>
|
||||
<div class="vrts-test-run-receipt__header-info">
|
||||
<?php esc_html_e( 'Test Receipt', 'visual-regression-tests' ); ?>
|
||||
<a href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php echo esc_html( home_url( '/' ) ); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vrts-test-run-receipt__info">
|
||||
<?php
|
||||
// translators: %s: the run number.
|
||||
printf( esc_html__( 'Run #%s', 'visual-regression-tests' ), esc_html( $data['run']->id ) );
|
||||
?>
|
||||
<?php echo wp_kses( Date_Time_Helpers::get_formatted_relative_date_time( $data['run']->finished_at ), [ 'time' => [ 'datetime' => true ] ] ); ?>
|
||||
</div>
|
||||
<div class="vrts-test-run-receipt__pages-status">
|
||||
<div class="vrts-test-run-receipt__pages-status-heading">
|
||||
<span><?php esc_html_e( 'Page', 'visual-regression-tests' ); ?></span>
|
||||
<span><?php esc_html_e( 'Difference', 'visual-regression-tests' ); ?></span>
|
||||
</div>
|
||||
<?php
|
||||
foreach ( $data['tests'] as $test ) :
|
||||
$alert = array_values( array_filter( $data['alerts'], static function ( $alert ) use ( $test ) {
|
||||
return $alert->post_id === $test['post_id'];
|
||||
} ) );
|
||||
$difference = $alert ? ceil( $alert[0]->differences ) : 0;
|
||||
?>
|
||||
<div class="vrts-test-run-receipt__pages-status-row">
|
||||
<?php if ( $test['permalink'] ) : ?>
|
||||
<a href="<?php echo esc_url( $test['permalink'] ); ?>"><?php echo esc_html( Url_Helpers::make_relative( $test['permalink'] ) ); ?></a>
|
||||
<?php else : ?>
|
||||
N/A
|
||||
<?php endif; ?>
|
||||
<span>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s. Test run receipt diff in pixels */
|
||||
esc_html_x( '%spx', 'test run receipt difference', 'visual-regression-tests' ),
|
||||
esc_html( number_format_i18n( $difference ) )
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<div class="vrts-test-run-receipt__total">
|
||||
<div class="vrts-test-run-receipt__total-heading">
|
||||
<span><?php esc_html_e( 'Total', 'visual-regression-tests' ); ?></span>
|
||||
<span>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s. Number of tests */
|
||||
esc_html( _n( '%s Test', '%s Tests', count( $data['tests'] ), 'visual-regression-tests' ) ), count( $data['tests'] )
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
<div class="vrts-test-run-receipt__total-row vrts-test-run-receipt__total-row--success">
|
||||
<span><?php esc_html_e( 'Passed', 'visual-regression-tests' ); ?></span>
|
||||
<span>
|
||||
<?php
|
||||
$passed_tests_count = count( $data['tests'] ) - count( $data['alerts'] );
|
||||
printf(
|
||||
/* translators: %s. Number of tests */
|
||||
esc_html( _n( '%s Test', '%s Tests', $passed_tests_count, 'visual-regression-tests' ) ), esc_html( $passed_tests_count )
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
<div class="vrts-test-run-receipt__total-row vrts-test-run-receipt__total-row--failed">
|
||||
<span><?php esc_html_e( 'Changes detected', 'visual-regression-tests' ); ?></span>
|
||||
<span>
|
||||
<?php
|
||||
$changed_detected_count = count( $data['alerts'] );
|
||||
printf(
|
||||
/* translators: %s. Number of tests */
|
||||
esc_html( _n( '%s Test', '%s Tests', $changed_detected_count, 'visual-regression-tests' ) ), esc_html( $changed_detected_count )
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="vrts-test-run-receipt__trigger">
|
||||
<?php esc_html_e( 'Trigger', 'visual-regression-tests' ); ?>
|
||||
<span class="vrts-test-run-trigger vrts-test-run-trigger--<?php echo esc_attr( $data['run']->trigger ); ?>">
|
||||
<?php echo esc_html( Test_Run::get_trigger_title( $data['run'] ) ); ?>
|
||||
</span>
|
||||
<?php if ( ! empty( $trigger_note ) ) : ?>
|
||||
<span class="vrts-test-run-receipt__trigger-notes" title="<?php echo esc_attr( $trigger_note ); ?>">
|
||||
<?php echo esc_html( $trigger_note ); ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="vrts-test-run-receipt__footer">
|
||||
<?php esc_html_e( 'Test Completed!', 'visual-regression-tests' ); ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,60 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
|
||||
.vrts-test-run-success {
|
||||
display: block;
|
||||
padding: max(50px, 8%) 20px;
|
||||
border-top: 0;
|
||||
overflow: hidden;
|
||||
|
||||
&__inner {
|
||||
margin-bottom: 1.5rem;
|
||||
max-width: 600px;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
&__lottie-player {
|
||||
position: relative;
|
||||
pointer-events: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
aspect-ratio: 10 / 8;
|
||||
margin-top: calc(100% / (10 / 8) * 0.3 * -1);
|
||||
|
||||
svg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
text-align: center;
|
||||
margin-top: calc(100% / (10 / 8) * 0.3 * -1);
|
||||
|
||||
> p {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 2rem auto 0 auto;
|
||||
max-width: 350px;
|
||||
text-wrap: balance;
|
||||
|
||||
p,
|
||||
cite {
|
||||
color: $gray-50;
|
||||
margin: 5px;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
cite {
|
||||
color: $gray-700;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
$quotes = [
|
||||
[
|
||||
'quote' => __( 'Change is inevitable – except from a vending machine.', 'visual-regression-tests' ),
|
||||
'author' => 'Robert C. Gallagher',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'It’s not what happens to you, but how you react to it that matters.', 'visual-regression-tests' ),
|
||||
'author' => 'Epictetus',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Every success story is a tale of constant adaptation, revision, and change.', 'visual-regression-tests' ),
|
||||
'author' => 'Richard Branson',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Change is hard at first, messy in the middle and gorgeous at the end.', 'visual-regression-tests' ),
|
||||
'author' => 'Robin Sharma',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Without deviation from the norm, progress is not possible.', 'visual-regression-tests' ),
|
||||
'author' => 'Frank Zappa',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Perfection is not attainable, but if we chase perfection we can catch excellence.', 'visual-regression-tests' ),
|
||||
'author' => 'Vince Lombardi',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'It’s the little details that are vital. Little things make big things happen.', 'visual-regression-tests' ),
|
||||
'author' => 'John Wooden',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'It is not the strongest of the species that survive, nor the most intelligent. It is the one that is most adaptable to change.', 'visual-regression-tests' ),
|
||||
'author' => 'Charles Darwin',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Attention to detail is not about perfection. It’s about excellence, about constant improvement.', 'visual-regression-tests' ),
|
||||
'author' => 'Chris Denny',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'The difference between something good and something great is attention to detail.', 'visual-regression-tests' ),
|
||||
'author' => 'Charles R Swindoll',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Details make perfection, and perfection is not a detail.', 'visual-regression-tests' ),
|
||||
'author' => 'Leonardo da Vinci',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Not everything that is faced can be changed, but nothing can be changed until it is faced.', 'visual-regression-tests' ),
|
||||
'author' => 'James Baldwin',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Small deeds done are better than great deeds planned.', 'visual-regression-tests' ),
|
||||
'author' => 'Peter Marshall',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Great things are not done by impulse, but by a series of small things brought together.', 'visual-regression-tests' ),
|
||||
'author' => 'Vincent Van Gogh',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Success is the sum of small efforts, repeated day in and day out.', 'visual-regression-tests' ),
|
||||
'author' => 'Robert Collier',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'To improve is to change; to be perfect is to change often.', 'visual-regression-tests' ),
|
||||
'author' => 'Winston Churchill',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'The details are not the details. They make the design.', 'visual-regression-tests' ),
|
||||
'author' => 'Charles Eames',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'God is in the details.', 'visual-regression-tests' ),
|
||||
'author' => 'Ludwig Mies van der Rohe',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Excellence is the gradual result of always striving to do better.', 'visual-regression-tests' ),
|
||||
'author' => 'Pat Riley',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'The world is changed by your example, not by your opinion.', 'visual-regression-tests' ),
|
||||
'author' => 'Paulo Coelho',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Doing the little things can make a big difference.', 'visual-regression-tests' ),
|
||||
'author' => 'Yogi Berra',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Tiny tweaks can lead to big changes.', 'visual-regression-tests' ),
|
||||
'author' => 'Amy Cuddy',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Life is a series of natural and spontaneous changes. Don’t resist them—that only creates sorrow. Let reality be reality.', 'visual-regression-tests' ),
|
||||
'author' => 'Lao Tzu',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'A bend in the road is not the end of the road… unless you fail to make the turn.', 'visual-regression-tests' ),
|
||||
'author' => 'Helen Keller',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'The only way to make sense out of change is to plunge into it, move with it, and join the dance.', 'visual-regression-tests' ),
|
||||
'author' => 'Alan Watts',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Change is the only constant in life.', 'visual-regression-tests' ),
|
||||
'author' => 'Heraclitus',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'The art of life lies in a constant readjustment to our surroundings.', 'visual-regression-tests' ),
|
||||
'author' => 'Okakura Kakuzō',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Adaptability is about the powerful difference between adapting to cope and adapting to win.', 'visual-regression-tests' ),
|
||||
'author' => 'Max McKeown',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'The pessimist complains about the wind; the optimist expects it to change; the realist adjusts the sails.', 'visual-regression-tests' ),
|
||||
'author' => 'William Arthur Ward',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'The world hates change, yet it is the only thing that has brought progress.', 'visual-regression-tests' ),
|
||||
'author' => 'Charles Kettering',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Change is inevitable. Change is constant.', 'visual-regression-tests' ),
|
||||
'author' => 'Benjamin Disraeli',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'You must welcome change as the rule but not as your ruler.', 'visual-regression-tests' ),
|
||||
'author' => 'Denis Waitley',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Change is the process by which the future invades our lives.', 'visual-regression-tests' ),
|
||||
'author' => 'Alvin Toffler',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Don’t fear failure. Fear being in the exact same place next year as you are today.', 'visual-regression-tests' ),
|
||||
'author' => 'Michael Hyatt',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Sometimes good things fall apart so better things can fall together.', 'visual-regression-tests' ),
|
||||
'author' => 'Marilyn Monroe',
|
||||
],
|
||||
[
|
||||
'quote' => __( 'Change starts when someone sees the next step.', 'visual-regression-tests' ),
|
||||
'author' => 'William Drayton',
|
||||
],
|
||||
];
|
||||
|
||||
mt_srand( $data['run']->id ); // phpcs:ignore WordPress.WP.AlternativeFunctions.rand_seeding_mt_srand -- It's ok.
|
||||
$random_quote = $quotes[ array_rand( $quotes ) ];
|
||||
|
||||
?>
|
||||
|
||||
<vrts-test-run-success class="vrts-test-run-success postbox">
|
||||
<div class="vrts-test-run-success__inner">
|
||||
<div class="vrts-test-run-success__lottie-player" vrts-lottie-player></div>
|
||||
<div class="vrts-test-run-success__content">
|
||||
<?php if ( $data['is_receipt'] ) : ?>
|
||||
<p><?php esc_html_e( 'Nice work – no more Alerts left to review!', 'visual-regression-tests' ); ?></p>
|
||||
<blockquote>
|
||||
<p>"<?php echo esc_html( $random_quote['quote'] ); ?>"</p>
|
||||
<cite>— <?php echo esc_html( $random_quote['author'] ); ?></cite>
|
||||
</blockquote>
|
||||
<?php else : ?>
|
||||
<p><?php esc_html_e( 'Smooth sailing – no changes found!', 'visual-regression-tests' ); ?></p>
|
||||
<p><?php esc_html_e( "You're good to go.", 'visual-regression-tests' ); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<span class="vrts-gradient-loader"></span>
|
||||
</vrts-test-run-success>
|
||||
@@ -0,0 +1,32 @@
|
||||
import lottie from 'lottie-web/build/player/lottie_light';
|
||||
|
||||
class VrtsTestRunSuccess extends window.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.resolveElements();
|
||||
}
|
||||
|
||||
resolveElements() {
|
||||
this.$lottiePlayer = this.querySelector( '[vrts-lottie-player]' );
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.lottieAnimation = lottie.loadAnimation( {
|
||||
path: `${ window.vrts_admin_vars.pluginUrl }/assets/animations/success-check.json`,
|
||||
container: this.$lottiePlayer,
|
||||
renderer: 'svg',
|
||||
loop: false,
|
||||
autoplay: true,
|
||||
} );
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.lottieAnimation.destroy();
|
||||
}
|
||||
|
||||
loaAnimation() {
|
||||
this.$lottiePlayer.play();
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define( 'vrts-test-run-success', VrtsTestRunSuccess );
|
||||
@@ -0,0 +1,183 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
@import "@wordpress/base-styles/breakpoints";
|
||||
|
||||
.vrts-test-runs-page {
|
||||
display: block;
|
||||
|
||||
.tablenav.top {
|
||||
clear: none;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-test-runs-list-table {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.check-column {
|
||||
text-align: center;
|
||||
padding: 10px 0 0 10px !important;
|
||||
width: 28px;
|
||||
}
|
||||
|
||||
.column-status {
|
||||
|
||||
@media screen and (max-width: 782px) {
|
||||
padding-bottom: 8px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-runs-status {
|
||||
|
||||
&--passed {
|
||||
color: $alert-green;
|
||||
}
|
||||
|
||||
&--scheduled {
|
||||
color: #f97b06;
|
||||
}
|
||||
|
||||
&--has-alerts {
|
||||
color: $alert-red;
|
||||
}
|
||||
|
||||
&--running {
|
||||
animation: vrts-rotate 1.5s linear infinite;
|
||||
color: $blue-50;
|
||||
}
|
||||
}
|
||||
|
||||
.row-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3125rem;
|
||||
color: $blue-50;
|
||||
line-height: 1;
|
||||
padding: 3px 0;
|
||||
|
||||
&:where(a)::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -38px;
|
||||
width: 100vw;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
[data-vrts-test-run-status="running"] .row-title {
|
||||
color: #f97b06;
|
||||
}
|
||||
|
||||
[data-vrts-test-run-status="scheduled"] .row-title {
|
||||
color: $gray-70;
|
||||
}
|
||||
|
||||
.row-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
visibility: hidden;
|
||||
|
||||
> *:not(:first-child)::before {
|
||||
content: " | ";
|
||||
}
|
||||
}
|
||||
|
||||
tr {
|
||||
|
||||
&[data-has-alerts] {
|
||||
|
||||
.row-title,
|
||||
.vrts-test-run-trigger,
|
||||
.vrts-testing-status-wrapper > *:first-child {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.row-title::after {
|
||||
content: "";
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: var(--vrts-admin-theme-color);
|
||||
border-radius: 50%;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.test-run-highlighted {
|
||||
animation: vrts-color-highlight 2s ease;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
.row-actions {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-test-run-view-alerts {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-test-runs-list-queue-table {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
thead,
|
||||
tfoot {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.subsubsub:has(+ &) {
|
||||
float: none;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
// .vrts-test-run-details {
|
||||
// display: none;
|
||||
|
||||
// [data-vrts-test-run-details="visible"] & {
|
||||
// display: block;
|
||||
// }
|
||||
|
||||
// .vrts-test-run-details-section {
|
||||
// margin: 15px 0;
|
||||
|
||||
// &:first-child {
|
||||
// margin-top: 25px;
|
||||
// }
|
||||
|
||||
// &-title {
|
||||
// border-bottom: 1px solid $gray-5;
|
||||
// color: $alert-red;
|
||||
// display: flex;
|
||||
// flex-wrap: wrap;
|
||||
// font-weight: 600;
|
||||
// gap: 10px;
|
||||
// justify-content: space-between;
|
||||
// margin-bottom: 10px;
|
||||
// padding-bottom: 10px;
|
||||
// }
|
||||
|
||||
// &--passed {
|
||||
|
||||
// .vrts-test-run-details-section-title {
|
||||
// color: $alert-green;
|
||||
// }
|
||||
// }
|
||||
|
||||
// ul {
|
||||
// margin: 0;
|
||||
// margin-left: 1rem;
|
||||
// list-style: outside;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .button {
|
||||
// margin-bottom: 4px;
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Features\Admin_Notices;
|
||||
use Vrts\Services\Manual_Test_Service;
|
||||
|
||||
?>
|
||||
<vrts-test-runs-page class="wrap vrts-list-table-page vrts-test-runs-page">
|
||||
<h1 class="wp-heading-inline">
|
||||
<?php esc_html_e( 'Runs', 'visual-regression-tests' ); ?>
|
||||
</h1>
|
||||
|
||||
<hr class="wp-header-end">
|
||||
|
||||
<?php
|
||||
$list_table = $data['list_queue_table'];
|
||||
$list_table->prepare_items();
|
||||
$list_table->views();
|
||||
$list_table->display();
|
||||
?>
|
||||
|
||||
<form method="post">
|
||||
<?php
|
||||
$list_table = $data['list_table'];
|
||||
$list_table->prepare_items();
|
||||
$list_table->views();
|
||||
$list_table->display();
|
||||
|
||||
if ( $list_table->has_items() ) {
|
||||
$list_table->inline_edit();
|
||||
}
|
||||
?>
|
||||
</form>
|
||||
<?php
|
||||
$vrts_manual_test_service = new Manual_Test_Service();
|
||||
$test_status = $vrts_manual_test_service->get_option();
|
||||
if ( $test_status ) {
|
||||
$vrts_manual_test_service->delete_option();
|
||||
if ( '1' === $test_status ) {
|
||||
Admin_Notices::render_notification( 'test_started', false, [] );
|
||||
} elseif ( '2' === $test_status ) {
|
||||
Admin_Notices::render_notification( 'test_failed', false, [] );
|
||||
}
|
||||
}
|
||||
?>
|
||||
</vrts-test-runs-page>
|
||||
@@ -0,0 +1,53 @@
|
||||
class VrtsTestRunsPage extends window.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.resolveElements();
|
||||
}
|
||||
|
||||
resolveElements() {
|
||||
this.$runsListTable = this.querySelector(
|
||||
'form .vrts-test-runs-list-table'
|
||||
);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.highlightNewTestRuns();
|
||||
}
|
||||
|
||||
highlightNewTestRuns() {
|
||||
const testRunIds = new Set(
|
||||
JSON.parse(
|
||||
window.localStorage.getItem( 'vrtsNewTestRuns' ) || '[]'
|
||||
)
|
||||
);
|
||||
|
||||
const rows = this.$runsListTable.querySelectorAll(
|
||||
'tr[data-test-run-id]'
|
||||
);
|
||||
|
||||
let staggerTimeout = 0;
|
||||
|
||||
rows.forEach( ( row ) => {
|
||||
const testRunId = row.getAttribute( 'data-test-run-id' );
|
||||
|
||||
if ( row.getAttribute( 'data-test-run-new' ) === 'true' ) {
|
||||
if ( ! testRunIds.has( testRunId ) ) {
|
||||
testRunIds.add( testRunId );
|
||||
setTimeout( () => {
|
||||
row.classList.add( 'test-run-highlighted' );
|
||||
}, staggerTimeout );
|
||||
staggerTimeout += 200;
|
||||
}
|
||||
} else if ( testRunIds.has( testRunId ) ) {
|
||||
testRunIds.delete( testRunId );
|
||||
}
|
||||
} );
|
||||
|
||||
window.localStorage.setItem(
|
||||
'vrtsNewTestRuns',
|
||||
JSON.stringify( [ ...testRunIds ] )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define( 'vrts-test-runs-page', VrtsTestRunsPage );
|
||||
@@ -0,0 +1,93 @@
|
||||
@import "@wordpress/base-styles/colors.native"; // stylelint-disable-line scss/at-import-partial-extension
|
||||
@import "@wordpress/base-styles/breakpoints";
|
||||
|
||||
.page-title-actions {
|
||||
list-style: none;
|
||||
display: inline-flex;
|
||||
padding: 0 0 4px;
|
||||
margin: 0;
|
||||
gap: 1ch;
|
||||
|
||||
li {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.vrts-page-title-action {
|
||||
position: relative;
|
||||
top: -3px;
|
||||
min-height: 32px;
|
||||
line-height: 2.30769231;
|
||||
padding: 0 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts_tests_page_wp_link {
|
||||
|
||||
@media (max-width: $break-mobile) {
|
||||
margin-top: -250px !important;
|
||||
max-height: 80vh;
|
||||
}
|
||||
|
||||
.link-url-field,
|
||||
.link-search-field {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.link-search-wrapper {
|
||||
position: relative;
|
||||
|
||||
.spinner {
|
||||
position: absolute;
|
||||
right: 40px;
|
||||
top: 4px;
|
||||
margin: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-tests--active {
|
||||
pointer-events: none;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
#link-options {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#wplink-link-existing-content {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
#wp-link .query-results {
|
||||
top: 80px;
|
||||
max-height: calc(100% - 90px);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.item {
|
||||
|
||||
&-permalink {
|
||||
font-size: 0.66rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vrts-list-table-page {
|
||||
|
||||
.quick-edit-row-test {
|
||||
|
||||
label {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.inline-edit-col {
|
||||
max-width: 485px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
switch ( $data['action'] ) {
|
||||
default:
|
||||
$template = __DIR__ . '/views/tests-page-list.php';
|
||||
break;
|
||||
}
|
||||
|
||||
if ( file_exists( $template ) ) {
|
||||
include $template;
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
/* global jQuery, ajaxurl, inlineEditTest */
|
||||
|
||||
document
|
||||
.getElementById( 'show-modal-add-new' )
|
||||
?.addEventListener( 'click', () => {
|
||||
window.wpLink.open( 'input_hidden_internal_url' );
|
||||
} );
|
||||
|
||||
window.wp = window.wp || {};
|
||||
( function ( $, wp ) {
|
||||
window.inlineEditTest = {
|
||||
/**
|
||||
* Initializes the inline and bulk post editor.
|
||||
*
|
||||
* Binds event handlers to the Escape key to close the inline editor
|
||||
* and to the save and close buttons. Changes DOM to be ready for inline
|
||||
* editing. Adds event handler to bulk edit.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditTest
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
init() {
|
||||
const t = this,
|
||||
qeRow = $( '#inline-edit' );
|
||||
|
||||
t.type = 'test';
|
||||
// Test ID prefix.
|
||||
t.what = '#test-';
|
||||
|
||||
/**
|
||||
* Binds the Escape key to revert the changes and close the quick editor.
|
||||
*
|
||||
* @return {boolean} The result of revert.
|
||||
*/
|
||||
qeRow.on( 'keyup', function ( e ) {
|
||||
// Revert changes if Escape key is pressed.
|
||||
if ( e.which === 27 ) {
|
||||
return inlineEditTest.revert();
|
||||
}
|
||||
} );
|
||||
|
||||
/**
|
||||
* Reverts changes and close the quick editor if the cancel button is clicked.
|
||||
*
|
||||
* @return {boolean} The result of revert.
|
||||
*/
|
||||
$( '.cancel', qeRow ).on( 'click', function () {
|
||||
return inlineEditTest.revert();
|
||||
} );
|
||||
|
||||
/**
|
||||
* Saves changes in the quick editor if the save(named: update) button is clicked.
|
||||
*
|
||||
* @return {boolean} The result of save.
|
||||
*/
|
||||
$( '.save', qeRow ).on( 'click', function () {
|
||||
return inlineEditTest.save( this );
|
||||
} );
|
||||
|
||||
/**
|
||||
* If Enter is pressed, and the target is not the cancel button, save the post.
|
||||
*
|
||||
* @return {boolean} The result of save.
|
||||
*/
|
||||
$( 'td', qeRow ).on( 'keydown', function ( e ) {
|
||||
if (
|
||||
e.which === 13 &&
|
||||
! e.shiftKey &&
|
||||
! $( e.target ).hasClass( 'cancel' )
|
||||
) {
|
||||
return inlineEditTest.save( this );
|
||||
}
|
||||
} );
|
||||
|
||||
/**
|
||||
* Binds click event to the .editinline button which opens the quick editor.
|
||||
*/
|
||||
$( '#the-list' ).on( 'click', '.editinline', function () {
|
||||
$( this ).attr( 'aria-expanded', 'true' );
|
||||
inlineEditTest.edit( this );
|
||||
} );
|
||||
|
||||
/**
|
||||
* Adds onclick events to the apply buttons.
|
||||
*/
|
||||
$( '#doaction' ).on( 'click', function ( e ) {
|
||||
t.whichBulkButtonId = $( this ).attr( 'id' );
|
||||
const n = t.whichBulkButtonId.substr( 2 );
|
||||
|
||||
if ( 'edit' === $( 'select[name="' + n + '"]' ).val() ) {
|
||||
e.preventDefault();
|
||||
} else if (
|
||||
$( 'form#posts-filter tr.inline-editor' ).length > 0
|
||||
) {
|
||||
t.revert();
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles the quick edit window, hiding it when it's active and showing it when
|
||||
* inactive.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditTest
|
||||
*
|
||||
* @param {Object} el Element within a post table row.
|
||||
*/
|
||||
toggle( el ) {
|
||||
const t = this;
|
||||
// eslint-disable-next-line
|
||||
$( t.what + t.getId( el ) ).css( 'display' ) === 'none'
|
||||
? t.revert()
|
||||
: t.edit( el );
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a quick edit window for the post that has been clicked.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditTest
|
||||
*
|
||||
* @param {number|Object} id The ID of the clicked post or an element within a post
|
||||
* table row.
|
||||
* @return {boolean} Always returns false at the end of execution.
|
||||
*/
|
||||
edit( id ) {
|
||||
const t = this;
|
||||
t.revert();
|
||||
|
||||
if ( typeof id === 'object' ) {
|
||||
id = t.getId( id );
|
||||
}
|
||||
|
||||
// Add the new edit row with an extra blank row underneath to maintain zebra striping.
|
||||
const editRow = $( '#inline-edit' ).clone( true );
|
||||
$( 'td', editRow ).attr(
|
||||
'colspan',
|
||||
$( 'th:visible, td:visible', '.widefat:first thead' ).length
|
||||
);
|
||||
|
||||
// Remove the ID from the copied row and let the `for` attribute reference the hidden ID.
|
||||
$( 'td', editRow ).find( '#quick-edit-legend' ).removeAttr( 'id' );
|
||||
$( 'td', editRow )
|
||||
.find( 'p[id^="quick-edit-"]' )
|
||||
.removeAttr( 'id' );
|
||||
|
||||
$( t.what + id )
|
||||
.removeClass( 'is-expanded' )
|
||||
.hide()
|
||||
.after( editRow )
|
||||
.after( '<tr class="hidden"></tr>' );
|
||||
|
||||
// Populate fields in the quick edit window.
|
||||
const rowData = $( '#inline_' + id );
|
||||
const hideInputSelectorsText = $(
|
||||
'.hide_css_selectors',
|
||||
rowData
|
||||
).text();
|
||||
$( ':input[name="hide_css_selectors"]', editRow ).val(
|
||||
hideInputSelectorsText
|
||||
);
|
||||
|
||||
$( editRow )
|
||||
.attr( 'id', 'edit-' + id )
|
||||
.addClass( 'inline-editor' )
|
||||
.show();
|
||||
$( ':input[name="hide_css_selectors"]', editRow ).trigger(
|
||||
'focus'
|
||||
);
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Saves the changes made in the quick edit window to the post.
|
||||
* Ajax saving is only for Quick Edit and not for bulk edit.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @param {number} id The ID for the post that has been changed.
|
||||
* @return {boolean} False, so the form does not submit when pressing
|
||||
* Enter on a focused field.
|
||||
*/
|
||||
save( id ) {
|
||||
if ( typeof id === 'object' ) {
|
||||
id = this.getId( id );
|
||||
}
|
||||
|
||||
$( 'table.widefat .spinner' ).addClass( 'is-active' );
|
||||
|
||||
const params = {
|
||||
action: 'vrts_test_quick_edit_save',
|
||||
test_id: id,
|
||||
hide_css_selectors: $(
|
||||
'#edit-' + id + ' [name="hide_css_selectors"]'
|
||||
).val(),
|
||||
nonce: $( '#_vrts_test_quick_edit_nonce' ).val(),
|
||||
};
|
||||
|
||||
// Make Ajax request
|
||||
$.post(
|
||||
ajaxurl,
|
||||
params,
|
||||
function ( response ) {
|
||||
$( 'table.widefat .spinner' ).removeClass( 'is-active' );
|
||||
|
||||
// Work with the response.
|
||||
response = $.parseJSON( response );
|
||||
|
||||
if ( ! response.success ) {
|
||||
const $errorNotice = $(
|
||||
'#edit-' + id + ' .inline-edit-save .notice-error'
|
||||
);
|
||||
$errorNotice.removeClass( 'hidden' );
|
||||
$errorNotice.text( response.message );
|
||||
wp.a11y.speak( response.message );
|
||||
return;
|
||||
}
|
||||
|
||||
$( '#inline_' + id + ' .hide_css_selectors' ).text(
|
||||
response.hide_css_selectors
|
||||
);
|
||||
|
||||
// Hide the quick edit window.
|
||||
const $tableWideFat = $( '.widefat' );
|
||||
id = $( '.inline-editor', $tableWideFat ).attr( 'id' );
|
||||
|
||||
if ( id ) {
|
||||
$( '.spinner', $tableWideFat ).removeClass(
|
||||
'is-active'
|
||||
);
|
||||
|
||||
// Remove both the inline-editor and its hidden tr siblings.
|
||||
$( '#' + id )
|
||||
.siblings( 'tr.hidden' )
|
||||
.addBack()
|
||||
.remove();
|
||||
id = id.substr( id.lastIndexOf( '-' ) + 1 );
|
||||
|
||||
// Show the post row and move focus back to the Quick Edit button.
|
||||
$( '#test-' + id )
|
||||
.fadeIn( 400 )
|
||||
.find( '.editinline' )
|
||||
.attr( 'aria-expanded', 'false' )
|
||||
.trigger( 'focus' );
|
||||
}
|
||||
|
||||
wp.a11y.speak( response.message );
|
||||
|
||||
// Update the snapshot column in the table and set the status of the snapshot.
|
||||
const snapshotStatus = response.snapshot_status;
|
||||
const $snapshotColumn = $(
|
||||
'#test-' + id + ' .base_screenshot_date'
|
||||
);
|
||||
if (
|
||||
null !== snapshotStatus &&
|
||||
undefined !== snapshotStatus &&
|
||||
'' !== snapshotStatus
|
||||
) {
|
||||
$snapshotColumn.text( snapshotStatus );
|
||||
}
|
||||
},
|
||||
'html'
|
||||
);
|
||||
|
||||
// Prevent submitting the form when pressing Enter on a focused field.
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Hides and empties the Quick Edit and/or Bulk Edit windows.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditTest
|
||||
*
|
||||
* @return {boolean} Always returns false.
|
||||
*/
|
||||
revert() {
|
||||
const $tableWideFat = $( '.widefat' );
|
||||
let id = $( '.inline-editor', $tableWideFat ).attr( 'id' );
|
||||
|
||||
if ( id ) {
|
||||
$( '.spinner', $tableWideFat ).removeClass( 'is-active' );
|
||||
|
||||
// Remove both the inline-editor and its hidden tr siblings.
|
||||
$( '#' + id )
|
||||
.siblings( 'tr.hidden' )
|
||||
.addBack()
|
||||
.remove();
|
||||
id = id.substr( id.lastIndexOf( '-' ) + 1 );
|
||||
|
||||
// Show the post row and move focus back to the Quick Edit button.
|
||||
$( this.what + id )
|
||||
.show()
|
||||
.find( '.editinline' )
|
||||
.attr( 'aria-expanded', 'false' )
|
||||
.trigger( 'focus' );
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the ID for a the post that you want to quick edit from the row in the quick
|
||||
* edit table.
|
||||
*
|
||||
* @since 2.7.0
|
||||
*
|
||||
* @memberof inlineEditTest
|
||||
*
|
||||
* @param {Object} o DOM row object to get the ID for.
|
||||
* @return {string} The post ID extracted from the table row in the object.
|
||||
*/
|
||||
getId( o ) {
|
||||
const id = $( o ).closest( 'tr' ).attr( 'id' ),
|
||||
parts = id.split( '-' );
|
||||
return parts[ parts.length - 1 ];
|
||||
},
|
||||
};
|
||||
|
||||
$( function () {
|
||||
if ( $( '.vrts-list-table-page' ).length ) {
|
||||
inlineEditTest.init();
|
||||
}
|
||||
} );
|
||||
} )( jQuery, window.wp );
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
use Vrts\Features\Admin_Notices;
|
||||
use Vrts\Features\Subscription;
|
||||
use Vrts\Services\Manual_Test_Service;
|
||||
|
||||
?>
|
||||
|
||||
<div class="wrap vrts-list-table-page">
|
||||
<h1 class="wp-heading-inline">
|
||||
<?php esc_html_e( 'Tests', 'visual-regression-tests' ); ?>
|
||||
</h1>
|
||||
|
||||
<menu class="page-title-actions">
|
||||
<li>
|
||||
<button type="button" class="vrts-page-title-action button-primary"
|
||||
id="<?php echo ( ! $data['is_connected'] || intval( $data['remaining_tests'] ) === 0 ) ? 'modal-add-new-disabled' : 'show-modal-add-new'; ?>"
|
||||
<?php echo ( ! $data['is_connected'] || intval( $data['remaining_tests'] ) === 0 ) ? ' disabled' : ''; ?>>
|
||||
<?php esc_html_e( 'Add New', 'visual-regression-tests' ); ?>
|
||||
</button>
|
||||
</li>
|
||||
<?php if ( Subscription::get_subscription_status() ) : ?>
|
||||
<li>
|
||||
<form method="post" id="form-run-manual-tests">
|
||||
<?php wp_nonce_field( 'submit_run_manual_tests', '_wpnonce' ); ?>
|
||||
<input type="submit" name="submit_run_manual_tests" value="<?php esc_attr_e( 'Run All Tests', 'visual-regression-tests' ); ?>"
|
||||
class="vrts-page-title-action button-secondary"
|
||||
id="<?php echo ( ! $data['is_connected'] || ! $data['running_tests_count'] ) ? 'run-manual-tests-disabled' : 'run-manual-tests'; ?>"
|
||||
<?php echo ( ! $data['is_connected'] || ! $data['running_tests_count'] ) ? ' disabled' : ''; ?>
|
||||
>
|
||||
</form>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</menu>
|
||||
|
||||
<?php if ( isset( $data['search_query'] ) && '' !== $data['search_query'] ) { ?>
|
||||
<span class="subtitle">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: search query. */
|
||||
esc_html__( 'Search results for: %s', 'visual-regression-tests' ),
|
||||
'<strong>' . esc_html( $data['search_query'] ) . '</strong>'
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
<?php } ?>
|
||||
|
||||
<hr class="wp-header-end">
|
||||
|
||||
<form method="post">
|
||||
<input type="hidden" name="page" value="vrts-tests_list_table">
|
||||
|
||||
<?php
|
||||
$list_table = $data['list_table'];
|
||||
$list_table->prepare_items();
|
||||
$list_table->views();
|
||||
$list_table->search_box( esc_attr__( 'Search', 'visual-regression-tests' ), 'search_id' );
|
||||
$list_table->display();
|
||||
|
||||
if ( $list_table->has_items() ) {
|
||||
$list_table->inline_edit();
|
||||
}
|
||||
|
||||
$vrts_manual_test_service = new Manual_Test_Service();
|
||||
$test_status = $vrts_manual_test_service->get_option();
|
||||
if ( $test_status ) {
|
||||
$vrts_manual_test_service->delete_option();
|
||||
if ( '1' === $test_status ) {
|
||||
Admin_Notices::render_notification( 'test_started', false, [] );
|
||||
} elseif ( '2' === $test_status ) {
|
||||
Admin_Notices::render_notification( 'test_failed', false, [] );
|
||||
}
|
||||
}
|
||||
?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="wp-link-backdrop" style="display: none"></div>
|
||||
<div id="wp-link-wrap" class="wp-core-ui vrts_tests_page_wp_link" style="display: none" role="dialog" aria-labelledby="link-modal-title">
|
||||
<form id="wp-link" tabindex="-1" method="post">
|
||||
<?php wp_nonce_field( 'internal-linking', '_ajax_linking_nonce', false ); ?>
|
||||
<?php wp_nonce_field( 'vrts_page_tests_nonce' ); ?>
|
||||
<h1 id="link-modal-title"><?php esc_html_e( 'Add New Test', 'visual-regression-tests' ); ?></h1>
|
||||
<button type="button" id="wp-link-close"><span class="screen-reader-text"><?php esc_html_e( 'Close', 'visual-regression-tests' ); ?></span></button>
|
||||
<div id="link-selector">
|
||||
<div id="link-options">
|
||||
<p class="howto" id="wplink-enter-url"><?php esc_html_e( 'Destination URL', 'visual-regression-tests' ); ?></p>
|
||||
<div>
|
||||
<input id="wp-link-url" class="link-url-field" type="text" aria-describedby="wplink-enter-url" name="internal_url" readonly />
|
||||
<input id="wp-link-id" type="hidden" name="post_id" />
|
||||
</div>
|
||||
</div>
|
||||
<p class="howto" id="wplink-link-existing-content"><?php esc_html_e( 'Search', 'visual-regression-tests' ); ?></p>
|
||||
<div id="search-panel">
|
||||
<div class="link-search-wrapper">
|
||||
<input type="search" id="wp-link-search" class="link-search-field" autocomplete="off" aria-describedby="wplink-link-existing-content" />
|
||||
<span class="spinner"></span>
|
||||
</div>
|
||||
<div id="search-results" class="query-results" tabindex="0">
|
||||
<ul></ul>
|
||||
<div class="river-waiting">
|
||||
<span class="spinner"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="most-recent-results" class="query-results" tabindex="0">
|
||||
<div class="query-notice" id="query-notice-message">
|
||||
<em class="query-notice-default"><?php esc_html_e( 'No search term specified. Showing recent items.', 'visual-regression-tests' ); ?></em>
|
||||
<em class="query-notice-hint screen-reader-text"><?php esc_html_e( 'Search or use up and down arrow keys to select an item.', 'visual-regression-tests' ); ?></em>
|
||||
</div>
|
||||
<ul></ul>
|
||||
<div class="river-waiting">
|
||||
<span class="spinner"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="submitbox">
|
||||
<div id="wp-link-cancel">
|
||||
<button type="button" class="button"><?php esc_html_e( 'Cancel', 'visual-regression-tests' ); ?></button>
|
||||
</div>
|
||||
<div id="wp-link-update">
|
||||
<?php
|
||||
submit_button(
|
||||
__( 'Add New Test', 'visual-regression-tests' ),
|
||||
'button button-primary',
|
||||
'submit_add_new_test',
|
||||
false,
|
||||
[ 'id' => 'wp-link-submit' ]
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,6 @@
|
||||
.vrts_upgrade_page {
|
||||
|
||||
iframe {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<div class="wrap vrts_upgrade_page">
|
||||
<iframe
|
||||
src="https://vrts.app/pricing-embedded/?current-tier=<?php echo rawurlencode( esc_attr( $data['tier_id'] ) ); ?>"
|
||||
title="<?php echo esc_html( $data['title'] ); ?>"
|
||||
loading="lazy"
|
||||
width="100%"
|
||||
id="vrts_upgrade_iframe">
|
||||
</iframe>
|
||||
</div>
|
||||