Skip to content
Open
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
187 changes: 187 additions & 0 deletions assets/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ $spatialdatablue: #40a9ff;
$squidpyviolet: #969dea;
$scirpypurple: #da347f;
$scviyellow: #fbb822;
$scversedeepblue: #262fb5; // the darker end of the Join button gradient

$github-black: #171b21;
$twitter-blue: #469be5;
Expand Down Expand Up @@ -1032,6 +1033,192 @@ body {
border-top: 0px;
}

// Specific to /stats

#stats-content {
.stats-updated {
font-size: 0.9rem;
color: $greydesc;
}

// The one number the page leads with
.stats-hero {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 1rem 3.5rem;
margin: 2.5rem 0 1rem;

.stats-hero-figure {
display: flex;
flex-direction: column;
gap: 0.35rem;
}
.stats-hero-figure--second {
padding-left: 3.5rem;
border-left: 1px solid $overline;
}
@media (max-width: 50rem) {
.stats-hero-figure--second {
padding-left: 0;
border-left: 0;
}
}

.stats-hero-value {
font-size: 4.5rem;
font-weight: 800;
line-height: 1;
color: black;
}
.stats-hero-label {
font-size: 1.15rem;
color: $tiletext;
}
.stats-hero-hint {
font-size: 0.9rem;
color: $greydesc;
}
@media (max-width: 50rem) {
.stats-hero-value {
font-size: 3rem;
}
}
}

.stats-tiles {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
gap: 0.75rem;
}

.stats-tile {
display: flex;
flex-direction: column;
gap: 0.3rem;
padding: 1.1rem 1.25rem;
background-color: $tilebg4;
border: 1px solid $overline;
border-radius: 0.75rem;

.stats-tile-value {
font-size: 2rem;
font-weight: 800;
line-height: 1.1;
color: black;
}
.stats-tile-label {
font-size: 0.85rem;
line-height: 1.35;
color: $tiletext2;
}
}

// Only tiles that lead somewhere get the affordance
a.stats-tile {
text-decoration: none;
transition: all 200ms ease-in-out;

&:hover,
&:focus-visible {
background-color: $tilebg;
border-color: $tilebg2;
transform: scale(1.02);

.stats-tile-value {
color: black;
}
.stats-tile-label {
color: $tiletext;
}
}
}

.stats-contributors {
display: grid;
gap: 0.15rem;
margin: 1.5rem 0;
padding: 0;
list-style: none;

a {
display: grid;
grid-template-columns: 2.5rem minmax(7rem, 11rem) 1fr auto;
align-items: center;
gap: 0.85rem;
padding: 0.35rem 0.5rem;
border-radius: 0.5rem;
color: $tiletext;
text-decoration: none;
transition: all 200ms ease-in-out;

&:hover {
color: black;
background-color: $tilebg4;
}
}
img {
width: 2.5rem;
height: 2.5rem;
border-radius: 50%;
}
.stats-contributor-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
// Thin recessive track, value anchored to the baseline with 4px ends
.stats-contributor-bar {
height: 0.5rem;
background-color: $tilebg;
border-radius: 0.25rem;

> span {
display: block;
min-width: 0.15rem;
height: 100%;
// A hue rather than a dark neutral, so extensions that invert the page keep the bar visible
background-color: $scversedeepblue;
border-radius: 0.25rem;
}
}
.stats-contributor-count {
font-size: 0.85rem;
color: $greydesc;
font-variant-numeric: tabular-nums;
}

@media (max-width: 50rem) {
a {
grid-template-columns: 2.5rem 1fr auto;
}
.stats-contributor-bar {
display: none;
}
}
}

.stats-rest {
summary {
width: fit-content;
padding: 0.35rem 0.5rem;
font-size: 0.9rem;
color: $tiletext2;
border-radius: 0.5rem;
cursor: pointer;
transition: all 200ms ease-in-out;

&:hover {
color: black;
background-color: $tilebg4;
}
}
&[open] summary {
margin-bottom: 0.5rem;
}
}
}

// Specific to /tutorials

#tutorials-content {
Expand Down
4 changes: 4 additions & 0 deletions content/stats/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
+++
title = "scverse in numbers"
preface = "How the scverse community and its packages are doing. The numbers cover the core packages and the scverse GitHub organisation, and are refreshed twice a week by <a href='https://github.com/scverse/stats'>scverse/stats</a>."
+++
3 changes: 3 additions & 0 deletions layouts/partials/header.html
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@
<li>
<a class="dropdown-item" href="/about/ai_policy">AI Policy</a>
</li>
<li>
<a class="dropdown-item" href="/stats">Statistics</a>
</li>
<li>
<a class="dropdown-item" href="/design">Media kit</a>
</li>
Expand Down
12 changes: 12 additions & 0 deletions layouts/partials/stats-contributor.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{{ $person := .person }}
{{ $most := .most }}
<li>
<a href="{{ $person.html_url }}" target="_blank" rel="noopener">
<img src="{{ $person.avatar_url }}&s=96" alt="" loading="lazy" width="40" height="40" />
<span class="stats-contributor-name">{{ $person.name | default $person.login }}</span>
<span class="stats-contributor-bar" aria-hidden="true">
<span style="width: {{ math.Round (div (mul (float $person.contributions) 100.0) (float $most)) }}%"></span>
</span>
<span class="stats-contributor-count">{{ lang.FormatNumberCustom 0 $person.contributions }}</span>
</a>
</li>
121 changes: 121 additions & 0 deletions layouts/stats/list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
{{ define "main" }}
<h1>{{ .Title }}</h1>
<article class="post">
<div class="post-content" id="stats-content">
{{ $base := "https://scverse.org/stats/" }}
{{ $stats := transform.Unmarshal (resources.GetRemote (printf "%sstats.json" $base)).Content }}
{{ $contributors := transform.Unmarshal (resources.GetRemote (printf "%scontributors.json" $base)).Content }}
{{ $gh := $stats.github }}


<p>{{ .Params.preface | safeHTML }}</p>

<p class="stats-updated">
Updated
<time datetime="{{ $stats.timestamp }}">{{ (time $stats.timestamp).Format "2 January 2006" }}</time>
</p>

{{/* The one number the page leads with. Everything else is a tile. */}}
<section class="stats-hero">
<div class="stats-hero-figure">
<span class="stats-hero-value">{{ printf "%.1fM" (div (float $stats.pepy_downloads) 1000000.0) }}</span>
<span class="stats-hero-label">downloads of the core packages, all time</span>
<span class="stats-hero-hint">
{{ lang.FormatNumberCustom 0 $stats.pepy_avg_daily_30 }} a day on average over the last 30 days
</span>
</div>
{{ with $stats.citation_count }}
<div class="stats-hero-figure stats-hero-figure--second">
<span class="stats-hero-value">{{ lang.FormatNumberCustom 0 . }}</span>
<span class="stats-hero-label">citations of scverse papers</span>
</div>
{{ end }}
</section>

{{/* A tile only gets a link where the destination genuinely shows the same number. */}}
{{/* LinkedIn is scraped upstream, so any given run may not have it. */}}
{{ $social := slice
(dict "value" $stats.zulip_users "label" "Zulip members" "url" "https://scverse.zulipchat.com/")
(dict "value" $stats.bluesky_followers "label" "Bluesky followers" "url" "https://bsky.app/profile/scverse.bsky.social")
}}
{{ with $stats.linkedin_followers }}
{{ $social = $social | append (dict "value" . "label" "LinkedIn followers" "url" "https://www.linkedin.com/company/scverse/") }}
{{ end }}

{{ $groups := slice
(dict
"name" "Community"
"tiles" ($social | append
(dict "value" $gh.unique_contributors "label" "code contributors" "url" "#contributors")
(dict "value" $gh.organization_members "label" "GitHub organisation members" "url" "https://github.com/orgs/scverse/people")
(dict "value" $stats.core_team_size "label" "core team members" "url" "/people")
)
)
(dict
"name" "Packages and code"
"tiles" (slice
(dict "value" $stats.ecosystem_packages "label" "ecosystem packages" "url" "/packages#ecosystem")
(dict "value" $gh.total_repositories "label" "core repositories" "url" "/packages#core-packages")
(dict "value" $gh.total_stars "label" "GitHub stars" "url" "https://github.com/scverse")
(dict "value" $gh.total_pull_requests_last_year "label" "pull requests in the last year")
(dict "value" $gh.total_pull_requests_closed "label" "pull requests closed, all time")
(dict "value" $gh.total_issues_open "label" "issues open")
(dict "value" $gh.total_issues_closed "label" "issues closed")
)
)
}}

{{ range $groups }}
<h2>{{ .name }}</h2>
<div class="stats-tiles">
{{ range .tiles }}
{{ if .url }}
<a
class="stats-tile"
href="{{ .url }}"
{{ if hasPrefix .url "http" }}target="_blank" rel="noopener"{{ end }}
>
<span class="stats-tile-value">{{ lang.FormatNumberCustom 0 .value }}</span>
<span class="stats-tile-label">{{ .label }}</span>
</a>
{{ else }}
<div class="stats-tile">
<span class="stats-tile-value">{{ lang.FormatNumberCustom 0 .value }}</span>
<span class="stats-tile-label">{{ .label }}</span>
</div>
{{ end }}
{{ end }}
</div>
{{ end }}


<h2 id="contributors">Top contributors</h2>
<p>
{{ lang.FormatNumberCustom 0 $contributors.total_contributors }} people have contributed code to the core
packages, ranked here by number of commits.
</p>

{{ $shown := 24 }}
{{ $top := first $shown $contributors.contributors }}
{{ $rest := after $shown $contributors.contributors }}
{{ $most := (index $top 0).contributions }}
<ol class="stats-contributors">
{{ range $top }}
{{ partial "stats-contributor.html" (dict "person" . "most" $most) }}
{{ end }}
</ol>

{{ with $rest }}
<details class="stats-rest">
<summary>Show the other {{ lang.FormatNumberCustom 0 (len .) }} contributors</summary>
<ol class="stats-contributors" start="{{ add $shown 1 }}">
{{ range . }}
{{ partial "stats-contributor.html" (dict "person" . "most" $most) }}
{{ end }}
</ol>
</details>
{{ end }}

</div>
</article>
{{ end }}