Enough for today
All checks were successful
Build and Deploy Nuxt / build (push) Successful in 49s

This commit is contained in:
2026-04-26 00:52:59 +02:00
parent c3e5448597
commit b69e571202
89 changed files with 2727 additions and 58 deletions

View File

@@ -0,0 +1,39 @@
name: Build and Deploy Nuxt
on:
push:
branches: [master]
jobs:
build:
runs-on: docker
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build frontend
run: |
docker build -t git.aranroig.com/${{ secrets.REGISTRY_USER }}/dragonroll-frontend:latest ./frontend
docker push git.aranroig.com/${{ secrets.REGISTRY_USER }}/dragonroll-frontend:latest
- name: Build backend
run: |
docker build -t git.aranroig.com/${{ secrets.REGISTRY_USER }}/dragonroll-backend:latest ./backend
docker push git.aranroig.com/${{ secrets.REGISTRY_USER }}/dragonroll-backend:latest
# - name: Copy files
# run: |
# scp docker-compose.yml deploy@${{ secrets.DEPLOY_HOST}}:/var/www/app/
# scp nginx.conf deploy@${{ secrets.DEPLOY_HOST }}:/var/www/app/nginx.conf
#- name: Deploy
# run: |
# ssh deploy@${{ secrets.DEPLOY_HOST }} << 'EOF'
# echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login git.aranroig.com -u "${{ secrets.REGISTRY_USER }}" --password-stdin
# cd /var/www/app/
# docker-compose pull
# docker-compose up -d
# EOF

6
frontend/18n.config.ts Normal file
View File

@@ -0,0 +1,6 @@
// i18n.config.ts
export default defineI18nConfig(() => ({
fallbackLocale: 'en',
missingWarn: true,
fallbackWarn: true
}))

View File

@@ -1,6 +1,6 @@
<script setup>
import { TransitionGroup } from 'vue'
import { Windows, ReloadRef, WindowMap } from '@/services/Windows';
import { Windows, ReloadRef, WindowMap, getComponent } from '@/services/Windows';
// Gestionem ventanas
const reload = ReloadRef();
@@ -11,7 +11,7 @@ const windows = Windows();
<template>
<div class="window-container" :key="reload">
<TransitionGroup name="window">
<component v-for="win in windows" :is="WindowMap()[win.type]" :key="win.id" :data="win"></component>
<component v-for="win in windows" :is="getComponent(win.type)" :key="win.id" :data="win"></component>
</TransitionGroup>
</div>
</template>

View File

@@ -9,7 +9,7 @@ const handle = ref(null);
const props = defineProps(['data']);
const data = props.data;
let id = data.id;
let id = data.type;
const test = ref(null)

View File

@@ -20,7 +20,7 @@ const handle = ref(null);
const props = defineProps(['data']);
const data = props.data;
let id = data.id;
let id = data.type;
const username = ref("");
const password = ref("");
@@ -28,7 +28,6 @@ const password = ref("");
onMounted(() => {
SetupHandle(id, handle);
SetSize(id, {width: 450, height: 480});
SetMovable(id, false);
SetResizable(id, false);
ResetPosition(id, "center");
});
@@ -77,18 +76,18 @@ function toRegister(){
<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" >
<label for="username">{{$t('login.username')}}</label>
<input id="username-field" type="text" :placeholder="$t('login.username-placeholder')" 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" >
<label for="password">{{$t('login.password')}}</label>
<input id="password-field" type="password" :placeholder="$t('login.password-placeholder')" name="password" v-model="password" autocomplete="off" >
</div>
<div class="form-field">
<button class="btn-primary sound-click">Log in</button>
<button class="btn-primary sound-click">{{$t('login.log-in')}}</button>
</div>
<div class="form-field center">
<p>You don't have an account? <a href="#" @click.prevent="toRegister">Register</a></p>
<p>{{$t('login.no-account')}} <a href="#" @click.prevent="toRegister">{{$t('login.register')}}</a></p>
</div>
</form>

View File

@@ -9,7 +9,7 @@ const handle = ref(null);
const props = defineProps(['data']);
const data = props.data;
let id = data.id;
let id = data.type;
const test = ref(null)

View File

@@ -5,6 +5,7 @@ import { GetWindowWithId, ClearWindow, Windows } from '@/services/Windows';
import ArrowLeftIcon from '/icons/iconoir/regular/arrow-left.svg';
import XMarkIcon from '/icons/iconoir/regular/xmark.svg';
import ResizeHandleIcon from '/icons/ui/resize-handle.svg';
import { AddSound } from '~/services/Sound';
const props = defineProps(['window', 'handleHeight', 'custom', 'color']);
const id = props.window;
@@ -25,7 +26,7 @@ let backFunction;
function setupHandle() {
let win = GetWindowWithId(id);
if(win.title) title.value = win.title;
if(win.title) title.value = $t(win.title);
if(win.close){
close.value = true;
closeAction = win.close;
@@ -43,6 +44,8 @@ function setupHandle() {
// Setup sounds
let currentWindowId = "window-wrapper-" + id;
let currentWindow = document.getElementById(currentWindowId);
AddSound(currentWindow);
}
function CloseButton(){

View File

@@ -0,0 +1,15 @@
function AddSound(element){
let soundClicks = element.getElementsByClassName("sound-click");
for (let i = 0; i < soundClicks.length; i++) {
soundClicks[i].addEventListener("click", async (event) => {
const audio = new Audio('/sounds/snap.wav');
audio.type = "audio/wav"
audio.play().catch((e)=>{});
})
}
}
export {
AddSound
};

View File

@@ -0,0 +1,24 @@
/*
Put here all dragonroll windows
*/
const defWindows = {
login: {
title: 'Login',
movable: false,
component: () => import('~/components/windows/LoginWindow.vue'),
},
register: {
title: 'Register',
movable: false,
component: () => import('~/components/windows/RegisterWindow.vue'),
},
example: {
title: 'Example',
component: () => import('~/components/windows/ExampleWindow.vue'),
}
}
export {
defWindows
}

View File

@@ -1,33 +1,9 @@
import { ref } from 'vue'
import { defWindows } from './WindowDefinitions';
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,
register: RegisterWindow,
example: ExampleWindow
};
// Presets
const defValues = {
'example': {
id: "example",
title: "Example",
close: () => ClearWindow('example')
},
'login': {
id: 'login',
title: 'Login',
},
'register': {
id: 'register',
title: 'Register'
}
}
const getComponent = (type) => defineAsyncComponent(defWindows[type]?.component)
const reload = ref(0);
@@ -36,11 +12,12 @@ let Windows = () => { return windows };
let WindowMap = () => { return windowMap };
let currentIndex = 10;
let currentId = 0;
function SetupHandle(id, handle) {
// Update window info with handle info
console.log(id);
let win = GetWindowWithId(id);
let currentWindowId = "window-wrapper-" + id;
@@ -68,7 +45,7 @@ function SetupHandle(id, handle) {
// Move window listeners
handler.addEventListener("mousedown", (event) => {
if(win.noMove) return;
if(!win.movable) return;
draggingWindow = true;
let windowRect = currentWindow.getBoundingClientRect();
@@ -77,7 +54,7 @@ function SetupHandle(id, handle) {
})
document.addEventListener("mousemove", (event) => {
if(win.noMove) return;
if(!win.movable) return;
if (!draggingWindow) return;
if (event.clientX + offsetX < -currentWindow.getBoundingClientRect().width + 20) currentWindow.style.left = (-currentWindow.getBoundingClientRect().width + 20) + "px";
@@ -90,7 +67,7 @@ function SetupHandle(id, handle) {
})
document.addEventListener("mouseup", (event) => {
if(win.noMove) return;
if(!win.movable) 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) });
@@ -128,6 +105,13 @@ function SetupHandle(id, handle) {
win.height = parseInt(currentWindow.style.height, 10);
});
// Should move eventually?
window.addEventListener('resize', (event) => {
if(!win.movable){
ResetPosition(id, "center");
}
})
handle.value.setupHandle();
}
@@ -138,7 +122,7 @@ function SetResizable(id, resizable) {
function SetMovable(id, movable) {
let win = GetWindowWithId(id);
win.noMove = !movable;
win.movable = movable;
}
function SetSize(id, size) {
@@ -211,35 +195,38 @@ function ResetPosition(id, pos) {
function CreateWindow(type, data = {}) {
let finalData = { ...{ type }, ...defValues[type], ...data }
let finalData = { ...{ type, id: currentId }, ...defWindows[type], ...data }
console.log(finalData);
let contains = false;
for (let i = 0; i < windows.value.length; i++) {
if (windows.value[i].id == finalData.id) {
if (windows.value[i].type == finalData.type) {
contains = true;
console.log("It contains")
break;
}
}
if (!contains) {
windows.value.push(finalData);
console.log("Pushed ", finalData.id);
currentId++;
console.log(finalData);
console.log("Pushed ", finalData.type);
// reload.value += 1;
console.log(windows.value);
setTimeout(() => {
SetOnTop(finalData.id);
SetOnTop(finalData.type);
if (finalData.create) finalData.create();
}, 0);
}
}
function CreateChildWindow(parentId, type, data = {}) {
let finalData = { ...{ type }, ...defValues[type], ...data }
let finalData = { ...{ type }, ...defWindows[type], ...data }
let parent = GetWindowWithId(parentId);
if (parent.children) parent.children.push(finalData.id);
else parent.children = [finalData.id];
if (parent.children) parent.children.push(finalData.type);
else parent.children = [finalData.type];
CreateWindow(type, data);
}
@@ -251,22 +238,23 @@ function ClearAll() {
function ClearWindows(data) {
for (let i = 0; i < windows.value.length; i++) {
ClearWindow(windows.value[i].id);
ClearWindow(windows.value[i].type);
}
// reload.value += 1;
}
function ClearWindow(id) {
let win = GetWindowWithId(id);
console.log(win);
if (!win) return;
if (win.children) for (let i = 0; i < win.children.length; i++) ClearWindow(win.children[i]);
windows.value = windows.value.filter((e) => { return e.id !== id });
windows.value = windows.value.filter((e) => { return e.type !== id });
// reload.value += 1;
}
function GetWindowWithId(id) {
for (let i = 0; i < windows.value.length; i++) {
if (windows.value[i].id == id) {
if (windows.value[i].type == id) {
return windows.value[i];
}
}
@@ -288,8 +276,10 @@ function SetOnTop(id) {
let currentWindowId = "window-wrapper-" + id;
let currentWindow = document.getElementById(currentWindowId);
currentIndex += 1;
currentWindow.style.zIndex = currentIndex;
try {
currentIndex += 1;
currentWindow.style.zIndex = currentIndex;
} catch(e) {}
}
export {
@@ -312,5 +302,6 @@ export {
SaveWindowPos,
GetPosition,
ClearWindow,
ClearAll
ClearAll,
getComponent
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1,16 @@
{
"windows": {
"login": "Login",
"register": "Register",
"example": "Example Window"
},
"login": {
"username": "Username",
"username-placeholder": "Enter your username here...",
"password": "Password",
"password-placeholder": "Enter your password...",
"log-in": "Log in",
"no-account": "You don't have an account?",
"register": "Register"
}
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -5,7 +5,8 @@ export default defineNuxtConfig({
include: [
'@vue/devtools-core',
'@vue/devtools-kit',
'axios'
'axios',
'mitt'
]
}
},
@@ -24,4 +25,16 @@ export default defineNuxtConfig({
apiBaseUrl: process.env.API_BASE_URL || 'http://localhost:5000/api'
}
},
i18n: {
locales: [
{ code: 'en', iso: 'en-US', name: '🇺🇸 English', file: 'en.json' },
{ code: 'es', iso: 'es-ES', name: '🇪🇸 Spanish', file: 'es.json' },
{ code: 'ca', iso: 'ca-ES', name: '🇦🇩 Catalan', file: 'ca.json' }
],
defaultLocale: 'en',
vueI18n: './i18n.config.ts',
langDir: 'locales/'
},
modules: ['@nuxtjs/i18n']
})

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,7 @@
"postinstall": "nuxt prepare"
},
"dependencies": {
"@nuxtjs/i18n": "^10.3.0",
"axios": "^1.15.2",
"mitt": "^3.0.1",
"nuxt": "^4.4.2",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.