Skip to content

Commit 21b31fe

Browse files
authored
feat: Add confirmation to Mac Next Steps card (#1300)
* feat: Add confirmation to Mac Next Steps card * chore: Make the fix better * fix: Text wrap in nextsteps button. * chore: Update to use strings for confirm text * chore: ordered the imports * fix: remove pause from the test * chore: set max-width to confirmation p tage * fix: Confirmation text styling * chore: Fix local var to a data.js solution * fix: TS nest
1 parent dc52beb commit 21b31fe

File tree

6 files changed

+110
-9
lines changed

6 files changed

+110
-9
lines changed

special-pages/pages/new-tab/app/components/Icons.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,23 @@ export function Cross() {
8282
</svg>
8383
);
8484
}
85+
86+
export function CheckColor() {
87+
return (
88+
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
89+
<path fill="#4CBA3C" d="M15.5 8a7.5 7.5 0 1 1-15 0 7.5 7.5 0 0 1 15 0" />
90+
<path
91+
fill="#fff"
92+
fill-rule="evenodd"
93+
d="M11.844 5.137a.5.5 0 0 1 .019.707l-4.5 4.75a.5.5 0 0 1-.733-.008l-2.5-2.75a.5.5 0 0 1 .74-.672l2.138 2.351 4.129-4.359a.5.5 0 0 1 .707-.019"
94+
clip-rule="evenodd"
95+
/>
96+
<path
97+
fill="#288419"
98+
fill-rule="evenodd"
99+
d="M8 1a7 7 0 1 0 0 14A7 7 0 0 0 8 1M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8"
100+
clip-rule="evenodd"
101+
/>
102+
</svg>
103+
);
104+
}

special-pages/pages/new-tab/app/next-steps/components/NextSteps.module.css

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,18 @@
4747
font-size: calc(11 * var(--px-in-rem));
4848
line-height: calc(14 * var(--px-in-rem));
4949
color: var(--ntp-color-primary);
50+
text-wrap: wrap; /* needed for some languages */
51+
52+
/* the active state created an awkward flash, adding transition out */
53+
&.supressActiveStateForSwitchToConfirmationText {
54+
opacity: 1;
55+
transition: opacity .3s ease-out;
56+
57+
&:active {
58+
background-color: var(--color-black-at-6);
59+
opacity: 0;
60+
}
61+
}
5062

5163
&:hover {
5264
background-color: var(--color-black-at-6);
@@ -73,6 +85,12 @@
7385
}
7486

7587
@media screen and (prefers-color-scheme: dark) {
88+
&.supressActiveStateForSwitchToConfirmationText {
89+
&:active {
90+
background-color: var(--color-black-at-9);
91+
}
92+
}
93+
7694
&:hover:not(:active) {
7795
background-color: var(--color-black-at-9);
7896
}
@@ -89,6 +107,26 @@
89107
}
90108
}
91109

110+
.confirmation {
111+
display: flex;
112+
align-items: center;
113+
transition: all .2s ease-in;
114+
min-height: 26px;
115+
116+
svg {
117+
height: 1rem;
118+
width: 1rem;
119+
margin-right: var(--sp-2);
120+
}
121+
122+
p {
123+
font-size: calc(11 * var(--px-in-rem));
124+
line-height: calc(14 * var(--px-in-rem));
125+
font-weight: 600;
126+
max-width: 8rem;
127+
}
128+
}
129+
92130
.dismissBtn {
93131
position: absolute;
94132
top: 0.5rem;

special-pages/pages/new-tab/app/next-steps/components/NextStepsCard.js

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import { h } from 'preact';
2-
import styles from './NextSteps.module.css';
2+
import cn from 'classnames';
3+
4+
import { useState } from 'preact/hooks';
35
import { DismissButton } from '../../components/DismissButton';
4-
import { variants } from '../nextsteps.data';
6+
import { CheckColor } from '../../components/Icons';
57
import { useTypedTranslationWith } from '../../types';
8+
import { variants, additionalCardStates } from '../nextsteps.data';
9+
import styles from './NextSteps.module.css';
610

711
/**
812
* @param {object} props
@@ -14,14 +18,35 @@ import { useTypedTranslationWith } from '../../types';
1418
export function NextStepsCard({ type, dismiss, action }) {
1519
const { t } = useTypedTranslationWith(/** @type {import("../strings.json")} */ ({}));
1620
const message = variants[type]?.(t);
21+
const [showConfirmation, setShowConfirmation] = useState(false);
22+
const hasConfirmationState = additionalCardStates.hasConfirmationText(message.id);
23+
24+
const handleClick = () => {
25+
if (!hasConfirmationState) {
26+
return action(message.id);
27+
}
28+
29+
action(message.id);
30+
setShowConfirmation(true);
31+
};
1732
return (
1833
<div class={styles.card}>
1934
<img src={`./icons/${message.icon}-128.svg`} alt="" class={styles.icon} />
2035
<h3 class={styles.title}>{message.title}</h3>
2136
<p class={styles.description}>{message.summary}</p>
22-
<button class={styles.btn} onClick={() => action(message.id)}>
23-
{message.actionText}
24-
</button>
37+
{hasConfirmationState && !!showConfirmation ? (
38+
<div class={styles.confirmation}>
39+
<CheckColor />
40+
<p>{message.confirmationText}</p>
41+
</div>
42+
) : (
43+
<button
44+
class={cn(styles.btn, hasConfirmationState && styles.supressActiveStateForSwitchToConfirmationText)}
45+
onClick={handleClick}
46+
>
47+
{message.actionText}
48+
</button>
49+
)}
2550

2651
<DismissButton className={styles.dismissBtn} onClick={() => dismiss(message.id)} />
2752
</div>

special-pages/pages/new-tab/app/next-steps/components/NextStepsGroup.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { h } from 'preact';
22
import cn from 'classnames';
3-
import styles from './NextSteps.module.css';
3+
import { useId } from 'preact/hooks';
4+
import { ShowHideButton } from '../../components/ShowHideButton';
45
import { useTypedTranslationWith } from '../../types';
5-
import { NextStepsCard } from './NextStepsCard';
66
import { otherText } from '../nextsteps.data';
7-
import { ShowHideButton } from '../../components/ShowHideButton';
8-
import { useId } from 'preact/hooks';
7+
import styles from './NextSteps.module.css';
8+
import { NextStepsCard } from './NextStepsCard';
99

1010
/**
1111
* @import enStrings from '../strings.json';

special-pages/pages/new-tab/app/next-steps/integrations-tests/next-steps.spec.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,14 @@ test.describe('newtab NextSteps cards', () => {
5858
await page.getByRole('button', { name: 'Try DuckPlayer' }).click();
5959
await ntp.mocks.waitForCallCount({ method: 'nextSteps_action', count: 1 });
6060
});
61+
62+
test('shows a confirmation state', async ({ page }, workerInfo) => {
63+
const ntp = NewtabPage.create(page, workerInfo);
64+
await ntp.reducedMotion();
65+
await ntp.openPage({ nextSteps: ['addAppToDockMac', 'defaultApp'] });
66+
await page.getByRole('button', { name: 'Add to Dock' }).click();
67+
68+
await expect(page.getByText('Added to Dock!')).toBeVisible();
69+
await expect(page.getByRole('button', { name: 'Add to Dock' })).not.toBeVisible();
70+
});
6171
});

special-pages/pages/new-tab/app/next-steps/nextsteps.data.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export const variants = {
5050
title: t('nextSteps_addAppDockMac_title'),
5151
summary: t('nextSteps_addAppDockMac_summary'),
5252
actionText: t('nextSteps_addAppDockMac_actionText'),
53+
confirmationText: t('nextSteps_addAppDockMac_confirmationText'),
5354
}),
5455
/** @param {(translationId: keyof enStrings) => string} t */
5556
pinAppToTaskbarWindows: (t) => ({
@@ -69,3 +70,10 @@ export const otherText = {
6970
/** @param {(translationId: keyof enStrings) => string} t */
7071
nextSteps_sectionTitle: (t) => t('nextSteps_sectionTitle'),
7172
};
73+
74+
/** @type {string[]} cardsWithConfirmationText */
75+
const cardsWithConfirmationText = ['addAppToDockMac'];
76+
77+
export const additionalCardStates = {
78+
hasConfirmationText: (/** @type {keyof variants} */ variantId) => cardsWithConfirmationText.includes(variantId),
79+
};

0 commit comments

Comments
 (0)