Second working version with vite-express integration.

Replace Bootstrap with Privemue.
Add i18n support. English and Brazilian Portuguese to start.
New UI with Primevue. Use tabbed menu, nice theme, etc..
WIP with Steam login.
This commit is contained in:
Daniel Ceregatti 2024-07-29 07:54:16 -07:00
parent 85e59ae8c6
commit 53dea0f45d
23 changed files with 553 additions and 173 deletions

View file

@ -19,7 +19,7 @@ services:
args:
- USER_ID
user: ${USER_ID}
hostname: web
hostname: dayzdockerserver
volumes:
- homedir_main:/home/user
- serverfiles:/serverfiles

View file

@ -7,12 +7,12 @@ trap '
' SIGINT SIGTERM
# Set PS1 so we know we're in the container
if grep -q "dz-web" .bashrc
if ! grep -q "dz-web" .bashrc
then
echo "Adding PS1 to .bashrc..."
cat >> .bashrc <<EOF
alias ls='ls --color'
export PS1="${debian_chroot:+($debian_chroot)}\u@dz-web:\w\$ "
export PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
unset DEVELOPMENT
export PATH=${PATH}:/usr/local/dotnet
EOF

View file

@ -1,7 +1,6 @@
<script setup>
import Error from '@/components/Error.vue'
import Login from '@/components/Login.vue'
import Main from '@/components/Main.vue'
import Header from '@/components/Header.vue'
import { useFetch } from '@vueuse/core'
import { useAppStore } from '@/store.js'
const store = useAppStore()
@ -17,8 +16,7 @@ useFetch('/status', {
<Suspense>
<main>
<Error />
<Login v-if="! store.steamStatus.loggedIn" />
<Main v-else />
<Header />
</main>
</Suspense>
</template>

View file

@ -1,9 +0,0 @@
<script setup>
import Mods from '@/components/Mods.vue'
import SearchResults from "@/components/SearchResults.vue";
</script>
<template>
<SearchResults />
<Mods />
</template>

View file

@ -1,40 +1,11 @@
<script setup>
import { watch } from 'vue'
import { Modal } from 'bootstrap'
import Dialog from 'primevue/dialog'
import { useAppStore } from '@/store.js'
const store = useAppStore()
let modal = {}
watch(() => store.errorText, () => {
modal = new Modal('#errorModal', {})
if (store.errorText) {
modal.show()
}
})
</script>
<template>
<div
class="modal"
id="errorModal"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabindex="-1"
aria-labelledby="errorModalLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="errorModalLabel">Error</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
{{ store.errorText }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<Dialog v-model:visible="store.errorText" modal :header="$t('Error')" :style="{ width: '25rem' }">
{{ store.errorText }}
</Dialog>
</template>

View file

@ -0,0 +1,19 @@
<script setup>
import Button from 'primevue/button'
import { useFetch } from '@vueuse/core'
import { useAppStore } from '@/store.js'
const store = useAppStore()
async function base() {
let which = '/installbase'
if (store.steamStatus.installed) {
which = '/updatebase'
}
const { data } = await useFetch(which).get().json()
store.errorText = data.value.message
}
</script>
<template>
<Button @click="base" v-if="store.steamStatus.installed">{{ store.steamStatus.installed ? $t('Update Server Files') : $t('Install Server Files') }}</Button>
<span v-else>{{ $t('Server files not installed') }}</span>
</template>

View file

@ -1,45 +1,50 @@
<script setup>
import Search from '@/components/Search.vue'
import Status from '@/components/Status.vue'
import Tabs from 'primevue/tabs'
import TabList from 'primevue/tablist'
import Tab from 'primevue/tab'
import TabPanels from 'primevue/tabpanels'
import TabPanel from 'primevue/tabpanel'
import Files from '@/components/Files.vue'
import Home from '@/components/Home.vue'
import Steam from '@/components/Steam.vue'
import Servers from '@/components/Servers.vue'
import { useFetch } from '@vueuse/core'
import { useAppStore } from '@/store.js'
const store = useAppStore()
const set = (w, e) => {
store.section = w
const active = Array.from(document.getElementsByClassName('active'))
active.forEach((a) => a.classList.remove('active'))
e.target.classList.add('active')
}
async function base() {
let which = '/installbase'
if (store.steamStatus.installed) {
which = '/updatebase'
}
const { data } = await useFetch(which).get().json()
store.errorText = data.value.message
}
import Mods from '@/components/Mods.vue'
import Status from '@/components/Status.vue'
</script>
<template>
<div v-if="store.steamStatus" class="row">
<div class="col-3 text-center">
<h1>DayZ Docker Server</h1>
</div>
<div class="col-5">
<button
@click="base"
class="btn btn-sm btn-success"
>
{{ store.steamStatus.installed ? "Update" : "Install" }} Server Files
</button>
<button @click="updatemods" class="btn btn-sm btn-outline-success">Update Mods</button>
<button type="button" @click="set('servers', $event)" class="btn btn-sm btn-outline-primary">Servers</button>
<button type="button" @click="set('mods', $event)" class="btn btn-sm btn-outline-primary active" data-bs-toggle="button">Mods</button>
<button type="button" @click="set('search', $event)" class="btn btn-sm btn-outline-primary">Search</button>
</div>
<Search />
<Status />
<Servers />
</div>
<div class="grid">
<div class="col-8 col-offset-2 text-center">
<Tabs value="0">
<TabList>
<Tab value="0">{{ $t('Home') }}</Tab>
<Tab value="1">{{ $t('Steam') }}</Tab>
<Tab value="2">{{ $t('Files') }}</Tab>
<Tab value="3">{{ $t('Mods') }}</Tab>
<Tab value="4">{{ $t('Servers') }}</Tab>
<Tab value="5">{{ $t('Status') }}</Tab>
</TabList>
<TabPanels>
<TabPanel value="0">
<Home />
</TabPanel>
<TabPanel value="1">
<Steam />
</TabPanel>
<TabPanel value="2">
<Files />
</TabPanel>
<TabPanel value="3">
<Mods />
</TabPanel>
<TabPanel value="4">
<Servers />
</TabPanel>
<TabPanel value="5">
<Status />
</TabPanel>
</TabPanels>
</Tabs>
</div>
</div>
</template>

View file

@ -0,0 +1,8 @@
<script setup>
</script>
<template>
<div class="">
<h1>{{ $t('DayZ Docker Server') }}</h1>
</div>
</template>

View file

@ -1,34 +0,0 @@
<script setup>
</script>
<template>
<div class="middle">
<h1>Login to Steam</h1>
<form name="form" method="POST" action="/login" enctype="application/x-www-form-urlencoded">
<div>
<input type="text" name="username" placeholder="Username" />
</div>
<div>
<input type="password" name="password" placeholder="Password" />
</div>
<div>
<input type="text" name="guard" placeholder="Steam Guard" />
</div>
<div>
<input type="checkbox" name="remember" id="remember" />
<label for="remember">Remember me</label>
</div>
<div>
<button type="submit" name="submit">Login</button>
</div>
</form>
</div>
</template>
<style scoped>
.middle {
margin: 0 auto;
width: 50%;
text-align: center;
}
</style>

View file

@ -4,8 +4,6 @@ import Header from './Header.vue'
</script>
<template>
<div class="container-fluid min-vh-100 d-flex flex-column bg-light">
<Header />
<Body />
</div>
<Header />
<!-- <Body />-->
</template>

View file

@ -4,7 +4,7 @@ import { useFetch } from '@vueuse/core'
import { useAppStore } from '@/store.js'
import ModInfo from '@/components/Modinfo.vue'
const store = useAppStore()
const { data, error } = useFetch(config.baseUrl + '/mods', {
const { data, error } = useFetch('/mods', {
afterFetch(ctx) {
store.mods = ctx.data.mods
return ctx
@ -13,14 +13,14 @@ const { data, error } = useFetch(config.baseUrl + '/mods', {
</script>
<template>
<div class="row flex-grow-1" v-if="store.section === 'mods'">
<div class="row flex-grow-1">
<div v-if="error" class="row text-danger">
{{ error }}
</div>
<div v-if="store.mods.length === 0">No mods are installed</div>
<div v-if="store.mods.length === 0">{{ $t('No mods are installed') }}</div>
<div v-else class="col-md-3 border" v-if="data">
<div>
<h4 class="text-center">Installed Mods</h4>
<h4 class="text-center">{{ $t('Installed Mods') }}</h4>
<table>
<tr>
<th>Steam Link</th>

View file

@ -1,20 +1,13 @@
<script setup>
import { useAppStore } from '@/store.js'
import { useAppStore} from '@/store.js'
const store = useAppStore()
</script>
<template>
<div class="row" v-if="store.section === 'servers'">
<div class="col text-center">
<div class="row">
<div class="col">
<h2>Servers</h2>
</div>
</div>
<div class="row flex-grow-1">
<div class="col-6 justify-content-end">Running</div>
<div class="col-6">Stopped</div>
</div>
</div>
</div>
<div v-if="store.servers.length > 0">
<h1>{{ $t('Servers') }}</h1>
</div>
<div v-else>
{{ $t('No servers have been created') }}
</div>
</template>

View file

@ -1,4 +1,5 @@
<script setup>
import Button from 'primevue/button'
import { useAppStore } from '@/store.js'
const store = useAppStore()
</script>
@ -6,18 +7,21 @@ const store = useAppStore()
<template>
<div class="col">
<div>
Logged into Steam:
<span v-if="store.steamStatus.loggedIn" class="bi bi-check h2 text-success"></span>
<span v-else class="bi bi-x h2 danger text-danger"></span>
{{ $t('Logged into Steam') }}:
<span v-if="store.steamStatus.loggedIn" class="pi pi-check" style="color: green"></span>
<span v-else class="pi pi-times" style="color: red"></span>
</div>
<div>
Server files installed:
<span v-if="store.steamStatus.installed" class="bi bi-check h2 text-success"></span>
<span v-else class="bi bi-x h2 danger text-danger"></span>
{{ $t('Server files installed') }}:
<span v-if="store.steamStatus.installed" class="pi pi-check" style="color: green"></span>
<span v-else class="pi pi-times" style="color: red"></span>
</div>
<div v-if="store.steamStatus.version">
Version: <span class="text-success fw-bold">{{ store.steamStatus.version }}</span>
<span class="text-success fw-bold">({{ store.steamStatus.appid }})</span>
{{ $t('Version') }}: <span style="color: green;">{{ store.steamStatus.version }}</span>
<span class="bold">({{ store.steamStatus.appid }})</span>
</div>
<div>
<Button @click="store.errorText = $t('This is an error message')">{{ $t('Test error') }}</Button>
</div>
</div>
</template>

View file

@ -0,0 +1,61 @@
<script setup>
import { useFetch } from '@vueuse/core'
import Checkbox from 'primevue/checkbox'
import Button from 'primevue/button'
import InputText from 'primevue/inputtext'
import Password from 'primevue/password'
import { useAppStore } from '@/store.js'
const store = useAppStore()
async function logOut() {
const response = await useFetch('/logout')
if (response.ok) {
store.steamStatus.loggedIn = false
} else if (response.err) {
store.errorText = response.err
}
}
function submit(e) {
console.log("Submit")
}
let username = ''
let password = ''
let remember = false
let steamGuardCode = ''
</script>
<template>
<div v-if="store.steamStatus.loggedIn">
<div>{{ $t('Already logged in to steam') }}</div>
<div>
<Button @click="logOut">{{ $t('Log out') }}</Button>
</div>
</div>
<div class="grid">
<div class="col-6 col-offset-3">
<div class="flex flex-column gap-2">
{{ $t('There are no saved Steam credentials. To install the server files and mods, please login to Steam') }}
</div>
<div class="">
</div>
<div class="flex flex-column gap-2">
<label for="username">{{ $t('Username') }}</label>
<InputText id="username" v-model="username" />
</div>
<div class="flex flex-column gap-2">
<label for="password">{{ $t('Password') }}</label>
<Password id="username" v-model="password" :feedback="false" toggleMask />
</div>
<div class="flex flex-column gap-2">
<label for="steamGuardCode">{{ $t('Steam Guard Code') }}</label>
<InputText id="steamGuardCode" v-model="steamGuardCode" />
</div>
<div class="flex flex-column gap-2">
<label for="remember">{{ $t('Remember Credentials') }}</label>
<Checkbox v-model="remember" />
</div>
<div class="flex flex-column gap-2">
<Button type="submit" onclick="submit()">{{ $t('Submit') }}</Button>
</div>
</div>
</div>
</template>

View file

@ -1,10 +1,6 @@
button {
padding: 5px;
margin: 10px;
}
th, td {
padding-right: 10px
.p-tablist-tab-list {
display: flex;
justify-content: center;
}
.active {

View file

@ -0,0 +1,42 @@
export const en = {
'Already logged in to steam': 'Already logged in to steam',
'DayZ': 'DayZ',
'DayZ Docker Server': 'DayZ Docker Server',
'Error': 'Error',
'Experimental': 'Experimental',
'Files': 'Files',
'Home': 'Home',
'Install': 'Install',
'Installed mods': 'Installed mods',
'Install Server Files': 'Install Server Files',
'Log out': 'Log out',
'Logged into Steam': 'Logged into Steam',
'Mods': 'Mods',
'Name': 'Name',
'No mods are installed': 'No mods are installed',
'No servers have been created': 'No servers have been created',
'Not Installed': 'Not Installed',
'Password': 'Password',
'Release': 'Release',
'Remember Credentials': 'Remember Credentials',
'Search': 'Search',
'Server files installed': 'Server files installed',
'Server files not installed': 'Server files not installed',
'Servers': 'Servers',
'Stable': 'Stable',
'Status': 'Status',
'Steam': 'Steam',
'Steam Guard Code': 'Steam Guard Code',
'Submit': 'Submit',
'Test error': 'Test error',
'There are no saved Steam credentials. To install the server files and mods, please login to Steam': 'There are no saved Steam credentials. To install the server files and mods, please login to Steam',
'This is an error message': 'This is an error message',
'Total servers': 'Total servers',
'Total workshop items': 'Total workshop items',
'Up to date': 'Up to date',
'Update': 'Update',
'Update Server Files': 'Update Server Files',
'Username': 'Username',
'Version': 'Version',
'Workshop': 'Workshop',
}

View file

@ -0,0 +1,16 @@
import { en } from './en.js'
import { pt } from './pt.js'
const messages = {
en: en,
pt: pt,
}
const locales = {
legacy: false,
locale: 'en',
fallbackLocale: 'en',
messages: messages
}
export { locales }

View file

@ -0,0 +1,42 @@
export const pt = {
'Already logged in to steam': 'Já registrado com Steam',
'DayZ': 'DayZ',
'DayZ Docker Server': 'Servidor DayZ de Docker',
'Error': 'Erro',
'Experimental': 'Experimental',
'Files': 'Arquivos',
'Home': 'Início',
'Install': 'Instalar',
'Installed mods': 'Mods instalados',
'Install Server Files': 'Instalar Arquivos de Servidor',
'Log out': 'Encerrar sessão',
'Logged into Steam': 'Registrado com Steam',
'Mods': 'Mods',
'Name': 'Nome',
'No mods are installed': 'Nenhum mod está installado',
'No servers have been created': 'Nenhum servidor foi criado',
'Not Installed': 'Não Instalado',
'Password': 'Senha',
'Release': 'Lançado',
'Remember Credentials': 'Lembrar Credenciais',
'Search': 'Procurar',
'Server files installed': 'Arquivos de servidor instalado',
'Server files not installed': 'Arquivos de servidor não instalados',
'Servers': 'Servidores',
'Stable': 'Estável',
'Status': 'Estado',
'Steam': 'Steam',
'Steam Guard Code': 'Còdigo Steam Guard',
'Submit': 'Enviar',
'Test error': 'Testar erro',
'There are no saved Steam credentials. To install the server files and mods, please login to Steam': 'Não existe credencias salvados. Para instalar o servidor, por favor registre-se no Steam',
'This is an error message': 'Esta é uma mensagem de erro',
'Total servers': 'Total de servidores',
'Total workshop items': 'Total de itens de oficina',
'Up to date': 'Atualizado',
'Update': 'Atualizar',
'Update Server Files': 'Atualizer Arquivos de Servidor',
'Username': 'Usuário',
'Version': 'Versão',
'Workshop': 'Oficina',
}

View file

@ -1,12 +1,15 @@
import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap'
import 'bootstrap-icons/font/bootstrap-icons.css'
import 'primeicons/primeicons.css'
import 'primeflex/primeflex.css'
import './css/index.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import {useAppStore} from '@/store'
import { useAppStore } from '@/store'
import PrimeVue from 'primevue/config'
import Aura from '@primevue/themes/aura'
import { createI18n } from 'vue-i18n'
import { locales } from '@/locales'
// Create an instance of our Vue app
const app = createApp(App)
@ -14,6 +17,10 @@ const app = createApp(App)
// Add the store
app.use(createPinia())
// Add i18n
const i18n = createI18n(locales)
app.use(i18n)
// A global error handler
app.config.errorHandler = (err, instance, info) => {
const store = useAppStore()
@ -21,5 +28,12 @@ app.config.errorHandler = (err, instance, info) => {
console.error('GLOBAL ERROR HANDLER! ', err, instance, info)
}
// Add PrimeVue
app.use(PrimeVue, {
theme: {
preset: Aura
}
})
// Mount it
app.mount('#app')

View file

@ -2,13 +2,13 @@ import { defineStore } from 'pinia'
export const useAppStore = defineStore('app', {
state: () => ({
errorText: '',
errorText: false,
modId: 0,
modFile: '',
messageText: '',
modFile: false,
messageText: false,
mods: [],
searchText: '',
section: 'mods',
searchText: false,
servers: [],
steamStatus: {appid: 0, installed: false, loggedIn: false, version: ''},
})
})

View file

@ -229,15 +229,27 @@ app.post(('/login'), async (req, res) => {
let args = `+login "${username}" "${password}"`
if (guard) args += ` "${guard}"`
const result = await steamcmd(args)
console.log(result)
if (remember) {
fs.writeFileSync(config.loginFile, username)
}
if (result) {
fs.writeFileSync(config.loginFile, username)
res.send(1)
res.send({"ok": 1})
} else {
res.send(0)
res.send({"ok": 0})
}
})
// Logout from Steam
app.get(('/logout'), async (req, res) => {
fs.unlink(config.loginFile, (err) => {
if (err) {
return res.send({"ok": 0, "error:": err})
}
res.send({"ok": 1})
})
})
// Get mod metadata by ID
app.get('/mod/:modId', (req, res) => {
const modId = req.params["modId"]

241
web/package-lock.json generated
View file

@ -10,11 +10,16 @@
"license": "ISC",
"dependencies": {
"@popperjs/core": "^2.11.8",
"@primevue/themes": "^4.0.2",
"@vueuse/core": "^10.11.0",
"bootstrap": "^5.3.3",
"bootstrap-icons": "^1.11.3",
"pinia": "^2.2.0",
"vue": "^3.4.34"
"primeflex": "^3.3.1",
"primeicons": "^7.0.0",
"primevue": "^4.0.2",
"vue": "^3.4.34",
"vue-i18n": "^9.13.1"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.1.1",
@ -403,6 +408,47 @@
"node": ">=12"
}
},
"node_modules/@intlify/core-base": {
"version": "9.13.1",
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.13.1.tgz",
"integrity": "sha512-+bcQRkJO9pcX8d0gel9ZNfrzU22sZFSA0WVhfXrf5jdJOS24a+Bp8pozuS9sBI9Hk/tGz83pgKfmqcn/Ci7/8w==",
"dependencies": {
"@intlify/message-compiler": "9.13.1",
"@intlify/shared": "9.13.1"
},
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@intlify/message-compiler": {
"version": "9.13.1",
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.13.1.tgz",
"integrity": "sha512-SKsVa4ajYGBVm7sHMXd5qX70O2XXjm55zdZB3VeMFCvQyvLew/dLvq3MqnaIsTMF1VkkOb9Ttr6tHcMlyPDL9w==",
"dependencies": {
"@intlify/shared": "9.13.1",
"source-map-js": "^1.0.2"
},
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@intlify/shared": {
"version": "9.13.1",
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.13.1.tgz",
"integrity": "sha512-u3b6BKGhE6j/JeRU6C/RL2FgyJfy6LakbtfeVF8fJXURpZZTzfh3e05J0bu0XPw447Q6/WUp3C4ajv4TMS4YsQ==",
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
@ -417,6 +463,63 @@
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@primeuix/styled": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/@primeuix/styled/-/styled-0.0.5.tgz",
"integrity": "sha512-pVoGn/uPkVm/DyF3TR3EmH/pL/dP4nR42FcYbVduFq9VfO3KVeOEqvcCULHXos66RZO9MCbCFUoLy6ctf9GUGQ==",
"dependencies": {
"@primeuix/utils": "^0.0.5"
},
"engines": {
"node": ">=12.11.0"
}
},
"node_modules/@primeuix/utils": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/@primeuix/utils/-/utils-0.0.5.tgz",
"integrity": "sha512-ntUiUgtRtkF8KuaxHffzhYxQxoXk6LAPHm7CVlFjdqS8Rx8xRkLkZVyo84E+pO2hcNFkOGVP/GxHhQ2s94O8zA==",
"engines": {
"node": ">=12.11.0"
}
},
"node_modules/@primevue/core": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@primevue/core/-/core-4.0.2.tgz",
"integrity": "sha512-SpCIQ1LG6B66cecmZt1UdFeY7tbdJrgnhncADolfE9fcCyTSBtbaVLLhCV2E4Q9myMwCFE5KQxqazA4rdLWk4w==",
"dependencies": {
"@primeuix/styled": "^0.0.5",
"@primeuix/utils": "^0.0.5"
},
"engines": {
"node": ">=12.11.0"
},
"peerDependencies": {
"vue": "^3.0.0"
}
},
"node_modules/@primevue/icons": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@primevue/icons/-/icons-4.0.2.tgz",
"integrity": "sha512-S1VEpMsx4uUAsTjZtII03LQqgocYwSKbXMF0YDFWybY8r5LaHaveVZxS/i+KbsCLaL18BXJw0L/7L1eQdJHzaA==",
"dependencies": {
"@primeuix/utils": "^0.0.5",
"@primevue/core": "4.0.2"
},
"engines": {
"node": ">=12.11.0"
}
},
"node_modules/@primevue/themes": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@primevue/themes/-/themes-4.0.2.tgz",
"integrity": "sha512-DGrdFOWRUb8/qDX+Hjkg0SkU2hvo6EmEE5/fA/+NSlLAemj5fcR8r3wo9jhFMIU0QVNl17jZycuL5taU0H72BA==",
"dependencies": {
"@primeuix/styled": "^0.0.5"
},
"engines": {
"node": ">=12.11.0"
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.19.1.tgz",
@ -1737,6 +1840,30 @@
"node": "^10 || ^12 || >=14"
}
},
"node_modules/primeflex": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/primeflex/-/primeflex-3.3.1.tgz",
"integrity": "sha512-zaOq3YvcOYytbAmKv3zYc+0VNS9Wg5d37dfxZnveKBFPr7vEIwfV5ydrpiouTft8MVW6qNjfkaQphHSnvgQbpQ=="
},
"node_modules/primeicons": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/primeicons/-/primeicons-7.0.0.tgz",
"integrity": "sha512-jK3Et9UzwzTsd6tzl2RmwrVY/b8raJ3QZLzoDACj+oTJ0oX7L9Hy+XnVwgo4QVKlKpnP/Ur13SXV/pVh4LzaDw=="
},
"node_modules/primevue": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/primevue/-/primevue-4.0.2.tgz",
"integrity": "sha512-bf5In//ixosZDOcfJ0iaBXhtQSpNC/CuAOE2KHd/SgUKZdij3VRljQ+I9+Be/TTxfikIeKH7eZ4gzDbWiIZurw==",
"dependencies": {
"@primeuix/styled": "^0.0.5",
"@primeuix/utils": "^0.0.5",
"@primevue/core": "4.0.2",
"@primevue/icons": "4.0.2"
},
"engines": {
"node": ">=12.11.0"
}
},
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@ -2191,6 +2318,25 @@
"optional": true
}
}
},
"node_modules/vue-i18n": {
"version": "9.13.1",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.13.1.tgz",
"integrity": "sha512-mh0GIxx0wPtPlcB1q4k277y0iKgo25xmDPWioVVYanjPufDBpvu5ySTjP5wOrSvlYQ2m1xI+CFhGdauv/61uQg==",
"dependencies": {
"@intlify/core-base": "9.13.1",
"@intlify/shared": "9.13.1",
"@vue/devtools-api": "^6.5.0"
},
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
},
"peerDependencies": {
"vue": "^3.0.0"
}
}
},
"dependencies": {
@ -2360,6 +2506,29 @@
"dev": true,
"optional": true
},
"@intlify/core-base": {
"version": "9.13.1",
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.13.1.tgz",
"integrity": "sha512-+bcQRkJO9pcX8d0gel9ZNfrzU22sZFSA0WVhfXrf5jdJOS24a+Bp8pozuS9sBI9Hk/tGz83pgKfmqcn/Ci7/8w==",
"requires": {
"@intlify/message-compiler": "9.13.1",
"@intlify/shared": "9.13.1"
}
},
"@intlify/message-compiler": {
"version": "9.13.1",
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.13.1.tgz",
"integrity": "sha512-SKsVa4ajYGBVm7sHMXd5qX70O2XXjm55zdZB3VeMFCvQyvLew/dLvq3MqnaIsTMF1VkkOb9Ttr6tHcMlyPDL9w==",
"requires": {
"@intlify/shared": "9.13.1",
"source-map-js": "^1.0.2"
}
},
"@intlify/shared": {
"version": "9.13.1",
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.13.1.tgz",
"integrity": "sha512-u3b6BKGhE6j/JeRU6C/RL2FgyJfy6LakbtfeVF8fJXURpZZTzfh3e05J0bu0XPw447Q6/WUp3C4ajv4TMS4YsQ=="
},
"@jridgewell/sourcemap-codec": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
@ -2370,6 +2539,45 @@
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="
},
"@primeuix/styled": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/@primeuix/styled/-/styled-0.0.5.tgz",
"integrity": "sha512-pVoGn/uPkVm/DyF3TR3EmH/pL/dP4nR42FcYbVduFq9VfO3KVeOEqvcCULHXos66RZO9MCbCFUoLy6ctf9GUGQ==",
"requires": {
"@primeuix/utils": "^0.0.5"
}
},
"@primeuix/utils": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/@primeuix/utils/-/utils-0.0.5.tgz",
"integrity": "sha512-ntUiUgtRtkF8KuaxHffzhYxQxoXk6LAPHm7CVlFjdqS8Rx8xRkLkZVyo84E+pO2hcNFkOGVP/GxHhQ2s94O8zA=="
},
"@primevue/core": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@primevue/core/-/core-4.0.2.tgz",
"integrity": "sha512-SpCIQ1LG6B66cecmZt1UdFeY7tbdJrgnhncADolfE9fcCyTSBtbaVLLhCV2E4Q9myMwCFE5KQxqazA4rdLWk4w==",
"requires": {
"@primeuix/styled": "^0.0.5",
"@primeuix/utils": "^0.0.5"
}
},
"@primevue/icons": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@primevue/icons/-/icons-4.0.2.tgz",
"integrity": "sha512-S1VEpMsx4uUAsTjZtII03LQqgocYwSKbXMF0YDFWybY8r5LaHaveVZxS/i+KbsCLaL18BXJw0L/7L1eQdJHzaA==",
"requires": {
"@primeuix/utils": "^0.0.5",
"@primevue/core": "4.0.2"
}
},
"@primevue/themes": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@primevue/themes/-/themes-4.0.2.tgz",
"integrity": "sha512-DGrdFOWRUb8/qDX+Hjkg0SkU2hvo6EmEE5/fA/+NSlLAemj5fcR8r3wo9jhFMIU0QVNl17jZycuL5taU0H72BA==",
"requires": {
"@primeuix/styled": "^0.0.5"
}
},
"@rollup/rollup-android-arm-eabi": {
"version": "4.19.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.19.1.tgz",
@ -3286,6 +3494,27 @@
"source-map-js": "^1.2.0"
}
},
"primeflex": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/primeflex/-/primeflex-3.3.1.tgz",
"integrity": "sha512-zaOq3YvcOYytbAmKv3zYc+0VNS9Wg5d37dfxZnveKBFPr7vEIwfV5ydrpiouTft8MVW6qNjfkaQphHSnvgQbpQ=="
},
"primeicons": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/primeicons/-/primeicons-7.0.0.tgz",
"integrity": "sha512-jK3Et9UzwzTsd6tzl2RmwrVY/b8raJ3QZLzoDACj+oTJ0oX7L9Hy+XnVwgo4QVKlKpnP/Ur13SXV/pVh4LzaDw=="
},
"primevue": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/primevue/-/primevue-4.0.2.tgz",
"integrity": "sha512-bf5In//ixosZDOcfJ0iaBXhtQSpNC/CuAOE2KHd/SgUKZdij3VRljQ+I9+Be/TTxfikIeKH7eZ4gzDbWiIZurw==",
"requires": {
"@primeuix/styled": "^0.0.5",
"@primeuix/utils": "^0.0.5",
"@primevue/core": "4.0.2",
"@primevue/icons": "4.0.2"
}
},
"proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@ -3577,6 +3806,16 @@
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"requires": {}
},
"vue-i18n": {
"version": "9.13.1",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.13.1.tgz",
"integrity": "sha512-mh0GIxx0wPtPlcB1q4k277y0iKgo25xmDPWioVVYanjPufDBpvu5ySTjP5wOrSvlYQ2m1xI+CFhGdauv/61uQg==",
"requires": {
"@intlify/core-base": "9.13.1",
"@intlify/shared": "9.13.1",
"@vue/devtools-api": "^6.5.0"
}
}
}
}

View file

@ -20,10 +20,15 @@
},
"dependencies": {
"@popperjs/core": "^2.11.8",
"@primevue/themes": "^4.0.2",
"@vueuse/core": "^10.11.0",
"bootstrap": "^5.3.3",
"bootstrap-icons": "^1.11.3",
"pinia": "^2.2.0",
"vue": "^3.4.34"
"primeflex": "^3.3.1",
"primeicons": "^7.0.0",
"primevue": "^4.0.2",
"vue": "^3.4.34",
"vue-i18n": "^9.13.1"
}
}