diff --git a/build-index.sh b/docs/build-v1.sh similarity index 100% rename from build-index.sh rename to docs/build-v1.sh diff --git a/docs/data.js b/docs/data.js index d39516c..ee8ba83 100644 --- a/docs/data.js +++ b/docs/data.js @@ -45,19 +45,16 @@ function decompressDataURI(dataURI, preamble, callback) { function zipToString(data, callback) { var array = base64ToByteArray(data); - if (array[0] == 31) { // Handle Brotli - var script= document.createElement('script'); - script.type = "module" - script.innerHTML = `import {BrotliDecode} from "./js/brotli/decode.js";console.log("yo");window.brotli = BrotliDecode;`; - document.head.appendChild(script); - setTimeout(() => { - return callback((window.brotli(array))); - },100); - return; - - } - - + // if (array[0] == 31) { // Handle Brotli + // var script= document.createElement('script'); + // script.type = "module" + // script.innerHTML = `import {BrotliDecode} from "./js/brotli/decode.js";console.log("yo");window.brotli = BrotliDecode;`; + // document.head.appendChild(script); + // setTimeout(() => { + // return callback((window.brotli(array))); + // },100); + // return; + // } LZMA.decompress(array, function(result, error) { if (!(typeof result === 'string')) result = new Uint8Array(result) diff --git a/docs/index.html b/docs/index.html index 6a24fef..77ba874 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2,9 +2,9 @@ - + - +
itty.bitty is experimental technology that renders linked content from outside sources. Learn more.

This content is only as trustworthy as its source, and it should be treated with the caution diff --git a/docs/legacy.html b/docs/legacy.html deleted file mode 100644 index 7c0b3c1..0000000 --- a/docs/legacy.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - -
itty.bitty is experimental technology that renders linked content from outside sources. Learn more. -

This content is only as trustworthy as its source, and it should be treated with the caution -you would show any insecure web page. -

- -
-edit - diff --git a/docs/v1/base.css b/docs/v1/base.css new file mode 100644 index 0000000..6fe47f3 --- /dev/null +++ b/docs/v1/base.css @@ -0,0 +1 @@ +body{margin:0 auto;padding:12vmin 10vmin;max-width:35em;line-height:1.5em;font-family: -apple-system,BlinkMacSystemFont,sans-serif;word-wrap: break-word;} \ No newline at end of file diff --git a/docs/legacy/data-min.js b/docs/v1/data-min.js similarity index 100% rename from docs/legacy/data-min.js rename to docs/v1/data-min.js diff --git a/docs/legacy/data.js b/docs/v1/data.js similarity index 100% rename from docs/legacy/data.js rename to docs/v1/data.js diff --git a/docs/v1/edit.css b/docs/v1/edit.css new file mode 100644 index 0000000..39fa54d --- /dev/null +++ b/docs/v1/edit.css @@ -0,0 +1,223 @@ +body { + margin: 0 auto; + padding: 12vh 10vmin; + max-width: 35em; + font-family: -apple-system, BlinkMacSystemFont, sans-serif; + line-height: 1.5em; + color: rgba(0, 0, 0, 0.87); +} + +h1 { + font-weight: 400; +} +h2 { + font-weight: 500; +} + +a { + color: #0070e0; +} + +*[contenteditable="true"] { + display: inline-block; +} + +body.loaded:not(.edited) #placeholder { + display: block; +} + +#placeholder { + display: none; + font-style: italic; + color: rgba(0, 0, 0, 0.3); + pointer-events: none; + position: absolute; +} + +body.drag #content { + outline: 3px dashed #ccc; + background-color: #fafafa; + border-radius: 1em; + pointer-events: all; +} + +#content, +#placeholder { + margin: -1em; + padding: 1em; + min-height: 7em; +} + +#content { + width: 100%; + outline: none; +} +#content:focus { + outline-color: #ccc; +} + +#doc-title { + outline: none; + min-width: 180px; + top: 0; + position: absolute; + padding: 0.5em 0; + font-family: monospace; + font-weight: bold; +} + +body.edited #doc-title:empty:before, +#doc-title:focus:empty:before { + content: "untitled"; + color: rgba(0, 0, 0, 0.333); +} + +#doc-title:focus { + border-bottom: 1px solid #ccc; +} + +#doc-title:empty:before { + background: transparent; +} + +#content:empty:before { + content: attr(placeholder); + color: rgba(0, 0, 0, 0.2); + background: transparent; +} +#doc-file { + border-radius: 1em; + background: #ebeff9; + padding: 0.25em 1em; + font-size: smaller; + margin-bottom: 2em; +} +#doc-file:empty { + display: none; +} + +#ib-info { + pointer-events: all; +} +#ib-info:hover { + pointer-events: all; + color: black; +} + +/*#toolbar a#copy { + transition: transform 1s; + cursor: default; +} + +#copy:active { + transform:translate(0, -0.5em); + transition: transform 100ms; + color:red; +} +*/ + +#sharehint { + display: none; + position: fixed; + bottom: 0; + left: 0; + right: 0; + font-family: monospace; + font-weight: bold; + text-align: center; +} +@media only screen and (max-device-width: 480px) { + #twitter, + #copy { + display: none; + } + #sharehint { + display: block; + } + #menu-share-hint { + display: none; + } +} + +#toolbar button { + vertical-align: baseline; + + font-family: monospace; +} + +#toolbar a.invalid { + text-decoration: line-through; +} + +#length { + opacity: 0.54; +} + +/*body.edited #toolbar { + opacity:1.0; + transform: translateY(0); +} +*/ +#toolbar { + position: fixed; + top: 0; + right: 0; + padding: 0.5em 1em; + text-align: right; + font-family: monospace; + font-weight: bold; + /*transform: translateY(-2em);*/ + transition: transform 100ms ease-out; + background-color: white; + border-bottom-left-radius: 1em; + cursor: pointer; +} + +#copy-message { + background: #2d2d2d; + color: white; + top: 0.5em; + right: 0.5em; + position: absolute; + padding: 0.5em 1em; + z-index: 100; + font-family: monospace; + font-weight: bold; +} + +body:not(.copied) #copy-message { + display: none; +} + +#menus-share-hint { + content: "hello"; +} +#toolbar .disabled { + opacity: 0.333; +} +#toolbar a { + margin-left: 0.5em; + cursor: pointer; + text-decoration: none; + color: #333; +} +#toolbar a:hover { + text-decoration: underline; + color: #111; +} + +.menu { + width: auto; + display: none; +} +#toolbar.menu-visible .menu { + display: block; +} + +#toolbar.menu-visible #menu { + opacity: 0.54; +} + +.menu hr { + border: none; +} diff --git a/docs/v1/edit.html b/docs/v1/edit.html new file mode 100644 index 0000000..c4c41ac --- /dev/null +++ b/docs/v1/edit.html @@ -0,0 +1,39 @@ + + + + + +itty.bitty + + + + + + + +
+
+ +
+itty bitty things
+can be conveyed in a link.
+type here – and then share!

about itty bitty
+

+
Link copied to clipboard.
+
+ +  qr code menu + + + + \ No newline at end of file diff --git a/docs/v1/edit.js b/docs/v1/edit.js new file mode 100644 index 0000000..e0e48b1 --- /dev/null +++ b/docs/v1/edit.js @@ -0,0 +1,296 @@ +var QS = document.querySelector.bind(document); +var QSS = document.querySelectorAll.bind(document); + +var DATA_PREFIX = "data:text/html;base64,"; +var DATA_PREFIX_8 = "data:text/html;charset=utf-8;base64,"; +var DATA_PREFIX_BXZE = "data:text/html;charset=utf-8;bxze64,"; + +var b = document.documentElement.setAttribute( + "data-useragent", + navigator.userAgent +); + +var importedFileData = undefined; + +var content = undefined; +window.onload = function() { + window.onpopstate = function(e) { + setContent(e.state); + }; + window.onhashchange = function(e) { + console.log("hash", e); + location.reload(); + }; + document.body.onclick = function(e) { + if (e.target == document.body) content.focus(); + }; + content = document.getElementById("content"); + content.ondragenter = function(e) { + document.body.classList.add("drag"); + }; + content.ondragleave = function(e) { + document.body.classList.remove("drag"); + }; + content.addEventListener("keydown", handleKey); + content.addEventListener("keyup", handleInput); + QS("#doc-title").addEventListener("keyup", handleInput); + content.addEventListener("drop", handleDrop); + content.addEventListener("paste", handlePaste); + content.contentEditable = "true"; + content.focus(); + document.execCommand("selectAll", false, null); + QS("#qrcode").onclick = makeQRCode; + QS("#twitter").onclick = tweetLink; + QS("#copy").onclick = copyLink; + QS("#menu").onclick = toggleMenu; + var hash = window.location.hash.substring(1); + + if (hash.length) { + var slashIndex = hash.indexOf("/"); + var title = hash.substring(0, slashIndex); + if (title.length) + QS("#doc-title").innerText = document.title = decodeURIComponent( + title.replace(/_/g, " ") + ); + hash = hash.substring(slashIndex + 1); + updateLink(hash, title); + if (hash.startsWith("?")) { + hash = hash.substring(1); + zipToString(hash, setContent); + } + } else { + updateBodyClass(); + } +}; + +function setContent(html) { + content.innerHTML = html; + updateBodyClass(); +} + +function setFileName(name) { + QS("#doc-file").innerText = name; + if (name.length) { + setContent(""); + document.body.classList.add("edited"); + } +} + +function updateBodyClass() { + var length = content.innerText.length; + if (length || importedFileData) { + document.body.classList.add("edited"); + } else { + document.body.classList.remove("edited"); + } + document.body.classList.add("loaded"); +} + +function handleDrop(e) { + e.preventDefault(); + if (e.dataTransfer.files) { + var file = e.dataTransfer.files[0]; + var reader = new FileReader(); + reader.addEventListener( + "load", + function() { + var url = reader.result; + url = url.replace(DATA_PREFIX, DATA_PREFIX_8); + compressDataURI(url, function(url2) { + var ratio = url2.length / url.length; + console.log("Compressed to", ratio); + if (e.ctrlKey) + decompressDataURI(url2, undefined, function(url3) { + console.log("Verified", url == url3); + }); + if (ratio > 0.95) url2 = url; + if (e.altKey) url2 = url2.replace(DATA_PREFIX_BXZE, "!"); + + importedFileData = url2; + updateLink(url2, file.name, true); + setFileName("📄" + file.name); + }); + }, + false + ); + reader.readAsDataURL(file); + } + document.body.classList.remove("drag"); +} + +// TODO Command+Shift+T for title (H1), Command+Shift+H for headline (H2), Command+Shift+B for body text (remove any of the above) +function handleKey(e) { + var code = e.which; + var handled = false; + if (e.metaKey && e.altKey) { + handled = true; + if (code == "1".charCodeAt(0)) { + document.execCommand("formatBlock", true, "

"); + } else if (code == "2".charCodeAt(0)) { + document.execCommand("formatBlock", true, "

"); + } else if (code == 220) { + // \ + document.execCommand("removeFormat"); + } else if (code == "0".charCodeAt(0)) { + document.execCommand("formatBlock", true, ""); + } else { + handled = false; + } + } else if (e.metaKey) { + if (code == "K".charCodeAt(0)) { + handled = true; + var url = prompt("Add a link", ""); + if (url) { + document.execCommand("createLink", true, url); + } + } + } + if (handled) e.preventDefault(); +} + +var codepenRE = /(https:\/\/codepen\.io\/[\w]+\/(\w+)\/(\w+))/; +function handlePaste(e) { + var clipboard = window.clipboardData || e.clipboardData; + var text = clipboard.getData("Text") || clipboard.getData("text/plain"); + if ((match = text.match(codepenRE))) { + fetchCodepen(match[0]); + } +} + +var TEMPLATE_MARKER = "/*use-itty-bitty-template*/"; +function fetchCodepen(url) { + var h, c, j; + $.when( + $.get({ url: url + ".html", cache: false }, function(html) { + h = html; + }), + $.get({ url: url + ".css", cache: false }, function(css) { + c = css; + }), + $.get({ url: url + ".js", cache: false }, function(js) { + j = js; + }) + ).then(function() { + var useTemplate = c.indexOf(TEMPLATE_MARKER) >= 0; + var string = + '" + + h + + '"; + stringToZip(string, function(zip) { + setFileName("✒️" + url); + var title = QS("#doc-title").innerText; + setTimeout(function() { + var data = (useTemplate ? "" : DATA_PREFIX_BXZE) + zip; + importedFileData = data; + updateLink(data, title); + }, 300); + }); + }); +} + +function handleInput(e) { + updateBodyClass(); + var text = content.innerText; + var title = QS("#doc-title").innerText; + + var rawHTML = text.indexOf(" 0; + if (rawHTML) { + text = text.replace(/[ |\t]+/g, " ").replace(/> + <"); + } else { + text = content.innerHTML; + } + + if (text.trim().length) { + stringToZip(text, function(zip) { + if (rawHTML) { + updateLink(DATA_PREFIX_BXZE + zip, title); + } else { + updateLink("?" + zip, title); + } + }); + setFileName(""); + } else if (importedFileData) { + updateLink(importedFileData, title); + } else { + updateLink(""); + } +} + +var maxLengths = { + // "#twitter": 4088, + // "#bitly": 2048, + "#qrcode": 2953 +}; + +function updateLink(url, title, push) { + if (title) title = encodeURIComponent(title.trim().replace(/\s/g, "_")); + if (url.length) { + url = "/#" + (title || "") + "/" + url; + } else { + url = "/edit"; + } + var hash = location.hash; + if (push || !hash || !hash.length) { + window.history.pushState(content.innerHTML, null, url); + } else { + window.history.replaceState(content.innerHTML, null, url); + } + var length = location.href.length; + + QS("#length").innerText = length + " bytes"; + QS("#length").href = url; + for (var key in maxLengths) { + var maxLength = maxLengths[key]; + if (length > maxLength) { + QS(key).classList.add("invalid"); + } else { + QS(key).classList.remove("invalid"); + } + } +} + +function makeQRCode() { + var url = + "https://zxing.org/w/chart?cht=qr&chs=548x548&chld=L|1&choe=UTF-8&chl=" + + encodeURIComponent(location.href); + this.href = url; +} + +function toggleMenu() { + QS("#toolbar").classList.toggle("menu-visible"); +} +function copyThenLink() { + copyLink(); + return confirm("Copied your link to the clipboard. Paste it to share."); +} +function copyLink() { + var text = location.href; + var dummy = document.createElement("input"); + document.body.appendChild(dummy); + dummy.value = text; + dummy.select(); + document.execCommand("copy"); + document.body.removeChild(dummy); + + document.body.classList.add("copied"); + setTimeout(function() { + document.body.classList.remove("copied"); + }, 2000); +} + +function saveLink() { + var url = "/" + location.hash; + window.history.pushState(null, null, url); + location.reload(); +} + +function tweetLink() { + var url = + "https://twitter.com/intent/tweet?url=" + encodeURIComponent(location.href); + window.open(url, "_blank"); + return false; +} diff --git a/docs/v1/favicon.ico b/docs/v1/favicon.ico new file mode 100644 index 0000000..08dc97b Binary files /dev/null and b/docs/v1/favicon.ico differ diff --git a/docs/legacy/index-min.css b/docs/v1/index-min.css similarity index 100% rename from docs/legacy/index-min.css rename to docs/v1/index-min.css diff --git a/docs/legacy/index-min.js b/docs/v1/index-min.js similarity index 100% rename from docs/legacy/index-min.js rename to docs/v1/index-min.js diff --git a/docs/legacy/index.css b/docs/v1/index.css similarity index 100% rename from docs/legacy/index.css rename to docs/v1/index.css diff --git a/docs/legacy/index.html b/docs/v1/index.html similarity index 100% rename from docs/legacy/index.html rename to docs/v1/index.html diff --git a/docs/legacy/index.js b/docs/v1/index.js similarity index 100% rename from docs/legacy/index.js rename to docs/v1/index.js diff --git a/docs/legacy/index.src.html b/docs/v1/index.src.html similarity index 100% rename from docs/legacy/index.src.html rename to docs/v1/index.src.html diff --git a/docs/v1/manifest.appcache b/docs/v1/manifest.appcache new file mode 100644 index 0000000..5255e9a --- /dev/null +++ b/docs/v1/manifest.appcache @@ -0,0 +1,2 @@ +CACHE MANIFEST +# v27 \ No newline at end of file