-
-
Save Adammatthiesen/2ed296220e74c43653ee826d879fd359 to your computer and use it in GitHub Desktop.
Ghost
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CONTENT_API_KEY=YOUR_GHOST_API_KEY | |
CONTENT_API_URL=https://ghost.io | |
CONTENT_API_VER=v5.0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
import SupportOurWork from '@components/crumbs/SupportOurWork.astro'; | |
import { PI, ghostClient } from '@lib/ghost'; | |
import LiveRender from '@layouts/LiveRender.astro'; | |
import Container from '@components/ui/container.astro'; | |
import BackToBlog from '@components/crumbs/BackToBlog.astro'; | |
import GhostPowered from '@components/crumbs/GhostPowered.astro'; | |
import { Picture } from 'astro:assets'; | |
// GET SLUG | |
const { slug } = Astro.params; | |
// IF SLUG DOSNT EXIST THEN THROW ERROR | |
if(slug === undefined){ throw new Error('Slug is required'); } | |
// GET POSTS FROM GHOST | |
const ghostPost = await ghostClient.posts.read({ | |
slug: `${slug}`, include: `${PI}`}) | |
// IF NO POST AVAILABLE THEN REDIRECT TO 404 | |
if(ghostPost === undefined) { return Astro.redirect('/404'); } | |
// GET PAGE VARIABLES AND SETTINGS FROM PAGE CREATION | |
const { title, html, feature_image, feature_image_alt, published_at, updated_at, primary_author, tags } = await ghostPost; | |
// DATE FORMATING/FIXES | |
const locale = "en-US"; | |
const dateOptions: object = { year: "numeric", month: "long", day: "numeric" }; | |
const formattedPublishDate = new Date(published_at).toLocaleDateString(locale, dateOptions ); | |
const formattedUpdatedDate = new Date(updated_at).toLocaleDateString(locale, dateOptions ); | |
--- | |
<LiveRender title={title}> | |
<Container> | |
<div class="mx-auto max-w-5xl mt-5"> | |
<center> | |
<Picture | |
src={feature_image? feature_image : "/mxyz-hero.png"} | |
alt={feature_image_alt? feature_image_alt : "alt"} | |
sizes="(max-width: 800px) 100vw, 800px" | |
width={800} height={600} | |
class="w-full rounded-md object-cover object-center"/> | |
</center> | |
<h1 class="text-4xl lg:text-5xl font-bold lg:tracking-tight mt-1 lg:leading-tight"> | |
{title} | |
</h1> | |
{tags && (<h3 class="text-gray-500">{tags.map((tag) => (<a href={`/blog/tag/${tag.slug}`}> #{tag.name}</a>))}</h3>) } | |
<div class="flex gap-2 mt-3 items-center flex-wrap md:flex-nowrap"> | |
Author: | |
<a href="/blog/authors" class="inline-flex pr-2 mb-2 focus:outline-none rounded-full border focus:z-10 focus:ring-4 focus:ring-gray-700 bg-slate-800 text-slate-300 border-gray-600 hover:bg-slate-600"> | |
<img class="w-7 h-7 me-1 rounded-full" src={primary_author.profile_image} alt= {primary_author.name}> | |
<span class="text-slate-100"> {primary_author.name}</span> | |
</a> | |
</div> | |
</div> | |
<!-- DIVIDER BAR --> | |
<div class="mb-0 mt-0 mx-auto max-w-5xl flex flex-row"> | |
<!-- TOP OF DIVIDER BAR --> | |
<!-- LEFT --> | |
<time class="text-slate-300 flex-1" datetime={published_at}> | |
Published: | |
<span class=" text-xs font-medium inline-flex items-center px-2.5 py-0.5 rounded me-2 bg-slate-700 text-slate-300 border border-slate-500 "> | |
<svg class="w-2.5 h-2.5 me-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20"> | |
<path d="M10 0a10 10 0 1 0 10 10A10.011 10.011 0 0 0 10 0Zm3.982 13.982a1 1 0 0 1-1.414 0l-3.274-3.274A1.012 1.012 0 0 1 9 10V6a1 1 0 0 1 2 0v3.586l2.982 2.982a1 1 0 0 1 0 1.414Z"/> | |
</svg> | |
{formattedPublishDate} | |
</span> | |
</time> | |
<!-- RIGHT --> | |
<time class="text-slate-300 flex-2" datetime={updated_at}> | |
Last Modified: | |
<span class="text-xs font-medium inline-flex items-center px-2.5 py-0.5 rounded bg-slate-700 text-blue-400 border border-blue-400"> | |
<svg class="w-2.5 h-2.5 me-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20"> | |
<path d="M10 0a10 10 0 1 0 10 10A10.011 10.011 0 0 0 10 0Zm3.982 13.982a1 1 0 0 1-1.414 0l-3.274-3.274A1.012 1.012 0 0 1 9 10V6a1 1 0 0 1 2 0v3.586l2.982 2.982a1 1 0 0 1 0 1.414Z"/> | |
</svg> | |
{formattedUpdatedDate} | |
</span> | |
</time> | |
</div> | |
<div class="divider mx-auto max-w-5xl my-0" /> | |
<!-- BOTTOM OF DIVIDER BAR --> | |
<div class="mb-0 mt-0 mx-auto max-w-5xl flex flex-row"> | |
<!-- LEFT --> | |
<div class="flex-1"> | |
<GhostPowered /> | |
</div> | |
<!-- RIGHT --> | |
<div class="flex-2"> | |
<SupportOurWork /> | |
</div> | |
</div> | |
<!-- END OF DIVIDER BAR --> | |
<div class="mx-auto prose prose-lg mt-6 max-w-5xl"> | |
<!-- CONTENT --> | |
<Fragment set:html={html} /> | |
</div> | |
<BackToBlog /> | |
</Container> | |
</LiveRender> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
import { getGhostFeaturedPosts } from "@lib/ghost"; | |
import { Picture } from "astro:assets"; | |
const posts = await getGhostFeaturedPosts(); | |
--- | |
<div class="mt-16 md:mt-10"> | |
<h2 class="text-4xl lg:text-5xl font-bold lg:tracking-tight"> | |
Featured posts from our Blog | |
</h2> | |
</div> | |
{posts.length === 0 ? ( | |
<div class="font-bold mt-10 ml-10"> Sorry</div> | |
<p class="text-gray-500 dark:text-gray-400 ml-10">There are no Featured posts at the moment! Check back later!</p> | |
) : ( | |
<div class="grid sm:grid-cols-2 md:grid-cols-3 mt-10 gap-6"> | |
{posts.map((post) => ( | |
<article class="p-4 border rounded-lg shadow-xl shadow-slate-950 bg-slate-900 border-slate-600"> | |
<div class="w-full rounded-md transition object-cover object-center"> | |
<Picture | |
class="w-full rounded-md transition object-cover object-center" | |
width={800} height={600} | |
src={post.feature_image} | |
alt={post.feature_image_alt}/> | |
</div> | |
<div class="mt-1"> | |
<h3 class="font-semibold inline text-lg">{post.title}</h3> | |
<p class="text-slate-300 mt-0 leading-relaxed">{post.excerpt}</p> | |
</div> | |
<div class="flex flex-row mt-5"> | |
<div class="flex-1" /> | |
<div class="flex-none justify-end justify-self-end justify-items-end"> | |
<a href={`/blog/${post.slug}`} class="text-slate-200 bg-gradient-to-r from-blue-500 via-blue-700 to-blue-900 hover:bg-gradient-to-br focus:ring-4 focus:outline-none focus:ring-blue-800 font-medium rounded-lg text-sm px-3 py-1.5 text-center me-2 mb-0 ">Read More</a> | |
</div> | |
</div> | |
</article> | |
))} | |
</div> | |
)} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import GhostContentAPI from '@tryghost/content-api'; | |
const env = import.meta.env; | |
export const PI = ['authors', 'tags'] | |
export const ghostClient = new GhostContentAPI({ | |
url: env.CONTENT_API_URL, key: env.CONTENT_API_KEY, | |
version: env.CONTENT_API_VER }) | |
export const getGhostPosts = async () => { | |
const posts = await ghostClient.posts.browse({ | |
limit: 'all', include: `${PI}`, filter: 'visibility:public' }) | |
return posts; | |
} | |
export const getGhostFeaturedPosts = async () => { | |
const posts = await ghostClient.posts.browse({ | |
limit: '3', include: `${PI}`, filter: 'featured:true' }) | |
return posts; | |
} | |
export const getGhostAuthors = async () => { | |
const authors = await ghostClient.authors.browse() | |
return authors; | |
} | |
export const getGhostTags = async () => { | |
const tags = await ghostClient.tags.browse() | |
.include({"count.posts": true,}) | |
return tags; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
import { Picture } from "astro:assets"; | |
const { post } = Astro.props; | |
const { title, excerpt, feature_image, feature_image_alt, published_at, primary_author } = post; | |
const locale = "en-US"; | |
const dateOptions: object = { year: "numeric", month: "long", day: "numeric" }; | |
const formattedPublishDate = new Date(published_at).toLocaleDateString(locale, dateOptions ); | |
--- | |
<li> | |
<div class="divider" /> | |
<a href={`/blog/${post.slug}`}> <div class="sr-only">Blog Post</div> | |
<div class="grid md:grid-cols-2 gap-5 md:gap-10 items-center"> | |
<Picture | |
src={feature_image? feature_image : "/mxyz-hero.png"} | |
alt={feature_image_alt? feature_image_alt : "alt"} | |
sizes="(max-width: 800px) 100vw, 800px" | |
width={800} height={600} | |
class="w-full rounded-md object-cover object-center"/> | |
<div class="sr-only">Blog Post Image</div> | |
<div> | |
<h2 class="text-3xl font-semibold leading-snug tracking-tight mt-1 ">{title}</h2> | |
<div class="flex gap-2 mt-3"> <div class="sr-only">Author</div> | |
<a href="/blog/authors" class="inline-flex pr-2 mb-2 focus:outline-none rounded-full border focus:z-10 focus:ring-4 focus:ring-gray-700 bg-slate-800 text-slate-300 border-gray-600 hover:bg-slate-600"> | |
<img class="w-7 h-7 me-1 rounded-full" src={primary_author.profile_image} alt={primary_author.name}> | |
<span class="text-slate-300 mt-1">{primary_author.name}</span> | |
</a> | |
<time class="text-slate-300 mt-1" datetime={published_at}>{formattedPublishDate}</time> | |
</div> | |
{excerpt && (<p class="text-slate-400">{excerpt}</p>)} | |
</div> | |
</div> | |
</a> | |
</li> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
import GhostPost from '@components/blog/GhostPost.astro'; | |
import { getGhostPosts } from '@lib/ghost'; | |
import LiveRender from '@layouts/LiveRender.astro'; | |
import Container from '@components/ui/container.astro'; | |
import Sectionhead from '@components/ui/sectionhead.astro'; | |
import GhostPowered from '@components/crumbs/GhostPowered.astro'; | |
import RssIcon from '@components/crumbs/RssIcon.astro'; | |
import OurBlogAuthors from '@components/blog/OurBlogAuthors.astro'; | |
const posts = await getGhostPosts(); | |
const tags = await getGhostTags(); | |
--- | |
<LiveRender title="Blog"> | |
<Container> | |
<GhostPowered /> | |
<Sectionhead> | |
<Fragment slot="title"> Blog <RssIcon /></Fragment> | |
<Fragment slot="desc">Our Posts & Tutorials, Our Tutorials mainly Focus on FOSS (Free Open Source Software).</Fragment> | |
</Sectionhead> | |
<main class="mt-5 max-w-5xl mx-auto"> | |
{tags && ( | |
<div class="text-white mt-2"> | |
Blog Tags: <span class="text-gray-400"> | |
{tags.map((tag) => ( | |
<a href={`/blog/tag/${tag.slug}`}> #{tag.name}</a> | |
))} </span> | |
</div> | |
)} | |
<OurBlogAuthors /> | |
<ul class="grid gap-16 "> | |
{ posts.map((post) => <GhostPost post={post} />) } | |
</ul> | |
</main> | |
</Container> | |
</LiveRender> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
import LiveRender from '@layouts/LiveRender.astro'; | |
import Container from '@components/ui/container.astro'; | |
import { ghostClient } from '@lib/ghost'; | |
import GhostPowered from '@components/crumbs/GhostPowered.astro'; | |
import Sectionhead from '@components/ui/sectionhead.astro'; | |
import OurBlogAuthors from '@components/blog/OurBlogAuthors.astro'; | |
import GhostPost from '@components/blog/GhostPost.astro'; | |
import BackToBlog from '@components/crumbs/BackToBlog.astro'; | |
const { slug } = Astro.params; | |
// IF SLUG DOSNT EXIST THEN THROW ERROR | |
if(slug === undefined){ throw new Error('Slug is required'); } | |
const ghostTag = await ghostClient.tags.read({ | |
slug: `${slug}`, | |
include: `count.posts` | |
}) | |
// IF NO TAG AVAILABLE THEN REDIRECT TO 404 | |
if(ghostTag === undefined) { return Astro.redirect('/404'); } | |
const posts = await ghostClient.posts.browse({ | |
filter: `tag:${ghostTag.slug}`, | |
limit: 'all', | |
include: ['tags', 'authors'], | |
}); | |
--- | |
<LiveRender title="tags"> | |
<Container> | |
<GhostPowered /> | |
<Sectionhead> | |
<Fragment slot="title"> Blog ( #{ghostTag.name} )</Fragment> | |
<Fragment slot="desc">Total Posts: {ghostTag.count.posts}</Fragment> | |
</Sectionhead> | |
<BackToBlog /> | |
<main class="mt-5 max-w-5xl mx-auto"> | |
<OurBlogAuthors /> | |
<ul class="grid gap-16 "> | |
{ posts.map((post) => <GhostPost post={post} />) } | |
</ul> | |
</main> | |
</Container> | |
</LiveRender> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment