Campaign description

This commit is contained in:
BinarySandia04 2024-09-26 01:15:53 +02:00
parent 80ede11f7c
commit be6d4fda26
13 changed files with 217 additions and 45 deletions

View File

@ -50,7 +50,8 @@ module.exports = io => {
console.log(socket.user.username + " ha entrado!"); console.log(socket.user.username + " ha entrado!");
SetPlayerProperty(campaignId, socket.user._id, "online", true); SetPlayerProperty(campaignId, socket.user._id, "online", true);
io.to(socket.campaign).emit('update-players', sessions[campaignId].players) // io.to(socket.campaign).emit('update-players', sessions[campaignId].players)
socket.emit('init-info', {players: sessions[campaignId].players})
// console.log(JSON.stringify(sessions[campaignId], null, 4)); // console.log(JSON.stringify(sessions[campaignId], null, 4));
} }

View File

@ -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},
description: {type: String},
system: {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},

View File

@ -99,4 +99,27 @@ router.get('/players', (req, res) => {
}).catch((err) => res.json({status: "error", msg: "not-found"})); }).catch((err) => res.json({status: "error", msg: "not-found"}));
}); });
router.put('/update', (req, res) => {
CampaignUser.find({campaign: req.query.campaign}).then((data) => {
if(data.is_dm){
let {
name,
description
} = req.body.campaign;
Campaign.findOneAndUpdate({_id: req.query.campaign}, {
name,
description
}).then((campaign) => {
res.json({stauts: "ok", campaign})
});
return;
}
res.json({
status: "error",
msg: "forbidden"
})
});
});
module.exports = router; module.exports = router;

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

View File

@ -20,6 +20,7 @@
"marked": "^9.1.6", "marked": "^9.1.6",
"marked-katex-extension": "^4.0.1", "marked-katex-extension": "^4.0.1",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"motion": "^10.18.0",
"prismjs": "^1.29.0", "prismjs": "^1.29.0",
"serve": "^14.2.3", "serve": "^14.2.3",
"socket.io-client": "^4.7.5", "socket.io-client": "^4.7.5",
@ -1193,6 +1194,70 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@motionone/animation": {
"version": "10.18.0",
"resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.18.0.tgz",
"integrity": "sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw==",
"license": "MIT",
"dependencies": {
"@motionone/easing": "^10.18.0",
"@motionone/types": "^10.17.1",
"@motionone/utils": "^10.18.0",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/dom": {
"version": "10.18.0",
"resolved": "https://registry.npmjs.org/@motionone/dom/-/dom-10.18.0.tgz",
"integrity": "sha512-bKLP7E0eyO4B2UaHBBN55tnppwRnaE3KFfh3Ps9HhnAkar3Cb69kUCJY9as8LrccVYKgHA+JY5dOQqJLOPhF5A==",
"license": "MIT",
"dependencies": {
"@motionone/animation": "^10.18.0",
"@motionone/generators": "^10.18.0",
"@motionone/types": "^10.17.1",
"@motionone/utils": "^10.18.0",
"hey-listen": "^1.0.8",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/easing": {
"version": "10.18.0",
"resolved": "https://registry.npmjs.org/@motionone/easing/-/easing-10.18.0.tgz",
"integrity": "sha512-VcjByo7XpdLS4o9T8t99JtgxkdMcNWD3yHU/n6CLEz3bkmKDRZyYQ/wmSf6daum8ZXqfUAgFeCZSpJZIMxaCzg==",
"license": "MIT",
"dependencies": {
"@motionone/utils": "^10.18.0",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/generators": {
"version": "10.18.0",
"resolved": "https://registry.npmjs.org/@motionone/generators/-/generators-10.18.0.tgz",
"integrity": "sha512-+qfkC2DtkDj4tHPu+AFKVfR/C30O1vYdvsGYaR13W/1cczPrrcjdvYCj0VLFuRMN+lP1xvpNZHCRNM4fBzn1jg==",
"license": "MIT",
"dependencies": {
"@motionone/types": "^10.17.1",
"@motionone/utils": "^10.18.0",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/types": {
"version": "10.17.1",
"resolved": "https://registry.npmjs.org/@motionone/types/-/types-10.17.1.tgz",
"integrity": "sha512-KaC4kgiODDz8hswCrS0btrVrzyU2CSQKO7Ps90ibBVSQmjkrt2teqta6/sOG59v7+dPnKMAg13jyqtMKV2yJ7A==",
"license": "MIT"
},
"node_modules/@motionone/utils": {
"version": "10.18.0",
"resolved": "https://registry.npmjs.org/@motionone/utils/-/utils-10.18.0.tgz",
"integrity": "sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw==",
"license": "MIT",
"dependencies": {
"@motionone/types": "^10.17.1",
"hey-listen": "^1.0.8",
"tslib": "^2.3.1"
}
},
"node_modules/@mrmlnc/readdir-enhanced": { "node_modules/@mrmlnc/readdir-enhanced": {
"version": "2.2.1", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
@ -7521,6 +7586,12 @@
"he": "bin/he" "he": "bin/he"
} }
}, },
"node_modules/hey-listen": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
"integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==",
"license": "MIT"
},
"node_modules/highlight.js": { "node_modules/highlight.js": {
"version": "10.7.3", "version": "10.7.3",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
@ -9226,6 +9297,18 @@
"resolved": "https://registry.npmjs.org/moment-mini/-/moment-mini-2.29.4.tgz", "resolved": "https://registry.npmjs.org/moment-mini/-/moment-mini-2.29.4.tgz",
"integrity": "sha512-uhXpYwHFeiTbY9KSgPPRoo1nt8OxNVdMVoTBYHfSEKeRkIkwGpO+gERmhuhBtzfaeOyTkykSrm2+noJBgqt3Hg==" "integrity": "sha512-uhXpYwHFeiTbY9KSgPPRoo1nt8OxNVdMVoTBYHfSEKeRkIkwGpO+gERmhuhBtzfaeOyTkykSrm2+noJBgqt3Hg=="
}, },
"node_modules/motion": {
"version": "10.18.0",
"resolved": "https://registry.npmjs.org/motion/-/motion-10.18.0.tgz",
"integrity": "sha512-MVAZZmwM/cp77BrNe1TxTMldxRPjwBNHheU5aPToqT4rJdZxLiADk58H+a0al5jKLxkB0OdgNq6DiVn11cjvIQ==",
"license": "MIT",
"dependencies": {
"@motionone/animation": "^10.18.0",
"@motionone/dom": "^10.18.0",
"@motionone/types": "^10.17.1",
"@motionone/utils": "^10.18.0"
}
},
"node_modules/mrmime": { "node_modules/mrmime": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
@ -12844,7 +12927,6 @@
"version": "2.6.3", "version": "2.6.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
"dev": true,
"license": "0BSD" "license": "0BSD"
}, },
"node_modules/type-check": { "node_modules/type-check": {

View File

@ -21,6 +21,7 @@
"marked": "^9.1.6", "marked": "^9.1.6",
"marked-katex-extension": "^4.0.1", "marked-katex-extension": "^4.0.1",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"motion": "^10.18.0",
"prismjs": "^1.29.0", "prismjs": "^1.29.0",
"serve": "^14.2.3", "serve": "^14.2.3",
"socket.io-client": "^4.7.5", "socket.io-client": "^4.7.5",

View File

@ -11,7 +11,10 @@
"username": "Username", "username": "Username",
"password": "Password", "password": "Password",
"password-confirm": "Confirm your password", "password-confirm": "Confirm your password",
"register": "Register" "register": "Register",
"quantity": "Quantity",
"weight": "Weight",
"price": "Price"
}, },
"placeholders": { "placeholders": {
"name": "John Doe", "name": "John Doe",

View File

@ -11,7 +11,10 @@
"username": "Nombre de usuario", "username": "Nombre de usuario",
"password": "Contraseña", "password": "Contraseña",
"password-confirm": "Confirma tu contraseña", "password-confirm": "Confirma tu contraseña",
"register": "Registrar-se" "register": "Registrar-se",
"quantity": "Quantity",
"weight": "Weight",
"price": "Price"
}, },
"placeholders": { "placeholders": {
"name": "John Doe", "name": "John Doe",

View File

@ -28,18 +28,27 @@ function Disconnect(){
} }
function DisplayCampaign(data = currentCampaign){ function DisplayCampaign(data = _currentCampaign){
ClearAll(); ClearAll();
CreateWindow('campaign_preview', {campaign: data}); CreateWindow('campaign_preview', {campaign: data});
} }
socket.on('update-players', data => { socket.on('update-players', data => {
_UpdatePlayers(data)
})
socket.on('init-info', data => {
_UpdatePlayers(data.players);
DisplayCampaign();
})
function _UpdatePlayers(data){
_players.value = []; _players.value = [];
Object.keys(data).forEach((key) => { Object.keys(data).forEach((key) => {
_players.value.push(data[key]); _players.value.push(data[key]);
if(GetUser()._id == data[key].user._id) _currentPlayer = data[key]; if(GetUser()._id == data[key].user._id) _currentPlayer = data[key];
}); });
}) }
export { export {
_currentCampaign, _currentCampaign,

View File

@ -23,7 +23,7 @@ onMounted(() => {
function ViewCampaign(){ function ViewCampaign(){
ConnectToCampaign(data); ConnectToCampaign(data);
DisplayCampaign(data); // DisplayCampaign(data);
} }
</script> </script>

View File

@ -2,11 +2,13 @@
import { onMounted, ref, watch } from 'vue'; import { onMounted, ref, watch } from 'vue';
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(['done']); const props = defineProps(['done', 'editable']);
import IconButton from '../partials/game/IconButton.vue'; import IconButton from '../partials/game/IconButton.vue';
const editing = ref(false); const editing = ref(false);
const isEditable = ref(true);
const editor = ref(null); const editor = ref(null);
const preview = ref(null); const preview = ref(null);
const text = ref(""); const text = ref("");
@ -21,12 +23,26 @@ function PreviewContent(){
preview.value.innerHTML = marked.parse(editor.value.value); preview.value.innerHTML = marked.parse(editor.value.value);
} }
function UpdateEditable(val){
if(val) {
isEditable.value = true;
} else {
isEditable.value = false;
editing.value = false;
}
}
onMounted(() => { onMounted(() => {
watch(text, () => { watch(text, () => {
editor.value.value = text.value; editor.value.value = text.value;
preview.value.innerHTML = marked.parse(editor.value.value); preview.value.innerHTML = marked.parse(editor.value.value);
}); });
UpdateEditable(props.editable);
watch(() => props.editable, () => {
UpdateEditable(props.editable);
})
editor.value.addEventListener("change", () => { editor.value.addEventListener("change", () => {
props.done(editor.value.value); props.done(editor.value.value);
}); });
@ -44,18 +60,18 @@ defineExpose({
<div class="markdown-editor"> <div class="markdown-editor">
<div class="editor-content"> <div class="editor-content">
<div v-show="!editing" class="preview"> <div v-show="!editing" class="preview">
<div class="document preview" ref="preview"> <div class="document" ref="preview">
</div> </div>
<div class="fixed-bottom-buttons"> <div class="fixed-bottom-buttons">
<IconButton icon="/icons/iconoir/regular/edit-pencil.svg" :action="EditContent"></IconButton> <IconButton v-show="isEditable" icon="/icons/iconoir/regular/edit-pencil.svg" :action="EditContent"></IconButton>
</div> </div>
</div> </div>
<div v-show="editing" class="editor"> <div v-show="editing" class="editor">
<textarea class="editing" ref="editor"></textarea> <textarea class="editing" ref="editor"></textarea>
<div class="fixed-bottom-buttons"> <div class="fixed-bottom-buttons">
<IconButton icon="/icons/iconoir/solid/eye.svg" :action="PreviewContent"></IconButton> <IconButton v-show="isEditable" icon="/icons/iconoir/solid/eye.svg" :action="PreviewContent"></IconButton>
</div> </div>
</div> </div>
</div> </div>
@ -68,7 +84,28 @@ defineExpose({
height: 100%; height: 100%;
} }
.document, .preview {
width: 100%;
max-width: 100%;
height: 100%;
max-height: 100%;
overflow-y: auto;
overflow-x: auto;
}
.document {
padding: 10px;
max-width: fit-content;
position: absolute;
}
.editor-content {
display: flex;
width: 100%;
}
.editing { .editing {
resize: none;
background-color: var(--color-background); background-color: var(--color-background);
} }
@ -86,9 +123,4 @@ defineExpose({
z-index: 2; z-index: 2;
display: flex; display: flex;
} }
.preview {
padding: 8px 0 8px 8px;
overflow-y: auto;
height: 100%;
}
</style> </style>

View File

@ -1,10 +1,10 @@
<script setup> <script setup>
import { onMounted, onUpdated, ref } from 'vue'; import { onMounted, onUpdated, ref, toRaw, watch } 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';
import PlayerList from '../../partials/PlayerList.vue'; import PlayerList from '../../partials/PlayerList.vue';
import { DisplayToast, GetClient } from '../../../services/Dragonroll'; import { DisplayToast, GetPlayerList } from '@/services/Dragonroll';
import CampaignBookList from '../../partials/books/CampaignBookList.vue'; import CampaignBookList from '../../partials/books/CampaignBookList.vue';
import { ClearAll, ClearWindow, CreateWindow, SetMinSize, SetResizable } from '../../../services/Windows'; import { ClearAll, ClearWindow, CreateWindow, SetMinSize, SetResizable } from '../../../services/Windows';
import { LaunchGame } from '../../../services/Game'; import { LaunchGame } from '../../../services/Game';
@ -14,8 +14,10 @@ import GameSystem from '@/views/partials/GameSystem.vue'
import { GetModule } from '../../../services/Modules'; import { GetModule } from '../../../services/Modules';
import { AddTooltip } from '../../../services/Tooltip'; import { AddTooltip } from '../../../services/Tooltip';
import { Disconnect } from '../../../services/Campaign'; import { Disconnect } from '../../../services/Campaign';
import MarkdownEditor from '@/views/partials/MarkdownEditor.vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { GetClient } from '../../../services/Dragonroll';
const {t} = useI18n(); const {t} = useI18n();
const handle = ref(null); const handle = ref(null);
@ -31,25 +33,6 @@ const copy_code_button = ref(null);
const container = ref(null); const container = ref(null);
let id = data.id; let id = data.id;
onMounted(() => {
SetupHandle(id, handle);
SetSize(id, {width: 800, height: 750});
SetResizable(id, true);
SetMinSize(id, {width: 600, height: 500});
hide_chat.value = true;
ResetPosition(id, "center");
hide_start.value = data.hide_start;
AddSound(container.value)
campaign_title.value.style.backgroundColor = GetModule(data.campaign.system).color ? GetModule(data.campaign.system).color : "#1f1f1f";
AddTooltip(copy_code_button.value, `<p>${t('campaigns.preview.copy-explain')}</p>`, {max_width: 300})
});
function CopyCode(){ function CopyCode(){
navigator.clipboard.writeText(GetCampaign().invite_code); navigator.clipboard.writeText(GetCampaign().invite_code);
@ -67,6 +50,30 @@ function Exit(){
CreateWindow('campaign_list'); CreateWindow('campaign_list');
} }
const description_editable = ref(false);
onMounted(() => {
if(GetClient().is_dm) description_editable.value = true;
SetupHandle(id, handle);
SetSize(id, {width: 800, height: 750});
SetResizable(id, true);
SetMinSize(id, {width: 800, height: 650});
hide_chat.value = true;
ResetPosition(id, "center");
hide_start.value = data.hide_start;
AddSound(container.value)
campaign_title.value.style.backgroundColor = GetModule(data.campaign.system).color ? GetModule(data.campaign.system).color : "#1f1f1f";
AddTooltip(copy_code_button.value, `<p>${t('campaigns.preview.copy-explain')}</p>`, {max_width: 300})
});
</script> </script>
@ -90,8 +97,10 @@ function Exit(){
<div class="campaign-main-container"> <div class="campaign-main-container">
<div class="campaign-main-container-scroll"> <div class="campaign-main-container-scroll">
<GameSystem :data="GetModule(data.campaign.system)"></GameSystem> <GameSystem :data="GetModule(data.campaign.system)"></GameSystem>
<h2>Books</h2> <div class="description">
<CampaignBookList class="small-book-list"></CampaignBookList> <MarkdownEditor ref="description" :done="DescriptionChanged" :editable="description_editable"></MarkdownEditor>
</div>
<!-- <CampaignBookList class="small-book-list"></CampaignBookList> -->
</div> </div>
</div> </div>
<div class="buttons-row"> <div class="buttons-row">
@ -109,6 +118,13 @@ function Exit(){
<style scoped lang="scss"> <style scoped lang="scss">
.description {
position: relative;
height: calc(100% - 55px);
width: 100%;
flex-grow: 0;
}
.small-book-list { .small-book-list {
margin: 20px; margin: 20px;
overflow: auto; overflow: auto;
@ -116,13 +132,13 @@ function Exit(){
.campaign-main-container-scroll { .campaign-main-container-scroll {
overflow-y: scroll; overflow-y: scroll;
height: 100%; height: calc(100% - 10px);
max-height: 520px;
} }
.campaign-main-container { .campaign-main-container {
height: 100%; height: 100%;
flex-grow: 1;
h2 { h2 {
text-align: left; text-align: left;
margin-left: 20px; margin-left: 20px;
@ -136,7 +152,6 @@ function Exit(){
font-weight: normal; font-weight: normal;
text-align: left; text-align: left;
padding: 20px; padding: 20px;
margin-bottom: 30px;
} }
.button-row { .button-row {
@ -145,7 +160,7 @@ function Exit(){
.campaign-preview-container { .campaign-preview-container {
width: 100%; width: 100%;
height: 100%; height: calc(100% - 24px);
display: flex; display: flex;
flex-direction: row; flex-direction: row;
} }
@ -158,7 +173,7 @@ function Exit(){
background-color: var(--color-background-soft); background-color: var(--color-background-soft);
border-right: 1px solid var(--color-border); border-right: 1px solid var(--color-border);
flex-grow: 1; flex-grow: 1;
min-width: 100px; min-width: 250px;
max-width: 300px; max-width: 300px;
} }
@ -166,7 +181,9 @@ function Exit(){
background-color: var(--color-background-semisoft); background-color: var(--color-background-semisoft);
display: flex; display: flex;
flex-direction: column;
flex-grow: 3; flex-grow: 3;
max-width: 100%;
} }
&.right { &.right {

View File

@ -199,7 +199,7 @@ onMounted(() => {
</div> </div>
</div> </div>
<div class="description"> <div class="description">
<MarkdownEditor ref="description" :done="DescriptionChanged"></MarkdownEditor> <MarkdownEditor ref="description" :done="DescriptionChanged" :editable="true"></MarkdownEditor>
</div> </div>
</div> </div>
</template> </template>