From 72966d2aa51724f1876fe8f4f0a8670634b94d96 Mon Sep 17 00:00:00 2001 From: Gulomov Bakhtovar Date: Fri, 25 Sep 2026 12:53:07 +0500 Subject: [PATCH] docs: Add the pictures for modstore.pro and extras.modx.com to the logo script --- .github/logo/icon-extras.png | Bin 0 -> 3586 bytes .github/logo/modstore.png | Bin 0 -> 2946 bytes .github/logo/modstore@2x.png | Bin 0 -> 5767 bytes README.md | 2 +- README.ru.md | 2 +- _build/logo.mjs | 42 ++++++++++++++++++++++++++++++++++- 6 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 .github/logo/icon-extras.png create mode 100644 .github/logo/modstore.png create mode 100644 .github/logo/modstore@2x.png diff --git a/.github/logo/icon-extras.png b/.github/logo/icon-extras.png new file mode 100644 index 0000000000000000000000000000000000000000..503a47d976af4c9552689d30bf05216fa3aefb62 GIT binary patch literal 3586 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 Social preview) // icon-.png the mark alone (icon.svg), square and // transparent: 64, 128, 256, 512, 1024 +// modstore.png, modstore@2x.png 320x240 and 640x480 on white, the size +// modstore.pro takes for the logo of a +// package +// icon-extras.png 512x512 on white, the mark at 72% of the +// side: the icon of a package on +// extras.modx.com // // The fonts come from Google Fonts. Without them the script stops before it // writes anything, rather than leaving logos in fallback fonts. -import { writeFileSync } from 'node:fs' +import { readFileSync, writeFileSync } from 'node:fs' import { pathToFileURL } from 'node:url' import { chromium } from '@playwright/test' @@ -51,6 +57,37 @@ async function iconPng (size) { return png } +// The mark on white, 368px of a 512px square: the icon of a package on +// extras.modx.com. The site shows the icon on a coloured box, so the square is +// opaque, and the mark takes 72% of it like the icons of the other packages of +// the author, so the list of their extras looks alike. +async function extrasIcon () { + const page = await browser.newPage({ viewport: { width: 512, height: 512 } }) + const svg = readFileSync(`${dir}/icon.svg`, 'utf8').replace(/width="76" height="76"/, 'width="368" height="368"') + await page.setContent(`${svg}`) + const png = await page.screenshot() + await page.close() + return png +} + +// The logo on white, centred on a 320x240 card: the logo of a package on +// modstore.pro. The mark and the wordmark keep the sizes of the other packages +// of the author, so the tiles of the catalogue look alike. +async function modstore (scale) { + const page = await browser.newPage({ viewport: { width: 320, height: 240 }, deviceScaleFactor: scale }) + await page.goto(url) + await page.waitForSelector('body[data-ready]') + await page.evaluate(() => { + document.documentElement.style.cssText = 'width: 320px; height: 240px; background: #fff' + document.body.style.cssText = 'margin: 0; width: 320px; height: 240px; background: #fff; overflow: hidden' + document.querySelector('.logo').style.height = '240px' + }) + await requireFonts(page, ['Outfit', 'JetBrains Mono']) + const png = await page.screenshot() + await page.close() + return png +} + // The logo on white, centred on a 1280x640 card: GitHub's size for the preview. async function social (text) { const page = await browser.newPage({ viewport: { width: 1280, height: 640 } }) @@ -82,6 +119,9 @@ try { 'logo@2x.png': await logo(2), 'logo-dark.png': await logo(1, '?dark'), 'logo-dark@2x.png': await logo(2, '?dark'), + 'modstore.png': await modstore(1), + 'modstore@2x.png': await modstore(2), + 'icon-extras.png': await extrasIcon(), 'social-en.png': await social('MODX forms without a page reload, protected from spam'), 'social-ru.png': await social('Формы MODX без перезагрузки страницы, с защитой от спама'), ...Object.fromEntries(await Promise.all([64, 128, 256, 512, 1024].map(async size => [`icon-${size}.png`, await iconPng(size)]))),