From c072a4b30e6a6e87e7b86711b68079acdf2faab2 Mon Sep 17 00:00:00 2001 From: Filipe Medeiros Date: Wed, 12 Apr 2023 13:27:12 +0100 Subject: [PATCH] feat: unsplash and small fix to types Signed-off-by: Filipe Medeiros --- frontend/src/cms/queries/blogPosts.ts | 5 +- frontend/src/pages/blog/[slug]/index.astro | 53 ++++++----- .../documentActions/blogPostPublishAction.ts | 11 +-- studio/package.json | 1 + studio/pnpm-lock.yaml | 48 ++++++++++ studio/sanity.config.ts | 4 +- studio/schemas/blogPost.ts | 87 +++++++++---------- 7 files changed, 126 insertions(+), 83 deletions(-) diff --git a/frontend/src/cms/queries/blogPosts.ts b/frontend/src/cms/queries/blogPosts.ts index 582b999..f74579d 100644 --- a/frontend/src/cms/queries/blogPosts.ts +++ b/frontend/src/cms/queries/blogPosts.ts @@ -16,7 +16,10 @@ export const forBlogPostPage = groq` _type != 'image' => @ }, headerImage, - publishDate + publishDate, + linkPreviewImage, + linkPreviewDescription, + twitterCardType }`; export const forBlogPage = groq` diff --git a/frontend/src/pages/blog/[slug]/index.astro b/frontend/src/pages/blog/[slug]/index.astro index bacf8b3..d59441c 100644 --- a/frontend/src/pages/blog/[slug]/index.astro +++ b/frontend/src/pages/blog/[slug]/index.astro @@ -15,46 +15,43 @@ export interface Props { publishDate: string; headerImage: ImageObject; summary: string; - metadata: { - twitterCardType: 'summary' | 'summary_large_image' | 'player' | 'app'; - description: string; - title: string; - image: ImageObject; - }; + twitterCardType: 'summary' | 'summary_large_image' | 'player' | 'app'; + linkPreviewDescription: string; + linkPreviewImage: ImageObject; } export async function getStaticPaths() { - const posts: { + const posts: (Props & { slug: string; - title: string; - content: PortableTextBlock[]; - publishDate: string; - headerImage: ImageObject; - summary: string; - metadata: Props['metadata']; - }[] = await client.fetch(forBlogPostPage, { live: !import.meta.env.DEV }); + })[] = await client.fetch(forBlogPostPage, { live: !import.meta.env.DEV }); - return posts.map( - ({ slug, title, content, publishDate, headerImage, summary, metadata }) => { - return { - params: { slug }, - props: { title, content, publishDate, headerImage, summary, metadata }, - }; - }, - ); + return posts.map(({ slug, ...blogPost }) => { + return { + params: { slug }, + props: blogPost, + }; + }); } -const { title, content, publishDate, headerImage, summary, metadata } = - Astro.props; +const { + title, + content, + publishDate, + headerImage, + summary, + twitterCardType, + linkPreviewDescription, + linkPreviewImage, +} = Astro.props; ---
diff --git a/studio/documentActions/blogPostPublishAction.ts b/studio/documentActions/blogPostPublishAction.ts index 42e661f..a90c388 100644 --- a/studio/documentActions/blogPostPublishAction.ts +++ b/studio/documentActions/blogPostPublishAction.ts @@ -1,14 +1,9 @@ import {useEffect, useState} from 'react' -import { - DocumentActionComponent, - DocumentActionProps, - PortableTextBlock, - useDocumentOperation, -} from 'sanity' +import {DocumentActionComponent, PortableTextBlock, useDocumentOperation} from 'sanity' import {toPlainText} from '@portabletext/toolkit' export function blogPostPublishAction(originalPublishAction: DocumentActionComponent) { - const BetterAction = (props: DocumentActionProps) => { + const BetterAction: DocumentActionComponent = (props) => { const {patch, publish} = useDocumentOperation(props.id, props.type) const [isPublishing, setIsPublishing] = useState(false) @@ -26,7 +21,7 @@ export function blogPostPublishAction(originalPublishAction: DocumentActionCompo const readTimeInMinutes = content ? Math.ceil(toPlainText(content).length / 5 / 180) : 0 return { - disabled: publish.disabled, + disabled: !!publish.disabled, label: isPublishing ? 'Publishing…' : 'Update & Publish', onHandle: () => { setIsPublishing(true) diff --git a/studio/package.json b/studio/package.json index 425fe42..6903949 100644 --- a/studio/package.json +++ b/studio/package.json @@ -22,6 +22,7 @@ "react-dom": "^18.2.0", "react-is": "^18.2.0", "sanity": "3.8.3", + "sanity-plugin-asset-source-unsplash": "^1.0.6", "sanity-plugin-media": "^2.0.5", "styled-components": "^5.3.9" }, diff --git a/studio/pnpm-lock.yaml b/studio/pnpm-lock.yaml index 5e5b13a..fa0a4e1 100644 --- a/studio/pnpm-lock.yaml +++ b/studio/pnpm-lock.yaml @@ -22,6 +22,9 @@ dependencies: sanity: specifier: 3.8.3 version: 3.8.3(@types/react@18.0.34)(react-dom@18.2.0)(react@18.2.0)(styled-components@5.3.9) + sanity-plugin-asset-source-unsplash: + specifier: ^1.0.6 + version: 1.0.6(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(sanity@3.8.3)(styled-components@5.3.9) sanity-plugin-media: specifier: ^2.0.5 version: 2.0.5(@sanity/color@2.2.5)(@sanity/icons@2.2.2)(@types/react@18.0.34)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(sanity@3.8.3)(styled-components@5.3.9) @@ -5884,6 +5887,15 @@ packages: react: 18.2.0 dev: false + /react-infinite-scroll-component@6.1.0(react@18.2.0): + resolution: {integrity: sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==} + peerDependencies: + react: '>=16.0.0' + dependencies: + react: 18.2.0 + throttle-debounce: 2.3.0 + dev: false + /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -5899,6 +5911,15 @@ packages: resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==} dev: false + /react-photo-album@2.0.4(react@18.2.0): + resolution: {integrity: sha512-m+1GO3u0EGDu+0u9A9JUBZtDzqu/pevGNp7TvsmbJR8laYr9KDH0SJUd61Cs22qcWZaxv35RS5G1/kpNnGq8AQ==} + engines: {node: '>=12'} + peerDependencies: + react: '>=16.8.0' + dependencies: + react: 18.2.0 + dev: false + /react-redux@7.2.9(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==} peerDependencies: @@ -6265,6 +6286,28 @@ packages: diff-match-patch: 1.0.5 dev: false + /sanity-plugin-asset-source-unsplash@1.0.6(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(sanity@3.8.3)(styled-components@5.3.9): + resolution: {integrity: sha512-oJK6tLc+neO/LSquP0C+ry4O/wpW5/p13LX+Uog6wKwAtRAjCgrNgkE9DYhJWsIKgbUJheXO0rEUck/xqXn6nQ==} + engines: {node: '>=14'} + peerDependencies: + react: ^18 + react-dom: ^18 + sanity: ^3 + styled-components: ^5.2 + dependencies: + '@sanity/incompatible-plugin': 1.0.4(react-dom@18.2.0)(react@18.2.0) + '@sanity/ui': 1.3.1(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(styled-components@5.3.9) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-infinite-scroll-component: 6.1.0(react@18.2.0) + react-photo-album: 2.0.4(react@18.2.0) + rxjs: 7.8.0 + sanity: 3.8.3(@types/react@18.0.34)(react-dom@18.2.0)(react@18.2.0)(styled-components@5.3.9) + styled-components: 5.3.9(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0) + transitivePeerDependencies: + - react-is + dev: false + /sanity-plugin-media@2.0.5(@sanity/color@2.2.5)(@sanity/icons@2.2.2)(@types/react@18.0.34)(react-dom@18.2.0)(react-is@18.2.0)(react@18.2.0)(sanity@3.8.3)(styled-components@5.3.9): resolution: {integrity: sha512-v1SyBezXoiLh2g3olX08cjFpytRF3NkCxCOkFzHz3RVbQQwpYSeazKmGq52XONi/Ci6DpyKmgLWRJCyT/xZc1g==} engines: {node: '>=14'} @@ -6764,6 +6807,11 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true + /throttle-debounce@2.3.0: + resolution: {integrity: sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==} + engines: {node: '>=8'} + dev: false + /through2@2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} dependencies: diff --git a/studio/sanity.config.ts b/studio/sanity.config.ts index cc97f2a..cc137ad 100644 --- a/studio/sanity.config.ts +++ b/studio/sanity.config.ts @@ -4,6 +4,7 @@ import {media} from 'sanity-plugin-media' import {visionTool} from '@sanity/vision' import {schemaTypes} from './schemas' import {blogPostPublishAction} from './documentActions/blogPostPublishAction' +import {unsplashImageAsset} from 'sanity-plugin-asset-source-unsplash' export default defineConfig({ name: 'personal-webiste', @@ -12,14 +13,13 @@ export default defineConfig({ projectId: 'tzamgyrm', dataset: 'production', - plugins: [deskTool(), visionTool(), media()], + plugins: [deskTool(), visionTool(), media(), unsplashImageAsset()], schema: { types: schemaTypes, }, document: { - // @ts-expect-error actions: (originalActions) => originalActions.map((originalAction) => originalAction.action === 'publish' ? blogPostPublishAction(originalAction) : originalAction diff --git a/studio/schemas/blogPost.ts b/studio/schemas/blogPost.ts index e0f86d5..aa4f32e 100644 --- a/studio/schemas/blogPost.ts +++ b/studio/schemas/blogPost.ts @@ -6,6 +6,18 @@ const blogPost = defineType({ title: 'Blog posts', type: 'document', icon: DocumentTextIcon, + fieldsets: [ + { + name: 'metadata', + title: 'Social media and SEO', + description: + 'Data about the article for SEO, social media previews, etc. This is very important for reach and brand awareness since it will be the first contact many people will have with our brand and content!', + options: { + collapsible: true, + collapsed: true, + }, + }, + ], fields: [ { name: 'title', @@ -85,52 +97,39 @@ const blogPost = defineType({ 'Leave this empty if you want to use the current date (of publish). If you use a date in the past, everything will go normal. If you use a date in the future, the article will be hidden until that day, on which it will be published automatically.', }, { - name: 'metadata', - title: 'Social media and SEO', + name: 'linkPreviewImage', + title: 'Link preview image', + type: 'image', + description: "If you don't specify this, falls back to 'Header image'", + fieldset: 'metadata', + }, + { + name: 'linkPreviewDescription', + title: 'Link preview description', + type: 'string', + description: "If you don't specify this, falls back to article summary", + fieldset: 'metadata', + }, + { + name: 'twitterCardType', + title: 'Twitter card type', + type: 'string', description: - 'Data about the article for SEO, social media previews, etc. This is very important for reach and brand awareness since it will be the first contact many people will have with our brand and content!', - type: 'object', - validation: (r) => r.required(), - fields: [ - { - name: 'image', - title: 'Image', - type: 'image', - description: "If you don't specify this, falls back to 'Header image'", - }, - { - name: 'title', - title: 'Title', - type: 'string', - description: "If you don't specify this, falls back to article title", - }, - { - name: 'description', - title: 'Description', - type: 'string', - description: "If you don't specify this, falls back to article summary", - }, - { - name: 'twitterCardType', - title: 'Twitter card type', - type: 'string', - description: - 'See https://developer.twitter.com/en/docs/twitter-for-websites/cards/guides/getting-started for more info.', - options: { - list: [ - {value: 'summary', title: 'Summary'}, - { - value: 'summary_large_image', - title: 'Summary with large image', - }, - {value: 'player', title: 'Player'}, - {value: 'app', title: 'App'}, - ], + 'See https://developer.twitter.com/en/docs/twitter-for-websites/cards/guides/getting-started for more info.', + options: { + list: [ + {value: 'summary', title: 'Summary'}, + { + value: 'summary_large_image', + title: 'Summary with large image', }, - initialValue: 'summary_large_image', - validation: (r) => r.required(), - }, - ], + {value: 'player', title: 'Player'}, + {value: 'app', title: 'App'}, + ], + }, + initialValue: 'summary_large_image', + validation: (r) => r.required(), + fieldset: 'metadata', }, ], preview: {