From 27808cfd0eb7851c07bc9058217bfc6f7c998c7d Mon Sep 17 00:00:00 2001 From: mifi Date: Fri, 13 Feb 2026 18:12:52 -0300 Subject: [PATCH] Tweaks, fixes, etc --- .prettierrc | 26 +++++------ README.md | 36 +++++++-------- docker-compose.yml | 1 + eslint.config.js | 30 ++++++------ package.json | 68 ++++++++++++++-------------- pnpm-lock.yaml | 87 +++++++++++++++-------------------- scripts/build.js | 98 ++++++++++++++++++++-------------------- src/assets/css/style.css | 86 +++++++++++++++++------------------ src/assets/js/ga-init.js | 18 ++++---- src/index.html | 96 +++++++++++++++++++++------------------ stylelint.config.js | 12 ++--- 11 files changed, 277 insertions(+), 281 deletions(-) diff --git a/.prettierrc b/.prettierrc index 85b0780..9358f75 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,15 +1,15 @@ { - "semi": false, - "singleQuote": true, - "tabWidth": 2, - "trailingComma": "none", - "overrides": [ - { - "files": "*.yml", - "options": { - "tabWidth": 4, - "proseWrap": "preserve" - } - } - ] + "semi": false, + "singleQuote": true, + "tabWidth": 4, + "trailingComma": "none", + "overrides": [ + { + "files": "*.yml", + "options": { + "tabWidth": 4, + "proseWrap": "preserve" + } + } + ] } diff --git a/README.md b/README.md index 83fb4f8..bc4b169 100644 --- a/README.md +++ b/README.md @@ -70,9 +70,9 @@ Static landing site for **mifi.holdings** (and www). Plain HTML/CSS/JS source; a - **Output**: `dist/` (gitignored). Do not edit `dist/`; it is generated. - **Steps** (see `scripts/build.js`): - 1. Clean and copy `src/` → `dist/`. - 2. Minify all `.js` (terser) and `.css` (clean-css). - 3. Inline critical CSS with **Critters** (lazy-loads the rest; no browser required, so it works in CI). + 1. Clean and copy `src/` → `dist/`. + 2. Minify all `.js` (terser) and `.css` (clean-css). + 3. Inline critical CSS with **Critters** (lazy-loads the rest; no browser required, so it works in CI). - **When**: Run before `docker build`. CI and the build pipeline both run `pnpm build` before packaging. --- @@ -81,7 +81,7 @@ Static landing site for **mifi.holdings** (and www). Plain HTML/CSS/JS source; a - **Frontend**: Static HTML + CSS + JS in `src/`; production build minifies and inlines critical CSS. - **Server**: nginx (Alpine) in Docker. -- **Tooling**: **pnpm**; Prettier (format); ESLint (JS), Stylelint (CSS), yamllint (YAML); **terser**, **clean-css**, **critters** (build). +- **Tooling**: **pnpm**; Prettier (format); ESLint (JS), Stylelint (CSS), yamllint (YAML); **terser**, **clean-css**, **beasties** (build). - **Deployment**: Docker image (from `dist/`) → Gitea registry → Portainer stack redeploy. --- @@ -93,9 +93,9 @@ Static landing site for **mifi.holdings** (and www). Plain HTML/CSS/JS source; a - **Lint**: `pnpm lint` (ESLint for `src/**/*.js`, Stylelint for `src/**/*.css`, yamllint for Woodpecker + docker-compose). Use `pnpm lint:fix` to auto-fix where supported. - **Build**: `pnpm build` → produces `dist/`. Required before building the Docker image. - **Run locally (Docker)**: - - Build site: `pnpm build`. - - Image: `pnpm docker:build` (or `docker build --platform linux/amd64 -t git.mifi.dev/mifi-holdings/landing:latest .`). - - Run: use `docker-compose up` **only** on a host that has `marina-net` and Traefik; otherwise run the image with a port map and open `http://localhost:`. + - Build site: `pnpm build`. + - Image: `pnpm docker:build` (or `docker build --platform linux/amd64 -t git.mifi.dev/mifi-holdings/landing:latest .`). + - Run: use `docker-compose up` **only** on a host that has `marina-net` and Traefik; otherwise run the image with a port map and open `http://localhost:`. No dev server; edit `src/` and run `pnpm build` (and optionally `docker run` or a local static server on `dist/`) to test. @@ -114,16 +114,16 @@ No dev server; edit `src/` and run `pnpm build` (and optionally `docker run` or Three pipelines: 1. **ci** (`.woodpecker/ci.yml`) - - **When**: Every PR and every push to `main`. - - **Steps**: Install deps → Prettier format check → lint (ESLint, Stylelint, yamllint) → **Build** (`pnpm build`). Mattermost notifications on success/failure. + - **When**: Every PR and every push to `main`. + - **Steps**: Install deps → Prettier format check → lint (ESLint, Stylelint, yamllint) → **Build** (`pnpm build`). Mattermost notifications on success/failure. 2. **build** (`.woodpecker/build.yml`) - - **When**: Push/tag/manual on `main` (and deployment to production); **depends_on: ci**. - - **Steps**: **Site build** (`pnpm install`, `pnpm build`) → Docker image build (linux/amd64, up to 3 retries) → push `:latest` and `:` to `git.mifi.dev/mifi-holdings/landing`. Mattermost notifications. + - **When**: Push/tag/manual on `main` (and deployment to production); **depends_on: ci**. + - **Steps**: **Site build** (`pnpm install`, `pnpm build`) → Docker image build (linux/amd64, up to 3 retries) → push `:latest` and `:` to `git.mifi.dev/mifi-holdings/landing`. Mattermost notifications. 3. **deploy** (`.woodpecker/deploy.yml`) - - **When**: Same as build (main / production deploy); **depends_on: ci**. - - **Steps**: Call Portainer webhook to redeploy the stack. Mattermost notifications. + - **When**: Same as build (main / production deploy); **depends_on: ci**. + - **Steps**: Call Portainer webhook to redeploy the stack. Mattermost notifications. Secrets used: `gitea_registry_username`, `gitea_package_token`, `portainer_webhook_url`, `mattermost_*` (bot token, channel IDs, API URL). @@ -134,11 +134,11 @@ Secrets used: `gitea_registry_username`, `gitea_package_token`, `portainer_webho - **Orchestration**: Stack defined in `docker-compose.yml`, deployed via **Portainer** (webhook triggered by Woodpecker deploy pipeline). - **Network**: Container joins external network `marina-net` (shared with Traefik). - **Traefik**: - - Hosts: `mifi.holdings`, `www.mifi.holdings`. - - Entrypoint: `websecure` (HTTPS). - - TLS: Let's Encrypt (`tls.certresolver=letsencrypt`). - - Middleware: `security-prison@file`. - - Backend: this service, port 80. + - Hosts: `mifi.holdings`, `www.mifi.holdings`. + - Entrypoint: `websecure` (HTTPS). + - TLS: Let's Encrypt (`tls.certresolver=letsencrypt`). + - Middleware: `security-prison@file`. + - Backend: this service, port 80. - **Healthcheck**: `wget --spider -q http://localhost/` every 20s (timeout 3s, 3 retries). To deploy manually: pull the latest image and redeploy the stack in Portainer, or trigger the Portainer webhook (e.g. same URL as in `portainer_webhook_url`). diff --git a/docker-compose.yml b/docker-compose.yml index 843e82b..fd01eba 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,6 +2,7 @@ services: mifi-holdings-landing: image: git.mifi.dev/mifi-holdings/landing:latest container_name: mifi-holdings-landing + restart: unless-stopped networks: - marina-net labels: diff --git a/eslint.config.js b/eslint.config.js index 61909ef..88e0620 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,20 +1,20 @@ import prettierConfig from 'eslint-config-prettier/flat' export default [ - { - files: ['src/**/*.js'], - languageOptions: { - ecmaVersion: 'latest', - sourceType: 'script', - globals: { - window: 'readonly', - document: 'readonly', - dataLayer: 'writable' - } + { + files: ['src/**/*.js'], + languageOptions: { + ecmaVersion: 'latest', + sourceType: 'script', + globals: { + window: 'readonly', + document: 'readonly', + dataLayer: 'writable' + } + }, + rules: { + 'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }] + } }, - rules: { - 'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }] - } - }, - prettierConfig + prettierConfig ] diff --git a/package.json b/package.json index 68b8e7a..ce1776c 100644 --- a/package.json +++ b/package.json @@ -1,36 +1,36 @@ { - "type": "module", - "name": "mifi-holdings-landing", - "version": "1.0.0", - "packageManager": "pnpm@10.29.3", - "scripts": { - "build": "node scripts/build.js", - "docker:build": "docker build --platform linux/amd64 -t git.mifi.dev/mifi-holdings/landing:latest .", - "docker:push": "docker push git.mifi.dev/mifi-holdings/landing:latest", - "format": "prettier --write .", - "format:check": "prettier --check .", - "lint": "pnpm run lint:yaml && pnpm run lint:js && pnpm run lint:css", - "lint:css": "stylelint \"src/**/*.css\"", - "lint:js": "eslint src/", - "lint:yaml": "yamllint .woodpecker/ci.yml .woodpecker/build.yml .woodpecker/deploy.yml docker-compose.yml", - "lint:fix": "pnpm run lint:fix:js && pnpm run lint:fix:css && pnpm run lint:fix:yaml", - "lint:fix:js": "eslint src/ --fix", - "lint:fix:css": "stylelint \"src/**/*.css\" --fix", - "lint:fix:yaml": "yamllint .woodpecker/ci.yml .woodpecker/build.yml .woodpecker/deploy.yml docker-compose.yml --fix" - }, - "devDependencies": { - "clean-css": "^5.3.3", - "critters": "^0.0.25", - "eslint": "^10.0.0", - "eslint-config-prettier": "^10.1.8", - "prettier": "^3.4.2", - "stylelint": "^17.3.0", - "stylelint-config-standard": "^40.0.0", - "terser": "^5.46.0", - "yaml-lint": "^1.7.0" - }, - "repository": { - "type": "git", - "url": "https://github.com/mifi-holdings/landing.git" - } + "name": "mifi-holdings-landing", + "type": "module", + "version": "1.0.0", + "packageManager": "pnpm@10.29.3", + "scripts": { + "build": "node scripts/build.js", + "docker:build": "docker build --platform linux/amd64 -t git.mifi.dev/mifi-holdings/landing:latest .", + "docker:push": "docker push git.mifi.dev/mifi-holdings/landing:latest", + "format": "prettier --write .", + "format:check": "prettier --check .", + "lint": "pnpm run lint:yaml && pnpm run lint:js && pnpm run lint:css", + "lint:css": "stylelint \"src/**/*.css\"", + "lint:js": "eslint src/", + "lint:yaml": "yamllint .woodpecker/ci.yml .woodpecker/build.yml .woodpecker/deploy.yml docker-compose.yml", + "lint:fix": "pnpm run lint:fix:js && pnpm run lint:fix:css && pnpm run lint:fix:yaml", + "lint:fix:js": "eslint src/ --fix", + "lint:fix:css": "stylelint \"src/**/*.css\" --fix", + "lint:fix:yaml": "yamllint .woodpecker/ci.yml .woodpecker/build.yml .woodpecker/deploy.yml docker-compose.yml --fix" + }, + "devDependencies": { + "clean-css": "^5.3.3", + "beasties": "^0.4.1", + "eslint": "^10.0.0", + "eslint-config-prettier": "^10.1.8", + "prettier": "^3.4.2", + "stylelint": "^17.3.0", + "stylelint-config-standard": "^40.0.0", + "terser": "^5.46.0", + "yaml-lint": "^1.7.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/mifi-holdings/landing.git" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 45c7730..66c0325 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,12 +8,12 @@ importers: .: devDependencies: + beasties: + specifier: ^0.4.1 + version: 0.4.1 clean-css: specifier: ^5.3.3 version: 5.3.3 - critters: - specifier: ^0.0.25 - version: 0.0.25 eslint: specifier: ^10.0.0 version: 10.0.0 @@ -241,6 +241,10 @@ packages: resolution: {integrity: sha512-x0K50QvKQ97fdEz2kPehIerj+YTeptKF9hyYkKf6egnwmMWAkADiO0QCzSp0R5xN8FTZgYaBfSaue46Ej62nMg==} engines: {node: 20 || >=22} + beasties@0.4.1: + resolution: {integrity: sha512-2Imdcw3LznDuxAbJM26RHniOLAzE6WgrK8OuvVXCQtNBS8rsnD9zsSEa3fHl4hHpUY7BYTlrpvtPVbvu9G6neg==} + engines: {node: '>=18.0.0'} + boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -262,10 +266,6 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - clean-css@5.3.3: resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} engines: {node: '>= 10.0'} @@ -298,10 +298,6 @@ packages: typescript: optional: true - critters@0.0.25: - resolution: {integrity: sha512-ROF/tjJyyRdM8/6W0VqoN5Ql05xAGnkf5b7f3sTEl1bI5jTQQf8O918RD/V9tEb9pRY/TKcvJekDbJtniHyPtQ==} - deprecated: Ownership of Critters has moved to the Nuxt team, who will be maintaining the project going forward. If you'd like to keep using Critters, please switch to the actively-maintained fork at https://github.com/danielroe/beasties - cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -310,15 +306,15 @@ packages: resolution: {integrity: sha512-8HFEBPKhOpJPEPu70wJJetjKta86Gw9+CCyCnB3sui2qQfOvRyqBy4IKLKKAwdMpWb2lHXWk9Wb4Z6AmaUT1Pg==} engines: {node: '>=12'} - css-select@5.2.2: - resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + css-select@6.0.0: + resolution: {integrity: sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==} css-tree@3.1.0: resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - css-what@6.2.2: - resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + css-what@7.0.0: + resolution: {integrity: sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==} engines: {node: '>= 6'} cssesc@3.0.0: @@ -362,6 +358,10 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -508,10 +508,6 @@ packages: globjoin@0.1.4: resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==} - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - has-flag@5.0.1: resolution: {integrity: sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==} engines: {node: '>=12'} @@ -527,8 +523,8 @@ packages: resolution: {integrity: sha512-n6l5uca7/y5joxZ3LUePhzmBFUJ+U2YWzhMa8XUTecSeSlQiZdF5XAd/Q3/WUl0VsXgUwWi8I7CNIwdI5WN1SQ==} engines: {node: '>=20.10'} - htmlparser2@8.0.2: - resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + htmlparser2@10.1.0: + resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} @@ -856,10 +852,6 @@ packages: resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} engines: {node: '>=18'} - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - supports-hyperlinks@4.4.0: resolution: {integrity: sha512-UKbpT93hN5Nr9go5UY7bopIB9YQlMz9nm/ct4IXt/irb5YRkn9WaqrOBJGZ5Pwvsd5FQzSVeYlGdXoCAPQZrPg==} engines: {node: '>=20'} @@ -1115,6 +1107,18 @@ snapshots: dependencies: jackspeak: 4.2.3 + beasties@0.4.1: + dependencies: + css-select: 6.0.0 + css-what: 7.0.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + htmlparser2: 10.1.0 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-media-query-parser: 0.2.3 + postcss-safe-parser: 7.0.1(postcss@8.5.6) + boolbase@1.0.0: {} brace-expansion@5.0.2: @@ -1137,11 +1141,6 @@ snapshots: callsites@3.1.0: {} - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - clean-css@5.3.3: dependencies: source-map: 0.6.1 @@ -1171,16 +1170,6 @@ snapshots: js-yaml: 4.1.1 parse-json: 5.2.0 - critters@0.0.25: - dependencies: - chalk: 4.1.2 - css-select: 5.2.2 - dom-serializer: 2.0.0 - domhandler: 5.0.3 - htmlparser2: 8.0.2 - postcss: 8.5.6 - postcss-media-query-parser: 0.2.3 - cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -1189,10 +1178,10 @@ snapshots: css-functions-list@3.3.3: {} - css-select@5.2.2: + css-select@6.0.0: dependencies: boolbase: 1.0.0 - css-what: 6.2.2 + css-what: 7.0.0 domhandler: 5.0.3 domutils: 3.2.2 nth-check: 2.1.1 @@ -1202,7 +1191,7 @@ snapshots: mdn-data: 2.12.2 source-map-js: 1.2.1 - css-what@6.2.2: {} + css-what@7.0.0: {} cssesc@3.0.0: {} @@ -1238,6 +1227,8 @@ snapshots: entities@4.5.0: {} + entities@7.0.1: {} + env-paths@2.2.1: {} error-ex@1.3.4: @@ -1410,8 +1401,6 @@ snapshots: globjoin@0.1.4: {} - has-flag@4.0.0: {} - has-flag@5.0.1: {} hashery@1.4.0: @@ -1422,12 +1411,12 @@ snapshots: html-tags@5.1.0: {} - htmlparser2@8.0.2: + htmlparser2@10.1.0: dependencies: domelementtype: 2.3.0 domhandler: 5.0.3 domutils: 3.2.2 - entities: 4.5.0 + entities: 7.0.1 ignore@5.3.2: {} @@ -1730,10 +1719,6 @@ snapshots: supports-color@10.2.2: {} - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - supports-hyperlinks@4.4.0: dependencies: has-flag: 5.0.1 diff --git a/scripts/build.js b/scripts/build.js index 60cc30b..1e987cb 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -1,18 +1,18 @@ /** - * Build script: copy src → dist, minify JS/CSS, inline critical CSS (Critters). + * Build script: copy src → dist, minify JS/CSS, inline critical CSS (Beasties). * Run with: pnpm build */ import { - rmSync, - mkdirSync, - readFileSync, - writeFileSync, - cpSync, - readdirSync + rmSync, + mkdirSync, + readFileSync, + writeFileSync, + cpSync, + readdirSync } from 'fs' import { join, dirname, extname } from 'path' import { fileURLToPath } from 'url' -import Critters from 'critters' +import Beasties from 'beasties' import { minify as minifyJs } from 'terser' import CleanCSS from 'clean-css' @@ -22,55 +22,57 @@ const srcDir = join(root, 'src') const distDir = join(root, 'dist') function getFiles(dir, files = []) { - const entries = readdirSync(dir, { withFileTypes: true }) - for (const e of entries) { - const full = join(dir, e.name) - if (e.isDirectory()) getFiles(full, files) - else files.push(full) - } - return files + const entries = readdirSync(dir, { withFileTypes: true }) + for (const e of entries) { + const full = join(dir, e.name) + if (e.isDirectory()) getFiles(full, files) + else files.push(full) + } + return files } async function main() { - // 1. Clean and copy src → dist - rmSync(distDir, { recursive: true, force: true }) - mkdirSync(distDir, { recursive: true }) - cpSync(srcDir, distDir, { recursive: true }) + // 1. Clean and copy src → dist + rmSync(distDir, { recursive: true, force: true }) + mkdirSync(distDir, { recursive: true }) + cpSync(srcDir, distDir, { recursive: true }) - const distFiles = getFiles(distDir) + const distFiles = getFiles(distDir) - // 2. Minify JS - const jsFiles = distFiles.filter((f) => extname(f) === '.js') - for (const f of jsFiles) { - const code = readFileSync(f, 'utf8') - const result = await minifyJs(code, { format: { comments: false } }) - if (result.code) writeFileSync(f, result.code) - } + // 2. Minify JS + const jsFiles = distFiles.filter((f) => extname(f) === '.js') + for (const f of jsFiles) { + const code = readFileSync(f, 'utf8') + const result = await minifyJs(code, { format: { comments: false } }) + if (result.code) writeFileSync(f, result.code) + } - // 3. Minify CSS - const cleanCss = new CleanCSS({ level: 2 }) - const cssFiles = distFiles.filter((f) => extname(f) === '.css') - for (const f of cssFiles) { - const code = readFileSync(f, 'utf8') - const result = cleanCss.minify(code) - if (!result.errors.length) writeFileSync(f, result.styles) - } + // 3. Minify CSS + const cleanCss = new CleanCSS({ level: 2 }) + const cssFiles = distFiles.filter((f) => extname(f) === '.css') + for (const f of cssFiles) { + const code = readFileSync(f, 'utf8') + const result = cleanCss.minify(code) + if (!result.errors.length) writeFileSync(f, result.styles) + } - // 4. Inline critical CSS with Critters (no browser; works in CI) - const critters = new Critters({ - path: distDir, - preload: 'default', - logLevel: 'warn' - }) - const indexPath = join(distDir, 'index.html') - const html = readFileSync(indexPath, 'utf8') - const inlined = await critters.process(html) - writeFileSync(indexPath, inlined) + // 4. Inline critical CSS with Beasties for all HTML files (no browser; works in CI) + const htmlFiles = distFiles.filter((f) => extname(f) === '.html') + const beasties = new Beasties({ + path: distDir, + preload: 'default', + logLevel: 'warn' + }) + for (const htmlFile of htmlFiles) { + const html = readFileSync(htmlFile, 'utf8') + const inlined = await beasties.process(html) + writeFileSync(htmlFile, inlined) + } - console.log('Build complete: dist/') + console.log('Build complete: dist/') } main().catch((err) => { - console.error(err) - process.exit(1) + console.error(err) + process.exit(1) }) diff --git a/src/assets/css/style.css b/src/assets/css/style.css index 0858bb5..952eeb5 100644 --- a/src/assets/css/style.css +++ b/src/assets/css/style.css @@ -1,70 +1,70 @@ html, body { - height: 100%; - margin: 0; - padding: 0; - background: #121212; - color: #f4f4f4; - font-family: Inter, Arial, sans-serif; + height: 100%; + margin: 0; + padding: 0; + background: #121212; + color: #f4f4f4; + font-family: Inter, Arial, sans-serif; } body { - display: flex; - align-items: center; - justify-content: center; - min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + min-height: 100vh; } .container { - text-align: center; - background: rgb(34 39 44 / 92%); - padding: 3rem 2rem; - border-radius: 1.5rem; - box-shadow: 0 2px 24px 0 rgb(0 0 0 / 13%); - max-width: 400px; - margin: 1rem; + text-align: center; + background: rgb(34 39 44 / 92%); + padding: 3rem 2rem; + border-radius: 1.5rem; + box-shadow: 0 2px 24px 0 rgb(0 0 0 / 13%); + max-width: 400px; + margin: 1rem; } .emoji { - font-size: 2.8rem; - margin-bottom: 1rem; + font-size: 2.8rem; + margin-bottom: 1rem; } h1 { - font-size: 2rem; - font-weight: 800; - margin-bottom: 0.5rem; - letter-spacing: -1px; + font-size: 2rem; + font-weight: 800; + margin-bottom: 0.5rem; + letter-spacing: -1px; } p { - color: #babed8; - margin-bottom: 1.7rem; - font-size: 1.14rem; - line-height: 1.55; + color: #babed8; + margin-bottom: 1.7rem; + font-size: 1.14rem; + line-height: 1.55; } .scram { - display: inline-block; - padding: 0.7rem 1.4rem; - background: #70ffd7; - color: #1b1e22; - border-radius: 999px; - font-weight: 700; - font-size: 1.1rem; - text-decoration: none; - transition: background 0.2s; - margin-top: 0.5rem; - box-shadow: 0 1px 4px 0 rgb(112 255 215 / 10%); + display: inline-block; + padding: 0.7rem 1.4rem; + background: #70ffd7; + color: #1b1e22; + border-radius: 999px; + font-weight: 700; + font-size: 1.1rem; + text-decoration: none; + transition: background 0.2s; + margin-top: 0.5rem; + box-shadow: 0 1px 4px 0 rgb(112 255 215 / 10%); } .scram:hover { - background: #50bf9c; - color: #fff; + background: #50bf9c; + color: #fff; } @media (width <= 430px) { - .container { - padding: 2rem 0.6rem; - } + .container { + padding: 2rem 0.6rem; + } } diff --git a/src/assets/js/ga-init.js b/src/assets/js/ga-init.js index a91fae8..3820ff4 100644 --- a/src/assets/js/ga-init.js +++ b/src/assets/js/ga-init.js @@ -1,11 +1,11 @@ ;(function () { - var script = document.currentScript - var id = script && script.getAttribute('data-ga-id') - if (!id) return - window.dataLayer = window.dataLayer || [] - function gtag() { - window.dataLayer.push(arguments) - } - gtag('js', new Date()) - gtag('config', id, { anonymize_ip: true }) + var script = document.currentScript + var id = script && script.getAttribute('data-ga-id') + if (!id) return + window.dataLayer = window.dataLayer || [] + function gtag() { + window.dataLayer.push(arguments) + } + gtag('js', new Date()) + gtag('config', id, { anonymize_ip: true }) })() diff --git a/src/index.html b/src/index.html index 8405136..3a2165c 100644 --- a/src/index.html +++ b/src/index.html @@ -1,51 +1,59 @@ - - - - + + + + - - + + - mifi.holdings - - - - + mifi.holdings + + + + - + - - - - - -
-
🛸
-

Nothing to See Here

-

- You've stumbled onto mifi.holdings — the legendary vault of - digital oddities, curios, and coffee-fueled experiments belonging to a - possibly-human, definitely-mysterious entity named - mifi.

- There's nothing here for you.
- Go on. Shoo. Scram. Or just keep wondering. -

-
- + + + + + +
+
🛸
+

Nothing to See Here

+

+ You've stumbled onto mifi.holdings — the legendary + vault of digital oddities, curios, and coffee-fueled experiments + belonging to a possibly-human, definitely-mysterious entity + named mifi.

+ There's nothing here for you.
+ Go on. Shoo. Scram. Or just keep wondering. +

+
+ diff --git a/stylelint.config.js b/stylelint.config.js index 8709456..aaeff91 100644 --- a/stylelint.config.js +++ b/stylelint.config.js @@ -1,8 +1,8 @@ export default { - extends: ['stylelint-config-standard'], - overrides: [ - { - files: ['src/**/*.css'] - } - ] + extends: ['stylelint-config-standard'], + overrides: [ + { + files: ['src/**/*.css'] + } + ] }