Add basic website (#437)

* Add Netlify configuration and website Makefile

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add .editorconfig file for IDE configs

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add empty content folder to satisfy Hugo requirement

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add basic Hugo site config

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add initial layout scaffolding

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add initial npm assets, yarn.lock, and .gitignore file to ignore node_modules/

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add initial site implementation

* Revert Hugo version to 0.50

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Change publish directory to website/public

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add basic site metadata in partial

Signed-off-by: Luc Perkins <lucperkins@gmail.com>

* Widen main logo on mobile

Signed-off-by: Luc Perkins <lucperkins@gmail.com>

* Add favicon link to CSS partial

Signed-off-by: Luc Perkins <lucperkins@gmail.com>

* Synchronize main color with logos

Signed-off-by: Luc Perkins <lucperkins@gmail.com>

* Add basic Providers and How it Works sections to home page

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Combine basics and providers sections into one

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add favicon link to site config

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add navbar fade in and out effect

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add Slack button

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add GitHub stars/watcher info

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add documentation layout

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add debugging and contributing links

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add docs button in main hero

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Fix footer layout issue

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Change docs header aesthetic

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Change syntax highlighting theme to fruity

Signed-off-by: lucperkins <lucperkins@gmail.com>

* More adjustments to sidebar

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add TOC panel for docs

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Adjust the padding on section elements

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Remove stickiness on main docs header

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add basic architecture doc

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Remove 'coming soon' banner

Signed-off-by: lucperkins <lucperkins@gmail.com>

* Add AnchorJS support for docs pages

Signed-off-by: lucperkins <lucperkins@gmail.com>
This commit is contained in:
Luc Perkins
2018-12-21 13:49:05 -08:00
committed by Robbie Zhang
parent 966f7a807b
commit b44072588b
42 changed files with 1059 additions and 1 deletions

View File

@@ -37,7 +37,7 @@ The best description is "Kubernetes API on top, programmable back."
The diagram below illustrates how Virtual-Kubelet works.
![diagram](diagram.svg)
![diagram](website/static/img/diagram.svg)
## Usage

13
netlify.toml Normal file
View File

@@ -0,0 +1,13 @@
[build]
base = "website"
publish = "website/public"
command = "make production-build"
[build.environment]
HUGO_VERSION = "0.50"
[context.deploy-preview]
command = "make preview-build"
[context.branch-deploy]
command = "make preview-build"

12
website/.editorconfig Normal file
View File

@@ -0,0 +1,12 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
[Makefile]
indent_style = tab
[*.{html,js,json,md,sass,yaml}]
indent_style = space
indent_size = 2

5
website/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
# npm assets
node_modules/
# Hugo-generated assets
public/

15
website/Makefile Normal file
View File

@@ -0,0 +1,15 @@
serve:
hugo server \
--buildDrafts \
--buildFuture \
--disableFastRender
production-build:
hugo --minify
preview-build:
hugo \
--baseURL $(DEPLOY_PRIME_URL) \
--buildDrafts \
--buildFuture \
--minify

335
website/assets/js/anchor.js Normal file
View File

@@ -0,0 +1,335 @@
/* eslint-env amd, node */
// https://github.com/umdjs/umd/blob/master/templates/returnExports.js
(function (root, factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], factory);
} else if (typeof module === 'object' && module.exports) {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory();
} else {
// Browser globals (root is window)
root.AnchorJS = factory();
root.anchors = new root.AnchorJS();
}
}(this, function () {
'use strict';
function AnchorJS(options) {
this.options = options || {};
this.elements = [];
/**
* Assigns options to the internal options object, and provides defaults.
* @param {Object} opts - Options object
*/
function _applyRemainingDefaultOptions(opts) {
opts.icon = opts.hasOwnProperty('icon') ? opts.icon : '\ue9cb'; // Accepts characters (and also URLs?), like '#', '¶', '❡', or '§'.
opts.visible = opts.hasOwnProperty('visible') ? opts.visible : 'hover'; // Also accepts 'always' & 'touch'
opts.placement = opts.hasOwnProperty('placement') ? opts.placement : 'right'; // Also accepts 'left'
opts.ariaLabel = opts.hasOwnProperty('ariaLabel') ? opts.ariaLabel : 'Anchor'; // Accepts any text.
opts.class = opts.hasOwnProperty('class') ? opts.class : ''; // Accepts any class name.
// Using Math.floor here will ensure the value is Number-cast and an integer.
opts.truncate = opts.hasOwnProperty('truncate') ? Math.floor(opts.truncate) : 64; // Accepts any value that can be typecast to a number.
}
_applyRemainingDefaultOptions(this.options);
/**
* Checks to see if this device supports touch. Uses criteria pulled from Modernizr:
* https://github.com/Modernizr/Modernizr/blob/da22eb27631fc4957f67607fe6042e85c0a84656/feature-detects/touchevents.js#L40
* @return {Boolean} - true if the current device supports touch.
*/
this.isTouchDevice = function() {
return !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch);
};
/**
* Add anchor links to page elements.
* @param {String|Array|Nodelist} selector - A CSS selector for targeting the elements you wish to add anchor links
* to. Also accepts an array or nodeList containing the relavant elements.
* @return {this} - The AnchorJS object
*/
this.add = function(selector) {
var elements,
elsWithIds,
idList,
elementID,
i,
index,
count,
tidyText,
newTidyText,
readableID,
anchor,
visibleOptionToUse,
indexesToDrop = [];
// We reapply options here because somebody may have overwritten the default options object when setting options.
// For example, this overwrites all options but visible:
//
// anchors.options = { visible: 'always'; }
_applyRemainingDefaultOptions(this.options);
visibleOptionToUse = this.options.visible;
if (visibleOptionToUse === 'touch') {
visibleOptionToUse = this.isTouchDevice() ? 'always' : 'hover';
}
// Provide a sensible default selector, if none is given.
if (!selector) {
selector = 'h2, h3, h4, h5, h6';
}
elements = _getElements(selector);
if (elements.length === 0) {
return this;
}
_addBaselineStyles();
// We produce a list of existing IDs so we don't generate a duplicate.
elsWithIds = document.querySelectorAll('[id]');
idList = [].map.call(elsWithIds, function assign(el) {
return el.id;
});
for (i = 0; i < elements.length; i++) {
if (this.hasAnchorJSLink(elements[i])) {
indexesToDrop.push(i);
continue;
}
if (elements[i].hasAttribute('id')) {
elementID = elements[i].getAttribute('id');
} else if (elements[i].hasAttribute('data-anchor-id')) {
elementID = elements[i].getAttribute('data-anchor-id');
} else {
tidyText = this.urlify(elements[i].textContent);
// Compare our generated ID to existing IDs (and increment it if needed)
// before we add it to the page.
newTidyText = tidyText;
count = 0;
do {
if (index !== undefined) {
newTidyText = tidyText + '-' + count;
}
index = idList.indexOf(newTidyText);
count += 1;
} while (index !== -1);
index = undefined;
idList.push(newTidyText);
elements[i].setAttribute('id', newTidyText);
elementID = newTidyText;
}
readableID = elementID.replace(/-/g, ' ');
// The following code builds the following DOM structure in a more effiecient (albeit opaque) way.
// '<a class="anchorjs-link ' + this.options.class + '" href="#' + elementID + '" aria-label="Anchor" data-anchorjs-icon="' + this.options.icon + '"></a>';
anchor = document.createElement('a');
anchor.className = 'anchorjs-link ' + this.options.class;
anchor.href = '#' + elementID;
anchor.setAttribute('aria-label', this.options.ariaLabel);
anchor.setAttribute('data-anchorjs-icon', this.options.icon);
if (visibleOptionToUse === 'always') {
anchor.style.opacity = '1';
}
if (this.options.icon === '\ue9cb') {
anchor.style.font = '1em/1 anchorjs-icons';
// We set lineHeight = 1 here because the `anchorjs-icons` font family could otherwise affect the
// height of the heading. This isn't the case for icons with `placement: left`, so we restore
// line-height: inherit in that case, ensuring they remain positioned correctly. For more info,
// see https://github.com/bryanbraun/anchorjs/issues/39.
if (this.options.placement === 'left') {
anchor.style.lineHeight = 'inherit';
}
}
if (this.options.placement === 'left') {
anchor.style.position = 'absolute';
anchor.style.marginLeft = '-1em';
anchor.style.paddingRight = '0.5em';
elements[i].insertBefore(anchor, elements[i].firstChild);
} else { // if the option provided is `right` (or anything else).
anchor.style.paddingLeft = '0.375em';
elements[i].appendChild(anchor);
}
}
for (i = 0; i < indexesToDrop.length; i++) {
elements.splice(indexesToDrop[i] - i, 1);
}
this.elements = this.elements.concat(elements);
return this;
};
/**
* Removes all anchorjs-links from elements targed by the selector.
* @param {String|Array|Nodelist} selector - A CSS selector string targeting elements with anchor links,
* OR a nodeList / array containing the DOM elements.
* @return {this} - The AnchorJS object
*/
this.remove = function(selector) {
var index,
domAnchor,
elements = _getElements(selector);
for (var i = 0; i < elements.length; i++) {
domAnchor = elements[i].querySelector('.anchorjs-link');
if (domAnchor) {
// Drop the element from our main list, if it's in there.
index = this.elements.indexOf(elements[i]);
if (index !== -1) {
this.elements.splice(index, 1);
}
// Remove the anchor from the DOM.
elements[i].removeChild(domAnchor);
}
}
return this;
};
/**
* Removes all anchorjs links. Mostly used for tests.
*/
this.removeAll = function() {
this.remove(this.elements);
};
/**
* Urlify - Refine text so it makes a good ID.
*
* To do this, we remove apostrophes, replace nonsafe characters with hyphens,
* remove extra hyphens, truncate, trim hyphens, and make lowercase.
*
* @param {String} text - Any text. Usually pulled from the webpage element we are linking to.
* @return {String} - hyphen-delimited text for use in IDs and URLs.
*/
this.urlify = function(text) {
// Regex for finding the nonsafe URL characters (many need escaping): & +$,:;=?@"#{}|^~[`%!'<>]./()*\ (newlines, tabs, backspace, & vertical tabs)
var nonsafeChars = /[& +$,:;=?@"#{}|^~[`%!'<>\]\.\/\(\)\*\\\n\t\b\v]/g,
urlText;
// The reason we include this _applyRemainingDefaultOptions is so urlify can be called independently,
// even after setting options. This can be useful for tests or other applications.
if (!this.options.truncate) {
_applyRemainingDefaultOptions(this.options);
}
// Note: we trim hyphens after truncating because truncating can cause dangling hyphens.
// Example string: // " ⚡⚡ Don't forget: URL fragments should be i18n-friendly, hyphenated, short, and clean."
urlText = text.trim() // "⚡⚡ Don't forget: URL fragments should be i18n-friendly, hyphenated, short, and clean."
.replace(/\'/gi, '') // "⚡⚡ Dont forget: URL fragments should be i18n-friendly, hyphenated, short, and clean."
.replace(nonsafeChars, '-') // "⚡⚡-Dont-forget--URL-fragments-should-be-i18n-friendly--hyphenated--short--and-clean-"
.replace(/-{2,}/g, '-') // "⚡⚡-Dont-forget-URL-fragments-should-be-i18n-friendly-hyphenated-short-and-clean-"
.substring(0, this.options.truncate) // "⚡⚡-Dont-forget-URL-fragments-should-be-i18n-friendly-hyphenated-"
.replace(/^-+|-+$/gm, '') // "⚡⚡-Dont-forget-URL-fragments-should-be-i18n-friendly-hyphenated"
.toLowerCase(); // "⚡⚡-dont-forget-url-fragments-should-be-i18n-friendly-hyphenated"
return urlText;
};
/**
* Determines if this element already has an AnchorJS link on it.
* Uses this technique: http://stackoverflow.com/a/5898748/1154642
* @param {HTMLElemnt} el - a DOM node
* @return {Boolean} true/false
*/
this.hasAnchorJSLink = function(el) {
var hasLeftAnchor = el.firstChild && ((' ' + el.firstChild.className + ' ').indexOf(' anchorjs-link ') > -1),
hasRightAnchor = el.lastChild && ((' ' + el.lastChild.className + ' ').indexOf(' anchorjs-link ') > -1);
return hasLeftAnchor || hasRightAnchor || false;
};
/**
* Turns a selector, nodeList, or array of elements into an array of elements (so we can use array methods).
* It also throws errors on any other inputs. Used to handle inputs to .add and .remove.
* @param {String|Array|Nodelist} input - A CSS selector string targeting elements with anchor links,
* OR a nodeList / array containing the DOM elements.
* @return {Array} - An array containing the elements we want.
*/
function _getElements(input) {
var elements;
if (typeof input === 'string' || input instanceof String) {
// See https://davidwalsh.name/nodelist-array for the technique transforming nodeList -> Array.
elements = [].slice.call(document.querySelectorAll(input));
// I checked the 'input instanceof NodeList' test in IE9 and modern browsers and it worked for me.
} else if (Array.isArray(input) || input instanceof NodeList) {
elements = [].slice.call(input);
} else {
throw new Error('The selector provided to AnchorJS was invalid.');
}
return elements;
}
/**
* _addBaselineStyles
* Adds baseline styles to the page, used by all AnchorJS links irregardless of configuration.
*/
function _addBaselineStyles() {
// We don't want to add global baseline styles if they've been added before.
if (document.head.querySelector('style.anchorjs') !== null) {
return;
}
var style = document.createElement('style'),
linkRule =
' .anchorjs-link {' +
' opacity: 0;' +
' text-decoration: none;' +
' -webkit-font-smoothing: antialiased;' +
' -moz-osx-font-smoothing: grayscale;' +
' }',
hoverRule =
' *:hover > .anchorjs-link,' +
' .anchorjs-link:focus {' +
' opacity: 1;' +
' }',
anchorjsLinkFontFace =
' @font-face {' +
' font-family: "anchorjs-icons";' + // Icon from icomoon; 10px wide & 10px tall; 2 empty below & 4 above
' src: url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype");' +
' }',
pseudoElContent =
' [data-anchorjs-icon]::after {' +
' content: attr(data-anchorjs-icon);' +
' }',
firstStyleEl;
style.className = 'anchorjs';
style.appendChild(document.createTextNode('')); // Necessary for Webkit.
// We place it in the head with the other style tags, if possible, so as to
// not look out of place. We insert before the others so these styles can be
// overridden if necessary.
firstStyleEl = document.head.querySelector('[rel="stylesheet"], style');
if (firstStyleEl === undefined) {
document.head.appendChild(style);
} else {
document.head.insertBefore(style, firstStyleEl);
}
style.sheet.insertRule(linkRule, style.sheet.cssRules.length);
style.sheet.insertRule(hoverRule, style.sheet.cssRules.length);
style.sheet.insertRule(pseudoElContent, style.sheet.cssRules.length);
style.sheet.insertRule(anchorjsLinkFontFace, style.sheet.cssRules.length);
}
}
return AnchorJS;
}));

33
website/assets/js/app.js Normal file
View File

@@ -0,0 +1,33 @@
function anchorJs() {
if ($('.is-docs-page').length > 0) {
anchors.options = {
icon: '#'
}
anchors.add('.content h2, .content h3, .content h4');
}
}
function scrollFadeInOut(threshold, element) {
//element.hide();
$(window).scroll(function() {
if ($(this).scrollTop() > threshold) {
element.fadeIn();
} else {
element.fadeOut();
}
});
}
function navbarScrollToggle() {
const navbar = $('.is-home-page .navbar');
const heroHeight = $('.hero').height();
scrollFadeInOut(heroHeight, navbar);
}
$(function() {
anchorJs();
navbarScrollToggle();
});

View File

@@ -0,0 +1,136 @@
{{- $fonts := .Site.Params.fonts }}
{{- $fontSlice := (slice) }}
{{- range $fonts }}
{{- $fontSlice = $fontSlice | append (printf "%s:%s" (replace .name " " "+") (delimit .sizes ",")) }}
{{- end }}
{{- $fontsUrl := printf "https://fonts.googleapis.com/css?family=%s" (delimit $fontSlice "|") }}
{{- $sansSerifFont := .Site.Params.sansSerifFont }}
//{{- $monospaceFont := .Site.Params.monospaceFont }}
{{- $fontAwesomeVersion := .Site.Params.fontAwesomeVersion }}
{{- $fontAwesomeUrl := printf "https://use.fontawesome.com/releases/v%s/css/all.css" $fontAwesomeVersion }}
@charset "utf-8"
@import url({{ $fontsUrl }})
@import url({{ $fontAwesomeUrl }})
@import "bulma/sass/utilities/initial-variables"
@import "bulma/sass/utilities/functions"
// Project-specific colors and variables
$vk-blue: #3e71db
$vk-dark: #383d49
// Other colors
$twitter-blue: #1da1f2
$slack-green: #74cdb0
// Bulma variable overwrites
$primary: $vk-blue
$dark: $vk-dark
$link: $primary
$link-hover: $dark
$code: $primary
$family-sans-serif: "{{ $sansSerifFont }}", BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif
//$family-code: "{{ $monospaceFont }}", monospace
$section-padding: 3rem 4rem
$navbar-height: 5rem
$navbar-item-img-max-height: 3.5rem
$dashboard-panel-padding: 3rem 2.5rem 5rem 2.5rem
$dashboard-panel-header-bottom-margin: 2rem
$toc-item-color: $white
$toc-item-font-size: 1.75rem
$toc-item-icon-color: $white-bis
$toc-item-icon-right-margin: 1.5rem
$toc-item-top-margin: 1rem
@import "bulma/sass/utilities/derived-variables"
$colors: mergeColorMaps(("twitter-blue": ($twitter-blue, $white), "slack-green": ($slack-green, $white)), $colors)
@import "bulma/bulma"
@import "bulma-dashboard/bulma-dashboard.sass"
@import "bulma-toc/bulma-toc.sass"
// Ensure sticky footer at the bottom of the page
.page
display: flex
flex-direction: column
min-height: 100vh
.main
flex: 1
=hide
display: none
=logo($tablet, $mobile)
+tablet
width: $tablet
+mobile
width: $mobile
.menu-item
font-size: 1.75rem
.icon
color: $white
margin-right: 1.5rem
.is-main-logo
+logo(40%, 90%)
.is-cncf-logo
+logo(40%, 80%)
.is-footer-logo
+logo(10%, 20%)
.has-extra-padding
padding: 3rem
.has-bottom-spacing
margin-bottom: 1rem
.is-home-page .navbar
+hide
.button
&.is-radiusless
border-radius: none
.dashboard
&-panel-header
img
width: 50%
.footer
flex: 1
.toc-panel
padding: 1.75rem
border-left: 1px solid $grey-light
.toc-bar
margin-top: 1.5rem
li
line-height: 110%
font-size: 1rem
a
color: $dark
ul
li
& + li
margin-top: .8rem
.content
figure
img
figcaption
font-size: 1.75rem
font-style: normal

55
website/config.toml Normal file
View File

@@ -0,0 +1,55 @@
# Basic site config
title = "Virtual Kubelet"
baseURL = "https://virtual-kubelet.netlify.com"
languageCode = "en-us"
enableRobotsTxt = true
# Taxonomy configuration (disable taxonomies for now)
disableKinds = ["taxonomyTerm"]
# Syntax highlighting config
pygmentsCodeFences = true
pygmentsStyle = "fruity"
# BlackFriday Markdown settings
[blackfriday]
hrefTargetBlank = true
# General site-level parameters
[params]
favicon = "https://raw.githubusercontent.com/cncf/artwork/master/virtualkubelet/icon/color/virtualkubelet-icon-color.png"
sansSerifFont = "Noto Sans TC"
#monospaceFont = "Fira Mono"
fontAwesomeVersion = "5.5.0"
description = """
**Virtual Kubelet** is an open-source [Kubernetes kubelet](https://kubernetes.io/docs/reference/generated/kubelet/) implementation that *masquerades* as a kubelet.
This allows Kubernetes nodes to be backed by Virtual Kubelet **providers** such as serverless cloud container platforms.
"""
[params.logos]
hero = "https://raw.githubusercontent.com/cncf/artwork/master/virtualkubelet/horizontal/white/virtualkubelet-horizontal-white.png"
navbar = "https://raw.githubusercontent.com/cncf/artwork/master/virtualkubelet/horizontal/white/virtualkubelet-horizontal-white.png"
sidebar = "https://raw.githubusercontent.com/cncf/artwork/master/virtualkubelet/stacked/white/virtualkubelet-stacked-white.png"
[[params.fonts]]
name = "Noto Sans TC"
sizes = [300,400,600,700]
[[params.social]]
name = "GitHub"
color = "black"
url = "https://github.com/virtual-kubelet/virtual-kubelet"
icon = "github"
[[params.social]]
name = "Twitter"
color = "twitter-blue"
url = "https://twitter.com/virtualkubelet"
icon = "twitter"
[[params.social]]
name = "Slack"
color = "slack-green"
url = "https://kubernetes.slack.com"
icon = "slack"

View File

@@ -0,0 +1,15 @@
---
title: Overview
description: The basics of Virtual Kubelet
weight: 1
---
**Virtual Kubelet** is an implementation of the Kubernetes [kubelet](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/) that masquerades as a kubelet for the purpose of connecting a Kubernetes cluster to other APIs. This allows Kubernetes [Nodes](https://kubernetes.io/docs/concepts/architecture/nodes/) to be backed by other services, such as serverless container platforms.
## Providers
Virtual Kubelet supports a variety of providers:
{{< providers >}}
You can also [add your own provider](providers#adding).

View File

@@ -0,0 +1,19 @@
---
title: Architecture
description: How Virtual Kubelet works
weight: 3
---
This document provides a high-level overview of how Virtual Kubelet works. It begins by explaining how normal---i.e. non-virtual---[kubelets work](#kubelets) and then [explains Virtual Kubelet](#virtual-kubelet) by way of contrast.
## How kubelets usually work {#kubelets}
Ordinarily, Kubernetes [kubelets](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/) implement Pod and container operations for each Kubernetes Node. They run as an agent on each Node, whether that Node is a physical server or a virtual machine, and handles Pod/container operations on that Node. kubelets take a configuration called a **PodSpec** as input and work to ensure that containers specified in the PodSpec are running and healthy.
## How Virtual Kubelet works {#virtual-kubelet}
From the standpoint of the Kubernetes API server, Virtual Kubelets *seem* like normal kubelets, but with the crucial difference that they scheduler containers elsewhere, for example in a cloud serverless API, and not on the Node.
[Figure 1](#figure-1) below shows a Kubernetes cluster with a series of standard kubelets and one Virtual Kubelet:
{{< svg src="img/diagram.svg" caption="Standard vs. Virtual Kubelets" >}}

View File

@@ -0,0 +1,39 @@
---
title: Providers
description: Extend the Virtual Kubelet interface
weight: 2
---
The Virtual Kubelet provides a pluggable **provider interface** that developers can implement to define the actions of a typical kubelet.
This enables on-demand and nearly instantaneous container compute, orchestrated by Kubernetes, without needing to manage VM infrastructure.
Each provider may have its own configuration file and required environment variables.
### Provider interface
Virtual Kubelet providers must provide the following functionality to be considered a fully compliant integration:
1. Provide the back-end plumbing necessary to support the lifecycle management of Pods, containers, and supporting resources in the context of Kubernetes.
2. Conform to the current API provided by Virtual Kubelet.
3. Restrict all access to the [Kubernetes API Server](https://kubernetes.io/docs/concepts/overview/kubernetes-api/) and provide a well-defined callback mechanism for retrieving data like [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) or [ConfigMaps](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/).
### Current providers
Virtual Kubelet currently has a wide variety of providers:
{{< providers >}}
## Adding new providers {#adding}
To add a new Virtual Kubelet provider, create a new directory for your provider in the [`providers`](https://github.com/virtual-kubelet/virtual-kubelet/tree/master/providers) directory.
```shell
git clone https://github.com/virtual-kubelet/virtual-kubelet
cd virtual-kubelet
mkdir providers/my-provider
```
In that created directory, implement the [`Provider`](https://godoc.org/github.com/virtual-kubelet/virtual-kubelet/providers#Provider) interface in [Go](https://golang.org).
For a basic example, see the [Virtual Kubelet CRI Provider](https://github.com/virtual-kubelet/virtual-kubelet/tree/master/providers/cri).

View File

@@ -0,0 +1,18 @@
- name: Alibaba Cloud Elastic Container Instance (**ECI**)
tag: alicloud
- name: AWS Fargate
tag: aws
- name: Azure Batch
tag: azurebatch
- name: Azure Container Instances (**ACI**)
tag: azure
- name: Kubernetes Container Runtime Interface (**CRI**)
tag: cri
- name: Huawei Cloud Container Instance (**CCI**)
tag: huawei
- name: Hyper.sh
tag: hypersh
- name: Service Fabric Mesh
tag: sfmesh
- name: vSphere Integrated Containers (**VIC**)
tag: vic

View File

@@ -0,0 +1,26 @@
{{- .Scratch.Set "numFigures" 1 }}
{{- $pageType := cond .IsHome "home" .Section }}
<!DOCTYPE html>
<html lang="{{ .Site.LanguageCode }}">
<head>
{{ partial "meta.html" . }}
<title>
{{ block "title" . }}{{ .Site.Title }}{{ end }}
</title>
{{ partial "css.html" . }}
</head>
<body class="page is-{{ $pageType }}-page">
{{ block "main" . }}
{{ partial "navbar.html" . }}
<main class="main">
{{ block "main" . }}
{{ end }}
</main>
{{ partial "footer.html" . }}
{{ end }}
{{ partial "javascript.html" . }}
</body>
</html>

View File

@@ -0,0 +1,7 @@
{{ define "title" }}
Virtual Kubelet | {{ .Title }}
{{ end }}
{{ define "main" }}
{{ partial "docs/dashboard.html" . }}
{{ end }}

View File

@@ -0,0 +1,7 @@
{{ define "title" }}
Virtual Kubelet docs | {{ .Title }}
{{ end }}
{{ define "main" }}
{{ partial "docs/dashboard.html" . }}
{{ end }}

View File

@@ -0,0 +1,11 @@
{{ define "title" }}
{{ .Site.Title }} | Home
{{ end }}
{{ define "main" }}
{{ partial "navbar.html" . }}
{{ partial "home/hero.html" . }}
{{ partial "home/info.html" . }}
{{ partial "home/cncf.html" . }}
{{ partial "footer.html" . }}
{{ end }}

View File

@@ -0,0 +1,16 @@
{{- $favicon := .Site.Params.favicon }}
{{- $inServerMode := .Site.IsServer }}
{{- $includePaths := (slice "node_modules") }}
{{- $sass := "sass/style.sass" }}
{{- $cssOutput := "css/style.css" }}
{{- $devOpts := (dict "targetPath" $cssOutput "includePaths" $includePaths "enableSourceMap" true) }}
{{- $prodOpts := (dict "targetPath" $cssOutput "includePaths" $includePaths "outputStyle" "compressed") }}
{{- $cssOpts := cond $inServerMode $devOpts $prodOpts }}
{{- $css := resources.Get $sass | resources.ExecuteAsTemplate $sass . | toCSS $cssOpts }}
{{- if $inServerMode }}
<link rel="stylesheet" href="{{ $css.RelPermalink }}">
{{- else }}
{{- $prodCss := $css | fingerprint }}
<link rel="stylesheet" href="{{ $prodCss.RelPermalink }}" integrity="{{ $prodCss.Data.Integrity }}">
{{- end }}
<link rel="shortcut icon" href="{{ $favicon }}">

View File

@@ -0,0 +1,5 @@
<div class="dashboard">
{{ partial "docs/sidebar.html" . }}
{{ partial "docs/main.html" . }}
{{ partial "docs/toc.html" . }}
</div>

View File

@@ -0,0 +1,11 @@
{{- $description := .Params.description }}
<section class="dashboard-main-header section has-background-dark">
<p class="title is-size-1 has-text-white-bis has-text-weight-light{{ if $description }} is-spaced{{ end }}">
{{ .Title }}
</p>
{{- with $description }}
<p class="subtitle is-size-3 is-size-4-mobile has-text-white-bis has-text-weight-light">
{{ . }}
</p>
{{- end }}
</section>

View File

@@ -0,0 +1,11 @@
<div class="dashboard-main is-scrollable">
{{ partial "docs/header.html" . }}
<section class="section">
<div class="content is-medium">
{{ .Content }}
</div>
</section>
{{ partial "footer.html" . }}
</div>

View File

@@ -0,0 +1,23 @@
{{- $sidebarLogo := .Site.Params.logos.sidebar }}
{{- $docs := where .Site.Pages "Section" "docs" }}
<div class="dashboard-panel is-medium is-hidden-mobile has-background-primary">
<div class="dashboard-panel-header has-text-centered">
<a href="{{ .Site.BaseURL }}">
<img src="{{ $sidebarLogo }}">
</a>
</div>
<br />
<div class="dashboard-panel-main">
<div class="toc">
{{- range $docs }}
<div class="toc-item has-text-weight-light">
<a href="{{ .URL }}">
{{ .Title }}
</a>
</div>
{{- end }}
</div>
</div>
</div>

View File

@@ -0,0 +1,9 @@
<div class="dashboard-panel toc-panel is-medium is-hidden-mobile">
<p class="is-size-4">
{{ .Title }}
</p>
<div class="toc-bar">
{{ .TableOfContents }}
</div>
</div>

View File

@@ -0,0 +1,12 @@
{{- $year := now.Year}}
<footer class="footer has-background-black">
<div class="has-text-centered">
<img class="is-footer-logo" src="https://raw.githubusercontent.com/cncf/artwork/master/virtualkubelet/icon/white/virtualkubelet-icon-white.png">
<br /><br />
<p class="is-size-5 is-size-6-mobile has-text-grey-lighter has-text-weight-light">
&copy; {{ $year }} The Virtual Kubelet authors
</p>
</div>
</footer>

View File

@@ -0,0 +1,9 @@
<section class="section has-background-grey-lightest">
<div class="container has-text-centered">
<p class="title is-size-4 is-size-5-mobile has-text-weight-light">
Virtual Kubelet is a <a href="https://cncf.io">Cloud Native Computing Foundation</a> sandbox project
</p>
<img class="is-cncf-logo" src="https://raw.githubusercontent.com/cncf/artwork/master/cncf/horizontal/color/cncf-color.png" alt="Cloud Native Computing Foundation logo">
</div>
</section>

View File

@@ -0,0 +1,16 @@
{{- $heroLogo := .Site.Params.logos.hero }}
<div class="hero is-primary">
<div class="hero-body">
<div class="section has-text-centered">
<img class="is-main-logo" src="{{ $heroLogo }}" alt="Main Virtual Kubelet hero logo">
<br /><br /><br />
<div class="buttons is-centered">
<a class="button is-large is-black" href="/docs">
Documentation
</a>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,40 @@
{{- $description := .Site.Params.description | markdownify }}
{{- $social := .Site.Params.social }}
{{- $providers := .Site.Data.providers }}
<section class="section">
<div class="container">
<div class="columns">
<div class="column has-background-white has-extra-padding">
<p class="title is-size-2 is-size-3-mobile has-text-primary has-text-weight-light">
The basics
</p>
<span class="content is-size-4 is-size-5-mobile">
{{ $description }}
</span>
<br /><br />
{{ partial "home/social.html" . }}
</div>
<div class="column has-background-black has-extra-padding">
<p class="title is-size-2 is-size-3-mobile has-text-white has-text-weight-light">
Providers
</p>
<ul>
{{- range $providers }}
{{- $url := printf "https://github.com/virtual-kubelet/virtual-kubelet/tree/master/providers/%s" .tag }}
<li class="has-bottom-spacing">
<a class="is-size-5 is-size-6-mobile has-text-grey-lighter has-text-weight-light" href="{{ $url }}" target="_blank">
{{ .name | markdownify }}
</a>
<br />
</li>
{{- end }}
</ul>
</div>
</div>
</div>
</section>

View File

@@ -0,0 +1,38 @@
{{- $socialButtons := .Site.Params.social }}
{{- $repoInfo := getJSON "https://api.github.com/repos/virtual-kubelet/virtual-kubelet" }}
{{- $numStars := $repoInfo.stargazers_count }}
{{- $numWatchers := $repoInfo.subscribers_count }}
<div class="buttons">
{{- range $socialButtons }}
<a class="button is-medium is-{{ .color }}" href="{{ .url }}" target="_blank">
<span class="icon">
<i class="fab fa-{{ .icon }}"></i>
</span>
<span>
{{ .name }}
</span>
</a>
{{- end }}
</div>
<div class="buttons">
<div class="button is-dark is-radiusless">
<span class="icon">
<i class="fab fa-github"></i>
</span>
<span>
Stars &nbsp;<strong>{{ $numStars }}</strong>
</span>
</div>
<div class="button is-dark is-radiusless">
<span class="icon">
<i class="fab fa-github"></i>
</span>
<span>
Watchers &nbsp;<strong>{{ $numWatchers }}</strong>
</span>
</div>
</div>

View File

@@ -0,0 +1,7 @@
{{- $jsFiles := (slice "anchor" "app") }}
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
{{- range $jsFiles }}
{{- $path := printf "js/%s.js" . }}
{{- $file := resources.Get $path | minify | fingerprint }}
<script src="{{ $file.RelPermalink }}" integrity="{{ $file.Data.Integrity }}"></script>
{{- end }}

View File

@@ -0,0 +1,2 @@
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">

View File

@@ -0,0 +1,18 @@
{{- $navbarLogo := .Site.Params.logos.navbar }}
<nav class="navbar is-fixed-top is-primary">
<div class="container">
<div class="navbar-brand">
<a class="navbar-item">
<img src="{{ $navbarLogo }}" alt="Virtual Kubelet navbar logo">
</a>
</div>
<div class="navbar-menu">
<div class="navbar-end">
<a class="navbar-item is-size-4" href="/docs">
Docs
</a>
</div>
</div>
</div>
</nav>

View File

@@ -0,0 +1,11 @@
{{- $providers := .Site.Data.providers }}
<ul>
{{- range $providers }}
{{- $url := printf "https://github.com/virtual-kubelet/virtual-kubelet/tree/master/providers/%s" .tag }}
<li>
<a href="{{ $url }}">
{{ .name | markdownify }}
</a>
</li>
{{- end }}
</ul>

View File

@@ -0,0 +1,10 @@
{{- $src := .Get "src" }}
{{- $path := printf "static/%s" $src | relURL }}
{{- $figureId := $.Page.Scratch.Get "numFigures" }}
<figure id="figure-{{ $figureId }}">
{{ $path | readFile | safeHTML }}
<figcaption>
<strong>Figure {{ $figureId }}</strong>{{ with .Get "caption" }}. {{ . | markdownify }}{{ end }}
</figcaption>
</figure>

24
website/package-lock.json generated Normal file
View File

@@ -0,0 +1,24 @@
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"bulma": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/bulma/-/bulma-0.7.2.tgz",
"integrity": "sha512-6JHEu8U/1xsyOst/El5ImLcZIiE2JFXgvrz8GGWbnDLwTNRPJzdAM0aoUM1Ns0avALcVb6KZz9NhzmU53dGDcQ==",
"dev": true
},
"bulma-dashboard": {
"version": "0.1.34",
"resolved": "https://registry.npmjs.org/bulma-dashboard/-/bulma-dashboard-0.1.34.tgz",
"integrity": "sha512-Js2qDAEF1uBN7p1iEaIy3JW0xWGERAOI5ksTPF4SYlPpmTA0lBjXfKdOiQ/yKwCUVX5eorgMhF2fMkufAHFFKg==",
"dev": true
},
"bulma-toc": {
"version": "0.1.11",
"resolved": "https://registry.npmjs.org/bulma-toc/-/bulma-toc-0.1.11.tgz",
"integrity": "sha512-k59pia2hf1NoB/DWEMYj3umVgqSJskpZP7JfShhicwGUqK81XLEJY0Q8mU1d+gry8YD/UwQSa3i+DIrT6Hfffw==",
"dev": true
}
}
}

8
website/package.json Normal file
View File

@@ -0,0 +1,8 @@
{
"private": true,
"devDependencies": {
"bulma": "^0.7.2",
"bulma-dashboard": "^0.1.34",
"bulma-toc": "^0.1.11"
}
}

View File

@@ -0,0 +1,33 @@
(function(root,factory){'use strict';if(typeof define==='function'&&define.amd){define([],factory);}else if(typeof module==='object'&&module.exports){module.exports=factory();}else{root.AnchorJS=factory();root.anchors=new root.AnchorJS();}}(this,function(){'use strict';function AnchorJS(options){this.options=options||{};this.elements=[];function _applyRemainingDefaultOptions(opts){opts.icon=opts.hasOwnProperty('icon')?opts.icon:'\ue9cb';opts.visible=opts.hasOwnProperty('visible')?opts.visible:'hover';opts.placement=opts.hasOwnProperty('placement')?opts.placement:'right';opts.ariaLabel=opts.hasOwnProperty('ariaLabel')?opts.ariaLabel:'Anchor';opts.class=opts.hasOwnProperty('class')?opts.class:'';opts.truncate=opts.hasOwnProperty('truncate')?Math.floor(opts.truncate):64;}
_applyRemainingDefaultOptions(this.options);this.isTouchDevice=function(){return!!(('ontouchstart'in window)||window.DocumentTouch&&document instanceof DocumentTouch);};this.add=function(selector){var elements,elsWithIds,idList,elementID,i,index,count,tidyText,newTidyText,readableID,anchor,visibleOptionToUse,indexesToDrop=[];_applyRemainingDefaultOptions(this.options);visibleOptionToUse=this.options.visible;if(visibleOptionToUse==='touch'){visibleOptionToUse=this.isTouchDevice()?'always':'hover';}
if(!selector){selector='h2, h3, h4, h5, h6';}
elements=_getElements(selector);if(elements.length===0){return this;}
_addBaselineStyles();elsWithIds=document.querySelectorAll('[id]');idList=[].map.call(elsWithIds,function assign(el){return el.id;});for(i=0;i<elements.length;i++){if(this.hasAnchorJSLink(elements[i])){indexesToDrop.push(i);continue;}
if(elements[i].hasAttribute('id')){elementID=elements[i].getAttribute('id');}else if(elements[i].hasAttribute('data-anchor-id')){elementID=elements[i].getAttribute('data-anchor-id');}else{tidyText=this.urlify(elements[i].textContent);newTidyText=tidyText;count=0;do{if(index!==undefined){newTidyText=tidyText+'-'+count;}
index=idList.indexOf(newTidyText);count+=1;}while(index!==-1);index=undefined;idList.push(newTidyText);elements[i].setAttribute('id',newTidyText);elementID=newTidyText;}
readableID=elementID.replace(/-/g,' ');anchor=document.createElement('a');anchor.className='anchorjs-link '+this.options.class;anchor.href='#'+elementID;anchor.setAttribute('aria-label',this.options.ariaLabel);anchor.setAttribute('data-anchorjs-icon',this.options.icon);if(visibleOptionToUse==='always'){anchor.style.opacity='1';}
if(this.options.icon==='\ue9cb'){anchor.style.font='1em/1 anchorjs-icons';if(this.options.placement==='left'){anchor.style.lineHeight='inherit';}}
if(this.options.placement==='left'){anchor.style.position='absolute';anchor.style.marginLeft='-1em';anchor.style.paddingRight='0.5em';elements[i].insertBefore(anchor,elements[i].firstChild);}else{anchor.style.paddingLeft='0.375em';elements[i].appendChild(anchor);}}
for(i=0;i<indexesToDrop.length;i++){elements.splice(indexesToDrop[i]-i,1);}
this.elements=this.elements.concat(elements);return this;};this.remove=function(selector){var index,domAnchor,elements=_getElements(selector);for(var i=0;i<elements.length;i++){domAnchor=elements[i].querySelector('.anchorjs-link');if(domAnchor){index=this.elements.indexOf(elements[i]);if(index!==-1){this.elements.splice(index,1);}
elements[i].removeChild(domAnchor);}}
return this;};this.removeAll=function(){this.remove(this.elements);};this.urlify=function(text){var nonsafeChars=/[& +$,:;=?@"#{}|^~[`%!'<>\]\.\/\(\)\*\\\n\t\b\v]/g,urlText;if(!this.options.truncate){_applyRemainingDefaultOptions(this.options);}
urlText=text.trim().replace(/\'/gi,'').replace(nonsafeChars,'-').replace(/-{2,}/g,'-').substring(0,this.options.truncate).replace(/^-+|-+$/gm,'').toLowerCase();return urlText;};this.hasAnchorJSLink=function(el){var hasLeftAnchor=el.firstChild&&((' '+el.firstChild.className+' ').indexOf(' anchorjs-link ')>-1),hasRightAnchor=el.lastChild&&((' '+el.lastChild.className+' ').indexOf(' anchorjs-link ')>-1);return hasLeftAnchor||hasRightAnchor||false;};function _getElements(input){var elements;if(typeof input==='string'||input instanceof String){elements=[].slice.call(document.querySelectorAll(input));}else if(Array.isArray(input)||input instanceof NodeList){elements=[].slice.call(input);}else{throw new Error('The selector provided to AnchorJS was invalid.');}
return elements;}
function _addBaselineStyles(){if(document.head.querySelector('style.anchorjs')!==null){return;}
var style=document.createElement('style'),linkRule=' .anchorjs-link {'+
' opacity: 0;'+
' text-decoration: none;'+
' -webkit-font-smoothing: antialiased;'+
' -moz-osx-font-smoothing: grayscale;'+
' }',hoverRule=' *:hover > .anchorjs-link,'+
' .anchorjs-link:focus {'+
' opacity: 1;'+
' }',anchorjsLinkFontFace=' @font-face {'+
' font-family: "anchorjs-icons";'+
' src: url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype");'+
' }',pseudoElContent=' [data-anchorjs-icon]::after {'+
' content: attr(data-anchorjs-icon);'+
' }',firstStyleEl;style.className='anchorjs';style.appendChild(document.createTextNode(''));firstStyleEl=document.head.querySelector('[rel="stylesheet"], style');if(firstStyleEl===undefined){document.head.appendChild(style);}else{document.head.insertBefore(style,firstStyleEl);}
style.sheet.insertRule(linkRule,style.sheet.cssRules.length);style.sheet.insertRule(hoverRule,style.sheet.cssRules.length);style.sheet.insertRule(pseudoElContent,style.sheet.cssRules.length);style.sheet.insertRule(anchorjsLinkFontFace,style.sheet.cssRules.length);}}
return AnchorJS;}));

View File

@@ -0,0 +1 @@
{"Target":"js/anchor.min.3231b81e93880d1db128c90bbea3b3540c38b614ddba93b568ca2d9092a385db.js","MediaType":"application/javascript","Data":{"Integrity":"sha256-MjG4HpOIDR2xKMkLvqOzVAw4thTdupO1aMotkJKjhds="}}

View File

@@ -0,0 +1,5 @@
function anchorJs(){if($('.is-docs-page').length>0){anchors.options={icon:'#'}
anchors.add('.content h2, .content h3, .content h4');}}
function scrollFadeInOut(threshold,element){$(window).scroll(function(){if($(this).scrollTop()>threshold){element.fadeIn();}else{element.fadeOut();}});}
function navbarScrollToggle(){const navbar=$('.is-home-page .navbar');const heroHeight=$('.hero').height();scrollFadeInOut(heroHeight,navbar);}
$(function(){anchorJs();navbarScrollToggle();});

View File

@@ -0,0 +1 @@
{"Target":"js/app.min.f21b34fa42a57f2e8dd0f59faffe4a19d8eb880de4359555cb257d027a2c1481.js","MediaType":"application/javascript","Data":{"Integrity":"sha256-8hs0+kKlfy6N0PWfr/5KGdjriA3kNZVVyyV9AnosFIE="}}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"Target":"css/style.7557002ca2e3a2c3558d1dd6957c18a5a518c37b0da952b617441ae9ed7ffc04.css","MediaType":"text/css","Data":{"Integrity":"sha256-dVcALKLjosNVjR3WlXwYpaUYw3sNqVK2F0Qa6e1//AQ="}}

View File

Before

Width:  |  Height:  |  Size: 236 KiB

After

Width:  |  Height:  |  Size: 236 KiB