Basic markdown with Tailwind CSS Typography

This commit is contained in:
Alphonse Paix
2025-09-20 14:03:13 +02:00
parent 38cb594882
commit bf2ec15e71
10 changed files with 83 additions and 18 deletions

16
Cargo.lock generated
View File

@@ -1502,6 +1502,15 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
[[package]]
name = "markdown"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5cab8f2cadc416a82d2e783a1946388b31654d391d1c7d92cc1f03e295b1deb"
dependencies = [
"unicode-id",
]
[[package]] [[package]]
name = "matchers" name = "matchers"
version = "0.1.0" version = "0.1.0"
@@ -3259,6 +3268,12 @@ version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
[[package]]
name = "unicode-id"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ba288e709927c043cbe476718d37be306be53fb1fafecd0dbe36d072be2580"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.18" version = "1.0.18"
@@ -3851,6 +3866,7 @@ dependencies = [
"config", "config",
"fake", "fake",
"linkify", "linkify",
"markdown",
"once_cell", "once_cell",
"quickcheck", "quickcheck",
"quickcheck_macros", "quickcheck_macros",

View File

@@ -20,6 +20,7 @@ axum-server = { version = "0.7.2", features = ["tls-rustls-no-provider"] }
base64 = "0.22.1" base64 = "0.22.1"
chrono = { version = "0.4.41", default-features = false, features = ["clock"] } chrono = { version = "0.4.41", default-features = false, features = ["clock"] }
config = "0.15.14" config = "0.15.14"
markdown = "1.0.0"
rand = { version = "0.9.2", features = ["std_rng"] } rand = { version = "0.9.2", features = ["std_rng"] }
reqwest = { version = "0.12.23", default-features = false, features = [ reqwest = { version = "0.12.23", default-features = false, features = [
"rustls-tls", "rustls-tls",

File diff suppressed because one or more lines are too long

50
package-lock.json generated
View File

@@ -7,6 +7,9 @@
"dependencies": { "dependencies": {
"@tailwindcss/cli": "^4.1.13", "@tailwindcss/cli": "^4.1.13",
"tailwindcss": "^4.1.13" "tailwindcss": "^4.1.13"
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.18"
} }
}, },
"node_modules/@isaacs/fs-minipass": { "node_modules/@isaacs/fs-minipass": {
@@ -636,6 +639,19 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/@tailwindcss/typography": {
"version": "0.5.18",
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.18.tgz",
"integrity": "sha512-dDIgwZOlf+tVkZ7A029VvQ1+ngKATENDjMEx2N35s2yPjfTS05RWSM8ilhEWSa5DMJ6ci2Ha9WNZEd2GQjrdQg==",
"dev": true,
"license": "MIT",
"dependencies": {
"postcss-selector-parser": "6.0.10"
},
"peerDependencies": {
"tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1"
}
},
"node_modules/braces": { "node_modules/braces": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
@@ -657,6 +673,19 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true,
"license": "MIT",
"bin": {
"cssesc": "bin/cssesc"
},
"engines": {
"node": ">=4"
}
},
"node_modules/detect-libc": { "node_modules/detect-libc": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
@@ -1067,6 +1096,20 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/postcss-selector-parser": {
"version": "6.0.10",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
"integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
"dev": true,
"license": "MIT",
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
},
"engines": {
"node": ">=4"
}
},
"node_modules/source-map-js": { "node_modules/source-map-js": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -1124,6 +1167,13 @@
"node": ">=8.0" "node": ">=8.0"
} }
}, },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true,
"license": "MIT"
},
"node_modules/yallist": { "node_modules/yallist": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",

View File

@@ -5,5 +5,8 @@
"dependencies": { "dependencies": {
"@tailwindcss/cli": "^4.1.13", "@tailwindcss/cli": "^4.1.13",
"tailwindcss": "^4.1.13" "tailwindcss": "^4.1.13"
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.18"
} }
} }

View File

@@ -14,4 +14,11 @@ impl PostEntry {
pub fn formatted_date(&self) -> String { pub fn formatted_date(&self) -> String {
self.published_at.format("%B %d, %Y").to_string() self.published_at.format("%B %d, %Y").to_string()
} }
pub fn to_html(self) -> Self {
Self {
content: markdown::to_html(&self.content),
..self
}
}
} }

View File

@@ -51,7 +51,8 @@ pub async fn see_post(
let post = get_post(&connection_pool, post_id) let post = get_post(&connection_pool, post_id)
.await .await
.context(format!("Failed to fetch post #{}", post_id)) .context(format!("Failed to fetch post #{}", post_id))
.map_err(AppError::unexpected_page)?; .map_err(AppError::unexpected_page)?
.to_html();
let template = PostTemplate { post }; let template = PostTemplate { post };
Ok(Html(template.render().unwrap()).into_response()) Ok(Html(template.render().unwrap()).into_response())
} }

View File

@@ -119,7 +119,7 @@
</div> </div>
<div> <div>
<label for="post-content" <label for="post-content"
class="block text-sm font-medium text-gray-700 mb-2">HTML content</label> class="block text-sm font-medium text-gray-700 mb-2">Markdown content</label>
<textarea id="post-content" <textarea id="post-content"
name="content" name="content"
rows="6" rows="6"

View File

@@ -1,13 +1,2 @@
@import "tailwindcss"; @import "tailwindcss";
@plugin "@tailwindcss/typography";
@layer utilities {
.font-inter {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
}
@layer base {
body {
font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11';
}
}

View File

@@ -32,9 +32,7 @@
</div> </div>
</div> </div>
</header> </header>
<div class="px-8 py-8"> <div class="px-8 py-8 prose prose-lg max-w-none">{{ post.content | safe }}</div>
<div class="prose prose-lg prose-blue max-w-none">{{ post.content | safe }}</div>
</div>
</article> </article>
<div class="mt-8 bg-gradient-to-r from-blue-600 to-indigo-700 rounded-lg shadow-lg text-white p-8 text-center"> <div class="mt-8 bg-gradient-to-r from-blue-600 to-indigo-700 rounded-lg shadow-lg text-white p-8 text-center">
<h3 class="text-2xl font-bold mb-2">Enjoyed this post?</h3> <h3 class="text-2xl font-bold mb-2">Enjoyed this post?</h3>