Compare commits

...

7 Commits

8 changed files with 93 additions and 28 deletions

View File

@ -15,6 +15,7 @@
"stylelint-config-standard-scss" "stylelint-config-standard-scss"
], ],
"rules": { "rules": {
"no-descending-specificity": null,
"string-quotes": "single" "string-quotes": "single"
} }
} }

View File

@ -8,10 +8,10 @@ use {
use crate::group_data::GroupDataModel; use crate::group_data::GroupDataModel;
const BACKGROUND_1: RGBColor = RGBColor(17, 17, 17); const BACKGROUND_1: RGBColor = RGBColor(31, 23, 49);
const BACKGROUND_2: RGBColor = RGBColor(0, 0, 0); const BACKGROUND_2: RGBColor = RGBColor(42, 32, 65);
const FOREGROUND: RGBColor = RGBColor(255, 255, 255); const FOREGROUND: RGBColor = RGBColor(242, 239, 255);
const ACCENT_1: RGBColor = RGBColor(255, 0, 255); const ACCENT_1: RGBColor = RGBColor(210, 184, 58);
/// The chart for the user count. /// The chart for the user count.
#[derive(Debug)] #[derive(Debug)]
@ -46,7 +46,7 @@ impl UserCountChart {
let path = parent.join("user-count.svg"); let path = parent.join("user-count.svg");
let chart_root = SVGBackend::new(&path, (1280, 720)).into_drawing_area(); let chart_root = SVGBackend::new(&path, (1280, 720)).into_drawing_area();
chart_root.fill(&BACKGROUND_1)?; chart_root.fill(&BACKGROUND_2)?;
let text_style = let text_style =
|font_size: i32| ("sans-serif", font_size).into_font().color(&FOREGROUND); |font_size: i32| ("sans-serif", font_size).into_font().color(&FOREGROUND);
@ -55,15 +55,15 @@ impl UserCountChart {
.margin(20, 20, 20, 20) .margin(20, 20, 20, 20)
.titled("Tildes User Count", text_style(30))?; .titled("Tildes User Count", text_style(30))?;
chart_root.fill(&BACKGROUND_1)?; chart_root.fill(&BACKGROUND_2)?;
let mut chart = ChartBuilder::on(&chart_root) let mut chart = ChartBuilder::on(&chart_root)
.caption( .caption(
format!("Using the {group_name} subscriber count."), format!("Using the {group_name} subscriber count."),
text_style(20), text_style(20),
) )
.x_label_area_size(40) .x_label_area_size(50)
.y_label_area_size(40) .y_label_area_size(50)
.margin(10) .margin(10)
.build_cartesian_2d(0..(datapoints_len + 1), min_count..max_count)?; .build_cartesian_2d(0..(datapoints_len + 1), min_count..max_count)?;
@ -75,9 +75,9 @@ impl UserCountChart {
.y_labels(5) .y_labels(5)
.y_label_formatter(&|y| format!("{y:0}")) .y_label_formatter(&|y| format!("{y:0}"))
.label_style(text_style(20)) .label_style(text_style(20))
.axis_style(&BACKGROUND_2) .axis_style(&BACKGROUND_1)
.light_line_style(&BACKGROUND_2) .light_line_style(&BACKGROUND_1)
.bold_line_style(&BACKGROUND_1) .bold_line_style(&BACKGROUND_2)
.draw()?; .draw()?;
chart chart

View File

@ -85,15 +85,19 @@ pub async fn run() -> Result<()> {
command: web_command, command: web_command,
} => match web_command { } => match web_command {
WebSubcommands::Build { output } => { WebSubcommands::Build { output } => {
let user_count_group = let (groups, user_count_group) =
if let Some(snapshot) = SnapshotModel::get_most_recent(&db).await? { if let Some(snapshot) = SnapshotModel::get_most_recent(&db).await? {
GroupDataModel::get_highest_subscribers(&db, &snapshot).await? (
GroupDataModel::get_all_by_snapshot(&db, &snapshot).await?,
GroupDataModel::get_highest_subscribers(&db, &snapshot).await?,
)
} else { } else {
None (vec![], None)
}; };
create_dir_all(&output).await?; create_dir_all(&output).await?;
HomeTemplate::new( HomeTemplate::new(
groups,
user_count_group.as_ref().map(|group| group.subscribers), user_count_group.as_ref().map(|group| group.subscribers),
) )
.render_to_file(&output) .render_to_file(&output)

View File

@ -19,7 +19,12 @@ impl GroupDataModel {
db: &DatabaseConnection, db: &DatabaseConnection,
snapshot: &SnapshotModel, snapshot: &SnapshotModel,
) -> Result<Vec<Self>> { ) -> Result<Vec<Self>> {
let groups = snapshot.find_related(GroupDataEntity).all(db).await?; let groups = snapshot
.find_related(GroupDataEntity)
.order_by_asc(GroupDataColumn::Name)
.all(db)
.await?;
Ok(groups) Ok(groups)
} }
@ -44,7 +49,7 @@ impl GroupDataModel {
name: &str, name: &str,
) -> Result<Vec<Self>> { ) -> Result<Vec<Self>> {
let groups = GroupDataEntity::find() let groups = GroupDataEntity::find()
.order_by_desc(GroupDataColumn::SnapshotId) .order_by_asc(GroupDataColumn::SnapshotId)
.filter(GroupDataColumn::Name.eq(name)) .filter(GroupDataColumn::Name.eq(name))
.limit(amount) .limit(amount)
.all(db) .all(db)

View File

@ -6,11 +6,11 @@ body {
--small-spacing: 4px; --small-spacing: 4px;
--medium-spacing: 8px; --medium-spacing: 8px;
--large-spacing: 16px; --large-spacing: 16px;
--background-1: #222; --background-1: #1f1731;
--background-2: #111; --background-2: #2a2041;
--foreground-1: #fff; --foreground-1: #f2efff;
--anchor-1: #f0f; --anchor-1: #d2b83a;
--anchor-2: #000; --anchor-2: var(--foreground-1);
background-color: var(--background-1); background-color: var(--background-1);
color: var(--foreground-1); color: var(--foreground-1);
@ -20,10 +20,8 @@ body {
a, a,
a:visited { a:visited {
color: var(--anchor-1); color: var(--anchor-1);
text-decoration: none;
&:hover { &:hover {
background-color: var(--anchor-1);
color: var(--anchor-2); color: var(--anchor-2);
} }
} }

View File

@ -24,13 +24,41 @@
.page-main { .page-main {
h2, h2,
img, img,
p { p,
table {
margin-bottom: var(--medium-spacing); margin-bottom: var(--medium-spacing);
&:last-child { &:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
} }
table {
border: 2px solid var(--background-2);
border-collapse: collapse;
width: 100%;
}
thead {
background-color: var(--background-2);
border-bottom: 2px solid var(--background-2);
text-align: left;
}
tr {
border: 2px solid var(--background-2);
}
td,
th {
padding: var(--medium-spacing);
}
tbody {
> tr:nth-of-type(2n) {
background-color: var(--background-2);
}
}
} }
.page-footer { .page-footer {

View File

@ -13,13 +13,38 @@
<h2>General</h2> <h2>General</h2>
<p> <p>
There are currently an There are currently an estimated
<abbr title="Based on the group with the highest subscriber count.">estimated</abbr>
<span class="underline">{{ user_count }}</span> <span class="underline">{{ user_count }}</span>
registered users on Tildes. registered users on Tildes.
</p> </p>
<img src="/charts/user-count.svg" alt="User Count Chart"> <img src="/charts/user-count.svg" alt="User Count Chart">
<table>
<thead>
<tr>
<th>Group</th>
<th>Subscribers</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{% for group in groups %}
<tr>
<td>
<a href="https://tildes.net/{{ group.name }}">{{ group.name }}</a>
</td>
<td>{{ group.subscribers }}</td>
<td>
{% if let Some(description) = group.description %}
{{ description }}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</main> </main>
<footer class="page-footer"> <footer class="page-footer">

View File

@ -7,12 +7,15 @@ use {
color_eyre::Result, color_eyre::Result,
}; };
use crate::utilities::today; use crate::{group_data::GroupDataModel, utilities::today};
/// The template for the home page. /// The template for the home page.
#[derive(Template)] #[derive(Template)]
#[template(path = "index.html")] #[template(path = "index.html")]
pub struct HomeTemplate { pub struct HomeTemplate {
/// The groups to create the table with.
pub groups: Vec<GroupDataModel>,
/// The string for the `<title>` element. /// The string for the `<title>` element.
pub page_title: String, pub page_title: String,
@ -25,8 +28,9 @@ pub struct HomeTemplate {
impl HomeTemplate { impl HomeTemplate {
/// Create a new [`HomeTemplate`]. /// Create a new [`HomeTemplate`].
pub fn new(user_count: Option<i64>) -> Self { pub fn new(groups: Vec<GroupDataModel>, user_count: Option<i64>) -> Self {
Self { Self {
groups,
page_title: "Tildes Statistics".to_string(), page_title: "Tildes Statistics".to_string(),
today: today(), today: today(),
user_count: user_count user_count: user_count