From 456cf011b36de91c9936994b1fa45703adcd309b Mon Sep 17 00:00:00 2001 From: Dawid Rycerz Date: Thu, 3 Jul 2025 10:56:21 +0300 Subject: Initial fork of chrismwilliams/astro-theme-cactus theme --- src/components/blog/Masthead.astro | 84 +++++++++++++++++++++++++ src/components/blog/PostPreview.astro | 24 +++++++ src/components/blog/TOC.astro | 22 +++++++ src/components/blog/TOCHeading.astro | 27 ++++++++ src/components/blog/webmentions/Comments.astro | 87 ++++++++++++++++++++++++++ src/components/blog/webmentions/Likes.astro | 52 +++++++++++++++ src/components/blog/webmentions/index.astro | 23 +++++++ 7 files changed, 319 insertions(+) create mode 100644 src/components/blog/Masthead.astro create mode 100644 src/components/blog/PostPreview.astro create mode 100644 src/components/blog/TOC.astro create mode 100644 src/components/blog/TOCHeading.astro create mode 100644 src/components/blog/webmentions/Comments.astro create mode 100644 src/components/blog/webmentions/Likes.astro create mode 100644 src/components/blog/webmentions/index.astro (limited to 'src/components/blog') diff --git a/src/components/blog/Masthead.astro b/src/components/blog/Masthead.astro new file mode 100644 index 0000000..1f52383 --- /dev/null +++ b/src/components/blog/Masthead.astro @@ -0,0 +1,84 @@ +--- +import { Image } from "astro:assets"; +import type { CollectionEntry } from "astro:content"; +import FormattedDate from "@/components/FormattedDate.astro"; + +interface Props { + content: CollectionEntry<"post">; + readingTime: string; +} + +const { + content: { data }, + readingTime, +} = Astro.props; + +const dateTimeOptions: Intl.DateTimeFormatOptions = { + month: "long", +}; +--- + +{ + data.coverImage && ( +
+ {data.coverImage.alt} +
+ ) +} +{data.draft ? (Draft) : null} +

+ {data.title} +

+
+

+ /{" "} + {readingTime} +

+ { + data.updatedDate && ( + + Updated: + + + ) + } +
+{ + !!data.tags?.length && ( +
+ + {data.tags.map((tag, i) => ( + <> + {/* prettier-ignore */} + + View more blogs with the tag {tag} + {i < data.tags.length - 1 && ", "} + + + ))} +
+ ) +} diff --git a/src/components/blog/PostPreview.astro b/src/components/blog/PostPreview.astro new file mode 100644 index 0000000..fc1a9a3 --- /dev/null +++ b/src/components/blog/PostPreview.astro @@ -0,0 +1,24 @@ +--- +import type { CollectionEntry } from "astro:content"; +import FormattedDate from "@/components/FormattedDate.astro"; +import type { HTMLTag, Polymorphic } from "astro/types"; + +type Props = Polymorphic<{ as: Tag }> & { + post: CollectionEntry<"post">; + withDesc?: boolean; +}; + +const { as: Tag = "div", post, withDesc = false } = Astro.props; +--- + + + + {post.data.draft && (Draft) } + + {post.data.title} + + +{withDesc && {post.data.description}} diff --git a/src/components/blog/TOC.astro b/src/components/blog/TOC.astro new file mode 100644 index 0000000..6649546 --- /dev/null +++ b/src/components/blog/TOC.astro @@ -0,0 +1,22 @@ +--- +import { generateToc } from "@/utils/generateToc"; +import type { MarkdownHeading } from "astro"; +import TOCHeading from "./TOCHeading.astro"; + +interface Props { + headings: MarkdownHeading[]; +} + +const { headings } = Astro.props; + +const toc = generateToc(headings); +--- + +
+ Table of Contents + +
diff --git a/src/components/blog/TOCHeading.astro b/src/components/blog/TOCHeading.astro new file mode 100644 index 0000000..b9dd486 --- /dev/null +++ b/src/components/blog/TOCHeading.astro @@ -0,0 +1,27 @@ +--- +import type { TocItem } from "@/utils/generateToc"; + +interface Props { + heading: TocItem; +} + +const { + heading: { children, depth, slug, text }, +} = Astro.props; +--- + +
  • 2 ? "ms-2" : ""}`}> + {text} + { + !!children.length && ( +
      + {children.map((subheading) => ( + + ))} +
    + ) + } +
  • diff --git a/src/components/blog/webmentions/Comments.astro b/src/components/blog/webmentions/Comments.astro new file mode 100644 index 0000000..5177d57 --- /dev/null +++ b/src/components/blog/webmentions/Comments.astro @@ -0,0 +1,87 @@ +--- +import { Image } from "astro:assets"; +import type { WebmentionsChildren } from "@/types"; +import { Icon } from "astro-icon/components"; + +interface Props { + mentions: WebmentionsChildren[]; +} + +const { mentions } = Astro.props; + +const validComments = ["mention-of", "in-reply-to"]; + +const comments = mentions.filter( + (mention) => validComments.includes(mention["wm-property"]) && mention.content?.text, +); +--- + +{ + !!comments.length && ( +
    +

    + {comments.length} Mention{comments.length > 1 ? "s" : ""} +

    +
      + {comments.map((mention) => ( +
    • + {mention.author?.photo && mention.author.photo !== "" ? ( + mention.author.url && mention.author.url !== "" ? ( + + {mention.author?.name} + + ) : ( + {mention.author?.name} + ) + ) : null} +
      +
      +

      + {mention.author?.name} +

      + + + +
      +

      + {mention.content?.text} +

      +
      +
    • + ))} +
    +
    + ) +} diff --git a/src/components/blog/webmentions/Likes.astro b/src/components/blog/webmentions/Likes.astro new file mode 100644 index 0000000..7862c43 --- /dev/null +++ b/src/components/blog/webmentions/Likes.astro @@ -0,0 +1,52 @@ +--- +import { Image } from "astro:assets"; +import type { WebmentionsChildren } from "@/types"; + +interface Props { + mentions: WebmentionsChildren[]; +} + +const { mentions } = Astro.props; +const MAX_LIKES = 10; + +const likes = mentions.filter((mention) => mention["wm-property"] === "like-of"); +const likesToShow = likes + .filter((like) => like.author?.photo && like.author.photo !== "") + .slice(0, MAX_LIKES); +--- + +{ + !!likes.length && ( +
    +

    + {likes.length} + {likes.length > 1 ? " People" : " Person"} liked this +

    + {!!likesToShow.length && ( +
      + {likesToShow.map((like) => ( +
    • + + + {like.author!.name} + + +
    • + ))} +
    + )} +
    + ) +} diff --git a/src/components/blog/webmentions/index.astro b/src/components/blog/webmentions/index.astro new file mode 100644 index 0000000..232b4f3 --- /dev/null +++ b/src/components/blog/webmentions/index.astro @@ -0,0 +1,23 @@ +--- +import { getWebmentionsForUrl } from "@/utils/webmentions"; +import Comments from "./Comments.astro"; +import Likes from "./Likes.astro"; + +const url = new URL(Astro.url.pathname, Astro.site); + +const webMentions = await getWebmentionsForUrl(`${url}`); + +// Return if no webmentions +if (!webMentions.length) return; +--- + +
    +

    Webmentions for this post

    +
    + + +
    +

    + Responses powered by{" "} + Webmentions +

    -- cgit v1.2.3