Skip to content
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
2 changes: 1 addition & 1 deletion app/pages/design-kit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ defineOgImage('Docs.takumi', {
<UPage v-if="pageData">
<UPageHero
:title="pageData.title"
:links="pageData.links"
:links="pickLinks(pageData.links)"
:description="pageData.description"
:ui="{
title: 'text-left',
Expand Down
7 changes: 4 additions & 3 deletions app/pages/docs/[...slug].vue
Original file line number Diff line number Diff line change
Expand Up @@ -317,10 +317,11 @@ const noRightAside = computed(() => route.path.includes('/examples/'))
</UPageAside>
</template>
<UPageHeader
:title="fm.title"
:description="fm.description"
:ui="{
wrapper: 'flex-row items-center flex-wrap justify-between'
}"
v-bind="fm"
>
<template #headline>
<UBreadcrumb :items="breadcrumb" />
Expand All @@ -347,10 +348,10 @@ const noRightAside = computed(() => route.path.includes('/examples/'))
color="neutral"
variant="soft"
:target="link.to.startsWith('http') ? '_blank' : undefined"
v-bind="{ ...link, size: 'sm' }"
v-bind="{ ...pickLink(link), size: 'sm' }"
>
<template v-if="link.avatar" #leading>
<UAvatar v-bind="link.avatar" size="2xs" :alt="`${link.label} avatar`" />
<UAvatar v-bind="pickAvatar(link.avatar)" size="2xs" :alt="`${link.label} avatar`" />
</template>
</UButton>

Expand Down
2 changes: 1 addition & 1 deletion app/pages/enterprise/agencies/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ await fetchList()
<UPageHero
:title="pageData.title"
:description="pageData.description"
:links="pageData.links"
:links="pickLinks(pageData.links)"
/>

<UContainer>
Expand Down
2 changes: 1 addition & 1 deletion app/pages/enterprise/jobs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ await fetchList()
<UPageHero
:title="pageData.title"
:description="pageData.description"
:links="pageData.links"
:links="pickLinks(pageData.links)"
:ui="{
title: 'text-left',
description: 'text-left',
Expand Down
2 changes: 1 addition & 1 deletion app/pages/enterprise/sponsors.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ defineOgImage('Docs.takumi', {
<UPageHero
:title="pageData.title"
:description="pageData.description"
:links="pageData.links"
:links="pickLinks(pageData.links)"
/>

<UPageBody class="relative">
Expand Down
14 changes: 7 additions & 7 deletions app/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ const isMounted = useMounted()
:in-view-options="{ once: true }"
>
<UPageFeature
v-bind="feature"
v-bind="pickFeature(feature)"
orientation="vertical"
/>
</Motion>
Expand Down Expand Up @@ -283,7 +283,7 @@ const isMounted = useMounted()
}"
>
<UUser
v-bind="pageData.testimonial.author"
v-bind="pickUser(pageData.testimonial.author)"
size="xl"
class="justify-center"
/>
Expand Down Expand Up @@ -412,7 +412,7 @@ const isMounted = useMounted()
<p class="text-muted text-center">
{{ pageData.stats.community.description }}
</p>
<UButton class="mt-4 w-fit" v-bind="pageData.stats.cta" />
<UButton class="mt-4 w-fit" v-bind="pickLink(pageData.stats.cta)" />
</div>
</UPageCard>
</div>
Expand Down Expand Up @@ -451,7 +451,7 @@ const isMounted = useMounted()

<UPageSection
:description="pageData.modules.description"
:links="pageData.modules.links"
:links="pickLinks(pageData.modules.links)"
:ui="{
root: 'bg-linear-to-b border-t border-default from-muted dark:from-muted/40 to-default',
title: 'text-left',
Expand Down Expand Up @@ -483,7 +483,7 @@ const isMounted = useMounted()
<UPageSection
:title="pageData.deploy.title"
:description="pageData.deploy.description"
:links="pageData.deploy.links"
:links="pickLinks(pageData.deploy.links)"
orientation="horizontal"
:ui="{
root: 'bg-linear-to-b border-t border-default from-muted dark:from-muted/40 to-default'
Expand All @@ -502,7 +502,7 @@ const isMounted = useMounted()
<UPageSection
:title="pageData.contributors.title"
:description="pageData.contributors.description"
:links="pageData.contributors.links"
:links="pickLinks(pageData.contributors.links)"
orientation="horizontal"
reverse
:ui="{
Expand Down Expand Up @@ -578,7 +578,7 @@ const isMounted = useMounted()
<UPageSection
:title="pageData.sponsors.title"
:description="pageData.sponsors.description"
:links="pageData.sponsors.links"
:links="pickLinks(pageData.sponsors.links)"
class="relative"
:ui="{
root: 'bg-linear-to-b border-t border-default from-muted dark:from-muted/40 to-default',
Expand Down
7 changes: 6 additions & 1 deletion app/pages/newsletter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,12 @@ defineOgImage('Docs.takumi', {

<UPageBody>
<UContainer>
<UPageCTA v-bind="pageData.cta" />
<UPageCTA
:headline="pageData.cta.headline"
:title="pageData.cta.title"
:description="pageData.cta.description"
:links="pickLinks(pageData.cta.links)"
/>
</UContainer>
</UPageBody>
</UPage>
Expand Down
2 changes: 1 addition & 1 deletion app/pages/templates.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ defineOgImage('Docs.takumi', {
<UPageHero
:title="pageData.title"
:description="pageData.description"
:links="pageData.links"
:links="pickLinks(pageData.links)"
/>
<UPageBody>
<UContainer>
Expand Down
2 changes: 1 addition & 1 deletion app/pages/video-courses.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ defineOgImage('Docs.takumi', {
<UPageHero
:title="pageData.title"
:description="pageData.description"
:links="pageData.links"
:links="pickLinks(pageData.links)"
/>
<UPageBody>
<UContainer>
Expand Down
48 changes: 48 additions & 0 deletions app/utils/content.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { NavigationItem } from 'comark-content'
import type { AvatarProps, ButtonProps, PageFeatureProps, UserProps } from '@nuxt/ui'

export function navPageFromPath(path: string, tree: NavigationItem[]): NavigationItem | undefined {
for (const file of tree) {
Expand Down Expand Up @@ -96,3 +97,50 @@ export function listSurround(

return [link(items?.[index - 1]), link(items?.[index + 1])]
}

/**
* Content data reaches components through these picks, never a `v-bind` spread.
* - Vue binds every unknown key to the DOM, so a spread lets content set any attribute.
* - Nuxt UI spreads each `links` item onto a `UButton`, each `authors` item onto a `UUser`…
* Keys are the ones content uses: add one here before content can set it.
*/

type ContentObject = Record<string, any> | null | undefined

function pick<T>(data: ContentObject, keys: readonly string[]): T {
const picked: Record<string, unknown> = {}
for (const key of keys) {
if (data?.[key] !== undefined) picked[key] = data[key]
}
return picked as T
}

const AVATAR_KEYS = ['src', 'srcset', 'alt', 'text', 'icon', 'provider', 'loading']
const LINK_KEYS = ['label', 'to', 'target', 'title', 'icon', 'leadingIcon', 'trailingIcon', 'trailing', 'color', 'variant', 'size', 'download', 'external']
const FEATURE_KEYS = ['title', 'description', 'icon', 'to', 'target']
const USER_KEYS = ['name', 'description', 'to', 'target']

export function pickAvatar(avatar: ContentObject): AvatarProps | undefined {
return avatar ? pick<AvatarProps>(avatar, AVATAR_KEYS) : undefined
}

export function pickLink(link: ContentObject): ButtonProps {
const picked = pick<ButtonProps>(link, LINK_KEYS)
if (link?.avatar) picked.avatar = pickAvatar(link.avatar)
return picked
}

/** `undefined` stays `undefined`, so components still skip an absent `links`. */
export function pickLinks(links: ContentObject[] | null | undefined): ButtonProps[] | undefined {
return links?.map(pickLink)
}

export function pickFeature(feature: ContentObject): PageFeatureProps {
return pick<PageFeatureProps>(feature, FEATURE_KEYS)
}

export function pickUser(user: ContentObject): UserProps {
const picked = pick<UserProps>(user, USER_KEYS)
if (user?.avatar) picked.avatar = pickAvatar(user.avatar)
return picked
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"@chat-adapter/discord": "^4.42.0",
"@chat-adapter/state-memory": "^4.42.0",
"@chat-adapter/state-redis": "^4.42.0",
"@comark/nuxt": "^0.7.0",
"@comark/nuxt": "^0.8.1",
"@iconify-json/heroicons": "^1.2.3",
"@iconify-json/logos": "^1.2.17",
"@iconify-json/lucide": "^1.2.146",
Expand Down
Loading
Loading