Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions lib/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ const da = {
'Statistics': 'Statistik',
'About': 'Om',
'Search apps': 'Søg efter apps',
'Search apps placeholder': 'Søg efter apps',
'Footer navigation': 'Sidefodsnavigation',
'TrackerControl project': 'TrackerControl-projektet',
'Contact': 'Kontakt',
Expand Down Expand Up @@ -77,7 +76,6 @@ const da = {
'reports may be out of date, incomplete or incorrect. They describe an analysed app version on the date shown, and automated analysis makes mistakes. ': 'rapporter kan være forældede, ufuldstændige eller forkerte. De beskriver en analyseret appversion på den viste dato, og automatiske analyser kan tage fejl. ',
'Read the full disclaimer': 'Læs hele ansvarsfraskrivelsen',

'Search apps heading': 'Søg efter apps',
'Search results': 'Søgeresultater',
'Search': 'Søg',
'No apps found for “{{term}}”.': 'Ingen apps fundet for “{{term}}”.',
Expand All @@ -89,8 +87,6 @@ const da = {
'No matching free app was returned by the UK App Store search. Check the spelling or try a shorter name.': 'Søgningen i den britiske App Store gav ingen matchende gratis app. Kontrollér stavningen, eller prøv et kortere navn.',
'Free apps without a published report open a confirmation page first. A request is queued only after confirmation.': 'Gratis apps uden en udgivet rapport åbner først en bekræftelsesside. En anmodning kommer kun i kø efter bekræftelse.',
'Search again': 'Søg igen',
'Search app': 'Søg efter app',
'Search apps title': 'Søg efter apps',

'App report': 'App-rapport',
'Untitled app': 'Unavngiven app',
Expand Down Expand Up @@ -260,6 +256,7 @@ const da = {
'{{count}} entries': '{{count}} poster',
'Tracker directory table': 'Trackerkatalogtabel',
'Company directory table': 'Virksomhedskatalogtabel',
'Scroll sideways to see all columns.': 'Rul sidelæns for at se alle kolonner.',
'Rank': 'Rang',
'Tracker': 'Tracker',
'Company': 'Virksomhed',
Expand Down
25 changes: 19 additions & 6 deletions public/css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ button { cursor: pointer; }
padding-bottom: 1rem;
}

.platform-header { border-bottom: 1px solid var(--border); }
.platform-header { background: var(--warm); border-bottom: 1px solid var(--border); }
.platform-nav { display: flex; flex-wrap: wrap; gap: .6rem 1.4rem; padding-top: .65rem; padding-bottom: .65rem; font-size: .78rem; }
.platform-nav a { color: var(--muted); text-decoration: none; }
.platform-nav a:hover { color: var(--brand); text-decoration: underline; }
Expand Down Expand Up @@ -155,7 +155,7 @@ h3 { font-size: 1.35rem; line-height: 1.2; margin-bottom: 1rem; }
text-transform: uppercase;
}

.hero { padding: 5rem 0 5.4rem; }
.hero { padding: 3rem 0 5.4rem; }
.hero h1 { max-width: 760px; }
.hero-intro { color: #4b3d3d; font-size: clamp(1.08rem, 2vw, 1.3rem); line-height: 1.45; margin-bottom: 3.3rem; max-width: 540px; }

Expand Down Expand Up @@ -217,6 +217,7 @@ input::placeholder { color: #796d6d; }
.metrics .section-note { grid-column: 1 / -1; margin-top: .4rem; }

.home-section, .stats-section, .about-section, .lookup-apps, .lookup-trackers { border-top: 1px solid var(--border); padding: 3.4rem 0 0; margin-top: 3.4rem; }
.metrics + .home-section { border-top: 0; margin-top: 0; }
.section-heading { margin-bottom: 1.7rem; }
.section-heading .eyebrow { margin-bottom: .55rem; }
.section-heading h2 { margin-bottom: 0; }
Expand All @@ -225,6 +226,8 @@ input::placeholder { color: #796d6d; }

.bar-list { display: grid; gap: 1rem; }
.bar-item { min-width: 0; }
.bar-item--tiny { position: relative; }
.bar-item--tiny::after { background: var(--brand); bottom: 0; content: ''; height: 8px; left: 0; pointer-events: none; position: absolute; width: 2px; }
.bar-label { align-items: baseline; display: flex; font-size: .84rem; gap: 1rem; justify-content: space-between; margin-bottom: .3rem; }
.bar-label span, .bar-label strong { overflow-wrap: anywhere; }
.bar-label strong { font-weight: 750; text-align: right; }
Expand Down Expand Up @@ -280,6 +283,7 @@ progress.bar-track::-moz-progress-bar { background: var(--brand); }
.directory-controls input { min-width: 0; }
.directory-controls .result-count { align-self: center; }
.result-count { color: var(--muted); flex: 0 1 auto; font-size: .8rem; }
.table-scroll-hint { display: none; }
.table-scroll { border: 1px solid var(--border); margin-top: 1.3rem; max-width: 100%; overflow-x: auto; }
.table-scroll:focus { outline: 3px solid #b71c1c; outline-offset: 3px; }
.data-table { border-collapse: collapse; min-width: 660px; width: 100%; }
Expand Down Expand Up @@ -378,8 +382,9 @@ progress.bar-track::-moz-progress-bar { background: var(--brand); }

@media (max-width: 1050px) {
.site-header { align-items: flex-start; }
.site-nav { order: 3; width: 100%; }
.nav-search { flex: 1 1 230px; margin-left: auto; }
.language-toggle { order: 1; }
.site-nav { order: 2; width: 100%; }
.nav-search { flex: 1 1 100%; order: 3; }
.search-form { grid-template-columns: 1fr; }
.metadata { grid-template-columns: repeat(2, 1fr); }
.report-summary { grid-template-columns: repeat(3, 1fr); }
Expand All @@ -391,9 +396,9 @@ progress.bar-track::-moz-progress-bar { background: var(--brand); }
.site-header { gap: .8rem 1rem; padding-bottom: 1.2rem; padding-top: 1.2rem; }
.nav-search { flex-basis: 100%; margin-left: 0; }
.nav-search input { min-height: 44px; }
.site-nav { gap: .5rem .9rem; }
.site-nav { display: grid; gap: .5rem .9rem; grid-template-columns: repeat(3, max-content); justify-content: space-between; }
.site-nav a, .site-footer nav a { align-items: center; display: inline-flex; min-height: 44px; }
.hero { padding: 3.5rem 0 4.2rem; }
.hero { padding: 2rem 0 4.2rem; }
h1 { font-size: clamp(2.45rem, 13vw, 3.5rem); }
.hero-intro { margin-bottom: 2.5rem; }
.search-form__controls { align-items: stretch; flex-direction: column; }
Expand All @@ -409,6 +414,7 @@ progress.bar-track::-moz-progress-bar { background: var(--brand); }
.directory-controls, .tracker-controls { align-items: stretch; grid-template-columns: 1fr; }
.directory-controls .result-count { align-self: start; }
.table-scroll { margin-left: 0; width: 100%; }
.table-scroll-hint { color: var(--muted); display: block; font-size: .8rem; margin: 1rem 0 -.7rem; }
.report-page { padding-top: 1.4rem; }
.report-header { gap: 1rem; grid-template-columns: 64px minmax(0, 1fr); padding: 2.2rem 0; }
.app-icon--large { border-radius: 12px; font-size: 2rem; height: 64px; width: 64px; }
Expand All @@ -429,3 +435,10 @@ progress.bar-track::-moz-progress-bar { background: var(--brand); }
.site-footer__inner { align-items: flex-start; flex-direction: column; gap: .8rem; min-height: 140px; padding-bottom: 1.4rem; padding-top: 1.4rem; }
.request-details { grid-template-columns: 110px minmax(0, 1fr); }
}

@media (max-width: 360px) {
.site-header { column-gap: .5rem; }
.site-header .wordmark { font-size: .95rem; }
.site-header .wordmark small { display: none; }
.site-header .wordmark__icon { height: 32px; width: 32px; }
}
6 changes: 3 additions & 3 deletions routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -456,22 +456,22 @@ router.get('/search',
}));

res.render('form', {
title: res.locals.t('Search app'),
title: res.locals.t('Search results'),
errors: errors.array(),
data: req.query,
searchResults
});
} catch (err) {
console.log(err);
res.status(502).render('form', {
title: res.locals.t('Search apps title'),
title: res.locals.t('Search apps'),
data: req.query,
errors: [{ msg: res.locals.t('Error while searching. Try again later.') }],
});
}
} else {
res.render('form', {
title: res.locals.t('Search app'),
title: res.locals.t('Search apps'),
errors: errors.array(),
data: req.query,
});
Expand Down
8 changes: 8 additions & 0 deletions test/websiteViews.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,17 @@ test('search, directory, lookup, statistics, about, request and error states ren
const emptySearch = render('form.pug', { currentPath: '/search', data: { search: 'nothing' }, searchResults: [] });
assertSingleH1(emptySearch, 'empty search');
assert.match(emptySearch, /id="nav-search"/);
assert.match(emptySearch, /placeholder="Search apps"/);
assert.match(emptySearch, /No apps found for/);
assert.match(emptySearch, /No matching free app/);

const failedSearch = render('form.pug', {
currentPath: '/search',
errors: [{ msg: 'Please enter a search term' }]
});
assert.match(failedSearch, /<h1 id="search-title">Search apps<\/h1>/);
assert.doesNotMatch(failedSearch, /Search apps (heading|placeholder|title)/);

const search = render('form.pug', {
data: { search: 'example' },
searchResults: [
Expand Down
1 change: 1 addition & 0 deletions views/about.pug
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ block content
p.eyebrow= translate('Company footprint')
h2#jurisdiction-title= translate('Who controls the tracking')
p= translate('Each tracker is traced to the company that runs it, up to the parent company at the top, and then to that company’s home country. What counts is whose laws a company answers to, not where its servers are: a US company can be compelled to hand data over under the CLOUD Act wherever that data is stored. Every app gets one label:')
p.table-scroll-hint= translate('Scroll sideways to see all columns.')
.table-scroll(role='region' tabindex='0' aria-label=translate('Jurisdiction classifications'))
table.data-table
caption= translate('Jurisdiction classifications')
Expand Down
1 change: 1 addition & 0 deletions views/directory.pug
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ block content
input#directory-filter(type='search' placeholder=translate(isTracker ? 'Filter trackers or companies' : 'Filter companies') aria-controls='directory-table' data-filter-target='#directory-table' autocomplete='off')
p#directory-count.result-count(role='status' aria-live='polite')= translate(directoryEntries.length === 1 ? '{{count}} entry' : '{{count}} entries', { count: directoryEntries.length })

p.table-scroll-hint= translate('Scroll sideways to see all columns.')
.table-scroll(role='region' tabindex='0' aria-label=translate(isTracker ? 'Tracker directory table' : 'Company directory table'))
table#directory-table.data-table
caption= translate(isTracker ? 'Tracker directory' : 'Company directory')
Expand Down
4 changes: 2 additions & 2 deletions views/form.pug
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ block content
- const pct = statsData.classificationPcts && statsData.classificationPcts[cls]
- const meta = metaData[cls] || {}
if count !== undefined && count !== null
.bar-item
.bar-item(class=Number(count) > 0 && Number(pct) < .5 ? 'bar-item--tiny' : undefined)
.bar-label
span= meta.label ? translate(meta.label) : cls.replace(/_/g, ' ')
strong= translate('{{count}} apps ({{pct}}%)', { count, pct: pct === undefined ? '0' : pct })
Expand Down Expand Up @@ -92,7 +92,7 @@ block content
if hasErrors
section.search-state(aria-labelledby='search-title')
p.eyebrow= translate('Search')
h1#search-title= translate('Search apps heading')
h1#search-title= translate('Search apps')
.notice.notice--warning(role='alert')
ul.error-list
each error in errors
Expand Down
2 changes: 1 addition & 1 deletion views/layout.pug
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ html(lang=localeCode === 'da' ? 'da-DK' : 'en-GB')
if current !== '/'
form.nav-search(action=localize('/search') method='GET' role='search')
label.sr-only(for='nav-search')= translate('Search apps')
input#nav-search(type='search' name='search' value=searchData.search || '' placeholder=translate('Search apps placeholder') autocomplete='off')
input#nav-search(type='search' name='search' value=searchData.search || '' placeholder=translate('Search apps') autocomplete='off')
button.button.button--small(type='submit')= translate('Search')
nav.language-toggle(aria-label=translate('Language'))
a(href=languageHref('en') class=localeCode === 'en' ? 'is-current' : undefined aria-current=localeCode === 'en' ? 'true' : undefined)= translate('English')
Expand Down
6 changes: 5 additions & 1 deletion views/statistics.pug
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ block content
- const pct = stats.classificationPcts && stats.classificationPcts[cls]
- const meta = metadata[cls] || {}
if count !== undefined && count !== null
.bar-item
.bar-item(class=Number(count) > 0 && Number(pct) < .5 ? 'bar-item--tiny' : undefined)
.bar-label
span= meta.label ? translate(meta.label) : cls.replace(/_/g, ' ')
strong= translate('{{count}} apps ({{pct}}%)', { count, pct: pct === undefined ? '0' : pct })
Expand All @@ -42,6 +42,7 @@ block content
h2#stats-trackers-title= translate('Most prevalent trackers')
if trackers.length > 0
p.section-note= translate('Most frequently embedded third-party tracker libraries, with parent company and jurisdiction.')
p.table-scroll-hint= translate('Scroll sideways to see all columns.')
.table-scroll(role='region' tabindex='0' aria-label=translate('Most prevalent trackers'))
table.data-table
caption= translate('Most prevalent trackers')
Expand Down Expand Up @@ -81,6 +82,7 @@ block content
h2#stats-companies-title= translate('Most prevalent tracking companies')
if stats.topCompaniesSorted && stats.topCompaniesSorted.length > 0
p.section-note= translate('Unique companies by ultimate parent, ranked by the number of analysed apps in which they appear.')
p.table-scroll-hint= translate('Scroll sideways to see all columns.')
.table-scroll(role='region' tabindex='0' aria-label=translate('Most prevalent tracking companies'))
table.data-table
caption= translate('Most prevalent tracking companies')
Expand Down Expand Up @@ -112,6 +114,7 @@ block content
h2#stats-category-title= translate('Jurisdiction by App Store category')
if stats.categoriesSorted && stats.categoriesSorted.length > 0
p.section-note= translate('US-only and European-only tracking percentages by category. Categories with fewer than three apps are excluded from this comparison.')
p.table-scroll-hint= translate('Scroll sideways to see all columns.')
.table-scroll(role='region' tabindex='0' aria-label=translate('Jurisdiction by App Store category'))
table.data-table
caption= translate('Jurisdiction by App Store category')
Expand Down Expand Up @@ -143,6 +146,7 @@ block content
h2#stats-alternatives-title= translate('European alternatives')
if alternatives.length > 0
p.section-note= translate('For each core tracking function, the dominant US provider and whether a viable European alternative appears in the reference data.')
p.table-scroll-hint= translate('Scroll sideways to see all columns.')
.table-scroll(role='region' tabindex='0' aria-label=translate('European alternatives'))
table.data-table
caption= translate('European alternatives')
Expand Down
Loading