dashboard: use webpack for builds; use tailwindcss instead of bulma; all sorts of tweaks
This commit is contained in:
parent
028786d348
commit
577500af92
42 changed files with 4813 additions and 3174 deletions
|
@ -1,8 +0,0 @@
|
||||||
{
|
|
||||||
"plugins": [
|
|
||||||
["transform-runtime", {
|
|
||||||
"regenerator": true
|
|
||||||
}],
|
|
||||||
"transform-object-rest-spread"
|
|
||||||
]
|
|
||||||
}
|
|
6541
dashboard/package-lock.json
generated
6541
dashboard/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -4,33 +4,45 @@
|
||||||
"description": "",
|
"description": "",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rimraf dist && parcel build src/index.html --no-source-maps --out-dir dist",
|
"build": "rimraf dist && cross-env NODE_ENV=production webpack --config webpack.config.js",
|
||||||
"build-with-report": "cross-env GENERATE_BUNDLE_SIZE_REPORT=1 npm run build",
|
"build-debug": "rimraf dist && cross-env NODE_ENV=development webpack --config webpack.config.js",
|
||||||
"build-debug": "rimraf dist && cross-env NODE_ENV=development parcel build src/index.html --no-minify --out-dir dist",
|
"watch": "cross-env NODE_ENV=development webpack-dev-server"
|
||||||
"watch": "parcel src/index.html"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/component-compiler-utils": "^3.0.0",
|
"@babel/core": "^7.6.3",
|
||||||
"babel-core": "^6.26.3",
|
"@babel/preset-env": "^7.6.3",
|
||||||
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
"@babel/preset-typescript": "^7.6.0",
|
||||||
"babel-plugin-transform-runtime": "^6.23.0",
|
"babel-loader": "^8.0.6",
|
||||||
"cross-env": "^5.2.0",
|
"cross-env": "^5.2.0",
|
||||||
"parcel-bundler": "^1.12.3",
|
"css-loader": "^3.2.0",
|
||||||
"parcel-plugin-bundle-visualiser": "git://github.com/Dragory/parcel-plugin-bundle-visualiser.git#explicit-env-var",
|
"cssnano": "^4.1.10",
|
||||||
"sass": "^1.21.0",
|
"dotenv-webpack": "^1.7.0",
|
||||||
"vue-template-compiler": "^2.6.10"
|
"file-loader": "^4.2.0",
|
||||||
|
"html-loader": "^0.5.5",
|
||||||
|
"html-webpack-plugin": "^4.0.0-beta.8",
|
||||||
|
"postcss-import": "^12.0.1",
|
||||||
|
"postcss-loader": "^3.0.0",
|
||||||
|
"postcss-nesting": "^7.0.1",
|
||||||
|
"postcss-preset-env": "^6.7.0",
|
||||||
|
"source-map-loader": "^0.2.4",
|
||||||
|
"tailwindcss": "^1.1.2",
|
||||||
|
"ts-loader": "^6.2.0",
|
||||||
|
"vue-loader": "^15.7.1",
|
||||||
|
"vue-style-loader": "^4.1.2",
|
||||||
|
"vue-template-compiler": "^2.6.10",
|
||||||
|
"webpack": "^4.41.0",
|
||||||
|
"webpack-cli": "^3.3.9",
|
||||||
|
"webpack-dev-server": "^3.8.2",
|
||||||
|
"webpack-merge": "^4.2.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"buefy": "^0.7.10",
|
|
||||||
"bulma": "^0.7.5",
|
|
||||||
"bulmaswatch": "^0.7.2",
|
|
||||||
"highlight.js": "^9.15.10",
|
"highlight.js": "^9.15.10",
|
||||||
"js-cookie": "^2.2.0",
|
|
||||||
"js-yaml": "^3.13.1",
|
"js-yaml": "^3.13.1",
|
||||||
"marked": "^0.7.0",
|
"marked": "^0.7.0",
|
||||||
|
"modern-css-reset": "^1.0.4",
|
||||||
"vue": "^2.6.10",
|
"vue": "^2.6.10",
|
||||||
"vue-highlightjs": "git://github.com/Dragory/vue-highlightjs.git#pass-hljs-instance",
|
"vue-highlightjs": "git://github.com/Dragory/vue-highlightjs.git#pass-hljs-instance",
|
||||||
"vue-hot-reload-api": "^2.3.3",
|
"vue-material-design-icons": "^4.1.0",
|
||||||
"vue-router": "^3.0.6",
|
"vue-router": "^3.0.6",
|
||||||
"vue2-ace-editor": "0.0.14",
|
"vue2-ace-editor": "0.0.14",
|
||||||
"vuex": "^3.1.1"
|
"vuex": "^3.1.1"
|
||||||
|
|
|
@ -11,7 +11,7 @@ const isAuthenticated = async () => {
|
||||||
|
|
||||||
export const authGuard: NavigationGuard = async (to, from, next) => {
|
export const authGuard: NavigationGuard = async (to, from, next) => {
|
||||||
if (await isAuthenticated()) return next();
|
if (await isAuthenticated()) return next();
|
||||||
next("/");
|
window.location.href = `${process.env.API_URL}/auth/login`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const loginCallbackGuard: NavigationGuard = async (to, from, next) => {
|
export const loginCallbackGuard: NavigationGuard = async (to, from, next) => {
|
||||||
|
@ -19,12 +19,7 @@ export const loginCallbackGuard: NavigationGuard = async (to, from, next) => {
|
||||||
await RootStore.dispatch("auth/setApiKey", to.query.apiKey);
|
await RootStore.dispatch("auth/setApiKey", to.query.apiKey);
|
||||||
next("/dashboard");
|
next("/dashboard");
|
||||||
} else {
|
} else {
|
||||||
next({
|
window.location.href = `/?error=noAccess`;
|
||||||
path: "/",
|
|
||||||
query: {
|
|
||||||
error: "noaccess",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
<template>
|
<template>
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
|
||||||
</script>
|
|
||||||
|
|
119
dashboard/src/components/Expandable.vue
Normal file
119
dashboard/src/components/Expandable.vue
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
<template>
|
||||||
|
<div class="expandable mb-4 bg-gray-800 border border-gray-600 rounded overflow-hidden" ref="root" v-bind:class="{'shadow-xl': isOpen}">
|
||||||
|
<div role="button" class="title p-2" v-on:click="toggle">
|
||||||
|
<chevron-down class="icon" v-bind:class="{'icon-open': isOpen}" />
|
||||||
|
<span class="title-text"><slot name="title"></slot></span>
|
||||||
|
</div>
|
||||||
|
<div class="content border-t border-gray-700" ref="content">
|
||||||
|
<div class="p-4 pb-0">
|
||||||
|
<slot name="content"></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
:root {
|
||||||
|
--animation-time: 400ms;
|
||||||
|
--target-height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expandable {
|
||||||
|
transition: box-shadow var(--animation-time);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
&:hover {
|
||||||
|
& .title-text {
|
||||||
|
@apply underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
transition: transform var(--animation-time);
|
||||||
|
transform-origin: 50% 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-open {
|
||||||
|
transform: rotate(179deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
overflow: hidden;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes open {
|
||||||
|
0% { height: 0; }
|
||||||
|
100% { height: var(--target-height); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes close {
|
||||||
|
100% { height: 0; }
|
||||||
|
0% { height: var(--target-height); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.opening {
|
||||||
|
animation: open var(--animation-time) ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.closing {
|
||||||
|
animation: close var(--animation-time) ease-in-out;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script type="ts">
|
||||||
|
import ChevronDown from 'vue-material-design-icons/ChevronDown.vue';
|
||||||
|
|
||||||
|
const ANIMATION_TIME = 400;
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { ChevronDown },
|
||||||
|
mounted() {
|
||||||
|
this.$refs.root.style.setProperty('--animation-time', `${ANIMATION_TIME}ms`);
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isOpen: false,
|
||||||
|
animating: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggle() {
|
||||||
|
if (this.isOpen) this.close();
|
||||||
|
else this.open();
|
||||||
|
},
|
||||||
|
open() {
|
||||||
|
if (this.animating) return;
|
||||||
|
this.animating = true;
|
||||||
|
this.isOpen = true;
|
||||||
|
|
||||||
|
this.$refs.content.style.display = 'block';
|
||||||
|
const targetHeight = this.$refs.content.clientHeight;
|
||||||
|
this.$refs.content.style.setProperty('--target-height', `${targetHeight}px`);
|
||||||
|
this.$refs.content.classList.add('opening');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs.content.classList.remove('opening');
|
||||||
|
this.animating = false;
|
||||||
|
}, ANIMATION_TIME);
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
if (this.animating) return;
|
||||||
|
this.animating = true;
|
||||||
|
this.isOpen = false;
|
||||||
|
|
||||||
|
const targetHeight = this.$refs.content.clientHeight;
|
||||||
|
this.$refs.content.style.setProperty('--target-height', `${targetHeight}px`);
|
||||||
|
this.$refs.content.classList.add('closing');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs.content.classList.remove('closing');
|
||||||
|
this.$refs.content.style.display = 'none';
|
||||||
|
this.animating = false;
|
||||||
|
}, ANIMATION_TIME);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -1,35 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="splash">
|
|
||||||
<div class="wrapper">
|
|
||||||
<div class="logo-column">
|
|
||||||
<img class="logo" src="../img/logo.png" alt="Zeppelin Logo">
|
|
||||||
</div>
|
|
||||||
<div class="info-column">
|
|
||||||
<h1>Zeppelin</h1>
|
|
||||||
<div class="description">
|
|
||||||
Zeppelin is a private moderation bot for Discord, designed with large servers and reliability in mind.
|
|
||||||
</div>
|
|
||||||
<div class="actions">
|
|
||||||
<router-link class="btn" to="/login">Dashboard</router-link>
|
|
||||||
<router-link class="btn" to="/docs">Documentation</router-link>
|
|
||||||
</div>
|
|
||||||
<div class="error" v-if="error">
|
|
||||||
<strong>Error</strong>
|
|
||||||
<div v-if="error === 'noaccess'">No access</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import "../style/splash.scss";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
computed: {
|
|
||||||
error() {
|
|
||||||
return this.$route.query.error;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
11
dashboard/src/components/Tab.vue
Normal file
11
dashboard/src/components/Tab.vue
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<template>
|
||||||
|
<li class="py-2 px-4 hover:text-gray-200" :class="{'pb-1 border-b border-gray-400 text-gray-200': active, 'text-gray-500': !active}">
|
||||||
|
<slot></slot>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
props: ["active"],
|
||||||
|
};
|
||||||
|
</script>
|
5
dashboard/src/components/Tabs.vue
Normal file
5
dashboard/src/components/Tabs.vue
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<template>
|
||||||
|
<ul class="list-none flex border-b border-gray-600 mb-4">
|
||||||
|
<slot></slot>
|
||||||
|
</ul>
|
||||||
|
</template>
|
|
@ -20,6 +20,15 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ace_editor {
|
||||||
|
box-shadow: 0 2px 16px -4px #0000009e;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #181818;
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapState} from "vuex";
|
import {mapState} from "vuex";
|
||||||
import {ApiError} from "../../api";
|
import {ApiError} from "../../api";
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import "../../style/dashboard.scss";
|
// import "../../style/dashboard.scss";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -1,83 +1,83 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="z-title is-1 mb-1">Argument Types</h1>
|
<h1>Argument Types</h1>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
This page details the different argument types available for commands.
|
This page details the different argument types available for commands.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 id="string" class="z-title is-2 mt-2 mb-1">string</h2>
|
<h2 id="string">string</h2>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Any text
|
Any text
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 id="number" class="z-title is-2 mt-2 mb-1">number</h2>
|
<h2 id="number">number</h2>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Any number
|
Any number
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 id="user" class="z-title is-2 mt-2 mb-1">user</h2>
|
<h2 id="user">user</h2>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Anything that uniquely identifies a user. This includes:
|
Anything that uniquely identifies a user. This includes:
|
||||||
</p>
|
</p>
|
||||||
<ul class="z-list z-ul mb-1">
|
<ul>
|
||||||
<li>User ID <code>108552944961454080</code></li>
|
<li>User ID <code>108552944961454080</code></li>
|
||||||
<li>User mention <code>@Dark#1010</code></li>
|
<li>User mention <code>@Dark#1010</code></li>
|
||||||
<li>Loose user mention <code>Dark#1010</code></li>
|
<li>Loose user mention <code>Dark#1010</code></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2 id="userId" class="z-title is-2 mt-2 mb-1">userId</h2>
|
<h2 id="userId">userId</h2>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
A valid user ID, e.g. <code>108552944961454080</code>
|
A valid user ID, e.g. <code>108552944961454080</code>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 id="channel" class="z-title is-2 mt-2 mb-1">channel</h2>
|
<h2 id="channel">channel</h2>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Anything that uniquely identifies a channel. This includes:
|
Anything that uniquely identifies a channel. This includes:
|
||||||
</p>
|
</p>
|
||||||
<ul class="z-list z-ul mb-1">
|
<ul>
|
||||||
<li>Channel ID <code>473087035574321152</code></li>
|
<li>Channel ID <code>473087035574321152</code></li>
|
||||||
<li>Channel mention <code>#my-channel</code></li>
|
<li>Channel mention <code>#my-channel</code></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2 id="channelId" class="z-title is-2 mt-2 mb-1">channelId</h2>
|
<h2 id="channelId">channelId</h2>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
A valid channel ID, e.g. <code>473087035574321152</code>
|
A valid channel ID, e.g. <code>473087035574321152</code>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 id="role" class="z-title is-2 mt-2 mb-1">role</h2>
|
<h2 id="role">role</h2>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Anything that uniquely identifies a role. This includes:
|
Anything that uniquely identifies a role. This includes:
|
||||||
</p>
|
</p>
|
||||||
<ul class="z-list z-ul mb-1">
|
<ul>
|
||||||
<li>Role ID <code>473085927053590538</code></li>
|
<li>Role ID <code class="inline-code">473085927053590538</code></li>
|
||||||
<li>Role mention <code>@MyRole</code></li>
|
<li>Role mention <code>@MyRole</code></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2 id="member" class="z-title is-2 mt-2 mb-1">member</h2>
|
<h2 id="member">member</h2>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Anything that uniquely identifies a member currently on the server. This includes:
|
Anything that uniquely identifies a member currently on the server. This includes:
|
||||||
</p>
|
</p>
|
||||||
<ul class="z-list z-ul mb-1">
|
<ul>
|
||||||
<li>User ID <code>108552944961454080</code></li>
|
<li>User ID <code>108552944961454080</code></li>
|
||||||
<li>User Mention <code>@Dark#1010</code></li>
|
<li>User Mention <code>@Dark#1010</code></li>
|
||||||
<li>Loose user mention <code>Dark#1010</code></li>
|
<li>Loose user mention <code>Dark#1010</code></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2 id="resolvedMember" class="z-title is-2 mt-2 mb-1">resolvedMember</h2>
|
<h2 id="resolvedMember">resolvedMember</h2>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
See <code>member</code> above
|
See <code>member</code> above
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 id="delay" class="z-title is-2 mt-2 mb-1">delay</h2>
|
<h2 id="delay">delay</h2>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
A delay is used to specify an amount of time. It uses simple letters to specify time durations.<br>
|
A delay is used to specify an amount of time. It uses simple letters to specify time durations.<br>
|
||||||
For example, <code>2d15h27m3s</code> would be 2 days, 15 hours, 27 minutes and 3 seconds.
|
For example, <code>2d15h27m3s</code> would be 2 days, 15 hours, 27 minutes and 3 seconds.
|
||||||
</p>
|
</p>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Note that the delay should always be written as 1 word, without spaces!
|
Note that the delay should always be written as 1 word, without spaces!
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<b-collapse :open="false" class="card mb-1">
|
<div :open="false" class="card mb-1"> <!-- b-collapse -->
|
||||||
<div slot="trigger" slot-scope="props" class="card-header" role="button">
|
<div slot="trigger" slot-scope="props" class="card-header" role="button">
|
||||||
<p class="card-header-title">Additional Information</p>
|
<p class="card-header-title">Additional Information</p>
|
||||||
<a class="card-header-icon">
|
<a class="card-header-icon">
|
||||||
|
@ -103,7 +103,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</b-collapse>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<pre class="codeblock" v-highlightjs><code :class="lang" v-trim-code="trim"><slot></slot></code></pre>
|
<pre class="codeblock" v-highlightjs><code :class="lang" v-trim-indents="trim"><slot></slot></code></pre>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.codeblock {
|
|
||||||
border-radius: 3px;
|
|
||||||
padding: 16px;
|
|
||||||
max-width: 970px; /* FIXME: temp fix for overflowing code blocks, look into properly later */
|
|
||||||
}
|
|
||||||
|
|
||||||
.hljs {
|
|
||||||
background: transparent;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: ["lang", "trim"],
|
props: ["lang", "trim"],
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="z-title is-1 mb-1">Configuration format</h1>
|
<h1>Configuration format</h1>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
This is the basic format of the bot configuration for a guild. The basic breakdown is:
|
This is the basic format of the bot configuration for a guild. The basic breakdown is:
|
||||||
</p>
|
</p>
|
||||||
<ol class="z-list mb-1">
|
|
||||||
|
<ul>
|
||||||
<li>Prefix (i.e. what character is preceding each command)</li>
|
<li>Prefix (i.e. what character is preceding each command)</li>
|
||||||
<li>Permission levels (see <router-link to="/docs/permissions">Permissions</router-link> for more info)</li>
|
<li>Permission levels (see <router-link to="/docs/permissions">Permissions</router-link> for more info)</li>
|
||||||
<li>Plugin-specific configuration (see <router-link to="/docs/plugin-configuration">Plugin configuration</router-link> for more info)</li>
|
<li>Plugin-specific configuration (see <router-link to="/docs/plugin-configuration">Plugin configuration</router-link> for more info)</li>
|
||||||
</ol>
|
</ul>
|
||||||
<CodeBlock lang="yaml" trim="4">
|
|
||||||
|
<CodeBlock lang="yaml" trim="start">
|
||||||
prefix: "!"
|
prefix: "!"
|
||||||
|
|
||||||
# role id: level
|
# role id: level
|
||||||
|
@ -33,8 +35,8 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import CodeBlock from "./CodeBlock";
|
import CodeBlock from "./CodeBlock.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { CodeBlock },
|
components: { CodeBlock },
|
||||||
|
|
|
@ -1,168 +1,134 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="docs docs-cloak">
|
<div class="docs">
|
||||||
<nav class="navbar" role="navigation" aria-label="main navigation">
|
<div class="container mx-auto px-4 py-2">
|
||||||
<div class="container">
|
<!-- Top bar -->
|
||||||
<div class="navbar-brand">
|
<nav class="flex items-stretch pl-4 pr-2 py-1 border border-gray-700 rounded bg-gray-800 shadow-xl">
|
||||||
<div class="navbar-item">
|
<div class="flex-initial flex items-center">
|
||||||
<img class="docs-logo" src="../../img/logo.png" alt="" aria-hidden="true">
|
<img class="flex-auto w-10 mr-5" src="../../img/logo.png" alt="" aria-hidden="true">
|
||||||
<h1 class="docs-title">Zeppelin Documentation</h1>
|
<h1 class="flex-auto">Zeppelin Documentation</h1>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex-1 flex items-center justify-end">
|
||||||
|
<router-link
|
||||||
|
to="/dashboard"
|
||||||
|
role="menuitem"
|
||||||
|
class="py-1 px-2 rounded hover:bg-gray-700">
|
||||||
|
Go to dashboard
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
<div class="navbar-menu is-active">
|
<!-- WIP bar -->
|
||||||
<div class="navbar-end">
|
<div class="mt-6 px-3 py-2 rounded bg-gray-800 shadow-md">
|
||||||
<router-link to="/dashboard" class="navbar-item">Go to dashboard</router-link>
|
<i class="mdi mdi-alert mr-1" title="Note"></i>
|
||||||
</div>
|
This documentation is a work in progress.
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="wip-bar">
|
<!-- Content wrapper -->
|
||||||
<i class="mdi mdi-alert"></i>
|
<div class="flex items-start mt-8">
|
||||||
<strong>Note!</strong> This documentation is a work in progress.
|
<!-- Sidebar -->
|
||||||
</div>
|
<nav class="docs-sidebar flex-none px-4 pt-2 pb-3 mr-8 border border-gray-700 rounded bg-gray-800 shadow-md">
|
||||||
|
<div role="none" v-for="(group, index) in menu">
|
||||||
<div class="wrapper">
|
<h1 class="font-bold" :aria-owns="'menu-group-' + index" :class="{'mt-4': index !== 0}">{{ group.label }}</h1>
|
||||||
<div class="docs-sidebar">
|
<ul v-bind:id="'menu-group-' + index" role="group" class="list-none pl-2">
|
||||||
<div class="docs-sidebar-content">
|
<li role="none" v-for="item in group.items">
|
||||||
<aside class="menu">
|
<router-link role="menuitem" :to="item.to" class="text-gray-300 hover:text-gray-500">{{ item.label }}</router-link>
|
||||||
<p class="menu-label">General</p>
|
|
||||||
<ul class="menu-list">
|
|
||||||
<li><router-link to="/docs/introduction">Introduction</router-link></li>
|
|
||||||
<li><router-link to="/docs/configuration-format">Configuration format</router-link></li>
|
|
||||||
<li><router-link to="/docs/plugin-configuration">Plugin configuration</router-link></li>
|
|
||||||
<li><router-link to="/docs/permissions">Permissions</router-link></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p class="menu-label">Reference</p>
|
|
||||||
<ul class="menu-list">
|
|
||||||
<li><router-link to="/docs/reference/argument-types">Argument types</router-link></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p class="menu-label">Setup guides</p>
|
|
||||||
<ul class="menu-list">
|
|
||||||
<li><router-link to="/docs/setup-guides/logs">Logs</router-link></li>
|
|
||||||
<li><router-link to="/docs/setup-guides/moderation">Moderation</router-link></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p class="menu-label">Plugins</p>
|
|
||||||
<ul class="menu-list">
|
|
||||||
<li v-for="plugin in plugins">
|
|
||||||
<router-link :to="'/docs/plugins/' + plugin.name">{{ plugin.info.prettyName || plugin.name }}</router-link>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</aside>
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
|
<div class="docs-content flex-auto overflow-x-hidden">
|
||||||
|
<router-view :key="$route.fullPath"></router-view>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="docs-main">
|
|
||||||
<router-view :key="$route.fullPath"></router-view>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<script lang="ts">
|
||||||
.docs-cloak {
|
|
||||||
/* Replaced by "visible" in docs.scss */
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.docs {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 1280px;
|
|
||||||
margin: 20px auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar {
|
|
||||||
border: 1px solid #4e5d6c;
|
|
||||||
border-radius: 3px;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
padding: 0 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.docs-logo {
|
|
||||||
margin-right: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.docs-title {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wip-bar {
|
|
||||||
padding: 4px 10px;
|
|
||||||
margin-bottom: 24px;
|
|
||||||
background-color: #2B3E50;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wip-bar i {
|
|
||||||
color: #fdd7a5;
|
|
||||||
font-size: 24px;
|
|
||||||
vertical-align: -3px;
|
|
||||||
margin-right: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapper {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.docs-sidebar {
|
|
||||||
flex: 0 0 280px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.docs-sidebar-content {
|
|
||||||
/* can't scroll with a long list before reaching the end of the page, figure out */
|
|
||||||
/*position: sticky;*/
|
|
||||||
/*top: 20px;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.docs-sidebar .menu {
|
|
||||||
padding: 12px 16px;
|
|
||||||
border: 1px solid #4e5d6c;
|
|
||||||
background-color: #2b3e50;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.docs-sidebar .menu-label {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.docs-main {
|
|
||||||
flex: 1 1 100%;
|
|
||||||
padding: 0 24px 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.docs-main >>> h4 {
|
|
||||||
margin-top: 1.25em; /* ? */
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import hljs from "highlight.js/lib/highlight.js";
|
|
||||||
import hljsYaml from "highlight.js/lib/languages/yaml.js";
|
|
||||||
import VueHighlightJS from "vue-highlightjs";
|
|
||||||
import Buefy from "buefy";
|
|
||||||
import {mapState} from "vuex";
|
import {mapState} from "vuex";
|
||||||
|
|
||||||
import "../../style/icons.scss";
|
type TMenuItem = {
|
||||||
import "buefy/dist/buefy.css";
|
to: string;
|
||||||
import "highlight.js/styles/ocean.css";
|
label: string;
|
||||||
import "../../directives/trim-code";
|
};
|
||||||
import "../../style/docs.scss";
|
type TMenuGroup = {
|
||||||
|
label: string;
|
||||||
|
items: TMenuItem[];
|
||||||
|
};
|
||||||
|
type TMenu = TMenuGroup[];
|
||||||
|
|
||||||
hljs.registerLanguage("yaml", hljsYaml);
|
const menu: TMenu = [
|
||||||
Vue.use(VueHighlightJS, { hljs });
|
{
|
||||||
Vue.use(Buefy);
|
label: 'General',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
to: '/docs/introduction',
|
||||||
|
label: 'Introduction',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/docs/configuration-format',
|
||||||
|
label: 'Configuration format',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/docs/plugin-configuration',
|
||||||
|
label: 'Plugin configuration',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/docs/permissions',
|
||||||
|
label: 'Permissions',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
label: 'Reference',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
to: '/docs/reference/argument-types',
|
||||||
|
label: 'Argument types',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
label: 'Setup guides',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
to: '/docs/setup-guides/logs',
|
||||||
|
label: 'Logs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/docs/setup-guides/moderation',
|
||||||
|
label: 'Moderation',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async mounted() {
|
async mounted() {
|
||||||
await this.$store.dispatch("docs/loadAllPlugins");
|
await this.$store.dispatch("docs/loadAllPlugins");
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapState('docs', {
|
...mapState('docs', {
|
||||||
plugins: 'allPlugins',
|
plugins: 'allPlugins',
|
||||||
}),
|
}),
|
||||||
|
menu() {
|
||||||
|
return [
|
||||||
|
...menu,
|
||||||
|
{
|
||||||
|
label: 'Plugins',
|
||||||
|
items: this.plugins.map(plugin => ({
|
||||||
|
label: plugin.info.prettyName || plugin.name,
|
||||||
|
to: `/docs/plugins/${plugin.name}`,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
];
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,29 +1,29 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="z-title is-1 mb-1">Introduction</h1>
|
<h1>Introduction</h1>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Zeppelin is a private moderation bot for Discord, designed with large servers and reliability in mind.
|
Zeppelin is a private moderation bot for Discord, designed with large servers and reliability in mind.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 class="z-title is-2 mt-2 mb-1">Getting the bot</h2>
|
<h2>Getting the bot</h2>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Since the bot is currently private, access to the bot is granted on a case by case basis.<br>
|
Since the bot is currently private, access to the bot is granted on a case by case basis.<br>
|
||||||
There are plans to streamline this process in the future.
|
There are plans to streamline this process in the future.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 class="z-title is-2 mt-2 mb-1">Configuration</h2>
|
<h2>Configuration</h2>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
All Zeppelin configuration is done through the dashboard by editing a YAML config file. By default, only the server
|
All Zeppelin configuration is done through the dashboard by editing a YAML config file. By default, only the server
|
||||||
owner has access to this, but they can give other users access as they see fit. See <router-link to="/docs/configuration-format">Configuration format</router-link> for more details.
|
owner has access to this, but they can give other users access as they see fit. See <router-link to="/docs/configuration-format">Configuration format</router-link> for more details.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 class="z-title is-2 mt-2 mb-1">Plugins</h2>
|
<h2>Plugins</h2>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Zeppelin is divided into plugins: grouped functionality that can be enabled/disabled as needed, and that have their own configurations.
|
Zeppelin is divided into plugins: grouped functionality that can be enabled/disabled as needed, and that have their own configurations.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 class="z-title is-2 mt-2 mb-1">Commands</h2>
|
<h2>Commands</h2>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
The commands for each plugin are listed on the plugin's page (see "Plugins" on the menu). On these pages, the command prefix is assumed to be <code>!</code> but this can be changed on a per-server basis.
|
The commands for each plugin are listed on the plugin's page (see "Plugins" on the menu). On these pages, the command prefix is assumed to be <code>!</code> but this can be changed on a per-server basis.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="z-title is-1 mb-1">Permissions</h1>
|
<h1>Permissions</h1>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Permissions in Zeppelin are simply values in plugin configuration that are checked when the command is used.
|
Permissions in Zeppelin are simply values in plugin configuration that are checked when the command is used.
|
||||||
These values can be changed with overrides (see <router-link to="/docs/plugin-configuration">Plugin configuration</router-link> for more info)
|
These values can be changed with overrides (see <router-link to="/docs/plugin-configuration">Plugin configuration</router-link> for more info)
|
||||||
and can depend on e.g. user id, role id, channel id, category id, or <strong>permission level</strong>.
|
and can depend on e.g. user id, role id, channel id, category id, or <strong>permission level</strong>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 class="z-title is-2 mt-2 mb-1">Permission levels</h2>
|
<h2>Permission levels</h2>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
The simplest way to control access to bot commands and features is via permission levels.
|
The simplest way to control access to bot commands and features is via permission levels.
|
||||||
These levels are simply a number (usually between 0 and 100), based on the user's roles or user id, that can then
|
These levels are simply a number (usually between 0 and 100), based on the user's roles or user id, that can then
|
||||||
be used in permission overrides. By default, several commands are "moderator only" (level 50 and up) or "admin only" (level 100 and up).
|
be used in permission overrides. By default, several commands are "moderator only" (level 50 and up) or "admin only" (level 100 and up).
|
||||||
</p>
|
</p>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Additionally, having a higher permission level means that certain commands (such as !ban) can't be used against
|
Additionally, having a higher permission level means that certain commands (such as !ban) can't be used against
|
||||||
you by users with a lower or equal permission level (so e.g. moderators can't ban each other or admins above them).
|
you by users with a lower or equal permission level (so e.g. moderators can't ban each other or admins above them).
|
||||||
</p>
|
</p>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Permission levels are defined in the config in the <strong>levels</strong> section. For example:
|
Permission levels are defined in the config in the <strong>levels</strong> section. For example:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -28,14 +28,14 @@
|
||||||
"172950000412655616": 50 # Example mod
|
"172950000412655616": 50 # Example mod
|
||||||
</CodeBlock>
|
</CodeBlock>
|
||||||
|
|
||||||
<h2 class="z-title is-2 mt-2 mb-1">Examples</h2>
|
<h2>Examples</h2>
|
||||||
|
|
||||||
<h3 class="z-title is-3 mb-1">Basic overrides</h3>
|
<h3>Basic overrides</h3>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
For this example, let's assume we have a plugin called <code>cats</code> which has a command <code>!cat</code> locked behind the permission <code>can_cat</code>.
|
For this example, let's assume we have a plugin called <code>cats</code> which has a command <code>!cat</code> locked behind the permission <code>can_cat</code>.
|
||||||
Let's say that by default, the plugin allows anyone to use <code>!cat</code>, but we want to restrict it to moderators only.
|
Let's say that by default, the plugin allows anyone to use <code>!cat</code>, but we want to restrict it to moderators only.
|
||||||
</p>
|
</p>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Here's what the configuration for this would look like:
|
Here's what the configuration for this would look like:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
can_cat: true
|
can_cat: true
|
||||||
</CodeBlock>
|
</CodeBlock>
|
||||||
|
|
||||||
<h3 class="z-title is-3 mt-2 mb-1">Replacing defaults</h3>
|
<h3>Replacing defaults</h3>
|
||||||
<p class="mb-1">
|
<p class="mb-1">
|
||||||
In this example, let's assume you don't want to use the default permission levels of 50 and 100 for mods and admins respectively.
|
In this example, let's assume you don't want to use the default permission levels of 50 and 100 for mods and admins respectively.
|
||||||
Let's say you're using various incremental levels instead: 10, 20, 30, 40, 50...<br>
|
Let's say you're using various incremental levels instead: 10, 20, 30, 40, 50...<br>
|
||||||
|
|
|
@ -3,21 +3,19 @@
|
||||||
Loading...
|
Loading...
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<h1 class="z-title is-1 mb-1">{{ data.info.prettyName || data.name }}</h1>
|
<h1>{{ data.info.prettyName || data.name }}</h1>
|
||||||
|
|
||||||
<!-- Description -->
|
<!-- Description -->
|
||||||
<MarkdownBlock :content="data.info.description" class="content"></MarkdownBlock>
|
<MarkdownBlock :content="data.info.description" class="content"></MarkdownBlock>
|
||||||
|
|
||||||
<div class="tabs">
|
<Tabs>
|
||||||
<ul>
|
<Tab :active="tab === 'usage'">
|
||||||
<li v-bind:class="{'is-active': tab === 'usage'}">
|
<router-link v-bind:to="'/docs/plugins/' + pluginName + '/usage'">Usage</router-link>
|
||||||
<router-link v-bind:to="'/docs/plugins/' + pluginName + '/usage'">Usage</router-link>
|
</Tab>
|
||||||
</li>
|
<Tab :active="tab === 'configuration'">
|
||||||
<li v-bind:class="{'is-active': tab === 'configuration'}">
|
<router-link v-bind:to="'/docs/plugins/' + pluginName + '/configuration'">Configuration</router-link>
|
||||||
<router-link v-bind:to="'/docs/plugins/' + pluginName + '/configuration'">Configuration</router-link>
|
</Tab>
|
||||||
</li>
|
</Tabs>
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Usage tab -->
|
<!-- Usage tab -->
|
||||||
<div class="usage" v-if="tab === 'usage'">
|
<div class="usage" v-if="tab === 'usage'">
|
||||||
|
@ -28,38 +26,33 @@
|
||||||
|
|
||||||
<!-- Usage guide -->
|
<!-- Usage guide -->
|
||||||
<div v-if="data.info.usageGuide">
|
<div v-if="data.info.usageGuide">
|
||||||
<h2 id="usage-guide" class="z-title is-2 mt-2 mb-1">Usage guide</h2>
|
<h2 id="usage-guide">Usage guide</h2>
|
||||||
<MarkdownBlock :content="data.info.usageGuide" class="content"></MarkdownBlock>
|
<MarkdownBlock :content="data.info.usageGuide" class="content"></MarkdownBlock>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Command list -->
|
<!-- Command list -->
|
||||||
<div v-if="data.commands.length">
|
<div v-if="data.commands.length">
|
||||||
<h2 id="commands" class="z-title is-2 mt-2 mb-1">Commands</h2>
|
<h2 id="commands">Commands</h2>
|
||||||
<div v-for="command in data.commands">
|
<div v-for="command in data.commands" class="mb-4">
|
||||||
<h3 class="z-title is-3 mt-2 mb-1">!{{ command.trigger }}</h3>
|
<h3 class="text-xl">!{{ command.trigger }}</h3>
|
||||||
<div v-if="command.config.extra.requiredPermission">
|
<div v-if="command.config.extra.requiredPermission">
|
||||||
Permission: <code>{{ command.config.extra.requiredPermission }}</code>
|
Permission: <code class="inline-code">{{ command.config.extra.requiredPermission }}</code>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="command.config.extra.info && command.config.extra.info.basicUsage">
|
<div v-if="command.config.extra.info && command.config.extra.info.basicUsage">
|
||||||
Basic usage: <code>{{ command.config.extra.info.basicUsage }}</code>
|
Basic usage: <code class="inline-code">{{ command.config.extra.info.basicUsage }}</code>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="command.config.aliases && command.config.aliases.length">
|
<div v-if="command.config.aliases && command.config.aliases.length">
|
||||||
Shortcut:
|
Shortcut:
|
||||||
<code style="margin-right: 4px" v-for="alias in command.config.aliases">!{{ alias }}</code>
|
<code class="inline-code" style="margin-right: 4px" v-for="alias in command.config.aliases">!{{ alias }}</code>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MarkdownBlock v-if="command.config.info && command.config.info.description" :content="command.config.info.description" class="content mt-1 mb-1"></MarkdownBlock>
|
<MarkdownBlock v-if="command.config.info && command.config.info.description" :content="command.config.info.description" class="content mb-4"></MarkdownBlock>
|
||||||
|
|
||||||
<b-collapse :open="false" class="card mt-1 mb-1">
|
<Expandable class="mt-4">
|
||||||
<div slot="trigger" slot-scope="props" class="card-header" role="button">
|
<template v-slot:title>Additional information</template>
|
||||||
<p class="card-header-title">Additional information</p>
|
<template v-slot:content>
|
||||||
<a class="card-header-icon">
|
|
||||||
<b-icon :icon="props.open ? 'menu-down' : 'menu-up'"></b-icon>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="card-content">
|
|
||||||
Signatures:
|
Signatures:
|
||||||
<ul class="z-list z-ul">
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<code>
|
<code>
|
||||||
!{{ command.trigger }}
|
!{{ command.trigger }}
|
||||||
|
@ -70,7 +63,7 @@
|
||||||
|
|
||||||
<div class="mt-2" v-if="command.parameters.length">
|
<div class="mt-2" v-if="command.parameters.length">
|
||||||
Command arguments:
|
Command arguments:
|
||||||
<ul class="z-list z-ul">
|
<ul>
|
||||||
<li v-for="param in command.parameters">
|
<li v-for="param in command.parameters">
|
||||||
<code>{{ renderParameter(param) }}</code>
|
<code>{{ renderParameter(param) }}</code>
|
||||||
<router-link :to="'/docs/reference/argument-types#' + (param.type || 'string')">{{ param.type || 'string' }}</router-link>
|
<router-link :to="'/docs/reference/argument-types#' + (param.type || 'string')">{{ param.type || 'string' }}</router-link>
|
||||||
|
@ -95,8 +88,8 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
</b-collapse>
|
</Expandable>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -104,26 +97,26 @@
|
||||||
<!-- Configuration tab -->
|
<!-- Configuration tab -->
|
||||||
<div class="configuration" v-if="tab === 'configuration'">
|
<div class="configuration" v-if="tab === 'configuration'">
|
||||||
<!-- Basic config info -->
|
<!-- Basic config info -->
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Name in config: <code>{{ data.name }}</code>
|
Name in config: <code>{{ data.name }}</code>
|
||||||
</p>
|
</p>
|
||||||
<p class="mt-1 mb-1">
|
<p>
|
||||||
To enable this plugin with default configuration, add <code>{{ data.name }}: {}</code> to the <code>plugins</code> list in config
|
To enable this plugin with default configuration, add <code>{{ data.name }}: {}</code> to the <code>plugins</code> list in config
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- Configuration guide -->
|
<!-- Configuration guide -->
|
||||||
<div v-if="data.info.configurationGuide">
|
<div v-if="data.info.configurationGuide">
|
||||||
<h2 id="configuration-guide" class="z-title is-2 mt-2 mb-1">Configuration guide</h2>
|
<h2 id="configuration-guide">Configuration guide</h2>
|
||||||
<MarkdownBlock :content="data.info.configurationGuide" class="content"></MarkdownBlock>
|
<MarkdownBlock :content="data.info.configurationGuide" class="content"></MarkdownBlock>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Default configuration -->
|
<!-- Default configuration -->
|
||||||
<h2 id="default-configuration" class="z-title is-2 mt-2 mb-1">Default configuration</h2>
|
<h2 id="default-configuration">Default configuration</h2>
|
||||||
<CodeBlock lang="yaml">{{ renderConfiguration(data.defaultOptions) }}</CodeBlock>
|
<CodeBlock lang="yaml">{{ renderConfiguration(data.defaultOptions) }}</CodeBlock>
|
||||||
|
|
||||||
<!-- Config schema -->
|
<!-- Config schema -->
|
||||||
<h2 id="config-schema" class="z-title is-2 mt-2 mb-1">Config schema</h2>
|
<h2 id="config-schema">Config schema</h2>
|
||||||
<b-collapse :open="false" class="card mt-1 mb-1">
|
<div :open="false" class="card mt-1 mb-1"> <!-- b-collapse -->
|
||||||
<div slot="trigger" slot-scope="props" class="card-header" role="button">
|
<div slot="trigger" slot-scope="props" class="card-header" role="button">
|
||||||
<p class="card-header-title">Click to expand</p>
|
<p class="card-header-title">Click to expand</p>
|
||||||
<a class="card-header-icon">
|
<a class="card-header-icon">
|
||||||
|
@ -133,23 +126,27 @@
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<CodeBlock lang="plain">{{ data.configSchema }}</CodeBlock>
|
<CodeBlock lang="plain">{{ data.configSchema }}</CodeBlock>
|
||||||
</div>
|
</div>
|
||||||
</b-collapse>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import {mapState} from "vuex";
|
import {mapState} from "vuex";
|
||||||
import yaml from "js-yaml";
|
import yaml from "js-yaml";
|
||||||
import CodeBlock from "./CodeBlock";
|
import CodeBlock from "./CodeBlock.vue";
|
||||||
import MarkdownBlock from "./MarkdownBlock";
|
import MarkdownBlock from "./MarkdownBlock.vue";
|
||||||
|
import Tabs from "../Tabs.vue";
|
||||||
|
import Tab from "../Tab.vue";
|
||||||
|
import Expandable from "../Expandable.vue";
|
||||||
|
import { DocsState } from "../../store/types";
|
||||||
|
|
||||||
const validTabs = ['usage', 'configuration'];
|
const validTabs = ['usage', 'configuration'];
|
||||||
const defaultTab = 'usage';
|
const defaultTab = 'usage';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { CodeBlock, MarkdownBlock },
|
components: { CodeBlock, MarkdownBlock, Tabs, Tab, Expandable },
|
||||||
|
|
||||||
async mounted() {
|
async mounted() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
@ -201,7 +198,7 @@
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState("docs", {
|
...mapState("docs", {
|
||||||
data(state) {
|
data(state: DocsState) {
|
||||||
return state.plugins[this.pluginName];
|
return state.plugins[this.pluginName];
|
||||||
},
|
},
|
||||||
hasUsageInfo() {
|
hasUsageInfo() {
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="z-title is-1 mb-1">Plugin configuration</h1>
|
<h1>Plugin configuration</h1>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Each plugin in Zeppelin has its own configuration options. In the config editor, you can both set the default config
|
Each plugin in Zeppelin has its own configuration options. In the config editor, you can both set the default config
|
||||||
and overrides based on specific conditions. Permissions are also just values in the plugin's config, and thus follow
|
and overrides based on specific conditions. Permissions are also just values in the plugin's config, and thus follow
|
||||||
the same rules with overrides etc. as other options (see <router-link to="/docs/permissions">Permissions</router-link> for more info).
|
the same rules with overrides etc. as other options (see <router-link to="/docs/permissions">Permissions</router-link> for more info).
|
||||||
</p>
|
</p>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Information about each plugin's options can be found on the plugin's page on the sidebar. See <router-link to="/docs/configuration-format">Configuration format</router-link> for an example of a full config.
|
Information about each plugin's options can be found on the plugin's page on the sidebar. See <router-link to="/docs/configuration-format">Configuration format</router-link> for an example of a full config.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 class="z-title is-2 mt-2 mb-1">Overrides</h2>
|
<h2>Overrides</h2>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Overrides are the primary mechanism of changing options and permissions based on permission levels, roles, channels, user ids, etc.
|
Overrides are the primary mechanism of changing options and permissions based on permission levels, roles, channels, user ids, etc.
|
||||||
</p>
|
</p>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
Here's an example demonstrating different types of overrides:
|
Here's an example demonstrating different types of overrides:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -74,8 +74,8 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import CodeBlock from "./CodeBlock";
|
import CodeBlock from "./CodeBlock.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { CodeBlock },
|
components: { CodeBlock },
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="z-title is-1 mb-1">Work in progress</h1>
|
<h1>Work in progress</h1>
|
||||||
<p class="mb-1">
|
<p>
|
||||||
This page is a work in progress.
|
This page is a work in progress.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
import Vue from "vue";
|
|
||||||
|
|
||||||
Vue.directive("trim-code", {
|
|
||||||
bind(el, binding) {
|
|
||||||
el.innerHTML = el.innerHTML
|
|
||||||
.replace(/(^\n+|\n+$)/g, "")
|
|
||||||
.split("\n")
|
|
||||||
.map(line => line.slice(binding.value))
|
|
||||||
.join("\n");
|
|
||||||
},
|
|
||||||
});
|
|
25
dashboard/src/directives/trim-indents.ts
Normal file
25
dashboard/src/directives/trim-indents.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import Vue from "vue";
|
||||||
|
|
||||||
|
Vue.directive("trim-indents", {
|
||||||
|
bind(el, binding) {
|
||||||
|
const withoutStartEndWhitespace = el.innerHTML.replace(/(^\n+|\n+$)/g, "");
|
||||||
|
|
||||||
|
const mode = binding.value != null ? binding.value : "start";
|
||||||
|
|
||||||
|
let spacesToTrim;
|
||||||
|
if (mode === "start") {
|
||||||
|
const match = withoutStartEndWhitespace.match(/^\s+/);
|
||||||
|
spacesToTrim = match ? match[0].length : 0;
|
||||||
|
} else if (mode === "end") {
|
||||||
|
const match = withoutStartEndWhitespace.match(/\s+$/);
|
||||||
|
spacesToTrim = match ? match[0].length : 0;
|
||||||
|
} else {
|
||||||
|
spacesToTrim = parseInt(mode, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
el.innerHTML = withoutStartEndWhitespace
|
||||||
|
.split("\n")
|
||||||
|
.map(line => line.slice(spacesToTrim))
|
||||||
|
.join("\n");
|
||||||
|
},
|
||||||
|
});
|
|
@ -8,8 +8,11 @@
|
||||||
<title>Zeppelin Dashboard</title>
|
<title>Zeppelin Dashboard</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<noscript>
|
||||||
|
<h1>Zeppelin</h1>
|
||||||
|
The Zeppelin dashboard requires JavaScript to load.
|
||||||
|
</noscript>
|
||||||
|
|
||||||
<script src="./main.ts"></script>
|
<div id="app"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
40
dashboard/src/init-vue.ts
Normal file
40
dashboard/src/init-vue.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import "./style/app.pcss";
|
||||||
|
|
||||||
|
import Vue from "vue";
|
||||||
|
|
||||||
|
import hljs from "highlight.js/lib/highlight.js";
|
||||||
|
import hljsYaml from "highlight.js/lib/languages/yaml.js";
|
||||||
|
import VueHighlightJS from "vue-highlightjs";
|
||||||
|
import "highlight.js/styles/ocean.css";
|
||||||
|
|
||||||
|
import { RootStore } from "./store";
|
||||||
|
import { router } from "./routes";
|
||||||
|
|
||||||
|
import "./directives/trim-indents";
|
||||||
|
|
||||||
|
import App from "./components/App.vue";
|
||||||
|
|
||||||
|
// Set up a read-only global variable to access specific env vars
|
||||||
|
Vue.mixin({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
get env() {
|
||||||
|
return Object.freeze({
|
||||||
|
API_URL: process.env.API_URL,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
hljs.registerLanguage("yaml", hljsYaml);
|
||||||
|
Vue.use(VueHighlightJS, { hljs });
|
||||||
|
|
||||||
|
const app = new Vue({
|
||||||
|
router,
|
||||||
|
store: RootStore,
|
||||||
|
el: "#app",
|
||||||
|
render(h) {
|
||||||
|
return h(App);
|
||||||
|
},
|
||||||
|
});
|
|
@ -1,29 +1,32 @@
|
||||||
import "./style/base.scss";
|
import "./style/initial.pcss";
|
||||||
|
const splashHtml = require("./splash.html");
|
||||||
|
|
||||||
import Vue from "vue";
|
if (window.location.pathname !== "/") {
|
||||||
import { RootStore } from "./store";
|
import("./init-vue");
|
||||||
import { router } from "./routes";
|
} else {
|
||||||
|
// @ts-ignore
|
||||||
|
document.querySelector("#app").innerHTML = splashHtml;
|
||||||
|
|
||||||
// Set up a read-only global variable to access specific env vars
|
const queryParams: any = window.location.search
|
||||||
Vue.mixin({
|
.slice(1)
|
||||||
data() {
|
.split("&")
|
||||||
return {
|
.reduce((map, str) => {
|
||||||
get env() {
|
const pair = str.split("=");
|
||||||
return Object.freeze({
|
map[pair[0]] = pair[1];
|
||||||
API_URL: process.env.API_URL,
|
return map;
|
||||||
});
|
}, {});
|
||||||
},
|
|
||||||
|
if (queryParams.error) {
|
||||||
|
const errorElement = document.querySelector("#error") as HTMLElement;
|
||||||
|
errorElement.classList.add("has-error");
|
||||||
|
|
||||||
|
const errorMessages = {
|
||||||
|
noAccess: "No dashboard access. If you think this is a mistake, please contact your server owner.",
|
||||||
};
|
};
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
import App from "./components/App.vue";
|
const errorMessageElem = document.createElement("div");
|
||||||
|
errorMessageElem.classList.add("message");
|
||||||
const app = new Vue({
|
errorMessageElem.innerText = errorMessages[queryParams.error] || "Unexpected error";
|
||||||
router,
|
errorElement.appendChild(errorMessageElem);
|
||||||
store: RootStore,
|
}
|
||||||
el: "#app",
|
}
|
||||||
render(h) {
|
|
||||||
return h(App);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import VueRouter, { RouteConfig } from "vue-router";
|
import VueRouter, { RouteConfig } from "vue-router";
|
||||||
import Splash from "./components/Splash.vue";
|
|
||||||
import { authGuard, authRedirectGuard, loginCallbackGuard } from "./auth";
|
import { authGuard, authRedirectGuard, loginCallbackGuard } from "./auth";
|
||||||
|
|
||||||
Vue.use(VueRouter);
|
Vue.use(VueRouter);
|
||||||
|
@ -8,7 +7,6 @@ Vue.use(VueRouter);
|
||||||
export const router = new VueRouter({
|
export const router = new VueRouter({
|
||||||
mode: "history",
|
mode: "history",
|
||||||
routes: [
|
routes: [
|
||||||
{ path: "/", component: Splash },
|
|
||||||
{ path: "/login", beforeEnter: authRedirectGuard },
|
{ path: "/login", beforeEnter: authRedirectGuard },
|
||||||
{ path: "/login-callback", beforeEnter: loginCallbackGuard },
|
{ path: "/login-callback", beforeEnter: loginCallbackGuard },
|
||||||
|
|
||||||
|
|
18
dashboard/src/splash.html
Normal file
18
dashboard/src/splash.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<div class="splash">
|
||||||
|
<div id="error"></div>
|
||||||
|
<div class="wrapper">
|
||||||
|
<div class="logo-column">
|
||||||
|
<img class="logo" src="./img/logo.png" alt="Zeppelin Logo">
|
||||||
|
</div>
|
||||||
|
<div class="info-column">
|
||||||
|
<h1>Zeppelin</h1>
|
||||||
|
<div class="description">
|
||||||
|
Zeppelin is a private moderation bot for Discord, designed with large servers and reliability in mind.
|
||||||
|
</div>
|
||||||
|
<div class="actions">
|
||||||
|
<a class="btn" href="/login">Dashboard</a>
|
||||||
|
<a class="btn" href="/docs">Documentation</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
18
dashboard/src/style/app.pcss
Normal file
18
dashboard/src/style/app.pcss
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
@import "~tailwindcss/base.css";
|
||||||
|
@import "~tailwindcss/components.css";
|
||||||
|
@import "~tailwindcss/utilities.css";
|
||||||
|
|
||||||
|
@import "~vue-material-design-icons/styles.css";
|
||||||
|
|
||||||
|
@import "components.pcss";
|
||||||
|
|
||||||
|
@import "docs.pcss";
|
||||||
|
|
||||||
|
body {
|
||||||
|
overflow-y: scroll;
|
||||||
|
|
||||||
|
@apply bg-gray-900;
|
||||||
|
@apply text-gray-300;
|
||||||
|
@apply text-base;
|
||||||
|
@apply p-4;
|
||||||
|
}
|
4
dashboard/src/style/base.pcss
Normal file
4
dashboard/src/style/base.pcss
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
body {
|
||||||
|
font: normal 18px/1.5 sans-serif;
|
||||||
|
font-family: system, -apple-system, ".SFNSText-Regular", "San Francisco", "Roboto", "Segoe UI", "Helvetica Neue", "Lucida Grande", sans-serif;
|
||||||
|
}
|
|
@ -1,6 +0,0 @@
|
||||||
@import url('https://fonts.googleapis.com/css?family=Open+Sans:300,400,600&display=swap');
|
|
||||||
@import "~bulma/sass/base/minireset";
|
|
||||||
|
|
||||||
body {
|
|
||||||
font: normal 16px/1.4 'Open Sans', sans-serif;
|
|
||||||
}
|
|
21
dashboard/src/style/components.pcss
Normal file
21
dashboard/src/style/components.pcss
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
.inline-code {
|
||||||
|
@apply inline-block;
|
||||||
|
@apply bg-gray-800;
|
||||||
|
@apply px-1;
|
||||||
|
@apply rounded;
|
||||||
|
@apply text-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.codeblock {
|
||||||
|
@apply bg-gray-800;
|
||||||
|
@apply p-3;
|
||||||
|
@apply mb-4;
|
||||||
|
@apply rounded;
|
||||||
|
@apply text-sm;
|
||||||
|
@apply shadow-md;
|
||||||
|
|
||||||
|
& .hljs {
|
||||||
|
@apply bg-transparent;
|
||||||
|
@apply p-0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,78 @@
|
||||||
|
@import "~buefy/dist/buefy.css";
|
||||||
|
@import "~highlight.js/styles/ocean.css";
|
||||||
|
|
||||||
|
$bulmaswatch-import-font: false;
|
||||||
$family-primary: 'Open Sans', sans-serif;
|
$family-primary: 'Open Sans', sans-serif;
|
||||||
|
$list-background-color: transparent;
|
||||||
|
|
||||||
|
$size-1: 2.5rem;
|
||||||
|
$size-2: 2rem;
|
||||||
|
$size-3: 1.5rem;
|
||||||
|
$size-4: 1.25rem;
|
||||||
|
|
||||||
@import "~bulmaswatch/superhero/_variables";
|
@import "~bulmaswatch/superhero/_variables";
|
||||||
|
|
||||||
|
$tabs-link-color: $grey-light;
|
||||||
|
$tabs-link-active-color: $grey-lighter;
|
||||||
|
$tabs-link-active-border-bottom-color: $grey-lighter;
|
||||||
|
|
||||||
@import "~bulma/bulma";
|
@import "~bulma/bulma";
|
||||||
@import "~bulmaswatch/superhero/_overrides";
|
@import "~bulmaswatch/superhero/_overrides";
|
||||||
|
|
||||||
.dashboard-cloak {
|
|
||||||
|
.init-cloak {
|
||||||
visibility: visible !important;
|
visibility: visible !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.z-title {
|
||||||
|
line-height: 1.125;
|
||||||
|
|
||||||
|
&.is-1 { font-size: $size-1; }
|
||||||
|
&.is-2 { font-size: $size-2; }
|
||||||
|
&.is-3 { font-size: $size-3; }
|
||||||
|
&.is-4 { font-size: $size-4; }
|
||||||
|
&.is-5 { font-size: $size-5; }
|
||||||
|
&.is-6 { font-size: $size-6; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.z-list {
|
||||||
|
margin-left: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.z-ul {
|
||||||
|
list-style: disc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-1 { margin-top: 1rem; }
|
||||||
|
.mt-2 { margin-top: 1.5rem; }
|
||||||
|
.mt-3 { margin-top: 2rem; }
|
||||||
|
|
||||||
|
.mb-1 { margin-bottom: 1rem; }
|
||||||
|
.mb-2 { margin-bottom: 1.5rem; }
|
||||||
|
.mb-3 { margin-bottom: 2rem; }
|
||||||
|
|
||||||
|
.codeblock,
|
||||||
|
.content .codeblock {
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 16px;
|
||||||
|
max-width: 970px; /* FIXME: temp fix for overflowing code blocks, look into properly later */
|
||||||
|
}
|
||||||
|
|
||||||
|
.codeblock .hljs {
|
||||||
|
background: transparent;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-label {
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-top: 1.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-bottom: 0.4em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-list .router-link-active {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
60
dashboard/src/style/docs.pcss
Normal file
60
dashboard/src/style/docs.pcss
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
.docs-sidebar {
|
||||||
|
& .router-link-active {
|
||||||
|
@apply underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-content {
|
||||||
|
& h1 {
|
||||||
|
@apply text-5xl;
|
||||||
|
@apply font-semibold;
|
||||||
|
@apply leading-none;
|
||||||
|
@apply pb-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
& h2 {
|
||||||
|
@apply text-2xl;
|
||||||
|
@apply font-semibold;
|
||||||
|
@apply pt-2;
|
||||||
|
@apply pb-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
& h3 {
|
||||||
|
@apply font-semibold;
|
||||||
|
@apply pb-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
& p {
|
||||||
|
@apply pb-4;
|
||||||
|
|
||||||
|
& code {
|
||||||
|
@apply inline-code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& a:not([class]) {
|
||||||
|
@apply text-blue-400;
|
||||||
|
@apply underline;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
@apply text-blue-200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& ul:not([class]) {
|
||||||
|
@apply list-disc;
|
||||||
|
@apply mb-4;
|
||||||
|
|
||||||
|
& li {
|
||||||
|
@apply ml-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
& code {
|
||||||
|
@apply inline-code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .expandable {
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,77 +0,0 @@
|
||||||
@import url('https://cdn.materialdesignicons.com/2.5.94/css/materialdesignicons.min.css');
|
|
||||||
|
|
||||||
$bulmaswatch-import-font: false;
|
|
||||||
$family-primary: 'Open Sans', sans-serif;
|
|
||||||
$list-background-color: transparent;
|
|
||||||
|
|
||||||
$size-1: 2.5rem;
|
|
||||||
$size-2: 2rem;
|
|
||||||
$size-3: 1.5rem;
|
|
||||||
$size-4: 1.25rem;
|
|
||||||
|
|
||||||
@import "~bulmaswatch/superhero/_variables";
|
|
||||||
|
|
||||||
$tabs-link-color: $grey-light;
|
|
||||||
$tabs-link-active-color: $grey-lighter;
|
|
||||||
$tabs-link-active-border-bottom-color: $grey-lighter;
|
|
||||||
|
|
||||||
@import "~bulma/bulma";
|
|
||||||
@import "~bulmaswatch/superhero/_overrides";
|
|
||||||
|
|
||||||
|
|
||||||
.docs-cloak {
|
|
||||||
visibility: visible !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.z-title {
|
|
||||||
line-height: 1.125;
|
|
||||||
|
|
||||||
&.is-1 { font-size: $size-1; }
|
|
||||||
&.is-2 { font-size: $size-2; }
|
|
||||||
&.is-3 { font-size: $size-3; }
|
|
||||||
&.is-4 { font-size: $size-4; }
|
|
||||||
&.is-5 { font-size: $size-5; }
|
|
||||||
&.is-6 { font-size: $size-6; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.z-list {
|
|
||||||
margin-left: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.z-ul {
|
|
||||||
list-style: disc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mt-1 { margin-top: 1rem; }
|
|
||||||
.mt-2 { margin-top: 1.5rem; }
|
|
||||||
.mt-3 { margin-top: 2rem; }
|
|
||||||
|
|
||||||
.mb-1 { margin-bottom: 1rem; }
|
|
||||||
.mb-2 { margin-bottom: 1.5rem; }
|
|
||||||
.mb-3 { margin-bottom: 2rem; }
|
|
||||||
|
|
||||||
.codeblock,
|
|
||||||
.content .codeblock {
|
|
||||||
border-radius: 3px;
|
|
||||||
padding: 16px;
|
|
||||||
max-width: 970px; /* FIXME: temp fix for overflowing code blocks, look into properly later */
|
|
||||||
}
|
|
||||||
|
|
||||||
.codeblock .hljs {
|
|
||||||
background: transparent;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-label {
|
|
||||||
&:not(:first-child) {
|
|
||||||
margin-top: 1.4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(:last-child) {
|
|
||||||
margin-bottom: 0.4em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-list .router-link-active {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
@import url("https://cdn.materialdesignicons.com/2.5.94/css/materialdesignicons.min.css");
|
|
3
dashboard/src/style/initial.pcss
Normal file
3
dashboard/src/style/initial.pcss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
@import "./reset.pcss";
|
||||||
|
@import "./base.pcss";
|
||||||
|
@import "./splash.pcss";
|
48
dashboard/src/style/reset.pcss
Normal file
48
dashboard/src/style/reset.pcss
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/* Box sizing rules */
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove default padding */
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove default margin */
|
||||||
|
body,
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
p,
|
||||||
|
ul,
|
||||||
|
ol,
|
||||||
|
li,
|
||||||
|
figure,
|
||||||
|
figcaption,
|
||||||
|
blockquote,
|
||||||
|
dl,
|
||||||
|
dd {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inherit fonts for inputs and buttons */
|
||||||
|
input,
|
||||||
|
button,
|
||||||
|
textarea,
|
||||||
|
select {
|
||||||
|
font: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove all animations and transitions for people that prefer not to see them */
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
* {
|
||||||
|
animation-duration: 0.01ms !important;
|
||||||
|
animation-iteration-count: 1 !important;
|
||||||
|
transition-duration: 0.01ms !important;
|
||||||
|
scroll-behavior: auto !important;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,58 +1,82 @@
|
||||||
.splash {
|
.splash {
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
background-color: #7289da;
|
background-color: #7289da;
|
||||||
background-image: linear-gradient(225deg, #7289da 0%, #5d70b4 100%);
|
background-image: linear-gradient(225deg, #7289da 0%, #5d70b4 100%);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: flex-start;
|
||||||
align-items: flex-start;
|
align-items: center;
|
||||||
|
|
||||||
a {
|
& a {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrapper {
|
& > #error {
|
||||||
flex: 0 1 750px;
|
width: 100%;
|
||||||
|
max-width: 750px;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
&.has-error {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .message {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
text-align: left;
|
||||||
|
padding: 8px 12px;
|
||||||
|
background-color: #404040;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 3px 12px -2px hsla(0, 0%, 0%, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .wrapper {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
|
||||||
|
width: 750px;
|
||||||
|
max-width: 100%;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: start;
|
align-items: flex-start;
|
||||||
|
|
||||||
.logo-column {
|
& .logo-column {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-column {
|
& .info-column {
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
& .logo {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
height: 300px;
|
height: 300px;
|
||||||
margin-right: 64px;
|
margin-right: 48px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
& h1 {
|
||||||
font-size: 80px;
|
font-size: 80px;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
margin-top: 40px
|
margin-top: 40px
|
||||||
}
|
}
|
||||||
|
|
||||||
.description {
|
& .description {
|
||||||
color: #f1f5ff;
|
color: #f1f5ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
& .actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
margin-left: -12px; // Negative button margin
|
margin-left: -12px;
|
||||||
|
|
||||||
.btn {
|
& .btn {
|
||||||
margin: 12px;
|
margin: 12px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
padding: 8px 24px;
|
padding: 8px 24px;
|
||||||
|
@ -73,7 +97,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
& .error {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
background-color: hsl(224, 52%, 32%);
|
background-color: hsl(224, 52%, 32%);
|
||||||
padding: 12px;
|
padding: 12px;
|
7
dashboard/tailwind.config.js
Normal file
7
dashboard/tailwind.config.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
module.exports = {
|
||||||
|
theme: {
|
||||||
|
extend: {}
|
||||||
|
},
|
||||||
|
variants: {},
|
||||||
|
plugins: []
|
||||||
|
}
|
|
@ -2,28 +2,20 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
|
"target": "esnext",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"target": "esnext",
|
"strict": false,
|
||||||
"strict": true,
|
|
||||||
"lib": [
|
"lib": [
|
||||||
"es2017",
|
|
||||||
"esnext",
|
"esnext",
|
||||||
"dom"
|
"dom"
|
||||||
],
|
],
|
||||||
"baseUrl": "./",
|
"baseUrl": ".",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"outDir": "./dist"
|
"allowJs": true
|
||||||
},
|
}
|
||||||
"include": [
|
|
||||||
"src/**/*.ts",
|
|
||||||
"src/**/*.vue"
|
|
||||||
],
|
|
||||||
"files": [
|
|
||||||
"ts-vue-shim.d.ts"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
169
dashboard/webpack.config.js
Normal file
169
dashboard/webpack.config.js
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const DotenvPlugin = require('dotenv-webpack');
|
||||||
|
const merge = require('webpack-merge');
|
||||||
|
|
||||||
|
const targetDir = path.normalize(path.join(__dirname, 'dist'));
|
||||||
|
|
||||||
|
if (! process.env.NODE_ENV) {
|
||||||
|
console.error('Please set NODE_ENV');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const babelOpts = {
|
||||||
|
presets: [
|
||||||
|
'@babel/preset-env',
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
let config = {
|
||||||
|
entry: './src/main.ts',
|
||||||
|
output: {
|
||||||
|
filename: '[name].[hash].js',
|
||||||
|
path: targetDir,
|
||||||
|
publicPath: '/',
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
// Vue / Babel / Typescript
|
||||||
|
{
|
||||||
|
test: /\.vue$/,
|
||||||
|
use: ["vue-loader"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.tsx?$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'babel-loader',
|
||||||
|
options: babelOpts,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: 'ts-loader',
|
||||||
|
options: {
|
||||||
|
appendTsSuffixTo: [/\.vue$/],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.m?js$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: {
|
||||||
|
loader: 'babel-loader',
|
||||||
|
options: babelOpts,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
use: ["source-map-loader"],
|
||||||
|
enforce: "pre",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Stylesheets
|
||||||
|
{
|
||||||
|
test: /\.p?css$/,
|
||||||
|
use: [
|
||||||
|
"vue-style-loader",
|
||||||
|
{
|
||||||
|
loader: "css-loader",
|
||||||
|
options: {
|
||||||
|
importLoaders: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: "postcss-loader",
|
||||||
|
options: {
|
||||||
|
ident: "postcss",
|
||||||
|
plugins: loader => {
|
||||||
|
const plugins = [
|
||||||
|
require('postcss-import')({
|
||||||
|
resolve(id, base, options) {
|
||||||
|
// Since WebStorm doesn't resolve imports from node_modules without a tilde (~) prefix,
|
||||||
|
// strip the tilde here to get the best of both worlds (webstorm support + postcss-import support)
|
||||||
|
if (id[0] === '~') id = id.slice(1);
|
||||||
|
// Call the original resolver after stripping the tilde
|
||||||
|
return require('postcss-import/lib/resolve-id')(id, base, options);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
require('postcss-nesting')(),
|
||||||
|
require('tailwindcss')(),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === "production") {
|
||||||
|
plugins.push(
|
||||||
|
require('postcss-preset-env')(),
|
||||||
|
require('cssnano')(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return plugins;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// Images/files
|
||||||
|
{
|
||||||
|
test: /\.(png|jpg)$/i,
|
||||||
|
use: ["file-loader"],
|
||||||
|
},
|
||||||
|
|
||||||
|
// HTML
|
||||||
|
{
|
||||||
|
test: /\.html$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: "html-loader",
|
||||||
|
options: {
|
||||||
|
root: path.resolve(__dirname, 'src'),
|
||||||
|
attrs: ['img:src', 'link:href'],
|
||||||
|
...(process.env.NODE_ENV === 'production' && {
|
||||||
|
minimize: true,
|
||||||
|
removeComments: true,
|
||||||
|
collapseWhitespace: true,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new VueLoaderPlugin(),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: 'src/index.html',
|
||||||
|
files: {
|
||||||
|
"css": ["./src/style/initial.pcss"],
|
||||||
|
"js": ["./src/main.ts"],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
new DotenvPlugin(),
|
||||||
|
],
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.ts', '.tsx', '.js', '.mjs', '.vue'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
config = merge(config, {
|
||||||
|
mode: 'production',
|
||||||
|
devtool: 'source-map',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
config = merge(config, {
|
||||||
|
mode: 'development',
|
||||||
|
devtool: 'eval',
|
||||||
|
devServer: {
|
||||||
|
...(process.env.DEV_HOST ? { host: process.env.DEV_HOST } : undefined),
|
||||||
|
historyApiFallback: true,
|
||||||
|
port: 1234,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = config;
|
|
@ -117,7 +117,7 @@ export function initAuth(app: express.Express) {
|
||||||
if (req.user && req.user.apiKey) {
|
if (req.user && req.user.apiKey) {
|
||||||
res.redirect(`${process.env.DASHBOARD_URL}/login-callback/?apiKey=${req.user.apiKey}`);
|
res.redirect(`${process.env.DASHBOARD_URL}/login-callback/?apiKey=${req.user.apiKey}`);
|
||||||
} else {
|
} else {
|
||||||
res.redirect(`${process.env.DASHBOARD_URL}/login-callback/?error=noaccess`);
|
res.redirect(`${process.env.DASHBOARD_URL}/login-callback/?error=noAccess`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Reference in a new issue