feat: unsplash and small fix to types

Signed-off-by: Filipe Medeiros <hello@filipesm.eu>
This commit is contained in:
Filipe Medeiros 2023-04-12 13:27:12 +01:00
parent d490d9b5da
commit c072a4b30e
Signed by: filipe
GPG key ID: 9533BD5467CC1E78
7 changed files with 126 additions and 83 deletions

View file

@ -16,7 +16,10 @@ export const forBlogPostPage = groq`
_type != 'image' => @
},
headerImage,
publishDate
publishDate,
linkPreviewImage,
linkPreviewDescription,
twitterCardType
}`;
export const forBlogPage = groq`

View file

@ -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;
---
<Layout title={`${title} - Filipe Medeiros`}>
<BlogPostMetadata
slot="metadata"
title={metadata.title ?? title}
description={metadata.description ?? summary}
image={metadata.image ?? headerImage}
twitterCardType={metadata.twitterCardType}
title={title}
description={linkPreviewDescription ?? summary}
image={linkPreviewImage ?? headerImage}
twitterCardType={twitterCardType}
/>
<article class="max-w-prose m-auto">
<header class="mb-5">

View file

@ -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)

View file

@ -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"
},

View file

@ -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:

View file

@ -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

View file

@ -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: {