From 7fbf8d8db6082cfce27f7fd7c76e7582e2664d89 Mon Sep 17 00:00:00 2001 From: yayunhuang Date: Fri, 30 Aug 2024 11:43:11 +0800 Subject: [PATCH 1/7] Add toastify-js package --- package-lock.json | 13 +++++++++++++ package.json | 2 ++ 2 files changed, 15 insertions(+) diff --git a/package-lock.json b/package-lock.json index c306f08..13e379a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,11 +18,13 @@ "image-size": "^1.1.1", "jszip": "^3.10.1", "localforage": "^1.10.0", + "toastify-js": "1.12.0", "zod": "^3.21.4" }, "devDependencies": { "@types/file-saver": "^2.0.7", "@types/node": "^20.4.5", + "@types/toastify-js": "1.12.3", "@typescript-eslint/eslint-plugin": "^6.3.0", "@typescript-eslint/parser": "^6.3.0", "eslint": "^8.46.0", @@ -1221,6 +1223,12 @@ "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", "dev": true }, + "node_modules/@types/toastify-js": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/@types/toastify-js/-/toastify-js-1.12.3.tgz", + "integrity": "sha512-9RjLlbAHMSaae/KZNHGv19VG4gcLIm3YjvacCXBtfMfYn26h76YP5oxXI8k26q4iKXCB9LNfv18lsoS0JnFPTg==", + "dev": true + }, "node_modules/@types/unist": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.7.tgz", @@ -8256,6 +8264,11 @@ "node": ">=8.0" } }, + "node_modules/toastify-js": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/toastify-js/-/toastify-js-1.12.0.tgz", + "integrity": "sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ==" + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", diff --git a/package.json b/package.json index 0328495..0ebf341 100644 --- a/package.json +++ b/package.json @@ -23,11 +23,13 @@ "image-size": "^1.1.1", "jszip": "^3.10.1", "localforage": "^1.10.0", + "toastify-js": "1.12.0", "zod": "^3.21.4" }, "devDependencies": { "@types/file-saver": "^2.0.7", "@types/node": "^20.4.5", + "@types/toastify-js": "1.12.3", "@typescript-eslint/eslint-plugin": "^6.3.0", "@typescript-eslint/parser": "^6.3.0", "eslint": "^8.46.0", From 86490f1b9c60ab2843b4af9ebcde9c81089765c4 Mon Sep 17 00:00:00 2001 From: yayunhuang Date: Fri, 30 Aug 2024 13:03:26 +0800 Subject: [PATCH 2/7] Implement toast utils --- src/scripts/utils/toast.ts | 44 ++++++++++++++++++++++++++++++++++++++ src/styles/toast.css | 11 ++++++++++ 2 files changed, 55 insertions(+) create mode 100644 src/scripts/utils/toast.ts create mode 100644 src/styles/toast.css diff --git a/src/scripts/utils/toast.ts b/src/scripts/utils/toast.ts new file mode 100644 index 0000000..b5db9c0 --- /dev/null +++ b/src/scripts/utils/toast.ts @@ -0,0 +1,44 @@ +import StartToastifyInstance from "toastify-js"; +import Toastify from "toastify-js"; +import "../../styles/toast.css"; + +interface ToastOptions extends StartToastifyInstance.Options { + description: string; + title?: string | HTMLElement; +} + +export function showToast(options: ToastOptions) { + const { description, avatar, title } = options; + const toastNode = document.createElement("div"); + const toastHeader = document.createElement("div"); + const toastMessage = document.createElement("div"); + + toastHeader.style.fontWeight = "bold"; + toastHeader.style.fontSize = "20px"; + toastHeader.style.color = "black"; + toastHeader.innerHTML = `
${ + avatar ? `` : "" + }${title}
`; + + toastMessage.innerHTML = description; + toastNode.appendChild(toastHeader); + toastNode.appendChild(toastMessage); + + Toastify({ + node: toastNode, + style: { + display: "flex", + background: "white", + color: "black", + alignItems: "start", + justifyContent: "start", + }, + onClick: function () {}, + duration: 3000, + close: true, + gravity: "top", + position: "center", + stopOnFocus: true, + ...options, + }).showToast(); +} diff --git a/src/styles/toast.css b/src/styles/toast.css new file mode 100644 index 0000000..f905276 --- /dev/null +++ b/src/styles/toast.css @@ -0,0 +1,11 @@ +@import url("toastify-js/src/toastify.css"); + +.toast-close { + color: black !important; +} + +.toast-header { + display: flex; + gap: 12px; + margin-bottom: 8px; +} From 245bef0ab971e6bf4aefa59008e5cc390fdbee0f Mon Sep 17 00:00:00 2001 From: yayunhuang Date: Fri, 30 Aug 2024 13:04:02 +0800 Subject: [PATCH 3/7] Show alert when some mockups generated failure --- src/pages/download/_downloadPythonPackage.js | 38 ++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/pages/download/_downloadPythonPackage.js b/src/pages/download/_downloadPythonPackage.js index 6359d2e..a23d361 100644 --- a/src/pages/download/_downloadPythonPackage.js +++ b/src/pages/download/_downloadPythonPackage.js @@ -1,6 +1,7 @@ import JSZip from "jszip"; import localforage from "localforage"; import { saveAs } from "file-saver"; +import { showToast } from "../../scripts/utils/toast"; async function allStorage() { var values = new Map(), @@ -43,6 +44,35 @@ function getJSZipDateWithOffset() { return dateWithOffset; } +function handlePartialSuccess(failedImages) { + const description = ` +
Image(s) failed to generate. Try a different image/device:
+
    + ${failedImages.map((failedImage) => `
  • ${failedImage}
  • `).join("")} +
+
If the issue persists, please report it on GitHub 🙏
+ https://github.com/oursky/mockuphone.com/issues
+ `; + + showToast({ + title: "Partial Success", + description: description, + avatar: "/images/upload-warning.svg", + }); +} + +function handleNoGeneratedMockup() { + const description = ` +
Try a different image/device.
If the issue persists, please report it on GitHub 🙏
+ https://github.com/oursky/mockuphone.com/issues
+ `; + showToast({ + title: "No generated mockup", + description: description, + avatar: "/images/upload-error.svg", + }); +} + export async function generateZIP(deviceId) { var zip = new JSZip(); var count = 0; @@ -74,4 +104,12 @@ export async function generateZIP(deviceId) { }); } }); + + if (failedImages.length > 0 && images.size > 0) { + handlePartialSuccess(failedImages); + } + + if (images.size === 0) { + handleNoGeneratedMockup(); + } } From 98f259faf2a89f0be7205682496143e6699517ab Mon Sep 17 00:00:00 2001 From: yayunhuang Date: Fri, 30 Aug 2024 13:13:28 +0800 Subject: [PATCH 4/7] Extract downloadGeneratedMOckup --- src/pages/download/_downloadPythonPackage.js | 32 ++++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/pages/download/_downloadPythonPackage.js b/src/pages/download/_downloadPythonPackage.js index a23d361..551081b 100644 --- a/src/pages/download/_downloadPythonPackage.js +++ b/src/pages/download/_downloadPythonPackage.js @@ -73,22 +73,11 @@ function handleNoGeneratedMockup() { }); } -export async function generateZIP(deviceId) { +function downloadGeneratedMockup(deviceId, images) { var zip = new JSZip(); var count = 0; const zipFilename = !!deviceId ? `${deviceId}-mockup.zip` : "mockup.zip"; - var images = new Map(); - var dataurlkey = await allStorage(); - var failedImages = []; - dataurlkey.forEach(function (value, key) { - // Only zip successfully generated mockups - if (value !== null) { - var file = dataURLtoFile(value, key.substring(3, key.length) + ".png"); - images.set(key, URL.createObjectURL(file)); - } else { - failedImages.push(key); - } - }); + images.forEach(async function (imgURL, k) { var filename = unescape(k.substring(3, k.length)) + ".png"; var image = await fetch(imgURL); @@ -104,6 +93,23 @@ export async function generateZIP(deviceId) { }); } }); +} + +export async function generateZIP(deviceId) { + var images = new Map(); + var dataurlkey = await allStorage(); + var failedImages = []; + dataurlkey.forEach(function (value, key) { + // Only zip successfully generated mockups + if (value !== null) { + var file = dataURLtoFile(value, key.substring(3, key.length) + ".png"); + images.set(key, URL.createObjectURL(file)); + } else { + failedImages.push(key); + } + }); + + downloadGeneratedMockup(deviceId, images); if (failedImages.length > 0 && images.size > 0) { handlePartialSuccess(failedImages); From d4a79518fd3e90f78608f7bb9f85a7740e3c22a5 Mon Sep 17 00:00:00 2001 From: yayunhuang Date: Fri, 30 Aug 2024 16:34:37 +0800 Subject: [PATCH 5/7] Move toast related files to src/scripts/utils/toast --- src/pages/download/_downloadPythonPackage.js | 2 +- src/{styles => scripts/utils/toast}/toast.css | 0 src/scripts/utils/{ => toast}/toast.ts | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/{styles => scripts/utils/toast}/toast.css (100%) rename src/scripts/utils/{ => toast}/toast.ts (97%) diff --git a/src/pages/download/_downloadPythonPackage.js b/src/pages/download/_downloadPythonPackage.js index 551081b..6a1ea1e 100644 --- a/src/pages/download/_downloadPythonPackage.js +++ b/src/pages/download/_downloadPythonPackage.js @@ -1,7 +1,7 @@ import JSZip from "jszip"; import localforage from "localforage"; import { saveAs } from "file-saver"; -import { showToast } from "../../scripts/utils/toast"; +import { showToast } from "../../scripts/utils/toast/toast"; async function allStorage() { var values = new Map(), diff --git a/src/styles/toast.css b/src/scripts/utils/toast/toast.css similarity index 100% rename from src/styles/toast.css rename to src/scripts/utils/toast/toast.css diff --git a/src/scripts/utils/toast.ts b/src/scripts/utils/toast/toast.ts similarity index 97% rename from src/scripts/utils/toast.ts rename to src/scripts/utils/toast/toast.ts index b5db9c0..2e40159 100644 --- a/src/scripts/utils/toast.ts +++ b/src/scripts/utils/toast/toast.ts @@ -1,6 +1,6 @@ import StartToastifyInstance from "toastify-js"; import Toastify from "toastify-js"; -import "../../styles/toast.css"; +import "./toast.css"; interface ToastOptions extends StartToastifyInstance.Options { description: string; From 01f3765a8fc6bc6b150deb97f3fb83a0c418d946 Mon Sep 17 00:00:00 2001 From: yayunhuang Date: Fri, 30 Aug 2024 16:43:23 +0800 Subject: [PATCH 6/7] Update toastHeader & move style to css --- src/scripts/utils/toast/toast.css | 3 +++ src/scripts/utils/toast/toast.ts | 12 +++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/scripts/utils/toast/toast.css b/src/scripts/utils/toast/toast.css index f905276..4c53893 100644 --- a/src/scripts/utils/toast/toast.css +++ b/src/scripts/utils/toast/toast.css @@ -8,4 +8,7 @@ display: flex; gap: 12px; margin-bottom: 8px; + font-size: 20px; + font-weight: bold; + color: black; } diff --git a/src/scripts/utils/toast/toast.ts b/src/scripts/utils/toast/toast.ts index 2e40159..2357ed1 100644 --- a/src/scripts/utils/toast/toast.ts +++ b/src/scripts/utils/toast/toast.ts @@ -4,7 +4,7 @@ import "./toast.css"; interface ToastOptions extends StartToastifyInstance.Options { description: string; - title?: string | HTMLElement; + title?: string; } export function showToast(options: ToastOptions) { @@ -13,12 +13,10 @@ export function showToast(options: ToastOptions) { const toastHeader = document.createElement("div"); const toastMessage = document.createElement("div"); - toastHeader.style.fontWeight = "bold"; - toastHeader.style.fontSize = "20px"; - toastHeader.style.color = "black"; - toastHeader.innerHTML = `
${ - avatar ? `` : "" - }${title}
`; + toastHeader.classList.add("toast-header"); + toastHeader.innerHTML = `${avatar ? `` : ""}${ + title ?? "" + }`; toastMessage.innerHTML = description; toastNode.appendChild(toastHeader); From 612dbeae015737ca9eb549acc2d4f19730b320b8 Mon Sep 17 00:00:00 2001 From: yayunhuang Date: Fri, 30 Aug 2024 16:46:50 +0800 Subject: [PATCH 7/7] Use shorter description in alert --- src/pages/download/_downloadPythonPackage.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/pages/download/_downloadPythonPackage.js b/src/pages/download/_downloadPythonPackage.js index 6a1ea1e..0c1e756 100644 --- a/src/pages/download/_downloadPythonPackage.js +++ b/src/pages/download/_downloadPythonPackage.js @@ -50,8 +50,7 @@ function handlePartialSuccess(failedImages) {
    ${failedImages.map((failedImage) => `
  • ${failedImage}
  • `).join("")}
-
If the issue persists, please report it on GitHub 🙏
- https://github.com/oursky/mockuphone.com/issues
+
If the issue persists, please report it on Github
`; showToast({ @@ -63,8 +62,7 @@ function handlePartialSuccess(failedImages) { function handleNoGeneratedMockup() { const description = ` -
Try a different image/device.
If the issue persists, please report it on GitHub 🙏
- https://github.com/oursky/mockuphone.com/issues
+
Try a different image/device.
If the issue persists, please report it on Github
`; showToast({ title: "No generated mockup",