Compare commits
7 Commits
b64b7836fa
...
352d107e35
Author | SHA1 | Date |
---|---|---|
Bauke | 352d107e35 | |
Bauke | 1771bd7eb3 | |
Bauke | 7cc2d7518f | |
Bauke | a25ae7adda | |
Bauke | fc2cccd53c | |
Bauke | ff6e1cde0d | |
Bauke | 7cebbb8f42 |
|
@ -15,6 +15,7 @@
|
||||||
"stylelint-config-standard-scss"
|
"stylelint-config-standard-scss"
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
|
"no-descending-specificity": null,
|
||||||
"string-quotes": "single"
|
"string-quotes": "single"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue