hhl/public/news/website-redesign/index.html

517 lines
23 KiB
HTML
Raw Normal View History

2021-02-19 22:43:36 -05:00
<!DOCTYPE html>
<html lang="en" class="sidebar-visible no-js light">
<head>
<meta charset="utf-8">
<title>Hitch Hiker Linux</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="icon" href="&#x2F;favicon.svg">
<link rel="shortcut icon" href="&#x2F;favicon.png">
<link rel="stylesheet" href="&#x2F;handbook&#x2F;css&#x2F;variables.css">
<link rel="stylesheet" href="&#x2F;handbook&#x2F;css&#x2F;general.css">
<link rel="stylesheet" href="&#x2F;handbook&#x2F;css&#x2F;chrome.css">
<link rel="stylesheet" href="&#x2F;handbook&#x2F;css&#x2F;print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="&#x2F;handbook&#x2F;FontAwesome&#x2F;css&#x2F;font-awesome.css">
<link rel="stylesheet" href="&#x2F;handbook&#x2F;fonts&#x2F;fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="&#x2F;handbook&#x2F;highlight.css">
<link rel="stylesheet" href="&#x2F;handbook&#x2F;tomorrow-night.css">
<link rel="stylesheet" href="&#x2F;handbook&#x2F;ayu-highlight.css">
<!-- Custom Stylesheets -->
<link rel="stylesheet" href="&#x2F;hhl.css">
</head>
<body>
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "&#x2F;handbook";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('no-js')
html.classList.remove('light')
html.classList.add(theme);
html.classList.add('js');
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter">
<li class="chapter-item affix ">
<a href="/">Home</a>
</li>
<li class="chapter-item affix ">
<a href="/news/">News</a>
</li>
<li class="chapter-item affix ">
<a href="/about/">About</a>
</li>
<li class="chapter-item affix ">
<a href="/pub/">Download</a>
</li>
<li class="chapter-item affix ">
<a href="https://git.hitchhiker-linux.org">Source</a>
</li>
<li class="spacer"></li>
<li class="chapter-item affix ">
<a href="/handbook/">Handbook</a>
</li>
</ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky bordered">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
</div>
<h1 class="menu-title">
Hitch Hiker Linux
</h1>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1><a class="header" href="#recent" id="recent">Website Redesign</a></h1>
<p class="subtitle"><strong>2021-02-18</strong></p>
<p>I know a little bit about a lot of things, and one of the things that I know
only in passing is web development.<span id="continue-reading"></span> I am by no means qualified at
or excited about web design. However, in the spirit of DIY I have always muddled
through all of my own projects. This has in the past meant using a CMS of some
sort, and a rather long time ago I settled on Mezzanine, a Django-based CMS
written in Python.</p>
<p>This worked out all right in most ways. However, a few weeks back I had a server
outage that I traced back to the update from Python 3.8 to Python 3.9. The
virtualenv that I had set up simply stopped working, causing the web server to be
unable to start as the default handler was DOA. Now, a Python virtualenv is a
supposedly complete standalone environment containing the Python interpretor and
libraries frozen to be version compatible with your application. It is supposed
to be self contained and not dependent upon the system-wide Python installation.
The fact that bumping a minor version number caused it to fail is distressing
and has soured my already low opinion of Python somewhat.</p>
<p>Additionally, I have long desired to incorporate a full handbook into the website
and do so in a way that looks seemless with the rest of the site. HitchHiker is
not going to be a turnkey system for most people and will need good documentation.
I have tried a few things that were available online, including Mezzanine Wiki,
but nothing is really suitable and many packages are broken and/or unmaintained
(including Mezzanine Wiki at the time I tried it).</p>
<p>Being impressed with the quality of the documentation for Rust I looked into what
they use. The Rust Book is built using <a href="https://github.com/rust-lang/mdBook">mdbook</a>,
which is a wonderful static markdown to html generator that does exaclt what it
claims to do and does it exceptionally well. After messing with it for all of two
minutes I was sold - it's just plain phenominal in use.</p>
<p>Having settled on mdbook for the forthcoming &quot;<strong>Hitch Hiker's Guide to Hitch Hiker
Linux</strong>&quot; I decided that if we're going static pages there, it would be a good
time to go static pages everywhere. I set about looking for a static site generator
that would give me enough flexibility for my needs and still be simple to use.</p>
<p>While there is no shortage of SSG's available right now, there were several popular
ones that I never really considered based on implementation. Jekyll, for one, is
written in Ruby and I'm not looking to pollute my machine with more interpreted
language cruft.</p>
<p>I gave <a href="https://gohugo.io/">Hugo</a> a long, hard look and went so far as to install
it and do some testing. Hugo is written in Go, seems to work well, and is definitely
fast. However, none of the available themes were going to be suitable without a
good deal of hacking.</p>
<p>At first glance, <a href="https://www.getzola.org/">Zola</a> appeared to have the same
strengths and the same issues as Hugo for my use case. I really couldn't see
applying any of the themes that I found directly without a lot of customization,
and there were a couple that I tried that were flat out broken. On top of whatever
customization I was going to have to do to whatever theme I picked, I was also
going to have to adapt to an mdbook theme as well....or was there another way?</p>
<p>It turns out that the default set of themes that ship with mdbook are pretty much
already great, and would look great adapted to an entire site. Now, mdbook itself
is pretty much not suitable for generating the entire site, as I need a front
page, I want to keep my blog, and I'd like to be able to incorporate other pages
as well that aren't going into the table of contents for the book. But what I
thought I could do is to create my own Zola template using the css from the mdbook
themes.</p>
<p>So in the end that's what I did. Zola, written in Rust, is actually quite a bit
simpler than Hugo and after a few initial trip ups getting started I'm finding
the template system to be something I can navigate all right. I'm left with a two
step rendering process to build the full site, as I'm rendering most of the site
using Zola and the book using mdbook. But hey, I've already proven that I can do
a good bit of automation using <code>make</code>, right?</p>
<p>While there's a bit more work left to finish migrating the old site, I have to
say that I'm completely satisfied with my choices as of now. Both Zola and mdbook
do things for me that were not going to be easily achievable in Mezzanine and come
with a lot of benefits right out of the box. As a for instance, built in syntax
highlighting for code snippets! Here's <code>echo</code> in Rust:</p>
<pre style="background-color:#2b303b;">
<code class="language-Rust" data-lang="Rust"><span style="color:#c0c5ce;">#![</span><span style="color:#bf616a;">warn</span><span style="color:#c0c5ce;">(clippy::all, clippy::pedantic)]
</span><span style="color:#b48ead;">use </span><span style="color:#c0c5ce;">std::env;
</span><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span style="color:#c0c5ce;">() {
</span><span style="color:#b48ead;">let</span><span style="color:#c0c5ce;"> args: Vec&lt;String&gt; = env::args().</span><span style="color:#96b5b4;">collect</span><span style="color:#c0c5ce;">();
</span><span style="color:#b48ead;">let</span><span style="color:#c0c5ce;"> len = args.</span><span style="color:#96b5b4;">len</span><span style="color:#c0c5ce;">();
</span><span style="color:#b48ead;">let</span><span style="color:#c0c5ce;"> n = len &gt; </span><span style="color:#d08770;">1 </span><span style="color:#c0c5ce;">&amp;&amp; args[</span><span style="color:#d08770;">1</span><span style="color:#c0c5ce;">] == &quot;</span><span style="color:#a3be8c;">-n</span><span style="color:#c0c5ce;">&quot;;
</span><span style="color:#b48ead;">let</span><span style="color:#c0c5ce;"> i = </span><span style="color:#b48ead;">if</span><span style="color:#c0c5ce;"> n { </span><span style="color:#d08770;">2 </span><span style="color:#c0c5ce;">} </span><span style="color:#b48ead;">else </span><span style="color:#c0c5ce;">{ </span><span style="color:#d08770;">1 </span><span style="color:#c0c5ce;">};
</span><span style="color:#b48ead;">for </span><span style="color:#c0c5ce;">(index, arg) in args.</span><span style="color:#96b5b4;">iter</span><span style="color:#c0c5ce;">().</span><span style="color:#96b5b4;">enumerate</span><span style="color:#c0c5ce;">().</span><span style="color:#96b5b4;">skip</span><span style="color:#c0c5ce;">(i) {
</span><span style="color:#b48ead;">if</span><span style="color:#c0c5ce;"> index &lt; len - </span><span style="color:#d08770;">1 </span><span style="color:#c0c5ce;">{
print!(&quot;</span><span style="color:#d08770;">{} </span><span style="color:#c0c5ce;">&quot;, arg);
} </span><span style="color:#b48ead;">else </span><span style="color:#c0c5ce;">{
print!(&quot;</span><span style="color:#d08770;">{}</span><span style="color:#c0c5ce;">&quot;, arg);
}
}
</span><span style="color:#b48ead;">if </span><span style="color:#c0c5ce;">!n {
println!();
}
}
</span></code></pre>
<hr>
<p class="subtitle"><strong>Tags for this post:</strong></p>
<a class="tags" href="&#x2F;tags&#x2F;site-news&#x2F;">Site News</a>
<a class="tags" href="&#x2F;tags&#x2F;web-programming&#x2F;">Web Programming</a>
<a class="tags" href="&#x2F;tags&#x2F;css&#x2F;">css</a>
<a class="tags" href="&#x2F;tags&#x2F;html&#x2F;">html</a>
<a class="tags" href="&#x2F;tags&#x2F;zola&#x2F;">Zola</a>
<a class="tags" href="&#x2F;tags&#x2F;mdbook&#x2F;">mdbook</a>
</main>
</div>
</div>
</div>
<script>
(function themes() {
var html = document.querySelector('html');
var themeToggleButton = document.getElementById('theme-toggle');
var themePopup = document.getElementById('theme-list');
var themeColorMetaTag = document.querySelector('meta[name="theme-color"]');
var stylesheets = {
ayuHighlight: document.querySelector("[href$='ayu-highlight.css']"),
tomorrowNight: document.querySelector("[href$='tomorrow-night.css']"),
highlight: document.querySelector("[href$='highlight.css']"),
};
function showThemes() {
themePopup.style.display = 'block';
themeToggleButton.setAttribute('aria-expanded', true);
themePopup.querySelector("button#" + get_theme()).focus();
}
function hideThemes() {
themePopup.style.display = 'none';
themeToggleButton.setAttribute('aria-expanded', false);
themeToggleButton.focus();
}
function get_theme() {
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch (e) { }
if (theme === null || theme === undefined) {
return default_theme;
} else {
return theme;
}
}
function set_theme(theme, store = true) {
let ace_theme;
if (theme == 'coal' || theme == 'navy') {
stylesheets.ayuHighlight.disabled = true;
stylesheets.tomorrowNight.disabled = false;
stylesheets.highlight.disabled = true;
ace_theme = "ace/theme/tomorrow_night";
} else if (theme == 'ayu') {
stylesheets.ayuHighlight.disabled = false;
stylesheets.tomorrowNight.disabled = true;
stylesheets.highlight.disabled = true;
ace_theme = "ace/theme/tomorrow_night";
} else {
stylesheets.ayuHighlight.disabled = true;
stylesheets.tomorrowNight.disabled = true;
stylesheets.highlight.disabled = false;
ace_theme = "ace/theme/dawn";
}
setTimeout(function () {
themeColorMetaTag.content = getComputedStyle(document.body).backgroundColor;
}, 1);
if (window.ace && window.editors) {
window.editors.forEach(function (editor) {
editor.setTheme(ace_theme);
});
}
var previousTheme = get_theme();
if (store) {
try { localStorage.setItem('mdbook-theme', theme); } catch (e) { }
}
html.classList.remove(previousTheme);
html.classList.add(theme);
}
// Set theme
var theme = get_theme();
set_theme(theme, false);
themeToggleButton.addEventListener('click', function () {
if (themePopup.style.display === 'block') {
hideThemes();
} else {
showThemes();
}
});
themePopup.addEventListener('click', function (e) {
var theme = e.target.id || e.target.parentElement.id;
set_theme(theme);
});
themePopup.addEventListener('focusout', function(e) {
// e.relatedTarget is null in Safari and Firefox on macOS (see workaround below)
if (!!e.relatedTarget && !themeToggleButton.contains(e.relatedTarget) && !themePopup.contains(e.relatedTarget)) {
hideThemes();
}
});
// Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628
document.addEventListener('click', function(e) {
if (themePopup.style.display === 'block' && !themeToggleButton.contains(e.target) && !themePopup.contains(e.target)) {
hideThemes();
}
});
document.addEventListener('keydown', function (e) {
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
if (!themePopup.contains(e.target)) { return; }
switch (e.key) {
case 'Escape':
e.preventDefault();
hideThemes();
break;
case 'ArrowUp':
e.preventDefault();
var li = document.activeElement.parentElement;
if (li && li.previousElementSibling) {
li.previousElementSibling.querySelector('button').focus();
}
break;
case 'ArrowDown':
e.preventDefault();
var li = document.activeElement.parentElement;
if (li && li.nextElementSibling) {
li.nextElementSibling.querySelector('button').focus();
}
break;
case 'Home':
e.preventDefault();
themePopup.querySelector('li:first-child button').focus();
break;
case 'End':
e.preventDefault();
themePopup.querySelector('li:last-child button').focus();
break;
}
});
})();
(function sidebar() {
var html = document.querySelector("html");
var sidebar = document.getElementById("sidebar");
var sidebarLinks = document.querySelectorAll('#sidebar a');
var sidebarToggleButton = document.getElementById("sidebar-toggle");
var sidebarResizeHandle = document.getElementById("sidebar-resize-handle");
var firstContact = null;
function showSidebar() {
html.classList.remove('sidebar-hidden')
html.classList.add('sidebar-visible');
Array.from(sidebarLinks).forEach(function (link) {
link.setAttribute('tabIndex', 0);
});
sidebarToggleButton.setAttribute('aria-expanded', true);
sidebar.setAttribute('aria-hidden', false);
try { localStorage.setItem('mdbook-sidebar', 'visible'); } catch (e) { }
}
var sidebarAnchorToggles = document.querySelectorAll('#sidebar a.toggle');
function toggleSection(ev) {
ev.currentTarget.parentElement.classList.toggle('expanded');
}
Array.from(sidebarAnchorToggles).forEach(function (el) {
el.addEventListener('click', toggleSection);
});
function hideSidebar() {
html.classList.remove('sidebar-visible')
html.classList.add('sidebar-hidden');
Array.from(sidebarLinks).forEach(function (link) {
link.setAttribute('tabIndex', -1);
});
sidebarToggleButton.setAttribute('aria-expanded', false);
sidebar.setAttribute('aria-hidden', true);
try { localStorage.setItem('mdbook-sidebar', 'hidden'); } catch (e) { }
}
// Toggle sidebar
sidebarToggleButton.addEventListener('click', function sidebarToggle() {
if (html.classList.contains("sidebar-hidden")) {
var current_width = parseInt(
document.documentElement.style.getPropertyValue('--sidebar-width'), 10);
if (current_width < 150) {
document.documentElement.style.setProperty('--sidebar-width', '150px');
}
showSidebar();
} else if (html.classList.contains("sidebar-visible")) {
hideSidebar();
} else {
if (getComputedStyle(sidebar)['transform'] === 'none') {
hideSidebar();
} else {
showSidebar();
}
}
});
sidebarResizeHandle.addEventListener('mousedown', initResize, false);
function initResize(e) {
window.addEventListener('mousemove', resize, false);
window.addEventListener('mouseup', stopResize, false);
html.classList.add('sidebar-resizing');
}
function resize(e) {
var pos = (e.clientX - sidebar.offsetLeft);
if (pos < 20) {
hideSidebar();
} else {
if (html.classList.contains("sidebar-hidden")) {
showSidebar();
}
pos = Math.min(pos, window.innerWidth - 100);
document.documentElement.style.setProperty('--sidebar-width', pos + 'px');
}
}
//on mouseup remove windows functions mousemove & mouseup
function stopResize(e) {
html.classList.remove('sidebar-resizing');
window.removeEventListener('mousemove', resize, false);
window.removeEventListener('mouseup', stopResize, false);
}
document.addEventListener('touchstart', function (e) {
firstContact = {
x: e.touches[0].clientX,
time: Date.now()
};
}, { passive: true });
document.addEventListener('touchmove', function (e) {
if (!firstContact)
return;
var curX = e.touches[0].clientX;
var xDiff = curX - firstContact.x,
tDiff = Date.now() - firstContact.time;
if (tDiff < 250 && Math.abs(xDiff) >= 150) {
if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300))
showSidebar();
else if (xDiff < 0 && curX < 300)
hideSidebar();
firstContact = null;
}
}, { passive: true });
// Scroll sidebar to current active section
var activeSection = document.getElementById("sidebar").querySelector(".active");
if (activeSection) {
// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
activeSection.scrollIntoView({ block: 'center' });
}
})();
</script>
</body>
</html>