feat(docs): setup Gridsome for the website

This commit is contained in:
Luca Spezzano
2021-11-02 18:35:41 +01:00
committed by Dario Tranchitella
parent 14f9686bbb
commit 0acc2d2ef1
111 changed files with 25054 additions and 149 deletions

BIN
docs/src/assets/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1 @@
<svg fill="none" stroke="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 10"><path d="M15 1.2l-7 7-7-7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>

After

Width:  |  Height:  |  Size: 192 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-github"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>

After

Width:  |  Height:  |  Size: 504 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-linkedin"><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path><rect x="2" y="9" width="4" height="12"></rect><circle cx="4" cy="4" r="2"></circle></svg>

After

Width:  |  Height:  |  Size: 377 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>

After

Width:  |  Height:  |  Size: 308 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-slack"><path d="M14.5 10c-.83 0-1.5-.67-1.5-1.5v-5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5v5c0 .83-.67 1.5-1.5 1.5z"></path><path d="M20.5 10H19V8.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"></path><path d="M9.5 14c.83 0 1.5.67 1.5 1.5v5c0 .83-.67 1.5-1.5 1.5S8 21.33 8 20.5v-5c0-.83.67-1.5 1.5-1.5z"></path><path d="M3.5 14H5v1.5c0 .83-.67 1.5-1.5 1.5S2 16.33 2 15.5 2.67 14 3.5 14z"></path><path d="M14 14.5c0-.83.67-1.5 1.5-1.5h5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-5c-.83 0-1.5-.67-1.5-1.5z"></path><path d="M15.5 19H14v1.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5-.67-1.5-1.5-1.5z"></path><path d="M10 9.5C10 8.67 9.33 8 8.5 8h-5C2.67 8 2 8.67 2 9.5S2.67 11 3.5 11h5c.83 0 1.5-.67 1.5-1.5z"></path><path d="M8.5 5H10V3.5C10 2.67 9.33 2 8.5 2S7 2.67 7 3.5 7.67 5 8.5 5z"></path></svg>

After

Width:  |  Height:  |  Size: 976 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-twitter"><path d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z"></path></svg>

After

Width:  |  Height:  |  Size: 385 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.3 KiB

1
docs/src/assets/logo.svg Normal file
View File

@@ -0,0 +1 @@
<svg viewBox="0 0 305 269" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M112 56.2c0-4.5-.4-9 0-13.5 0-1.2 2.1-3.1 3.4-3.3 7-.8 14-1.4 21-1.8 2.5 0 3.6-1 4.4-3 2-5.2 4-10.3 6.3-15.4.9-1.9.6-2.8-1.2-4-4.4-3.2-5-8.5-1.6-12.1 3.7-4 8.9-4.1 12.6-.2 3.5 3.7 3.1 9-1.3 12.1-2 1.4-2.1 2.5-1.3 4.5 2.2 5 4 10.3 6.4 15.2a6.2 6.2 0 0 0 4.2 3c7.6.7 15.2 1 22.8 1.6 2.7.1 4.2 1.2 4.2 4.1.1 4 .5 7.9.7 11.9-1.5 0-3 .2-4.5 0-12.6-.7-37.5-2.6-37.5-2.6L112 56.2Z" fill="#274872"/><path d="M13.4 193.8c2.9-4.2 5.7-8.3 8.7-12.4.8-1.1 2.1-2 3.2-2.9 8.7 2.8 17.2 6 26 8.2 7.3 1.8 7.6 1.3 11.1-5.6 9.6-18.2 19-36.5 28.5-54.9 3.5-6.9 7-13.8 10.3-20.8 1.9-4 1-5.3-3.3-5.1-5 .2-10 .6-15.2 1 1.8-2.4 3.3-4.9 5.2-7 4.5-4.9 9.2-9.6 13.8-14.4h5.5l43.9-3.2-.3 2.5v145.2c-15.7.9-30.4 1-47.4-.6-16-1-30.7-3.5-46.6-5.5A119 119 0 0 1 17.6 207c-4.8-2.4-5.9-5.4-4.3-10.4.3-.9.1-1.8.1-2.7Z" fill="#5783AB"/><path d="M150.9 224.4V76.7c5.6.1 11.4 0 17 .3 11.4.8 22.7 1.9 34 2.8 2.7 3 5.5 6.1 8 9.3 3.5 4.2 6.7 8.5 10 12.7-6-.5-12-1.2-18.1-1.5-4.2-.2-5 1.2-3.1 4.8l29.6 57.8c4 7.8 8.2 15.5 12.3 23.3 1.4 2.8 3.6 3.9 6.6 3.2l34.5-8.6c1.8 3 3.5 6.2 5.4 9.1 1 1.4 2.2 2.6 3.2 3.9 0 .5-.1 1.2 0 1.6 3.4 6.3 0 10-5.7 12.6a140.8 140.8 0 0 1-44.6 11.4l-38.6 3.7c-6.3.6-12.5 1.5-18.8 1.8-4.5.3-9.2-.1-13.8-.3H151l-.1-.2Z" fill="#EAECEC"/><path d="m281.7 180.8-34.5 8.6c-3 .7-5.2-.4-6.6-3.2-4-7.8-8.3-15.5-12.3-23.3L198.7 105c-1.9-3.6-1-5 3-4.8 6.1.3 12.1 1 18.2 1.5 1.9.4 2.5.1 5 3.7 17.1 24.4 37 47.8 54.9 71.7.8 1 1.3 2.4 2 3.6Z" fill="#5783AB"/><path d="m23.5 180 33.8 8.2c3 .7 5.1-.3 6.6-3.2L76 161.7c10-19.2 17.3-37.2 26.4-56.7 1.8-3.5.7-5-3.4-4.7-6 .3-10.1.4-16.2 1a10 10 0 0 0-3.8 3.4c-18 23.7-35.8 47.6-53.7 71.5-.8 1.1-1.3 2.5-1.9 3.7Z" fill="#EAECEC"/><path d="M290.4 193.8c0 .5-.2 1.2 0 1.6 3.3 6.3-.2 10-5.8 12.6a140.8 140.8 0 0 1-44.5 11.4l-38.7 3.7c-6.3.7-13 1.3-19 1.3-4.6 0-9 .4-13.6.2H151l-.1-.2c-15.4.4-28.8.4-46.2-1.2-16-1.4-32-3-47.9-5A119 119 0 0 1 17.6 207c-4.8-2.4-5.9-5.4-4.3-10.5.3-.8.1-1.7.1-2.6C7 196.3 2.1 200.2.6 207.5a25 25 0 0 0 5.7 21.7c1.5 1.8 2.4 3.2.1 5.2-.7.6-.8 3.3-.2 4a51 51 0 0 0 22.4 12.3c2.4.6 4.1 0 4.6-2.9.1-.6 1.7-1.6 2.3-1.5l26 6.2c1.9.4 2.6 1 1.4 3-1.4 2.4-.4 3.9 2 5 8.7 3.5 17.9 3.9 27 4.3 2.2 0 4.5-1 3.5-4-1-3.1.5-3.1 2.8-3 8.6.8 17.2 1.5 25.8 2 3.1.2 4 1 2.4 4s-.3 4.8 2.9 4.8c14.8 0 29.6.2 44.4-.1 4.6 0 5.1-1.3 3.4-5.6-.8-2.1-1-2.9 1.8-3a646 646 0 0 0 27.4-2.2c2.5-.2 3 .4 2.6 2.6-.6 2.3 0 4 2.7 4.1 9.5.2 18.9-.5 27.8-4.3 2-.9 3-2.1 1.7-4.3-1.7-2.7 0-3.1 2.2-3.6a901 901 0 0 0 24.6-6c1.8-.4 3-.7 3.2 1.6.3 3 2.1 3.4 4.6 2.6 8-2.3 15.5-6 21.6-12 .6-.6 1-3 .5-3.3-3.2-2.7-1.4-4.7.5-7 8-9.6 9.5-27.9-8-34.3Z" fill="#274872"/><path d="M192.8 70.5a4896.2 4896.2 0 0 1-39.1-1h-2.5l-.6.1V52.1c12.6 1 24.6 2 37.2 2.7h4.8l.2 15.7Z" fill="#EAECEC"/><path d="M111.8 71c6.7-.3 10-.4 16.8-.5l19-.5h2.4s.6-.6.6-.4V52.1c-12.6 1-21.3 2-33.8 2.7H112l-.2 16.2Z" fill="#5783AB"/><path d="m196 70.7-4-.3-40-1h-.1l-40 1-4 .3c-6.2.5-6.8 1.1-6.7 7.2 0 .7.2 1.3.3 2h5.7c15-1 28.7-2.1 43.6-3.2l46 3.1c1.8.2 3.7.1 5.6.1.1-.7.3-1.3.3-2 .2-6-.4-6.7-6.7-7.2Z" fill="#274872"/></svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -0,0 +1,49 @@
<template>
<div>
<button @click="toggleIsOpened()" class="flex items-center space-x-3 text-left">
<slot name="title" />
<icon-arrow
class="w-2 transition-all duration-200 transform"
:class="{
'rotate-180': isOpened,
'rotate-0': !isOpened,
}"
/>
</button>
<div
class="transition-all duration-400 overflow-hidden"
:class="{
'max-h-99': isOpened,
'max-h-0': !isOpened,
}"
>
<slot name="content" />
</div>
</div>
</template>
<script>
import IconArrow from "~/assets/icon/arrow.svg?inline";
export default {
components: {
IconArrow,
},
data() {
return {
isOpened: false,
};
},
methods: {
toggleIsOpened() {
this.isOpened = !this.isOpened;
},
},
};
</script>
<style scoped>
.max-h-99 {
max-height: 99rem;
}
</style>

View File

@@ -0,0 +1,32 @@
<template>
<component
:is="link ? 'g-link' : 'button'"
:to="link"
class="
inline-block
focus:outline-none
font-medium
rounded-md
relative
bg-primary
py-3 px-8
"
>
<slot />
</component>
</template>
<script>
export default {
props: {
link: {
type: String,
required: false,
default: () => undefined,
},
},
};
</script>
<style>
</style>

View File

@@ -0,0 +1,71 @@
<template>
<footer class="py-8 bg-gray-900 bg-opacity-50">
<div
class="
container
lg:flex lg:items-center lg:justify-between
space-y-4
lg:space-y-0
"
>
<div class="space-y-2">
<h1 class="font-bold text-2xl inline-block">Capsule</h1>
<small class="block">
©{{ new Date().getFullYear() }} All rights reserved
</small>
</div>
<ul class="lg:flex lg:items-center lg:space-x-5 space-y-2 lg:space-y-0">
<li class="block lg:hidden">
<g-link to="/">About Capsule</g-link>
</li>
<li class="block lg:hidden pb-4">
<g-link to="/docs">Documentation</g-link>
</li>
<li>
<a
href="https://github.com/clastix/capsule"
target="_blank"
rel="noopener noreferrer"
class="flex space-x-2 hover:text-blue-400"
><icon-github class="w-5 h-5" /> <span> Github </span></a
>
</li>
<li>
<a
href="https://twitter.com/clastixio"
target="_blank"
rel="noopener noreferrer"
class="flex space-x-2 hover:text-blue-400"
><icon-twitter class="w-5 h-5" /> <span>Twitter</span></a
>
</li>
<li>
<a
href="https://www.linkedin.com/company/clastix/"
target="_blank"
rel="noopener noreferrer"
class="flex space-x-2 hover:text-blue-400"
><icon-linkedin class="w-5 h-5" /> <span>Linkedin</span></a
>
</li>
</ul>
</div>
</footer>
</template>
<script>
import IconGithub from "~/assets/icon/github.svg?inline";
import IconTwitter from "~/assets/icon/twitter.svg?inline";
import IconLinkedin from "~/assets/icon/linkedin.svg?inline";
export default {
components: {
IconGithub,
IconLinkedin,
IconTwitter,
},
};
</script>
<style>
</style>

View File

@@ -0,0 +1,404 @@
<template>
<header class="py-3 lg:py-6 relative bg-gray-900 bg-opacity-50">
<div class="container flex items-center lg:justify-between">
<div class="w-full flex items-center space-x-4 lg:space-x-0">
<div class="w-2/12 lg:hidden" v-if="type === 'doc'">
<button
class="
lg:hidden
relative
z-30
shadow-lg
w-8
h-8
space-y-1
inline-flex
flex-col
justify-center
items-center
outline-none
focus:outline-none
transition-all
duration-200
transform
"
@click="toggleMenu()"
>
<span
class="
inline-block
w-6
h-0.5
rounded-sm
transition-all
duration-200
bg-gray-100
"
:class="{
'transform rotate-45 translate-y-1.5': menuOpened,
}"
></span>
<span
class="inline-block w-6 h-0.5 rounded-sm bg-gray-100"
:class="{
invisible: menuOpened,
}"
></span>
<span
class="
inline-block
w-6
h-0.5
rounded-sm
transition-all
duration-200
bg-gray-100
"
:class="{
'transform -rotate-45 -translate-y-1.5': menuOpened,
}"
></span>
</button>
</div>
<div
class="w-8/12 lg:w-auto text-center flex items-center space-x-16"
:class="{
'justify-center lg:justify-start': type === 'doc',
}"
>
<g-link to="/" class="flex items-center space-x-4">
<logo-capsule class="w-10 lg:w-12" />
<h1 class="font-bold text-2xl lg:text-3xl inline-block">Capsule</h1>
</g-link>
<nav class="hidden lg:inline-block">
<ul class="flex items-center font-medium space-x-5">
<li class="hidden lg:block">
<g-link to="/">About Capsule</g-link>
</li>
<li>
<g-link to="/docs">Documentation</g-link>
</li>
<!-- <li class="group relative">
main
<ul
class="
py-2
px-4
absolute
top-full
hidden
group-hover:block
bg-gray-100
text-gray-800
rounded
text-left
"
>
<li>
<a href="/" target="_blank" rel="noopener noreferrer">
v1.5.0
</a>
</li>
<li>
<a href="/" target="_blank" rel="noopener noreferrer">
v1.6.0
</a>
</li>
<li>
<a href="/" target="_blank" rel="noopener noreferrer">
main
</a>
</li>
</ul>
</li> -->
</ul>
</nav>
</div>
<div class="w-2/12 lg:hidden" v-if="type === 'doc'">
<button @click="toggleSearch()" class="block ml-auto">
<icon-search class="w-8" />
</button>
</div>
</div>
<div
class="relative"
:class="{
'hidden lg:flex items-center space-x-16': type === 'doc',
}"
>
<div v-if="type === 'doc'">
<div class="relative">
<icon-search
class="w-8 absolute left-0 bottom-2 text-gray-100 opacity-80"
/>
<input
type="search"
name="search"
id="search"
class="
rounded-0
pl-10
pr-2
py-2
outline-none
w-96
bg-transparent
border-b border-solid border-gray-100
text-gray-100
"
placeholder="Search"
@focus="focused = true"
@blur="focusOut()"
@input="query = $event.target.value"
@change="query = $event.target.value"
/>
</div>
<ul
v-show="showResult"
class="
absolute
left-0
top-12
z-20
text-left
bg-gray-900
rounded-br rounded-bl
text-sm
min-w-96
"
>
<li v-if="results.length === 0" class="px-4 py-2">
No results for <span class="font-bold">{{ query }}</span
>.
</li>
<li v-else v-for="result in results" :key="result.id">
<g-link
:to="result.item.path + result.item.anchor"
class="block px-4 py-2 hover:bg-gray-700 hover:text-blue-400"
>
<span v-if="result.item.value === result.item.title">
{{ result.item.value }}
</span>
<span v-else class="flex items-center">
{{ result.item.title }}
<icon-arrow class="w-2 mx-2 transform -rotate-90" />
<span class="font-normal opacity-75">
{{ result.item.value }}
</span>
</span>
</g-link>
</li>
</ul>
</div>
<ul
class="items-center"
:class="{
'hidden lg:flex': type === 'doc',
flex: type === 'default',
}"
>
<li>
<a
href="https://github.com/clastix/capsule"
target="_blank"
rel="noopener noreferrer"
>
Github
</a>
</li>
</ul>
</div>
</div>
<div
class="
container
py-4
absolute
bg-gray-900
inset-x-0
top-0
z-30
shadow-xl
rounded-br rounded-bl
"
v-if="searchOpened && type === 'doc'"
>
<div class="flex items-center space-x-4">
<input
type="search"
name="search"
id="search"
class="w-full rounded p-2 outline-none text-gray-800"
placeholder="Search"
@focus="focused = true"
@blur="focusOutMobile()"
@input="query = $event.target.value"
@change="query = $event.target.value"
/>
<button @click="toggleSearch()">Cancel</button>
</div>
<ul class="p-4 space-y-2" v-show="showResult">
<li v-if="results.length === 0">
No results for <span class="font-bold">{{ query }}</span
>.
</li>
<li v-else v-for="result in results" :key="result.id">
<g-link
:to="result.item.path + result.item.anchor"
class="hover:text-blue-400"
>
<span v-if="result.item.value === result.item.title">
{{ result.item.value }}
</span>
<span v-else class="flex items-center">
{{ result.item.title }}
<span class="block">
<icon-arrow class="w-2 mx-2 transform -rotate-90" />
</span>
<span class="font-normal opacity-75">
{{ result.item.value }}
</span>
</span>
</g-link>
</li>
</ul>
</div>
</header>
</template>
<static-query>
query Search {
allMarkdownPage{
edges {
node {
id
path
title
headings {
depth
value
anchor
}
}
}
}
}
</static-query>
<script>
import Fuse from "fuse.js";
import IconSearch from "~/assets/icon/search.svg?inline";
import IconGithub from "~/assets/icon/github.svg?inline";
import IconTwitter from "~/assets/icon/twitter.svg?inline";
import IconSlack from "~/assets/icon/slack.svg?inline";
import IconArrow from "~/assets/icon/arrow.svg?inline";
import LogoCapsule from "~/assets/logo.svg?inline";
export default {
props: {
type: {
type: String,
required: false,
default: () => "default",
validator: (value) => ["default", "doc"].includes(value),
},
},
components: {
IconSearch,
IconGithub,
IconTwitter,
IconSlack,
IconArrow,
LogoCapsule,
},
data() {
return {
menuOpened: false,
searchOpened: false,
query: "",
focusIndex: -1,
focused: false,
};
},
watch: {
$route: function () {
if (this.menuOpened) {
this.menuOpened = false;
this.$emit("onToggleMenu", this.menuOpened);
document.querySelector("body").classList.remove("overflow-hidden");
}
},
},
computed: {
results() {
const fuse = new Fuse(this.headings, {
keys: ["value"],
threshold: 0.25,
});
return fuse.search(this.query).slice(0, 15);
},
headings() {
let result = [];
const allPages = this.$static.allMarkdownPage.edges.map(
(edge) => edge.node
);
// Create the array of all headings of all pages.
allPages.forEach((page) => {
page.headings.forEach((heading) => {
result.push({
...heading,
path: page.path,
title: page.title,
});
});
});
return result;
},
showResult() {
// Show results, if the input is focused and the query is not empty.
return this.focused && this.query.length > 0;
},
},
methods: {
toggleMenu() {
this.menuOpened = !this.menuOpened;
this.$emit("onToggleMenu", this.menuOpened);
if (this.menuOpened) {
document.querySelector("body").classList.add("overflow-hidden");
} else {
document.querySelector("body").classList.remove("overflow-hidden");
}
},
toggleSearch() {
this.searchOpened = !this.searchOpened;
},
focusOut() {
const _this = this;
setTimeout(function () {
_this.focused = false;
}, 200);
},
focusOutMobile() {
const _this = this;
setTimeout(function () {
_this.focused = false;
_this.toggleSearch();
}, 200);
},
},
};
</script>

View File

@@ -0,0 +1,135 @@
<template>
<aside>
<nav>
<ul class="space-y-3 pl-4 lg:pl-0">
<li
v-for="section in $static.allSidebar.edges[0].node.sections"
:key="section.id"
>
<h5
class="text-2xl lg:text-xl font-bold mb-1"
v-if="section.title !== ''"
>
{{ section.title }}
</h5>
<ul
class="space-y-1.5"
:class="{
'pl-2': section.title !== '',
}"
>
<template v-for="(item, index) in section.items">
<li :key="item.id" v-if="item.title === ''">
<g-link
:to="item.path"
class="
block
transition-transform
duration-100
transform
hover:translate-x-1
text-lg
lg:text-base
hover:text-blue-400
"
:class="{
'js-index-link': item.path === '/docs/' && index === 0,
}"
>
{{ item.label }}</g-link
>
</li>
<template v-else>
<li :key="item.id">
<app-accordion>
<template v-slot:title>
<h6 class="font-semibold text-xl lg:text-lg mb-1">
{{ item.title }}
</h6>
</template>
<template v-slot:content>
<ul class="space-y-1.5 pl-2">
<li v-for="subItem in item.subItems" :key="subItem.id">
<g-link
:to="subItem.path"
class="
block
transition-transform
duration-100
transform
hover:translate-x-1
text-lg
lg:text-base
hover:text-blue-400
"
>
{{ subItem.label }}</g-link
>
</li>
</ul>
</template>
</app-accordion>
</li>
</template>
</template>
</ul>
</li>
</ul>
</nav>
</aside>
</template>
<static-query>
{
allSidebar {
edges{
node{
id
sections {
title
items{
title
label
path
subItems {
label
path
}
}
}
}
}
}
}
</static-query>
<script>
import AppAccordion from "~/components/AppAccordion.vue";
export default {
components: {
AppAccordion,
},
watch: {
$route: function () {
if (process.isClient && this.$route.fullPath !== "/docs/") {
setTimeout(function () {
document.querySelector(".js-index-link").classList.remove("active");
}, 80);
}
},
},
mounted() {
if (this.$route.fullPath !== "/docs/") {
document.querySelector(".js-index-link").classList.remove("active");
}
},
};
</script>
<style lang="scss" scoped>
.active {
@apply text-blue-400 font-semibold;
}
</style>

View File

@@ -0,0 +1,108 @@
<template>
<ul class="space-y-2">
<template v-for="(heading, index) in headings">
<li v-if="heading.depth > 1" :key="index" class="hover:underline">
<g-link
:to="`${pagePath}${heading.anchor}`"
class="text-sm"
:class="{
'text-white underline font-semibold':
activeAnchor === heading.anchor,
'text-gray-300': activeAnchor !== heading.anchor,
}"
>
{{ heading.value }}
</g-link>
</li>
</template>
</ul>
</template>
<script>
export default {
props: {
headings: {
type: Array,
required: true,
},
pagePath: {
type: String,
required: true,
},
},
data() {
return {
activeAnchor: "",
observer: null,
};
},
watch: {
$route: function () {
if (process.isClient && window.location.hash) {
this.activeAnchor = window.location.hash;
}
if (this.observer) {
// Clear the current observer.
this.observer.disconnect();
this.$nextTick(this.initObserver);
}
},
},
mounted() {
if (process.isClient) {
if (window.location.hash) {
this.activeAnchor = window.location.hash;
}
this.$nextTick(this.initObserver);
}
},
methods: {
observerCallback(entries, observer) {
// This early return fixes the jumping
// of the bubble active state when we click on a link.
// There should be only one intersecting element anyways.
if (entries.length > 1) {
return;
}
const id = entries[0].target.id;
// We want to give the link of the intersecting
// headline active and add the hash to the url.
if (id) {
this.activeAnchor = "#" + id;
if (history.replaceState) {
history.replaceState(null, null, "#" + id);
}
}
},
initObserver() {
this.observer = new IntersectionObserver(this.observerCallback, {
// This rootMargin should allow intersections at the top of the page.
// root: document.querySelector('.content'),
rootMargin: "0px 0px 99999px",
threshold: 1,
});
const elements = document.querySelectorAll(
".content h2, .content h3, .content h4, .content h5, .content h6"
);
for (let i = 0; i < elements.length; i++) {
this.observer.observe(elements[i]);
}
},
},
};
</script>
<style>
</style>

View File

@@ -0,0 +1,4 @@
Add components that will be imported to Pages and Layouts to this folder.
Learn more about components here: https://gridsome.org/docs/components/
You can delete this file.

View File

@@ -0,0 +1,41 @@
<template>
<div class="bg-gray-800 text-gray-100 relative">
<app-navbar @onToggleMenu="toggleMenu" class="mb-16" />
<div
class="
relative
lg:flex lg:items-stretch lg:space-x-12
min-h-screen
whitespace-normal
"
>
<slot />
</div>
<app-footer />
</div>
</template>
<script>
import AppNavbar from "~/components/AppNavbar.vue";
import AppFooter from "~/components/AppFooter.vue";
import AppSidebar from "~/components/AppSidebar.vue";
export default {
components: {
AppNavbar,
AppFooter,
AppSidebar,
},
data() {
return {
isMenuOpened: false,
};
},
methods: {
toggleMenu(value) {
this.isMenuOpened = value;
console.log(this.isMenuOpened);
},
},
};
</script>

View File

@@ -0,0 +1,92 @@
<template>
<div class="bg-gray-800 text-gray-100 relative">
<app-navbar @onToggleMenu="toggleMenu" type="doc" class="mb-16" />
<div
class="
container
relative
lg:flex lg:items-stretch lg:space-x-12
min-h-screen
whitespace-normal
"
>
<div
class="
lg:w-3/12
2xl:w-2/12
bg-gray-900
lg:bg-gray-800
fixed
z-20
lg:sticky
bottom-0
lg:bottom-auto
left-0
lg:left-auto
right-0
lg:right-auto
top-0
lg:top-6
h-screen
overflow-auto
pt-20
lg:pt-0
pb-16
pr-2
transform
transition-transform
duration-200
"
:class="{
'-translate-x-full lg:translate-x-0': !isMenuOpened,
'translate-x-0': isMenuOpened,
}"
>
<app-sidebar />
</div>
<div class="lg:w-7/12 2xl:w-8/12 overflow-hidden">
<article class="pb-96">
<slot />
</article>
</div>
<div
class="
hidden
lg:inline-block lg:w-2/12 lg:sticky
top-6
h-screen
overflow-auto
pb-16
"
>
<slot name="onThisPage"></slot>
</div>
</div>
<app-footer />
</div>
</template>
<script>
import AppNavbar from "~/components/AppNavbar.vue";
import AppFooter from "~/components/AppFooter.vue";
import AppSidebar from "~/components/AppSidebar.vue";
export default {
components: {
AppNavbar,
AppFooter,
AppSidebar,
},
data() {
return {
isMenuOpened: false,
};
},
methods: {
toggleMenu(value) {
this.isMenuOpened = value;
console.log(this.isMenuOpened);
},
},
};
</script>

View File

@@ -0,0 +1,5 @@
Layout components are used to wrap pages and templates. Layouts should contain components like headers, footers or sidebars that will be used across the site.
Learn more about Layouts: https://gridsome.org/docs/layouts/
You can delete this file.

12
docs/src/main.js Normal file
View File

@@ -0,0 +1,12 @@
// This is the main.js file. Import global CSS and scripts here.
// The Client API can be used here. Learn more: gridsome.org/docs/client-api
import 'prism-themes/themes/prism-lucario.min.css'
import DefaultLayout from '~/layouts/Default.vue'
import MarkdownLayout from '~/layouts/Markdown.vue'
export default function (Vue, { router, head, isClient }) {
// Set default layout as a global component
Vue.component('LayoutDefault', DefaultLayout)
Vue.component('LayoutMarkdown', MarkdownLayout)
}

172
docs/src/pages/Index.vue Normal file
View File

@@ -0,0 +1,172 @@
<template>
<layout-default>
<div class="w-full">
<div class="relative text-center">
<div
class="absolute inset-x-0 -bottom-12 h-72 bg-deco opacity-50"
></div>
<div
class="
absolute
inset-x-0
-bottom-12
h-72
bg-gradient-to-b
from-gray-800
to-transparent
"
></div>
<div class="container relative">
<div class="lg:w-7/12 mx-auto mb-28">
<logo-capsule class="w-32 lg:w-48 mx-auto mb-4" />
<h1 class="text-4xl lg:text-6xl font-bold mb-8">capsule</h1>
<p class="text-lg lg:text-2xl mb-8">
Capsule helps to implement a multi-tenancy and policy-based
environment in your Kubernetes cluster. It is not intended to be
yet another PaaS, instead, it has been designed as a
micro-services-based ecosystem with the minimalist approach,
leveraging only on upstream Kubernetes.
</p>
<div>
<app-button link="/docs">Get Started</app-button>
</div>
</div>
</div>
</div>
<div class="container">
<div
class="
2xl:w-10/12
mx-auto
grid grid-cols-1
md:grid-cols-2
lg:grid-cols-3
gap-8
lg:gap-16
mb-16
"
>
<div class="bg-gray-900 bg-opacity-20 p-5 rounded-md shadow-lg">
<h2 class="text-xl lg:text-3xl font-semibold mb-2.5">
Self-Service
</h2>
<p class="lg:text-lg">
Leave to developers the freedom to self-provision their cluster
resources according to the assigned boundaries.
</p>
</div>
<div class="bg-gray-900 bg-opacity-20 p-5 rounded-md shadow-lg">
<h2 class="text-xl lg:text-3xl font-semibold mb-2.5">
Preventing Clusters Sprawl
</h2>
<p class="lg:text-lg">
Share a single cluster with multiple teams, groups of users, or
departments by saving operational and management efforts.
</p>
</div>
<div class="bg-gray-900 bg-opacity-20 p-5 rounded-md shadow-lg">
<h2 class="text-xl lg:text-3xl font-semibold mb-2.5">Governance</h2>
<p class="lg:text-lg">
Leverage Kubernetes Admission Controllers to enforce the industry
security best practices and meet legal requirements.
</p>
</div>
<div class="bg-gray-900 bg-opacity-20 p-5 rounded-md shadow-lg">
<h2 class="text-xl lg:text-3xl font-semibold mb-2.5">
Resources Control
</h2>
<p class="lg:text-lg">
Leverage Kubernetes Admission Controllers to enforce the industry
security best practices and meet legal requirements.
</p>
</div>
<div class="bg-gray-900 bg-opacity-20 p-5 rounded-md shadow-lg">
<h2 class="text-xl lg:text-3xl font-semibold mb-2.5">
Resources Control
</h2>
<p class="lg:text-lg">
Take control of the resources consumed by users while preventing
them to overtake.
</p>
</div>
<div class="bg-gray-900 bg-opacity-20 p-5 rounded-md shadow-lg">
<h2 class="text-xl lg:text-3xl font-semibold mb-2.5">
Native Experience
</h2>
<p class="lg:text-lg">
Provide multi-tenancy with a native Kubernetes experience without
introducing additional management layers, plugins, or customized
binaries.
</p>
</div>
</div>
</div>
</div>
</layout-default>
</template>
<page-query>
query {
metadata {
siteDescription
}
}
</page-query>
<script>
import AppButton from "~/components/AppButton.vue";
import LogoCapsule from "~/assets/logo.svg?inline";
export default {
metaInfo() {
return {
title: "Capsule: Kubernetes Operator for multi-tenancy",
meta: [
{
property: "og:title",
content: "Capsule Documentation | Capsule: Kubernetes Operator for multi-tenancy",
},
{
property: "og:description",
content: this.$page.metadata.siteDescription,
},
{
property: "og:image",
content: 'https://quizzical-roentgen-574926.netlify.app/assets/share.png',
},
{
property: "twitter:card",
content: "summary",
},
{
property: "twitter:title",
content: "Capsule Documentation | Capsule: Kubernetes Operator for multi-tenancy",
},
{
property: "twitter:description",
content: this.$page.metadata.siteDescription,
},
// {
// property: "og:url",
// content: window.location.href ,
// },
// TO CHANGE
{ name: "robots", content: "noindex, nofollow" },
],
};
},
components: {
AppButton,
LogoCapsule,
},
};
</script>
<style lang="scss" scoped>
.bg-deco {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2000 1500'%3E%3Cdefs%3E%3Crect stroke='%231F2937' stroke-width='0.5' width='1' height='1' id='s'/%3E%3Cpattern id='a' width='3' height='3' patternUnits='userSpaceOnUse' patternTransform='scale(12) translate(-916.67 -687.5)'%3E%3Cuse fill='%232f3641' href='%23s' y='2'/%3E%3Cuse fill='%232f3641' href='%23s' x='1' y='2'/%3E%3Cuse fill='%233b414a' href='%23s' x='2' y='2'/%3E%3Cuse fill='%233b414a' href='%23s'/%3E%3Cuse fill='%23454a52' href='%23s' x='2'/%3E%3Cuse fill='%23454a52' href='%23s' x='1' y='1'/%3E%3C/pattern%3E%3Cpattern id='b' width='7' height='11' patternUnits='userSpaceOnUse' patternTransform='scale(12) translate(-916.67 -687.5)'%3E%3Cg fill='%234e5259'%3E%3Cuse href='%23s'/%3E%3Cuse href='%23s' y='5' /%3E%3Cuse href='%23s' x='1' y='10'/%3E%3Cuse href='%23s' x='2' y='1'/%3E%3Cuse href='%23s' x='2' y='4'/%3E%3Cuse href='%23s' x='3' y='8'/%3E%3Cuse href='%23s' x='4' y='3'/%3E%3Cuse href='%23s' x='4' y='7'/%3E%3Cuse href='%23s' x='5' y='2'/%3E%3Cuse href='%23s' x='5' y='6'/%3E%3Cuse href='%23s' x='6' y='9'/%3E%3C/g%3E%3C/pattern%3E%3Cpattern id='h' width='5' height='13' patternUnits='userSpaceOnUse' patternTransform='scale(12) translate(-916.67 -687.5)'%3E%3Cg fill='%234e5259'%3E%3Cuse href='%23s' y='5'/%3E%3Cuse href='%23s' y='8'/%3E%3Cuse href='%23s' x='1' y='1'/%3E%3Cuse href='%23s' x='1' y='9'/%3E%3Cuse href='%23s' x='1' y='12'/%3E%3Cuse href='%23s' x='2'/%3E%3Cuse href='%23s' x='2' y='4'/%3E%3Cuse href='%23s' x='3' y='2'/%3E%3Cuse href='%23s' x='3' y='6'/%3E%3Cuse href='%23s' x='3' y='11'/%3E%3Cuse href='%23s' x='4' y='3'/%3E%3Cuse href='%23s' x='4' y='7'/%3E%3Cuse href='%23s' x='4' y='10'/%3E%3C/g%3E%3C/pattern%3E%3Cpattern id='c' width='17' height='13' patternUnits='userSpaceOnUse' patternTransform='scale(12) translate(-916.67 -687.5)'%3E%3Cg fill='%23565a60'%3E%3Cuse href='%23s' y='11'/%3E%3Cuse href='%23s' x='2' y='9'/%3E%3Cuse href='%23s' x='5' y='12'/%3E%3Cuse href='%23s' x='9' y='4'/%3E%3Cuse href='%23s' x='12' y='1'/%3E%3Cuse href='%23s' x='16' y='6'/%3E%3C/g%3E%3C/pattern%3E%3Cpattern id='d' width='19' height='17' patternUnits='userSpaceOnUse' patternTransform='scale(12) translate(-916.67 -687.5)'%3E%3Cg fill='%231F2937'%3E%3Cuse href='%23s' y='9'/%3E%3Cuse href='%23s' x='16' y='5'/%3E%3Cuse href='%23s' x='14' y='2'/%3E%3Cuse href='%23s' x='11' y='11'/%3E%3Cuse href='%23s' x='6' y='14'/%3E%3C/g%3E%3Cg fill='%235d6066'%3E%3Cuse href='%23s' x='3' y='13'/%3E%3Cuse href='%23s' x='9' y='7'/%3E%3Cuse href='%23s' x='13' y='10'/%3E%3Cuse href='%23s' x='15' y='4'/%3E%3Cuse href='%23s' x='18' y='1'/%3E%3C/g%3E%3C/pattern%3E%3Cpattern id='e' width='47' height='53' patternUnits='userSpaceOnUse' patternTransform='scale(12) translate(-916.67 -687.5)'%3E%3Cg fill='%235783AB'%3E%3Cuse href='%23s' x='2' y='5'/%3E%3Cuse href='%23s' x='16' y='38'/%3E%3Cuse href='%23s' x='46' y='42'/%3E%3Cuse href='%23s' x='29' y='20'/%3E%3C/g%3E%3C/pattern%3E%3Cpattern id='f' width='59' height='71' patternUnits='userSpaceOnUse' patternTransform='scale(12) translate(-916.67 -687.5)'%3E%3Cg fill='%235783AB'%3E%3Cuse href='%23s' x='33' y='13'/%3E%3Cuse href='%23s' x='27' y='54'/%3E%3Cuse href='%23s' x='55' y='55'/%3E%3C/g%3E%3C/pattern%3E%3Cpattern id='g' width='139' height='97' patternUnits='userSpaceOnUse' patternTransform='scale(12) translate(-916.67 -687.5)'%3E%3Cg fill='%235783AB'%3E%3Cuse href='%23s' x='11' y='8'/%3E%3Cuse href='%23s' x='51' y='13'/%3E%3Cuse href='%23s' x='17' y='73'/%3E%3Cuse href='%23s' x='99' y='57'/%3E%3C/g%3E%3C/pattern%3E%3C/defs%3E%3Crect fill='url(%23a)' width='100%25' height='100%25'/%3E%3Crect fill='url(%23b)' width='100%25' height='100%25'/%3E%3Crect fill='url(%23h)' width='100%25' height='100%25'/%3E%3Crect fill='url(%23c)' width='100%25' height='100%25'/%3E%3Crect fill='url(%23d)' width='100%25' height='100%25'/%3E%3Crect fill='url(%23e)' width='100%25' height='100%25'/%3E%3Crect fill='url(%23f)' width='100%25' height='100%25'/%3E%3Crect fill='url(%23g)' width='100%25' height='100%25'/%3E%3C/svg%3E");
// background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' version='1.1' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:svgjs='http://svgjs.com/svgjs' width='1440' height='250' preserveAspectRatio='none' viewBox='0 0 1440 250'%3e%3cg mask='url(%26quot%3b%23SvgjsMask1012%26quot%3b)' fill='none'%3e%3crect width='1440' height='250' x='0' y='0' fill='rgba(31%2c 41%2c 55%2c 1)'%3e%3c/rect%3e%3cpath d='M36 250L286 0L571 0L321 250z' fill='url(%23SvgjsLinearGradient1013)'%3e%3c/path%3e%3cpath d='M264.6 250L514.6 0L678.1 0L428.1 250z' fill='url(%23SvgjsLinearGradient1013)'%3e%3c/path%3e%3cpath d='M507.20000000000005 250L757.2 0L1073.7 0L823.7 250z' fill='url(%23SvgjsLinearGradient1013)'%3e%3c/path%3e%3cpath d='M725.8000000000001 250L975.8000000000001 0L1302.8000000000002 0L1052.8000000000002 250z' fill='url(%23SvgjsLinearGradient1013)'%3e%3c/path%3e%3cpath d='M1439 250L1189 0L995.5 0L1245.5 250z' fill='url(%23SvgjsLinearGradient1014)'%3e%3c/path%3e%3cpath d='M1157.4 250L907.4000000000001 0L817.4000000000001 0L1067.4 250z' fill='url(%23SvgjsLinearGradient1014)'%3e%3c/path%3e%3cpath d='M961.8 250L711.8 0L383.29999999999995 0L633.3 250z' fill='url(%23SvgjsLinearGradient1014)'%3e%3c/path%3e%3cpath d='M688.1999999999999 250L438.19999999999993 0L208.69999999999993 0L458.69999999999993 250z' fill='url(%23SvgjsLinearGradient1014)'%3e%3c/path%3e%3cpath d='M1247.2258701549645 250L1440 57.225870154964355L1440 250z' fill='url(%23SvgjsLinearGradient1013)'%3e%3c/path%3e%3cpath d='M0 250L192.77412984503565 250L 0 57.225870154964355z' fill='url(%23SvgjsLinearGradient1014)'%3e%3c/path%3e%3c/g%3e%3cdefs%3e%3cmask id='SvgjsMask1012'%3e%3crect width='1440' height='250' fill='white'%3e%3c/rect%3e%3c/mask%3e%3clinearGradient x1='0%25' y1='100%25' x2='100%25' y2='0%25' id='SvgjsLinearGradient1013'%3e%3cstop stop-color='rgba(87%2c 131%2c 171%2c 0.14)' offset='0'%3e%3c/stop%3e%3cstop stop-opacity='0' stop-color='rgba(87%2c 131%2c 171%2c 0.14)' offset='0.66'%3e%3c/stop%3e%3c/linearGradient%3e%3clinearGradient x1='100%25' y1='100%25' x2='0%25' y2='0%25' id='SvgjsLinearGradient1014'%3e%3cstop stop-color='rgba(87%2c 131%2c 171%2c 0.14)' offset='0'%3e%3c/stop%3e%3cstop stop-opacity='0' stop-color='rgba(87%2c 131%2c 171%2c 0.14)' offset='0.66'%3e%3c/stop%3e%3c/linearGradient%3e%3c/defs%3e%3c/svg%3e");
background-size: cover;
}
</style>

5
docs/src/pages/README.md Normal file
View File

@@ -0,0 +1,5 @@
Pages are usually used for normal pages or for listing items from a GraphQL collection.
Add .vue files here to create pages. For example **About.vue** will be **site.com/about**.
Learn more about pages: https://gridsome.org/docs/pages/
You can delete this file.

View File

@@ -0,0 +1,139 @@
<template>
<layout-markdown>
<div class="content" v-html="$page.markdownPage.content"></div>
<template v-slot:onThisPage>
<on-this-page
:headings="$page.markdownPage.headings"
:pagePath="$page.markdownPage.path"
/>
</template>
</layout-markdown>
</template>
<page-query>
query ($id: ID!) {
markdownPage(id: $id) {
id
title
content
path
headings{
depth
value
anchor
}
}
metadata {
siteDescription
}
}
</page-query>
<script>
import OnThisPage from "~/components/OnThisPage.vue";
export default {
metaInfo() {
return {
title: this.$page.markdownPage.title,
meta: [
{
property: "og:title",
content: this.$page.markdownPage.title,
},
{
property: "og:description",
content: this.$page.metadata.siteDescription,
},
{
property: "og:image",
content: 'https://quizzical-roentgen-574926.netlify.app/assets/share.png',
},
{
property: "twitter:card",
content: "summary",
},
{
property: "twitter:title",
content: this.$page.markdownPage.title,
},
{
property: "twitter:description",
content: this.$page.metadata.siteDescription,
},
// {
// property: "og:url",
// content: "",
// },
// TO CHANGE
{ name: "robots", content: "noindex, nofollow" },
],
};
},
components: {
OnThisPage,
},
};
</script>
<style lang="scss">
.content {
a {
@apply underline hover:text-blue-400;
}
p {
@apply mb-2;
}
pre {
margin-bottom: 1.5rem !important;
margin-top: 1rem !important;
}
h1,
h2,
h3,
h4,
h5,
h6 {
@apply font-bold mb-2.5;
&:not(:first-child) {
@apply font-bold mt-4;
}
}
h1 {
@apply text-3xl;
}
h2 {
@apply text-2xl;
}
h3 {
@apply text-xl;
}
h4 {
@apply text-lg;
}
h5 {
@apply text-base;
}
h6 {
@apply text-sm;
}
ul {
@apply list-disc mb-2;
}
ol {
@apply list-decimal mb-2;
}
ol,
ul {
@apply pl-5;
li {
@apply mb-0.5;
}
}
}
</style>

View File

@@ -0,0 +1,7 @@
Templates for **GraphQL collections** should be added here.
To create a template for a collection called `WordPressPost`
create a file named `WordPressPost.vue` in this folder.
Learn more: https://gridsome.org/docs/templates/
You can delete this file.