@wyxos/vibe 1.6.26 → 1.6.28
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/README.md +287 -254
- package/lib/index.js +1158 -1108
- package/lib/vibe.css +1 -1
- package/package.json +1 -1
- package/src/Masonry.vue +167 -190
- package/src/components/MasonryItem.vue +4 -6
- package/src/components/examples/BasicExample.vue +2 -1
- package/src/components/examples/CustomItemExample.vue +2 -1
- package/src/components/examples/HeaderFooterExample.vue +79 -78
- package/src/components/examples/ManualInitExample.vue +78 -0
- package/src/components/examples/SwipeModeExample.vue +2 -1
- package/src/{useMasonryTransitions.ts → createMasonryTransitions.ts} +24 -33
- package/src/types.ts +101 -38
- package/src/useMasonryItems.ts +231 -240
- package/src/useMasonryLayout.ts +164 -164
- package/src/useMasonryPagination.ts +529 -454
- package/src/useMasonryVirtualization.ts +1 -1
- package/src/views/Examples.vue +80 -32
- package/src/views/Home.vue +321 -321
package/README.md
CHANGED
|
@@ -1,254 +1,287 @@
|
|
|
1
|
-
# VIBE — Vue Infinite Block Engine
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/@wyxos/vibe)
|
|
4
|
-
[](https://opensource.org/licenses/MIT)
|
|
5
|
-
[](https://wyxos.github.io/vibe/)
|
|
6
|
-
|
|
7
|
-
A high-performance, responsive masonry layout engine for Vue 3 with built-in infinite scrolling and virtualization.
|
|
8
|
-
|
|
9
|
-
VIBE (Vue Infinite Block Engine) is designed for applications that need to display large datasets in a masonry grid without compromising performance. Unlike other masonry libraries, VIBE leverages virtualization to render only what is visible on the screen, ensuring smooth scrolling even with thousands of items.
|
|
10
|
-
|
|
11
|
-

|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Features
|
|
16
|
-
|
|
17
|
-
- **High Performance Virtualization**: Efficiently renders thousands of items by only mounting elements currently in the viewport.
|
|
18
|
-
- **Responsive Masonry Layout**: Automatically adjusts column counts and layout based on screen width and breakpoints.
|
|
19
|
-
- **Mobile Swipe Feed**: Automatically switches to a vertical swipe feed on mobile devices for optimal mobile UX.
|
|
20
|
-
- **Infinite Scrolling**: Seamlessly loads more content as the user scrolls, with built-in support for async data fetching.
|
|
21
|
-
- **Dynamic Updates**: Supports adding, removing, and reflowing items with smooth FLIP animations.
|
|
22
|
-
- **Scroll Position Maintenance**: Keeps the user's scroll position stable when new items are loaded or the layout changes.
|
|
23
|
-
- **Built-in Item Component**: Includes a production-ready `MasonryItem` with lazy loading, image/video support, error handling, and hover effects.
|
|
24
|
-
- **Customizable Rendering**: Full control over item markup via scoped slots.
|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
## Installation
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
npm install @wyxos/vibe
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
## Usage
|
|
37
|
-
|
|
38
|
-
### Basic Usage (Default Item)
|
|
39
|
-
|
|
40
|
-
By default, VIBE uses the built-in `MasonryItem` component, which handles image loading and provides a clean UI. On mobile devices (screen width < 768px by default), it automatically switches to a vertical swipe feed mode where users can swipe through items one at a time.
|
|
41
|
-
|
|
42
|
-
```vue
|
|
43
|
-
<script setup>
|
|
44
|
-
import { ref } from 'vue'
|
|
45
|
-
import { Masonry } from '@wyxos/vibe'
|
|
46
|
-
|
|
47
|
-
const items = ref([])
|
|
48
|
-
|
|
49
|
-
// Layout configuration
|
|
50
|
-
const layout = {
|
|
51
|
-
gutterX: 12,
|
|
52
|
-
gutterY: 12,
|
|
53
|
-
sizes: { base: 1, sm: 2, md: 3, lg: 4 }
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async function
|
|
57
|
-
const response = await fetch(`/api/items?page=${page}`)
|
|
58
|
-
const data = await response.json()
|
|
59
|
-
// Items must have a 'src' property for the default MasonryItem
|
|
60
|
-
// Optional: include 'type' ('image' or 'video') and 'notFound' (boolean)
|
|
61
|
-
return {
|
|
62
|
-
items: data.items,
|
|
63
|
-
nextPage: page + 1
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
</script>
|
|
67
|
-
|
|
68
|
-
<template>
|
|
69
|
-
<Masonry
|
|
70
|
-
v-model:items="items"
|
|
71
|
-
:get-
|
|
72
|
-
:layout="layout"
|
|
73
|
-
layout-mode="auto"
|
|
74
|
-
:mobile-breakpoint="768"
|
|
75
|
-
/>
|
|
76
|
-
</template>
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
###
|
|
80
|
-
|
|
81
|
-
VIBE supports
|
|
82
|
-
|
|
83
|
-
- **`'auto'
|
|
84
|
-
- **`'
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### Item
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
---
|
|
196
|
-
|
|
197
|
-
##
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
|
204
|
-
|
|
205
|
-
| `
|
|
206
|
-
| `
|
|
207
|
-
| `
|
|
208
|
-
| `
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
1
|
+
# VIBE — Vue Infinite Block Engine
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@wyxos/vibe)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://wyxos.github.io/vibe/)
|
|
6
|
+
|
|
7
|
+
A high-performance, responsive masonry layout engine for Vue 3 with built-in infinite scrolling and virtualization.
|
|
8
|
+
|
|
9
|
+
VIBE (Vue Infinite Block Engine) is designed for applications that need to display large datasets in a masonry grid without compromising performance. Unlike other masonry libraries, VIBE leverages virtualization to render only what is visible on the screen, ensuring smooth scrolling even with thousands of items.
|
|
10
|
+
|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- **High Performance Virtualization**: Efficiently renders thousands of items by only mounting elements currently in the viewport.
|
|
18
|
+
- **Responsive Masonry Layout**: Automatically adjusts column counts and layout based on screen width and breakpoints.
|
|
19
|
+
- **Mobile Swipe Feed**: Automatically switches to a vertical swipe feed on mobile devices for optimal mobile UX.
|
|
20
|
+
- **Infinite Scrolling**: Seamlessly loads more content as the user scrolls, with built-in support for async data fetching.
|
|
21
|
+
- **Dynamic Updates**: Supports adding, removing, and reflowing items with smooth FLIP animations.
|
|
22
|
+
- **Scroll Position Maintenance**: Keeps the user's scroll position stable when new items are loaded or the layout changes.
|
|
23
|
+
- **Built-in Item Component**: Includes a production-ready `MasonryItem` with lazy loading, image/video support, error handling, and hover effects.
|
|
24
|
+
- **Customizable Rendering**: Full control over item markup via scoped slots.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install @wyxos/vibe
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
### Basic Usage (Default Item)
|
|
39
|
+
|
|
40
|
+
By default, VIBE uses the built-in `MasonryItem` component, which handles image loading and provides a clean UI. On mobile devices (screen width < 768px by default), it automatically switches to a vertical swipe feed mode where users can swipe through items one at a time.
|
|
41
|
+
|
|
42
|
+
```vue
|
|
43
|
+
<script setup>
|
|
44
|
+
import { ref } from 'vue'
|
|
45
|
+
import { Masonry } from '@wyxos/vibe'
|
|
46
|
+
|
|
47
|
+
const items = ref([])
|
|
48
|
+
|
|
49
|
+
// Layout configuration
|
|
50
|
+
const layout = {
|
|
51
|
+
gutterX: 12,
|
|
52
|
+
gutterY: 12,
|
|
53
|
+
sizes: { base: 1, sm: 2, md: 3, lg: 4 }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function getPage(page) {
|
|
57
|
+
const response = await fetch(`/api/items?page=${page}`)
|
|
58
|
+
const data = await response.json()
|
|
59
|
+
// Items must have a 'src' property for the default MasonryItem
|
|
60
|
+
// Optional: include 'type' ('image' or 'video') and 'notFound' (boolean)
|
|
61
|
+
return {
|
|
62
|
+
items: data.items,
|
|
63
|
+
nextPage: page + 1
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
<template>
|
|
69
|
+
<Masonry
|
|
70
|
+
v-model:items="items"
|
|
71
|
+
:get-page="getPage"
|
|
72
|
+
:layout="layout"
|
|
73
|
+
layout-mode="auto"
|
|
74
|
+
:mobile-breakpoint="768"
|
|
75
|
+
/>
|
|
76
|
+
</template>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Initialization Modes
|
|
80
|
+
|
|
81
|
+
VIBE supports two initialization modes:
|
|
82
|
+
|
|
83
|
+
- **`'auto'`**: Automatically calls `loadPage` on mount to fetch the first page. Use this when you want the component to start loading immediately.
|
|
84
|
+
- **`'manual'`**: Does nothing on mount. You must manually call `initialize()` to initialize the component with items. Use this when you need to restore items from saved state or have more control over when loading begins.
|
|
85
|
+
|
|
86
|
+
```vue
|
|
87
|
+
<!-- Auto mode: loads first page automatically -->
|
|
88
|
+
<Masonry
|
|
89
|
+
v-model:items="items"
|
|
90
|
+
:get-page="getPage"
|
|
91
|
+
init="auto"
|
|
92
|
+
:load-at-page="1"
|
|
93
|
+
/>
|
|
94
|
+
|
|
95
|
+
<!-- Manual mode: you control when to initialize -->
|
|
96
|
+
<Masonry
|
|
97
|
+
ref="masonry"
|
|
98
|
+
v-model:items="items"
|
|
99
|
+
:get-page="getPage"
|
|
100
|
+
init="manual"
|
|
101
|
+
/>
|
|
102
|
+
<script setup>
|
|
103
|
+
const masonry = ref(null)
|
|
104
|
+
|
|
105
|
+
// Later, initialize manually
|
|
106
|
+
masonry.value.items = []
|
|
107
|
+
masonry.value.initialize(savedItems, savedPage, savedNextPage)
|
|
108
|
+
</script>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Layout Modes
|
|
112
|
+
|
|
113
|
+
VIBE supports three layout modes:
|
|
114
|
+
|
|
115
|
+
- **`'auto'`** (default): Automatically switches between masonry grid (desktop) and swipe feed (mobile) based on screen width
|
|
116
|
+
- **`'masonry'`**: Always use masonry grid layout regardless of screen size
|
|
117
|
+
- **`'swipe'`**: Always use swipe feed layout regardless of screen size
|
|
118
|
+
|
|
119
|
+
```vue
|
|
120
|
+
<!-- Force masonry layout on all devices -->
|
|
121
|
+
<Masonry layout-mode="masonry" ... />
|
|
122
|
+
|
|
123
|
+
<!-- Force swipe feed on all devices -->
|
|
124
|
+
<Masonry layout-mode="swipe" ... />
|
|
125
|
+
|
|
126
|
+
<!-- Custom breakpoint (use Tailwind breakpoint name) -->
|
|
127
|
+
<Masonry layout-mode="auto" mobile-breakpoint="lg" ... />
|
|
128
|
+
|
|
129
|
+
<!-- Custom breakpoint (use pixel value) -->
|
|
130
|
+
<Masonry layout-mode="auto" :mobile-breakpoint="1024" ... />
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Custom Item Rendering
|
|
134
|
+
|
|
135
|
+
You can fully customize the item rendering using the `#item` slot. You can also import and use `MasonryItem` inside the slot if you want to wrap it or extend it.
|
|
136
|
+
|
|
137
|
+
```vue
|
|
138
|
+
<script setup>
|
|
139
|
+
import { Masonry, MasonryItem } from '@wyxos/vibe'
|
|
140
|
+
// ... setup code ...
|
|
141
|
+
</script>
|
|
142
|
+
|
|
143
|
+
<template>
|
|
144
|
+
<Masonry
|
|
145
|
+
v-model:items="items"
|
|
146
|
+
:get-page="getPage"
|
|
147
|
+
:layout="layout"
|
|
148
|
+
>
|
|
149
|
+
<template #item="{ item, remove }">
|
|
150
|
+
<!-- Custom container -->
|
|
151
|
+
<div class="custom-card">
|
|
152
|
+
<!-- You can use the built-in item or your own -->
|
|
153
|
+
<MasonryItem :item="item" :remove="remove">
|
|
154
|
+
<!-- Optional: MasonryItem also has a default slot for overlays -->
|
|
155
|
+
<div class="absolute bottom-0 p-2 text-white">
|
|
156
|
+
{{ item.title }}
|
|
157
|
+
</div>
|
|
158
|
+
</MasonryItem>
|
|
159
|
+
</div>
|
|
160
|
+
</template>
|
|
161
|
+
</Masonry>
|
|
162
|
+
</template>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Item Data Structure
|
|
166
|
+
|
|
167
|
+
Items can include the following properties:
|
|
168
|
+
|
|
169
|
+
```javascript
|
|
170
|
+
{
|
|
171
|
+
id: 'unique-id', // Required: unique identifier
|
|
172
|
+
width: 300, // Required: original width
|
|
173
|
+
height: 200, // Required: original height
|
|
174
|
+
src: 'https://...', // Required: media source URL
|
|
175
|
+
type: 'image' | 'video', // Optional: media type (defaults to 'image')
|
|
176
|
+
notFound: false, // Optional: show "Not Found" state
|
|
177
|
+
// ... any other custom properties
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Slot Props
|
|
182
|
+
|
|
183
|
+
The `MasonryItem` component exposes the following props to its default slot:
|
|
184
|
+
|
|
185
|
+
- `item`: The item object
|
|
186
|
+
- `remove`: The remove callback function
|
|
187
|
+
- `imageLoaded`: Boolean indicating if image has loaded
|
|
188
|
+
- `imageError`: Boolean indicating if image failed to load
|
|
189
|
+
- `videoLoaded`: Boolean indicating if video has loaded
|
|
190
|
+
- `videoError`: Boolean indicating if video failed to load
|
|
191
|
+
- `showNotFound`: Boolean indicating if item is in "not found" state
|
|
192
|
+
- `isLoading`: Boolean indicating if media is currently loading
|
|
193
|
+
- `mediaType`: String indicating the media type ('image' or 'video')
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Props
|
|
198
|
+
|
|
199
|
+
| Prop | Type | Required | Description |
|
|
200
|
+
|------|------|----------|-------------|
|
|
201
|
+
| `items` | `Array` | Yes | Two-way bound item array. Each item must include `width`, `height`, and `id`. |
|
|
202
|
+
| `getPage` | `Function(page: Number)` | Yes | Async function to load a page. Must return `{ items, nextPage }`. |
|
|
203
|
+
| `layout` | `Object` | No | Configuration object for layout, including sizes and gutters. |
|
|
204
|
+
| `loadAtPage` | `Number` | No | The starting page number (default: `1`). |
|
|
205
|
+
| `init` | `String` | No | Initialization mode: `'auto'` (automatically loads first page on mount) or `'manual'` (user must call `initialize()` manually) (default: `'manual'`). |
|
|
206
|
+
| `paginationType` | `String` | No | `'page'` or `'cursor'` (default: `'page'`). |
|
|
207
|
+
| `pageSize` | `Number` | No | Number of items per page, used for backfilling (default: `40`). |
|
|
208
|
+
| `layoutMode` | `String` | No | Layout mode: `'auto'` (detect from screen size), `'masonry'`, or `'swipe'` (default: `'auto'`). |
|
|
209
|
+
| `mobileBreakpoint` | `Number \| String` | No | Breakpoint for switching to swipe mode in pixels or Tailwind breakpoint name (default: `768`). |
|
|
210
|
+
|
|
211
|
+
### Layout Configuration Example
|
|
212
|
+
|
|
213
|
+
```js
|
|
214
|
+
{
|
|
215
|
+
gutterX: 10,
|
|
216
|
+
gutterY: 10,
|
|
217
|
+
sizes: {
|
|
218
|
+
base: 1,
|
|
219
|
+
sm: 2,
|
|
220
|
+
md: 3,
|
|
221
|
+
lg: 4,
|
|
222
|
+
xl: 5,
|
|
223
|
+
'2xl': 6
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## MasonryItem Component
|
|
231
|
+
|
|
232
|
+
The built-in `MasonryItem` component is available for use within the `#item` slot or as a standalone component. It provides intelligent lazy loading, media type detection, and comprehensive error handling.
|
|
233
|
+
|
|
234
|
+
### Props
|
|
235
|
+
|
|
236
|
+
| Prop | Type | Description |
|
|
237
|
+
|------|------|-------------|
|
|
238
|
+
| `item` | `Object` | The item object. Must contain `src` for media loading. Can include `type` (`'image'` or `'video'`), `notFound` (boolean), and other custom properties. |
|
|
239
|
+
| `remove` | `Function` | Optional callback to remove the item. If provided, a remove button is shown on hover. |
|
|
240
|
+
| `type` | `'image' \| 'video'` | Optional. Overrides `item.type`. Defaults to `'image'`. |
|
|
241
|
+
| `notFound` | `Boolean` | Optional. Overrides `item.notFound`. When `true`, displays a "Not Found" state instead of loading media. |
|
|
242
|
+
|
|
243
|
+
### Features
|
|
244
|
+
|
|
245
|
+
- **Lazy Loading with Intersection Observer**: Only starts preloading media when the item comes into view (50%+ visible), significantly improving initial page load performance.
|
|
246
|
+
- **Image & Video Support**: Automatically handles both images and videos with appropriate loading strategies.
|
|
247
|
+
- **Media Type Indicator**: Shows a badge icon (image/video) on hover to indicate the media type.
|
|
248
|
+
- **Smart Spinner**: Displays a loading spinner underneath the media (not covering it) during preload.
|
|
249
|
+
- **Error Handling**: Displays user-friendly error states if media fails to load.
|
|
250
|
+
- **Not Found State**: Special visual state for items that cannot be located.
|
|
251
|
+
- **Hover Effects**: Includes subtle zoom, overlay gradient, and smooth transitions.
|
|
252
|
+
- **Performance Optimized**: Properly cleans up Intersection Observers to prevent memory leaks.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Slots
|
|
257
|
+
|
|
258
|
+
| Slot Name | Props | Description |
|
|
259
|
+
|-----------|-------|-------------|
|
|
260
|
+
| `item` | `{ item, remove }` | Scoped slot for custom rendering of each masonry block. |
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Run Locally
|
|
265
|
+
|
|
266
|
+
To run the demo project locally:
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
git clone https://github.com/wyxos/vibe
|
|
270
|
+
cd vibe
|
|
271
|
+
npm install
|
|
272
|
+
npm run dev
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Visit `http://localhost:5173` to view the demo.
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Live Demo
|
|
280
|
+
|
|
281
|
+
[View Live Demo on GitHub Pages](https://wyxos.github.io/vibe/)
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## License
|
|
286
|
+
|
|
287
|
+
MIT © [@wyxos](https://github.com/wyxos)
|