@wyxos/vibe 1.6.12 → 1.6.14
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/lib/index.js +778 -701
- package/lib/vibe.css +1 -1
- package/package.json +92 -67
- package/src/Masonry.vue +1233 -1213
- package/src/components/CodeTabs.vue +158 -0
- package/src/components/MasonryItem.vue +431 -346
- package/src/components/examples/BasicExample.vue +45 -0
- package/src/components/examples/CustomItemExample.vue +86 -0
- package/src/components/examples/HeaderFooterExample.vue +78 -0
- package/src/components/examples/SwipeModeExample.vue +39 -0
- package/src/pages.json +36401 -36401
- package/src/useMasonryScroll.ts +60 -60
- package/src/views/Examples.vue +275 -20
- package/src/views/Home.vue +236 -208
- package/toggle-link.mjs +92 -92
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Masonry
|
|
3
|
+
v-model:items="items"
|
|
4
|
+
:get-next-page="getPage"
|
|
5
|
+
:load-at-page="1"
|
|
6
|
+
:layout="layout"
|
|
7
|
+
/>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script setup lang="ts">
|
|
11
|
+
import { ref } from 'vue'
|
|
12
|
+
import Masonry from '../../Masonry.vue'
|
|
13
|
+
import fixture from '../../pages.json'
|
|
14
|
+
import type { MasonryItem, GetPageResult } from '../../types'
|
|
15
|
+
|
|
16
|
+
const items = ref<MasonryItem[]>([])
|
|
17
|
+
|
|
18
|
+
const layout = {
|
|
19
|
+
sizes: { base: 1, sm: 2, md: 3, lg: 4 },
|
|
20
|
+
gutterX: 10,
|
|
21
|
+
gutterY: 10
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const getPage = async (page: number): Promise<GetPageResult> => {
|
|
25
|
+
return new Promise((resolve) => {
|
|
26
|
+
setTimeout(() => {
|
|
27
|
+
const pageData = (fixture as any[])[page - 1] as { items: MasonryItem[] } | undefined
|
|
28
|
+
|
|
29
|
+
if (!pageData) {
|
|
30
|
+
resolve({
|
|
31
|
+
items: [],
|
|
32
|
+
nextPage: null
|
|
33
|
+
})
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
resolve({
|
|
38
|
+
items: pageData.items,
|
|
39
|
+
nextPage: page < (fixture as any[]).length ? page + 1 : null
|
|
40
|
+
})
|
|
41
|
+
}, 300)
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
</script>
|
|
45
|
+
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Masonry
|
|
3
|
+
v-model:items="items"
|
|
4
|
+
:get-next-page="getPage"
|
|
5
|
+
:load-at-page="1"
|
|
6
|
+
:layout="layout"
|
|
7
|
+
>
|
|
8
|
+
<template #item="{ item, remove }">
|
|
9
|
+
<div class="custom-card">
|
|
10
|
+
<img v-if="item.src" :src="item.src" :alt="item.title || 'Item'" />
|
|
11
|
+
<div class="overlay">
|
|
12
|
+
<h3 class="text-white font-semibold text-sm mb-2">{{ item.title || 'Untitled' }}</h3>
|
|
13
|
+
<button
|
|
14
|
+
@click="remove"
|
|
15
|
+
class="px-3 py-1 bg-white/20 hover:bg-white/30 border border-white/30 rounded text-white text-xs transition-colors"
|
|
16
|
+
>
|
|
17
|
+
Remove
|
|
18
|
+
</button>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
</Masonry>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script setup lang="ts">
|
|
26
|
+
import { ref } from 'vue'
|
|
27
|
+
import Masonry from '../../Masonry.vue'
|
|
28
|
+
import fixture from '../../pages.json'
|
|
29
|
+
import type { MasonryItem, GetPageResult } from '../../types'
|
|
30
|
+
|
|
31
|
+
const items = ref<MasonryItem[]>([])
|
|
32
|
+
|
|
33
|
+
const layout = {
|
|
34
|
+
sizes: { base: 1, sm: 2, md: 3, lg: 4 },
|
|
35
|
+
gutterX: 10,
|
|
36
|
+
gutterY: 10
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const getPage = async (page: number): Promise<GetPageResult> => {
|
|
40
|
+
return new Promise((resolve) => {
|
|
41
|
+
setTimeout(() => {
|
|
42
|
+
const pageData = (fixture as any[])[page - 1] as { items: MasonryItem[] } | undefined
|
|
43
|
+
|
|
44
|
+
if (!pageData) {
|
|
45
|
+
resolve({
|
|
46
|
+
items: [],
|
|
47
|
+
nextPage: null
|
|
48
|
+
})
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
resolve({
|
|
53
|
+
items: pageData.items,
|
|
54
|
+
nextPage: page < (fixture as any[]).length ? page + 1 : null
|
|
55
|
+
})
|
|
56
|
+
}, 300)
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
<style scoped>
|
|
62
|
+
.custom-card {
|
|
63
|
+
position: relative;
|
|
64
|
+
width: 100%;
|
|
65
|
+
height: 100%;
|
|
66
|
+
border-radius: 8px;
|
|
67
|
+
overflow: hidden;
|
|
68
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.custom-card img {
|
|
72
|
+
width: 100%;
|
|
73
|
+
height: 100%;
|
|
74
|
+
object-fit: cover;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.custom-card .overlay {
|
|
78
|
+
position: absolute;
|
|
79
|
+
bottom: 0;
|
|
80
|
+
left: 0;
|
|
81
|
+
right: 0;
|
|
82
|
+
background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
|
|
83
|
+
padding: 16px;
|
|
84
|
+
}
|
|
85
|
+
</style>
|
|
86
|
+
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Masonry
|
|
3
|
+
v-model:items="items"
|
|
4
|
+
:get-next-page="getPage"
|
|
5
|
+
:load-at-page="1"
|
|
6
|
+
:layout="layout"
|
|
7
|
+
>
|
|
8
|
+
<template #item-header="{ item }">
|
|
9
|
+
<div class="h-full flex items-center justify-between px-3">
|
|
10
|
+
<div class="flex items-center gap-2">
|
|
11
|
+
<div class="w-6 h-6 rounded-full bg-white/80 backdrop-blur-sm flex items-center justify-center shadow-sm">
|
|
12
|
+
<i :class="item.type === 'video' ? 'fas fa-video text-[10px] text-slate-500' : 'fas fa-image text-[10px] text-slate-500'"></i>
|
|
13
|
+
</div>
|
|
14
|
+
<span class="text-xs font-medium text-slate-700">#{{ String(item.id).split('-')[0] }}</span>
|
|
15
|
+
</div>
|
|
16
|
+
<span v-if="item.title" class="text-[11px] text-slate-600 truncate max-w-[160px]">{{ item.title }}</span>
|
|
17
|
+
</div>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<template #item-footer="{ item, remove }">
|
|
21
|
+
<div class="h-full flex items-center justify-between px-3">
|
|
22
|
+
<div class="flex items-center gap-2">
|
|
23
|
+
<button
|
|
24
|
+
v-if="remove"
|
|
25
|
+
class="px-2.5 py-1 rounded-full bg-white/90 text-slate-700 text-[11px] shadow-sm hover:bg-red-500 hover:text-white transition-colors"
|
|
26
|
+
@click.stop="remove(item)"
|
|
27
|
+
>
|
|
28
|
+
Remove
|
|
29
|
+
</button>
|
|
30
|
+
</div>
|
|
31
|
+
<div class="text-[11px] text-slate-600">
|
|
32
|
+
{{ item.width }}×{{ item.height }}
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
36
|
+
</Masonry>
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<script setup lang="ts">
|
|
40
|
+
import { ref } from 'vue'
|
|
41
|
+
import Masonry from '../../Masonry.vue'
|
|
42
|
+
import fixture from '../../pages.json'
|
|
43
|
+
import type { MasonryItem, GetPageResult } from '../../types'
|
|
44
|
+
|
|
45
|
+
const items = ref<MasonryItem[]>([])
|
|
46
|
+
|
|
47
|
+
const layout = {
|
|
48
|
+
sizes: { base: 1, sm: 2, md: 3, lg: 4 },
|
|
49
|
+
gutterX: 10,
|
|
50
|
+
gutterY: 10,
|
|
51
|
+
header: 36,
|
|
52
|
+
footer: 40
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const getPage = async (page: number): Promise<GetPageResult> => {
|
|
56
|
+
return new Promise((resolve) => {
|
|
57
|
+
setTimeout(() => {
|
|
58
|
+
const pageData = (fixture as any[])[page - 1] as { items: MasonryItem[] } | undefined
|
|
59
|
+
|
|
60
|
+
if (!pageData) {
|
|
61
|
+
resolve({
|
|
62
|
+
items: [],
|
|
63
|
+
nextPage: null
|
|
64
|
+
})
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
resolve({
|
|
69
|
+
items: pageData.items,
|
|
70
|
+
nextPage: page < (fixture as any[]).length ? page + 1 : null
|
|
71
|
+
})
|
|
72
|
+
}, 300)
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
</script>
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Masonry
|
|
3
|
+
v-model:items="items"
|
|
4
|
+
:get-next-page="getPage"
|
|
5
|
+
:load-at-page="1"
|
|
6
|
+
layout-mode="swipe"
|
|
7
|
+
/>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script setup lang="ts">
|
|
11
|
+
import { ref } from 'vue'
|
|
12
|
+
import Masonry from '../../Masonry.vue'
|
|
13
|
+
import fixture from '../../pages.json'
|
|
14
|
+
import type { MasonryItem, GetPageResult } from '../../types'
|
|
15
|
+
|
|
16
|
+
const items = ref<MasonryItem[]>([])
|
|
17
|
+
|
|
18
|
+
const getPage = async (page: number): Promise<GetPageResult> => {
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
setTimeout(() => {
|
|
21
|
+
const pageData = (fixture as any[])[page - 1] as { items: MasonryItem[] } | undefined
|
|
22
|
+
|
|
23
|
+
if (!pageData) {
|
|
24
|
+
resolve({
|
|
25
|
+
items: [],
|
|
26
|
+
nextPage: null
|
|
27
|
+
})
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
resolve({
|
|
32
|
+
items: pageData.items,
|
|
33
|
+
nextPage: page < (fixture as any[]).length ? page + 1 : null
|
|
34
|
+
})
|
|
35
|
+
}, 300)
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
</script>
|
|
39
|
+
|