My personal site cherry.computer
htmx tailwind axum askama

feat: link to source code in footer

cherry.computer 361bde4c 94dde481

verified
+46 -5
+1 -1
justfile
··· 8 watchexec --restart --watch esbuild.js npm start 9 10 [working-directory('server')] 11 - serve-rs args="" $RUST_LOG=env('RUST_LOG', 'debug,selectors=warn,html5ever=warn'): 12 watchexec --restart --ignore "target/**" cargo run {{ args }}
··· 8 watchexec --restart --watch esbuild.js npm start 9 10 [working-directory('server')] 11 + serve-rs args="" $RUST_LOG=env('RUST_LOG', 'debug,selectors=warn,html5ever=warn') $MYIVO_GIT_SHA=`jj log -r@ --no-graph -T commit_id`: 12 watchexec --restart --ignore "target/**" cargo run {{ args }}
+11 -4
server/src/main.rs
··· 1 mod scrapers; 2 mod templates; 3 4 - use std::{net::SocketAddr, sync::Arc}; 5 6 use crate::scrapers::{MediaType, apple_music::AppleMusicClient}; 7 #[cfg(debug_assertions)] 8 use crate::templates::am_auth_flow::AuthFlowTemplate; 9 use crate::templates::{ 10 - index::{IndexOptions, RootTemplate}, 11 media::{MediaTemplate, fetch_media_of_type}, 12 }; 13 ··· 27 #[derive(Clone)] 28 struct AppState { 29 apple_music_client: Arc<AppleMusicClient>, 30 } 31 32 #[tokio::main] ··· 34 tracing_subscriber::fmt::init(); 35 36 let apple_music_client = Arc::new(AppleMusicClient::new()?); 37 - let state = AppState { apple_music_client }; 38 39 let app = Router::new() 40 .route("/", get(render_index_handler)) ··· 63 Query(options): Query<IndexOptions>, 64 State(state): State<AppState>, 65 ) -> impl IntoResponse { 66 - let template = RootTemplate::new(state.apple_music_client, &options); 67 template.render().map(Html).map_err(|err| { 68 tracing::error!("failed to render index: {err:?}"); 69 StatusCode::INTERNAL_SERVER_ERROR
··· 1 mod scrapers; 2 mod templates; 3 4 + use std::{env, net::SocketAddr, sync::Arc}; 5 6 use crate::scrapers::{MediaType, apple_music::AppleMusicClient}; 7 #[cfg(debug_assertions)] 8 use crate::templates::am_auth_flow::AuthFlowTemplate; 9 use crate::templates::{ 10 + index::{IndexOptions, RootTemplate, Shas}, 11 media::{MediaTemplate, fetch_media_of_type}, 12 }; 13 ··· 27 #[derive(Clone)] 28 struct AppState { 29 apple_music_client: Arc<AppleMusicClient>, 30 + shas: Shas, 31 } 32 33 #[tokio::main] ··· 35 tracing_subscriber::fmt::init(); 36 37 let apple_music_client = Arc::new(AppleMusicClient::new()?); 38 + let shas = Shas { 39 + website: env::var("MYIVO_GIT_SHA").ok(), 40 + }; 41 + let state = AppState { 42 + apple_music_client, 43 + shas, 44 + }; 45 46 let app = Router::new() 47 .route("/", get(render_index_handler)) ··· 70 Query(options): Query<IndexOptions>, 71 State(state): State<AppState>, 72 ) -> impl IntoResponse { 73 + let template = RootTemplate::new(state.apple_music_client, state.shas, &options); 74 template.render().map(Html).map_err(|err| { 75 tracing::error!("failed to render index: {err:?}"); 76 StatusCode::INTERNAL_SERVER_ERROR
+8
server/src/templates/index.rs
··· 15 16 type MediaList = [(MediaType, Option<Media>); 3]; 17 18 #[derive(Template, Debug, Clone)] 19 #[template(path = "index.html")] 20 pub struct RootTemplate { 21 media: MediaList, 22 consumption_verb: &'static str, 23 } 24 25 impl RootTemplate { 26 pub fn new( 27 apple_music_client: Arc<AppleMusicClient>, 28 #[allow(unused_variables)] options: &IndexOptions, 29 ) -> RootTemplate { 30 #[cfg(debug_assertions)] ··· 41 RootTemplate { 42 media, 43 consumption_verb, 44 } 45 } 46
··· 15 16 type MediaList = [(MediaType, Option<Media>); 3]; 17 18 + #[derive(Debug, Clone)] 19 + pub struct Shas { 20 + pub website: Option<String>, 21 + } 22 + 23 #[derive(Template, Debug, Clone)] 24 #[template(path = "index.html")] 25 pub struct RootTemplate { 26 media: MediaList, 27 consumption_verb: &'static str, 28 + shas: Shas, 29 } 30 31 impl RootTemplate { 32 pub fn new( 33 apple_music_client: Arc<AppleMusicClient>, 34 + shas: Shas, 35 #[allow(unused_variables)] options: &IndexOptions, 36 ) -> RootTemplate { 37 #[cfg(debug_assertions)] ··· 48 RootTemplate { 49 media, 50 consumption_verb, 51 + shas, 52 } 53 } 54
+26
server/templates/index.html
··· 54 </div> 55 <p class="font-serif text-3xl text-pink-50">Free Palestine 🇵🇸</p> 56 </div> 57 </div> 58 </body> 59 </html>
··· 54 </div> 55 <p class="font-serif text-3xl text-pink-50">Free Palestine 🇵🇸</p> 56 </div> 57 + <div class="bg-gray-800"> 58 + <div 59 + class="flex w-full justify-around px-5 py-2 leading-5 text-pink-50 italic" 60 + > 61 + <p> 62 + running on 63 + <a 64 + href="https://tangled.org/cherry.computer/nixos" 65 + target="_blank" 66 + class="text-pink-300 hover:text-pink-500" 67 + >NixOS</a 68 + > 69 + </p> 70 + {% if let Some(website_rev) = shas.website %} 71 + <p> 72 + site revision 73 + <a 74 + href="https://tangled.org/cherry.computer/website/tree/{{website_rev}}" 75 + target="_blank" 76 + class="text-pink-300 hover:text-pink-500" 77 + >{{ website_rev | fmt("{:.8}") }}</a 78 + > 79 + </p> 80 + {% endif %} 81 + </div> 82 + </div> 83 </div> 84 </body> 85 </html>