mirror of
https://github.com/danbulant/Nertivia-Client
synced 2026-05-27 05:42:44 +00:00
added public theme service
This commit is contained in:
parent
c827a425ba
commit
bce31bb9dd
12 changed files with 1023 additions and 213 deletions
|
|
@ -166,9 +166,6 @@ export default {
|
||||||
this.changed = true;
|
this.changed = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
|
||||||
console.log(this.server);
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
googleDriveLinked() {
|
googleDriveLinked() {
|
||||||
return this.$store.getters["settingsModule/settings"].GDriveLinked;
|
return this.$store.getters["settingsModule/settings"].GDriveLinked;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
<template>
|
||||||
|
<div class="theme">
|
||||||
|
<div
|
||||||
|
class="name"
|
||||||
|
:class="{ selected: selectedThemeID === theme.id }"
|
||||||
|
@click="themeClick()"
|
||||||
|
>
|
||||||
|
{{ theme.name }}
|
||||||
|
</div>
|
||||||
|
<div class="context" v-if="theme.id == selectedThemeID">
|
||||||
|
<div class="button" @click="applyButton">
|
||||||
|
<div class="material-icons">check</div>
|
||||||
|
<div class="btn-name">Apply</div>
|
||||||
|
</div>
|
||||||
|
<div class="button" @click="editButton">
|
||||||
|
<div class="material-icons">edit</div>
|
||||||
|
<div class="btn-name">Edit</div>
|
||||||
|
</div>
|
||||||
|
<div class="button" @click="makePublicButton">
|
||||||
|
<div class="material-icons">public</div>
|
||||||
|
<div class="btn-name">Manage Public</div>
|
||||||
|
</div>
|
||||||
|
<div class="button delete-button" @click="deleteButton">
|
||||||
|
<div class="material-icons">delete</div>
|
||||||
|
<div class="btn-name">Delete</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: ['theme', 'selectedThemeID'],
|
||||||
|
methods: {
|
||||||
|
themeClick() {
|
||||||
|
this.$emit('clicked')
|
||||||
|
},
|
||||||
|
applyButton() {
|
||||||
|
this.$emit('apply')
|
||||||
|
},
|
||||||
|
editButton(){
|
||||||
|
this.$emit('edit')
|
||||||
|
},
|
||||||
|
deleteButton(){
|
||||||
|
this.$emit('delete')
|
||||||
|
},
|
||||||
|
makePublicButton() {
|
||||||
|
this.$emit('makePublic')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.theme {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
widows: 100%;
|
||||||
|
min-height: 30px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
color: rgb(230, 230, 230);
|
||||||
|
transition: 0.2s;
|
||||||
|
.name {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 30px;
|
||||||
|
padding-left: 5px;
|
||||||
|
flex: 1;
|
||||||
|
align-items: center;
|
||||||
|
transition: 0.2s;
|
||||||
|
&:hover {
|
||||||
|
color: white;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
&.selected {
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.context {
|
||||||
|
display: flex;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
.button {
|
||||||
|
display: flex;
|
||||||
|
margin: 5px;
|
||||||
|
align-content: center;
|
||||||
|
align-items: center;
|
||||||
|
opacity: 0.8;
|
||||||
|
transition: 0.2s;
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.material-icons {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
.delete-button {
|
||||||
|
margin: auto;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,34 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="editing" v-if="editing">
|
<make-public v-if="showMakePublic" @back="closeButton" :name="name" :themeID="selectedThemeID" />
|
||||||
<div class="bar">
|
<Editor
|
||||||
<input
|
v-else-if="editing"
|
||||||
class="theme-name"
|
:themeName="name"
|
||||||
v-model="name"
|
:themeCode="code"
|
||||||
type="text"
|
:savingStatus="saving"
|
||||||
placeholder="Theme name"
|
@close="closeButton"
|
||||||
/>
|
@save="saveButton"
|
||||||
<div class="button" @click="saveButton">
|
/>
|
||||||
<div class="material-icons">save</div>
|
|
||||||
Save & Apply
|
|
||||||
</div>
|
|
||||||
<div class="button" @click="closeButton">
|
|
||||||
<div class="material-icons">clear</div>
|
|
||||||
Close
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- <prism-editor class="editor" v-model="code" language="css"></prism-editor> -->
|
|
||||||
<codemirror
|
|
||||||
class="editor"
|
|
||||||
v-model="code"
|
|
||||||
:options="cmOptions"
|
|
||||||
@ready="onCmReady"
|
|
||||||
/>
|
|
||||||
<div class="notice">
|
|
||||||
<div class="material-icons">warning</div>
|
|
||||||
<div class="notice-message">Warning: Pasting someone elses code could be dangerous.</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="managing" v-else>
|
<div class="managing" v-else>
|
||||||
<div class="bar">
|
<div class="bar">
|
||||||
<div class="button">
|
<div class="button">
|
||||||
|
|
@ -42,131 +22,106 @@
|
||||||
</div>
|
</div>
|
||||||
<spinner v-if="!themes" />
|
<spinner v-if="!themes" />
|
||||||
<div v-if="themes" class="themes-list">
|
<div v-if="themes" class="themes-list">
|
||||||
<div class="theme" v-for="theme in themes" :key="theme.id">
|
<theme-template
|
||||||
<div
|
v-for="theme in themes"
|
||||||
class="name"
|
:theme="theme"
|
||||||
:class="{ selected: selectedThemeID === theme.id }"
|
:selectedThemeID="selectedThemeID"
|
||||||
@click="themeClick(theme.id)"
|
@clicked="themeClick(theme.id, theme.name)"
|
||||||
>
|
@apply="applyButton(theme.id)"
|
||||||
{{ theme.name }}
|
@edit="editButton(theme.id)"
|
||||||
</div>
|
@makePublic="makePublicButton(theme.id)"
|
||||||
<div class="context" v-if="theme.id == selectedThemeID">
|
@delete="deleteButton(theme.id)"
|
||||||
<div class="button" @click="applyButton(theme.id)">
|
:key="theme.id"
|
||||||
<div class="material-icons">check</div>
|
/>
|
||||||
<div class="btn-name">Apply</div>
|
|
||||||
</div>
|
|
||||||
<div class="button" @click="editButton(theme.id)">
|
|
||||||
<div class="material-icons">edit</div>
|
|
||||||
<div class="btn-name">Edit</div>
|
|
||||||
</div>
|
|
||||||
<div class="button delete-button" @click="deleteButton(theme.id)">
|
|
||||||
<div class="material-icons">delete</div>
|
|
||||||
<div class="btn-name">Delete</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// import "prismjs";
|
import ThemeTemplate from "./MyThemeTemplate";
|
||||||
// import "prismjs/themes/prism-twilight.css";
|
import Editor from "./themesEditor";
|
||||||
// const PrismEditor = () => import("vue-prism-editor");
|
import MakePublic from "./MyThemesMakePublic";
|
||||||
// language js
|
|
||||||
import "codemirror/mode/css/css.js";
|
|
||||||
|
|
||||||
import "codemirror/addon/hint/show-hint.css";
|
|
||||||
import "codemirror/addon/hint/show-hint.js";
|
|
||||||
import "codemirror/addon/hint/css-hint";
|
|
||||||
// theme css
|
|
||||||
import "codemirror/theme/base16-dark.css";
|
|
||||||
import "codemirror/lib/codemirror.css";
|
|
||||||
import { codemirror } from "vue-codemirror";
|
|
||||||
|
|
||||||
import Spinner from "@/components/Spinner";
|
import Spinner from "@/components/Spinner";
|
||||||
|
|
||||||
import config from "@/config.js";
|
import config from "@/config.js";
|
||||||
import ThemeService from "@/services/ThemeService";
|
import ThemeService from "@/services/ThemeService";
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
codemirror,
|
Spinner,
|
||||||
Spinner
|
Editor,
|
||||||
|
ThemeTemplate,
|
||||||
|
MakePublic,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
name: "",
|
||||||
|
code: "",
|
||||||
saving: false,
|
saving: false,
|
||||||
selectedThemeID: null,
|
selectedThemeID: null,
|
||||||
themes: null,
|
themes: null,
|
||||||
editing: null,
|
editing: null,
|
||||||
name: "",
|
showMakePublic: false,
|
||||||
code: `/* Start writing your styles*/\n`,
|
|
||||||
cmOptions: {
|
|
||||||
// codemirror options
|
|
||||||
tabSize: 2,
|
|
||||||
mode: "text/css",
|
|
||||||
theme: "base16-dark",
|
|
||||||
lineNumbers: true,
|
|
||||||
line: true
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async fetchThemes() {
|
async fetchThemes() {
|
||||||
this.themes = null;
|
this.themes = null;
|
||||||
// fetch themes
|
// fetch themes
|
||||||
const {ok, result, error} = await ThemeService.getThemes();
|
const { ok, result, error } = await ThemeService.getThemes();
|
||||||
if (ok) {
|
if (ok) {
|
||||||
this.themes = result.data;
|
this.themes = result.data;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
createButton() {
|
createButton() {
|
||||||
this.name = "Untitled"
|
this.name = "Untitled";
|
||||||
this.code = `/* Start writing your styles*/\n`;
|
this.code = `/* Start writing your styles*/\n`;
|
||||||
this.editing = true;
|
this.editing = true;
|
||||||
},
|
},
|
||||||
closeButton() {
|
closeButton() {
|
||||||
|
this.showMakePublic = false;
|
||||||
this.editing = false;
|
this.editing = false;
|
||||||
this.fetchThemes();
|
this.fetchThemes();
|
||||||
},
|
},
|
||||||
themeClick(id) {
|
themeClick(id, name) {
|
||||||
if (this.selectedThemeID === id) {
|
if (this.selectedThemeID === id) {
|
||||||
this.selectedThemeID = null;
|
this.selectedThemeID = null;
|
||||||
|
this.name = null;
|
||||||
} else {
|
} else {
|
||||||
this.selectedThemeID = id;
|
this.selectedThemeID = id;
|
||||||
|
this.name = name;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onCmReady(cm) {
|
async saveButton({ name, css }) {
|
||||||
cm.on("keypress", () => {
|
if (this.saving) {
|
||||||
cm.showHint({ completeSingle: false });
|
return;
|
||||||
});
|
}
|
||||||
},
|
|
||||||
async saveButton() {
|
|
||||||
if (this.saving) {return}
|
|
||||||
this.saving = true;
|
this.saving = true;
|
||||||
const css = this.code;
|
this.name = name;
|
||||||
const name = this.name;
|
if (typeof this.editing === "string") {
|
||||||
if (typeof this.editing === 'string'){
|
|
||||||
const response = await ThemeService.update({ name, css }, this.editing);
|
const response = await ThemeService.update({ name, css }, this.editing);
|
||||||
this.applyButton(this.editing)
|
this.applyButton(this.editing);
|
||||||
} else {
|
} else {
|
||||||
const response = await ThemeService.save({ name, css });
|
const response = await ThemeService.save({ name, css });
|
||||||
this.editing = response.result.data.id;
|
this.editing = response.result.data.id;
|
||||||
this.applyButton(response.result.data.id)
|
this.applyButton(response.result.data.id, css);
|
||||||
}
|
}
|
||||||
this.saving = false;
|
this.saving = false;
|
||||||
},
|
},
|
||||||
async applyButton(id) {
|
async applyButton(id, css) {
|
||||||
const {ok, result, error} = await ThemeService.getTheme(id);
|
if (css) {
|
||||||
if (ok) {
|
this.code = css;
|
||||||
this.code = result.data.css;
|
} else {
|
||||||
|
const { ok, result, error } = await ThemeService.getTheme(id);
|
||||||
|
if (ok) {
|
||||||
|
this.code = result.data.css;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// save to local storage.
|
// save to local storage.
|
||||||
localStorage.setItem('appliedThemeId', id);
|
localStorage.setItem("appliedThemeId", id);
|
||||||
|
|
||||||
const styleEl = document.createElement("style");
|
const styleEl = document.createElement("style");
|
||||||
styleEl.classList.add('theme-' + id);
|
styleEl.classList.add("theme-" + id);
|
||||||
styleEl.id = "theme";
|
styleEl.id = "theme";
|
||||||
styleEl.innerHTML = this.code;
|
styleEl.innerHTML = this.code;
|
||||||
|
|
||||||
|
|
@ -179,25 +134,28 @@ export default {
|
||||||
},
|
},
|
||||||
async editButton(id) {
|
async editButton(id) {
|
||||||
// fetch theme
|
// fetch theme
|
||||||
const {ok, result, error} = await ThemeService.getTheme(id);
|
const { ok, result, error } = await ThemeService.getTheme(id);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
const {name, css} = result.data;
|
const { name, css } = result.data;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.code = css;
|
this.code = css;
|
||||||
this.editing = id;
|
this.editing = id;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async deleteButton (id) {
|
async deleteButton(id) {
|
||||||
localStorage.removeItem('appliedThemeId');
|
localStorage.removeItem("appliedThemeId");
|
||||||
const themeEl = document.getElementById('theme');
|
const themeEl = document.getElementById("theme");
|
||||||
if (themeEl && themeEl.classList.contains('theme-' + id)) {
|
if (themeEl && themeEl.classList.contains("theme-" + id)) {
|
||||||
document.getElementById('theme').outerHTML = ''
|
document.getElementById("theme").outerHTML = "";
|
||||||
}
|
}
|
||||||
const {ok, result, error} = await ThemeService.delete(id);
|
const { ok, result, error } = await ThemeService.delete(id);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
this.themes = this.themes.filter(t => t.id !== id);
|
this.themes = this.themes.filter(t => t.id !== id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
makePublicButton() {
|
||||||
|
this.showMakePublic = true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
this.fetchThemes();
|
this.fetchThemes();
|
||||||
|
|
@ -245,102 +203,8 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.editing {
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
.theme-name {
|
|
||||||
height: 20px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.editor {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.notice {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
align-content: center;
|
|
||||||
background: rgb(255, 54, 54);
|
|
||||||
height: 40px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
padding-left: 5px;
|
|
||||||
.notice-message {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.themes-list {
|
.themes-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
.theme {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
widows: 100%;
|
|
||||||
min-height: 30px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
|
||||||
color: rgb(230, 230, 230);
|
|
||||||
transition: 0.2s;
|
|
||||||
.name {
|
|
||||||
flex-shrink: 0;
|
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
|
||||||
min-height: 30px;
|
|
||||||
padding-left: 5px;
|
|
||||||
flex: 1;
|
|
||||||
align-items: center;
|
|
||||||
transition: 0.2s;
|
|
||||||
&:hover {
|
|
||||||
color: white;
|
|
||||||
background: rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
&.selected {
|
|
||||||
background: rgba(0, 0, 0, 0.5);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.context {
|
|
||||||
display: flex;
|
|
||||||
background: rgba(0, 0, 0, 0.6);
|
|
||||||
.button {
|
|
||||||
display: flex;
|
|
||||||
margin: 5px;
|
|
||||||
align-content: center;
|
|
||||||
align-items: center;
|
|
||||||
opacity: 0.8;
|
|
||||||
transition: 0.2s;
|
|
||||||
&:hover {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.delete-button {
|
|
||||||
margin: auto;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.CodeMirror-hints {
|
|
||||||
background-color: #33332f !important;
|
|
||||||
border-color: #232321 !important;
|
|
||||||
}
|
|
||||||
.CodeMirror-hint {
|
|
||||||
color: #666 !important;
|
|
||||||
}
|
|
||||||
.CodeMirror-hint-active {
|
|
||||||
background-color: transparent !important;
|
|
||||||
color: #6cb5d9 !important;
|
|
||||||
}
|
|
||||||
.CodeMirror {
|
|
||||||
height: 100% !important;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,300 @@
|
||||||
|
<template>
|
||||||
|
<div class="make-public">
|
||||||
|
<Spinner v-if="details === null" />
|
||||||
|
<div v-else class="main-container" ref="scroll">
|
||||||
|
<div class="notice">
|
||||||
|
<strong>Note:</strong> Making your theme public requires reviewing. This
|
||||||
|
may take some days to review.
|
||||||
|
</div>
|
||||||
|
<ErrorList v-if="errors" :errors="errors" />
|
||||||
|
<div class="container">
|
||||||
|
<div class="block">
|
||||||
|
Theme Status
|
||||||
|
<div v-if="details === false"><strong>Not published</strong></div>
|
||||||
|
<div class="warn" v-else-if="details.updatedCss"><strong>Update Getting Reviewed.</strong></div>
|
||||||
|
<div class="warn" v-else-if="details.approved === false"><strong>Getting Reviewed.</strong></div>
|
||||||
|
<div class="valid" v-else><strong>Theme is public!</strong></div>
|
||||||
|
</div>
|
||||||
|
<div class="block">
|
||||||
|
Name:
|
||||||
|
<div>
|
||||||
|
<strong>{{ name }}</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="block">
|
||||||
|
Theme Preview
|
||||||
|
<div
|
||||||
|
class="preview"
|
||||||
|
:style="{
|
||||||
|
backgroundImage: `url(${update.screenshot || (details ? `${screenshotDomain}${details.screenshot}` : '')})`
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<div class="button" @click="$refs.screenshotBrowser.click()">
|
||||||
|
Upload
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
ref="screenshotBrowser"
|
||||||
|
type="file"
|
||||||
|
accept=".jpeg, .jpg, .png, .gif"
|
||||||
|
class="hidden"
|
||||||
|
@change="screenshotBrowseChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="input">
|
||||||
|
<div class="title" v-if="update.description === undefined && !details">
|
||||||
|
Description (0/150)
|
||||||
|
</div>
|
||||||
|
<div class="title" v-if="update.description !== undefined">
|
||||||
|
Description (<span :class="{ warn: update.description.length > 150}">{{
|
||||||
|
update.description.length
|
||||||
|
}}</span
|
||||||
|
>/150)
|
||||||
|
</div>
|
||||||
|
<div class="title" v-if="update.description === undefined && details">
|
||||||
|
Description (<span :class="{ warn: details.description.length > 150}">{{
|
||||||
|
details.description.length
|
||||||
|
}}</span
|
||||||
|
>/150)
|
||||||
|
</div>
|
||||||
|
<textarea placeholder="Description" :default-value.prop="details.description || ''" @input="descriptionInput" ></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="buttons">
|
||||||
|
<div class="button" @click="backButton">Back</div>
|
||||||
|
<div class="button" v-if="details" @click="updateButton">{{submitClicked ? 'Updating...' : 'Update'}}</div>
|
||||||
|
<div class="button" @click="sendForReviewButton" v-else>{{submitClicked ? 'Sending...' : 'Send For Review'}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Spinner from "@/components/Spinner";
|
||||||
|
import ErrorList from '@/components/app/errorsListTemplate';
|
||||||
|
import path from "path";
|
||||||
|
import config from "@/config.js";
|
||||||
|
import exploreService from "@/services/exploreService";
|
||||||
|
export default {
|
||||||
|
components: { Spinner, ErrorList },
|
||||||
|
props: ["themeID", "name"],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
update: {},
|
||||||
|
errors: null,
|
||||||
|
success: null,
|
||||||
|
details: null,
|
||||||
|
screenshotDomain: config.domain + "/media/",
|
||||||
|
submitClicked: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async updateButton() {
|
||||||
|
this.errors = null;
|
||||||
|
if (this.submitClicked === true) return;
|
||||||
|
this.submitClicked = true;
|
||||||
|
|
||||||
|
const {result, ok, error} = await exploreService.updateTheme(this.themeID, this.update);
|
||||||
|
if (!ok) {
|
||||||
|
if (error.response.data.message) {
|
||||||
|
this.errors = [{msg: error.response.data.message}];
|
||||||
|
} else {
|
||||||
|
this.errors = error.response.data.errors;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.details = result.data;
|
||||||
|
}
|
||||||
|
this.submitClicked = false;
|
||||||
|
this.$refs.scroll.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
|
|
||||||
|
},
|
||||||
|
async sendForReviewButton() {
|
||||||
|
this.errors = null;
|
||||||
|
if (this.submitClicked === true) return;
|
||||||
|
this.submitClicked = true;
|
||||||
|
|
||||||
|
const {result, ok, error} = await exploreService.addTheme(this.themeID, this.update);
|
||||||
|
if (!ok) {
|
||||||
|
if (error.response.data.message) {
|
||||||
|
this.errors = [{msg: error.response.data.message}];
|
||||||
|
} else {
|
||||||
|
this.errors = error.response.data.errors;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.details = result.data;
|
||||||
|
}
|
||||||
|
this.submitClicked = false;
|
||||||
|
this.$refs.scroll.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
|
|
||||||
|
},
|
||||||
|
screenshotBrowseChange(event) {
|
||||||
|
if (!this.googleDriveLinked) {
|
||||||
|
event.target.value = "";
|
||||||
|
return this.$store.dispatch("setPopoutVisibility", {
|
||||||
|
name: "GDLinkMenu",
|
||||||
|
visibility: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const file = event.target.files[0];
|
||||||
|
|
||||||
|
const _this = this;
|
||||||
|
const maxSize = 2092000;
|
||||||
|
if (file.size > maxSize) {
|
||||||
|
return this.$store.dispatch(
|
||||||
|
"setGenericMessage",
|
||||||
|
"Image is larger than 2MB"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
event.target.value = "";
|
||||||
|
const allowedFormats = [".png", ".jpeg", ".gif", ".jpg"];
|
||||||
|
if (!allowedFormats.includes(path.extname(file.name).toLowerCase())) {
|
||||||
|
return this.$store.dispatch(
|
||||||
|
"setGenericMessage",
|
||||||
|
"That file format is not allowed!"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let reader = new FileReader();
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
|
||||||
|
reader.onload = function() {
|
||||||
|
_this.$set(_this.update, "screenshot", reader.result);
|
||||||
|
};
|
||||||
|
reader.onerror = function(error) {
|
||||||
|
console.log("Error: ", error);
|
||||||
|
return this.$store.dispatch(
|
||||||
|
"setGenericMessage",
|
||||||
|
"Something went wrong. Try again later."
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
backButton() {
|
||||||
|
this.$emit("back");
|
||||||
|
},
|
||||||
|
async fetchDetails() {
|
||||||
|
const {ok, error, result} = await exploreService.getTheme(this.themeID);
|
||||||
|
if (!ok && !error.response) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (error){
|
||||||
|
this.details = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.details = result.data;
|
||||||
|
},
|
||||||
|
descriptionInput(event) {
|
||||||
|
this.$set(this.update, 'description', event.target.value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
this.fetchDetails();
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
googleDriveLinked() {
|
||||||
|
return this.$store.getters["settingsModule/settings"].GDriveLinked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.make-public {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.main-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
align-items: center;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.notice {
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
padding: 5px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
background-color: #044050;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 5px;
|
||||||
|
align-self: flex-start;
|
||||||
|
height: 155px;
|
||||||
|
width: 300px;
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
flex-direction: column;
|
||||||
|
.title {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
background: #032d38;
|
||||||
|
resize: none;
|
||||||
|
outline: none;
|
||||||
|
margin-top: 2px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding: 10px;
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.warn {
|
||||||
|
color: rgb(255, 67, 67);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.block {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: #044050;
|
||||||
|
max-width: 300px;
|
||||||
|
margin: 5px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
padding: 10px;
|
||||||
|
align-self: center;
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
transition: 0.2s;
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.preview {
|
||||||
|
height: 150px;
|
||||||
|
width: 300px;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
background-position: center;
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.valid {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
.warn {
|
||||||
|
color: orange;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,162 @@
|
||||||
|
<template>
|
||||||
|
<div class="editing">
|
||||||
|
<div class="bar">
|
||||||
|
<input
|
||||||
|
class="theme-name"
|
||||||
|
v-model="name"
|
||||||
|
type="text"
|
||||||
|
placeholder="Theme name"
|
||||||
|
/>
|
||||||
|
<div class="button" @click="saveButton">
|
||||||
|
<div class="material-icons">save</div>
|
||||||
|
{{savingStatus ? 'Saving...' : 'Save & Apply'}}
|
||||||
|
</div>
|
||||||
|
<div class="button" @click="closeButton">
|
||||||
|
<div class="material-icons">clear</div>
|
||||||
|
Close
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <prism-editor class="editor" v-model="code" language="css"></prism-editor> -->
|
||||||
|
<codemirror
|
||||||
|
class="editor"
|
||||||
|
v-model="code"
|
||||||
|
:options="cmOptions"
|
||||||
|
@ready="onCmReady"
|
||||||
|
/>
|
||||||
|
<div class="notice">
|
||||||
|
<div class="material-icons">warning</div>
|
||||||
|
<div class="notice-message">
|
||||||
|
Warning: Pasting someone elses code could be dangerous.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import "codemirror/mode/css/css.js";
|
||||||
|
|
||||||
|
import "codemirror/addon/hint/show-hint.css";
|
||||||
|
import "codemirror/addon/hint/show-hint.js";
|
||||||
|
import "codemirror/addon/hint/css-hint";
|
||||||
|
// theme css
|
||||||
|
import "codemirror/theme/base16-dark.css";
|
||||||
|
import "codemirror/lib/codemirror.css";
|
||||||
|
import { codemirror } from "vue-codemirror";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { codemirror },
|
||||||
|
props: ['themeName', 'themeCode', 'savingStatus'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
name: '',
|
||||||
|
code: `/* Start writing your styles*/\n`,
|
||||||
|
cmOptions: {
|
||||||
|
// codemirror options
|
||||||
|
tabSize: 2,
|
||||||
|
mode: "text/css",
|
||||||
|
theme: "base16-dark",
|
||||||
|
lineNumbers: true,
|
||||||
|
line: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.themeName) {
|
||||||
|
this.name = this.themeName;
|
||||||
|
}
|
||||||
|
if (this.themeCode) {
|
||||||
|
this.code = this.themeCode
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onCmReady(cm) {
|
||||||
|
cm.on("keypress", () => {
|
||||||
|
cm.showHint({ completeSingle: false });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
saveButton() {
|
||||||
|
this.$emit("save", {name: this.name, css: this.code});
|
||||||
|
},
|
||||||
|
closeButton() {
|
||||||
|
this.$emit("close");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.bar {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
height: 40px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
.button {
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
align-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
&.end {
|
||||||
|
margin: auto;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
.material-icons {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.editing {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
.theme-name {
|
||||||
|
height: 20px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.editor {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.notice {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
align-content: center;
|
||||||
|
background: rgb(255, 54, 54);
|
||||||
|
height: 40px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding-left: 5px;
|
||||||
|
.notice-message {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.CodeMirror-hints {
|
||||||
|
background-color: #33332f !important;
|
||||||
|
border-color: #232321 !important;
|
||||||
|
}
|
||||||
|
.CodeMirror-hint {
|
||||||
|
color: #666 !important;
|
||||||
|
}
|
||||||
|
.CodeMirror-hint-active {
|
||||||
|
background-color: transparent !important;
|
||||||
|
color: #6cb5d9 !important;
|
||||||
|
}
|
||||||
|
.CodeMirror {
|
||||||
|
height: 100% !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -104,6 +104,7 @@ export default {
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 3px;
|
width: 3px;
|
||||||
background: #ffffff5e;
|
background: #ffffff5e;
|
||||||
|
transition: 0.2s;
|
||||||
}
|
}
|
||||||
&.selected::before {
|
&.selected::before {
|
||||||
content: "";
|
content: "";
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@
|
||||||
<i class="material-icons">{{tabs[selectedTab].icon}}</i>
|
<i class="material-icons">{{tabs[selectedTab].icon}}</i>
|
||||||
{{tabs[selectedTab].name}}
|
{{tabs[selectedTab].name}}
|
||||||
</div>
|
</div>
|
||||||
<div class="coming-soon" v-if="selectedTab > 0">
|
<div class="coming-soon" v-if="selectedTab > 1">
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<i class="material-icons">explore</i>
|
<i class="material-icons">explore</i>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -72,20 +72,21 @@
|
||||||
<script>
|
<script>
|
||||||
import { bus } from "@/main";
|
import { bus } from "@/main";
|
||||||
import Servers from "./Explore/servers";
|
import Servers from "./Explore/servers";
|
||||||
|
import Themes from "./Explore/themes";
|
||||||
import ServerService from "@/services/ServerService";
|
import ServerService from "@/services/ServerService";
|
||||||
import Navigation from "@/components/app/Navigation";
|
import Navigation from "@/components/app/Navigation";
|
||||||
import MyMiniInformation from "@/components/app/MyMiniInformation.vue";
|
import MyMiniInformation from "@/components/app/MyMiniInformation.vue";
|
||||||
export default {
|
export default {
|
||||||
components: { Servers, Navigation, MyMiniInformation },
|
components: { Servers, Themes, Navigation, MyMiniInformation },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showLeftPanel: false,
|
showLeftPanel: false,
|
||||||
selectedTab: 0,
|
selectedTab: 0,
|
||||||
tabs: [
|
tabs: [
|
||||||
// {icon: "home", name: "home", component: ""},
|
// {icon: "home", name: "home", component: ""},
|
||||||
{ icon: "rss_feed", name: "Servers", component: "servers" },
|
{ icon: "rss_feed", name: "Servers", component: "Servers" },
|
||||||
|
{ icon: "brush", name: "Themes", component: "Themes" },
|
||||||
{ icon: "face", name: "Emoji Packs", component: "" },
|
{ icon: "face", name: "Emoji Packs", component: "" },
|
||||||
{ icon: "brush", name: "Themes", component: "" },
|
|
||||||
{ icon: "message", name: "Message Styles", component: "" }
|
{ icon: "message", name: "Message Styles", component: "" }
|
||||||
],
|
],
|
||||||
nertiviaServerID: "6572915451527958528",
|
nertiviaServerID: "6572915451527958528",
|
||||||
|
|
@ -168,6 +169,7 @@ export default {
|
||||||
.material-icons {
|
.material-icons {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-content: center;
|
align-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -183,6 +185,15 @@ export default {
|
||||||
background: #053240;
|
background: #053240;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.item:nth-child(2)::before {
|
||||||
|
content: 'NEW';
|
||||||
|
font-size: 14px;
|
||||||
|
background: rgb(255, 55, 55);
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 2px;
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.header {
|
.header {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
87
src/components/app/Tabs/Explore/themes.vue
Normal file
87
src/components/app/Tabs/Explore/themes.vue
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<template>
|
||||||
|
<div class="themes-tab">
|
||||||
|
<div class="items-main-container">
|
||||||
|
<div class="note">Themes below are safe and manually reviewed.</div>
|
||||||
|
<div class="items-container">
|
||||||
|
<spinner class="spinner" v-if="!publicThemes" :size="80"/>
|
||||||
|
<div class="items">
|
||||||
|
<theme-template v-for="theme in publicThemes" :key="theme.id" :theme="theme"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import searchHeader from "./searchHeader";
|
||||||
|
import themeTemplate from './themesTemplate';
|
||||||
|
import exploreService from '@/services/exploreService';
|
||||||
|
import Spinner from "@/components/Spinner";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { searchHeader, themeTemplate, Spinner },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
publicThemes: null,
|
||||||
|
params: '?verified=true'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async getThemesList() {
|
||||||
|
this.publicThemes = null;
|
||||||
|
const {ok, result, error} = await exploreService.getThemes();
|
||||||
|
if (ok) {
|
||||||
|
this.publicThemes = result.data;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getThemesList();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.themes-tab {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.items-main-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
.items-container {
|
||||||
|
display: block;
|
||||||
|
align-content: center;
|
||||||
|
align-items: center;
|
||||||
|
max-width: 1066px;
|
||||||
|
margin: auto;
|
||||||
|
width: 100%;
|
||||||
|
.items {
|
||||||
|
margin-top: 40px;
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 16px;
|
||||||
|
grid-template-columns: repeat(auto-fill, 250px);
|
||||||
|
grid-auto-rows: min-content;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.spinner {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note {
|
||||||
|
background: rgba(52, 116, 255, 0.658);
|
||||||
|
padding: 5px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
238
src/components/app/Tabs/Explore/themesTemplate.vue
Normal file
238
src/components/app/Tabs/Explore/themesTemplate.vue
Normal file
|
|
@ -0,0 +1,238 @@
|
||||||
|
<template>
|
||||||
|
<div class="item">
|
||||||
|
<div class="top">
|
||||||
|
<div
|
||||||
|
@click="bannerImageClicked"
|
||||||
|
class="background-dark"
|
||||||
|
:style="{backgroundImage: `url(${bannerDomain + theme.screenshot}${'?type=png'})`}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="bottom">
|
||||||
|
<div class="name">
|
||||||
|
<div class="name-container">
|
||||||
|
<span class="inner-name">{{theme.theme.name}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="description">{{theme.description}}</div>
|
||||||
|
<div class="buttons">
|
||||||
|
<!-- <div class="stars-button">
|
||||||
|
<div class="material-icons">star</div>
|
||||||
|
{{theme.stars}}
|
||||||
|
</div> -->
|
||||||
|
<div class="button un-apply" v-if="appliedTheme === theme.id" @click="unApplyButton">
|
||||||
|
<span>Unapply</span>
|
||||||
|
</div>
|
||||||
|
<div v-else class="button" @click="applyButton">
|
||||||
|
<span>Apply</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { bus } from "@/main";
|
||||||
|
import Spinner from "@/components/Spinner";
|
||||||
|
import config from "@/config.js";
|
||||||
|
import exploreService from '@/services/exploreService';
|
||||||
|
export default {
|
||||||
|
props: ["theme"],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
joinClicked: false,
|
||||||
|
bannerDomain: config.domain + "/media/",
|
||||||
|
appliedTheme: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async applyButton() {
|
||||||
|
// get css
|
||||||
|
const {ok, error, result} = await exploreService.applyTheme(this.theme.id);
|
||||||
|
if (ok) {
|
||||||
|
const css = result.data.css;
|
||||||
|
const id = result.data.id;
|
||||||
|
// save to local storage.
|
||||||
|
localStorage.setItem("appliedThemeId", id);
|
||||||
|
|
||||||
|
const styleEl = document.createElement("style");
|
||||||
|
styleEl.classList.add("theme-" + id);
|
||||||
|
styleEl.id = "theme";
|
||||||
|
styleEl.innerHTML = css;
|
||||||
|
|
||||||
|
const currentStyle = document.getElementById("theme");
|
||||||
|
if (currentStyle) {
|
||||||
|
currentStyle.outerHTML = styleEl.outerHTML;
|
||||||
|
} else {
|
||||||
|
document.head.innerHTML += styleEl.outerHTML;
|
||||||
|
}
|
||||||
|
this.appliedTheme = id;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bannerImageClicked() {
|
||||||
|
this.$store.dispatch(
|
||||||
|
"setImagePreviewURL",
|
||||||
|
this.bannerDomain + this.theme.screenshot + '?type=png'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
unApplyButton () {
|
||||||
|
this.appliedTheme = null;
|
||||||
|
localStorage.removeItem("appliedThemeId");
|
||||||
|
document.getElementById("theme").outerHTML = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.appliedTheme = localStorage.getItem("appliedThemeId");
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.item {
|
||||||
|
position: relative;
|
||||||
|
width: 250px;
|
||||||
|
height: 350px;
|
||||||
|
background: #024253;
|
||||||
|
opacity: 0.9;
|
||||||
|
margin: 5px;
|
||||||
|
border-radius: 4px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
transition: 0.3s;
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.top {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
height: 150px;
|
||||||
|
justify-content: center;
|
||||||
|
align-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
position: relative;
|
||||||
|
.background-dark {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
background-position: center;
|
||||||
|
background-size: cover;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.avatar {
|
||||||
|
background: rgb(26, 133, 255);
|
||||||
|
height: 80px;
|
||||||
|
width: 80px;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.bottom {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: #04333F;
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
.name {
|
||||||
|
margin-top: 9px;
|
||||||
|
font-size: 21px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
z-index: 999;
|
||||||
|
.name-container {
|
||||||
|
display: flex;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
.inner-name {
|
||||||
|
max-width: 200px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.material-icons {
|
||||||
|
color: #66e0ff;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
margin: 10px;
|
||||||
|
flex: 1;
|
||||||
|
opacity: 0.9;
|
||||||
|
overflow: auto;
|
||||||
|
font-size: 14px;
|
||||||
|
word-break: break-word;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.stars-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
align-content: center;
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-top: 0px;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-right: 10px;
|
||||||
|
transition: 0.2s;
|
||||||
|
flex: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
background: #ff501bd7;
|
||||||
|
&:hover {
|
||||||
|
background: #ff501b;
|
||||||
|
}
|
||||||
|
.material-icons {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: rgba(0, 179, 219, 0.8);
|
||||||
|
transition: 0.2s;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
background: #00B4DB;
|
||||||
|
}
|
||||||
|
&.selected {
|
||||||
|
background: grey;
|
||||||
|
}
|
||||||
|
&.un-apply {
|
||||||
|
background: rgba(255, 53, 53, 0.808);
|
||||||
|
&:hover {
|
||||||
|
background:rgb(255, 53, 53);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import {instance, wrapper} from './Api';
|
import {instance, wrapper} from './Api';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
// servers
|
||||||
getServersList (params) {
|
getServersList (params) {
|
||||||
return wrapper(instance().get(`explore/servers${params || ''}`))
|
return wrapper(instance().get(`explore/servers${params || ''}`))
|
||||||
},
|
},
|
||||||
|
|
@ -17,4 +18,22 @@ export default {
|
||||||
return wrapper(instance().post(`explore/servers`, data))
|
return wrapper(instance().post(`explore/servers`, data))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// themes
|
||||||
|
getThemes() {
|
||||||
|
return wrapper(instance().get(`explore/themes`));
|
||||||
|
},
|
||||||
|
getTheme(id) {
|
||||||
|
return wrapper(instance().get(`explore/themes/${id}`));
|
||||||
|
},
|
||||||
|
addTheme(id, data) {
|
||||||
|
return wrapper(instance().post(`explore/themes/${id}`, data))
|
||||||
|
},
|
||||||
|
updateTheme(id, data) {
|
||||||
|
return wrapper(instance().patch(`explore/themes/${id}`, data))
|
||||||
|
},
|
||||||
|
applyTheme(id) {
|
||||||
|
return wrapper(instance().get(`explore/themes/${id}/apply`));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -9,12 +9,22 @@ const prototype = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const config = [
|
const config = [
|
||||||
|
{
|
||||||
|
version: 8.9,
|
||||||
|
title: "Public Themes!",
|
||||||
|
shortTitle: "",
|
||||||
|
date: "7/21/2019",
|
||||||
|
headColor: "#007792",
|
||||||
|
new: [
|
||||||
|
"You can now make your themes public! Note: Making your theme public will require reviewing which may take few hours or days.",
|
||||||
|
],
|
||||||
|
|
||||||
|
},
|
||||||
{
|
{
|
||||||
version: 8.8,
|
version: 8.8,
|
||||||
title: "Themes!",
|
title: "Themes!",
|
||||||
shortTitle: "",
|
shortTitle: "",
|
||||||
date: "29/11/2019",
|
date: "29/11/2019",
|
||||||
headColor: "#007792",
|
|
||||||
new: [
|
new: [
|
||||||
"You can now create your own themes in the settings popout using css! (You cannot share themes for now, that feature is coming soon though!)",
|
"You can now create your own themes in the settings popout using css! (You cannot share themes for now, that feature is coming soon though!)",
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ import ConnectingScreen from "./../components/app/ConnectingScreen.vue";
|
||||||
import Spinner from "./../components/Spinner.vue";
|
import Spinner from "./../components/Spinner.vue";
|
||||||
import MainNav from "./../components/app/MainNav.vue";
|
import MainNav from "./../components/app/MainNav.vue";
|
||||||
import ThemeService from '../services/ThemeService';
|
import ThemeService from '../services/ThemeService';
|
||||||
|
import ExploreService from '../services/exploreService';
|
||||||
|
|
||||||
const ElectronFrameButtons = () =>
|
const ElectronFrameButtons = () =>
|
||||||
import("@/components/ElectronJS/FrameButtons.vue");
|
import("@/components/ElectronJS/FrameButtons.vue");
|
||||||
|
|
@ -128,12 +129,26 @@ export default {
|
||||||
|
|
||||||
|
|
||||||
if (!themeAppliedID) {return;}
|
if (!themeAppliedID) {return;}
|
||||||
const {ok, result, error} = await ThemeService.getTheme(themeAppliedID);
|
let exploreThemes = await ExploreService.applyTheme(themeAppliedID);
|
||||||
if (!ok) { return; }
|
let privateThemes;
|
||||||
|
if (!exploreThemes.ok) {
|
||||||
|
privateThemes = await ThemeService.getTheme(themeAppliedID);
|
||||||
|
}
|
||||||
|
let id;
|
||||||
|
let css;
|
||||||
|
if (exploreThemes.ok) {
|
||||||
|
css = exploreThemes.result.data.css;
|
||||||
|
id = exploreThemes.result.data.id;
|
||||||
|
}
|
||||||
|
if (privateThemes) {
|
||||||
|
css = privateThemes.result.data.css;
|
||||||
|
id = privateThemes.result.data.id;
|
||||||
|
}
|
||||||
|
if (!id && !css) {return}
|
||||||
const styleEl = document.createElement('style');
|
const styleEl = document.createElement('style');
|
||||||
styleEl.id = "theme"
|
styleEl.id = "theme"
|
||||||
styleEl.classList.add('theme-' + result.data.id)
|
styleEl.classList.add('theme-' + id)
|
||||||
styleEl.innerHTML = result.data.css
|
styleEl.innerHTML = css
|
||||||
document.head.innerHTML += styleEl.outerHTML;
|
document.head.innerHTML += styleEl.outerHTML;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue