Skip to content

Commit

Permalink
feat: rework blog and layout
Browse files Browse the repository at this point in the history
  • Loading branch information
Barbapapazes committed Oct 27, 2023
1 parent a999b45 commit cf71bd8
Show file tree
Hide file tree
Showing 12 changed files with 336 additions and 79 deletions.
34 changes: 34 additions & 0 deletions app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ export default defineAppConfig({
},
},
},
buttonGroup: {
shadow: 'shadow-none',
},
tooltip: {
background: 'bg-white dark:bg-zinc-900',
color: 'text-zinc-900 dark:text-white',
Expand All @@ -23,6 +26,37 @@ export default defineAppConfig({
background: 'bg-zinc-100 dark:bg-zinc-800',
ring: 'ring-1 ring-zinc-300 dark:ring-zinc-700 ring-inset',
},
card: {
base: 'transition ease-in duration-150',
background: 'bg-white dark:bg-zinc-900',
divide: 'divide-y divide-zinc-200 dark:divide-zinc-800',
ring: 'ring-1 ring-zinc-200 dark:ring-zinc-700',
},
input: {
color: {
white: {
outline: 'shadow-none bg-white dark:bg-zinc-900 text-zinc-900 dark:text-white ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 focus:ring-2 focus:ring-primary-500 dark:focus:ring-primary-400',
},
placeholder: 'placeholder-zinc-400 dark:placeholder-zinc-500',
},
},
select: {
placeholder: 'text-zinc-900 dark:text-white',
color: {
white: {
outline: 'shadow-none bg-white dark:bg-zinc-900 text-zinc-900 dark:text-white ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 focus:ring-2 focus:ring-primary-500 dark:focus:ring-primary-400',
},
},
},
selectMenu: {
background: 'bg-white dark:bg-zinc-800',
ring: 'ring-1 ring-zinc-200 dark:ring-zinc-700',
option: {
base: 'cursor-pointer',
color: 'text-zinc-900 dark:text-white',
active: 'bg-zinc-100 dark:bg-zinc-900',
},
},
},
website: {
search: {
Expand Down
2 changes: 1 addition & 1 deletion components/app/AppFooter.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts" setup>
const website = useWebsite()
const uiButton = { color: { gray: { ghost: 'hover:bg-primary/10 dark:hover:bg-primary/90' } } }
const uiButton = { color: { gray: { ghost: 'hover:bg-[#ECDC5A]/10 dark:hover:bg-[#ECDC5A]/90' } } }
</script>

<template>
Expand Down
4 changes: 2 additions & 2 deletions components/app/AppHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ defineShortcuts({
})
const { metaSymbol } = useShortcuts()
const uiButton = { color: { gray: { ghost: 'hover:bg-primary/10 dark:hover:bg-primary/90' } } }
const uiButton = { color: { gray: { ghost: 'hover:bg-[#ECDC5A]/30 dark:hover:bg-[#ECDC5A]/90' } } }
</script>

<template>
Expand All @@ -37,7 +37,7 @@ const uiButton = { color: { gray: { ghost: 'hover:bg-primary/10 dark:hover:bg-pr
<nav v-if="navigation" class="hidden lg:flex justify-center">
<ol class="text-[1.125rem] flex gap-4 leading-5">
<li v-for="item in navigation" :key="item._path">
<UButton size="md" variant="ghost" color="gray" :to="item._path" :icon="item.icon" :ui="{ size: { md: 'text-base' }, ...uiButton }" active-class="bg-primary bg-opacity-30">
<UButton size="md" variant="ghost" color="gray" :to="item._path" :icon="item.icon" :ui="{ size: { md: 'text-base' }, ...uiButton }" active-class="bg-[#ECDC5A] bg-opacity-30">
{{ item.title }}
</UButton>
</li>
Expand Down
21 changes: 16 additions & 5 deletions components/app/AppHero.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
<script lang="ts" setup>
defineProps<{
title?: string
description?: string
}>()
</script>

<template>
<section p="x-6 y-8" flex="~ col" gap="4" bg="white" rounded="4" border="~ light">
<h1 text="gray-900 2xl md:3xl lg:4xl" font="extrabold" tracking="wide" leading="normal md:normal">
<slot name="title" />
<section class="px-6 py-8 flex flex-col gap-4 bg-white rounded-2xl ring-1 ring-zinc-200">
<h1 class="text-zinc-900 text-2xl md:text-3xl lg:text-4xl font-extrabold tracking-wide leading-normal md:leading-normal">
<slot name="title">
{{ title }}
</slot>
</h1>
<p max-w="2xl" text="gray-600 lg md:2.5xl" leading="normal md:normal">
<slot name="description" />
<p class="max-w-2xl text-zinc-600 text-lg md:text-[1.75rem] leading-normal md:leading-normal">
<slot name="description">
{{ description }}
</slot>
</p>
</section>
</template>
10 changes: 0 additions & 10 deletions components/content/blog/BlogHero.vue

This file was deleted.

10 changes: 0 additions & 10 deletions components/content/packages/PackagesHero.vue

This file was deleted.

2 changes: 1 addition & 1 deletion components/home/HomeSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<h2 class="text-2xl md:text-3xl lg:text-4xl text-gray-900 font-extrabold tracking-wide">
<slot name="title" />
</h2>
<p class="text-lg md:text-[2.5xl] text-zinc-600 md:leading-tight">
<p class="text-lg md:text-[1.75rem] text-zinc-600 md:leading-tight">
<slot name="subtitle" />
</p>
</div>
Expand Down
31 changes: 31 additions & 0 deletions composables/useSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,34 @@ function useIndexedMiniSearch(search: MaybeRefOrGetter<string>, indexedData: May
indexedMiniSearch,
}
}

export function useMiniSearch<DataItem>(search: MaybeRefOrGetter<string>, data: MaybeRefOrGetter<DataItem[]>, options: MiniSearchOptions) {
const createMiniSearch = () => {
const miniSearch = new MiniSearch(toValue(options))
miniSearch.addAll(toValue(data))
return miniSearch
}

const miniSearch = shallowRef(createMiniSearch())

watch(
() => toValue(options),
() => { miniSearch.value = createMiniSearch() },
{ deep: true },
)

watch(
() => toValue(data),
() => {
miniSearch.value.removeAll()
miniSearch.value.addAll(toValue(data))
},
{ deep: true },
)

const results = computed(() => {
return miniSearch.value.search(toValue(search))
})

return results
}
9 changes: 0 additions & 9 deletions content/1.packages.md → content/1.packages.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,4 @@
---
title: Packages
description: Every project of the organization. A gateway to our galaxy of JavaScript utilities, libraries, and tools created to empower developers.
navigation.icon: i-heroicons-cube-solid
layout: packages
---

::packages-hero
#title
Packages
#description
Every project of the organization. A gateway to our galaxy of JavaScript utilities, libraries, and tools created to empower developers.
::
9 changes: 0 additions & 9 deletions content/2.blog.md → content/2.blog.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,4 @@
---
title: Blog
description: Never miss a package release with the UnJS blog. Stay up-to-date on the latest announcements and get access to cutting-edge news.
navigation.icon: i-heroicons-newspaper-solid
layout: blog
---

::blog-hero
#title
Blog
#description
Never miss a package release with the UnJS blog. Stay up-to-date on the latest announcements and get access to cutting-edge news.
::
145 changes: 139 additions & 6 deletions layouts/blog.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,151 @@
<script lang="ts" setup>
import type { BlogPostCard } from 'types/blog'
import type { BlogPostCard } from '~/types/blog'
const { data } = await useAsyncData('blog', () => queryContent('/blog/').only(['_path', 'cover', 'title', 'description', 'publishedAt', 'authors']).sort({ publishedAt: -1 }).find() as Promise<BlogPostCard[]>)
const { page } = useContent()
const { data: blog } = await useAsyncData('blog', () => queryContent('/blog/').only(['_path', 'cover', 'title', 'description', 'publishedAt', 'authors']).sort({ publishedAt: -1 }).find() as Promise<BlogPostCard[]>)
if (!blog.value) {
throw createError({
statusCode: 500,
message: 'No blog found',
})
}
const search = ref('')
const searchDebounced = refDebounced(search, 150)
const searchResults = useMiniSearch(searchDebounced, blog, {
idField: 'title',
fields: ['title', 'description'],
storeFields: ['title', 'description', '_path'],
searchOptions: {
prefix: true,
fuzzy: 0.2,
},
})
const order = ref<1 | -1>(1)
const toggleOrder = function () {
order.value = order.value === 1 ? -1 : 1
}
const orderByOptions = [
{
id: 'title',
label: 'Name',
},
]
const orderBy = ref<string>('title')
const currentOrderBy = computed(() => orderByOptions.find(option => option.id === orderBy.value))
const results = computed(() => {
const currentBlog = searchDebounced.value ? searchResults.value : blog.value
if (!orderBy.value)
return currentBlog
return currentBlog.sort((a, b) => {
const aTitle = a.title.toLowerCase()
const bTitle = b.title.toLowerCase()
if (aTitle < bTitle)
return -1 * order.value
if (aTitle > bTitle)
return 1 * order.value
return 0
})
})
</script>

<template>
<Head>
<SchemaOrgWebPage :type="['CollectionPage']" />
</Head>
<main m="y-6 md:y-10">
<slot />
<main class="my-6 md:my-10">
<AppHero :title="page.title" :description="page.description" />

<section class="mt-8">
<h2 class="sr-only">
Packages list
</h2>

<div class="p-4 rounded-lg ring-1 ring-zinc-200 bg-white flex items-center justify-between">
<UInput
v-model="search"
color="white"
variant="outline"
name="search-packages"
placeholder="Search a package"
icon="i-heroicons-magnifying-glass-solid"
/>
<UButtonGroup size="sm" orientation="horizontal">
<UButton
:icon="order === 1 ? 'i-heroicons-bars-arrow-up-20-solid' : 'i-heroicons-bars-arrow-down-20-solid'"
color="white"
:title="order === 1 ? 'Ascending order' : 'Descending order'"
@click="toggleOrder()"
/>
<USelectMenu
v-model="orderBy"
class="w-32"
:options="orderByOptions"
color="white"
placeholder="Order By"
select-class="cursor-pointer"
value-attribute="id"
option-attribute="label"
>
<template #label>
{{ currentOrderBy?.label }}
</template>
</USelectMenu>
</UButtonGroup>
</div>

<ol v-if="blog" class="mt-8 grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-8 place-items-stretch">
<li v-for="item in results" :key="item.title">
<UCard as="article" :ui="{ base: 'h-full relative', divide: '', shadow: 'shadow-none hover:shadow-lg', rounded: 'rounded-xl', header: { base: 'flex gap-3 items-center', padding: 'py-0 pt-4 sm:px-4 sm:pt-4' }, body: { padding: 'p-4 sm:p-4' }, footer: { padding: 'py-0 pb-4 sm:px-4 sm:pb-4' } }">
<template #header>
<h3 class="text-xl font-semibold">
<NuxtLink :to="item._path" class="absolute inset-0" />
{{ item.title }}
</h3>
</template>

<p class="text-zinc-500">
{{ item.description }}
</p>

<section v-if="data" m="t-6" grid="~ cols-1 md:cols-2 lg:cols-3" gap-6>
<BlogCard v-for="post in data" :key="post._path" :post="post" />
<template #footer>
<dl class="text-zinc-500 text-sm flex flex-row justify-between items-center">
<dt class="sr-only">
Published on
</dt>
<dd>
<time :datetime="toISODateString(item.publishedAt)">
{{ toLocaleDateString(item.publishedAt) }}
</time>
</dd>
<dt class="sr-only">
Authors
</dt>
<dd>
<ul class="flex gap-2">
<li v-for="author in item.authors" :key="author._id">
<UAvatar :src="author.picture" :alt="author.name" size="xs" />
</li>
</ul>
</dd>
</dl>
</template>
</UCard>
</li>
</ol>
</section>
</main>
</template>
Loading

0 comments on commit cf71bd8

Please sign in to comment.