Whatever ClearWindow needs to be in json
All checks were successful
Build and Deploy Nuxt / build (push) Successful in 42s
All checks were successful
Build and Deploy Nuxt / build (push) Successful in 42s
This commit is contained in:
@@ -5,6 +5,7 @@ import WindowManager from './components/managers/WindowManager.vue';
|
|||||||
|
|
||||||
import { CreateWindow } from '@/services/Windows'
|
import { CreateWindow } from '@/services/Windows'
|
||||||
import { GetUser, HasAdmin } from './services/User';
|
import { GetUser, HasAdmin } from './services/User';
|
||||||
|
import TooltipManager from './components/managers/TooltipManager.vue';
|
||||||
|
|
||||||
async function start(){
|
async function start(){
|
||||||
if(GetUser()){
|
if(GetUser()){
|
||||||
@@ -39,6 +40,7 @@ onMounted(() => {
|
|||||||
<template>
|
<template>
|
||||||
<div class="viewer">
|
<div class="viewer">
|
||||||
<ToastManager></ToastManager>
|
<ToastManager></ToastManager>
|
||||||
|
<TooltipManager></TooltipManager>
|
||||||
<WindowManager></WindowManager>
|
<WindowManager></WindowManager>
|
||||||
<ContentManager></ContentManager>
|
<ContentManager></ContentManager>
|
||||||
<!-- Managers -->
|
<!-- Managers -->
|
||||||
|
|||||||
41
frontend/app/components/managers/TooltipManager.vue
Normal file
41
frontend/app/components/managers/TooltipManager.vue
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, watch, ref } from 'vue';
|
||||||
|
import { GetContentRef, SetupTooltip } from '../../services/Tooltip';
|
||||||
|
|
||||||
|
let contentRef = ref("");
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
SetupTooltip();
|
||||||
|
let content = GetContentRef();
|
||||||
|
|
||||||
|
watch(GetContentRef(), () => {
|
||||||
|
contentRef.value = GetContentRef().value;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="mouse-tooltip" class="mouse-tooltip">
|
||||||
|
<div class="document">
|
||||||
|
<span v-html="contentRef"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.mouse-tooltip {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 214748364;
|
||||||
|
|
||||||
|
background-color: var(--tooltip-background);
|
||||||
|
padding: 3px 6px 3px 6px;
|
||||||
|
|
||||||
|
-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);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,17 +1,14 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { TransitionGroup } from 'vue'
|
import { TransitionGroup } from 'vue'
|
||||||
import { Windows, ReloadRef, WindowMap, getComponent } from '@/services/Windows';
|
import { windows, getComponent } from '@/services/Windows';
|
||||||
|
|
||||||
// Gestionem ventanas
|
|
||||||
const reload = ReloadRef();
|
|
||||||
const windows = Windows();
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="window-container" :key="reload">
|
<div class="window-container">
|
||||||
<TransitionGroup name="window">
|
<TransitionGroup name="window" tag="div">
|
||||||
<component v-for="win in windows" :is="getComponent(win.type)" :key="win.id" :data="win"></component>
|
<div v-for="win in windows" :key="win.id">
|
||||||
|
<component :is="getComponent(win.type)" :data="win" />
|
||||||
|
</div>
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ import { GetUser, LogoutUser } from '@/services/User'
|
|||||||
|
|
||||||
import Server from '@/services/Server'
|
import Server from '@/services/Server'
|
||||||
|
|
||||||
import { ClearWindows, CreateWindow, CreateChildWindow, ClearWindow } from '../../services/Windows';
|
import { CreateWindow, CreateChildWindow, ClearWindow, GetFirstWindowId } from '../../services/Windows';
|
||||||
import { backendUrl } from '../../services/BackendURL';
|
import { backendUrl } from '../../services/BackendURL';
|
||||||
import Spinner from './Spinner.vue';
|
import Spinner from './Spinner.vue';
|
||||||
const emitter = useEmitter();
|
|
||||||
const loadedIcon = ref(false);
|
const loadedIcon = ref(false);
|
||||||
|
|
||||||
const username = ref("");
|
const username = ref("");
|
||||||
@@ -45,13 +44,12 @@ function retrieveAvatar(){
|
|||||||
function LogOut(){
|
function LogOut(){
|
||||||
LogoutUser();
|
LogoutUser();
|
||||||
|
|
||||||
ClearWindows({type: "main_menu"});
|
ClearWindow({type: "main_menu"});
|
||||||
CreateWindow('login');
|
CreateWindow('login');
|
||||||
}
|
}
|
||||||
|
|
||||||
function EditProfile(){
|
function EditProfile(){
|
||||||
console.log("User:"); console.log(GetUser());
|
CreateChildWindow(GetFirstWindowId('main_menu'), 'edit_profile', {
|
||||||
CreateChildWindow('main_menu', 'edit_profile', {
|
|
||||||
user: GetUser()
|
user: GetUser()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -104,7 +102,7 @@ onMounted(() => {
|
|||||||
<Spinner v-show="!loadedIcon" :size="30"></Spinner>
|
<Spinner v-show="!loadedIcon" :size="30"></Spinner>
|
||||||
</div>
|
</div>
|
||||||
<div class="main-user-info">
|
<div class="main-user-info">
|
||||||
<b>{{ username }}</b><br>Hola
|
<b>{{ username }}</b><br>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="main-user-actions">
|
<div class="main-user-actions">
|
||||||
|
|||||||
84
frontend/app/components/partials/IconButton.vue
Normal file
84
frontend/app/components/partials/IconButton.vue
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<script setup>
|
||||||
|
|
||||||
|
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" ref="button">
|
||||||
|
<img class="icon" draggable="false" :src="icon" :class="size">
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.icon-button {
|
||||||
|
height: 32px;
|
||||||
|
width: 32px;
|
||||||
|
|
||||||
|
&.big {
|
||||||
|
height: 42px;
|
||||||
|
width: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.small {
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.toggled {
|
||||||
|
filter: invert(0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
background-color: var(--color-background-soft);
|
||||||
|
border-radius: 6px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin: 2px;
|
||||||
|
|
||||||
|
transition: .3s background-color;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button:hover {
|
||||||
|
background-color: var(--color-background-softer);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
&.big {
|
||||||
|
height: 38px;
|
||||||
|
width: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.small {
|
||||||
|
height: 18px;
|
||||||
|
width: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
89
frontend/app/components/windows/EditProfileWindow.vue
Normal file
89
frontend/app/components/windows/EditProfileWindow.vue
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
|
||||||
|
|
||||||
|
import Server from '@/services/Server'
|
||||||
|
import { SetMinSize, SetResizable } from '@/services/Windows';
|
||||||
|
import { backendUrl } from '@/services/BackendURL';
|
||||||
|
import { GetUser } from '@/services/User';
|
||||||
|
|
||||||
|
import WindowHandle from './partials/WindowHandle.vue';
|
||||||
|
import BigIconTemplate from './partials/BigIconTemplate.vue';
|
||||||
|
import FixedBottomButtons from './partials/FixedBottomButtons.vue';
|
||||||
|
|
||||||
|
const props = defineProps(['data']);
|
||||||
|
const data = props.data;
|
||||||
|
const userIcon = ref("");
|
||||||
|
|
||||||
|
const handle = ref(null);
|
||||||
|
const isAdmin = ref(false);
|
||||||
|
|
||||||
|
let id = data.id;
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
SetupHandle(id, handle);
|
||||||
|
SetSize(id, {width: 500, height: 480});
|
||||||
|
ResetPosition(id, "center");
|
||||||
|
|
||||||
|
SetResizable(id, true);
|
||||||
|
SetMinSize(id, {width: 350, height: 280});
|
||||||
|
|
||||||
|
isAdmin.value = GetUser().admin;
|
||||||
|
|
||||||
|
Server().get('/user/retrieve-avatar?username=' + data.user.username).then((response) => {
|
||||||
|
if(response.data.image) userIcon.value = backendUrl + "public/" + response.data.image;
|
||||||
|
else userIcon.value = "public/img/def-avatar.jpg";
|
||||||
|
}).catch((err) => console.log("Internal error"));
|
||||||
|
});
|
||||||
|
|
||||||
|
function RemoveUser(){
|
||||||
|
alert("Remove")
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="window-wrapper" :id="'window-wrapper-' + id">
|
||||||
|
<WindowHandle :window="id" ref="handle"></WindowHandle>
|
||||||
|
|
||||||
|
<BigIconTemplate :title="data.user.username" :img="userIcon">
|
||||||
|
<div v-if="props.data.editable || isAdmin">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</BigIconTemplate>
|
||||||
|
|
||||||
|
<FixedBottomButtons v-if="isAdmin" :remove="RemoveUser"></FixedBottomButtons>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.window-wrapper {
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
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>
|
||||||
@@ -9,9 +9,7 @@ const handle = ref(null);
|
|||||||
const props = defineProps(['data']);
|
const props = defineProps(['data']);
|
||||||
const data = props.data;
|
const data = props.data;
|
||||||
|
|
||||||
let id = data.type;
|
let id = data.id;
|
||||||
|
|
||||||
const test = ref(null)
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
SetupHandle(id, handle);
|
SetupHandle(id, handle);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const handle = ref(null);
|
|||||||
const props = defineProps(['data']);
|
const props = defineProps(['data']);
|
||||||
const data = props.data;
|
const data = props.data;
|
||||||
|
|
||||||
let id = data.type;
|
let id = data.id;
|
||||||
|
|
||||||
const username = ref("");
|
const username = ref("");
|
||||||
const password = ref("");
|
const password = ref("");
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ const handle = ref(null);
|
|||||||
const props = defineProps(['data']);
|
const props = defineProps(['data']);
|
||||||
const data = props.data;
|
const data = props.data;
|
||||||
|
|
||||||
let id = data.type;
|
let id = data.id;
|
||||||
|
|
||||||
const test = ref(null)
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
SetupHandle(id, handle);
|
SetupHandle(id, handle);
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ const handle = ref(null);
|
|||||||
const props = defineProps(['data']);
|
const props = defineProps(['data']);
|
||||||
const data = props.data;
|
const data = props.data;
|
||||||
|
|
||||||
let id = data.type;
|
let id = data.id;
|
||||||
|
|
||||||
|
|
||||||
const username = ref("");
|
const username = ref("");
|
||||||
const password = ref("");
|
const password = ref("");
|
||||||
|
|||||||
31
frontend/app/components/windows/partials/BigIconTemplate.vue
Normal file
31
frontend/app/components/windows/partials/BigIconTemplate.vue
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, ref, watch } from 'vue';
|
||||||
|
const props = defineProps(['title', 'img']);
|
||||||
|
|
||||||
|
const imgSrc = ref("");
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
imgSrc.value = props.img;
|
||||||
|
watch(() => props.img, () => {
|
||||||
|
imgSrc.value = props.img;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="document centered">
|
||||||
|
<h1>{{props.title}}</h1>
|
||||||
|
<img :src="imgSrc" class="big-icon">
|
||||||
|
<br>
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.big-icon {
|
||||||
|
height: 80px;
|
||||||
|
width: 80px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
margin:auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<script setup>
|
||||||
|
import IconButton from '~/components/partials/IconButton.vue';
|
||||||
|
|
||||||
|
const props = defineProps(['plus', 'edit', 'view', 'remove']);
|
||||||
|
|
||||||
|
let plus = props.plus;
|
||||||
|
let edit = props.edit;
|
||||||
|
let view = props.view;
|
||||||
|
let remove = props.remove;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="fixed-bottom-buttons">
|
||||||
|
<IconButton v-show="plus" icon="/icons/iconoir/regular/plus.svg" :action="plus"></IconButton>
|
||||||
|
<IconButton v-show="edit" icon="/icons/iconoir/regular/edit-pencil.svg" :action="edit"></IconButton>
|
||||||
|
<IconButton v-show="view" icon="/icons/iconoir/solid/eye.svg" :action="view"></IconButton>
|
||||||
|
<IconButton v-show="remove" icon="/icons/iconoir/solid/trash.svg" :action="remove"></IconButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.fixed-bottom-buttons {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
right: 10px;
|
||||||
|
z-index: 2;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref, watch } from 'vue';
|
import { onMounted, ref, watch } from 'vue';
|
||||||
import { GetWindowWithId, ClearWindow, Windows } from '@/services/Windows';
|
import { GetWindowWithId } from '@/services/Windows';
|
||||||
|
|
||||||
import ArrowLeftIcon from '/icons/iconoir/regular/arrow-left.svg';
|
import ArrowLeftIcon from '/icons/iconoir/regular/arrow-left.svg';
|
||||||
import XMarkIcon from '/icons/iconoir/regular/xmark.svg';
|
import XMarkIcon from '/icons/iconoir/regular/xmark.svg';
|
||||||
|
|||||||
87
frontend/app/services/Tooltip.js
Normal file
87
frontend/app/services/Tooltip.js
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import { ref } from 'vue';
|
||||||
|
import { animate } from 'motion';
|
||||||
|
|
||||||
|
let content = ref("");
|
||||||
|
let margin = 14;
|
||||||
|
|
||||||
|
let cursorX = 0;
|
||||||
|
let cursorY = 0;
|
||||||
|
|
||||||
|
let showed = false;
|
||||||
|
let hided = false;
|
||||||
|
|
||||||
|
function ShowTooltip(){
|
||||||
|
let tooltip = document.getElementById('mouse-tooltip');
|
||||||
|
|
||||||
|
tooltip.style.display = "block";
|
||||||
|
|
||||||
|
if(!showed){
|
||||||
|
animate(tooltip, {
|
||||||
|
opacity: [0, 1],
|
||||||
|
translateY: [20, 0]
|
||||||
|
}, {duration: 0.1, ease: 'ease-out'});
|
||||||
|
showed = true;
|
||||||
|
hided = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function HideTooltip(){
|
||||||
|
let tooltip = document.getElementById('mouse-tooltip');
|
||||||
|
|
||||||
|
|
||||||
|
if(!hided){
|
||||||
|
animate(tooltip, {
|
||||||
|
opacity: [1, 0],
|
||||||
|
translateY: [0, 20]
|
||||||
|
}, {duration: 0.1, ease: 'ease-in'}).finished.then(() => tooltip.style.display = "none")
|
||||||
|
hided = true;
|
||||||
|
showed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function AddTooltip(element, val, data = {}){
|
||||||
|
element._dr_tooltip = {value: val, ...data};
|
||||||
|
}
|
||||||
|
|
||||||
|
function UpdateVisibilityThread(){
|
||||||
|
let tooltip = document.getElementById('mouse-tooltip');
|
||||||
|
let elements = document.elementsFromPoint(cursorX, cursorY);
|
||||||
|
|
||||||
|
let visible = false;
|
||||||
|
for(let i = 0; i < elements.length; i++){
|
||||||
|
let element = elements[i];
|
||||||
|
if(element._dr_tooltip){
|
||||||
|
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";
|
||||||
|
visible = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!visible) HideTooltip();
|
||||||
|
|
||||||
|
setTimeout(UpdateVisibilityThread, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SetupTooltip(){
|
||||||
|
let tooltip = document.getElementById('mouse-tooltip');
|
||||||
|
|
||||||
|
document.addEventListener("mousemove", (event) => {
|
||||||
|
cursorX = event.clientX;
|
||||||
|
cursorY = event.clientY;
|
||||||
|
|
||||||
|
tooltip.style.top = (cursorY + margin) + "px";
|
||||||
|
tooltip.style.left = (cursorX + margin) + "px";
|
||||||
|
});
|
||||||
|
|
||||||
|
UpdateVisibilityThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
let GetContentRef = () => content;
|
||||||
|
|
||||||
|
export {
|
||||||
|
SetupTooltip,
|
||||||
|
GetContentRef,
|
||||||
|
AddTooltip,
|
||||||
|
};
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
|
import { ClearWindowsWithType, GetFirstWindowId } from './Windows'
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Put here all dragonroll windows
|
Put here all dragonroll windows
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const defWindows = {
|
const defWindows = {
|
||||||
login: {
|
login: {
|
||||||
title: 'windows.login',
|
title: 'windows.login',
|
||||||
@@ -20,7 +21,13 @@ const defWindows = {
|
|||||||
example: {
|
example: {
|
||||||
title: 'windows.example',
|
title: 'windows.example',
|
||||||
component: () => import('~/components/windows/ExampleWindow.vue'),
|
component: () => import('~/components/windows/ExampleWindow.vue'),
|
||||||
}
|
},
|
||||||
|
edit_profile: {
|
||||||
|
title: "windows.edit-profile",
|
||||||
|
component: () => import('~/components/windows/EditProfileWindow.vue'),
|
||||||
|
close: () => ClearWindowsWithType(GetFirstWindowId('edit_profile')),
|
||||||
|
movable: true
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { defWindows } from './WindowDefinitions';
|
import { defWindows } from './WindowDefinitions';
|
||||||
|
import { defineAsyncComponent } from 'vue'
|
||||||
|
|
||||||
|
const componentCache = {}
|
||||||
|
|
||||||
|
const getComponent = (type) => {
|
||||||
|
if (!componentCache[type]) {
|
||||||
|
componentCache[type] = defineAsyncComponent(
|
||||||
|
defWindows[type].component
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return componentCache[type]
|
||||||
|
}
|
||||||
|
|
||||||
const windows = ref([]);
|
const windows = ref([]);
|
||||||
|
|
||||||
const getComponent = (type) => defineAsyncComponent(defWindows[type]?.component)
|
|
||||||
|
|
||||||
const reload = ref(0);
|
|
||||||
|
|
||||||
let ReloadRef = () => { return reload };
|
|
||||||
let Windows = () => { return windows };
|
|
||||||
let WindowMap = () => { return windowMap };
|
let WindowMap = () => { return windowMap };
|
||||||
|
|
||||||
let currentIndex = 10;
|
let currentIndex = 10;
|
||||||
@@ -107,8 +113,9 @@ function SetupHandle(id, handle) {
|
|||||||
|
|
||||||
// Should move eventually?
|
// Should move eventually?
|
||||||
window.addEventListener('resize', (event) => {
|
window.addEventListener('resize', (event) => {
|
||||||
if(!win.movable){
|
for(const w of windows.value){
|
||||||
ResetPosition(id, "center");
|
if(w.movable) continue;
|
||||||
|
ResetPosition(w.id, "center");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -182,6 +189,7 @@ function GetPosition(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ResetPosition(id, pos) {
|
function ResetPosition(id, pos) {
|
||||||
|
console.log("The id: ", id)
|
||||||
let win = GetWindowWithId(id);
|
let win = GetWindowWithId(id);
|
||||||
let data = { x: win.x, y: win.y };
|
let data = { x: win.x, y: win.y };
|
||||||
|
|
||||||
@@ -194,42 +202,48 @@ function ResetPosition(id, pos) {
|
|||||||
|
|
||||||
|
|
||||||
function CreateWindow(type, data = {}) {
|
function CreateWindow(type, data = {}) {
|
||||||
|
console.log("Creating window")
|
||||||
|
console.log(windows.value);
|
||||||
|
|
||||||
let finalData = { ...{ type, id: currentId }, ...defWindows[type], ...data }
|
let finalData = { ...{ type, id: currentId }, ...defWindows[type], ...data }
|
||||||
console.log(finalData);
|
currentId++;
|
||||||
|
|
||||||
let contains = false;
|
let contains = false;
|
||||||
for (let i = 0; i < windows.value.length; i++) {
|
for (let i = 0; i < windows.value.length; i++) {
|
||||||
if (windows.value[i].type == finalData.type) {
|
if (windows.value[i].type == finalData.type) {
|
||||||
contains = true;
|
contains = true;
|
||||||
console.log("It contains")
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!contains) {
|
if (!contains) {
|
||||||
windows.value.push(finalData);
|
windows.value.push(finalData);
|
||||||
currentId++;
|
|
||||||
console.log(finalData);
|
console.log(windows.value)
|
||||||
console.log("Pushed ", finalData.type);
|
|
||||||
// reload.value += 1;
|
|
||||||
|
|
||||||
console.log(windows.value);
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
SetOnTop(finalData.type);
|
SetOnTop(finalData.id);
|
||||||
if (finalData.create) finalData.create();
|
if (finalData.create) finalData.create();
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function CreateChildWindow(parentId, type, data = {}) {
|
function CreateChildWindow(parentId, type, data = {}) {
|
||||||
|
console.log("Creating child window")
|
||||||
|
console.log(parentId, type, data);
|
||||||
let finalData = { ...{ type }, ...defWindows[type], ...data }
|
let finalData = { ...{ type }, ...defWindows[type], ...data }
|
||||||
|
|
||||||
let parent = GetWindowWithId(parentId);
|
let parent = GetWindowWithId(parentId);
|
||||||
|
console.log(parent);
|
||||||
if (parent.children) parent.children.push(finalData.type);
|
if (parent.children) parent.children.push(finalData.type);
|
||||||
else parent.children = [finalData.type];
|
else parent.children = [finalData.type];
|
||||||
CreateWindow(type, data);
|
CreateWindow(type, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function GetFirstWindowId(type) {
|
||||||
|
for (let i = 0; i < windows.value.length; i++) {
|
||||||
|
if (windows.value[i].type == type) return windows.value[i].id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function ClearAll() {
|
function ClearAll() {
|
||||||
Object.keys(windows).forEach((key) => {
|
Object.keys(windows).forEach((key) => {
|
||||||
windows.value = [];
|
windows.value = [];
|
||||||
@@ -243,21 +257,25 @@ function ClearWindows(data) {
|
|||||||
// reload.value += 1;
|
// reload.value += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ClearWindowsWithType(type) {
|
||||||
|
const index = windows.value.findIndex(w => w.type === type);
|
||||||
|
if (index !== -1) ClearWindow(windows.value[index].id)
|
||||||
|
// reload.value += 1;
|
||||||
|
}
|
||||||
|
|
||||||
function ClearWindow(id) {
|
function ClearWindow(id) {
|
||||||
let win = GetWindowWithId(id);
|
let win = GetWindowWithId(id);
|
||||||
console.log(win);
|
console.log(win);
|
||||||
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].id);
|
||||||
windows.value = windows.value.filter((e) => { return e.type !== id });
|
const index = windows.value.findIndex(w => w.type === id)
|
||||||
|
if (index !== -1) windows.value.splice(index, 1)
|
||||||
// reload.value += 1;
|
// reload.value += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function GetWindowWithId(id) {
|
function GetWindowWithId(id) {
|
||||||
for (let i = 0; i < windows.value.length; i++) {
|
const index = windows.value.findIndex(w => w.id === id);
|
||||||
if (windows.value[i].type == id) {
|
if (index !== -1) return windows.value[index];
|
||||||
return windows.value[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function CallWindow(id, callableName, arg) {
|
function CallWindow(id, callableName, arg) {
|
||||||
@@ -283,6 +301,7 @@ function SetOnTop(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
windows,
|
||||||
SetupHandle,
|
SetupHandle,
|
||||||
SetSize,
|
SetSize,
|
||||||
SetResizable,
|
SetResizable,
|
||||||
@@ -291,17 +310,17 @@ export {
|
|||||||
SetPosition,
|
SetPosition,
|
||||||
SetMovable,
|
SetMovable,
|
||||||
ResetPosition,
|
ResetPosition,
|
||||||
Windows,
|
|
||||||
WindowMap,
|
WindowMap,
|
||||||
ReloadRef,
|
|
||||||
ClearWindows,
|
ClearWindows,
|
||||||
CreateWindow,
|
CreateWindow,
|
||||||
CreateChildWindow,
|
CreateChildWindow,
|
||||||
|
GetFirstWindowId,
|
||||||
CallWindow,
|
CallWindow,
|
||||||
GetWindowWithId,
|
GetWindowWithId,
|
||||||
SaveWindowPos,
|
SaveWindowPos,
|
||||||
GetPosition,
|
GetPosition,
|
||||||
ClearWindow,
|
ClearWindow,
|
||||||
|
ClearWindowsWithType,
|
||||||
ClearAll,
|
ClearAll,
|
||||||
getComponent
|
getComponent
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,8 @@
|
|||||||
"login": "Login",
|
"login": "Login",
|
||||||
"register": "Register",
|
"register": "Register",
|
||||||
"main-menu": "Dragonroll",
|
"main-menu": "Dragonroll",
|
||||||
"example": "Example Window"
|
"example": "Example Window",
|
||||||
|
"edit-profile": "Edit Profile"
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"username": "Username or email",
|
"username": "Username or email",
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ export default defineNuxtConfig({
|
|||||||
'@vue/devtools-core',
|
'@vue/devtools-core',
|
||||||
'@vue/devtools-kit',
|
'@vue/devtools-kit',
|
||||||
'axios',
|
'axios',
|
||||||
'mitt'
|
'mitt',
|
||||||
|
'motion'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
72
frontend/package-lock.json
generated
72
frontend/package-lock.json
generated
@@ -10,6 +10,7 @@
|
|||||||
"@nuxtjs/i18n": "^10.3.0",
|
"@nuxtjs/i18n": "^10.3.0",
|
||||||
"axios": "^1.15.2",
|
"axios": "^1.15.2",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
|
"motion": "^12.38.0",
|
||||||
"nuxt": "^4.4.2",
|
"nuxt": "^4.4.2",
|
||||||
"pixelarticons": "^2.1.0",
|
"pixelarticons": "^2.1.0",
|
||||||
"sass": "^1.99.0",
|
"sass": "^1.99.0",
|
||||||
@@ -7784,6 +7785,33 @@
|
|||||||
"url": "https://github.com/sponsors/rawify"
|
"url": "https://github.com/sponsors/rawify"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/framer-motion": {
|
||||||
|
"version": "12.38.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.38.0.tgz",
|
||||||
|
"integrity": "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"motion-dom": "^12.38.0",
|
||||||
|
"motion-utils": "^12.36.0",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@emotion/is-prop-valid": "*",
|
||||||
|
"react": "^18.0.0 || ^19.0.0",
|
||||||
|
"react-dom": "^18.0.0 || ^19.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@emotion/is-prop-valid": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fresh": {
|
"node_modules/fresh": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
|
||||||
@@ -9042,6 +9070,47 @@
|
|||||||
"integrity": "sha512-aF7yRQr/Q0O2/4pIXm6PZ5G+jAd7QS4Yu8m+WEeEHGnbo+7mE36CbLSDQiXYV8bVL3NfmdeqPJct0tUlnjVSnA==",
|
"integrity": "sha512-aF7yRQr/Q0O2/4pIXm6PZ5G+jAd7QS4Yu8m+WEeEHGnbo+7mE36CbLSDQiXYV8bVL3NfmdeqPJct0tUlnjVSnA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/motion": {
|
||||||
|
"version": "12.38.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/motion/-/motion-12.38.0.tgz",
|
||||||
|
"integrity": "sha512-uYfXzeHlgThchzwz5Te47dlv5JOUC7OB4rjJ/7XTUgtBZD8CchMN8qEJ4ZVsUmTyYA44zjV0fBwsiktRuFnn+w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"framer-motion": "^12.38.0",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@emotion/is-prop-valid": "*",
|
||||||
|
"react": "^18.0.0 || ^19.0.0",
|
||||||
|
"react-dom": "^18.0.0 || ^19.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@emotion/is-prop-valid": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/motion-dom": {
|
||||||
|
"version": "12.38.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.38.0.tgz",
|
||||||
|
"integrity": "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"motion-utils": "^12.36.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/motion-utils": {
|
||||||
|
"version": "12.36.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.36.0.tgz",
|
||||||
|
"integrity": "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/mrmime": {
|
"node_modules/mrmime": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
|
||||||
@@ -11410,8 +11479,7 @@
|
|||||||
"version": "2.8.1",
|
"version": "2.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
"license": "0BSD",
|
"license": "0BSD"
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"node_modules/type-check": {
|
"node_modules/type-check": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"@nuxtjs/i18n": "^10.3.0",
|
"@nuxtjs/i18n": "^10.3.0",
|
||||||
"axios": "^1.15.2",
|
"axios": "^1.15.2",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
|
"motion": "^12.38.0",
|
||||||
"nuxt": "^4.4.2",
|
"nuxt": "^4.4.2",
|
||||||
"pixelarticons": "^2.1.0",
|
"pixelarticons": "^2.1.0",
|
||||||
"sass": "^1.99.0",
|
"sass": "^1.99.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user