| name | composables |
| description | Project composables - useBlog, usePageSeo, useEnterAnimations, useBlogScroll, useGsapAnimations. Use when consuming blog/SEO/animation logic. |
Composables
All project composables in app/composables/. Auto-imported by Nuxt.
Files
app/composables/useBlog.ts
app/composables/usePageSeo.ts
app/composables/useSiteSeoDefaults.ts
app/composables/useBlogScroll.ts
app/composables/useEnterAnimations.ts
useBlog()
Blog logic. Uses the active locale internally.
const {
getPosts,
getPost,
getAdjacentPosts,
findEquivalentPost,
getRecentPosts,
getPostsByTag,
getAllTags,
} = useBlog()
BlogPost type
interface BlogPost {
slug?: string
title: string
date: string
order?: number
lastmod?: string
author?: string
tags?: string[]
summary?: string
image?: string
id?: string
path?: string
}
Usage with useAsyncData
const { locale } = useI18n()
const { getPosts } = useBlog()
const { data: posts, pending } = await useAsyncData(
() => `blog-index-${locale.value}`,
() => getPosts(),
{ watch: [locale] }
)
const { data: post } = await useAsyncData(
() => `blog-post-${slug}-${locale.value}`,
() => getPost(slug),
{ watch: [locale] }
)
usePageSeo(pageKey, options?)
Configures all the SEO of a page (title, description, OG, Twitter).
usePageSeo('home')
usePageSeo('me')
usePageSeo('projects')
usePageSeo('blog')
usePageSeo('resources')
usePageSeo('blog', {
title: () => post.value?.title,
description: () => post.value?.summary,
ogType: 'article',
image: () => post.value?.image,
keywords: () => post.value?.tags?.join(', '),
})
useSiteSeoDefaults()
Only call in app/app.vue. Configures robots, canonical and global site defaults.
useSiteSeoDefaults()
useBlogScroll()
const { scrollToTop, getScrollTop, getScrollElement } = useBlogScroll()
scrollToTop()
getScrollTop()
getScrollElement()
useEnterAnimations()
Header pattern (label + title + description) + panels with GSAP.
const {
label,
titleEl,
descriptionEl,
setPanelRef,
resetPanelRefs,
setupEnterAnimations,
cleanupEnterAnimations,
} = useEnterAnimations()
{
headerStart?: string
panelsStart?: string
headerTrigger?: HTMLElement | null
panelsTrigger?: HTMLElement | null
fadeHeader?: boolean
fadePanels?: boolean
}
<script setup>
const { label, titleEl, descriptionEl, setPanelRef, setupEnterAnimations, cleanupEnterAnimations } = useEnterAnimations()
onMounted(() => nextTick(() => setupEnterAnimations()))
onUnmounted(() => cleanupEnterAnimations())
</script>
<template>
<p ref="label" class="eyebrow">Label</p>
<h1 ref="titleEl">Title</h1>
<p ref="descriptionEl">Description</p>
<div v-for="item in items" :key="item.id" :ref="setPanelRef">...</div>
</template>
useGsapAnimations()
For custom animations without the header/panels pattern. Automatic cleanup in onBeforeUnmount.
const { setupAnimations, cleanup } = useGsapAnimations()
onMounted(() => {
nextTick(() => {
setupAnimations(() => {
const scroller = getMainScroller()
animateInOnEnter(document.querySelector('.my-el'), {
from: { opacity: 0, y: 30 },
to: { ...gsapDefaults, opacity: 1, y: 0 },
scroller,
})
})
})
})