Signed-off-by: David Calavera <david.calavera@gmail.com>
This commit is contained in:
David Calavera 2016-11-21 14:52:41 -08:00
commit 0143a64735
No known key found for this signature in database
GPG Key ID: DE3D437CCBECE2C4
43 changed files with 1109 additions and 0 deletions

7
.babelrc Normal file
View File

@ -0,0 +1,7 @@
{
"presets": ["es2015"],
"plugins": [
"syntax-object-rest-spread",
"transform-object-rest-spread"
]
}

101
.eslintrc Normal file
View File

@ -0,0 +1,101 @@
env:
browser: true
parser: babel-eslint
plugins: [ "import" ]
# enable ECMAScript features
ecmaFeatures:
arrowFunctions: true
binaryLiterals: true
blockBindings: true
classes: true
defaultParams: true
destructuring: true
forOf: true
generators: true
jsx: true
modules: true
objectLiteralShorthandMethods: true
objectLiteralShorthandProperties: true
octalLiterals: true
spread: true
templateStrings: true
rules:
# Possible Errors
# https://github.com/eslint/eslint/tree/master/docs/rules#possible-errors
no-control-regex: 2
no-console: 1
no-debugger: 2
no-dupe-args: 2
no-dupe-keys: 2
no-duplicate-case: 2
no-empty-character-class: 2
no-ex-assign: 2
no-extra-boolean-cast : 2
no-extra-semi: 2
no-invalid-regexp: 2
no-irregular-whitespace: 1
no-proto: 2
no-unexpected-multiline: 2
no-unreachable: 2
valid-typeof: 2
# Best Practices
# https://github.com/eslint/eslint/tree/master/docs/rules#best-practices
no-fallthrough: 2
no-redeclare: 2
# Stylistic Issues
# https://github.com/eslint/eslint/tree/master/docs/rules#stylistic-issues
comma-spacing: 2
eol-last: 2
eqeqeq: ["error", "smart"]
indent: [2, 2, {SwitchCase: 1}]
keyword-spacing: 2
max-len: [1, 160, 2]
new-parens: 2
no-mixed-spaces-and-tabs: 2
no-multiple-empty-lines: [2, {max: 2}]
no-trailing-spaces: 2
object-curly-spacing: [2, "never"]
quotes: [2, "double", "avoid-escape"]
semi: 2
space-before-blocks: [2, "always"]
space-before-function-paren: [2, "never"]
space-in-parens: [2, "never"]
space-infix-ops: 2
space-unary-ops: 2
# ECMAScript 6
# http://eslint.org/docs/rules/#ecmascript-6
arrow-parens: [2, "always"]
arrow-spacing: [2, {"before": true, "after": true}]
no-confusing-arrow: 2
prefer-const: 2
# JSX
jsx-quotes: [2, "prefer-double"]
# Import
import/no-unresolved: [1, {"commonjs": true, "amd": true}]
import/export: 2
# Strict Mode
# https://github.com/eslint/eslint/tree/master/docs/rules#strict-mode
strict: [2, "global"]
# Variables
# https://github.com/eslint/eslint/tree/master/docs/rules#variables
no-undef: 2
no-unused-vars: [2, {"args": "none"}]
# Global scoped method and vars
globals:
__dirname: true
require: true
process: true
ENV: true
module: true

27
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,27 @@
<!--
If you are reporting a new issue, make sure that we do not have any duplicates
already open. You can ensure this by searching the issue list for this
repository. If there is a duplicate, please close your issue and add a comment
to the existing issue instead.
If you suspect your issue is a bug, please edit your issue description to
include the BUG REPORT INFORMATION shown below. If you fail to provide this
information within 7 days, we cannot debug your issue and will close it. We
will, however, reopen it if you later provide the information.
---------------------------------------------------
BUG REPORT INFORMATION
---------------------------------------------------
Use the commands below to provide key information from your environment:
You do NOT have to include this information if this is a FEATURE REQUEST
-->
**- Do you want to request a *feature* or report a *bug*?**
**- What is the current behavior?**
**- If the current behavior is a bug, please provide the steps to reproduce.**
**- What is the expected behavior?**
**- Please mention your node.js, and operating system version.**

35
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,35 @@
<!--
Thanks for submitting a pull request!
Please make sure you've read and understood our contributing guidelines;
https://github.com/netlify/netlify-statuskit/blob/master/CONTRIBUTING.md
If this is a bug fix, make sure your description includes "fixes #xxxx", or
"closes #xxxx", where #xxxx is the issue number.
Please provide enough information so that others can review your pull request.
The first three fields are mandatory:
-->
**- Summary**
<!--
Explain the **motivation** for making this change.
What existing problem does the pull request solve?
-->
**- Test plan**
<!--
Demonstrate the code is solid.
Example: The exact commands you ran and their output, screenshots / videos if the pull request changes UI.
-->
**- Description for the changelog**
<!--
Write a short (one line) summary that describes the changes in this
pull request for inclusion in the changelog:
-->
**- A picture of a cute animal (not mandatory but encouraged)**

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
node_modules/
dist/
npm-debug.log

74
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,74 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at david@netlify.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

47
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,47 @@
# CONTRIBUTING
Contributions are always welcome, no matter how large or small. Before contributing,
please read the [code of conduct](CODE_OF_CONDUCT.md).
## Setup
> Install yarn on your system: https://yarnpkg.com/en/docs/install
```sh
$ git clone https://github.com/netlify/netlify-statuskit
$ cd netlify-statuskit
$ yarn
```
## Building
```sh
$ npm run build
```
## Testing
```sh
$ npm run test
```
## Runing the server
```sh
$ npm run start
```
## Pull Requests
We actively welcome your pull requests.
1. Fork the repo and create your branch from `master`.
2. If you've added code that should be tested, add tests.
3. If you've changed APIs, update the documentation.
4. Ensure the test suite passes.
5. Make sure your code lints.
## License
By contributing to Netlify StatusKit, you agree that your contributions will be licensed
under its [MIT license](LICENSE).

22
LICENSE Normal file
View File

@ -0,0 +1,22 @@
Copyright (c) 2016 Netlify <hello@netlify.com>
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

58
README.md Normal file
View File

@ -0,0 +1,58 @@
# Introduction
Netlify StatusKit is a template to deploy your own Status pages on Netlify.
Netlify StatusKit is released under the [MIT License](LICENSE).
Please make sure you understand its [implications and guarantees](https://writing.kemitchell.com/2016/09/21/MIT-License-Line-by-Line.html).
[![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/netlify/netlify-statuskit)
## Initial configuration
Click in the Deploy to Netlify button above to create your own site directly and push this repository to your own account.
Before creating the site, Netlify will ask you to fill required environment variables listed here:
- `STATUSKIT_PAGE_TITLE` - Title to show in the browser for your status site.
- `STATUSKIT_COMPANY_LOGO` - URL to your company's logo.
- `STATUSKIT_SUPPORT_CONTACT_LINK` - URL to a support page for your users to talk with you.
- `STATUSKIT_RESOURCES_LINK` - URL to documentation for your users.
- `STATUSKIT_FAVICONS_PATH` - Path where the favicons for different statuses are. By default, we use `/images/favicon/favicon-ok.ico` when there are no incidents, `/images/favicon/favicon-warning.ico` when there are no major incidents, and `/images/favicon/favicon-danger.ico` when there are major incidents. This path can be an external URL, like `https://my-favourite-cdn/images/status-favicons`. The names for the different statuses must be `favicon-ok.ico`, favicon-warning.ico` and `favicon-danger.ico`.
## Extra configuration
After the site is created, you can modify the code as much as you want and push it to your GitHub repository. Netlify will pick up changes from there.
### Reporting systems
You can add systems you want to report about to your Status page. For instance, you might want to tell your users about a status change in your CDN infrastructure but not in your API.
Go to `site/config.toml` and change the global `systems` variables. Once that's done, you'll be able to change the status of each one of those systems individually when you open or modify an incident.
### Full customization
This template is based in [Netlify's Victor-Hugo](https://github.com/netlify/victor-hugo) boilerplate.
To work on it you'll need NPM installed. To download dependencies type `npm run dependencies`, that will check if you have Hugo installed and will download it for you if you don't. It will also run `npm install` for the first time to download extra dependencies. After that, you can run `npm install` every time you want to install packages.
## Creating incidents
Adding incidents to your status page is as simple as adding a new document to the incidents collection.
Create a new incident using Hugo with a command like this:
```
hugo -s site new -k incidents incidents/oh-no-something-went-wrong.md
```
Hugo will create a new Markdown file for you with title and date based on the file name and a few predefined settings in the header. To learn more about the different states and report, you can see more detailed examples in `site/archetypes/incidents.md`.
After explaining the current situation in the incident, you can just push the file to GitHub. Netlify will deploy the indicent announcement for you in a matter of seconds.
## Resolving incidents
Everything will be operational again when all incidents are marked with `resolved = true`.
# Development
Netlify StatusKit uses NPM to manage dependencies. It also bundles a version of Hugo to work out of the box.
1. Use `npm install` to download dependencies.
2. Use `npm start` to start the development server.

BIN
bin/hugo_0.17_darwin_amd64 Executable file

Binary file not shown.

BIN
bin/hugo_0.17_linux_amd64 Executable file

Binary file not shown.

BIN
bin/hugo_0.17_windows_amd64.exe Executable file

Binary file not shown.

65
gulpfile.babel.js Normal file
View File

@ -0,0 +1,65 @@
import gulp from "gulp";
import cp from "child_process";
import gutil from "gulp-util";
import postcss from "gulp-postcss";
import cssImport from "postcss-import";
import cssnext from "postcss-cssnext";
import BrowserSync from "browser-sync";
import webpack from "webpack";
import webpackConfig from "./webpack.conf";
const browserSync = BrowserSync.create();
const hugoBin = `./bin/hugo_0.17_${process.platform}_amd64${process.platform === "windows" ? ".exe" : ""}`;
const defaultArgs = ["-d", "../dist", "-s", "site", "-v"];
gulp.task("hugo", (cb) => buildSite(cb));
gulp.task("hugo-preview", (cb) => buildSite(cb, ["--buildDrafts", "--buildFuture"]));
gulp.task("build", ["css", "js", "hugo"]);
gulp.task("build-preview", ["css", "js", "hugo-preview"]);
gulp.task("css", () => (
gulp.src("./src/css/*.css")
.pipe(postcss([cssnext(), cssImport({from: "./src/css/main.css"})]))
.pipe(gulp.dest("./dist/css"))
.pipe(browserSync.stream())
));
gulp.task("js", (cb) => {
const myConfig = Object.assign({}, webpackConfig);
webpack(myConfig, (err, stats) => {
if (err) throw new gutil.PluginError("webpack", err);
gutil.log("[webpack]", stats.toString({
colors: true,
progress: true
}));
browserSync.reload();
cb();
});
});
gulp.task("server", ["hugo", "css", "js"], () => {
browserSync.init({
server: {
baseDir: "./dist"
}
});
gulp.watch("./src/js/**/*.js", ["js"]);
gulp.watch("./src/css/**/*.css", ["css"]);
gulp.watch("./site/**/*", ["hugo"]);
});
function buildSite(cb, options) {
const args = options ? defaultArgs.concat(options) : defaultArgs;
return cp.spawn(hugoBin, args, {stdio: "inherit"}).on("close", (code) => {
if (code === 0) {
browserSync.reload();
cb();
} else {
browserSync.notify("Hugo build failed :(");
cb("Hugo build failed");
}
});
}

13
netlify.toml Normal file
View File

@ -0,0 +1,13 @@
[build]
command = "npm run build"
publish = "dist"
[context.deploy-preview]
command = "npm run build-preview"
[template.environment]
STATUSKIT_PAGE_TITLE = "title for the page"
STATUSKIT_COMPANY_LOGO = "url to your company's logo"
STATUSKIT_SUPPORT_CONTACT_LINK = "url to your support page"
STATUSKIT_RESOURCES_LINK = "url to your knowledge base page"
STATUSKIT_FAVICONS_PATH = "/images/favicons/"

47
package.json Normal file
View File

@ -0,0 +1,47 @@
{
"name": "netlify-statusKit",
"version": "1.0.0",
"description": "StatusKit is a template to build Status pages for your business",
"main": "index.js",
"scripts": {
"hugo": "gulp hugo",
"webpack": "gulp webpack",
"build": "gulp build",
"build-preview": "gulp build-preview",
"start": "gulp server",
"lint": "eslint src"
},
"author": "",
"license": "MIT",
"dependencies": {
"autoprefixer": "^6.3.7",
"babel-eslint": "^6.1.2",
"babel-loader": "^6.2.4",
"babel-plugin-syntax-object-rest-spread": "^6.13.0",
"babel-plugin-transform-class-properties": "^6.10.2",
"babel-plugin-transform-object-assign": "^6.8.0",
"babel-plugin-transform-object-rest-spread": "^6.8.0",
"babel-preset-es2015": "^6.9.0",
"babel-register": "^6.11.6",
"browser-sync": "^2.13.0",
"css-loader": "^0.23.1",
"eslint": "^3.1.1",
"eslint-plugin-import": "^1.11.1",
"exports-loader": "^0.6.3",
"file-loader": "^0.9.0",
"gulp": "^3.9.1",
"gulp-babel": "^6.1.2",
"gulp-postcss": "^6.1.1",
"gulp-util": "^3.0.7",
"imports-loader": "^0.6.5",
"postcss-cssnext": "^2.7.0",
"postcss-import": "^8.1.2",
"postcss-loader": "^0.9.1",
"url-loader": "^0.5.7",
"webpack": "^1.13.1",
"whatwg-fetch": "^1.0.0"
},
"optionalDependencies": {
"fsevents": "^1.0.15"
}
}

View File

@ -0,0 +1,30 @@
+++
# default attributes for an incident.
#
# Hugo adds `title` and `date` by default
# when running `hugo new incidents/new-incident.md`,
# so we don't have to specify them here.
# state: represents the global state of
# your system due to the current incident.
# This is the list of supported states:
#
# - under-maintenance
# - degraded-performance
# - partial-outage
# - major-outage
#
state = "degraded-performance"
# affectedsystem: is a list of systems affected
# by the incident.
# Example:
# affectedsytems = ["API", "Build servers"]
#
affectedsytems = ["API", "Build servers"]
# resolved: marks an incident as resolved.
# It can be either true or false.
#
resolved = false
+++

17
site/config.toml Normal file
View File

@ -0,0 +1,17 @@
baseurl = "/"
languageCode = "en-us"
title = "StatusKit"
[permalinks]
incidents = "/incidents/:year/:month/:day/:slug/"
[params]
defaultLogo = "https://www.netlify.com/img/press/logos/logomark.svg"
faviconsPath = "/images/favicon/"
# List of systems monitored in this status page.
# You'll be able to change their status every time
# you open or update an incident.
# Example:
# systems = ["API", "CDN", "DNS", "Site delivery"]
systems = []

0
site/content/.keep Normal file
View File

View File

0
site/data/.keep Normal file
View File

13
site/data/states.toml Normal file
View File

@ -0,0 +1,13 @@
[descriptions]
ok = "Up and running"
under-maintenance = "Under maintenance"
degraded-performance = "Degraded performance"
partial-outage = "Partial outage"
major-outage = "Major outage"
[alerts]
ok = "ok"
under-maintenance = "warning"
degraded-performance = "warning"
partial-outage = "warning"
major-outage = "danger"

View File

@ -0,0 +1,4 @@
{{ partial "header" . }}
{{ partial "incident" . }}
</div>

31
site/layouts/index.html Normal file
View File

@ -0,0 +1,31 @@
{{ partial "header" . }}
{{ $incidents := where .Site.Pages.ByDate.Reverse "Section" "incidents" }}
{{ $active := where $incidents "Params.resolved" "!=" true }}
{{ partial "systems" (dict "content" . "incidents" $active) }}
{{ with $active }}
<div class="section-title">Active Incidents</div>
{{ range $active }}
{{ partial "incident" . }}
{{ end }}
{{ else }}
{{ $latest := index $incidents 0 }}
{{ partial "all-clear" $latest }}
{{ end }}
{{ $recents := first 3 (where $incidents "Params.resolved" "==" true) }}
{{ with $recents }}
<div class="history">
<div class="section-title">Past Incidents</div>
{{ range $recents }}
{{ partial "incident" . }}
{{ end }}
<a href="/incidents" class="see-more">See all incidents</a>
</div>
{{ end }}
{{ partial "footer" . }}
<script src="/app.js"></script>

View File

@ -0,0 +1,10 @@
<div class="system-check-ok">
<img src="/images/icon-large-ok.svg" />
{{ with .Date }}
{{ $latestDate := dateFormat "2006-01-02T15:04:05" .Date}}
<p id="days-since-latest" data-latest-incident-date="{{ $latestDate }}">48+ days since last incident</p>
{{ else }}
<p>No incidents so far, all is good</p>
{{ end }}
</div>

View File

@ -0,0 +1,5 @@
<div class="footer">
<a href="http://netlify.com">
Powered by Netlify
</a>
</div>

View File

@ -0,0 +1,37 @@
<!doctype html>
{{ $logo := getenv "STATUSKIT_COMPANY_LOGO" | default .Site.Params.defaultLogo }}
{{ $title := getenv "STATUSKIT_PAGE_TITLE" | default .Site.Title }}
{{ $resources := getenv "STATUSKIT_RESOURCES_LINK" | default .Site.Params.resourcesLink }}
{{ $contact := getenv "STATUSKIT_SUPPORT_CONTACT_LINK" | default .Site.Params.contactLink }}
{{ $favicons := getenv "STATUSKIT_FAVICONS_PATH" | default .Site.Params.faviconsPath }}
{{ $incidents := where .Site.Pages.ByDate.Reverse "Section" "incidents" }}
{{ $active := where $incidents "Params.resolved" "!=" true }}
{{ $major := where $active "Params.state" "major-outage" }}
<html>
<head>
<title>{{ $title }}</title>
<link rel="stylesheet" href="/css/main.css"/>
{{ if $major }}
<link rel="icon" href="{{ absURL $favicons }}favicon-danger.ico">
{{ else if $active }}
<link rel="icon" href="{{ absURL $favicons }}favicon-warning.ico">
{{ else }}
<link rel="icon" href="{{ absURL $favicons }}favicon-ok.ico">
{{ end }}
</head>
<body>
<div class="gangsta-wrap">
<div class="header">
<img src="{{ $logo }}" class="logo"/>
<span class="title"><a href="/">{{ $title }}</a></span>
<div class="right-links">
{{ with $resources }}
<a href="{{ . }}" class="button resources-link">Resources</a>
{{ end }}
{{ with $contact }}
<a href="{{ . }}" class="button contact-link">Contact</a>
{{ end }}
</div>
</div>

View File

@ -0,0 +1,14 @@
<div class="incident card">
<div class="incident-header">
<p class="incident-title">{{ .Title }}</p>
<p class="incident-date">{{ dateFormat "02 Jan 2006 15:04 -0700 MST" .Date }}</p>
</div>
<div class="incident-description">
{{- .Content -}}
</div>
{{- $alert := index .Site.Data.states.alerts .Params.state -}}
<p class="incident-status color-{{ $alert }}">
{{ index .Site.Data.states.descriptions .Params.state }}
</p>
</div>

View File

@ -0,0 +1,31 @@
{{ $pag := $.Paginator }}
{{ if gt $pag.TotalPages 1 }}
<ul class="pagination">
{{ if gt $pag.TotalPages 5 }}
{{ with $pag.First }}
<li>
<a href="{{ .URL }}" aria-label="First"><span aria-hidden="true">&laquo;&laquo;</span></a>
</li>
{{ end }}
{{ end }}
<li
{{ if not $pag.HasPrev }}class="disabled"{{ end }}>
<a href="{{ if $pag.HasPrev }}{{ $pag.Prev.URL }}{{ end }}" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a>
</li>
{{ range $pag.Pagers }}
<li
{{ if eq . $pag }}class="active"{{ end }}><a href="{{ .URL }}">{{ .PageNumber }}</a></li>
{{ end }}
<li
{{ if not $pag.HasNext }}class="disabled"{{ end }}>
<a href="{{ if $pag.HasNext }}{{ $pag.Next.URL }}{{ end }}" aria-label="Next"><span aria-hidden="true">&raquo;</span></a>
</li>
{{ if gt $pag.TotalPages 5 }}
{{ with $pag.Last }}
<li>
<a href="{{ .URL }}" aria-label="Last"><span aria-hidden="true">&raquo;&raquo;</span></a>
</li>
{{ end }}
{{ end }}
</ul>
{{ end }}

View File

@ -0,0 +1,5 @@
<div class="system-status-badge color-{{ .alert }}">
<!-- Depends on status -->
<img src="/images/icon-{{ .alert }}.svg" />
{{ .description }}
</div>

View File

@ -0,0 +1,29 @@
{{ $okAlert := index .content.Site.Data.states.alerts "ok"}}
{{ $okDesc := index .content.Site.Data.states.descriptions "ok" }}
{{ with .content.Site.Params.systems }}
<div class="systems">
{{ range . }}
{{ $name := . }}
<div class="system-operational">
<div class="card">
{{ $name }}
{{ if $.incidents }}
{{ range $.incidents }}
{{ if in .Params.affectedsystems $name }}
{{ $alert := index .Site.Data.states.alerts .Params.state }}
{{ $desc := index .Site.Data.states.descriptions .Params.state }}
{{ partial "status-badge" (dict "alert" $alert "description" $desc) }}
{{ else }}
{{ partial "status-badge" (dict "alert" $okAlert "description" $okDesc) }}
{{ end }}
{{ end }}
{{ else }}
{{ partial "status-badge" (dict "alert" $okAlert "description" $okDesc) }}
{{ end }}
</div>
</div>
{{ end }}
</div>
{{ end }}

View File

@ -0,0 +1,16 @@
{{ partial "header" . }}
<div class="incidents">
{{ range (.Paginate .Data.Pages.ByPublishDate 15 ).Pages }}
<div class="incident-summary">
<a href="{{ .Permalink }}" class="article article-title">
{{ .Title }}
</a>
<span class="article-date">
{{ dateFormat "02 Jan 2006 15:04 -0700 MST" .Date }}
</span>
</div>
{{ end }}
{{ partial "paginator" . }}
</div>

0
site/static/.keep Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="#BD1F1A" fill-rule="evenodd" d="M31.9518167,60 L39.6352947,52.316522 C40.121127,51.8306897 40.1214237,51.045068 39.63705,50.5606943 L37.4393057,48.36295 C36.9556324,47.8792767 36.1688211,47.8793622 35.683478,48.3647053 L28,56.0481833 L20.316522,48.3647053 C19.8306897,47.878873 19.045068,47.8785763 18.5606943,48.36295 L16.36295,50.5606943 C15.8792767,51.0443676 15.8793622,51.8311789 16.3647053,52.316522 L24.0481833,60 L16.3647053,67.683478 C15.878873,68.1693103 15.8785763,68.954932 16.36295,69.4393057 L18.5606943,71.63705 C19.0443676,72.1207233 19.8311789,72.1206378 20.316522,71.6352947 L28,63.9518167 L35.683478,71.6352947 C36.1693103,72.121127 36.954932,72.1214237 37.4393057,71.63705 L39.63705,69.4393057 C40.1207233,68.9556324 40.1206378,68.1688211 39.6352947,67.683478 L31.9518167,60 L31.9518167,60 Z" transform="translate(-16 -48)"/>
</svg>

After

Width:  |  Height:  |  Size: 951 B

View File

@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" width="141" height="141" viewBox="0 0 141 141" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<circle id="a" cx="70.5" cy="70.5" r="70.5"/>
<mask id="b" width="141" height="141" x="0" y="0" fill="white">
<use xlink:href="#a"/>
</mask>
</defs>
<g fill="none" fill-rule="evenodd">
<path fill="#009A8D" d="M96.2371576,45.8858211 C95.0357448,44.7047263 93.0652397,44.7047263 91.8630436,45.8858211 L63.0661795,74.0040203 C61.8639835,75.1851151 59.8942616,75.1851151 58.6920655,74.0040203 L49.136369,64.6168175 C47.9341729,63.4357227 45.964451,63.4357227 44.762255,64.6168175 L38.901647,70.3776361 C37.699451,71.5587309 37.699451,73.4938797 38.901647,74.6749745 L58.6920655,94.1141789 C59.8942616,95.2952737 61.8639835,95.2952737 63.0661795,94.1141789 L102.097766,55.9409004 C103.300745,54.7590361 103.300745,52.8246568 102.097766,51.6427926 L96.2371576,45.8858211 Z"/>
<use stroke="#009A8D" stroke-width="20" mask="url(#b)" xlink:href="#a"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="31" height="24" viewBox="0 0 31 24">
<path fill="#009A8D" fill-rule="evenodd" d="M43.7746444,48.4251941 C43.2016629,47.8582686 42.2618835,47.8582686 41.6885285,48.4251941 L27.9546395,61.9219298 C27.3812844,62.4888553 26.4418786,62.4888553 25.8685235,61.9219298 L21.3111914,57.4160724 C20.7378363,56.8491469 19.7984305,56.8491469 19.2250754,57.4160724 L16.4300163,60.1812653 C15.8566612,60.7481908 15.8566612,61.6770623 16.4300163,62.2439878 L25.8685235,71.5748059 C26.4418786,72.1417314 27.3812844,72.1417314 27.9546395,71.5748059 L46.5697036,53.2516322 C47.1434321,52.6843373 47.1434321,51.7558353 46.5697036,51.1885404 L43.7746444,48.4251941 Z" transform="translate(-16 -48)"/>
</svg>

After

Width:  |  Height:  |  Size: 736 B

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="27" height="24" viewBox="0 0 27 24">
<g fill="#DFAA00" fill-rule="evenodd">
<path d="M23.8964786,23.9045455 L3.04807208,23.9045455 C1.82549221,23.9045455 0.841330519,23.4182727 0.348013636,22.5692727 C-0.145028571,21.7216364 -0.0774584416,20.6318182 0.533968831,19.581 L10.9578974,1.65381818 C11.569874,0.602727273 12.4861909,0 13.47255,0 C14.4591838,0 15.3755006,0.603 15.9866532,1.65409091 L26.4100325,19.5815455 C27.0217344,20.6326364 27.0895792,21.7219091 26.596537,22.5698182 C26.1032201,23.4182727 25.1190584,23.9045455 23.8964786,23.9045455 Z M13.47255,2.17581818 C13.3294442,2.17581818 13.0833351,2.35090909 12.8559039,2.74227273 L2.43170065,20.6691818 C2.20399481,21.0602727 2.17432987,21.3594545 2.24574545,21.4824545 C2.31716104,21.6046364 2.59293506,21.7287273 3.04807208,21.7287273 L23.8964786,21.7287273 C24.3516156,21.7287273 24.6271149,21.6046364 24.6988052,21.4819091 C24.7702208,21.3594545 24.7400065,21.0605455 24.5125753,20.6691818 L14.0886468,2.742 C13.8614903,2.35090909 13.6151065,2.17581818 13.47255,2.17581818 Z"/>
<path d="M12.1716877 14.2895455C12.2293695 14.8838182 12.3263299 15.3207273 12.4686117 15.6259091 12.6471506 16.0099091 12.9784091 16.2128182 13.4272286 16.2128182 13.8664344 16.2128182 14.1998903 16.0071818 14.392163 15.6182727 14.5484532 15.3008182 14.6470617 14.8699091 14.6921084 14.3042727L15.0783019 9.90790909C15.1208766 9.49636364 15.142576 9.08290909 15.142576 8.67954545 15.142576 7.95872727 15.0472636 7.41354545 14.8503214 7.01236364 14.6921084 6.69027273 14.3353052 6.30681818 13.5354506 6.30681818 13.0212584 6.30681818 12.5979838 6.47945455 12.2774377 6.81981818 11.9618357 7.155 11.8017 7.61509091 11.8017 8.18890909 11.8017 8.55872727 11.8291675 9.16881818 11.8832786 10.0039091L12.1716877 14.2895455zM13.4634857 17.1531818C13.0012071 17.1531818 12.6048506 17.3154545 12.2845792 17.6326364 11.9640331 17.9506364 11.8017 18.342 11.8017 18.7941818 11.8017 19.3093636 11.9755695 19.7203636 12.318639 20.0157273 12.648524 20.3007273 13.0396617 20.4441818 13.4813396 20.4441818 13.9180734 20.4441818 14.3056403 20.2982727 14.6333279 20.0089091 14.9709039 19.7102727 15.142576 19.3022727 15.142576 18.7939091 15.142576 18.3400909 14.9766721 17.9481818 14.6481604 17.6296364 14.3223955 17.3138182 13.9235669 17.1531818 13.4634857 17.1531818z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,4 @@
body {
font-size: 16px;
margin: 0;
}

290
src/css/main.css Normal file
View File

@ -0,0 +1,290 @@
@import "imports/reset.css";
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
color: #202020;
font-size: 16px;
}
a {
color: #3A71B0;
text-decoration: none;
}
a:hover,
a:focus,
a:active {
text-decoration: underline;
}
.gangsta-wrap {
max-width: 800px;
margin: auto;
padding: 16px;
padding-bottom: 104px;
}
.header {
margin-bottom: 40px;
padding: 16px 0 24px 0;
border-bottom: 2px solid #F7F7F8;
}
.logo {
position: relative;
top: 4px;
height: 24px;
margin-right: 8px;
}
.title {
font-size: 21px;
font-weight: 500;
letter-spacing: 0;
line-height: 24px;
}
.title a {
color: #202020;
}
.title a:hover,
.title a:focus, {
text-decoration: none;
}
.right-links {
float: right;
}
@media (max-width: 450px) {
.right-links {
float: left;
margin-top: 24px;
}
.header {
padding-bottom: 68px;
}
}
.button {
position: relative;
top: 4px;
padding: 8px 16px 8px 16px;
font-size: 14px;
font-weight: 600;
color: #202020;
letter-spacing: 0;
line-height: 24px;
text-decoration: none;
border: 2px solid #202020;
border-radius: 4px;
background: #fff;
transition: all 0.3s ease;
}
.button:hover,
.button:active,
.button:focus {
text-decoration: none;
background: #202020;
color: #fff;
}
.contact-link {
margin-left: 16px;
}
.systems {
display: flex;
flex-wrap: wrap;
}
.card {
display: flex;
flex-direction: column;
justify-content: flex-start;
overflow: hidden;
margin-bottom: 24px;
padding: 16px;
border-radius: 10px;
background: #fff;
box-shadow: 0px 8px 20px 0px rgba(19, 39, 48, .08);
font-size: 16px;
font-weight: 500;
color: #202020;
}
.system-operational {
flex-grow: 1;
margin-right: 16px;
}
.system-operational:last-child {
margin-right: 0;
}
.system-status-badge {
margin-top: 8px;
}
.system-status-badge img {
position: relative;
top: 2px;
margin-right: 4px;
height: 16px;
}
.incident {
color: #202020;
}
.incident-title {
float: left;
text-transform: capitalize;
}
.incident-date {
float: right;
font-size: 14px;
opacity: 0.3;
}
@media (max-width: 450px) {
.incident-date {
width: 100%;
}
}
.incident-description {
font-size: 14px;
font-weight: 400;
}
.incident-status {
margin: 24px 0 0 0;
}
.system-check-ok {
margin: 80px auto 104px auto;
width: 100%;
max-width: 300px;
text-align: center;
font-weight: 500;
color: #009A8D; /*Switch to appropriate color*/
}
.system-check-ok img {
margin: auto;
width: 140px;
}
.section-title {
margin-top: 40px;
margin-bottom: 16px;
padding-left: 16px;
padding-bottom: 16px;
font-size: 16px;
font-weight: 500;
border-bottom: 2px solid #F7F7F8;
color: #bbb;
}
.see-more {
display: block;
width: 100%;
text-align: center;
margin-top: 40px;
padding-top: 24px;
border-top: 2px solid #F7F7F8;
}
.history {
margin-top: 104px;
}
.color-ok {
color: #009A8D;
}
.color-warning {
color: #DFAA00;
}
.color-danger {
color: #BD1F1A;
}
.incident-summary {
margin-bottom: 24px;
overflow: hidden;
}
.article-title {
width: 70%;
float: left;
text-transform: capitalize;
}
.article-date {
width: 29%;
float: right;
text-align: right;
font-size: 14px;
opacity: 0.3;
}
.pagination,
.pagination li {
list-style: none;
display: inline;
-webkit-padding-start: 0px;
margin-right: 8px;
}
.pagination {
display: block;
margin-top: 40px;
padding-top: 24px;
border-top: 2px solid #F7F7F8;
}
.pagination .active a {
font-weight: 600;
color: #3A71B0;
opacity: 1;
}
.pagination li a {
color: #202020;
opacity: 0.5;
transition: all 0.3s ease;
}
.pagination li a:hover {
color: #3A71B0;
opacity: 1;
}
.footer {
margin-top: 104px;
padding-top: 24px;
border-top: 2px solid #F7F7F8;
}
.footer a {
display: inline-block;
width: 100%;
font-size: 14px;
color: #202020;
opacity: 0.3;
transition: all 0.3s ease;
text-align: left;
}
.footer a:hover {
color: #3A71B0;
opacity: 1;
}

13
src/js/app.js Normal file
View File

@ -0,0 +1,13 @@
// JS Goes here - ES6 supported
const daysSince = document.getElementById("days-since-latest");
console.log(daysSince);
if (daysSince) {
const aDay = 1000*60*60*24;
const dateSince = daysSince.getAttribute("data-latest-incident-date");
const timeSince = new Date() - new Date(dateSince);
const endDays = Math.floor(timeSince / aDay);
console.log(endDays);
daysSince.innerHTML = `${endDays} days since last incident`
}

37
webpack.conf.js Normal file
View File

@ -0,0 +1,37 @@
import webpack from "webpack";
import path from "path";
export default {
module: {
loaders: [
{
test: /\.((png)|(eot)|(woff)|(woff2)|(ttf)|(svg)|(gif))(\?v=\d+\.\d+\.\d+)?$/,
loader: "file?name=/[hash].[ext]"
},
{test: /\.json$/, loader: "json-loader"},
{
loader: "babel",
test: /\.js?$/,
exclude: /node_modules/,
query: {cacheDirectory: true}
}
]
},
plugins: [
new webpack.ProvidePlugin({
"fetch": "imports?this=>global!exports?global.fetch!whatwg-fetch"
})
],
context: path.join(__dirname, "src"),
entry: {
app: ["./js/app"]
},
output: {
path: path.join(__dirname, "dist"),
publicPath: "/",
filename: "[name].js"
},
externals: [/^vendor\/.+\.js$/]
};