The (very WIP) home of the next versions of my web presences

lx: `View` -> `Component`

I will follow this with updates to the layout of templates as well:
these are really what I had done with “components” historically via
macros.

+75 -262
+3 -3
lx/src/archive.rs
··· 5 5 use thiserror::Error; 6 6 7 7 use crate::{ 8 - page::{Item, Post, PostLink}, 9 - templates::view::{self, View}, 8 + page::{Item, PostLink}, 9 + templates::component::Component, 10 10 }; 11 11 12 12 /// A data structure that maps each post to Y -> M -> D -> posts, preserving the order of ··· 44 44 } 45 45 } 46 46 47 - impl<'e> View for Archive<'e> { 47 + impl<'e> Component for Archive<'e> { 48 48 const VIEW_NAME: &'static str = "archive"; 49 49 50 50 fn view(&self, env: &Environment) -> Result<String, minijinja::Error> {
+2 -5
lx/src/data/config.rs
··· 52 52 use serde::{Deserialize, Serialize}; 53 53 use thiserror::Error; 54 54 55 - use crate::{ 56 - data::email::Email, 57 - templates::view::{self, View}, 58 - }; 55 + use crate::{data::email::Email, templates::component::Component}; 59 56 60 57 #[derive(Serialize, Deserialize, Debug)] 61 58 pub struct Config { ··· 123 120 } 124 121 125 122 // TODO: maybe move this elsewhere? 126 - impl View for NavItem { 123 + impl Component for NavItem { 127 124 const VIEW_NAME: &'static str = "nav-item"; 128 125 129 126 fn view(&self, env: &Environment) -> Result<String, minijinja::Error> {
+3 -3
lx/src/data/item/mod.rs
··· 15 15 use crate::{ 16 16 archive::Archive, 17 17 page::{self, Item}, 18 - templates::view::{self, View}, 18 + templates::component::Component, 19 19 }; 20 20 21 21 use self::cascade::Cascade; ··· 233 233 } 234 234 } 235 235 236 - impl View for Qualifiers { 236 + impl Component for Qualifiers { 237 237 const VIEW_NAME: &'static str = "qualifiers"; 238 238 239 239 fn view(&self, env: &Environment) -> Result<String, minijinja::Error> { ··· 306 306 archive: Archive<'a>, 307 307 } 308 308 309 - impl<'a> View for BookView<'a> { 309 + impl<'a> Component for BookView<'a> { 310 310 const VIEW_NAME: &'static str = "book"; 311 311 312 312 fn view(&self, env: &Environment) -> Result<String, minijinja::Error> {
+8 -1
lx/src/data/item/serial.rs
··· 11 11 use serde::{Deserialize, Serialize}; 12 12 use thiserror::Error; 13 13 14 - use crate::data::{image::serial::Image, item::nice_list}; 14 + use crate::{ 15 + data::{image::serial::Image, item::nice_list}, 16 + templates::component::Component, 17 + }; 15 18 16 19 #[derive(Deserialize, Debug, Default)] 17 20 pub struct Item { ··· 89 92 pub discusses: Vec<String>, 90 93 pub disclosure: Option<String>, 91 94 pub retraction: Option<Retraction>, 95 + } 96 + 97 + impl Component for Qualifiers { 98 + const VIEW_NAME: &'static str = "qualifiers"; 92 99 } 93 100 94 101 #[derive(Serialize, Deserialize, Clone, Debug)]
+2 -2
lx/src/page.rs
··· 3 3 config::Config, 4 4 item::{self, Metadata, Slug, cascade::Cascade, serial}, 5 5 }, 6 - templates::view::View, 6 + templates::component::Component, 7 7 }; 8 8 use camino::{Utf8Path, Utf8PathBuf}; 9 9 use chrono::{DateTime, FixedOffset}; ··· 254 254 } 255 255 } 256 256 257 - impl<'e> View for PostLink<'e> { 257 + impl<'e> Component for PostLink<'e> { 258 258 const VIEW_NAME: &'static str = "post-link"; 259 259 } 260 260
+2 -2
lx/src/templates/functions.rs
··· 9 9 use crate::{ 10 10 data::{config::Config, image::Image, item::Metadata}, 11 11 page::{self, RootedPath}, 12 - templates::view::{self, View}, 12 + templates::component::{self, Component}, 13 13 }; 14 14 15 15 pub(crate) fn add_all(env: &mut minijinja::Environment<'_>) { ··· 178 178 } 179 179 } 180 180 181 - impl View for Label { 181 + impl Component for Label { 182 182 const VIEW_NAME: &'static str = "twitter-label"; 183 183 184 184 fn view(&self, env: &minijinja::Environment) -> Result<String, minijinja::Error> {
+1 -1
lx/src/templates/mod.rs
··· 1 + pub mod component; 1 2 mod filters; 2 3 mod functions; 3 - pub mod view; 4 4 5 5 use std::io::Write; 6 6
+2 -2
lx/src/templates/view.rs lx/src/templates/component.rs
··· 1 1 use minijinja::Environment; 2 2 use serde::Serialize; 3 3 4 - pub(crate) trait View: Serialize + Sized { 4 + pub(crate) trait Component: Serialize + Sized { 5 5 const VIEW_NAME: &'static str; 6 6 7 7 fn view(&self, env: &Environment) -> Result<String, minijinja::Error> { ··· 9 9 } 10 10 11 11 fn template() -> String { 12 - format!("views/{}.jinja", Self::VIEW_NAME) 12 + format!("components/{}.jinja", Self::VIEW_NAME) 13 13 } 14 14 }
+42
sites/v6/_ui/components/archive.jinja
··· 1 + <section class="archive"> 2 + <ul class='archive-list'> 3 + {%- for (year, months) in archive %} 4 + <li class='year'> 5 + <div class='year-info sticky'> 6 + <h2 class='year-title date'>{{year}}</h2> 7 + </div> 8 + <ul class='year-items'> 9 + {%- for (month, days) in months %} 10 + <li class='month'> 11 + {# TODO: `month.name` is not yet callable. #} 12 + <h3 class='month-title date'><span class='month-sticky'>{{month.name()}}</span></h3> 13 + <ul class='month-items'> 14 + {%- for (day, post_links) in days %} 15 + <li class='day'> 16 + {# TODO: `day.name` is not yet callable. #} 17 + <h4 class='day-title date'><span class='day-sticky'>{{day.name()}}</span></h4> 18 + <ul class='day-items'> 19 + {%- for post_link in post_links %} 20 + <li class='item'> 21 + <h5 class='item-title'>{{post_link()}}</h5> 22 + {% if item.data.subtitle -%} 23 + <p class='item-subtitle'>{{item.data.subtitle | safe}}</p> 24 + {%- endif %} 25 + {%- if not item.data.title %} 26 + <article class='item-content article-content'> 27 + {{item.templateContent | safe}} 28 + </article> 29 + {% endif -%} 30 + </li> 31 + {% endfor -%} 32 + </ul> 33 + </li> 34 + {% endfor -%} 35 + </ul> 36 + </li> 37 + {%- endfor -%} 38 + </ul> 39 + </li> 40 + {% endfor -%} 41 + </ul> 42 + </section>
-5
sites/v6/_ui/components/archive.njk
··· 1 - {% macro archive(archive_items, context) %} 2 - <section class='archive {{context}}'> 3 - TODO: an archive! 4 - </section> 5 - {% endmacro %}
-184
sites/v6/_ui/components/atom.jinja
··· 1 - {%- macro entries(items, config, includeReplyViaEmail = true, includeThanksForReading = true) -%} 2 - {# invalid without date #} 3 - {%- if items is not undefined and items.length > 0 -%} 4 - {%- for item in items | withValidDate | take(25) -%} 5 - <entry> 6 - {#- Invalid to send an item without title or description -#} 7 - {% set url -%} 8 - {%- if item.data.feedId -%} 9 - {{item.data.feedId | absoluteUrl(config.url)}} 10 - {%- else -%} 11 - {{item.url | absoluteUrl(config.url)}} 12 - {%- endif -%} 13 - {%- endset -%} 14 - <id>{{url}}</id> 15 - {%- set entryTitle -%} 16 - {%- if item.data.title -%} 17 - {{item.data.title | striptags}} 18 - {%- else -%} 19 - {% localeDate item.date, 'yyyy.MM.dd.HHmm' -%} 20 - {%- endif -%} 21 - {%- endset -%} 22 - <title type="html">[{{item.inputPath | toRootCollection}}] {{entryTitle}}</title> 23 - {%- set updated -%} 24 - {% if item.data.updated -%} 25 - {{item.data.updated | isoDate}} 26 - {%- else -%} 27 - {{item.date | isoDate}} 28 - {%- endif -%} 29 - {%- endset -%} 30 - <published>{{item.date | isoDate}}</published> 31 - <updated>{{updated}}</updated> 32 - <link href='{{url}}'/> 33 - {%- set summary -%} 34 - {%- if item.data.summary -%} 35 - {{-item.data.summary-}} 36 - {%- elif item.data.book.review -%} 37 - {{-item.data.book.review.rating | safe-}}: 38 - {{item.data.book.review.summary | striptags(true) | safe-}} 39 - {%- elif item.data.subtitle -%} 40 - {{-item.data.subtitle-}} 41 - {%- else -%} 42 - {{-item.templateContent | excerpt -}} 43 - {%- endif -%} 44 - {%- endset %} 45 - <summary type="html">{{- summary -}}</summary> 46 - <content type="html"> 47 - <![CDATA[ 48 - {%- if item.data.feedOnly -%} 49 - <p><em>Psst: this is a feed-only item which will <em>never</em> appear on the regular site!</em></p> 50 - {%- endif -%} 51 - 52 - {%- if item.data.subtitle -%} 53 - <p><i>{{- item.data.subtitle | safe -}}</i></p> 54 - {%- endif -%} 55 - 56 - {%- if item.data.qualifiers.retraction -%} 57 - {{- item.data.qualifiers.retraction | safe -}} 58 - {%- endif -%} 59 - 60 - {%- if item.data.qualifiers.audience -%} 61 - {{- item.data.qualifiers.audience | safe -}} 62 - {%- endif -%} 63 - 64 - {%- if item.data.qualifiers.disclosure -%} 65 - {{- item.data.qualifiers.disclosure | safe -}} 66 - {%- endif -%} 67 - 68 - {%- if item.data.qualifiers.context -%} 69 - {{- item.data.qualifiers.context | safe -}} 70 - {%- endif -%} 71 - 72 - {%- if item.data.qualifiers.epistemic -%} 73 - {{- item.data.qualifiers.epistemic | safe -}} 74 - {%- endif -%} 75 - 76 - {%- if item.data.qualifiers.discusses -%} 77 - {{- item.data.qualifiers.discusses | safe -}} 78 - {%- endif -%} 79 - 80 - {%- if updates -%} 81 - <p><i>Meaningful changes since creating this page:</i></p> 82 - <ul> 83 - {%- for update in updates -%} 84 - <li> 85 - <i>{% localeDate update.at, 'MMMM d, yyyy' %}:</i> 86 - {{update.changes | safe}} 87 - </li> 88 - {%- endfor -%} 89 - </ul> 90 - {%- endif -%} 91 - 92 - {%- if item.data.qualifiers -%} 93 - <hr/> 94 - {%- endif -%} 95 - 96 - {%- if item.data.book and item.data.book.review -%} 97 - {%- set book = item.data.book -%} 98 - 99 - {%- set book_desc -%} 100 - {%- if book.link -%} 101 - <p><a href="{{book.link | safe}}"><cite>{{book.title | safe}}</cite></a>, {{book.author | safe}} ({{book.year | safe}})</p> 102 - {%- else -%} 103 - <p><cite>{{book.title | safe}}</cite>, {{book.author | safe}} ({{book.year | safe}})</p> 104 - {%- endif -%} 105 - {%- endset -%} 106 - 107 - {%- set book_review -%} 108 - {%- if book.review -%} 109 - <p><b>{{book.review.rating | safe}}:</b> {{book.review.summary | safe -}}</p> 110 - {%- endif -%} 111 - {%- endset -%} 112 - 113 - {%- if book.cover -%} 114 - <figure> 115 - <img src="{{book.cover | resolvedImage | safe}}" alt="cover art for {{book.title | safe}}" /> 116 - <figcaption> 117 - {{-book_desc | safe-}} 118 - {{-book_review | safe-}} 119 - </figcaption> 120 - </figure> 121 - {%- else -%} 122 - {{-book_desc | safe-}} 123 - {{-book_review | safe-}} 124 - {%- endif -%} 125 - {%- endif -%} 126 - 127 - {{-item.templateContent | safe-}} 128 - 129 - {%- if item.related.length > 0 -%} 130 - <h2>Related:</h2> 131 - <ul class='section-content'> 132 - {%- for item in related %} 133 - <li>{{item | inlineMd | safe}}</li> 134 - {%- endfor -%} 135 - </ul> 136 - {%- endif -%} 137 - {%- if item.data.thanks -%} 138 - <hr/> 139 - <p><strong>Thanks:</strong> {{item.data.thanks | safe}}</p> 140 - {%- endif -%} 141 - <hr/> 142 - {%- if includeThanksForReading -%} 143 - <p> 144 - Thanks for reading my feed! Thoughts, comments, or questions? 145 - {% if includeReplyViaEmail -%} 146 - <a href="mailto:{{config.author.email}}?subject=Re%3A%20{{entryTitle | urlencode}}">Shoot me an email</a> 147 - {%- if item.data.discuss is defined -%} 148 - , or leave a comment on 149 - <a href="{{item.data.discuss.hn}}">Hacker News</a> or 150 - <a href="{{item.data.discuss.lobsters}}">lobste.rs</a>. 151 - {%- else -%} 152 - ! 153 - {%- endif -%} 154 - {%- else -%} 155 - {%- if item.data.discuss is defined -%} 156 - Leave a comment on 157 - <a href="{{item.data.discuss.hn}}">Hacker News</a> or 158 - <a href="{{item.data.discuss.lobsters}}">lobste.rs</a>. 159 - {%- endif -%} 160 - {%- endif -%} 161 - </p> 162 - {%- endif -%} 163 - ]]> 164 - </content> 165 - {%- include 'blocks/rss-author.njk' -%} 166 - {#- <comments>TODO: Webmention!</comments> -#} 167 - {%- for tag in item.data.tags -%} 168 - <category term="{{tag}}"/> 169 - {%- endfor -%} 170 - {%- set image -%} 171 - {%- if item.data.book and item.data.book.cover -%} 172 - {{-item.data.book.cover | resolvedImage | safe-}} 173 - {%- elif item.data.image -%} 174 - {{-item.image | resolvedImage | safe-}} 175 - {%- endif -%} 176 - {%- endset -%} 177 - {%- if image -%} 178 - <link rel='enclosure' href='{{image | safe}}'/> 179 - <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="{{image | safe}}"/> 180 - {%- endif -%} 181 - </entry> 182 - {%- endfor -%} 183 - {%- endif -%} 184 - {%- endmacro -%}
-5
sites/v6/_ui/components/feed-author.jinja
··· 1 - <author> 2 - <name>{{config.author.name}}</name> 3 - <email>{{config.author.email}}</email> 4 - <uri>{{config.url}}</uri> 5 - </author>
sites/v6/_ui/components/note.jinja sites/v6/_ui/macros/note.jinja
+9
sites/v6/_ui/includes/feed-author.jinja
··· 1 + {# 2 + TODO: should this be a component, a macro, something else? I definitely do not like 3 + having it with implicit context of `config`. 4 + #} 5 + <author> 6 + <name>{{config.author.name}}</name> 7 + <email>{{config.author.email}}</email> 8 + <uri>{{config.url}}</uri> 9 + </author>
-48
sites/v6/_ui/views/archive.jinja
··· 1 - {# TODO: this doesn't need to be a macro, but can still be callable via `View`. #} 2 - {# TODO: this (pulled directly from v5) needs to be reworked a bit in terms of the new 3 - data structures I am using here. The “view” for an `Archive` may end up being best 4 - represented by something other than the `Archive` type’s own use of the `IndexMap`, 5 - like an iterator over it or such? 6 - #} 7 - {#{% macro list(collection, idByCollection=false) %}#} 8 - <ul class='archive-list'> 9 - {%- for (year, months) in archive %} 10 - <li class='year'> 11 - <div class='year-info sticky'> 12 - <h2 class='year-title date'>{{year}}</h2> 13 - </div> 14 - <ul class='year-items'> 15 - {%- for (month, days) in months %} 16 - <li class='month'> 17 - {# TODO: `month.name` is not yet callable. #} 18 - <h3 class='month-title date'><span class='month-sticky'>{{month.name()}}</span></h3> 19 - <ul class='month-items'> 20 - {%- for (day, post_links) in days %} 21 - <li class='day'> 22 - {# TODO: `day.name` is not yet callable. #} 23 - <h4 class='day-title date'><span class='day-sticky'>{{day.name()}}</span></h4> 24 - <ul class='day-items'> 25 - {%- for post_link in post_links %} 26 - <li class='item'> 27 - <h5 class='item-title'>{{post_link()}}</h5> 28 - {% if item.data.subtitle -%} 29 - <p class='item-subtitle'>{{item.data.subtitle | safe}}</p> 30 - {%- endif %} 31 - {%- if not item.data.title %} 32 - <article class='item-content article-content'> 33 - {{item.templateContent | safe}} 34 - </article> 35 - {% endif -%} 36 - </li> 37 - {% endfor -%} 38 - </ul> 39 - </li> 40 - {% endfor -%} 41 - </ul> 42 - </li> 43 - {%- endfor -%} 44 - </ul> 45 - </li> 46 - {% endfor -%} 47 - </ul> 48 - {#{% endmacro %}#}
+1 -1
sites/v6/_ui/views/book.jinja sites/v6/_ui/components/book.jinja
··· 1 1 <section class='book'> 2 - 2 + {# TODO: actually render the contents of the `Book` item. #} 3 3 </section> 4 4 5 5 {#
sites/v6/_ui/views/nav-item.jinja sites/v6/_ui/components/nav-item.jinja
sites/v6/_ui/views/post-link.jinja sites/v6/_ui/components/post-link.jinja
sites/v6/_ui/views/qualifiers.jinja sites/v6/_ui/components/qualifiers.jinja