This commit is contained in:
BinarySandia04 2024-09-27 12:23:36 +02:00
parent b04ac1ae40
commit 55972e07af
25 changed files with 279 additions and 79 deletions

1
.gitignore vendored
View File

@ -9,6 +9,7 @@ backend/plugins/
client/public/data/ client/public/data/
server/uploads/ server/uploads/
client/src/locales/ client/src/locales/
client/public/plugins/
# local env files # local env files
.env.local .env.local

BIN
client/public/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -304,3 +304,7 @@ span.artifact {
.form-element label { .form-element label {
flex-grow: 1; flex-grow: 1;
} }
.form-element.centered {
justify-content: center;
}

View File

@ -18,6 +18,8 @@ function ConnectToCampaign(campaign){
chat.value = []; chat.value = [];
socket.emit('enter', GetUser(), _currentCampaign._id); socket.emit('enter', GetUser(), _currentCampaign._id);
console.log("Hola")
console.log(_currentCampaign)
} }
function Disconnect(){ function Disconnect(){
@ -31,13 +33,12 @@ function Disconnect(){
function DisplayCampaign(data = _currentCampaign){ function DisplayCampaign(data = _currentCampaign){
ClearAll(); ClearAll();
console.log(data)
CreateWindow('campaign_preview', {campaign: data}); CreateWindow('campaign_preview', {campaign: data});
} }
function UpdateCampaignData(data){ function UpdateCampaignData(data){
Api().put('/campaign/update?campaign=' + GetCampaign()._id, {campaign: data}).then(response => { Api().put('/campaign/update?campaign=' + GetCampaign()._id, {campaign: data}).then(response => {
console.log(response);
}); });
} }
@ -46,6 +47,7 @@ socket.on('update-players', data => {
}) })
socket.on('init-info', data => { socket.on('init-info', data => {
console.log("Hola2")
_UpdatePlayers(data.players); _UpdatePlayers(data.players);
DisplayCampaign(); DisplayCampaign();
}) })

View File

@ -11,7 +11,6 @@ let arrowIcon = "icons/iconoir/regular/nav-arrow-right.svg";
import { animate } from 'motion' import { animate } from 'motion'
function Show(){ function Show(){
console.log("SHOW")
let contextMenu = document.getElementById('context-menu'); let contextMenu = document.getElementById('context-menu');
contextMenu.style.display = "flex"; contextMenu.style.display = "flex";
contextMenu.style.top = (cursorY + margin) + "px"; contextMenu.style.top = (cursorY + margin) + "px";
@ -102,7 +101,6 @@ function AddContextMenu(element, val, options = {}){
let contextMenu = document.getElementById('context-menu'); let contextMenu = document.getElementById('context-menu');
contextMenu.style.top = rect.bottom + "px"; contextMenu.style.top = rect.bottom + "px";
contextMenu.style.left = rect.left + "px"; contextMenu.style.left = rect.left + "px";
console.log(rect.top);
} }
} }

View File

@ -9,6 +9,8 @@ import * as Sound from "@/services/Sound"
import * as Tooltip from "@/services/Tooltip" import * as Tooltip from "@/services/Tooltip"
import * as Windows from "@/services/Windows" import * as Windows from "@/services/Windows"
let pluginInfo = []
async function FetchPlugins(){ async function FetchPlugins(){
let pluginNames = GetPluginPaths(); let pluginNames = GetPluginPaths();
@ -17,6 +19,14 @@ async function FetchPlugins(){
let pluginData = (await import(/* @vite-ignore */ `../../plugins/${pluginName}/plugin.json`)).default let pluginData = (await import(/* @vite-ignore */ `../../plugins/${pluginName}/plugin.json`)).default
console.log(`Loading plugin %c${pluginData.name}`, "color: #00ffff"); console.log(`Loading plugin %c${pluginData.name}`, "color: #00ffff");
pluginInfo.push({
name: pluginData.name,
_id: pluginName,
info: {
}
});
import(/* @vite-ignore */ `../../plugins/${pluginName}/${pluginData.entrypoint}`).then(module => { import(/* @vite-ignore */ `../../plugins/${pluginName}/${pluginData.entrypoint}`).then(module => {
module.Main({ module.Main({
Dragonroll, Dragonroll,
@ -32,6 +42,12 @@ async function FetchPlugins(){
} }
} }
export { function _GetPlugins(){
FetchPlugins return pluginInfo
}
export {
FetchPlugins,
_GetPlugins
} }

View File

@ -70,7 +70,7 @@ watch(game, () => {
<template> <template>
<div class="game-root" ref="game" v-if="in_game"> <div class="game-root" ref="game" v-show="in_game">
<!-- Aquests dos son absolute --> <!-- Aquests dos son absolute -->
<div class="vertical-button"> <div class="vertical-button">

View File

@ -29,7 +29,8 @@ import CompendiumWindow from '../windows/CompendiumWindow.vue'
import BookAnvilWindow from '../windows/BookAnvilWindow.vue' import BookAnvilWindow from '../windows/BookAnvilWindow.vue'
import IconSelectorWindow from '../windows/selectors/IconSelectorWindow.vue' import IconSelectorWindow from '../windows/selectors/IconSelectorWindow.vue'
import DatabaseWindow from '../windows/game/DatabaseWindow.vue' import DatabaseWindow from '../windows/game/DatabaseWindow.vue'
import AccountManagementWindow from '../windows/settings/AccountManagementWindow.vue'
import PluginManagementWindow from '../windows/settings/PluginManagementWindow.vue'
// Gestionem ventanas // Gestionem ventanas
const reload = ReloadRef(); const reload = ReloadRef();
@ -59,7 +60,9 @@ let WindowMap = {
compendium_window: CompendiumWindow, compendium_window: CompendiumWindow,
book_anvil_window: BookAnvilWindow, book_anvil_window: BookAnvilWindow,
icon_selector: IconSelectorWindow, icon_selector: IconSelectorWindow,
database: DatabaseWindow database: DatabaseWindow,
plugin_management: PluginManagementWindow,
account_management: AccountManagementWindow
}; };
async function InjectSystemWindows(system){ async function InjectSystemWindows(system){

View File

@ -4,23 +4,23 @@ import { AddContextMenu } from '@/services/ContextMenu';
import { AddTooltip } from '@/services/Tooltip'; import { AddTooltip } from '@/services/Tooltip';
import { marked } from "https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js"; import { marked } from "https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js";
const props = defineProps(['element']); const props = defineProps(['element', 'context', 'tooltip', 'icon']);
const element = ref({}); const element = ref({});
const elementDiv = ref(null); const elementDiv = ref(null);
const tooltipContainer = ref(null); const tooltipContainer = ref(null);
const icon = ref("icons/game-icons/ffffff/lorc/crossed-swords.svg")
function updateElement(){ function updateElement(){
element.value = props.element; element.value = props.element;
// Do whatever // Do whatever
let desc = element.value.info.description; let desc = element.value.info.description;
desc = desc ? marked.parse(desc) : ''; desc = desc ? marked.parse(desc) : '';
console.log(desc);
AddTooltip(tooltipContainer.value, `<div class='document item'> if(props.icon) icon.value = props.icon(element.value);
<h2>${element.value.name}</h2>
<img src='${element.value.info.icon}'></img> let tooltip = props.tooltip(element.value);
<div class='document'>${desc}</div> if(tooltip) AddTooltip(tooltipContainer.value, tooltip);
</div>`)
} }
onMounted(() => { onMounted(() => {
@ -29,17 +29,14 @@ onMounted(() => {
updateElement(); updateElement();
}); });
AddContextMenu(elementDiv.value, [ let context = props.context();
{name: "Open"}, if(context) AddContextMenu(elementDiv.value, context);
{name: "Delete"}
]);
}) })
</script> </script>
<template> <template>
<div class="concept-element" ref="elementDiv"> <div class="concept-element" ref="elementDiv">
<div class="concept-tooltip-container" ref="tooltipContainer"> <div class="concept-tooltip-container" ref="tooltipContainer">
<img :src="element.info ? element.info.icon : 'icons/game-icons/ffffff/lorc/crossed-swords.svg'" class="concept-icon"> <img :src="icon" class="concept-icon">
<span class="title">{{ element.name }}</span> <span class="title">{{ element.name }}</span>
</div> </div>
</div> </div>

View File

@ -6,26 +6,27 @@ import { ClearWindow, CreateWindow } from '../../services/Windows';
import { animate } from "motion" import { animate } from "motion"
import ConceptEntry from './ConceptEntry.vue'; import ConceptEntry from './ConceptEntry.vue';
const props = defineProps(['elements']); const props = defineProps(['elements', 'open', 'tooltip', 'context', 'icon']);
const listContainer = ref(null); const listContainer = ref(null);
const elements = ref([]); const elements = ref([]);
let OpenElement = () => {};
let TooltipElement = () => {};
let ContextElement = () => {};
let IconElement = () => {};
onMounted(() => { onMounted(() => {
if(props.open) OpenElement = props.open;
if(props.tooltip) TooltipElement = props.tooltip;
if(props.context) ContextElement = props.context;
if(props.icon) IconElement = props.icon;
watch(() => props.elements, () => { watch(() => props.elements, () => {
elements.value = props.elements; elements.value = props.elements;
}); });
}); });
function OpenConcept(element){
CreateWindow('item_sheet', {
id: 'item_sheet_' + element._id,
title: 'Edit Item',
item_id: element._id,
close: () => ClearWindow('item_sheet_' + element._id)
});
}
function onBeforeEnter(el) { function onBeforeEnter(el) {
el.style.opacity = 0 el.style.opacity = 0
} }
@ -48,7 +49,14 @@ function onLeave(el, done) {
<template> <template>
<div class="list-container" ref="listContainer"> <div class="list-container" ref="listContainer">
<TransitionGroup name="list-element" :css="false" @before-enter="onBeforeEnter" @enter="onEnter" @leave="onLeave"> <TransitionGroup name="list-element" :css="false" @before-enter="onBeforeEnter" @enter="onEnter" @leave="onLeave">
<ConceptEntry class="list-element" v-for="(element, index) in elements" :key="element._id" :element="element" v-on:click.prevent="OpenConcept(element)" :data-index="index"></ConceptEntry> <ConceptEntry class="list-element" v-for="(element, index) in elements"
:key="element._id"
:element="element"
:context="() => ContextElement(element)"
:tooltip="(el) => TooltipElement(el)"
:icon="(el) => IconElement(el)"
v-on:click.prevent="OpenElement(element)"
:data-index="index"></ConceptEntry>
</TransitionGroup> </TransitionGroup>
</div> </div>
</template> </template>

View File

@ -2,19 +2,14 @@
import { inject, onMounted, ref } from 'vue'; import { inject, onMounted, ref } from 'vue';
import { GetEmitter } from '../../services/Dragonroll'; import { GetEmitter } from '../../services/Dragonroll';
const props = defineProps(['data']); const props = defineProps(['data', 'click']);
const data = props.data; const data = props.data;
const title = ref(""); const title = ref("");
const image = ref(null); const image = ref(null);
const clearParent = inject('clearParent');
function Select(){ function Select(){
if(data.id){ if(props.click) props.click(data.id);
GetEmitter().emit("select", data.id);
clearParent();
}
} }
onMounted(() => { onMounted(() => {

View File

@ -1,7 +1,8 @@
<script setup> <script setup>
import { onMounted, onUpdated, provide, ref, watch } from 'vue'; import { onMounted, onUpdated, provide, ref, watch } from 'vue';
import { SetupHandle, SetSize, SetPosition, ResetPosition } from '@/services/Windows'; import { SetupHandle, SetSize, SetPosition, ResetPosition } from '@/services/Windows';
import { CreateChildWindow } from '../../services/Windows'; import { ClearWindow, CreateChildWindow } from '../../services/Windows';
import { GetModule, GetModules } from '../../services/Modules';
const selectedSystem = ref(""); const selectedSystem = ref("");
const selectedImage = ref(null); const selectedImage = ref(null);
@ -11,22 +12,17 @@ const props = defineProps(['windowId']);
let windowId = props.windowId; let windowId = props.windowId;
function DisplaySystemSelector(){ function DisplaySystemSelector(){
CreateChildWindow(windowId, 'system_selector'); CreateChildWindow(windowId, 'system_selector', {'done': (data) => {
console.log("Hola")
let module = GetModule(data.selected);
selectedSystem.value = data.selected;
selectedImage.value.src = `modules/${module.id}/icon.png`;
systemTitle.value = module.title;
ClearWindow('system-selector');
}});
} }
defineExpose({ selectedSystem }); 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> </script>

View File

@ -1,6 +1,6 @@
<script setup> <script setup>
import { onMounted, onUpdated, ref, compile, render, h } from 'vue'; import { onMounted, ref } from 'vue';
import { SetupHandle, SetSize, SetPosition, ResetPosition } from '@/services/Windows'; import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
import WindowHandle from '@/views/partials/WindowHandle.vue'; import WindowHandle from '@/views/partials/WindowHandle.vue';

View File

@ -7,6 +7,7 @@ import WindowHandle from '@/views/partials/WindowHandle.vue';
import Tabs from '../partials/Tabs.vue'; import Tabs from '../partials/Tabs.vue';
import Dropdown from '../partials/Dropdown.vue'; import Dropdown from '../partials/Dropdown.vue';
import { GetUserSetting, SetUserSetting } from '../../services/User'; import { GetUserSetting, SetUserSetting } from '../../services/User';
import { ClearWindow, CreateChildWindow, SetMaxSize, SetMinSize, SetResizable } from '../../services/Windows';
const handle = ref(null); const handle = ref(null);
@ -41,8 +42,33 @@ onMounted(() => {
SetupHandle(id, handle); SetupHandle(id, handle);
SetSize(id, {width: 400, height: 480}); SetSize(id, {width: 400, height: 480});
ResetPosition(id, "center"); ResetPosition(id, "center");
SetResizable(id, true);
SetMinSize(id, {width: 350, height: 280});
}); });
function OpenManageAccounts(){
CreateChildWindow(id, '', {
type: 'account_management',
title: 'settings.site-administration.manage-accounts.title',
id: 'account-management',
close: () => {
ClearWindow('account-management')
}
})
}
function OpenManagePlugins(){
CreateChildWindow(id, '', {
type: 'plugin_management',
title: 'settings.site-administration.manage-plugins.title',
id: 'plugin-management',
close: () => {
ClearWindow('plugin-management')
}
})
}
async function OnLanguageChange(value){ async function OnLanguageChange(value){
let codes = { let codes = {
"English": "en-US", "English": "en-US",
@ -69,7 +95,12 @@ async function OnLanguageChange(value){
</div> </div>
</template> </template>
<template #site-administration> <template #site-administration>
<div class="form-element centered">
<button v-on:click.prevent="OpenManageAccounts">{{ $t('settings.site-administration.manage-accounts-button') }}</button>
</div>
<div class="form-element centered">
<button v-on:click.prevent="OpenManagePlugins">{{ $t('settings.site-administration.manage-plugins-button') }}</button>
</div>
</template> </template>
</Tabs> </Tabs>
</div> </div>

View File

@ -8,30 +8,20 @@ import Api from '@/services/Api.js'
import SystemSelector from '../../partials/SystemSelector.vue'; import SystemSelector from '../../partials/SystemSelector.vue';
import { GetModules } from '../../../services/Modules'; import { GetModules } from '../../../services/Modules';
import GameSystem from '../../partials/GameSystem.vue'; import GameSystem from '../../partials/GameSystem.vue';
import { ClearWindow } from '../../../services/Windows'; import { CallWindow, ClearWindow } from '../../../services/Windows';
const handle = ref(null); const handle = ref(null);
const props = defineProps(['data']); const props = defineProps(['data']);
const data = props.data; const data = props.data;
const campaignName = ref("");
let id = data.id; let id = data.id;
let systems = ref(GetModules()); let systems = ref(GetModules());
function Clear(){
ClearWindow(id);
}
provide('clearParent', Clear);
onMounted(() => { onMounted(() => {
SetupHandle(id, handle); SetupHandle(id, handle);
SetSize(id, {width: 300, height: 600}); SetSize(id, {width: 300, height: 600});
ResetPosition(id, "center"); ResetPosition(id, "center");
console.log(systems.value)
}); });
</script> </script>
@ -42,7 +32,7 @@ onMounted(() => {
<!-- Body --> <!-- Body -->
<div class="system-list"> <div class="system-list">
<GameSystem v-for="system in systems" :id="system.id" :data="system"></GameSystem> <GameSystem v-for="system in systems" :id="system.id" :data="system" :click="(moduleId) => CallWindow(id, 'done', {selected: moduleId})"></GameSystem>
</div> </div>
</div> </div>
</template> </template>

View File

@ -27,9 +27,7 @@ onMounted(() => {
SetMinSize(id, {width: 350, height: 300}); SetMinSize(id, {width: 350, height: 300});
watch(GetConcepts, () => { watch(GetConcepts, () => {
console.log("Updated???")
elements.value = GetConcepts(); elements.value = GetConcepts();
console.log(elements);
}); });
FetchConcepts(); FetchConcepts();
@ -37,6 +35,36 @@ onMounted(() => {
function OpenCreateItemPrompt(){ function OpenCreateItemPrompt(){
CreateWindow('create_item_prompt', {id: 'create_item_prompt', title: 'Create Item', close: () => ClearWindow('create_item_prompt')}) CreateWindow('create_item_prompt', {id: 'create_item_prompt', title: 'Create Item', close: () => ClearWindow('create_item_prompt')})
} }
function OpenConcept(element){
CreateWindow('item_sheet', {
id: 'item_sheet_' + element._id,
title: 'Edit Item',
item_id: element._id,
close: () => ClearWindow('item_sheet_' + element._id)
});
}
function ElementContext(element){
console.log(element);
return [
{name: "Open"},
{name: "Delete"}
];
}
function ElementTooltip(element){
return `<div class='document item'>
<h2>${element.name}</h2>
<img src='${element.info.icon}'></img>
<div class='document'>${element.info.description ?? ''}</div>
</div>`;
}
function ElementIcon(element){
return element.info ? element.info.icon : 'icons/game-icons/ffffff/lorc/crossed-swords.svg'
}
</script> </script>
@ -51,7 +79,13 @@ function OpenCreateItemPrompt(){
{id: 'features', value: 'database.tabs.features'} {id: 'features', value: 'database.tabs.features'}
]"> ]">
<template #items> <template #items>
<ConceptList :elements="elements"></ConceptList> <ConceptList
:elements="elements"
:open="OpenConcept"
:context="ElementContext"
:tooltip="ElementTooltip"
:icon="ElementIcon"
></ConceptList>
</template> </template>
</Tabs> </Tabs>
</div> </div>

View File

@ -0,0 +1,42 @@
<script setup>
import { onMounted, ref } from 'vue';
import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
import WindowHandle from '@/views/partials/WindowHandle.vue';
const handle = ref(null);
const props = defineProps(['data']);
const data = props.data;
let id = data.id;
const test = ref(null)
onMounted(() => {
SetupHandle(id, handle);
SetSize(id, {width: 500, height: 380});
ResetPosition(id, "center");
});
</script>
<template>
<div class="window-wrapper" :id="'window-wrapper-' + id">
<WindowHandle :window="id" ref="handle"></WindowHandle>
<!-- Body -->
<div ref="test"></div>
</div>
</template>
<style scoped>
.window-wrapper {
display: flex;
align-items: center;
}
</style>

View File

@ -0,0 +1,58 @@
<script setup>
import { onMounted, ref, shallowRef } from 'vue';
import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
import WindowHandle from '@/views/partials/WindowHandle.vue';
import ConceptList from '../../partials/ConceptList.vue';
import { _GetPlugins } from '../../../services/Plugins';
import { SetMinSize, SetResizable } from '../../../services/Windows';
const handle = ref(null);
const props = defineProps(['data']);
const data = props.data;
let id = data.id;
const test = ref(null)
const elements = shallowRef([]);
onMounted(() => {
SetupHandle(id, handle);
SetSize(id, {width: 500, height: 380});
ResetPosition(id, "center");
SetResizable(id, true);
SetMinSize(id, {width: 350, height: 280});
elements.value = _GetPlugins();
});
function GetPluginIcon(plugin){
return `/plugins/${plugin._id}/icon.png`;
}
</script>
<template>
<div class="window-wrapper" :id="'window-wrapper-' + id">
<WindowHandle :window="id" ref="handle"></WindowHandle>
<!-- Body -->
<ConceptList
:elements="elements"
:icon="GetPluginIcon"
></ConceptList>
</div>
</template>
<style scoped>
.window-wrapper {
display: flex;
align-items: center;
}
</style>

View File

@ -45,10 +45,15 @@
"site-administration": "Site Administration" "site-administration": "Site Administration"
}, },
"account": { "account": {
"account-settings": "Account Settings", "language": "Language:",
"language": "Language:" "account-settings": "Account Settings"
}, },
"site-administration": {} "site-administration": {
"manage-accounts-button": "Manage site accounts",
"manage-plugins-button": "Manage plugins",
"manage-accounts": "Manage site accounts",
"manage-plugins": "Manage plugins"
}
}, },
"campaigns": { "campaigns": {
"title": "Campaigns", "title": "Campaigns",

View File

@ -45,10 +45,18 @@
"site-administration": "Site Administration" "site-administration": "Site Administration"
}, },
"account": { "account": {
"account-settings": "Account Settings",
"language": "Language:" "language": "Language:"
}, },
"site-administration": {} "site-administration": {
"manage-accounts-button": "Manage site accounts",
"manage-plugins-button": "Manage plugins",
"manage-accounts": {
"title": "Manage Accounts"
},
"manage-plugins": {
"title": "Manage Plugins"
}
}
}, },
"campaigns": { "campaigns": {
"title": "Campaigns", "title": "Campaigns",

View File

@ -45,10 +45,15 @@
"site-administration": "Administración" "site-administration": "Administración"
}, },
"account": { "account": {
"account-settings": "Ajustes de la cuenta", "language": "Idioma:",
"language": "Idioma:" "account-settings": "Ajustes de la cuenta"
}, },
"site-administration": {} "site-administration": {
"manage-accounts-button": "Manage site accounts",
"manage-plugins-button": "Manage plugins",
"manage-accounts": "Manage site accounts",
"manage-plugins": "Manage plugins"
}
}, },
"campaigns": { "campaigns": {
"title": "Campañas", "title": "Campañas",

View File

@ -1,3 +1,6 @@
// TODO: We should move client/plugin.json to plugin.json and generate the client plugin.json
// with the prebuild.js
function Main(Api){ function Main(Api){
console.log("Hello World!"); console.log("Hello World!");
console.log(Api); console.log(Api);

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -96,6 +96,10 @@ for(let j = 0; j < plugins.length; j++){
if(fs.existsSync(`./plugins/${plugins[j]}/client/`)){ if(fs.existsSync(`./plugins/${plugins[j]}/client/`)){
fs.cpSync(`./plugins/${plugins[j]}/client/`, `./client/plugins/${plugins[j]}`, {recursive: true}); fs.cpSync(`./plugins/${plugins[j]}/client/`, `./client/plugins/${plugins[j]}`, {recursive: true});
} }
if(fs.existsSync(`./plugins/${plugins[j]}/public/`)){
fs.cpSync(`./plugins/${plugins[j]}/public/`, `./client/public/plugins/${plugins[j]}`, {recursive: true});
}
} }
fs.writeFileSync(outputPath, JSON.stringify({ fs.writeFileSync(outputPath, JSON.stringify({