mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-22 16:00:39 +01:00
docs: update
This commit is contained in:
@@ -1,58 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
const id = 'nuxt-ui-banner-1'
|
||||
const to = '/pro/pricing'
|
||||
|
||||
const hideBanner = () => {
|
||||
localStorage.setItem(id, 'true')
|
||||
|
||||
document.querySelector('html')?.classList.add('hide-banner')
|
||||
}
|
||||
|
||||
if (import.meta.server) {
|
||||
useHead({
|
||||
script: [{
|
||||
key: 'prehydrate-template-banner',
|
||||
innerHTML: `
|
||||
if (localStorage.getItem('${id}') === 'true') {
|
||||
document.querySelector('html').classList.add('hide-banner')
|
||||
}`.replace(/\s+/g, ' '),
|
||||
type: 'text/javascript'
|
||||
}]
|
||||
})
|
||||
}
|
||||
const config = useRuntimeConfig().public
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative bg-primary hover:bg-primary/90 transition-[background] backdrop-blur z-50 app-banner">
|
||||
<UContainer class="py-2">
|
||||
<NuxtLink v-if="to" :to="to" class="focus:outline-none" aria-label="Nuxt UI Pro pricing" tabindex="-1">
|
||||
<span class="absolute inset-0 " aria-hidden="true" />
|
||||
</NuxtLink>
|
||||
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<div class="lg:flex-1 hidden lg:flex items-center" />
|
||||
|
||||
<p class="text-sm font-medium text-white dark:text-gray-900">
|
||||
<UIcon name="i-heroicons-rocket-launch" class="w-5 h-5 align-top flex-shrink-0 pointer-events-none mr-2" />
|
||||
<span class="font-semibold">Nuxt UI Pro v1.0</span> is out with dashboard components!
|
||||
</p>
|
||||
|
||||
<div class="flex items-center justify-end lg:flex-1">
|
||||
<button
|
||||
class="p-1.5 rounded-md inline-flex hover:bg-primary/90"
|
||||
aria-label="Close banner"
|
||||
@click.prevent="hideBanner"
|
||||
>
|
||||
<UIcon name="i-heroicons-x-mark-20-solid" class="w-5 h-5 text-white dark:text-gray-900" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</UContainer>
|
||||
</div>
|
||||
<UBanner icon="i-heroicons-light-bulb" :actions="[{ label: 'Go to Nuxt UI v2', to: 'https://ui.nuxt.com', trailingIcon: 'i-heroicons-arrow-right-20-solid', color: 'white', class: 'rounded-full' }]" :close="false">
|
||||
<template #title>
|
||||
You're looking at the documentation for <span class="font-semibold">Nuxt UI v{{ config.version }}</span>!
|
||||
</template>
|
||||
</UBanner>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.hide-banner .app-banner {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
const links = [{
|
||||
icon: 'i-simple-icons-figma',
|
||||
const route = useRoute()
|
||||
|
||||
const items = [{
|
||||
label: 'Figma Kit',
|
||||
to: 'https://www.figma.com/community/file/1288455405058138934',
|
||||
target: '_blank'
|
||||
}, {
|
||||
label: 'Playground',
|
||||
icon: 'i-simple-icons-stackblitz',
|
||||
to: 'https://stackblitz.com/edit/nuxt-ui',
|
||||
target: '_blank'
|
||||
}, {
|
||||
label: 'Roadmap',
|
||||
icon: 'i-heroicons-map',
|
||||
to: '/roadmap'
|
||||
}, {
|
||||
label: 'Releases',
|
||||
icon: 'i-heroicons-rocket-launch',
|
||||
to: '/releases'
|
||||
}]
|
||||
</script>
|
||||
@@ -23,9 +21,9 @@ const links = [{
|
||||
<template>
|
||||
<USeparator icon="i-simple-icons-nuxtdotjs" class="h-px" />
|
||||
|
||||
<UFooter :links="links">
|
||||
<UFooter>
|
||||
<template #left>
|
||||
<NuxtLink v-if="$route.path.startsWith('/pro')" to="https://ui.nuxt.com/pro/purchase" target="_blank" class="text-sm text-gray-500 dark:text-gray-400">
|
||||
<NuxtLink v-if="route.path.startsWith('/pro')" to="https://ui.nuxt.com/pro/purchase" target="_blank" class="text-sm text-gray-500 dark:text-gray-400">
|
||||
Purchase <span class="text-gray-900 dark:text-white">Nuxt UI Pro</span>
|
||||
</NuxtLink>
|
||||
<NuxtLink v-else to="https://github.com/nuxt/ui" target="_blank" class="text-sm text-gray-500 dark:text-gray-400">
|
||||
@@ -33,6 +31,8 @@ const links = [{
|
||||
</NuxtLink>
|
||||
</template>
|
||||
|
||||
<UNavigationMenu :items="items" variant="link" color="black" />
|
||||
|
||||
<template #right>
|
||||
<UButton aria-label="Nuxt Website" icon="i-simple-icons-nuxtdotjs" to="https://nuxt.com" target="_blank" color="gray" variant="ghost" />
|
||||
<UButton aria-label="Nuxt UI on Discord" icon="i-simple-icons-discord" to="https://chat.nuxt.dev" target="_blank" color="gray" variant="ghost" />
|
||||
|
||||
@@ -1,26 +1,43 @@
|
||||
<script setup lang="ts">
|
||||
import type { NavItem } from '@nuxt/content/dist/runtime/types'
|
||||
import type { NavigationMenuItem } from '#ui/types'
|
||||
|
||||
const props = defineProps<{
|
||||
links: NavigationMenuItem[]
|
||||
}>()
|
||||
|
||||
const route = useRoute()
|
||||
const config = useRuntimeConfig().public
|
||||
|
||||
const open = inject<Ref<boolean>>('open')
|
||||
const navigation = inject<Ref<NavItem[]>>('navigation')
|
||||
|
||||
const items = computed(() => props.links.map(({ icon, ...link }) => link))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UHeader
|
||||
:links="links"
|
||||
:class="{
|
||||
'border-primary-200/75 dark:border-primary-900/50': $route.path === '/',
|
||||
'border-gray-200 dark:border-gray-800': $route.path !== '/'
|
||||
'border-primary-200/75 dark:border-primary-900/50': route.path === '/',
|
||||
'border-gray-200 dark:border-gray-800': route.path !== '/'
|
||||
}"
|
||||
>
|
||||
<template #left>
|
||||
<NuxtLink to="/" class="flex items-end gap-2 font-bold text-xl text-gray-900 dark:text-white" aria-label="Nuxt UI">
|
||||
<Logo class="w-auto h-6" />
|
||||
|
||||
<UBadge v-if="$route.path.startsWith('/pro')" label="Pro" variant="subtle" size="sm" class="-mb-[2px] rounded font-semibold" />
|
||||
<UBadge v-if="$route.path.startsWith('/dev')" label="Edge" variant="subtle" size="sm" class="-mb-[2px] rounded font-semibold" />
|
||||
<UBadge :label="`v${config.version}`" variant="subtle" size="sm" class="-mb-[2px] rounded font-semibold" />
|
||||
</NuxtLink>
|
||||
</template>
|
||||
|
||||
<UNavigationMenu :items="items" variant="link" />
|
||||
|
||||
<template #right>
|
||||
<!-- <ColorPicker /> -->
|
||||
|
||||
<!-- <UTooltip text="Search" :shortcuts="[metaSymbol, 'K']" :popper="{ strategy: 'absolute' }">
|
||||
<UContentSearchButton :label="null" />
|
||||
</UTooltip> -->
|
||||
<UTooltip text="Search" :kbds="['meta', 'K']">
|
||||
<UButton aria-label="Search" icon="i-heroicons-magnifying-glass-20-solid" color="gray" variant="ghost" @click="open = true" />
|
||||
</UTooltip>
|
||||
|
||||
<!-- <UColorModeButton /> -->
|
||||
|
||||
@@ -34,35 +51,12 @@
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #panel>
|
||||
<!-- <UAsideLinks :links="links" /> -->
|
||||
<template #content>
|
||||
<UNavigationMenu orientation="vertical" :items="items" class="-ml-2.5" />
|
||||
|
||||
<!-- <UDivider type="dashed" class="my-4" /> -->
|
||||
<USeparator type="dashed" class="my-4" />
|
||||
|
||||
<!-- <BranchSelect /> -->
|
||||
|
||||
<!-- <UNavigationTree :links="mapContentNavigation(navigation)" :multiple="false" default-open /> -->
|
||||
<UContentNavigation :navigation="navigation" />
|
||||
</template>
|
||||
</UHeader>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { NavItem } from '@nuxt/content/dist/runtime/types'
|
||||
import type { HeaderLink } from '#ui-pro/types'
|
||||
|
||||
defineProps<{
|
||||
links: HeaderLink[]
|
||||
}>()
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const nav = inject<Ref<NavItem[]>>('navigation')
|
||||
|
||||
const navigation = computed(() => {
|
||||
if (route.path.startsWith('/pro')) {
|
||||
return nav.value.find(item => item._path === '/pro')?.children
|
||||
}
|
||||
|
||||
return nav.value.filter(item => !item._path.startsWith('/pro'))
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<template>
|
||||
<svg width="264" height="264" viewBox="0 0 264 264" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M146.496 211.2H234.822C237.627 211.2 240.383 210.468 242.813 209.078C245.242 207.688 247.259 205.688 248.662 203.279C250.064 200.871 250.801 198.139 250.8 195.359C250.799 192.579 250.059 189.847 248.655 187.44L189.337 85.612C187.935 83.2043 185.918 81.2049 183.489 79.8147C181.06 78.4246 178.305 77.6927 175.5 77.6927C172.695 77.6927 169.94 78.4246 167.511 79.8147C165.082 81.2049 163.065 83.2043 161.663 85.612L146.496 111.666L116.841 60.7179C115.438 58.3104 113.42 56.3113 110.991 54.9214C108.561 53.5315 105.805 52.7998 103 52.7998C100.195 52.7998 97.4386 53.5315 95.0089 54.9214C92.5793 56.3113 90.5615 58.3104 89.1583 60.7179L15.3453 187.44C13.9411 189.847 13.2012 192.579 13.2 195.359C13.1987 198.139 13.9363 200.871 15.3384 203.279C16.7405 205.688 18.7578 207.688 21.1873 209.078C23.6168 210.468 26.3728 211.2 29.1783 211.2H84.6219C106.589 211.2 122.789 201.636 133.937 182.979L161 136.526L175.496 111.666L219 186.34H161L146.496 211.2ZM83.7181 186.314L45.0255 186.306L103.026 86.7466L131.966 136.526L112.589 169.798C105.186 181.904 96.7763 186.314 83.7181 186.314Z" fill="currentColor" />
|
||||
</svg>
|
||||
</template>
|
||||
@@ -1,45 +0,0 @@
|
||||
<template>
|
||||
<div ref="carbonads" class="carbon" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const carbonads = ref(null)
|
||||
|
||||
onMounted(() => {
|
||||
if (carbonads.value) {
|
||||
const script = document.createElement('script')
|
||||
script.setAttribute('type', 'text/javascript')
|
||||
script.setAttribute('src', 'https://cdn.carbonads.com/carbon.js?serve=CWYIVK3E&placement=uinuxtcom')
|
||||
script.setAttribute('id', '_carbonads_js')
|
||||
carbonads.value.appendChild(script)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="postcss">
|
||||
.carbon > #carbonads {
|
||||
@apply relative border border-gray-200 dark:border-gray-800 rounded-lg bg-white dark:bg-gray-800/50 hover:border-gray-300 dark:hover:border-gray-700 w-full transition-colors min-h-[220px];
|
||||
|
||||
&:hover {
|
||||
.carbon-text {
|
||||
@apply text-gray-700 dark:text-gray-200;
|
||||
}
|
||||
}
|
||||
|
||||
.carbon-img {
|
||||
@apply flex justify-center p-2 w-full;
|
||||
|
||||
& > img {
|
||||
@apply !max-w-full w-full rounded;
|
||||
}
|
||||
}
|
||||
|
||||
.carbon-text {
|
||||
@apply flex px-2 text-sm text-gray-500 dark:text-gray-400 transition-colors text-center w-full;
|
||||
}
|
||||
|
||||
.carbon-poweredby {
|
||||
@apply block text-xs text-center text-gray-400 dark:text-gray-500 hover:text-gray-500 dark:hover:text-gray-400 pt-1 pb-2 px-2 transition-colors;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,27 +0,0 @@
|
||||
<template>
|
||||
<div class="relative group/ad border border-gray-200 dark:border-gray-800 rounded-lg bg-white dark:bg-gray-800/50 hover:border-gray-300 dark:hover:border-gray-700 p-2 w-full transition-colors">
|
||||
<NuxtLink to="/pro" class="focus:outline-none" tabindex="-1">
|
||||
<span class="absolute inset-0" aria-hidden="true" />
|
||||
</NuxtLink>
|
||||
|
||||
<UColorModeImage
|
||||
light="/illustrations/pro-light.svg"
|
||||
dark="/illustrations/pro-dark.svg"
|
||||
alt="Nuxt UI Pro"
|
||||
loading="lazy"
|
||||
class="w-full"
|
||||
/>
|
||||
|
||||
<div class="flex flex-col items-center mt-2 text-center">
|
||||
<div class="inline-flex gap-1.5">
|
||||
<Logo class="h-4 w-auto" />
|
||||
|
||||
<UBadge variant="subtle" size="xs" label="Pro" class="font-semibold rounded" />
|
||||
</div>
|
||||
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 group-hover/ad:text-gray-700 dark:group-hover/ad:text-gray-200 mt-1 transition-colors">
|
||||
The Building Blocks for Modern Web Apps.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,206 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
const refs = ref([])
|
||||
const section = ref()
|
||||
|
||||
const { stop } = useIntersectionObserver(
|
||||
section,
|
||||
([{ isIntersecting }]) => {
|
||||
if (!isIntersecting) {
|
||||
return
|
||||
}
|
||||
|
||||
refs.value.forEach(element => element.style.animationPlayState = 'running')
|
||||
|
||||
stop()
|
||||
},
|
||||
{ threshold: 0.3 }
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
refs.value.forEach((element) => {
|
||||
if (!element) {
|
||||
return
|
||||
}
|
||||
|
||||
element.style.animationFillMode = 'forwards'
|
||||
element.style.transformOrigin = 'center'
|
||||
element.style.animationPlayState = 'paused'
|
||||
element.style.animationDuration = '1s'
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ULandingGrid ref="section" class="lg:grid-cols-10 lg:gap-8">
|
||||
<div :ref="(el) => (refs[1] = el)" class="col-span-8 flex items-center animate-top">
|
||||
<RangeExample />
|
||||
</div>
|
||||
|
||||
<div :ref="(el) => (refs[2] = el)" class="col-span-2 row-span-2 flex items-center animate-right">
|
||||
<RadioExample />
|
||||
</div>
|
||||
|
||||
<div :ref="(el) => (refs[4] = el)" class="col-span-2 animate-left z-10">
|
||||
<DropdownExampleBasic :popper="{ placement: 'bottom-start', strategy: 'absolute' }" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
:ref="(el) => (refs[3] = el)"
|
||||
class="col-span-6 flex flex-wrap items-center justify-between gap-1 animate-bottom"
|
||||
>
|
||||
<UAvatarGroup :max="2">
|
||||
<UAvatar
|
||||
src="https://ipx.nuxt.com/s_32x32/gh_avatar/benjamincanac"
|
||||
srcset="https://ipx.nuxt.com/s_64x64/gh_avatar/benjamincanac 2x"
|
||||
alt="benjamincanac"
|
||||
width="40"
|
||||
height="40"
|
||||
loading="lazy"
|
||||
/>
|
||||
<UAvatar
|
||||
src="https://ipx.nuxt.com/s_32x32/gh_avatar/Atinux"
|
||||
srcset="https://ipx.nuxt.com/s_64x64/gh_avatar/Atinux 2x"
|
||||
alt="Atinux"
|
||||
width="40"
|
||||
height="40"
|
||||
loading="lazy"
|
||||
/>
|
||||
<UAvatar
|
||||
src="https://ipx.nuxt.com/s_32x32/gh_avatar/smarroufin"
|
||||
srcset="https://ipx.nuxt.com/s_64x64/gh_avatar/smarroufin 2x"
|
||||
alt="smarroufin"
|
||||
width="40"
|
||||
height="40"
|
||||
loading="lazy"
|
||||
/>
|
||||
</UAvatarGroup>
|
||||
|
||||
<UButton label="Button" loading />
|
||||
|
||||
<UBadge label="Badge" />
|
||||
|
||||
<UColorModeToggle />
|
||||
|
||||
<PaginationExampleBasic />
|
||||
</div>
|
||||
|
||||
<div :ref="(el) => (refs[5] = el)" class="col-span-3 row-span-8 gap-6 flex flex-col justify-between animate-left">
|
||||
<UNotification
|
||||
:id="1"
|
||||
title="Notification"
|
||||
description="This is a notification!"
|
||||
icon="i-heroicons-command-line"
|
||||
:ui="{ shadow: 'shadow' }"
|
||||
:close-button="null"
|
||||
:timeout="30000"
|
||||
/>
|
||||
|
||||
<TabsExampleItemCustomSlot />
|
||||
|
||||
<UCard class="flex-shrink-0">
|
||||
<div class="flex items-center gap-4 justify-center">
|
||||
<USkeleton class="h-14 w-14 flex-shrink-0" :ui="{ rounded: 'rounded-full' }" />
|
||||
<div class="space-y-3 flex-1">
|
||||
<USkeleton class="h-4 w-full" />
|
||||
<USkeleton class="h-4 w-2/3" />
|
||||
</div>
|
||||
</div>
|
||||
</UCard>
|
||||
</div>
|
||||
|
||||
<div :ref="(el) => (refs[6] = el)" class="col-span-5 row-span-2 flex flex-col animate-bottom">
|
||||
<UCard
|
||||
:ui="{ body: { base: 'flex-1 flex flex-col overflow-y-auto', padding: '' } }"
|
||||
class="col-span-4 row-span-6 flex-1 flex flex-col"
|
||||
>
|
||||
<CommandPaletteExampleGroups />
|
||||
</UCard>
|
||||
</div>
|
||||
|
||||
<div :ref="(el) => (refs[7] = el)" class="col-span-2 row-span-2 gap-6 flex flex-col animate-right z-10">
|
||||
<CheckboxExample />
|
||||
|
||||
<InputExampleClearable />
|
||||
|
||||
<UFormGroup label="Labels">
|
||||
<SelectMenuExampleCreatable />
|
||||
</UFormGroup>
|
||||
|
||||
<UCard :ui="{ body: { padding: '!p-1' } }">
|
||||
<VerticalNavigationExampleAvatarSlot />
|
||||
</UCard>
|
||||
</div>
|
||||
|
||||
<div :ref="(el) => (refs[8] = el)" class="col-span-7 row-span-6 animate-bottom">
|
||||
<UCard :ui="{ body: { padding: '' } }">
|
||||
<TableExampleClickable :ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }" />
|
||||
</UCard>
|
||||
</div>
|
||||
</ULandingGrid>
|
||||
</template>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
.animate-top {
|
||||
animation: translateDown;
|
||||
}
|
||||
|
||||
.animate-bottom {
|
||||
animation: translateUp;
|
||||
}
|
||||
|
||||
.animate-left {
|
||||
animation: translateLeft;
|
||||
}
|
||||
|
||||
.animate-right {
|
||||
animation-name: translateRight;
|
||||
}
|
||||
|
||||
@keyframes translateDown {
|
||||
0% {
|
||||
transform: translate3D(0, -100px, 0);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(0, 0, 0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes translateUp {
|
||||
0% {
|
||||
transform: translate3D(0, 100px, 0);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(0, 0, 0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes translateLeft {
|
||||
0% {
|
||||
transform: translate3D(-100px, 0, 0);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translate3D(0, 0, 0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes translateRight {
|
||||
0% {
|
||||
transform: translate3D(100px, 0, 0);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translate3D(0, 0, 0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,31 +0,0 @@
|
||||
<template>
|
||||
<div class="rounded-xl border border-gray-800/10 dark:border-gray-200/10 bg-gray-200/20 dark:bg-gray-700/20 p-4 flex-1 w-full">
|
||||
<div class="relative h-full">
|
||||
<TransitionGroup name="fade">
|
||||
<HomeProDemoBlock v-for="(block, index) in blocks" :key="index" :block="block">
|
||||
<template v-for="(_, name) in $slots" #[name]="slotData">
|
||||
<slot :name="name" v-bind="slotData" />
|
||||
</template>
|
||||
</HomeProDemoBlock>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { HomeProBlock } from '~/types'
|
||||
|
||||
defineProps<{ blocks: HomeProBlock[] }>()
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,59 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
:id="block.id"
|
||||
:class="twMerge(
|
||||
'absolute rounded-lg flex items-center justify-center',
|
||||
block.class,
|
||||
!block.slot && (block.inactive || block.inactive === undefined ? 'border border-gray-800/10 dark:border-gray-200/10 bg-gray-200/20 dark:bg-gray-700/20 transition-[background,text] duration-500' : 'bg-primary transition-[background,text] duration-500'),
|
||||
block.name?.startsWith('#') && 'border-dashed'
|
||||
)"
|
||||
:style="block.style"
|
||||
>
|
||||
<NuxtLink v-if="block.to && !block.inactive" :to="block.to" class="focus:outline-none" tabindex="-1">
|
||||
<span class="absolute inset-0" aria-hidden="true" />
|
||||
</NuxtLink>
|
||||
|
||||
<template v-if="block.inactive">
|
||||
<TransitionGroup name="fade">
|
||||
<HomeProDemoBlock v-for="(subComponent, subIndex) in block.children" :key="subIndex" :block="subComponent">
|
||||
<template v-for="(_, name) in $slots" #[name]="slotData: any">
|
||||
<slot :name="name" v-bind="slotData" />
|
||||
</template>
|
||||
</HomeProDemoBlock>
|
||||
</TransitionGroup>
|
||||
</template>
|
||||
<template v-else-if="block.slot">
|
||||
<slot :name="block.slot" />
|
||||
</template>
|
||||
<p
|
||||
v-else
|
||||
class="font-semibold flex flex-col gap-1 text-center"
|
||||
:class="[
|
||||
!block.slot && (block.inactive || block.inactive === undefined ? 'text-gray-900 dark:text-white' : 'text-white dark:text-gray-900'),
|
||||
]"
|
||||
>
|
||||
{{ block.name }}
|
||||
|
||||
<span v-if="block.description" class="font-normal">{{ block.description }}</span>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import type { HomeProBlock } from '~/types'
|
||||
|
||||
defineProps<{ block: HomeProBlock }>()
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,108 +0,0 @@
|
||||
<template>
|
||||
<Transition appear name="fade">
|
||||
<div
|
||||
:style="{
|
||||
'--cell': `${width / cols}px`,
|
||||
'--rows': rows - 1
|
||||
}"
|
||||
>
|
||||
<div
|
||||
ref="el"
|
||||
class="absolute inset-0 grid justify-center auto-rows-[--cell] -space-y-px"
|
||||
>
|
||||
<div v-for="(row, rowIndex) in grid" :key="rowIndex" class="grid grid-flow-col auto-cols-[--cell] flex-1 -space-x-px">
|
||||
<div
|
||||
v-for="(cell, cellIndex) in row"
|
||||
:key="cellIndex"
|
||||
class="relative border border-primary-200/50 dark:border-primary-900/25"
|
||||
>
|
||||
<div class="absolute inset-0 bg-primary-500/10 hover:bg-primary-500/20 dark:bg-primary-400/5 dark:hover:bg-primary-400/10 opacity-0 transition-opacity will-change-[opacity] duration-1000" :class="[cell && 'opacity-100 cursor-pointer']" @click="cell && removeCell(rowIndex, cellIndex)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="absolute top-[calc((var(--cell)*var(--rows))+1px)] inset-x-0 h-[calc(var(--cell)*2)] bg-gradient-to-t from-white dark:from-gray-900 pointer-events-none" />
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useElementSize } from '@vueuse/core'
|
||||
|
||||
const el = ref(null)
|
||||
const grid = ref([])
|
||||
const rows = ref(0)
|
||||
const cols = ref(0)
|
||||
|
||||
const { width, height } = useElementSize(el)
|
||||
|
||||
function createGrid () {
|
||||
grid.value = []
|
||||
|
||||
for (let i = 0; i <= rows.value; i++) {
|
||||
grid.value.push(new Array(cols.value).fill(null))
|
||||
}
|
||||
}
|
||||
|
||||
function createNewCell () {
|
||||
const x = Math.floor(Math.random() * cols.value)
|
||||
|
||||
grid.value[0][x] = true
|
||||
}
|
||||
|
||||
function moveCellsDown () {
|
||||
for (let row = rows.value - 1; row >= 0; row--) {
|
||||
for (let col = 0; col < cols.value; col++) {
|
||||
if (grid.value[row][col] !== null && grid.value[row + 1][col] === null) {
|
||||
grid.value[row + 1][col] = grid.value[row][col]
|
||||
grid.value[row][col] = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (grid.value[rows.value].every(cell => cell !== null)) {
|
||||
for (let col = 0; col < cols.value; col++) {
|
||||
grid.value[rows.value][col] = null
|
||||
}
|
||||
}
|
||||
}, 500)
|
||||
}
|
||||
|
||||
function removeCell (row, col) {
|
||||
grid.value[row][col] = null
|
||||
}
|
||||
|
||||
function calcGrid () {
|
||||
const base = Math.ceil(width.value / 60)
|
||||
const cell = width.value / base
|
||||
|
||||
rows.value = Math.ceil(height.value / cell)
|
||||
cols.value = width.value / cell
|
||||
|
||||
createGrid()
|
||||
}
|
||||
|
||||
watch(width, calcGrid)
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(calcGrid, 50)
|
||||
|
||||
setInterval(() => {
|
||||
moveCellsDown()
|
||||
createNewCell()
|
||||
}, 1000)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,54 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { useIntersectionObserver } from '@vueuse/core'
|
||||
|
||||
defineProps<{
|
||||
date: {
|
||||
day: Date
|
||||
release?: {
|
||||
name: string
|
||||
}
|
||||
pulls?: {
|
||||
id: number
|
||||
number: number
|
||||
title: string
|
||||
html_url: string
|
||||
user: {
|
||||
login: string
|
||||
}
|
||||
}[]
|
||||
}
|
||||
}>()
|
||||
|
||||
const target = ref(null)
|
||||
const targetIsVisible = ref(false)
|
||||
|
||||
useIntersectionObserver(target, ([{ isIntersecting }]) => {
|
||||
targetIsVisible.value = isIntersecting
|
||||
}, {
|
||||
rootMargin: '-68px 0px -68px 0px'
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="target" class="flex flex-col transition-opacity duration-500" :class="targetIsVisible ? 'opacity-100' : 'opacity-25'">
|
||||
<time :datetime="date.day.toISOString()" class="flex-shrink-0 text-sm/6 font-semibold text-gray-500 dark:text-gray-400">{{ date.day.toLocaleString('en-us', { year: 'numeric', month: 'short', day: 'numeric' })
|
||||
}}</time>
|
||||
|
||||
<NuxtLink v-if="date.release" :to="`https://github.com/nuxt/ui/releases/tag/${date.release.name}`" target="_blank" class="text-gray-900 dark:text-white font-bold text-3xl mt-2 group hover:text-primary-500 dark:hover:text-primary-400 transition-[color]">
|
||||
{{ date.release.name }}
|
||||
</NuxtLink>
|
||||
<ul v-if="date.pulls?.length" class="mt-2 space-y-1 text-gray-600 dark:text-gray-300">
|
||||
<li v-for="pull in date.pulls" :key="pull.id" class="text-sm/6 break-all">
|
||||
<NuxtLink :to="`https://github.com/${pull.user.login}`" target="_blank" class="text-gray-900 dark:text-white transition-colors inline-flex items-center gap-1 rounded-full bg-gray-100/50 dark:bg-gray-800/50 dark:hover:bg-gray-800 p-0.5 pr-1 ring-1 ring-gray-300 dark:ring-gray-700 text-xs font-medium flex-shrink-0 align-middle">
|
||||
<UAvatar :src="`https://github.com/${pull.user.login}.png`" size="3xs" />
|
||||
|
||||
{{ pull.user.login }}
|
||||
</NuxtLink>
|
||||
|
||||
pushed <NuxtLink :to="pull.html_url" target="_blank" class="font-medium text-gray-700 dark:text-gray-200 hover:text-primary-500 dark:hover:text-primary-400 transition-[color]">
|
||||
#{{ pull.number }} {{ pull.title }}
|
||||
</NuxtLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user