diff --git a/docs/bitty-menu.js b/docs/bitty-menu.js
new file mode 100644
index 0000000..cdd8b31
--- /dev/null
+++ b/docs/bitty-menu.js
@@ -0,0 +1,174 @@
+class Menu {
+ /**
+ * @constructor
+ */
+ constructor(button) {
+ this.button = button;
+ }
+
+ makeTinyurl() {
+ console.log("url", location.href)
+ location.href='https://tinyurl.com/create.php?url=' + encodeURIComponent(location.href)
+ }
+
+ makeText() {
+ console.log("url", location.href)
+ location.href='imessage:&body=' + encodeURIComponent(location.href)
+ }
+
+ makeQR() {
+
+ }
+ sendEmail() {
+ console.log("url", location.href)
+ location.href='mailto:info@example.com?body=' + encodeURIComponent(location.href)
+ }
+
+ makeToot() {
+ return false;
+ }
+
+ makeTweet() {
+ var url =
+ "https://twitter.com/intent/tweet?url=" + encodeURIComponent(location.href);
+ window.open(url, "_blank");
+ return false;
+ }
+
+ showAbout() {
+ var url = "https://about.bitty.site";
+ window.open(url, "_blank");
+ return false;
+ }
+ 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);
+ }
+
+
+ systemShare( info) {
+ if (!info.url) info = {title:document.title, text:document.title, url:location.href};
+
+ if (navigator.share) {
+ navigator.share(info)
+ .then(() => { console.log('Shared!');})
+ .catch(console.error);
+ } else {
+ copyLink(info)
+ }
+ }
+
+ icons = {
+ "qr": ``,
+ "text": `
+ `,
+ "email": `
+ `,
+ "mastodon": `
+ `,
+ "twitter": `
+ `,
+ }
+
+ selectField(target) {
+ target.select();
+ target.scrollLeft = 0;
+ }
+
+ close() {
+ let menu = document.querySelector("dialog.menu");
+ menu?.close();
+ this.button?.classList.remove("open")
+ }
+ show(info) {
+ let url = location.href;
+ let fullMenu = !info;
+ this.button?.classList.add("open")
+ let urlField = el("input.url", {value:url, readonly:true});
+ urlField.onclick = (e) => this.selectField(urlField);
+ let menu = el("dialog.menu", {onclick: (e) => {
+ if (e.target.tagName == 'DIALOG') {
+ e.target.close();
+ this.button?.classList.remove("open")
+ }
+ }}, el("div.menu-container", {},
+ urlField,
+ el("div.menu-icons",
+ el("div.menu-item", {id: "qrcode", onclick:this.makeQR, innerHTML:this.icons.qr} ),
+ el("div.menu-item", {id: "text", onclick:this.makeText, innerHTML:this.icons.text} ),
+ el("div.menu-item", {id: "email", onclick:this.sendEmail, innerHTML:this.icons.email} ),
+ // el("div.menu-item", {id: "mastodon", onclick:this.tootLink, innerHTML:this.icons.mastodon} ),
+ el("div.menu-item", {id: "twitter", onclick:this.makeTweet, innerHTML:this.icons.twitter} ),
+ ),
+ el("div.menu-item", {onclick:this.copyLink}, "copy"),
+ el("div.menu-item", {onclick:this.systemShare}, "share…"),
+ // el("div.menu-item", {onclick:this.makeTinyurl}, "shorten"),
+ // el("div.menu-item", {onclick:this.makeTinyurl}, "edit…"),
+ fullMenu ? el("hr") : null,
+ fullMenu ? el("div.menu-item", {onclick:this.showAbout}, "itty bitty") : null,
+ )
+ )
+
+ document.body.appendChild(menu)
+
+ if (info) {
+ menu.style.display = "block";
+
+ let x = info.offset.left;
+ let y = info.offset.top;
+ let w = menu.offsetWidth;
+ let h = menu.offsetHeight
+ x -= w / 2;
+ y -= h / 2;
+
+ let overflowX = x + w - window.innerWidth + 8;
+ let overflowY = y + h - window.innerHeight + 8;
+
+
+ if (overflowX > 0) x -= overflowX;
+ if (overflowY > 0) y -= overflowY;
+
+ x = Math.round(Math.max(8, x));
+ y = Math.round(Math.max(8, y));
+
+ menu.style.left = x + "px";
+ menu.style.top = y + "px";
+
+
+ menu.style.removeProperty("display")
+
+ // if (window.innerWidth - info.offset.left > 300) {
+ // menu.style.left = info?.offset.left + "px";
+ // } else {
+ // menu.style.right = (window.innerWidth - info?.offset.right) + "px";
+ // }
+
+ // if (window.innerHeight - info.offset.bottom > 300) {
+ // menu.style.top = info?.offset.bottom + "px";
+ // } else {
+ // menu.style.top = "auto";
+
+ // menu.style.bottom = (window.innerHeight - info?.offset.top) + "px";
+ // }
+ // console.log("info", info, menu, window.innerWidth, window.innerHeight);
+ }
+ menu.showModal()
+ this.selectField(urlField)
+
+ }
+
+}
+
+export {
+ Menu
+};
diff --git a/docs/bitty.js b/docs/bitty.js
index cb224bb..158db60 100644
--- a/docs/bitty.js
+++ b/docs/bitty.js
@@ -1,5 +1,9 @@
const padForBase64 = (s, c = " ") => s.padEnd(s.length + (3 - s.length % 3) % 3, c)
-const HEAD_TAGS = () => btoa(padForBase64('\n'));
+const HEAD_TAGS = (prefixes) => {
+ let tags = ['']
+ prefixes?.split(" ").forEach((p) => tags.push(p.endsWith(".css") ? `` : ``))
+ return btoa(padForBase64(tags.join("\n")));
+};
const HEAD_TAGS_EXTENDED = () => btoa(padForBase64(``));
const dataUrlRE =
@@ -132,8 +136,8 @@ class DataURL {
}
compress = async (format = GZIP_MARKER) => {
- let rawData = this.encoding ? await base64ToByteArray(this.data) : stringToByteArray(this.data);
- let compressedData = await compressData(rawData, format);
+ this.rawData = this.encoding ? await base64ToByteArray(this.data) : stringToByteArray(this.data);
+ let compressedData = await compressData(this.rawData, format);
if (this.params.cipher && this.params._password) {
let encryptedData = await encryptData(this.params.cipher, this.params._password, compressedData);
@@ -262,7 +266,7 @@ async function decompressDataGzip(data) {
async function compressDataGzip(data) {
if (typeof CompressionStream !== 'undefined') {
let blob = new Blob([data])
- const stream = blob.stream().pipeThrough(new CompressionStream("gzip"));
+ const stream = blob.stream().pipeThrough(new CompressionStream("deflate"));
let response = await new Response (stream).arrayBuffer().catch(e => {console.error("CompressionStream error", e)})
if (response) return response
}
diff --git a/docs/index.css b/docs/index.css
index e7ac983..70270e4 100644
--- a/docs/index.css
+++ b/docs/index.css
@@ -3,10 +3,23 @@ body {
margin:0;
}
-@media(prefers-color-scheme: dark){
+:root {
+ --text-color: #16161d;
+ --background-color: white;
+ --shadow-color: var(--text-color);
+ --backdrop-color: red;
+ /* repeating-conic-gradient(rgba(255,255,255,1.0) 0% 25%, transparent 0% 50%) 50% / 4px 4px; */
+}
+@media (prefers-color-scheme: dark) {
+ :root {
+ --text-color:white;
+ --background-color: #16161d;
+ --backdrop: repeating-conic-gradient(rgba(128,128,128,.5) 0% 25%, transparent 0% 50%) 50% / 4px 4px;
+
+ }
body{
- color:white;
- background-color:#121212;
+ color:var(--text-color);
+ background-color:var(--background-color);
}
}
@@ -18,6 +31,48 @@ body {
width: 100%;
height: 100%;
}
+
+
+#menu {
+ width: 48px;
+ height: 48px;
+ top:0;
+ right: 0;
+ position:fixed;
+ z-index:9;
+ border:none;
+ color: #16161d;
+ opacity: .8;
+ border-bottom-left-radius: 0;
+ font-size: 18px;
+ transition: font-size 100ms cubic-bezier(0.4, 0.0, 0.2, 1);;
+ text-align: right;
+}
+
+#menu svg {
+ width: 1em;
+ height: 1em;
+}
+
+#menu.open,
+#menu:hover {
+ color:white;
+ opacity:1.0;
+ font-size: 48px;
+ /* transition: font-size 1000ms ease-in; */
+}
+#menu:hover svg{
+ background:#16161d;
+
+}
+
+#menu:hover svg .inner {
+ fill:white;
+}
+#menu:hover svg .outer {
+ fill:transparent;
+}
+
#edit {
font-family: monospace;
font-weight: bold;
@@ -216,21 +271,22 @@ body:not(.loading) #loader {
}
-dialog {
+.dialog {
border: 2px solid white;
border-radius: 4px;
box-shadow: 0 0 0 2px black, inset 0 0 0 3px black;
- min-width: 320px;
+ min-width: 300px;
padding: 1.2em;
}
-dialog, dialog button {font-size: 18px;font-weight: 600;font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";}
+.dialog, .dialog button {font-size: 18px;font-weight: 600;font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";}
dialog::backdrop {
- background: repeating-conic-gradient(rgba(128,128,128,.5) 0% 25%, transparent 0% 50%) 50% / 4px 4px;
+ background: rgba(255,255,255,0.5);
+ /* repeating-conic-gradient(rgba(255,255,255,.5) 0% 25%, transparent 0% 50%) 50% / 4px 4px; */
}
-dialog button {
+.dialog button {
border: 1px solid white;
border-radius: 9px;
box-shadow: inset 0 0 0 2px black;
@@ -239,13 +295,121 @@ dialog button {
background-color: white;
margin-left:1em;
padding: 0 0.8em;
+ color:currentColor;
}
-dialog button:last-child {
+
+.dialog button:last-child {
box-shadow: 0 0 0 4px black, inset 0 0 0 2px black;
}
-dialog form {
+.dialog form {
text-align: right;
margin-top: 1em;
font-size: 18px;
+}
+
+dialog.menu {
+ top: 48px;
+ right: 0;
+ position: fixed;
+ margin: 0;
+ left: auto;
+ padding:0;
+ bottom: 0;
+ max-width:16em;
+ font-weight:bold;
+ padding-bottom:.8em;
+}
+
+.menu-container {
+ display:flex;
+ flex-direction: column;
+
+}
+
+.menu .url {
+ overflow:hidden;
+ text-overflow:ellipsis;
+ white-space: nowrap;
+ opacity: 0.5;
+ padding: 0.2em 0.8em;
+ width:auto;
+ border: 1.9px solid black;
+ flex: 1 1 auto;
+ margin: 2px;
+ font-size: 16px;
+}
+
+.menu hr {
+ background-color:var(--text-color);
+ height:2px;
+ width: 100%;
+}
+.menu .url:focus {
+}
+.menu .url:focus-within {
+}
+
+.menu .menu-icons {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0;
+ cursor:default;
+}
+
+.menu .menu-icons .menu-item {
+ width: 24px;
+ height: 24px;
+ padding: 12px;
+ /* display:flex; */
+ /* justify-content: center; */
+}
+.menu .menu-icons .menu-item svg{
+ width:2em;
+ height:2em;
+ font-size:12px;
+}
+
+.menu .menu-item {
+ padding: 0.65em 1em;
+ cursor:default;
+}
+
+.menu .menu-item:hover {
+ background-color:black;
+ color:white;
+}
+
+
+
+.menu {
+ /* width: auto; */
+ color: var(--text-color);
+ /* background-color: var(--background-color); */
+ border: 2px solid currentColor;
+ padding: 0.5em 0;
+ box-shadow: 2px 2px var(--shadow-color);
+ margin-right: 2px;
+ border-radius: 2px;
+ margin-top: -2px;
+ z-index: 300;
+ /* top: 100px; */
+ /* text-align: left; */
+ /* float: right; */
+ /* width: 10rem; */
+ position: absolute;
+ /* right: 1rem; */
+ background-color:var(--background-color);
+ }
+
+
+.menu .menu-item {
+ color: var(--text-color);
+ text-decoration: none;
+ line-height: 2em;
+ text-align: left;
+ display: block;
+ padding: 0 1em;
+ cursor: default;
}
\ No newline at end of file
diff --git a/docs/index.html b/docs/index.html
index 0bb0605..042f765 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -4,16 +4,14 @@
-
-
-
-
-
+
+
+
+
-