backup
This commit is contained in:
@@ -1,9 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import ContentManager from './components/managers/ContentManager.vue';
|
||||
import ToastManager from './components/managers/ToastManager.vue';
|
||||
import WindowManager from './components/managers/WindowManager.vue';
|
||||
import Content from './components/viewer/content/Content.vue';
|
||||
import StatusBar from './components/viewer/statusbar/StatusBar.vue';
|
||||
import TopBar from './components/viewer/TopBar.vue';
|
||||
|
||||
|
||||
import { CreateWindow } from '@/services/Windows'
|
||||
|
||||
@@ -14,19 +12,17 @@ async function start(){
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
setupTheme();
|
||||
setTheme('dark');
|
||||
start();
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="viewer">
|
||||
<ToastManager></ToastManager>
|
||||
<WindowManager></WindowManager>
|
||||
|
||||
|
||||
<TopBar></TopBar>
|
||||
<Content></Content>
|
||||
<StatusBar></StatusBar>
|
||||
|
||||
<ContentManager></ContentManager>
|
||||
<!-- Managers -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -3,27 +3,53 @@
|
||||
$themes: (
|
||||
dark: (
|
||||
background: #141414,
|
||||
background-light: #202020,
|
||||
background-line: #202324,
|
||||
background-fore: #10141f,
|
||||
|
||||
window-handle-background: #191919,
|
||||
window-background: #141414,
|
||||
window-border: #202324,
|
||||
window-shadow: #00000077,
|
||||
|
||||
button-background: #20202077,
|
||||
button-hover: #202020aa,
|
||||
button-active: #202020cc,
|
||||
|
||||
hover: #21262d,
|
||||
selected: #4a4a4b,
|
||||
border-color: #819796,
|
||||
border: #202324,
|
||||
text: #ebede9,
|
||||
container-shadow: #151d28,
|
||||
sticky-header-bg: #20202077
|
||||
sticky-header-bg: #20202077,
|
||||
|
||||
icon-invert: 100%
|
||||
),
|
||||
light: (
|
||||
background: #ffffff,
|
||||
background-light: #f9f9f9,
|
||||
background-line: #f0f0f0,
|
||||
background-fore: #ffffff,
|
||||
|
||||
window-handle-background: #f0f0f0,
|
||||
window-background: #ffffff,
|
||||
window-border: #e0e0e0,
|
||||
window-shadow: #d4d4d4,
|
||||
|
||||
button-background: #f0f0f0,
|
||||
button-hover: #e9e9e9,
|
||||
button-active: #d4d4d4,
|
||||
|
||||
border-color: #e0e0e0,
|
||||
border: #f0f0f0,
|
||||
hover: #e9e9e9,
|
||||
selected: #d4d4d4,
|
||||
text: #1e1e1e,
|
||||
container-shadow: #5f6774,
|
||||
sticky-header-bg: #fff
|
||||
sticky-header-bg: #fff,
|
||||
|
||||
icon-invert: 0%
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -1,25 +1,31 @@
|
||||
body {
|
||||
color: var(--text-color);
|
||||
color: var(--color-text);
|
||||
font-family: "BookInsanityRemake", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--background-color);
|
||||
background-color: var(--color-background);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
* {
|
||||
color: var(--text-color);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--link-color);
|
||||
color: var(--color-link);
|
||||
}
|
||||
|
||||
.icon {
|
||||
height: 12px;
|
||||
filter: invert(var(--color-icon-invert));
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: BookInsanityRemake;
|
||||
}
|
||||
|
||||
|
||||
*::-webkit-scrollbar
|
||||
{
|
||||
width: 6px;
|
||||
@@ -39,6 +45,141 @@ a {
|
||||
color: var(--error-link);
|
||||
}
|
||||
|
||||
.buttons-row {
|
||||
width: 100%;
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.button-row {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
padding-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: left;
|
||||
flex-direction: column;
|
||||
justify-content: left;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
height: 1px;
|
||||
width: 30%;
|
||||
overflow: visible;
|
||||
position: relative;
|
||||
margin: 16px auto 16px auto;
|
||||
background-color: var(--separator);
|
||||
}
|
||||
|
||||
hr:before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: var(--separator);
|
||||
position: absolute;
|
||||
transform: rotate(45deg);
|
||||
top: -2.5px;
|
||||
left: 50%;
|
||||
margin: -1px 0 0 -1px;
|
||||
}
|
||||
|
||||
input[type=text], input[type=password], input[type=email] {
|
||||
background-color: var(--color-background-softer);
|
||||
border: none;
|
||||
padding: 8px;
|
||||
border-radius: 6px;
|
||||
color: var(--color-text);
|
||||
transition: 300ms background-color;
|
||||
border: solid 1px var(--color-border);
|
||||
}
|
||||
|
||||
|
||||
textarea {
|
||||
background-color: var(--color-background-softer);
|
||||
padding: 12px;
|
||||
color: var(--color-text);
|
||||
border: none;
|
||||
}
|
||||
|
||||
input[type=text]:focus, input[type=password]:focus, input[type=email]:focus {
|
||||
outline: none;
|
||||
background-color: var(--color-background-softest);
|
||||
}
|
||||
|
||||
textarea:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
|
||||
padding: 14px;
|
||||
font-size: 15px;
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
|
||||
border: solid 1px var(--color-border);
|
||||
-webkit-box-shadow: 0px 0px 10px -2px rgba(0,0,0,0.25);
|
||||
-moz-box-shadow: 0px 0px 10px -2px rgba(0,0,0,0.25);
|
||||
box-shadow: 0px 0px 10px -2px rgba(0,0,0,0.25);
|
||||
|
||||
transition: 300ms background-color;
|
||||
background-color: var(--color-button-background);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: var(--color-button-hover);
|
||||
}
|
||||
|
||||
button:active {
|
||||
background-color: var(--color-button-active);
|
||||
}
|
||||
|
||||
.render-image {
|
||||
max-width: 600px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.confirm-form-button {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.centered {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.window-wrapper {
|
||||
display: flex;
|
||||
@@ -51,4 +192,166 @@ a {
|
||||
-webkit-box-shadow: 0px 0px 10px -2px var(--shadow-color);
|
||||
-moz-box-shadow: 0px 0px 10px -2px var(--shadow-color);
|
||||
box-shadow: 0px 0px 10px -2px var(--shadow-color);
|
||||
}
|
||||
}
|
||||
|
||||
.document {
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.document.centered {
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.document.item {
|
||||
text-align: center;
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.document.item img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
|
||||
.document h1 {
|
||||
font-weight: normal;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
.document b {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.text-icon {
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
margin-bottom: -4px;
|
||||
}
|
||||
|
||||
.invert {
|
||||
filter: invert(0.9);
|
||||
}
|
||||
|
||||
.main-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
|
||||
span.important {
|
||||
font-family: NodestoCapsCondensed;
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
span.common {
|
||||
color: var(--color-common);
|
||||
}
|
||||
span.uncommon {
|
||||
color: var(--color-uncommon);
|
||||
}
|
||||
span.rare {
|
||||
color: var(--color-rare);
|
||||
}
|
||||
span.very-rare {
|
||||
color: var(--color-very-rare);
|
||||
}
|
||||
span.legendary {
|
||||
color: var(--color-legendary);
|
||||
}
|
||||
span.artifact {
|
||||
color: var(--color-artifact);
|
||||
}
|
||||
|
||||
.form-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-element {
|
||||
padding: 10px 0 10px 0;
|
||||
margin: 0 10px 0 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px dashed var(--color-border);
|
||||
}
|
||||
|
||||
.form-element label {
|
||||
flex-grow: 0;
|
||||
margin-right: 6px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.form-element.centered {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
|
||||
.subsection.border:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.subsection.border {
|
||||
border-left: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.subsection {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: left;
|
||||
justify-content: left;
|
||||
}
|
||||
|
||||
.subsection.left {
|
||||
align-items: left;
|
||||
justify-content: left;
|
||||
|
||||
}
|
||||
|
||||
.subsection.right {
|
||||
align-items: right;
|
||||
justify-content: right;
|
||||
|
||||
}
|
||||
|
||||
.subsection.center {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.window-enter-active,
|
||||
.window-leave-active {
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
.window-enter-from,
|
||||
.window-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(15px);
|
||||
}
|
||||
|
||||
.window-wrapper {
|
||||
background-color: var(--window-background);
|
||||
|
||||
/* backdrop-filter: blur(10px); */
|
||||
position: fixed;
|
||||
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
18
frontend/app/components/managers/ContentManager.vue
Normal file
18
frontend/app/components/managers/ContentManager.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<script setup>
|
||||
import Content from '../viewer/content/Content.vue';
|
||||
import StatusBar from '../viewer/statusbar/StatusBar.vue';
|
||||
import TopBar from '../viewer/TopBar.vue';
|
||||
|
||||
import { ShowContent } from '../../services/Content.js';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-show="ShowContent">
|
||||
<TopBar></TopBar>
|
||||
<Content></Content>
|
||||
<StatusBar></StatusBar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
120
frontend/app/components/managers/ToastManager.vue
Normal file
120
frontend/app/components/managers/ToastManager.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { emitter } from '@/services/Emitter';
|
||||
|
||||
const text = ref("");
|
||||
const toast = ref(null);
|
||||
|
||||
let toastQueue = [];
|
||||
let displayingToast = false;
|
||||
|
||||
function DisplayToast(){
|
||||
if(displayingToast) return;
|
||||
if(toastQueue.length == 0) return;
|
||||
|
||||
displayingToast = true;
|
||||
let data = toastQueue.pop();
|
||||
|
||||
text.value = data.text;
|
||||
|
||||
toast.value.classList.add(data.color);
|
||||
toast.value.classList.add("show");
|
||||
setTimeout(() => {
|
||||
toast.value.classList.add("sliding");
|
||||
setTimeout(() => {
|
||||
toast.value.style = {};
|
||||
toast.value.classList.remove("show");
|
||||
toast.value.classList.remove("sliding");
|
||||
toast.value.classList.remove(data.color);
|
||||
displayingToast = false;
|
||||
DisplayToast();
|
||||
}, 400);
|
||||
}, data.duration);
|
||||
}
|
||||
|
||||
emitter.on('toast', data => {
|
||||
toastQueue.push(data);
|
||||
DisplayToast();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<div class="toast" ref="toast">
|
||||
<div class="toast-container">{{ text }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<style scoped lang="scss">
|
||||
.toast-container {
|
||||
height: 100%;
|
||||
background-color: var(--color-background-soft);
|
||||
padding: 10px;
|
||||
margin-left: 5px;
|
||||
border-top-right-radius: 6px;
|
||||
border-bottom-right-radius: 6px;
|
||||
transform: translate(2px,0px)
|
||||
}
|
||||
|
||||
.toast {
|
||||
position: absolute;
|
||||
display: none;
|
||||
|
||||
top: 10px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
|
||||
min-width: 400px;
|
||||
min-height: 40px;
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
|
||||
z-index: 9999999;
|
||||
|
||||
|
||||
animation: slide-in 0.4s ease-in-out;
|
||||
@keyframes slide-in {
|
||||
0% {
|
||||
transform: translate(-50%,-50px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.sliding {
|
||||
@keyframes slide-out {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%,-50px);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
animation: slide-out .4s ease-in-out forwards;
|
||||
}
|
||||
|
||||
&.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Colors!!!! */
|
||||
|
||||
&.red {
|
||||
background-color: rgb(243, 68, 68);
|
||||
}
|
||||
|
||||
&.green {
|
||||
background-color: rgb(92, 199, 92);
|
||||
}
|
||||
|
||||
&.aqua {
|
||||
background-color: rgb(113, 250, 250);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -29,7 +29,7 @@ const windows = Windows();
|
||||
}
|
||||
|
||||
.window-wrapper {
|
||||
background-color: var(--window-background);
|
||||
background-color: var(--color-window-background);
|
||||
|
||||
/* backdrop-filter: blur(10px); */
|
||||
position: fixed;
|
||||
@@ -37,6 +37,15 @@ const windows = Windows();
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
align-items: center;
|
||||
|
||||
border: solid 1px var(--color-window-border);
|
||||
|
||||
/* opacity: 0; */
|
||||
user-select: none;
|
||||
-webkit-box-shadow: 0px 0px 10px -2px var(--color-window-shadow);
|
||||
-moz-box-shadow: 0px 0px 10px -2px var(--color-window-shadow);
|
||||
box-shadow: 0px 0px 10px -2px var(--color-window-shadow);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -21,7 +21,7 @@ import TopSearchBar from './topbar/TopSearchBar.vue';
|
||||
flex-shrink: 0;
|
||||
min-height: 40px;
|
||||
width: 100%;
|
||||
background-color: var(--top-bar-background-color);
|
||||
background-color: var(--color-background-light);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import Note from './Note.vue';
|
||||
|
||||
const emitter = useEmitter();
|
||||
import { emitter } from '~/services/Emitter';
|
||||
|
||||
let noteData = ref([]);
|
||||
|
||||
@@ -61,6 +60,7 @@ emitter.on("delete-note", (key) => {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
background-color: var(--color-background);
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup>
|
||||
import { ref,onMounted } from 'vue';
|
||||
const emitter = useEmitter();
|
||||
import { emitter } from '~/services/Emitter';
|
||||
|
||||
|
||||
const statusIcon = ref(null);
|
||||
const statusMessage = ref(null);
|
||||
|
||||
@@ -22,7 +22,7 @@ import FetchStatus from './FetchStatus.vue';
|
||||
min-height: 24px;
|
||||
max-height: 24px;
|
||||
width: 100%;
|
||||
background-color: var(--top-bar-background-color);
|
||||
background-color: var(--color-background-light);
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
42
frontend/app/components/windows/ExampleWindow.vue
Normal file
42
frontend/app/components/windows/ExampleWindow.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
|
||||
|
||||
import WindowHandle from './partials/WindowHandle.vue';
|
||||
|
||||
const handle = ref(null);
|
||||
|
||||
const props = defineProps(['data']);
|
||||
const data = props.data;
|
||||
|
||||
let id = data.id;
|
||||
|
||||
const test = ref(null)
|
||||
|
||||
onMounted(() => {
|
||||
SetupHandle(id, handle);
|
||||
SetSize(id, {width: 500, height: 380});
|
||||
ResetPosition(id, "center");
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<div class="window-wrapper" :id="'window-wrapper-' + id">
|
||||
<WindowHandle :window="id" ref="handle"></WindowHandle>
|
||||
|
||||
<!-- Body -->
|
||||
<div ref="test"></div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.window-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
|
||||
import {
|
||||
SetupHandle,
|
||||
SetSize,
|
||||
ResetPosition,
|
||||
SetResizable,
|
||||
SetMovable,
|
||||
ClearWindow,
|
||||
CreateWindow,
|
||||
} from '@/services/Windows';
|
||||
|
||||
import WindowHandle from './partials/WindowHandle.vue';
|
||||
import { DisplayToast } from '~/services/Toaster';
|
||||
import Server from '~/services/Server';
|
||||
import { SetUser } from '~/services/User';
|
||||
|
||||
const handle = ref(null);
|
||||
|
||||
@@ -11,13 +22,44 @@ const data = props.data;
|
||||
|
||||
let id = data.id;
|
||||
|
||||
const test = ref(null)
|
||||
const username = ref("");
|
||||
const password = ref("");
|
||||
|
||||
onMounted(() => {
|
||||
SetupHandle(id, handle);
|
||||
SetSize(id, {width: 500, height: 380});
|
||||
SetSize(id, {width: 450, height: 480});
|
||||
SetMovable(id, false);
|
||||
SetResizable(id, false);
|
||||
ResetPosition(id, "center");
|
||||
});
|
||||
|
||||
function login() {
|
||||
Server().post('/user/login', { username: username.value, password: password.value }).then((response) => {
|
||||
const data = response.data;
|
||||
console.log(data);
|
||||
|
||||
if(data.status == "error"){
|
||||
DisplayToast('red', "Wrong username or password", 3000)
|
||||
} else {
|
||||
SetUser(data.token);
|
||||
|
||||
ShowMainMenu();
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
if(error.response.status == 429){
|
||||
// errorMessage.value = error.response.data;
|
||||
} else {
|
||||
// errorMessage.value = "Hi ha hagut un error intern, torna'ho a provar més tard";
|
||||
console.log(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function toRegister(){
|
||||
CreateWindow('register');
|
||||
ClearWindow('login');
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -26,8 +68,30 @@ onMounted(() => {
|
||||
<WindowHandle :window="id" ref="handle"></WindowHandle>
|
||||
|
||||
<!-- Body -->
|
||||
<div ref="test">
|
||||
<p>Hola</p>
|
||||
<div class="vert-expand">
|
||||
<picture align="center">
|
||||
<source media="(prefers-color-scheme: dark)" srcset="/img/logo-splash.png">
|
||||
<source media="(prefers-color-scheme: light)" srcset="/img/logo-splash-light.png">
|
||||
<img alt="Dragonroll logo" src="/img/logo-splash.png" class="splash-image" draggable="false">
|
||||
</picture>
|
||||
|
||||
<form v-on:submit.prevent="login">
|
||||
<div class="form-field">
|
||||
<label for="username">Username</label>
|
||||
<input id="username-field" type="text" placeholder="Enter your username here..." name="username" v-model="username" autocomplete="off" >
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="password">Password</label>
|
||||
<input id="password-field" type="password" placeholder="Enter your password..." name="password" v-model="password" autocomplete="off" >
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<button class="btn-primary sound-click">Log in</button>
|
||||
</div>
|
||||
<div class="form-field center">
|
||||
<p>You don't have an account? <a href="#" @click.prevent="toRegister">Register</a></p>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -35,10 +99,41 @@ onMounted(() => {
|
||||
|
||||
|
||||
<style scoped>
|
||||
p {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.vert-expand {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.window-wrapper {
|
||||
user-select: none;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.splash-image {
|
||||
width: 450px;
|
||||
}
|
||||
|
||||
form {
|
||||
margin-left: 30px;
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
label {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
42
frontend/app/components/windows/RegisterWindow.vue
Normal file
42
frontend/app/components/windows/RegisterWindow.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { SetupHandle, SetSize, ResetPosition } from '@/services/Windows';
|
||||
|
||||
import WindowHandle from './partials/WindowHandle.vue';
|
||||
|
||||
const handle = ref(null);
|
||||
|
||||
const props = defineProps(['data']);
|
||||
const data = props.data;
|
||||
|
||||
let id = data.id;
|
||||
|
||||
const test = ref(null)
|
||||
|
||||
onMounted(() => {
|
||||
SetupHandle(id, handle);
|
||||
SetSize(id, {width: 500, height: 380});
|
||||
ResetPosition(id, "center");
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<div class="window-wrapper" :id="'window-wrapper-' + id">
|
||||
<WindowHandle :window="id" ref="handle"></WindowHandle>
|
||||
|
||||
<!-- Body -->
|
||||
<div ref="test"></div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.window-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ defineExpose({
|
||||
|
||||
display: flex;
|
||||
|
||||
background-color: var(--color-handler);
|
||||
background-color: var(--color-window-handle-background);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
47
frontend/app/composables/useTheme.ts
Normal file
47
frontend/app/composables/useTheme.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { ref, onMounted, watch } from 'vue'
|
||||
|
||||
type Theme = 'light' | 'dark'
|
||||
type Accent = 'katlum'
|
||||
|
||||
const theme = ref<Theme>('light')
|
||||
const accent = ref<Accent>('katlum')
|
||||
|
||||
const applyTheme = () => {
|
||||
document.documentElement.setAttribute('data-theme', theme.value)
|
||||
document.documentElement.setAttribute('data-accent', accent.value)
|
||||
}
|
||||
|
||||
const setTheme = (value: Theme) => {
|
||||
theme.value = value
|
||||
localStorage.setItem('theme', value)
|
||||
applyTheme();
|
||||
}
|
||||
|
||||
const setAccent = (value: Accent) => {
|
||||
accent.value = value
|
||||
localStorage.setItem('accent', value)
|
||||
applyTheme();
|
||||
}
|
||||
|
||||
const setupTheme = () => {
|
||||
const savedTheme = localStorage.getItem('theme') as Theme | null
|
||||
const savedAccent = localStorage.getItem('accent') as Accent | null
|
||||
|
||||
const media = window.matchMedia('(prefers-color-scheme: dark)')
|
||||
|
||||
theme.value = savedTheme || (media.matches ? 'dark' : 'light')
|
||||
accent.value = savedAccent || 'katlum'
|
||||
|
||||
applyTheme()
|
||||
|
||||
media.addEventListener('change', (e) => {
|
||||
if (!localStorage.getItem('theme')) {
|
||||
theme.value = e.matches ? 'dark' : 'light'
|
||||
applyTheme()
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
watch([theme, accent], applyTheme)
|
||||
|
||||
export { theme, accent, setTheme, setAccent, setupTheme}
|
||||
@@ -1,11 +0,0 @@
|
||||
import mitt from 'mitt'
|
||||
|
||||
export default defineNuxtPlugin(() => {
|
||||
const emitter = mitt()
|
||||
|
||||
return {
|
||||
provide: {
|
||||
emitter
|
||||
}
|
||||
}
|
||||
})
|
||||
11
frontend/app/services/BackendURL.js
Normal file
11
frontend/app/services/BackendURL.js
Normal file
@@ -0,0 +1,11 @@
|
||||
var backendUrl = ''
|
||||
if (import.meta.env.PROD) {
|
||||
backendUrl = 'https://api.aranroig.com/';
|
||||
} else {
|
||||
backendUrl = 'http://localhost:5000/'
|
||||
}
|
||||
|
||||
|
||||
export {
|
||||
backendUrl
|
||||
};
|
||||
12
frontend/app/services/Content.js
Normal file
12
frontend/app/services/Content.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { ref } from 'vue';
|
||||
|
||||
const ShowContent = ref(false);
|
||||
|
||||
function SetShowContent(value) {
|
||||
ShowContent.value = value;
|
||||
}
|
||||
|
||||
export {
|
||||
ShowContent,
|
||||
SetShowContent
|
||||
}
|
||||
3
frontend/app/services/Emitter.js
Normal file
3
frontend/app/services/Emitter.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import mitt from 'mitt'
|
||||
|
||||
export const emitter = mitt();
|
||||
21
frontend/app/services/Server.js
Normal file
21
frontend/app/services/Server.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import axios from 'axios';
|
||||
|
||||
import { backendUrl } from './BackendURL';
|
||||
|
||||
const server = axios.create({
|
||||
baseURL: backendUrl,
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
}
|
||||
});
|
||||
|
||||
// Attach token dynamically on each request via interceptor
|
||||
server.interceptors.request.use((config) => {
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
});
|
||||
|
||||
export default () => server;
|
||||
9
frontend/app/services/Toaster.js
Normal file
9
frontend/app/services/Toaster.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { emitter } from './Emitter';
|
||||
|
||||
function DisplayToast(color, text, duration = 1000){
|
||||
emitter.emit("toast", {color, text, duration});
|
||||
}
|
||||
|
||||
export {
|
||||
DisplayToast,
|
||||
}
|
||||
80
frontend/app/services/User.js
Normal file
80
frontend/app/services/User.js
Normal file
@@ -0,0 +1,80 @@
|
||||
import { ref } from 'vue';
|
||||
import Server from './Server';
|
||||
|
||||
const UserStatus = ref(0);
|
||||
|
||||
function parseJwt(token) {
|
||||
return JSON.parse(atob(token.split('.')[1]));
|
||||
}
|
||||
|
||||
function SetUser(token){
|
||||
localStorage.setItem('token', token);
|
||||
UserStatus.value = 1;
|
||||
}
|
||||
|
||||
async function HasAdmin(){
|
||||
let response = await Server().get('/user/has-admin');
|
||||
return response.data.status != "init";
|
||||
}
|
||||
|
||||
async function SetUserSetting(key, value){
|
||||
let user = GetUser();
|
||||
if(!user.settings) user.settings = {};
|
||||
user.settings[key] = value;
|
||||
const response = await Server().post('/user/update-settings', { settings: user.settings });
|
||||
return response.data.settings;
|
||||
}
|
||||
|
||||
async function GetUserSetting(key){
|
||||
const response = await Server().get('/user/get-settings');
|
||||
if (response.data.settings)
|
||||
return response.data.settings[key];
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function GetUser(){
|
||||
const token = localStorage.getItem('token');
|
||||
|
||||
if(token){
|
||||
const data = parseJwt(token);
|
||||
|
||||
// Check if token is expired
|
||||
const now = Date.now() / 1000;
|
||||
if(now > data.exp){
|
||||
LogoutUser();
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function IsAdmin(){
|
||||
const user = GetUser();
|
||||
if(user){
|
||||
return user.admin;
|
||||
}
|
||||
}
|
||||
|
||||
function LoadUser(){
|
||||
const token = localStorage.getItem('token');
|
||||
if(token) UserStatus.value = 1;
|
||||
}
|
||||
|
||||
function LogoutUser(){
|
||||
localStorage.removeItem("token");
|
||||
UserStatus.value = 0;
|
||||
}
|
||||
|
||||
export {
|
||||
UserStatus,
|
||||
GetUser,
|
||||
SetUser,
|
||||
LoadUser,
|
||||
IsAdmin,
|
||||
LogoutUser,
|
||||
HasAdmin,
|
||||
GetUserSetting,
|
||||
SetUserSetting
|
||||
}
|
||||
@@ -3,22 +3,29 @@ import { ref } from 'vue'
|
||||
const windows = ref([]);
|
||||
|
||||
import LoginWindow from '~/components/windows/LoginWindow.vue';
|
||||
import RegisterWindow from '~/components/windows/RegisterWindow.vue';
|
||||
import ExampleWindow from '~/components/windows/ExampleWindow.vue';
|
||||
|
||||
let windowMap = {
|
||||
login: LoginWindow
|
||||
login: LoginWindow,
|
||||
register: RegisterWindow,
|
||||
example: ExampleWindow
|
||||
};
|
||||
|
||||
async function InjectWindow(window_type, plugin, window_component) {
|
||||
let systemWidows = {};
|
||||
systemWidows[window_type] = (await import(`../../plugins/${plugin}/views/${window_component}.vue`)).default;
|
||||
windowMap = { ...windowMap, ...systemWidows };
|
||||
}
|
||||
|
||||
// Presets
|
||||
const defValues = {
|
||||
'example': {
|
||||
id: "example",
|
||||
title: "Example",
|
||||
close: () => ClearWindow('example')
|
||||
},
|
||||
'login': {
|
||||
id: 'login',
|
||||
title: 'Login',
|
||||
},
|
||||
'register': {
|
||||
id: 'register',
|
||||
title: 'Register'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +66,9 @@ function SetupHandle(id, handle) {
|
||||
SetOnTop(id);
|
||||
});
|
||||
|
||||
// Move window listeners
|
||||
handler.addEventListener("mousedown", (event) => {
|
||||
if(win.noMove) return;
|
||||
draggingWindow = true;
|
||||
|
||||
let windowRect = currentWindow.getBoundingClientRect();
|
||||
@@ -67,8 +76,8 @@ function SetupHandle(id, handle) {
|
||||
offsetY = windowRect.top - event.clientY;
|
||||
})
|
||||
|
||||
// Move window listeners
|
||||
document.addEventListener("mousemove", (event) => {
|
||||
if(win.noMove) return;
|
||||
if (!draggingWindow) return;
|
||||
|
||||
if (event.clientX + offsetX < -currentWindow.getBoundingClientRect().width + 20) currentWindow.style.left = (-currentWindow.getBoundingClientRect().width + 20) + "px";
|
||||
@@ -81,6 +90,7 @@ function SetupHandle(id, handle) {
|
||||
})
|
||||
|
||||
document.addEventListener("mouseup", (event) => {
|
||||
if(win.noMove) return;
|
||||
draggingWindow = false;
|
||||
// ummm suposo que no pots tancar mentres mous?
|
||||
SaveWindowPos({ id, x: parseInt(currentWindow.style.left, 10), y: parseInt(currentWindow.style.top, 10) });
|
||||
@@ -126,6 +136,11 @@ function SetResizable(id, resizable) {
|
||||
win.resizable = resizable;
|
||||
}
|
||||
|
||||
function SetMovable(id, movable) {
|
||||
let win = GetWindowWithId(id);
|
||||
win.noMove = !movable;
|
||||
}
|
||||
|
||||
function SetSize(id, size) {
|
||||
let currentWindowId = "window-wrapper-" + id;
|
||||
let currentWindow = document.getElementById(currentWindowId);
|
||||
@@ -284,10 +299,10 @@ export {
|
||||
SetMaxSize,
|
||||
SetMinSize,
|
||||
SetPosition,
|
||||
SetMovable,
|
||||
ResetPosition,
|
||||
Windows,
|
||||
WindowMap,
|
||||
InjectWindow,
|
||||
ReloadRef,
|
||||
ClearWindows,
|
||||
CreateWindow,
|
||||
|
||||
@@ -4,7 +4,8 @@ export default defineNuxtConfig({
|
||||
optimizeDeps: {
|
||||
include: [
|
||||
'@vue/devtools-core',
|
||||
'@vue/devtools-kit'
|
||||
'@vue/devtools-kit',
|
||||
'axios'
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
253
frontend/package-lock.json
generated
253
frontend/package-lock.json
generated
@@ -7,6 +7,7 @@
|
||||
"name": "dragonroll",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"axios": "^1.15.2",
|
||||
"mitt": "^3.0.1",
|
||||
"nuxt": "^4.4.2",
|
||||
"pixelarticons": "^2.1.0",
|
||||
@@ -3991,6 +3992,12 @@
|
||||
"integrity": "sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/autoprefixer": {
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz",
|
||||
@@ -4027,6 +4034,17 @@
|
||||
"postcss": "^8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.15.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.15.2.tgz",
|
||||
"integrity": "sha512-wLrXxPtcrPTsNlJmKjkPnNPK2Ihe0hn0wGSaTEiHRPxwjvJwT3hKmXF4dpqxmPO9SoNb2FsYXj/xEo0gHN+D5A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.11",
|
||||
"form-data": "^4.0.5",
|
||||
"proxy-from-env": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/b4a": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz",
|
||||
@@ -4345,6 +4363,19 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-api": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
|
||||
@@ -4448,6 +4479,18 @@
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/commondir": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
|
||||
@@ -4895,6 +4938,15 @@
|
||||
"integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/denque": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||
@@ -5037,6 +5089,20 @@
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/duplexer": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
||||
@@ -5103,6 +5169,15 @@
|
||||
"integrity": "sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
@@ -5118,6 +5193,33 @@
|
||||
"integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.27.7",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz",
|
||||
@@ -5359,6 +5461,26 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
|
||||
"integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/foreground-child": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
|
||||
@@ -5375,6 +5497,43 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
|
||||
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/form-data/node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/form-data/node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/fraction.js": {
|
||||
"version": "5.3.4",
|
||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz",
|
||||
@@ -5469,12 +5628,49 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.1.1",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-proto": "^1.0.1",
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"math-intrinsics": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-port-please": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.2.0.tgz",
|
||||
"integrity": "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/get-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/get-stream": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
|
||||
@@ -5560,6 +5756,18 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
@@ -5604,6 +5812,33 @@
|
||||
"integrity": "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
|
||||
@@ -6268,6 +6503,15 @@
|
||||
"source-map-js": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/mdn-data": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz",
|
||||
@@ -7622,6 +7866,15 @@
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
|
||||
"integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/quansync": {
|
||||
"version": "0.2.11",
|
||||
"resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.15.2",
|
||||
"mitt": "^3.0.1",
|
||||
"nuxt": "^4.4.2",
|
||||
"pixelarticons": "^2.1.0",
|
||||
|
||||
BIN
frontend/public/img/logo-light.png
Normal file
BIN
frontend/public/img/logo-light.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
frontend/public/img/logo-splash-light.png
Normal file
BIN
frontend/public/img/logo-splash-light.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 312 KiB |
BIN
frontend/public/img/logo-splash.png
Normal file
BIN
frontend/public/img/logo-splash.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
BIN
frontend/public/img/logo.png
Normal file
BIN
frontend/public/img/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
Reference in New Issue
Block a user