Mostly accessibility stuff (#344)

This commit is contained in:
stairman06 2022-01-20 22:21:13 -06:00 committed by GitHub
parent 98c85441f8
commit 643cd87706
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 212 additions and 162 deletions

View File

@ -3,12 +3,16 @@
.iconified-input {
align-items: center;
display: inline-flex;
position: relative;
input {
padding-left: 2rem;
width: 100%;
}
svg {
position: absolute;
left: 0.6rem;
height: 1rem;
z-index: 1;
@ -35,7 +39,7 @@
border-radius: 2rem;
&:hover,
&:focus {
&:focus-visible {
background-color: var(--color-button-bg-hover);
}
@ -306,7 +310,7 @@
background-color: var(--color-button-bg);
font-weight: var(--font-weight-medium);
font-size: var(--font-size-nm);
&:focus,
&:focus-visible,
&:hover {
background-color: var(--color-button-bg-hover);
}
@ -326,7 +330,7 @@
color: var(--color-text);
background-color: transparent;
&:focus,
&:focus-visible,
&:hover,
&.selected,
&.nuxt-link-exact-active,
@ -349,7 +353,7 @@
@extend .button;
color: var(--color-brand-inverted);
background-color: var(--color-brand);
&:focus,
&:focus-visible,
&:hover {
background-color: var(--color-brand-hover);
color: var(--color-brand-inverted);
@ -364,7 +368,7 @@
box-shadow: inset 0px -1px 1px rgba(0, 0, 0, 0.25);
color: var(--color-brand-inverted);
background-color: var(--color-brand);
&:focus,
&:focus-visible,
&:hover {
background-color: var(--color-brand-hover);
color: var(--color-brand-inverted);

View File

@ -146,7 +146,7 @@ body {
--color-badge-red-bg: #db3162;
--color-badge-green-text: #1ebb7b;
--color-badge-green-bg: #24a54e;
--color-badge-yellow-text: #755920;
--color-badge-yellow-text: #dba22d;
--color-badge-yellow-bg: #f7bb43;
--color-block-quote: var(--color-code-bg);
@ -307,7 +307,7 @@ button {
border: none;
border-radius: var(--size-rounded-control);
&:focus,
&:focus-visible,
&:hover {
background-color: var(--color-button-bg-hover);
color: var(--color-button-text-hover);

View File

@ -79,6 +79,7 @@ export default {
onSmallScreen: false,
windowResizeListenerDebounce: null,
ethicalAdLoad: null,
ethicalAdTries: 0,
}
},
head: {
@ -165,14 +166,18 @@ export default {
},
refresh_ad() {
if (this.ethical_ads_on) {
this.ethicalAdTries++
clearTimeout(this.ethicalAdLoad)
this.ethicalAdLoad = setTimeout(() => {
if (typeof window.ethicalads === 'undefined') {
console.log('EthicalAds are not loaded yet, retrying...')
this.refresh_ad()
}
ethicalads.load()
}, 100)
if (this.ethicalAdTries <= 5) {
this.ethicalAdLoad = setTimeout(() => {
if (typeof window.ethicalads === 'undefined') {
console.log('EthicalAds are not loaded yet, retrying...')
this.refresh_ad()
}
ethicalads.load()
}, 100)
}
}
},
},

View File

@ -1,9 +1,22 @@
<template>
<div class="checkbox-outer" :class="{ disabled }" @click="toggle">
<button class="checkbox" :disabled="disabled" :class="{ checked: value }">
<CheckIcon v-if="value" />
<div
class="checkbox-outer"
:class="{ disabled }"
role="presentation"
@click="toggle"
>
<button
class="checkbox"
role="checkbox"
:disabled="disabled"
:class="{ checked: value }"
:aria-label="description"
:aria-checked="value"
>
<CheckIcon v-if="value" aria-hidden="true" />
</button>
<p v-if="label">{{ label }}</p>
<!-- aria-hidden is set so screenreaders only use the <button>'s aria-label -->
<p v-if="label" aria-hidden="true">{{ label }}</p>
<slot v-else />
</div>
</template>
@ -25,6 +38,10 @@ export default {
type: Boolean,
default: false,
},
description: {
type: String,
default: '',
},
value: Boolean,
clickEvent: {
type: Function,

View File

@ -1,5 +1,5 @@
<template>
<article class="project-card card">
<article class="project-card card" :aria-label="name" role="listitem">
<div class="columns">
<div class="icon">
<nuxt-link :to="`/${type}/${id}`">
@ -26,7 +26,7 @@
v-if="clientSide === 'optional' && serverSide === 'optional'"
class="side-descriptor"
>
<InfoIcon />
<InfoIcon aria-hidden="true" />
Universal {{ type }}
</div>
<div
@ -36,7 +36,7 @@
"
class="side-descriptor"
>
<InfoIcon />
<InfoIcon aria-hidden="true" />
Client {{ type }}
</div>
<div
@ -46,7 +46,7 @@
"
class="side-descriptor"
>
<InfoIcon />
<InfoIcon aria-hidden="true" />
Server {{ type }}
</div>
</div>
@ -56,18 +56,18 @@
<Categories :categories="categories" class="right-categories" />
<div class="dates">
<div class="date">
<CalendarIcon />
<CalendarIcon aria-hidden="true" />
Created {{ $dayjs(createdAt).fromNow() }}
</div>
<div class="date">
<EditIcon />
<EditIcon aria-hidden="true" />
Updated {{ $dayjs(updatedAt).fromNow() }}
</div>
</div>
</div>
<div class="right-side">
<div v-if="downloads" class="stat">
<DownloadIcon />
<DownloadIcon aria-hidden="true" />
<p>
<strong>{{ formatNumber(downloads) }}</strong> download<span
v-if="downloads !== '1'"
@ -76,7 +76,7 @@
</p>
</div>
<div v-if="follows" class="stat">
<HeartIcon />
<HeartIcon aria-hidden="true" />
<p>
<strong>{{ formatNumber(follows) }}</strong> follower<span
v-if="follows !== '1'"

View File

@ -2,12 +2,13 @@
<Checkbox
class="filter"
:value="activeFilters.includes(facetName)"
:description="displayName"
@input="toggle()"
>
<div class="filter-text">
<div v-if="icon" class="icon" v-html="icon"></div>
<div v-if="icon" aria-hidden="true" class="icon" v-html="icon"></div>
<div v-else class="icon"><slot /></div>
<span> {{ displayName }}</span>
<span aria-hidden="true"> {{ displayName }}</span>
</div>
</Checkbox>
</template>

View File

@ -1,14 +1,14 @@
<template>
<div class="layout">
<header class="site-header">
<section class="navbar columns">
<section class="logo column">
<NuxtLink to="/">
<ModrinthLogo aria-label="modrinth" class="text-logo" />
<header class="site-header" role="presentation">
<section class="navbar columns" role="navigation">
<section class="logo column" role="presentation">
<NuxtLink to="/" aria-label="Modrinth home page">
<ModrinthLogo aria-hidden="true" class="text-logo" />
</NuxtLink>
</section>
<section class="nav-group columns">
<section class="nav">
<section class="nav-group columns" role="presentation">
<section class="nav" aria-label="Page links">
<div class="styled-tabs">
<NuxtLink to="/mods" class="tab">
<span>Mods</span>
@ -18,25 +18,34 @@
</NuxtLink>
</div>
</section>
<section class="column-grow user-outer">
<section class="column-grow user-outer" aria-label="Account links">
<section class="user-controls">
<button class="control-button" @click="changeTheme">
<MoonIcon v-if="$colorMode.value === 'light'" />
<SunIcon v-else />
<button
class="control-button"
title="Switch theme"
@click="changeTheme"
>
<MoonIcon
v-if="$colorMode.value === 'light'"
aria-hidden="true"
/>
<SunIcon v-else aria-hidden="true" />
</button>
<nuxt-link
v-if="$auth.user"
to="/create/project"
class="control-button"
title="Create project"
>
<PlusIcon />
<PlusIcon aria-hidden="true" />
</nuxt-link>
<nuxt-link
v-if="$auth.user"
to="/notifications"
class="control-button"
title="Notifications"
>
<NotificationIcon />
<NotificationIcon aria-hidden="true" />
<div v-if="$user.notifications.length > 0" class="bubble">
{{ $user.notifications.length }}
</div>
@ -202,8 +211,8 @@
<Nuxt />
</main>
<footer>
<div class="logo-info">
<ModrinthLogo aria-label="modrinth" class="text-logo" />
<div class="logo-info" role="region" aria-label="Modrinth information">
<ModrinthLogo aria-hidden="true" class="text-logo" />
<p>
Modrinth is open source software. You may view the source code at
<a
@ -217,8 +226,8 @@
<p>modrinth/knossos {{ version }}</p>
<p>© Guavy LLC</p>
</div>
<div class="links">
<h4>Legal</h4>
<div class="links" role="region" aria-label="Legal">
<h4 aria-hidden="true">Legal</h4>
<nuxt-link to="/legal/terms">Terms</nuxt-link>
<nuxt-link to="/legal/privacy">Privacy</nuxt-link>
<nuxt-link to="/legal/rules">Rules</nuxt-link>
@ -229,23 +238,21 @@
License
</a>
</div>
<div class="links">
<h4>Resources</h4>
<div class="links" role="region" aria-label="Resources">
<h4 aria-hidden="true">Resources</h4>
<a target="_blank" href="https://blog.modrinth.com">Blog</a>
<a target="_blank" href="https://discord.gg/EUHuJHt">Discord</a>
<a target="_blank" href="https://github.com/modrinth/knossos">GitHub</a>
<a target="_blank" href="https://docs.modrinth.com">Docs</a>
</div>
<div class="buttons">
<nuxt-link to="/settings/privacy">
<button class="iconified-button">
<ShieldIcon />
Privacy settings
</button>
<nuxt-link to="/settings/privacy" class="iconified-button">
<ShieldIcon aria-hidden="true" />
Privacy settings
</nuxt-link>
<button class="iconified-button" @click="changeTheme">
<MoonIcon v-if="$colorMode.value === 'light'" />
<SunIcon v-else />
<MoonIcon v-if="$colorMode.value === 'light'" aria-hidden="true" />
<SunIcon v-else aria-hidden="true" />
Change theme
</button>
</div>
@ -886,7 +893,7 @@ html {
margin-right: auto;
&:hover,
&:focus {
&:focus-visible {
background-color: var(--color-button-bg-hover);
}
}

View File

@ -37,7 +37,7 @@
"
class="side-descriptor"
>
<InfoIcon />
<InfoIcon aria-hidden="true" />
Universal {{ project.project_type }}
</div>
<div
@ -49,7 +49,7 @@
"
class="side-descriptor"
>
<InfoIcon />
<InfoIcon aria-hidden="true" />
Client {{ project.project_type }}
</div>
<div
@ -61,7 +61,7 @@
"
class="side-descriptor"
>
<InfoIcon />
<InfoIcon aria-hidden="true" />
Server {{ project.project_type }}
</div>
<p class="description">
@ -81,14 +81,14 @@
</div>
<div class="dates">
<div class="date">
<CalendarIcon />
<CalendarIcon aria-hidden="true" />
<span class="label">Created</span>
<span class="value">{{
$dayjs(project.published).fromNow()
}}</span>
</div>
<div class="date">
<UpdateIcon />
<UpdateIcon aria-hidden="true" />
<span class="label">Updated</span>
<span class="value">{{ $dayjs(project.updated).fromNow() }}</span>
</div>
@ -100,7 +100,7 @@
:to="`/create/report?id=${project.id}&t=project`"
class="iconified-button"
>
<ReportIcon />
<ReportIcon aria-hidden="true" />
Report
</nuxt-link>
<button
@ -110,7 +110,7 @@
class="iconified-button"
@click="$store.dispatch('user/followProject', project)"
>
<FollowIcon />
<FollowIcon aria-hidden="true" />
Follow
</button>
<button
@ -120,7 +120,7 @@
class="iconified-button"
@click="$store.dispatch('user/unfollowProject', project)"
>
<FollowIcon fill="currentColor" />
<FollowIcon fill="currentColor" aria-hidden="true" />
Unfollow
</button>
</div>
@ -215,7 +215,7 @@
class="title"
target="_blank"
>
<IssuesIcon />
<IssuesIcon aria-hidden="true" />
<span>Issues</span>
</a>
<a
@ -224,7 +224,7 @@
class="title"
target="_blank"
>
<CodeIcon />
<CodeIcon aria-hidden="true" />
<span>Source</span>
</a>
<a
@ -233,7 +233,7 @@
class="title"
target="_blank"
>
<WikiIcon />
<WikiIcon aria-hidden="true" />
<span>Wiki</span>
</a>
<a
@ -244,8 +244,9 @@
<DiscordIcon
v-if="$colorMode.value === 'light'"
class="shrink"
aria-hidden="true"
/>
<DiscordIconWhite v-else class="shrink" />
<DiscordIconWhite v-else class="shrink" aria-hidden="true" />
<span>Discord</span>
</a>
<a
@ -256,18 +257,20 @@
>
<BuyMeACoffeeLogo
v-if="donation.id === 'bmac' && $colorMode.value === 'light'"
aria-hidden="true"
/>
<BuyMeACoffeeLogoWhite
v-else-if="
donation.id === 'bmac' && $colorMode.value === 'dark'
"
aria-hidden="true"
/>
<img
v-else-if="
donation.id === 'patreon' && $colorMode.value === 'light'
"
class="shrink"
alt="patreon"
alt=""
src="~/assets/images/external/patreon.png"
/>
<img
@ -275,7 +278,7 @@
donation.id === 'patreon' && $colorMode.value === 'dark'
"
class="shrink"
alt="patreon"
alt=""
src="~/assets/images/external/patreon-white.png"
/>
<img
@ -283,7 +286,7 @@
donation.id === 'paypal' && $colorMode.value === 'light'
"
class="shrink"
alt="paypal"
alt=""
src="~/assets/images/external/paypal.png"
/>
<img
@ -291,21 +294,21 @@
donation.id === 'paypal' && $colorMode.value === 'dark'
"
class="shrink"
alt="paypal"
alt=""
src="~/assets/images/external/paypal-white.png"
/>
<img
v-else-if="
donation.id === 'ko-fi' && $colorMode.value === 'light'
"
alt="kofi"
alt=""
src="~/assets/images/external/kofi.png"
/>
<img
v-else-if="
donation.id === 'ko-fi' && $colorMode.value === 'dark'
"
alt="kofi"
alt=""
src="~/assets/images/external/kofi-white.png"
/>
<FollowIcon v-else-if="donation.id === 'github'" />
@ -332,6 +335,7 @@
<a
:href="findPrimary(version).url"
class="download"
:title="`Download ${version.name}`"
@click.prevent="
downloadFile(
findPrimary(version).hashes.sha1,
@ -339,7 +343,7 @@
)
"
>
<DownloadIcon />
<DownloadIcon aria-hidden="true" />
</a>
<div class="info">
<nuxt-link

View File

@ -38,6 +38,7 @@
<a
:href="$parent.findPrimary(version).url"
class="iconified-button download"
:title="`Download ${version.name}`"
@click.prevent="
$parent.downloadFile(
$parent.findPrimary(version).hashes.sha1,
@ -45,7 +46,7 @@
)
"
>
<DownloadIcon />
<DownloadIcon aria-hidden="true" />
Download
</a>
</div>

View File

@ -16,7 +16,7 @@
project.slug ? project.slug : project.id
}/versions`"
>
<BackIcon />
<BackIcon aria-hidden="true" />
Back to list
</nuxt-link>
</div>
@ -25,14 +25,14 @@
<h2>{{ version.name }}</h2>
<div v-if="version.featured" class="featured">
<StarIcon />
<StarIcon aria-hidden="true" />
Featured
</div>
<div
v-else-if="featuredVersions.find((x) => x.id === version.id)"
class="featured"
>
<StarIcon />
<StarIcon aria-hidden="true" />
Auto-featured
</div>
</div>
@ -41,7 +41,7 @@
class="action iconified-button brand-button-colors"
@click="saveEditedVersion"
>
<CheckIcon />
<CheckIcon aria-hidden="true" />
Save
</button>
<nuxt-link
@ -51,7 +51,7 @@
}/version/${encodeURIComponent(version.version_number)}`"
class="action iconified-button"
>
<TrashIcon />
<TrashIcon aria-hidden="true" />
Discard changes
</nuxt-link>
</div>
@ -60,7 +60,7 @@
class="action iconified-button brand-button-colors"
@click="createVersion"
>
<CheckIcon />
<CheckIcon aria-hidden="true" />
Save
</button>
<nuxt-link
@ -70,7 +70,7 @@
}/versions`"
class="action iconified-button"
>
<TrashIcon />
<TrashIcon aria-hidden="true" />
Discard version
</nuxt-link>
</div>
@ -79,11 +79,12 @@
v-if="primaryFile"
:href="primaryFile.url"
class="action iconified-button brand-button-colors"
:title="`Download ${primaryFile.filename}`"
@click.prevent="
$parent.downloadFile(primaryFile.hashes.sha1, primaryFile.url)
"
>
<DownloadIcon />
<DownloadIcon aria-hidden="true" />
Download
</a>
<nuxt-link
@ -91,7 +92,7 @@
:to="`/create/report?id=${version.id}&t=version`"
class="action iconified-button"
>
<ReportIcon />
<ReportIcon aria-hidden="true" />
Report
</nuxt-link>
<button
@ -99,7 +100,7 @@
class="action iconified-button"
@click="$refs.delete_version_popup.show()"
>
<TrashIcon />
<TrashIcon aria-hidden="true" />
Delete
</button>
<nuxt-link
@ -110,7 +111,7 @@
}/version/${encodeURIComponent(version.version_number)}/edit`"
@click.prevent="mode = 'edit'"
>
<EditIcon />
<EditIcon aria-hidden="true" />
Edit
</nuxt-link>
</div>
@ -409,14 +410,16 @@
v-if="primaryFile.hashes.sha1 === file.hashes.sha1"
class="featured"
>
<StarIcon />
<StarIcon aria-hidden="true" />
Primary
</div>
<a
class="action iconified-button"
:title="`Download ${file.filename}`"
tabindex="0"
@click.prevent="$parent.downloadFile(file.hashes.sha1, file.url)"
>
<DownloadIcon />
<DownloadIcon aria-hidden="true" />
Download
</a>
<button
@ -427,7 +430,7 @@
version.files.splice(index, 1)
"
>
<TrashIcon />
<TrashIcon aria-hidden="true" />
Delete
</button>
<button
@ -437,7 +440,7 @@
class="action iconified-button"
@click="primaryFile = file"
>
<StarIcon />
<StarIcon aria-hidden="true" />
Make primary
</button>
</div>
@ -452,7 +455,7 @@
class="action iconified-button"
@click="newFiles.splice(index, 1)"
>
<TrashIcon />
<TrashIcon aria-hidden="true" />
Delete
</button>
</div>

View File

@ -11,7 +11,7 @@
<table>
<thead>
<tr>
<th></th>
<th role="presentation"></th>
<th>Version</th>
<th>Supports</th>
<th>Stats</th>
@ -23,6 +23,7 @@
<a
:href="$parent.findPrimary(version).url"
class="download-button"
:title="`Download ${version.name}`"
@click.prevent="
$parent.downloadFile(
$parent.findPrimary(version).hashes.sha1,
@ -30,7 +31,7 @@
)
"
>
<DownloadIcon />
<DownloadIcon aria-hidden="true" />
</a>
</td>
<td>

View File

@ -1,13 +1,13 @@
<template>
<div class="normal-page">
<aside class="normal-page__sidebar">
<section class="card">
<aside class="normal-page__sidebar" aria-label="Filters">
<section class="card" role="presentation">
<button
class="iconified-button sidebar-menu-close-button"
@click="sidebarMenuOpen = !sidebarMenuOpen"
>
<EyeOffIcon v-if="sidebarMenuOpen" />
<EyeIcon v-else />
<EyeOffIcon v-if="sidebarMenuOpen" aria-hidden="true" />
<EyeIcon v-else aria-hidden="true" />
{{ sidebarMenuOpen ? 'Hide filters' : 'Show filters' }}
</button>
<div
@ -24,71 +24,78 @@
class="iconified-button"
@click="clearFilters"
>
<ExitIcon />
<ExitIcon aria-hidden="true" />
Clear filters
</button>
<h3
v-if="
$tag.categories.filter((x) => x.project_type === projectType)
.length > 0
"
class="sidebar-menu-heading"
>
Categories
</h3>
<SearchFilter
v-for="category in $tag.categories.filter(
(x) => x.project_type === projectType
)"
:key="category.name"
:active-filters="facets"
:display-name="category.name"
:facet-name="`categories:${category.name}`"
:icon="category.icon"
@toggle="toggleFacet"
/>
<h3
v-if="
$tag.loaders.filter((x) =>
<section aria-label="Category filters">
<h3
v-if="
$tag.categories.filter((x) => x.project_type === projectType)
.length > 0
"
class="sidebar-menu-heading"
>
Categories
</h3>
<SearchFilter
v-for="category in $tag.categories.filter(
(x) => x.project_type === projectType
)"
:key="category.name"
:active-filters="facets"
:display-name="category.name"
:facet-name="`categories:${category.name}`"
:icon="category.icon"
@toggle="toggleFacet"
/>
</section>
<section aria-label="Loader filters">
<h3
v-if="
$tag.loaders.filter((x) =>
x.supported_project_types.includes(projectType)
).length > 0
"
class="sidebar-menu-heading"
>
Loaders
</h3>
<SearchFilter
v-for="loader in $tag.loaders.filter((x) =>
x.supported_project_types.includes(projectType)
).length > 0
"
class="sidebar-menu-heading"
>
Loaders
</h3>
<SearchFilter
v-for="loader in $tag.loaders.filter((x) =>
x.supported_project_types.includes(projectType)
)"
:key="loader.name"
:active-filters="facets"
:display-name="loader.name"
:facet-name="`categories:${loader.name}`"
:icon="loader.icon"
@toggle="toggleFacet"
/>
<h3 class="sidebar-menu-heading">Environments</h3>
<SearchFilter
:active-filters="selectedEnvironments"
display-name="Client"
facet-name="client"
@toggle="toggleEnv"
>
<ClientSide />
</SearchFilter>
<SearchFilter
:active-filters="selectedEnvironments"
display-name="Server"
facet-name="server"
@toggle="toggleEnv"
>
<ServerSide />
</SearchFilter>
)"
:key="loader.name"
:active-filters="facets"
:display-name="loader.name"
:facet-name="`categories:${loader.name}`"
:icon="loader.icon"
@toggle="toggleFacet"
/>
</section>
<section aria-label="Environment filters">
<h3 class="sidebar-menu-heading">Environments</h3>
<SearchFilter
:active-filters="selectedEnvironments"
display-name="Client"
facet-name="client"
@toggle="toggleEnv"
>
<ClientSide aria-hidden="true" />
</SearchFilter>
<SearchFilter
:active-filters="selectedEnvironments"
display-name="Server"
facet-name="server"
@toggle="toggleEnv"
>
<ServerSide aria-hidden="true" />
</SearchFilter>
</section>
<h3 class="sidebar-menu-heading">Minecraft versions</h3>
<Checkbox
v-model="showSnapshots"
label="Include snapshots"
description="Include snapshots"
style="margin-bottom: 0.5rem"
:border="false"
/>
@ -132,7 +139,7 @@
<div class="card search-controls">
<div class="iconified-input">
<label class="hidden" for="search">Search Mods</label>
<SearchIcon />
<SearchIcon aria-hidden="true" />
<input
id="search"
v-model="query"
@ -191,10 +198,10 @@
ethical-ads-big
/>
<div v-if="$fetchState.pending" class="no-results">
<LogoAnimated />
<LogoAnimated aria-hidden="true" />
<p>Loading...</p>
</div>
<div v-else>
<div v-else role="list" aria-label="Search results">
<SearchResult
v-for="result in results"
:id="result.slug ? result.slug : result.project_id"

View File

@ -13,7 +13,7 @@
:to="`/create/report?id=${user.id}&t=user`"
class="sidebar__item report-button iconified-button"
>
<ReportIcon />
<ReportIcon aria-hidden="true" />
Report
</nuxt-link>
<div class="sidebar__item">
@ -29,19 +29,19 @@
<span v-if="user.bio" class="sidebar__item bio">{{ user.bio }}</span>
<div class="sidebar__item stats-block">
<div class="stats-block__item secondary-stat">
<SunriseIcon class="secondary-stat__icon" />
<SunriseIcon class="secondary-stat__icon" aria-hidden="true" />
<span class="secondary-stat__text">
Joined {{ $dayjs(user.created).fromNow() }}
</span>
</div>
<div class="stats-block__item secondary-stat">
<UserIcon class="secondary-stat__icon" />
<UserIcon class="secondary-stat__icon" aria-hidden="true" />
<span class="secondary-stat__text">User ID: {{ user.id }}</span>
</div>
</div>
<div class="sidebar__item stats-block">
<div class="stats-block__item primary-stat">
<DownloadIcon class="primary-stat__icon" />
<DownloadIcon class="primary-stat__icon" aria-hidden="true" />
<div class="primary-stat__text">
<span class="primary-stat__counter">{{ sumDownloads() }}</span>
<span class="primary-stat__label">downloads</span>