Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
7 changes: 6 additions & 1 deletion app/lib/frontend/templates/views/pkg/score_tab.dart
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ d.Node _section(ReportSection section) {
}

d.Node _downloadsChart(WeeklyVersionDownloadCounts weeklyVersionDownloads) {
return d.div(
final container = d.div(
classes: ['downloads-chart'],
id: '-downloads-chart',
attributes: {
Expand All @@ -186,6 +186,11 @@ d.Node _downloadsChart(WeeklyVersionDownloadCounts weeklyVersionDownloads) {
base64Encode(jsonUtf8Encoder.convert(weeklyVersionDownloads))
},
);

return d.fragment([
d.h1(text: 'Weekly Downloads over the last 40 weeks'),
container,
]);
}

final _statusIconUrls = {
Expand Down
24 changes: 24 additions & 0 deletions pkg/_pub_shared/lib/format/date_format.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// Formats a DateTime into abbreviated month and day

String formatAbbrMonthDay(DateTime date) {
final month = switch (date.month) {
1 => 'Jan',
2 => 'Feb',
3 => 'Mar',
4 => 'Apr',
5 => 'May',
6 => 'Jun',
7 => 'Jul',
8 => 'Aug',
9 => 'Sep',
10 => 'Oct',
11 => 'Nov',
_ => 'Dec'
};

return '$month ${date.day}';
}
11 changes: 9 additions & 2 deletions pkg/web_app/lib/src/widget/downloads_chart/computations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,22 @@ Iterable<String> prepareRanges(List<VersionRangeCount> rangeDownloads) {
///
/// The 'i'th entry in the iterable is a list of the download values
/// (y coordinates) for the 'i'th week (x coordinate).
List<List<int>> prepareWeekLists(
({List<String> ranges, List<List<int>> weekLists}) prepareWeekLists(
List<int> totals,
List<VersionRangeCount> rangeDownloads,
int displayLength,
) {
final result = <List<int>>[];
final ranges = <String>[];

final showOther =
totals[0] > rangeDownloads.fold(0, (sum, d) => sum + d.counts[0]);

if (showOther) {
ranges.add('Other');
}
rangeDownloads.forEach((d) => ranges.add(d.versionRange));

for (int week = 0; week < displayLength; week++) {
final weekList = <int>[];
if (showOther) {
Expand All @@ -32,5 +38,6 @@ List<List<int>> prepareWeekLists(
rangeDownloads.forEach((d) => weekList.add(d.counts[week]));
result.add(weekList);
}
return result.reversed.toList();

return (ranges: ranges, weekLists: result.reversed.toList());
}
243 changes: 237 additions & 6 deletions pkg/web_app/lib/src/widget/downloads_chart/widget.dart

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ void main() {
(counts: l3, versionRange: '>=6.0.0-0 <7.0.0')
];

final w1 = prepareWeekLists(totals, majorRangeDownloads, 52).toList();
final w2 = prepareWeekLists(totals, minorRangeDownloads, 52).toList();
final w3 = prepareWeekLists(totals, patchRangeDownloads, 52).toList();
final w1 = prepareWeekLists(totals, majorRangeDownloads, 52).weekLists;
final w2 = prepareWeekLists(totals, minorRangeDownloads, 52).weekLists;
final w3 = prepareWeekLists(totals, patchRangeDownloads, 52).weekLists;

for (int i = 42; i < 52; i++) {
expect(w1[i], [10, 10, 10, 10, 70]);
Expand Down
93 changes: 93 additions & 0 deletions pkg/web_css/lib/src/_pkg.scss
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,99 @@
}
}

.downloads-chart {
display: flex;
height: 700px;
width: 775px;
flex-direction: column;
margin-top: 16px;
padding-top: 16px;
}

.downloads-chart-frame {
fill:none;
stroke-width: 1;
stroke: var(--pub-downloads-chart-frame-color);
}

.downloads-chart-x-axis {
fill: none;
stroke-width: 1;
stroke: var(--pub-score_label-text-color);
}

.downloads-chart-tick-label {
fill: var(--pub-score_label-text-color);
font-size: small;
}

.downloads-chart-tick-label-x {
text-anchor: middle;
}

.downloads-chart-tick-label-y {
dominant-baseline: middle;
}

.downloads-chart-legend {
fill-opacity: 0.3;
stroke-width: 1;
}

.downloads-chart-fill-blue {
fill:var(--pub-downloads-chart-color-0);
}

.downloads-chart-fill-red {
fill:var(--pub-downloads-chart-color-1);
}

.downloads-chart-fill-green {
fill:var(--pub-downloads-chart-color-2);
}

.downloads-chart-fill-purple {
fill:var(--pub-downloads-chart-color-3);
}

.downloads-chart-fill-orange {
fill:var(--pub-downloads-chart-color-4);
}

.downloads-chart-fill-turquoise {
fill:var(--pub-downloads-chart-color-5);
}

.downloads-chart-line {
fill: none;
stroke-width: 2;
stroke-linejoin: round;
}

.downloads-chart-stroke-blue {
stroke: var(--pub-downloads-chart-color-0);
}

.downloads-chart-stroke-red {
stroke: var(--pub-downloads-chart-color-1);
}

.downloads-chart-stroke-green {
stroke: var(--pub-downloads-chart-color-2);
}

.downloads-chart-stroke-purple {
stroke: var(--pub-downloads-chart-color-3);
}

.downloads-chart-stroke-orange {
stroke: var(--pub-downloads-chart-color-4);
}

.downloads-chart-stroke-turquoise {
stroke: var(--pub-downloads-chart-color-5);
}

.pkg-page-title-copy {
position: relative;
display: inline-block;
Expand Down
11 changes: 11 additions & 0 deletions pkg/web_css/lib/src/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@
--mdc-theme-primary: #0175c2;
--mdc-theme-secondary: #0066d9;
--mdc-typography-font-family: var(--pub-default-text-font_family);

--pub-downloads-chart-color-0: var(--pub-markdown-alert-note);
--pub-downloads-chart-color-1: var(--pub-markdown-alert-caution);
--pub-downloads-chart-color-2: var(--pub-markdown-alert-tip);
--pub-downloads-chart-color-3: var(--pub-markdown-alert-important);
--pub-downloads-chart-color-4: var(--pub-markdown-alert-warning);
--pub-downloads-chart-color-5: #12a4af;
}

/// Variables that are specific to the light theme.
Expand Down Expand Up @@ -127,6 +134,8 @@
--pub-tag_simplebadge-text-color: #444444;
--pub-tag_sdkbadge-separator-color: rgba(25, 103, 210, 0.5); // #1967d2 + 0.5 opacity;
--pub-tag_sdkbadge-text-color: #1967d2;

--pub-downloads-chart-frame-color: #d3d3d3;
}

.light-theme {
Expand Down Expand Up @@ -183,6 +192,8 @@
--pub-tag_sdkbadge-separator-color: var(--pub-neutral-textColor);
--pub-tag_sdkbadge-text-color: var(--pub-neutral-textColor);

--pub-downloads-chart-frame-color: #55585a;

// Material Design theme customizations
--mdc-theme-surface: var(--pub-neutral-bgColor);
--mdc-theme-on-primary: var(--pub-neutral-textColor);
Expand Down
2 changes: 2 additions & 0 deletions pkg/web_css/test/expression_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ void main() {
(e) => e.startsWith('detail-tab-') && e.endsWith('-content'));
expressions.removeWhere((e) => e.startsWith('package-badge-'));
expressions.removeWhere((e) => e.startsWith('pub-toc-node-'));
// downloads chart color classes
expressions.removeWhere((e) => e.startsWith('downloads-chart'));
// shared CSS file (with dartdoc)
expressions.removeAll([
'cookie-notice-container',
Expand Down
Loading