diff --git a/server/src/client/assets/css/style.css b/server/src/client/assets/css/style.css
index f1c84e8..8a2c82f 100644
--- a/server/src/client/assets/css/style.css
+++ b/server/src/client/assets/css/style.css
@@ -119,6 +119,28 @@ ul {
a {
color: unset;
text-decoration: unset;
+
+ &:not(:has(time)):is([href^="http"], [href^="mailto"]) {
+ padding-inline-end: 0.9em;
+
+ &::after {
+ transition: all 0.3s ease;
+ position: absolute;
+ content: '';
+ display: inline-block;
+ width: 1em;
+ height: 1em;
+ margin-inline-start: -0.05em;
+ background-size: 100%;
+ transform: scale(0.8);
+ background-image: url("/assets/images/external.svg");
+ }
+
+ &:is(:hover, :active, :focus-visible)::after {
+ filter: invert(100%);
+ }
+
+ }
}
form {
@@ -135,7 +157,7 @@ input {
margin: 0;
}
-input:is([type="text"], [type="password"], [type="search"]) {
+input:is([type="text"], [type="password"], [type="search"], [type="email"], ) {
padding: 0.5ch 1ch;
&:focus,
@@ -347,7 +369,60 @@ header {
}
+footer {
+ border-block-start: var(--border);
+ display: flex;
+ min-block-size: calc(var(--header-size) * 2.5);
+ padding: 1rem;
+ gap: 2rem;
+ flex-direction: column;
+ align-items: start;
+ justify-content: start;
+
+ &>* {
+ max-inline-size: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: start;
+ }
+
+ line-height: 1.6em;
+
+ form {
+ display: flex;
+ flex-direction: column;
+
+ & div {
+ display: flex;
+ max-inline-size: 100%;
+
+ &>* {
+ min-inline-size: 0;
+ }
+
+ input[type="submit"] {
+ min-inline-size: min-content;
+ }
+ }
+
+ }
+
+ h1,
+ ul {
+ margin-block: 0 1rem;
+ }
+
+ p,
+ li,
+ input {
+ margin-block: 0.3rem;
+ }
+
+
+}
+
main {
+ min-block-size: 100svb;
margin-block: var(--default-padding) 40svb;
margin-inline: auto;
max-inline-size: min(60ch, 80%);
@@ -422,6 +497,15 @@ main {
}
}
+ footer {
+ flex-direction: row;
+
+ &>* {
+ max-inline-size: 40ch;
+ min-inline-size: 30ch;
+ }
+ }
+
main {
margin-block: var(--default-padding);
}
diff --git a/server/src/client/assets/images/external.svg b/server/src/client/assets/images/external.svg
new file mode 100644
index 0000000..1e7e0f3
--- /dev/null
+++ b/server/src/client/assets/images/external.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/server/src/html.rs b/server/src/html.rs
index 4c99f9e..77a4b77 100644
--- a/server/src/html.rs
+++ b/server/src/html.rs
@@ -72,6 +72,12 @@ where
}
Ok(())
}),
+ element!("site-footer", |site_footer| {
+ if settings.site_footer {
+ site_footer.replace(template!("site-footer"), ContentType::Html);
+ }
+ Ok(())
+ }),
element!("br", |br| {
br.remove();
Ok(())
@@ -187,7 +193,7 @@ where
.unwrap_or_default();
make_page(
html,
- PageSettings::new("Editor", Some(vec!["/assets/css/editor.css"]), true),
+ PageSettings::new("Editor", Some(vec!["/assets/css/editor.css"]), true, false),
)
}
@@ -229,7 +235,7 @@ pub(crate) fn login_status(next: &str, success: bool) -> String {
.unwrap_or_default();
make_page(
html,
- PageSettings::new("Login", Some(vec!["/assets/css/login.css"]), false),
+ PageSettings::new("Login", Some(vec!["/assets/css/login.css"]), false, false),
)
}
@@ -237,7 +243,7 @@ pub(crate) async fn admin_page(session_id: i64, db: &BlogDb) -> String {
let content = admin_widgets(template!("admin"), session_id, db).await;
make_page(
&content,
- PageSettings::new("Admin", Some(vec!["/assets/css/admin.css"]), true),
+ PageSettings::new("Admin", Some(vec!["/assets/css/admin.css"]), true, false),
)
}
@@ -558,7 +564,7 @@ pub(crate) async fn blog_roll(db: &BlogDb) -> String {
make_page(
blog_roll_html,
- PageSettings::new("Blog", Some(vec!["/assets/css/blog.css"]), true),
+ PageSettings::new("Blog", Some(vec!["/assets/css/blog.css"]), true, true),
)
}
@@ -653,6 +659,7 @@ pub(crate) async fn search_page(
["Results for “", &query, "”"].concat(),
Some(vec!["/assets/css/blog.css"]),
true,
+ true,
),
)
}
@@ -694,6 +701,7 @@ pub(crate) struct PageSettings {
title: String,
stylesheets: Option>,
site_header: bool,
+ site_footer: bool,
}
impl PageSettings {
@@ -705,9 +713,15 @@ impl PageSettings {
title: title.to_string(),
stylesheets: None,
site_header: true,
+ site_footer: true,
}
}
- pub(crate) fn new(title: S, stylesheets: Option>, site_header: bool) -> Self
+ pub(crate) fn new(
+ title: S,
+ stylesheets: Option>,
+ site_header: bool,
+ site_footer: bool,
+ ) -> Self
where
S: ToString,
T: ToString,
@@ -718,6 +732,7 @@ impl PageSettings {
title: title.to_string(),
stylesheets,
site_header,
+ site_footer,
}
}
}
@@ -754,6 +769,12 @@ where
.unwrap_or_default()
}
+// fn footer(input: S) -> String
+// where
+// S: AsRef,
+// {
+// }
+
pub(crate) fn sanitize>(input: S) -> String {
rewrite_str(
input.as_ref(),
diff --git a/server/src/templates/default.html b/server/src/templates/default.html
index 535d7ae..4d20c4a 100644
--- a/server/src/templates/default.html
+++ b/server/src/templates/default.html
@@ -11,6 +11,7 @@
+