Add Categories and Tags with new configs
This commit is contained in:
@ -15,7 +15,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Astro uses this full URL to generate your sitemap and canonical URLs in your final build
|
// Astro uses this full URL to generate your sitemap and canonical URLs in your final build
|
||||||
site: SITE.domain,
|
site: SITE.domain,
|
||||||
base: "/",
|
base: SITE.baseUrl,
|
||||||
|
|
||||||
output: "static",
|
output: "static",
|
||||||
|
|
||||||
|
@ -15,6 +15,8 @@ const {
|
|||||||
description = "",
|
description = "",
|
||||||
image: _image = defaultImage,
|
image: _image = defaultImage,
|
||||||
canonical,
|
canonical,
|
||||||
|
noindex = false,
|
||||||
|
nofollow = false
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
|
|
||||||
const image =
|
const image =
|
||||||
@ -34,6 +36,8 @@ const image =
|
|||||||
{canonical &&
|
{canonical &&
|
||||||
<link rel="canonical" href={canonical} />}
|
<link rel="canonical" href={canonical} />}
|
||||||
|
|
||||||
|
<meta name="robots" content={`${noindex ? "noindex": "index"}, ${nofollow ? "nofollow" : "follow"}`} />
|
||||||
|
|
||||||
<!-- Google / Search Engine Tags -->
|
<!-- Google / Search Engine Tags -->
|
||||||
<meta itemprop="name" content={title} />
|
<meta itemprop="name" content={title} />
|
||||||
<meta itemprop="description" content={description} />
|
<meta itemprop="description" content={description} />
|
||||||
@ -62,4 +66,5 @@ const image =
|
|||||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;700&display=swap" rel="stylesheet" />
|
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;700&display=swap" rel="stylesheet" />
|
||||||
|
|
||||||
<!-- Google Site Verification -->
|
<!-- Google Site Verification -->
|
||||||
{SITE.googleSiteVerificationId && <meta name="google-site-verification" content={SITE.googleSiteVerificationId} />}
|
{SITE.googleSiteVerificationId &&
|
||||||
|
<meta name="google-site-verification" content={SITE.googleSiteVerificationId} />}
|
@ -1,31 +1,15 @@
|
|||||||
---
|
---
|
||||||
import BlogListItem from "~/components/widgets/BlogListItem.astro";
|
import BlogListItem from "~/components/widgets/BlogListItem.astro";
|
||||||
import Pagination from "~/components/widgets/Pagination.astro";
|
|
||||||
|
|
||||||
const { page } = Astro.props;
|
const { page } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<section class="px-4 sm:px-6 py-8 sm:py-16 lg:py-20 mx-auto max-w-3xl">
|
<ul>
|
||||||
<header>
|
|
||||||
<h1 class="text-center text-5xl md:text-[3.50rem] font-bold leading-tighter tracking-tighter mb-8 md:mb-16">
|
|
||||||
News and step-by-step guides about
|
|
||||||
<span class="bg-clip-text text-transparent bg-gradient-to-r from-blue-500 to-pink-500">AstroWind
|
|
||||||
</span>
|
|
||||||
</h1>
|
|
||||||
</header>
|
|
||||||
<ul>
|
|
||||||
{
|
|
||||||
page.data.map((post) => (
|
|
||||||
<li class="mb-10 md:mb-16">
|
|
||||||
<BlogListItem post={post} />
|
|
||||||
</li>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{
|
{
|
||||||
(page.url.prev || page.url.next) && (
|
page.data.map((post) => (
|
||||||
<Pagination prevUrl={page.url.prev} nextUrl={page.url.next} />
|
<li class="mb-10 md:mb-16">
|
||||||
)
|
<BlogListItem post={post} />
|
||||||
|
</li>
|
||||||
|
))
|
||||||
}
|
}
|
||||||
</section>
|
</ul>
|
@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
import Picture from "~/components/core/Picture.astro";
|
import Picture from "~/components/core/Picture.astro";
|
||||||
|
import { getPermalink } from "~/utils/permalinks";
|
||||||
import { findImage } from "~/utils/findImage";
|
import { findImage } from "~/utils/findImage";
|
||||||
import { getFormattedDate } from "~/utils/getFormatedDate";
|
import { getFormattedDate } from "~/utils/getFormatedDate";
|
||||||
|
|
||||||
@ -20,7 +21,7 @@ const image = await findImage(post.image);
|
|||||||
<header>
|
<header>
|
||||||
<h2 class="text-xl sm:text-2xl font-bold leading-snug mb-2">
|
<h2 class="text-xl sm:text-2xl font-bold leading-snug mb-2">
|
||||||
<a class="hover:text-blue-600 underline underline-offset-4 decoration-1 decoration-dotted transition ease-in duration-200"
|
<a class="hover:text-blue-600 underline underline-offset-4 decoration-1 decoration-dotted transition ease-in duration-200"
|
||||||
href={`/blog/${post.slug}`}>
|
href={getPermalink(post.slug, "post")}>
|
||||||
{post.title}
|
{post.title}
|
||||||
</a>
|
</a>
|
||||||
</h2>
|
</h2>
|
||||||
@ -31,7 +32,7 @@ const image = await findImage(post.image);
|
|||||||
<footer class="flex items-center mt-4">
|
<footer class="flex items-center mt-4">
|
||||||
<div>
|
<div>
|
||||||
<span class="text-gray-500 dark:text-slate-400">
|
<span class="text-gray-500 dark:text-slate-400">
|
||||||
<time datetime={post.pubDate}>{getFormattedDate(post.pubDate)}</time>
|
<time datetime={post.pubDate}>{getFormattedDate(post.pubDate)}</time> ~ {Math.ceil(post.readingTime)} min read
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
@ -9,10 +9,10 @@ const { post } = Astro.props;
|
|||||||
<article>
|
<article>
|
||||||
<header>
|
<header>
|
||||||
<p class="max-w-3xl mx-auto text-center">
|
<p class="max-w-3xl mx-auto text-center">
|
||||||
<time datetime={post.pubDate}>{getFormattedDate(post.pubDate)}</time> ~ {Math.ceil(post.readingTime)} min
|
<time datetime={post.pubDate}>{getFormattedDate(post.pubDate)}</time> ~ {Math.ceil(post.readingTime)} min read
|
||||||
</p>
|
</p>
|
||||||
<h1
|
<h1
|
||||||
class="px-4 sm:px-6 max-w-3xl mx-auto text-center text-5xl md:text-[3.50rem] font-bold leading-tighter tracking-tighter mb-6 md:mb-8">
|
class="px-4 sm:px-6 max-w-3xl mx-auto text-center text-4xl md:text-5xl font-bold leading-tighter tracking-tighter mb-8">
|
||||||
{post.title}
|
{post.title}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ const { post } = Astro.props;
|
|||||||
}
|
}
|
||||||
</header>
|
</header>
|
||||||
<div
|
<div
|
||||||
class="container mx-auto px-4 sm:px-6 max-w-3xl prose prose-lg lg:prose-xl dark:prose-invert dark:prose-headings:text-slate-300 prose-md prose-headings:leading-tighter prose-headings:tracking-tighter prose-headings:font-bold prose-a:text-blue-600 dark:prose-a:text-blue-400 prose-img:rounded-md prose-img:shadow-lg mt-8">
|
class="container mx-auto px-8 sm:px-6 max-w-3xl prose prose-lg lg:prose-xl dark:prose-invert dark:prose-headings:text-slate-300 prose-md prose-headings:leading-tighter prose-headings:tracking-tighter prose-headings:font-bold prose-a:text-blue-600 dark:prose-a:text-blue-400 prose-img:rounded-md prose-img:shadow-lg mt-8">
|
||||||
<Fragment set:html={post.body} />
|
<Fragment set:html={post.body} />
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
|
const { } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<section class="flex items-center h-full p-16">
|
<section class="flex items-center h-full p-16">
|
||||||
|
@ -7,7 +7,7 @@ const { } = Astro.props;
|
|||||||
<footer>
|
<footer>
|
||||||
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
<div class="max-w-6xl mx-auto px-4 sm:px-6">
|
||||||
<div class="grid grid-cols-12 gap-4 gap-y-8 sm:gap-8 py-8 md:py-12 border-t border-gray-200 dark:border-slate-800">
|
<div class="grid grid-cols-12 gap-4 gap-y-8 sm:gap-8 py-8 md:py-12 border-t border-gray-200 dark:border-slate-800">
|
||||||
<div class="col-span-12 lg:col-span-3">
|
<div class="col-span-12 lg:col-span-4">
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<a class="inline-block font-bold text-xl" href="/">AstroWind</a>
|
<a class="inline-block font-bold text-xl" href="/">AstroWind</a>
|
||||||
</div>
|
</div>
|
||||||
@ -22,59 +22,54 @@ const { } = Astro.props;
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 md:col-span-3 lg:col-span-2">
|
<div class="col-span-6 md:col-span-3 lg:col-span-2">
|
||||||
<div class="text-gray-800 dark:text-gray-300 font-medium mb-2">
|
<div class="text-gray-800 dark:text-gray-300 font-medium mb-2">
|
||||||
Products
|
Product
|
||||||
</div>
|
</div>
|
||||||
<ul class="text-sm">
|
<ul class="text-sm">
|
||||||
<li class="mb-2">
|
<li class="mb-2">
|
||||||
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
href="#">Web Studio
|
href="#">Features
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="mb-2">
|
<li class="mb-2">
|
||||||
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
href="#">DynamicBox Flex
|
href="#">Security
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="mb-2">
|
<li class="mb-2">
|
||||||
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
href="#">Programming Forms
|
href="#">Team
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="mb-2">
|
<li class="mb-2">
|
||||||
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
href="#">Integrations
|
href="#">Enterprise
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="mb-2">
|
<li class="mb-2">
|
||||||
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
href="#">Command-line
|
href="#">Customer stories
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="mb-2">
|
||||||
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
|
href="#">Pricing
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="mb-2">
|
||||||
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
|
href="#">Resources
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 md:col-span-3 lg:col-span-2">
|
<div class="col-span-6 md:col-span-3 lg:col-span-2">
|
||||||
<div class="text-gray-800 dark:text-gray-300 font-medium mb-2">
|
<div class="text-gray-800 dark:text-gray-300 font-medium mb-2">
|
||||||
Resources
|
Platform
|
||||||
</div>
|
</div>
|
||||||
<ul class="text-sm">
|
<ul class="text-sm">
|
||||||
<li class="mb-2">
|
<li class="mb-2">
|
||||||
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
href="#">Documentation
|
href="#">Developer API
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="mb-2">
|
|
||||||
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
|
||||||
href="#">Tutorials & Guides
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="mb-2">
|
|
||||||
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
|
||||||
href="#">Blog
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="mb-2">
|
|
||||||
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
|
||||||
href="#">Support Center
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="mb-2">
|
<li class="mb-2">
|
||||||
@ -82,6 +77,53 @@ const { } = Astro.props;
|
|||||||
href="#">Partners
|
href="#">Partners
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="mb-2">
|
||||||
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
|
href="#">Atom
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="mb-2">
|
||||||
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
|
href="#">Electron
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="mb-2">
|
||||||
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
|
href="#">GitHub Desktop
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-6 md:col-span-3 lg:col-span-2">
|
||||||
|
<div class="text-gray-800 dark:text-gray-300 font-medium mb-2">
|
||||||
|
Support
|
||||||
|
</div>
|
||||||
|
<ul class="text-sm">
|
||||||
|
<li class="mb-2">
|
||||||
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
|
href="#">Docs
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="mb-2">
|
||||||
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
|
href="#">Community Forum
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="mb-2">
|
||||||
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
|
href="#">Professional Services
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="mb-2">
|
||||||
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
|
href="#">Skills
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="mb-2">
|
||||||
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
|
href="#">Status
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-6 md:col-span-3 lg:col-span-2">
|
<div class="col-span-6 md:col-span-3 lg:col-span-2">
|
||||||
@ -91,32 +133,42 @@ const { } = Astro.props;
|
|||||||
<ul class="text-sm">
|
<ul class="text-sm">
|
||||||
<li class="mb-2">
|
<li class="mb-2">
|
||||||
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
href="#">Home
|
href="#">About
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="mb-2">
|
<li class="mb-2">
|
||||||
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
href="#">About us
|
href="#">Blog
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="mb-2">
|
<li class="mb-2">
|
||||||
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
href="#">Company values
|
href="#">Careers
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="mb-2">
|
<li class="mb-2">
|
||||||
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
href="#">Pricing
|
href="#">Press
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="mb-2">
|
<li class="mb-2">
|
||||||
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
href="#">Privacy Policy
|
href="#">Inclusion
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="mb-2">
|
||||||
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
|
href="#">Social Impact
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="mb-2">
|
||||||
|
<a class="text-gray-600 hover:text-gray-700 dark:text-gray-400 transition duration-150 ease-in-out"
|
||||||
|
href="#">Shop
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-12 md:col-span-3 lg:col-span-3">
|
<!-- <div class="col-span-12 md:col-span-3 lg:col-span-3">
|
||||||
<div class="text-gray-800 dark:text-gray-300 font-medium mb-2">
|
<div class="text-gray-800 dark:text-gray-300 font-medium mb-2">
|
||||||
Subscribe
|
Subscribe
|
||||||
</div>
|
</div>
|
||||||
@ -142,7 +194,7 @@ const { } = Astro.props;
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
<div class="md:flex md:items-center md:justify-between py-4 md:py-8">
|
<div class="md:flex md:items-center md:justify-between py-4 md:py-8">
|
||||||
<ul class="flex mb-6 md:order-1 md:ml-4 md:mb-0">
|
<ul class="flex mb-6 md:order-1 md:ml-4 md:mb-0">
|
||||||
@ -166,10 +218,16 @@ const { } = Astro.props;
|
|||||||
</li>
|
</li>
|
||||||
<li class="ml-4">
|
<li class="ml-4">
|
||||||
<a class="flex justify-center items-center text-gray-600 hover:text-gray-700 bg-white hover:bg-white-100 rounded-full shadow transition duration-150 ease-in-out dark:bg-gray-800 dark:text-gray-400 p-1.5"
|
<a class="flex justify-center items-center text-gray-600 hover:text-gray-700 bg-white hover:bg-white-100 rounded-full shadow transition duration-150 ease-in-out dark:bg-gray-800 dark:text-gray-400 p-1.5"
|
||||||
aria-label="Twitter" href="/rss.xml">
|
aria-label="RSS" href="/rss.xml">
|
||||||
<Icon name="tabler:rss" class="w-5 h-5" />
|
<Icon name="tabler:rss" class="w-5 h-5" />
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="ml-4">
|
||||||
|
<a class="flex justify-center items-center text-gray-600 hover:text-gray-700 bg-white hover:bg-white-100 rounded-full shadow transition duration-150 ease-in-out dark:bg-gray-800 dark:text-gray-400 p-1.5"
|
||||||
|
aria-label="Github" href="">
|
||||||
|
<Icon name="tabler:brand-github" class="w-5 h-5" />
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="text-sm text-gray-700 mr-4 dark:text-slate-400">
|
<div class="text-sm text-gray-700 mr-4 dark:text-slate-400">
|
||||||
<span
|
<span
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
---
|
---
|
||||||
import { Icon } from "astro-icon";
|
import { Icon } from "astro-icon";
|
||||||
import Logo from "~/components/widgets/Logo.astro";
|
import Logo from "~/components/widgets/Logo.astro";
|
||||||
|
import { getPermalink, getBlogPermalink, getHomePermalink } from "~/utils/permalinks";
|
||||||
|
|
||||||
const { } = Astro.props;
|
const { } = Astro.props;
|
||||||
---
|
---
|
||||||
@ -9,7 +10,7 @@ const { } = Astro.props;
|
|||||||
class="sticky top-0 z-40 flex-none mx-auto w-full bg-white md:bg-white/90 dark:bg-slate-900 dark:md:bg-slate-900/90 md:backdrop-blur-sm border-b dark:border-b-0">
|
class="sticky top-0 z-40 flex-none mx-auto w-full bg-white md:bg-white/90 dark:bg-slate-900 dark:md:bg-slate-900/90 md:backdrop-blur-sm border-b dark:border-b-0">
|
||||||
<div class="py-3 px-3 mx-auto w-full md:flex md:justify-between max-w-6xl md:px-4">
|
<div class="py-3 px-3 mx-auto w-full md:flex md:justify-between max-w-6xl md:px-4">
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<a class="flex items-center" href="/">
|
<a class="flex items-center" href={getHomePermalink()}>
|
||||||
<Logo />
|
<Logo />
|
||||||
</a>
|
</a>
|
||||||
<div class="flex items-center md:hidden">
|
<div class="flex items-center md:hidden">
|
||||||
@ -36,12 +37,12 @@ const { } = Astro.props;
|
|||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="font-medium hover:text-gray-900 dark:hover:text-white px-4 py-3 flex items-center transition duration-150 ease-in-out"
|
<a class="font-medium hover:text-gray-900 dark:hover:text-white px-4 py-3 flex items-center transition duration-150 ease-in-out"
|
||||||
href="#">Resources
|
href={getPermalink("useful-resources-to-create-websites", "post")}>Resources
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="font-medium hover:text-gray-900 dark:hover:text-white px-4 py-3 flex items-center transition duration-150 ease-in-out"
|
<a class="font-medium hover:text-gray-900 dark:hover:text-white px-4 py-3 flex items-center transition duration-150 ease-in-out"
|
||||||
href="/blog">Blog
|
href={getBlogPermalink()}>Blog
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="md:hidden">
|
<li class="md:hidden">
|
||||||
@ -78,11 +79,10 @@ const { } = Astro.props;
|
|||||||
@apply transition;
|
@apply transition;
|
||||||
}
|
}
|
||||||
[data-aw-toggle-menu].expanded g > path:first-child {
|
[data-aw-toggle-menu].expanded g > path:first-child {
|
||||||
@apply -rotate-45 translate-y-[14px] translate-x-[-3px];
|
@apply -rotate-45 translate-y-[15px] translate-x-[-3px];
|
||||||
/* transform: rotate(-45deg) translate(-12px, 8px); */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-aw-toggle-menu].expanded g > path:last-child {
|
[data-aw-toggle-menu].expanded g > path:last-child {
|
||||||
@apply rotate-45 translate-y-[-9px] translate-x-[14px];
|
@apply rotate-45 translate-y-[-8px] translate-x-[14px];
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,6 +1,21 @@
|
|||||||
---
|
---
|
||||||
import Picture from "~/components/core/Picture.astro";
|
import Picture from "~/components/core/Picture.astro";
|
||||||
|
import { findPostsByIds } from "~/utils/fetchPosts";
|
||||||
|
import { findImage } from "~/utils/findImage";
|
||||||
|
import { getPermalink } from "~/utils/permalinks";
|
||||||
const { } = Astro.props;
|
const { } = Astro.props;
|
||||||
|
|
||||||
|
const ids = [
|
||||||
|
"get-started-website-with-astro-tailwind-css",
|
||||||
|
"how-to-customize-astrowind-to-your-brand",
|
||||||
|
"useful-resources-to-create-websites",
|
||||||
|
"astrowind-template-in-depth"
|
||||||
|
]
|
||||||
|
|
||||||
|
const items = (await Promise.all((await findPostsByIds(ids))
|
||||||
|
.map(async (item) =>
|
||||||
|
({ ...item, image: await findImage(item.image) }
|
||||||
|
))));
|
||||||
---
|
---
|
||||||
|
|
||||||
<section class="px-4 py-16 mx-auto max-w-6xl lg:py-20">
|
<section class="px-4 py-16 mx-auto max-w-6xl lg:py-20">
|
||||||
@ -18,73 +33,19 @@ const { } = Astro.props;
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid gap-6 row-gap-5 md:grid-cols-2 lg:grid-cols-4 -mb-6">
|
<div class="grid gap-6 row-gap-5 md:grid-cols-2 lg:grid-cols-4 -mb-6">
|
||||||
<div class="mb-6 transition">
|
{items.map((post) => (
|
||||||
<Picture src={import("~/assets/images/steps.jpg")}
|
<article class="mb-6 transition">
|
||||||
class="object-cover w-full h-64 mb-6 rounded shadow-lg bg-gray-400 dark:bg-slate-700" widths={[400]}
|
<Picture src={post.image} class="object-cover w-full h-64 mb-6 rounded shadow-lg bg-gray-400 dark:bg-slate-700"
|
||||||
alt="Post 2 Image" aspectRatio="16:9" />
|
widths={[400]} alt="Post 2 Image" aspectRatio="16:9" />
|
||||||
<h3 class="mb-2 text-xl font-bold leading-snug sm:text-2xl">
|
<h3 class="mb-2 text-xl font-bold leading-snug sm:text-2xl">
|
||||||
<a href="/blog/get-started-website-with-astro-tailwind-css"
|
<a href={getPermalink(post.slug, "type")}
|
||||||
class="hover:text-blue-600 underline underline-offset-4 decoration-1 decoration-dotted transition ease-in duration-200">Get
|
class="hover:text-blue-600 underline underline-offset-4 decoration-1 decoration-dotted transition ease-in duration-200">{post.title}
|
||||||
started with AstroWind to create a website using Astro and
|
|
||||||
Tailwind CSS
|
|
||||||
</a>
|
</a>
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-gray-700 dark:text-gray-400">
|
<p class="text-gray-700 dark:text-gray-400">
|
||||||
Sint sit cillum pariatur eiusmod nulla pariatur ipsum. Sit laborum anim
|
{post.excerpt || post.description}
|
||||||
qui mollit tempor pariatur nisi minim dolor. Aliquip et adipisicing sit
|
|
||||||
sit fugiat
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</article>
|
||||||
|
))}
|
||||||
<div class="mb-6 transition">
|
|
||||||
<Picture src={import("~/assets/images/colors.jpg")}
|
|
||||||
class="object-cover w-full h-64 mb-6 rounded shadow-lg bg-gray-400 dark:bg-slate-700" widths={[400]}
|
|
||||||
alt="Post 1 Image" aspectRatio="16:9" />
|
|
||||||
<h3 class="mb-2 text-xl font-bold leading-snug sm:text-2xl">
|
|
||||||
<a href="/blog/how-to-customize-astrowind-to-your-brand"
|
|
||||||
class="hover:text-blue-600 underline underline-offset-4 decoration-1 decoration-dotted transition ease-in duration-200">How
|
|
||||||
to customize AstroWind template to suit your branding
|
|
||||||
</a>
|
|
||||||
</h3>
|
|
||||||
<p class="text-gray-700 dark:text-gray-400">
|
|
||||||
Sint sit cillum pariatur eiusmod nulla pariatur ipsum. Sit laborum anim
|
|
||||||
qui mollit tempor pariatur nisi minim dolor. Aliquip et adipisicing sit
|
|
||||||
sit fugiat
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-6 transition">
|
|
||||||
<Picture src={import("~/assets/images/tools.jpg")}
|
|
||||||
class="object-cover w-full h-64 mb-6 rounded shadow-lg bg-gray-400 dark:bg-slate-700" widths={[400]}
|
|
||||||
alt="Post 3 Image" aspectRatio="16:9" />
|
|
||||||
<h3 class="mb-2 text-xl font-bold leading-snug sm:text-2xl">
|
|
||||||
<a href="/blog/useful-resources-to-create-websites"
|
|
||||||
class="hover:text-blue-600 underline underline-offset-4 decoration-1 decoration-dotted transition ease-in duration-200">Useful
|
|
||||||
tools and resources to create a professional website
|
|
||||||
</a>
|
|
||||||
</h3>
|
|
||||||
<p class="text-gray-700 dark:text-gray-400">
|
|
||||||
Nibh senectus lacinia volutpat nostra taciti ac posuere, dictum
|
|
||||||
ultricies dictumst luctus in vehicula, mus molestie venenatis penatibus
|
|
||||||
ridiculus elementum. Phasellus sollicitudin dignissim parturient.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-6 transition">
|
|
||||||
<Picture src={import("~/assets/images/hero.jpg")}
|
|
||||||
class="object-cover w-full h-64 mb-6 rounded shadow-lg bg-gray-400 dark:bg-slate-700" widths={[400]}
|
|
||||||
alt="Post 2 Image" aspectRatio="16:9" />
|
|
||||||
<h3 class="mb-2 text-xl font-bold leading-snug sm:text-2xl">
|
|
||||||
<a href="/blog/astrowind-template-in-depth"
|
|
||||||
class="hover:text-blue-600 underline underline-offset-4 decoration-1 decoration-dotted transition ease-in duration-200">AstroWind
|
|
||||||
template in depth
|
|
||||||
</a>
|
|
||||||
</h3>
|
|
||||||
<p class="text-gray-700 dark:text-gray-400">
|
|
||||||
Ornare cum cursus laoreet sagittis nunc fusce posuere per euismod dis
|
|
||||||
vehicula a, semper fames lacus maecenas dictumst pulvinar neque enim non
|
|
||||||
potenti. Torquent hac sociosqu eleifend potenti.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
@ -1,30 +1,25 @@
|
|||||||
---
|
---
|
||||||
const { prevUrl, nextUrl } = Astro.props;
|
import { Icon } from "astro-icon"
|
||||||
|
const { prevUrl, nextUrl, prevText = "Newer posts", nextText = "Older posts" } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
|
{(prevUrl || nextUrl) && (
|
||||||
<div class="container flex">
|
<div class="container flex">
|
||||||
<div class="flex flex-row mx-auto container justify-between">
|
<div class="flex flex-row mx-auto container justify-between">
|
||||||
<a href={prevUrl} class={`btn font-medium text-gray-600 hover:text-gray-900 dark:hover:text-white shadow-none mr-2
|
<a href={prevUrl} class={`btn font-medium text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white shadow-none mr-2
|
||||||
${ !prevUrl ? "invisible" : "" }`}>
|
${ !prevUrl ? "invisible" : "" }`}>
|
||||||
<div class="flex flex-row align-middle">
|
<div class="flex flex-row align-middle">
|
||||||
<svg class="w-5 mr-2" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
<Icon name="tabler:arrow-left" class="w-6 h-6" />
|
||||||
<path fill-rule="evenodd"
|
<p class="ml-2">{prevText}</p>
|
||||||
d="M7.707 14.707a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l2.293 2.293a1 1 0 010 1.414z"
|
|
||||||
clip-rule="evenodd"></path>
|
|
||||||
</svg>
|
|
||||||
<p class="ml-2">Newer posts</p>
|
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<a href={nextUrl} class={`btn font-medium text-gray-600 hover:text-gray-900 dark:hover:text-white shadow-none ${
|
<a href={nextUrl} class={`btn font-medium text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white shadow-none ${
|
||||||
!nextUrl ? "invisible" : "" }`}>
|
!nextUrl ? "invisible" : "" }`}>
|
||||||
<div class="flex flex-row align-middle">
|
<div class="flex flex-row align-middle">
|
||||||
<span class="mr-2">Older posts</span>
|
<span class="mr-2">{nextText}</span>
|
||||||
<svg class="w-5 ml-2" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
<Icon name="tabler:arrow-right" class="w-6 h-6" />
|
||||||
<path fill-rule="evenodd"
|
|
||||||
d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
@ -7,7 +7,11 @@ const { } = Astro.props;
|
|||||||
|
|
||||||
<section class="px-4 py-16 sm:px-6 mx-auto lg:px-8 lg:py-20 max-w-6xl">
|
<section class="px-4 py-16 sm:px-6 mx-auto lg:px-8 lg:py-20 max-w-6xl">
|
||||||
<div class="grid gap-6 row-gap-10 md:grid-cols-2">
|
<div class="grid gap-6 row-gap-10 md:grid-cols-2">
|
||||||
<div class="md:py-6 md:pr-16 text-gray-700 dark:text-gray-400">
|
<div class="md:pb-6 md:pr-16">
|
||||||
|
<h2 class="mb-8 text-3xl lg:text-4xl font-bold font-heading">
|
||||||
|
Sed ac magna sit amet risus tristique interdum.
|
||||||
|
hac.
|
||||||
|
</h2>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="flex flex-col items-center mr-4">
|
<div class="flex flex-col items-center mr-4">
|
||||||
<div>
|
<div>
|
||||||
|
@ -1,12 +1,30 @@
|
|||||||
export const SITE = {
|
export const SITE = {
|
||||||
name: "AstroWind",
|
name: "AstroWind",
|
||||||
|
|
||||||
domain: "https://astrowind.vercel.app",
|
domain: "https://astrowind.vercel.app",
|
||||||
|
baseUrl: "/",
|
||||||
|
|
||||||
title: "AstroWind — Your website with Astro + Tailwind CSS",
|
title: "AstroWind — Your website with Astro + Tailwind CSS",
|
||||||
description: "🚀 AstroWind is a free and ready to start template to make your website using Astro and Tailwind CSS.",
|
description: "🚀 AstroWind is a free and ready to start template to make your website using Astro and Tailwind CSS.",
|
||||||
|
|
||||||
postsPerPage: 6,
|
|
||||||
|
|
||||||
googleAnalyticsId: false, // or "G-XXXXXXXXXX",
|
googleAnalyticsId: false, // or "G-XXXXXXXXXX",
|
||||||
googleSiteVerificationId: "orcPxI47GSa-cRvY11tUe6iGg2IO_RPvnA1q95iEM3M",
|
googleSiteVerificationId: "orcPxI47GSa-cRvY11tUe6iGg2IO_RPvnA1q95iEM3M",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const BLOG = {
|
||||||
|
disabled: false,
|
||||||
|
slug: "blog",
|
||||||
|
|
||||||
|
postsWithoutBlogSlug: true,
|
||||||
|
postsPerPage: 6,
|
||||||
|
|
||||||
|
category: {
|
||||||
|
disabled: false,
|
||||||
|
slug: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
tag: {
|
||||||
|
disabled: false,
|
||||||
|
slug: "tag",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@ -3,6 +3,8 @@ pubDate: "Aug 08 2022"
|
|||||||
title: "AstroWind template in depth"
|
title: "AstroWind template in depth"
|
||||||
description: "Ornare cum cursus laoreet sagittis nunc fusce posuere per euismod dis vehicula a, semper fames lacus maecenas dictumst pulvinar neque enim non potenti. Torquent hac sociosqu eleifend potenti."
|
description: "Ornare cum cursus laoreet sagittis nunc fusce posuere per euismod dis vehicula a, semper fames lacus maecenas dictumst pulvinar neque enim non potenti. Torquent hac sociosqu eleifend potenti."
|
||||||
image: "~/assets/images/hero.jpg"
|
image: "~/assets/images/hero.jpg"
|
||||||
|
category: "Guide"
|
||||||
|
tags: [astrowind]
|
||||||
---
|
---
|
||||||
|
|
||||||
## Dictum integer fusce ac ridiculus et odio sollicitudin diam at
|
## Dictum integer fusce ac ridiculus et odio sollicitudin diam at
|
||||||
|
@ -4,6 +4,7 @@ title: "Get started with AstroWind to create a website using Astro and Tailwind
|
|||||||
description: "Lorem ipsum dolor sit amet"
|
description: "Lorem ipsum dolor sit amet"
|
||||||
excerpt: "Sint sit cillum pariatur eiusmod nulla pariatur ipsum. Sit laborum anim qui mollit tempor pariatur nisi minim dolor. Aliquip et adipisicing sit sit fugiat"
|
excerpt: "Sint sit cillum pariatur eiusmod nulla pariatur ipsum. Sit laborum anim qui mollit tempor pariatur nisi minim dolor. Aliquip et adipisicing sit sit fugiat"
|
||||||
image: "~/assets/images/steps.jpg"
|
image: "~/assets/images/steps.jpg"
|
||||||
|
category: "Guide"
|
||||||
---
|
---
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||||
|
16
src/layouts/BlogLayout.astro
Normal file
16
src/layouts/BlogLayout.astro
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
import Layout from "~/layouts/PageLayout.astro";
|
||||||
|
|
||||||
|
const { meta } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout meta={meta}>
|
||||||
|
<section class="px-8 sm:px-6 py-12 sm:py-16 lg:py-20 mx-auto max-w-3xl">
|
||||||
|
<header>
|
||||||
|
<h1 class="text-center text-4xl md:text-5xl font-bold leading-tighter tracking-tighter mb-8 md:mb-16">
|
||||||
|
<slot name="title" />
|
||||||
|
</h1>
|
||||||
|
</header>
|
||||||
|
<slot />
|
||||||
|
</section>
|
||||||
|
</Layout>
|
39
src/pages/[...blog]/[...page].astro
Normal file
39
src/pages/[...blog]/[...page].astro
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
import { SITE, BLOG } from "~/config.mjs";
|
||||||
|
import { fetchPosts } from "~/utils/fetchPosts";
|
||||||
|
import Layout from "~/layouts/BlogLayout.astro";
|
||||||
|
import BlogList from "~/components/widgets/BlogList.astro";
|
||||||
|
import Pagination from "~/components/widgets/Pagination.astro";
|
||||||
|
import { getCanonical, getPermalink } from "~/utils/permalinks";
|
||||||
|
|
||||||
|
|
||||||
|
export async function getStaticPaths({ paginate }) {
|
||||||
|
if (BLOG?.disabled) return [];
|
||||||
|
|
||||||
|
const posts = await fetchPosts();
|
||||||
|
|
||||||
|
return paginate(posts, {
|
||||||
|
params: { blog: BLOG?.slug || undefined },
|
||||||
|
pageSize: BLOG.postsPerPage,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { page } = Astro.props;
|
||||||
|
const currentPage = page.currentPage ?? 1;
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: `Blog ${currentPage > 1 ? `— Page ${currentPage} ` : ""}— ${SITE.name}`,
|
||||||
|
description: SITE.description,
|
||||||
|
canonical: getCanonical(getPermalink(page.url.current))
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout meta={meta}>
|
||||||
|
<Fragment slot="title">
|
||||||
|
News and step-by-step guides about
|
||||||
|
<span class="bg-clip-text text-transparent bg-gradient-to-r from-blue-500 to-pink-500">AstroWind
|
||||||
|
</span>
|
||||||
|
</Fragment>
|
||||||
|
<BlogList page={page} />
|
||||||
|
<Pagination prevUrl={page.url.prev} nextUrl={page.url.next} />
|
||||||
|
</Layout>
|
33
src/pages/[...blog]/[slug].astro
Normal file
33
src/pages/[...blog]/[slug].astro
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
import { SITE, BLOG } from "~/config.mjs";
|
||||||
|
import { getCanonical, getPermalink } from "~/utils/permalinks";
|
||||||
|
import { fetchPosts } from "~/utils/fetchPosts";
|
||||||
|
import { findImage } from "~/utils/findImage";
|
||||||
|
import Layout from "~/layouts/PageLayout.astro";
|
||||||
|
import BlogPost from "~/components/widgets/BlogPost.astro";
|
||||||
|
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
if (BLOG?.disabled) return [];
|
||||||
|
|
||||||
|
const posts = await fetchPosts();
|
||||||
|
|
||||||
|
return posts.map((post) => ({
|
||||||
|
params: { slug: post.slug, blog: BLOG.postsWithoutBlogSlug ? undefined : BLOG?.slug || undefined },
|
||||||
|
props: { post },
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { post } = Astro.props;
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: `${post.title} — ${SITE.name}`,
|
||||||
|
description: post.description,
|
||||||
|
canonical: post.canonical || getCanonical(getPermalink(post.slug, "post")),
|
||||||
|
image: await findImage(post.image),
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout meta={meta}>
|
||||||
|
<BlogPost post={{ ...post, image: meta.image }} />
|
||||||
|
</Layout>
|
46
src/pages/[...categories]/[category]/[...page].astro
Normal file
46
src/pages/[...categories]/[category]/[...page].astro
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
import { SITE, BLOG } from "~/config.mjs";
|
||||||
|
import { fetchPosts } from "~/utils/fetchPosts";
|
||||||
|
import Layout from "~/layouts/BlogLayout.astro";
|
||||||
|
import BlogList from "~/components/widgets/BlogList.astro";
|
||||||
|
import Pagination from "~/components/widgets/Pagination.astro";
|
||||||
|
import { getCanonical, getPermalink } from "~/utils/permalinks";
|
||||||
|
|
||||||
|
|
||||||
|
export async function getStaticPaths({ paginate }) {
|
||||||
|
if (BLOG?.disabled || BLOG?.category?.disabled) return [];
|
||||||
|
|
||||||
|
const posts = await fetchPosts();
|
||||||
|
|
||||||
|
const categories = new Set()
|
||||||
|
posts.map(post => {
|
||||||
|
typeof post.category === "string" && categories.add(post.category.toLowerCase())
|
||||||
|
})
|
||||||
|
|
||||||
|
return Array.from(categories).map((category) => (
|
||||||
|
paginate(posts.filter((post) => typeof post.category === "string" && category === post.category.toLowerCase()), {
|
||||||
|
params: { category, categories: BLOG?.category?.slug || undefined },
|
||||||
|
pageSize: BLOG.postsPerPage,
|
||||||
|
})
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
const { page } = Astro.props;
|
||||||
|
const { category } = Astro.params;
|
||||||
|
|
||||||
|
const currentPage = page.currentPage ?? 1;
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: `Category ${category} ${currentPage > 1 ? `— Page ${currentPage} ` : ""}— ${SITE.name}`,
|
||||||
|
description: SITE.description,
|
||||||
|
canonical: getCanonical(getPermalink(page.url.current))
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout meta={{ ...meta, noindex: true }}>
|
||||||
|
<Fragment slot="title">
|
||||||
|
Category {category}
|
||||||
|
</Fragment>
|
||||||
|
<BlogList page={page} />
|
||||||
|
<Pagination prevUrl={page.url.prev} nextUrl={page.url.next} />
|
||||||
|
</Layout>
|
46
src/pages/[...tags]/[tag]/[...page].astro
Normal file
46
src/pages/[...tags]/[tag]/[...page].astro
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
import { SITE, BLOG } from "~/config.mjs";
|
||||||
|
import { fetchPosts } from "~/utils/fetchPosts";
|
||||||
|
import Layout from "~/layouts/BlogLayout.astro";
|
||||||
|
import BlogList from "~/components/widgets/BlogList.astro";
|
||||||
|
import Pagination from "~/components/widgets/Pagination.astro";
|
||||||
|
import { getCanonical, getPermalink } from "~/utils/permalinks";
|
||||||
|
|
||||||
|
|
||||||
|
export async function getStaticPaths({ paginate }) {
|
||||||
|
if (BLOG?.disabled || BLOG?.tag?.disabled) return [];
|
||||||
|
|
||||||
|
const posts = await fetchPosts();
|
||||||
|
|
||||||
|
const tags = new Set()
|
||||||
|
posts.map(post => {
|
||||||
|
Array.isArray(post.tags) && post.tags.map(tag => tags.add(tag.toLowerCase()))
|
||||||
|
})
|
||||||
|
|
||||||
|
return Array.from(tags).map((tag) => (
|
||||||
|
paginate(posts.filter((post) => Array.isArray(post.tags) && post.tags.includes(tag)), {
|
||||||
|
params: { tag, tags: BLOG?.tag?.slug || undefined },
|
||||||
|
pageSize: BLOG.postsPerPage,
|
||||||
|
})
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
const { page } = Astro.props;
|
||||||
|
const { tag } = Astro.params;
|
||||||
|
|
||||||
|
const currentPage = page.currentPage ?? 1;
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: `Posts by tag '${tag}' ${currentPage > 1 ? `— Page ${currentPage} ` : ""}— ${SITE.name}`,
|
||||||
|
description: SITE.description,
|
||||||
|
canonical: getCanonical(getPermalink(page.url.current))
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout meta={{ ...meta, noindex: true }}>
|
||||||
|
<Fragment slot="title">
|
||||||
|
Tag {tag}
|
||||||
|
</Fragment>
|
||||||
|
<BlogList page={page} />
|
||||||
|
<Pagination prevUrl={page.url.prev} nextUrl={page.url.next} />
|
||||||
|
</Layout>
|
@ -1,28 +0,0 @@
|
|||||||
---
|
|
||||||
import Layout from "~/layouts/PageLayout.astro";
|
|
||||||
|
|
||||||
import { SITE } from "~/config.mjs";
|
|
||||||
import { fetchPosts } from "~/utils/fetchPosts";
|
|
||||||
|
|
||||||
import BlogList from "~/components/widgets/BlogList.astro";
|
|
||||||
|
|
||||||
export async function getStaticPaths({ paginate }) {
|
|
||||||
const posts = await fetchPosts();
|
|
||||||
|
|
||||||
return paginate(posts, {
|
|
||||||
pageSize: SITE.postsPerPage,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const { page } = Astro.props;
|
|
||||||
|
|
||||||
const currentPage = page.currentPage ?? 1;
|
|
||||||
|
|
||||||
const title = `Blog ${currentPage > 1 ? `— Page ${currentPage} ` : ""}— ${SITE.name}`;
|
|
||||||
const description = SITE.description;
|
|
||||||
const canonical = new URL(page.url.current, Astro.site);
|
|
||||||
---
|
|
||||||
|
|
||||||
<Layout meta={{ title, description, canonical }}>
|
|
||||||
<BlogList page={page} />
|
|
||||||
</Layout>
|
|
@ -1,29 +0,0 @@
|
|||||||
---
|
|
||||||
import { SITE } from "~/config.mjs";
|
|
||||||
import { fetchPosts } from "~/utils/fetchPosts";
|
|
||||||
import { findImage } from "~/utils/findImage";
|
|
||||||
|
|
||||||
import Layout from "~/layouts/PageLayout.astro";
|
|
||||||
import BlogPost from "~/components/widgets/BlogPost.astro";
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
|
||||||
const posts = await fetchPosts();
|
|
||||||
|
|
||||||
return posts.map((post) => ({
|
|
||||||
params: { slug: post.slug },
|
|
||||||
props: { post },
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
const { post } = Astro.props;
|
|
||||||
|
|
||||||
const title = `${post.title} — ${SITE.name}`;
|
|
||||||
const description = post.description;
|
|
||||||
const canonical = post.canonical || new URL(`blog/${post.slug}`, Astro.site);
|
|
||||||
|
|
||||||
const image = await findImage(post.image);
|
|
||||||
---
|
|
||||||
|
|
||||||
<Layout meta={{ title, description, canonical, image, }}>
|
|
||||||
<BlogPost post={{ ...post, image }} />
|
|
||||||
</Layout>
|
|
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
import Layout from "~/layouts/PageLayout.astro";
|
|
||||||
|
|
||||||
import { SITE } from "~/config.mjs";
|
import { SITE } from "~/config.mjs";
|
||||||
|
import { getCanonical, getHomePermalink } from "~/utils/permalinks";
|
||||||
|
import Layout from "~/layouts/PageLayout.astro";
|
||||||
|
|
||||||
import Hero from "~/components/widgets/Hero.astro";
|
import Hero from "~/components/widgets/Hero.astro";
|
||||||
import BasicCTA from "~/components/widgets/BasicCTA.astro";
|
import BasicCTA from "~/components/widgets/BasicCTA.astro";
|
||||||
@ -13,12 +13,14 @@ import StepsLeft from "~/components/widgets/StepsLeft.astro";
|
|||||||
import HighlightedPosts from "~/components/widgets/HighlightedPosts.astro";
|
import HighlightedPosts from "~/components/widgets/HighlightedPosts.astro";
|
||||||
import Stats from "~/components/widgets/Stats.astro";
|
import Stats from "~/components/widgets/Stats.astro";
|
||||||
|
|
||||||
const title = SITE.title;
|
const meta = {
|
||||||
const description = SITE.description;
|
title: SITE.title,
|
||||||
const canonical = new URL("", Astro.site);
|
description: SITE.description,
|
||||||
|
canonical: getCanonical(getHomePermalink()),
|
||||||
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout meta={{ title, description, canonical }}>
|
<Layout meta={meta}>
|
||||||
<Hero />
|
<Hero />
|
||||||
<BasicFeatures />
|
<BasicFeatures />
|
||||||
<StepsLeft />
|
<StepsLeft />
|
||||||
|
@ -2,6 +2,7 @@ import rss from "@astrojs/rss";
|
|||||||
|
|
||||||
import { SITE } from "~/config.mjs";
|
import { SITE } from "~/config.mjs";
|
||||||
import { fetchPosts } from "~/utils/fetchPosts";
|
import { fetchPosts } from "~/utils/fetchPosts";
|
||||||
|
import { getPermalink } from "~/utils/permalinks";
|
||||||
|
|
||||||
const posts = await fetchPosts();
|
const posts = await fetchPosts();
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ export const get = () =>
|
|||||||
site: import.meta.env.SITE,
|
site: import.meta.env.SITE,
|
||||||
|
|
||||||
items: posts.map((post) => ({
|
items: posts.map((post) => ({
|
||||||
link: `blog/${post.slug}`,
|
link: getPermalink(post.slug, "post"),
|
||||||
title: post.title,
|
title: post.title,
|
||||||
description: post.description,
|
description: post.description,
|
||||||
pubDate: post.pubDate,
|
pubDate: post.pubDate,
|
||||||
|
@ -10,9 +10,9 @@ const load = async function () {
|
|||||||
return await getNormalizedPost(post);
|
return await getNormalizedPost(post);
|
||||||
});
|
});
|
||||||
|
|
||||||
const results = (await Promise.all(normalizedPosts)).sort(
|
const results = (await Promise.all(normalizedPosts))
|
||||||
(a, b) => new Date(b.pubDate).valueOf() - new Date(a.pubDate).valueOf()
|
.sort((a, b) => new Date(b.pubDate).valueOf() - new Date(a.pubDate).valueOf())
|
||||||
);
|
.filter((post) => !post.draft);
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -23,3 +23,16 @@ export const fetchPosts = async () => {
|
|||||||
|
|
||||||
return await _posts;
|
return await _posts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const findPostsByIds = async (ids) => {
|
||||||
|
if (!Array.isArray(ids)) return [];
|
||||||
|
|
||||||
|
const posts = await fetchPosts();
|
||||||
|
|
||||||
|
return ids.reduce(function (r, a) {
|
||||||
|
posts.some(function (el) {
|
||||||
|
return a === el.slug && r.push(el);
|
||||||
|
});
|
||||||
|
return r;
|
||||||
|
}, []);
|
||||||
|
};
|
||||||
|
@ -5,6 +5,7 @@ export const getNormalizedPost = async (post) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
pubDate: frontmatter.pubDate,
|
pubDate: frontmatter.pubDate,
|
||||||
|
draft: frontmatter.draft,
|
||||||
|
|
||||||
canonical: frontmatter.canonical,
|
canonical: frontmatter.canonical,
|
||||||
slug: file.split("/").pop().split(".").shift(),
|
slug: file.split("/").pop().split(".").shift(),
|
||||||
|
47
src/utils/permalinks.js
Normal file
47
src/utils/permalinks.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { SITE, BLOG } from "~/config.mjs";
|
||||||
|
|
||||||
|
const trim = (str, ch) => {
|
||||||
|
let start = 0, end = str.length;
|
||||||
|
while(start < end && str[start] === ch)
|
||||||
|
++start;
|
||||||
|
while(end > start && str[end - 1] === ch)
|
||||||
|
--end;
|
||||||
|
return (start > 0 || end < str.length) ? str.substring(start, end) : str;
|
||||||
|
}
|
||||||
|
|
||||||
|
const trimSlash = (s) => trim(s, "/");
|
||||||
|
const createPath = (...params) => "/" + params.filter((el) => !!el).join("/")
|
||||||
|
|
||||||
|
const baseUrl = trimSlash(SITE.baseUrl);
|
||||||
|
const blogBaseUrl = trimSlash(BLOG.slug);
|
||||||
|
const categoryBaseUrl = trim(BLOG?.category?.slug);
|
||||||
|
const tagBaseUrl = trim(BLOG?.tag?.slug);
|
||||||
|
|
||||||
|
const cleanSlug = (slug) => trimSlash(slug);
|
||||||
|
|
||||||
|
export const getCanonical = (path = "") => new URL(path, SITE.domain);
|
||||||
|
|
||||||
|
export const getPermalink = (slug = "", type = "page") => {
|
||||||
|
const _slug = cleanSlug(slug);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case "category":
|
||||||
|
return createPath(baseUrl, categoryBaseUrl, _slug)
|
||||||
|
|
||||||
|
case "tag":
|
||||||
|
return createPath(baseUrl, tagBaseUrl, _slug)
|
||||||
|
|
||||||
|
case "post":
|
||||||
|
return createPath(baseUrl, BLOG.postsWithoutBlogSlug ? "" : blogBaseUrl, _slug);
|
||||||
|
|
||||||
|
case "page":
|
||||||
|
default:
|
||||||
|
return createPath(baseUrl, _slug);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getBlogPermalink = () => getPermalink(blogBaseUrl);
|
||||||
|
export const getHomePermalink = () => {
|
||||||
|
const permalink = getPermalink();
|
||||||
|
return permalink !== "/" ? permalink + "/" : permalink;
|
||||||
|
}
|
Reference in New Issue
Block a user