@voidzero-dev/vitepress-theme 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/src/aliases.js +14 -0
- package/src/vitepress/assets/clients/clickup.svg +5 -0
- package/src/vitepress/assets/clients/stripe.svg +3 -0
- package/src/vitepress/components/oss/Footer.vue +4 -21
- package/src/vitepress/components/oss/Header.vue +82 -180
- package/src/vitepress/components/oss/Sponsors.vue +3 -3
- package/src/vitepress/components/oss/TopBanner.vue +20 -79
- package/src/vitepress/components/oss/TrustedBy.vue +1 -1
- package/src/vitepress/components/vite/Community.vue +3 -3
- package/src/vitepress/components/vite/FeatureGrid1.vue +63 -0
- package/src/vitepress/components/vite/{FeatureGrid.vue → FeatureGrid2.vue} +8 -10
- package/src/vitepress/components/vite/Hero.vue +6 -15
- package/src/vitepress/components/vitepress-default/VPDocOutlineItem.vue +2 -2
- package/src/vitepress/components/vitepress-default/VPFlyout.vue +1 -1
- package/src/vitepress/components/vitepress-default/VPMenuLink.vue +1 -1
- package/src/vitepress/components/vitepress-default/VPNavBarMenuLink.vue +1 -1
- package/src/vitepress/components/vitepress-default/VPSidebarItem.vue +1 -1
- package/src/vitepress/components/vitepress-default/VPSocialLink.vue +1 -2
- package/src/vitepress/fonts/APK-Protocol-Semi-Bold.woff2 +0 -0
- package/src/vitepress/fonts/inter-italic-cyrillic-ext.woff2 +0 -0
- package/src/vitepress/fonts/inter-italic-cyrillic.woff2 +0 -0
- package/src/vitepress/fonts/inter-italic-greek-ext.woff2 +0 -0
- package/src/vitepress/fonts/inter-italic-greek.woff2 +0 -0
- package/src/vitepress/fonts/inter-italic-latin-ext.woff2 +0 -0
- package/src/vitepress/fonts/inter-italic-latin.woff2 +0 -0
- package/src/vitepress/fonts/inter-italic-vietnamese.woff2 +0 -0
- package/src/vitepress/fonts/inter-roman-cyrillic-ext.woff2 +0 -0
- package/src/vitepress/fonts/inter-roman-cyrillic.woff2 +0 -0
- package/src/vitepress/fonts/inter-roman-greek-ext.woff2 +0 -0
- package/src/vitepress/fonts/inter-roman-greek.woff2 +0 -0
- package/src/vitepress/fonts/inter-roman-latin-ext.woff2 +0 -0
- package/src/vitepress/fonts/inter-roman-latin.woff2 +0 -0
- package/src/vitepress/fonts/inter-roman-vietnamese.woff2 +0 -0
- package/src/vitepress/index.ts +64 -230
- package/src/vitepress/layouts/VPLayout.vue +2 -17
- package/src/vitepress/styles/tokens.css +194 -10
- package/src/vitepress/types/theme-context.ts +33 -0
- package/src/vitepress/assets/clients/beehiiv.svg +0 -30
- package/src/vitepress/assets/clients/excalidraw.svg +0 -82
- package/src/vitepress/assets/clients/get-your-guide.svg +0 -1
- package/src/vitepress/assets/clients/posthog.svg +0 -1
- package/src/vitepress/assets/clients/ramp.svg +0 -1
- package/src/vitepress/assets/clients/shopee.svg +0 -55
- package/src/vitepress/components/vite/FeaturePanel1.vue +0 -41
- package/src/vitepress/components/vite/FeaturePanel2.vue +0 -37
- package/src/vitepress/components/vite/FeaturePanel3.vue +0 -43
- package/src/vitepress/components/vite/FeaturePanel4.vue +0 -46
- package/src/vitepress/components/voidzero/Footer.vue +0 -65
- package/src/vitepress/components/voidzero/Header.vue +0 -560
- package/src/vitepress/components/voidzero/Megamenu.vue +0 -190
- package/src/vitepress/components/voidzero/about/CareerCTA.vue +0 -56
- package/src/vitepress/components/voidzero/about/Hero.vue +0 -206
- package/src/vitepress/components/voidzero/about/Investors.vue +0 -112
- package/src/vitepress/components/voidzero/about/TeamGrid.vue +0 -161
- package/src/vitepress/components/voidzero/about/TeamSectionHeading.vue +0 -13
- package/src/vitepress/components/voidzero/blog/BlogArchive.vue +0 -223
- package/src/vitepress/components/voidzero/blog/BlogSingleContent.vue +0 -364
- package/src/vitepress/components/voidzero/blog/BlogSingleHero.vue +0 -113
- package/src/vitepress/components/voidzero/blog/BlogSingleRelated.vue +0 -92
- package/src/vitepress/components/voidzero/blog/FeaturedArticles.vue +0 -146
- package/src/vitepress/components/voidzero/blog/types.ts +0 -56
- package/src/vitepress/components/voidzero/home/CaseStudySlider.vue +0 -235
- package/src/vitepress/components/voidzero/home/CustomersSectionHeading.vue +0 -5
- package/src/vitepress/components/voidzero/home/GitHubStats.vue +0 -27
- package/src/vitepress/components/voidzero/home/Hero.vue +0 -69
- package/src/vitepress/components/voidzero/home/Investors.vue +0 -30
- package/src/vitepress/components/voidzero/home/NewsletterCTA.vue +0 -23
- package/src/vitepress/components/voidzero/home/OpenSourceSectionHeading.vue +0 -6
- package/src/vitepress/components/voidzero/home/OpenSourceSectionProjects.vue +0 -419
- package/src/vitepress/components/voidzero/home/Resources.vue +0 -144
- package/src/vitepress/components/voidzero/home/Statistics.vue +0 -507
- package/src/vitepress/components/voidzero/home/StatisticsSectionHeading.vue +0 -5
- package/src/vitepress/components/voidzero/home/TeamCTA.vue +0 -17
- package/src/vitepress/components/voidzero/home/TrustedBy.vue +0 -248
- package/src/vitepress/components/voidzero/home/VitePlusSectionFeatures.vue +0 -55
- package/src/vitepress/components/voidzero/home/VitePlusSectionHeading.vue +0 -17
- package/src/vitepress/fonts/KHTeka-Medium.woff2 +0 -0
- package/src/vitepress/fonts/KHTeka-Regular.woff2 +0 -0
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import {computed} from 'vue'
|
|
3
|
-
import {type Post, type Author, getAuthorImage, formatDateShort} from './types'
|
|
4
|
-
|
|
5
|
-
interface Props {
|
|
6
|
-
articles: Post[]
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const props = defineProps<Props>()
|
|
10
|
-
|
|
11
|
-
// Get featured articles (first 3)
|
|
12
|
-
const featuredArticles = computed(() => {
|
|
13
|
-
return props.articles.slice(0, 3)
|
|
14
|
-
})
|
|
15
|
-
</script>
|
|
16
|
-
|
|
17
|
-
<template>
|
|
18
|
-
<section
|
|
19
|
-
class="wrapper wrapper--ticks border-t grid grid-cols-1 md:grid-cols-3 divide-y md:divide-y-0 md:divide-x divide-stroke">
|
|
20
|
-
<!-- Large Featured Article (Left) -->
|
|
21
|
-
<a
|
|
22
|
-
v-if="featuredArticles[0]"
|
|
23
|
-
:href="featuredArticles[0].url"
|
|
24
|
-
class="featured-article md:col-span-2 flex flex-col hover:bg-beige transition-colors"
|
|
25
|
-
>
|
|
26
|
-
<div class="px-6 md:px-20 py-10 flex-1 flex flex-col justify-center">
|
|
27
|
-
<div class="w-full flex flex-col gap-6">
|
|
28
|
-
|
|
29
|
-
<!-- Image -->
|
|
30
|
-
<div class="w-full bg-nickel overflow-hidden">
|
|
31
|
-
<img
|
|
32
|
-
v-if="featuredArticles[0].cover"
|
|
33
|
-
:src="featuredArticles[0].cover"
|
|
34
|
-
:alt="featuredArticles[0].title"
|
|
35
|
-
class="w-full object-cover"
|
|
36
|
-
/>
|
|
37
|
-
</div>
|
|
38
|
-
|
|
39
|
-
<!-- Content -->
|
|
40
|
-
<div class="flex flex-col gap-3">
|
|
41
|
-
<span class="text-grey text-xs font-medium font-mono uppercase tracking-wide">// {{
|
|
42
|
-
featuredArticles[0].category
|
|
43
|
-
}}</span>
|
|
44
|
-
<h2 class="text-2xl md:text-3xl text-pretty text-primary font-normal leading-tight">
|
|
45
|
-
{{ featuredArticles[0].title }}
|
|
46
|
-
</h2>
|
|
47
|
-
</div>
|
|
48
|
-
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
|
|
52
|
-
<!-- Full-width divider and author section -->
|
|
53
|
-
<div class="mt-auto border-t border-stroke">
|
|
54
|
-
<div class="px-6 md:px-20 py-5">
|
|
55
|
-
<div class="flex items-center justify-between">
|
|
56
|
-
<div class="flex items-center gap-4">
|
|
57
|
-
<img
|
|
58
|
-
v-if="featuredArticles[0].authors?.[0] && getAuthorImage(featuredArticles[0].authors[0])"
|
|
59
|
-
:src="getAuthorImage(featuredArticles[0].authors[0])!"
|
|
60
|
-
:alt="featuredArticles[0].authors[0].name"
|
|
61
|
-
class="w-10 h-10 rounded object-cover"
|
|
62
|
-
/>
|
|
63
|
-
<div v-else class="w-10 h-10 rounded bg-grey/20"></div>
|
|
64
|
-
<span class="text-sm text-primary font-mono">{{
|
|
65
|
-
featuredArticles[0].authors?.[0]?.name || 'Unknown'
|
|
66
|
-
}}</span>
|
|
67
|
-
</div>
|
|
68
|
-
<span class="text-grey text-xs font-medium font-mono uppercase tracking-wide">{{
|
|
69
|
-
formatDateShort(featuredArticles[0].date.string)
|
|
70
|
-
}}</span>
|
|
71
|
-
</div>
|
|
72
|
-
</div>
|
|
73
|
-
</div>
|
|
74
|
-
</a>
|
|
75
|
-
|
|
76
|
-
<!-- Smaller Articles (Right) -->
|
|
77
|
-
<div class="flex flex-col divide-y divide-stroke md:col-span-1">
|
|
78
|
-
<!-- Article 2 -->
|
|
79
|
-
<a
|
|
80
|
-
v-if="featuredArticles[1]"
|
|
81
|
-
:href="featuredArticles[1].url"
|
|
82
|
-
class="featured-article-small flex flex-col hover:bg-beige transition-colors"
|
|
83
|
-
>
|
|
84
|
-
<!-- Image -->
|
|
85
|
-
<div class="p-10 pb-5">
|
|
86
|
-
<div class="w-full bg-nickel overflow-hidden">
|
|
87
|
-
<img
|
|
88
|
-
v-if="featuredArticles[1].cover"
|
|
89
|
-
:src="featuredArticles[1].cover"
|
|
90
|
-
:alt="featuredArticles[1].title"
|
|
91
|
-
class="w-full object-cover"
|
|
92
|
-
/>
|
|
93
|
-
</div>
|
|
94
|
-
</div>
|
|
95
|
-
|
|
96
|
-
<!-- Content -->
|
|
97
|
-
<div class="px-10 pb-10 flex flex-col gap-2 grow">
|
|
98
|
-
<span class="text-grey text-xs font-medium font-mono uppercase tracking-wide">// {{
|
|
99
|
-
featuredArticles[1].category
|
|
100
|
-
}}</span>
|
|
101
|
-
<h4 class="text-xl text-pretty text-primary font-normal leading-snug">
|
|
102
|
-
{{ featuredArticles[1].title }}
|
|
103
|
-
</h4>
|
|
104
|
-
<span class="text-grey text-xs font-medium font-mono uppercase tracking-wide">{{
|
|
105
|
-
formatDateShort(featuredArticles[1].date.string)
|
|
106
|
-
}}</span>
|
|
107
|
-
</div>
|
|
108
|
-
</a>
|
|
109
|
-
|
|
110
|
-
<!-- Article 3 -->
|
|
111
|
-
<a
|
|
112
|
-
v-if="featuredArticles[2]"
|
|
113
|
-
:href="featuredArticles[2].url"
|
|
114
|
-
class="featured-article-small flex flex-col hover:bg-beige transition-colors"
|
|
115
|
-
>
|
|
116
|
-
<!-- Image -->
|
|
117
|
-
<div class="p-10 pb-5">
|
|
118
|
-
<div class="w-full bg-nickel overflow-hidden">
|
|
119
|
-
<img
|
|
120
|
-
v-if="featuredArticles[2].cover"
|
|
121
|
-
:src="featuredArticles[2].cover"
|
|
122
|
-
:alt="featuredArticles[2].title"
|
|
123
|
-
class="w-full object-cover"
|
|
124
|
-
/>
|
|
125
|
-
</div>
|
|
126
|
-
</div>
|
|
127
|
-
|
|
128
|
-
<!-- Content -->
|
|
129
|
-
<div class="px-10 pb-10 flex flex-col gap-2 grow">
|
|
130
|
-
<span class="text-grey text-xs font-medium font-mono uppercase tracking-wide">// {{
|
|
131
|
-
featuredArticles[2].category
|
|
132
|
-
}}</span>
|
|
133
|
-
<h4 class="text-xl text-pretty text-primary font-normal leading-snug">
|
|
134
|
-
{{ featuredArticles[2].title }}
|
|
135
|
-
</h4>
|
|
136
|
-
<span class="text-grey text-xs font-medium font-mono uppercase tracking-wide">{{
|
|
137
|
-
formatDateShort(featuredArticles[2].date.string)
|
|
138
|
-
}}</span>
|
|
139
|
-
</div>
|
|
140
|
-
</a>
|
|
141
|
-
</div>
|
|
142
|
-
</section>
|
|
143
|
-
</template>
|
|
144
|
-
|
|
145
|
-
<style scoped>
|
|
146
|
-
</style>
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared types for VoidZero blog components
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
type BaseAuthor = {
|
|
6
|
-
name: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
type GravatarAuthor = {
|
|
10
|
-
type: 'gravatar'
|
|
11
|
-
gravatar: string
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
type GitHubAuthor = {
|
|
15
|
-
type: 'github'
|
|
16
|
-
username: string
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export type Author = BaseAuthor & (GravatarAuthor | GitHubAuthor)
|
|
20
|
-
|
|
21
|
-
export interface Post {
|
|
22
|
-
title: string
|
|
23
|
-
url: string
|
|
24
|
-
category: string
|
|
25
|
-
cover: string
|
|
26
|
-
authors: Author[]
|
|
27
|
-
date: {
|
|
28
|
-
time: number
|
|
29
|
-
string: string
|
|
30
|
-
}
|
|
31
|
-
excerpt: string | undefined
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Helper to get author avatar image URL
|
|
36
|
-
*/
|
|
37
|
-
export function getAuthorImage(author: Author): string | null {
|
|
38
|
-
if ('gravatar' in author && author.gravatar) {
|
|
39
|
-
return `https://www.gravatar.com/avatar/${author.gravatar}?s=80`
|
|
40
|
-
}
|
|
41
|
-
if ('username' in author && author.username) {
|
|
42
|
-
return `https://github.com/${author.username}.png?size=80`
|
|
43
|
-
}
|
|
44
|
-
return null
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Format date as "SEPT 11, 2025"
|
|
49
|
-
*/
|
|
50
|
-
export function formatDateShort(dateString: string): string {
|
|
51
|
-
const date = new Date(dateString)
|
|
52
|
-
const month = date.toLocaleDateString('en-US', {month: 'short'}).toUpperCase()
|
|
53
|
-
const day = date.getDate()
|
|
54
|
-
const year = date.getFullYear()
|
|
55
|
-
return `${month} ${day}, ${year}`
|
|
56
|
-
}
|
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ref, onMounted, onUnmounted } from 'vue'
|
|
3
|
-
import emblaCarouselVue from 'embla-carousel-vue'
|
|
4
|
-
import Autoplay from 'embla-carousel-autoplay'
|
|
5
|
-
|
|
6
|
-
// Import assets
|
|
7
|
-
import plaidLogo from '@assets/clients/plaid.svg'
|
|
8
|
-
import viteIcon from '@assets/icons/vite-light.svg'
|
|
9
|
-
import vitestIcon from '@assets/icons/vitest-light.svg'
|
|
10
|
-
import rolldownIcon from '@assets/icons/rolldown-light.svg'
|
|
11
|
-
import oxcIcon from '@assets/icons/oxc-light.svg'
|
|
12
|
-
|
|
13
|
-
// Slides data
|
|
14
|
-
const slides = ref([
|
|
15
|
-
{
|
|
16
|
-
id: 1,
|
|
17
|
-
title: 'How PLAID Cut Build Times by 97% Migrating From Rollup To Rolldown',
|
|
18
|
-
thumbnail: plaidLogo,
|
|
19
|
-
projects: [
|
|
20
|
-
{ name: 'Vite', logo: viteIcon, url: 'https://vite.dev/' },
|
|
21
|
-
{ name: 'Rolldown', logo: rolldownIcon, url: 'https://rolldown.rs/' }
|
|
22
|
-
]
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
id: 2,
|
|
26
|
-
title: 'How PLAID Cut Build Times by 97% Migrating From Rollup To Rolldown',
|
|
27
|
-
thumbnail: plaidLogo,
|
|
28
|
-
projects: [
|
|
29
|
-
{ name: 'Vitest', logo: vitestIcon, url: 'https://vitest.dev/' },
|
|
30
|
-
{ name: 'Rolldown', logo: rolldownIcon, url: 'https://rolldown.rs/' }
|
|
31
|
-
]
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
id: 3,
|
|
35
|
-
title: 'How PLAID Cut Build Times by 97% Migrating From Rollup To Rolldown',
|
|
36
|
-
thumbnail: plaidLogo,
|
|
37
|
-
projects: [
|
|
38
|
-
{ name: 'Vite', logo: viteIcon, url: 'https://vite.dev/' },
|
|
39
|
-
{ name: 'Oxc', logo: oxcIcon, url: 'https://oxc.rs/' }
|
|
40
|
-
]
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
id: 4,
|
|
44
|
-
title: 'How PLAID Cut Build Times by 97% Migrating From Rollup To Rolldown',
|
|
45
|
-
thumbnail: plaidLogo,
|
|
46
|
-
projects: [
|
|
47
|
-
{ name: 'Vitest', logo: vitestIcon, url: 'https://vitest.dev/' },
|
|
48
|
-
{ name: 'Oxc', logo: oxcIcon, url: 'https://oxc.rs/' }
|
|
49
|
-
]
|
|
50
|
-
}
|
|
51
|
-
])
|
|
52
|
-
|
|
53
|
-
// Selected slide index
|
|
54
|
-
const selectedIndex = ref(0)
|
|
55
|
-
|
|
56
|
-
// Main carousel
|
|
57
|
-
const [emblaMainRef, emblaMainApi] = emblaCarouselVue(
|
|
58
|
-
{ loop: true },
|
|
59
|
-
[Autoplay()]
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
// Thumbnail carousel
|
|
63
|
-
const [emblaThumbRef, emblaThumbApi] = emblaCarouselVue({
|
|
64
|
-
containScroll: 'keepSnaps',
|
|
65
|
-
dragFree: true
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
// Click handler for thumbnails
|
|
69
|
-
const onThumbClick = (index) => {
|
|
70
|
-
if (!emblaMainApi.value) return
|
|
71
|
-
emblaMainApi.value.scrollTo(index)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Sync thumbnail active state with main carousel
|
|
75
|
-
const onSelect = () => {
|
|
76
|
-
if (!emblaMainApi.value || !emblaThumbApi.value) return
|
|
77
|
-
selectedIndex.value = emblaMainApi.value.selectedScrollSnap()
|
|
78
|
-
emblaThumbApi.value.scrollTo(emblaMainApi.value.selectedScrollSnap())
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Set up event listeners
|
|
82
|
-
onMounted(() => {
|
|
83
|
-
if (!emblaMainApi.value || !emblaThumbApi.value) return
|
|
84
|
-
|
|
85
|
-
onSelect()
|
|
86
|
-
emblaMainApi.value.on('select', onSelect)
|
|
87
|
-
emblaMainApi.value.on('reInit', onSelect)
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
// Clean up event listeners
|
|
91
|
-
onUnmounted(() => {
|
|
92
|
-
if (!emblaMainApi.value) return
|
|
93
|
-
emblaMainApi.value.off('select', onSelect)
|
|
94
|
-
emblaMainApi.value.off('reInit', onSelect)
|
|
95
|
-
})
|
|
96
|
-
</script>
|
|
97
|
-
|
|
98
|
-
<template>
|
|
99
|
-
<section class="wrapper">
|
|
100
|
-
<!-- Main Carousel -->
|
|
101
|
-
<div class="bg-wine case-study-background">
|
|
102
|
-
<div class="overflow-hidden" ref="emblaMainRef">
|
|
103
|
-
<div class="flex py-10 md:py-20">
|
|
104
|
-
<div
|
|
105
|
-
v-for="(slide, index) in slides"
|
|
106
|
-
:key="slide.id"
|
|
107
|
-
:class="['embla__slide p-6 md:p-10 w-[calc(100vw-4rem)] md:w-[55rem] rounded-lg relative', index === selectedIndex ? 'bg-primary' : 'bg-primary/75']"
|
|
108
|
-
>
|
|
109
|
-
<div :class="['embla__slide__content', { 'embla__slide__content--active': index === selectedIndex }]">
|
|
110
|
-
<img :src="slide.thumbnail" :alt="slide.title" class="absolute top-6 md:top-10 right-6 md:right-10 h-4 md:h-5" />
|
|
111
|
-
<span class="text-grey text-xs font-mono uppercase tracking-wide">Case Study</span>
|
|
112
|
-
<a href="#" target="_blank">
|
|
113
|
-
<h5 class="text-white text-balance max-w-[20rem] pt-5">{{slide.title}}</h5>
|
|
114
|
-
</a>
|
|
115
|
-
<a href="#" target="_blank" class="text-white font-medium border-b inline-block mt-4">Read case study →</a>
|
|
116
|
-
<div class="absolute bottom-0 left-0 right-0 flex gap-4 px-6 md:px-10 py-4 border-t border-slate items-center">
|
|
117
|
-
<span class="text-grey text-xs font-mono uppercase tracking-wide">OSS</span>
|
|
118
|
-
<template v-for="(project, projectIndex) in slide.projects" :key="project.name">
|
|
119
|
-
<a :href="project.url" target="_blank">
|
|
120
|
-
<figure class="project-icon">
|
|
121
|
-
<img loading="lazy" class="size-5" :src="project.logo" :alt="project.name">
|
|
122
|
-
<figcaption>{{ project.name }}</figcaption>
|
|
123
|
-
</figure>
|
|
124
|
-
</a>
|
|
125
|
-
<span v-if="projectIndex < slide.projects.length - 1"
|
|
126
|
-
class="text-grey text-xs font-mono uppercase tracking-wide">//</span>
|
|
127
|
-
</template>
|
|
128
|
-
</div>
|
|
129
|
-
</div>
|
|
130
|
-
</div>
|
|
131
|
-
</div>
|
|
132
|
-
</div>
|
|
133
|
-
</div>
|
|
134
|
-
|
|
135
|
-
<!-- Thumbnail Carousel -->
|
|
136
|
-
<div class="embla-thumbs bg-primary">
|
|
137
|
-
<div class="embla-thumbs__wrapper">
|
|
138
|
-
<div class="overflow-hidden" ref="emblaThumbRef">
|
|
139
|
-
<div class="embla-thumbs__container">
|
|
140
|
-
<div
|
|
141
|
-
v-for="(slide, index) in slides"
|
|
142
|
-
:key="`thumb-${slide.id}`"
|
|
143
|
-
:class="['embla-thumbs__slide', { 'embla-thumbs__slide--selected': index === selectedIndex }]"
|
|
144
|
-
>
|
|
145
|
-
<button
|
|
146
|
-
type="button"
|
|
147
|
-
class="embla-thumbs__slide__button"
|
|
148
|
-
@click="onThumbClick(index)"
|
|
149
|
-
>
|
|
150
|
-
<img :src="slide.thumbnail" :alt="`Slide ${index + 1}`" class="embla-thumbs__slide__img" />
|
|
151
|
-
</button>
|
|
152
|
-
</div>
|
|
153
|
-
</div>
|
|
154
|
-
</div>
|
|
155
|
-
</div>
|
|
156
|
-
</div>
|
|
157
|
-
</section>
|
|
158
|
-
</template>
|
|
159
|
-
|
|
160
|
-
<style scoped>
|
|
161
|
-
|
|
162
|
-
.case-study-background {
|
|
163
|
-
background-image: url('@assets/voidzero/backgrounds/casestudies.jpg');
|
|
164
|
-
background-size: cover;
|
|
165
|
-
background-position: center;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
.embla__slide {
|
|
169
|
-
flex: 0 0 auto;
|
|
170
|
-
min-width: 0;
|
|
171
|
-
min-height: 20rem;
|
|
172
|
-
margin: 0 1rem;
|
|
173
|
-
transition: background-color 0.6s ease, backdrop-filter 0.6s ease;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
@media (min-width: 768px) {
|
|
177
|
-
.embla__slide {
|
|
178
|
-
min-height: 25rem;
|
|
179
|
-
margin: 0 2rem;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
.embla__slide__content {
|
|
184
|
-
opacity: 0;
|
|
185
|
-
transition: opacity 0.3s ease;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
.embla__slide__content--active {
|
|
189
|
-
opacity: 1;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
.embla-thumbs {
|
|
193
|
-
padding: 1rem 2rem;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
.embla-thumbs__wrapper {
|
|
197
|
-
display: flex;
|
|
198
|
-
justify-content: center;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
.embla-thumbs__container {
|
|
202
|
-
display: flex;
|
|
203
|
-
gap: 1rem;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
.embla-thumbs__slide {
|
|
207
|
-
flex: 0 0 auto;
|
|
208
|
-
opacity: 0.3;
|
|
209
|
-
transition: all 0.3s ease;
|
|
210
|
-
transform: scale(0.8);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
.embla-thumbs__slide--selected {
|
|
214
|
-
opacity: 1;
|
|
215
|
-
transform: scale(1);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
.embla-thumbs__slide__button {
|
|
219
|
-
padding: 0.5rem;
|
|
220
|
-
background: transparent;
|
|
221
|
-
border: none;
|
|
222
|
-
cursor: pointer;
|
|
223
|
-
display: flex;
|
|
224
|
-
align-items: center;
|
|
225
|
-
justify-content: center;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
.embla-thumbs__slide__img {
|
|
229
|
-
height: 1.25rem;
|
|
230
|
-
width: auto;
|
|
231
|
-
max-width: 8rem;
|
|
232
|
-
object-fit: contain;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
</style>
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
defineProps<{
|
|
3
|
-
href: string
|
|
4
|
-
stars: string
|
|
5
|
-
contributors: string
|
|
6
|
-
}>()
|
|
7
|
-
</script>
|
|
8
|
-
|
|
9
|
-
<template>
|
|
10
|
-
<div class="flex gap-4 divide-nickel items-center bg-slate px-3 py-1 w-fit rounded-sm">
|
|
11
|
-
<a :href="href" target="_blank" rel="noopener noreferrer">
|
|
12
|
-
<img src="@assets/social/github.svg" alt="GitHub" class="invert size-6">
|
|
13
|
-
</a>
|
|
14
|
-
<div class="flex gap-1 items-baseline">
|
|
15
|
-
<span class="text-white font-medium tracking-tight">{{ stars }}</span>
|
|
16
|
-
<span class="text-grey text-base tracking-tight">stars</span>
|
|
17
|
-
</div>
|
|
18
|
-
<div class="flex gap-1 items-baseline">
|
|
19
|
-
<span class="text-white text-lg font-medium tracking-tight">{{ contributors }}</span>
|
|
20
|
-
<span class="text-grey text-base tracking-tight">contributors</span>
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
23
|
-
</template>
|
|
24
|
-
|
|
25
|
-
<style scoped>
|
|
26
|
-
|
|
27
|
-
</style>
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="wrapper flex flex-col justify-start items-center gap-6 pt-6 md:pt-20 pb-10">
|
|
3
|
-
<div class="w-full sm:w-2xl flex flex-col justify-start items-center gap-10 px-5 sm:px-0">
|
|
4
|
-
<div class="flex flex-col justify-start items-center gap-4">
|
|
5
|
-
<div inert class="px-3 py-1 bg-primary-white rounded shadow-[0px_2px_4px_0px_rgba(0,0,0,0.05)] outline outline-nickel/5 flex items-center gap-1.5 font-mono font-medium text-sm tracking-tighter mb-3">
|
|
6
|
-
<div class="p-0.5 bg-[#00B442]/10 rounded-sm inline-flex justify-start items-center gap-2">
|
|
7
|
-
<div class="size-1.5 bg-[#00B442] rounded-[1.10px] animate-pulse"></div>
|
|
8
|
-
</div>
|
|
9
|
-
<span class="text-grey">prod server</span>
|
|
10
|
-
<span class="text-grey">/</span>
|
|
11
|
-
<span class="text-nickel">running</span>
|
|
12
|
-
</div>
|
|
13
|
-
<h1 class="text-center text-primary text-balance shine-text">
|
|
14
|
-
<span class="inline-block">The JavaScript</span>
|
|
15
|
-
<span class="inline-block">Tooling Company</span>
|
|
16
|
-
</h1>
|
|
17
|
-
<p class="self-stretch text-center text-balance text-nickel">We are building a unified JavaScript toolchain to make web developers more productive than ever before.</p>
|
|
18
|
-
</div>
|
|
19
|
-
<div class="flex items-center gap-5">
|
|
20
|
-
<a href="https://viteplus.dev" target="_blank" rel="noopener noreferrer" class="button button--primary">
|
|
21
|
-
<img src="@assets/icons/viteplus-light.svg" class="size-7" alt="Vite+ Logo">
|
|
22
|
-
<span>Explore Vite+</span>
|
|
23
|
-
</a>
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
26
|
-
<RiveAnimation
|
|
27
|
-
:desktop-src="homepageAnimation"
|
|
28
|
-
:mobile-src="homepageAnimationMobile"
|
|
29
|
-
:desktop-width="1280"
|
|
30
|
-
:desktop-height="580"
|
|
31
|
-
:mobile-width="343"
|
|
32
|
-
:mobile-height="148"
|
|
33
|
-
canvas-class="w-full pt-6 md:pt-0 max-w-[60rem] mx-auto"
|
|
34
|
-
/>
|
|
35
|
-
</div>
|
|
36
|
-
</template>
|
|
37
|
-
|
|
38
|
-
<script setup lang="ts">
|
|
39
|
-
import RiveAnimation from "@components/shared/RiveAnimation.vue";
|
|
40
|
-
import homepageAnimation from '@assets/voidzero/animations/1280_x_552_homepage.riv'
|
|
41
|
-
import homepageAnimationMobile from '@assets/voidzero/animations/343_x_148_homepage_mobile.riv'
|
|
42
|
-
</script>
|
|
43
|
-
|
|
44
|
-
<style scoped>
|
|
45
|
-
.shine-text {
|
|
46
|
-
background: linear-gradient(
|
|
47
|
-
110deg,
|
|
48
|
-
var(--color-primary) 0%,
|
|
49
|
-
var(--color-primary) 40%,
|
|
50
|
-
#6C3BFF 48%,
|
|
51
|
-
#6C3BFF 50%,
|
|
52
|
-
#6C3BFF 52%,
|
|
53
|
-
var(--color-primary) 60%,
|
|
54
|
-
var(--color-primary) 100%
|
|
55
|
-
);
|
|
56
|
-
background-size: 400% 100%;
|
|
57
|
-
background-position: 100% 0;
|
|
58
|
-
background-clip: text;
|
|
59
|
-
-webkit-background-clip: text;
|
|
60
|
-
-webkit-text-fill-color: transparent;
|
|
61
|
-
animation: shine 5s ease-in-out 0s 1 forwards;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
@keyframes shine {
|
|
65
|
-
to {
|
|
66
|
-
background-position: 35% 0;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
</style>
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import accelLogo from '@assets/voidzero/investors/accel.svg'
|
|
3
|
-
import amplifyLogo from '@assets/voidzero/investors/amplify.svg'
|
|
4
|
-
import sunflowerLogo from '@assets/voidzero/investors/sunflower.png'
|
|
5
|
-
import peakxvLogo from '@assets/voidzero/investors/peakxv.png'
|
|
6
|
-
|
|
7
|
-
const investors = [
|
|
8
|
-
{src: accelLogo, alt: 'Accel'},
|
|
9
|
-
{src: peakxvLogo, alt: 'Peak XV'},
|
|
10
|
-
{src: sunflowerLogo, alt: 'Sunflower'},
|
|
11
|
-
{src: amplifyLogo, alt: 'Amplify'}
|
|
12
|
-
]
|
|
13
|
-
</script>
|
|
14
|
-
|
|
15
|
-
<template>
|
|
16
|
-
<section class="wrapper wrapper--ticks border-t items-center bg-[#FBFAF7] grid grid-cols-1 md:grid-cols-10">
|
|
17
|
-
<div class="px-5 md:px-10 py-6 md:py-0 col-span-4 border-b md:border-b-0 text-center md:text-start">
|
|
18
|
-
<p class="text-primary text-balance">Backed by the very best in the dev tools space.</p>
|
|
19
|
-
</div>
|
|
20
|
-
<div class="col-span-6 border-l border-stroke">
|
|
21
|
-
<LogoGrid
|
|
22
|
-
:logos="investors"
|
|
23
|
-
/>
|
|
24
|
-
</div>
|
|
25
|
-
</section>
|
|
26
|
-
</template>
|
|
27
|
-
|
|
28
|
-
<style scoped>
|
|
29
|
-
|
|
30
|
-
</style>
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import NewsletterForm from '@components/shared/NewsletterForm.vue'
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
endpoint?: string
|
|
6
|
-
formId?: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
defineProps<Props>()
|
|
10
|
-
</script>
|
|
11
|
-
|
|
12
|
-
<template>
|
|
13
|
-
<section class="wrapper wrapper--ticks border-t">
|
|
14
|
-
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-6 px-6 md:px-10 py-10">
|
|
15
|
-
<h2 class="text-xl md:text-2xl text-primary font-normal">
|
|
16
|
-
Subscribe to our monthly newsletter
|
|
17
|
-
</h2>
|
|
18
|
-
<div class="w-full md:w-auto md:min-w-[400px]">
|
|
19
|
-
<NewsletterForm :endpoint="endpoint" :form-id="formId" />
|
|
20
|
-
</div>
|
|
21
|
-
</div>
|
|
22
|
-
</section>
|
|
23
|
-
</template>
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<section class="wrapper wrapper--ticks border-t px-10 h-48 sm:h-90 flex flex-col justify-center gap-5">
|
|
3
|
-
<h2 class="text-start text-white">Open Source</h2>
|
|
4
|
-
<p class="max-w-md text-balance text-white/70">We are the creators, maintainers, and contributors of some of the most critical infrastructure projects in the JavaScript ecosystem.</p>
|
|
5
|
-
</section>
|
|
6
|
-
</template>
|