Add form pages

This commit is contained in:
Yannik Rödel 2021-09-18 12:03:57 +02:00
parent 2e62832756
commit 0441b5439b
23 changed files with 1093 additions and 346 deletions

View file

@ -6,6 +6,7 @@ const pluginNavigation = require("@11ty/eleventy-navigation");
const Image = require("@11ty/eleventy-img");
const markdownIt = require("markdown-it");
const markdownItAnchor = require("markdown-it-anchor");
const markdownItAttrs = require("markdown-it-attrs");
function hyphenize(input) {
return input.replace(/[^\w- ]/, "").replace(/[_ ]/, "-").toLowerCase();
@ -107,9 +108,9 @@ ${content}
let markdownLibrary = markdownIt({
html: true,
breaks: true,
breaks: false,
linkify: true
});
}).use(markdownItAnchor).use(markdownItAttrs);
eleventyConfig.setLibrary("md", markdownLibrary);
//

View file

@ -0,0 +1,85 @@
---
layout: layouts/page.njk
eleventyNavigation:
key: Computer beantragen
order: 40
---
# Computer beantragen
Um einen Computer von uns zu erhalten, müssen wir zunächst einige Dinge klären.
Danach können wir den Antrag prüfen und wir werden uns bei Ihnen melden. Alle
Daten werden natürlich [geschützt verarbeitet](/datenschutzhinweis). Bitte
teilen Sie uns zunächst mit, für wen ein Gerät beantragt werden soll.
- [*Privat* für mich oder meine Familie](/computer-beantragen/privat)
- [Als *gemeinnützige Organisation*](/computer-beantragen/organisation)
{.form-choices}
## Informationen und häufig gestellte Fragen
Es ist sehr einfach, einen Computer von uns zu erhalten. Normalerweise läuft es
in drei Schritten ab:
1. Sie stellen einen Antrag über das Kontaktformular
([oben](#computer-beantragen) auf dieser Seite)
2. Wir vereinbaren einen Termin zur Abholung mit Ihnen. Falls kein Gerät direkt
zur Verfügung steht, setzen wir Sie auf unsere Warteliste.
3. Sie erhalten zum vereinbarten Termin einen Computer von uns.
### Wer bekommt einen Computer?
Alle Personen, die einen der folgenden Nachweise vorlegen können:
- eine Arbeitslosengeldbescheinigung (ALG I)
- Bescheinigung über ALG II (Hartz IV)
- ein Bewilligungsbescheid (für Geflüchtete)
- Bescheinigungen vom Sozialamt, von der Schuldnerberatung oder vom Jobcenter
- Bescheinigung eines anerkannten Trägers (z. B. Caritas, Diakonie,
Jugendhilfeinrichtungen)
- BAföG-Bescheid
- Rentenbescheid
- Grundsicherungsbescheid
- Lohnbescheid (Geringverdiener)
Außerdem verschenken wir PCs auch an Organisationen, die selbst gemeinnützige
oder mildtätige Zwecke erfüllen. Nehmen Sie in diesem Fall gerne über den obigen
Link Kontakt zu uns auf, dann finden wir gemeinsam eine passende Lösung.
### Wie stelle ich einen Antrag?
Über die beiden Links [oben](#computer-beantragen) auf dieser Seite gelangen
Sie zum entsprechenden Kontaktformular. Bitte verwenden Sie dieses, um einen
Computer zu beantragen.
### Wie lange dauert es?
Alle Anfragen bearbeiten wir der Reihe nach. Wenn gerade viele Anträge bei uns
eintreffen, kann die Bearbeitungszeit durchaus ein paar Monate dauern. In
ruhigeren Zeiten können wir Ihnen oft auch schon in zwei Wochen einen Computer
überreichen. In jedem Fall werden Sie von uns benachrichtigt, sobald ein Gerät
für Sie bereit steht.
*Hinweis: da unsere Arbeit von ehrenamtlichen gestemmt wird also Freiwilligen,
die kein Geld dafür erhalten geben wir bei diesem Thema keine festen
Versprechen.*
### Versenden Sie Computer?
Nein.
### Warum versenden Sie keine Computer?
Wir sind nur wenige Freiwillige, die an dem Projekt arbeiten. Aktuell haben wir
keine Kapazitäten, Computer per Post zu verschicken.
### Gibt es eine Garantie auf die Geräte?
Nein. Es sind gebrauchte Computer, auf die wir keine Garantie geben.
### Welches Betriebssystem ist auf den Computern installiert?
Auf allen unseren Geräten ist [Ubuntu](https://wiki.ubuntuusers.de/Einsteiger/)
installiert. Es gibt ein Programm zum Schreiben
([LibreOffice](https://de.libreoffice.org/)) und für das Internet
([Firefox](https://www.mozilla.org/de/firefox/new/)). Außerdem gibt es viele
weitere kostenlose Software.

View file

@ -0,0 +1,77 @@
---
layout: layouts/page.njk
---
# Geräte für eine gemeinnützige Organisation beantragen
<form method="post" action="/computer-beantragen/organisation">
Wir möchten nicht, dass gute Aktionen an fehlender Hardware scheitern. Deshalb
haben gemeinnützige Organisationen wie Vereine die Möglichkeit, Hardware für
ihre Zwecke zu beantragen. Dazu benötigen wir zunächst Ihre Kontaktdaten als
Ansprechpartner.
<label class="form-input">
<span>Name:</span>
<input type="text" name="contactname" required placeholder="Vorname Nachname" />
</label>
<label class="form-input">
<span>Email:</span>
<input type="email" name="contactemail" required placeholder="mail@beispiel.de" />
</label>
In den folgenden Feldern können Sie uns mitteilen, um welchen Empfänger es sich
handelt. Hier geht es um die Organisation, nicht um konkrete Mitarbeiterinnen
oder Mitarbeiter.
<label class="form-input">
<span>Name:</span>
<input type="text" name="organization" required placeholder="Name der Organisation" />
</label>
<label class="form-input">
<span>Adresse:</span>
<input type="text" name="addressline" required placeholder="Straße und Hausnummer" />
</label>
<label class="form-input">
<span>Postleitzahl:</span>
<input type="text" name="postalcode" required placeholder="12345" />
</label>
<label class="form-input">
<span>Ort:</span>
<input type="text" name="city" required placeholder="Würzburg" />
</label>
Nun würden wir gerne von Ihnen eine grobe Auflistung der Geräte erfassen, die
Sie benötigen. Genauere Anforderungen können Sie weiter unten im Freitextfeld
angeben.
<label class="form-input">
<span>Anzahl Desktops:</span>
<input type="number" name="desktopcount" value="0" min="0" max="100" />
</label>
<label class="form-input">
<span>Anzahl Laptops:</span>
<input type="number" name="laptopcount" value="0" min="0" max="100" />
</label>
<label class="form-input">
<span>Anzahl Drucker:</span>
<input type="number" name="printercount" value="0" min="0" max="100" />
</label>
Im folgenden Feld können Sie weitere Anmerkungen ergänzen.
<label class="form-input">
<span>Eigene Angaben:</span>
<textarea name="message"></textarea>
</label>
<div class="form-submit">
<input type="submit" value="Abschicken" />
</div>
</form>

View file

@ -0,0 +1,90 @@
---
layout: layouts/page.njk
---
# Privat einen Computer beantragen
<form method="post" action="/computer-beantragen/privat">
Auf dieser Seite können Sie einen Antrag einreichen, um einen Computer von uns
zu erhalten. Bitte teilen Sie uns zunächst *Ihre* Kontaktdaten mit.
<label class="form-input">
<span>Name:</span>
<input type="text" name="contactname" required placeholder="Vorname Nachname" />
</label>
<label class="form-input">
<span>Email:</span>
<input type="email" name="contactemail" required placeholder="mail@beispiel.de" />
</label>
Damit Sie einen Computer von uns erhalten können, benötigen wir von Ihnen einen
Nachweis der Bedürftigkeit. Das ist eines dieser Papiere, die von offiziellen
Stellen ausgestellt werden:
- eine Arbeitslosengeldbescheinigung (ALG I)
- Bescheinigung über ALG II (Hartz IV)
- ein Bewilligungsbescheid (für Geflüchtete)
- Bescheinigungen vom Sozialamt, von der Schuldnerberatung oder vom Jobcenter
- Bescheinigung eines anerkannten Trägers (z. B. Caritas, Diakonie,
Jugendhilfeinrichtungen)
- BAföG-Bescheid
- Rentenbescheid
- Grundsicherungsbescheid
- Lohnbescheid (Geringverdiener)
Bitte laden Sie das Dokument im folgenden Schritt hoch entweder als Foto
oder eingescannt als PDF.
<label class="form-input">
<span>Nachweis hochladen:</span>
<input type="file" name="document" required />
</label>
Bitte geben Sie uns jetzt noch Ihre Anschrift. Das sollte die gleiche sein, die
auch im obigen Dokument erwähnt ist.
<label class="form-input">
<span>Adresse:</span>
<input type="text" name="addressline" required placeholder="Straße und Hausnummer" />
</label>
<label class="form-input">
<span>Postleitzahl:</span>
<input type="text" name="postalcode" required placeholder="12345" />
</label>
<label class="form-input">
<span>Ort:</span>
<input type="text" name="city" required placeholder="Würzburg" />
</label>
Soviel zu den Angaben, die wir von Ihnen benötigen. Falls Sie noch etwas anderes
ergänzen möchten, können Sie das jetzt tun.
<label class="form-input">
<span>Eigene Angaben:</span>
<textarea name="message"></textarea>
</label>
Bevor Sie das Formular abschicken, lesen Sie Sich bitte die folgenden Hinweise
aufmerksam durch:
- Wir versenden keine Geräte per Post der Computer muss persönlich abgeholt
werden.
- Die aktuelle geschätzte Wartezeit liegt bei 2 6 Wochen.
- Normalerweise vergeben wir Laptops. Falls Sie einen Desktop-PC oder Zubehör
wie Bildschirm, Tastatur, Maus oder Drucker benötigen können Sie das gerne in
dem Kommentarfeld erwähnen.
<label class="form-checkbox">
<input type="checkbox" name="hints" required>
<div></div>
<span>Ich habe die obigen Hinweise gelesen.</span>
</label>
<div class="form-submit">
<input type="submit" value="Abschicken" />
</div>
</form>

15
computer-reparieren.md Normal file
View file

@ -0,0 +1,15 @@
---
layout: layouts/page.njk
---
# Computer reparieren
Sofern es sich für uns einrichten lässt, führen wir auf Wunsch auch Reparaturen
von Computern oder Notebooks durch. Dies ist selbstverständlich kostenlos.
Hierfür wird ein gütiger ALGII-, HarzIV-, Rentenbescheid, Behinderten- oder
Asylausweis benötigt. Bitte denken Sie daran, vor der Abgabe des Gerätes alle
wichtigen Daten zu sichern! Wir übernehmen keine Haftung für entstandene Schäden
oder Datenverluste.
Bitte kontaktieren Sie uns vor der Reparatur telefonisch oder über das
[Kontaktformular](/kontakt/sonstiges). **Aufgrund der sehr hohen Nachfrage
führen wir zurzeit allerdings nur in Ausnahmefällen Reparaturanfragen durch**.

69
hardware-spenden/index.md Normal file
View file

@ -0,0 +1,69 @@
---
layout: layouts/page.njk
eleventyNavigation:
key: Hardware spenden
order: 50
---
# Hardware spenden
Wir sind allen Spendern sehr dankbar, die uns gebrauchte Hardware überlassen,
damit wir sie wiederum weiterschenken können nur dadurch ist unser Projekt
überhaupt erst möglich geworden! Wenn Sie nicht mehr benötigte Hardware einem
guten Zweck hinterlassen möchten, sind wir der ideale Partner dafür. Auf diesen
Seiten können Sie mit uns in Kontakt treten, um eine Übergabe zu organisieren.
- [Als *Privatperson* spenden](/hardware-spenden/privat)
- [Als *Firma, Verein oder andere Organisation* spenden](/hardware-spenden/organisation)
{.form-choices}
## Informationen und häufig gestellte Fragen
...
### Welche Mindestanforderungen muss ein zu spendender Computer erfüllen?
Wir möchten vermeiden, dass unser Verein als "Wertstoffhof" genutzt wird, um
alte Hardware loszuwerden, die nach heutigen Standards nicht mehr verwendbar
ist. Deshalb können wir Geräte, die unter folgenden Anforderungen liegen, leider
nicht annehmen:
<dl>
<dt>Computer</dt>
<dd>
*Für Laien*: das Gerät sollte **höchstens 8 Jahre alt** und für mindestens Windows Vista
ausgelegt sein.
*Für Experten*: das Gerät sollte folgenden Spezifikationen genügen:
- Prozessor: mindestens Intel Dual Core / AMD Athlon 64
- Hauptspeicher: mindestens DDR2
- Festplatte: mindestens IDE 80GB
- Grafikprozessor (sofern vorhanden): ab AGP
</dd>
<dt>Bildschirme</dt>
<dd>
Wir nehmen nur Flachbildschirme (TFT) an. Andere Modelle wie zum Beispiel
CRT-Röhrenmonitore können wir leider nicht akzeptieren.
</dd>
<dt>Drucker</dt>
<dd>
Gespendete Drucker müssen voll funktionsfähig sein. Weiterhin bitten wir darum,
diese inklusive Patronen zu übergeben.
</dd>
</dl>
### Werden Spendenquittungen ausgestellt?
...
### Wie wird sichergestellt, dass alle meine Daten von dem Gerät gelöscht sind?
...

View file

@ -0,0 +1,55 @@
---
layout: layouts/page.njk
---
# Hardware als Organisation spenden
<form method="post" action="/hardware-spenden/organisation">
Danke, dass Sie Ihre gebrauchte Hardware uns überlassen möchten! Um die Übergabe
möglichst reibungslos zu gestalten, benötigen wir zunächst ein paar Angaben zu
Ihrer Organsation und wie wir Sie erreichen können.
<label class="form-input">
<span>Name:</span>
<input type="text" name="organization" required placeholder="Name der Organisation" />
</label>
<label class="form-input">
<span>Ansprechpartner:</span>
<input type="text" name="contactname" required placeholder="Vorname Nachname" />
</label>
<label class="form-input">
<span>Email:</span>
<input type="email" name="contactemail" required placeholder="mail@beispiel.de" />
</label>
Bitte beschreiben Sie uns im Folgenden Ihre Hardwarespende etwas genauer. Wir
werden dann mit etwaigen Fragen auf Sie zukommen und alles Weitere direkt
besprechen. Falls Sie eine Inventarliste o. Ä. über das zu spendende Material
zur Verfügung haben, können Sie diese gerne hier direkt anhängen.
<label class="form-input">
<span>Inventarliste:</span>
<input type="file" name="inventory" />
</label>
<label class="form-input">
<span>Nachricht:</span>
<textarea name="message"></textarea>
</label>
<div class="form-submit">
<input type="submit" value="Abschicken" />
</div>
</form>
Die aktuelle geschätzte Wartezeit liegt bei 2 6 Wochen.
Normalerweise vergeben wir Laptops. Falls Sie einen Desktop-PC oder Zubehör wie Bildschirm, Tastatur, Maus oder Drucker benötigen können Sie das gerne in dem Kommentarfeld erwähnen.
## Weitere Informationen
...
### Fertigen von Übergabefotos
...

View file

@ -0,0 +1,59 @@
---
layout: layouts/page.njk
---
# Privat Hardware spenden
Danke, dass Sie Ihre gebrauchte Hardware uns überlassen möchten! Hier können
Sie direkt zum entsprechenden Bereich springen:
- [Zum Bereich *Laptops*](#laptops)
- [Zum Bereich *Desktop-PCs*](#desktop-pcs)
- [Zum Bereich *Drucker*](#drucker)
{.form-choices}
## Laptops
<form method="post" action="/hardware-spenden/privat/laptop">
Um die Übergabe möglichst reibungslos zu gestalten, benötigen wir zunächst
ein paar Kontaktdaten, damit wir auf Sie zurückkommen können.
<label class="form-input">
<span>Name:</span>
<input type="text" name="contactname" required placeholder="Vorname Nachname" />
</label>
<label class="form-input">
<span>Email:</span>
<input type="email" name="contactemail" required placeholder="mail@beispiel.de" />
</label>
Gegebenenfalls können Sie uns im folgenden Feld etwas über das Gerät erzählen
(zum Beispiel die Modellnummer, sofern Sie sie kennen). Falls nicht, ist das
auch kein Problem.
<label class="form-input">
<span>Geräteinfos:</span>
<input type="text" name="device" />
</label>
<label class="form-input">
<span>Nachricht:</span>
<textarea name="message"></textarea>
</label>
<div class="form-submit">
<input type="submit" value="Abschicken" />
</div>
</form>
## Desktop-PCs
Leider können wir aus Platzmangel zur Zeit keine PC-Spenden entgegennehmen. Wir
hoffen, diese Limitierung bald wieder aufheben zu können, aber aktuell haben
nicht die Kapazität, neu angenommene PCs zu lagern.
## Drucker
...

7
kontakt/erfolg.md Normal file
View file

@ -0,0 +1,7 @@
---
layout: layouts/page.njk
---
# Erfolgreich abgesendet
Vielen Dank, wir haben Ihre Anfrage entgegengenommen. Sie sollten in Kürze
per E-Mail eine entsprechende Bestätigung erhalten.

50
kontakt/index.md Normal file
View file

@ -0,0 +1,50 @@
---
layout: layouts/page.njk
eleventyNavigation:
key: Kontakt
order: 100
---
# Kontakt zu uns aufnehmen
Schön, dass Sie sich für unsere Arbeit interessieren! Bitte wählen Sie unten
eine Kategorie aus, um direkt zum entsprechenden Kontaktformular zu gelangen. So
können wir Ihre Anfrage besser zuordnen. Sie erreichen uns natürlich auch
postalisch oder per E-Mail bei den unten angegebenen Adressen.
- [Ich möchte einen (oder mehrere) *Computer beantragen*](/computer-beantragen)
- [Ich möchte *Hardware spenden*](/hardware-spenden)
- [Ich habe ein *Problem mit einem Computer*, den ich von Angestöpselt habe](/kontakt/problem)
- [Ich möchte mich ehrenamtlich im Verein *engagieren*](/mitmachen)
- [Ich habe ein *anderes Anliegen*](#andere-anliegen)
{.form-choices}
## Andere Anliegen
Bei anderen Angelegenheiten können Sie uns über folgendes Formular erreichen.
Bitte sehen Sie aber zunächst oben in der Liste nach, weil wir für viele Themen
bereits entsprechende Formulare bereitstellen. Zögern Sie aber nicht, bei Fragen
auf uns zuzukommen!
<form method="post" action="/kontakt">
<label class="form-input">
<span>Name:</span>
<input type="text" name="contactname" required placeholder="Vorname Nachname" />
</label>
<label class="form-input">
<span>Email:</span>
<input type="email" name="contactemail" required placeholder="mail@beispiel.de" />
</label>
<label class="form-input">
<span>Nachricht:</span>
<textarea name="message"></textarea>
</label>
<div class="form-submit">
<input type="submit" value="Abschicken" />
</div>
</form>

43
kontakt/problem.md Normal file
View file

@ -0,0 +1,43 @@
---
layout: layouts/page.njk
---
# Hilfe bei Problemen mit unseren Computern
<form method="post" action="/kontakt/problem">
Falls Sie in irgendeiner Form Probleme mit den von uns ausgestellten Geräten
haben sollten, können Sie uns auf dieser Seite davon berichten. Wir werden uns
anschließend bei Ihnen melden und versuchen gemeinsam, eine Lösung zu finden.
Wir bitten Sie zunächst um ein paar Kontaktdaten zu Ihrer Person.
<label class="form-input">
<span>Name:</span>
<input type="text" name="contactname" required placeholder="Vorname Nachname" />
</label>
<label class="form-input">
<span>Email:</span>
<input type="email" name="contactemail" required placeholder="mail@beispiel.de" />
</label>
Alle von uns ausgegebene Rechner haben eine Nummer. Wenn Sie diese angeben,
können wir das Problem besser eingrenzen und schneller eine Lösung finden. Falls
es sich bei dieser Anfrage nicht um einen Computer, sondern um ein anderes
Gerät, handelt können Sie das Feld leer lassen. Beschreiben Sie bitte im
Anschluss Ihr Problem möglichst präzise.
<label class="form-input">
<span>Rechnernummer:</span>
<input type="text" name="reference" placeholder="ABC123" />
</label>
<label class="form-input">
<span>Nachricht:</span>
<textarea name="message"></textarea>
</label>
<div class="form-submit">
<input type="submit" value="Abschicken" />
</div>
</form>

20
package-lock.json generated
View file

@ -17,6 +17,7 @@
"luxon": "^1.26.0",
"markdown-it": "^12.0.4",
"markdown-it-anchor": "^7.1.0",
"markdown-it-attrs": "^4.0.0",
"sass": "^1.35.1"
}
},
@ -2727,6 +2728,18 @@
"markdown-it": "*"
}
},
"node_modules/markdown-it-attrs": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-attrs/-/markdown-it-attrs-4.0.0.tgz",
"integrity": "sha512-uLjtdCmhhmL3BuZsReYkFxk74qKjj5ahe34teBpOCJ4hYZZl7/ftLyXWLowngC2moRkbLEvKwN/7TMwbhbHE/A==",
"dev": true,
"engines": {
"node": ">=6"
},
"peerDependencies": {
"markdown-it": ">= 9.0.0 < 13.0.0"
}
},
"node_modules/markdown-it/node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@ -7136,6 +7149,13 @@
"dev": true,
"requires": {}
},
"markdown-it-attrs": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-attrs/-/markdown-it-attrs-4.0.0.tgz",
"integrity": "sha512-uLjtdCmhhmL3BuZsReYkFxk74qKjj5ahe34teBpOCJ4hYZZl7/ftLyXWLowngC2moRkbLEvKwN/7TMwbhbHE/A==",
"dev": true,
"requires": {}
},
"maximatch": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/maximatch/-/maximatch-0.1.0.tgz",

View file

@ -19,6 +19,7 @@
"luxon": "^1.26.0",
"markdown-it": "^12.0.4",
"markdown-it-anchor": "^7.1.0",
"markdown-it-attrs": "^4.0.0",
"sass": "^1.35.1"
}
}

View file

@ -1,7 +0,0 @@
---
layout: layouts/page.njk
eleventyNavigation:
key: Zweite Seite
order: 2
---
## Das ist die zweite Seite

View file

@ -2,6 +2,10 @@
@use 'layout';
@use 'typography';
* {
box-sizing: border-box;
}
body {
margin: 0;
color: colors.$main-text;
@ -42,7 +46,6 @@ h2 {
margin: layout.$normal-gap 0;
font-size: typography.$subheading-size;
line-height: typography.$heading-line-height;
margin: layout.$normal-gap 0;
}
h3 {
@ -53,6 +56,24 @@ p {
margin: layout.$normal-gap 0;
}
ul, ol {
margin: layout.$normal-gap 0;
}
li {
margin: layout.$small-gap 0;
}
dt {
margin: layout.$normal-gap 0;
font-weight: typography.$emphasized-weight;
color: colors.$blue-800;
}
dd {
margin: layout.$normal-gap 0 layout.$normal-gap layout.$large-gap;
}
a {
color: colors.$main-text;

View file

@ -1,334 +0,0 @@
@use 'base';
@use 'colors';
@use 'layout';
@use 'typography';
// --------------------
// Site-wide components
// --------------------
@mixin header-item {
padding: 0 layout.$normal-gap;
line-height: 3rem;
}
// The site logo text. More specific styles for this element are also present
// underneath .site-header.
.site-logo {
margin: 0 layout.$normal-gap;
text-transform: lowercase;
}
// The navigation is present twice on the site: once in the header and once in
// the footer. The former also has some specific styles (see .site-header
// below).
.site-navigation {
&.horizontal {
> ul {
display: flex;
margin-bottom: 0;
}
a {
display: inline-block;
@include header-item;
}
}
> ul {
margin: 0;
padding: 0;
list-style: none;
}
a {
display: block;
padding: layout.$small-gap;
font-weight: typography.$emphasized-weight;
text-align: center;
text-decoration: none;
text-transform: lowercase;
}
}
.site-mobile-navigation {
cursor: pointer;
> summary {
display: block;
@include header-item;
}
&[open] {
flex-basis: 100%;
> summary {
// The positioning requires that the header component has relative
// positioning.
position: absolute;
top: 0;
right: 0;
color: colors.$blue-800;
}
}
// This is the next site navigation block (the one that's visible on desktop),
// while...
+ .site-navigation {
display: none;
}
// ... this here is the one inside the mobile-only <details> block.
> .site-navigation {
&::before {
content: '';
display: block;
margin: 0 auto;
width: calc(100% - #{2 * layout.$normal-gap});
height: 1px;
background-color: colors.$gray-300;
}
}
@media screen and (min-width: layout.$breakpoint) {
display: none;
+ .site-navigation {
display: block;
}
}
}
.site-header {
display: flex;
// This container needs to wrap because when the navigation is open on small
// screens, we want it to overflow into its own line.
flex-wrap: wrap;
align-items: center;
// Relative positioning is required here so that we can fake the menu button's
// location on mobile.
position: relative;
z-index: 10;
background-color: colors.$main-background;
@include colors.block-shadow;
> .site-logo {
flex-grow: 1;
margin: 0;
font-size: typography.$subheading-size;
text-decoration: none;
@include header-item;
}
}
.site-footer {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: layout.$normal-gap;
}
// ------------------------------
// Components on individual pages
// ------------------------------
// This is the wrapper element around individual .page-content blocks. The home
// page contains a few of these sections, while normal pages only contain one.
// Spanning the entire width, sections may have different themes.
.page-section {
padding: layout.$large-gap;
&.inverse {
color: colors.$gray-50;
background-color: colors.$blue-800;
h2:after {
background-color: colors.$gray-50;
}
}
&.footer {
background-color: colors.$teal-500;
}
}
.page-content {
margin: 0 auto;
max-width: 80rem;
}
// Banners can be put at the top of a page to draw attention. A banner has
// two children:
// - A .background element which contains an image to render behind the text
// - A .content which holds the actual text.
.page-banner {
display: flex;
flex-direction: column;
justify-content: space-around;
position: relative;
min-height: 60vh;
> .background {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
> .content {
display: flex;
flex-direction: column;
align-items: flex-start;
position: relative;
padding: layout.$normal-gap max(#{layout.$large-gap}, 15vw);
> div {
display: inline-block;
padding: layout.$small-gap layout.$normal-gap;
font-size: typography.$subheading-size;
background-color: colors.$yellow-600;
> p:first-child {
margin-top: 0;
}
> p:last-child {
margin-bottom: 0;
}
}
> .title {
padding: 0 layout.$normal-gap;
line-height: 5rem;
font-size: typography.$title-size;
font-weight: typography.$emphasized-weight;
background-color: colors.$teal-500;
}
}
}
.boxes-module {
padding: layout.$large-gap;
background-color: colors.$teal-300;
.content,
.box {
&:not(:last-child) {
margin-bottom: layout.$large-gap;
}
}
.content {
> *:first-child {
margin-top: 0;
}
> *:last-child {
margin-bottom: 0;
}
}
.box {
margin: layout.$large-gap 0;
padding: layout.$large-gap;
background: colors.$gray-50;
@include colors.card-shadow;
h3 {
margin: 0;
text-transform: uppercase;
}
}
@media screen and (min-width: layout.$breakpoint) {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: layout.$large-gap;
.content,
.box {
grid-column: span 3;
margin: 0;
&:not(:last-child) {
margin-bottom: 0;
}
}
.box:not(.first) {
grid-column: span 2;
}
}
}
// This is an HTML/CSS-only tabs component. It expects the following markup:
//
// <div class="tabs-widget">
// <div id="second" class="tab">Other, totally novel content.</div>
// <a href="#second" rel="tab">Second</a>
// <div id="first" class="tab">Some content, including a heading.</div>
// <a href="#first" rel="tab">First</a>
// </div>
//
// The key thing here is that the container is a flexbox with that flows in
// reverse row direction. That means that the first element in the container
// <div> will be shown last, which means we can use the ~ and + selectors to
// target all and the immediately following tabs and / or their corresponding
// links.
// The last tab in the DOM (which is shown first because of the reversed
// flexbox) is shown by default, while the other ones are hidden. If one of the
// tabs is targeted by the URL's hash, it is shown instead and the default tab
// is hidden.
.tabs-widget {
display: flex;
flex-direction: row-reverse;
flex-wrap: wrap;
justify-content: center;
margin-top: #{-1 * layout.$large-gap};
> a {
display: block;
margin: 0 layout.$normal-gap;
text-decoration: none;
color: inherit;
}
> .tab {
flex: 100% 1;
order: -1;
display: none;
margin: layout.$large-gap 0;
padding: layout.$large-gap;
background: colors.$gray-50;
@include colors.card-shadow;
&:last-of-type,
&:target {
display: block;
+ a {
font-weight: typography.$emphasized-weight;
color: colors.$blue-800;
}
}
&:target {
~ .tab {
display: none;
+ a {
font-weight: inherit;
color: inherit;
}
}
}
}
}

View file

@ -1,6 +1,7 @@
$normal-weight: 400;
$emphasized-weight: 600;
// This is the major third type scale.
$base-size: 1rem;
$title-size: 2.44rem;
$heading-size: 1.95rem;
@ -37,7 +38,7 @@ $comfortaa-weights: (
html {
$fallback-fonts: Roboto, Arial, sans-serif;
font-size: 100%;
font-size: 125%; // Scale from 16px to 20px
font-family: Comfortaa, $fallback-fonts;
font-weight: $normal-weight;

View file

@ -0,0 +1,56 @@
@use '../colors';
@use '../layout';
.boxes-module {
padding: layout.$large-gap;
background-color: colors.$teal-300;
.content,
.box {
&:not(:last-child) {
margin-bottom: layout.$large-gap;
}
}
.content {
> *:first-child {
margin-top: 0;
}
> *:last-child {
margin-bottom: 0;
}
}
.box {
margin: layout.$large-gap 0;
padding: layout.$large-gap;
background: colors.$gray-50;
@include colors.card-shadow;
h3 {
margin: 0;
text-transform: uppercase;
}
}
@media screen and (min-width: layout.$breakpoint) {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: layout.$large-gap;
.content,
.box {
grid-column: span 3;
margin: 0;
&:not(:last-child) {
margin-bottom: 0;
}
}
.box:not(.first) {
grid-column: span 2;
}
}
}

View file

@ -0,0 +1,157 @@
@use '../colors';
@use '../layout';
@use '../typography';
.form-choices {
margin: layout.$huge-gap auto;
max-width: 50rem;
list-style: none;
text-align: center;
> li {
position: relative;
&:before {
content: '\2771';
display: inline-block;
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
}
&:not(:last-child) {
&:before {
top: calc(50% - #{layout.$large-gap / 2});
}
&::after {
content: '';
display: block;
margin: layout.$large-gap auto;
width: 15rem;
height: 1px;
background-color: colors.$gray-300;
}
}
> a {
padding: layout.$small-gap layout.$normal-gap;
display: inline-block;
line-height: 2.5;
text-decoration: none;
&:hover {
background-color: colors.$yellow-600;
color: inherit;
@include colors.card-shadow;
}
> em {
padding-block: layout.$small-gap;
font-style: inherit;
background-color: colors.$yellow-600;
}
}
}
}
%form-item {
display: flex;
align-items: center;
margin: layout.$normal-gap auto;
max-width: 50rem;
}
%form-label {
font-weight: typography.$emphasized-weight;
color: colors.$blue-800;
}
%base-form-input {
background-color: transparent;
border: #{2px / 16px * 1rem} solid colors.$blue-800;
}
%form-input {
@extend %base-form-input;
padding: layout.$small-gap;
font: inherit;
&:hover {
background-color: colors.$gray-300;
}
&:focus-visible,
&:active {
outline: none;
background-color: colors.$yellow-600;
}
}
.form-input {
@extend %form-item;
> span {
@extend %form-label;
flex-grow: 1;
text-align: right;
}
> input,
> textarea {
@extend %form-input;
flex-basis: 60%;
margin-left: layout.$normal-gap;
}
}
.form-checkbox {
$size: 2rem;
$gap: layout.$small-gap;
@extend %form-item;
justify-content: flex-end;
&:hover > div {
background-color: colors.$gray-300;
}
> input {
opacity: 0;
&:checked + div::before {
content: '\2713';
font-size: 1.8rem;
line-height: $size;
}
&:focus-visible + div {
background-color: colors.$yellow-600;
}
}
> div {
@extend %base-form-input;
width: $size;
height: $size;
text-align: center;
}
> span {
@extend %form-label;
flex-basis: calc(60% - #{$size + $gap});
margin-left: $gap;
}
}
.form-submit {
@extend %form-item;
justify-content: flex-end;
margin: layout.$huge-gap auto;
> input {
@extend %form-input;
flex-basis: 60%;
}
}

View file

@ -0,0 +1,86 @@
@use '../colors';
@use '../layout';
@use '../typography';
// This is the wrapper element around individual .page-content blocks. The home
// page contains a few of these sections, while normal pages only contain one.
// Spanning the entire width, sections may have different themes.
.page-section {
padding: layout.$large-gap;
&.inverse {
color: colors.$gray-50;
background-color: colors.$blue-800;
h2:after {
background-color: colors.$gray-50;
}
}
&.footer {
background-color: colors.$teal-500;
}
}
.page-content {
margin: 0 auto layout.$huge-gap auto;
max-width: 60rem;
}
// Banners can be put at the top of a page to draw attention. A banner has
// two children:
// - A .background element which contains an image to render behind the text
// - A .content which holds the actual text.
.page-banner {
display: flex;
flex-direction: column;
justify-content: space-around;
position: relative;
min-height: 60vh;
> .background {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
> .content {
display: flex;
flex-direction: column;
align-items: flex-start;
position: relative;
padding: layout.$normal-gap max(#{layout.$large-gap}, 15vw);
> div {
display: inline-block;
padding: layout.$small-gap layout.$normal-gap;
font-size: typography.$subheading-size;
background-color: colors.$yellow-600;
> p:first-child {
margin-top: 0;
}
> p:last-child {
margin-bottom: 0;
}
}
> .title {
padding: 0 layout.$normal-gap;
line-height: 5rem;
font-size: typography.$title-size;
font-weight: typography.$emphasized-weight;
background-color: colors.$teal-500;
}
}
}

View file

@ -0,0 +1,124 @@
@use '../colors';
@use '../layout';
@use '../typography';
@mixin header-item {
padding: 0 layout.$normal-gap;
line-height: 3rem;
}
// The site logo text. More specific styles for this element are also present
// underneath .site-header.
.site-logo {
margin: 0 layout.$normal-gap;
text-transform: lowercase;
}
// The navigation is present twice on the site: once in the header and once in
// the footer. The former also has some specific styles (see .site-header
// below).
.site-navigation {
&.horizontal {
> ul {
display: flex;
margin-bottom: 0;
}
a {
display: inline-block;
@include header-item;
}
}
> ul {
margin: 0;
padding: 0;
list-style: none;
}
a {
display: block;
padding: layout.$small-gap;
font-weight: typography.$emphasized-weight;
text-align: center;
text-decoration: none;
text-transform: lowercase;
}
}
.site-mobile-navigation {
cursor: pointer;
> summary {
display: block;
@include header-item;
}
&[open] {
flex-basis: 100%;
> summary {
// The positioning requires that the header component has relative
// positioning.
position: absolute;
top: 0;
right: 0;
color: colors.$blue-800;
}
}
// This is the next site navigation block (the one that's visible on desktop),
// while...
+ .site-navigation {
display: none;
}
// ... this here is the one inside the mobile-only <details> block.
> .site-navigation {
&::before {
content: '';
display: block;
margin: 0 auto;
width: calc(100% - #{2 * layout.$normal-gap});
height: 1px;
background-color: colors.$gray-300;
}
}
@media screen and (min-width: layout.$breakpoint) {
display: none;
+ .site-navigation {
display: block;
}
}
}
.site-header {
display: flex;
// This container needs to wrap because when the navigation is open on small
// screens, we want it to overflow into its own line.
flex-wrap: wrap;
align-items: center;
// Relative positioning is required here so that we can fake the menu button's
// location on mobile.
position: relative;
z-index: 10;
background-color: colors.$main-background;
@include colors.block-shadow;
> .site-logo {
flex-grow: 1;
margin: 0;
font-size: typography.$subheading-size;
text-decoration: none;
@include header-item;
}
}
.site-footer {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: layout.$normal-gap;
}

View file

@ -0,0 +1,67 @@
@use '../colors';
@use '../layout';
@use '../typography';
// This is an HTML/CSS-only tabs component. It expects the following markup:
//
// <div class="tabs-widget">
// <div id="second" class="tab">Other, totally novel content.</div>
// <a href="#second" rel="tab">Second</a>
// <div id="first" class="tab">Some content, including a heading.</div>
// <a href="#first" rel="tab">First</a>
// </div>
//
// The key thing here is that the container is a flexbox with that flows in
// reverse row direction. That means that the first element in the container
// <div> will be shown last, which means we can use the ~ and + selectors to
// target all and the immediately following tabs and / or their corresponding
// links.
// The last tab in the DOM (which is shown first because of the reversed
// flexbox) is shown by default, while the other ones are hidden. If one of the
// tabs is targeted by the URL's hash, it is shown instead and the default tab
// is hidden.
.tabs-widget {
display: flex;
flex-direction: row-reverse;
flex-wrap: wrap;
justify-content: center;
margin-top: #{-1 * layout.$large-gap};
> a {
display: block;
margin: 0 layout.$normal-gap;
text-decoration: none;
color: inherit;
}
> .tab {
flex: 100% 1;
order: -1;
display: none;
margin: layout.$large-gap 0;
padding: layout.$large-gap;
background: colors.$gray-50;
@include colors.card-shadow;
&:last-of-type,
&:target {
display: block;
+ a {
font-weight: typography.$emphasized-weight;
color: colors.$blue-800;
}
}
&:target {
~ .tab {
display: none;
+ a {
font-weight: inherit;
color: inherit;
}
}
}
}
}

View file

@ -1,3 +1,7 @@
@use 'typography';
@use 'base';
@use 'components';
@use 'components/site';
@use 'components/page';
@use 'components/boxes';
@use 'components/tabs';
@use 'components/forms';