|
1 | | -// Script to generate an icon gallery image for the README |
2 | | -// Run with: node scripts/generate-gallery.js |
| 1 | +// Script to generate icon gallery image for README |
| 2 | +const puppeteer = require('puppeteer'); |
| 3 | +const path = require('path'); |
| 4 | +const fs = require('fs'); |
3 | 5 |
|
4 | | -import puppeteer from 'puppeteer'; |
5 | | -import path from 'path'; |
6 | | -import fs from 'fs'; |
7 | | -import { fileURLToPath } from 'url'; |
8 | | - |
9 | | -// Get the directory name in ESM |
10 | | -const __filename = fileURLToPath(import.meta.url); |
11 | | -const __dirname = path.dirname(__filename); |
| 6 | +(async () => { |
| 7 | + console.log('Generating gallery image...'); |
| 8 | + |
| 9 | + // Make sure the gallery HTML file exists |
| 10 | + const galleryPath = path.resolve(__dirname, '../examples/gallery-generator.html'); |
| 11 | + if (!fs.existsSync(galleryPath)) { |
| 12 | + console.error('Gallery HTML file not found:', galleryPath); |
| 13 | + process.exit(1); |
| 14 | + } |
12 | 15 |
|
13 | | -async function generateGalleryImage() { |
14 | | - console.log('Launching browser...'); |
| 16 | + // Launch browser |
15 | 17 | const browser = await puppeteer.launch({ |
16 | | - headless: 'new', // Use new headless mode |
| 18 | + headless: 'new', |
17 | 19 | args: ['--no-sandbox', '--disable-setuid-sandbox'] |
18 | 20 | }); |
19 | | - |
| 21 | + |
20 | 22 | try { |
21 | 23 | const page = await browser.newPage(); |
22 | 24 |
|
23 | | - // Set viewport to a reasonable size |
24 | | - await page.setViewport({ |
25 | | - width: 1200, |
26 | | - height: 800, |
27 | | - deviceScaleFactor: 2, // Higher resolution image |
28 | | - }); |
29 | | - |
30 | | - const htmlPath = path.resolve(__dirname, '../examples/gallery-generator.html'); |
31 | | - const fileUrl = `file://${htmlPath}`; |
32 | | - |
33 | | - console.log(`Opening gallery page: ${fileUrl}`); |
| 25 | + // Go to gallery page |
| 26 | + const fileUrl = `file://${galleryPath}`; |
34 | 27 | await page.goto(fileUrl, { waitUntil: 'networkidle0' }); |
35 | 28 |
|
36 | | - // Make sure the DOM is fully loaded |
37 | | - await page.waitForSelector('.gallery'); |
38 | | - |
39 | | - // Give additional time for all visual elements to render |
| 29 | + // Allow time for all SVGs to load |
40 | 30 | await page.waitForTimeout(1000); |
41 | 31 |
|
42 | | - // Find the gallery element and get its dimensions |
43 | | - const galleryElement = await page.$('.gallery'); |
44 | | - const boundingBox = await galleryElement.boundingBox(); |
| 32 | + // Take screenshot of gallery area |
| 33 | + const gallery = await page.$('#gallery'); |
| 34 | + if (!gallery) { |
| 35 | + throw new Error('Gallery element not found on page'); |
| 36 | + } |
45 | 37 |
|
46 | 38 | const outputPath = path.resolve(__dirname, '../examples/icon-gallery.png'); |
47 | | - console.log(`Taking screenshot and saving to: ${outputPath}`); |
48 | 39 |
|
49 | | - // Take screenshot of just the gallery area |
| 40 | + // Get the first 6 rows of icons |
| 41 | + await page.evaluate(() => { |
| 42 | + // Calculate row height based on first icon |
| 43 | + const iconItem = document.querySelector('.icon-item'); |
| 44 | + if (!iconItem) return; |
| 45 | + |
| 46 | + const itemHeight = iconItem.offsetHeight; |
| 47 | + const containerWidth = document.getElementById('gallery').offsetWidth; |
| 48 | + const rowSize = Math.floor(containerWidth / (iconItem.offsetWidth + 20)); // 20px is the gap |
| 49 | + |
| 50 | + // Show limited number of rows for the image |
| 51 | + const showItems = rowSize * 6; // Show 6 rows |
| 52 | + |
| 53 | + // Update subtitle |
| 54 | + const subtitle = document.querySelector('.subtitle'); |
| 55 | + if (subtitle) { |
| 56 | + subtitle.textContent = 'A collection of 486 pixel-perfect icons for React'; |
| 57 | + } |
| 58 | + |
| 59 | + // Hide icons beyond the first 6 rows |
| 60 | + const items = document.querySelectorAll('.icon-item'); |
| 61 | + if (items.length > showItems) { |
| 62 | + for (let i = showItems; i < items.length; i++) { |
| 63 | + items[i].style.display = 'none'; |
| 64 | + } |
| 65 | + } |
| 66 | + }); |
| 67 | + |
| 68 | + // Take a screenshot with appropriate padding |
| 69 | + await page.evaluate(() => { |
| 70 | + const gallery = document.getElementById('gallery'); |
| 71 | + const header = document.querySelector('.header'); |
| 72 | + if (gallery && header) { |
| 73 | + // Add padding and margin for better appearance |
| 74 | + document.body.style.padding = '40px'; |
| 75 | + gallery.style.marginBottom = '40px'; |
| 76 | + } |
| 77 | + }); |
| 78 | + |
| 79 | + // Take full page screenshot |
50 | 80 | await page.screenshot({ |
51 | 81 | path: outputPath, |
| 82 | + fullPage: false, |
52 | 83 | clip: { |
53 | | - x: boundingBox.x, |
54 | | - y: boundingBox.y - 100, // Include the header |
55 | | - width: boundingBox.width, |
56 | | - height: boundingBox.height + 150 // Add some padding |
| 84 | + x: 0, |
| 85 | + y: 0, |
| 86 | + width: 1000, |
| 87 | + height: 550 |
57 | 88 | } |
58 | 89 | }); |
| 90 | + |
| 91 | + console.log(`Gallery image generated: ${outputPath}`); |
59 | 92 |
|
60 | | - console.log('Gallery image created successfully!'); |
61 | 93 | } catch (error) { |
62 | 94 | console.error('Error generating gallery image:', error); |
63 | 95 | process.exit(1); |
64 | 96 | } finally { |
65 | 97 | await browser.close(); |
66 | 98 | } |
67 | | -} |
68 | | - |
69 | | -generateGalleryImage(); |
| 99 | +})(); |
0 commit comments