mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-14 20:19:34 +01:00
docs(showcase): update
This commit is contained in:
@@ -165,12 +165,12 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
<circle cx="6.53711" cy="37.4551" r="1.5" fill="var(--ui-border-accented)" />
|
<circle cx="6.53711" cy="37.4551" r="1.5" fill="var(--ui-border-accented)" />
|
||||||
<circle cx="38.5957" cy="37.4551" r="1.5" fill="var(--ui-border-accented)" />
|
<circle cx="38.5957" cy="37.4551" r="1.5" fill="var(--ui-border-accented)" />
|
||||||
</svg>
|
</svg>
|
||||||
<UIcon :name="feature.icon" class="size-5 flex-shrink-0" />
|
<UIcon :name="feature.icon" class="size-5 shrink-0" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<h2 class="font-medium text-(--ui-text-highlighted) inline-flex items-center gap-x-1">
|
<h2 class="font-medium text-(--ui-text-highlighted) inline-flex items-center gap-x-1">
|
||||||
{{ feature.title }}
|
{{ feature.title }}
|
||||||
<UIcon v-if="feature.to" name="i-lucide-arrow-right" class="size-4 flex-shrink-0 opacity-0 group-hover:opacity-100 transition-all duration-200 -translate-x-1 group-hover:translate-x-0" />
|
<UIcon v-if="feature.to" name="i-lucide-arrow-right" class="size-4 shrink-0 opacity-0 group-hover:opacity-100 transition-all duration-200 -translate-x-1 group-hover:translate-x-0" />
|
||||||
</h2>
|
</h2>
|
||||||
<p class="text-sm text-(--ui-text-muted)">
|
<p class="text-sm text-(--ui-text-muted)">
|
||||||
{{ feature.description }}
|
{{ feature.description }}
|
||||||
|
|||||||
@@ -37,12 +37,12 @@ useSeoMeta({
|
|||||||
|
|
||||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||||
|
|
||||||
<div class="border border-(--ui-border) bg-(--ui-bg)">
|
<div class="border-l border-t border-(--ui-border)">
|
||||||
<ul class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 items-start justify-center">
|
<ul class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 items-start justify-center divide-y divide-x divide-(--ui-border)">
|
||||||
<li
|
<li
|
||||||
v-for="item in page.items"
|
v-for="item in page.items"
|
||||||
:key="item.name"
|
:key="item.name"
|
||||||
class="relative flex flex-col gap-y-4 justify-start group h-full p-4 hover:bg-(--ui-bg-elevated)/50 border-(--ui-border) border-b max-sm:last:border-b-0 border-r max-sm:border-r-0 sm:even:border-r-0 lg:even:border-r lg:border-r lg:[&:nth-child(4n)]:border-r-0 lg:[&:nth-child(5n)]:border-b-0 lg:[&:nth-child(6n)]:border-b-0"
|
class="group relative flex items-center justify-center flex-1 size-full p-2 last:border-r last:border-b border-(--ui-border) overflow-hidden"
|
||||||
>
|
>
|
||||||
<NuxtLink class="inset-0 absolute" :to="item.url" target="_blank">
|
<NuxtLink class="inset-0 absolute" :to="item.url" target="_blank">
|
||||||
<span class="sr-only">Go to {{ item.name }}</span>
|
<span class="sr-only">Go to {{ item.name }}</span>
|
||||||
@@ -51,20 +51,34 @@ useSeoMeta({
|
|||||||
<NuxtImg
|
<NuxtImg
|
||||||
:src="`/assets/showcase/${item.name.toLowerCase().replace(/\s/g, '-')}.png`"
|
:src="`/assets/showcase/${item.name.toLowerCase().replace(/\s/g, '-')}.png`"
|
||||||
:alt="`Screenshot of ${item.name}`"
|
:alt="`Screenshot of ${item.name}`"
|
||||||
width="311"
|
width="327"
|
||||||
height="194"
|
height="184"
|
||||||
class="rounded-[calc(var(--ui-radius)*1.5)] group-hover:scale-103 duration-200 transition-transform pointer-events-none"
|
:modifiers="{
|
||||||
|
position: 'top'
|
||||||
|
}"
|
||||||
|
class="aspect-[16/9] size-full opacity-75 group-hover:opacity-100 group-hover:scale-110 duration-200 transition-[scale,opacity] pointer-events-none"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="flex items-center gap-1 px-1">
|
<div class="absolute flex items-center px-2.5 py-0.75 gap-1 opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none bg-black/90 rounded-full">
|
||||||
<span class="font-medium text-(--ui-text-highlighted)">
|
<span class="text-sm text-(--ui-text-highlighted) font-medium">
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</span>
|
</span>
|
||||||
<UIcon name="i-lucide-arrow-right" class="size-4 flex-shrink-0 opacity-0 group-hover:opacity-100 transition-all duration-200 -translate-x-1 group-hover:translate-x-0 text-(--ui-text-muted)" />
|
<UIcon name="i-lucide-arrow-up-right" class="size-4 shrink-0" />
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-center -mb-[36px]">
|
||||||
|
<UButton
|
||||||
|
label="Submit your project"
|
||||||
|
trailing-icon="i-lucide-plus"
|
||||||
|
color="neutral"
|
||||||
|
size="lg"
|
||||||
|
to="https://github.com/nuxt/ui/edit/v3/docs/content/showcase.yml"
|
||||||
|
target="_blank"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</UPageHero>
|
</UPageHero>
|
||||||
</UMain>
|
</UMain>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -5,15 +5,27 @@ hero:
|
|||||||
title: Showcase
|
title: Showcase
|
||||||
description: Discover our selection of projects built with Nuxt UI.
|
description: Discover our selection of projects built with Nuxt UI.
|
||||||
items:
|
items:
|
||||||
|
- name: Ovatu
|
||||||
|
url: https://ovatu.com/
|
||||||
- name: Shelve
|
- name: Shelve
|
||||||
url: https://shelve.cloud
|
url: https://shelve.cloud/
|
||||||
- name: Uneed
|
- name: Uneed
|
||||||
url: https://uneed.best
|
url: https://uneed.best/
|
||||||
- name: Details
|
- name: Details
|
||||||
url: https://details.team
|
url: https://details.team/
|
||||||
- name: Espace Asso by Benevolt
|
- name: Espace Asso by Benevolt
|
||||||
url: https://asso.benevolt.fr
|
url: https://asso.benevolt.fr/
|
||||||
- name: Directus Docs
|
- name: Directus Docs
|
||||||
url: https://docs.directus.io
|
url: https://docs.directus.io/
|
||||||
- name: Super SaaS
|
- name: Super SaaS
|
||||||
url: https://supersaas.dev/
|
url: https://supersaas.dev/
|
||||||
|
- name: Passionate People
|
||||||
|
url: https://passionatepeople.io/
|
||||||
|
- name: The Companies API
|
||||||
|
url: https://www.thecompaniesapi.com/
|
||||||
|
- name: Thuprai
|
||||||
|
url: https://thuprai.com/
|
||||||
|
- name: Juno.one
|
||||||
|
url: https://www.juno.one/
|
||||||
|
- name: Pallyy
|
||||||
|
url: https://pallyy.com/
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
import { defineNuxtModule } from '@nuxt/kit'
|
|
||||||
import { existsSync } from 'node:fs'
|
|
||||||
import { join } from 'pathe'
|
|
||||||
import captureWebsite from 'capture-website'
|
|
||||||
|
|
||||||
interface ContentFile {
|
|
||||||
id?: string
|
|
||||||
items?: any
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TemplateItem {
|
|
||||||
name: string
|
|
||||||
url?: string
|
|
||||||
screenshotUrl?: string
|
|
||||||
screenshotOptions?: Record<string, any>
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineNuxtModule((options, nuxt) => {
|
|
||||||
nuxt.hook('content:file:afterParse', async ({ content: file }: { content: ContentFile }) => {
|
|
||||||
if (file.id?.includes('showcase') && file.items) {
|
|
||||||
const itemsArray: TemplateItem[] = Array.isArray(file.items)
|
|
||||||
? file.items
|
|
||||||
: Object.values(file.items)
|
|
||||||
if (itemsArray.length === 0) {
|
|
||||||
console.log('No items to process')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
console.log(`Processing ${itemsArray.length} template items`)
|
|
||||||
for (const template of itemsArray) {
|
|
||||||
const url = template.screenshotUrl || template.url
|
|
||||||
if (!url) {
|
|
||||||
console.error(`Template ${template.name} has no "url" or "screenshotUrl" to take a screenshot from`)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
const name = template.name.toLowerCase().replace(/\s/g, '-')
|
|
||||||
const filename = join(process.cwd(), 'docs/public/assets/showcase', `${name}.png`)
|
|
||||||
if (existsSync(filename)) {
|
|
||||||
console.log(`Screenshot for ${template.name} already exists, skipping`)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
console.log(`Generating screenshot for Template ${template.name} hitting ${url}...`)
|
|
||||||
try {
|
|
||||||
await captureWebsite.file(url, filename, {
|
|
||||||
...(template.screenshotOptions || {}),
|
|
||||||
launchOptions: { headless: true }
|
|
||||||
})
|
|
||||||
console.log(`Screenshot for ${template.name} generated successfully`)
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error generating screenshot for ${template.name}:`, error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
56
docs/modules/showcase.ts
Normal file
56
docs/modules/showcase.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { defineNuxtModule } from '@nuxt/kit'
|
||||||
|
import { existsSync } from 'node:fs'
|
||||||
|
import { join } from 'pathe'
|
||||||
|
import captureWebsite from 'capture-website'
|
||||||
|
|
||||||
|
interface ContentFile {
|
||||||
|
id?: string
|
||||||
|
body?: {
|
||||||
|
items: TemplateItem[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TemplateItem {
|
||||||
|
name: string
|
||||||
|
url?: string
|
||||||
|
screenshotUrl?: string
|
||||||
|
screenshotOptions?: Record<string, any>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineNuxtModule((_, nuxt) => {
|
||||||
|
nuxt.hook('content:file:afterParse', async ({ content: file }: { content: ContentFile }) => {
|
||||||
|
if (!file.id?.includes('showcase')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!file.body?.items?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (const template of file.body.items) {
|
||||||
|
const url = template.screenshotUrl || template.url
|
||||||
|
if (!url) {
|
||||||
|
console.error(`Template ${template.name} has no "url" or "screenshotUrl" to take a screenshot from`)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = template.name.toLowerCase().replace(/\s/g, '-')
|
||||||
|
const filename = join(process.cwd(), 'docs/public/assets/showcase', `${name}.png`)
|
||||||
|
|
||||||
|
if (existsSync(filename)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Generating screenshot for Template ${template.name} hitting ${url}...`)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await captureWebsite.file(url, filename, {
|
||||||
|
...(template.screenshotOptions || {}),
|
||||||
|
launchOptions: { headless: true }
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(`Screenshot for ${template.name} generated successfully`)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error generating screenshot for ${template.name}:`, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
BIN
docs/public/assets/showcase/juno.one.png
Normal file
BIN
docs/public/assets/showcase/juno.one.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 422 KiB |
BIN
docs/public/assets/showcase/ovatu.png
Normal file
BIN
docs/public/assets/showcase/ovatu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.4 MiB |
BIN
docs/public/assets/showcase/pallyy.png
Normal file
BIN
docs/public/assets/showcase/pallyy.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 518 KiB |
BIN
docs/public/assets/showcase/passionate-people.png
Normal file
BIN
docs/public/assets/showcase/passionate-people.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 749 KiB |
BIN
docs/public/assets/showcase/the-companies-api.png
Normal file
BIN
docs/public/assets/showcase/the-companies-api.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 575 KiB |
BIN
docs/public/assets/showcase/thuprai.png
Normal file
BIN
docs/public/assets/showcase/thuprai.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
Reference in New Issue
Block a user