Skip to content

Commit

Permalink
feat(open-graph): use useSeoMeta over useHead
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed May 10, 2023
1 parent 4b1eb2c commit f7d11ee
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 31 deletions.
46 changes: 28 additions & 18 deletions packages/devtools/client/components/OpenGraphMissingTabs.vue
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { defu } from 'defu'
import type { ReactiveHead } from '@unhead/vue'
import type { MetaFlatInput } from '@uhead/schema'
import type { NormalizedHeadTag } from '../../src/types'
import { ogTags } from '../data/open-graph'
Expand All @@ -13,27 +14,36 @@ const missingTags = computed(() => {
return ogTags.filter(define => !props.tags?.some(tag => tag.name === define.name))
})
const missingRequiredTags = computed(() => {
return missingTags.value.filter(i => i.suggestion === 'required')
})
const missingRecommendedTags = computed(() => {
return missingTags.value.filter(i => i.suggestion === 'recommended')
})
const mergedMissingTags = computed(() => {
let data: Partial<ReactiveHead> = {}
const codeSnippet = computed(() => {
let mergedHeadOptions: Partial<ReactiveHead> = {}
const mergedSeoMetaOptions: Partial<MetaFlatInput> = {}
missingTags.value
.forEach((tag) => {
data = defu(data, tag.default)
if (tag.seoMeta)
Object.assign(mergedSeoMetaOptions, tag.seoMeta)
else
mergedHeadOptions = defu(mergedHeadOptions, tag.head)
})
return data
})
const codeSnippet = computed(() => {
const body = JSON.stringify(mergedMissingTags.value, null, 2)
.replace(/"([^"]+)":/g, '$1:')
.replace(/"/g, '\'')
return `useHead(${body})`
const lines = []
if (Object.keys(mergedSeoMetaOptions).length) {
const body = JSON.stringify(mergedSeoMetaOptions, null, 2)
.replace(/"([^"]+)":/g, '$1:')
.replace(/"/g, '\'')
lines.push(`useSeoMeta(${body})`)
}
if (Object.keys(mergedHeadOptions).length) {
const body = JSON.stringify(mergedHeadOptions, null, 2)
.replace(/"([^"]+)":/g, '$1:')
.replace(/"/g, '\'')
lines.push(`useHead(${body})`)
}
return lines.join('\n\n')
})
const copy = useCopy()
Expand All @@ -50,7 +60,7 @@ const selectedTab = ref(tabs[0])
<template v-if="missingTags.length">
<NSectionBlock
text="Missing Tags"
:description="`${missingTags.length} missing tags (${missingRequiredTags.length} required, ${missingRecommendedTags.length} recommended)`"
:description="`${missingTags.length} missing tags`"
icon="carbon:warning-other"
header-class="text-orange op100! [[open]_&]:text-inherit"
:padding="false"
Expand Down
58 changes: 45 additions & 13 deletions packages/devtools/client/data/open-graph.ts
@@ -1,9 +1,11 @@
import type { ReactiveHead } from '@unhead/vue'
import type { MetaFlatInput } from '@unhead/schema'

export interface OpenGraphTagDefine {
name: string
suggestion: 'required' | 'recommended' | 'optional'
default: Partial<ReactiveHead>
head: Partial<ReactiveHead>
seoMeta?: Partial<MetaFlatInput> & { title?: string }
docs?: string
description?: string
}
Expand All @@ -12,7 +14,10 @@ export const ogTags: OpenGraphTagDefine[] = [
{
name: 'title',
suggestion: 'required',
default: {
head: {
title: '[title]',
},
seoMeta: {
title: '[title]',
},
docs: 'https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title',
Expand All @@ -21,20 +26,23 @@ export const ogTags: OpenGraphTagDefine[] = [
{
name: 'description',
suggestion: 'required',
default: {
head: {
meta: [
{
name: 'description',
content: '[description]',
},
],
},
seoMeta: {
description: '[description]',
},
description: 'A one to two sentence summary for search engines that includes relevant keywords to improve visibility in search results.',
},
{
name: 'icon',
suggestion: 'recommended',
default: {
head: {
link: [
{
rel: 'icon',
Expand All @@ -48,7 +56,7 @@ export const ogTags: OpenGraphTagDefine[] = [
{
name: 'lang',
suggestion: 'recommended',
default: {
head: {
htmlAttrs: {
lang: 'en',
},
Expand All @@ -58,111 +66,135 @@ export const ogTags: OpenGraphTagDefine[] = [
{
name: 'og:title',
suggestion: 'recommended',
default: {
head: {
meta: [
{
property: 'og:title',
content: '[og:title]',
},
],
},
seoMeta: {
ogTitle: '[og:title]',
},
docs: 'https://ogp.me/#metadata',
description: 'A title for the link preview used by social media platforms.',
},
{
name: 'og:description',
suggestion: 'recommended',
default: {
head: {
meta: [
{
property: 'og:description',
content: '[og:description]',
},
],
},
seoMeta: {
ogDescription: '[og:description]',
},
docs: 'https://ogp.me/#metadata',
description: 'A description for the link preview used by social media platforms.',
},
{
name: 'og:image',
suggestion: 'recommended',
default: {
head: {
meta: [
{
property: 'og:image',
content: '[og:image]',
},
],
},
seoMeta: {
ogImage: '[og:image]',
},
docs: 'https://ogp.me/#metadata',
description: 'An image for the link preview used by social media platforms.',
},
{
name: 'og:url',
suggestion: 'recommended',
default: {
head: {
meta: [
{
property: 'og:url',
content: '[og:url]',
},
],
},
seoMeta: {
ogUrl: '[og:url]',
},
docs: 'https://ogp.me/#metadata',
description: 'A canonical URL for the link preview used to specify the preferred URL to display in search engine results and social media previews when multiple URLs may point to the same page.',
},
{
name: 'twitter:title',
suggestion: 'recommended',
default: {
head: {
meta: [
{
name: 'twitter:title',
content: '[twitter:title]',
},
],
},
seoMeta: {
twitterTitle: '[twitter:title]',
},
docs: 'https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/abouts-cards',
description: 'A title for the Twitter card used to provide a preview of the content shared on the page.',
},
{
name: 'twitter:description',
suggestion: 'recommended',
default: {
head: {
meta: [{
name: 'twitter:description',
content: '[twitter:description]',
},
],
},
seoMeta: {
twitterDescription: '[twitter:description]',
},
docs: 'https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/abouts-cards',
description: 'A description for the Twitter card used to provide a preview of the content shared on the page.',
},
{
name: 'twitter:image',
suggestion: 'recommended',
default: {
head: {
meta: [
{
name: 'twitter:image',
content: '[twitter:image]',
},
],
},
seoMeta: {
twitterImage: '[twitter:image]',
},
docs: 'https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/abouts-cards',
description: 'An image for the Twitter card used to provide a preview of the content shared on the page.',
},
{
name: 'twitter:card',
suggestion: 'recommended',
default: {
head: {
meta: [
{
name: 'twitter:card',
content: 'summary',
},
],
},
seoMeta: {
twitterCard: 'summary',
},
docs: 'https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/abouts-cards',
description: 'The type of Twitter card to use, which determines the type of card to display in link previews on Twitter.',
},
Expand Down

0 comments on commit f7d11ee

Please sign in to comment.