social-masonry 1.0.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/LICENSE +21 -0
- package/README.md +394 -0
- package/dist/index.d.ts +550 -0
- package/dist/index.esm.js +1495 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +1512 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.d.ts +195 -0
- package/dist/react/index.esm.js +730 -0
- package/dist/react/index.esm.js.map +1 -0
- package/dist/react/index.js +735 -0
- package/dist/react/index.js.map +1 -0
- package/dist/styles.css +2 -0
- package/dist/styles.css.map +1 -0
- package/package.json +85 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/tkana-dev/social-masonry/main/assets/logo.svg" alt="Social Masonry" width="120" />
|
|
3
|
+
<h1>Social Masonry</h1>
|
|
4
|
+
<p><strong>Beautiful masonry layout for X (Twitter) and Instagram embeds</strong></p>
|
|
5
|
+
|
|
6
|
+
[](https://www.npmjs.com/package/social-masonry)
|
|
7
|
+
[](https://bundlephobia.com/package/social-masonry)
|
|
8
|
+
[](https://github.com/tkana-dev/social-masonry/blob/main/LICENSE)
|
|
9
|
+
[](https://www.typescriptlang.org/)
|
|
10
|
+
|
|
11
|
+
<a href="https://social-masonry.dev">Demo</a> ยท <a href="#installation">Installation</a> ยท <a href="#usage">Usage</a> ยท <a href="#api">API</a>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
<p align="center">
|
|
17
|
+
<img src="https://raw.githubusercontent.com/tkana-dev/social-masonry/main/assets/demo.gif" alt="Demo" width="100%" />
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
## โจ Features
|
|
21
|
+
|
|
22
|
+
- ๐จ **Beautiful Cards** - Native-looking X and Instagram post cards with 5 design variants
|
|
23
|
+
- โก **High Performance** - Virtual scrolling for smooth rendering of thousands of posts
|
|
24
|
+
- ๐ฑ **Responsive** - Adaptive column layouts that look great on any screen size
|
|
25
|
+
- ๐ญ **Themeable** - Light, dark, and auto themes with full customization
|
|
26
|
+
- ๐ **Infinite Scroll** - Built-in load more functionality
|
|
27
|
+
- ๐ฏ **TypeScript** - Full type safety and excellent DX
|
|
28
|
+
- โ๏ธ **React Ready** - First-class React component with hooks
|
|
29
|
+
- ๐ชถ **Lightweight** - ~8KB gzipped with zero dependencies
|
|
30
|
+
|
|
31
|
+
## ๐ฆ Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# npm
|
|
35
|
+
npm install social-masonry
|
|
36
|
+
|
|
37
|
+
# yarn
|
|
38
|
+
yarn add social-masonry
|
|
39
|
+
|
|
40
|
+
# pnpm
|
|
41
|
+
pnpm add social-masonry
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## ๐ Quick Start
|
|
45
|
+
|
|
46
|
+
### Vanilla JavaScript
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
import { createSocialMasonry } from 'social-masonry';
|
|
50
|
+
import 'social-masonry/styles';
|
|
51
|
+
|
|
52
|
+
const masonry = createSocialMasonry({
|
|
53
|
+
container: '#posts',
|
|
54
|
+
posts: [
|
|
55
|
+
{
|
|
56
|
+
platform: 'twitter',
|
|
57
|
+
id: '1',
|
|
58
|
+
url: 'https://twitter.com/user/status/123',
|
|
59
|
+
author: {
|
|
60
|
+
username: 'johndoe',
|
|
61
|
+
displayName: 'John Doe',
|
|
62
|
+
avatarUrl: 'https://...',
|
|
63
|
+
verified: true,
|
|
64
|
+
},
|
|
65
|
+
content: {
|
|
66
|
+
text: 'Hello, world! ๐',
|
|
67
|
+
},
|
|
68
|
+
metrics: {
|
|
69
|
+
likes: 1234,
|
|
70
|
+
retweets: 567,
|
|
71
|
+
replies: 89,
|
|
72
|
+
},
|
|
73
|
+
createdAt: '2024-01-15T10:30:00Z',
|
|
74
|
+
},
|
|
75
|
+
// ... more posts
|
|
76
|
+
],
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Add more posts
|
|
80
|
+
masonry.addPosts(newPosts);
|
|
81
|
+
|
|
82
|
+
// Clean up
|
|
83
|
+
masonry.destroy();
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### React
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
import { SocialMasonry } from 'social-masonry/react';
|
|
90
|
+
import 'social-masonry/styles';
|
|
91
|
+
|
|
92
|
+
function App() {
|
|
93
|
+
const posts = usePosts();
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<SocialMasonry
|
|
97
|
+
posts={posts}
|
|
98
|
+
columns={[
|
|
99
|
+
{ columns: 4, minWidth: 1200 },
|
|
100
|
+
{ columns: 3, minWidth: 900 },
|
|
101
|
+
{ columns: 2, minWidth: 600 },
|
|
102
|
+
{ columns: 1, minWidth: 0 },
|
|
103
|
+
]}
|
|
104
|
+
gap={16}
|
|
105
|
+
variant="elevated"
|
|
106
|
+
theme="auto"
|
|
107
|
+
onPostClick={(post) => window.open(post.url)}
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## ๐ Usage
|
|
114
|
+
|
|
115
|
+
### Post Types
|
|
116
|
+
|
|
117
|
+
#### Twitter/X Post
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const twitterPost: TwitterPost = {
|
|
121
|
+
platform: 'twitter',
|
|
122
|
+
id: 'unique-id',
|
|
123
|
+
url: 'https://twitter.com/user/status/123',
|
|
124
|
+
author: {
|
|
125
|
+
username: 'johndoe',
|
|
126
|
+
displayName: 'John Doe',
|
|
127
|
+
avatarUrl: 'https://example.com/avatar.jpg',
|
|
128
|
+
verified: true,
|
|
129
|
+
},
|
|
130
|
+
content: {
|
|
131
|
+
text: 'This is my tweet! #awesome',
|
|
132
|
+
html: 'This is my tweet! <a href="#">#awesome</a>', // Optional: pre-rendered HTML
|
|
133
|
+
},
|
|
134
|
+
media: [
|
|
135
|
+
{
|
|
136
|
+
type: 'image',
|
|
137
|
+
url: 'https://example.com/image.jpg',
|
|
138
|
+
aspectRatio: 16 / 9,
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
metrics: {
|
|
142
|
+
likes: 1234,
|
|
143
|
+
retweets: 567,
|
|
144
|
+
replies: 89,
|
|
145
|
+
views: 50000,
|
|
146
|
+
},
|
|
147
|
+
quotedPost: { /* nested TwitterPost */ }, // Optional
|
|
148
|
+
createdAt: '2024-01-15T10:30:00Z',
|
|
149
|
+
};
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
#### Instagram Post
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
const instagramPost: InstagramPost = {
|
|
156
|
+
platform: 'instagram',
|
|
157
|
+
id: 'unique-id',
|
|
158
|
+
url: 'https://instagram.com/p/ABC123',
|
|
159
|
+
author: {
|
|
160
|
+
username: 'janedoe',
|
|
161
|
+
displayName: 'Jane Doe',
|
|
162
|
+
avatarUrl: 'https://example.com/avatar.jpg',
|
|
163
|
+
verified: false,
|
|
164
|
+
},
|
|
165
|
+
content: {
|
|
166
|
+
caption: 'Beautiful sunset ๐
#photography',
|
|
167
|
+
},
|
|
168
|
+
media: {
|
|
169
|
+
type: 'image', // 'image' | 'video' | 'carousel'
|
|
170
|
+
url: 'https://example.com/image.jpg',
|
|
171
|
+
aspectRatio: 1, // Square
|
|
172
|
+
carouselItems: [ /* for carousel type */ ],
|
|
173
|
+
},
|
|
174
|
+
metrics: {
|
|
175
|
+
likes: 5678,
|
|
176
|
+
comments: 123,
|
|
177
|
+
},
|
|
178
|
+
createdAt: '2024-01-15T10:30:00Z',
|
|
179
|
+
};
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Configuration Options
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
const masonry = createSocialMasonry({
|
|
186
|
+
// Required
|
|
187
|
+
container: '#posts', // Element or selector
|
|
188
|
+
posts: [], // Array of SocialPost
|
|
189
|
+
|
|
190
|
+
// Layout
|
|
191
|
+
gap: 16, // Gap between cards (px)
|
|
192
|
+
columns: [ // Responsive breakpoints
|
|
193
|
+
{ columns: 4, minWidth: 1200 },
|
|
194
|
+
{ columns: 3, minWidth: 900 },
|
|
195
|
+
{ columns: 2, minWidth: 600 },
|
|
196
|
+
{ columns: 1, minWidth: 0 },
|
|
197
|
+
],
|
|
198
|
+
padding: 0, // Container padding
|
|
199
|
+
|
|
200
|
+
// Animation
|
|
201
|
+
animate: true,
|
|
202
|
+
animationDuration: 300,
|
|
203
|
+
easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
204
|
+
|
|
205
|
+
// Card Styling
|
|
206
|
+
variant: 'default', // 'default' | 'minimal' | 'elevated' | 'bordered' | 'glass'
|
|
207
|
+
theme: 'auto', // 'light' | 'dark' | 'auto'
|
|
208
|
+
borderRadius: 12,
|
|
209
|
+
hoverEffect: true,
|
|
210
|
+
|
|
211
|
+
// Content
|
|
212
|
+
showPlatformIcon: true,
|
|
213
|
+
showAuthor: true,
|
|
214
|
+
showMetrics: true,
|
|
215
|
+
showTimestamp: true,
|
|
216
|
+
|
|
217
|
+
// Custom Formatters
|
|
218
|
+
formatDate: (date) => formatRelativeTime(date),
|
|
219
|
+
formatNumber: (num) => formatNumber(num),
|
|
220
|
+
|
|
221
|
+
// Image Loading
|
|
222
|
+
imageLoading: 'lazy', // 'lazy' | 'eager'
|
|
223
|
+
fallbackImage: 'https://...', // Fallback for broken images
|
|
224
|
+
|
|
225
|
+
// Virtualization (for large lists)
|
|
226
|
+
virtualization: {
|
|
227
|
+
enabled: false,
|
|
228
|
+
overscan: 3,
|
|
229
|
+
estimatedItemHeight: 400,
|
|
230
|
+
scrollContainer: null, // Default: window
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
// Infinite Scroll
|
|
234
|
+
loadMoreThreshold: 500,
|
|
235
|
+
showLoading: true,
|
|
236
|
+
loadingElement: '<div>Loading...</div>',
|
|
237
|
+
emptyMessage: 'No posts to display',
|
|
238
|
+
|
|
239
|
+
// Events
|
|
240
|
+
onPostClick: (post, event) => {},
|
|
241
|
+
onAuthorClick: (post, event) => {},
|
|
242
|
+
onMediaClick: (post, mediaIndex, event) => {},
|
|
243
|
+
onLayoutComplete: (positions) => {},
|
|
244
|
+
onLoadMore: async () => {},
|
|
245
|
+
onImageError: (post, error) => {},
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Card Variants
|
|
250
|
+
|
|
251
|
+
| Variant | Description |
|
|
252
|
+
|---------|-------------|
|
|
253
|
+
| `default` | Clean card with subtle border and shadow |
|
|
254
|
+
| `minimal` | No background, perfect for embedding |
|
|
255
|
+
| `elevated` | Floating card with prominent shadow |
|
|
256
|
+
| `bordered` | Strong border, no shadow |
|
|
257
|
+
| `glass` | Glassmorphism effect with blur |
|
|
258
|
+
|
|
259
|
+
### API Methods
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
// Add posts to the end
|
|
263
|
+
masonry.addPosts(newPosts);
|
|
264
|
+
|
|
265
|
+
// Replace all posts
|
|
266
|
+
masonry.setPosts(posts);
|
|
267
|
+
|
|
268
|
+
// Remove a post
|
|
269
|
+
masonry.removePost(postId);
|
|
270
|
+
|
|
271
|
+
// Update options
|
|
272
|
+
masonry.setOptions({ theme: 'dark' });
|
|
273
|
+
|
|
274
|
+
// Get current state
|
|
275
|
+
const state = masonry.getLayoutState();
|
|
276
|
+
const posts = masonry.getPosts();
|
|
277
|
+
|
|
278
|
+
// Scroll to a post
|
|
279
|
+
masonry.scrollToPost(postId, 'smooth');
|
|
280
|
+
|
|
281
|
+
// Recalculate layout
|
|
282
|
+
masonry.refresh();
|
|
283
|
+
|
|
284
|
+
// Clean up
|
|
285
|
+
masonry.destroy();
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### React Hooks
|
|
289
|
+
|
|
290
|
+
```tsx
|
|
291
|
+
import { useRef } from 'react';
|
|
292
|
+
import { SocialMasonry, SocialMasonryRef } from 'social-masonry/react';
|
|
293
|
+
|
|
294
|
+
function App() {
|
|
295
|
+
const masonryRef = useRef<SocialMasonryRef>(null);
|
|
296
|
+
|
|
297
|
+
const handleAddPost = () => {
|
|
298
|
+
masonryRef.current?.addPosts([newPost]);
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
return (
|
|
302
|
+
<SocialMasonry
|
|
303
|
+
ref={masonryRef}
|
|
304
|
+
posts={posts}
|
|
305
|
+
// ...
|
|
306
|
+
/>
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## ๐จ Customization
|
|
312
|
+
|
|
313
|
+
### CSS Variables
|
|
314
|
+
|
|
315
|
+
Override the default theme using CSS variables:
|
|
316
|
+
|
|
317
|
+
```css
|
|
318
|
+
:root {
|
|
319
|
+
/* Colors */
|
|
320
|
+
--sm-bg: #ffffff;
|
|
321
|
+
--sm-bg-hover: #f7f9fa;
|
|
322
|
+
--sm-text: #0f1419;
|
|
323
|
+
--sm-text-secondary: #536471;
|
|
324
|
+
--sm-text-muted: #8b98a5;
|
|
325
|
+
--sm-border: #eff3f4;
|
|
326
|
+
--sm-link: #1d9bf0;
|
|
327
|
+
|
|
328
|
+
/* Brand Colors */
|
|
329
|
+
--sm-twitter-primary: #1d9bf0;
|
|
330
|
+
--sm-instagram-primary: #e1306c;
|
|
331
|
+
|
|
332
|
+
/* Shadows */
|
|
333
|
+
--sm-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
334
|
+
--sm-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
335
|
+
--sm-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.12);
|
|
336
|
+
|
|
337
|
+
/* Transitions */
|
|
338
|
+
--sm-transition-fast: 150ms ease;
|
|
339
|
+
--sm-transition-base: 200ms ease;
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Custom Classes
|
|
344
|
+
|
|
345
|
+
Add custom classes to cards:
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
createSocialMasonry({
|
|
349
|
+
className: 'my-custom-card',
|
|
350
|
+
// ...
|
|
351
|
+
});
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## ๐ Performance
|
|
355
|
+
|
|
356
|
+
Social Masonry is optimized for performance:
|
|
357
|
+
|
|
358
|
+
- **Virtual Scrolling**: Only renders visible cards, enabling smooth scrolling with 10,000+ posts
|
|
359
|
+
- **Efficient Layout**: Uses a columnar algorithm with O(n) complexity
|
|
360
|
+
- **Smart Updates**: Batched DOM updates and position caching
|
|
361
|
+
- **Lazy Loading**: Images load only when cards enter the viewport
|
|
362
|
+
|
|
363
|
+
Enable virtualization for large datasets:
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
createSocialMasonry({
|
|
367
|
+
virtualization: {
|
|
368
|
+
enabled: true,
|
|
369
|
+
overscan: 3, // Extra items to render above/below viewport
|
|
370
|
+
estimatedItemHeight: 400,
|
|
371
|
+
},
|
|
372
|
+
// ...
|
|
373
|
+
});
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## ๐ Browser Support
|
|
377
|
+
|
|
378
|
+
| Browser | Version |
|
|
379
|
+
|---------|---------|
|
|
380
|
+
| Chrome | 80+ |
|
|
381
|
+
| Firefox | 75+ |
|
|
382
|
+
| Safari | 14+ |
|
|
383
|
+
| Edge | 80+ |
|
|
384
|
+
|
|
385
|
+
## ๐ License
|
|
386
|
+
|
|
387
|
+
MIT ยฉ [tkana_dev](https://github.com/tkana-dev)
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
<div align="center">
|
|
392
|
+
<p>If you find this project useful, please consider giving it a โญ๏ธ</p>
|
|
393
|
+
<a href="https://github.com/tkana-dev/social-masonry">GitHub</a> ยท <a href="https://www.npmjs.com/package/social-masonry">npm</a> ยท <a href="https://social-masonry.dev">Demo</a>
|
|
394
|
+
</div>
|