Linked styles
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{
|
use syn::{
|
||||||
Ident, LitStr, Result, Token, braced,
|
Expr, Ident, LitStr, Result, Token, braced,
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
parse_macro_input,
|
parse_macro_input,
|
||||||
};
|
};
|
||||||
@@ -92,7 +92,7 @@ pub fn assets(input: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
// Generate documentation showing the original asset definition
|
// Generate documentation showing the original asset definition
|
||||||
let doc = format!(
|
let doc = format!(
|
||||||
"This is an `asset!`\n```notrust\n{} {{\n\tsource: \"{}\",\n\ttarget: \"{}\"\n}}\n```",
|
"This is an `asset!`\n```notrust\n{} {{\n\tsource: \"{:?}\",\n\ttarget: \"{}\"\n}}\n```",
|
||||||
name, source, target
|
name, source, target
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ pub fn assets(input: TokenStream) -> TokenStream {
|
|||||||
const URL_PREFIX: &'static str = #prefix;
|
const URL_PREFIX: &'static str = #prefix;
|
||||||
const URL_POSTFIX: &'static str = #target;
|
const URL_POSTFIX: &'static str = #target;
|
||||||
const URL: &'static str = concat!(#prefix, #target);
|
const URL: &'static str = concat!(#prefix, #target);
|
||||||
const BYTES: &'static [u8] = include_bytes!(#source);
|
const BYTES: &'static [u8] = #source;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -115,9 +115,20 @@ pub fn assets(input: TokenStream) -> TokenStream {
|
|||||||
let router_fn = if let Some(router_name) = &input.router {
|
let router_fn = if let Some(router_name) = &input.router {
|
||||||
let route_definitions = input.assets.iter().map(|asset| {
|
let route_definitions = input.assets.iter().map(|asset| {
|
||||||
let name = &asset.name;
|
let name = &asset.name;
|
||||||
|
|
||||||
|
let headers = asset
|
||||||
|
.headers
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| quote! { #x })
|
||||||
|
.unwrap_or(quote! { [] });
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
.route(#name::URL_POSTFIX, ::axum::routing::get(|| async {
|
.route(#name::URL_POSTFIX, ::axum::routing::get(|| async {
|
||||||
(::axum::http::StatusCode::OK, #name::BYTES)
|
(
|
||||||
|
::axum::http::StatusCode::OK,
|
||||||
|
#headers,
|
||||||
|
#name::BYTES
|
||||||
|
)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -159,8 +170,9 @@ struct AssetsInput {
|
|||||||
/// Represents a single asset definition within the macro
|
/// Represents a single asset definition within the macro
|
||||||
struct AssetDefinition {
|
struct AssetDefinition {
|
||||||
name: Ident,
|
name: Ident,
|
||||||
source: String,
|
source: Expr,
|
||||||
target: String,
|
target: String,
|
||||||
|
headers: Option<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for AssetsInput {
|
impl Parse for AssetsInput {
|
||||||
@@ -214,26 +226,60 @@ impl Parse for AssetDefinition {
|
|||||||
let content;
|
let content;
|
||||||
braced!(content in input);
|
braced!(content in input);
|
||||||
|
|
||||||
// Parse "source:"
|
// Parse fields in any order
|
||||||
let _source_ident: Ident = content.parse()?;
|
let mut source: Option<Expr> = None;
|
||||||
let _colon1: Token![:] = content.parse()?;
|
let mut target: Option<String> = None;
|
||||||
let source_lit: LitStr = content.parse()?;
|
let mut headers: Option<Expr> = None;
|
||||||
let source = source_lit.value();
|
|
||||||
let _comma1: Token![,] = content.parse()?;
|
|
||||||
|
|
||||||
// Parse "target:"
|
while !content.is_empty() {
|
||||||
let _target_ident: Ident = content.parse()?;
|
// Parse field name
|
||||||
let _colon2: Token![:] = content.parse()?;
|
let field_name: Ident = content.parse()?;
|
||||||
let target_lit: LitStr = content.parse()?;
|
let _colon: Token![:] = content.parse()?;
|
||||||
let target = target_lit.value();
|
|
||||||
|
|
||||||
// Optional trailing comma
|
// Parse field value based on name
|
||||||
let _ = content.parse::<Token![,]>();
|
match field_name.to_string().as_str() {
|
||||||
|
"source" => {
|
||||||
|
if source.is_some() {
|
||||||
|
return Err(syn::Error::new(field_name.span(), "duplicate 'source' field"));
|
||||||
|
}
|
||||||
|
source = Some(content.parse()?);
|
||||||
|
}
|
||||||
|
"target" => {
|
||||||
|
if target.is_some() {
|
||||||
|
return Err(syn::Error::new(field_name.span(), "duplicate 'target' field"));
|
||||||
|
}
|
||||||
|
let target_lit: LitStr = content.parse()?;
|
||||||
|
target = Some(target_lit.value());
|
||||||
|
}
|
||||||
|
"headers" => {
|
||||||
|
if headers.is_some() {
|
||||||
|
return Err(syn::Error::new(field_name.span(), "duplicate 'headers' field"));
|
||||||
|
}
|
||||||
|
headers = Some(content.parse()?);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(syn::Error::new(
|
||||||
|
field_name.span(),
|
||||||
|
format!("unknown field '{}', expected 'source', 'target', or 'headers'", field_name)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse comma if not at end
|
||||||
|
if !content.is_empty() {
|
||||||
|
content.parse::<Token![,]>()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate required fields
|
||||||
|
let source = source.ok_or_else(|| syn::Error::new(name.span(), "missing required field 'source'"))?;
|
||||||
|
let target = target.ok_or_else(|| syn::Error::new(name.span(), "missing required field 'target'"))?;
|
||||||
|
|
||||||
Ok(AssetDefinition {
|
Ok(AssetDefinition {
|
||||||
name,
|
name,
|
||||||
source,
|
source,
|
||||||
target,
|
target,
|
||||||
|
headers,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use macro_sass::sass;
|
use assetserver::Asset;
|
||||||
use maud::{DOCTYPE, Markup, PreEscaped, Render, html};
|
use maud::{DOCTYPE, Markup, PreEscaped, Render, html};
|
||||||
|
|
||||||
use crate::components::misc::FarLink;
|
use crate::{components::misc::FarLink, routes::assets::Styles_Main};
|
||||||
|
|
||||||
pub struct PageMetadata {
|
pub struct PageMetadata {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
@@ -30,15 +30,12 @@ impl Render for PageMetadata {
|
|||||||
meta property="og:description" content=(description) {}
|
meta property="og:description" content=(description) {}
|
||||||
meta property="twitter:description" content=(description) {}
|
meta property="twitter:description" content=(description) {}
|
||||||
|
|
||||||
|
|
||||||
meta content=(image) property="og:image" {}
|
meta content=(image) property="og:image" {}
|
||||||
link rel="shortcut icon" href=(image) type="image/x-icon" {}
|
link rel="shortcut icon" href=(image) type="image/x-icon" {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const CSS: &str = sass!("css/main.scss");
|
|
||||||
|
|
||||||
pub struct BasePage<T: Render>(pub PageMetadata, pub T);
|
pub struct BasePage<T: Render>(pub PageMetadata, pub T);
|
||||||
|
|
||||||
impl<T: Render> Render for BasePage<T> {
|
impl<T: Render> Render for BasePage<T> {
|
||||||
@@ -54,9 +51,11 @@ impl<T: Render> Render for BasePage<T> {
|
|||||||
meta content="text/html; charset=UTF-8" http-equiv="content-type" {}
|
meta content="text/html; charset=UTF-8" http-equiv="content-type" {}
|
||||||
meta property="og:type" content="website" {}
|
meta property="og:type" content="website" {}
|
||||||
|
|
||||||
|
link rel="stylesheet" href=(Styles_Main::URL) {}
|
||||||
|
|
||||||
|
|
||||||
(meta)
|
(meta)
|
||||||
title { (PreEscaped(meta.title.clone())) }
|
title { (PreEscaped(meta.title.clone())) }
|
||||||
style { (PreEscaped(CSS)) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
|||||||
@@ -1,27 +1,50 @@
|
|||||||
use assetserver::Asset;
|
use assetserver::Asset;
|
||||||
|
use axum::http::header;
|
||||||
use macro_assets::assets;
|
use macro_assets::assets;
|
||||||
|
use macro_sass::sass;
|
||||||
|
|
||||||
assets! {
|
assets! {
|
||||||
prefix: "/assets"
|
prefix: "/assets"
|
||||||
router: asset_router()
|
router: asset_router()
|
||||||
|
|
||||||
|
//
|
||||||
|
// MARK: styles
|
||||||
|
//
|
||||||
|
|
||||||
|
Styles_Main {
|
||||||
|
source: sass!("css/main.scss").as_bytes(),
|
||||||
|
target: "/css/main.css",
|
||||||
|
headers: [
|
||||||
|
(header::CONTENT_TYPE, "text/css")
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// MARK: images
|
// MARK: images
|
||||||
//
|
//
|
||||||
|
|
||||||
Image_Cover {
|
Image_Cover {
|
||||||
source: "../../assets/images/cover-small.jpg",
|
source: include_bytes!("../../assets/images/cover-small.jpg"),
|
||||||
target: "/img/face.jpg"
|
target: "/img/face.jpg",
|
||||||
|
headers: [
|
||||||
|
(header::CONTENT_TYPE, "image/jpg")
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
Image_Betalupi {
|
Image_Betalupi {
|
||||||
source: "../../assets/images/betalupi-map.png",
|
source: include_bytes!("../../assets/images/betalupi-map.png"),
|
||||||
target: "/img/betalupi.png"
|
target: "/img/betalupi.png",
|
||||||
|
headers: [
|
||||||
|
(header::CONTENT_TYPE, "image/png")
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
Image_Icon {
|
Image_Icon {
|
||||||
source: "../../assets/images/icon.png",
|
source: include_bytes!("../../assets/images/icon.png"),
|
||||||
target: "/img/icon.png"
|
target: "/img/icon.png",
|
||||||
|
headers: [
|
||||||
|
(header::CONTENT_TYPE, "image/png")
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -29,33 +52,51 @@ assets! {
|
|||||||
//
|
//
|
||||||
|
|
||||||
FiraCode_Bold_woff2 {
|
FiraCode_Bold_woff2 {
|
||||||
source: "../../assets/fonts/fira/FiraCode-Bold.woff2",
|
source: include_bytes!("../../assets/fonts/fira/FiraCode-Bold.woff2"),
|
||||||
target: "/fonts/FiraCode-Bold.woff2"
|
target: "/fonts/FiraCode-Bold.woff2",
|
||||||
|
headers: [
|
||||||
|
(header::CONTENT_TYPE, "application/font-woff2")
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
FiraCode_Light_woff2 {
|
FiraCode_Light_woff2 {
|
||||||
source: "../../assets/fonts/fira/FiraCode-Light.woff2",
|
source: include_bytes!("../../assets/fonts/fira/FiraCode-Light.woff2"),
|
||||||
target: "/fonts/FiraCode-Light.woff2"
|
target: "/fonts/FiraCode-Light.woff2",
|
||||||
|
headers: [
|
||||||
|
(header::CONTENT_TYPE, "application/font-woff2")
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
FiraCode_Medium_woff2 {
|
FiraCode_Medium_woff2 {
|
||||||
source: "../../assets/fonts/fira/FiraCode-Medium.woff2",
|
source: include_bytes!("../../assets/fonts/fira/FiraCode-Medium.woff2"),
|
||||||
target: "/fonts/FiraCode-Medium.woff2"
|
target: "/fonts/FiraCode-Medium.woff2",
|
||||||
|
headers: [
|
||||||
|
(header::CONTENT_TYPE, "application/font-woff2")
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
FiraCode_Regular_woff2 {
|
FiraCode_Regular_woff2 {
|
||||||
source: "../../assets/fonts/fira/FiraCode-Regular.woff2",
|
source: include_bytes!("../../assets/fonts/fira/FiraCode-Regular.woff2"),
|
||||||
target: "/fonts/FiraCode-Regular.woff2"
|
target: "/fonts/FiraCode-Regular.woff2",
|
||||||
|
headers: [
|
||||||
|
(header::CONTENT_TYPE, "application/font-woff2")
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
FiraCode_SemiBold_woff2 {
|
FiraCode_SemiBold_woff2 {
|
||||||
source: "../../assets/fonts/fira/FiraCode-SemiBold.woff2",
|
source: include_bytes!("../../assets/fonts/fira/FiraCode-SemiBold.woff2"),
|
||||||
target: "/fonts/FiraCode-SemiBold.woff2"
|
target: "/fonts/FiraCode-SemiBold.woff2",
|
||||||
|
headers: [
|
||||||
|
(header::CONTENT_TYPE, "application/font-woff2")
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
FiraCode_VF_woff2 {
|
FiraCode_VF_woff2 {
|
||||||
source: "../../assets/fonts/fira/FiraCode-VF.woff2",
|
source: include_bytes!("../../assets/fonts/fira/FiraCode-VF.woff2"),
|
||||||
target: "/fonts/FiraCode-VF.woff2"
|
target: "/fonts/FiraCode-VF.woff2",
|
||||||
|
headers: [
|
||||||
|
(header::CONTENT_TYPE, "application/font-woff2")
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -63,32 +104,50 @@ assets! {
|
|||||||
//
|
//
|
||||||
|
|
||||||
Fa_Brands_woff2 {
|
Fa_Brands_woff2 {
|
||||||
source: "../../assets/fonts/fa/fa-brands-400.woff2",
|
source: include_bytes!("../../assets/fonts/fa/fa-brands-400.woff2"),
|
||||||
target: "/fonts/fa/fa-brands-400.woff2"
|
target: "/fonts/fa/fa-brands-400.woff2",
|
||||||
|
headers: [
|
||||||
|
(header::CONTENT_TYPE, "application/font-woff2")
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
Fa_Regular_woff2 {
|
Fa_Regular_woff2 {
|
||||||
source: "../../assets/fonts/fa/fa-regular-400.woff2",
|
source: include_bytes!("../../assets/fonts/fa/fa-regular-400.woff2"),
|
||||||
target: "/fonts/fa/fa-regular-400.woff2"
|
target: "/fonts/fa/fa-regular-400.woff2",
|
||||||
|
headers: [
|
||||||
|
(header::CONTENT_TYPE, "application/font-woff2")
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
Fa_Solid_woff2 {
|
Fa_Solid_woff2 {
|
||||||
source: "../../assets/fonts/fa/fa-solid-900.woff2",
|
source: include_bytes!("../../assets/fonts/fa/fa-solid-900.woff2"),
|
||||||
target: "/fonts/fa/fa-solid-900.woff2"
|
target: "/fonts/fa/fa-solid-900.woff2",
|
||||||
|
headers: [
|
||||||
|
(header::CONTENT_TYPE, "application/font-woff2")
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
Fa_Brands_ttf {
|
Fa_Brands_ttf {
|
||||||
source: "../../assets/fonts/fa/fa-brands-400.ttf",
|
source: include_bytes!("../../assets/fonts/fa/fa-brands-400.ttf"),
|
||||||
target: "/fonts/fa/fa-brands-400.ttf"
|
target: "/fonts/fa/fa-brands-400.ttf",
|
||||||
|
headers: [
|
||||||
|
(header::CONTENT_TYPE, "application/font-ttf")
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
Fa_Regular_ttf {
|
Fa_Regular_ttf {
|
||||||
source: "../../assets/fonts/fa/fa-regular-400.ttf",
|
source: include_bytes!("../../assets/fonts/fa/fa-regular-400.ttf"),
|
||||||
target: "/fonts/fa/fa-regular-400.ttf"
|
target: "/fonts/fa/fa-regular-400.ttf",
|
||||||
|
headers: [
|
||||||
|
(header::CONTENT_TYPE, "application/font-ttf")
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
Fa_Solid_ttf {
|
Fa_Solid_ttf {
|
||||||
source: "../../assets/fonts/fa/fa-solid-900.ttf",
|
source: include_bytes!("../../assets/fonts/fa/fa-solid-900.ttf"),
|
||||||
target: "/fonts/fa/fa-solid-900.ttf"
|
target: "/fonts/fa/fa-solid-900.ttf",
|
||||||
|
headers: [
|
||||||
|
(header::CONTENT_TYPE, "application/font-ttf")
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use axum::routing::get;
|
|||||||
use tracing::info;
|
use tracing::info;
|
||||||
use utoipa::OpenApi;
|
use utoipa::OpenApi;
|
||||||
|
|
||||||
mod assets;
|
pub mod assets;
|
||||||
mod betalupi;
|
mod betalupi;
|
||||||
mod index;
|
mod index;
|
||||||
mod links;
|
mod links;
|
||||||
|
|||||||
Reference in New Issue
Block a user