Remove deprecated web interface
This commit is contained in:
parent
d7ffa8830d
commit
8afb2f892b
14
web/.babelrc
14
web/.babelrc
@ -1,14 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"env",
|
||||
{
|
||||
"targets": {
|
||||
"browsers": [
|
||||
"last 2 Chrome versions"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
3
web/.gitignore
vendored
3
web/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
.cache/
|
||||
dist/
|
||||
node_modules/
|
@ -1,63 +0,0 @@
|
||||
import { EventEmitter } from "eventemitter3"
|
||||
|
||||
const SITE_ROOT = process.env.NODE_ENV === "production" ? "https://pluralkit.me" : "http://localhost:1234";
|
||||
const API_ROOT = process.env.NODE_ENV === "production" ? "https://api.pluralkit.me" : "http://localhost:2939";
|
||||
const CLIENT_ID = process.env.NODE_ENV === "production" ? "466378653216014359" : "467772037541134367";
|
||||
export const AUTH_URI = `https://discordapp.com/api/oauth2/authorize?client_id=${CLIENT_ID}&redirect_uri=${encodeURIComponent(SITE_ROOT + "/auth/discord")}&response_type=code&scope=identify`
|
||||
|
||||
|
||||
class API extends EventEmitter {
|
||||
async init() {
|
||||
this.token = localStorage.getItem("pk-token");
|
||||
if (this.token) {
|
||||
this.me = await fetch(API_ROOT + "/s", {headers: {"X-Token": this.token}}).then(r => r.json());
|
||||
this.emit("update", this.me);
|
||||
}
|
||||
}
|
||||
|
||||
async fetchSystem(id) {
|
||||
return await fetch(API_ROOT + "/s/" + id).then(r => r.json()) || null;
|
||||
}
|
||||
|
||||
async fetchSystemMembers(id) {
|
||||
return await fetch(API_ROOT + "/s/" + id + "/members").then(r => r.json()) || [];
|
||||
}
|
||||
|
||||
async fetchSystemSwitches(id) {
|
||||
return await fetch(API_ROOT + "/s/" + id + "/switches").then(r => r.json()) || [];
|
||||
}
|
||||
|
||||
async fetchMember(id) {
|
||||
return await fetch(API_ROOT + "/m/" + id).then(r => r.json()) || null;
|
||||
}
|
||||
|
||||
async saveSystem(system) {
|
||||
return await fetch(API_ROOT + "/s", {
|
||||
method: "PATCH",
|
||||
headers: {"X-Token": this.token},
|
||||
body: JSON.stringify(system)
|
||||
});
|
||||
}
|
||||
|
||||
async login(code) {
|
||||
this.token = await fetch(API_ROOT + "/discord_oauth", {method: "POST", body: code}).then(r => r.text());
|
||||
this.me = await fetch(API_ROOT + "/s", {headers: {"X-Token": this.token}}).then(r => r.json());
|
||||
|
||||
if (this.me) {
|
||||
localStorage.setItem("pk-token", this.token);
|
||||
this.emit("update", this.me);
|
||||
} else {
|
||||
this.logout();
|
||||
}
|
||||
return this.me;
|
||||
}
|
||||
|
||||
logout() {
|
||||
localStorage.removeItem("pk-token");
|
||||
this.emit("update", null);
|
||||
this.token = null;
|
||||
this.me = null;
|
||||
}
|
||||
}
|
||||
|
||||
export default new API();
|
@ -1,84 +0,0 @@
|
||||
<template>
|
||||
<div class="app">
|
||||
<b-navbar>
|
||||
<b-navbar-brand :to="{name: 'home'}">PluralKit</b-navbar-brand>
|
||||
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
|
||||
<b-collapse id="nav-collapse" is-nav>
|
||||
<b-navbar-nav class="ml-auto">
|
||||
<b-nav-item v-if="me" :to="{name: 'system', params: {id: me.id}}">My system</b-nav-item>
|
||||
<b-nav-item variant="primary" :href="authUri" v-if="!me">Log in</b-nav-item>
|
||||
<b-nav-item v-on:click="logout" v-if="me">Log out</b-nav-item>
|
||||
</b-navbar-nav>
|
||||
</b-collapse>
|
||||
</b-navbar>
|
||||
|
||||
<router-view :me="me"></router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BCollapse from 'bootstrap-vue/es/components/collapse/collapse';
|
||||
import BNav from 'bootstrap-vue/es/components/nav/nav';
|
||||
import BNavItem from 'bootstrap-vue/es/components/nav/nav-item';
|
||||
import BNavbar from 'bootstrap-vue/es/components/navbar/navbar';
|
||||
import BNavbarBrand from 'bootstrap-vue/es/components/navbar/navbar-brand';
|
||||
import BNavbarNav from 'bootstrap-vue/es/components/navbar/navbar-nav';
|
||||
import BNavbarToggle from 'bootstrap-vue/es/components/navbar/navbar-toggle';
|
||||
|
||||
import API from "./API";
|
||||
import { AUTH_URI } from "./API";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
me: null
|
||||
}
|
||||
},
|
||||
created() {
|
||||
API.on("update", this.apply);
|
||||
API.init();
|
||||
},
|
||||
methods: {
|
||||
apply(system) {
|
||||
this.me = system;
|
||||
},
|
||||
logout() {
|
||||
API.logout();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
authUri() {
|
||||
return AUTH_URI;
|
||||
}
|
||||
},
|
||||
components: {BCollapse, BNav, BNavItem, BNavbar, BNavbarBrand, BNavbarNav, BNavbarToggle}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$font-family-sans-serif: "PT Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default;
|
||||
$container-max-widths: (
|
||||
sm: 540px,
|
||||
md: 720px,
|
||||
lg: 959px,
|
||||
xl: 960px,
|
||||
) !default;
|
||||
|
||||
|
||||
@import '~bootstrap/scss/_functions';
|
||||
@import '~bootstrap/scss/_variables';
|
||||
@import '~bootstrap/scss/_mixins';
|
||||
|
||||
@import '~bootstrap/scss/_buttons';
|
||||
@import '~bootstrap/scss/_code';
|
||||
@import '~bootstrap/scss/_forms';
|
||||
@import '~bootstrap/scss/_grid';
|
||||
@import '~bootstrap/scss/_nav';
|
||||
@import '~bootstrap/scss/_navbar';
|
||||
@import '~bootstrap/scss/_reboot';
|
||||
@import '~bootstrap/scss/_type';
|
||||
@import '~bootstrap/scss/_utilities';
|
||||
|
||||
@import '~bootstrap-vue/src/index.scss';
|
||||
</style>
|
||||
|
@ -1,9 +0,0 @@
|
||||
<template>
|
||||
<h1>Hello</h1>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
@ -1,66 +0,0 @@
|
||||
<template>
|
||||
<div class="member-card">
|
||||
<div
|
||||
class="member-avatar"
|
||||
:style="{backgroundImage: `url(${member.avatar_url})`, borderColor: member.color}"
|
||||
></div>
|
||||
<div class="member-body">
|
||||
<span class="member-name">{{ member.name }}</span>
|
||||
<div class="member-description">{{ member.description }}</div>
|
||||
<ul class="taglist">
|
||||
<li>
|
||||
<hash-icon></hash-icon>
|
||||
{{ member.id }}
|
||||
</li>
|
||||
<li v-if="member.birthday">
|
||||
<calendar-icon></calendar-icon>
|
||||
{{ member.birthday }}
|
||||
</li>
|
||||
<li v-if="member.pronouns">
|
||||
<message-circle-icon></message-circle-icon>
|
||||
{{ member.pronouns }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CalendarIcon from "vue-feather-icons/icons/CalendarIcon";
|
||||
import HashIcon from "vue-feather-icons/icons/HashIcon";
|
||||
import MessageCircleIcon from "vue-feather-icons/icons/MessageCircleIcon";
|
||||
|
||||
export default {
|
||||
props: ["member"],
|
||||
components: { HashIcon, CalendarIcon, MessageCircleIcon }
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.member-card {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.member-avatar {
|
||||
margin: 1.5rem 1rem 0 0;
|
||||
border-radius: 50%;
|
||||
background-size: cover;
|
||||
background-position: top center;
|
||||
flex-basis: 4rem;
|
||||
height: 4rem;
|
||||
border: 4px solid white;
|
||||
}
|
||||
|
||||
.member-body {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 1rem 1rem 1rem 0;
|
||||
|
||||
.member-name {
|
||||
font-size: 13pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,93 +0,0 @@
|
||||
<template>
|
||||
<b-container v-if="loading" class="d-flex justify-content-center">
|
||||
<b-spinner class="m-5"></b-spinner>
|
||||
</b-container>
|
||||
<b-container v-else-if="error">Error</b-container>
|
||||
<b-container v-else>
|
||||
<h1>Editing "{{member.name}}"</h1>
|
||||
|
||||
<b-form>
|
||||
<b-form-group label="Name">
|
||||
<b-form-input v-model="member.name" required></b-form-input>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group label="Description">
|
||||
<b-form-textarea v-model="member.description" rows="3" max-rows="6"></b-form-textarea>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group label="Proxy tags">
|
||||
<b-row>
|
||||
<b-col>
|
||||
<b-input-group prepend="Prefix">
|
||||
<b-form-input class="text-right" v-model="member.prefix" placeholder="ex: ["></b-form-input>
|
||||
</b-input-group>
|
||||
</b-col>
|
||||
<b-col>
|
||||
<b-input-group append="Suffix">
|
||||
<b-form-input v-model="member.suffix" placeholder="ex: ]"></b-form-input>
|
||||
</b-input-group>
|
||||
</b-col>
|
||||
<b-col></b-col>
|
||||
</b-row>
|
||||
<template
|
||||
v-slot:description
|
||||
v-if="member.prefix || member.suffix"
|
||||
>Example proxy message: {{member.prefix}}text{{member.suffix}}</template>
|
||||
<template v-slot:description v-else>(no prefix or suffix defined, proxying will be disabled)</template>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group label="Pronouns" description="Free text field - put anything you'd like :)">
|
||||
<b-form-input v-model="member.pronouns" placeholder="eg. he/him"></b-form-input>
|
||||
</b-form-group>
|
||||
|
||||
<b-row>
|
||||
<b-col md>
|
||||
<b-form-group label="Birthday">
|
||||
<b-input-group>
|
||||
<b-input-group-prepend is-text>
|
||||
<input type="checkbox" v-model="hideBirthday" label="uwu"> Hide year
|
||||
</b-input-group-prepend>
|
||||
<b-form-input v-model="member.birthday" type="date"></b-form-input>
|
||||
</b-input-group>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
<b-col md>
|
||||
<b-form-group label="Color" description="Will be displayed on system profile cards.">
|
||||
<b-form-input type="color" v-model="member.color"></b-form-input>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-form>
|
||||
</b-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import API from "./API";
|
||||
|
||||
export default {
|
||||
props: ["id"],
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
error: false,
|
||||
hideBirthday: false,
|
||||
member: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.fetch();
|
||||
},
|
||||
methods: {
|
||||
async fetch() {
|
||||
this.loading = true;
|
||||
this.error = false;
|
||||
this.member = await API.fetchMember(this.id);
|
||||
if (!this.member) this.error = true;
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
@ -1,20 +0,0 @@
|
||||
<template>
|
||||
<b-container class="d-flex justify-content-center"><span class="sr-only">Loading...</span><b-spinner class="m-5"></b-spinner></b-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import API from "./API";
|
||||
|
||||
export default {
|
||||
async created() {
|
||||
const code = this.$route.query.code;
|
||||
if (!code) this.$router.push({ name: "home" });
|
||||
const me = await API.login(code);
|
||||
if (me) this.$router.push({ name: "home" });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
@ -1,83 +0,0 @@
|
||||
<template>
|
||||
<b-container>
|
||||
<b-container v-if="loading" class="d-flex justify-content-center"><b-spinner class="m-5"></b-spinner></b-container>
|
||||
<b-form v-else>
|
||||
<h1>Editing "{{ system.name || system.id }}"</h1>
|
||||
<b-form-group label="System name">
|
||||
<b-form-input v-model="system.name" placeholder="Enter something..."></b-form-input>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group label="Description">
|
||||
<b-form-textarea v-model="system.description" placeholder="Enter something..." rows="3" max-rows="3" maxlength="1000"></b-form-textarea>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group label="System tag">
|
||||
<b-form-input maxlength="30" v-model="system.tag" placeholder="Enter something..."></b-form-input>
|
||||
<template v-slot:description>
|
||||
This is added to the names of proxied accounts. For example: <code>John {{ system.tag }}</code>
|
||||
</template>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group class="d-flex justify-content-end">
|
||||
<b-button type="reset" variant="outline-secondary">Back</b-button>
|
||||
<b-button v-if="!saving" type="submit" variant="primary" v-on:click="save">Save</b-button>
|
||||
<b-button v-else variant="primary" disabled>
|
||||
<b-spinner small></b-spinner>
|
||||
<span class="sr-only">Saving...</span>
|
||||
</b-button>
|
||||
<b-form-group>
|
||||
</b-form>
|
||||
</b-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BButton from 'bootstrap-vue/es/components/button/button';
|
||||
import BContainer from 'bootstrap-vue/es/components/layout/container';
|
||||
import BLink from 'bootstrap-vue/es/components/link/link';
|
||||
import BSpinner from 'bootstrap-vue/es/components/spinner/spinner';
|
||||
import BForm from 'bootstrap-vue/es/components/form/form';
|
||||
import BFormInput from 'bootstrap-vue/es/components/form-input/form-input';
|
||||
import BFormGroup from 'bootstrap-vue/es/components/form-group/form-group';
|
||||
import BFormTextarea from 'bootstrap-vue/es/components/form-textarea/form-textarea';
|
||||
|
||||
import API from "./API";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
saving: false,
|
||||
system: null
|
||||
}
|
||||
},
|
||||
props: ["me", "id"],
|
||||
created() {
|
||||
this.fetch()
|
||||
},
|
||||
watch: {
|
||||
"id": "fetch"
|
||||
},
|
||||
methods: {
|
||||
async fetch() {
|
||||
this.loading = true;
|
||||
this.system = await API.fetchSystem(this.id);
|
||||
if (!this.me || !this.system || this.system.id != this.me.id) {
|
||||
this.$router.push({name: "system", params: {id: this.id}});
|
||||
}
|
||||
this.loading = false;
|
||||
},
|
||||
async save() {
|
||||
this.saving = true;
|
||||
if (await API.saveSystem(this.system)) {
|
||||
this.$router.push({ name: "system", params: {id: this.system.id} });
|
||||
}
|
||||
this.saving = false;
|
||||
}
|
||||
},
|
||||
components: {BButton, BContainer, BLink, BSpinner, BForm, BFormGroup, BFormInput, BFormTextarea}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
@ -1,113 +0,0 @@
|
||||
<template>
|
||||
<b-container v-if="loading" class="d-flex justify-content-center"><b-spinner class="m-5"></b-spinner></b-container>
|
||||
<b-container v-else-if="error">An error occurred.</b-container>
|
||||
<b-container v-else>
|
||||
<ul v-if="system" class="taglist">
|
||||
<li>
|
||||
<hash-icon></hash-icon>
|
||||
{{ system.id }}
|
||||
</li>
|
||||
<li v-if="system.tag">
|
||||
<tag-icon></tag-icon>
|
||||
{{ system.tag }}
|
||||
</li>
|
||||
<li v-if="system.tz">
|
||||
<clock-icon></clock-icon>
|
||||
{{ system.tz }}
|
||||
</li>
|
||||
<li v-if="isMine" class="ml-auto">
|
||||
<b-link :to="{name: 'edit-system', params: {id: system.id}}">
|
||||
<edit-2-icon></edit-2-icon>
|
||||
Edit
|
||||
</b-link>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h1 v-if="system && system.name">{{ system.name }}</h1>
|
||||
<div v-if="system && system.description">{{ system.description }}</div>
|
||||
|
||||
<h2>Members</h2>
|
||||
<div v-if="members">
|
||||
<MemberCard v-for="member in members" :member="member" :key="member.id"/>
|
||||
</div>
|
||||
</b-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import API from "./API";
|
||||
|
||||
import BContainer from 'bootstrap-vue/es/components/layout/container';
|
||||
import BLink from 'bootstrap-vue/es/components/link/link';
|
||||
import BSpinner from 'bootstrap-vue/es/components/spinner/spinner';
|
||||
|
||||
import MemberCard from "./MemberCard.vue";
|
||||
|
||||
import Edit2Icon from "vue-feather-icons/icons/Edit2Icon";
|
||||
import ClockIcon from "vue-feather-icons/icons/ClockIcon";
|
||||
import HashIcon from "vue-feather-icons/icons/HashIcon";
|
||||
import TagIcon from "vue-feather-icons/icons/TagIcon";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
error: false,
|
||||
system: null,
|
||||
members: null
|
||||
};
|
||||
},
|
||||
props: ["me", "id"],
|
||||
created() {
|
||||
this.fetch();
|
||||
},
|
||||
methods: {
|
||||
async fetch() {
|
||||
this.loading = true;
|
||||
this.system = await API.fetchSystem(this.id);
|
||||
if (!this.system) {
|
||||
this.error = true;
|
||||
this.loading = false;
|
||||
return;
|
||||
}
|
||||
this.members = await API.fetchSystemMembers(this.id);
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
id: "fetch"
|
||||
},
|
||||
computed: {
|
||||
isMine() {
|
||||
return this.system && this.me && this.me.id == this.system.id;
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Edit2Icon,
|
||||
ClockIcon,
|
||||
HashIcon,
|
||||
TagIcon,
|
||||
MemberCard,
|
||||
BContainer, BLink, BSpinner
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.taglist {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #aaa;
|
||||
display: flex;
|
||||
|
||||
li {
|
||||
display: inline-block;
|
||||
margin-right: 1rem;
|
||||
list-style-type: none;
|
||||
.feather {
|
||||
display: inline-block;
|
||||
margin-top: -2px;
|
||||
width: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,23 +0,0 @@
|
||||
import Vue from "vue";
|
||||
|
||||
import VueRouter from "vue-router";
|
||||
Vue.use(VueRouter);
|
||||
|
||||
const App = () => import("./App.vue");
|
||||
const HomePage = () => import("./HomePage.vue");
|
||||
const SystemPage = () => import("./SystemPage.vue");
|
||||
const SystemEditPage = () => import("./SystemEditPage.vue");
|
||||
const MemberEditPage = () => import("./MemberEditPage.vue");
|
||||
const OAuthRedirectPage = () => import("./OAuthRedirectPage.vue");
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: "history",
|
||||
routes: [
|
||||
{ name: "home", path: "/", component: HomePage },
|
||||
{ name: "system", path: "/s/:id", component: SystemPage, props: true },
|
||||
{ name: "edit-system", path: "/s/:id/edit", component: SystemEditPage, props: true },
|
||||
{ name: "edit-member", path: "/m/:id/edit", component: MemberEditPage, props: true },
|
||||
{ name: "auth-discord", path: "/auth/discord", component: OAuthRedirectPage }
|
||||
]
|
||||
})
|
||||
new Vue({ el: "#app", render: r => r(App), router });
|
@ -1,9 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=PT+Sans:400,700" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="app/index.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,19 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"bootstrap": "^4.3.1",
|
||||
"bootstrap-vue": "^2.0.0-rc.16",
|
||||
"eventemitter3": "^3.1.0",
|
||||
"vue": "^2.6.10",
|
||||
"vue-feather-icons": "^4.10.0",
|
||||
"vue-router": "^3.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/component-compiler-utils": "^2.6.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"cssnano": "^4.1.10",
|
||||
"parcel-plugin-bundle-visualiser": "^1.2.0",
|
||||
"sass": "^1.17.3",
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
}
|
||||
}
|
3296
web/yarn.lock
3296
web/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user