diff --git a/.github/workflows/bundle.yml b/.github/workflows/bundle.yml index a3b512e..7ff9b52 100644 --- a/.github/workflows/bundle.yml +++ b/.github/workflows/bundle.yml @@ -1,16 +1,16 @@ -name: Test Bundles - -on: - pull_request: - -jobs: - bundle: - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v2 - - name: build ci environment - run: | - docker build --pull --rm -t qrapps:ci . - - name: generate QR - run: | - docker run --rm -v .:/src -w /src qrapps:ci qrs.py --htmldirs=apps --builddir=bundles +name: Test Bundles + +on: + pull_request: + +jobs: + bundle: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - name: build ci environment + run: | + docker compose build + - name: generate QR + run: | + docker compose run --rm qrs diff --git a/.github/workflows/prospector.yml b/.github/workflows/prospector.yml deleted file mode 100644 index 6937ec3..0000000 --- a/.github/workflows/prospector.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Prospector - -on: - pull_request: - -jobs: - prospector: - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v2 - - name: build ci environment - run: | - docker build --pull --rm -t qrapps:ci . - - name: lint with prospector - run: | - docker run --rm -v .:/src -w /src --entrypoint=prospector qrapps:ci \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 27c5cab..b470594 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,32 +1,31 @@ -name: Release Bundles - -on: - push: - branches: [ main ] - -jobs: - bundle: - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v2 - - name: build ci environment - run: | - docker build --pull --rm -t qrapps:ci . - - name: generate QR - run: | - docker run --rm -v .:/src -w /src qrapps:ci qrs.py --htmldirs=apps --builddir=bundles - - name: generate README.md - run: | - rm -rf docs - mv bundles docs - sudo cp -at docs .google/* - sudo git checkout -- docs/_config.yml - docker run --rm -v .:/src -w /src qrapps:ci release.py - - name: release - run: | - git config --global user.email "woldemar@mimas.ru" - git config --global user.name "Vladimir Looze" - git add docs - git commit -m "release new bundles" - git push --force origin main - +name: Release Bundles + +on: + push: + branches: [ main ] + +jobs: + bundle: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - name: build ci environment + run: | + docker compose build + - name: generate QR + run: | + docker compose run --rm qrs + - name: generate README.md + run: | + rm -rf docs + mv bundles docs + sudo cp -at docs .google/* + sudo git checkout -- docs/_config.yml + docker compose run --rm release + - name: release + run: | + git config --global user.email "woldemar@mimas.ru" + git config --global user.name "Vladimir Looze" + git add docs + git commit -m "release new bundles" + git push --force origin main diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml new file mode 100644 index 0000000..a44bd89 --- /dev/null +++ b/.github/workflows/ruff.yml @@ -0,0 +1,16 @@ +name: ruff + +on: + pull_request: + +jobs: + ruff: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - name: build ci environment + run: | + docker compose build + - name: lint with ruff + run: | + docker compose run --rm lint diff --git a/Dockerfile b/Dockerfile index 352fed5..33650f8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,40 +1,23 @@ -# Self-contained environment, useful commands: -# -# Build environment image: -# docker build --pull --rm -t qrapps:ci . -# -# After image has been built, you can run: -# -# Interactive shell, useful for debugging: -# docker run --rm -it -v .:/src -w /src --entrypoint=bash qrapps:ci -# -# Code quality check: -# docker run --rm -v .:/src -w /src --entrypoint=prospector qrapps:ci -# -# Convert everything to QR codes: -# docker run --rm -v .:/src -w /src qrapps:ci qrs.py --htmldirs=apps --builddir=bundles -# -# Convert single app to QR code: -# docker run --rm -v .:/src -w /src qrapps:ci qr.py --htmldir=apps/demo-clock --builddir=bundles +# Self-contained environment for QR Apps project -from debian:12 +FROM debian:12 RUN apt-get -y update && apt-get install -y --no-install-recommends \ python3-pip=23.0.1+dfsg-1 \ python3-venv=3.11.2-1+b1 \ npm=9.2.0~ds1-1 \ - && \ - rm -rf /var/lib/apt/lists/* + && rm -rf /var/lib/apt/lists/* -RUN --mount=type=bind,source=requirements.txt,target=requirements.txt \ - --mount=type=bind,source=requirements-contrib.txt,target=requirements-contrib.txt \ - python3 -m venv /venv && \ +COPY requirements.txt /tmp/requirements.txt +COPY requirements-contrib.txt /tmp/requirements-contrib.txt + +RUN python3 -m venv /venv && \ /venv/bin/python3 -m pip install --upgrade pip && \ - /venv/bin/python3 -m pip install -r requirements.txt && \ - /venv/bin/python3 -m pip install -r requirements-contrib.txt + /venv/bin/python3 -m pip install -r /tmp/requirements.txt && \ + /venv/bin/python3 -m pip install -r /tmp/requirements-contrib.txt RUN npm install -g uglify-js html-minifier inline-scripts -ENV PATH="/venv/bin:${PATH}" - +ENV PATH=/venv/bin:$PATH +WORKDIR /src ENTRYPOINT ["/venv/bin/python3"] \ No newline at end of file diff --git a/README.md b/README.md index 90aff0c..1c25edc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -[](https://github.com/worldemar/qrapps/actions/workflows/codeql.yml) +[](https://github.com/worldemar/qrapps/actions/workflows/codeql.yml) [](https://github.com/worldemar/qrapps/actions/workflows/pages/pages-build-deployment) -[](https://github.com/worldemar/qrapps/actions/workflows/prospector.yml) +[](https://github.com/worldemar/qrapps/actions/workflows/ruff.yml) # QR Code Apps @@ -24,6 +24,7 @@ Since QR code content is [Data URL](https://en.wikipedia.org/wiki/Data_URI_schem (see `demo-*` apps for file content examples) - Use build instructions from [Dockerfile](Dockerfile) +- See [docker.md](docker.md) for Docker Compose commands ## Why would you do that? For fun, challenge and as a demonstration of modern browser capabilities. diff --git a/apps/demo-segmented-clock/README.md b/apps/demo-segmented-clock/README.md new file mode 100644 index 0000000..2a2b55e --- /dev/null +++ b/apps/demo-segmented-clock/README.md @@ -0,0 +1,3 @@ +# Segmented Clock + +A digital clock display using 7-segment display style. Shows hours, minutes, and seconds with blinking colons between them. \ No newline at end of file diff --git a/apps/demo-segmented-clock/index.html b/apps/demo-segmented-clock/index.html new file mode 100644 index 0000000..12bdb35 --- /dev/null +++ b/apps/demo-segmented-clock/index.html @@ -0,0 +1,75 @@ + +
+ + + + \ No newline at end of file diff --git a/apps/demo-segmented-clock/index.js b/apps/demo-segmented-clock/index.js new file mode 100644 index 0000000..617bd16 --- /dev/null +++ b/apps/demo-segmented-clock/index.js @@ -0,0 +1,72 @@ +const segments = { + 0: ['a','b','c','d','e','f'], + 1: ['b','c'], + 2: ['a','b','g','e','d'], + 3: ['a','b','g','c','d'], + 4: ['f','g','b','c'], + 5: ['a','f','g','c','d'], + 6: ['a','f','g','c','d','e'], + 7: ['a','b','c'], + 8: ['a','b','c','d','e','f','g'], + 9: ['a','b','c','d','f','g'] +}; + +function createDigit() { + const digit = document.createElement('div'); + digit.className = 'digit'; + ['a','b','c','d','e','f','g'].forEach(seg => { + const segment = document.createElement('div'); + segment.className = `segment ${seg}`; + digit.appendChild(segment); + }); + return digit; +} + +function createColon() { + const colon = document.createElement('div'); + colon.className = 'colon'; + const dot1 = document.createElement('div'); + dot1.className = 'dot top'; + const dot2 = document.createElement('div'); + dot2.className = 'dot bottom'; + colon.appendChild(dot1); + colon.appendChild(dot2); + return colon; +} + +function updateDigit(digit, number) { + const activeSegments = segments[number] || []; + digit.querySelectorAll('.segment').forEach(seg => { + seg.style.opacity = activeSegments.includes(seg.className.split(' ')[1]) ? '1' : '0.1'; + }); +} + +function updateClock() { + const now = new Date(); + const hours = now.getHours().toString().padStart(2, '0'); + const minutes = now.getMinutes().toString().padStart(2, '0'); + const seconds = now.getSeconds().toString().padStart(2, '0'); + + const digits = document.querySelectorAll('.digit'); + updateDigit(digits[1], hours[0]); + updateDigit(digits[2], hours[1]); + updateDigit(digits[4], minutes[0]); + updateDigit(digits[5], minutes[1]); + updateDigit(digits[7], seconds[0]); + updateDigit(digits[8], seconds[1]); +} + +function init() { + const clock = document.getElementById('clock'); + // Create 6 digits (2 for hours, 2 for minutes, 2 for seconds) + for (let i = 0; i < 6; i++) { + clock.appendChild(createDigit()); + if (i === 1 || i === 3) { + clock.appendChild(createColon()); + } + } + updateClock(); + setInterval(updateClock, 1000); +} + +init(); \ No newline at end of file diff --git a/apps/demo-segmented-clock/minify.json b/apps/demo-segmented-clock/minify.json new file mode 100644 index 0000000..a7b6afa --- /dev/null +++ b/apps/demo-segmented-clock/minify.json @@ -0,0 +1,6 @@ +{ + "collapseWhitespace": true, + "minifyJS": true, + "minifyCSS": true, + "removeOptionalTags": true +} \ No newline at end of file diff --git a/apps/demo-segmented-clock/uglify.json b/apps/demo-segmented-clock/uglify.json new file mode 100644 index 0000000..48099a8 --- /dev/null +++ b/apps/demo-segmented-clock/uglify.json @@ -0,0 +1,15 @@ +{ + "mangle": true, + "toplevel": true, + "compress": { + "sequences": true, + "dead_code": true, + "conditionals": true, + "loops": true, + "booleans": true, + "unused": true, + "if_return": true, + "join_vars": true, + "drop_console": true + } +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e8c597e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,95 @@ +# Docker Compose for QR Apps project + +services: + # Interactive shell for debugging + shell: + build: + context: . + dockerfile: Dockerfile + volumes: + - .:/src + working_dir: /src + entrypoint: bash + stdin_open: true + tty: true + + # Code quality check with ruff + lint: + build: + context: . + dockerfile: Dockerfile + volumes: + - .:/src + working_dir: /src + entrypoint: ["ruff", "check"] + + # Convert all apps to QR codes + qrs: + build: + context: . + dockerfile: Dockerfile + volumes: + - .:/src + working_dir: /src + command: ["qrs.py", "--htmldirs=apps", "--builddir=bundles"] + + # Convert single app to QR code + # Usage: docker-compose run --rm qr --htmldir=apps/demo-clock --builddir=bundles + qr: + build: + context: . + dockerfile: Dockerfile + volumes: + - .:/src + working_dir: /src + entrypoint: ["python3", "qr.py"] + + # Generate release documentation + release: + build: + context: . + dockerfile: Dockerfile + volumes: + - .:/src + working_dir: /src + command: ["release.py"] + + # Run uglify-js + uglifyjs: + build: + context: . + dockerfile: Dockerfile + volumes: + - .:/src + working_dir: /src + entrypoint: uglifyjs + + # Run html-minifier + html-minifier: + build: + context: . + dockerfile: Dockerfile + volumes: + - .:/src + working_dir: /src + entrypoint: html-minifier + + # Run inline-script-tags + inline-script-tags: + build: + context: . + dockerfile: Dockerfile + volumes: + - .:/src + working_dir: /src + entrypoint: inline-script-tags + + # Run inline-stylesheets + inline-stylesheets: + build: + context: . + dockerfile: Dockerfile + volumes: + - .:/src + working_dir: /src + entrypoint: inline-stylesheets diff --git a/docker.md b/docker.md new file mode 100644 index 0000000..bf1814a --- /dev/null +++ b/docker.md @@ -0,0 +1,72 @@ +# Docker Compose Commands + +This project uses Docker Compose to simplify all development and build commands. + +## Prerequisites + +- Docker Desktop installed +- Docker Compose (v2+) installed + +## Build the Environment + +```bash +docker-compose build +``` + +## Interactive Shell for Debugging + +```bash +docker-compose run --rm shell +``` + +Opens an interactive bash shell with all dependencies installed and your local code mounted. + +## Code Quality Check + +```bash +docker-compose run --rm lint +``` + +Runs ruff linting on Python code. + +## Convert Everything to QR Codes + +```bash +docker-compose run --rm qrs +``` + +Converts all apps in `apps/` directory to QR codes in `bundles/`. + +## Convert Single App to QR Code + +```bash +docker-compose run --rm qr --htmldir=apps/demo-clock --builddir=bundles +``` + +Replace `demo-clock` with any app directory name under `apps/`. + +## Release Bundles + +```bash +docker-compose run --rm release +``` + +Generates `docs/README.md` with links and QR codes for all apps. + +## Additional Utility Commands + +### Minification Tools + +```bash +# Uglify JS files +docker-compose run --rm uglifyjs [options]