@voidzero-dev/vitepress-theme 3.1.0 → 3.2.1
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 +3 -11
- package/src/assets/vite/vite-featurepanel-2-terminal.png +0 -0
- package/src/components/oss/Sponsors.vue +145 -265
- package/src/components/oss/TrustedBy.vue +8 -33
- package/src/components/oxc/FeatureResolver.vue +3 -3
- package/src/components/oxc/Hero.vue +9 -16
- package/src/components/rolldown/Hero.vue +2 -2
- package/src/components/vite/Community.vue +1 -1
- package/src/components/vite/FeatureGrid1.vue +12 -9
- package/src/components/vite/FeatureGrid2.vue +7 -4
- package/src/components/vite/Hero.vue +5 -4
- package/src/components/vitest/Hero.vue +3 -3
- package/src/types/sponsors.ts +14 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voidzero-dev/vitepress-theme",
|
|
3
|
-
"version": "3.1
|
|
3
|
+
"version": "3.2.1",
|
|
4
4
|
"description": "Shared VitePress theme for VoidZero projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -15,20 +15,12 @@
|
|
|
15
15
|
"*.css"
|
|
16
16
|
],
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"@docsearch/css": "^4.3.2",
|
|
19
|
-
"@docsearch/js": "^4.3.2",
|
|
20
18
|
"vitepress": "^2.0.0-alpha.12",
|
|
21
19
|
"vue": "^3.5.0"
|
|
22
20
|
},
|
|
23
|
-
"peerDependenciesMeta": {
|
|
24
|
-
"@docsearch/css": {
|
|
25
|
-
"optional": true
|
|
26
|
-
},
|
|
27
|
-
"@docsearch/js": {
|
|
28
|
-
"optional": true
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
21
|
"dependencies": {
|
|
22
|
+
"@docsearch/css": "^4.3.2",
|
|
23
|
+
"@docsearch/js": "^4.3.2",
|
|
32
24
|
"@rive-app/canvas": "^2.31.6",
|
|
33
25
|
"@tailwindcss/typography": "^0.5.19",
|
|
34
26
|
"@tailwindcss/vite": "^4.1.18",
|
|
Binary file
|
|
@@ -1,44 +1,15 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue'
|
|
3
|
-
|
|
4
|
-
// Sponsor with optional explicit image path
|
|
5
|
-
interface Sponsor {
|
|
6
|
-
name: string
|
|
7
|
-
url: string
|
|
8
|
-
img?: string // If provided, use directly; otherwise auto-generate
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
interface SponsorWithImg extends Sponsor {
|
|
12
|
-
img: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Tier configuration structure
|
|
16
|
-
interface TierConfig {
|
|
17
|
-
displayName: string
|
|
18
|
-
columns: number
|
|
19
|
-
size?: 'large' | 'medium' | 'small' | 'avatar'
|
|
20
|
-
avatarMode?: boolean // For backers dense grid
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Processed tier for rendering
|
|
24
|
-
interface ProcessedTier {
|
|
25
|
-
tierKey: string
|
|
26
|
-
displayName: string
|
|
27
|
-
columns: number
|
|
28
|
-
size: 'large' | 'medium' | 'small' | 'avatar'
|
|
29
|
-
avatarMode: boolean
|
|
30
|
-
items: SponsorWithImg[]
|
|
31
|
-
}
|
|
3
|
+
import type { SponsorTier, SponsorSize } from '../../types/sponsors'
|
|
32
4
|
|
|
33
5
|
interface Props {
|
|
34
|
-
sponsors?:
|
|
35
|
-
tierConfig?: Record<string, Partial<TierConfig>> // Override defaults
|
|
36
|
-
imageBasePath?: string // Default: '/sponsors/'
|
|
37
|
-
sideBySideTiers?: [string, string] // e.g., ['bronze', 'backers'] for OXC layout
|
|
6
|
+
sponsors?: SponsorTier[]
|
|
38
7
|
heading?: string
|
|
39
8
|
description?: string
|
|
40
9
|
sponsorLink?: string
|
|
41
10
|
sponsorLinkText?: string
|
|
11
|
+
sideBySideTiers?: [string, string] // e.g., ['bronze', 'backers'] for side-by-side layout
|
|
12
|
+
logoStyle?: 'opencollective'
|
|
42
13
|
}
|
|
43
14
|
|
|
44
15
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -48,285 +19,176 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
48
19
|
sponsorLinkText: 'Become a Sponsor',
|
|
49
20
|
})
|
|
50
21
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
// Vitest tiers
|
|
58
|
-
special: { displayName: 'SPECIAL SPONSORS', columns: 3, size: 'large' },
|
|
59
|
-
|
|
60
|
-
// Shared tier
|
|
61
|
-
gold: { displayName: 'GOLD SPONSORS', columns: 5, size: 'medium' },
|
|
62
|
-
|
|
63
|
-
// OXC tiers
|
|
64
|
-
bronze: { displayName: 'BRONZE SPONSORS', columns: 1, size: 'medium' },
|
|
65
|
-
silver: { displayName: 'SILVER SPONSORS', columns: 3, size: 'medium' },
|
|
66
|
-
backers: { displayName: 'BACKERS', columns: 15, size: 'avatar', avatarMode: true },
|
|
22
|
+
const sizeConfig: Record<SponsorSize, { columns: number; padding: string; logoSize: string; avatarMode?: boolean }> = {
|
|
23
|
+
big: { columns: 3, padding: 'py-16', logoSize: 'h-13 w-[220px]' },
|
|
24
|
+
medium: { columns: 5, padding: 'py-7', logoSize: 'h-8 w-[120px]' },
|
|
25
|
+
small: { columns: 7, padding: 'py-5', logoSize: 'h-6 w-[100px]' },
|
|
26
|
+
avatar: { columns: 15, padding: 'py-3', logoSize: 'w-10 h-10', avatarMode: true },
|
|
67
27
|
}
|
|
68
28
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
29
|
+
const gridClasses: Record<number, string> = {
|
|
30
|
+
1: 'grid-cols-1',
|
|
31
|
+
2: 'grid-cols-1 sm:grid-cols-2',
|
|
32
|
+
3: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3',
|
|
33
|
+
4: 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-4',
|
|
34
|
+
5: 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-5',
|
|
35
|
+
6: 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-6',
|
|
36
|
+
7: 'grid-cols-2 sm:grid-cols-4 lg:grid-cols-7',
|
|
74
37
|
}
|
|
75
38
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
return
|
|
39
|
+
const getEffectiveColumns = (size: SponsorSize, itemCount: number) =>
|
|
40
|
+
Math.min(sizeConfig[size].columns, itemCount)
|
|
41
|
+
|
|
42
|
+
const getGridColumns = (size: SponsorSize, itemCount: number) =>
|
|
43
|
+
gridClasses[getEffectiveColumns(size, itemCount)] || 'grid-cols-1'
|
|
44
|
+
|
|
45
|
+
const getEmptyCells = (itemCount: number, size: SponsorSize) => {
|
|
46
|
+
const cols = getEffectiveColumns(size, itemCount)
|
|
47
|
+
const remainder = itemCount % cols
|
|
48
|
+
return remainder === 0 ? 0 : cols - remainder
|
|
86
49
|
}
|
|
87
50
|
|
|
88
|
-
//
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
return
|
|
92
|
-
tierKey,
|
|
93
|
-
displayName: config.displayName,
|
|
94
|
-
columns: config.columns,
|
|
95
|
-
size: config.size || 'medium',
|
|
96
|
-
avatarMode: config.avatarMode || false,
|
|
97
|
-
items: items.map(sponsor => ({
|
|
98
|
-
...sponsor,
|
|
99
|
-
img: resolveImagePath(sponsor),
|
|
100
|
-
})),
|
|
101
|
-
}
|
|
51
|
+
// Calculate empty slots for backers grid (maintain visual consistency)
|
|
52
|
+
const getBackerEmptySlots = (itemCount: number, minSlots: number = 30) => {
|
|
53
|
+
const targetSlots = Math.max(itemCount, minSlots)
|
|
54
|
+
return Math.max(0, targetSlots - itemCount)
|
|
102
55
|
}
|
|
103
56
|
|
|
104
|
-
// Side-by-side tier data (for OXC
|
|
57
|
+
// Side-by-side tier data (for layouts like OXC: Bronze + Backers)
|
|
105
58
|
const sideBySideData = computed(() => {
|
|
106
59
|
if (!props.sponsors || !props.sideBySideTiers) return null
|
|
107
60
|
|
|
108
|
-
const [
|
|
109
|
-
const
|
|
110
|
-
const
|
|
61
|
+
const [leftTierName, rightTierName] = props.sideBySideTiers
|
|
62
|
+
const leftTier = props.sponsors.find(t => t.tier.toLowerCase() === leftTierName.toLowerCase())
|
|
63
|
+
const rightTier = props.sponsors.find(t => t.tier.toLowerCase() === rightTierName.toLowerCase())
|
|
111
64
|
|
|
112
|
-
if (!
|
|
65
|
+
if (!leftTier || !rightTier) return null
|
|
113
66
|
|
|
114
|
-
return {
|
|
115
|
-
left: processTier(leftTierKey, leftItems),
|
|
116
|
-
right: processTier(rightTierKey, rightItems),
|
|
117
|
-
}
|
|
67
|
+
return { left: leftTier, right: rightTier }
|
|
118
68
|
})
|
|
119
69
|
|
|
120
70
|
// Standard stacked tier data (excludes side-by-side tiers)
|
|
121
|
-
const
|
|
71
|
+
const stackedSponsors = computed(() => {
|
|
122
72
|
if (!props.sponsors) return []
|
|
73
|
+
if (!props.sideBySideTiers) return props.sponsors
|
|
123
74
|
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
return Object.entries(props.sponsors)
|
|
127
|
-
.filter(([tierKey]) => !sideBySideKeys.includes(tierKey))
|
|
128
|
-
.map(([tierKey, items]) => processTier(tierKey, items))
|
|
75
|
+
const sideBySideNames = props.sideBySideTiers.map(n => n.toLowerCase())
|
|
76
|
+
return props.sponsors.filter(tier => !sideBySideNames.includes(tier.tier.toLowerCase()))
|
|
129
77
|
})
|
|
130
|
-
|
|
131
|
-
// Get grid columns class based on specified columns
|
|
132
|
-
const getGridColumns = (columns: number) => {
|
|
133
|
-
const gridClasses: Record<number, string> = {
|
|
134
|
-
1: 'grid-cols-1',
|
|
135
|
-
2: 'grid-cols-1 sm:grid-cols-2',
|
|
136
|
-
3: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3',
|
|
137
|
-
4: 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-4',
|
|
138
|
-
5: 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-5',
|
|
139
|
-
6: 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-6',
|
|
140
|
-
7: 'grid-cols-2 sm:grid-cols-4 lg:grid-cols-7',
|
|
141
|
-
}
|
|
142
|
-
return gridClasses[columns] || 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4'
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Size-based padding classes
|
|
146
|
-
const getSponsorPadding = (size: string) => {
|
|
147
|
-
const paddingMap: Record<string, string> = {
|
|
148
|
-
large: 'py-16',
|
|
149
|
-
medium: 'py-7',
|
|
150
|
-
small: 'py-5',
|
|
151
|
-
avatar: 'py-3',
|
|
152
|
-
}
|
|
153
|
-
return paddingMap[size] || 'py-7'
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Size-based logo dimension classes
|
|
157
|
-
const getLogoSize = (size: string) => {
|
|
158
|
-
const sizeMap: Record<string, string> = {
|
|
159
|
-
large: 'max-h-12 max-w-[200px]',
|
|
160
|
-
medium: 'max-h-6 max-w-[120px]',
|
|
161
|
-
small: 'max-h-5 max-w-[100px]',
|
|
162
|
-
avatar: 'max-h-8 max-w-[80px]',
|
|
163
|
-
}
|
|
164
|
-
return sizeMap[size] || 'max-h-6 max-w-[120px]'
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Calculate number of empty cells needed to fill the last row
|
|
168
|
-
const getEmptyCells = (itemCount: number, columns: number) => {
|
|
169
|
-
const remainder = itemCount % columns
|
|
170
|
-
return remainder === 0 ? 0 : columns - remainder
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Calculate empty slots for backers grid (maintain visual consistency)
|
|
174
|
-
const getBackerEmptySlots = (itemCount: number, minSlots: number = 30) => {
|
|
175
|
-
const targetSlots = Math.max(itemCount, minSlots)
|
|
176
|
-
return Math.max(0, targetSlots - itemCount)
|
|
177
|
-
}
|
|
178
78
|
</script>
|
|
179
79
|
|
|
180
80
|
<template>
|
|
181
|
-
<div class="wrapper wrapper--ticks border-t py-14 sm:py-30 px-
|
|
182
|
-
<div
|
|
81
|
+
<div class="wrapper wrapper--ticks border-t py-14 sm:py-30 px-10">
|
|
82
|
+
<div
|
|
83
|
+
class="flex flex-col md:flex-row justify-between items-center gap-8 md:gap-20 text-center md:text-left md:pl-15">
|
|
183
84
|
<div class="flex flex-col gap-3">
|
|
184
85
|
<h3 class="text-white max-w-xl text-balance">{{ heading }}</h3>
|
|
185
86
|
<p class="max-w-lg text-white/70 text-balance">{{ description }}</p>
|
|
186
87
|
<a :href="sponsorLink" target="_blank" class="button w-fit mt-8 mx-auto md:mx-0">{{ sponsorLinkText }}</a>
|
|
187
88
|
</div>
|
|
188
|
-
<
|
|
189
|
-
|
|
190
|
-
|
|
89
|
+
<a class="flex gap-8 md:gap-12 items-start justify-center md:justify-start md:pr-25" href="https://voidzero.dev"
|
|
90
|
+
target="_blank">
|
|
91
|
+
<img src="../../assets/vite/vite-by-voidzero.png" alt="Brought to you by VoidZero"
|
|
92
|
+
class="h-44 max-w-full object-contain mt-10 md:mt-0" />
|
|
93
|
+
</a>
|
|
191
94
|
</div>
|
|
192
95
|
</div>
|
|
193
|
-
<div v-if="sponsors &&
|
|
194
|
-
|
|
96
|
+
<div v-if="sponsors && sponsors.length > 0" class="wrapper"
|
|
97
|
+
:class="{ 'sponsor-style-oc': logoStyle === 'opencollective' }">
|
|
98
|
+
<!-- Standard Stacked Sponsors Grid -->
|
|
99
|
+
<div v-for="(tier, tierIndex) in stackedSponsors" :key="tierIndex" class="border-t border-nickel">
|
|
100
|
+
<!-- Tier Heading -->
|
|
101
|
+
<div class="py-5 px-5 sm:px-10 border-b border-nickel">
|
|
102
|
+
<span class="text-white/70 text-xs font-mono uppercase tracking-wide">
|
|
103
|
+
{{ tier.tier }}
|
|
104
|
+
</span>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<!-- Avatar Mode Grid (for backers-style tiers) -->
|
|
108
|
+
<div v-if="sizeConfig[tier.size].avatarMode" class="backers-grid px-5 sm:px-10 py-6">
|
|
109
|
+
<a v-for="(sponsor, index) in tier.items" :key="index" :href="sponsor.url" target="_blank"
|
|
110
|
+
rel="noopener noreferrer" class="backer-avatar group relative">
|
|
111
|
+
<img :src="sponsor.img" :alt="sponsor.name"
|
|
112
|
+
class="w-10 h-10 rounded object-cover border border-nickel transition-all group-hover:border-white/50 group-hover:scale-110" />
|
|
113
|
+
<span class="backer-tooltip">{{ sponsor.name }}</span>
|
|
114
|
+
</a>
|
|
115
|
+
<!-- Empty placeholder slots -->
|
|
116
|
+
<div v-for="emptyIndex in getBackerEmptySlots(tier.items.length)" :key="`empty-${emptyIndex}`"
|
|
117
|
+
class="backer-avatar-placeholder" aria-hidden="true">
|
|
118
|
+
<div class="w-10 h-10 rounded border border-nickel/30"></div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<!-- Standard Logo Grid -->
|
|
123
|
+
<div v-else class="grid [&>*]:border-r [&>*]:border-b [&>*]:border-nickel"
|
|
124
|
+
:class="getGridColumns(tier.size, tier.items.length)">
|
|
125
|
+
<a v-for="(sponsor, index) in tier.items" :key="index" :href="sponsor.url" target="_blank"
|
|
126
|
+
rel="noopener noreferrer"
|
|
127
|
+
class="sponsor-link flex items-center justify-center px-8 transition-opacity opacity-85 hover:opacity-100"
|
|
128
|
+
:class="sizeConfig[tier.size].padding">
|
|
129
|
+
<img :src="sponsor.img" :alt="sponsor.name" class="sponsor-logo object-contain"
|
|
130
|
+
:class="sizeConfig[tier.size].logoSize" />
|
|
131
|
+
<span class="sponsor-name ml-5">{{ sponsor.name }}</span>
|
|
132
|
+
</a>
|
|
133
|
+
|
|
134
|
+
<!-- Empty cells to fill incomplete rows -->
|
|
135
|
+
<div v-for="emptyIndex in getEmptyCells(tier.items.length, tier.size)" :key="`empty-${emptyIndex}`"
|
|
136
|
+
class="sponsor-link flex items-center justify-center px-8" :class="sizeConfig[tier.size].padding"
|
|
137
|
+
aria-hidden="true" />
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<!-- Side-by-Side Layout (e.g., Bronze + Backers) -->
|
|
195
142
|
<div v-if="sideBySideData" class="grid grid-cols-1 lg:grid-cols-2 border-t border-nickel">
|
|
196
|
-
<!-- Left Tier
|
|
143
|
+
<!-- Left Tier -->
|
|
197
144
|
<div class="border-b lg:border-b-0 lg:border-r border-nickel">
|
|
198
145
|
<div class="py-5 px-5 sm:px-10 border-b border-nickel">
|
|
199
146
|
<span class="text-white/70 text-xs font-mono uppercase tracking-wide">
|
|
200
|
-
{{ sideBySideData.left.
|
|
147
|
+
{{ sideBySideData.left.tier }}
|
|
201
148
|
</span>
|
|
202
149
|
</div>
|
|
203
150
|
<div class="flex flex-col">
|
|
204
|
-
<a
|
|
205
|
-
v-for="(sponsor, index) in sideBySideData.left.items"
|
|
206
|
-
:key="index"
|
|
207
|
-
:href="sponsor.url"
|
|
208
|
-
target="_blank"
|
|
151
|
+
<a v-for="(sponsor, index) in sideBySideData.left.items" :key="index" :href="sponsor.url" target="_blank"
|
|
209
152
|
rel="noopener noreferrer"
|
|
210
|
-
class="sponsor-link flex items-center justify-center px-8 py-12 transition-opacity opacity-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
:alt="sponsor.name"
|
|
215
|
-
class="sponsor-logo object-contain max-h-8 max-w-[160px]"
|
|
216
|
-
/>
|
|
153
|
+
class="sponsor-link flex items-center justify-center px-8 py-12 transition-opacity opacity-85 hover:opacity-100 border-b border-nickel last:border-b-0">
|
|
154
|
+
<img :src="sponsor.img" :alt="sponsor.name" class="sponsor-logo object-contain"
|
|
155
|
+
:class="sizeConfig[sideBySideData.left.size].logoSize" />
|
|
156
|
+
<span class="sponsor-name ml-5">{{ sponsor.name }}</span>
|
|
217
157
|
</a>
|
|
218
158
|
</div>
|
|
219
159
|
</div>
|
|
220
160
|
|
|
221
|
-
<!-- Right Tier (Backers) -->
|
|
161
|
+
<!-- Right Tier (Backers style) -->
|
|
222
162
|
<div>
|
|
223
163
|
<div class="py-5 px-5 sm:px-10 border-b border-nickel">
|
|
224
164
|
<span class="text-white/70 text-xs font-mono uppercase tracking-wide">
|
|
225
|
-
{{ sideBySideData.right.
|
|
165
|
+
{{ sideBySideData.right.tier }}
|
|
226
166
|
</span>
|
|
227
167
|
</div>
|
|
228
|
-
<div class="backers-grid px-5 sm:px-10 py-6">
|
|
229
|
-
<a
|
|
230
|
-
|
|
231
|
-
:
|
|
232
|
-
|
|
233
|
-
target="_blank"
|
|
234
|
-
rel="noopener noreferrer"
|
|
235
|
-
class="backer-avatar group relative"
|
|
236
|
-
>
|
|
237
|
-
<img
|
|
238
|
-
:src="sponsor.img"
|
|
239
|
-
:alt="sponsor.name"
|
|
240
|
-
class="w-10 h-10 rounded object-cover border border-nickel transition-all group-hover:border-white/50 group-hover:scale-110"
|
|
241
|
-
/>
|
|
168
|
+
<div v-if="sizeConfig[sideBySideData.right.size].avatarMode" class="backers-grid px-5 sm:px-10 py-6">
|
|
169
|
+
<a v-for="(sponsor, index) in sideBySideData.right.items" :key="index" :href="sponsor.url" target="_blank"
|
|
170
|
+
rel="noopener noreferrer" class="backer-avatar group relative">
|
|
171
|
+
<img :src="sponsor.img" :alt="sponsor.name"
|
|
172
|
+
class="w-10 h-10 rounded object-cover border border-nickel transition-all group-hover:border-white/50 group-hover:scale-110" />
|
|
242
173
|
<span class="backer-tooltip">{{ sponsor.name }}</span>
|
|
243
174
|
</a>
|
|
244
175
|
<!-- Empty placeholder slots for visual consistency -->
|
|
245
|
-
<div
|
|
246
|
-
|
|
247
|
-
:key="`empty-${emptyIndex}`"
|
|
248
|
-
class="backer-avatar-placeholder"
|
|
249
|
-
aria-hidden="true"
|
|
250
|
-
>
|
|
251
|
-
<div class="w-10 h-10 rounded border border-nickel/30"></div>
|
|
252
|
-
</div>
|
|
253
|
-
</div>
|
|
254
|
-
</div>
|
|
255
|
-
</div>
|
|
256
|
-
|
|
257
|
-
<!-- Standard Stacked Sponsors Grid -->
|
|
258
|
-
<div v-if="stackedSponsorData && stackedSponsorData.length > 0">
|
|
259
|
-
<div
|
|
260
|
-
v-for="(tierData, tierIndex) in stackedSponsorData"
|
|
261
|
-
:key="tierIndex"
|
|
262
|
-
class="border-t border-nickel"
|
|
263
|
-
>
|
|
264
|
-
<!-- Tier Heading -->
|
|
265
|
-
<div class="py-5 px-5 sm:px-10 border-b border-nickel">
|
|
266
|
-
<span class="text-white/70 text-xs font-mono uppercase tracking-wide">
|
|
267
|
-
{{ tierData.displayName }}
|
|
268
|
-
</span>
|
|
269
|
-
</div>
|
|
270
|
-
|
|
271
|
-
<!-- Avatar Mode Grid (for backers-style tiers) -->
|
|
272
|
-
<div v-if="tierData.avatarMode" class="backers-grid px-5 sm:px-10 py-6">
|
|
273
|
-
<a
|
|
274
|
-
v-for="(sponsor, index) in tierData.items"
|
|
275
|
-
:key="index"
|
|
276
|
-
:href="sponsor.url"
|
|
277
|
-
target="_blank"
|
|
278
|
-
rel="noopener noreferrer"
|
|
279
|
-
class="backer-avatar group relative"
|
|
280
|
-
>
|
|
281
|
-
<img
|
|
282
|
-
:src="sponsor.img"
|
|
283
|
-
:alt="sponsor.name"
|
|
284
|
-
class="w-10 h-10 rounded object-cover border border-nickel transition-all group-hover:border-white/50 group-hover:scale-110"
|
|
285
|
-
/>
|
|
286
|
-
<span class="backer-tooltip">{{ sponsor.name }}</span>
|
|
287
|
-
</a>
|
|
288
|
-
<!-- Empty placeholder slots -->
|
|
289
|
-
<div
|
|
290
|
-
v-for="emptyIndex in getBackerEmptySlots(tierData.items.length)"
|
|
291
|
-
:key="`empty-${emptyIndex}`"
|
|
292
|
-
class="backer-avatar-placeholder"
|
|
293
|
-
aria-hidden="true"
|
|
294
|
-
>
|
|
176
|
+
<div v-for="emptyIndex in getBackerEmptySlots(sideBySideData.right.items.length)" :key="`empty-${emptyIndex}`"
|
|
177
|
+
class="backer-avatar-placeholder" aria-hidden="true">
|
|
295
178
|
<div class="w-10 h-10 rounded border border-nickel/30"></div>
|
|
296
179
|
</div>
|
|
297
180
|
</div>
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
v-
|
|
302
|
-
class="grid [&>*]:border-r [&>*]:border-b [&>*]:border-nickel"
|
|
303
|
-
:class="getGridColumns(tierData.columns)"
|
|
304
|
-
>
|
|
305
|
-
<a
|
|
306
|
-
v-for="(sponsor, index) in tierData.items"
|
|
307
|
-
:key="index"
|
|
308
|
-
:href="sponsor.url"
|
|
309
|
-
target="_blank"
|
|
181
|
+
<!-- Fallback to standard grid if not avatar mode -->
|
|
182
|
+
<div v-else class="grid [&>*]:border-r [&>*]:border-b [&>*]:border-nickel"
|
|
183
|
+
:class="getGridColumns(sideBySideData.right.size, sideBySideData.right.items.length)">
|
|
184
|
+
<a v-for="(sponsor, index) in sideBySideData.right.items" :key="index" :href="sponsor.url" target="_blank"
|
|
310
185
|
rel="noopener noreferrer"
|
|
311
|
-
class="sponsor-link flex items-center justify-center px-8 transition-opacity opacity-
|
|
312
|
-
:class="
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
:alt="sponsor.name"
|
|
317
|
-
class="sponsor-logo object-contain"
|
|
318
|
-
:class="getLogoSize(tierData.size)"
|
|
319
|
-
/>
|
|
186
|
+
class="sponsor-link flex items-center justify-center px-8 transition-opacity opacity-85 hover:opacity-100"
|
|
187
|
+
:class="sizeConfig[sideBySideData.right.size].padding">
|
|
188
|
+
<img :src="sponsor.img" :alt="sponsor.name" class="sponsor-logo object-contain"
|
|
189
|
+
:class="sizeConfig[sideBySideData.right.size].logoSize" />
|
|
190
|
+
<span class="sponsor-name ml-5">{{ sponsor.name }}</span>
|
|
320
191
|
</a>
|
|
321
|
-
|
|
322
|
-
<!-- Empty cells to fill incomplete rows -->
|
|
323
|
-
<div
|
|
324
|
-
v-for="emptyIndex in getEmptyCells(tierData.items.length, tierData.columns)"
|
|
325
|
-
:key="`empty-${emptyIndex}`"
|
|
326
|
-
class="sponsor-link flex items-center justify-center px-8"
|
|
327
|
-
:class="getSponsorPadding(tierData.size)"
|
|
328
|
-
aria-hidden="true"
|
|
329
|
-
/>
|
|
330
192
|
</div>
|
|
331
193
|
</div>
|
|
332
194
|
</div>
|
|
@@ -334,6 +196,31 @@ const getBackerEmptySlots = (itemCount: number, minSlots: number = 30) => {
|
|
|
334
196
|
</template>
|
|
335
197
|
|
|
336
198
|
<style scoped>
|
|
199
|
+
/* Sponsor grid - clip outer borders using overflow */
|
|
200
|
+
.grid[class*="grid-cols"] {
|
|
201
|
+
overflow: hidden;
|
|
202
|
+
margin-right: -1px;
|
|
203
|
+
margin-bottom: -1px;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.sponsor-logo {
|
|
207
|
+
filter: grayscale(1) invert(1);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.sponsor-style-oc .sponsor-logo {
|
|
211
|
+
filter: none;
|
|
212
|
+
width: auto;
|
|
213
|
+
border-radius: 0.25rem;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.sponsor-name {
|
|
217
|
+
display: none;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.sponsor-style-oc .sponsor-name {
|
|
221
|
+
display: inline-block;
|
|
222
|
+
}
|
|
223
|
+
|
|
337
224
|
/* Backers dense avatar grid */
|
|
338
225
|
.backers-grid {
|
|
339
226
|
display: flex;
|
|
@@ -389,11 +276,4 @@ const getBackerEmptySlots = (itemCount: number, minSlots: number = 30) => {
|
|
|
389
276
|
.backer-avatar-placeholder div {
|
|
390
277
|
background: transparent;
|
|
391
278
|
}
|
|
392
|
-
|
|
393
|
-
/* Sponsor grid - clip outer borders using overflow */
|
|
394
|
-
.grid[class*="grid-cols"] {
|
|
395
|
-
overflow: hidden;
|
|
396
|
-
margin-right: -1px;
|
|
397
|
-
margin-bottom: -1px;
|
|
398
|
-
}
|
|
399
279
|
</style>
|
|
@@ -1,40 +1,14 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed } from 'vue'
|
|
3
2
|
import LogoGrid from '@components/shared/LogoGrid.vue'
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import: 'default'
|
|
9
|
-
})
|
|
4
|
+
const props = defineProps<{
|
|
5
|
+
logos: string[]
|
|
6
|
+
}>()
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
logoAssets[filename] = module as string
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
// Default logo order (matches current implementation)
|
|
19
|
-
const DEFAULT_LOGO_ORDER = ['openai', 'framer', 'linear', 'ramp', 'shopify']
|
|
20
|
-
|
|
21
|
-
// Props interface
|
|
22
|
-
interface Props {
|
|
23
|
-
logos?: string[] // Optional: array of logo names in desired order
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const props = defineProps<Props>()
|
|
27
|
-
|
|
28
|
-
// Computed logos array - resolves logo names to actual assets
|
|
29
|
-
const logos = computed(() => {
|
|
30
|
-
const order = props.logos || DEFAULT_LOGO_ORDER
|
|
31
|
-
return order
|
|
32
|
-
.filter(name => name in logoAssets) // Filter out invalid names
|
|
33
|
-
.map(name => ({
|
|
34
|
-
src: logoAssets[name],
|
|
35
|
-
alt: name.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')
|
|
36
|
-
}))
|
|
37
|
-
})
|
|
8
|
+
const logos = props.logos.map(name => ({
|
|
9
|
+
src: `/trusted-by/${name}.svg`,
|
|
10
|
+
alt: name,
|
|
11
|
+
}))
|
|
38
12
|
</script>
|
|
39
13
|
|
|
40
14
|
<template>
|
|
@@ -51,5 +25,6 @@ const logos = computed(() => {
|
|
|
51
25
|
<style scoped>
|
|
52
26
|
:deep(img) {
|
|
53
27
|
filter: brightness(0) invert(1);
|
|
28
|
+
opacity: 0.7;
|
|
54
29
|
}
|
|
55
30
|
</style>
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
<p class="text-white/70 text-base max-w-[25rem] text-pretty">Node.js-compatible CJS and ESM module resolution
|
|
12
12
|
</p>
|
|
13
13
|
<ul class="checkmark-list">
|
|
14
|
-
<li>Behavior alignment with <code
|
|
15
|
-
|
|
14
|
+
<li>Behavior alignment with <code class="mx-1 outline-none bg-nickel/50 text-aqua">enhanced-resolve</code>
|
|
15
|
+
</li>
|
|
16
16
|
<li>28x faster than <code class="mx-1 outline-none bg-nickel/50 text-aqua">enhanced-resolve</code>
|
|
17
|
-
<li>Highly customizable</li>
|
|
18
17
|
</li>
|
|
18
|
+
<li>Highly customizable</li>
|
|
19
19
|
</ul>
|
|
20
20
|
<a href="/docs/guide/usage/resolver" class="button w-fit mt-6">Usage Guide</a>
|
|
21
21
|
</div>
|
|
@@ -7,17 +7,19 @@ import oxcAnimation from '@assets/oxc/animations/640_x_630_oxc masthead_.riv'
|
|
|
7
7
|
<div class="wrapper wrapper--ticks grid md:grid-cols-2 w-full border-nickel divide-x">
|
|
8
8
|
<div class="flex flex-col p-10 justify-center items-center md:items-start">
|
|
9
9
|
<div class="flex flex-col gap-5 max-w-[30rem] text-center md:text-left items-center md:items-start">
|
|
10
|
-
<
|
|
10
|
+
<a class="flex items-center gap-2" href="https://voidzero.dev" target="_blank">
|
|
11
11
|
<span class="text-grey text-xs font-mono uppercase tracking-wide">By</span>
|
|
12
12
|
<img src="@assets/logos/voidzero-light.svg" alt="VoidZero" class="h-2.5">
|
|
13
|
-
</
|
|
13
|
+
</a>
|
|
14
14
|
<h1 class="text-white text-pretty">The JavaScript Oxidation Compiler</h1>
|
|
15
|
-
<p class="text-white/70 text-lg max-w-[25rem] text-pretty">A collection of high-performance JavaScript tools
|
|
15
|
+
<p class="text-white/70 text-lg max-w-[25rem] text-pretty">A collection of high-performance JavaScript tools
|
|
16
|
+
written in Rust</p>
|
|
16
17
|
<div class="flex items-center gap-5 mt-8">
|
|
17
18
|
<a href="/docs/guide/introduction" class="button button--primary inline-block w-fit">
|
|
18
19
|
Get Started
|
|
19
20
|
</a>
|
|
20
|
-
<a href="https://github.com/oxc-project/oxc" target="_blank" rel="noopener noreferrer"
|
|
21
|
+
<a href="https://github.com/oxc-project/oxc" target="_blank" rel="noopener noreferrer"
|
|
22
|
+
class="button inline-block w-fit">
|
|
21
23
|
View on GitHub
|
|
22
24
|
</a>
|
|
23
25
|
</div>
|
|
@@ -25,20 +27,11 @@ import oxcAnimation from '@assets/oxc/animations/640_x_630_oxc masthead_.riv'
|
|
|
25
27
|
</div>
|
|
26
28
|
<div class="flex flex-col min-h-[22rem] sm:min-h-[30rem]">
|
|
27
29
|
<div class="relative px-10 h-full flex flex-col justify-center overflow-clip pb-10 sm:pb-0">
|
|
28
|
-
<RiveAnimation
|
|
29
|
-
|
|
30
|
-
:mobile-src="oxcAnimation"
|
|
31
|
-
:desktop-width="640"
|
|
32
|
-
:desktop-height="630"
|
|
33
|
-
:mobile-width="640"
|
|
34
|
-
:mobile-height="630"
|
|
35
|
-
canvas-class="w-full"
|
|
36
|
-
/>
|
|
30
|
+
<RiveAnimation :desktop-src="oxcAnimation" :mobile-src="oxcAnimation" :desktop-width="640" :desktop-height="630"
|
|
31
|
+
:mobile-width="640" :mobile-height="630" canvas-class="w-full" />
|
|
37
32
|
</div>
|
|
38
33
|
</div>
|
|
39
34
|
</div>
|
|
40
35
|
</template>
|
|
41
36
|
|
|
42
|
-
<style scoped>
|
|
43
|
-
|
|
44
|
-
</style>
|
|
37
|
+
<style scoped></style>
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
<div class="wrapper wrapper--ticks grid md:grid-cols-2 w-full border-nickel divide-x">
|
|
3
3
|
<div class="flex flex-col p-10 justify-between items-center md:items-start">
|
|
4
4
|
<div class="flex flex-col gap-5 text-center md:text-left items-center md:items-start">
|
|
5
|
-
<
|
|
5
|
+
<a class="flex items-center gap-2" href="https://voidzero.dev" target="_blank">
|
|
6
6
|
<span class="text-grey text-xs font-mono uppercase tracking-wide">By</span>
|
|
7
7
|
<img src="@assets/logos/voidzero-light.svg" alt="VoidZero" class="h-2.5">
|
|
8
|
-
</
|
|
8
|
+
</a>
|
|
9
9
|
<h1 class="text-white text-pretty max-w-[35rem]">Blazing Fast<br>Rust-based bundler for JavaScript</h1>
|
|
10
10
|
<p class="text-white/70 text-lg max-w-[30rem] text-pretty">with Rollup-compatible API and esbuild feature parity</p>
|
|
11
11
|
<div class="flex items-center gap-5 mt-6">
|
|
@@ -122,7 +122,7 @@ const testimonials: Testimonial[] = [
|
|
|
122
122
|
>
|
|
123
123
|
<!-- Comment -->
|
|
124
124
|
<div class="relative z-[2] flex flex-col gap-4">
|
|
125
|
-
<p v-for="(paragraph, pIndex) in testimonial.comment" :key="pIndex" class="text-white/70 leading-relaxed">
|
|
125
|
+
<p v-for="(paragraph, pIndex) in testimonial.comment" :key="pIndex" class="text-white/70 leading-relaxed text-sm sm:text-base">
|
|
126
126
|
{{ paragraph }}
|
|
127
127
|
</p>
|
|
128
128
|
</div>
|
|
@@ -8,7 +8,8 @@ import viteAnimation from '@assets/vite/animations/563_x_420_rich_features.riv'
|
|
|
8
8
|
<div class="flex flex-col gap-3 justify-between">
|
|
9
9
|
<div class="p-5 sm:p-10 flex flex-col gap-3">
|
|
10
10
|
<h5 class="text-balance sm:text-pretty text-white">Instant Server Start</h5>
|
|
11
|
-
<p class="sm:max-w-[28rem] text-pretty">On demand source file serving over
|
|
11
|
+
<p class="sm:max-w-[28rem] text-pretty">On demand source file serving over
|
|
12
|
+
native ESM, with blazing fast
|
|
12
13
|
dependency pre-bundling.</p>
|
|
13
14
|
</div>
|
|
14
15
|
<div class="card-bg1 p-10 sm:p-15 flex justify-center">
|
|
@@ -19,18 +20,19 @@ import viteAnimation from '@assets/vite/animations/563_x_420_rich_features.riv'
|
|
|
19
20
|
<div class="flex flex-col gap-3 justify-between border-r-0">
|
|
20
21
|
<div class="p-5 sm:p-10 flex flex-col gap-3">
|
|
21
22
|
<h5 class="text-white">Lightning Fast HMR</h5>
|
|
22
|
-
<p class="max-w-[26rem] text-pretty">
|
|
23
|
-
|
|
23
|
+
<p class="max-w-[26rem] text-pretty">Instantly reflect changes as you save, no matter how
|
|
24
|
+
big your app is.</p>
|
|
24
25
|
</div>
|
|
25
|
-
<div class="
|
|
26
|
-
<img src="@assets/vite/vite-featurepanel-2-terminal.png" inert loading="lazy"
|
|
27
|
-
|
|
26
|
+
<div class="flex justify-end">
|
|
27
|
+
<img src="@assets/vite/vite-featurepanel-2-terminal.png" class="md:max-w-[80%]" inert loading="lazy"
|
|
28
|
+
alt="lightning fast hot module replacement">
|
|
28
29
|
</div>
|
|
29
30
|
</div>
|
|
30
31
|
|
|
31
|
-
<div class="p-5 sm:p-10 pb-0 sm:pb-0 flex flex-col gap-3 border-b-0">
|
|
32
|
+
<div class="p-5 sm:p-10 pb-0 sm:pb-0 flex flex-col gap-3 lg:border-b-0">
|
|
32
33
|
<h5 class="text-white">Rich Features Out of the Box</h5>
|
|
33
|
-
<p class="sm:max-w-[28rem] text-pretty">TypeScript, JSX, CSS, Workers, Web
|
|
34
|
+
<p class="sm:max-w-[28rem] text-pretty">TypeScript, JSX, CSS, Workers, Web
|
|
35
|
+
Assembly... and more with just a plugin away.</p>
|
|
34
36
|
<RiveAnimation :desktop-src="viteAnimation" :mobile-src="viteAnimation" :desktop-width="563" :desktop-height="300"
|
|
35
37
|
:mobile-width="563" :mobile-height="420" canvas-class="w-full" />
|
|
36
38
|
</div>
|
|
@@ -38,7 +40,8 @@ import viteAnimation from '@assets/vite/animations/563_x_420_rich_features.riv'
|
|
|
38
40
|
<div class="flex flex-col gap-3 justify-between border-r-0 border-b-0">
|
|
39
41
|
<div class="p-5 sm:p-10 flex flex-col gap-3">
|
|
40
42
|
<h5 class="text-white">Optimized Build</h5>
|
|
41
|
-
<p class="max-w-[25rem] text-pretty">Advanced tree-shaking, built-in
|
|
43
|
+
<p class="max-w-[25rem] text-pretty">Advanced tree-shaking, built-in
|
|
44
|
+
minification, fine-grained chunking control
|
|
42
45
|
powered by Rolldown.</p>
|
|
43
46
|
</div>
|
|
44
47
|
<div class="card-bg p-10 sm:p-15 flex justify-center">
|
|
@@ -7,7 +7,8 @@ import flexiblePluginAnimation from '@assets/vite/animations/640_x_300_flexible_
|
|
|
7
7
|
<section class="wrapper wrapper--ticks border-t grid lg:grid-cols-2 divide-x divide-y divide-nickel">
|
|
8
8
|
<div class="p-5 sm:p-10 flex flex-col gap-3">
|
|
9
9
|
<h5 class="text-balance sm:text-pretty text-white">Flexible Plugin System</h5>
|
|
10
|
-
<p class="sm:max-w-[28rem] text-pretty">Vite plugins extends Rollup's
|
|
10
|
+
<p class="sm:max-w-[28rem] text-pretty">Vite plugins extends Rollup's
|
|
11
|
+
well-designed plugin interface with a few
|
|
11
12
|
extra Vite-specific options.</p>
|
|
12
13
|
<RiveAnimation :desktop-src="flexiblePluginAnimation" :desktop-width="640" :desktop-height="300"
|
|
13
14
|
canvas-class="w-[calc(100%_+_2.5rem)] mt-5 -mx-5" />
|
|
@@ -23,9 +24,10 @@ import flexiblePluginAnimation from '@assets/vite/animations/640_x_300_flexible_
|
|
|
23
24
|
</div>
|
|
24
25
|
</div>
|
|
25
26
|
|
|
26
|
-
<div class="p-5 sm:p-10 flex flex-col gap-3 border-b-0">
|
|
27
|
+
<div class="p-5 sm:p-10 flex flex-col gap-3 lg:border-b-0">
|
|
27
28
|
<h5 class="text-white">First class SSR Support</h5>
|
|
28
|
-
<p class="sm:max-w-[28rem] text-pretty mb-12 sm:mb-16">It's never been easier to
|
|
29
|
+
<p class="sm:max-w-[28rem] text-pretty mb-12 sm:mb-16">It's never been easier to
|
|
30
|
+
setup custom SSR (Server-Side
|
|
29
31
|
Rendering), or build your own SSR framework.</p>
|
|
30
32
|
<img src="@assets/vite/vite-ssr-support.png" alt="SSR Support" loading="lazy" class="w-full px-5">
|
|
31
33
|
</div>
|
|
@@ -33,7 +35,8 @@ import flexiblePluginAnimation from '@assets/vite/animations/640_x_300_flexible_
|
|
|
33
35
|
<div class="flex flex-col gap-3 justify-between">
|
|
34
36
|
<div class="p-5 sm:p-10 flex flex-col gap-3">
|
|
35
37
|
<h5 class="text-white">Continuous ecosystem integration</h5>
|
|
36
|
-
<p class="max-w-[25rem] text-pretty">Our CI continuously tests Vite changes
|
|
38
|
+
<p class="max-w-[25rem] text-pretty">Our CI continuously tests Vite changes
|
|
39
|
+
against downstream projects,
|
|
37
40
|
allowing us to improve Vite with stability and confidence.</p>
|
|
38
41
|
</div>
|
|
39
42
|
<div class="px-5 sm:px-10 flex justify-center">
|
|
@@ -17,12 +17,13 @@ const installTabs = [
|
|
|
17
17
|
<div class="wrapper wrapper--ticks grid md:grid-cols-2 w-full border-nickel md:divide-x">
|
|
18
18
|
<div class="flex flex-col p-10 justify-between gap-20 items-center md:items-start">
|
|
19
19
|
<div class="flex flex-col gap-5 items-center md:items-start text-center md:text-left">
|
|
20
|
-
<
|
|
20
|
+
<a class="flex items-center gap-2" href="https://voidzero.dev" target="_blank">
|
|
21
21
|
<span class="text-grey text-xs font-mono uppercase tracking-wide">By</span>
|
|
22
|
-
<img src="
|
|
23
|
-
</
|
|
22
|
+
<img src="@assets/logos/voidzero-light.svg" alt="VoidZero" class="h-2.5">
|
|
23
|
+
</a>
|
|
24
24
|
<h1 class="text-white text-pretty max-w-[25rem]">The Build Tool for the Web</h1>
|
|
25
|
-
<p class="text-white/70 md:text-lg max-w-[27rem] text-pretty">Vite is a blazing fast frontend build tool
|
|
25
|
+
<p class="text-white/70 md:text-lg max-w-[27rem] text-pretty">Vite is a blazing fast frontend build tool
|
|
26
|
+
powering
|
|
26
27
|
the next generation of web applications.</p>
|
|
27
28
|
<div class="flex items-center gap-5 mt-8">
|
|
28
29
|
<a href="/guide/" class="button button--primary inline-block w-fit">
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
<div class="wrapper wrapper--ticks grid md:grid-cols-2 w-full border-nickel divide-x">
|
|
3
3
|
<div class="flex flex-col p-10 justify-center items-center md:items-start">
|
|
4
4
|
<div class="flex flex-col gap-5 max-w-[30rem] text-center md:text-left items-center md:items-start">
|
|
5
|
-
<
|
|
5
|
+
<a class="flex items-center gap-2" href="https://voidzero.dev" target="_blank">
|
|
6
6
|
<span class="text-grey text-xs font-mono uppercase tracking-wide">By</span>
|
|
7
7
|
<img src="@assets/logos/voidzero-light.svg" alt="VoidZero" class="h-2.5">
|
|
8
|
-
</
|
|
8
|
+
</a>
|
|
9
9
|
<h1 class="text-white text-pretty">Next Generation Testing Framework</h1>
|
|
10
10
|
<p class="text-white/70 text-lg max-w-[25rem] text-pretty">A Vite-native testing framework. It's fast!</p>
|
|
11
11
|
<div class="flex items-center gap-5 mt-8">
|
|
@@ -34,4 +34,4 @@
|
|
|
34
34
|
}
|
|
35
35
|
</style>
|
|
36
36
|
<script setup lang="ts">
|
|
37
|
-
</script>
|
|
37
|
+
</script>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface Sponsor {
|
|
2
|
+
name: string
|
|
3
|
+
img: string
|
|
4
|
+
url: string
|
|
5
|
+
hasDark?: true
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type SponsorSize = 'big' | 'medium' | 'small' | 'avatar'
|
|
9
|
+
|
|
10
|
+
export interface SponsorTier {
|
|
11
|
+
tier: string
|
|
12
|
+
size: SponsorSize
|
|
13
|
+
items: Sponsor[]
|
|
14
|
+
}
|