diff --git a/esbuild-helper/copy-file-plugin.js b/esbuild-helper/copy-file-plugin.js new file mode 100644 index 0000000..64b1b27 --- /dev/null +++ b/esbuild-helper/copy-file-plugin.js @@ -0,0 +1,16 @@ +import fs from "fs"; + +const copyFilePlugin = (fileSrcPath, fileDestPAth) => ({ + name: "copy-file-plugin", + setup(build) { + build.onEnd(async () => { + try { + fs.copyFileSync(fileSrcPath, fileDestPAth); + } catch (e) { + console.error(`Failed to copy file: ${fileSrcPath}`, e); + } + }); + }, +}); + +export default copyFilePlugin; diff --git a/esbuild.js b/esbuild.js index 9a596dd..8a959bc 100644 --- a/esbuild.js +++ b/esbuild.js @@ -2,6 +2,7 @@ import * as esbuild from "esbuild"; import copyStaticFiles from "esbuild-copy-static-files"; import * as fsExtra from "fs-extra"; import { sentryEsbuildPlugin } from "@sentry/esbuild-plugin"; +import copyFilePlugin from "./esbuild-helper/copy-file-plugin.js"; fsExtra.emptyDirSync("./dist"); @@ -13,6 +14,8 @@ esbuild.build({ sourcemap: true, // Source map needed for sentry to work mainFields: ["module", "main"], plugins: [ + copyFilePlugin("./manifest.json", "./dist/manifest.json"), + copyFilePlugin("./sw.js", "./dist/sw.js"), copyStaticFiles({ src: "./css", dest: "dist/css", diff --git a/html/index.html b/html/index.html index f8f6de9..b397284 100644 --- a/html/index.html +++ b/html/index.html @@ -14,6 +14,7 @@ type="image/png" href="./assets/images/favicon/favicon-48.png" /> +

diff --git a/js/editor.js b/js/editor.js index 3f3e5d8..98752a9 100644 --- a/js/editor.js +++ b/js/editor.js @@ -759,6 +759,28 @@ export async function initSentry() { }); } +export function registerSW() { + try { + if ("serviceWorker" in navigator) { + window.addEventListener("load", () => { + navigator.serviceWorker + .register("../sw.js") + .then((registration) => { + console.log( + "Service Worker registered with scope:", + registration.scope + ); + }) + .catch((error) => { + console.error("Service Worker registration failed:", error); + }); + }); + } + } catch (error) { + console.error("Service Worker registration failed:", error); + } +} + export async function init() { initSentry(); setupDocument(); @@ -770,4 +792,5 @@ export async function init() { setupListeners(); evaluate(editor.innerText); updateOutputDisplay(output); + registerSW(); } diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..2a967c6 --- /dev/null +++ b/manifest.json @@ -0,0 +1,31 @@ +{ + "name": "Type to Calculate", + "short_name": "Type to Calculate", + + "icons": [ + { + "src": "/assets/images/favicon/favicon-16.png", + "sizes": "16x16", + "type": "image/png" + }, + { + "src": "/assets/images/favicon/favicon-32.png", + "sizes": "32x32", + "type": "image/png" + }, + { + "src": "/assets/images/favicon/favicon-48.png", + "sizes": "48x48", + "type": "image/png" + }, + { + "src": "/assets/images/favicon/favicon-150.png", + "sizes": "150x150", + "type": "image/png" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#191919", + "background_color": "#7f7f7f" +} diff --git a/sw.js b/sw.js new file mode 100644 index 0000000..e4a0bd9 --- /dev/null +++ b/sw.js @@ -0,0 +1,28 @@ +// sw.js +const CACHE_NAME = "ttc-cache-v1"; +const urlsToCache = [ + "/", + "/index.html", + "css/*.css", + "js/editor.js", + "/favicon-150.png", + "/favicon-48.png", +]; + +// Install the service worker +self.addEventListener("install", (event) => { + event.waitUntil( + caches.open(CACHE_NAME).then((cache) => { + return cache.addAll(urlsToCache); + }) + ); +}); + +// Fetch the cached assets +self.addEventListener("fetch", (event) => { + event.respondWith( + caches.match(event.request).then((response) => { + return response || fetch(event.request); + }) + ); +});