Compare commits

...

27 Commits

Author SHA1 Message Date
Adam Matthiesen dfaa820f06 Update readme 2024-03-21 01:54:57 +00:00
github-actions[bot] b98c62f0b6
Chore: Ready for Release (#30)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-19 05:06:38 -07:00
dependabot[bot] 6ccd6dc5b8
Bump the prod-dependencies group with 5 updates (#29)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-03-19 05:02:20 -07:00
dependabot[bot] 3f6e9a996b
Bump the dev-dependencies group with 3 updates (#28)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-03-19 04:57:36 -07:00
github-actions[bot] a1ea3d7a78
Chore: Ready for Release (#26)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-16 11:07:39 -07:00
create-issue-branch[bot] 6464de28f8
fix: 🐛 need new fallback for ogImage (#25)
Co-authored-by: create-issue-branch[bot] <53036503+create-issue-branch[bot]@users.noreply.github.com>
Co-authored-by: Adam Matthiesen <amatthiesen@outlook.com>
2024-03-16 11:05:57 -07:00
github-actions[bot] b375a29495
Chore: Ready for Release (#23)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-15 14:27:09 -07:00
create-issue-branch[bot] e54bfbbfd2
feat: Not able to pull publication title from Hashnode (#22)
Co-authored-by: create-issue-branch[bot] <53036503+create-issue-branch[bot]@users.noreply.github.com>
Co-authored-by: Adam Matthiesen <amatthiesen@outlook.com>
2024-03-15 14:25:49 -07:00
Rishi Raj Jain cf327f266f
Update README.md (#20)
Co-authored-by: Adam Matthiesen <30383579+Adammatthiesen@users.noreply.github.com>
2024-03-15 12:32:17 -07:00
github-actions[bot] fae567c480
Chore: Ready for Release (#19)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-14 03:06:16 -07:00
Adam Matthiesen 784cb63fcb
view transition updates (#18) 2024-03-14 03:04:22 -07:00
github-actions[bot] b7eec6bb98
Chore: Ready for Release (#17)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-12 20:13:01 -07:00
create-issue-branch[bot] 337a5b09ce
feat: Chore: Update package.json information (#16)
Co-authored-by: create-issue-branch[bot] <53036503+create-issue-branch[bot]@users.noreply.github.com>
Co-authored-by: Adam Matthiesen <amatthiesen@outlook.com>
2024-03-12 20:11:46 -07:00
github-actions[bot] 32e2569373
Chore: Ready for Release (#14)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-12 15:16:30 -07:00
create-issue-branch[bot] fc94343873
feat: Chore: Update `AIK` and add ViewTransition support (#13)
Co-authored-by: create-issue-branch[bot] <53036503+create-issue-branch[bot]@users.noreply.github.com>
Co-authored-by: Adam Matthiesen <amatthiesen@outlook.com>
Co-authored-by: Jacob Jenkins <7649031+jdtjenkins@users.noreply.github.com>
2024-03-12 15:15:03 -07:00
Adam Matthiesen 8fbe34124d
Update coauthor.yml 2024-03-12 15:14:25 -07:00
github-actions[bot] cb033a0bd2
Chore: Ready for Release (#11)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-11 20:01:55 -07:00
Adam Matthiesen 4df3b17fea
Update changeset-dependabot.yml 2024-03-11 20:00:48 -07:00
Adam Matthiesen e1dbf1dc5c
Update changeset-main.yml 2024-03-11 20:00:17 -07:00
create-issue-branch[bot] 773376207b
feat: Add SSR Handling (#10)
* Create draft PR for #9
[skip ci]

* Implement SSR

* add changeset

---------

Co-authored-by: create-issue-branch[bot] <53036503+create-issue-branch[bot]@users.noreply.github.com>
Co-authored-by: Adam Matthiesen <amatthiesen@outlook.com>
2024-03-11 19:56:58 -07:00
Adam Matthiesen 4b159a9bbb
Update gitlab-sync.yml 2024-03-11 15:15:15 -07:00
Adam Matthiesen b634d82bc1
Update gitlab-sync.yml 2024-03-11 15:13:15 -07:00
Adam Matthiesen bcf5a896a2
Update gitlab-sync.yml 2024-03-11 15:07:30 -07:00
Adam Matthiesen ce1401ba81
Update gitlab-sync.yml 2024-03-11 15:00:59 -07:00
Adam Matthiesen 17d2c9f272
Update gitlab-sync.yml 2024-03-11 14:58:55 -07:00
Adam Matthiesen 943819d43b
Update gitlab-sync.yml 2024-03-11 14:54:24 -07:00
Adam Matthiesen 453880f1e3
Update gitlab-sync.yml 2024-03-11 14:52:44 -07:00
28 changed files with 786 additions and 326 deletions

View File

@ -1,8 +1,8 @@
name: "Changesets: Build Changesets for Dependabot" name: "Changesets: Build Changesets for Dependabot"
#on: pull_request on: pull_request
on: #on:
workflow_dispatch: #workflow_dispatch:
permissions: permissions:
contents: write contents: write

View File

@ -1,5 +1,6 @@
name: "Changesets: Publish Packages from main" name: "Changesets: Publish Packages from main"
on: on:
workflow_dispatch:
push: push:
branches: branches:
- main - main

View File

@ -14,4 +14,4 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: kevinzunigacuellar/coauthor-action@v0.1.1 - uses: kevinzunigacuellar/coauthor-action@v0.1.2

View File

@ -1,9 +1,11 @@
name: "Sync: GitHub => GitLab" name: "Sync to GitLab"
on: on:
- push - push
- delete - delete
permissions: read-all
jobs: jobs:
sync: sync:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -12,11 +14,11 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: jauderho/git-repo-sync@63782025e80e84c48b25a1ee6bb9a22a3bd570d3 - uses: MatthiesenXYZ/git-sync-action@v1.1
with: with:
# Such as https://github.com/wangchucheng/git-repo-sync.git # Such as https://github.com/wangchucheng/git-repo-sync.git
target-url: ${{ secrets.GITLAB_URL }} target-url: ${{ secrets.GITLAB_URL }}
# Such as wangchucheng # Such as wangchucheng
target-username: ${{ secrets.GITLAB_USERNAME }} target-username: ${{ secrets.GITLAB_USERNAME }}
# You can store token in your project's 'Setting > Secrets' and reference the name here. Such as ${{ secrets.ACCESS\_TOKEN }} # You can store token in your project's 'Setting > Secrets' and reference the name here. Such as ${{ secrets.ACCESS\_TOKEN }}
target-token: ${{ secrets.GITLAB_ACCESS }} target-token: ${{ secrets.GITLAB_ACCESS }}

View File

@ -31,4 +31,6 @@ You can now edit files in `package`. Please note that making changes to those fi
[MIT Licensed](./LICENSE). Made with ❤️ by [Adam M.](https://github.com/adammatthiesen). [MIT Licensed](./LICENSE). Made with ❤️ by [Adam M.](https://github.com/adammatthiesen).
This project is cloned to [Gitea](https://git.matthiesen.dev)
This project is also cloned to [GitLab](https://gitlab.com/matthiesenxyz/astro-hashnode) This project is also cloned to [GitLab](https://gitlab.com/matthiesenxyz/astro-hashnode)

View File

@ -13,7 +13,7 @@
"ci:publish": "pnpm changeset publish" "ci:publish": "pnpm changeset publish"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "1.6.0", "@biomejs/biome": "1.6.1",
"@changesets/cli": "^2.27.1" "@changesets/cli": "^2.27.1"
} }
} }

View File

@ -1,5 +1,54 @@
# @matthiesenxyz/astro-hashnode # @matthiesenxyz/astro-hashnode
## 0.1.8
### Patch Changes
- 6ccd6dc: Bump dependencies:
- @tailwindcss/vite from to
- astro-font from to
- tailwindcss from to
- @astrojs/node from to
- astro from to
## 0.1.7
### Patch Changes
- 6464de2: [fix] add extra fallback option for ogImage
## 0.1.6
### Patch Changes
- cf327f2: Update README.md
- e54bfbb: [Internal] better handling of the `hashnodeURL` input to verify that including `http` or `https` in the URL does not break the entire integration
## 0.1.5
### Patch Changes
- 784cb63: view transition updates
## 0.1.4
### Patch Changes
- 337a5b0: added new keyword "cms" and updated Dependencies
## 0.1.3
### Patch Changes
- fc94343: This updates internal `AIK` as well as impliments ViewTransitions with a disable switch in the user config
## 0.1.2
### Patch Changes
- 7733762: Add SSR support for blog posts (Tags are still prerendered)
## 0.1.1 ## 0.1.1
### Patch Changes ### Patch Changes

View File

@ -11,7 +11,7 @@ pnpm astro add @matthiesenxyz/astro-hashnode
``` ```
```bash ```bash
npm astro add @matthiesenxyz/astro-hashnode npx astro add @matthiesenxyz/astro-hashnode
``` ```
```bash ```bash
@ -54,6 +54,7 @@ export default defineConfig({
astroHashnode({ astroHashnode({
hashnodeURL: 'astroplayground.hashnode.dev', // Your hashnode URL hashnodeURL: 'astroplayground.hashnode.dev', // Your hashnode URL
landingPage: true, // Lets you disable the default landing page! landingPage: true, // Lets you disable the default landing page!
useViewTransitions: true, // Lets you enable/disable the default included ViewTransitions.
layoutComponent: './src/layouts/YourLayout.astro' // Lets you change the default Layout.astro being used by the Integration Pages. layoutComponent: './src/layouts/YourLayout.astro' // Lets you change the default Layout.astro being used by the Integration Pages.
verbose: false // Change to Verbose console output verbose: false // Change to Verbose console output
}) })

View File

@ -1,6 +1,6 @@
{ {
"name": "@matthiesenxyz/astro-hashnode", "name": "@matthiesenxyz/astro-hashnode",
"version": "0.1.1", "version": "0.1.8",
"description": "An Integration to bring your Hashnode Headless Blog content into Astro!", "description": "An Integration to bring your Hashnode Headless Blog content into Astro!",
"author": { "author": {
"email": "adam@matthiesen.xyz", "email": "adam@matthiesen.xyz",
@ -12,6 +12,7 @@
"astro-integration", "astro-integration",
"withastro", "withastro",
"astro", "astro",
"cms",
"hashnode", "hashnode",
"blog", "blog",
"graphql", "graphql",
@ -43,15 +44,15 @@
"vite": "^5.1.5" "vite": "^5.1.5"
}, },
"dependencies": { "dependencies": {
"@tailwindcss/vite": "4.0.0-alpha.7", "@tailwindcss/vite": "4.0.0-alpha.9",
"astro-font": "^0.0.77", "astro-font": "^0.0.78",
"astro-integration-kit": "^0.5.1", "astro-integration-kit": "0.6.0",
"astro-remote": "^0.3.2", "astro-remote": "^0.3.2",
"astro-seo": "^0.8.3", "astro-seo": "^0.8.3",
"graphql": "^16.8.1", "graphql": "^16.8.1",
"graphql-request": "^6.1.0", "graphql-request": "^6.1.0",
"picocolors": "^1.0.0", "picocolors": "^1.0.0",
"tailwindcss": "4.0.0-alpha.7", "tailwindcss": "4.0.0-alpha.9",
"ultrahtml": "^1.5.3" "ultrahtml": "^1.5.3"
} }
} }

View File

@ -15,6 +15,7 @@ export default defineIntegration({
optionsSchema, optionsSchema,
plugins: [ ...corePlugins, addDtsPlugin ], plugins: [ ...corePlugins, addDtsPlugin ],
setup({ options }) { setup({ options }) {
type outputType = "static" | "hybrid" | "server";
return { return {
"astro:config:setup": ({ "astro:config:setup": ({
@ -50,6 +51,13 @@ export default defineIntegration({
throw new AstroError(message) throw new AstroError(message)
} }
// Check if output is static or hybrid
const checkIfStatic = (output: outputType) => {
if (output === "static") { return true }
if (output === "hybrid") { return true }
return false
}
hashLogNoVerbose("Setting up Astro-Hashnode Integration") hashLogNoVerbose("Setting up Astro-Hashnode Integration")
// Check for Hashnode URL // Check for Hashnode URL
@ -61,8 +69,7 @@ export default defineIntegration({
hashLog("Setting up Virtual Imports and Layout Component") hashLog("Setting up Virtual Imports and Layout Component")
// Setup Layout Component // Setup Layout Component
// biome-ignore lint/suspicious/noImplicitAnyLet: This is a false positive let layoutComponentPath: string;
let layoutComponentPath
if (options.layoutComponent) { if (options.layoutComponent) {
layoutComponentPath = rootResolve(options.layoutComponent) layoutComponentPath = rootResolve(options.layoutComponent)
@ -81,8 +88,8 @@ export default defineIntegration({
content: readFileSync(resolve("./definitions/astro-hashnode.d.ts"), "utf-8"), content: readFileSync(resolve("./definitions/astro-hashnode.d.ts"), "utf-8"),
}) })
hashLog("Setting up 'Tailwind CSS v4' Integration")
// Add & Setup Tailwind CSS // Add & Setup Tailwind CSS
hashLog("Setting up 'Tailwind CSS v4' Integration")
const twplugin = tailwindcss(); const twplugin = tailwindcss();
for (const twp of twplugin) { for (const twp of twplugin) {
addVitePlugin(twp); addVitePlugin(twp);
@ -102,22 +109,19 @@ export default defineIntegration({
} }
}) })
hashLog("Setting up Page Routes")
// Add Page Routes // Add Page Routes
hashLog("Setting up Page Routes")
if (options.landingPage) { if (options.landingPage) {
injectRoute({ injectRoute({
pattern: config.base, pattern: config.base,
entrypoint: resolve("./pages/index.astro"), entrypoint: resolve("./pages/index.astro"),
prerender: true,
}); });
} }
injectRoute({ injectRoute({
pattern: `${config.base}blog`, pattern: `${config.base}blog`,
entrypoint: resolve("./pages/blog/index.astro"), entrypoint: resolve("./pages/blog/index.astro"),
}) })
injectRoute({
pattern: `${config.base}blog/[slug]`,
entrypoint: resolve("./pages/blog/[slug].astro"),
})
injectRoute({ injectRoute({
pattern: `${config.base}blog/about`, pattern: `${config.base}blog/about`,
entrypoint: resolve("./pages/blog/about.astro"), entrypoint: resolve("./pages/blog/about.astro"),
@ -125,7 +129,26 @@ export default defineIntegration({
injectRoute({ injectRoute({
pattern: `${config.base}blog/tags/[tag]`, pattern: `${config.base}blog/tags/[tag]`,
entrypoint: resolve("./pages/blog/tags/[tag].astro"), entrypoint: resolve("./pages/blog/tags/[tag].astro"),
prerender: true,
}) })
// Add Blog Post Routes based on output type
if ( checkIfStatic(config.output) ) {
// Static & Hybrid Routes
injectRoute({
pattern: `${config.base}blog/[slug]`,
entrypoint: resolve("./pages/blog/[slug].astro"),
prerender: true,
})
} else {
// Server Routes
injectRoute({
pattern: `${config.base}blog/[slug]`,
entrypoint: resolve("./pages/ssr-pages/[slug].astro"),
})
}
}, },
"astro:config:done": ({ logger }) => { "astro:config:done": ({ logger }) => {
const HashLogger = logger.fork(c.bold(c.blue("Astro-Hashnode"))); const HashLogger = logger.fork(c.bold(c.blue("Astro-Hashnode")));

View File

@ -20,16 +20,24 @@ const { post } = Astro.props;
height={50} height={50}
class="rounded-3xl mr-3" class="rounded-3xl mr-3"
loading="eager" loading="eager"
transition:animate={"fade"}
transition:name={'author:' + post.author.profilePicture}
/> />
<div class="mt-3 flex"> <div class="mt-3 flex">
<span>{post.author.name}</span> <span transition:animate={"fade"}
transition:name={'author:' + post.author.name}
>{post.author.name}</span>
<span class="mx-3 block font-bold text-slate-500">.</span> <span class="mx-3 block font-bold text-slate-500">.</span>
</div> </div>
</div> </div>
</div> </div>
<div class="mb-5 flex w-full flex-row items-center justify-center md:mb-0 md:w-auto md:justify-start"> <div class="mb-5 flex w-full flex-row items-center justify-center md:mb-0 md:w-auto md:justify-start" >
<span>{getFormattedDate(post.publishedAt)}</span> <span transition:animate={"fade"}
transition:name={'hero:' + post.publishedAt}
>{getFormattedDate(post.publishedAt)}</span>
<span class="mx-3 block font-bold text-slate-500">.</span> <span class="mx-3 block font-bold text-slate-500">.</span>
<span>{post.readTimeInMinutes} min read</span> <span transition:animate={"fade"}
transition:name={'hero:' + post.readTimeInMinutes}
>{post.readTimeInMinutes} min read</span>
</div> </div>
</div> </div>

View File

@ -7,6 +7,27 @@ const aboutPageData = await getAboutPage();
const baseURL = import.meta.env.BASE_URL; const baseURL = import.meta.env.BASE_URL;
const pathname = new URL(Astro.request.url).pathname;
// remove leading and trailing slash
const removeTrailingAndLeadingSlash = (str:string) => {
// define checked string as the original string
let checkedStr = str;
// remove leading slash
if (str.startsWith("/")) {
checkedStr = str.slice(1);
}
// remove trailing slash
if (str.endsWith("/")) {
checkedStr = str.slice(0, -1);
}
// return checked string
return checkedStr;
}
const currentPath = removeTrailingAndLeadingSlash(pathname);
--- ---
<header class="flex bg-blue-200 w-full p-3"> <header class="flex bg-blue-200 w-full p-3">
<h1 class="text-2xl"> <h1 class="text-2xl">
@ -35,8 +56,22 @@ const baseURL = import.meta.env.BASE_URL;
</a> </a>
</h1> </h1>
<div class="ml-5 pt-0.5 text-lg"> <div class="ml-5 pt-0.5 text-lg">
<a class="mr-3" href={baseURL}>Home</a> <a
<a class="mr-3" href={`${baseURL}blog`}>Blog</a> class=`mr-3 ${currentPath === "" ? "font-bold" : ""}`
{aboutPageData && <a href={`${baseURL}blog/about/`}>About</a>} href={baseURL}
>Home
</a>
<a
class=`mr-3 ${currentPath === "blog" ? "font-bold" : ""}`
href={`${baseURL}blog`}
>Blog
</a>
{ aboutPageData && (
<a
class=`mr-3 ${currentPath === "blog/about" ? "font-bold" : ""}`
href={`${baseURL}blog/about`}
>About
</a>
) }
</div> </div>
</header> </header>

View File

@ -26,6 +26,7 @@ const p = await getPost(post.slug);
src={p.coverImage.url} src={p.coverImage.url}
alt={post.title} alt={post.title}
inferSize={true} inferSize={true}
transition:name={'hero:' + p.coverImage.url}
/> />
<div class="flex flex-col m-4"> <div class="flex flex-col m-4">
<p class="mb-2 text-lg">{post.brief}</p> <p class="mb-2 text-lg">{post.brief}</p>

View File

@ -1,6 +1,6 @@
declare module 'virtual:astro-hashnode/config' { declare module 'virtual:astro-hashnode/config' {
const userConfig: import("./src/schemas/user-config").Options; const Config: import("./src/schemas/user-config").Options;
export default config as userConfig; export default config as Config;
} }
declare module 'virtual:astro-hashnode/components' { declare module 'virtual:astro-hashnode/components' {

View File

@ -1,18 +1,28 @@
import { gql, GraphQLClient } from "graphql-request"; import { gql, GraphQLClient } from "graphql-request";
import type { AllPostsData, PostOrPageData, PublicationData } from "./schema"; import type { AllPostsData, PostOrPageData, PublicationData } from "./schema";
import Config from "virtual:astro-hashnode/config"; import config from "virtual:astro-hashnode/config";
export const getClient = () => { export const getClient = () => {
return new GraphQLClient("https://gql.hashnode.com") return new GraphQLClient("https://gql.hashnode.com")
} }
export function removeHTTPSProtocol(url: string) {
return url.replace(/^https?:\/\//, '');
}
export function removeHTTPProtocol(url: string) {
const fixHTTPS = removeHTTPSProtocol(url);
return fixHTTPS.replace(/^http?:\/\//, '');
}
const newURL = removeHTTPProtocol(config.hashnodeURL);
export const getAllPosts = async () => { export const getAllPosts = async () => {
const client = getClient(); const client = getClient();
const allPosts = await client.request<AllPostsData>( const allPosts = await client.request<AllPostsData>(
gql` gql`
query allPosts { query allPosts {
publication(host: "${Config.hashnodeURL}") { publication(host: "${newURL}") {
title title
posts(first: 20) { posts(first: 20) {
pageInfo{ pageInfo{
@ -56,7 +66,7 @@ export const getPost = async (slug: string) => {
const data = await client.request<PostOrPageData>( const data = await client.request<PostOrPageData>(
gql` gql`
query postDetails($slug: String!) { query postDetails($slug: String!) {
publication(host: "${Config.hashnodeURL}") { publication(host: "${newURL}") {
post(slug: $slug) { post(slug: $slug) {
author{ author{
name name
@ -92,7 +102,7 @@ export const getAboutPage = async () => {
const page = await client.request<PostOrPageData>( const page = await client.request<PostOrPageData>(
gql` gql`
query pageData { query pageData {
publication(host: "${Config.hashnodeURL}") { publication(host: "${newURL}") {
staticPage(slug: "about") { staticPage(slug: "about") {
title title
content { content {
@ -114,11 +124,14 @@ export const getPublication = async () => {
const data = await client.request<PublicationData>( const data = await client.request<PublicationData>(
gql` gql`
query pubData { query pubData {
publication(host: "${Config.hashnodeURL}") { publication(host: "${newURL}") {
title title
displayTitle displayTitle
descriptionSEO descriptionSEO
favicon favicon
author {
profilePicture
}
preferences { preferences {
logo logo
disableFooterBranding disableFooterBranding

View File

@ -60,6 +60,9 @@ export const PublicationDataSchema = z.object({
displayTitle: z.string(), displayTitle: z.string(),
descriptionSEO: z.string(), descriptionSEO: z.string(),
favicon: z.string(), favicon: z.string(),
author: z.object({
profilePicture: z.string(),
}),
preferences: z.object({ preferences: z.object({
logo: z.string(), logo: z.string(),
disableFooterBranding: z.boolean(), disableFooterBranding: z.boolean(),

View File

@ -1,3 +1,3 @@
import astroHashnode from "./astro-hashnode.js"; import astroHashnode from "./astro-hashnode";
export default astroHashnode; export default astroHashnode;

View File

@ -6,6 +6,10 @@ import { getPublication } from '../hn-gql'
import { SEO } from "astro-seo"; import { SEO } from "astro-seo";
import { AstroFont } from "astro-font"; import { AstroFont } from "astro-font";
import type { AstroHashnodeLayoutProps } from '../proptypes/layouttypes' import type { AstroHashnodeLayoutProps } from '../proptypes/layouttypes'
import { ViewTransitions } from 'astro:transitions';
import config from "virtual:astro-hashnode/config";
const useTranstions = config.useViewTransitions;
const pubData = await getPublication(); const pubData = await getPublication();
@ -37,7 +41,7 @@ const { pageTitle, hideFooter, hideHeader, ogImage } = Astro.props as AstroHashn
basic: { basic: {
title: pageTitle ? pageTitle + " | " + pubHeader : pubHeader, title: pageTitle ? pageTitle + " | " + pubHeader : pubHeader,
type: 'text', type: 'text',
image: ogImage || pubData.favicon, image: ogImage || pubData.favicon || pubData.author.profilePicture,
}, },
optional: { optional: {
description: pubData.descriptionSEO, description: pubData.descriptionSEO,
@ -54,10 +58,11 @@ const { pageTitle, hideFooter, hideHeader, ogImage } = Astro.props as AstroHashn
] ]
}} }}
/> />
{useTranstions && <ViewTransitions />}
</head> </head>
<body> <body>
<div class="flex flex-col"> <div class="flex flex-col">
{!hideHeader && <Header />} {!hideHeader && <Header transition:animate="none" />}
<div class="flex flex-wrap flex-col mt-0 mr-auto mb-0 ml-auto lg:w-[60%]"> <div class="flex flex-wrap flex-col mt-0 mr-auto mb-0 ml-auto lg:w-[60%]">
<slot /> <slot />
</div> </div>

View File

@ -18,6 +18,7 @@ export async function getStaticPaths() {
} }
const { slug } = Astro.params; const { slug } = Astro.params;
const post = await getPost(slug); const post = await getPost(slug);
--- ---
<Layout pageTitle={post.title} ogImage={post.coverImage.url}> <Layout pageTitle={post.title} ogImage={post.coverImage.url}>
<article class="bg-white p-3 mt-3 flex flex-col"> <article class="bg-white p-3 mt-3 flex flex-col">
@ -27,11 +28,12 @@ const post = await getPost(slug);
alt={post.title} alt={post.title}
inferSize={true} inferSize={true}
loading="eager" loading="eager"
transition:name={'hero:' + post.coverImage.url}
/> />
<h1 class="text-4xl font-bold pt-5">{post.title}</h1> <h1 class="text-4xl font-bold pt-5" transition:name={'banner'} transition:animate={'fade'}>{post.title}</h1>
<h2 class="text-xl pt-3 pb-3" aria-label="CoverPhoto Subtitle">{post.subtitle}</h2> <h2 class="text-xl pt-3 pb-3" aria-label="CoverPhoto Subtitle">{post.subtitle}</h2>
<Author post={post} /> <Author post={post}/>
<div class="flex flex-wrap justify-center items-center mt-5 mb-5"> <div class="flex flex-wrap justify-center items-center mt-5 mb-5">
{post.tags && post.tags.map((tag) => <Tag tag={tag} />)} {post.tags && post.tags.map((tag) => <Tag tag={tag} />)}

View File

@ -9,7 +9,9 @@ const data = await getAboutPage();
<Layout pageTitle="About"> <Layout pageTitle="About">
<div class="flex flex-col justify-center p-2"> <div class="flex flex-col justify-center p-2">
<h2 class="text-3xl mb-3">{data.title} Page</h2> <h2 class="text-3xl mb-3"
transition:name={'banner'}
transition:animate={'fade'}>{data.title}</h2>
<div class="about-content"> <div class="about-content">
<Markdown content={data.content.markdown} <Markdown content={data.content.markdown}
components={{ components={{

View File

@ -10,7 +10,7 @@ const allPosts = data.publication.posts.edges;
--- ---
<Layout pageTitle="Blog"> <Layout pageTitle="Blog">
<div class="flex flex-col justify-center items-center p-2"> <div class="flex flex-col justify-center items-center p-2">
<h2 class="text-2xl pt-2 font-semibold">{`Welcome to ${pub.displayTitle || pub.title}`}</h2> <h2 transition:animate={'fade'} transition:name={'banner'} class="text-2xl pt-2 font-semibold">{`Welcome to ${pub.displayTitle || pub.title}`}</h2>
<Posts allPosts={allPosts}/> <Posts allPosts={allPosts}/>
</div> </div>

View File

@ -4,10 +4,13 @@ import Posts from '../../../components/Posts.astro';
import {getAllPosts} from '../../../hn-gql'; import {getAllPosts} from '../../../hn-gql';
import Taged from '../../../components/Tag.astro'; import Taged from '../../../components/Tag.astro';
export const prerender = true
export async function getStaticPaths() { export async function getStaticPaths() {
const data = await getAllPosts(); const data = await getAllPosts();
const allPosts = data.publication.posts.edges; const allPosts = data.publication.posts.edges;
// biome-ignore lint/complexity/useFlatMap: <explanation>
const allTags = [...new Set(allPosts.map((post) => post.node.tags).flat())]; const allTags = [...new Set(allPosts.map((post) => post.node.tags).flat())];
const jsonObject = allTags.map((object) => JSON.stringify(object)); const jsonObject = allTags.map((object) => JSON.stringify(object));
const uniqueSet = new Set(jsonObject); const uniqueSet = new Set(jsonObject);
@ -15,8 +18,10 @@ export async function getStaticPaths() {
return uniqueTags.map((uTag) => { return uniqueTags.map((uTag) => {
const filteredPosts: { node: { author: { name: string; profilePicture: string; }; publishedAt: string; title: string; subtitle: string; brief: string; slug: string; readTimeInMinutes: number; content: { html: string; }; tags: { name: string; slug: string; }[]; coverImage: { url: string; }; }; }[] = []; const filteredPosts: { node: { author: { name: string; profilePicture: string; }; publishedAt: string; title: string; subtitle: string; brief: string; slug: string; readTimeInMinutes: number; content: { html: string; }; tags: { name: string; slug: string; }[]; coverImage: { url: string; }; }; }[] = [];
// biome-ignore lint/complexity/noForEach: <explanation>
allPosts.forEach((post) => { allPosts.forEach((post) => {
const tags = post.node.tags; const tags = post.node.tags;
// biome-ignore lint/complexity/noForEach: <explanation>
tags.forEach((tag) => { tags.forEach((tag) => {
if(tag.slug === uTag.slug) { if(tag.slug === uTag.slug) {
filteredPosts.push(post) filteredPosts.push(post)

View File

@ -13,8 +13,14 @@ import background from "../assets/blog.jpg";
height={1080} height={1080}
width={1920} width={1920}
loading="eager" loading="eager"
transition:name={'background:' + background}
transition:animate={'fade'}
/> />
<div class="absolute p-2 flex flex-col justify-center items-center z-10 bg-purple-50 lg:w-2/5 h-1/4 rounded-md"> <div
class="absolute p-2 flex flex-col justify-center items-center z-10 bg-purple-50 lg:w-2/5 h-1/4 rounded-md"
transition:name={'banner'}
transition:animate={'fade'}
>
<div class="flex pb-5 mb-5 text-5xl text-purple-800"> <div class="flex pb-5 mb-5 text-5xl text-purple-800">
<p>Hashnode Blog</p> <p>Hashnode Blog</p>
</div> </div>

View File

@ -0,0 +1,58 @@
---
import { Layout } from "virtual:astro-hashnode/components";
import { getPost } from '../../hn-gql';
import Tag from '../../components/Tag.astro';
import Author from '../../components/Author.astro';
import { Markup } from 'astro-remote';
import { Image } from 'astro:assets';
import RemoteImage from '../../components/astro-remote/RemoteImage.astro';
const { slug } = Astro.params;
const checkSlug = (slug:string|undefined) => {
if (slug !== undefined) {
return slug as string;
}
return " " as string;
}
const post = await getPost(checkSlug(slug));
---
{post ? (
<Layout pageTitle={post.title} ogImage={post.coverImage.url}>
<article class="bg-white p-3 mt-3 flex flex-col">
<Image
class="rounded-lg"
src={post.coverImage.url}
alt={post.title}
inferSize={true}
loading="eager"
transition:name={'hero:' + post.coverImage.url}
/>
<h1 class="text-4xl font-bold pt-5">{post.title}</h1>
<h2 class="text-xl pt-3 pb-3" aria-label="CoverPhoto Subtitle">{post.subtitle}</h2>
<Author post={post} />
<div class="flex flex-wrap justify-center items-center mt-5 mb-5">
{post.tags && post.tags.map((tag) => <Tag tag={tag} />)}
</div>
<div class="post-details">
<Markup
content={post.content.html}
components={{
img: RemoteImage
}}
/>
</div>
</article>
</Layout>) : (
<Layout pageTitle="404">
<div class="text-center my-20">
<h1 class="text-4xl font-bold">404</h1>
<p>Post not found</p>
</div>
</Layout>
)}

View File

@ -1,7 +1,4 @@
import { z } from "astro/zod"; import { z } from "astro/zod";
import { createResolver } from 'astro-integration-kit';
const { resolve } = createResolver(import.meta.url)
export function LayoutConfigSchema() { export function LayoutConfigSchema() {
return z return z
@ -9,9 +6,29 @@ export function LayoutConfigSchema() {
.optional() .optional()
} }
export const optionsSchema = z.object({ export const optionsSchema = z.object({
/**
* The URL of the Hashnode blog
*/
hashnodeURL: z.string(), hashnodeURL: z.string(),
/**
* Allows the user to disable the default landing page and use their own Astro site instead of a landing page.
* @default true
*/
landingPage: z.boolean().default(true), landingPage: z.boolean().default(true),
/**
* Allows the user to enable/disable the Astro ViewTransitions component.
* @default true
* @see https://docs.astro.build/en/guides/view-transitions/ for more information about ViewTransitions
*/
useViewTransitions: z.boolean().default(true),
/**
* Allows the user to change the layout component used for Astro-Hashnode pages.
*/
layoutComponent: LayoutConfigSchema(), layoutComponent: LayoutConfigSchema(),
/**
* Allows the user to enable verbose logging
* @default false
*/
verbose: z.boolean().default(false), verbose: z.boolean().default(false),
}); });

View File

@ -1,12 +1,18 @@
import { defineConfig } from "astro/config"; import { defineConfig } from "astro/config";
import astroHashnode from "@matthiesenxyz/astro-hashnode"; import astroHashnode from "@matthiesenxyz/astro-hashnode";
// import node from '@astrojs/node';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
// output: 'server',
// adapter: node({
// mode: 'standalone',
// }),
integrations: [ integrations: [
astroHashnode({ astroHashnode({
hashnodeURL: "astroplayground.hashnode.dev", hashnodeURL: "astroplayground.hashnode.dev",
verbose: true, verbose: true,
disableViewTransitions: false,
}) })
], ],
}); });

View File

@ -11,12 +11,13 @@
"astro": "astro" "astro": "astro"
}, },
"dependencies": { "dependencies": {
"astro": "^4.4.15", "@astrojs/node": "8.2.4",
"@matthiesenxyz/astro-hashnode": "workspace:*" "@matthiesenxyz/astro-hashnode": "workspace:*",
"astro": "^4.5.6"
}, },
"devDependencies": { "devDependencies": {
"@astrojs/check": "^0.5.7", "@astrojs/check": "^0.5.9",
"@types/node": "^20.11.25", "@types/node": "^20.11.28",
"typescript": "^5.3.3" "typescript": "^5.4.2"
} }
} }

File diff suppressed because it is too large Load Diff