Tailwind for post_list

This commit is contained in:
Michal Vanko 2024-02-27 22:53:08 +01:00
parent 0cb8e84666
commit 8201312c26
12 changed files with 273 additions and 67 deletions

View File

@ -0,0 +1,9 @@
layout {
pane size=1 borderless=true {
plugin location="zellij:tab-bar"
}
pane
pane size=2 borderless=true {
plugin location="zellij:status-bar"
}
}

View File

@ -0,0 +1,25 @@
layout {
pane size=1 borderless=true {
plugin location="zellij:tab-bar"
}
pane split_direction="vertical" focus=true {
pane edit="src/main.rs"
pane split_direction="horizontal" size=60 {
just { args "server_dev"; }
just { args "test"; }
}
}
pane_template name="just" {
command "just"
start_suspended true
}
floating_panes {
pane {
command "just"
args "tailwind"
}
}
pane size=2 borderless=true {
plugin location="zellij:status-bar"
}
}

View File

@ -17,5 +17,6 @@ serde = "1.0.195"
serde_json = "1.0.111"
tokio = { version = "1.35.1", features = ["full"] }
tower-http = { version = "0.5.0", features = ["trace", "fs"] }
tower-livereload = "0.9.2"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

View File

@ -11,6 +11,10 @@ server_dev:
dev:
(just server_dev; just tailwind) | parallel
# Run dev server in watch mode
test:
cargo test
# Run server in production mode
prod:
cargo run --release

View File

@ -4,26 +4,20 @@ pub struct Link {
}
pub struct HeaderProps {
pub links: Vec<Link>,
pub back_link: Option<Link>,
}
impl Default for HeaderProps {
fn default() -> Self {
Self { back_link: None }
}
}
impl HeaderProps {
pub fn with_back_link(link: Link) -> Self {
Self {
links: vec![
Link {
href: "/".to_string(),
label: "Introduction".to_string(),
},
Link {
href: "/blog".to_string(),
label: "Blog".to_string(),
},
Link {
href: "/portfolio".to_string(),
label: "Portfolio".to_string(),
},
],
back_link: Some(link),
..Default::default()
}
}
}

View File

@ -1,5 +1,6 @@
use axum;
use tower_http::services::ServeDir;
use tower_livereload::LiveReloadLayer;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
mod components;
@ -25,6 +26,10 @@ async fn main() {
// build our application with a single route
let app = router::get_router().nest_service("/styles", ServeDir::new("styles"));
#[cfg(debug_assertions)]
let app = app.layer(LiveReloadLayer::new());
// run our app with hyper, listening globally on port 3080
let port = std::option_env!("PORT").unwrap_or("3080");
let addr = format!("0.0.0.0:{}", port);

View File

@ -4,7 +4,7 @@ use axum::{extract::Path, http::StatusCode};
use crate::{
components::{
site_footer::{render_site_footer, SiteFooter},
site_header::HeaderProps,
site_header::{HeaderProps, Link},
},
post_list::get_post_list,
post_parser::ParseResult,
@ -50,12 +50,21 @@ pub async fn render_post_list(tag: Option<Path<String>>) -> Result<PostListTempl
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
// TODO if we have a tag we want to go back to all posts, otherwise we don't
let header_props = match tag {
Some(_) => HeaderProps::with_back_link(Link {
href: "/blog".to_string(),
label: "All posts".to_string(),
}),
None => HeaderProps::default(),
};
Ok(PostListTemplate {
title: "Posts".to_owned(),
posts,
tag,
site_footer,
header_props: HeaderProps::default(),
header_props,
})
}

View File

@ -544,19 +544,188 @@ video {
--tw-backdrop-sepia: ;
}
.m-3 {
margin: 0.75rem;
}
.m-1 {
margin: 0.25rem;
}
.my-3 {
margin-top: 0.75rem;
margin-bottom: 0.75rem;
}
.my-5 {
margin-top: 1.25rem;
margin-bottom: 1.25rem;
}
.my-8 {
margin-top: 2rem;
margin-bottom: 2rem;
}
.my-10 {
margin-top: 2.5rem;
margin-bottom: 2.5rem;
}
.my-12 {
margin-top: 3rem;
margin-bottom: 3rem;
}
.mx-4 {
margin-left: 1rem;
margin-right: 1rem;
}
.mb-3 {
margin-bottom: 0.75rem;
}
.block {
display: block;
}
.inline {
display: inline;
}
.flex {
display: flex;
}
.h-0 {
height: 0px;
}
.min-h-full {
min-height: 100%;
}
.flex-grow {
flex-grow: 1;
}
.content-end {
align-content: flex-end;
}
.justify-end {
justify-content: flex-end;
}
.border-blue-200 {
--tw-border-opacity: 1;
border-color: rgb(191 219 254 / var(--tw-border-opacity));
}
.bg-blue-50 {
--tw-bg-opacity: 1;
background-color: rgb(239 246 255 / var(--tw-bg-opacity));
}
.bg-blue-800 {
--tw-bg-opacity: 1;
background-color: rgb(30 64 175 / var(--tw-bg-opacity));
}
.p-3 {
padding: 0.75rem;
}
.p-2 {
padding: 0.5rem;
}
.px-2 {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.px-4 {
padding-left: 1rem;
padding-right: 1rem;
}
.px-5 {
padding-left: 1.25rem;
padding-right: 1.25rem;
}
.pr-2 {
padding-right: 0.5rem;
}
.pr-3 {
padding-right: 0.75rem;
}
.text-right {
text-align: right;
}
.text-lg {
font-size: 1.125rem;
line-height: 1.75rem;
}
.text-base {
font-size: 1rem;
line-height: 1.5rem;
}
.text-2xl {
font-size: 1.5rem;
line-height: 2rem;
}
.text-sm {
font-size: 0.875rem;
line-height: 1.25rem;
}
.font-medium {
font-weight: 500;
}
.italic {
font-style: italic;
}
.text-gray-600 {
--tw-text-opacity: 1;
color: rgb(75 85 99 / var(--tw-text-opacity));
}
.text-blue-700 {
--tw-text-opacity: 1;
color: rgb(29 78 216 / var(--tw-text-opacity));
}
.text-blue-800 {
--tw-text-opacity: 1;
color: rgb(30 64 175 / var(--tw-text-opacity));
}
.text-gray-800 {
--tw-text-opacity: 1;
color: rgb(31 41 55 / var(--tw-text-opacity));
}
.drop-shadow-md {
--tw-drop-shadow: drop-shadow(0 4px 3px rgb(0 0 0 / 0.07)) drop-shadow(0 2px 2px rgb(0 0 0 / 0.06));
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
.filter {
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
.after\:content-\[\'\2c \'\]::after {
--tw-content: ',';
content: var(--tw-content);
}

View File

@ -33,7 +33,7 @@
<link rel="icon" type="image/svg+xml" href="/m-logo.svg" />
<link rel="icon" type="image/png" href="/m-logo-192.png" />
</head>
<body>
<body class="bg-blue-50">
{% include "site_header.html" %}
{% block content %} Placeholder {% endblock %}
{# footer, should be not dependant on the each individual handler but it should have it's own handler #}

View File

@ -11,7 +11,7 @@
<ul>
{% for post in posts %}
<li>
<li class="my-12">
{% include "post_preview_card.html" %} {#
<ArticlePreviewCard {article} {segment} /> #} {#
<ArticleFooter {article} {segment} /> #}

View File

@ -1,27 +1,29 @@
<article>
<header>
<h2>
<header class="px-4 mb-3">
<h2 class="text-2xl">
<a rel="prefetch" href="/blog/{{post.slug}}">{{post.metadata.title}}</a>
</h2>
<section class="created-at m-1 text-right text-sm text-gray-600">
<span>Published on</span>
<time datetime="{post.metadata.date}"> {{post.metadata.date}} </time>
</section>
</header>
{# article preview, maybe implement as a filter? #}
</article>
<footer>
<div class="article-tags">
{% if post.metadata.tags.len() > 0 %}
<span class="lighten">Tags:</span>
<ul>
{% for tag in post.metadata.tags %}
<li class="{tagsListLiClass}">
<a href="/blog/tags/{{tag}}">{{tag}}</a>
</li>
{% endfor %}
</ul>
{% endif %}
</div>
<div class="created-at">
<span>Published on</span>
<time datetime="{post.metadata.date}"> {{post.metadata.date}} </time>
</div>
</footer>
<p class="px-5 text-gray-800"> TODO: article preview, maybe implement as a filter?,
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Ald </p>
<hr class="my-3 mx-4 h-0 border-blue-200 bg-blue-800 text-blue-800" />
<footer class="px-4">
<section class="article-tags text-base">
{% if post.metadata.tags.len() > 0 %}
<span class="text-gray-600">Tags:</span>
<ul class="inline">
{% for tag in post.metadata.tags %}
<li class="inline italic text-blue-700 {% if !loop.last %} after:content-[','] {% endif %}">
<a href="/blog/tags/{{tag}}">{{tag}}</a>
</li>
{% endfor %}
</ul>
{% endif %}
</div>
</footer>
</article>

View File

@ -1,31 +1,19 @@
<header class="min-h-full bg-blue-50">
<nav class="">
<section>
<ul class="">
{% for link in header_props.links %}
<li>
<a
rel="prefetch"
class=""
href="{{link.href}}"
>
{{link.label}}
</a>
</li>
{% endfor %}
</ul>
<aside class="logo-section ">
<a class="logo" href=".">
<img
class=""
src="/m-logo.svg"
alt="m logo"
width="44px"
height="44px"
/>
<nav class="flex">
{% match header_props.back_link %}
{% when Some with (link) %}
<a
class="p-3 text-lg font-medium drop-shadow-md"
href="{{link.href}}"
>
{{link.label}}
</a>
{% when None %}
{% endmatch %}
<aside class="flex logo-section flex-grow justify-end content-end">
<a class="logo p-3 text-base" href=".">
@michalvankodev
</a>
</aside>
</section>
</nav>
</header>