Added preferences and preference management.

This commit adds a few fancy flourishes, including ASCII art and 1337 themes.
This is managed by a few, suitably skinned, form elements, some javascript and
judicious use of the localStorage web API.
This commit is contained in:
Dakota Blair 2020-09-25 20:58:56 -07:00
parent d3ca53795d
commit a0d8ca002d
3 changed files with 262 additions and 17 deletions

View File

@ -4,7 +4,7 @@
<meta charset="UTF-8">
<title>Dakota's tilde.club</title>
<link rel="stylesheet" type="text/css" href="tilde.css" media="screen" />
<script src="tilde.js" async defer crossorigin="anonymous"></script>
<script src="tilde.js" async defer></script>
</head>
<body>
<header>
@ -15,12 +15,14 @@
<li><a href="#bash">Fun bash one liners</a></li>
<li>
<a href="#readings">Readings</a>:
<a href="#2020">2020</a>
<a href="#2019">2019</a>
<a href="#2018">2018</a>
<a href="#2017">2017</a>
<a href="#2016">2016</a>
<a href="#2015">2015</a>
<ul>
<li><a href="#2020">2020</a></li>
<li><a href="#2019">2019</a></li>
<li><a href="#2018">2018</a></li>
<li><a href="#2017">2017</a></li>
<li><a href="#2016">2016</a></li>
<li><a href="#2015">2015</a></li>
</ul>
</li>
</ol>
</header>
@ -28,36 +30,53 @@
<section id="about">
<h1>About</h1>
This is Dakota's tilde.club page.
<h2>Preferences</h2>
<ul id="preferences">
<li>
<input type="checkbox" id="pref-force" />
<label for="pref-force">Force mode</label>
<input type="radio" id="pref-theme-dark" name="pref-theme" value="dark" />
<label for="pref-theme-dark">Dark</label>
<input type="radio" id="pref-theme-light" name="pref-theme" value="light" />
<label for="pref-theme-light">Light</label>
<input type="radio" id="pref-theme-h4x0r" name="pref-theme" value="h4x0r" />
<label for="pref-theme-h4x0r">h4x0r</label>
</li>
<li>
<input type="checkbox" id="pref-ascii" />
<label for="pref-ascii">Intensified ASCII aesthetics.</label>
</li>
</ul>
</section>
<hr />
<section id="bash">
<h1>Fun bash one liners</h1>
<dl>
<dt>Print a few random numbers</dt>
<dd>od -d &lt; /dev/random | awk '{ print $2 }' | head</dd>
</dl>
<dl>
<dt>A simple awk for isolating columns</dt>
<dd>awk '{print $2}'</dd>
<dt>Remove all tab characters</dt>
<dd>tr -d '\t'</dd>
</dl>
<dl>
<dt>Find lines containing literal tabs</dt>
<dd>awk '/\t/'</dd>
<dd>grep -P</dd>
</dl>
<dl>
<dt>Remove all tab characters</dt>
<dd>tr -d '\t'</dd>
</dl>
<dl>
<dt>Join files using a tab separator</dt>
<dd>join -t $'\t' file1 file2</dd>
</dl>
<dl>
<dt>A simple awk for isolating columns</dt>
<dd>awk '{print $2}'</dd>
</dl>
<dl>
<dt>Simple system benchmarks</dt>
<dd>yes | sed '=' | sed '/y/d'</dd>
<dd>time seq -n 1e6</dd>
</dl>
<dl>
<dt>Print a few random numbers</dt>
<dd>od -d &lt; /dev/random | awk '{ print $2 }' | head</dd>
</dl>
<dl>
<dt>What shell am I using?</dt>
<dd>lsof -p $$</dd>

161
tilde.css
View File

@ -1,3 +1,164 @@
/* Default color schemes */
:root {
--bg: #fff;
--fg: #000;
--font-size: 18px;
--link: #00f;
--link-visited: #519;
}
/* Dark mode */
@media (prefers-color-scheme: dark) {
:root {
--bg: #334;
--fg: #fff;
--font-size: 18px;
--link: #0bf;
--link-visited: #b4d;
}
}
/* Other themes */
.dark {
--bg: #334;
--fg: #fff;
--link: #0bf;
--link-visited: #b4d;
}
.h4x0r {
--bg: #000;
--fg: #0f0;
--link: #0ff;
--link-visited: #f0f;
}
.light {
--bg: #fff;
--fg: #000;
--link: #00f;
--link-visited: #519;
}
/* Apply themes */
* {
font-family: monospace;
}
body {
background-color: var(--bg);
color: var(--fg);
font-size: var(--font-size);
}
a {
color: var(--link);
}
a:visited {
color: var(--link-visited);
}
/* ASCII aesthetics */
hr {
border: none;
}
hr:after {
content: "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
}
input[type=checkbox], input[type=radio] {
background-color: var(--bg);
color: var(--fg);
font-size: var(--font-size);
left: -1000px;
margin: 0px;
padding: 0px;
position: relative;
top: -5px;
width: 3ch;
white-space: nowrap;
}
input[type=checkbox]:after, input[type=radio]:after {
left: 1000px;
position: relative;
}
input[type=checkbox]:after {
content: "[ ]";
}
input[type=checkbox]:checked:after {
content: "[x]";
}
input[type=radio]:after {
content: "( )";
}
input[type=radio]:checked:after {
content: "(o)";
}
header, section {
max-width: 80ch;
}
ul#preferences {
padding-inline-start: 0px;
}
/* ASCII aesthetics intensifies */
body.ascii h1 {
position: relative;
}
body.ascii h1:before {
font-size: var(--font-size);
position: absolute;
right: 0ch;
white-space: pre;
}
body.ascii header h1:before {
content: "\
___ ___ ___\A\
/ | / | / - \\\A\
/ /] | / /] | / __ \\\A\
/_____/ /_____/ /_____/\A";
top: calc(-1*var(--font-size));
}
body.ascii #about h1:before {
content: "\
\A\
\A\
\A";
line-height: 1;
top: calc(-1*var(--font-size));
}
body.ascii #bash h1:before {
content: "\
____ ____ ____ ____\A\
||b |||a |||s |||h ||\A\
||__|||__|||__|||__||\A\
|/__\\|/__\\|/__\\|/__\\|\A";
top: calc(-2*var(--font-size));
}
body.ascii #readings h1:before {
content: '\
ooooooooo. .o8 o8o\A\
`888 `Y88. "888 `"`\A\
888 .d88` .ooooo. .oooo. .oooo888 oooo ooo. .oo. .oooooooo .oooo.o\A\
888ooo88P` d88` `88b `P )88b d88` `888 `888 `888P"Y88b 888` `88b d88( "8\A\
888`88b. 888ooo888 .oP"888 888 888 888 888 888 888 888 `"Y88b.\A\
888 `88b. 888 .o d8( 888 888 888 888 888 888 `88bod8P` o. )88b\A\
o888o o888o `Y8bod8P` `Y888""8o `Y8bod88P" o888o o888o o888o `8oooooo. 8""888P`\A\
d" YD\A\
"Y88888P\A';
transform: translateX(20ch) translateY(calc(-3*var(--font-size))) scale(.5);
}

65
tilde.js Normal file
View File

@ -0,0 +1,65 @@
(() => {
/* DOM */
const ascii = document.getElementById('pref-ascii');
const force = document.getElementById('pref-force');
const themeRadios = document.getElementsByName('pref-theme');
const bodyClass = document.body.classList;
/* localStorage management */
const lsn = "~ddb:"; // localStorage namespace
const getPref = (pref) => localStorage.getItem(lsn + pref);
const setPref = (pref, value) => localStorage.setItem(lsn + pref, value);
const getPrefs = () => ({
prefASCII: getPref('ascii') === 'true',
prefForce: getPref('force') === 'true',
prefTheme: getPref('theme') || 'dark',
});
/* Update the state of the document based on client preferences. */
const renderPreferences = () => {
const { prefASCII, prefForce, prefTheme } = getPrefs();
if(prefASCII) {
bodyClass.add('ascii');
ascii.checked = "checked";
}
if(prefForce) {
bodyClass.add(prefTheme);
force.checked = "checked";
}
themeRadios.forEach(radio => {
if(radio.value === prefTheme) {
radio.checked = true;
}
});
};
renderPreferences();
/* ASCII aesthetic intensifies */
ascii.onchange = (evt) => {
const { prefASCII } = getPrefs();
bodyClass.toggle('ascii');
setPref('ascii', (!prefASCII).toString());
};
/* Manage theme forcing behavior */
const themes = Array.from(themeRadios).map(radio => radio.value);
force.onchange = () => {
const { prefForce, prefTheme } = getPrefs();
const nextForce = !prefForce;
themes.forEach(theme => bodyClass.remove(theme));
if (nextForce) {
bodyClass.add(prefTheme);
}
setPref('force', nextForce.toString())
};
/* Manage theme selection */
themeRadios.forEach(radio => radio.onchange = () => {
const { prefForce } = getPrefs();
setPref('theme', radio.value);
if(prefForce) {
themes.forEach(theme => bodyClass.remove(theme));
bodyClass.add(radio.value);
}
});
})()