mirror of
https://github.com/ZeppelinBot/Zeppelin.git
synced 2025-07-06 10:37:19 +00:00
Merge branch 'dashboard-vite'
This commit is contained in:
commit
f4d728ea25
47 changed files with 1345 additions and 9763 deletions
|
@ -5,5 +5,12 @@
|
||||||
|
|
||||||
"service": "devenv",
|
"service": "devenv",
|
||||||
"remoteUser": "ubuntu",
|
"remoteUser": "ubuntu",
|
||||||
"workspaceFolder": "/workspace/zeppelin"
|
"workspaceFolder": "/workspace/zeppelin",
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"Vue.volar"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,6 @@
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"deep-diff": "^1.0.2",
|
"deep-diff": "^1.0.2",
|
||||||
"discord.js": "^14.19.3",
|
"discord.js": "^14.19.3",
|
||||||
"dotenv": "^4.0.0",
|
|
||||||
"emoji-regex": "^8.0.0",
|
"emoji-regex": "^8.0.0",
|
||||||
"escape-string-regexp": "^1.0.5",
|
"escape-string-regexp": "^1.0.5",
|
||||||
"express": "^4.20.0",
|
"express": "^4.20.0",
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
collapseWhitespace: false,
|
|
||||||
};
|
|
|
@ -14,7 +14,10 @@
|
||||||
<h1>Zeppelin</h1>
|
<h1>Zeppelin</h1>
|
||||||
The Zeppelin website requires JavaScript to load.
|
The Zeppelin website requires JavaScript to load.
|
||||||
</noscript>
|
</noscript>
|
||||||
|
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/env.js"></script>
|
||||||
|
<script type="module" src="./src/index.ts"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -3,54 +3,37 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rimraf dist && cross-env NODE_ENV=production webpack --config webpack.config.js",
|
"dev": "vite",
|
||||||
"build-debug": "rimraf dist && cross-env NODE_ENV=development webpack --config webpack.config.js",
|
"build": "vite build",
|
||||||
"watch": "cross-env NODE_ENV=development webpack-dev-server"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.22.5",
|
"@tailwindcss/vite": "^4.1.8",
|
||||||
"@babel/preset-env": "^7.22.5",
|
"@vitejs/plugin-vue": "^5.2.4",
|
||||||
"@babel/preset-typescript": "^7.22.5",
|
"@vue/tsconfig": "^0.7.0",
|
||||||
"babel-loader": "^9.1.2",
|
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"css-loader": "^6.8.1",
|
|
||||||
"cssnano": "^4.1.10",
|
|
||||||
"dotenv": "^16.4.5",
|
|
||||||
"file-loader": "^6.2.0",
|
|
||||||
"html-loader": "^4.2.0",
|
|
||||||
"html-webpack-plugin": "^5.5.3",
|
|
||||||
"postcss-import": "^15.1.0",
|
|
||||||
"postcss-loader": "^7.3.3",
|
|
||||||
"postcss-nesting": "^11.3.0",
|
|
||||||
"postcss-preset-env": "^8.5.1",
|
|
||||||
"source-map-loader": "^4.0.1",
|
|
||||||
"tailwindcss": "^1.9.6",
|
|
||||||
"ts-loader": "^9.4.3",
|
|
||||||
"vue-loader": "^17.4.2",
|
|
||||||
"vue-style-loader": "^4.1.3",
|
|
||||||
"vue-template-compiler": "^2.7.14",
|
|
||||||
"webpack": "^5.94.0",
|
|
||||||
"webpack-cli": "^5.1.4",
|
|
||||||
"webpack-dev-server": "^4.15.1",
|
|
||||||
"webpack-merge": "^5.9.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@fastify/static": "^7.0.1",
|
|
||||||
"fastify": "^4.26.2",
|
|
||||||
"highlight.js": "^11.8.0",
|
"highlight.js": "^11.8.0",
|
||||||
"humanize-duration": "^3.27.0",
|
"humanize-duration": "^3.27.0",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"marked": "^5.1.0",
|
"marked": "^5.1.0",
|
||||||
"modern-css-reset": "^1.4.0",
|
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
|
"postcss-nesting": "^13.0.1",
|
||||||
|
"tailwindcss": "^4.1.8",
|
||||||
|
"vite": "npm:rolldown-vite@latest",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-material-design-icons": "^5.3.1",
|
"vue-material-design-icons": "^5.3.1",
|
||||||
"vue-router": "^4.5.0",
|
"vue-router": "^4.5.0",
|
||||||
|
"vue-tsc": "^2.2.10",
|
||||||
"vue3-ace-editor": "^2.2.4",
|
"vue3-ace-editor": "^2.2.4",
|
||||||
"vue3-highlightjs": "^1.0.5",
|
"vue3-highlightjs": "^1.0.5",
|
||||||
"vuex": "^4.1.0"
|
"vuex": "^4.1.0"
|
||||||
},
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@fastify/static": "^7.0.1",
|
||||||
|
"fastify": "^4.26.2"
|
||||||
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"last 2 Chrome versions"
|
"last 2 Chrome versions"
|
||||||
]
|
]
|
||||||
|
|
8
dashboard/postcss.config.js
Normal file
8
dashboard/postcss.config.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import nesting from "postcss-nesting";
|
||||||
|
|
||||||
|
/** @type {import('postcss-load-config').Config} */
|
||||||
|
const config = {
|
||||||
|
plugins: [nesting]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default config;
|
2
dashboard/public/env.js
Normal file
2
dashboard/public/env.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
// Don't edit this directly, it uses env vars in prod via serve.js
|
||||||
|
window.API_URL = "/api";
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
@ -1,9 +1,22 @@
|
||||||
const fastify = require("fastify")({ logger: true });
|
import Fastify from "fastify";
|
||||||
const fastifyStatic = require("@fastify/static");
|
import fastifyStatic from "@fastify/static";
|
||||||
const path = require("path");
|
import path from "node:path";
|
||||||
|
|
||||||
|
const fastify = Fastify({
|
||||||
|
// We already get logs from nginx, so disable here
|
||||||
|
logger: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
fastify.addHook("preHandler", (req, reply, done) => {
|
||||||
|
if (req.url === "/env.js") {
|
||||||
|
reply.header("Content-Type", "application/javascript; charset=utf8");
|
||||||
|
reply.send(`window.API_URL = ${JSON.stringify(process.env.API_URL)};`);
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
fastify.register(fastifyStatic, {
|
fastify.register(fastifyStatic, {
|
||||||
root: path.join(__dirname, "dist"),
|
root: path.join(import.meta.dirname, "dist"),
|
||||||
wildcard: false,
|
wildcard: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { RootStore } from "./store";
|
import { RootStore } from "./store";
|
||||||
const apiUrl = process.env.API_URL;
|
|
||||||
|
|
||||||
type QueryParamObject = { [key: string]: string | null };
|
type QueryParamObject = { [key: string]: string | null };
|
||||||
|
|
||||||
|
@ -28,7 +27,7 @@ function buildQueryString(params: QueryParamObject) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function request(resource, fetchOpts: RequestInit = {}) {
|
export function request(resource, fetchOpts: RequestInit = {}) {
|
||||||
return fetch(`${apiUrl}/${resource}`, fetchOpts).then(async (res) => {
|
return fetch(`${window.API_URL}/${resource}`, fetchOpts).then(async (res) => {
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
if (res.status === 401) {
|
if (res.status === 401) {
|
||||||
RootStore.dispatch("auth/expiredLogin");
|
RootStore.dispatch("auth/expiredLogin");
|
||||||
|
@ -74,7 +73,7 @@ type FormPostOpts = {
|
||||||
export function formPost(resource: string, body: Record<any, any> = {}, opts: FormPostOpts = {}) {
|
export function formPost(resource: string, body: Record<any, any> = {}, opts: FormPostOpts = {}) {
|
||||||
body["X-Api-Key"] = RootStore.state.auth.apiKey;
|
body["X-Api-Key"] = RootStore.state.auth.apiKey;
|
||||||
const form = document.createElement("form");
|
const form = document.createElement("form");
|
||||||
form.action = `${apiUrl}/${resource}`;
|
form.action = `${window.API_URL}/${resource}`;
|
||||||
form.method = "POST";
|
form.method = "POST";
|
||||||
form.enctype = "multipart/form-data";
|
form.enctype = "multipart/form-data";
|
||||||
if (opts.target != null) {
|
if (opts.target != null) {
|
||||||
|
|
|
@ -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();
|
||||||
window.location.href = `${process.env.API_URL}/auth/login`;
|
window.location.href = `${window.API_URL}/auth/login`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const loginCallbackGuard: NavigationGuard = async (to, from, next) => {
|
export const loginCallbackGuard: NavigationGuard = async (to, from, next) => {
|
||||||
|
@ -26,6 +26,6 @@ export const loginCallbackGuard: NavigationGuard = async (to, from, next) => {
|
||||||
|
|
||||||
export const authRedirectGuard: NavigationGuard = async (to, form, next) => {
|
export const authRedirectGuard: NavigationGuard = async (to, form, next) => {
|
||||||
if (await isAuthenticated()) return next("/dashboard");
|
if (await isAuthenticated()) return next("/dashboard");
|
||||||
window.location.href = `${process.env.API_URL}/auth/login`;
|
window.location.href = `${window.API_URL}/auth/login`;
|
||||||
return next();
|
return next();
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@import "../style/components.pcss";
|
@reference "../style/app.css";
|
||||||
|
|
||||||
.expandable {
|
.expandable {
|
||||||
--animation-time: 400ms;
|
--animation-time: 400ms;
|
||||||
|
|
|
@ -87,6 +87,6 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script type="ts">
|
<script type="ts">
|
||||||
import "../style/privacy-policy.pcss";
|
import "../style/privacy-policy.css";
|
||||||
export default {};
|
export default {};
|
||||||
</script>
|
</script>
|
||||||
|
|
53
dashboard/src/components/Splash.vue
Normal file
53
dashboard/src/components/Splash.vue
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<template>
|
||||||
|
<div class="splash">
|
||||||
|
<div class="error" v-if="error">
|
||||||
|
<div class="message">{{ error }}</div>
|
||||||
|
</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="/dashboard">Dashboard</a>
|
||||||
|
<a class="btn" href="/docs">Documentation</a>
|
||||||
|
</div>
|
||||||
|
<ul class="links">
|
||||||
|
<li>
|
||||||
|
<a href="https://discord.gg/zeppelin">Official Discord Server</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://github.com/Dragory/ZeppelinBot">GitHub</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/privacy-policy">Privacy Policy</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
const errorMessages = {
|
||||||
|
noAccess: "No dashboard access. If you think this is a mistake, please contact your server owner.",
|
||||||
|
expiredLogin: "Dashboard login expired. Please log in again.",
|
||||||
|
};
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const error = ref<string | null>(null);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.query.error,
|
||||||
|
(value) => {
|
||||||
|
error.value = errorMessages[String(value)] || null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
</script>
|
|
@ -5,6 +5,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@reference "../style/app.css";
|
||||||
|
|
||||||
li {
|
li {
|
||||||
padding-bottom: 1px;
|
padding-bottom: 1px;
|
||||||
|
|
||||||
|
@ -26,7 +28,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.active a {
|
.active :deep(a) {
|
||||||
@apply text-gray-200;
|
@apply text-gray-200;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
lang="yaml"
|
lang="yaml"
|
||||||
theme="tomorrow_night"
|
theme="tomorrow_night"
|
||||||
ref="aceEditor"
|
ref="aceEditor"
|
||||||
v-options="{
|
:options="{
|
||||||
useSoftTabs: true,
|
useSoftTabs: true,
|
||||||
tabSize: 2
|
tabSize: 2
|
||||||
}"
|
}"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<div>
|
<div>
|
||||||
<h1>Guild Info</h1>
|
<h1>Guild Info</h1>
|
||||||
<p>
|
<p>
|
||||||
<img class="inline-block w-16 mr-4" style="vertical-align: -20px" src="../../img/squint.png"> What are you doing here
|
<img class="inline-block w-16 mr-4" style="vertical-align: -20px" src="/img/squint.png"> What are you doing here
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
<nav class="flex items-stretch flex-wrap pl-4 pr-2 py-1 border border-gray-700 rounded bg-gray-800 shadow-xl mb-8">
|
<nav class="flex items-stretch flex-wrap pl-4 pr-2 py-1 border border-gray-700 rounded bg-gray-800 shadow-xl mb-8">
|
||||||
<div class="flex-full md:flex-initial flex items-center">
|
<div class="flex-full md:flex-initial flex items-center">
|
||||||
<img class="w-10 mr-5" :src="logoUrl" alt="" aria-hidden="true">
|
<img class="w-10 mr-5" src="/img/logo.png" alt="" aria-hidden="true">
|
||||||
|
|
||||||
<router-link to="/dashboard">
|
<router-link to="/dashboard">
|
||||||
<h1 class="font-semibold">Zeppelin Dashboard</h1>
|
<h1 class="font-semibold">Zeppelin Dashboard</h1>
|
||||||
|
@ -48,7 +48,6 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Title from "../Title.vue";
|
import Title from "../Title.vue";
|
||||||
import logoUrl from "../../img/logo.png";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -60,8 +59,5 @@
|
||||||
window.location.pathname = '/';
|
window.location.pathname = '/';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
|
||||||
return { logoUrl };
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -104,8 +104,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import CodeBlock from "./CodeBlock";
|
import CodeBlock from "./CodeBlock.vue";
|
||||||
import Expandable from "../Expandable";
|
import Expandable from "../Expandable.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -346,8 +346,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import CodeBlock from "./CodeBlock";
|
import CodeBlock from "./CodeBlock.vue";
|
||||||
import Expandable from "../Expandable";
|
import Expandable from "../Expandable.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { CodeBlock, Expandable },
|
components: { CodeBlock, Expandable },
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<!-- Top bar -->
|
<!-- Top bar -->
|
||||||
<nav class="flex items-stretch pl-4 pr-2 py-1 border border-gray-700 rounded bg-gray-800 shadow-xl">
|
<nav class="flex items-stretch pl-4 pr-2 py-1 border border-gray-700 rounded bg-gray-800 shadow-xl">
|
||||||
<div class="flex-initial flex items-center">
|
<div class="flex-initial flex items-center">
|
||||||
<img class="flex-auto w-10 mr-5" :src="logoUrl" alt="" aria-hidden="true">
|
<img class="flex-auto w-10 mr-5" src="/img/logo.png" alt="" aria-hidden="true">
|
||||||
|
|
||||||
<router-link to="/docs">
|
<router-link to="/docs">
|
||||||
<h1 class="flex-auto font-semibold">Zeppelin Documentation</h1>
|
<h1 class="flex-auto font-semibold">Zeppelin Documentation</h1>
|
||||||
|
@ -27,9 +27,9 @@
|
||||||
<a class="sr-only-when-not-focused text-center block py-2" href="#main-anchor">Skip to main content</a>
|
<a class="sr-only-when-not-focused text-center block py-2" href="#main-anchor">Skip to main content</a>
|
||||||
|
|
||||||
<!-- Content wrapper -->
|
<!-- Content wrapper -->
|
||||||
<div class="flex flex-wrap items-start mt-8">
|
<div class="flex flex-wrap lg:flex-nowrap items-start mt-8 gap-8">
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<nav class="docs-sidebar px-4 pt-2 pb-3 mr-8 mb-4 border border-gray-700 rounded bg-gray-800 shadow-md flex-full lg:flex-none lg:block" v-bind:class="{ closed: !mobileMenuOpen }">
|
<nav class="docs-sidebar px-4 pt-2 pb-3 border border-gray-700 rounded bg-gray-800 shadow-md flex-full lg:flex-none lg:block" v-bind:class="{ closed: !mobileMenuOpen }">
|
||||||
<div role="none" v-for="(group, index) in menu">
|
<div role="none" v-for="(group, index) in menu">
|
||||||
<h1 class="font-bold" :aria-owns="'menu-group-' + index" :class="{'mt-4': typeof index === 'number' && index !== 0}">{{ group.label }}</h1>
|
<h1 class="font-bold" :aria-owns="'menu-group-' + index" :class="{'mt-4': typeof index === 'number' && index !== 0}">{{ group.label }}</h1>
|
||||||
<ul v-bind:id="'menu-group-' + index" role="group" class="list-none pl-2">
|
<ul v-bind:id="'menu-group-' + index" role="group" class="list-none pl-2">
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- Content -->
|
<!-- Content -->
|
||||||
<main class="docs-content main-content flex-flexible overflow-x-hidden">
|
<main class="docs-content main-content flex-auto overflow-x-hidden">
|
||||||
<a id="main-anchor" ref="main-anchor" tabindex="-1" class="sr-only"></a>
|
<a id="main-anchor" ref="main-anchor" tabindex="-1" class="sr-only"></a>
|
||||||
<router-view :key="$route.fullPath"></router-view>
|
<router-view :key="$route.fullPath"></router-view>
|
||||||
</main>
|
</main>
|
||||||
|
@ -53,7 +53,6 @@
|
||||||
import {mapState} from "vuex";
|
import {mapState} from "vuex";
|
||||||
import Menu from 'vue-material-design-icons/Menu.vue';
|
import Menu from 'vue-material-design-icons/Menu.vue';
|
||||||
import Title from "../Title.vue";
|
import Title from "../Title.vue";
|
||||||
import logoUrl from "../../img/logo.png";
|
|
||||||
|
|
||||||
type TMenuItem = {
|
type TMenuItem = {
|
||||||
to: string;
|
to: string;
|
||||||
|
@ -132,12 +131,12 @@
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
mobileMenuOpen: false,
|
mobileMenuOpen: false,
|
||||||
logoUrl,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
toggleMobileMenu() {
|
toggleMobileMenu() {
|
||||||
|
console.log('hi');
|
||||||
this.mobileMenuOpen = !this.mobileMenuOpen;
|
this.mobileMenuOpen = !this.mobileMenuOpen;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import CodeBlock from "./CodeBlock";
|
import CodeBlock from "./CodeBlock.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { CodeBlock },
|
components: { CodeBlock },
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<MarkdownBlock :content="data.info.description" class="content"></MarkdownBlock>
|
<MarkdownBlock :content="data.info.description" class="content"></MarkdownBlock>
|
||||||
|
|
||||||
<div v-if="data.info.type === 'legacy'">
|
<div v-if="data.info.type === 'legacy'">
|
||||||
<div class="px-3 py-2 mb-4 rounded bg-gray-800 shadow-md inline-block flex">
|
<div class="px-3 py-2 mb-4 rounded bg-gray-800 shadow-md flex">
|
||||||
<div class="flex-none mr-2">
|
<div class="flex-none mr-2">
|
||||||
<alert class="inline-icon mr-1 text-yellow-300" />
|
<alert class="inline-icon mr-1 text-yellow-300" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -163,6 +163,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@reference "../../style/app.css";
|
||||||
|
|
||||||
.command.target {
|
.command.target {
|
||||||
@apply mt-5 mb-3;
|
@apply mt-5 mb-3;
|
||||||
@apply pt-2 pb-2 pl-4 pr-4;
|
@apply pt-2 pb-2 pl-4 pr-4;
|
||||||
|
@ -174,7 +176,6 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
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.vue";
|
import CodeBlock from "./CodeBlock.vue";
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import "./style/app.pcss";
|
import "./style/app.css";
|
||||||
|
|
||||||
import { createApp } from "vue";
|
import { createApp } from "vue";
|
||||||
|
|
||||||
import VueHighlightJS from "vue3-highlightjs";
|
|
||||||
import "highlight.js/styles/base16/ocean.css";
|
import "highlight.js/styles/base16/ocean.css";
|
||||||
|
import VueHighlightJS from "vue3-highlightjs";
|
||||||
|
|
||||||
import { router } from "./routes";
|
import { router } from "./routes";
|
||||||
import { RootStore } from "./store";
|
import { RootStore } from "./store";
|
||||||
|
@ -13,24 +13,14 @@ import "./directives/trim-indents";
|
||||||
import App from "./components/App.vue";
|
import App from "./components/App.vue";
|
||||||
import { trimIndents } from "./directives/trim-indents";
|
import { trimIndents } from "./directives/trim-indents";
|
||||||
|
|
||||||
|
if (!window.API_URL) {
|
||||||
|
throw new Error("Missing API_URL");
|
||||||
|
}
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
|
||||||
app.use(router);
|
app.use(router);
|
||||||
app.use(RootStore);
|
app.use(RootStore);
|
||||||
|
|
||||||
// Set up a read-only global variable to access specific env vars
|
|
||||||
app.mixin({
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
get env() {
|
|
||||||
return Object.freeze({
|
|
||||||
API_URL: process.env.API_URL,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use(VueHighlightJS);
|
app.use(VueHighlightJS);
|
||||||
|
|
||||||
app.directive("trim-indents", trimIndents);
|
app.directive("trim-indents", trimIndents);
|
|
@ -1,33 +0,0 @@
|
||||||
import "./style/initial.pcss";
|
|
||||||
const splashHtml = require("./splash.html");
|
|
||||||
|
|
||||||
if (window.location.pathname !== "/") {
|
|
||||||
import("./init-vue");
|
|
||||||
} else {
|
|
||||||
// @ts-ignore
|
|
||||||
document.querySelector("#app").innerHTML = splashHtml;
|
|
||||||
|
|
||||||
const queryParams: any = window.location.search
|
|
||||||
.slice(1)
|
|
||||||
.split("&")
|
|
||||||
.reduce((map, str) => {
|
|
||||||
const pair = str.split("=");
|
|
||||||
map[pair[0]] = pair[1];
|
|
||||||
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.",
|
|
||||||
expiredLogin: "Dashboard login expired. Please log in again.",
|
|
||||||
};
|
|
||||||
|
|
||||||
const errorMessageElem = document.createElement("div");
|
|
||||||
errorMessageElem.classList.add("message");
|
|
||||||
errorMessageElem.innerText = errorMessages[queryParams.error] || "Unexpected error";
|
|
||||||
errorElement.appendChild(errorMessageElem);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,12 @@
|
||||||
import { createRouter, createWebHistory } from "vue-router";
|
import { createRouter, createWebHistory } from "vue-router";
|
||||||
import { authGuard, authRedirectGuard, loginCallbackGuard } from "./auth";
|
import { authGuard, authRedirectGuard, loginCallbackGuard } from "./auth";
|
||||||
|
import Splash from "./components/Splash.vue";
|
||||||
|
|
||||||
export const router = createRouter({
|
export const router = createRouter({
|
||||||
history: createWebHistory(),
|
history: createWebHistory(),
|
||||||
routes: [
|
routes: [
|
||||||
|
{ path: "/", component: Splash },
|
||||||
|
|
||||||
{ path: "/login", components: {}, beforeEnter: authRedirectGuard },
|
{ path: "/login", components: {}, beforeEnter: authRedirectGuard },
|
||||||
{ path: "/login-callback", component: {}, beforeEnter: loginCallbackGuard },
|
{ path: "/login-callback", component: {}, beforeEnter: loginCallbackGuard },
|
||||||
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
<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="/dashboard">Dashboard</a>
|
|
||||||
<a class="btn" href="/docs">Documentation</a>
|
|
||||||
</div>
|
|
||||||
<ul class="links">
|
|
||||||
<li>
|
|
||||||
<a href="https://github.com/Dragory/ZeppelinBot">GitHub</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://discord.com/invite/w8njuNu">Discord</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://www.patreon.com/zeppelinbot">Patreon</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/privacy-policy">Privacy Policy</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,13 +1,12 @@
|
||||||
@import "~tailwindcss/base.css";
|
@import "./reset.css";
|
||||||
@import "~tailwindcss/components.css";
|
@import "./base.css";
|
||||||
@import "~tailwindcss/utilities.css";
|
@import "./splash.css";
|
||||||
|
|
||||||
@import "~vue-material-design-icons/styles.css";
|
@import "tailwindcss";
|
||||||
|
@import "vue-material-design-icons/styles.css";
|
||||||
|
|
||||||
@import "components.pcss";
|
@import "./content.css";
|
||||||
@import "content.pcss";
|
@import "./docs.css";
|
||||||
|
|
||||||
@import "docs.pcss";
|
|
||||||
|
|
||||||
/* Reset some icon default styles for more predictable alignment */
|
/* Reset some icon default styles for more predictable alignment */
|
||||||
.material-design-icon > .material-design-icon__svg {
|
.material-design-icon > .material-design-icon__svg {
|
|
@ -1,3 +1,5 @@
|
||||||
|
@import "./components.css";
|
||||||
|
|
||||||
.main-content {
|
.main-content {
|
||||||
& h1 {
|
& h1 {
|
||||||
@apply text-3xl;
|
@apply text-3xl;
|
||||||
|
@ -25,7 +27,12 @@
|
||||||
|
|
||||||
& a:not([class]),
|
& a:not([class]),
|
||||||
& a[class=""] {
|
& a[class=""] {
|
||||||
@apply link;
|
@apply text-blue-400;
|
||||||
|
@apply underline;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
@apply text-blue-200;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& ul:not([class]) {
|
& ul:not([class]) {
|
||||||
|
@ -47,7 +54,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
& code:not([class]) {
|
& code:not([class]) {
|
||||||
@apply inline-code;
|
@apply inline-block;
|
||||||
|
@apply bg-gray-800;
|
||||||
|
@apply px-1;
|
||||||
|
@apply rounded;
|
||||||
|
@apply text-sm;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .expandable:not(.wide) {
|
& .expandable:not(.wide) {
|
||||||
|
@ -55,15 +66,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@screen lg {
|
@media (width >= theme(--breakpoint-lg)) {
|
||||||
.main-content {
|
.main-content {
|
||||||
& h1 {
|
& h1 {
|
||||||
@apply text-5xl;
|
@apply text-5xl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@media (width >= theme(--breakpoint-xl)) {
|
||||||
@screen xl {
|
|
||||||
.main-content {
|
.main-content {
|
||||||
& a:not([class]),
|
& a:not([class]),
|
||||||
& a[class=""] {
|
& a[class=""] {
|
|
@ -4,7 +4,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@screen until-lg {
|
@media (width < theme(--breakpoint-lg)) {
|
||||||
.docs-sidebar.closed:not(:focus-within) {
|
.docs-sidebar.closed:not(:focus-within) {
|
||||||
@apply sr-only;
|
@apply sr-only;
|
||||||
}
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
@import "./reset.pcss";
|
|
||||||
@import "./base.pcss";
|
|
||||||
@import "./splash.pcss";
|
|
50
dashboard/src/style/reset.css
Normal file
50
dashboard/src/style/reset.css
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
@layer base {
|
||||||
|
/* 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,48 +0,0 @@
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,17 +15,14 @@
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > #error {
|
& > .error {
|
||||||
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 750px;
|
max-width: 750px;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
|
|
||||||
&.has-error {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .message {
|
& .message {
|
||||||
flex: 0 1 auto;
|
flex: 0 1 auto;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
@ -154,7 +151,3 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 1024px) {
|
|
||||||
|
|
||||||
}
|
|
10
dashboard/src/vite-env.d.ts
vendored
Normal file
10
dashboard/src/vite-env.d.ts
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
declare module '*.html' {
|
||||||
|
const value: string;
|
||||||
|
export default value;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Window {
|
||||||
|
API_URL: string;
|
||||||
|
}
|
|
@ -1,28 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
important: true,
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
lineHeight: {
|
|
||||||
zero: "0",
|
|
||||||
},
|
|
||||||
flex: {
|
|
||||||
full: "0 0 100%",
|
|
||||||
flexible: "1 1 0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
screens: {
|
|
||||||
sm: "640px",
|
|
||||||
md: "768px",
|
|
||||||
"until-lg": { max: "1023px" },
|
|
||||||
lg: "1024px",
|
|
||||||
xl: "1280px",
|
|
||||||
"2xl": "1536px",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
variants: {},
|
|
||||||
plugins: [],
|
|
||||||
purge: ["./src/**/*.{html,vue}"],
|
|
||||||
future: {
|
|
||||||
purgeLayersByDefault: true,
|
|
||||||
},
|
|
||||||
};
|
|
10
dashboard/ts-vue-shim.d.ts
vendored
10
dashboard/ts-vue-shim.d.ts
vendored
|
@ -1,10 +0,0 @@
|
||||||
declare module "*.vue" {
|
|
||||||
import { DefineComponent } from "vue";
|
|
||||||
const component: DefineComponent;
|
|
||||||
export default component;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module "*.png" {
|
|
||||||
const value: string;
|
|
||||||
export default value;
|
|
||||||
}
|
|
|
@ -15,7 +15,7 @@
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowJs": true
|
"allowJs": true
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.vue", "./ts-vue-shim.d.ts"],
|
"include": ["src/**/*.ts", "src/**/*.vue"],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"path": "../shared/tsconfig.json"
|
"path": "../shared/tsconfig.json"
|
||||||
|
|
24
dashboard/vite.config.ts
Normal file
24
dashboard/vite.config.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import { defineConfig } from "vite";
|
||||||
|
import vue from "@vitejs/plugin-vue";
|
||||||
|
import tailwind from "@tailwindcss/vite";
|
||||||
|
|
||||||
|
export default defineConfig((configEnv) => {
|
||||||
|
return {
|
||||||
|
server: {
|
||||||
|
port: 3002,
|
||||||
|
host: "0.0.0.0",
|
||||||
|
allowedHosts: true,
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
vue({
|
||||||
|
template: {
|
||||||
|
compilerOptions: {
|
||||||
|
// Needed to prevent hardcoded code blocks from breaking in docs
|
||||||
|
whitespace: "preserve",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
tailwind(),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
});
|
|
@ -1,196 +0,0 @@
|
||||||
const path = require("path");
|
|
||||||
const { VueLoaderPlugin } = require("vue-loader");
|
|
||||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
|
||||||
const { merge } = require("webpack-merge");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
const dotenv = require("dotenv");
|
|
||||||
|
|
||||||
dotenv.config({ path: path.resolve(process.cwd(), "../.env") });
|
|
||||||
|
|
||||||
const targetDir = path.normalize(path.join(__dirname, "dist"));
|
|
||||||
|
|
||||||
if (!process.env.NODE_ENV) {
|
|
||||||
console.error("Please set NODE_ENV");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!process.env.API_URL) {
|
|
||||||
console.error("API_URL missing from environment variables");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const babelOpts = {
|
|
||||||
presets: ["@babel/preset-env"],
|
|
||||||
};
|
|
||||||
|
|
||||||
const tsconfig = require("./tsconfig.json");
|
|
||||||
const pathAliases = Object.entries(tsconfig.compilerOptions.paths || []).reduce((aliases, pair) => {
|
|
||||||
let alias = pair[0];
|
|
||||||
if (alias.endsWith("/*")) alias = alias.slice(0, -2);
|
|
||||||
|
|
||||||
let aliasPath = pair[1][0];
|
|
||||||
if (aliasPath.endsWith("/*")) aliasPath = aliasPath.slice(0, -2);
|
|
||||||
|
|
||||||
aliases[alias] = path.resolve(__dirname, aliasPath);
|
|
||||||
return aliases;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
const postcssPlugins = [
|
|
||||||
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") {
|
|
||||||
postcssPlugins.push(require("postcss-preset-env")(), require("cssnano")());
|
|
||||||
}
|
|
||||||
|
|
||||||
let config = {
|
|
||||||
entry: "./src/main.ts",
|
|
||||||
output: {
|
|
||||||
filename: "[name].[fullhash].js",
|
|
||||||
path: targetDir,
|
|
||||||
publicPath: "/",
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
// Vue / Babel / Typescript
|
|
||||||
{
|
|
||||||
test: /\.vue$/,
|
|
||||||
loader: "vue-loader",
|
|
||||||
options: {
|
|
||||||
compilerOptions: {
|
|
||||||
whitespace: 'preserve', // not the default despite the docs saying so
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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",
|
|
||||||
postcssOptions: {
|
|
||||||
plugins: postcssPlugins,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
// Images/files
|
|
||||||
{
|
|
||||||
test: /\.(png|jpg)$/i,
|
|
||||||
use: {
|
|
||||||
loader: "file-loader",
|
|
||||||
options: {
|
|
||||||
name: "[name]-[hash].[ext]",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// HTML
|
|
||||||
{
|
|
||||||
test: /\.html$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: "html-loader",
|
|
||||||
options: {
|
|
||||||
esModule: false,
|
|
||||||
...(process.env.NODE_ENV === "production" && {
|
|
||||||
minimize: true,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new VueLoaderPlugin(),
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
template: "src/index.html",
|
|
||||||
files: {
|
|
||||||
css: ["./src/style/initial.pcss"],
|
|
||||||
js: ["./src/main.ts"],
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
new webpack.EnvironmentPlugin(["API_URL"]),
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
__VUE_OPTIONS_API__: true,
|
|
||||||
__VUE_PROD_DEVTOOLS__: false,
|
|
||||||
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false,
|
|
||||||
})
|
|
||||||
],
|
|
||||||
resolve: {
|
|
||||||
extensions: [".ts", ".tsx", ".js", ".mjs", ".vue"],
|
|
||||||
alias: pathAliases,
|
|
||||||
roots: [path.resolve(__dirname, "src")],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "production") {
|
|
||||||
config = merge(config, {
|
|
||||||
mode: "production",
|
|
||||||
devtool: "source-map",
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
config = merge(config, {
|
|
||||||
mode: "development",
|
|
||||||
devtool: "eval",
|
|
||||||
devServer: {
|
|
||||||
allowedHosts: "all",
|
|
||||||
historyApiFallback: true,
|
|
||||||
port: 3002,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = config;
|
|
|
@ -12,6 +12,11 @@ server {
|
||||||
# This is the address of the internal docker compose DNS server.
|
# This is the address of the internal docker compose DNS server.
|
||||||
resolver 127.0.0.11;
|
resolver 127.0.0.11;
|
||||||
proxy_pass $dashboard_upstream$uri$is_args$args;
|
proxy_pass $dashboard_upstream$uri$is_args$args;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /api {
|
location /api {
|
||||||
|
|
10387
package-lock.json
generated
10387
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -27,5 +27,8 @@
|
||||||
"shared",
|
"shared",
|
||||||
"backend",
|
"backend",
|
||||||
"dashboard"
|
"dashboard"
|
||||||
]
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"dotenv": "^16.5.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue