use crate::prelude::*;
#[derive(AutoDefault, Copy, Clone, Debug, Eq, PartialEq)]
pub enum IntroOpening {
#[default]
PageTop,
Custom,
}
#[derive(Clone, Debug, Getters)]
pub struct Intro {
title: L10n,
slogan: L10n,
button: Option<(L10n, FnPathByContext)>,
opening: IntroOpening,
children: Children,
}
impl Default for Intro {
fn default() -> Self {
const BUTTON_LINK: &str = "https://pagetop.cillero.es";
Intro {
title: L10n::l("intro_default_title"),
slogan: L10n::l("intro_default_slogan").with_arg("app", &global::SETTINGS.app.name),
button: Some((L10n::l("intro_default_button"), |_| BUTTON_LINK.into())),
opening: IntroOpening::default(),
children: Children::default(),
}
}
}
impl Component for Intro {
fn new() -> Self {
Self::default()
}
fn prepare(&self, cx: &mut Context) -> Result<Markup, ComponentError> {
cx.alter_assets(AssetsOp::AddStyleSheet(
StyleSheet::from("/css/intro.css").with_version(PAGETOP_VERSION),
));
if *self.opening() == IntroOpening::PageTop {
cx.alter_assets(AssetsOp::AddJavaScript(JavaScript::on_load_async("intro-js", |cx|
util::indoc!(r#"
try {
const resp = await fetch("https://crates.io/api/v1/crates/pagetop");
const data = await resp.json();
const date = new Date(data.versions[0].created_at);
const formatted = date.toLocaleDateString("LANGID", { year: "numeric", month: "2-digit", day: "2-digit" });
document.getElementById("intro-release").src = `https://img.shields.io/badge/Release%20date-${encodeURIComponent(formatted)}-blue?label=LABEL&style=for-the-badge`;
document.getElementById("intro-badges").style.display = "block";
} catch (e) {
console.error("Failed to fetch release date from crates.io:", e);
}
"#)
.replace("LANGID", cx.langid().to_string().as_str())
.replace("LABEL", L10n::l("intro_release_label").using(cx).as_str())
)));
}
Ok(html! {
div class="intro" {
div class="intro-header" {
section class="intro-header-body" {
h1 class="intro-header-title" {
span { (self.title().using(cx)) }
(self.slogan().using(cx))
}
}
aside class="intro-header-img" aria-hidden="true" {
div class="intro-header-mascot" {
(PageTopSvg::Color.render(cx))
}
}
}
div class="intro-content" {
section class="intro-content-body" {
div class="intro-text" {
@if let Some((txt, lnk)) = self.button() {
div class="intro-button" {
a
class="intro-button-link"
href=((lnk)(cx))
target="_blank"
rel="noopener noreferrer"
{
span {} span {} span {}
div class="intro-button-text" {
(txt.using(cx))
}
}
}
}
div class="intro-text-body" {
@if *self.opening() == IntroOpening::PageTop {
p class="intro-text-lead" {
(L10n::l("intro_text1").using(cx))
}
div id="intro-badges" {
img
src="https://img.shields.io/crates/v/pagetop.svg?label=PageTop&style=for-the-badge"
alt=[L10n::l("intro_pagetop_label").lookup(cx)] {} (" ")
img
id="intro-release"
alt=[L10n::l("intro_release_label").lookup(cx)] {} (" ")
img
src=(format!(
"https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label={}&style=for-the-badge",
L10n::l("intro_license_label").lookup(cx).unwrap_or_default()
))
alt=[L10n::l("intro_license_label").lookup(cx)] {}
}
p class="intro-text-lead" {
(L10n::l("intro_text2").using(cx))
}
}
(self.children().render(cx))
}
}
}
}
div class="intro-footer" {
section class="intro-footer-body" {
div class="intro-footer-logo" {
(PageTopSvg::LineLight.render(cx))
}
div class="intro-footer-links" {
a href="https://crates.io/crates/pagetop" target="_blank" rel="noopener noreferrer" { ("Crates.io") }
a href="https://docs.rs/pagetop" target="_blank" rel="noopener noreferrer" { ("Docs.rs") }
a href="https://git.cillero.es/manuelcillero/pagetop" target="_blank" rel="noopener noreferrer" { (L10n::l("intro_code").using(cx)) }
em { (L10n::l("intro_have_fun").using(cx)) }
}
}
}
}
})
}
}
impl Intro {
#[builder_fn]
pub fn with_title(mut self, title: L10n) -> Self {
self.title = title;
self
}
#[builder_fn]
pub fn with_slogan(mut self, slogan: L10n) -> Self {
self.slogan = slogan;
self
}
#[builder_fn]
pub fn with_button(mut self, button: Option<(L10n, FnPathByContext)>) -> Self {
self.button = button;
self
}
#[builder_fn]
pub fn with_opening(mut self, opening: IntroOpening) -> Self {
self.opening = opening;
self
}
#[builder_fn]
pub fn with_child(mut self, op: impl Into<ChildOp>) -> Self {
self.children.alter_child(op.into());
self
}
}