feat(demo): Open permalink button and restore params from URL (#311)

pull/312/head
Jonah Lawrence 2 months ago committed by GitHub
parent d0db5c8262
commit 2df85256ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -49,7 +49,7 @@
<form class="parameters three-columns lines"> <form class="parameters three-columns lines">
<!-- Lines are added in JavaScript --> <!-- Lines are added in JavaScript -->
</form> </form>
<button class="add-line btn" onclick="return preview.addLine();">+ Add line</button> <button class="add-line btn" onclick="return preview.addLines(1);">+ Add line</button>
<h2>Options</h2> <h2>Options</h2>
<form class="parameters two-columns options"> <form class="parameters two-columns options">
@ -131,6 +131,8 @@
</span> </span>
<input type="button" class="btn" value="Reset" onclick="preview.reset();"> <input type="button" class="btn" value="Reset" onclick="preview.reset();">
<button type="button" class="copy-button btn tooltip" onclick="clipboard.copyPermalink(this);" onmouseout="tooltip.reset(this);" disabled>Copy Permalink</button>
</form> </form>
</div> </div>
@ -152,7 +154,7 @@
<code></code> <code></code>
</div> </div>
<button class="copy-button btn tooltip" onclick="clipboard.copy(this);" onmouseout="tooltip.reset(this);" disabled> <button class="copy-button btn tooltip" onclick="clipboard.copyCode(this);" onmouseout="tooltip.reset(this);" disabled>
Copy To Clipboard Copy To Clipboard
</button> </button>
</div> </div>
@ -163,7 +165,7 @@
<code></code> <code></code>
</div> </div>
<button class="copy-button btn tooltip" onclick="clipboard.copy(this);" onmouseout="tooltip.reset(this);" disabled> <button class="copy-button btn tooltip" onclick="clipboard.copyCode(this);" onmouseout="tooltip.reset(this);" disabled>
Copy To Clipboard Copy To Clipboard
</button> </button>
</div> </div>

@ -1,5 +1,5 @@
const preview = { const preview = {
// default values // default values for Readme Typing SVG parameters
defaults: { defaults: {
font: "monospace", font: "monospace",
weight: "400", weight: "400",
@ -18,6 +18,12 @@ const preview = {
random: "false", random: "false",
separator: ";", separator: ";",
}, },
// input field initial values that differ from the defaults
overrides: {
font: "Fira Code",
pause: "1000",
width: "435",
},
// dummy text for default line values // dummy text for default line values
dummyText: [ dummyText: [
"The five boxing wizards jump quickly", "The five boxing wizards jump quickly",
@ -30,11 +36,11 @@ const preview = {
], ],
/** /**
* Update the preview image and markdown * Get the current parameters from the form
* @returns {object} The current parameters
*/ */
update() { getParams() {
const copyButtons = document.querySelectorAll(".copy-button"); // get all parameters from the .param fields
// get parameter values from all .param elements
const params = Array.from(document.querySelectorAll(".param:not([data-index])")).reduce((acc, next) => { const params = Array.from(document.querySelectorAll(".param:not([data-index])")).reduce((acc, next) => {
// copy accumulator into local object // copy accumulator into local object
let obj = acc; let obj = acc;
@ -72,14 +78,20 @@ const preview = {
} }
} }
params.lines = mergeLines(lineInputs, params.separator); params.lines = mergeLines(lineInputs, params.separator);
// function to URI encode string but keep semicolons as ';' and spaces as '+' return params;
const encode = (str) => { },
return encodeURIComponent(str).replace(/%3B/g, ";").replace(/%20/g, "+");
}; /**
* Update the preview image and markdown
*/
update() {
const copyButtons = document.querySelectorAll(".copy-button");
// get parameter values
const params = this.getParams();
// convert parameters to query string // convert parameters to query string
const query = Object.keys(params) const query = Object.keys(params)
.filter((key) => params[key] !== this.defaults[key]) // skip if default value .filter((key) => params[key] !== this.defaults[key]) // skip if default value
.map((key) => encode(key) + "=" + encode(params[key])) // encode keys and values .map((key) => this.customEncode(key) + "=" + this.customEncode(params[key])) // encode keys and values
.join("&"); // join lines with '&' delimiter .join("&"); // join lines with '&' delimiter
// generate links and markdown // generate links and markdown
const imageURL = `${window.location.origin}?${query}`; const imageURL = `${window.location.origin}?${query}`;
@ -102,44 +114,58 @@ const preview = {
htmlElement.innerText = html; htmlElement.innerText = html;
// disable copy button if no lines are filled in // disable copy button if no lines are filled in
copyButtons.forEach((el) => (el.disabled = !params.lines.length)); copyButtons.forEach((el) => (el.disabled = !params.lines.length));
// update URL to match parameters
this.openPermalink();
}, },
/** /**
* Add a new line to the input fields * Encode a string for use in a URL but keep semicolons as ';' and spaces as '+'
* @param {string} str The string to encode
* @returns The encoded string
*/
customEncode(str) {
return encodeURIComponent(str).replace(/%3B/g, ";").replace(/%20/g, "+");
},
/**
* Add new line input fields
* @param {number} count The number of lines to add
* @returns {false} Always returns false to prevent form submission * @returns {false} Always returns false to prevent form submission
*/ */
addLine() { addLines(count) {
const parent = document.querySelector(".lines"); for (let i = 0; i < count; i++) {
const index = parent.querySelectorAll("input").length + 1; const parent = document.querySelector(".lines");
// label const index = parent.querySelectorAll("input").length + 1;
const label = document.createElement("label"); // label
label.innerText = `Line ${index}`; const label = document.createElement("label");
label.setAttribute("for", `line-${index}`); label.innerText = `Line ${index}`;
label.dataset.index = index; label.setAttribute("for", `line-${index}`);
// line input box label.dataset.index = index;
const input = document.createElement("input"); // line input box
input.className = "param"; const input = document.createElement("input");
input.type = "text"; input.className = "param";
input.id = `line-${index}`; input.type = "text";
input.name = `line-${index}`; input.id = `line-${index}`;
input.placeholder = "Enter text here"; input.name = `line-${index}`;
input.value = this.dummyText[(index - 1) % this.dummyText.length]; input.placeholder = "Enter text here";
input.dataset.index = index; input.value = this.dummyText[(index - 1) % this.dummyText.length];
// removal button input.dataset.index = index;
const deleteButton = document.createElement("button"); // removal button
deleteButton.className = "delete-line btn"; const deleteButton = document.createElement("button");
deleteButton.setAttribute("onclick", "return preview.removeLine(this.dataset.index);"); deleteButton.className = "delete-line btn";
deleteButton.innerHTML = deleteButton.setAttribute("onclick", "return preview.removeLine(this.dataset.index);");
'<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 1024 1024" height="0.85em" width="0.85em" xmlns="http://www.w3.org/2000/svg"> <path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"> </path> </svg>'; deleteButton.innerHTML =
deleteButton.dataset.index = index; '<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 1024 1024" height="0.85em" width="0.85em" xmlns="http://www.w3.org/2000/svg"> <path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"> </path> </svg>';
deleteButton.dataset.index = index;
// add elements // add elements
parent.appendChild(label); parent.appendChild(label);
parent.appendChild(input); parent.appendChild(input);
parent.appendChild(deleteButton); parent.appendChild(deleteButton);
// disable button if only 1 // disable button if only 1
parent.querySelector(".delete-line.btn").disabled = index == 1; parent.querySelector(".delete-line.btn").disabled = index == 1;
}
// update and exit // update and exit
this.update(); this.update();
@ -147,7 +173,7 @@ const preview = {
}, },
/** /**
* Remove a line from the input fields * Remove a line input field
* @param {number} index The index of the line to remove * @param {number} index The index of the line to remove
* @returns {false} Always returns false to prevent form submission * @returns {false} Always returns false to prevent form submission
*/ */
@ -192,19 +218,14 @@ const preview = {
}, },
/** /**
* Reset all input fields to default values * Reset all input fields to their initial values
* @returns {false} Always returns false to prevent form submission * @returns {false} Always returns false to prevent form submission
*/ */
reset() { reset() {
const overrides = {
font: "Fira Code",
pause: "1000",
width: "435",
};
// reset all inputs // reset all inputs
const inputs = document.querySelectorAll(".param"); const inputs = document.querySelectorAll(".param");
inputs.forEach((input) => { inputs.forEach((input) => {
let value = overrides[input.name] || this.defaults[input.name]; let value = this.overrides[input.name] || this.defaults[input.name];
if (value) { if (value) {
if (["color", "background"].includes(input.name)) { if (["color", "background"].includes(input.name)) {
input.jscolor.fromString(value); input.jscolor.fromString(value);
@ -214,20 +235,89 @@ const preview = {
} }
}); });
}, },
/**
* Get the current parameters in a permalink format
* @returns {string} The permalink URL
*/
getPermalink() {
// get parameters from form
const params = this.getParams();
// convert parameters to query string
const defaultInputs = { ...this.defaults, ...this.overrides };
defaultInputs.lines = this.dummyText[0];
const query = Object.keys(params)
.filter((key) => params[key] !== defaultInputs[key]) // skip if default value
.map((key) => this.customEncode(key) + "=" + this.customEncode(params[key])) // encode keys and values
.join("&"); // join lines with '&' delimiter
// return permalink
return `${window.location.origin}${window.location.pathname}` + (query ? `?${query}` : "");
},
/**
* Save the current parameters to the URL
*/
openPermalink() {
window.history.replaceState({}, "", this.getPermalink());
},
/**
* Restore the last saved parameters from the URL
*/
restore() {
// get parameters from URL
const urlParams = new URLSearchParams(window.location.search);
const params = { ...this.defaults, ...this.overrides, ...Object.fromEntries(urlParams) };
// set all parameters
const inputs = document.querySelectorAll(".param");
inputs.forEach((input) => {
let value = params[input.name];
if (value) {
if (["color", "background"].includes(input.name)) {
input.jscolor.fromString(value);
} else {
input.value = value;
}
}
});
// add lines
const lines = params.lines || this.dummyText[0];
const lineInputs = lines.split(params.separator);
this.addLines(lineInputs.length);
lineInputs.forEach((line, index) => {
document.querySelector(`#line-${index + 1}`).value = line;
});
},
}; };
const clipboard = { const clipboard = {
/** /**
* Copy the text from a code block to the clipboard * Copy text to the clipboard
* @param {HTMLElement} el The element that was clicked * @param {HTMLElement} btn The element that was clicked
* @param {String} text The text to copy
*/ */
copy(el) { copy(btn, text) {
const textToCopy = el.parentElement.querySelector("code").innerText; navigator.clipboard.writeText(text).then(() => {
navigator.clipboard.writeText(textToCopy).then(() => {
// set tooltip text // set tooltip text
el.title = "Copied!"; btn.title = "Copied!";
}); });
}, },
/**
* Copy the text from a code block to the clipboard
* @param {HTMLElement} btn The element that was clicked
*/
copyCode(btn) {
this.copy(btn, btn.parentElement.querySelector("code").innerText);
},
/**
* Copy the permalink to the clipboard
* @param {HTMLElement} btn The element that was clicked
*/
copyPermalink(btn) {
this.copy(btn, preview.getPermalink());
},
}; };
const tooltip = { const tooltip = {
@ -255,9 +345,8 @@ document.querySelector(".show-border input").addEventListener("change", function
window.addEventListener( window.addEventListener(
"load", "load",
() => { () => {
// add first line preview.restore(); // restore parameters
preview.addLine(); preview.update(); // update preview
preview.update();
}, },
false false
); );

Loading…
Cancel
Save