From 9f3d7df5cdec2ceb9b40963b4063ba95969486c3 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Thu, 17 Apr 2025 08:46:31 +0200 Subject: [PATCH] Update shlink-web-client with support for client-side generated QRs --- CHANGELOG.md | 3 +- dev.Dockerfile | 7 ++++ package-lock.json | 93 ++++++++++++++++++++++++++++++++--------------- package.json | 2 +- src/tailwind.css | 9 +++++ 5 files changed, 82 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87e23ac5..1bd4342f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] ### Added -* *Nothing* +* [shlink-web-component#637](https://github.com/shlinkio/shlink-web-component/pull/637) QR codes are now generated client-side, without hitting Shlink. +* [shlink-web-component#641](https://github.com/shlinkio/shlink-web-component/issues/641) It is now possible to provide any logo to be used with QR codes. ### Changed * Update to `react-router` 7.0 diff --git a/dev.Dockerfile b/dev.Dockerfile index 53f0ef33..7c97f058 100644 --- a/dev.Dockerfile +++ b/dev.Dockerfile @@ -1,8 +1,15 @@ FROM mcr.microsoft.com/playwright:v1.51.1-noble ENV NODE_VERSION 22.14 +ENV TINI_VERSION v0.19.0 # Install Node.js RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash && \ \. "$HOME/.nvm/nvm.sh" && \ nvm install ${NODE_VERSION} + +# Install tini +ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /sbin/tini +RUN chmod +x /sbin/tini +# Set tini as the entry point, as node does not properly handle signals +ENTRYPOINT ["/sbin/tini", "--"] diff --git a/package-lock.json b/package-lock.json index 117ae8dd..e5003249 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "@shlinkio/data-manipulation": "^1.0.3", "@shlinkio/shlink-frontend-kit": "^0.8.10", "@shlinkio/shlink-js-sdk": "^2.0.0", - "@shlinkio/shlink-web-component": "^0.13.1", + "@shlinkio/shlink-web-component": "^0.13.2", "bootstrap": "5.2.3", "bottlejs": "^2.0.1", "clsx": "^2.1.1", @@ -3444,9 +3444,9 @@ "license": "MIT" }, "node_modules/@shlinkio/shlink-web-component": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@shlinkio/shlink-web-component/-/shlink-web-component-0.13.1.tgz", - "integrity": "sha512-NuEX4Gq3TyzARMVkBJYt7M/io8NgfwDBUEScxD84cw3tuJsZWDP5mTEGGesSTbMHAcENaq06UJvSGjHifGJ8Rg==", + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/@shlinkio/shlink-web-component/-/shlink-web-component-0.13.2.tgz", + "integrity": "sha512-cF8MynPEUYV7Nk3zCGqcVrZeADD8h1FD72o8/16BTbOgQMcKVKXy3e5ybeSMltCoInPIAbp35B7oHPf/awQVOA==", "license": "MIT", "dependencies": { "@formkit/drag-and-drop": "^0.4.2", @@ -3459,11 +3459,12 @@ "date-fns": "^4.1.0", "event-source-polyfill": "^1.0.31", "leaflet": "^1.9.4", - "react-external-link": "^2.4.0", + "qr-code-styling": "^1.9.2", + "react-external-link": "^2.5.0", "react-leaflet": "^4.2.1 || ^5.0", "react-swipeable": "^7.0.2", "react-tag-autocomplete": "^7.5.0", - "recharts": "^2.15.1" + "recharts": "^2.15.2" }, "peerDependencies": { "@fortawesome/fontawesome-svg-core": "^6.4.2", @@ -3472,7 +3473,7 @@ "@fortawesome/free-solid-svg-icons": "^6.4.2", "@fortawesome/react-fontawesome": "^0.2.2", "@reduxjs/toolkit": "^2.5.0", - "@shlinkio/shlink-frontend-kit": "^0.7.2 || ^0.8", + "@shlinkio/shlink-frontend-kit": "^0.8.10", "@shlinkio/shlink-js-sdk": "^2.0.0", "react": "^18.3 || ^19.0", "react-dom": "^18.3 || ^19.0", @@ -3996,15 +3997,15 @@ } }, "node_modules/@types/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", "license": "MIT" }, "node_modules/@types/d3-scale": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", - "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", "license": "MIT", "dependencies": { "@types/d3-time": "*" @@ -8839,6 +8840,24 @@ "node": ">=6" } }, + "node_modules/qr-code-styling": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/qr-code-styling/-/qr-code-styling-1.9.2.tgz", + "integrity": "sha512-RgJaZJ1/RrXJ6N0j7a+pdw3zMBmzZU4VN2dtAZf8ZggCfRB5stEQ3IoDNGaNhYY3nnZKYlYSLl5YkfWN5dPutg==", + "license": "MIT", + "dependencies": { + "qrcode-generator": "^1.4.4" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/qrcode-generator": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/qrcode-generator/-/qrcode-generator-1.4.4.tgz", + "integrity": "sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw==", + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -9074,9 +9093,9 @@ } }, "node_modules/recharts": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.1.tgz", - "integrity": "sha512-v8PUTUlyiDe56qUj82w/EDVuzEFXwEHp9/xOowGAZwfLjB9uAy3GllQVIYMWF6nU+qibx85WF75zD7AjqoT54Q==", + "version": "2.15.2", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.2.tgz", + "integrity": "sha512-xv9lVztv3ingk7V3Jf05wfAZbM9Q2umJzu5t/cfnAK7LUslNrGT7LPBr74G+ok8kSCeFMaePmWMg0rcYOnczTw==", "license": "MIT", "dependencies": { "clsx": "^2.0.0", @@ -13524,9 +13543,9 @@ "integrity": "sha512-+HOZlMTPe0EKE9uNlXe2EuAoQK3EmHUv0zvkN9oZvVkBCXR5FLfDKSab74xj9SJ6qgrd0JDvpxBVmFPKWoiNPg==" }, "@shlinkio/shlink-web-component": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@shlinkio/shlink-web-component/-/shlink-web-component-0.13.1.tgz", - "integrity": "sha512-NuEX4Gq3TyzARMVkBJYt7M/io8NgfwDBUEScxD84cw3tuJsZWDP5mTEGGesSTbMHAcENaq06UJvSGjHifGJ8Rg==", + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/@shlinkio/shlink-web-component/-/shlink-web-component-0.13.2.tgz", + "integrity": "sha512-cF8MynPEUYV7Nk3zCGqcVrZeADD8h1FD72o8/16BTbOgQMcKVKXy3e5ybeSMltCoInPIAbp35B7oHPf/awQVOA==", "requires": { "@formkit/drag-and-drop": "^0.4.2", "@json2csv/plainjs": "^7.0.6", @@ -13538,11 +13557,12 @@ "date-fns": "^4.1.0", "event-source-polyfill": "^1.0.31", "leaflet": "^1.9.4", - "react-external-link": "^2.4.0", + "qr-code-styling": "^1.9.2", + "react-external-link": "^2.5.0", "react-leaflet": "^4.2.1 || ^5.0", "react-swipeable": "^7.0.2", "react-tag-autocomplete": "^7.5.0", - "recharts": "^2.15.1" + "recharts": "^2.15.2" } }, "@streamparser/json": { @@ -13874,14 +13894,14 @@ } }, "@types/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==" }, "@types/d3-scale": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", - "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", "requires": { "@types/d3-time": "*" } @@ -17152,6 +17172,19 @@ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true }, + "qr-code-styling": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/qr-code-styling/-/qr-code-styling-1.9.2.tgz", + "integrity": "sha512-RgJaZJ1/RrXJ6N0j7a+pdw3zMBmzZU4VN2dtAZf8ZggCfRB5stEQ3IoDNGaNhYY3nnZKYlYSLl5YkfWN5dPutg==", + "requires": { + "qrcode-generator": "^1.4.4" + } + }, + "qrcode-generator": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/qrcode-generator/-/qrcode-generator-1.4.4.tgz", + "integrity": "sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw==" + }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -17292,9 +17325,9 @@ "dev": true }, "recharts": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.1.tgz", - "integrity": "sha512-v8PUTUlyiDe56qUj82w/EDVuzEFXwEHp9/xOowGAZwfLjB9uAy3GllQVIYMWF6nU+qibx85WF75zD7AjqoT54Q==", + "version": "2.15.2", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.2.tgz", + "integrity": "sha512-xv9lVztv3ingk7V3Jf05wfAZbM9Q2umJzu5t/cfnAK7LUslNrGT7LPBr74G+ok8kSCeFMaePmWMg0rcYOnczTw==", "requires": { "clsx": "^2.0.0", "eventemitter3": "^4.0.1", diff --git a/package.json b/package.json index b8432dd8..95bd63e2 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "@shlinkio/data-manipulation": "^1.0.3", "@shlinkio/shlink-frontend-kit": "^0.8.10", "@shlinkio/shlink-js-sdk": "^2.0.0", - "@shlinkio/shlink-web-component": "^0.13.1", + "@shlinkio/shlink-web-component": "^0.13.2", "bootstrap": "5.2.3", "bottlejs": "^2.0.1", "clsx": "^2.1.1", diff --git a/src/tailwind.css b/src/tailwind.css index d241616d..ca6ffb15 100644 --- a/src/tailwind.css +++ b/src/tailwind.css @@ -2,6 +2,15 @@ @source '../node_modules/@shlinkio/shlink-frontend-kit'; @import '@shlinkio/shlink-frontend-kit/tailwind.preset.css'; +@theme { + /* Override breakpoints with the values from bootstrap, to keep sizing until fully migrated */ + --breakpoint-sm: 576px; + --breakpoint-md: 768px; + --breakpoint-lg: 992px; + --breakpoint-xl: 1200px; + --breakpoint-2xl: 1400px; +} + @layer base { :root { --header-height: 56px;