Compare commits

...

4 Commits

Author SHA1 Message Date
Alphonse Paix
c11e552d0a fix mobile menu margins
Some checks failed
Rust / Test (push) Has been cancelled
Rust / Rustfmt (push) Has been cancelled
Rust / Clippy (push) Has been cancelled
Rust / Code coverage (push) Has been cancelled
2025-09-20 16:25:47 +02:00
Alphonse Paix
6308ac279e <pre> element overflow 2025-09-20 16:05:20 +02:00
Alphonse Paix
ddb837be56 Markdown rendering 2025-09-20 16:01:51 +02:00
Alphonse Paix
8f0b59775e Basic markdown with Tailwind CSS Typography 2025-09-20 14:03:13 +02:00
11 changed files with 170 additions and 16 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"
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]]
name = "matchers"
version = "0.1.0"
@@ -3259,6 +3268,12 @@ version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
[[package]]
name = "unicode-id"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ba288e709927c043cbe476718d37be306be53fb1fafecd0dbe36d072be2580"
[[package]]
name = "unicode-ident"
version = "1.0.18"
@@ -3851,6 +3866,7 @@ dependencies = [
"config",
"fake",
"linkify",
"markdown",
"once_cell",
"quickcheck",
"quickcheck_macros",

View File

@@ -20,6 +20,7 @@ axum-server = { version = "0.7.2", features = ["tls-rustls-no-provider"] }
base64 = "0.22.1"
chrono = { version = "0.4.41", default-features = false, features = ["clock"] }
config = "0.15.14"
markdown = "1.0.0"
rand = { version = "0.9.2", features = ["std_rng"] }
reqwest = { version = "0.12.23", default-features = false, features = [
"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": {
"@tailwindcss/cli": "^4.1.13",
"tailwindcss": "^4.1.13"
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.18"
}
},
"node_modules/@isaacs/fs-minipass": {
@@ -636,6 +639,19 @@
"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": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
@@ -657,6 +673,19 @@
"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": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
@@ -1067,6 +1096,20 @@
"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": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -1124,6 +1167,13 @@
"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": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",

View File

@@ -5,5 +5,8 @@
"dependencies": {
"@tailwindcss/cli": "^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 {
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)
.await
.context(format!("Failed to fetch post #{}", post_id))
.map_err(AppError::unexpected_page)?;
.map_err(AppError::unexpected_page)?
.to_html();
let template = PostTemplate { post };
Ok(Html(template.render().unwrap()).into_response())
}

View File

@@ -58,7 +58,7 @@
</div>
</div>
<div id="mobile-menu"
class="hidden md:hidden pb-4 border-t border-gray-100 mt-4">
class="hidden md:hidden border-t border-gray-100 pb-4 pt-4">
<nav class="flex flex-col space-y-2">
<a href="/"
class="text-gray-700 hover:text-blue-600 hover:bg-blue-50 px-4 py-2 rounded-lg text-sm font-medium transition-colors duration-200">

View File

@@ -119,7 +119,7 @@
</div>
<div>
<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"
name="content"
rows="6"

View File

@@ -1,13 +1,91 @@
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@layer utilities {
.font-inter {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@layer components {
.prose-compact {
@apply prose prose-slate max-w-none;
--tw-prose-body: theme(colors.gray.700);
--tw-prose-headings: theme(colors.gray.900);
--tw-prose-links: theme(colors.blue.600);
--tw-prose-code: theme(colors.gray.800);
}
@layer base {
body {
font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11';
.prose-compact p {
@apply mb-2 mt-0;
}
.prose-compact h1 {
@apply pb-2 mb-3 border-b-2 border-gray-100;
}
.prose-compact h2 {
@apply mt-4 pb-2 mb-3 border-b-2 border-gray-100 font-semibold;
}
.prose-compact h3 {
@apply mt-3 mb-1;
}
.prose-compact h4,
.prose-compact h5,
.prose-compact h6 {
@apply mt-2 mb-1;
}
.prose-compact ul,
.prose-compact ol {
@apply my-2 space-y-0;
}
.prose-compact li {
@apply my-0;
}
.prose-compact blockquote {
@apply my-3 py-2;
}
.prose-compact img {
@apply m-0 align-top;
}
.prose-compact a:has(img) {
@apply no-underline border-0 inline-block align-top;
}
.prose-compact a img {
@apply inline-block align-top;
}
.prose-compact :not(pre) > code {
@apply bg-gray-100 text-gray-800 px-1.5 py-0.5 rounded text-sm font-mono font-normal;
}
.prose-compact :not(pre) > code::before,
.prose-compact :not(pre) > code::after {
content: none !important;
}
.prose-compact pre {
@apply my-3 p-4 bg-gray-100 text-gray-800 rounded-sm overflow-x-auto border border-gray-200;
overflow-x: auto;
max-width: 100%;
width: 0;
min-width: 100%;
}
.prose-compact pre code {
@apply bg-transparent text-gray-800 p-0 rounded-none;
}
.prose-compact pre code::before,
.prose-compact pre code::after {
content: none !important;
}
}

View File

@@ -32,9 +32,7 @@
</div>
</div>
</header>
<div class="px-8 py-8">
<div class="prose prose-lg prose-blue max-w-none">{{ post.content | safe }}</div>
</div>
<div class="px-8 py-8 prose-compact">{{ post.content | safe }}</div>
</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">
<h3 class="text-2xl font-bold mb-2">Enjoyed this post?</h3>