mirror of
https://github.com/anotherhadi/blog.git
synced 2026-05-20 05:32:32 +02:00
remove dead code and unify patterns
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
This commit is contained in:
@@ -14,7 +14,6 @@
|
|||||||
"@types/bun": "^1.3.13",
|
"@types/bun": "^1.3.13",
|
||||||
"astro": "6.1.9",
|
"astro": "6.1.9",
|
||||||
"daisyui": "^5.5.19",
|
"daisyui": "^5.5.19",
|
||||||
"lucide-astro": "^0.556.0",
|
|
||||||
"node-html-parser": "^7.1.0",
|
"node-html-parser": "^7.1.0",
|
||||||
"svelte": "^5.55.5",
|
"svelte": "^5.55.5",
|
||||||
"tailwindcss": "^4.2.4",
|
"tailwindcss": "^4.2.4",
|
||||||
@@ -624,8 +623,6 @@
|
|||||||
|
|
||||||
"lru-cache": ["lru-cache@11.2.7", "", {}, "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA=="],
|
"lru-cache": ["lru-cache@11.2.7", "", {}, "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA=="],
|
||||||
|
|
||||||
"lucide-astro": ["lucide-astro@0.556.0", "", { "peerDependencies": { "astro": ">=2.7.1" } }, "sha512-ugMjPb45AMfkLCaduNSbyy5NQEKvB1TxVVMmUS4S6L807PMESnX0Qp+DIKHjbyjJmPXOyLRbrzvR3YikTK7brg=="],
|
|
||||||
|
|
||||||
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
|
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
|
||||||
|
|
||||||
"magicast": ["magicast@0.5.2", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "source-map-js": "^1.2.1" } }, "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ=="],
|
"magicast": ["magicast@0.5.2", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "source-map-js": "^1.2.1" } }, "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ=="],
|
||||||
|
|||||||
@@ -1273,10 +1273,6 @@
|
|||||||
url = "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz";
|
url = "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz";
|
||||||
hash = "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==";
|
hash = "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==";
|
||||||
};
|
};
|
||||||
"lucide-astro@0.556.0" = fetchurl {
|
|
||||||
url = "https://registry.npmjs.org/lucide-astro/-/lucide-astro-0.556.0.tgz";
|
|
||||||
hash = "sha512-ugMjPb45AMfkLCaduNSbyy5NQEKvB1TxVVMmUS4S6L807PMESnX0Qp+DIKHjbyjJmPXOyLRbrzvR3YikTK7brg==";
|
|
||||||
};
|
|
||||||
"magic-string@0.30.21" = fetchurl {
|
"magic-string@0.30.21" = fetchurl {
|
||||||
url = "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz";
|
url = "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz";
|
||||||
hash = "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==";
|
hash = "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==";
|
||||||
|
|||||||
+1
-2
@@ -21,8 +21,7 @@
|
|||||||
"@types/bun": "^1.3.13",
|
"@types/bun": "^1.3.13",
|
||||||
"astro": "6.1.9",
|
"astro": "6.1.9",
|
||||||
"daisyui": "^5.5.19",
|
"daisyui": "^5.5.19",
|
||||||
"lucide-astro": "^0.556.0",
|
"node-html-parser": "^7.1.0",
|
||||||
"node-html-parser": "^7.1.0",
|
|
||||||
"svelte": "^5.55.5",
|
"svelte": "^5.55.5",
|
||||||
"tailwindcss": "^4.2.4"
|
"tailwindcss": "^4.2.4"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import { ArrowUp } from "lucide-astro";
|
import { ArrowUp } from "@lucide/astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -2,21 +2,13 @@
|
|||||||
import type { CollectionEntry } from "astro:content";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import TagBadge from "./TagBadge.astro";
|
import TagBadge from "./TagBadge.astro";
|
||||||
import { Image } from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
|
import { formatDate } from "../utils/notes";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
post: CollectionEntry<"blog">;
|
post: CollectionEntry<"blog">;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { post } = Astro.props;
|
const { post } = Astro.props;
|
||||||
|
|
||||||
function formatDate(date: Date) {
|
|
||||||
const options: Intl.DateTimeFormatOptions = {
|
|
||||||
month: "long",
|
|
||||||
day: "numeric",
|
|
||||||
year: "numeric",
|
|
||||||
};
|
|
||||||
return date.toLocaleDateString("en-US", options);
|
|
||||||
}
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<article
|
<article
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
---
|
---
|
||||||
import { ArrowRight, FolderCode, Key, Rss } from "@lucide/astro";
|
import { ArrowRight, FolderCode, Key, Rss } from "@lucide/astro";
|
||||||
import { Image } from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
|
import type { SocialLinks } from "../config";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -8,19 +9,7 @@ interface Props {
|
|||||||
description: string;
|
description: string;
|
||||||
avatar: any;
|
avatar: any;
|
||||||
location?: string;
|
location?: string;
|
||||||
socialLinks?: {
|
socialLinks?: SocialLinks;
|
||||||
github?: string;
|
|
||||||
gitlab?: string;
|
|
||||||
gitea?: string;
|
|
||||||
linkedin?: string;
|
|
||||||
twitter?: string;
|
|
||||||
bluesky?: string;
|
|
||||||
instagram?: string;
|
|
||||||
youTube?: string;
|
|
||||||
medium?: string;
|
|
||||||
kofi?: string;
|
|
||||||
codetips?: string;
|
|
||||||
};
|
|
||||||
gpgKey?: string;
|
gpgKey?: string;
|
||||||
rssFeed?: string;
|
rssFeed?: string;
|
||||||
}
|
}
|
||||||
@@ -205,10 +194,10 @@ const {
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{socialLinks.youTube && (
|
{socialLinks.youtube && (
|
||||||
<div class="tooltip" data-tip="Youtube">
|
<div class="tooltip" data-tip="Youtube">
|
||||||
<a
|
<a
|
||||||
href={socialLinks.youTube}
|
href={socialLinks.youtube}
|
||||||
class="btn btn-circle btn-ghost"
|
class="btn btn-circle btn-ghost"
|
||||||
aria-label="YouTube"
|
aria-label="YouTube"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
|||||||
@@ -110,8 +110,6 @@ function isActive(href: string) {
|
|||||||
if (!btn || !menu) return;
|
if (!btn || !menu) return;
|
||||||
const lines = btn.querySelectorAll<HTMLElement>(".hamburger-line");
|
const lines = btn.querySelectorAll<HTMLElement>(".hamburger-line");
|
||||||
let open = false;
|
let open = false;
|
||||||
|
|
||||||
open = false;
|
|
||||||
menu.style.display = "none";
|
menu.style.display = "none";
|
||||||
lines[0].style.transform = "";
|
lines[0].style.transform = "";
|
||||||
lines[1].style.opacity = "";
|
lines[1].style.opacity = "";
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ export interface SocialLinks {
|
|||||||
twitter?: string;
|
twitter?: string;
|
||||||
bluesky?: string;
|
bluesky?: string;
|
||||||
instagram?: string;
|
instagram?: string;
|
||||||
youTube?: string;
|
youtube?: string;
|
||||||
codetips?: string;
|
codetips?: string;
|
||||||
kofi?: string;
|
kofi?: string;
|
||||||
medium?: string;
|
medium?: string;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import BackToTop from "../components/BackToTop.astro";
|
|||||||
import { ChevronLeft } from "@lucide/astro";
|
import { ChevronLeft } from "@lucide/astro";
|
||||||
import { parse } from "node-html-parser";
|
import { parse } from "node-html-parser";
|
||||||
import Author from "../components/Author.astro";
|
import Author from "../components/Author.astro";
|
||||||
|
import { formatDate } from "../utils/notes";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -19,14 +20,6 @@ interface Props {
|
|||||||
const { title, description, publishDate, updatedDate, image, tags } =
|
const { title, description, publishDate, updatedDate, image, tags } =
|
||||||
Astro.props;
|
Astro.props;
|
||||||
|
|
||||||
function formatDate(date: Date) {
|
|
||||||
return date.toLocaleDateString("en-US", {
|
|
||||||
month: "long",
|
|
||||||
day: "numeric",
|
|
||||||
year: "numeric",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const content = await Astro.slots.render("default");
|
const content = await Astro.slots.render("default");
|
||||||
const wordCount = content.split(/\s+/).length;
|
const wordCount = content.split(/\s+/).length;
|
||||||
const readingTime = Math.ceil(wordCount / 200);
|
const readingTime = Math.ceil(wordCount / 200);
|
||||||
|
|||||||
@@ -15,26 +15,11 @@ const {
|
|||||||
description = "Infosec engineer passionate about Linux/NixOS, blockchains, OSINT & FOSS. Hacking with Go, exploring open tech, and contributing whenever I can 🐧",
|
description = "Infosec engineer passionate about Linux/NixOS, blockchains, OSINT & FOSS. Hacking with Go, exploring open tech, and contributing whenever I can 🐧",
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
|
|
||||||
// Custom blur-fade animation configuration
|
const anim = {
|
||||||
const blurFadeAnimation = {
|
old: { name: "blurFadeOut", duration: "0.1s", easing: "ease-in-out", fillMode: "forwards" },
|
||||||
old: {
|
new: { name: "blurFadeIn", duration: "0.1s", easing: "ease-in-out", fillMode: "backwards" },
|
||||||
name: "blurFadeOut",
|
|
||||||
duration: "0.1s",
|
|
||||||
easing: "ease-in-out",
|
|
||||||
fillMode: "forwards",
|
|
||||||
},
|
|
||||||
new: {
|
|
||||||
name: "blurFadeIn",
|
|
||||||
duration: "0.1s",
|
|
||||||
easing: "ease-in-out",
|
|
||||||
fillMode: "backwards",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const pageTransition = {
|
|
||||||
forwards: blurFadeAnimation,
|
|
||||||
backwards: blurFadeAnimation,
|
|
||||||
};
|
};
|
||||||
|
const pageTransition = { forwards: anim, backwards: anim };
|
||||||
|
|
||||||
const origin = Astro.url.origin;
|
const origin = Astro.url.origin;
|
||||||
---
|
---
|
||||||
@@ -49,23 +34,19 @@ const origin = Astro.url.origin;
|
|||||||
<meta name="generator" content={Astro.generator} />
|
<meta name="generator" content={Astro.generator} />
|
||||||
<title>{title}</title>
|
<title>{title}</title>
|
||||||
|
|
||||||
<!-- View Transitions -->
|
|
||||||
<ClientRouter />
|
<ClientRouter />
|
||||||
|
|
||||||
<!-- Open Graph / Social Media -->
|
|
||||||
<meta property="og:title" content={title} />
|
<meta property="og:title" content={title} />
|
||||||
<meta property="og:description" content={description} />
|
<meta property="og:description" content={description} />
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:url" content={origin} />
|
<meta property="og:url" content={origin} />
|
||||||
<meta property="og:image" content={`${origin}/images/og_home.png`} />
|
<meta property="og:image" content={`${origin}/images/og_home.png`} />
|
||||||
|
|
||||||
<!-- Twitter -->
|
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
<meta name="twitter:title" content={title} />
|
<meta name="twitter:title" content={title} />
|
||||||
<meta name="twitter:description" content={description} />
|
<meta name="twitter:description" content={description} />
|
||||||
<meta name="twitter:image" content={`${origin}/images/og_home.png`} />
|
<meta name="twitter:image" content={`${origin}/images/og_home.png`} />
|
||||||
|
|
||||||
<!-- RSS Feed -->
|
|
||||||
<link
|
<link
|
||||||
rel="alternate"
|
rel="alternate"
|
||||||
type="application/rss+xml"
|
type="application/rss+xml"
|
||||||
@@ -87,13 +68,11 @@ const origin = Astro.url.origin;
|
|||||||
<Oneko />
|
<Oneko />
|
||||||
<Console />
|
<Console />
|
||||||
|
|
||||||
<!-- Smooth Scroll -->
|
|
||||||
<style is:global>
|
<style is:global>
|
||||||
html {
|
html {
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initial Page Load Blur-Fade Animation */
|
|
||||||
@keyframes pageLoadBlurFade {
|
@keyframes pageLoadBlurFade {
|
||||||
0% {
|
0% {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -106,11 +85,10 @@ const origin = Astro.url.origin;
|
|||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
animation: pageLoadBlurFade 0.3s ease-in-out;
|
animation: pageLoadBlurFade 0.1s ease-in-out;
|
||||||
animation-fill-mode: both;
|
animation-fill-mode: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Blur Fade View Transitions (for page-to-page navigation) */
|
|
||||||
@keyframes blurFadeIn {
|
@keyframes blurFadeIn {
|
||||||
0% {
|
0% {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|||||||
@@ -1,229 +0,0 @@
|
|||||||
---
|
|
||||||
import Layout from "./Layout.astro";
|
|
||||||
import { Image } from "astro:assets";
|
|
||||||
import TagBadge from "../components/TagBadge.astro";
|
|
||||||
import { ChevronLeft, ExternalLink } from "@lucide/astro";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
image: any;
|
|
||||||
tags: string[];
|
|
||||||
demoLink?: string;
|
|
||||||
url?: string;
|
|
||||||
sourceLink?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { title, description, image, tags, demoLink, url, sourceLink } =
|
|
||||||
Astro.props;
|
|
||||||
---
|
|
||||||
|
|
||||||
<Layout title={`${title} - Another Hadi`} description={description}>
|
|
||||||
<article class="max-w-4xl mx-auto px-4 py-20">
|
|
||||||
<!-- Back button -->
|
|
||||||
<div class="mb-8 flex flex-wrap justify-between gap-5">
|
|
||||||
<a href="/projects" class="btn btn-ghost btn-sm">
|
|
||||||
<ChevronLeft size={18} />
|
|
||||||
Back to Projects
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Featured Image -->
|
|
||||||
<!-- TODO: Future Enhancement - Support multiple images/project gallery -->
|
|
||||||
{
|
|
||||||
image && (
|
|
||||||
<figure class="mb-8 rounded-2xl overflow-hidden">
|
|
||||||
<Image
|
|
||||||
src={image}
|
|
||||||
alt={title}
|
|
||||||
class="w-full aspect-video object-cover"
|
|
||||||
width={1200}
|
|
||||||
height={630}
|
|
||||||
/>
|
|
||||||
</figure>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
<!-- Project Header -->
|
|
||||||
<header class="mb-8">
|
|
||||||
<h1 class="text-5xl font-bold mb-4">{title}</h1>
|
|
||||||
<p class="text-xl text-base-content/70 mb-6">{description}</p>
|
|
||||||
|
|
||||||
<!-- Prominent Action Buttons -->
|
|
||||||
{
|
|
||||||
(demoLink || sourceLink) && (
|
|
||||||
<div class="flex flex-wrap gap-3 mb-6">
|
|
||||||
{demoLink && (
|
|
||||||
<a
|
|
||||||
href={demoLink}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
class="btn btn-primary gap-2"
|
|
||||||
>
|
|
||||||
<ExternalLink class="size-5" />
|
|
||||||
Live Demo
|
|
||||||
</a>
|
|
||||||
)}
|
|
||||||
{url && (
|
|
||||||
<a
|
|
||||||
href={url}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
class="btn btn-soft gap-2"
|
|
||||||
>
|
|
||||||
<ExternalLink class="size-4" />
|
|
||||||
Website
|
|
||||||
</a>
|
|
||||||
)}
|
|
||||||
{sourceLink && (
|
|
||||||
<a
|
|
||||||
href={sourceLink}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
class="btn btn-soft gap-2"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 32 32"
|
|
||||||
fill="currentColor"
|
|
||||||
>
|
|
||||||
<path d="M16,2.345c7.735,0,14,6.265,14,14-.002,6.015-3.839,11.359-9.537,13.282-.7,.14-.963-.298-.963-.665,0-.473,.018-1.978,.018-3.85,0-1.312-.437-2.152-.945-2.59,3.115-.35,6.388-1.54,6.388-6.912,0-1.54-.543-2.783-1.435-3.762,.14-.35,.63-1.785-.14-3.71,0,0-1.173-.385-3.85,1.435-1.12-.315-2.31-.472-3.5-.472s-2.38,.157-3.5,.472c-2.677-1.802-3.85-1.435-3.85-1.435-.77,1.925-.28,3.36-.14,3.71-.892,.98-1.435,2.24-1.435,3.762,0,5.355,3.255,6.563,6.37,6.913-.403,.35-.77,.963-.893,1.872-.805,.368-2.818,.963-4.077-1.155-.263-.42-1.05-1.452-2.152-1.435-1.173,.018-.472,.665,.017,.927,.595,.332,1.277,1.575,1.435,1.978,.28,.787,1.19,2.293,4.707,1.645,0,1.173,.018,2.275,.018,2.607,0,.368-.263,.787-.963,.665-5.719-1.904-9.576-7.255-9.573-13.283,0-7.735,6.265-14,14-14Z" />
|
|
||||||
</svg>
|
|
||||||
View Source
|
|
||||||
</a>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<!-- Tags -->
|
|
||||||
{
|
|
||||||
tags && tags.length > 0 && (
|
|
||||||
<div class="flex flex-wrap gap-2 mt-4">
|
|
||||||
{tags.map((tag) => (
|
|
||||||
<TagBadge tag={tag} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
<!-- Divider -->
|
|
||||||
<div class="divider"></div>
|
|
||||||
|
|
||||||
<!-- Project Content -->
|
|
||||||
<div class="prose-content max-w-none">
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Divider -->
|
|
||||||
<div class="divider mt-12"></div>
|
|
||||||
|
|
||||||
<!-- Back to projects link -->
|
|
||||||
<div class="flex justify-center gap-2 mt-12">
|
|
||||||
<div class="flex gap-3 justify-center flex-wrap text-sm">
|
|
||||||
<a href="/projects" class="link link-hover">View All Projects</a>
|
|
||||||
<span class="text-base-content/30">•</span>
|
|
||||||
<a href="/#contact" class="link link-hover">Contact me</a>
|
|
||||||
<span class="text-base-content/30">•</span>
|
|
||||||
<a href="https://ko-fi.com/anotherhadi" class="link link-hover"
|
|
||||||
>Support me</a
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
</Layout>
|
|
||||||
|
|
||||||
<style is:global>
|
|
||||||
.prose-content {
|
|
||||||
color: inherit;
|
|
||||||
line-height: 1.75;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose-content h1,
|
|
||||||
.prose-content h2,
|
|
||||||
.prose-content h3,
|
|
||||||
.prose-content h4,
|
|
||||||
.prose-content h5,
|
|
||||||
.prose-content h6 {
|
|
||||||
font-weight: 700;
|
|
||||||
margin-top: 2rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose-content h1 {
|
|
||||||
font-size: 2.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose-content h2 {
|
|
||||||
font-size: 1.875rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose-content h3 {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose-content p {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose-content a {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose-content ul,
|
|
||||||
.prose-content ol {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
margin-left: 1.5rem;
|
|
||||||
list-style-position: outside;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose-content ul {
|
|
||||||
list-style-type: disc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose-content ol {
|
|
||||||
list-style-type: decimal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose-content li {
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose-content code {
|
|
||||||
padding: 0.125rem 0.375rem;
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-family: ui-monospace, monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose-content pre {
|
|
||||||
padding: 1rem;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
overflow-x: auto;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose-content pre code {
|
|
||||||
background: transparent;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose-content blockquote {
|
|
||||||
border-left-width: 4px;
|
|
||||||
padding-left: 1rem;
|
|
||||||
font-style: italic;
|
|
||||||
margin: 1rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose-content img {
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
margin: 1.5rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose-content strong {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
+2
-11
@@ -7,16 +7,7 @@ export function getCategory(n: {
|
|||||||
return parts.length > 1 ? parts[0] : "General";
|
return parts.length > 1 ? parts[0] : "General";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extractInlineHashtags(body: string): string[] {
|
function slugify(text: string): string {
|
||||||
const re = /#(\w+)/g;
|
|
||||||
const tags: string[] = [];
|
|
||||||
let m;
|
|
||||||
while ((m = re.exec(body)) !== null) tags.push(m[1].toLowerCase());
|
|
||||||
return [...new Set(tags)];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mirrors github-slugger: keeps _, keeps unicode letters/numbers, spaces → hyphens
|
|
||||||
export function slugify(text: string): string {
|
|
||||||
return text
|
return text
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replace(/[^\p{L}\p{N}\s_-]/gu, "")
|
.replace(/[^\p{L}\p{N}\s_-]/gu, "")
|
||||||
@@ -34,7 +25,7 @@ export function extractLinks(body: string): string[] {
|
|||||||
|
|
||||||
export function formatDate(date: Date): string {
|
export function formatDate(date: Date): string {
|
||||||
return date.toLocaleDateString("en-US", {
|
return date.toLocaleDateString("en-US", {
|
||||||
month: "short",
|
month: "long",
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user