More things

This commit is contained in:
BinarySandia04 2024-09-10 18:51:24 +02:00
parent 8b6db3c9c3
commit e347409e89
12 changed files with 378 additions and 54 deletions

View File

@ -0,0 +1,115 @@
// You should hide the context menu when the element that has the
// event gets removed
let margin = -3;
let cursorX = 0;
let cursorY = 0;
let arrowIcon = "icons/iconoir/regular/nav-arrow-right.svg";
function ShowContextMenu(){
let contextMenu = document.getElementById('context-menu');
contextMenu.style.display = "flex";
contextMenu.style.top = (cursorY + margin) + "px";
contextMenu.style.left = (cursorX + margin) + "px";
}
function HideContextMenu(){
let contextMenu = document.getElementById('context-menu');
contextMenu.style.display = "none";
}
function PopulateContext(val){
let children = [];
val.forEach(element => {
let contextMenuElement = document.createElement('div');
contextMenuElement.classList.add("context-menu-element");
if(element.action)
contextMenuElement.addEventListener("click", element.action);
let spanInfo = document.createElement('span');
spanInfo.innerText = element.name;
contextMenuElement.appendChild(spanInfo);
if(element.context){
let iconContextElement = document.createElement('img');
iconContextElement.src = arrowIcon;
contextMenuElement.appendChild(iconContextElement);
let childContextMenuElement = document.createElement('div');
childContextMenuElement.classList.add("context-menu");
childContextMenuElement.style.left = "100%";
childContextMenuElement.style.top = "0";
childContextMenuElement.style.display = "none";
let childChildren = PopulateContext(element.context);
childChildren.forEach((child) => childContextMenuElement.appendChild(child));
contextMenuElement.addEventListener("mouseenter", () => {
childContextMenuElement.style.display = "flex";
});
contextMenuElement.addEventListener("mouseleave", () => {
childContextMenuElement.style.display = "none";
})
contextMenuElement.appendChild(childContextMenuElement);
}
children.push(contextMenuElement);
});
return children;
}
function PopulateContextMenu(val){
let contextMenu = document.getElementById('context-menu');
let children = PopulateContext(val);
contextMenu.replaceChildren();
children.forEach((el) => contextMenu.appendChild(el));
}
function AddContextMenu(element, val){
element._dr_context = val;
element.addEventListener('contextmenu', (e) => {
e.preventDefault();
PopulateContextMenu(val);
ShowContextMenu();
});
}
function UpdateVisibility(){
let contextMenu = document.getElementById('context-menu');
let element = document.elementFromPoint(cursorX, cursorY);
let mustHide = true;
while(element){
if(element == contextMenu){
mustHide = false;
break;
}
element = element.parentElement;
}
if(mustHide) HideContextMenu();
}
function SetupContextMenu(){
HideContextMenu();
document.addEventListener('mousemove', (e) => {
cursorX = e.clientX;
cursorY = e.clientY;
});
document.addEventListener('mousedown', UpdateVisibility);
}
export {
SetupContextMenu,
AddContextMenu,
ShowContextMenu,
HideContextMenu
};

View File

@ -16,20 +16,19 @@ function HideTooltip(){
tooltip.style.display = "none";
}
function AddTooltip(element, val){
element._dr_tooltip = val;
function AddTooltip(element, val, data = {}){
element._dr_tooltip = {value: val, ...data};
}
function UpdateVisibilityThread(){
let hiding = true;
document.elementsFromPoint(cursorX, cursorY).forEach(element => {
let tooltip = document.getElementById('mouse-tooltip');
let element = document.elementFromPoint(cursorX, cursorY);
if(element._dr_tooltip){
hiding = false;
content.value = element._dr_tooltip;
}
});
if(hiding) HideTooltip();
else ShowTooltip();
ShowTooltip();
content.value = element._dr_tooltip.value;
if(element._dr_tooltip.max_width) tooltip.style.maxWidth = element._dr_tooltip.max_width + "px";
else tooltip.style.maxWidth = "none";
} else HideTooltip();
setTimeout(UpdateVisibilityThread, 0);
}

View File

@ -10,6 +10,7 @@ import Toast from './partials/Toast.vue';
import { DisplayToast, SetEmitter } from '../services/Dragonroll';
import GameManager from './managers/GameManager.vue';
import TooltipManager from './managers/TooltipManager.vue';
import ContextMenuManager from './managers/ContextMenuManager.vue';
</script>
@ -18,6 +19,7 @@ import TooltipManager from './managers/TooltipManager.vue';
<Toast></Toast>
<GameManager></GameManager>
<TooltipManager></TooltipManager>
<ContextMenuManager></ContextMenuManager>
<WindowManager></WindowManager>
</template>

View File

@ -0,0 +1,70 @@
<script setup>
import { onMounted, watch, ref } from 'vue';
import { SetupContextMenu } from '../../services/ContextMenu';
onMounted(() => {
SetupContextMenu();
});
</script>
<template>
<div id="context-menu" class="context-menu">
<div class="context-menu-element">
<span>Hola</span> <img src="icons/iconoir/regular/nav-arrow-right.svg">
</div>
<div class="context-menu-element">
<span>Holaa</span>
</div>
<div class="context-menu-element">
<span>Holaa</span>
</div>
<div class="context-menu-element">
<span>Holaaaaaaa</span>
</div>
</div>
</template>
<style lang="scss">
.context-menu {
position: absolute;
z-index: 214748363;
flex-direction: column;
background-color: var(--tooltip-background);
-webkit-box-shadow: 0px 0px 5px -2px rgba(0,0,0,0.75);
-moz-box-shadow: 0px 0px 5px -2px rgba(0,0,0,0.75);
box-shadow: 0px 0px 5px -2px rgba(0,0,0,0.75);
border: solid 1px var(--color-border);
.context-menu-element {
padding: 3px 5px 3px 5px;
cursor: default;
user-select: none;
transition: background-color 100ms;
display: flex;
align-items: center;
position: relative;
span {
flex-grow: 1;
padding-right: 20px;
white-space: nowrap;
}
img {
filter: invert(1);
width: 18px;
height: 18px;
}
&:hover {
background-color: var(--color-background-softest);
}
}
}
</style>

View File

@ -1,11 +1,18 @@
<script setup>
import { onMounted, watch } from 'vue';
import { onMounted, watch, ref } from 'vue';
import { GetBackgroundColor, SetupTilemap } from '../../services/Map';
import { AddContextMenu } from '../../services/ContextMenu';
const backgroundColor = GetBackgroundColor();
const canvas = ref(null);
onMounted(() => {
SetupTilemap();
AddContextMenu(canvas.value, [
{name: "Ping"}
]);
});
watch(backgroundColor, () => {
@ -16,7 +23,7 @@ watch(backgroundColor, () => {
</script>
<template>
<canvas class="tilemap" id="tilemap"></canvas>
<canvas class="tilemap" id="tilemap" ref="canvas"></canvas>
</template>
<style scoped lang="scss">

View File

@ -17,8 +17,10 @@ onMounted(() => {
<template>
<div id="mouse-tooltip" class="mouse-tooltip">
<div class="document">
<span v-html="contentRef"></span>
</div>
</div>
</template>
<style scoped lang="scss">

View File

@ -34,7 +34,7 @@ onMounted(() => {
textInput.value.style.height = "1px";
textInput.value.style.height = (textInput.value.scrollHeight)+"px";
}
})
});
});
watch(chat, () => {
@ -58,10 +58,10 @@ watch(chat, () => {
<textarea ref="textInput" class="chat-input"></textarea>
<div class="chat-input-actions">
<div class="chat-input-actions-left">
<IconButton icon="icons/iconoir/regular/trash.svg"></IconButton>
<IconButton icon="icons/iconoir/regular/trash.svg" tooltip="Clear chat"></IconButton>
</div>
<div class="chat-input-actions-right">
<IconButton icon="icons/iconoir/regular/send.svg"></IconButton>
<IconButton icon="icons/iconoir/regular/send.svg" tooltip="Send message"></IconButton>
</div>
</div>
</div>

View File

@ -1,16 +1,28 @@
<script setup>
const props = defineProps(['icon', 'action', 'size', 'toggled']);
import { onMounted, ref } from 'vue';
import { AddTooltip } from '../../../services/Tooltip';
const props = defineProps(['icon', 'action', 'size', 'toggled', 'tooltip']);
let icon = props.icon;
let action = props.action;
let size = props.size;
let toggled = props.toggled;
let tooltip = props.tooltip;
const button = ref(null);
onMounted(() => {
if(tooltip){
AddTooltip(button.value, tooltip);
}
})
</script>
<template>
<div class="icon-button sound-click" :class="size + ' ' + toggled" v-on:click.prevent="action">
<div class="icon-button sound-click" :class="size + ' ' + toggled" v-on:click.prevent="action" ref="button">
<img class="icon" draggable="false" :src="icon" :class="size">
</div>
</template>
@ -53,6 +65,7 @@ let toggled = props.toggled;
.icon {
height: 24px;
width: 24px;
pointer-events: none;
&.big {
height: 38px;

View File

@ -13,6 +13,7 @@ import Api from '@/services/Api.js'
import useEmitter from '@/services/Emitter';
import { ClearWindow, CreateWindow, Windows } from '../../services/Windows';
import { AddTooltip } from '../../services/Tooltip';
import { AddContextMenu } from '../../services/ContextMenu';
const emitter = useEmitter();
const handle = ref(null);
@ -30,28 +31,24 @@ onMounted(() => {
SetSize(id, {width: 500, height: 540});
ResetPosition(id, "center", emitter);
AddTooltip(campaignButton.value, "<h2>Hey</h2>Hola test");
});
// ???
/*
function OpenDatabase(){
ClearWindow(id);
CreateWindow({
type: 'db_window',
id: 'db_window',
title: "Database",
back: () => {
ClearWindow('db_window');
CreateWindow({
type: 'main_menu',
id: 'main_menu',
title: 'Dragonroll'
})
}
});
}
AddTooltip(campaignButton.value, "<h2>Hey</h2>Hola test");
AddContextMenu(campaignButton.value, [
{name: "Test", action: () => {alert("Test")}},
{name: "A", action: () => {alert("A")}},
{name: "B", action: () => {alert("B")}},
{name: "Patata", action: () => {alert("Patata")}, context: [
{name: "Test 2dsadsadsdsadasdasdsad", action: () => {alert("Test context")}},
{name: "A 3", action: () => {alert("A context")}, context: [
{name: "Test", action: () => {alert("Test")}},
{name: "A", action: () => {alert("A")}},
{name: "B", action: () => {alert("B")}},
]},
{name: "B 5", action: () => {alert("B context")}},
]},
])
*/
});
function OpenCampaigns(){
ClearWindow(id);

View File

@ -12,6 +12,7 @@ import { AddSound } from '../../../services/Sound';
import ChatComponent from '../../partials/ChatComponent.vue';
import GameSystem from '@/views/partials/GameSystem.vue'
import { GetModule } from '../../../services/Modules';
import { AddTooltip } from '../../../services/Tooltip';
const handle = ref(null);
@ -21,6 +22,7 @@ const data = props.data;
const hide_start = ref(false);
const hide_chat = ref(false);
const campaign_title = ref(null);
const copy_code_button = ref(null);
const container = ref(null);
@ -41,6 +43,8 @@ onMounted(() => {
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>Click this button to copy the invite code of your campaign to the clipboard</p>", {max_width: 300})
});
function CopyCode(){
@ -74,7 +78,7 @@ function Exit(){
<h2>Players</h2>
<PlayerList :campaign="data.campaign"></PlayerList>
<div class="buttons-row">
<button class="btn-primary button-row sound-click" v-on:click.prevent="CopyCode">Copy invite code</button>
<button class="btn-primary button-row sound-click" v-on:click.prevent="CopyCode" ref="copy_code_button">Copy invite code</button>
</div>
</div>
<div class="campaign-preview-column center">

View File

@ -38,6 +38,7 @@ function comp (s, m, n, f, a) {
r += Math.floor( Math.random() * f ) + 1;
return r * m + a;
};
function parse( de ) {
return comp.apply( this, de.match(/(?:(\d+)\s*\*\s*)?(\d*)d(\d+)(?:\s*([\+\-]\s*\d+))?/i) );
}
@ -82,17 +83,17 @@ onMounted(() => {
<WindowHandle :window="id" ref="handle"></WindowHandle>
<div class="horizontal-dice">
<IconButton icon="icons/game-icons/000000/skoll/d4.svg" :action="ThrowD4" size="big"></IconButton>
<IconButton icon="icons/game-icons/000000/delapouite/perspective-dice-six-svg.svg" :action="ThrowD6" size="big"></IconButton>
<IconButton icon="icons/game-icons/000000/delapouite/dice-eight-faces-eight.svg" :action="ThrowD8" size="big"></IconButton>
<IconButton icon="icons/game-icons/000000/skoll/d10.svg" :action="ThrowD10" size="big"></IconButton>
<IconButton icon="icons/game-icons/000000/skoll/d12.svg" :action="ThrowD12" size="big"></IconButton>
<IconButton icon="icons/game-icons/000000/delapouite/dice-twenty-faces-twenty.svg" :action="ThrowD20" size="big"></IconButton>
<IconButton icon="icons/game-icons/000000/skoll/d4.svg" :action="ThrowD4" tooltip="Throw d4" size="big"></IconButton>
<IconButton icon="icons/game-icons/000000/delapouite/perspective-dice-six-svg.svg" :action="ThrowD6" tooltip="Throw d6" size="big"></IconButton>
<IconButton icon="icons/game-icons/000000/delapouite/dice-eight-faces-eight.svg" :action="ThrowD8" tooltip="Throw d8" size="big"></IconButton>
<IconButton icon="icons/game-icons/000000/skoll/d10.svg" :action="ThrowD10" tooltip="Throw d10" size="big"></IconButton>
<IconButton icon="icons/game-icons/000000/skoll/d12.svg" :action="ThrowD12" tooltip="Throw d12" size="big"></IconButton>
<IconButton icon="icons/game-icons/000000/delapouite/dice-twenty-faces-twenty.svg" :action="ThrowD20" tooltip="Throw d20" size="big"></IconButton>
</div>
<div class="custom-dice">
<input type="text" ref="diceField">
<IconButton icon="icons/game-icons/000000/delapouite/rolling-dices.svg" size="big" :action="ThrowCustomDice"></IconButton>
<IconButton icon="icons/game-icons/000000/delapouite/rolling-dices.svg" size="big" :action="ThrowCustomDice" tooltip="Throw"></IconButton>
</div>
<div class="roll-result">{{ diceResult }}</div>

View File

@ -158,7 +158,7 @@ function ConfigureBookmarks(){
</div>
</div>
</div>
<div class="flex-container">
<div class="flex-container overflow">
<div class="saving-throws">
<span class="span-header">Saving Throws</span>
<div class="saving-throws-container">
@ -289,20 +289,130 @@ function ConfigureBookmarks(){
</div>
</div>
</div>
<div class="skill-throws">
<span class="span-header">Skills</span>
<div class="skill-throws-container">
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Acrobatics (Dex)</span>
<span class="skill-throw-modifier">+1</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Animal Handling (Wis)</span>
<span class="skill-throw-modifier">+5</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Arcana (Int)</span>
<span class="skill-throw-modifier">+2</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Athletics (Str)</span>
<span class="skill-throw-modifier">+3</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Deception (Cha)</span>
<span class="skill-throw-modifier">-1</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">History (Int)</span>
<span class="skill-throw-modifier">+1</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Insight (Wis)</span>
<span class="skill-throw-modifier">+1</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Intimidation (Cha)</span>
<span class="skill-throw-modifier">+1</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Investigation (Int)</span>
<span class="skill-throw-modifier">+1</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Medicine (Wis)</span>
<span class="skill-throw-modifier">+1</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Nature (Int)</span>
<span class="skill-throw-modifier">+1</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Perception (Wis)</span>
<span class="skill-throw-modifier">+1</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Performance (Cha)</span>
<span class="skill-throw-modifier">+1</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Persuasion (Cha)</span>
<span class="skill-throw-modifier">+1</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Religion (Int)</span>
<span class="skill-throw-modifier">+1</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Sleight of Hand (Dex)</span>
<span class="skill-throw-modifier">+1</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Stealth (Dex)</span>
<span class="skill-throw-modifier">+1</span>
</div>
<div class="skill-throw">
<input type="checkbox" name="str-saving">
<span class="skill-throw-class">Survival (Wis)</span>
<span class="skill-throw-modifier">+1</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sheet-content" v-show="selectedBookmark == 1">
Actions
<!-- Inventory -->
<div class="fixed-container">
<div class="weight-container"></div>
<div class="money-container"></div>
<div class="filter-container"></div>
<div class="inventory-container"></div>
</div>
</div>
<div class="sheet-content" v-show="selectedBookmark == 2">
Inventory
<div class="classes-container"></div>
<div class="features-container"></div>
</div>
<div class="sheet-content" v-show="selectedBookmark == 3">
Traits
<!-- spells -->
<div class="spellcasting-container"></div>
<div class="spells-container"></div>
</div>
<div class="sheet-content" v-show="selectedBookmark == 4">
Bio
<div class="effects-container"></div>
<div class="conditions-container"></div>
</div>
<div class="sheet-content" v-show="selectedBookmark == 5">
<div class="properties-container"></div>
<div class="bio-traits-container"></div>
<div class="bio-container"></div>
</div>
</div>
</template>
@ -571,8 +681,7 @@ div.player-info-div {
}
.two-column-layout {
display: grid;
grid-template-columns: 1fr 1fr;
display: flex;
flex-direction: row;
margin-top: 50px;
margin-left: 20px;
@ -582,6 +691,11 @@ div.player-info-div {
&.border {
border: 1px solid var(--color-border);
background-color: #1b1b1b;
/* Change */
position: sticky;
align-self: flex-start;
top: 50px;
margin-top: 0px;
}
margin: auto;
width: 300px;