The best commit of humanity

This commit is contained in:
BinarySandia04 2024-08-07 22:49:59 +02:00
parent 569e165690
commit 5875b69089
13 changed files with 506 additions and 190 deletions

View File

@ -71,13 +71,14 @@
--chat-background: var(--c-white); --chat-background: var(--c-white);
--section-gap: 160px; --section-gap: 160px;
--separator-color: #2e2e2e;
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root { :root {
--window-background: var(--c-black-blurred); --window-background: var(--c-black-blurred);
--color-handler: var(--c-black-semisoft); --color-handler: #181818;
--color-background: var(--c-black); --color-background: var(--c-black);
--color-background-semisoft: var(--c-black-semisoft); --color-background-semisoft: var(--c-black-semisoft);
--color-background-soft: var(--c-black-soft); --color-background-soft: var(--c-black-soft);
@ -98,8 +99,9 @@
--color-chat-other: #1d1d1d; --color-chat-other: #1d1d1d;
--color-roll-dice-chat: #665750; --color-roll-dice-chat: #665750;
--separator-color: #363636;
--color-hover: var() /* --color-hover: var() */
} }
} }

View File

@ -143,4 +143,25 @@ button:active {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
display: block; display: block;
}
.parameters {
display: flex;
flex-direction: column;
width: 100%;
padding: 10px;
}
.param-element {
width: 100%;
display: flex;
flex-direction: row;
}
.param-text {
margin-right: auto;
}
.param-value {
margin-left: auto;
} }

191
client/src/services/Map.js Normal file
View File

@ -0,0 +1,191 @@
import { initCustomFormatter, ref } from 'vue';
let offsetX = 0;
let offsetY = 0;
let scale = 1;
let mouseX = 0;
let mouseY = 0;
function SetupTilemap(){
let tilemap = document.getElementById("tilemap");
tilemap.addEventListener("wheel", (event) => {
let direction = 0;
if(event.deltaY > 0) direction = 0.95;
else if(event.deltaY < 0) direction = 1.05;
zoom(direction);
})
let mouseDown = false;
let startX = 0, startY = 0;
let oldOffsetX = offsetX, oldOffsetY = offsetY;
tilemap.addEventListener("mousedown", (event) => {
mouseDown = true
startX = event.clientX;
startY = event.clientY;
oldOffsetX = offsetX;
oldOffsetY = offsetY;
});
tilemap.addEventListener("mousemove", (event) => {
mouseX = event.clientX;
mouseY = event.clientY;
if(!mouseDown) return;
offsetX = oldOffsetX + ((event.clientX - startX) * (1 / scale));
offsetY = oldOffsetY + ((event.clientY - startY) * (1 / scale));
Draw();
});
tilemap.addEventListener("mouseup", () => mouseDown = false);
addEventListener("resize", Draw)
offsetX = window.innerWidth / 2;
offsetY = window.innerHeight / 2;
Draw();
}
// Map coords -> Real coords
function toMapX(xReal) {
return (xReal + offsetX) * scale;
}
function toMapY(yReal){
return (yReal + offsetY) * scale;
}
// Real coords -> Map coords
function toRealX(xVirt){
return xVirt / scale - offsetX;
}
function toRealY(yVirt){
return yVirt / scale - offsetY;
}
function zoom(amount){
let dx = ((mouseX) / scale - offsetX) - ((mouseX) / (scale * amount) - offsetX)
let dy = ((mouseY) / scale - offsetY) - ((mouseY) / (scale * amount) - offsetY)
scale *= amount;
offsetX -= dx;
offsetY -= dy;
Draw();
}
let xUpperLeft = -Infinity;
let yUpperLeft = -Infinity;
let xDownRight = Infinity;
let yDownRight = Infinity;
function drawGrid(cellSize){
let canvas = document.getElementById('tilemap');
const width = canvas.clientWidth;
const height = canvas.clientHeight;
let ctx = canvas.getContext("2d");
ctx.strokeStyle = "#434343";
ctx.lineWidth = 1;
ctx.beginPath();
for (let x = (offsetX % cellSize) * scale; x <= width; x += cellSize * scale) {
if(toRealX(x) < xUpperLeft) continue;
if(toRealX(x) > xDownRight) continue;
ctx.moveTo(x, Math.max(0, toMapY(yUpperLeft)));
ctx.lineTo(x, Math.min(height, toMapY(yDownRight)));
}
for (let y = (offsetY % cellSize) * scale; y <= height; y += cellSize * scale) {
if(toRealY(y) < yUpperLeft) continue;
if(toRealY(y) > yDownRight) continue;
ctx.moveTo(Math.max(0, toMapX(xUpperLeft)), y);
ctx.lineTo(Math.min(width, toMapX(xDownRight)), y);
}
ctx.stroke();
ctx.strokeStyle = "red";
ctx.lineWidth = 1;
ctx.beginPath();
ctx.rect(toMapX(-10), toMapY(-10), 10 * scale, 10 * scale);
ctx.stroke();
}
// Ok aqui coses del mapa en si
let gridSize = 150;
let images = [];
let lines_of_sight = [];
let backgroundColor = ref('#0f0f0f');
function Draw(){
let canvas = document.getElementById('tilemap');
let ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
ctx.clearRect(0, 0, canvas.width, canvas.height);
images.forEach((image) => {
ctx.drawImage(image, toMapX(0), toMapY(0), image.naturalWidth * scale, image.naturalHeight * scale);
});
ctx.beginPath();
ctx.strokeStyle = "white";
ctx.lineWidth = 3;
lines_of_sight.forEach((line) => {
ctx.moveTo(toMapX(line[0].x * gridSize), toMapY(line[0].y * gridSize));
ctx.lineTo(toMapX(line[1].x * gridSize), toMapY(line[1].y * gridSize));
});
ctx.stroke();
drawGrid(gridSize);
}
function ImportDD2VTT(data){
console.log(data);
var image = new Image();
image.onload = function() {
images.push(image);
Draw();
};
gridSize = data.resolution.pixels_per_grid;
lines_of_sight = data.line_of_sight;
backgroundColor.value = '#' + data.environment.ambient_light;
xUpperLeft = data.resolution.map_origin.x * data.resolution.pixels_per_grid;
yUpperLeft = data.resolution.map_origin.y * data.resolution.pixels_per_grid;
xDownRight = xUpperLeft + data.resolution.map_size.x * data.resolution.pixels_per_grid;
yDownRight = yUpperLeft + data.resolution.map_size.y * data.resolution.pixels_per_grid;
image.src = "data:image/png;base64," + data.image;
}
let GetBackgroundColor = () => backgroundColor;
export {
toMapX,
toMapY,
toRealX,
toRealY,
zoom,
SetupTilemap,
// Draw,
ImportDD2VTT,
GetBackgroundColor,
};

View File

@ -1,30 +1,16 @@
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import { Disconnect } from './Dragonroll'; import { Disconnect } from './Dragonroll';
const windows = { const windows = ref([])
login: ref([]),
register: ref([]),
test: ref([]),
main_menu: ref([]),
edit_profile: ref([]),
account_settings: ref([]),
db_window: ref([]),
campaign_list: ref([]),
new_campaign: ref([]),
join_campaign: ref([]),
campaign_preview: ref([]),
chat: ref([]),
dice_menu: ref([]),
};
const defValues = { const defValues = {
'login': { 'login': {
id: 'login', id: 'login',
title: 'Login' title: 'Login',
}, },
'register': { 'register': {
id: 'register', id: 'register',
title: 'Register' title: 'Register',
}, },
'main_menu': { 'main_menu': {
id: 'main_menu', id: 'main_menu',
@ -78,6 +64,16 @@ const defValues = {
id: 'dice_menu', id: 'dice_menu',
title: 'Dice roll', title: 'Dice roll',
close: true close: true
},
'map_buttons': {
id: 'map_buttons',
title: '',
close: true
},
'environment': {
id: 'environment',
title: 'Edit environment',
close: true
} }
} }
@ -166,6 +162,11 @@ function SetPosition(id, pos){
SaveWindowPos({id, x: pos.x, y: pos.y}) SaveWindowPos({id, x: pos.x, y: pos.y})
} }
function GetPosition(id){
let win = GetWindowWithId(id);
return {x: win.x, y: win.y};
}
function ResetPosition(id, pos){ function ResetPosition(id, pos){
let win = GetWindowWithId(id); let win = GetWindowWithId(id);
let data = {x: win.x, y: win.y}; let data = {x: win.x, y: win.y};
@ -181,22 +182,18 @@ function ResetPosition(id, pos){
function CreateWindow(type, data = {}){ function CreateWindow(type, data = {}){
let finalData = {...{type}, ...defValues[type], ...data} let finalData = {...{type}, ...defValues[type], ...data}
if(windows[finalData.type] === undefined){
console.error("Window type " + finalData.type + " is not defined!");
return;
}
let contains = false; let contains = false;
for (let i = 0; i < windows[finalData.type].value.length; i++) { for (let i = 0; i < windows.value.length; i++) {
if(windows[finalData.type].value[i].id == finalData.id){ if(windows.value[i].id == finalData.id){
contains = true; contains = true;
break; break;
} }
} }
if(!contains) { if(!contains) {
windows[finalData.type].value.push(finalData); windows.value.push(finalData);
// reload.value += 1; // reload.value += 1;
console.log(windows.value);
setTimeout(() => SetOnTop(finalData.id), 0); setTimeout(() => SetOnTop(finalData.id), 0);
} }
} }
@ -212,7 +209,7 @@ function CreateChildWindow(parentId, type, data = {}){
function ClearAll(){ function ClearAll(){
Object.keys(windows).forEach((key) => { Object.keys(windows).forEach((key) => {
windows[key].value = []; windows.value = [];
}); });
} }
@ -227,16 +224,14 @@ function ClearWindow(id){
let win = GetWindowWithId(id); let win = GetWindowWithId(id);
if(!win) return; if(!win) return;
if(win.children) for(let i = 0; i < win.children.length; i++) ClearWindow(win.children[i]); if(win.children) for(let i = 0; i < win.children.length; i++) ClearWindow(win.children[i]);
windows[win.type].value = windows[win.type].value.filter((e) => {return e.id !== id}); windows.value = windows.value.filter((e) => {return e.id !== id});
// reload.value += 1; // reload.value += 1;
} }
function GetWindowWithId(id){ function GetWindowWithId(id){
for(let key of Object.keys(windows)){ for(let i = 0; i < windows.value.length; i++){
for(let i = 0; i < windows[key].value.length; i++){ if(windows.value[i].id == id){
if(windows[key].value[i].id == id){ return windows.value[i];
return windows[key].value[i];
}
} }
} }
} }
@ -268,6 +263,7 @@ export {
CreateChildWindow, CreateChildWindow,
GetWindowWithId, GetWindowWithId,
SaveWindowPos, SaveWindowPos,
GetPosition,
ClearWindow, ClearWindow,
ClearAll ClearAll
} }

View File

@ -4,11 +4,12 @@ import { InGameRef } from '../../services/Game';
import IconButton from '../partials/game/IconButton.vue'; import IconButton from '../partials/game/IconButton.vue';
import { AddSound } from '../../services/Sound'; import { AddSound } from '../../services/Sound';
import TileMap from './TileMap.vue'; import TileMap from './TileMap.vue';
import { DisplayCampaign, GetCampaign } from '../../services/Dragonroll'; import { DisplayCampaign, GetCampaign, GetClient } from '../../services/Dragonroll';
import { ClearAll, CreateWindow } from '../../services/Windows'; import { ClearAll, CreateWindow } from '../../services/Windows';
const game = ref(null); const game = ref(null);
const in_game = InGameRef(); const in_game = InGameRef();
const is_dm = ref(false);
function OpenCampaignPreview(){ function OpenCampaignPreview(){
CreateWindow('campaign_preview', {campaign: GetCampaign(), style: 'compact', hide_start: true, back: undefined, close: true}); CreateWindow('campaign_preview', {campaign: GetCampaign(), style: 'compact', hide_start: true, back: undefined, close: true});
@ -22,9 +23,16 @@ function OpenDiceMenu(){
CreateWindow('dice_menu'); CreateWindow('dice_menu');
} }
function OpenMapButtons(){
CreateWindow('map_buttons');
}
watch(game, () => { watch(game, () => {
if(game.value && in_game.value){ if(game.value && in_game.value){
AddSound(game.value); AddSound(game.value);
// Check if we are dm
is_dm.value = GetClient().is_dm;
} }
}); });
@ -40,6 +48,11 @@ watch(game, () => {
<IconButton icon="icons/iconoir/regular/cursor-pointer.svg"></IconButton> <IconButton icon="icons/iconoir/regular/cursor-pointer.svg"></IconButton>
<IconButton icon="icons/game-icons/000000/delapouite/rolling-dice-cup.svg" :action="OpenDiceMenu"></IconButton> <IconButton icon="icons/game-icons/000000/delapouite/rolling-dice-cup.svg" :action="OpenDiceMenu"></IconButton>
</div> </div>
<div class="vertical-button gm" v-if="is_dm">
<IconButton icon="icons/iconoir/regular/map.svg" :action="OpenMapButtons"></IconButton>
</div>
<div class="horizontal-button"> <div class="horizontal-button">
<IconButton icon="icons/iconoir/regular/group.svg"></IconButton> <IconButton icon="icons/iconoir/regular/group.svg"></IconButton>
<IconButton icon="icons/iconoir/regular/bookmark-book.svg"></IconButton> <IconButton icon="icons/iconoir/regular/bookmark-book.svg"></IconButton>
@ -62,6 +75,10 @@ watch(game, () => {
z-index: 1; z-index: 1;
user-select: none; user-select: none;
&.gm {
left: 48px;
}
} }
.horizontal-button { .horizontal-button {

View File

@ -1,133 +1,18 @@
<script setup> <script setup>
import { onMounted } from 'vue'; import { onMounted, watch } from 'vue';
import { GetBackgroundColor, SetupTilemap } from '../../services/Map';
const backgroundColor = GetBackgroundColor();
let offsetX = 0;
let offsetY = 0;
let scale = 1;
let mouseX = 0;
let mouseY = 0;
// Map coords -> Real coords
function toMapX(xReal) {
return (xReal + offsetX) * scale;
}
function toMapY(yReal){
return (yReal + offsetY) * scale;
}
// Real coords -> Map coords
function toRealX(xVirt){
return xVirt / scale - offsetX;
}
function toRealY(yVirt){
return yVirt / scale - offsetY;
}
function zoom(amount){
let dx = ((mouseX) / scale - offsetX) - ((mouseX) / (scale * amount) - offsetX)
let dy = ((mouseY) / scale - offsetY) - ((mouseY) / (scale * amount) - offsetY)
scale *= amount;
offsetX -= dx;
offsetY -= dy;
console.log(scale);
draw();
}
function drawGrid(){
let canvas = document.getElementById('tilemap');
const width = canvas.clientWidth;
const height = canvas.clientHeight;
let ctx = canvas.getContext("2d");
let cellSize = 30;
ctx.strokeStyle = "#434343";
ctx.lineWidth = 1;
ctx.beginPath();
/* Vertical lines spanning the full width */
for (let x = (offsetX % cellSize) * scale; x <= width; x += cellSize * scale) {
ctx.moveTo(x, 0);
ctx.lineTo(x, height);
}
/* Horizontal lines spanning the full height */
for (let y = (offsetY % cellSize) * scale; y <= height; y += cellSize * scale) {
ctx.moveTo(0, y);
ctx.lineTo(width, y);
}
ctx.stroke();
ctx.strokeStyle = "red";
ctx.lineWidth = 1;
ctx.beginPath();
ctx.rect(toMapX(-10), toMapY(-10), 10 * scale, 10 * scale);
ctx.stroke();
}
function draw(){
let canvas = document.getElementById('tilemap');
let ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawGrid();
}
onMounted(() => { onMounted(() => {
let tilemap = document.getElementById("tilemap"); SetupTilemap();
tilemap.addEventListener("wheel", (event) => {
let direction = 0;
if(event.deltaY > 0) direction = 0.95;
else if(event.deltaY < 0) direction = 1.05;
zoom(direction);
})
let mouseDown = false;
let startX = 0, startY = 0;
let oldOffsetX = offsetX, oldOffsetY = offsetY;
tilemap.addEventListener("mousedown", (event) => {
mouseDown = true
startX = event.clientX;
startY = event.clientY;
oldOffsetX = offsetX;
oldOffsetY = offsetY;
});
tilemap.addEventListener("mousemove", (event) => {
mouseX = event.clientX;
mouseY = event.clientY;
if(!mouseDown) return;
offsetX = oldOffsetX + ((event.clientX - startX) * (1 / scale));
offsetY = oldOffsetY + ((event.clientY - startY) * (1 / scale));
draw();
// console.log("x: " + offsetX + ", y: " + offsetY);
});
tilemap.addEventListener("mouseup", () => mouseDown = false);
addEventListener("resize", draw)
offsetX = window.innerWidth / 2;
offsetY = window.innerHeight / 2;
draw();
}); });
watch(backgroundColor, () => {
let tilemap = document.getElementById('tilemap');
tilemap.style.backgroundColor = backgroundColor.value;
}, {deep: true});
</script> </script>
<template> <template>

View File

@ -17,43 +17,33 @@ import JoinCampaignWindow from '../windows/campaigns/JoinCampaignWindow.vue'
import CampaignPreviewWindow from '@/views/windows/campaigns/CampaignPreviewWindow.vue' import CampaignPreviewWindow from '@/views/windows/campaigns/CampaignPreviewWindow.vue'
import ChatWindow from '../windows/game/ChatWindow.vue' 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 EnvironmentWindow from '../windows/dm/EnvironmentWindow.vue'
// Gestionem ventanas // Gestionem ventanas
const reload = ReloadRef(); const reload = ReloadRef();
const windows = Windows(); const windows = Windows();
// Win names const WindowMap = {
const login = windows.login; login: LoginWindow,
const register = windows.register; main_menu: MainMenuWindow,
const test = windows.test; register: RegisterWindow,
const main_menu = windows.main_menu; edit_profile: EditProfileWindow,
const edit_profile = windows.edit_profile; account_settings: AccountSettingsWindow,
const account_settings = windows.account_settings; campaign_list: CampaignListWindow,
const db_window = windows.db_window; new_campaign: NewCampaignWindow,
const campaign_list = windows.campaign_list; join_campaign: JoinCampaignWindow,
const new_campaign = windows.new_campaign; campaign_preview: CampaignPreviewWindow,
const join_campaign = windows.join_campaign; chat: ChatWindow,
const campaign_preview = windows.campaign_preview; dice_menu: DiceWindow,
const chat = windows.chat; map_buttons: MapButtons,
const dice_menu = windows.dice_menu; environment: EnvironmentWindow
};
</script> </script>
<template> <template>
<div class="window-container" :key="reload"> <div class="window-container" :key="reload">
<LoginWindow v-for="win in login" :key="win.id" :data="win"></LoginWindow> <component v-for="win in windows" :is="WindowMap[win.type]" :key="win.id" :data="win"></component>
<RegisterWindow v-for="win in register" :key="win.id" :data="win"></RegisterWindow>
<ExampleWindow v-for="win in test" :key="win.id" :data="win"></ExampleWindow>
<MainMenuWindow v-for="win in main_menu" :key="win.id" :data="win"></MainMenuWindow>
<EditProfileWindow v-for="win in edit_profile" :key="win.id" :data="win"></EditProfileWindow>
<AccountSettingsWindow v-for="win in account_settings" :key="win.id" :data="win"></AccountSettingsWindow>
<DbWindow v-for="win in db_window" :key="win.id" :data="win"></DbWindow>
<CampaignListWindow v-for="win in campaign_list" :key="win.id" :data="win"></CampaignListWindow>
<NewCampaignWindow v-for="win in new_campaign" :key="win.id" :data="win"></NewCampaignWindow>
<JoinCampaignWindow v-for="win in join_campaign" :key="win.id" :data="win"></JoinCampaignWindow>
<CampaignPreviewWindow v-for="win in campaign_preview" :key="win.id" :data="win"></CampaignPreviewWindow>
<ChatWindow v-for="win in chat" :key="win.id" :data="win"></ChatWindow>
<DiceWindow v-for="win in dice_menu" :key="win.id" :data="win"></DiceWindow>
</div> </div>
</template> </template>

View File

@ -92,7 +92,7 @@ watch(chat, () => {
flex-direction: column; flex-direction: column;
overflow-y: auto; overflow-y: auto;
max-height: 580px; max-height: 620px;
margin-bottom: 10px; margin-bottom: 10px;
} }

View File

@ -0,0 +1,48 @@
<script setup>
import { onMounted, ref } from 'vue';
const color = ref("");
const colorValue = ref(null);
const colorPicker = ref(null);
onMounted(() => {
colorValue.value.addEventListener('click', () => {
console.log("Click");
colorPicker.value.click();
})
colorPicker.value.addEventListener('input', (event) => {
let newColor = event.target.value;
colorValue.value.classList.remove('unselected');
colorValue.value.style.backgroundColor = newColor;
color.value = newColor;
});
});
let GetColor = () => color;
defineExpose({ GetColor });
</script>
<template>
<input type="color" id="colorPicker" ref="colorPicker">
<div class="color-value unselected" ref="colorValue"></div>
</template>
<style lang="scss">
#colorPicker {
display: none;
}
.color-value {
width: 30px;
height: 20px;
&.unselected {
background-image: linear-gradient(45deg, #808080 25%, transparent 25%), linear-gradient(-45deg, #808080 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #808080 75%), linear-gradient(-45deg, transparent 75%, #808080 75%);
background-size: 10px 10px;
background-position: 0 0, 0 5px, 5px -5px, -5px 0px;
}
}
</style>

View File

@ -0,0 +1,59 @@
<script setup>
import WindowHandle from '@/views/partials/WindowHandle.vue';
import { onMounted, onUpdated, ref, watch } from 'vue';
import { SetupHandle, SetSize, SetPosition, ResetPosition } from '@/services/Windows';
import IconButton from '@/views/partials/game/IconButton.vue'
import ColorValue from '../../partials/parameters/ColorValue.vue';
import { GetBackgroundColor } from '../../../services/Map';
const props = defineProps(['data']);
const data = props.data;
const handle = ref(null);
const mapUploader = ref(null);
const env_background = ref(null);
let id = data.id;
onMounted(() => {
SetupHandle(id, handle);
SetSize(id, {x: 200, y: 300});
ResetPosition(id, {x: data.x, y: data.y});
console.log(env_background.value.GetColor());
watch(env_background.value.GetColor(), () => {
GetBackgroundColor().value = env_background.value.GetColor().value; // XD
});
});
function UploadButton(){
mapUploader.value.click();
}
</script>
<template>
<div class="window-wrapper" :id="'window-wrapper-' + id">
<WindowHandle :window="id" ref="handle"></WindowHandle>
<div class="parameters">
<div class="param-element">
<div class="param-text">Background color: </div>
<div class="param-value"><ColorValue ref="env_background"></ColorValue></div>
</div>
</div>
</div>
</template>
<style scoped>
.window-wrapper {
display: flex;
align-items: center;
user-select: none;
}
</style>

View File

@ -0,0 +1,107 @@
<script setup>
import WindowHandle from '@/views/partials/WindowHandle.vue';
import { onMounted, onUpdated, ref } from 'vue';
import { SetupHandle, SetSize, SetPosition, ResetPosition } from '@/services/Windows';
import IconButton from '@/views/partials/game/IconButton.vue'
import { ImportDD2VTT } from '../../../services/Map';
import { CreateChildWindow, GetPosition } from '../../../services/Windows';
const props = defineProps(['data']);
const data = props.data;
const handle = ref(null);
const mapUploader = ref(null);
let id = data.id;
onMounted(() => {
SetupHandle(id, handle);
SetSize(id, {x: 40, y: 500});
ResetPosition(id, {x: 10, y: 200});
mapUploader.value.addEventListener('change', (event) => {
let file = event.target.files[0];
let reader = new FileReader();
reader.addEventListener('load', (event) => {
ImportDD2VTT(JSON.parse(event.target.result));
});
reader.readAsText(file);
})
});
function UploadButton(){
mapUploader.value.click();
}
function EditEnvironment(){
let winPos = GetPosition(id);
CreateChildWindow(id, 'environment', {x: winPos.x + 50, y: winPos.y});
}
</script>
<template>
<form id="send-map-form" enctype="multipart/form-data">
<input name="file" type="file" accept=".dd2vtt" ref="mapUploader">
</form>
<div class="window-wrapper" :id="'window-wrapper-' + id">
<WindowHandle :window="id" ref="handle"></WindowHandle>
<div class="vertical-button">
<IconButton icon="icons/iconoir/regular/upload.svg" :action="UploadButton"></IconButton>
<hr>
<IconButton icon="icons/iconoir/regular/square-3d-three-points.svg" :action="UploadButton"></IconButton>
<IconButton icon="icons/iconoir/regular/orthogonal-view.svg" :action="UploadButton"></IconButton>
<hr>
<IconButton icon="icons/iconoir/regular/sun-light.svg" :action="EditEnvironment"></IconButton>
</div>
</div>
</template>
<style scoped>
#send-map-form {
display: none;
}
.window-wrapper {
display: flex;
align-items: center;
user-select: none;
}
.vertical-button {
position: absolute;
top: 26px;
left: 2px;
display: flex;
flex-direction: column;
z-index: 1;
user-select: none;
&.gm {
left: 48px;
}
hr::before {
width: 0px;
height: 0px;
}
hr {
margin-left: auto;
margin-right: auto;
width: 30px;
margin-top: 1px;
margin-bottom: 1px;
background-color: var(--separator-color);
}
}
</style>

View File

@ -15,7 +15,7 @@ let id = data.id;
onMounted(() => { onMounted(() => {
SetupHandle(id, handle); SetupHandle(id, handle);
SetSize(id, {x: 400, y: 750}); SetSize(id, {x: 400, y: 750});
ResetPosition(id, "center"); ResetPosition(id, {x: window.innerWidth - 420, y: 80});
}); });
</script> </script>

View File

@ -72,7 +72,7 @@ function ThrowCustomDice(){
onMounted(() => { onMounted(() => {
SetupHandle(id, handle); SetupHandle(id, handle);
SetSize(id, {x: 300, y: 210}); SetSize(id, {x: 300, y: 210});
ResetPosition(id, "center"); ResetPosition(id, {x: 100, y: 150});
}); });
</script> </script>