Compare commits

..

4 Commits

Author SHA1 Message Date
02e9aa1ac4 token validity increase from 1 hour to 7 days 2026-02-16 07:41:49 +01:00
b3be74e652 changed path to SFTPsync utility in deploy script 2026-02-16 07:35:34 +01:00
af437963bb added change language into settings 2026-02-15 18:16:01 +01:00
6ff28dae13 added PWA manifest,
added deploy script for Windows
2026-02-15 17:28:16 +01:00
18 changed files with 155 additions and 5 deletions

View File

@ -105,7 +105,7 @@ class Users extends \TPsoft\DBmodel\DBmodel {
return password_verify($password, $password_hash);
}
public function generateToken(int $user_id, int $ttl_seconds = 3600): string {
public function generateToken(int $user_id, int $ttl_seconds = 604800): string {
if ($user_id <= 0) {
throw new \Exception('Invalid user_id');
}
@ -152,7 +152,7 @@ class Users extends \TPsoft\DBmodel\DBmodel {
if (!hash_equals($stored_token, $token)) {
return false;
}
$refresh_expires = date('Y-m-d H:i:s', time() + 3600);
$refresh_expires = date('Y-m-d H:i:s', time() + 604800); // 7 days
$updated = $this->user($user_id, array(
'token_expires' => $refresh_expires
));

9
deploy.bat Normal file
View File

@ -0,0 +1,9 @@
@echo off
call php d:\www\sftpsync\src\sftpsync.php --host nutrio.tpsoft.org --user igor ^
--delete-dir /storage/tpsoft.org/nutrio/public ^
--sync d:/www/Nutrio/dist /storage/tpsoft.org/nutrio ^
--skip .git ^
--print-relative
echo ✔️ Done.

View File

@ -163,3 +163,76 @@ Požiadavky na build.bat:
- na konci vypíš, že DocumentRoot má byť nastavený na dist/public a frontend je v dist/public
Dodaj kompletný obsah súboru build.bat.
----- 2026-02-15 17:05:23 -----------------------------------------------------
Úloha:
V projekte vytvor plne funkčnú konfiguráciu PWA.
1⃣ Manifest
Vytvor súbor: frontend/public/manifest.json
Obsah musí:
- byť validný JSON
obsahovať:
- name
- short_name
- start_url
- display = "standalone"
- background_color
- theme_color
- icons pole
Použi tieto hodnoty:
{
"name": "Nutrio",
"short_name": "Nutrio",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#22c55e"
}
2⃣ Ikony
Zdrojový obrázok:
frontend/public/Nutrio.600.png
Z neho vytvor PNG ikony do adresára:
frontend/public/icons/
Vygeneruj tieto veľkosti:
16x16
32x32
48x48
180x180 (apple touch icon)
192x192 (PWA required)
512x512 (PWA required)
Požiadavky:
zachovať pomer strán
zachovať priehľadnosť
nepoužívať žiadne orezávanie
výstupné názvy:
icon-16.png
icon-32.png
icon-48.png
icon-180.png
icon-192.png
icon-512.png
3⃣ Manifest icons sekcia
Pole icons musí obsahovať iba:
[
{
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
"src": "/icons/icon-512.png",
"sizes": "512x512",
}
]
4⃣ Úprava index.html
Do frontend/index.html pridaj do <head>:
<link rel="manifest" href="/manifest.json">
<link rel="icon" type="image/png" sizes="32x32" href="/icons/icon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/icons/icon-16.png">
<link rel="apple-touch-icon" href="/icons/icon-180.png">
<meta name="theme-color" content="#22c55e">
5⃣ Výstup
nevysvetľuj
nevypisuj komentáre
vytvor alebo uprav iba potrebné súbory
ak adresár icons neexistuje, vytvor ho

View File

@ -2,7 +2,11 @@
<html lang="">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<link rel="manifest" href="/manifest.json">
<link rel="icon" type="image/png" sizes="32x32" href="/icons/icon-32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/icons/icon-16.png">
<link rel="apple-touch-icon" href="/icons/icon-180.png">
<meta name="theme-color" content="#22c55e">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nutrio</title>
</head>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 874 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -0,0 +1,20 @@
{
"name": "Nutrio",
"short_name": "Nutrio",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#22c55e",
"icons": [
{
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}

View File

@ -167,6 +167,7 @@
"accountTitle": "Nastavení účtu",
"loggedInAs": "Přihlášený uživatel",
"themeTitle": "Vzhled",
"languageTitle": "Jazyk",
"logout": "Odhlásit se"
}
}

View File

@ -167,6 +167,7 @@
"accountTitle": "Kontoeinstellungen",
"loggedInAs": "Angemeldet als",
"themeTitle": "Darstellung",
"languageTitle": "Sprache",
"logout": "Abmelden"
}
}

View File

@ -167,6 +167,7 @@
"accountTitle": "Account settings",
"loggedInAs": "Logged in as",
"themeTitle": "Appearance",
"languageTitle": "Language",
"logout": "Log out"
}
}

View File

@ -167,6 +167,7 @@
"accountTitle": "Ajustes de cuenta",
"loggedInAs": "Sesión iniciada como",
"themeTitle": "Apariencia",
"languageTitle": "Idioma",
"logout": "Cerrar sesión"
}
}

View File

@ -167,6 +167,7 @@
"accountTitle": "Nastavenia účtu",
"loggedInAs": "Prihlásený používateľ",
"themeTitle": "Vzhľad",
"languageTitle": "Jazyk",
"logout": "Odhlásiť sa"
}
}

View File

@ -1,12 +1,41 @@
<script setup lang="ts">
<script setup lang="ts">
import { computed, watch } from 'vue'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import ThemeToggle from '@/components/common/ThemeToggle.vue'
import i18n from '@/i18n'
import { SUPPORTED_LOCALES, type AppLocale } from '@/i18n'
import { useAuthStore } from '@/stores/auth'
const router = useRouter()
const auth = useAuthStore()
const { t } = useI18n()
const { t } = useI18n({ useScope: 'global' })
const isSupportedLocale = (value: string): value is AppLocale => {
return SUPPORTED_LOCALES.includes(value as AppLocale)
}
const setLocale = (value: string) => {
if (!isSupportedLocale(value)) {
return
}
i18n.global.locale.value = value
document.documentElement.setAttribute('lang', value)
localStorage.setItem('locale', value)
}
const localeValue = computed({
get: () => i18n.global.locale.value as AppLocale,
set: (value: string) => setLocale(value),
})
watch(
() => i18n.global.locale.value,
(nextLocale) => {
document.documentElement.setAttribute('lang', nextLocale)
},
{ immediate: true },
)
const onLogout = async () => {
await auth.logout()
@ -25,6 +54,16 @@ const onLogout = async () => {
<span>{{ t('settings.themeTitle') }}</span>
<ThemeToggle />
</div>
<div class="settings-card__theme">
<span>{{ t('settings.languageTitle') }}</span>
<label class="locale-control" :aria-label="t('settings.languageTitle')">
<select v-model="localeValue">
<option v-for="lang in SUPPORTED_LOCALES" :key="lang" :value="lang">
{{ t(`locale.${lang}`) }}
</option>
</select>
</label>
</div>
<button class="btn btn-danger" type="button" @click="onLogout">{{ t('settings.logout') }}</button>
</section>
</section>