www: General overhaul

- Move wiki sidebar to its own component
- Remove footer footnote
- Fix some layout issues
- Add a route in WikiController for non-device wiki pages
- Add error-handling for not-found wiki pages
- Better 404 and 500 error pages
- Add some content to the homepage

Change-Id: I944030ea0cb21fca0d784ea42f69d2534d95e2fa
diff --git a/components/aside.html.twig b/components/aside.html.twig
new file mode 100644
index 0000000..62caf97
--- /dev/null
+++ b/components/aside.html.twig
@@ -0,0 +1,31 @@
+{% set currentDevice = app.request.attributes.get('_route_params').device|default('') %}
+
+<aside>
+  <div class="accordion">
+    <div class="accordion-item">
+      <input type="checkbox" id="devices" checked />
+      <label class="accordion-label" for="devices">Devices</label>
+      <div class="accordion-content">
+        <ul>
+          {% for device in availableDevices %}
+            <li>
+              <a href="{{ path('leaf_wiki_device', { device: device.codename }) }}" class="{{ currentDevice == device.codename ? 'active' : '' }}">{{ device.codename }}</a>
+            </li>
+          {% endfor %}
+        </ul>
+      </div>
+    </div>
+
+    <div class="accordion-item">
+      <input type="checkbox" id="how-to" />
+      <label class="accordion-label" for="how-to">How-to</label>
+      <div class="accordion-content">
+        <ul>
+          <li>
+            <a href="{{ path('leaf_wiki_howto', { page: 'request-device' }) }}">Request a device</a>
+          </li>
+        </ul>
+      </div>
+    </div>
+  </div>
+</aside>
diff --git a/components/footer.html.twig b/components/footer.html.twig
index 52b636e..a5fb04f 100644
--- a/components/footer.html.twig
+++ b/components/footer.html.twig
@@ -4,7 +4,4 @@
     <p>Open-source, AOSP-based Android custom ROM</p>
     <p>© 2022-2023 The LeafOS Project</p>
   </div>
-  <p class="footnote">
-    Website designed and developed by <a href="http://rlazarotto.pages.dev" target="_blank">Firehawk</a>.
-  </p>
 </footer>
diff --git a/components/navbar.html.twig b/components/navbar.html.twig
index e4e5ead..3123198 100644
--- a/components/navbar.html.twig
+++ b/components/navbar.html.twig
@@ -10,7 +10,7 @@
       </label>
     {% endif %}
     <a href="{{ path('leaf_home') }}" class="logo">
-      <svg id="vector" xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 0 140.2 76.8">
+      <svg id="vector" xmlns="http://www.w3.org/2000/svg" width="36px" height="36px" viewBox="0 0 140.2 76.8">
         <path fill="#90ee90" d="M28.88 31.84C35.54 40 45.19 48.78 51 58.5c5.14 10.73 14.22 25.34 -3.33 13.65 -13.43 -6.58 -29.21 -10 -38.22 -22.22C0.3 42.26 -2.77 -3.82 2.74 0.25 24.46 11 48 9.35 60.23 23.48a40.75 40.75 0 0 1 8.15 14.85c2.81 7.88 5.2 -7.21 7.53 -9.22C79.66 22.69 85.58 18 92.06 14.8c14.06 -5.15 29.14 -7 42.88 -13.31 2.26 -1 4.25 -1.55 4.8 -0.43 1.28 18.32 0.77 39.76 -12.86 53.37C114.91 65.51 98 67.91 84.12 76.7c-3.83 1 -0.62 -5.45 0.17 -8 5.56 -16 17.39 -24.86 29.34 -37.27C85.69 39.75 77.73 81 73.41 67.29c-1.25 -2 -0.53 -7.12 -3.5 -7.3 -3.17 0.58 -2.27 13.27 -8.27 7.83C53.88 54 43.86 37.9 28.88 31.84Z" id="path_0"></path>
       </svg>
     </a>
diff --git a/public/assets/app.css b/public/assets/app.css
index 6652a18..89aff6b 100644
--- a/public/assets/app.css
+++ b/public/assets/app.css
@@ -24,10 +24,18 @@
 
   --control-bg: #e4f6ee;
   --control-color: #669982;
-
   --control-hover: #f2fbf7;
   --control-active: #bee9d6;
   --control-text-active: #669982;
+
+  --shadow: 0 2px 6px rgb(0 0 0 / 25%);
+
+  --alert-bg: #fff2ae;
+  --alert-color: #ad6c00;
+  --error-bg: #fdcdcd;
+  --error-color: #d83e3e;
+  --success-bg: #b4f1af;
+  --success-color: #33722d;
 }
 
 @media (prefers-color-scheme: dark) {
@@ -56,9 +64,28 @@
     --control-hover: #17231e;
     --control-active: #060908;
     --control-text-active: #6c9381;
+
+    --shadow: 0 2px 6px rgb(0 0 0 / 50%);
   }
 }
 
+::-webkit-scrollbar {
+  width: 8px;
+  height: 8px;
+}
+
+::-webkit-scrollbar-track {
+  border: 1px solid var(--button-bg-active);
+}
+
+::-webkit-scrollbar-thumb {
+  background: var(--button-bg);
+}
+
+::-webkit-scrollbar-thumb:hover {
+  background: var(--button-bg-hover);
+}
+
 html {
   box-sizing: border-box;
   font-family: "Inter", sans-serif;
@@ -99,6 +126,7 @@
 .layout {
   display: flex;
   flex-direction: column;
+  height: 100vh;
 }
 
 .layout main {
@@ -110,9 +138,10 @@
 main aside {
   width: 220px;
   min-width: 220px;
-  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
+  box-shadow: var(--shadow);
   min-height: 100vh;
   background-color: var(--background-color);
+  z-index: 2;
 }
 
 aside h2 {
@@ -120,6 +149,58 @@
   padding: 20px 16px;
 }
 
+.accordion,
+.accordion-item {
+  overflow: hidden;
+}
+
+.accordion-item {
+  width: 100%;
+}
+
+.accordion-item input {
+  display: none;
+}
+
+.accordion-item label {
+  display: flex;
+  justify-content: space-between;
+  padding: 1em;
+  background: var(--control-bg);
+  font-weight: bold;
+  cursor: pointer;
+}
+
+.accordion-item label:hover {
+  background: var(--control-hover);
+}
+
+.accordion-item label::after {
+  content: "❯";
+  width: 1em;
+  height: 1em;
+  text-align: center;
+  transition: all 0.35s;
+}
+
+.accordion-content {
+  max-height: 0;
+  color: var(--text-color);
+  background: var(--background-color);
+  transition: all 500ms ease-in-out;
+  display: block;
+}
+
+input:checked + .accordion-label {
+  background: var(--control-active);
+}
+input:checked + .accordion-label::after {
+  transform: rotate(90deg);
+}
+input:checked ~ .accordion-content {
+  max-height: fit-content;
+}
+
 aside ul {
   list-style: none;
   padding: 0;
@@ -145,12 +226,17 @@
 
 main article {
   flex-grow: 1;
-  min-height: calc(100vh - (64px) - (40px * 2 + 21px));
+}
+
+hr {
+  border-style: solid;
+  border-color: var(--control-bg);
 }
 
 footer {
   background-color: var(--hero-bg-color);
   padding: 20px 0;
+  z-index: 3;
 }
 
 footer div {
@@ -163,14 +249,6 @@
   color: var(--control-color);
 }
 
-footer .footnote {
-  text-align: center;
-  padding: 15px 0;
-  font-size: 10px;
-  font-weight: 600;
-  text-transform: uppercase;
-}
-
 table.center thead th,
 table.center tbody td {
   text-align: center;
@@ -186,9 +264,10 @@
   position: sticky;
   top: 0;
   z-index: 999;
-  box-shadow: 0 2px 6px rgb(0 0 0 / 50%);
+  box-shadow: var(--shadow);
   display: flex;
   justify-items: center;
+  height: 60px;
 }
 
 .navbar div {
@@ -197,7 +276,7 @@
 }
 
 .navbar a.logo {
-  padding: 14px 16px;
+  padding: 0 20px;
   border: 0;
 }
 
@@ -206,11 +285,12 @@
   margin: 0;
   padding: 0;
   display: flex;
+  align-items: center;
 }
 
 .navbar ul li a {
   background-color: var(--background-color);
-  display: block;
+  display: inline-block;
   color: var(--control-color);
   text-align: center;
   padding: 21px 16px;
@@ -244,7 +324,7 @@
   color: var(--button-color);
   font-weight: 600;
   display: inline-block;
-  transition: all 200ms ease-in-out;
+  transition: var(--transition);
   border-radius: 4px;
   border: 0;
 }
@@ -289,6 +369,16 @@
   box-shadow: 0 2px 8px black;
 }
 
+.wiki {
+  display: grid;
+  grid-template-columns: repeat(2, minmax(0, 1fr));
+  column-gap: 30px;
+}
+
+.wiki .for-developers {
+  column-span: 2;
+}
+
 .device-info {
   display: flex;
   gap: 8px;
@@ -379,6 +469,26 @@
   row-gap: 25px;
 }
 
+.error {
+  display: flex;
+  justify-content: center;
+  flex-grow: 1;
+  align-items: center;
+  flex-direction: column;
+  gap: 10px;
+}
+
+.error h2 {
+  text-align: center;
+  padding: 10px 0;
+}
+
+.error .buttons {
+  display: flex;
+  gap: 10px;
+  padding: 20px 0;
+}
+
 /* Media queries */
 @media (min-width: 576px) {
   .contribute {
@@ -445,13 +555,18 @@
     flex-direction: column;
     display: none;
     position: absolute;
-    margin-top: 63px;
+    margin-top: 60px;
   }
 
   .navbar ul li {
     width: 100vw;
   }
 
+  .navbar ul li a {
+    background-color: var(--control-bg);
+    display: block;
+  }
+
   .navbar .label-aside,
   .navbar .label-navbar {
     display: block;
@@ -501,15 +616,16 @@
     flex-direction: column;
     align-items: flex-end;
     justify-content: center;
-    margin-right: 5px;
+    padding-right: 25px;
   }
 
   .navbar .label-navbar .icon-bar {
     display: block;
-    width: 48px;
-    height: 6px;
+    width: 30px;
+    height: 2px;
     background-color: var(--control-color);
-    margin: 5px;
+    margin-top: 2px;
+    margin-bottom: 2px;
     transition: all 0.2s;
   }
 
@@ -522,7 +638,7 @@
   }
 
   #toggle-navbar:checked ~ .label-navbar .top-bar {
-    transform: translateY(16px) rotate(45deg);
+    transform: translateY(8px) rotate(45deg);
   }
 
   #toggle-navbar:checked ~ .label-navbar .middle-bar {
@@ -530,26 +646,18 @@
   }
 
   #toggle-navbar:checked ~ .label-navbar .bottom-bar {
-    transform: translateY(-16px) rotate(-45deg);
+    transform: translateY(-4px) rotate(-45deg);
   }
 
   #toggle-navbar:checked ~ ul {
     display: flex;
   }
 
-  .features {
+  .wiki {
     grid-template-columns: repeat(1, minmax(0, 1fr));
   }
 
-  .screenshot-gallery {
-    flex-direction: column;
-  }
-
-  .banner svg {
-    right: 5%;
-  }
-
-  footer p:not(.footnote) {
-    font-size: 12px;
+  .features {
+    grid-template-columns: repeat(1, minmax(0, 1fr));
   }
 }
diff --git a/src/Controller/WikiController.php b/src/Controller/WikiController.php
index e8be874..b25d317 100644
--- a/src/Controller/WikiController.php
+++ b/src/Controller/WikiController.php
@@ -3,25 +3,36 @@
 namespace App\Controller;
 
 use App\Enum\OtaFlavor;
+use App\Exception\WikiPageNotFoundException;
 use App\Service\DeviceService;
 use App\Service\LeafOtaService;
 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\Routing\Annotation\Route;
+use Twig\Environment;
+use Twig\Loader\LoaderInterface;
 
 class WikiController extends AbstractController {
+    private LoaderInterface $loader;
+    private array $availableDevices;
+
+    public function __construct(Environment $twig, private DeviceService $deviceService) {
+        $this->loader = $twig->getLoader();
+        $this->availableDevices = $deviceService->getAvailableDevices();
+    }
+
     #[Route('/wiki', name: 'leaf_wiki')]
-    public function index(DeviceService $deviceService): Response {
+    public function index(): Response {
         return $this->render(
             'wiki/index.html.twig',
             [
                 'showSidenav' => true,
-                'availableDevices' => $deviceService->getAvailableDevices()
+                'availableDevices' => $this->availableDevices
             ]
         );
     }
 
-    #[Route('/wiki/{device}', name: 'leaf_device')]
+    #[Route('/wiki/device/{device}', name: 'leaf_wiki_device')]
     public function device(DeviceService $deviceService, LeafOtaService $otaService, string $device): Response {
         $latestBuilds = [
             'vanilla' => $otaService->getLatestBuildForDevice($device, OtaFlavor::Vanilla->value),
@@ -42,7 +53,7 @@
             'wiki/device.html.twig',
             [
                 'showSidenav' => true,
-                'availableDevices' => $deviceService->getAvailableDevices(),
+                'availableDevices' => $this->availableDevices,
                 'device' => $deviceService->getDeviceInfo($device),
                 'downloads' => [
                     'latestBuilds' => $latestBuilds,
@@ -53,4 +64,16 @@
             ]
         );
     }
+
+    #[Route('/wiki/how-to/{page}', name: 'leaf_wiki_howto')]
+    public function howTos(string $page): Response {
+        if ($this->loader->exists("wiki/how-to/{$page}.html.twig")) {
+            return $this->render(
+                "wiki/how-to/{$page}.html.twig",
+                ['availableDevices' => $this->availableDevices]
+            );
+        } else {
+            throw new WikiPageNotFoundException("The wiki page for \"{$page}\" doesn't exist.");
+        }
+    }
 }
diff --git a/src/EventListener/ExceptionListener.php b/src/EventListener/ExceptionListener.php
index 9dc812f..ad5f108 100644
--- a/src/EventListener/ExceptionListener.php
+++ b/src/EventListener/ExceptionListener.php
@@ -3,6 +3,7 @@
 namespace App\EventListener;
 
 use App\Exception\DeviceNotFoundException;
+use App\Exception\WikiPageNotFoundException;
 use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\Event\ExceptionEvent;
@@ -31,6 +32,25 @@
 
                 $event->setResponse($response);
                 break;
+            case WikiPageNotFoundException::class:
+                $html = $this->twig->render('errors/404.html.twig', [
+                    'subject' => 'page',
+                    'message' => $throwable->getMessage()
+                ]);
+                $response = new Response();
+                $response->setContent($html);
+
+                $event->setResponse($response);
+                break;
+            default:
+                $html = $this->twig->render('errors/500.html.twig', [
+                    'subject' => 'page',
+                    'message' => "Our server misbehaved. Bad Server, boo."
+                ]);
+                $response = new Response();
+                $response->setContent($html);
+
+                $event->setResponse($response);
         }
     }
 }
diff --git a/src/Exception/DeviceNotFoundException.php b/src/Exception/DeviceNotFoundException.php
index 0b2355e..b02381a 100644
--- a/src/Exception/DeviceNotFoundException.php
+++ b/src/Exception/DeviceNotFoundException.php
@@ -2,4 +2,5 @@
 
 namespace App\Exception;
 
-class DeviceNotFoundException extends \Exception {};
\ No newline at end of file
+class DeviceNotFoundException extends \Exception {
+};
diff --git a/src/Exception/WikiPageNotFoundException.php b/src/Exception/WikiPageNotFoundException.php
new file mode 100644
index 0000000..51f6c1a
--- /dev/null
+++ b/src/Exception/WikiPageNotFoundException.php
@@ -0,0 +1,6 @@
+<?php
+
+namespace App\Exception;
+
+class WikiPageNotFoundException extends \Exception {
+};
diff --git a/src/Service/DeviceService.php b/src/Service/DeviceService.php
index 9d9af13..9ba890a 100644
--- a/src/Service/DeviceService.php
+++ b/src/Service/DeviceService.php
@@ -32,7 +32,7 @@
         if (is_file($file)) {
             return Yaml::parseFile($file);
         } else {
-            throw new DeviceNotFoundException("The device \"" . $device . "\" doesn't exist.");
+            throw new DeviceNotFoundException("The device \"{$device}\" doesn't exist.");
         }
     }
 }
diff --git a/templates/errors/404.html.twig b/templates/errors/404.html.twig
index bd9badf..1b0740f 100644
--- a/templates/errors/404.html.twig
+++ b/templates/errors/404.html.twig
@@ -1,16 +1,22 @@
 {% extends 'base.html.twig' %}
 
 {% block title %}
-  LeafOS 404 - {{ subject|capitalize }} not found.
+  404 - {{ subject|capitalize }} not found :: LeafOS Wiki
 {% endblock %}
 
 {% block body %}
-  <div class="content">
-    <div class="banner">
-      <div class="container">
-        <h1>404 - {{ subject|capitalize }} not found!</h1>
-        <p>{{ message }}</p>
-      </div>
+  <div class="error">
+    <span style="color: var(--alert-color)">
+      <svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" fill="currentColor" viewBox="0 0 256 256">
+        <path d="M225.86,102.82c-3.77-3.94-7.67-8-9.14-11.57-1.36-3.27-1.44-8.69-1.52-13.94-.15-9.76-.31-20.82-8-28.51s-18.75-7.85-28.51-8c-5.25-.08-10.67-.16-13.94-1.52-3.56-1.47-7.63-5.37-11.57-9.14C146.28,23.51,138.44,16,128,16s-18.27,7.51-25.18,14.14c-3.94,3.77-8,7.67-11.57,9.14C88,40.64,82.56,40.72,77.31,40.8c-9.76.15-20.82.31-28.51,8S41,67.55,40.8,77.31c-.08,5.25-.16,10.67-1.52,13.94-1.47,3.56-5.37,7.63-9.14,11.57C23.51,109.72,16,117.56,16,128s7.51,18.27,14.14,25.18c3.77,3.94,7.67,8,9.14,11.57,1.36,3.27,1.44,8.69,1.52,13.94.15,9.76.31,20.82,8,28.51s18.75,7.85,28.51,8c5.25.08,10.67.16,13.94,1.52,3.56,1.47,7.63,5.37,11.57,9.14C109.72,232.49,117.56,240,128,240s18.27-7.51,25.18-14.14c3.94-3.77,8-7.67,11.57-9.14,3.27-1.36,8.69-1.44,13.94-1.52,9.76-.15,20.82-.31,28.51-8s7.85-18.75,8-28.51c.08-5.25.16-10.67,1.52-13.94,1.47-3.56,5.37-7.63,9.14-11.57C232.49,146.28,240,138.44,240,128S232.49,109.73,225.86,102.82Zm-11.55,39.29c-4.79,5-9.75,10.17-12.38,16.52-2.52,6.1-2.63,13.07-2.73,19.82-.1,7-.21,14.33-3.32,17.43s-10.39,3.22-17.43,3.32c-6.75.1-13.72.21-19.82,2.73-6.35,2.63-11.52,7.59-16.52,12.38S132,224,128,224s-9.15-4.92-14.11-9.69-10.17-9.75-16.52-12.38c-6.1-2.52-13.07-2.63-19.82-2.73-7-.1-14.33-.21-17.43-3.32s-3.22-10.39-3.32-17.43c-.1-6.75-.21-13.72-2.73-19.82-2.63-6.35-7.59-11.52-12.38-16.52S32,132,32,128s4.92-9.15,9.69-14.11,9.75-10.17,12.38-16.52c2.52-6.1,2.63-13.07,2.73-19.82.1-7,.21-14.33,3.32-17.43S70.51,56.9,77.55,56.8c6.75-.1,13.72-.21,19.82-2.73,6.35-2.63,11.52-7.59,16.52-12.38S124,32,128,32s9.15,4.92,14.11,9.69,10.17,9.75,16.52,12.38c6.1,2.52,13.07,2.63,19.82,2.73,7,.1,14.33.21,17.43,3.32s3.22,10.39,3.32,17.43c.1,6.75.21,13.72,2.73,19.82,2.63,6.35,7.59,11.52,12.38,16.52S224,124,224,128,219.08,137.15,214.31,142.11ZM120,136V80a8,8,0,0,1,16,0v56a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,172Z"></path>
+      </svg>
+    </span>
+    <h1 style="color: var(--alert-color)">Ops! {{ subject|capitalize }} not found.</h1>
+    <h2>{{ message }}</h2>
+
+    <div class="buttons">
+      <a href="{{ path('leaf_home') }}">Return to home</a>
+      <a href="javascript:history.back()">Go back</a>
     </div>
   </div>
 {% endblock %}
diff --git a/templates/errors/500.html.twig b/templates/errors/500.html.twig
new file mode 100644
index 0000000..eb4139f
--- /dev/null
+++ b/templates/errors/500.html.twig
@@ -0,0 +1,21 @@
+{% extends 'base.html.twig' %}
+
+{% block title %}
+  500 - Internal Server Error :: LeafOS Wiki
+{% endblock %}
+
+{% block body %}
+  <div class="error">
+    <span style="color: var(--error-color)">
+      <svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" fill="currentColor" viewBox="0 0 256 256">
+        <path d="M236.8,188.09,149.35,36.22h0a24.76,24.76,0,0,0-42.7,0L19.2,188.09a23.51,23.51,0,0,0,0,23.72A24.35,24.35,0,0,0,40.55,224h174.9a24.35,24.35,0,0,0,21.33-12.19A23.51,23.51,0,0,0,236.8,188.09ZM222.93,203.8a8.5,8.5,0,0,1-7.48,4.2H40.55a8.5,8.5,0,0,1-7.48-4.2,7.59,7.59,0,0,1,0-7.72L120.52,44.21a8.75,8.75,0,0,1,15,0l87.45,151.87A7.59,7.59,0,0,1,222.93,203.8ZM120,144V104a8,8,0,0,1,16,0v40a8,8,0,0,1-16,0Zm20,36a12,12,0,1,1-12-12A12,12,0,0,1,140,180Z"></path>
+      </svg>
+    </span>
+    <h1 style="color: var(--error-color)">Internal Server Error</h1>
+    <h2>{{ message }}</h2>
+
+    <div class="buttons">
+      <a href="{{ path('leaf_home') }}">Return to home</a>
+    </div>
+  </div>
+{% endblock %}
diff --git a/templates/wiki/device.html.twig b/templates/wiki/device.html.twig
index f2b78f6..7f1a670 100644
--- a/templates/wiki/device.html.twig
+++ b/templates/wiki/device.html.twig
@@ -1,19 +1,11 @@
 {% extends 'base.html.twig' %}
 
-{% set currentDevice = app.request.attributes.get('_route_params').device %}
-
 {% block title %}
   LeafOS Wiki
 {% endblock %}
 
 {% block body %}
-  <aside class="navigation">
-    <h2>Devices</h2>
-
-    {% for device in availableDevices %}
-      <a href="{{ path('leaf_device', { device: device.codename }) }}" class="{{ currentDevice == device.codename ? 'active' : '' }}">{{ device.codename }}</a>
-    {% endfor %}
-  </aside>
+  {% include '@components/aside.html.twig' %}
   <article>
     <div class="banner">
       <div class="container">
@@ -26,6 +18,7 @@
         <div class="instructions">
           <h2>Downloads</h2>
           <h3>Latest builds</h3>
+          <hr />
           <div class="latest-builds">
             {% for build in downloads.latestBuilds %}
               <div class="build-card">
@@ -51,7 +44,7 @@
                       </tr>
                       <tr>
                         <td colspan="2" class="center">
-                          <a href="{{build.url}}" class="button">Download</a>
+                          <a href="{{ build.url }}" class="button">Download</a>
                         </td>
                       </tr>
                     </tbody>
@@ -71,36 +64,26 @@
           <table>
             <tbody>
               <tr>
-                <td>
-                  SoC
-                </td>
+                <td>SoC</td>
                 <td>{{ device.soc }} ({{ device.architecture }})</td>
               </tr>
               <tr>
-                <td>
-                  CPU
-                </td>
+                <td>CPU</td>
                 <td>
                   <p>{{ device.cpu_cores }} cores {{ device.cpu }}</p>
                   <p>{{ device.cpu_freq }}</p>
                 </td>
               </tr>
               <tr>
-                <td>
-                  GPU
-                </td>
+                <td>GPU</td>
                 <td>{{ device.gpu }}</td>
               </tr>
               <tr>
-                <td>
-                  RAM
-                </td>
+                <td>RAM</td>
                 <td>{{ device.ram }}</td>
               </tr>
               <tr>
-                <td>
-                  Storage
-                </td>
+                <td>Storage</td>
                 <td>
                   <p>{{ device.storage }}</p>
                   {% if device.sdcard is defined %}
@@ -109,9 +92,7 @@
                 </td>
               </tr>
               <tr>
-                <td>
-                  Screen
-                </td>
+                <td>Screen</td>
                 <td>
                   <ul>
                     <li>{{ device.screen.size }}</li>
@@ -121,16 +102,12 @@
                 </td>
               </tr>
               <tr>
-                <td>
-                  Battery
-                </td>
+                <td>Battery</td>
                 <td colspan="2">{{ device.battery.removable ? 'Removable' : 'Non-removable' }}
                   {{ device.battery.tech }} {{ device.battery.capacity }} mAh</td>
               </tr>
               <tr>
-                <td>
-                  Cameras
-                </td>
+                <td>Cameras</td>
                 <td>
                   <ul>
                     {% for camera in device.cameras %}
@@ -140,9 +117,7 @@
                 </td>
               </tr>
               <tr>
-                <td>
-                  Network
-                </td>
+                <td>Network</td>
                 <td>
                   <ul>
                     {% for network in device.network %}
@@ -152,15 +127,11 @@
                 </td>
               </tr>
               <tr>
-                <td>
-                  WiFi
-                </td>
+                <td>WiFi</td>
                 <td>{{ device.wifi }}</td>
               </tr>
               <tr>
-                <td>
-                  Bluetooth
-                </td>
+                <td>Bluetooth</td>
                 <td>
                   {{ device.bluetooth.spec }}
                   {% if device.bluetooth.profiles is defined and device.bluetooth.profiles is not empty %}
@@ -175,5 +146,5 @@
         </div>
       </div>
     </div>
-  </artic>
+  </article>
 {% endblock %}
diff --git a/templates/wiki/how-to/request-device.html.twig b/templates/wiki/how-to/request-device.html.twig
new file mode 100644
index 0000000..5f4a077
--- /dev/null
+++ b/templates/wiki/how-to/request-device.html.twig
@@ -0,0 +1,29 @@
+{% extends 'base.html.twig' %}
+
+{% block title %}
+  LeafOS Wiki
+{% endblock %}
+
+{% block body %}
+  {% include '@components/aside.html.twig' %}
+  <article>
+    <div class="banner">
+      <div class="container">
+        <h1>Requesting LeafOS for your device</h1>
+      </div>
+    </div>
+
+    <div class="container">
+      <p>
+        <b>tl;dr:</b> It’s up to you.
+      </p>
+
+      <p>Sorry to let you down, but LeafOS device support has nothing to do with the number of device requests received. The folks who maintain devices for LeafOS choose devices that interest them. Remember, these are regular people enjoying a hobby. LeafOS is not a corporation with employees. So, step one, purge your mind of the mentality that developers are sitting around waiting for advice about what to work on next.</p>
+
+      <p>There’s more to this story, though. Be wary of individuals who tout, “I bought a new device! It will therefore have fancy AOSP soon!” All too often, these are folks who underestimate the difficulty of bringing AOSP to a device. Even skilled maintainers cannot predict all the hurdles they will face in bring-up. Someone who says “soon” is someone who hasn’t experienced the utter joy of having a device 99% finished, but one last function (e.g. fingerprint reader, HDR, encryption) takes months to get working.</p>
+      <p>Perhaps the only somewhat reliable indicator of whether a device may be officially supported is when a developer’s hard work in bringing-up a device is forked over to github.com/LeafOS. Notice, this is after a developer (or regular Joe, see below) puts in the time and effort to get LeafOS running reliably. There’s still no guarantee of official support at this point; the device needs to meet a number of quality control checklist items and the developer needs to agree to maintain the device over time. But, there’s at least a decent chance.</p>
+
+      <p>Ok, so if nobody is making headway on your device, where do you go from here? Consider that the majority of the device maintainers for LeafOS have significantly different day jobs than Android device maintenance (or even programming, for that matter). If you are passionate enough about getting LeafOS up and running on your device, you can make it happen. Start easy; buy an old, but well supported device and try compiling your first ROM. Once you’re running software you compiled yourself, start investigating the device configuration files. Tweak, and then tweak some more. Eventually, see what you’re able to accomplish on your device of interest!</p>
+    </div>
+  </article>
+{% endblock %}
diff --git a/templates/wiki/index.html.twig b/templates/wiki/index.html.twig
index ebe62e4..618af61 100644
--- a/templates/wiki/index.html.twig
+++ b/templates/wiki/index.html.twig
@@ -5,17 +5,7 @@
 {% endblock %}
 
 {% block body %}
-  <aside>
-    <h2>Devices</h2>
-
-    <ul>
-      {% for device in availableDevices %}
-        <li>
-          <a href="{{ path('leaf_device', { device: device.codename }) }}">{{ device.codename }}</a>
-        </li>
-      {% endfor %}
-    </ul>
-  </aside>
+  {% include '@components/aside.html.twig' %}
   <article>
     <div class="banner">
       <div class="container">
@@ -23,5 +13,39 @@
         <p>You can find various information, how-tos, build instructions and much more here in our wiki.</p>
       </div>
     </div>
+
+    <div class="container wiki">
+      <div>
+        <h2>For users</h2>
+        <hr />
+        <h3>Get LeafOS</h3>
+        <ul>
+          <li>Check on the sidebar for our currently supported devices.</li>
+          <li>If you device isn't on the list, you can check on how to request a device.</li>
+        </ul>
+        <h3>Reporting bugs</h3>
+        <p>For a proper bug report, you'll need to grab logs immediately after the bug happens. Check our Capturing logs page for more information.</p>
+        <ul>
+          <li>Learn here how to setup your device and your computer to retrieve logs.</li>
+          <li>Learn here how to submit your bug report.</li>
+        </ul>
+      </div>
+      <div>
+        <h2>For everyone</h2>
+        <hr />
+        <h3>Contribute to the Wiki</h3>
+        <p>LeafOS' wiki is powered by Symfony.</p>
+        <ul>
+          <li>The source is available on Gerrit.</li>
+          <li>And here is our guide on contributing.</li>
+        </ul>
+
+        <h3>Build for your device</h3>
+        <p>All of our officially-supported devices have their own set of build-instructions. Check the device page for more detailed information.</p>
+      </div>
+      <div>
+        <h2>For everyone</h2>
+      </div>
+    </div>
   </article>
 {% endblock %}