Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions resources/tools/qr-generator.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#qr-generator-controls {
width: fit-content;
}

#qr-generator--btn {
display: block;
margin: auto;
margin-top: 20px;
}

#qr-generator--target {
margin-left: 20px;
width: 500px;
padding: 5px;
}

#qr-generator-output {
margin-top: 20px;
}
102 changes: 102 additions & 0 deletions resources/tools/qr-generator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
const makeQRImg = ( data ) => {
const img = document.createElement( 'img' );
// Figure out size
let size = '250x250';
if ( data.length > 400 ) {
size = '500x500';
} else if ( data.length > 200 ) {
size = '300x300';
}
img.setAttribute(
'src',
'https://api.qrserver.com/v1/create-qr-code/?size=' + size + '&data=' + encodeURIComponent( data )
);
return img;
}

/**
* Return the overall <div> that holds the elements
*/
const makeControls = () => {
const wrapper = document.createElement( 'div' );
wrapper.setAttribute( 'id', 'qr-generator-controls' );

const targetLabel = document.createElement( 'label' );
targetLabel.setAttribute( 'for', 'qr-generator--target' );
targetLabel.innerText = 'Target URL:';
wrapper.append( targetLabel );

const targetElem = document.createElement( 'input' );
targetElem.setAttribute( 'type', 'text' );
targetElem.setAttribute( 'id', 'qr-generator--target' );

wrapper.append( targetElem );

const generateBtn = document.createElement( 'button' );
generateBtn.setAttribute( 'id', 'qr-generator--btn' );
generateBtn.innerText = 'Generate';

const emitGeneration = () => {
const newEvent = new CustomEvent(
'do-generate',
{
detail: {
url: targetElem.value
}
}
);
wrapper.dispatchEvent( newEvent );
};

generateBtn.addEventListener( 'click', emitGeneration );

// Listen to the enter key
targetElem.addEventListener(
'keypress' ,
( e ) => {
if ( e.key === 'Enter' ) {
emitGeneration();
}
}
);

wrapper.append( generateBtn );

return wrapper;
};

const onLoad = () => {
// Popup to avoid accidental reloads
window.onbeforeunload = () => false;

const target = document.getElementById( 'tool-target' );

const controls = makeControls();
target.append( controls );

const outputElem = document.createElement( 'div' );
outputElem.setAttribute( 'id', 'qr-generator-output' );
target.append( outputElem );

const downloadNote = document.createElement( 'p' );
downloadNote.innerText = 'To download, right click on the image and save the image.';
downloadNote.innerText += 'You can submit a new URL to generate a new QR code.'

const downloadNoteHolder = document.createElement( 'div' );
target.append( downloadNoteHolder );

controls.addEventListener(
'do-generate',
( e ) => {
// console.log( e );
// So that a new URL clears the existing image while waiting
outputElem.replaceChildren();
outputElem.replaceChildren( makeQRImg( e.detail.url ) )
if ( downloadNoteHolder.children.length === 0 ) {
downloadNoteHolder.append( downloadNote );
}
}
);
};

document.addEventListener( 'DOMContentLoaded', onLoad );
1 change: 1 addition & 0 deletions src/Pages/ToolPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class ToolPage extends BasePage {
private const TOOL_MAPPING = [
'countdown' => true,
'dvorak' => true,
'qr-generator' => true,
];

public function __construct( array $params ) {
Expand Down
2 changes: 1 addition & 1 deletion tests/data/tools-index.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<!DOCTYPE html>
<html lang="en"><head><link rel="icon" href="data:,"><meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1"><link rel="stylesheet" type="text/css" href="/resources/default-styles.css"><title>Tools</title></head><body><div class="des-navbar"><a href="/Home">Home</a><a href="/files/Resume.pdf">Résumé</a><a href="/OpenSource">Open Source</a><a href="/Work">Work</a><a href="/Blog">Blog</a></div><div class="content-wrapper"><h1>Known tools</h1><ul><li><a href="/Tools/countdown">countdown</a></li><li><a href="/Tools/dvorak">dvorak</a></li></ul><p>These are just some JavaScript utilities for Daniel, though anyone who wants to
<html lang="en"><head><link rel="icon" href="data:,"><meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1"><link rel="stylesheet" type="text/css" href="/resources/default-styles.css"><title>Tools</title></head><body><div class="des-navbar"><a href="/Home">Home</a><a href="/files/Resume.pdf">Résumé</a><a href="/OpenSource">Open Source</a><a href="/Work">Work</a><a href="/Blog">Blog</a></div><div class="content-wrapper"><h1>Known tools</h1><ul><li><a href="/Tools/countdown">countdown</a></li><li><a href="/Tools/dvorak">dvorak</a></li><li><a href="/Tools/qr-generator">qr-generator</a></li></ul><p>These are just some JavaScript utilities for Daniel, though anyone who wants to
is obviously free to use them.</p></div><div class="des-footer"><div class="des-footer--content">Content is © 2025 Daniel Scherzer</div></div></body></html>
2 changes: 1 addition & 1 deletion tests/data/tools-missing.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<!DOCTYPE html>
<html lang="en"><head><link rel="icon" href="data:,"><meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1"><link rel="stylesheet" type="text/css" href="/resources/default-styles.css"><title>Tools</title><link rel="stylesheet" type="text/css" href="/resources/error-styles.css"></head><body><div class="des-navbar"><a href="/Home">Home</a><a href="/files/Resume.pdf">Résumé</a><a href="/OpenSource">Open Source</a><a href="/Work">Work</a><a href="/Blog">Blog</a></div><div class="content-wrapper"><div class="error-box"><h1>Error</h1><p>The requested tool `missing` is not recognized</p></div><h1>Known tools</h1><ul><li><a href="/Tools/countdown">countdown</a></li><li><a href="/Tools/dvorak">dvorak</a></li></ul><p>These are just some JavaScript utilities for Daniel, though anyone who wants to
<html lang="en"><head><link rel="icon" href="data:,"><meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1"><link rel="stylesheet" type="text/css" href="/resources/default-styles.css"><title>Tools</title><link rel="stylesheet" type="text/css" href="/resources/error-styles.css"></head><body><div class="des-navbar"><a href="/Home">Home</a><a href="/files/Resume.pdf">Résumé</a><a href="/OpenSource">Open Source</a><a href="/Work">Work</a><a href="/Blog">Blog</a></div><div class="content-wrapper"><div class="error-box"><h1>Error</h1><p>The requested tool `missing` is not recognized</p></div><h1>Known tools</h1><ul><li><a href="/Tools/countdown">countdown</a></li><li><a href="/Tools/dvorak">dvorak</a></li><li><a href="/Tools/qr-generator">qr-generator</a></li></ul><p>These are just some JavaScript utilities for Daniel, though anyone who wants to
is obviously free to use them.</p></div><div class="des-footer"><div class="des-footer--content">Content is © 2025 Daniel Scherzer</div></div></body></html>