]> git.ardis.lu - zip-page/commitdiff
Initial commit
authorArdis Lu <ardisglu@gmail.com>
Wed, 27 Sep 2023 06:20:30 +0000 (23:20 -0700)
committerArdis Lu <ardisglu@gmail.com>
Wed, 27 Sep 2023 06:20:30 +0000 (23:20 -0700)
README.md [new file with mode: 0644]
index.html [new file with mode: 0644]

diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..be988a9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,11 @@
+# zip-page
+
+Minimal utility for zipping entire web pages into a URL.
+
+Uses the [Compression Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Compression_Streams_API) for `gzip`.
+
+## Similar projects
+
+- [Netlify Drop](https://app.netlify.com/drop)
+- [Surge](https://surge.sh/)
+- [Instant Preview](https://github.com/kjk/instaprev)
diff --git a/index.html b/index.html
new file mode 100644 (file)
index 0000000..935e2ea
--- /dev/null
@@ -0,0 +1,145 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <link rel="icon" href="data:,">
+  <title>zip-page</title>
+  <script>
+    async function gzipBase64ToText(b64) {
+      const encoded = atob(b64);
+      const buffer = Uint8Array.from(encoded, c => c.charCodeAt(0));
+      const stream = new Blob([buffer]).stream();
+      const decompressed = stream.pipeThrough(new DecompressionStream('gzip'));
+      const text = await new Response(decompressed).text();
+      return text;
+    }
+
+    if (location.hash !== '') {
+      gzipBase64ToText(location.hash.substring(1)).then(html => {
+        document.open();
+        document.write(html);
+        document.close();
+      });
+    }
+  </script>
+  <style>
+    body {
+      font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif;
+      color: hsl(216deg 50% 10%);
+      background: hsl(216deg 50% 95%);
+      block-size: 100dvh;
+      margin: 0;
+    }
+
+    body,
+    form {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+    }
+
+    header,
+    main {
+      display: flex;
+      justify-content: center;
+      inline-size: min(100% - 16px, 720px);
+      margin-inline: auto;
+    }
+
+    form {
+      inline-size: 100%;
+      gap: 16px;
+    }
+
+    textarea,
+    button {
+      padding: 8px;
+      border-radius: 8px;
+      border: 1px solid hsl(216deg 50% 60%);
+      font-size: 1rem;
+    }
+
+    textarea {
+      font-family: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace;
+      box-sizing: border-box;
+      min-inline-size: min(100%, 720px);
+      min-block-size: 40ch;
+      white-space: nowrap;
+    }
+
+    button {
+      inline-size: fit-content;
+      padding: 4px 8px;
+      cursor: pointer;
+    }
+
+    footer {
+      margin-block-start: auto;
+      margin-block-end: 16px;
+    }
+
+    a {
+      text-decoration: none;
+      font-weight: 700;
+      color: hsl(216deg 50% 50%);
+    }
+
+    .visually-hidden {
+      clip: rect(0 0 0 0);
+      clip-path: inset(50%);
+      height: 1px;
+      overflow: hidden;
+      position: absolute;
+      white-space: nowrap;
+      width: 1px;
+    }
+  </style>
+</head>
+
+<body>
+  <header>
+    <h1>zip-page</h1>
+  </header>
+
+  <main>
+    <form>
+      <label for="content" class="visually-hidden">Content</label>
+      <textarea id="content" name="content"></textarea>
+
+      <button>Get zip-page URL</button>
+
+      <label for="url" class="visually-hidden">Zip-page URL</label>
+      <output id="url" name="url"></output>
+    </form>
+  </main>
+
+  <footer>
+    <a href="https://github.com/ardislu/zip-page">GitHub</a>
+  </footer>
+
+  <script type="module">
+    async function textToGzipBase64(text) {
+      const stream = new Blob([text]).stream();
+      const compressed = stream.pipeThrough(new CompressionStream('gzip'));
+      const buffer = new Uint8Array(await new Response(compressed).arrayBuffer());
+      let encoded = '';
+      buffer.forEach(byte => encoded += String.fromCharCode(byte));
+      const b64 = btoa(encoded);
+      return b64;
+    }
+
+    document.querySelector('form').addEventListener('submit', async e => {
+      e.preventDefault();
+
+      const content = new FormData(e.target).get('content');
+      const b64 = await textToGzipBase64(content);
+
+      const url = `${location.origin}/#${b64}`;
+      e.target.elements['url'].innerHTML = `<a href="${url}">${url}</a>`;
+    });
+  </script>
+</body>
+
+</html>
\ No newline at end of file
This page took 0.044747 seconds and 4 git commands to generate.