diff --git a/CHANGELOG.md b/CHANGELOG.md
index a285686c..0f33db9a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,71 @@
+# 0.5.0
+
+![Release Date: 2018-12-29](https://img.shields.io/badge/Release_Date-2018--12--29-88c0d0.svg?style=flat-square&colorA=4c566a) [![Project Board](https://img.shields.io/badge/Project_Board-0.5.0-88c0d0.svg?style=flat-square&colorA=4c566a&logo=github&logoColor=eceff4)](https://github.com/arcticicestudio/nord-docs/projects/7) [![Milestone](https://img.shields.io/badge/Milestone-0.5.0-88c0d0.svg?style=flat-square&colorA=4c566a&logo=github&logoColor=eceff4)](https://github.com/arcticicestudio/nord-docs/milestone/5)
+
+This version focused on the essential [footer][gh-106] as well as a styled [link component][gh-105]. It also includes the integration of the Webpack [size-plugin][gh-109] to print the gzipped sizes of assets and the changes since the last production build.
+
+## Features
+
+
+
+The following issues are related to the [“Components” design concept][gh-63].
+
+**Core Atom: “Link”** — #105 ⇄ #107 (⊶ cf1f1184)
+↠ Implemented the core atom `Link` that wraps the [base HTML element atom component the `A`][gh-70] and adds matching brand styles to it.
+
+**Core Organism Component: “Footer”** — #106 ⇄ #108 (⊶ 9a6c0496)
+↠ Implemented the core organism component `Footer` which represent the `` element and is an essential part of _Nord Docs_. It provides a sitemap, the Arctic Ice Studio organization branding logo and caption, networking & social media links as well as the copyright paragraph including version information.
+
+### Layout
+
+The footer uses a CSS [flexbox][mdn-flexbox] and [grid][mdn-grids] layout consisting of two container components with the maximum of flexible space between both. The left-side container contains the branding and link components while the right-side container contains the sitemap like documented in the sections below.
+
+#### Wave Divider
+
+For a nice and smooth transition between the last section/element of a page a new SVG vector graphic divider in form of multiple “overlapping waves” has been added. It must be rendered by the last component/element (in most cases a `Section`/``) to ensure the transparent background of the wave's container matches the last components background by rendering it in the bounds.
+
+#### Sitemap
+
+To allow users to simply navigate around the site, next to the main header, the component provides the quickly accessible sitemap. This container uses the [flexbox][mdn-flexbox] layout where each base route of the site is added as one category represented as a column. Each of these consists of an heading, the name of the route, and the corresponding sub-routes.
+
+As of now the following base routes are included:
+
+- “Nord” — links to `/` and includes all sections of the main landing page.
+- “Ports” — links to `/ports` and includes all sections of the Nord port projects.
+- “Docs” — links to `/docs` and includes all sections of Nord's documentation.
+- “Blog” — links to `/blog` and includes all sections of Nord's blog.
+- “Community” — links to `/community` and includes all sections of the Nord community channels.
+
+#### Organization Branding
+
+To represent Arctic Ice Studio's branding, the left-sided container contains the logo with the caption that'll link to the organization website. It is placed in one line with the category heading of the sitemap like documented in the section above.
+
+#### Social Media & Networking Links
+
+The left-side container also contains the social media & networking links where each link is represented through the icon of the corresponding site/service. They are placed in one line with a flexible layout to adust based on the available width.
+
+#### Version Information
+
+The last elements of the left-side container is a paragraph providing version information about the site like the currently running version (with _commits ahead_ metadata when required) and the build & deployment date. It also has additional Git metadata added as `data-` attributes and a `` HTML element.
+
+Full Width
+
+Reduced Width
+
+Small Width
+
+### Responsive Design
+
+For reduced width views (responsive design) the footer adjusts several styles and composed components. For really small view ports the grid layout be switches to a flexbox layout.
+
+
+
+**Core Organism Component: “Footer”** — #109 (⊶ 75435d07)
+↠ Integrated the Webpack [size-plugin][gh-sp] that prints the gzipped sizes of assets and the changes since the last build added through [gatsby-plugin-webpack-size][gh-gp-ws].
+
# 0.4.0
![Release Date: 2018-12-23](https://img.shields.io/badge/Release_Date-2018--12--23-88c0d0.svg?style=flat-square&colorA=4c566a) [![Project Board](https://img.shields.io/badge/Project_Board-0.4.0-88c0d0.svg?style=flat-square&colorA=4c566a&logo=github&logoColor=eceff4)](https://github.com/arcticicestudio/nord-docs/projects/6) [![Milestone](https://img.shields.io/badge/Milestone-0.4.0-88c0d0.svg?style=flat-square&colorA=4c566a&logo=github&logoColor=eceff4)](https://github.com/arcticicestudio/nord-docs/milestone/4)
@@ -720,6 +785,7 @@ Note that packages marked with an double exclamation mark `‼` have been affect
[gh-65]: https://github.com/arcticicestudio/nord-docs/issues/65
[gh-66]: https://github.com/arcticicestudio/nord-docs/issues/66
[gh-69]: https://github.com/arcticicestudio/nord-docs/issues/69
+[gh-70]: https://github.com/arcticicestudio/nord-docs/issues/70
[gh-74]: https://github.com/arcticicestudio/nord-docs/issues/74
[gh-78]: https://github.com/arcticicestudio/nord-docs/issues/78
[gh-84]: https://github.com/arcticicestudio/nord-docs/issues/84
@@ -732,9 +798,13 @@ Note that packages marked with an double exclamation mark `‼` have been affect
[gh-98]: https://github.com/arcticicestudio/nord-docs/issues/98
[gh-100]: https://github.com/arcticicestudio/nord-docs/issues/100
[gh-101]: https://github.com/arcticicestudio/nord-docs/issues/101
+[gh-105]: https://github.com/arcticicestudio/nord-docs/issues/105
+[gh-106]: https://github.com/arcticicestudio/nord-docs/issues/106
+[gh-109]: https://github.com/arcticicestudio/nord-docs/issues/109
[gh-bsl]: https://github.com/willmcpo/body-scroll-lock
[gh-community-profile]: https://github.com/arcticicestudio/nord-docs/community
[gh-eslint-config-arcticicestudio]: https://github.com/arcticicestudio/eslint-config-arcticicestudio
+[gh-gp-ws]: https://github.com/axe312ger/gatsby-plugin-webpack-size
[gh-help-coc]: https://help.github.com/articles/adding-a-code-of-conduct-to-your-project
[gh-help-code-owners]: https://help.github.com/articles/about-codeowners
[gh-help-contrib-gl]: https://help.github.com/articles/setting-guidelines-for-repository-contributors
@@ -750,6 +820,7 @@ Note that packages marked with an double exclamation mark `‼` have been affect
[gh-remark-lint]: https://github.com/remarkjs/remark-lint
[gh-remark-preset-lint-arcticicestudio]: https://github.com/arcticicestudio/remark-preset-lint-arcticicestudio
[gh-rtl]: https://github.com/kentcdodds/react-testing-library
+[gh-sp]: https://github.com/GoogleChromeLabs/size-plugin
[gh-styleguide-git]: https://github.com/arcticicestudio/styleguide-git
[gh-styleguide-js]: https://github.com/arcticicestudio/styleguide-javascript
[gh-styleguide-md]: https://github.com/arcticicestudio/styleguide-markdown
@@ -762,6 +833,8 @@ Note that packages marked with an double exclamation mark `‼` have been affect
[json-ld]: https://json-ld.org
[md]: https://material.io
[md-com-es]: https://material.io/design/communication/empty-states.html
+[mdn-flexbox]: https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox
+[mdn-grids]: https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Grids
[md-motion-speed]: https://material.io/design/motion/speed.html
[mdn-html-el-a]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a
[mdn-html-el-cs]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element#Content_sectioning
diff --git a/gatsby-config.js b/gatsby-config.js
index 77eb70fe..fc4c00f9 100644
--- a/gatsby-config.js
+++ b/gatsby-config.js
@@ -26,7 +26,7 @@ const {
const { BASE_PUBLIC_URL } = require("./src/config/routes/constants");
const gatsbyPluginGoogleGtagConfig = require("./.gatsby/plugins/google/gtag");
const gatsbyPluginManifestConfig = require("./.gatsby/plugins/manifest");
-const gatsbyPluginRobotsTxt = require("./.gatsby/plugins/robots-txt");
+const gatsbyPluginRobotsTxtConfig = require("./.gatsby/plugins/robots-txt");
module.exports = {
siteMetadata: {
@@ -43,6 +43,7 @@ module.exports = {
"gatsby-transformer-yaml",
"gatsby-plugin-svgr",
"gatsby-plugin-sitemap",
+ "gatsby-plugin-webpack-size",
{
resolve: "gatsby-plugin-canonical-urls",
options: {
@@ -90,7 +91,7 @@ module.exports = {
},
{
resolve: "gatsby-plugin-robots-txt",
- options: gatsbyPluginRobotsTxt
+ options: gatsbyPluginRobotsTxtConfig
},
/* NOTE: The following plugins rely on the order in this array and must be placed at last in order work properly! */
{
diff --git a/package-lock.json b/package-lock.json
index 1205826f..43a5facf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "nord-docs",
- "version": "0.4.0",
+ "version": "0.5.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -7627,6 +7627,14 @@
"resolved": "https://registry.npmjs.org/gatsby-plugin-svgr/-/gatsby-plugin-svgr-2.0.1.tgz",
"integrity": "sha512-iNhS3e8TrWkrPY5EgrWpKoxh13DEcP3f8DrVGQ0mz8qafCHxcxjLUKaCUO6WZlgxsANIhm3dMXiABvqAebApzw=="
},
+ "gatsby-plugin-webpack-size": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/gatsby-plugin-webpack-size/-/gatsby-plugin-webpack-size-0.0.3.tgz",
+ "integrity": "sha512-+SeXLobugpnDd9ZMKTQqypvUi67XjzJJm4NfNhOsEiRVbOep4TJNWGYzh4smb29/26cT/ZKfg+tdeTYpuB6AXA==",
+ "requires": {
+ "size-plugin": "^1.0.1"
+ }
+ },
"gatsby-react-router-scroll": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/gatsby-react-router-scroll/-/gatsby-react-router-scroll-2.0.2.tgz",
@@ -16836,6 +16844,41 @@
"url-join": "^1.1.0"
}
},
+ "size-plugin": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/size-plugin/-/size-plugin-1.1.1.tgz",
+ "integrity": "sha512-32k0gfNVkP8bHYtA1zmgsko6kKRuB97l480rmnUxQe9jHabYSx29psB2eFXb9dlqQww0T1E/cqV2D1fXaFnjfQ==",
+ "requires": {
+ "chalk": "^2.4.1",
+ "escape-string-regexp": "^1.0.5",
+ "glob": "^7.1.2",
+ "gzip-size": "^5.0.0",
+ "minimatch": "^3.0.4",
+ "pretty-bytes": "^5.1.0",
+ "util.promisify": "^1.0.0"
+ },
+ "dependencies": {
+ "gzip-size": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.0.0.tgz",
+ "integrity": "sha512-5iI7omclyqrnWw4XbXAmGhPsABkSIDQonv2K0h61lybgofWa6iZyvrI3r2zsJH4P8Nb64fFVzlvfhs0g7BBxAA==",
+ "requires": {
+ "duplexer": "^0.1.1",
+ "pify": "^3.0.0"
+ }
+ },
+ "pify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
+ },
+ "pretty-bytes": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.1.0.tgz",
+ "integrity": "sha512-wa5+qGVg9Yt7PB6rYm3kXlKzgzgivYTLRandezh43jjRqgyDyP+9YxfJpJiLs9yKD1WeU8/OvtToWpW7255FtA=="
+ }
+ }
+ },
"slash": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
diff --git a/package.json b/package.json
index 3177b0cb..f45dfa1b 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "nord-docs",
"title": "Nord Docs",
- "version": "0.4.0",
+ "version": "0.5.0",
"description": "The official Nord website and documentation",
"author": {
"name": "Arctic Ice Studio",
@@ -98,6 +98,7 @@
"gatsby-plugin-sitemap": "2.0.3",
"gatsby-plugin-styled-components": "3.0.4",
"gatsby-plugin-svgr": "2.0.1",
+ "gatsby-plugin-webpack-size": "0.0.3",
"gatsby-source-filesystem": "2.0.12",
"gatsby-transformer-yaml": "2.1.6",
"inter-ui": "3.1.0",
@@ -108,6 +109,7 @@
"react-dom": "16.7.0",
"react-helmet": "5.2.0",
"react-pose": "4.0.4",
+ "semver": "5.6.0",
"styled-components": "4.1.3",
"styled-modern-normalize": ">=0.2.0 <1.0.0",
"styled-theming": "2.2.0",
diff --git a/src/assets/images/icons/eva-icons/heart-fill.svg b/src/assets/images/icons/eva-icons/heart-fill.svg
new file mode 100755
index 00000000..b37023aa
--- /dev/null
+++ b/src/assets/images/icons/eva-icons/heart-fill.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/assets/images/icons/eva-icons/heart-outline.svg b/src/assets/images/icons/eva-icons/heart-outline.svg
new file mode 100755
index 00000000..aec33fe9
--- /dev/null
+++ b/src/assets/images/icons/eva-icons/heart-outline.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/assets/images/icons/simple-icons/discord.svg b/src/assets/images/icons/simple-icons/discord.svg
new file mode 100755
index 00000000..4380f9f6
--- /dev/null
+++ b/src/assets/images/icons/simple-icons/discord.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/assets/images/icons/simple-icons/github.svg b/src/assets/images/icons/simple-icons/github.svg
new file mode 100755
index 00000000..922b47b6
--- /dev/null
+++ b/src/assets/images/icons/simple-icons/github.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/assets/images/icons/simple-icons/keybase.svg b/src/assets/images/icons/simple-icons/keybase.svg
new file mode 100755
index 00000000..08018c59
--- /dev/null
+++ b/src/assets/images/icons/simple-icons/keybase.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/assets/images/icons/simple-icons/reddit.svg b/src/assets/images/icons/simple-icons/reddit.svg
new file mode 100755
index 00000000..ef3b25d3
--- /dev/null
+++ b/src/assets/images/icons/simple-icons/reddit.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/assets/images/icons/simple-icons/slack.svg b/src/assets/images/icons/simple-icons/slack.svg
new file mode 100755
index 00000000..88801ae1
--- /dev/null
+++ b/src/assets/images/icons/simple-icons/slack.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/assets/images/icons/simple-icons/stackoverflow.svg b/src/assets/images/icons/simple-icons/stackoverflow.svg
new file mode 100755
index 00000000..3695aa2d
--- /dev/null
+++ b/src/assets/images/icons/simple-icons/stackoverflow.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/assets/images/icons/simple-icons/twitter.svg b/src/assets/images/icons/simple-icons/twitter.svg
new file mode 100755
index 00000000..8c49818b
--- /dev/null
+++ b/src/assets/images/icons/simple-icons/twitter.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/assets/images/icons/spectrum.svg b/src/assets/images/icons/spectrum.svg
new file mode 100644
index 00000000..a1de462c
--- /dev/null
+++ b/src/assets/images/icons/spectrum.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/assets/images/logos/arcticicestudio.svg b/src/assets/images/logos/arcticicestudio.svg
new file mode 100644
index 00000000..62affec4
--- /dev/null
+++ b/src/assets/images/logos/arcticicestudio.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/components/atoms/core/Link/Link.jsx b/src/components/atoms/core/Link/Link.jsx
new file mode 100644
index 00000000..93e96d21
--- /dev/null
+++ b/src/components/atoms/core/Link/Link.jsx
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import PropTypes from "prop-types";
+import styled from "styled-components";
+
+import { A } from "atoms/core/HTMLElements";
+
+import { calmly, decent, minimal } from "./styles";
+
+const variants = {
+ calmly,
+ decent,
+ minimal
+};
+
+/**
+ * A wrapper for the base HTML component `A` with multiple styles that can be selected through the `variant` prop.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+const Link = styled(A)`
+ ${({ variant }) => variants[variant]};
+`;
+
+Link.propTypes = {
+ variant: PropTypes.oneOf(Object.keys(variants))
+};
+
+Link.defaultProps = {
+ variant: "calmly"
+};
+
+export default Link;
diff --git a/src/components/atoms/core/Link/index.js b/src/components/atoms/core/Link/index.js
new file mode 100644
index 00000000..19903a1b
--- /dev/null
+++ b/src/components/atoms/core/Link/index.js
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+export { default } from "./Link";
diff --git a/src/components/atoms/core/Link/styles.js b/src/components/atoms/core/Link/styles.js
new file mode 100644
index 00000000..978bc8cf
--- /dev/null
+++ b/src/components/atoms/core/Link/styles.js
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+/**
+ * @file Provides multiple styles for the `Link` component.
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+
+import { css } from "styled-components";
+import { lighten, rgba } from "polished";
+
+import { colors, motion, themedMode, MODE_BRIGHT_SNOW_FLURRY, MODE_DARK_NIGHT_FROST } from "styles/theme";
+
+const backgroundColorHover = themedMode({
+ [MODE_BRIGHT_SNOW_FLURRY]: rgba(colors.nord6, 0.45),
+ [MODE_DARK_NIGHT_FROST]: rgba(colors.nord3, 0.8)
+});
+
+const fontColor = themedMode({
+ [MODE_BRIGHT_SNOW_FLURRY]: colors.nord10,
+ [MODE_DARK_NIGHT_FROST]: colors.nord8
+});
+
+const fontColorDecent = themedMode({
+ [MODE_BRIGHT_SNOW_FLURRY]: colors.nord0,
+ [MODE_DARK_NIGHT_FROST]: lighten(0.2, colors.font.base[MODE_DARK_NIGHT_FROST])
+});
+
+const fontColorHover = themedMode({
+ [MODE_BRIGHT_SNOW_FLURRY]: colors.nord10
+});
+
+const fontColorHoverMinimal = themedMode({
+ [MODE_BRIGHT_SNOW_FLURRY]: colors.nord0,
+ [MODE_DARK_NIGHT_FROST]: lighten(0.2, colors.font.base[MODE_DARK_NIGHT_FROST])
+});
+
+const calmly = css`
+ border-radius: 0.25em;
+ color: ${fontColor};
+ transition: color ${motion.speed.duration.transition.text.fade}ms ease-in-out,
+ background-color ${motion.speed.duration.transition.text.fade}ms ease-in-out;
+
+ &:hover,
+ &:active,
+ &:focus {
+ background-color: ${backgroundColorHover};
+ color: ${fontColorHover};
+ }
+`;
+
+const decent = css`
+ border-bottom: 1px solid ${fontColor};
+ color: ${fontColorDecent};
+ transition: color ${motion.speed.duration.transition.text.fade}ms ease-in-out;
+
+ &:hover,
+ &:active,
+ &:focus {
+ color: ${fontColor};
+ }
+`;
+
+const minimal = css`
+ border-bottom: 1px solid ${fontColor};
+ transition: border-bottom-color ${motion.speed.duration.transition.text.fade}ms ease-in-out;
+
+ &:hover,
+ &:active,
+ &:focus {
+ border-bottom-color: ${fontColorHoverMinimal};
+ }
+`;
+
+export { calmly, decent, minimal };
diff --git a/src/components/atoms/core/SiteMetadata/SiteMetadata.jsx b/src/components/atoms/core/SiteMetadata/SiteMetadata.jsx
index 8701a089..f2eacd87 100644
--- a/src/components/atoms/core/SiteMetadata/SiteMetadata.jsx
+++ b/src/components/atoms/core/SiteMetadata/SiteMetadata.jsx
@@ -26,7 +26,9 @@ const PureSiteMetadata = ({
description,
keywords: keywordsNord,
links: {
- social: { twitter }
+ organization: {
+ social: { twitter }
+ }
},
title
},
@@ -38,7 +40,7 @@ const PureSiteMetadata = ({
}) => (
-
+
@@ -110,9 +112,11 @@ const SiteMetadata = ({ pathName, ...passProp }) => (
description
keywords
links {
- social {
- twitter {
- id
+ organization {
+ social {
+ twitter {
+ id
+ }
}
}
}
diff --git a/src/components/atoms/core/vectors/divider/DividerSvg.jsx b/src/components/atoms/core/vectors/divider/DividerSvg.jsx
new file mode 100644
index 00000000..1280f6f4
--- /dev/null
+++ b/src/components/atoms/core/vectors/divider/DividerSvg.jsx
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import styled from "styled-components";
+
+/**
+ * A styled SVG element with essential styles for divider vector graphic components.
+ *
+ * It applies two CSS styles to render problems and ensure SVG vector graphic components are handled as block-elements.
+ * Setting `dislay: block` is required to prevent gaps within the container caused by the SVG being treated as text
+ * element (`inline-block`) by default which gets affected by the `line-height` property. This can also be fixed by
+ * setting `line-height: 0` instead.
+ *
+ * Due to a bug or difference between Firefox and other browser rendering engines there is a `1px` gap between rendered
+ * SVGs elements and the following element.
+ * Applying `bottom: -1px` prevents these gaps, but unfortunately also requires following elements in the DOM to
+ * compensate for the resulting gap.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @see https://developer.mozilla.org/de/docs/Web/SVG
+ * @since 0.5.0
+ */
+const DividerSvg = styled.svg`
+ display: block;
+ bottom: -1px;
+ left: 0;
+ right: 0;
+ width: 100%;
+ background-color: transparent;
+ pointer-events: none;
+ user-select: none;
+ vertical-align: middle;
+ overflow: hidden;
+`;
+
+export default DividerSvg;
diff --git a/src/components/atoms/core/vectors/divider/WaveFooter.jsx b/src/components/atoms/core/vectors/divider/WaveFooter.jsx
new file mode 100644
index 00000000..608aa58d
--- /dev/null
+++ b/src/components/atoms/core/vectors/divider/WaveFooter.jsx
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import { css } from "styled-components";
+import { darken, lighten } from "polished";
+
+import { colors, themedMode, MODE_BRIGHT_SNOW_FLURRY, MODE_DARK_NIGHT_FROST } from "styles/theme";
+
+import { themeModeFillColorStyles } from "../shared/styles";
+import DividerSvg from "./DividerSvg";
+
+const fillColorWave1 = themedMode({
+ [MODE_BRIGHT_SNOW_FLURRY]: lighten(0.025, colors.nord6),
+ [MODE_DARK_NIGHT_FROST]: darken(0.02, colors.nord1)
+});
+
+const fillColorWave2 = themedMode({
+ [MODE_BRIGHT_SNOW_FLURRY]: lighten(0.035, colors.nord6),
+ [MODE_DARK_NIGHT_FROST]: darken(0.01, colors.nord1)
+});
+
+const fillColorWave3 = themedMode({
+ [MODE_BRIGHT_SNOW_FLURRY]: colors.background.sectioning.primary[MODE_BRIGHT_SNOW_FLURRY],
+ [MODE_DARK_NIGHT_FROST]: colors.background.sectioning.primary[MODE_DARK_NIGHT_FROST]
+});
+
+/**
+ * A SVG vector graphic divider component consisting of three overlapping waves.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @see https://developer.mozilla.org/de/docs/Web/SVG
+ * @since 0.5.0
+ */
+const WaveFooter = props => (
+
+
+
+
+
+);
+
+export default WaveFooter;
diff --git a/src/components/atoms/core/vectors/divider/index.js b/src/components/atoms/core/vectors/divider/index.js
new file mode 100644
index 00000000..e324f19f
--- /dev/null
+++ b/src/components/atoms/core/vectors/divider/index.js
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+/**
+ * @file Provides SVG vector graphic divider components.
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @see https://developer.mozilla.org/de/docs/Web/SVG
+ * @since 0.5.0
+ */
+
+import WaveFooter from "./WaveFooter";
+
+/* eslint-disable-next-line import/prefer-default-export */
+export { WaveFooter };
diff --git a/src/components/atoms/core/vectors/icons/Discord.jsx b/src/components/atoms/core/vectors/icons/Discord.jsx
new file mode 100644
index 00000000..121cd9e1
--- /dev/null
+++ b/src/components/atoms/core/vectors/icons/Discord.jsx
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import styled from "styled-components";
+
+import { ReactComponent as DiscordSVG } from "assets/images/icons/simple-icons/discord.svg";
+
+import { iconDefaultProps, iconPropTypes, themeModeFillColorStyles } from "../shared";
+
+const DiscordIcon = styled(DiscordSVG)`
+ ${themeModeFillColorStyles};
+`;
+
+/**
+ * The "Discord" logo icon from the "Simple Icons" project as styled SVG vector graphic component.
+ * By default, it uses the fill color and transition based on the current active global theme mode.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @see https://simpleicons.org
+ * @since 0.5.0
+ */
+const Discord = ({ className, svgRef }) => ;
+
+Discord.propTypes = iconPropTypes;
+
+Discord.defaultProps = iconDefaultProps;
+
+export default Discord;
diff --git a/src/components/atoms/core/vectors/icons/GitHub.jsx b/src/components/atoms/core/vectors/icons/GitHub.jsx
new file mode 100644
index 00000000..4a92e560
--- /dev/null
+++ b/src/components/atoms/core/vectors/icons/GitHub.jsx
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import styled from "styled-components";
+
+import { ReactComponent as GitHubSVG } from "assets/images/icons/simple-icons/github.svg";
+
+import { iconDefaultProps, iconPropTypes, themeModeFillColorStyles } from "../shared";
+
+const GitHubIcon = styled(GitHubSVG)`
+ ${themeModeFillColorStyles};
+`;
+
+/**
+ * The "GitHub" logo icon from the "Simple Icons" project as styled SVG vector graphic component.
+ * By default, it uses the fill color and transition based on the current active global theme mode.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @see https://simpleicons.org
+ * @since 0.5.0
+ */
+const GitHub = ({ className, svgRef }) => ;
+
+GitHub.propTypes = iconPropTypes;
+
+GitHub.defaultProps = iconDefaultProps;
+
+export default GitHub;
diff --git a/src/components/atoms/core/vectors/icons/Heart.jsx b/src/components/atoms/core/vectors/icons/Heart.jsx
new file mode 100644
index 00000000..d64acfcc
--- /dev/null
+++ b/src/components/atoms/core/vectors/icons/Heart.jsx
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import styled from "styled-components";
+
+import { ReactComponent as HeartSVGFill } from "assets/images/icons/eva-icons/heart-fill.svg";
+import { ReactComponent as HeartSVGOutline } from "assets/images/icons/eva-icons/heart-outline.svg";
+
+import { iconDefaultProps, iconPropTypes, themeModeFillColorStyles } from "../shared";
+
+const HeartIconFill = styled(HeartSVGFill)`
+ ${themeModeFillColorStyles};
+`;
+
+const HeartIconOutline = styled(HeartSVGOutline)`
+ ${themeModeFillColorStyles};
+`;
+
+/**
+ * The "heart" icon from "Eva Icons" as styled SVG vector graphic component.
+ * The "outline" variant can be used by passing the `outlined` boolean prop.
+ * By default, it uses the fill color and transition based on the current active global theme mode.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @see https://akveo.github.io/eva-icons
+ * @since 0.5.0
+ */
+const Heart = ({ className, outlined, svgRef }) =>
+ outlined ? (
+
+ ) : (
+
+ );
+
+Heart.propTypes = iconPropTypes;
+
+Heart.defaultProps = iconDefaultProps;
+
+export default Heart;
diff --git a/src/components/atoms/core/vectors/icons/Keybase.jsx b/src/components/atoms/core/vectors/icons/Keybase.jsx
new file mode 100644
index 00000000..9ca6c410
--- /dev/null
+++ b/src/components/atoms/core/vectors/icons/Keybase.jsx
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import styled from "styled-components";
+
+import { ReactComponent as KeybaseSVG } from "assets/images/icons/simple-icons/keybase.svg";
+
+import { iconDefaultProps, iconPropTypes, themeModeFillColorStyles } from "../shared";
+
+const KeybaseIcon = styled(KeybaseSVG)`
+ ${themeModeFillColorStyles};
+`;
+
+/**
+ * The "Keybase" logo icon from the "Simple Icons" project as styled SVG vector graphic component.
+ * By default, it uses the fill color and transition based on the current active global theme mode.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @see https://simpleicons.org
+ * @since 0.5.0
+ */
+const Keybase = ({ className, svgRef }) => ;
+
+Keybase.propTypes = iconPropTypes;
+
+Keybase.defaultProps = iconDefaultProps;
+
+export default Keybase;
diff --git a/src/components/atoms/core/vectors/icons/Menu.jsx b/src/components/atoms/core/vectors/icons/Menu.jsx
index 5bdcdd28..c0f8f7d8 100644
--- a/src/components/atoms/core/vectors/icons/Menu.jsx
+++ b/src/components/atoms/core/vectors/icons/Menu.jsx
@@ -19,7 +19,7 @@ const MenuIconOutline = styled(MenuSVGOutline)`
`;
/**
- * The "menu" icon from "Eva Icons" as SVG vector graphic component.
+ * The "menu" icon from "Eva Icons" as styled SVG vector graphic component.
* By default, it uses the fill color and transition based on the current active global theme mode.
*
* @author Arctic Ice Studio
@@ -27,7 +27,7 @@ const MenuIconOutline = styled(MenuSVGOutline)`
* @see https://akveo.github.io/eva-icons
* @since 0.3.0
*/
-const Menu = ({ svgRef }) => ;
+const Menu = ({ className, svgRef }) => ;
Menu.propTypes = iconPropTypes;
diff --git a/src/components/atoms/core/vectors/icons/Moon.jsx b/src/components/atoms/core/vectors/icons/Moon.jsx
index f7f7d3b7..a165a444 100644
--- a/src/components/atoms/core/vectors/icons/Moon.jsx
+++ b/src/components/atoms/core/vectors/icons/Moon.jsx
@@ -24,7 +24,7 @@ const MoonIconOutline = styled(MoonSVGOutline)`
`;
/**
- * The "moon" icon from "Eva Icons" as SVG vector graphic component.
+ * The "moon" icon from "Eva Icons" as styled SVG vector graphic component.
* The "outline" variant can be used by passing the `outlined` boolean prop.
* By default, it uses the fill color and transition based on the current active global theme mode.
*
@@ -33,8 +33,12 @@ const MoonIconOutline = styled(MoonSVGOutline)`
* @see https://akveo.github.io/eva-icons
* @since 0.3.0
*/
-const Moon = ({ outlined, svgRef }) =>
- outlined ? : ;
+const Moon = ({ className, outlined, svgRef }) =>
+ outlined ? (
+
+ ) : (
+
+ );
Moon.propTypes = iconPropTypes;
diff --git a/src/components/atoms/core/vectors/icons/Reddit.jsx b/src/components/atoms/core/vectors/icons/Reddit.jsx
new file mode 100644
index 00000000..b61b55f9
--- /dev/null
+++ b/src/components/atoms/core/vectors/icons/Reddit.jsx
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import styled from "styled-components";
+
+import { ReactComponent as RedditSVG } from "assets/images/icons/simple-icons/reddit.svg";
+
+import { iconDefaultProps, iconPropTypes, themeModeFillColorStyles } from "../shared";
+
+const RedditIcon = styled(RedditSVG)`
+ ${themeModeFillColorStyles};
+`;
+
+/**
+ * The "Reddit" logo icon from the "Simple Icons" project as styled SVG vector graphic component.
+ * By default, it uses the fill color and transition based on the current active global theme mode.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @see https://simpleicons.org
+ * @since 0.5.0
+ */
+const Reddit = ({ className, svgRef }) => ;
+
+Reddit.propTypes = iconPropTypes;
+
+Reddit.defaultProps = iconDefaultProps;
+
+export default Reddit;
diff --git a/src/components/atoms/core/vectors/icons/Slack.jsx b/src/components/atoms/core/vectors/icons/Slack.jsx
new file mode 100644
index 00000000..d47bb75a
--- /dev/null
+++ b/src/components/atoms/core/vectors/icons/Slack.jsx
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import styled from "styled-components";
+
+import { ReactComponent as SlackSVG } from "assets/images/icons/simple-icons/slack.svg";
+
+import { iconDefaultProps, iconPropTypes, themeModeFillColorStyles } from "../shared";
+
+const SlackIcon = styled(SlackSVG)`
+ ${themeModeFillColorStyles};
+`;
+
+/**
+ * The "Slack" logo icon from the "Simple Icons" project as styled SVG vector graphic component.
+ * By default, it uses the fill color and transition based on the current active global theme mode.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @see https://simpleicons.org
+ * @since 0.5.0
+ */
+const Slack = ({ className, svgRef }) => ;
+
+Slack.propTypes = iconPropTypes;
+
+Slack.defaultProps = iconDefaultProps;
+
+export default Slack;
diff --git a/src/components/atoms/core/vectors/icons/Spectrum.jsx b/src/components/atoms/core/vectors/icons/Spectrum.jsx
new file mode 100644
index 00000000..e1f265ae
--- /dev/null
+++ b/src/components/atoms/core/vectors/icons/Spectrum.jsx
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import styled from "styled-components";
+
+import { ReactComponent as SpectrumSVG } from "assets/images/icons/spectrum.svg";
+
+import { iconDefaultProps, iconPropTypes, themeModeFillColorStyles } from "../shared";
+
+const SpectrumIcon = styled(SpectrumSVG)`
+ ${themeModeFillColorStyles};
+`;
+
+/**
+ * The "Spectrum" logo icon as styled SVG vector graphic component.
+ * By default, it uses the fill color and transition based on the current active global theme mode.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @see https://github.com/withspectrum/spectrum/blob/alpha/public/img/mark.svg
+ * @since 0.5.0
+ */
+const Spectrum = ({ className, svgRef }) => ;
+
+Spectrum.propTypes = iconPropTypes;
+
+Spectrum.defaultProps = iconDefaultProps;
+
+export default Spectrum;
diff --git a/src/components/atoms/core/vectors/icons/StackOverflow.jsx b/src/components/atoms/core/vectors/icons/StackOverflow.jsx
new file mode 100644
index 00000000..50d753a7
--- /dev/null
+++ b/src/components/atoms/core/vectors/icons/StackOverflow.jsx
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import styled from "styled-components";
+
+import { ReactComponent as StackOverflowSVG } from "assets/images/icons/simple-icons/stackoverflow.svg";
+
+import { iconDefaultProps, iconPropTypes, themeModeFillColorStyles } from "../shared";
+
+const StackOverflowIcon = styled(StackOverflowSVG)`
+ ${themeModeFillColorStyles};
+`;
+
+/**
+ * The "StackOverflow" logo icon from the "Simple Icons" project as styled SVG vector graphic component.
+ * By default, it uses the fill color and transition based on the current active global theme mode.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @see https://simpleicons.org
+ * @since 0.5.0
+ */
+const StackOverflow = ({ className, svgRef }) => ;
+
+StackOverflow.propTypes = iconPropTypes;
+
+StackOverflow.defaultProps = iconDefaultProps;
+
+export default StackOverflow;
diff --git a/src/components/atoms/core/vectors/icons/Sun.jsx b/src/components/atoms/core/vectors/icons/Sun.jsx
index 69a0bce4..f5ba4331 100644
--- a/src/components/atoms/core/vectors/icons/Sun.jsx
+++ b/src/components/atoms/core/vectors/icons/Sun.jsx
@@ -24,7 +24,7 @@ const SunIconOutline = styled(SunSVGOutline)`
`;
/**
- * The "sun" icon from "Eva Icons" as SVG vector graphic component.
+ * The "sun" icon from "Eva Icons" as styled SVG vector graphic component.
* The "outline" variant can be used by passing the `outlined` boolean prop.
* By default, it uses the fill color and transition based on the current active global theme mode.
*
@@ -33,7 +33,12 @@ const SunIconOutline = styled(SunSVGOutline)`
* @see https://akveo.github.io/eva-icons
* @since 0.3.0
*/
-const Sun = ({ outlined, svgRef }) => (outlined ? : );
+const Sun = ({ className, outlined, svgRef }) =>
+ outlined ? (
+
+ ) : (
+
+ );
Sun.propTypes = iconPropTypes;
diff --git a/src/components/atoms/core/vectors/icons/Twitter.jsx b/src/components/atoms/core/vectors/icons/Twitter.jsx
new file mode 100644
index 00000000..205eb7f3
--- /dev/null
+++ b/src/components/atoms/core/vectors/icons/Twitter.jsx
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import styled from "styled-components";
+
+import { ReactComponent as TwitterSVG } from "assets/images/icons/simple-icons/twitter.svg";
+
+import { iconDefaultProps, iconPropTypes, themeModeFillColorStyles } from "../shared";
+
+const TwitterIcon = styled(TwitterSVG)`
+ ${themeModeFillColorStyles};
+`;
+
+/**
+ * The "Twitter" logo icon from the "Simple Icons" project as styled SVG vector graphic component.
+ * By default, it uses the fill color and transition based on the current active global theme mode.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @see https://simpleicons.org
+ * @since 0.5.0
+ */
+const Twitter = ({ className, svgRef }) => ;
+
+Twitter.propTypes = iconPropTypes;
+
+Twitter.defaultProps = iconDefaultProps;
+
+export default Twitter;
diff --git a/src/components/atoms/core/vectors/icons/index.js b/src/components/atoms/core/vectors/icons/index.js
index f1c8e068..6581bf7a 100644
--- a/src/components/atoms/core/vectors/icons/index.js
+++ b/src/components/atoms/core/vectors/icons/index.js
@@ -15,8 +15,17 @@
* @since 0.3.0
*/
+import Discord from "./Discord";
+import GitHub from "./GitHub";
+import Heart from "./Heart";
+import Keybase from "./Keybase";
import Menu from "./Menu";
import Moon from "./Moon";
+import Reddit from "./Reddit";
+import Slack from "./Slack";
+import Spectrum from "./Spectrum";
+import StackOverflow from "./StackOverflow";
import Sun from "./Sun";
+import Twitter from "./Twitter";
-export { Menu, Moon, Sun };
+export { Discord, GitHub, Heart, Keybase, Menu, Moon, Reddit, Slack, Spectrum, StackOverflow, Sun, Twitter };
diff --git a/src/components/atoms/core/vectors/logos/ArcticIceStudio.jsx b/src/components/atoms/core/vectors/logos/ArcticIceStudio.jsx
new file mode 100644
index 00000000..a1919b42
--- /dev/null
+++ b/src/components/atoms/core/vectors/logos/ArcticIceStudio.jsx
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import styled from "styled-components";
+
+import { ReactComponent as ArcticIceStudioSVG } from "assets/images/logos/arcticicestudio.svg";
+
+import { themeModeFillColorStyles } from "../shared";
+
+/**
+ * The Arctic Ice Studio logo as SVG vector graphic component.
+ * By default, it uses the fill color and transition based on the current active global theme mode.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @see https://arcticicestudio.com
+ * @since 0.5.0
+ */
+const ArcticIceStudio = styled(ArcticIceStudioSVG)`
+ ${themeModeFillColorStyles};
+`;
+
+export default ArcticIceStudio;
diff --git a/src/components/atoms/core/vectors/logos/index.js b/src/components/atoms/core/vectors/logos/index.js
index 9aff104b..68f7bc0d 100644
--- a/src/components/atoms/core/vectors/logos/index.js
+++ b/src/components/atoms/core/vectors/logos/index.js
@@ -15,7 +15,7 @@
* @since 0.3.0
*/
+import ArcticIceStudio from "./ArcticIceStudio";
import Nord from "./Nord";
-/* eslint-disable-next-line import/prefer-default-export */
-export { Nord };
+export { ArcticIceStudio, Nord };
diff --git a/src/components/containers/core/Section/Content.jsx b/src/components/containers/core/Section/Content.jsx
index 3e7bb80f..959669ad 100644
--- a/src/components/containers/core/Section/Content.jsx
+++ b/src/components/containers/core/Section/Content.jsx
@@ -19,8 +19,8 @@ import CoreContent from "containers/core/Content";
* @since 0.3.0
*/
const Content = styled(CoreContent)`
- margin-top: ${({ compact }) => !compact && "5em"};
- margin-bottom: ${({ compact }) => !compact && "5em"};
+ padding-top: ${({ compact }) => !compact && "5em"};
+ padding-bottom: ${({ compact }) => !compact && "5em"};
`;
export default Content;
diff --git a/src/components/layouts/core/BaseLayout/BaseLayout.jsx b/src/components/layouts/core/BaseLayout/BaseLayout.jsx
index 7e339530..68d94e6b 100644
--- a/src/components/layouts/core/BaseLayout/BaseLayout.jsx
+++ b/src/components/layouts/core/BaseLayout/BaseLayout.jsx
@@ -10,6 +10,7 @@
import React, { Fragment } from "react";
import PropTypes from "prop-types";
+import Footer from "organisms/core/Footer";
import Header from "organisms/core/Header";
import Page from "containers/core/Page";
import Root from "containers/core/Root";
@@ -28,6 +29,7 @@ const BaseLayout = ({ children, pathName }) => (
{children}
+
);
diff --git a/src/components/organisms/core/Footer/Footer.jsx b/src/components/organisms/core/Footer/Footer.jsx
new file mode 100644
index 00000000..dae07b06
--- /dev/null
+++ b/src/components/organisms/core/Footer/Footer.jsx
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React, { Fragment } from "react";
+import { css } from "styled-components";
+/* eslint-disable-next-line import/no-extraneous-dependencies */
+import { Match } from "@reach/router";
+import { StaticQuery, graphql } from "gatsby";
+
+import Link from "atoms/core/Link";
+import { A } from "atoms/core/HTMLElements";
+import { GitHub, Heart, Keybase, Reddit, Slack, Spectrum, StackOverflow, Twitter } from "atoms/core/vectors/icons";
+import { ArcticIceStudio } from "atoms/core/vectors/logos";
+import Section, { Content } from "containers/core/Section";
+import { isRoutePartiallyMatch } from "utils";
+import sitemapCategories from "data/components/organisms/core/Footer/sitemapCategories";
+import { links as projectLinks } from "data/project";
+import {
+ COPYRIGHT_YEAR,
+ GIT_BRANCH,
+ GIT_COMMITHASH,
+ GIT_COMMITS_AHEAD,
+ VERSION,
+ VERSION_CHANNEL,
+ VERSION_STABILITY_STATUS
+} from "config/project/constants";
+
+import { heartIconStyles, organizationBrandLogoHeight, socialNetworkingIconStyles } from "./styles";
+import {
+ Category,
+ Copyright,
+ Grid,
+ Metadata,
+ OrganizationBrand,
+ OrganizationBrandCaption,
+ Sitemap,
+ SitemapCategory,
+ SitemapLink,
+ SitemapList,
+ SocialNetworking
+} from "./styled";
+
+/**
+ * Renders the sitemap category links.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+const renderSitemapCategories = sitemapCategories.map(({ name, url = "", links }, idx) => (
+
+
+
+ {({ location, match }) => (
+
+ {!url ? {name} : {name} }
+
+ )}
+
+
+
+ {links.map(({ title: linkTitle, url: linkURL }) => (
+
+ {linkTitle}
+
+ ))}
+
+
+));
+
+/**
+ * The essential footer component that provides the Arctic Ice Studio's organization branding logo and caption,
+ * networking & social media links as well as the copyright paragraph including version information.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/footer
+ * @since 0.5.0
+ */
+const Footer = () => (
+ (
+
+
+
+
+
+
+ Arctic Ice Studio
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ © 2016-
+ {COPYRIGHT_YEAR} Arctic Ice Studio &{" "}
+ Sven Greb
+
+
+ Made with{" "}
+ {" "}
+ in Germany
+
+
+
+ {VERSION}
+
+
+
+
+
+ {renderSitemapCategories}
+
+
+
+ )}
+ />
+ /* eslint-enable react/jsx-no-bind */
+);
+
+export default Footer;
diff --git a/src/components/organisms/core/Footer/index.js b/src/components/organisms/core/Footer/index.js
new file mode 100644
index 00000000..dfe8043c
--- /dev/null
+++ b/src/components/organisms/core/Footer/index.js
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+export { default } from "./Footer";
diff --git a/src/components/organisms/core/Footer/styled/Category.jsx b/src/components/organisms/core/Footer/styled/Category.jsx
new file mode 100644
index 00000000..a1721820
--- /dev/null
+++ b/src/components/organisms/core/Footer/styled/Category.jsx
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import PropTypes from "prop-types";
+import styled from "styled-components";
+
+import { colors, motion, themedMode, MODE_BRIGHT_SNOW_FLURRY, MODE_DARK_NIGHT_FROST } from "styles/theme";
+
+import { sitemapCategoryFontSize } from "../styles";
+
+const fontColor = themedMode({
+ [MODE_BRIGHT_SNOW_FLURRY]: ({ isActiveRouteMatch }) =>
+ isActiveRouteMatch ? colors.font.base[MODE_BRIGHT_SNOW_FLURRY] : colors.font.faded[MODE_BRIGHT_SNOW_FLURRY],
+ [MODE_DARK_NIGHT_FROST]: ({ isActiveRouteMatch }) =>
+ isActiveRouteMatch ? colors.font.base[MODE_DARK_NIGHT_FROST] : colors.font.faded[MODE_DARK_NIGHT_FROST]
+});
+
+const borderBottomColor = themedMode({
+ [MODE_BRIGHT_SNOW_FLURRY]: ({ isActiveRouteMatch }) =>
+ isActiveRouteMatch ? colors.font.base[MODE_BRIGHT_SNOW_FLURRY] : "transparent",
+ [MODE_DARK_NIGHT_FROST]: ({ isActiveRouteMatch }) =>
+ isActiveRouteMatch ? colors.font.base[MODE_DARK_NIGHT_FROST] : "transparent"
+});
+
+/**
+ * A container for the heading of a sitemap category.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+const Category = styled.div`
+ align-self: center;
+ font-size: ${sitemapCategoryFontSize};
+ color: ${fontColor};
+ border-bottom: 2px solid ${borderBottomColor};
+ transition: border-bottom ${motion.speed.duration.transition.base.themeModeSwitch}ms ease-in-out,
+ color ${motion.speed.duration.transition.base.themeModeSwitch}ms ease-in-out;
+`;
+
+Category.propTypes = {
+ /**
+ * Indicates if the category matches the currently active route.
+ */
+ isActiveRouteMatch: PropTypes.bool
+};
+
+Category.defaultProps = {
+ isActiveRouteMatch: false
+};
+
+export default Category;
diff --git a/src/components/organisms/core/Footer/styled/Copyright.jsx b/src/components/organisms/core/Footer/styled/Copyright.jsx
new file mode 100644
index 00000000..5f571a64
--- /dev/null
+++ b/src/components/organisms/core/Footer/styled/Copyright.jsx
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import styled from "styled-components";
+
+import { colors, motion, themedMode, MODE_BRIGHT_SNOW_FLURRY, MODE_DARK_NIGHT_FROST } from "styles/theme";
+
+const fontColor = themedMode({
+ [MODE_BRIGHT_SNOW_FLURRY]: colors.font.faded[MODE_BRIGHT_SNOW_FLURRY],
+ [MODE_DARK_NIGHT_FROST]: colors.font.faded[MODE_DARK_NIGHT_FROST]
+});
+
+/**
+ * A container for copyright related metadata components.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+const Copyright = styled.div`
+ display: flex;
+ flex-direction: column;
+ text-align: center;
+ font-size: 0.8em;
+ color: ${fontColor};
+ transition: color ${motion.speed.duration.transition.base.themeModeSwitch}ms ease-in-out;
+ margin-top: 1.125em;
+
+ ${({ theme }) => theme.media.tabletLandscape`
+ display: block;
+ text-align: start;
+ `};
+`;
+
+export default Copyright;
diff --git a/src/components/organisms/core/Footer/styled/Grid.jsx b/src/components/organisms/core/Footer/styled/Grid.jsx
new file mode 100644
index 00000000..be1f2c1c
--- /dev/null
+++ b/src/components/organisms/core/Footer/styled/Grid.jsx
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import styled from "styled-components";
+
+/**
+ * A footer container that defines the grid layout.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+const Grid = styled.div`
+ display: flex;
+ flex-direction: column;
+
+ ${({ theme }) => theme.media.tabletPortrait`
+ display: grid;
+ grid-template-columns: repeat(${({ categoryCount }) => categoryCount}, 1fr);
+ grid-template-rows: auto;
+ grid-row-gap: 1em;
+ `};
+
+ ${({ theme }) => theme.media.tabletLandscape`
+ grid-template-columns: 30% repeat(${({ categoryCount }) => categoryCount}, 1fr);
+ `};
+`;
+
+export default Grid;
diff --git a/src/components/organisms/core/Footer/styled/Metadata.jsx b/src/components/organisms/core/Footer/styled/Metadata.jsx
new file mode 100644
index 00000000..bb2ea635
--- /dev/null
+++ b/src/components/organisms/core/Footer/styled/Metadata.jsx
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import styled from "styled-components";
+
+/**
+ * A container for the grid cell that contains metadata components.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+const Metadata = styled.div`
+ display: flex;
+ grid-column: span ${({ categoryCount }) => categoryCount};
+ flex-direction: column;
+ align-items: center;
+
+ ${({ theme }) => theme.media.tabletLandscape`
+ grid-column: unset;
+ justify-content: space-between;
+ align-items: unset;
+ `};
+`;
+
+export default Metadata;
diff --git a/src/components/organisms/core/Footer/styled/OrganizationBrand.jsx b/src/components/organisms/core/Footer/styled/OrganizationBrand.jsx
new file mode 100644
index 00000000..d80bcf31
--- /dev/null
+++ b/src/components/organisms/core/Footer/styled/OrganizationBrand.jsx
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import styled from "styled-components";
+
+/**
+ * A container for the grid cell that contains branding components.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+const OrganizationBrand = styled.div`
+ display: flex;
+ align-items: center;
+ margin-bottom: 2em;
+`;
+
+export default OrganizationBrand;
diff --git a/src/components/organisms/core/Footer/styled/OrganizationBrandCaption.jsx b/src/components/organisms/core/Footer/styled/OrganizationBrandCaption.jsx
new file mode 100644
index 00000000..1ad92bee
--- /dev/null
+++ b/src/components/organisms/core/Footer/styled/OrganizationBrandCaption.jsx
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import styled from "styled-components";
+
+import { organizationBrandCaptionFontSize } from "../styles";
+
+/**
+ * A brand caption.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+const OrganizationBrandCaption = styled.span`
+ font-size: ${organizationBrandCaptionFontSize};
+ font-weight: 400;
+ margin-left: 0.7em;
+`;
+
+export default OrganizationBrandCaption;
diff --git a/src/components/organisms/core/Footer/styled/Sitemap.jsx b/src/components/organisms/core/Footer/styled/Sitemap.jsx
new file mode 100644
index 00000000..8ff59a4c
--- /dev/null
+++ b/src/components/organisms/core/Footer/styled/Sitemap.jsx
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import styled from "styled-components";
+
+/**
+ * A container for sitemap components.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+const Sitemap = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin-top: 1em;
+ margin-bottom: 1em;
+
+ ${({ theme }) => theme.media.tabletPortrait`
+ align-items: unset;
+ margin-top: 0;
+ margin-bottom: 0;
+ `};
+`;
+
+export default Sitemap;
diff --git a/src/components/organisms/core/Footer/styled/SitemapCategory.jsx b/src/components/organisms/core/Footer/styled/SitemapCategory.jsx
new file mode 100644
index 00000000..8b6be8c9
--- /dev/null
+++ b/src/components/organisms/core/Footer/styled/SitemapCategory.jsx
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import styled from "styled-components";
+
+import { colors, motion, themedMode, MODE_BRIGHT_SNOW_FLURRY, MODE_DARK_NIGHT_FROST } from "styles/theme";
+
+const borderBottomColor = themedMode({
+ [MODE_BRIGHT_SNOW_FLURRY]: colors.nord4,
+ [MODE_DARK_NIGHT_FROST]: colors.nord3
+});
+
+/**
+ * A container for a sitemap category.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+const SitemapCategory = styled.div`
+ display: flex;
+ justify-content: center;
+ border-bottom: 1px solid ${borderBottomColor};
+ transition: border-bottom ${motion.speed.duration.transition.base.themeModeSwitch}ms ease-in-out;
+ margin-bottom: 1em;
+ width: 70%;
+ user-select: none;
+
+ ${({ theme }) => theme.media.tabletPortrait`
+ width: unset;
+ `};
+
+ ${({ theme }) => theme.media.tabletLandscape`
+ justify-content: unset;
+ `};
+`;
+
+export default SitemapCategory;
diff --git a/src/components/organisms/core/Footer/styled/SitemapLink.jsx b/src/components/organisms/core/Footer/styled/SitemapLink.jsx
new file mode 100644
index 00000000..7d61883f
--- /dev/null
+++ b/src/components/organisms/core/Footer/styled/SitemapLink.jsx
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import styled from "styled-components";
+
+import { A } from "atoms/core/HTMLElements";
+import { colors, motion, themedMode, MODE_BRIGHT_SNOW_FLURRY, MODE_DARK_NIGHT_FROST } from "styles/theme";
+
+const fontColor = themedMode({
+ [MODE_BRIGHT_SNOW_FLURRY]: colors.font.faded[MODE_BRIGHT_SNOW_FLURRY],
+ [MODE_DARK_NIGHT_FROST]: colors.font.faded[MODE_DARK_NIGHT_FROST]
+});
+
+const fontColorHover = themedMode({
+ [MODE_BRIGHT_SNOW_FLURRY]: colors.font.base[MODE_BRIGHT_SNOW_FLURRY],
+ [MODE_DARK_NIGHT_FROST]: colors.font.base[MODE_DARK_NIGHT_FROST]
+});
+
+/**
+ * A link for a sitemap page link.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+const SitemapLink = styled(A)`
+ display: block;
+ padding: 0.4em 0;
+ font-size: 0.9em;
+ color: ${fontColor};
+ transition: color ${motion.speed.duration.transition.text.fade}ms ease-in-out;
+
+ &:active,
+ &:focus,
+ &:hover {
+ color: ${fontColorHover};
+ }
+
+ &:first-child {
+ padding-top: 0;
+ }
+
+ &:last-child {
+ padding-bottom: 0;
+ }
+`;
+
+export default SitemapLink;
diff --git a/src/components/organisms/core/Footer/styled/SitemapList.jsx b/src/components/organisms/core/Footer/styled/SitemapList.jsx
new file mode 100644
index 00000000..7eef7cee
--- /dev/null
+++ b/src/components/organisms/core/Footer/styled/SitemapList.jsx
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import styled from "styled-components";
+
+/**
+ * A container for sitemap page links.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+const SitemapList = styled.div`
+ text-align: center;
+
+ ${({ theme }) => theme.media.tabletLandscape`
+ text-align: start;
+ `};
+`;
+
+export default SitemapList;
diff --git a/src/components/organisms/core/Footer/styled/SocialNetworking.jsx b/src/components/organisms/core/Footer/styled/SocialNetworking.jsx
new file mode 100644
index 00000000..9f62c525
--- /dev/null
+++ b/src/components/organisms/core/Footer/styled/SocialNetworking.jsx
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import styled from "styled-components";
+
+/**
+ * A container for the grid cell that contains social media & networking related components.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+const SocialNetworking = styled.div`
+ display: flex;
+ justify-content: space-between;
+
+ ${({ theme }) => theme.media.tabletLandscape`
+ justify-content: unset;
+
+ * {
+ margin: 0 0.625em;
+
+ &:last-child {
+ margin-right: 0;
+ }
+
+ &:first-child {
+ margin-left: 0;
+ }
+ }
+ `};
+`;
+
+export default SocialNetworking;
diff --git a/src/components/organisms/core/Footer/styled/index.js b/src/components/organisms/core/Footer/styled/index.js
new file mode 100644
index 00000000..87fe26ae
--- /dev/null
+++ b/src/components/organisms/core/Footer/styled/index.js
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import Category from "./Category";
+import Copyright from "./Copyright";
+import Grid from "./Grid";
+import Metadata from "./Metadata";
+import OrganizationBrand from "./OrganizationBrand";
+import OrganizationBrandCaption from "./OrganizationBrandCaption";
+import Sitemap from "./Sitemap";
+import SitemapCategory from "./SitemapCategory";
+import SitemapLink from "./SitemapLink";
+import SitemapList from "./SitemapList";
+import SocialNetworking from "./SocialNetworking";
+
+export {
+ Category,
+ Copyright,
+ Grid,
+ Metadata,
+ OrganizationBrand,
+ OrganizationBrandCaption,
+ Sitemap,
+ SitemapCategory,
+ SitemapLink,
+ SitemapList,
+ SocialNetworking
+};
diff --git a/src/components/organisms/core/Footer/styles.js b/src/components/organisms/core/Footer/styles.js
new file mode 100644
index 00000000..bfa705bb
--- /dev/null
+++ b/src/components/organisms/core/Footer/styles.js
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+/**
+ * @file Provides component styles.
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+
+import { css } from "styled-components";
+import { darken, lighten } from "polished";
+
+import { colors, motion, ms, themedMode, MODE_BRIGHT_SNOW_FLURRY, MODE_DARK_NIGHT_FROST } from "styles/theme";
+
+const socialNetworkingIconFillColor = themedMode({
+ [MODE_BRIGHT_SNOW_FLURRY]: lighten(0.15, colors.font.base[MODE_BRIGHT_SNOW_FLURRY]),
+ [MODE_DARK_NIGHT_FROST]: darken(0.1, colors.font.base[MODE_DARK_NIGHT_FROST])
+});
+
+const socialNetworkingIconStyles = css`
+ display: inline-block;
+ width: 1em;
+ height: 1em;
+ fill: ${socialNetworkingIconFillColor};
+ transition: fill ${motion.speed.duration.transition.text.fade}ms ease-in-out;
+
+ &:active,
+ &:focus,
+ &:hover {
+ fill: ${colors.nord8};
+ }
+`;
+
+const heartIconStyles = css`
+ width: 0.8em;
+ height: 0.8em;
+ vertical-align: middle;
+ fill: ${({ theme }) => lighten(0.2, theme.colors.nord11)};
+`;
+
+const organizationBrandLogoHeight = ms(4);
+
+const organizationBrandCaptionFontSize = ms(3);
+
+const sitemapCategoryFontSize = ms(1);
+
+export {
+ heartIconStyles,
+ organizationBrandCaptionFontSize,
+ organizationBrandLogoHeight,
+ sitemapCategoryFontSize,
+ socialNetworkingIconStyles
+};
diff --git a/src/components/organisms/page/404/SectionLanding/SectionLanding.jsx b/src/components/organisms/page/404/SectionLanding/SectionLanding.jsx
index aaaaabdb..ef88d83a 100644
--- a/src/components/organisms/page/404/SectionLanding/SectionLanding.jsx
+++ b/src/components/organisms/page/404/SectionLanding/SectionLanding.jsx
@@ -9,6 +9,7 @@
import React from "react";
+import { WaveFooter } from "atoms/core/vectors/divider";
import Section, { Content } from "containers/core/Section";
import ErrorState404 from "molecules/core/ErrorState404";
@@ -30,6 +31,7 @@ const SectionLanding = () => (
subline="…but that's not the place to find the page you were looking for."
/>
+
);
diff --git a/src/components/organisms/page/blog/SectionBlogPosts/SectionBlogPosts.jsx b/src/components/organisms/page/blog/SectionBlogPosts/SectionBlogPosts.jsx
index 3f6f9ad6..65f05739 100644
--- a/src/components/organisms/page/blog/SectionBlogPosts/SectionBlogPosts.jsx
+++ b/src/components/organisms/page/blog/SectionBlogPosts/SectionBlogPosts.jsx
@@ -9,6 +9,7 @@
import React from "react";
+import { WaveFooter } from "atoms/core/vectors/divider";
import Section, { Content } from "containers/core/Section";
import EmptyState from "molecules/core/EmptyState";
@@ -30,6 +31,7 @@ const SectionBlogPosts = () => (
subline="Please check back later, we're working hard on this page!"
/>
+
);
diff --git a/src/components/organisms/page/community/SectionLanding/SectionLanding.jsx b/src/components/organisms/page/community/SectionLanding/SectionLanding.jsx
index 10e2fb55..e52a8d6b 100644
--- a/src/components/organisms/page/community/SectionLanding/SectionLanding.jsx
+++ b/src/components/organisms/page/community/SectionLanding/SectionLanding.jsx
@@ -9,6 +9,7 @@
import React from "react";
+import { WaveFooter } from "atoms/core/vectors/divider";
import Section, { Content } from "containers/core/Section";
import EmptyState from "molecules/core/EmptyState";
@@ -30,6 +31,7 @@ const SectionLanding = () => (
subline="Please check back later, we're working hard on this page!"
/>
+
);
diff --git a/src/components/organisms/page/docs/SectionLanding/SectionLanding.jsx b/src/components/organisms/page/docs/SectionLanding/SectionLanding.jsx
index d009f38f..ecb532a3 100644
--- a/src/components/organisms/page/docs/SectionLanding/SectionLanding.jsx
+++ b/src/components/organisms/page/docs/SectionLanding/SectionLanding.jsx
@@ -9,6 +9,7 @@
import React from "react";
+import { WaveFooter } from "atoms/core/vectors/divider";
import Section, { Content } from "containers/core/Section";
import EmptyState from "molecules/core/EmptyState";
@@ -30,6 +31,7 @@ const SectionLanding = () => (
subline="Please check back later, we're working hard on this page!"
/>
+
);
diff --git a/src/components/organisms/page/landing/SectionHero/SectionHero.jsx b/src/components/organisms/page/landing/SectionHero/SectionHero.jsx
index de645530..7f19c61f 100644
--- a/src/components/organisms/page/landing/SectionHero/SectionHero.jsx
+++ b/src/components/organisms/page/landing/SectionHero/SectionHero.jsx
@@ -9,6 +9,7 @@
import React from "react";
+import { WaveFooter } from "atoms/core/vectors/divider";
import Section, { Content } from "containers/core/Section";
import EmptyState from "molecules/core/EmptyState";
@@ -30,6 +31,7 @@ const SectionHero = () => (
subline="Please check back later, we're working hard on this page!"
/>
+
);
diff --git a/src/components/organisms/page/ports/SectionLanding/SectionLanding.jsx b/src/components/organisms/page/ports/SectionLanding/SectionLanding.jsx
index e0227239..86074b76 100644
--- a/src/components/organisms/page/ports/SectionLanding/SectionLanding.jsx
+++ b/src/components/organisms/page/ports/SectionLanding/SectionLanding.jsx
@@ -9,6 +9,7 @@
import React from "react";
+import { WaveFooter } from "atoms/core/vectors/divider";
import Section, { Content } from "containers/core/Section";
import EmptyState from "molecules/core/EmptyState";
@@ -30,6 +31,7 @@ const SectionLanding = () => (
subline="Please check back later, we're working hard on this page!"
/>
+
);
diff --git a/src/config/project/constants.js b/src/config/project/constants.js
new file mode 100644
index 00000000..ff50559e
--- /dev/null
+++ b/src/config/project/constants.js
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+/**
+ * @file Provides general project constants.
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+
+import { metadataNordDocs } from "data/project";
+import { getSemVerFromGitDescribe } from "utils";
+
+/**
+ * The current copyright year.
+ *
+ * @constant {string}
+ */
+const COPYRIGHT_YEAR = new Date().getFullYear();
+
+/**
+ * The date format for the "date-fns" library according to ISO 8601.
+ *
+ * @constant {string}
+ * @see https://date-fns.org/v1.29.0/docs/format
+ * @see https://en.wikipedia.org/wiki/ISO_8601
+ */
+const DATE_FORMAT = "yyyy-MM-ddTHH:mm:ssxx";
+
+/**
+ * The name of the current Git branch extracted from the local Git repository.
+ *
+ * @constant {string}
+ */
+const GIT_BRANCH = process.env.NORD_DOCS_GIT_BRANCH || "";
+
+/**
+ * The full SHA hash of the latest Git commit extracted from the local Git repository.
+ *
+ * @constant {string}
+ */
+const GIT_COMMITHASH = process.env.NORD_DOCS_GIT_COMMITHASH || "";
+
+/**
+ * The count of additional commits on top of the latest tag extracted from the local Git repository.
+ *
+ * @constant {string}
+ */
+const GIT_COMMITS_AHEAD = getSemVerFromGitDescribe(process.env.NORD_DOCS_GIT_VERSION)?.commitsAhead;
+
+/**
+ * The version (SemVer) extracted from the local Git repository. Defaults to the version of the package metadata if the
+ * "NORD_DOCS_GIT_VERSION" environment variable is not set or empty.
+ *
+ * @constant {string}
+ */
+const VERSION = getSemVerFromGitDescribe(process.env.NORD_DOCS_GIT_VERSION)?.raw || metadataNordDocs.version;
+
+/**
+ * The version (SemVer) channel extracted from the {@link VERSION}.
+ *
+ * @constant {string}
+ */
+const VERSION_CHANNEL = getSemVerFromGitDescribe(process.env.NORD_DOCS_GIT_VERSION)?.channel;
+
+/**
+ * The version (SemVer) channel extracted from the {@link VERSION}.
+ *
+ * @constant {string}
+ */
+const VERSION_STABILITY_STATUS = getSemVerFromGitDescribe(process.env.NORD_DOCS_GIT_VERSION)?.stabilityStatus;
+
+export {
+ COPYRIGHT_YEAR,
+ DATE_FORMAT,
+ GIT_BRANCH,
+ GIT_COMMITHASH,
+ GIT_COMMITS_AHEAD,
+ VERSION,
+ VERSION_CHANNEL,
+ VERSION_STABILITY_STATUS
+};
diff --git a/src/data/components/organisms/core/Footer/sitemapCategories.js b/src/data/components/organisms/core/Footer/sitemapCategories.js
new file mode 100644
index 00000000..d9a7a445
--- /dev/null
+++ b/src/data/components/organisms/core/Footer/sitemapCategories.js
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import { ROUTE_BLOG, ROUTE_COMMUNITY, ROUTE_DOCS, ROUTE_PORTS, ROUTE_ROOT } from "config/routes/mappings";
+
+/**
+ * The mapping of categories for the sitemap.
+ *
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @since 0.5.0
+ */
+const sitemapCategories = [
+ {
+ name: "Nord",
+ url: ROUTE_ROOT,
+ links: []
+ },
+ {
+ name: "Ports",
+ url: ROUTE_PORTS,
+ links: []
+ },
+ {
+ name: "Docs",
+ url: ROUTE_DOCS,
+ links: []
+ },
+ {
+ name: "Blog",
+ url: ROUTE_BLOG,
+ links: []
+ },
+ {
+ name: "Community",
+ url: ROUTE_COMMUNITY,
+ links: []
+ }
+];
+
+export default sitemapCategories;
diff --git a/src/data/project.js b/src/data/project.js
index ebe91b3b..a9c40580 100644
--- a/src/data/project.js
+++ b/src/data/project.js
@@ -38,30 +38,37 @@ const links = {
url: "https://spectrum.chat/arcticicestudio"
}
},
- social: {
- github: {
- id: "arcticicestudio",
- url: "https://github.com/arcticicestudio"
- },
- keybase: {
- id: "arcticicestudio",
- url: "https://keybase.io/arcticicestudio"
- },
- reddit: {
- id: "arcticicestudio",
- url: "https://www.reddit.com/user/arcticicestudio"
- },
- spectrum: {
- id: "arcticicestudio",
- url: "https://spectrum.chat/users/arcticicestudio"
- },
- stackoverflow: {
- id: "4568698",
- url: "https://stackoverflow.com/users/4568698/arctic-ice-studio"
- },
- twitter: {
- id: "arcticicestudio",
- url: "https://twitter.com/arcticicestudio"
+ organization: {
+ url: "https://arcticicestudio.com",
+ social: {
+ github: {
+ id: "arcticicestudio",
+ url: "https://github.com/arcticicestudio"
+ },
+ keybase: {
+ id: "arcticicestudio",
+ url: "https://keybase.io/arcticicestudio"
+ },
+ reddit: {
+ id: "arcticicestudio",
+ url: "https://www.reddit.com/user/arcticicestudio"
+ },
+ slack: {
+ id: "arcticicestudio",
+ url: "https://arcticicestudio.slack.com"
+ },
+ spectrum: {
+ id: "arcticicestudio",
+ url: "https://spectrum.chat/users/arcticicestudio"
+ },
+ stackoverflow: {
+ id: "4568698",
+ url: "https://stackoverflow.com/users/4568698/arctic-ice-studio"
+ },
+ twitter: {
+ id: "arcticicestudio",
+ url: "https://twitter.com/arcticicestudio"
+ }
}
}
};
diff --git a/src/styles/theme/colors/font.js b/src/styles/theme/colors/font.js
index f5523a8c..fb7452b8 100644
--- a/src/styles/theme/colors/font.js
+++ b/src/styles/theme/colors/font.js
@@ -14,6 +14,8 @@
* @since 0.2.0
*/
+import { darken, lighten } from "polished";
+
import nord from "./nord";
import { MODE_BRIGHT_SNOW_FLURRY, MODE_DARK_NIGHT_FROST } from "../constants";
@@ -22,6 +24,11 @@ const base = {
[MODE_DARK_NIGHT_FROST]: nord.nord6
};
-const font = { base };
+const faded = {
+ [MODE_BRIGHT_SNOW_FLURRY]: lighten(0.2, base[MODE_BRIGHT_SNOW_FLURRY]),
+ [MODE_DARK_NIGHT_FROST]: darken(0.2, base[MODE_DARK_NIGHT_FROST])
+};
+
+const font = { base, faded };
export default font;
diff --git a/src/utils/getSemVerFromGitDescribe.js b/src/utils/getSemVerFromGitDescribe.js
new file mode 100644
index 00000000..4d2dd15d
--- /dev/null
+++ b/src/utils/getSemVerFromGitDescribe.js
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+/**
+ * @file Provides utility functions to get Git SemVer version information.
+ * @author Arctic Ice Studio
+ * @author Sven Greb
+ * @see https://git-scm.com/docs/git-describe
+ * @see https://semver.org
+ * @since 0.5.0
+ */
+
+import semver from "semver";
+
+/**
+ * Returns the channel based on the passed build metadata and pre-release version.
+ *
+ * @private
+ * @method getVersionChannel
+ * @param {Array} build The build metadata of the version from which the channel should be extracted.
+ * @param {Array<(string|number)>} prerelease The pre-release version from which the channel should be
+ * extracted.
+ * @return {string} The channel of the passed version.
+ */
+const getVersionChannel = (build, prerelease) => {
+ if (build.length !== 0) {
+ if (prerelease.length !== 0) {
+ return "pre-release-snapshot";
+ }
+ return "snapshot";
+ }
+
+ if (prerelease.length !== 0) {
+ return "pre-release";
+ }
+ return "release";
+};
+
+/**
+ * Returns the stability status of the passed (SemVer) version.
+ *
+ * @private
+ * @method getVersionStabilityStatus
+ * @param {Array} build The build metadata of the version from which the channel should be extracted.
+ * @param {Array<(string|number)>} prerelease The pre-release version from which the channel should be
+ * extracted.
+ * @return {string} The stability status of the passed version.
+ */
+const getVersionStabilityStatus = (build, prerelease) => {
+ if (build.length === 0 && prerelease.length === 0) {
+ return "stable";
+ }
+ return "unstable";
+};
+
+/**
+ * Converts the output from the Git "describe --always" command to a SemVer version.
+ *
+ * @method getSemVerFromGitDescribe
+ * @param {string} gitVersion The output of the Git "describe --always" command
+ * @return {?Object} The SemVer information, `null` otherwise if the passed `gitVersion` is not compatible with SemVer.
+ * @see https://semver.org
+ */
+const getSemVerFromGitDescribe = gitVersion => {
+ /*
+ * Split the Git version output where the array index
+ *
+ * - [0] contains the value of the recent tag that is reachable from the latest commit, or the hash of the latest
+ * commit if no tags have been found, e.g. "v0.1.8" or "9b205b0".
+ * - [1]/[2] contains, separated with a dash character, either
+ * - the pre-release string
+ * - the count of additional commits on top of the tag string (when found).
+ * - [2]/[3] contains, separated with a dash character, either
+ * - the contain the count of additional commits (if not already contained in index [1])
+ * - the hash of the latest commit prefixed with the "g" character
+ */
+ const gitVersionElements = gitVersion.split("-");
+
+ /* Reject invalid strings and single commit SHA hashs not compatible with SemVer. */
+ if (gitVersionElements.length === 1 && !semver.valid(gitVersionElements[0])) return null;
+
+ const tagElement = gitVersionElements[0];
+ let buildMetadataElement = "";
+ let commitsAhead = 0;
+ let preReleaseElement = "";
+ let scmPrefix = "";
+
+ /* Extract necessary elements from array and remove count of ahead commits afterwards. */
+ if (gitVersionElements.length >= 3) {
+ buildMetadataElement = gitVersionElements[gitVersionElements.length - 1];
+ commitsAhead = Number.parseInt(gitVersionElements[gitVersionElements.length - 2], 10);
+
+ /*
+ * Remove the prefix character added by "git describe" that indicates the SCM type (where "g" means "Git").
+ *
+ * @see https://git-scm.com/docs/git-describe
+ */
+ if (buildMetadataElement.charAt(0) === "g") {
+ buildMetadataElement = buildMetadataElement.substring(1);
+ scmPrefix = "g";
+
+ /*
+ * Prepend the separator character for build metadata as defined in the SemVer specification.
+ *
+ * @see https://semver.org/#spec-item-10
+ */
+ buildMetadataElement = `+${buildMetadataElement}`;
+ }
+
+ gitVersionElements.splice(gitVersionElements.length - 2, 1);
+ }
+
+ /*
+ * Extract the pre-release element and prepend the separator as defined in the SemVer specification.
+ *
+ * @see https://semver.org/#spec-item-9
+ */
+ if (gitVersionElements.length > 2) {
+ preReleaseElement = gitVersionElements[gitVersionElements.length - 2];
+ preReleaseElement = `-${preReleaseElement}`;
+ }
+
+ const parsedSemVer = semver.parse(`${tagElement}${preReleaseElement}${buildMetadataElement}`, {
+ includePrerelease: true
+ });
+
+ /* Append additional useful information about the version. */
+ parsedSemVer.commitsAhead = commitsAhead;
+ parsedSemVer.channel = getVersionChannel(parsedSemVer.build, parsedSemVer.prerelease);
+ parsedSemVer.scmPrefix = scmPrefix;
+ parsedSemVer.stabilityStatus = getVersionStabilityStatus(parsedSemVer.build, parsedSemVer.prerelease);
+
+ return parsedSemVer;
+};
+
+export default getSemVerFromGitDescribe;
diff --git a/src/utils/index.js b/src/utils/index.js
index c895b1b0..e5d1a04d 100644
--- a/src/utils/index.js
+++ b/src/utils/index.js
@@ -14,8 +14,9 @@
* @since 0.2.0
*/
+import getSemVerFromGitDescribe from "./getSemVerFromGitDescribe";
import isRouteInternal from "./isRouteInternal";
import isRoutePartiallyMatch from "./isRoutePartiallyMatch";
import { readSessionCache, writeSessionCache } from "./sessionCache";
-export { isRouteInternal, isRoutePartiallyMatch, readSessionCache, writeSessionCache };
+export { getSemVerFromGitDescribe, isRouteInternal, isRoutePartiallyMatch, readSessionCache, writeSessionCache };
diff --git a/test/babel-config.js b/test/babel-config.js
index bccbdbaf..e91bb2b6 100644
--- a/test/babel-config.js
+++ b/test/babel-config.js
@@ -17,7 +17,8 @@
*/
const jestBabelConfig = {
- presets: ["babel-preset-gatsby"]
+ presets: ["babel-preset-gatsby"],
+ plugins: ["@babel/plugin-proposal-optional-chaining", "@babel/plugin-proposal-export-default-from"]
};
module.exports = require("babel-jest").createTransformer(jestBabelConfig);
diff --git a/test/components/atoms/core/HTMLElements/inlineTextSemantics/A.test.jsx b/test/components/atoms/core/HTMLElements/inlineTextSemantics/A.test.jsx
index 3a62cd4e..ed474c6e 100644
--- a/test/components/atoms/core/HTMLElements/inlineTextSemantics/A.test.jsx
+++ b/test/components/atoms/core/HTMLElements/inlineTextSemantics/A.test.jsx
@@ -17,21 +17,25 @@ import { metadataNordDocs } from "data/project";
describe("logical behavior", () => {
test("renders inernal URLs with `to` prop", () => {
const { container } = render(Docs );
+ expect(container.firstChild).toHaveAttribute("href", ROUTE_DOCS);
expect(container.firstChild).toMatchSnapshot();
});
test("renders inernal URLs with `href` prop", () => {
const { container } = render(Docs );
+ expect(container.firstChild).toHaveAttribute("href", ROUTE_DOCS);
expect(container.firstChild).toMatchSnapshot();
});
test("renders external URLs with `href` prop", () => {
const { container } = render(Docs );
+ expect(container.firstChild).toHaveAttribute("href", metadataNordDocs.homepage);
expect(container.firstChild).toMatchSnapshot();
});
test("renders external URLs with `to` prop", () => {
const { container } = render(Docs );
+ expect(container.firstChild).toHaveAttribute("href", metadataNordDocs.homepage);
expect(container.firstChild).toMatchSnapshot();
});
});
diff --git a/test/components/atoms/core/Link/Link.test.jsx b/test/components/atoms/core/Link/Link.test.jsx
new file mode 100644
index 00000000..5627f02b
--- /dev/null
+++ b/test/components/atoms/core/Link/Link.test.jsx
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+
+import { renderWithTheme } from "nord-docs-test-utils";
+import Link from "atoms/core/Link";
+
+describe("theme styles", () => {
+ test("matches the snapshot with default variant", () => {
+ const { container } = renderWithTheme( Nord);
+ expect(container.firstChild).toMatchSnapshot();
+ });
+
+ test("matches the snapshot with `calmly` variant", () => {
+ const { container } = renderWithTheme( Nord);
+ expect(container.firstChild).toMatchSnapshot();
+ });
+
+ test("matches the snapshot with `decent` variant", () => {
+ const { container } = renderWithTheme( Nord);
+ expect(container.firstChild).toMatchSnapshot();
+ });
+
+ test("matches the snapshot with `minimal` variant", () => {
+ const { container } = renderWithTheme( Nord);
+ expect(container.firstChild).toMatchSnapshot();
+ });
+});
diff --git a/test/components/atoms/core/Link/__snapshots__/Link.test.jsx.snap b/test/components/atoms/core/Link/__snapshots__/Link.test.jsx.snap
new file mode 100644
index 00000000..5a337222
--- /dev/null
+++ b/test/components/atoms/core/Link/__snapshots__/Link.test.jsx.snap
@@ -0,0 +1,146 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`theme styles matches the snapshot with \`calmly\` variant 1`] = `
+.c1 {
+ color: inherit;
+ cursor: pointer;
+ -webkit-text-decoration: none;
+ text-decoration: none;
+}
+
+.c1:active,
+.c1:focus,
+.c1:hover,
+.c1:visited {
+ outline: none;
+}
+
+.c0 {
+ border-radius: 0.25em;
+ color: #5e81ac;
+ -webkit-transition: color 200ms ease-in-out, background-color 200ms ease-in-out;
+ transition: color 200ms ease-in-out, background-color 200ms ease-in-out;
+}
+
+.c0:hover,
+.c0:active,
+.c0:focus {
+ background-color: rgba(236,239,244,0.45);
+ color: #5e81ac;
+}
+
+
+ Nord
+
+`;
+
+exports[`theme styles matches the snapshot with \`decent\` variant 1`] = `
+.c1 {
+ color: inherit;
+ cursor: pointer;
+ -webkit-text-decoration: none;
+ text-decoration: none;
+}
+
+.c1:active,
+.c1:focus,
+.c1:hover,
+.c1:visited {
+ outline: none;
+}
+
+.c0 {
+ border-bottom: 1px solid #5e81ac;
+ color: #2e3440;
+ -webkit-transition: color 200ms ease-in-out;
+ transition: color 200ms ease-in-out;
+}
+
+.c0:hover,
+.c0:active,
+.c0:focus {
+ color: #5e81ac;
+}
+
+
+ Nord
+
+`;
+
+exports[`theme styles matches the snapshot with \`minimal\` variant 1`] = `
+.c1 {
+ color: inherit;
+ cursor: pointer;
+ -webkit-text-decoration: none;
+ text-decoration: none;
+}
+
+.c1:active,
+.c1:focus,
+.c1:hover,
+.c1:visited {
+ outline: none;
+}
+
+.c0 {
+ border-bottom: 1px solid #5e81ac;
+ -webkit-transition: border-bottom-color 200ms ease-in-out;
+ transition: border-bottom-color 200ms ease-in-out;
+}
+
+.c0:hover,
+.c0:active,
+.c0:focus {
+ border-bottom-color: #2e3440;
+}
+
+
+ Nord
+
+`;
+
+exports[`theme styles matches the snapshot with default variant 1`] = `
+.c1 {
+ color: inherit;
+ cursor: pointer;
+ -webkit-text-decoration: none;
+ text-decoration: none;
+}
+
+.c1:active,
+.c1:focus,
+.c1:hover,
+.c1:visited {
+ outline: none;
+}
+
+.c0 {
+ border-radius: 0.25em;
+ color: #5e81ac;
+ -webkit-transition: color 200ms ease-in-out, background-color 200ms ease-in-out;
+ transition: color 200ms ease-in-out, background-color 200ms ease-in-out;
+}
+
+.c0:hover,
+.c0:active,
+.c0:focus {
+ background-color: rgba(236,239,244,0.45);
+ color: #5e81ac;
+}
+
+
+ Nord
+
+`;
diff --git a/test/components/atoms/core/SiteMetadata/SiteMetadata.test.jsx b/test/components/atoms/core/SiteMetadata/SiteMetadata.test.jsx
index 4d57a662..957e6afd 100644
--- a/test/components/atoms/core/SiteMetadata/SiteMetadata.test.jsx
+++ b/test/components/atoms/core/SiteMetadata/SiteMetadata.test.jsx
@@ -26,8 +26,10 @@ const staticQueryResultDataMock = {
description: metadataNord.description,
keywords: metadataNord.keywords,
links: {
- social: {
- twitter: metadataNord.links.social.twitter
+ organization: {
+ social: {
+ twitter: metadataNord.links.organization.social.twitter
+ }
}
},
title: metadataNord.title
@@ -98,7 +100,7 @@ describe("data consistency", () => {
}),
expect.objectContaining({
name: "twitter:site",
- content: expect.stringContaining(metadataNord.links.social.twitter.id)
+ content: expect.stringContaining(metadataNord.links.organization.social.twitter.id)
}),
expect.objectContaining({
name: "twitter:description",
@@ -130,17 +132,6 @@ describe("data consistency", () => {
);
});
- test("contains Open Graph Protocol HTML schema `prefix` attribute", () => {
- renderWithTheme( );
- const generatedHelmetData = Helmet.peek();
-
- expect(generatedHelmetData.htmlAttributes).toEqual(
- expect.objectContaining({
- prefix: expect.stringContaining("ogp.me")
- })
- );
- });
-
test("contains JSON-LD schema linked data `script` tag", () => {
renderWithTheme( );
const generatedHelmetData = Helmet.peek();
diff --git a/test/components/containers/core/Section/Content.test.jsx b/test/components/containers/core/Section/Content.test.jsx
index 7a0f968c..dd5666b1 100644
--- a/test/components/containers/core/Section/Content.test.jsx
+++ b/test/components/containers/core/Section/Content.test.jsx
@@ -14,23 +14,23 @@ import { Content } from "containers/core/Section";
import { renderWithTheme } from "nord-docs-test-utils";
describe("theme styles", () => {
- test("has top and bottom margin", () => {
+ test("has top and bottom padding", () => {
const { container } = renderWithTheme(Nord );
- const marginTop = stripUnit(getComputedStyle(container.firstChild).marginTop);
- const marginBottom = stripUnit(getComputedStyle(container.firstChild).marginBottom);
+ const paddingTop = stripUnit(getComputedStyle(container.firstChild).paddingTop);
+ const paddingBottom = stripUnit(getComputedStyle(container.firstChild).paddingBottom);
- expect(marginTop).toBeGreaterThan(0);
- expect(marginBottom).toBeGreaterThan(0);
+ expect(paddingTop).toBeGreaterThan(0);
+ expect(paddingBottom).toBeGreaterThan(0);
expect(container.firstChild).toMatchSnapshot();
});
- test("adjusts top and bottom margin to passed props", () => {
+ test("adjusts top and bottom padding to passed props", () => {
const { container } = renderWithTheme(Nord );
- const marginTop = stripUnit(getComputedStyle(container.firstChild).marginTop);
- const marginBottom = stripUnit(getComputedStyle(container.firstChild).marginBottom);
+ const paddingTop = stripUnit(getComputedStyle(container.firstChild).paddingTop);
+ const paddingBottom = stripUnit(getComputedStyle(container.firstChild).paddingBottom);
- expect(marginTop).toBeFalsy();
- expect(marginBottom).toBeFalsy();
+ expect(paddingTop).toBeFalsy();
+ expect(paddingBottom).toBeFalsy();
expect(container.firstChild).toMatchSnapshot();
});
});
diff --git a/test/components/containers/core/Section/__snapshots__/Content.test.jsx.snap b/test/components/containers/core/Section/__snapshots__/Content.test.jsx.snap
index 644adda2..ffd34279 100644
--- a/test/components/containers/core/Section/__snapshots__/Content.test.jsx.snap
+++ b/test/components/containers/core/Section/__snapshots__/Content.test.jsx.snap
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`theme styles adjusts top and bottom margin to passed props 1`] = `
+exports[`theme styles adjusts top and bottom padding to passed props 1`] = `
.c0 {
width: 100%;
}
@@ -18,11 +18,11 @@ exports[`theme styles adjusts top and bottom margin to passed props 1`] = `
`;
-exports[`theme styles has top and bottom margin 1`] = `
+exports[`theme styles has top and bottom padding 1`] = `
.c0 {
width: 100%;
- margin-top: 5em;
- margin-bottom: 5em;
+ padding-top: 5em;
+ padding-bottom: 5em;
}
@media (min-width:75em) {
diff --git a/test/components/layouts/core/BaseLayout/BaseLayout.test.jsx b/test/components/layouts/core/BaseLayout/BaseLayout.test.jsx
deleted file mode 100644
index 7d06d90e..00000000
--- a/test/components/layouts/core/BaseLayout/BaseLayout.test.jsx
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2018-present Arctic Ice Studio
- * Copyright (C) 2018-present Sven Greb
- *
- * Project: Nord Docs
- * Repository: https://github.com/arcticicestudio/nord-docs
- * License: MIT
- */
-
-import React, { Fragment } from "react";
-import { render } from "react-testing-library";
-
-import BaseLayout from "layouts/core/BaseLayout";
-
-/*
- * This test is disabled because it will be covered by E2E tests with Cypress later on.
- * It is also skipped due to problems with mocking transitive modules and components.
- */
-test.skip("snapshot", () => {
- const { container } = render(
-
-
-
- );
- expect(container).toMatchSnapshot();
-});
diff --git a/test/components/layouts/core/BaseLayout/__snapshots__/BaseLayout.test.jsx.snap b/test/components/layouts/core/BaseLayout/__snapshots__/BaseLayout.test.jsx.snap
deleted file mode 100644
index 3a2e181c..00000000
--- a/test/components/layouts/core/BaseLayout/__snapshots__/BaseLayout.test.jsx.snap
+++ /dev/null
@@ -1,9 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`snapshot 1`] = `
-
-
-
-`;
diff --git a/test/components/organisms/core/Footer/styled/Category.test.jsx b/test/components/organisms/core/Footer/styled/Category.test.jsx
new file mode 100644
index 00000000..6e3e02b8
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/Category.test.jsx
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+
+import { renderWithTheme } from "nord-docs-test-utils";
+import { Category } from "organisms/core/Footer/styled";
+
+describe("theme styles", () => {
+ test("has visible border-bottom when matching the active route", () => {
+ const { container } = renderWithTheme(Nord );
+
+ expect(container.firstChild).toHaveStyleRule("border-bottom", expect.not.stringContaining("transparent"));
+ expect(container.firstChild).toMatchSnapshot();
+ });
+
+ test("has invisible border-bottom when not matching the active route", () => {
+ const { container } = renderWithTheme(Nord );
+
+ expect(container.firstChild).toHaveStyleRule("border-bottom", expect.stringContaining("transparent"));
+ expect(container.firstChild).toMatchSnapshot();
+ });
+});
diff --git a/test/components/organisms/core/Footer/styled/Copyright.test.jsx b/test/components/organisms/core/Footer/styled/Copyright.test.jsx
new file mode 100644
index 00000000..f45b427f
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/Copyright.test.jsx
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import { em, stripUnit } from "polished";
+
+import { renderWithTheme } from "nord-docs-test-utils";
+import { Copyright } from "organisms/core/Footer/styled";
+import { media } from "styles/theme";
+
+describe("theme styles", () => {
+ test("has required CSS breakpoints", () => {
+ const { container } = renderWithTheme( );
+ const mediaQuery = `(min-width: ${em(media.breakpoints.tabletLandscapeLowerBoundary)})`;
+
+ expect(container.firstChild).toHaveStyleRule("display", "block", {
+ media: mediaQuery
+ });
+ expect(container.firstChild).toHaveStyleRule("text-align", "start", {
+ media: mediaQuery
+ });
+ });
+
+ test("has reduced font size", () => {
+ const { container } = renderWithTheme( );
+ const fontSize = stripUnit(getComputedStyle(container.firstChild).fontSize);
+
+ expect(fontSize).toBeLessThan(1);
+ expect(container.firstChild).toHaveStyleRule("font-size", `${fontSize}em`);
+ });
+
+ test("matches the snapshot", () => {
+ const { container } = renderWithTheme( );
+ expect(container.firstChild).toMatchSnapshot();
+ });
+});
diff --git a/test/components/organisms/core/Footer/styled/Grid.test.jsx b/test/components/organisms/core/Footer/styled/Grid.test.jsx
new file mode 100644
index 00000000..6f4850a4
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/Grid.test.jsx
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import { em } from "polished";
+
+import { renderWithTheme } from "nord-docs-test-utils";
+import { Grid } from "organisms/core/Footer/styled";
+import { media } from "styles/theme";
+
+describe("theme styles", () => {
+ test("has grid layout styles for defined CSS breakpoints", () => {
+ const categoryCount = "5";
+ const mediaQueryTabletPortrait = `(min-width: ${em(media.breakpoints.tabletPortraitLowerBoundary)})`;
+ const mediaQueryTabletLandscape = `(min-width: ${em(media.breakpoints.tabletLandscapeLowerBoundary)})`;
+
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("display", "grid", {
+ media: mediaQueryTabletPortrait
+ });
+
+ expect(container.firstChild).toHaveStyleRule("grid-template-columns", expect.stringContaining(categoryCount), {
+ media: mediaQueryTabletPortrait
+ });
+
+ expect(container.firstChild).toHaveStyleRule("grid-template-rows", expect.stringContaining("auto"), {
+ media: mediaQueryTabletPortrait
+ });
+
+ expect(container.firstChild).toHaveStyleRule("grid-template-columns", expect.stringContaining("%"), {
+ media: mediaQueryTabletLandscape
+ });
+ });
+
+ test("has flexbox layout styles", () => {
+ const { container } = renderWithTheme( );
+ expect(container.firstChild).toHaveStyleRule("display", "flex");
+ });
+
+ test("matches the snapshot", () => {
+ const { container } = renderWithTheme( );
+ expect(container.firstChild).toMatchSnapshot();
+ });
+});
diff --git a/test/components/organisms/core/Footer/styled/Metadata.test.jsx b/test/components/organisms/core/Footer/styled/Metadata.test.jsx
new file mode 100644
index 00000000..265f3ccf
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/Metadata.test.jsx
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import { em } from "polished";
+
+import { renderWithTheme } from "nord-docs-test-utils";
+import { Metadata } from "organisms/core/Footer/styled";
+import { media } from "styles/theme";
+
+describe("theme styles", () => {
+ const categoryCount = "5";
+
+ test("uses automatic grid column assignment for defined CSS breakpoints", () => {
+ const mediaQuery = `(min-width: ${em(media.breakpoints.tabletLandscapeLowerBoundary)})`;
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("grid-column", "unset", {
+ media: mediaQuery
+ });
+ });
+
+ test("spans all grid columns", () => {
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("grid-column", expect.stringContaining(categoryCount));
+ });
+
+ test("has flexbox column layout styles", () => {
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("display", "flex");
+ expect(container.firstChild).toHaveStyleRule("flex-direction", "column");
+ });
+
+ test("matches the snapshot", () => {
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toMatchSnapshot();
+ });
+});
diff --git a/test/components/organisms/core/Footer/styled/OrganizationBrand.test.jsx b/test/components/organisms/core/Footer/styled/OrganizationBrand.test.jsx
new file mode 100644
index 00000000..07d7eb2c
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/OrganizationBrand.test.jsx
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import { stripUnit } from "polished";
+
+import { renderWithTheme } from "nord-docs-test-utils";
+import { OrganizationBrand } from "organisms/core/Footer/styled";
+
+describe("theme styles", () => {
+ test("has flexbox layout styles", () => {
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("display", "flex");
+ });
+
+ test("has bottom margin", () => {
+ const { container } = renderWithTheme( );
+ const marginBottom = stripUnit(getComputedStyle(container.firstChild).marginBottom);
+
+ expect(marginBottom).toBeGreaterThan(0);
+ });
+
+ test("matches the snapshot", () => {
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toMatchSnapshot();
+ });
+});
diff --git a/test/components/organisms/core/Footer/styled/Sitemap.test.jsx b/test/components/organisms/core/Footer/styled/Sitemap.test.jsx
new file mode 100644
index 00000000..8e105bba
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/Sitemap.test.jsx
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import { stripUnit } from "polished";
+
+import { renderWithTheme } from "nord-docs-test-utils";
+import { Sitemap } from "organisms/core/Footer/styled";
+
+describe("theme styles", () => {
+ test("has top and bottom margin", () => {
+ const { container } = renderWithTheme( );
+ const margingTop = stripUnit(getComputedStyle(container.firstChild).marginTop);
+ const marginBottom = stripUnit(getComputedStyle(container.firstChild).marginBottom);
+
+ expect(margingTop).toBeGreaterThan(0);
+ expect(marginBottom).toBeGreaterThan(0);
+ });
+
+ test("has flexbox column layout styles", () => {
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("display", "flex");
+ expect(container.firstChild).toHaveStyleRule("flex-direction", "column");
+ });
+
+ test("matches the snapshot", () => {
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toMatchSnapshot();
+ });
+});
diff --git a/test/components/organisms/core/Footer/styled/SitemapCategory.test.jsx b/test/components/organisms/core/Footer/styled/SitemapCategory.test.jsx
new file mode 100644
index 00000000..212c6445
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/SitemapCategory.test.jsx
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import { em, stripUnit } from "polished";
+
+import { renderWithTheme } from "nord-docs-test-utils";
+import { SitemapCategory } from "organisms/core/Footer/styled";
+import { media } from "styles/theme";
+
+describe("theme styles", () => {
+ test("resets width for defined CSS breakpoints", () => {
+ const mediaQuery = `(min-width: ${em(media.breakpoints.tabletPortraitLowerBoundary)})`;
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("width", "unset", {
+ media: mediaQuery
+ });
+ });
+
+ test("resets justified flexbox content for defined CSS breakpoints", () => {
+ const mediaQuery = `(min-width: ${em(media.breakpoints.tabletLandscapeLowerBoundary)})`;
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("justify-content", "unset", {
+ media: mediaQuery
+ });
+ });
+
+ test("has centered flexbox content layout", () => {
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("display", "flex");
+ expect(container.firstChild).toHaveStyleRule("justify-content", "center");
+ });
+
+ test("has visible border-bottom", () => {
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("border-bottom", expect.not.stringContaining("transparent"));
+ });
+
+ test("has bottom margin", () => {
+ const { container } = renderWithTheme( );
+ const marginBottom = stripUnit(getComputedStyle(container.firstChild).marginBottom);
+
+ expect(marginBottom).toBeGreaterThan(0);
+ });
+
+ test("has reduced width", () => {
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("width", expect.any(String));
+ });
+
+ test("has disabled user selection", () => {
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("user-select", "none");
+ });
+
+ test("matches the snapshot", () => {
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toMatchSnapshot();
+ });
+});
diff --git a/test/components/organisms/core/Footer/styled/SitemapLink.test.jsx b/test/components/organisms/core/Footer/styled/SitemapLink.test.jsx
new file mode 100644
index 00000000..cdb2c26e
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/SitemapLink.test.jsx
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import { stripUnit } from "polished";
+
+import { renderWithTheme } from "nord-docs-test-utils";
+import { SitemapLink } from "organisms/core/Footer/styled";
+
+describe("theme styles", () => {
+ test("has top and bottom padding", () => {
+ const { container } = renderWithTheme(Nord );
+
+ expect(container.firstChild).toHaveStyleRule("padding", expect.stringContaining("em"));
+ expect(container.firstChild).toHaveStyleRule("padding-bottom", "0", {
+ modifier: ":last-child"
+ });
+ expect(container.firstChild).toHaveStyleRule("padding-top", "0", {
+ modifier: ":first-child"
+ });
+ });
+
+ test("has reduced font size", () => {
+ const { container } = renderWithTheme(Nord );
+ const fontSize = stripUnit(getComputedStyle(container.firstChild).fontSize);
+
+ expect(fontSize).toBeLessThan(1);
+ expect(container.firstChild).toHaveStyleRule("font-size", `${fontSize}em`);
+ });
+
+ test("changes color on hover", () => {
+ const { container } = renderWithTheme(Nord );
+
+ expect(container.firstChild).toHaveStyleRule("color", expect.any(String), {
+ modifier: ":hover"
+ });
+ });
+
+ test("matches the snapshot", () => {
+ const { container } = renderWithTheme(Nord );
+ expect(container.firstChild).toMatchSnapshot();
+ });
+});
diff --git a/test/components/organisms/core/Footer/styled/SitemapList.test.jsx b/test/components/organisms/core/Footer/styled/SitemapList.test.jsx
new file mode 100644
index 00000000..2d7bfd5e
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/SitemapList.test.jsx
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import { em } from "polished";
+
+import { renderWithTheme } from "nord-docs-test-utils";
+import { SitemapList } from "organisms/core/Footer/styled";
+import { media } from "styles/theme";
+
+describe("theme styles", () => {
+ test("has 'start' text alignment for defined CSS breakpoints", () => {
+ const mediaQuery = `(min-width: ${em(media.breakpoints.tabletLandscapeLowerBoundary)})`;
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("text-align", "start", {
+ media: mediaQuery
+ });
+ });
+
+ test("has centered text alignment", () => {
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("text-align", "center");
+ });
+
+ test("matches the snapshot", () => {
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toMatchSnapshot();
+ });
+});
diff --git a/test/components/organisms/core/Footer/styled/SocialNetworking.test.jsx b/test/components/organisms/core/Footer/styled/SocialNetworking.test.jsx
new file mode 100644
index 00000000..56e79ad9
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/SocialNetworking.test.jsx
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import React from "react";
+import { em } from "polished";
+
+import { renderWithTheme } from "nord-docs-test-utils";
+import { SocialNetworking } from "organisms/core/Footer/styled";
+import { media } from "styles/theme";
+
+describe("theme styles", () => {
+ test("sets children element margins for defined CSS breakpoints", () => {
+ const mediaQuery = `(min-width: ${em(media.breakpoints.tabletLandscapeLowerBoundary)})`;
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("margin", expect.stringContaining("em"), {
+ media: mediaQuery,
+ modifier: "*"
+ });
+ });
+
+ test("unsets justified flexbox content for defined CSS breakpoints", () => {
+ const mediaQuery = `(min-width: ${em(media.breakpoints.tabletLandscapeLowerBoundary)})`;
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("justify-content", "unset", {
+ media: mediaQuery
+ });
+ });
+
+ test("has flexbox layout styles", () => {
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toHaveStyleRule("display", "flex");
+ expect(container.firstChild).toHaveStyleRule("justify-content", "space-between");
+ });
+
+ test("matches the snapshot", () => {
+ const { container } = renderWithTheme( );
+
+ expect(container.firstChild).toMatchSnapshot();
+ });
+});
diff --git a/test/components/organisms/core/Footer/styled/__snapshots__/Category.test.jsx.snap b/test/components/organisms/core/Footer/styled/__snapshots__/Category.test.jsx.snap
new file mode 100644
index 00000000..40393797
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/__snapshots__/Category.test.jsx.snap
@@ -0,0 +1,39 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`theme styles has invisible border-bottom when not matching the active route 1`] = `
+.c0 {
+ -webkit-align-self: center;
+ -ms-flex-item-align: center;
+ align-self: center;
+ font-size: 1.125em;
+ color: #7b88a1;
+ border-bottom: 2px solid transparent;
+ -webkit-transition: border-bottom 400ms ease-in-out, color 400ms ease-in-out;
+ transition: border-bottom 400ms ease-in-out, color 400ms ease-in-out;
+}
+
+
+ Nord
+
+`;
+
+exports[`theme styles has visible border-bottom when matching the active route 1`] = `
+.c0 {
+ -webkit-align-self: center;
+ -ms-flex-item-align: center;
+ align-self: center;
+ font-size: 1.125em;
+ color: #4c566a;
+ border-bottom: 2px solid #4c566a;
+ -webkit-transition: border-bottom 400ms ease-in-out, color 400ms ease-in-out;
+ transition: border-bottom 400ms ease-in-out, color 400ms ease-in-out;
+}
+
+
+ Nord
+
+`;
diff --git a/test/components/organisms/core/Footer/styled/__snapshots__/Copyright.test.jsx.snap b/test/components/organisms/core/Footer/styled/__snapshots__/Copyright.test.jsx.snap
new file mode 100644
index 00000000..bf5585aa
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/__snapshots__/Copyright.test.jsx.snap
@@ -0,0 +1,30 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`theme styles matches the snapshot 1`] = `
+.c0 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ text-align: center;
+ font-size: 0.8em;
+ color: #7b88a1;
+ -webkit-transition: color 400ms ease-in-out;
+ transition: color 400ms ease-in-out;
+ margin-top: 1.125em;
+}
+
+@media (min-width:56.25em) {
+ .c0 {
+ display: block;
+ text-align: start;
+ }
+}
+
+
+`;
diff --git a/test/components/organisms/core/Footer/styled/__snapshots__/Grid.test.jsx.snap b/test/components/organisms/core/Footer/styled/__snapshots__/Grid.test.jsx.snap
new file mode 100644
index 00000000..baccf296
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/__snapshots__/Grid.test.jsx.snap
@@ -0,0 +1,32 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`theme styles matches the snapshot 1`] = `
+.c0 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column;
+}
+
+@media (min-width:37.5em) {
+ .c0 {
+ display: grid;
+ grid-template-columns: repeat(,1fr);
+ grid-template-rows: auto;
+ grid-row-gap: 1em;
+ }
+}
+
+@media (min-width:56.25em) {
+ .c0 {
+ grid-template-columns: 30% repeat(,1fr);
+ }
+}
+
+
+`;
diff --git a/test/components/organisms/core/Footer/styled/__snapshots__/Metadata.test.jsx.snap b/test/components/organisms/core/Footer/styled/__snapshots__/Metadata.test.jsx.snap
new file mode 100644
index 00000000..f318aff9
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/__snapshots__/Metadata.test.jsx.snap
@@ -0,0 +1,36 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`theme styles matches the snapshot 1`] = `
+.c0 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ grid-column: span 5;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+}
+
+@media (min-width:56.25em) {
+ .c0 {
+ grid-column: unset;
+ -webkit-box-pack: justify;
+ -webkit-justify-content: space-between;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ -webkit-align-items: unset;
+ -webkit-box-align: unset;
+ -ms-flex-align: unset;
+ align-items: unset;
+ }
+}
+
+
+`;
diff --git a/test/components/organisms/core/Footer/styled/__snapshots__/OrganizationBrand.test.jsx.snap b/test/components/organisms/core/Footer/styled/__snapshots__/OrganizationBrand.test.jsx.snap
new file mode 100644
index 00000000..a5b9cb23
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/__snapshots__/OrganizationBrand.test.jsx.snap
@@ -0,0 +1,19 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`theme styles matches the snapshot 1`] = `
+.c0 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ margin-bottom: 2em;
+}
+
+
+`;
diff --git a/test/components/organisms/core/Footer/styled/__snapshots__/Sitemap.test.jsx.snap b/test/components/organisms/core/Footer/styled/__snapshots__/Sitemap.test.jsx.snap
new file mode 100644
index 00000000..69f01aac
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/__snapshots__/Sitemap.test.jsx.snap
@@ -0,0 +1,34 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`theme styles matches the snapshot 1`] = `
+.c0 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+@media (min-width:37.5em) {
+ .c0 {
+ -webkit-align-items: unset;
+ -webkit-box-align: unset;
+ -ms-flex-align: unset;
+ align-items: unset;
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+}
+
+
+`;
diff --git a/test/components/organisms/core/Footer/styled/__snapshots__/SitemapCategory.test.jsx.snap b/test/components/organisms/core/Footer/styled/__snapshots__/SitemapCategory.test.jsx.snap
new file mode 100644
index 00000000..fe17344c
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/__snapshots__/SitemapCategory.test.jsx.snap
@@ -0,0 +1,42 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`theme styles matches the snapshot 1`] = `
+.c0 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: center;
+ -webkit-justify-content: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+ border-bottom: 1px solid #d8dee9;
+ -webkit-transition: border-bottom 400ms ease-in-out;
+ transition: border-bottom 400ms ease-in-out;
+ margin-bottom: 1em;
+ width: 70%;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+@media (min-width:37.5em) {
+ .c0 {
+ width: unset;
+ }
+}
+
+@media (min-width:56.25em) {
+ .c0 {
+ -webkit-box-pack: unset;
+ -webkit-justify-content: unset;
+ -ms-flex-pack: unset;
+ justify-content: unset;
+ }
+}
+
+
+`;
diff --git a/test/components/organisms/core/Footer/styled/__snapshots__/SitemapLink.test.jsx.snap b/test/components/organisms/core/Footer/styled/__snapshots__/SitemapLink.test.jsx.snap
new file mode 100644
index 00000000..08a99304
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/__snapshots__/SitemapLink.test.jsx.snap
@@ -0,0 +1,47 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`theme styles matches the snapshot 1`] = `
+.c1 {
+ color: inherit;
+ cursor: pointer;
+ -webkit-text-decoration: none;
+ text-decoration: none;
+}
+
+.c1:active,
+.c1:focus,
+.c1:hover,
+.c1:visited {
+ outline: none;
+}
+
+.c0 {
+ display: block;
+ padding: 0.4em 0;
+ font-size: 0.9em;
+ color: #7b88a1;
+ -webkit-transition: color 200ms ease-in-out;
+ transition: color 200ms ease-in-out;
+}
+
+.c0:active,
+.c0:focus,
+.c0:hover {
+ color: #4c566a;
+}
+
+.c0:first-child {
+ padding-top: 0;
+}
+
+.c0:last-child {
+ padding-bottom: 0;
+}
+
+
+ Nord
+
+`;
diff --git a/test/components/organisms/core/Footer/styled/__snapshots__/SitemapList.test.jsx.snap b/test/components/organisms/core/Footer/styled/__snapshots__/SitemapList.test.jsx.snap
new file mode 100644
index 00000000..23d8bc41
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/__snapshots__/SitemapList.test.jsx.snap
@@ -0,0 +1,17 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`theme styles matches the snapshot 1`] = `
+.c0 {
+ text-align: center;
+}
+
+@media (min-width:56.25em) {
+ .c0 {
+ text-align: start;
+ }
+}
+
+
+`;
diff --git a/test/components/organisms/core/Footer/styled/__snapshots__/SocialNetworking.test.jsx.snap b/test/components/organisms/core/Footer/styled/__snapshots__/SocialNetworking.test.jsx.snap
new file mode 100644
index 00000000..5b74a9e5
--- /dev/null
+++ b/test/components/organisms/core/Footer/styled/__snapshots__/SocialNetworking.test.jsx.snap
@@ -0,0 +1,39 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`theme styles matches the snapshot 1`] = `
+.c0 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-box-pack: justify;
+ -webkit-justify-content: space-between;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+}
+
+@media (min-width:56.25em) {
+ .c0 {
+ -webkit-box-pack: unset;
+ -webkit-justify-content: unset;
+ -ms-flex-pack: unset;
+ justify-content: unset;
+ }
+
+ .c0 * {
+ margin: 0 0.625em;
+ }
+
+ .c0 *:last-child {
+ margin-right: 0;
+ }
+
+ .c0 *:first-child {
+ margin-left: 0;
+ }
+}
+
+
+`;
diff --git a/test/pages/__snapshots__/index.test.jsx.snap b/test/pages/__snapshots__/index.test.jsx.snap
deleted file mode 100644
index 3a2e181c..00000000
--- a/test/pages/__snapshots__/index.test.jsx.snap
+++ /dev/null
@@ -1,9 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`snapshot 1`] = `
-
-
-
-`;
diff --git a/test/pages/index.test.jsx b/test/pages/index.test.jsx
deleted file mode 100644
index 4ffc144a..00000000
--- a/test/pages/index.test.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2018-present Arctic Ice Studio
- * Copyright (C) 2018-present Sven Greb
- *
- * Project: Nord Docs
- * Repository: https://github.com/arcticicestudio/nord-docs
- * License: MIT
- */
-
-import React from "react";
-import { render } from "react-testing-library";
-
-import Landing from "pages";
-
-/*
- * This test is disabled because it will be covered by E2E tests with Cypress later on.
- * It is also skipped due to problems with mocking transitive modules and components.
- */
-test.skip("snapshot", () => {
- const { container } = render( );
- expect(container).toMatchSnapshot();
-});
diff --git a/test/utils/getSemVerFromGitDescribe.test.js b/test/utils/getSemVerFromGitDescribe.test.js
new file mode 100644
index 00000000..4e944c4f
--- /dev/null
+++ b/test/utils/getSemVerFromGitDescribe.test.js
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018-present Arctic Ice Studio
+ * Copyright (C) 2018-present Sven Greb
+ *
+ * Project: Nord Docs
+ * Repository: https://github.com/arcticicestudio/nord-docs
+ * License: MIT
+ */
+
+import { getSemVerFromGitDescribe } from "utils";
+
+const CHANNEL_PRERELEASE = "pre-release";
+const CHANNEL_RELEASE = "release";
+const CHANNEL_SNAPSHOT = "snapshot";
+const CHANNEL_PRERELEASE_SNAPSHOT = `${CHANNEL_PRERELEASE}-${CHANNEL_SNAPSHOT}`;
+const STABILITY_STATUS_STABLE = "stable";
+const STABILITY_STATUS_UNSTABLE = "unstable";
+const SCM_PREFIX = "g";
+
+const PREFIX = "v";
+const MAJOR_VERSION = "0";
+const MINOR_VERSION = "1";
+const PATCH_VERSION = "2";
+const COMMITS_AHEAD = "8";
+const COMMIT_HASH = "abcd1234";
+const PRE_RELEASE_NAME = "frost";
+const PRE_RELEASE_NUMBER = "2";
+const PRE_RELEASE = `${PRE_RELEASE_NAME}.${PRE_RELEASE_NUMBER}`;
+const VERSION = `${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}`;
+const VERSION_WITH_PREFIX = `${PREFIX}${VERSION}`;
+const VERSION_SNAPSHOT = `${VERSION}-${COMMITS_AHEAD}-${SCM_PREFIX}${COMMIT_HASH}`;
+const VERSION_PRE_RELEASE = `${VERSION}-${PRE_RELEASE}`;
+const VERSION_PRE_RELEASE_SNAPTSHOT = `${VERSION_PRE_RELEASE}-${COMMITS_AHEAD}-${SCM_PREFIX}${COMMIT_HASH}`;
+
+describe("rejects incompatible SemVer versions", () => {
+ test("single commit SHA hash", () => {
+ expect(getSemVerFromGitDescribe(COMMIT_HASH)).toBeNull();
+ });
+
+ test("empty string and single whitespace", () => {
+ expect(getSemVerFromGitDescribe("")).toBeNull();
+ expect(getSemVerFromGitDescribe(" ")).toBeNull();
+ });
+
+ test("invalid tag/version prefixes", () => {
+ [
+ `V${VERSION}`,
+ `vv${VERSION}`,
+ `version${VERSION}`,
+ `invalid${VERSION}`,
+ `_${VERSION}`,
+ `_v${VERSION}`,
+ `v_${VERSION}`,
+ ` ${VERSION}`,
+ ` v${VERSION}`
+ ].forEach(invalidVersionPrefix => expect(getSemVerFromGitDescribe(invalidVersionPrefix)).toBeNull());
+ });
+});
+
+describe("processes valid SemVer versions including additional metadata", () => {
+ test("stable release version without any additional metadata", () => {
+ const parsedSemVer = getSemVerFromGitDescribe(VERSION_WITH_PREFIX);
+
+ expect(parsedSemVer.version).toBe(VERSION);
+ expect(parsedSemVer.prerelease).toHaveLength(0);
+ expect(parsedSemVer.build).toHaveLength(0);
+ expect(parsedSemVer.commitsAhead).toBe(0);
+ expect(parsedSemVer.channel).toBe(CHANNEL_RELEASE);
+ expect(parsedSemVer.stabilityStatus).toBe(STABILITY_STATUS_STABLE);
+ });
+
+ test("snapshot version with number of commits ahead", () => {
+ const parsedSemVer = getSemVerFromGitDescribe(`${PREFIX}${VERSION_SNAPSHOT}`);
+
+ expect(parsedSemVer.version).toBe(VERSION);
+ expect(parsedSemVer.prerelease).toHaveLength(0);
+ expect(parsedSemVer.build).toHaveLength(1);
+ expect(parsedSemVer.build).toContainEqual(COMMIT_HASH);
+ expect(parsedSemVer.commitsAhead).toBe(8);
+ expect(parsedSemVer.channel).toBe(CHANNEL_SNAPSHOT);
+ expect(parsedSemVer.stabilityStatus).toBe(STABILITY_STATUS_UNSTABLE);
+ expect(parsedSemVer.raw).toBe(`${VERSION_WITH_PREFIX}+${COMMIT_HASH}`);
+ });
+
+ test("pre-release snapshot version with number of commits ahead", () => {
+ const parsedSemVer = getSemVerFromGitDescribe(`${PREFIX}${VERSION_PRE_RELEASE_SNAPTSHOT}`);
+
+ expect(parsedSemVer.version).toBe(VERSION_PRE_RELEASE);
+ expect(parsedSemVer.prerelease).toHaveLength(2);
+ expect(parsedSemVer.prerelease).toContainEqual(PRE_RELEASE_NAME);
+ expect(parsedSemVer.prerelease).toContainEqual(Number.parseInt(PRE_RELEASE_NUMBER, 10));
+ expect(parsedSemVer.build).toHaveLength(1);
+ expect(parsedSemVer.build).toContainEqual(COMMIT_HASH);
+ expect(parsedSemVer.commitsAhead).toBe(8);
+ expect(parsedSemVer.channel).toBe(CHANNEL_PRERELEASE_SNAPSHOT);
+ expect(parsedSemVer.stabilityStatus).toBe(STABILITY_STATUS_UNSTABLE);
+ expect(parsedSemVer.raw).toBe(`${PREFIX}${VERSION_PRE_RELEASE}+${COMMIT_HASH}`);
+ });
+});