diff --git a/CHANGELOG.md b/CHANGELOG.md
index be3381b..159c773 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,23 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+
+## [Untagged]
+
+### Features
+- Display tags page navigation and filtering
+- Improve page title display
+- Add hero images to blog posts and pages
+- Enhance cards and SEO in /pages section
+- Update post configuration for better population
+- Add more posts to /blog with date sorting
+- Display links in homepage
+
+### Fixed
+- Fix search page functionality
+- Fix bug in Strapi local setup
+- Remove unnecessary Dockerfile
+
## v4.3.1 (2024-07-27)
### Fix
@@ -74,7 +91,7 @@ All notable changes to this project will be documented in this file. See [standa
### Others
-* adds blog post for how to add a social icon ([#221](https://github.com/satnaing/astro-paper/issues/221))
+* adds blog post for how to add a social icon ([#221](https://github.com/satnaing/astro-paper/issues/221))
* updates the hook post with a smarter updateHook ([#222](https://github.com/satnaing/astro-paper/issues/222))
* update breadcrumbs delimiter to "»" ([#213](https://github.com/satnaing/astro-paper/issues/213))
diff --git a/src/components/Card.tsx b/src/components/Card.tsx
index 711a252..08b70f7 100644
--- a/src/components/Card.tsx
+++ b/src/components/Card.tsx
@@ -1,35 +1,75 @@
-import { slugifyStr } from "@utils/slugify";
-import Datetime from "./Datetime";
-import type { CollectionEntry } from "astro:content";
+import Tag from './Tag.astro';
+import type { SEO } from '../interfaces/Article';
export interface Props {
href?: string;
- frontmatter: CollectionEntry<"blog">["data"];
+ author?: string;
+ tags: string[];
+ frontmatter: {
+ title: string;
+ pubDatetime: Date;
+ modDatetime: Date;
+ description: string;
+ SEO?: SEO;
+ author?: string;
+ };
secHeading?: boolean;
}
-export default function Card({ href, frontmatter, secHeading = true }: Props) {
- const { title, pubDatetime, modDatetime, description } = frontmatter;
-
- const headerProps = {
- style: { viewTransitionName: slugifyStr(title) },
- className: "text-lg font-medium decoration-dashed hover:underline",
- };
+export default function Card({ href, frontmatter, tags, secHeading = true }: Props) {
+ const { title, pubDatetime, description, SEO } = frontmatter;
+ const imageUrl = SEO?.socialImage?.url;
return (
-
-
- {secHeading ? (
- {title}
- ) : (
- {title}
- )}
-
-
- {description}
+
+
+
+ {imageUrl && (
+
+
+
+
+ )}
+
+ {secHeading ? (
+
+ {title}
+
+ ) : (
+
+ {title}
+
+ )}
+
+
+ {new Date(pubDatetime).toLocaleDateString()}
+
+
+
+ {description}
+
+
+
+ {tags?.map((tag) => {
+ if (!tag) return null;
+
+ })}
+
+
+
+
);
}
diff --git a/src/components/Footer.astro b/src/components/Footer.astro
index 4137dad..4695a08 100644
--- a/src/components/Footer.astro
+++ b/src/components/Footer.astro
@@ -6,19 +6,26 @@ const currentYear = new Date().getFullYear();
export interface Props {
noMarginTop?: boolean;
+ activeNav?: string;
}
-const { noMarginTop = false } = Astro.props;
+const { activeNav, noMarginTop = false } = Astro.props;
---
-
+
{Title}
- {post.data.Tags.map(tag => )}
+ {Tags.map(tag => )}
(
tag.Label)}
frontmatter={{
author: "x",
- tags: ["x"],
title: data.Title || "---",
pubDatetime: new Date(data.createdAt),
modDatetime: new Date(data.updatedAt),
description: data.SEO?.metaDescription || "",
+ SEO: { ...data.SEO },
}}
/>
))
@@ -53,5 +54,5 @@ const { currentPage, totalPages, paginatedPosts } = Astro.props;
nextUrl={`/posts/${currentPage + 1}/`}
/>
- 1} />
+ 1} activeNav="x" />
diff --git a/src/layouts/TagPosts.astro b/src/layouts/TagPosts.astro
index cdd5343..820cc16 100644
--- a/src/layouts/TagPosts.astro
+++ b/src/layouts/TagPosts.astro
@@ -6,13 +6,15 @@ import Header from "@components/Header.astro";
import Footer from "@components/Footer.astro";
import Card from "@components/Card";
import Pagination from "@components/Pagination.astro";
-import { SITE } from "@config";
+import { SITE, markketplace } from "@config";
import { getCollection } from "astro:content";
import type Store from "../interfaces/Store";
import { slugifyStr } from "@utils/slugify";
const stores = await getCollection("stores");
-const store = stores?.[0]?.data as unknown as Store;
+const store = stores?.find(
+ (store: { data: Store }) => store.data.slug === markketplace.STORE_SLUG
+)?.data;
export interface Props {
currentPage: number;
@@ -22,7 +24,13 @@ export interface Props {
tagName: string;
}
-const { currentPage, totalPages, paginatedPosts, tag, tagName } = Astro.props;
+const {
+ currentPage,
+ totalPages,
+ paginatedPosts,
+ tag = "all",
+ tagName,
+} = Astro.props;
---
@@ -38,9 +46,9 @@ const { currentPage, totalPages, paginatedPosts, tag, tagName } = Astro.props;
paginatedPosts.map(({ data, id }) => (
tag.Label)}
frontmatter={{
author: "x",
- tags: data.Tags.map(tag => tag.Label),
title: data.Title,
pubDatetime: new Date(data.createdAt),
modDatetime: new Date(data.updatedAt),
diff --git a/src/lib/strapi-loader.ts b/src/lib/strapi-loader.ts
index 83cd4fa..8d88439 100644
--- a/src/lib/strapi-loader.ts
+++ b/src/lib/strapi-loader.ts
@@ -14,9 +14,9 @@ const SYNC_INTERVAL = 60 * 1000; // 1 minute in milliseconds
* @param filter The filter to apply to the content &filters[store][id][$eq]=${STRAPI_STORE_ID}
* @returns An Astro loader for the specified content type
*/
-export function strapiLoader({ contentType, filter }: { contentType: string, filter?: string }): Loader {
+export function strapiLoader({ contentType, filter, populate = 'SEO.socialImage' }: { contentType: string, filter?: string, populate?: string }): Loader {
return {
- name: "strapi-posts",
+ name: `strapi-${contentType}`,
load: async function (this: Loader, { store, meta, logger }) {
const lastSynced = meta.get("lastSynced");
@@ -43,13 +43,19 @@ export function strapiLoader({ contentType, filter }: { contentType: string, fil
[filterKey, filterValue] = filter.split('=');
}
- const data = await fetchFromStrapi(`/api/${contentType}s?`, { [filterKey]: filterValue, populate: '*' });
- const posts = data?.data;
+ const data = await fetchFromStrapi(`/api/${contentType}s?`, {
+ [filterKey]: filterValue,
+ populate,
+ });
+ let posts = data?.data;
if (!posts || !Array.isArray(posts)) {
throw new Error("Invalid data received from Strapi");
}
+ // Sort posts by creation date in descending order
+ posts = posts.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
+
// Get the schema
const schemaOrFn = this.schema;
if (!schemaOrFn) {
@@ -172,11 +178,29 @@ async function fetchFromStrapi(
const url = new URL(path, baseUrl || STRAPI_BASE_URL);
if (params) {
+ // Handle populate parameters
+ if (params.populate) {
+ const populateFields = params.populate.split(',');
+ populateFields.forEach((field, index) => {
+ if (field.includes('.')) {
+ const [parent, child] = field.split('.');
+ url.searchParams.append('populate', parent);
+ url.searchParams.append(`populate[${index + 1}]`, `${parent}.${child}`);
+ } else {
+ url.searchParams.append('populate', field);
+ }
+ });
+ delete params.populate;
+ }
+
+ // Handle remaining parameters (including filters)
Object.entries(params).forEach(([key, value]) => {
url.searchParams.set(key, value);
});
}
+ console.log('Fetching URL:', url.toString());
+
try {
const response = await fetch(url.href);
if (!response.ok) {
diff --git a/src/pages/[slug].astro b/src/pages/[slug].astro
index 101fb21..c677b6f 100644
--- a/src/pages/[slug].astro
+++ b/src/pages/[slug].astro
@@ -1,6 +1,7 @@
---
import { type CollectionEntry, getCollection } from "astro:content";
-import type { Page, Store } from "@interfaces/index";
+import type { Store } from "@interfaces/index";
+import HeroImage from "@components/HeroImage.astro";
import {
BlocksRenderer,
type BlocksContent,
@@ -12,13 +13,13 @@ import Breadcrumbs from "@components/Breadcrumbs.astro";
import Hr from "@components/Hr.astro";
export interface Props {
- page: CollectionEntry<"page">;
+ page: CollectionEntry<"pages">;
}
export async function getStaticPaths() {
const pages = await getCollection("pages");
- return pages.map((page: { data: CollectionEntry<"page"> }) => ({
+ return pages.map((page: CollectionEntry<"pages">) => ({
params: { slug: page.data.slug },
props: { page: page.data },
}));
@@ -28,14 +29,20 @@ const stores = await getCollection("stores");
const store = stores?.[0]?.data as unknown as Store;
const { page } = Astro.props;
+console.log({ x: page });
+// const { SEO } = page.data;
---
-
-
+
+ {
+ page?.SEO?.socialImage && (
+
+ )
+ }
{page.Title}
@@ -45,4 +52,4 @@ const { page } = Astro.props;
-
+
diff --git a/src/pages/index.astro b/src/pages/index.astro
index e35bff9..5e65ff4 100644
--- a/src/pages/index.astro
+++ b/src/pages/index.astro
@@ -27,14 +27,14 @@ const pages = await getCollection("pages");
const homePage = pages.find(
(page: { data: Page }) => page.data.slug === "home"
-) as unknown as { data: Page };
+) as { data: Page };
const links = store?.URLS || [];
// const products = store?.products?.data || [];
---
-
+
@@ -121,33 +121,6 @@ const links = store?.URLS || [];
} -->
- {
- pages.length > 0 && (
- <>
-
- Pages
-
- {pages.map(page => (
-
- ))}
-
-
- {posts.length > 0 && }
- >
- )
- }
-
{
posts.length > 0 && (
@@ -160,11 +133,12 @@ const links = store?.URLS || [];
href={`/posts/${id}-${slugifyStr(data.Title)}`}
frontmatter={{
author: "x",
- tags: data.Tags.map(tag => tag.Label),
+ tags: data.Tags?.map(tag => tag.Label),
title: data.Title,
pubDatetime: new Date(data.createdAt),
modDatetime: new Date(data.updatedAt),
description: data.SEO?.metaDescription || "",
+ SEO: { ...data.SEO },
}}
secHeading={false}
/>
@@ -188,18 +162,25 @@ const links = store?.URLS || [];
-
-
- Built with Markketplace-astro -
-
- a minimal, responsive, accessible and SEO-friendly Astro blog theme, compatible
- with Markketplace/Strapi. This theme follows best practices and provides
- accessibility out of the box. Light and dark mode are supported by default.
- Moreover, additional color schemes can also be configured.
-
+ {
+ !store?.Description && (
+ <>
+
+
+ Built with Markketplace-astro -
+
+ a minimal, responsive, accessible and SEO-friendly Astro blog
+ theme, compatible with Markketplace/Strapi. This theme follows
+ best practices and provides accessibility out of the box. Light
+ and dark mode are supported by default. Moreover, additional
+ color schemes can also be configured.
+
+ >
+ )
+ }
diff --git a/src/pages/pages.astro b/src/pages/pages.astro
new file mode 100644
index 0000000..89d44b5
--- /dev/null
+++ b/src/pages/pages.astro
@@ -0,0 +1,43 @@
+---
+import { getCollection } from "astro:content";
+import Layout from "@layouts/Layout.astro";
+import Main from "@layouts/Main.astro";
+import Card from "@components/Card";
+import { slugifyStr } from "@utils/slugify";
+import { SITE } from "@config";
+import Footer from "@components/Footer.astro";
+import Header from "@components/Header.astro";
+import type Store from "@interfaces/Store";
+
+const stores = await getCollection("stores");
+const store = stores?.[0]?.data as Store;
+
+let pages = await getCollection("pages");
+pages = pages.sort(
+ (a, b) =>
+ new Date(b.data.createdAt).getTime() - new Date(a.data.createdAt).getTime()
+);
+---
+
+
+
+
+
+ {
+ pages.map(page => (
+
+ ))
+ }
+
+
+
+
diff --git a/src/pages/rss.xml.ts b/src/pages/rss.xml.ts
index a50b5e8..c5239e7 100644
--- a/src/pages/rss.xml.ts
+++ b/src/pages/rss.xml.ts
@@ -6,6 +6,7 @@ import { slugifyStr } from "@utils/slugify";
export async function GET() {
const posts = await getCollection("posts");
const pages = await getCollection("pages");
+ // const products =
const items = [];
diff --git a/src/pages/search.astro b/src/pages/search.astro
index 5f6d151..9a206ca 100644
--- a/src/pages/search.astro
+++ b/src/pages/search.astro
@@ -29,5 +29,5 @@ const searchList = posts.map(({ data, id }) => ({
-
+
diff --git a/src/pages/tags/[tag]/[page].astro b/src/pages/tags/[tag]/[page].astro
index 354461b..c0e67cf 100644
--- a/src/pages/tags/[tag]/[page].astro
+++ b/src/pages/tags/[tag]/[page].astro
@@ -8,22 +8,38 @@ import getPagination from "@utils/getPagination";
export interface Props {
post: CollectionEntry<"posts">;
- tag: string;
+ tag?: string;
tagName: string;
}
export async function getStaticPaths() {
const posts = await getCollection("posts");
-
const tags = getUniqueTags(posts);
+ // Handle case with no tags
+ if (!tags.length) {
+ return [
+ {
+ params: { tag: "all", page: "1" },
+ props: { tag: "all", tagName: "All Posts", page: "1" },
+ },
+ ];
+ }
+
return tags.flatMap(({ tag, tagName }) => {
const tagPosts = getPostsByTag(posts, tag);
const totalPages = getPageNumbers(tagPosts.length);
- return totalPages.map(page => ({
- params: { tag, page },
- props: { tag, tagName },
+ return totalPages.map(pageNum => ({
+ params: {
+ tag: tag || "all",
+ page: String(pageNum),
+ },
+ props: {
+ tag,
+ tagName,
+ page: String(pageNum),
+ },
}));
});
}
@@ -33,7 +49,7 @@ const { tag, tagName } = Astro.props;
const posts = await getCollection("posts");
-const postsByTag = getPostsByTag(posts, tag);
+const postsByTag = getPostsByTag(posts, tag || "all");
const pagination = getPagination({
posts: postsByTag,
@@ -41,4 +57,4 @@ const pagination = getPagination({
});
---
-
+
diff --git a/src/pages/tags/[tag]/index.astro b/src/pages/tags/[tag]/index.astro
index 58b43c5..3159e45 100644
--- a/src/pages/tags/[tag]/index.astro
+++ b/src/pages/tags/[tag]/index.astro
@@ -7,15 +7,22 @@ import getUniqueTags from "@utils/getUniqueTags";
export async function getStaticPaths() {
const posts = await getCollection("posts");
-
const tags = getUniqueTags(posts);
- return tags.map(({ tag, tagName }) => {
- return {
- params: { tag },
- props: { tag, tagName, posts },
- };
- });
+ // Add default "all" tag
+ const allTags = [
+ { tag: "all", tagName: "All Posts" },
+ ...tags.filter(tag => tag.tag && tag.tag.length > 0), // Filter out empty tags
+ ];
+
+ return allTags.map(({ tag, tagName }) => ({
+ params: { tag: tag || "all" }, // Ensure tag is never empty
+ props: {
+ tag: tag || "all",
+ tagName: tagName || "All Posts",
+ posts: tag === "all" ? posts : getPostsByTag(posts, tag),
+ },
+ }));
}
const { tag, tagName, posts } = Astro.props;
diff --git a/src/utils/getPostsByTag.ts b/src/utils/getPostsByTag.ts
index 8053030..f5183e6 100644
--- a/src/utils/getPostsByTag.ts
+++ b/src/utils/getPostsByTag.ts
@@ -3,7 +3,7 @@ import { slugifyStr } from "./slugify";
const getPostsByTag = (posts: CollectionEntry<"posts">[], tag: string) =>
posts.filter(post => {
- const tags = post.data.Tags.map(tag => slugifyStr(tag.Label));
+ const tags = post.data.Tags.map((post_tag: { Label: string }) => slugifyStr(post_tag.Label));
return tags.includes(tag);
})
diff --git a/tailwind.config.cjs b/tailwind.config.cjs
index 8cad411..6371937 100644
--- a/tailwind.config.cjs
+++ b/tailwind.config.cjs
@@ -18,7 +18,19 @@ module.exports = {
sm: "640px",
},
+
+
extend: {
+ colors: {
+ accent: {
+ 100: '#e6f7ff',
+ 300: '#91d5ff',
+ 400: '#69c0ff',
+ 500: '#40a9ff',
+ 700: '#096dd9',
+ 900: '#003a8c',
+ },
+ },
textColor: {
skin: {
base: withOpacity("--color-text-base"),