Getting things ready for dnd
This commit is contained in:
parent
5875b69089
commit
168d683b13
BIN
client/public/modules/dnd-5e/icon.png
Normal file
BIN
client/public/modules/dnd-5e/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 82 KiB |
12
client/public/modules/dnd-5e/module.json
Normal file
12
client/public/modules/dnd-5e/module.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"id": "dnd-5e",
|
||||||
|
"title": "Dungeons & Dragons 5e",
|
||||||
|
"description": "Dungeons & Dragons Fifth edition game system support",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Aran Roig"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": "1.0.0",
|
||||||
|
"color": "#e92026"
|
||||||
|
}
|
@ -6,10 +6,43 @@ import { RouterLink, RouterView } from 'vue-router'
|
|||||||
import { GetUser, UserStatus, LoadUser } from '@/services/User.js'
|
import { GetUser, UserStatus, LoadUser } from '@/services/User.js'
|
||||||
import { IsAdmin } from './services/User'
|
import { IsAdmin } from './services/User'
|
||||||
|
|
||||||
|
import useEmitter from '@/services/Emitter';
|
||||||
|
const emitter = useEmitter();
|
||||||
|
|
||||||
|
import { DisplayToast, SetEmitter } from './services/Dragonroll'
|
||||||
|
import { ImportModule, GetModulesToLoad } from './services/Modules'
|
||||||
|
import { CreateWindow } from './services/Windows';
|
||||||
|
|
||||||
console.clear();
|
console.clear();
|
||||||
console.log("%cLoaded!!!", "color: #22ff22; font-size: 24px");
|
console.log("%cLoaded!!!", "color: #22ff22; font-size: 24px");
|
||||||
LoadUser();
|
LoadUser();
|
||||||
|
|
||||||
|
SetEmitter(emitter);
|
||||||
|
onMounted(() => {
|
||||||
|
async function preloadModules(){
|
||||||
|
const modules = GetModulesToLoad();
|
||||||
|
let moduleLoads = [];
|
||||||
|
|
||||||
|
modules.forEach(moduleName => {
|
||||||
|
moduleLoads.push(ImportModule(moduleName));
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(moduleLoads);
|
||||||
|
DisplayToast('aqua', 'All modules loaded successfully');
|
||||||
|
|
||||||
|
if(GetUser()){
|
||||||
|
CreateWindow('main_menu')
|
||||||
|
// CreateWindow('test');
|
||||||
|
DisplayToast('green', 'Logged in successfully as ' + GetUser().username + '!', 3000)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CreateWindow('login');
|
||||||
|
}
|
||||||
|
|
||||||
|
preloadModules();
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -164,4 +164,4 @@ button:active {
|
|||||||
|
|
||||||
.param-value {
|
.param-value {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
@ -27,14 +27,11 @@ import 'prismjs/components/prism-csharp';
|
|||||||
import 'prismjs/components/prism-ruby';
|
import 'prismjs/components/prism-ruby';
|
||||||
import 'prismjs/components/prism-bash';
|
import 'prismjs/components/prism-bash';
|
||||||
|
|
||||||
|
|
||||||
VueMarkdownEditor.lang.use('es-Es', esEs);
|
VueMarkdownEditor.lang.use('es-Es', esEs);
|
||||||
VueMarkdownEditor.use(vuepressTheme, { Prism });
|
VueMarkdownEditor.use(vuepressTheme, { Prism });
|
||||||
VueMarkdownEditor.use(createKatexPlugin());
|
VueMarkdownEditor.use(createKatexPlugin());
|
||||||
|
|
||||||
const app = createApp(App).use(VueMarkdownEditor);
|
const app = createApp(App).use(VueMarkdownEditor);
|
||||||
|
|
||||||
|
|
||||||
app.config.globalProperties.emitter = emitter
|
app.config.globalProperties.emitter = emitter
|
||||||
app.config.globalProperties.rollWindows = {
|
app.config.globalProperties.rollWindows = {
|
||||||
login: reactive([]),
|
login: reactive([]),
|
||||||
@ -46,4 +43,5 @@ app.config.globalProperties.rollWindows = {
|
|||||||
|
|
||||||
app.use(router)
|
app.use(router)
|
||||||
|
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import Api from '@/services/Api'
|
|||||||
import { backendUrl } from './BackendURL';
|
import { backendUrl } from './BackendURL';
|
||||||
import { GetUser } from './User';
|
import { GetUser } from './User';
|
||||||
import { ExitGame } from './Game';
|
import { ExitGame } from './Game';
|
||||||
|
import { GetModule } from './Modules';
|
||||||
|
|
||||||
let emitter;
|
let emitter;
|
||||||
|
|
||||||
@ -12,6 +13,8 @@ function SetEmitter(newEmitter){
|
|||||||
emitter = newEmitter
|
emitter = newEmitter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let GetEmitter = () => emitter;
|
||||||
|
|
||||||
function DisplayToast(color, text, duration = 1000){
|
function DisplayToast(color, text, duration = 1000){
|
||||||
emitter.emit("toast", {color, text, duration});
|
emitter.emit("toast", {color, text, duration});
|
||||||
}
|
}
|
||||||
@ -109,8 +112,13 @@ function GetPlayer(player_campaign){
|
|||||||
if(index != -1) return players.value[index];
|
if(index != -1) return players.value[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function GetSystem(){
|
||||||
|
if(currentCampaign) return GetModule(currentCampaign.system)
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
SetEmitter,
|
SetEmitter,
|
||||||
|
GetEmitter,
|
||||||
|
|
||||||
DisplayToast,
|
DisplayToast,
|
||||||
|
|
||||||
@ -122,6 +130,7 @@ export {
|
|||||||
GetClient,
|
GetClient,
|
||||||
GetPlayerList,
|
GetPlayerList,
|
||||||
GetPlayer,
|
GetPlayer,
|
||||||
|
GetSystem,
|
||||||
|
|
||||||
GetChatRef,
|
GetChatRef,
|
||||||
SendMessage
|
SendMessage
|
||||||
|
32
client/src/services/Modules.js
Normal file
32
client/src/services/Modules.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
let modulesToLoad = [
|
||||||
|
"dnd-5e"
|
||||||
|
]
|
||||||
|
let modules = [];
|
||||||
|
|
||||||
|
async function GetJson(url){
|
||||||
|
let obj = await (await fetch(url)).json();
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ImportModule(moduleFolder) {
|
||||||
|
let moduleInfo = await GetJson('/modules/' + moduleFolder + '/module.json');
|
||||||
|
modules.push(moduleInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
let GetModules = () => modules;
|
||||||
|
let GetModulesToLoad = () => modulesToLoad;
|
||||||
|
|
||||||
|
function GetModule(id){
|
||||||
|
let module = null;
|
||||||
|
modules.forEach(mod => {
|
||||||
|
if(mod.id == id) module = mod;
|
||||||
|
})
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
ImportModule,
|
||||||
|
GetModules,
|
||||||
|
GetModule,
|
||||||
|
GetModulesToLoad,
|
||||||
|
}
|
@ -4,6 +4,11 @@ import { Disconnect } from './Dragonroll';
|
|||||||
const windows = ref([])
|
const windows = ref([])
|
||||||
|
|
||||||
const defValues = {
|
const defValues = {
|
||||||
|
'test': {
|
||||||
|
id: "example",
|
||||||
|
title: "Example",
|
||||||
|
close: true
|
||||||
|
},
|
||||||
'login': {
|
'login': {
|
||||||
id: 'login',
|
id: 'login',
|
||||||
title: 'Login',
|
title: 'Login',
|
||||||
@ -74,6 +79,11 @@ const defValues = {
|
|||||||
id: 'environment',
|
id: 'environment',
|
||||||
title: 'Edit environment',
|
title: 'Edit environment',
|
||||||
close: true
|
close: true
|
||||||
|
},
|
||||||
|
'system_selector': {
|
||||||
|
id: 'system-selector',
|
||||||
|
title: "Select a game system",
|
||||||
|
close: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,8 +224,8 @@ function ClearAll(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ClearWindows(data){
|
function ClearWindows(data){
|
||||||
for (let i = 0; i < windows[data.type].value.length; i++) {
|
for (let i = 0; i < windows.value.length; i++) {
|
||||||
ClearWindow(windows[data.type].value[i].id);
|
ClearWindow(windows.value[i].id);
|
||||||
}
|
}
|
||||||
// reload.value += 1;
|
// reload.value += 1;
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,6 @@
|
|||||||
import { onMounted } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
import { RouterLink, RouterView } from 'vue-router'
|
import { RouterLink, RouterView } from 'vue-router'
|
||||||
|
|
||||||
import useEmitter from '@/services/Emitter';
|
|
||||||
const emitter = useEmitter();
|
|
||||||
|
|
||||||
import WindowManager from '@/views/managers/WindowManager.vue'
|
import WindowManager from '@/views/managers/WindowManager.vue'
|
||||||
import { GetUser } from '@/services/User'
|
import { GetUser } from '@/services/User'
|
||||||
|
|
||||||
@ -13,17 +10,6 @@ import Toast from './partials/Toast.vue';
|
|||||||
import { DisplayToast, SetEmitter } from '../services/Dragonroll';
|
import { DisplayToast, SetEmitter } from '../services/Dragonroll';
|
||||||
import GameManager from './managers/GameManager.vue';
|
import GameManager from './managers/GameManager.vue';
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
SetEmitter(emitter);
|
|
||||||
if(GetUser()){
|
|
||||||
CreateWindow('main_menu')
|
|
||||||
DisplayToast('green', 'Logged in successfully as ' + GetUser().username + '!', 3000)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CreateWindow('login');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -19,12 +19,14 @@ import ChatWindow from '../windows/game/ChatWindow.vue'
|
|||||||
import DiceWindow from '../windows/game/DiceWindow.vue'
|
import DiceWindow from '../windows/game/DiceWindow.vue'
|
||||||
import MapButtons from '../windows/dm/MapButtons.vue'
|
import MapButtons from '../windows/dm/MapButtons.vue'
|
||||||
import EnvironmentWindow from '../windows/dm/EnvironmentWindow.vue'
|
import EnvironmentWindow from '../windows/dm/EnvironmentWindow.vue'
|
||||||
|
import SystemSelectorWindow from '../windows/campaigns/SystemSelectorWindow.vue'
|
||||||
|
|
||||||
// Gestionem ventanas
|
// Gestionem ventanas
|
||||||
const reload = ReloadRef();
|
const reload = ReloadRef();
|
||||||
const windows = Windows();
|
const windows = Windows();
|
||||||
|
|
||||||
const WindowMap = {
|
const WindowMap = {
|
||||||
|
test: ExampleWindow,
|
||||||
login: LoginWindow,
|
login: LoginWindow,
|
||||||
main_menu: MainMenuWindow,
|
main_menu: MainMenuWindow,
|
||||||
register: RegisterWindow,
|
register: RegisterWindow,
|
||||||
@ -37,7 +39,8 @@ const WindowMap = {
|
|||||||
chat: ChatWindow,
|
chat: ChatWindow,
|
||||||
dice_menu: DiceWindow,
|
dice_menu: DiceWindow,
|
||||||
map_buttons: MapButtons,
|
map_buttons: MapButtons,
|
||||||
environment: EnvironmentWindow
|
environment: EnvironmentWindow,
|
||||||
|
system_selector: SystemSelectorWindow
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
68
client/src/views/partials/GameSystem.vue
Normal file
68
client/src/views/partials/GameSystem.vue
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<script setup>
|
||||||
|
import { inject, onMounted, ref } from 'vue';
|
||||||
|
import { GetEmitter } from '../../services/Dragonroll';
|
||||||
|
|
||||||
|
const props = defineProps(['data']);
|
||||||
|
const data = props.data;
|
||||||
|
|
||||||
|
const title = ref("");
|
||||||
|
const image = ref(null);
|
||||||
|
|
||||||
|
const clearParent = inject('clearParent');
|
||||||
|
|
||||||
|
function Select(){
|
||||||
|
if(data.id){
|
||||||
|
GetEmitter().emit("select", data.id);
|
||||||
|
clearParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
title.value = data.title;
|
||||||
|
image.value.src = "modules/" + data.id + "/icon.png"
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="system-container" v-on:click="Select">
|
||||||
|
<img class="system-icon" ref="image">
|
||||||
|
<div class="system-content">
|
||||||
|
<span class="title">{{ title }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.system-content {
|
||||||
|
margin-left: 10px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: left;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.system-container {
|
||||||
|
display: flex;
|
||||||
|
padding: 10px;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
transition: background-color .2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--color-background-softer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.system-icon {
|
||||||
|
width: 32px;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
</style>
|
75
client/src/views/partials/SystemSelector.vue
Normal file
75
client/src/views/partials/SystemSelector.vue
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, onUpdated, provide, ref, watch } from 'vue';
|
||||||
|
import { SetupHandle, SetSize, SetPosition, ResetPosition } from '@/services/Windows';
|
||||||
|
import { CreateChildWindow } from '../../services/Windows';
|
||||||
|
import { GetModules } from '../../services/Modules';
|
||||||
|
|
||||||
|
const selectedSystem = ref("");
|
||||||
|
const selectedImage = ref(null);
|
||||||
|
const systemTitle = ref("")
|
||||||
|
|
||||||
|
const props = defineProps(['windowId']);
|
||||||
|
let windowId = props.windowId;
|
||||||
|
|
||||||
|
function DisplaySystemSelector(){
|
||||||
|
CreateChildWindow(windowId, 'system_selector');
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ selectedSystem });
|
||||||
|
|
||||||
|
watch(selectedSystem, () => {
|
||||||
|
let modules = GetModules();
|
||||||
|
let module = null;
|
||||||
|
modules.forEach(mod => {
|
||||||
|
if(mod.id == selectedSystem.value) module = mod;
|
||||||
|
});
|
||||||
|
if(module){
|
||||||
|
selectedImage.value.src = "modules/" + module.id + "/icon.png"
|
||||||
|
systemTitle.value = module.title;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="system-selector" v-on:click="DisplaySystemSelector">
|
||||||
|
<span v-show="selectedSystem == ''" class="none">No game system selected</span>
|
||||||
|
<div v-show="selectedSystem != ''" class="yes">
|
||||||
|
<img ref="selectedImage" class="system-icon">
|
||||||
|
{{ systemTitle }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
|
||||||
|
.system-selector {
|
||||||
|
user-select: none;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
|
||||||
|
padding: 14px;
|
||||||
|
font-size: 15px;
|
||||||
|
border-radius: 6px;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
transition: 300ms background-color;
|
||||||
|
background-color: var(--color-background-softer);
|
||||||
|
color: var(--color-text);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.none {
|
||||||
|
color: var(--text-disabled)
|
||||||
|
}
|
||||||
|
.yes {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.system-icon {
|
||||||
|
width: 32px;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
</style>
|
@ -8,7 +8,16 @@ const emitter = useEmitter();
|
|||||||
const text = ref("");
|
const text = ref("");
|
||||||
const toast = ref(null);
|
const toast = ref(null);
|
||||||
|
|
||||||
emitter.on('toast', data => {
|
let toastQueue = [];
|
||||||
|
let displayingToast = false;
|
||||||
|
|
||||||
|
function DisplayToast(){
|
||||||
|
if(displayingToast) return;
|
||||||
|
if(toastQueue.length == 0) return;
|
||||||
|
|
||||||
|
displayingToast = true;
|
||||||
|
let data = toastQueue.pop();
|
||||||
|
|
||||||
text.value = data.text;
|
text.value = data.text;
|
||||||
|
|
||||||
toast.value.classList.add(data.color);
|
toast.value.classList.add(data.color);
|
||||||
@ -20,8 +29,15 @@ emitter.on('toast', data => {
|
|||||||
toast.value.classList.remove("show");
|
toast.value.classList.remove("show");
|
||||||
toast.value.classList.remove("sliding");
|
toast.value.classList.remove("sliding");
|
||||||
toast.value.classList.remove(data.color);
|
toast.value.classList.remove(data.color);
|
||||||
|
displayingToast = false;
|
||||||
|
DisplayToast();
|
||||||
}, 400);
|
}, 400);
|
||||||
}, data.duration);
|
}, data.duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
emitter.on('toast', data => {
|
||||||
|
toastQueue.push(data);
|
||||||
|
DisplayToast();
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -28,7 +28,6 @@ onMounted(() => {
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.book-list {
|
.book-list {
|
||||||
height: 100%;
|
|
||||||
background-color: var(--color-background);
|
background-color: var(--color-background);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, onUpdated, ref } from 'vue';
|
import { onMounted, onUpdated, ref, compile, render, h } from 'vue';
|
||||||
import { SetupHandle, SetSize, SetPosition, ResetPosition } from '@/services/Windows';
|
import { SetupHandle, SetSize, SetPosition, ResetPosition } from '@/services/Windows';
|
||||||
|
|
||||||
import WindowHandle from '@/views/partials/WindowHandle.vue';
|
import WindowHandle from '@/views/partials/WindowHandle.vue';
|
||||||
@ -10,6 +10,9 @@ const props = defineProps(['data']);
|
|||||||
const data = props.data;
|
const data = props.data;
|
||||||
|
|
||||||
let id = data.id;
|
let id = data.id;
|
||||||
|
|
||||||
|
const test = ref(null)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
SetupHandle(id, handle);
|
SetupHandle(id, handle);
|
||||||
SetSize(id, {x: 500, y: 380});
|
SetSize(id, {x: 500, y: 380});
|
||||||
@ -23,6 +26,7 @@ onMounted(() => {
|
|||||||
<WindowHandle :window="id" ref="handle"></WindowHandle>
|
<WindowHandle :window="id" ref="handle"></WindowHandle>
|
||||||
|
|
||||||
<!-- Body -->
|
<!-- Body -->
|
||||||
|
<div ref="test"></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -30,29 +34,9 @@ onMounted(() => {
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.window-wrapper {
|
.window-wrapper {
|
||||||
min-width: 700px;
|
|
||||||
min-height: 630px;
|
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.splash-image {
|
|
||||||
width: 600px;
|
|
||||||
height: 250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-field {
|
|
||||||
padding: 10px;
|
|
||||||
display: flex;
|
|
||||||
align-items: left;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: left;
|
|
||||||
width: 600px;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import { CreateWindow, CreateChildWindow } from '../../../services/Windows';
|
|||||||
|
|
||||||
import Api from '@/services/Api.js'
|
import Api from '@/services/Api.js'
|
||||||
import CampaignEntry from '../../partials/CampaignEntry.vue';
|
import CampaignEntry from '../../partials/CampaignEntry.vue';
|
||||||
|
import { GetEmitter } from '../../../services/Dragonroll';
|
||||||
|
|
||||||
const handle = ref(null);
|
const handle = ref(null);
|
||||||
|
|
||||||
@ -23,6 +24,8 @@ onMounted(() => {
|
|||||||
ResetPosition(id, "center");
|
ResetPosition(id, "center");
|
||||||
|
|
||||||
RefreshCampaigns();
|
RefreshCampaigns();
|
||||||
|
|
||||||
|
GetEmitter().on('refresh_campaign', () => { RefreshCampaigns() });
|
||||||
});
|
});
|
||||||
|
|
||||||
function CreateCampaign(){
|
function CreateCampaign(){
|
||||||
|
@ -10,6 +10,8 @@ import { ClearAll, ClearWindow, CreateWindow } from '../../../services/Windows';
|
|||||||
import { LaunchGame } from '../../../services/Game';
|
import { LaunchGame } from '../../../services/Game';
|
||||||
import { AddSound } from '../../../services/Sound';
|
import { AddSound } from '../../../services/Sound';
|
||||||
import ChatComponent from '../../partials/ChatComponent.vue';
|
import ChatComponent from '../../partials/ChatComponent.vue';
|
||||||
|
import GameSystem from '@/views/partials/GameSystem.vue'
|
||||||
|
import { GetModule } from '../../../services/Modules';
|
||||||
|
|
||||||
const handle = ref(null);
|
const handle = ref(null);
|
||||||
|
|
||||||
@ -18,6 +20,7 @@ const data = props.data;
|
|||||||
|
|
||||||
const hide_start = ref(false);
|
const hide_start = ref(false);
|
||||||
const hide_chat = ref(false);
|
const hide_chat = ref(false);
|
||||||
|
const campaign_title = ref(null);
|
||||||
|
|
||||||
const container = ref(null);
|
const container = ref(null);
|
||||||
|
|
||||||
@ -37,6 +40,8 @@ onMounted(() => {
|
|||||||
hide_start.value = data.hide_start;
|
hide_start.value = data.hide_start;
|
||||||
|
|
||||||
AddSound(container.value)
|
AddSound(container.value)
|
||||||
|
|
||||||
|
campaign_title.value.style.backgroundColor = GetModule(data.campaign.system).color ? GetModule(data.campaign.system).color : "#1f1f1f";
|
||||||
});
|
});
|
||||||
|
|
||||||
function CopyCode(){
|
function CopyCode(){
|
||||||
@ -74,10 +79,10 @@ function Exit(){
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="campaign-preview-column center">
|
<div class="campaign-preview-column center">
|
||||||
<h1 class="campaign-title">{{ data.campaign.name }}</h1>
|
<h1 class="campaign-title" ref="campaign_title">{{ data.campaign.name }}</h1>
|
||||||
<div class="campaign-main-container">
|
<div class="campaign-main-container">
|
||||||
<div class="campaign-main-container-scroll">
|
<div class="campaign-main-container-scroll">
|
||||||
<div class="">Dnd 5e</div>
|
<GameSystem :data="GetModule(data.campaign.system)"></GameSystem>
|
||||||
<h2>Books</h2>
|
<h2>Books</h2>
|
||||||
<CampaignBookList class="small-book-list"></CampaignBookList>
|
<CampaignBookList class="small-book-list"></CampaignBookList>
|
||||||
</div>
|
</div>
|
||||||
@ -98,7 +103,6 @@ function Exit(){
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.small-book-list {
|
.small-book-list {
|
||||||
height: 400px;
|
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
@ -137,10 +141,10 @@ function Exit(){
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 3fr 5fr 4fr;
|
grid-template-columns: 2fr 4fr 3fr;
|
||||||
|
|
||||||
&.campaign-preview-compact {
|
&.campaign-preview-compact {
|
||||||
grid-template-columns: 2fr 3fr;
|
grid-template-columns: 2fr 4fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,4 +177,8 @@ h1, h2 {
|
|||||||
font-family: MrEavesRemake;
|
font-family: MrEavesRemake;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
background-color: rgb(143, 39, 39);
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, onUpdated, ref } from 'vue';
|
import { onMounted, onUpdated, ref, provide } from 'vue';
|
||||||
import { SetupHandle, SetSize, SetPosition, ResetPosition } from '@/services/Windows';
|
import { SetupHandle, SetSize, SetPosition, ResetPosition, ClearWindow } from '@/services/Windows';
|
||||||
|
|
||||||
import WindowHandle from '@/views/partials/WindowHandle.vue';
|
import WindowHandle from '@/views/partials/WindowHandle.vue';
|
||||||
|
import ErrorMessage from '@/components/partials/ErrorMessage.vue'
|
||||||
|
|
||||||
import Api from '@/services/Api.js'
|
import Api from '@/services/Api.js'
|
||||||
|
import SystemSelector from '../../partials/SystemSelector.vue';
|
||||||
|
import { GetEmitter } from '../../../services/Dragonroll';
|
||||||
|
|
||||||
const handle = ref(null);
|
const handle = ref(null);
|
||||||
|
|
||||||
@ -12,20 +15,41 @@ const props = defineProps(['data']);
|
|||||||
const data = props.data;
|
const data = props.data;
|
||||||
|
|
||||||
const campaignName = ref("");
|
const campaignName = ref("");
|
||||||
|
const systemSelector = ref(null);
|
||||||
|
|
||||||
|
const errorMessage = ref("");
|
||||||
|
|
||||||
let id = data.id;
|
let id = data.id;
|
||||||
|
let system = "";
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
SetupHandle(id, handle);
|
SetupHandle(id, handle);
|
||||||
SetSize(id, {x: 300, y: 150});
|
SetSize(id, {x: 300, y: 240});
|
||||||
ResetPosition(id, "center");
|
ResetPosition(id, "center");
|
||||||
|
GetEmitter().on('select', (system_id) => Select(system_id))
|
||||||
|
|
||||||
|
console.log(system);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function Select(system_id){
|
||||||
|
system = system_id;
|
||||||
|
try {
|
||||||
|
systemSelector.value.selectedSystem = system_id;
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function NewCampaign(){
|
function NewCampaign(){
|
||||||
Api().post('/campaign/create', {
|
Api().post('/campaign/create', {
|
||||||
name: campaignName.value
|
name: campaignName.value,
|
||||||
|
system
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
console.log(response);
|
if(response.data.status == "error"){
|
||||||
|
errorMessage.value = response.data.msg;
|
||||||
|
} else {
|
||||||
|
ClearWindow(id);
|
||||||
|
GetEmitter().emit('refresh_campaign');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -40,10 +64,15 @@ function NewCampaign(){
|
|||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<input id="username-field" type="text" placeholder="Enter campaign name..." name="campaignName" v-model="campaignName" autocomplete="off" >
|
<input id="username-field" type="text" placeholder="Enter campaign name..." name="campaignName" v-model="campaignName" autocomplete="off" >
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-field">
|
||||||
|
<SystemSelector :windowId="id" ref="systemSelector"></SystemSelector>
|
||||||
|
</div>
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<button class="btn-primary sound-click">Create</button>
|
<button class="btn-primary sound-click">Create</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<ErrorMessage v-if="errorMessage">{{ errorMessage }}</ErrorMessage>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
63
client/src/views/windows/campaigns/SystemSelectorWindow.vue
Normal file
63
client/src/views/windows/campaigns/SystemSelectorWindow.vue
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, onUpdated, provide, ref, inject } from 'vue';
|
||||||
|
import { SetupHandle, SetSize, SetPosition, ResetPosition } from '@/services/Windows';
|
||||||
|
|
||||||
|
import WindowHandle from '@/views/partials/WindowHandle.vue';
|
||||||
|
|
||||||
|
import Api from '@/services/Api.js'
|
||||||
|
import SystemSelector from '../../partials/SystemSelector.vue';
|
||||||
|
import { GetModules } from '../../../services/Modules';
|
||||||
|
import GameSystem from '../../partials/GameSystem.vue';
|
||||||
|
import { ClearWindow } from '../../../services/Windows';
|
||||||
|
|
||||||
|
const handle = ref(null);
|
||||||
|
|
||||||
|
const props = defineProps(['data']);
|
||||||
|
const data = props.data;
|
||||||
|
|
||||||
|
const campaignName = ref("");
|
||||||
|
|
||||||
|
let id = data.id;
|
||||||
|
let systems = ref(GetModules());
|
||||||
|
|
||||||
|
function Clear(){
|
||||||
|
ClearWindow(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
provide('clearParent', Clear);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
SetupHandle(id, handle);
|
||||||
|
SetSize(id, {x: 300, y: 600});
|
||||||
|
ResetPosition(id, "center");
|
||||||
|
|
||||||
|
console.log(systems.value)
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="window-wrapper" :id="'window-wrapper-' + id">
|
||||||
|
<WindowHandle :window="id" ref="handle"></WindowHandle>
|
||||||
|
|
||||||
|
<!-- Body -->
|
||||||
|
<div class="system-list">
|
||||||
|
<GameSystem v-for="system in systems" :id="system.id" :data="system"></GameSystem>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.window-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.system-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -11,6 +11,7 @@ export default defineConfig({
|
|||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||||
|
'vue': 'vue/dist/vue.esm-bundler.js'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
proxy: {
|
proxy: {
|
||||||
|
12
server/models/Book.js
Normal file
12
server/models/Book.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
const mongoose = require("mongoose");
|
||||||
|
const Schema = mongoose.Schema;
|
||||||
|
|
||||||
|
const BookSchema = new Schema({
|
||||||
|
title: {type: String, required: true},
|
||||||
|
authors: { type: [String] },
|
||||||
|
system: {type: String, required: true},
|
||||||
|
image: { type: String },
|
||||||
|
data: { type: Object },
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = mongoose.model('Book', BookSchema);
|
@ -3,6 +3,7 @@ const Schema = mongoose.Schema;
|
|||||||
|
|
||||||
const CampaignSchema = new Schema({
|
const CampaignSchema = new Schema({
|
||||||
name: {type: String, required: true},
|
name: {type: String, required: true},
|
||||||
|
system: {type: String, required: true},
|
||||||
creation_date: { type: Date, default: Date.now},
|
creation_date: { type: Date, default: Date.now},
|
||||||
last_opened: { type: Date, default: Date.now},
|
last_opened: { type: Date, default: Date.now},
|
||||||
invite_code: { type: String, unique: true },
|
invite_code: { type: String, unique: true },
|
||||||
|
11
server/models/Character.js
Normal file
11
server/models/Character.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const mongoose = require("mongoose");
|
||||||
|
const Schema = mongoose.Schema;
|
||||||
|
|
||||||
|
const CharacterSchema = new Schema({
|
||||||
|
name: {type: String, required: true},
|
||||||
|
data: { type: Object },
|
||||||
|
campaign_user: {type: mongoose.Types.ObjectId, ref: "CampaignUser"},
|
||||||
|
image: { type: String },
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = mongoose.model('Character', CharacterSchema);
|
11
server/models/Entity.js
Normal file
11
server/models/Entity.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
const mongoose = require("mongoose");
|
||||||
|
const Schema = mongoose.Schema;
|
||||||
|
|
||||||
|
const EntitySchema = new Schema({
|
||||||
|
name: {type: String, required: true},
|
||||||
|
data: { type: Object },
|
||||||
|
campaign: {type: mongoose.Types.ObjectId, ref: "Campaign"},
|
||||||
|
image: { type: String },
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = mongoose.model('Entity', EntitySchema);
|
12
server/models/Map.js
Normal file
12
server/models/Map.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
const mongoose = require("mongoose");
|
||||||
|
const Schema = mongoose.Schema;
|
||||||
|
|
||||||
|
const MapSchema = new Schema({
|
||||||
|
name: {type: String, required: true},
|
||||||
|
data: { type: Object }, // Data del format dd2vtt
|
||||||
|
campaign: {type: mongoose.Types.ObjectId, ref: "Campaign"},
|
||||||
|
image: { type: String },
|
||||||
|
entities: { type: Object }
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = mongoose.model('Entity', EntitySchema);
|
@ -16,10 +16,11 @@ router.post('/register', passport.authenticate('jwt', {session: false}), rateLim
|
|||||||
|
|
||||||
router.post('/create', passport.authenticate('jwt', {session: false}), rateLimitMiddleware, (req, res) => {
|
router.post('/create', passport.authenticate('jwt', {session: false}), rateLimitMiddleware, (req, res) => {
|
||||||
let {
|
let {
|
||||||
name
|
name,
|
||||||
|
system
|
||||||
} = req.body;
|
} = req.body;
|
||||||
|
|
||||||
if(!(name)){
|
if(!(name && system)){
|
||||||
res.json({
|
res.json({
|
||||||
status: "error",
|
status: "error",
|
||||||
msg: "params"
|
msg: "params"
|
||||||
@ -28,7 +29,7 @@ router.post('/create', passport.authenticate('jwt', {session: false}), rateLimit
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the campaign
|
// Create the campaign
|
||||||
let campaign = new Campaign({name});
|
let campaign = new Campaign({name, system});
|
||||||
campaign.invite_code = Campaign.generateInvite();
|
campaign.invite_code = Campaign.generateInvite();
|
||||||
|
|
||||||
campaign.save().then(campaign => {
|
campaign.save().then(campaign => {
|
||||||
|
Loading…
Reference in New Issue
Block a user