From 7d4dbb00a09c8f185d3d851c09cf23ef25722aa1 Mon Sep 17 00:00:00 2001 From: baalajimaestro Date: Sat, 13 Jul 2024 00:36:15 +0530 Subject: [PATCH] Integrate ghost cms Signed-off-by: baalajimaestro --- package.json | 2 + pnpm-lock.yaml | 90 +++++++++++++++++++ src/components/ListPosts.vue | 42 ++++----- src/layouts/BaseLayout.astro | 1 + .../blog/{[...path].astro => index.astro} | 25 ++---- src/pages/index.astro | 1 - src/pages/posts/[...slug].astro | 65 +++++++------- src/site-config.ts | 18 +--- src/utils/ghost.ts | 13 +++ 9 files changed, 164 insertions(+), 93 deletions(-) rename src/pages/blog/{[...path].astro => index.astro} (66%) create mode 100644 src/utils/ghost.ts diff --git a/package.json b/package.json index 11bde0a..47ab582 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@astrojs/rss": "^4.0.7", "@astrojs/sitemap": "^3.1.6", "@astrojs/vue": "^4.5.0", + "@tryghost/content-api": "^1.11.21", "@unocss/reset": "^0.61.0", "astro": "^4.11.3", "nprogress": "^0.2.0", @@ -27,6 +28,7 @@ "@iconify/json": "^2.2.204", "@types/lodash-es": "^4.17.12", "@types/nprogress": "^0.2.3", + "@types/tryghost__content-api": "^1.3.16", "@vueuse/core": "^10.11.0", "bumpp": "^9.4.1", "eslint": "^8.57.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8280eb7..4f131a6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ importers: '@astrojs/vue': specifier: ^4.5.0 version: 4.5.0(astro@4.11.5(typescript@5.5.3))(rollup@4.18.1)(vite@5.3.3)(vue@3.4.31(typescript@5.5.3)) + '@tryghost/content-api': + specifier: ^1.11.21 + version: 1.11.21 '@unocss/reset': specifier: ^0.61.0 version: 0.61.3 @@ -48,6 +51,9 @@ importers: '@types/nprogress': specifier: ^0.2.3 version: 0.2.3 + '@types/tryghost__content-api': + specifier: ^1.3.16 + version: 1.3.16 '@vueuse/core': specifier: ^10.11.0 version: 10.11.0(vue@3.4.31(typescript@5.5.3)) @@ -846,6 +852,9 @@ packages: peerDependencies: eslint: '>=8.40.0' + '@tryghost/content-api@1.11.21': + resolution: {integrity: sha512-ozJqEMHDUO7D0SGxPbUnG+RvwBbzC3zmdGOW8cFvkcKzrhe7uOAmVKyq7/J3kRAM2QthTlmiDpqp7NEo9ZLlKg==} + '@types/acorn@4.0.6': resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} @@ -915,6 +924,9 @@ packages: '@types/sax@1.2.7': resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} + '@types/tryghost__content-api@1.3.16': + resolution: {integrity: sha512-i3TryXx8ZoW5LC9dMDWLkCg6vFMeCh4tAvr0ijAdlEzIhoSC8q5RPMANNmkiDxDcNMRCByVMoT4+RfB5qeURZQ==} + '@types/unist@2.0.10': resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} @@ -1301,6 +1313,12 @@ packages: peerDependencies: '@astrojs/compiler': '>=0.27.0' + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.7.2: + resolution: {integrity: sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==} + axobject-query@4.0.0: resolution: {integrity: sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==} @@ -1490,6 +1508,10 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -1582,6 +1604,10 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -2006,6 +2032,19 @@ packages: resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} engines: {node: '>=8'} + follow-redirects@1.15.6: + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + fs-extra@11.2.0: resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} engines: {node: '>=14.14'} @@ -2657,6 +2696,14 @@ packages: resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -2962,6 +3009,9 @@ packages: property-information@6.5.0: resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -4490,6 +4540,12 @@ snapshots: - supports-color - typescript + '@tryghost/content-api@1.11.21': + dependencies: + axios: 1.7.2 + transitivePeerDependencies: + - debug + '@types/acorn@4.0.6': dependencies: '@types/estree': 1.0.5 @@ -4570,6 +4626,8 @@ snapshots: dependencies: '@types/node': 17.0.45 + '@types/tryghost__content-api@1.3.16': {} + '@types/unist@2.0.10': {} '@types/unist@3.0.2': {} @@ -5197,6 +5255,16 @@ snapshots: '@astrojs/compiler': 2.8.2 synckit: 0.9.0 + asynckit@0.4.0: {} + + axios@1.7.2: + dependencies: + follow-redirects: 1.15.6 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + axobject-query@4.0.0: dependencies: dequal: 2.0.3 @@ -5392,6 +5460,10 @@ snapshots: colorette@2.0.20: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} commander@12.1.0: {} @@ -5458,6 +5530,8 @@ snapshots: defu@6.1.4: {} + delayed-stream@1.0.0: {} + dequal@2.0.3: {} destr@2.0.3: {} @@ -6010,6 +6084,14 @@ snapshots: flattie@1.1.1: {} + follow-redirects@1.15.6: {} + + form-data@4.0.0: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + fs-extra@11.2.0: dependencies: graceful-fs: 4.2.11 @@ -6980,6 +7062,12 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + mimic-fn@2.1.0: {} mimic-fn@4.0.0: {} @@ -7293,6 +7381,8 @@ snapshots: property-information@6.5.0: {} + proxy-from-env@1.1.0: {} + punycode@2.3.1: {} queue-microtask@1.2.3: {} diff --git a/src/components/ListPosts.vue b/src/components/ListPosts.vue index e97ec3f..66d3ae2 100644 --- a/src/components/ListPosts.vue +++ b/src/components/ListPosts.vue @@ -2,10 +2,14 @@ interface Post { id: string slug: string - body: string - data: Record - collection: string - render: any + title: string + html: string + excerpt: string + feature_image: string + published_at: string + reading_time: number + tags: Array<{ name: string, slug: string }> + primary_author: { name: string, profile_image: string } } withDefaults(defineProps<{ @@ -19,17 +23,9 @@ function getDate(date: string) { } function getHref(post: Post) { - if (post.data.redirect) - return post.data.redirect return `/posts/${post.slug}` } -function getTarget(post: Post) { - if (post.data.redirect) - return '_blank' - return '_self' -} - function isSameYear(a: Date | string | number, b: Date | string | number) { return a && b && getYear(a) === getYear(b) } @@ -46,30 +42,26 @@ function getYear(date: Date | string | number) { nothing here yet. -
  • -
    +
  • +
    - {{ getYear(post.data.date) }} + {{ getYear(post.published_at) }}
    - +
    - - {{ post.data.title }} + {{ post.title }}
    - - - - · {{ post.data.duration }} - · {{ post.data.tag }} - · 中文 + + · {{ post.reading_time }} min read + · {{ post.tags[0].name }}
    -
    {{ post.data.description }}
    +
    {{ post.excerpt }}
  • diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index 5d9ae61..6d648e9 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -12,6 +12,7 @@ const { ...head } = Astro.props + diff --git a/src/pages/blog/[...path].astro b/src/pages/blog/index.astro similarity index 66% rename from src/pages/blog/[...path].astro rename to src/pages/blog/index.astro index cdfd6fa..4dc5061 100644 --- a/src/pages/blog/[...path].astro +++ b/src/pages/blog/index.astro @@ -2,23 +2,16 @@ import BaseLayout from '@/layouts/BaseLayout.astro' import ListPosts from '@/components/ListPosts.vue' import siteConfig from '@/site-config' -import { getPosts } from '@/utils/posts' - -export async function getStaticPaths() { - const paths = siteConfig.page.blogLinks.map((nav) => { - const href = nav.href.replace('/blog', '') - return { - params: { - path: href === '' ? undefined : href.replace(/^\/+|\/+$/g, ''), - }, - } - }) - return paths -} +import { posts } from '@/utils/ghost' const { path } = Astro.params -const posts = await getPosts(path) +const ghostPosts = await posts + .browse({ + limit: 'all', + include: ['tags', 'authors'], + filter: path ? `tag:${path}` : undefined + }) function activeLink(pathname: string) { return Astro.url.pathname.replace(/\/+/g, '/').replace(/\/$/, '') === pathname @@ -44,5 +37,5 @@ function activeLink(pathname: string) { )) } - - + + \ No newline at end of file diff --git a/src/pages/index.astro b/src/pages/index.astro index 078b5dc..dc027b8 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -2,7 +2,6 @@ import BaseLayout from '@/layouts/BaseLayout.astro' import siteConfig from '@/site-config' --- -

    Vitesse theme

    diff --git a/src/pages/posts/[...slug].astro b/src/pages/posts/[...slug].astro index 887e03e..10f7703 100644 --- a/src/pages/posts/[...slug].astro +++ b/src/pages/posts/[...slug].astro @@ -1,47 +1,44 @@ --- import BaseLayout from '@/layouts/BaseLayout.astro' -import { type CollectionPosts } from '@/types' -import { getPosts } from '@/utils/posts' +import { api } from '@/utils/ghost' export async function getStaticPaths() { - const posts = await getPosts() - return posts.map((post) => { - return { - params: { slug: post.slug }, - props: { - post, - }, - } - }) + const posts = await api.posts + .browse({ + limit: 'all', + fields: ['slug', 'title'] + }) + .catch(err => { + console.error('Error fetching posts:', err); + return []; + }); + + return posts.map((post) => ({ + params: { slug: post.slug }, + props: { slug: post.slug }, + })); } -type Props = { post: CollectionPosts } +const { slug } = Astro.props; -const { post } = Astro.props -const { title, image, description, date, duration, tag } = post.data - -const { Content } = await post.render() - -function getDate(date: string) { - return new Date(date).toISOString() +let post; +post = await api.posts.read({ slug }, { include: ['tags', 'authors'] }); +if (!post) { + return Astro.redirect('/404'); } --- - - +
    -

    {title}

    +

    {post.title}

    - {date && } - {duration && · {duration}} - {tag && · {tag}} + {post.published_at && } + {post.reading_time && · {post.reading_time} min read} + {post.primary_tag && · {post.primary_tag.name}}

    - { - image && ( -

    - {image.alt -

    - ) - } - + {post.feature_image && ( + {post.feature_image_alt + )} + +
    -
    +
    \ No newline at end of file diff --git a/src/site-config.ts b/src/site-config.ts index 6d74c3f..348b75a 100644 --- a/src/site-config.ts +++ b/src/site-config.ts @@ -47,14 +47,6 @@ export const siteConfig = { text: 'Blog', href: '/blog', }, - { - text: 'Notes', - href: '/blog/notes', - }, - { - text: 'Talks', - href: '/blog/talks', - }, { text: 'Projects', href: '/projects', @@ -66,15 +58,7 @@ export const siteConfig = { { text: 'Blog', href: '/blog', - }, - { - text: 'Notes', - href: '/blog/notes', - }, - { - text: 'Talks', - href: '/blog/talks', - }, + } ], }, footer: { diff --git a/src/utils/ghost.ts b/src/utils/ghost.ts new file mode 100644 index 0000000..aa4133c --- /dev/null +++ b/src/utils/ghost.ts @@ -0,0 +1,13 @@ +import GhostContentAPI from '@tryghost/content-api'; + +export const api = new GhostContentAPI({ + url: import.meta.env.CONTENT_API_URL, + key: import.meta.env.CONTENT_API_KEY, + version: 'v5.0', +}); + +export const posts = api.posts +export const tags = api.tags +export const authors = api.authors +export const pages = api.pages +export const settings = api.settings