Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

137 chore add the blog post series #144

Merged
merged 5 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions apps/studio/schemas/documents/blog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ export default defineType({
type: 'array',
of: [{ type: 'string' }],
}),
defineField({
title: 'Series',
name: 'series',
type: 'reference',
to: [{ type: 'series' }],
}),
defineField({
title: 'Content',
name: 'content',
Expand Down
41 changes: 41 additions & 0 deletions apps/studio/schemas/documents/series.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Calendar } from 'react-iconly'
import { defineField, defineType } from 'sanity'

export default defineType({
title: 'Blog Series',
name: 'series',
type: 'document',
icon: Calendar,
fields: [
defineField({
title: 'Image',
name: 'thumbnail',
type: 'image',
}),
defineField({
title: 'SLUG',
name: 'slug',
type: 'slug',
options: {
source: 'title',
},
}),
defineField({
title: 'Title',
name: 'title',
type: 'string',
}),
defineField({
title: 'Description',
name: 'desc',
type: 'text',
}),
],
preview: {
select: {
media: 'thumbnail',
title: 'title',
subtitle: 'slug.current',
},
},
})
2 changes: 2 additions & 0 deletions apps/studio/schemas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import faq from './documents/faq'
import page from './documents/page'
import product from './documents/product'
import project from './documents/project'
import series from './documents/series'
import timeline from './documents/timeline'
import bio from './objects/content/bio'

Expand All @@ -16,4 +17,5 @@ export const schemaTypes = [
faq,
app,
product,
series,
]
41 changes: 41 additions & 0 deletions apps/web/components/blog/BlogSeriesItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<template>
<NuxtLink
:href="`/blog/${data.slug}`"
class="flex flex-col laptop:flex-row gap-5 transition-all duration-700 hover:scale-95 group"
>
<div
class="flex justify-center items-center overflow-hidden h-64 laptop:h-44 laptop:w-44 rounded-3xl relative"
>
<NuxtImg
:src="data.thumbnail"
:alt="data.title"
class="flex h-full w-full object-cover transition-all duration-500 hover:scale-105"
/>
<span
class="absolute bg-white dark:bg-black transition-all rounded-full h-12 w-12 flex justify-center items-center text-xl top-2 left-2"
>{{ position }}</span
>
</div>
<div class="flex flex-col flex-1 py-2">
<h3 class="text-2xl !leading-tight line-clamp-2">{{ data.title }}</h3>
<div class="flex flex-wrap mt-5">
<span
class="flex justify-center items-center px-5 py-3 rounded-full border border-neutral-100 dark:border-neutral-800 gap-3"
>
<p class="h-2 w-2 rounded-full bg-black dark:bg-white"></p>
{{ data.tag }}</span
>
</div>
</div>
</NuxtLink>
</template>

<script setup lang="ts">
import { BlogPost } from '~/types/content'

interface BlogSeriesItemProps {
position: number
data: BlogPost
}
defineProps<BlogSeriesItemProps>()
</script>
23 changes: 23 additions & 0 deletions apps/web/components/blog/SeriesItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<template>
<NuxtLink :href="`/blog/series/${data.slug}`" class="flex flex-col">
<div
class="flex h-64 w-full justify-center items-center overflow-hidden rounded-2xl"
>
<NuxtImg
:src="data.thumbnail"
:alt="data.title"
class="flex h-full w-full object-cover transition-all duration-700 hover:scale-105"
/>
</div>
<h3 class="text-2xl mt-7 line-clamp-2">{{ data.title }}</h3>
</NuxtLink>
</template>

<script setup lang="ts">
import { BlogSeries } from '~/types/content'

interface SeriesItemProps {
data: BlogSeries
}
defineProps<SeriesItemProps>()
</script>
27 changes: 27 additions & 0 deletions apps/web/lib/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ export const blogQuery = `
featured,
"isIncoming": "Incoming" in tags[],
},
"series": *[_type == "series"]{
"slug": slug.current,
"thumbnail": thumbnail.asset -> url,
title,
desc,
},
"latest": *[_type == "blog"] | order(_updatedAt desc){
"slug": slug.current,
title,
Expand Down Expand Up @@ -138,3 +144,24 @@ export const productsQuery = `
}
}
`

export const loadSeriesDetail = `
{
"detail": *[_type == "series" && slug.current == $slug][0]{
title,
desc,
"thumbnail": thumbnail.asset -> url,
"slug": slug.current,
"totalContent": count(*[_type == "blog" && references(^._id)])
},
"contents": *[_type == "blog" && references(*[_type == "series" && slug.current == $slug][0]._id)] | order(_createdAt desc){
"slug": slug.current,
title,
"thumbnail": thumbnail.asset -> url,
"tag": tags[0],
_createdAt,
featured,
"isIncoming": "Incoming" in tags[],
}
}
`
19 changes: 14 additions & 5 deletions apps/web/pages/blog/index.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<main class="flex flex-col min-h-screen pt-40 text-xl pb-80">
<!-- Featured posts -->
<section class="container mx-auto flex flex-col px-5 laptop:px-10">
<h3 class="flex text-3xl font-semibold">🎉 Featured</h3>
<section class="container mx-auto flex flex-col px-5 laptop:px-20">
<h3 class="flex text-3xl">🎉 Featured</h3>
<div
class="flex flex-col laptop:grid laptop:grid-cols-6 mt-10 w-full gap-6"
>
Expand All @@ -15,13 +15,21 @@
</div>
</section>

<!-- series post -->
<section class="container mx-auto px-5 laptop:px-20 mt-60">
<h3 class="text-3xl">🏀 Top Series</h3>
<div class="grid grid-cols-1 laptop:grid-cols-3 mt-16 w-full">
<SeriesItem v-for="(item, i) in series" :key="i" :data="item" />
</div>
</section>

<!-- Latest post -->
<section
class="container mx-auto px-5 laptop:px-10 flex flex-col laptop:mt-60 mt-28"
>
<!-- filter -->
<div class="flex flex-col">
<h4 class="text-2xl font-semibold">Search blog posts</h4>
<h4 class="text-2xl">Search blog posts</h4>
<div class="flex laptop:w-4/12 mt-10">
<TextInput
placeholder="search blog posts ..."
Expand Down Expand Up @@ -53,15 +61,16 @@
<script setup lang="ts">
import { tags } from '~/assets/data/blog.json'
import { blogQuery } from '~/lib/queries'
import { BlogPost } from '~/types/content'
import { BlogPost, BlogSeries } from '~/types/content'

const {
data: {
value: { featured, latest },
value: { featured, latest, series },
},
} = await useSanityQuery<{
featured: BlogPost[]
latest: BlogPost[]
series: BlogSeries[]
}>(blogQuery)

useSeoMeta({
Expand Down
79 changes: 79 additions & 0 deletions apps/web/pages/blog/series/[slug].vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<template>
<main class="flex flex-col py-40">
<section
class="flex flex-col laptop:flex-row container mx-auto px-5 laptop:px-20 gap-10"
>
<div
class="flex flex-col laptop:w-1/2 h-[250px] laptop:h-[600px] overflow-hidden rounded-3xl"
>
<NuxtImg
:src="detail.thumbnail"
:alt="detail.title"
class="h-full w-full object-cover transition-all duration-700 hover:scale-105"
/>
</div>
<div class="flex flex-col laptop:w-1/2 laptop:pt-10">
<div class="flex">
<TextButton
@click="navigateTo('/blog')"
class="transition-all duration-500 hover:-translate-x-1"
><i
class="fi fi-rr-arrow-left text-2xl h-12 w-12 rounded-full bg-black text-white dark:bg-white dark:text-black"
></i>
Back to blog</TextButton
>
</div>
<h2 class="text-4xl laptop:text-5xl !leading-tight mt-10">
{{ detail.title }}
</h2>
<div class="flex flex-wrap mt-5">
<span
class="border border-neutral-100 dark:border-neutral-800 px-5 py-3 rounded-full relative"
>
<span
class="h-2 w-2 rounded-full bg-red-500 absolute top-1 right-1"
></span>
{{ detail.totalContent > 0 ? detail.totalContent : 'No' }}
Articles</span
>
</div>
<p class="text-xl leading-relaxed mt-10">{{ detail.desc }}</p>
</div>
</section>

<section
class="flex container mx-auto px-5 laptop:px-20 mt-20 laptop:mt-40"
>
<div class="grid grid-cols-1 laptop:grid-cols-2 w-full gap-10">
<BlogSeriesItem
v-for="(post, i) in contents"
:data="post"
:position="i + 1"
/>
</div>
</section>
</main>
</template>

<script setup lang="ts">
import { BlogSeriesDetail } from '~/types/content'
import { loadSeriesDetail } from '~/lib/queries'

definePageMeta({
layout: 'blog',
})

const route = useRoute()
const {
data: {
value: { detail, contents },
},
} = await useSanityQuery<BlogSeriesDetail>(loadSeriesDetail, {
slug: route.params.slug,
})

useSeoMeta({
title: detail.title,
description: detail.desc.substring(0, 40),
})
</script>
18 changes: 18 additions & 0 deletions apps/web/types/content.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@ export interface BlogPost {
isIncoming: boolean
}

export interface BlogSeries {
thumbnail: string
title: string
slug: string
desc: string
}

export interface BlogSeriesDetail {
detail: {
thumbnail: string
title: string
slug: string
desc: string
totalContent: number
}
contents: BlogPost[]
}

export interface BlogDetail {
post: {
slug: string
Expand Down