Skip to content

Commit bcf726e

Browse files
authored
NTP: UI Privacy Stats spacing and secondary expansion (#1270)
* chore: Update Privacy stats view * chore: Modify the showHide button * chore: FInalize button and spacing in card * fix: lint * fix: Making sure round buttons stay round * fix: Line height for empty subtitle * chore: Move rowmax to a const * chore: Markup cleanpu
1 parent 80c4a7b commit bcf726e

File tree

5 files changed

+117
-48
lines changed

5 files changed

+117
-48
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ export function ChevronButton() {
1515
);
1616
}
1717

18-
export function Chevron({ className }) {
18+
export function Chevron() {
1919
return (
20-
<svg fill="none" width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" class={className}>
20+
<svg fill="none" width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
2121
<path
2222
fill="currentColor"
2323
fill-rule="evenodd"

special-pages/pages/new-tab/app/components/ShowHide.module.css

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111
color: var(--ntp-text-normal);
1212
height: var(--ntp-gap);
1313
width: 100%;
14-
border-radius: var(--border-radius-md);
14+
border-radius: var(--border-radius-sm);
1515

1616
&.round {
17+
height: 2rem;
1718
width: 2rem;
1819
border-radius: 50%;
1920

@@ -22,6 +23,13 @@
2223
}
2324
}
2425

26+
&.withText {
27+
border: 1px solid var(--color-black-at-9);
28+
svg {
29+
margin-right: var(--sp-2);
30+
}
31+
}
32+
2533
svg {
2634
transition: transform .3s;
2735
}
@@ -34,4 +42,10 @@
3442
opacity: 1;
3543
box-shadow: var(--focus-ring-thin);
3644
}
37-
}
45+
46+
@media (prefers-color-scheme: dark) {
47+
&.withText {
48+
border-color: var(--color-white-at-9);
49+
}
50+
}
51+
}
Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,34 @@
11
import styles from './ShowHide.module.css';
22
import cn from 'classnames';
3-
import { ChevronButton } from './Icons.js';
4-
import { h } from 'preact';
3+
import { ChevronButton, Chevron } from './Icons.js';
4+
import { Fragment, h } from 'preact';
55

66
/**
77
* Function to handle showing or hiding content based on certain conditions.
88
*
99
* @param {Object} props - Input parameters for controlling the behavior of the ShowHide functionality.
1010
* @param {string} props.text
11+
* @param {boolean} [props.showText]
1112
* @param {() => void} props.onClick
1213
* @param {'none'|'round'} [props.shape]
1314
* @param {import("preact").ComponentProps<'button'>} [props.buttonAttrs]
1415
*/
15-
export function ShowHideButton({ text, onClick, buttonAttrs = {}, shape = 'none' }) {
16+
export function ShowHideButton({ text, onClick, buttonAttrs = {}, shape = 'none', showText = false }) {
1617
return (
17-
<button {...buttonAttrs} class={cn(styles.button, shape === 'round' && styles.round)} aria-label={text} onClick={onClick}>
18-
<ChevronButton />
18+
<button
19+
{...buttonAttrs}
20+
class={cn(styles.button, shape === 'round' && styles.round, !!showText && styles.withText)}
21+
aria-label={text}
22+
onClick={onClick}
23+
>
24+
{showText ? (
25+
<Fragment>
26+
<Chevron />
27+
{text}
28+
</Fragment>
29+
) : (
30+
<ChevronButton />
31+
)}
1932
</button>
2033
);
2134
}

special-pages/pages/new-tab/app/privacy-stats/components/PrivacyStats.js

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Fragment, h } from 'preact';
2+
import cn from 'classnames';
23
import styles from './PrivacyStats.module.css';
34
import { useTypedTranslationWith } from '../../types.js';
45
import { useContext, useState, useId, useCallback } from 'preact/hooks';
@@ -105,7 +106,7 @@ export function Heading({ expansion, trackerCompanies, onToggle, buttonAttrs = {
105106
{none && <p className={styles.title}>{t('stats_noRecent')}</p>}
106107
{some && <p className={styles.title}>{alltimeTitle}</p>}
107108
{recent > 0 && (
108-
<span className={styles.expander}>
109+
<span className={styles.widgetExpander}>
109110
<ShowHideButton
110111
buttonAttrs={{
111112
...buttonAttrs,
@@ -119,7 +120,7 @@ export function Heading({ expansion, trackerCompanies, onToggle, buttonAttrs = {
119120
</span>
120121
)}
121122
{recent === 0 && <p className={styles.subtitle}>{t('stats_noActivity')}</p>}
122-
{recent > 0 && <p className={styles.subtitle}>{t('stats_feedCountBlockedPeriod')}</p>}
123+
{recent > 0 && <p className={cn(styles.subtitle, styles.uppercase)}>{t('stats_feedCountBlockedPeriod')}</p>}
123124
</div>
124125
);
125126
}
@@ -133,11 +134,21 @@ export function Heading({ expansion, trackerCompanies, onToggle, buttonAttrs = {
133134
export function PrivacyStatsBody({ trackerCompanies, listAttrs = {} }) {
134135
const { t } = useTypedTranslationWith(/** @type {enStrings} */ ({}));
135136
const [formatter] = useState(() => new Intl.NumberFormat());
137+
const defaultRowMax = 5;
136138
const sorted = sortStatsForDisplay(trackerCompanies);
137139
const max = sorted[0]?.count ?? 0;
138-
const [visible, setVisible] = useState(5);
140+
const [visible, setVisible] = useState(defaultRowMax);
139141
const hasmore = sorted.length > visible;
140142

143+
const toggleListExpansion = () => {
144+
if (visible === defaultRowMax) {
145+
setVisible(sorted.length);
146+
}
147+
if (visible === sorted.length) {
148+
setVisible(defaultRowMax);
149+
}
150+
};
151+
141152
return (
142153
<Fragment>
143154
<ul {...listAttrs} class={styles.list} data-testid="CompanyList">
@@ -153,28 +164,37 @@ export function PrivacyStatsBody({ trackerCompanies, listAttrs = {} }) {
153164
if (company.displayName === DDG_STATS_OTHER_COMPANY_IDENTIFIER) {
154165
const otherText = t('stats_otherCount', { count: String(company.count) });
155166
return (
156-
<li key={company.displayName}>
157-
<div class={styles.textRow}>{otherText}</div>
167+
<li key={company.displayName} class={styles.otherTrackersRow}>
168+
{otherText}
158169
</li>
159170
);
160171
}
161172
return (
162-
<li key={company.displayName}>
163-
<div class={styles.row}>
164-
<div class={styles.company}>
165-
<CompanyIcon displayName={company.displayName} />
166-
<span class={styles.name}>{displayName}</span>
167-
</div>
168-
<span class={styles.count}>{countText}</span>
169-
<span class={styles.bar}></span>
170-
<span class={styles.fill} style={inlineStyles}></span>
173+
<li key={company.displayName} class={styles.row}>
174+
<div class={styles.company}>
175+
<CompanyIcon displayName={company.displayName} />
176+
<span class={styles.name}>{displayName}</span>
171177
</div>
178+
<span class={styles.count}>{countText}</span>
179+
<span class={styles.bar}></span>
180+
<span class={styles.fill} style={inlineStyles}></span>
172181
</li>
173182
);
174183
})}
175184
</ul>
176-
{hasmore && visible < sorted.length && <button onClick={() => setVisible(sorted.length)}>{t('ntp_show_more')}</button>}
177-
{visible > 5 && visible === sorted.length && <button onClick={() => setVisible(5)}>{t('ntp_show_less')}</button>}
185+
{sorted.length > defaultRowMax && (
186+
<div class={styles.listExpander}>
187+
<ShowHideButton
188+
onClick={toggleListExpansion}
189+
text={hasmore ? t('ntp_show_more') : t('ntp_show_less')}
190+
showText={true}
191+
buttonAttrs={{
192+
'aria-expanded': !hasmore,
193+
'aria-pressed': visible === sorted.length,
194+
}}
195+
/>
196+
</div>
197+
)}
178198
</Fragment>
179199
);
180200
}

special-pages/pages/new-tab/app/privacy-stats/components/PrivacyStats.module.css

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,15 @@
66
display: grid;
77
align-items: start;
88
grid-template-columns: auto;
9-
grid-row-gap: calc(18 * var(--px-in-rem));
109
width: 100%;
1110
margin-bottom: var(--ntp-gap);
1211

12+
&:hover {
13+
.listExpander * {
14+
opacity: 1;
15+
}
16+
}
17+
1318
@media screen and (prefers-color-scheme: dark) {
1419
border-color: var(--color-white-at-9);
1520
}
@@ -18,28 +23,26 @@
1823
.heading {
1924
display: grid;
2025
grid-template-columns: 1.5rem auto 2rem;
21-
gap: var(--sp-3);
26+
grid-column-gap: var(--sp-2);
27+
grid-row-gap: var(--sp-1);
2228
grid-template-rows: auto;
2329
grid-template-areas: 'icon title expander';
2430
}
2531
.heading:has(.subtitle) {
2632
grid-template-rows: auto auto;
2733
grid-template-areas:
28-
'icon title expander'
29-
'label label label';
34+
'icon title expander'
35+
'empty label label';
3036
}
3137
.headingIcon {
3238
grid-area: icon;
3339
width: 1.5rem;
34-
height: 1.5rem;
40+
height: var(--title-2-line-height);
3541
position: relative;
36-
37-
img {
38-
position: absolute;
39-
top: 50%;
40-
left: 50%;
41-
transform: translate(-50%, calc(-50% - 2px));
42-
}
42+
display: flex;
43+
align-items: center;
44+
justify-content: center;
45+
padding-top: 2px;
4346
}
4447

4548
.title {
@@ -49,7 +52,7 @@
4952
line-height: var(--title-2-line-height);
5053
}
5154

52-
.expander {
55+
.widgetExpander {
5356
position: relative;
5457

5558
& [aria-controls] {
@@ -63,14 +66,18 @@
6366
.subtitle {
6467
grid-area: label;
6568
color: var(--ntp-text-muted);
66-
padding-left: 2px;
69+
&.uppercase {
70+
line-height: 1;
71+
text-transform: uppercase;
72+
}
6773
}
6874

6975
.list {
7076
display: grid;
7177
grid-template-columns: auto;
7278
grid-row-gap: calc(6 * var(--px-in-rem));
7379
transition: opacity ease-in-out 0.3s, visibility ease-in-out 0.3s;
80+
margin-top: 18px;
7481
}
7582

7683
.entering {
@@ -120,17 +127,22 @@
120127
.row {
121128
min-height: 2rem;
122129
display: grid;
123-
grid-gap: 0.75rem;
130+
grid-gap: var(--sp-2);
124131
grid-template-columns: auto auto 40%;
125132
grid-template-areas: 'company count bar';
126133
align-items: center;
134+
127135
@media screen and (min-width: 500px) {
128136
grid-template-columns: auto auto 60%;
129137
}
130138
}
131-
.textRow {
132-
margin-top: 12px;
139+
140+
.otherTrackersRow {
141+
margin-top: var(--sp-3);
142+
padding-left: var(--sp-1);
143+
color: var(--ntp-text-muted);
133144
}
145+
134146
.company {
135147
grid-area: company;
136148
display: flex;
@@ -145,12 +157,14 @@
145157
height: 1rem;
146158
border-radius: 50%;
147159
flex-shrink: 0;
160+
148161
img, svg {
149162
display: block;
150163
font-size: 0;
151164
width: 1rem;
152165
height: 1rem;
153166
}
167+
154168
&:has([data-errored=true]) {
155169
outline: 1px solid var(--ntp-surface-border-color);
156170
@media screen and (prefers-color-scheme: dark) {
@@ -173,6 +187,13 @@
173187
line-height: 1;
174188
}
175189

190+
.count {
191+
grid-area: count;
192+
text-align: right;
193+
color: var(--ntp-text-normal);
194+
line-height: 1;
195+
}
196+
176197
.bar {
177198
grid-area: bar;
178199
width: 100%;
@@ -190,16 +211,17 @@
190211
grid-area: bar;
191212
height: 1rem;
192213
border-radius: calc(20 * var(--px-in-rem));
193-
194214
background: var(--color-black-at-6);
195215

196216
@media screen and (prefers-color-scheme: dark) {
197217
background: var(--color-white-at-9);
198218
}
199219
}
200220

201-
.count {
202-
grid-area: count;
203-
text-align: right;
204-
color: var(--ntp-text-normal);
205-
}
221+
.listExpander {
222+
margin-top: var(--sp-3);
223+
button {
224+
color: var(--ntp-text-muted);
225+
opacity: 1;
226+
}
227+
}

0 commit comments

Comments
 (0)