Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .github/logo/logo-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/logo/logo-dark@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
50 changes: 50 additions & 0 deletions .github/logo/logo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<!--
The logo of FetchIt: npm run logo renders it next to this file, on a
transparent background, for light pages (logo.png, logo@2x.png) and dark
ones (logo-dark.png, logo-dark@2x.png: logo.html?dark), and social.png for
the preview of links to the repository. The mark is a form: two fields and
the send button, in sky-500 of Tailwind CSS 4.
-->
<style>
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@400&family=JetBrains+Mono:wght@200&display=block');
html, body { margin: 0; width: 320px; height: 240px; background: transparent; overflow: hidden; }
.logo { display: flex; align-items: center; justify-content: center; gap: 13px; height: 240px; box-sizing: border-box; }
.word { font-size: 34px; line-height: 1; color: #111; white-space: nowrap; }
.dark .word { color: #f0f6fc; }
.sans { font-family: Outfit, 'Segoe UI', sans-serif; font-weight: 400; }
.mono { font-family: 'JetBrains Mono', Consolas, monospace; font-weight: 200; letter-spacing: -0.04em; }
</style>
</head>
<body>
<div class="logo">
<svg width="76" height="76" viewBox="0 0 76 76">
<rect width="76" height="76" rx="5" fill="#EBEBEB"/>
<!-- Two fields and the send button. -->
<rect x="8" y="13" width="60" height="13" rx="2" fill="#FFFFFF"/>
<rect x="8" y="31.5" width="60" height="13" rx="2" fill="#FFFFFF"/>
<rect x="8" y="50" width="30" height="13" rx="2" fill="#00A6F4"/>
</svg>
<div class="word"><span class="sans">Fetch</span><span class="mono">It</span></div>
</div>
<script>
if (location.search === '?dark') {
document.body.classList.add('dark')
}
// The wordmark fits the space right of the mark.
document.fonts.ready.then(() => {
const word = document.querySelector('.word')
const room = 320 - 76 - 13 - 50
let size = 34
while (word.scrollWidth > room && size > 12) {
size -= 0.5
word.style.fontSize = `${size}px`
}
document.body.dataset.ready = ''
})
</script>
</body>
</html>
Binary file added .github/logo/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/logo/logo@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/logo/social.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ jobs:
- name: Committed build matches src/
run: npm run build:check

- name: The build runs in every browser of browserslist (ES2019)
run: npm run check:syntax

scripts:
name: Workflows and shell scripts
runs-on: ubuntu-latest
Expand Down
376 changes: 255 additions & 121 deletions README.md

Large diffs are not rendered by default.

80 changes: 80 additions & 0 deletions _build/logo.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Render the logo from .github/logo/logo.html:
//
// npm run logo
//
// logo.png, logo@2x.png 320x240, transparent, for light pages
// logo-dark.png, logo-dark@2x.png the same for dark pages (GitHub's dark theme)
// social.png 1280x640, the preview of links to the
// repository (upload it in Settings >
// General > Social preview)
//
// 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 { pathToFileURL } from 'node:url'
import { chromium } from '@playwright/test'

const dir = '.github/logo'
const url = pathToFileURL(`${dir}/logo.html`).href
const browser = await chromium.launch()

// document.fonts.ready resolves even when the fonts failed to load.
async function requireFonts (page, families) {
const missing = await page.evaluate(names => names.filter(name =>
![...document.fonts].some(face => face.family.replace(/"/g, '') === name && face.status === 'loaded')), families)
if (missing.length) {
throw new Error(`The fonts did not load (${missing.join(', ')}); the logo needs the network for Google Fonts`)
}
}

async function logo (scale, query = '') {
const page = await browser.newPage({ viewport: { width: 320, height: 240 }, deviceScaleFactor: scale })
await page.goto(url + query)
await page.waitForSelector('body[data-ready]')
await requireFonts(page, ['Outfit', 'JetBrains Mono'])
const png = await page.screenshot({ omitBackground: true })
await page.close()
return png
}

// The logo on white, centred on a 1280x640 card: GitHub's size for the preview.
async function social () {
const page = await browser.newPage({ viewport: { width: 1280, height: 640 } })
await page.goto(url)
await page.waitForSelector('body[data-ready]')
// Outfit has no Cyrillic: the line under the logo is set in Onest.
await page.addStyleTag({ url: 'https://fonts.googleapis.com/css2?family=Onest:wght@400&display=block' })
await page.evaluate(async () => {
document.documentElement.style.cssText = 'width: 1280px; height: 640px'
document.body.style.cssText = 'width: 1280px; height: 640px; display: grid; place-items: center; background: #fff'
const mark = document.querySelector('.logo')
mark.style.cssText = 'height: auto; padding: 0; transform: scale(2.6)'
const line = document.createElement('div')
line.textContent = 'Формы MODX без перезагрузки страницы, с защитой от спама'
line.style.cssText = 'position: absolute; bottom: 120px; width: 100%; text-align: center; font: 400 30px Onest, sans-serif; color: #555'
document.body.append(line)
await document.fonts.load('400 30px Onest', line.textContent)
})
await requireFonts(page, ['Outfit', 'JetBrains Mono', 'Onest'])
const png = await page.screenshot()
await page.close()
return png
}

try {
// Every picture first, then the files: a failure leaves the old ones.
const files = {
'logo.png': await logo(1),
'logo@2x.png': await logo(2),
'logo-dark.png': await logo(1, '?dark'),
'logo-dark@2x.png': await logo(2, '?dark'),
'social.png': await social(),
}
for (const [name, png] of Object.entries(files)) {
writeFileSync(`${dir}/${name}`, png)
}
console.log(`The logo is in ${dir}/`)
} finally {
await browser.close()
}
13 changes: 8 additions & 5 deletions assets/components/fetchit/js/fetchit.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ interface FetchItAnswer {

/**
* Hooks for notifications: set FetchIt.Message to show the answers your
* way. They run before the event of the same moment is dispatched, so
* cancelling the event does not undo them. An exception in a hook is logged
* and does not stop the form.
* way. They run before the event of the same moment is dispatched (reset
* after fetchit:reset), so cancelling the event does not undo them. An
* exception in a hook is logged and does not stop the form.
*/
interface FetchItMessage {
/** On submit, before fetchit:before */
Expand All @@ -85,7 +85,7 @@ interface FetchItMessage {
success?: ((message: string) => void) | undefined;
/** When the form was refused or could not be sent, before fetchit:error */
error?: ((message: string) => void) | undefined;
/** On every reset of the form, the one after a success included */
/** On every reset of the form, the one after a success included; after fetchit:reset */
reset?: (() => void) | undefined;
}

Expand Down Expand Up @@ -147,7 +147,10 @@ interface FetchItErrorDetail extends FetchItBeforeDetail {
error?: unknown;
}

/** fetchit:reset, not cancelable */
/**
* fetchit:reset, not cancelable: the form is being reset (its button,
* form.reset(), or after a success); the fields still hold their values.
*/
interface FetchItResetDetail {
form: HTMLFormElement;
fetchit: FetchItInstance;
Expand Down
Loading
Loading