@@ -1,4 +1,4 @@
|
|||||||
name: Deploy Spot
|
name: Deploy Livetrail
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -7,12 +7,12 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
runs-on: spot
|
runs-on: livetrail
|
||||||
|
|
||||||
env:
|
env:
|
||||||
COMPOSER_NO_INTERACTION: "1"
|
COMPOSER_NO_INTERACTION: "1"
|
||||||
COMPOSER_HOME: .composer
|
COMPOSER_HOME: .composer
|
||||||
DEPLOY_PATH: /var/www/spot
|
DEPLOY_PATH: /var/www/livetrail
|
||||||
npm_config_cache: .npm-cache
|
npm_config_cache: .npm-cache
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
cd "$(dirname "$0")/../public" || exit 1 #Execute from public folder
|
cd "$(dirname "$0")/../public" || exit 1 #Execute from public folder
|
||||||
php -f index.php a=update_project > /dev/null
|
php -f index.php a=update_project > /dev/null
|
||||||
|
|
||||||
#Crontab job: 0 * * * * /path/to/spot/cli/cron.sh > /dev/null
|
#Crontab job: 0 * * * * /path/to/livetrail/cli/cron.sh > /dev/null
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "franzz/spot",
|
"name": "franzz/livetrail",
|
||||||
"description": "LiveTrail",
|
"description": "LiveTrail",
|
||||||
"type": "project",
|
"type": "project",
|
||||||
"license": "GPL-3.0-or-later",
|
"license": "GPL-3.0-or-later",
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Franzz\\Spot\\": "lib/",
|
"Franzz\\Livetrail\\": "lib/",
|
||||||
"Franzz\\Objects\\": "../objects/inc/"
|
"Franzz\\Objects\\": "../objects/inc/"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "franzz/spot",
|
"name": "franzz/livetrail",
|
||||||
"description": "LiveTrail",
|
"description": "LiveTrail",
|
||||||
"type": "project",
|
"type": "project",
|
||||||
"license": "GPL-3.0-or-later",
|
"license": "GPL-3.0-or-later",
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Franzz\\Spot\\": "lib/"
|
"Franzz\\Livetrail\\": "lib/"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"config/settings.php"
|
"config/settings.php"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "8eb764990f0cb9427030c2bf01390d62",
|
"content-hash": "4b438f8df113fa3394f395aa5b8e6081",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "franzz/objects",
|
"name": "franzz/objects",
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
DirectoryIndex index.php
|
DirectoryIndex index.php
|
||||||
|
|
||||||
# Serve http://localhost/spot/ from the public web root.
|
# Serve http://localhost/livetrail/ from the public web root.
|
||||||
Alias /spot /var/www/html/spot/public
|
Alias /livetrail /var/www/html/livetrail/public
|
||||||
|
|
||||||
<Directory /var/www/html/spot/public>
|
<Directory /var/www/html/livetrail/public>
|
||||||
Options FollowSymLinks
|
Options FollowSymLinks
|
||||||
AllowOverride None
|
AllowOverride None
|
||||||
Require all granted
|
Require all granted
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ class Settings
|
|||||||
const DB_SERVER = 'localhost';
|
const DB_SERVER = 'localhost';
|
||||||
const DB_LOGIN = '';
|
const DB_LOGIN = '';
|
||||||
const DB_PASS = '';
|
const DB_PASS = '';
|
||||||
const DB_NAME = 'spot';
|
const DB_NAME = 'livetrail';
|
||||||
const DB_ENC = 'utf8mb4';
|
const DB_ENC = 'utf8mb4';
|
||||||
const TEXT_ENC = 'UTF-8';
|
const TEXT_ENC = 'UTF-8';
|
||||||
const TIMEZONE = 'Europe/Zurich';
|
const TIMEZONE = 'Europe/Zurich';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Franzz\Spot;
|
namespace Franzz\Livetrail;
|
||||||
|
|
||||||
use Franzz\Objects\PhpObject;
|
use Franzz\Objects\PhpObject;
|
||||||
use Franzz\Objects\ToolBox;
|
use Franzz\Objects\ToolBox;
|
||||||
@@ -27,7 +27,7 @@ class Controller extends PhpObject
|
|||||||
'logout'
|
'logout'
|
||||||
);
|
);
|
||||||
|
|
||||||
private Spot $oSpot;
|
private Livetrail $oLivetrail;
|
||||||
private array $asReq;
|
private array $asReq;
|
||||||
private string $sCsrfToken = '';
|
private string $sCsrfToken = '';
|
||||||
|
|
||||||
@@ -69,22 +69,22 @@ class Controller extends PhpObject
|
|||||||
//Authentication and CSRF protection share the same server-side session.
|
//Authentication and CSRF protection share the same server-side session.
|
||||||
$this->initCsrfToken();
|
$this->initCsrfToken();
|
||||||
|
|
||||||
//Create Spot Instance
|
//Create Livetrail instance
|
||||||
$this->oSpot = new Spot($sProcessPage, $this->asReq['t']);
|
$this->oLivetrail = new Livetrail($sProcessPage, $this->asReq['t']);
|
||||||
|
|
||||||
//Validate CSRF, then release the session lock before long-running work.
|
//Validate CSRF, then release the session lock before long-running work.
|
||||||
$bValidMutationRequest = $this->validateMutationRequest($sAction);
|
$bValidMutationRequest = $this->validateMutationRequest($sAction);
|
||||||
if(!$bValidMutationRequest || !in_array($sAction, self::SESSION_WRITING_ACTIONS, true)) $this->closeSession();
|
if(!$bValidMutationRequest || !in_array($sAction, self::SESSION_WRITING_ACTIONS, true)) $this->closeSession();
|
||||||
|
|
||||||
if(!$bValidMutationRequest) $sResult = Spot::getJsonResult(false, Spot::UNAUTHORIZED);
|
if(!$bValidMutationRequest) $sResult = Livetrail::getJsonResult(false, Livetrail::UNAUTHORIZED);
|
||||||
else {
|
else {
|
||||||
$this->oSpot->setProjectId($this->asReq['id_project']);
|
$this->oLivetrail->setProjectId($this->asReq['id_project']);
|
||||||
$sResult = ($sAction == '')?$this->oSpot->getAppMainPage($this->getCsrfToken()):$this->dispatch($sAction);
|
$sResult = ($sAction == '')?$this->oLivetrail->getAppMainPage($this->getCsrfToken()):$this->dispatch($sAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Clean errors
|
//Clean errors
|
||||||
$sDebug = ob_get_clean();
|
$sDebug = ob_get_clean();
|
||||||
if($sDebug != '') $this->oSpot->addUncaughtError($sDebug);
|
if($sDebug != '') $this->oLivetrail->addUncaughtError($sDebug);
|
||||||
$this->closeSession();
|
$this->closeSession();
|
||||||
|
|
||||||
return $sResult;
|
return $sResult;
|
||||||
@@ -140,36 +140,36 @@ class Controller extends PhpObject
|
|||||||
private function dispatch(string $sAction): string
|
private function dispatch(string $sAction): string
|
||||||
{
|
{
|
||||||
return match($sAction) {
|
return match($sAction) {
|
||||||
'markers' => $this->oSpot->getMarkers(),
|
'markers' => $this->oLivetrail->getMarkers(),
|
||||||
'last_update' => $this->oSpot->getLastUpdate(),
|
'last_update' => $this->oLivetrail->getLastUpdate(),
|
||||||
'next_feed' => $this->oSpot->getNextFeed($this->asReq['id']),
|
'next_feed' => $this->oLivetrail->getNextFeed($this->asReq['id']),
|
||||||
'new_feed' => $this->oSpot->getNewFeed($this->asReq['id']),
|
'new_feed' => $this->oLivetrail->getNewFeed($this->asReq['id']),
|
||||||
'add_post' => $this->oSpot->addPost($this->asReq['name'], $this->asReq['content']),
|
'add_post' => $this->oLivetrail->addPost($this->asReq['name'], $this->asReq['content']),
|
||||||
'subscribe' => $this->oSpot->subscribe(),
|
'subscribe' => $this->oLivetrail->subscribe(),
|
||||||
'unsubscribe' => $this->oSpot->unsubscribe(),
|
'unsubscribe' => $this->oLivetrail->unsubscribe(),
|
||||||
'login' => $this->oSpot->login($this->asReq['email'], $this->asReq['password'], $this->asReq['name']),
|
'login' => $this->oLivetrail->login($this->asReq['email'], $this->asReq['password'], $this->asReq['name']),
|
||||||
'logout' => $this->oSpot->logout(),
|
'logout' => $this->oLivetrail->logout(),
|
||||||
'update_project' => $this->oSpot->updateProject(),
|
'update_project' => $this->oLivetrail->updateProject(),
|
||||||
default => $this->dispatchAdmin($sAction)
|
default => $this->dispatchAdmin($sAction)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private function dispatchAdmin(string $sAction): string
|
private function dispatchAdmin(string $sAction): string
|
||||||
{
|
{
|
||||||
if(!$this->oSpot->checkUserClearance(User::CLEARANCE_ADMIN)) {
|
if(!$this->oLivetrail->checkUserClearance(User::CLEARANCE_ADMIN)) {
|
||||||
return Spot::getJsonResult(false, Spot::NOT_FOUND);
|
return Livetrail::getJsonResult(false, Livetrail::NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
return match($sAction) {
|
return match($sAction) {
|
||||||
'upload' => $this->oSpot->upload(),
|
'upload' => $this->oLivetrail->upload(),
|
||||||
'add_comment' => $this->oSpot->addComment($this->asReq['id_entity'], $this->asReq['content']),
|
'add_comment' => $this->oLivetrail->addComment($this->asReq['id_entity'], $this->asReq['content']),
|
||||||
'add_position' => $this->oSpot->addPosition($this->asReq['latitude'], $this->asReq['longitude'], $this->asReq['timestamp']),
|
'add_position' => $this->oLivetrail->addPosition($this->asReq['latitude'], $this->asReq['longitude'], $this->asReq['timestamp']),
|
||||||
'admin_get' => $this->oSpot->getAdminSettings(),
|
'admin_get' => $this->oLivetrail->getAdminSettings(),
|
||||||
'admin_set' => $this->oSpot->setAdminSettings($this->asReq['type'], $this->asReq['id_entity'], $this->asReq['field'], $this->asReq['value']),
|
'admin_set' => $this->oLivetrail->setAdminSettings($this->asReq['type'], $this->asReq['id_entity'], $this->asReq['field'], $this->asReq['value']),
|
||||||
'admin_create' => $this->oSpot->createAdminSettings($this->asReq['type']),
|
'admin_create' => $this->oLivetrail->createAdminSettings($this->asReq['type']),
|
||||||
'admin_delete' => $this->oSpot->deleteAdminSettings($this->asReq['type'], $this->asReq['id_entity']),
|
'admin_delete' => $this->oLivetrail->deleteAdminSettings($this->asReq['type'], $this->asReq['id_entity']),
|
||||||
'sql' => $this->oSpot->getDbBuildScript(),
|
'sql' => $this->oLivetrail->getDbBuildScript(),
|
||||||
default => Spot::getJsonResult(false, Spot::NOT_FOUND)
|
default => Livetrail::getJsonResult(false, Livetrail::NOT_FOUND)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Franzz\Spot;
|
namespace Franzz\Livetrail;
|
||||||
use Franzz\Objects\PhpObject;
|
use Franzz\Objects\PhpObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Franzz\Spot;
|
namespace Franzz\Livetrail;
|
||||||
use Franzz\Objects\PhpObject;
|
use Franzz\Objects\PhpObject;
|
||||||
use Franzz\Objects\Mask;
|
use Franzz\Objects\Mask;
|
||||||
use PHPMailer\PHPMailer\PHPMailer;
|
use PHPMailer\PHPMailer\PHPMailer;
|
||||||
@@ -57,13 +57,13 @@ class Email extends PhpObject {
|
|||||||
$oPHPMailer->Password = Settings::MAIL_PASS; //SMTP password
|
$oPHPMailer->Password = Settings::MAIL_PASS; //SMTP password
|
||||||
$oPHPMailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; //Enable TLS encryption; `PHPMailer::ENCRYPTION_SMTPS` encouraged
|
$oPHPMailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; //Enable TLS encryption; `PHPMailer::ENCRYPTION_SMTPS` encouraged
|
||||||
$oPHPMailer->Port = 587; //TCP port to connect to, use 465 for `PHPMailer::ENCRYPTION_SMTPS` above
|
$oPHPMailer->Port = 587; //TCP port to connect to, use 465 for `PHPMailer::ENCRYPTION_SMTPS` above
|
||||||
$oPHPMailer->setFrom(Settings::MAIL_FROM, Spot::PROJECT_NAME);
|
$oPHPMailer->setFrom(Settings::MAIL_FROM, Livetrail::PROJECT_NAME);
|
||||||
$oPHPMailer->addReplyTo(Settings::MAIL_FROM, Spot::PROJECT_NAME);
|
$oPHPMailer->addReplyTo(Settings::MAIL_FROM, Livetrail::PROJECT_NAME);
|
||||||
|
|
||||||
$bSuccess = true;
|
$bSuccess = true;
|
||||||
foreach($this->asDests as $asDest) {
|
foreach($this->asDests as $asDest) {
|
||||||
//Message
|
//Message
|
||||||
$this->oTemplate->setLanguage($asDest['language'], Spot::DEFAULT_LANG);
|
$this->oTemplate->setLanguage($asDest['language'], Livetrail::DEFAULT_LANG);
|
||||||
$this->oTemplate->setTimezone($asDest['timezone']);
|
$this->oTemplate->setTimezone($asDest['timezone']);
|
||||||
|
|
||||||
//Unsubscribe Link
|
//Unsubscribe Link
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Franzz\Spot;
|
namespace Franzz\Livetrail;
|
||||||
use Franzz\Objects\PhpObject;
|
use Franzz\Objects\PhpObject;
|
||||||
use Franzz\Objects\Db;
|
use Franzz\Objects\Db;
|
||||||
use Franzz\Objects\Translator;
|
use Franzz\Objects\Translator;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Franzz\Spot;
|
namespace Franzz\Livetrail;
|
||||||
use Franzz\Objects\PhpObject;
|
use Franzz\Objects\PhpObject;
|
||||||
use \Settings;
|
use \Settings;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Franzz\Spot;
|
namespace Franzz\Livetrail;
|
||||||
|
|
||||||
class GeoJson extends Geo {
|
class GeoJson extends Geo {
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Franzz\Spot;
|
namespace Franzz\Livetrail;
|
||||||
use Franzz\Objects\ToolBox;
|
use Franzz\Objects\ToolBox;
|
||||||
|
|
||||||
class Gpx extends Geo {
|
class Gpx extends Geo {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Franzz\Spot;
|
namespace Franzz\Livetrail;
|
||||||
use Franzz\Objects\Db;
|
use Franzz\Objects\Db;
|
||||||
use Franzz\Objects\Main;
|
use Franzz\Objects\Main;
|
||||||
use Franzz\Objects\Translator;
|
use Franzz\Objects\Translator;
|
||||||
@@ -32,7 +32,7 @@ use \Settings;
|
|||||||
* - timezone: Site Timezone (stored user's timezone for emails)
|
* - timezone: Site Timezone (stored user's timezone for emails)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Spot extends Main
|
class Livetrail extends Main
|
||||||
{
|
{
|
||||||
//Database
|
//Database
|
||||||
const POST_TABLE = 'posts';
|
const POST_TABLE = 'posts';
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Franzz\Spot;
|
namespace Franzz\Livetrail;
|
||||||
use Franzz\Objects\PhpObject;
|
use Franzz\Objects\PhpObject;
|
||||||
use Franzz\Objects\Db;
|
use Franzz\Objects\Db;
|
||||||
use \Settings;
|
use \Settings;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Franzz\Spot;
|
namespace Franzz\Livetrail;
|
||||||
use Franzz\Objects\PhpObject;
|
use Franzz\Objects\PhpObject;
|
||||||
use Franzz\Objects\Db;
|
use Franzz\Objects\Db;
|
||||||
use Franzz\Objects\ToolBox;
|
use Franzz\Objects\ToolBox;
|
||||||
@@ -57,7 +57,7 @@ class Media extends PhpObject {
|
|||||||
}
|
}
|
||||||
else $sError = 'media.no_id';
|
else $sError = 'media.no_id';
|
||||||
|
|
||||||
return Spot::getResult(($sError==''), $sError, $asData);
|
return Livetrail::getResult(($sError==''), $sError, $asData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMediasInfo($oMediaIds=null) {
|
public function getMediasInfo($oMediaIds=null) {
|
||||||
@@ -138,7 +138,7 @@ class Media extends PhpObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Spot::getResult(($sError==''), $sError, $asParams);
|
return Livetrail::getResult(($sError==''), $sError, $asParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getMediaInfoFromFile($sMediaName)
|
private function getMediaInfoFromFile($sMediaName)
|
||||||
@@ -173,7 +173,7 @@ class Media extends PhpObject {
|
|||||||
//Taken On
|
//Taken On
|
||||||
if(isset($asExif['format']['tags']['com.apple.quicktime.creationdate'])) {
|
if(isset($asExif['format']['tags']['com.apple.quicktime.creationdate'])) {
|
||||||
$sTakenOn = $asExif['format']['tags']['com.apple.quicktime.creationdate']; //contains Time Zone
|
$sTakenOn = $asExif['format']['tags']['com.apple.quicktime.creationdate']; //contains Time Zone
|
||||||
$sTimeZone = Spot::getTimeZoneFromDate($sTakenOn) ?? $sTimeZone;
|
$sTimeZone = Livetrail::getTimeZoneFromDate($sTakenOn) ?? $sTimeZone;
|
||||||
}
|
}
|
||||||
else $sTakenOn = $asExif['format']['tags']['creation_time'] ?? $asExif['streams'][0]['tags']['creation_time'];
|
else $sTakenOn = $asExif['format']['tags']['creation_time'] ?? $asExif['streams'][0]['tags']['creation_time'];
|
||||||
|
|
||||||
@@ -207,7 +207,7 @@ class Media extends PhpObject {
|
|||||||
* 3. Timezone extracted from DateTimeOriginal
|
* 3. Timezone extracted from DateTimeOriginal
|
||||||
* 4. Uploader Browser Time Zone (PHP Default Time Zone)
|
* 4. Uploader Browser Time Zone (PHP Default Time Zone)
|
||||||
*/
|
*/
|
||||||
$sTimeZone = $asExif['EXIF']['OffsetTimeOriginal'] ?? $asExif['EXIF']['UndefinedTag:0x9011'] ?? Spot::getTimeZoneFromDate($sTakenOn) ?? $sTimeZone;
|
$sTimeZone = $asExif['EXIF']['OffsetTimeOriginal'] ?? $asExif['EXIF']['UndefinedTag:0x9011'] ?? Livetrail::getTimeZoneFromDate($sTakenOn) ?? $sTimeZone;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Location
|
//Location
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Franzz\Spot;
|
namespace Franzz\Livetrail;
|
||||||
use Franzz\Objects\PhpObject;
|
use Franzz\Objects\PhpObject;
|
||||||
use Franzz\Objects\Db;
|
use Franzz\Objects\Db;
|
||||||
use \Settings;
|
use \Settings;
|
||||||
@@ -153,8 +153,8 @@ class Project extends PhpObject {
|
|||||||
case 2: $asProject['mode'] = self::MODE_HISTO; break;
|
case 2: $asProject['mode'] = self::MODE_HISTO; break;
|
||||||
}
|
}
|
||||||
$asProject['editable'] = $this->isModeEditable($asProject['mode']);
|
$asProject['editable'] = $this->isModeEditable($asProject['mode']);
|
||||||
$asProject['gpxfilepath'] = Spot::addTimestampToFilePath(Gpx::getFrontendFilePath($sCodeName));
|
$asProject['gpxfilepath'] = Livetrail::addTimestampToFilePath(Gpx::getFrontendFilePath($sCodeName));
|
||||||
$asProject['geofilepath'] = Spot::addTimestampToFilePath(GeoJson::getFrontendFilePath($sCodeName));
|
$asProject['geofilepath'] = Livetrail::addTimestampToFilePath(GeoJson::getFrontendFilePath($sCodeName));
|
||||||
$asProject['codename'] = $sCodeName;
|
$asProject['codename'] = $sCodeName;
|
||||||
$asProject['default'] = ($sCodeName == $sDefaultProjectCodeName);
|
$asProject['default'] = ($sCodeName == $sDefaultProjectCodeName);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Franzz\Spot;
|
namespace Franzz\Livetrail;
|
||||||
use Franzz\Objects\UploadHandler;
|
use Franzz\Objects\UploadHandler;
|
||||||
use Franzz\Objects\Translator;
|
use Franzz\Objects\Translator;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Franzz\Spot;
|
namespace Franzz\Livetrail;
|
||||||
use Franzz\Objects\PhpObject;
|
use Franzz\Objects\PhpObject;
|
||||||
use Franzz\Objects\Db;
|
use Franzz\Objects\Db;
|
||||||
use \Settings;
|
use \Settings;
|
||||||
@@ -116,16 +116,16 @@ class User extends PhpObject {
|
|||||||
$this->updateGravatar($iUserId, $sEmail);
|
$this->updateGravatar($iUserId, $sEmail);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Spot::getResult($bSuccess, $sDesc, [Db::getId(self::USER_TABLE) => $iUserId]);
|
return Livetrail::getResult($bSuccess, $sDesc, [Db::getId(self::USER_TABLE) => $iUserId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setSubscription($bSubscribed) {
|
public function setSubscription($bSubscribed) {
|
||||||
if($this->getUserId() > 0) {
|
if($this->getUserId() > 0) {
|
||||||
$iSubscribed = $bSubscribed?1:0;
|
$iSubscribed = $bSubscribed?1:0;
|
||||||
$iUserId = $this->oDb->updateRow(self::USER_TABLE, $this->getUserId(), array('subscribed'=>$iSubscribed));
|
$iUserId = $this->oDb->updateRow(self::USER_TABLE, $this->getUserId(), array('subscribed'=>$iSubscribed));
|
||||||
if(!$iUserId) return Spot::getResult(false, 'lang:error.commit_db');
|
if(!$iUserId) return Livetrail::getResult(false, 'lang:error.commit_db');
|
||||||
$this->asUserInfo['subscribed'] = $iSubscribed;
|
$this->asUserInfo['subscribed'] = $iSubscribed;
|
||||||
return Spot::getResult(true, $iSubscribed?'lang:account.subscribed':'lang:account.unsubscribed');
|
return Livetrail::getResult(true, $iSubscribed?'lang:account.subscribed':'lang:account.unsubscribed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +200,7 @@ class User extends PhpObject {
|
|||||||
$this->setTokenCookie();
|
$this->setTokenCookie();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Spot::getResult($bSuccess, $sDesc);
|
return Livetrail::getResult($bSuccess, $sDesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function logout() {
|
public function logout() {
|
||||||
@@ -208,7 +208,7 @@ class User extends PhpObject {
|
|||||||
$this->clearSession();
|
$this->clearSession();
|
||||||
$this->clearCookie();
|
$this->clearCookie();
|
||||||
$this->setUserId(0);
|
$this->setUserId(0);
|
||||||
return Spot::getResult(true, 'lang:account.logged_out');
|
return Livetrail::getResult(true, 'lang:account.logged_out');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateNickname($sNickname) {
|
public function updateNickname($sNickname) {
|
||||||
@@ -239,7 +239,7 @@ class User extends PhpObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Spot::getResult($bSuccess, $sDesc);
|
return Livetrail::getResult($bSuccess, $sDesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Session */
|
/* Session */
|
||||||
|
|||||||
@@ -2,6 +2,6 @@
|
|||||||
|
|
||||||
require __DIR__.'/../vendor/autoload.php';
|
require __DIR__.'/../vendor/autoload.php';
|
||||||
|
|
||||||
use Franzz\Spot\Controller;
|
use Franzz\Livetrail\Controller;
|
||||||
|
|
||||||
echo (new Controller())->handle(__FILE__, $argv ?? array());
|
echo (new Controller())->handle(__FILE__, $argv ?? array());
|
||||||
|
|||||||
@@ -43,13 +43,13 @@ Runtime data is exposed through symlinks only: `public/files -> ../files` and `p
|
|||||||
|
|
||||||
`npm run dev` watches and builds development assets into `public/assets/`. `npm run prod` builds hashed production assets into `public/assets/`. PHP reads `public/.vite/manifest.json` and populates the CSS, module, and preload parts defined in `resources/masks/index.html` while rendering the request.
|
`npm run dev` watches and builds development assets into `public/assets/`. `npm run prod` builds hashed production assets into `public/assets/`. PHP reads `public/.vite/manifest.json` and populates the CSS, module, and preload parts defined in `resources/masks/index.html` while rendering the request.
|
||||||
|
|
||||||
When developing Spot and the sibling `objects` library together, install dependencies through the local Composer manifest:
|
When developing Livetrail and the sibling `objects` library together, install dependencies through the local Composer manifest:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
COMPOSER=composer.dev.json composer update
|
COMPOSER=composer.dev.json composer update
|
||||||
```
|
```
|
||||||
|
|
||||||
This makes Composer link `vendor/franzz/objects` to `../objects` and autoload that namespace directly from the local source path. Production continues to use `composer.json`, which installs `franzz/objects` from its Git repository. Commit and publish `objects` changes before updating/deploying a Spot version that relies on them.
|
This makes Composer link `vendor/franzz/objects` to `../objects` and autoload that namespace directly from the local source path. Production continues to use `composer.json`, which installs `franzz/objects` from its Git repository. Commit and publish `objects` changes before updating/deploying a Livetrail version that relies on them.
|
||||||
|
|
||||||
## To Do List
|
## To Do List
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
"feed": {
|
"feed": {
|
||||||
"counter": "#$0",
|
"counter": "#$0",
|
||||||
"id": "Feed ID",
|
"id": "Feed ID",
|
||||||
"last_update": "Last Spot update",
|
"last_update": "Last SPOT update",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"new": "New feed",
|
"new": "New feed",
|
||||||
"plural": "Feeds",
|
"plural": "Feeds",
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
"feed": {
|
"feed": {
|
||||||
"counter": "N.º $0",
|
"counter": "N.º $0",
|
||||||
"id": "ID Feed",
|
"id": "ID Feed",
|
||||||
"last_update": "Última actualización de Spot",
|
"last_update": "Última actualización de SPOT",
|
||||||
"name": "Descripción",
|
"name": "Descripción",
|
||||||
"new": "Nuevo feed",
|
"new": "Nuevo feed",
|
||||||
"plural": "Feeds",
|
"plural": "Feeds",
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
"feed": {
|
"feed": {
|
||||||
"counter": "N°$0",
|
"counter": "N°$0",
|
||||||
"id": "ID feed",
|
"id": "ID feed",
|
||||||
"last_update": "Dernière vérification Spot",
|
"last_update": "Dernière vérification de SPOT",
|
||||||
"name": "Description",
|
"name": "Description",
|
||||||
"new": "Nouveau feed",
|
"new": "Nouveau feed",
|
||||||
"plural": "Feeds",
|
"plural": "Feeds",
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import { defineAsyncComponent } from 'vue';
|
import { defineAsyncComponent } from 'vue';
|
||||||
import Project from '@components/project';
|
import Project from '@components/Project';
|
||||||
|
|
||||||
const aoRoutes = {
|
const aoRoutes = {
|
||||||
'project': Project, //Merge app.js and project.js calls to avoid extra http request on inital page
|
'project': Project, //Merge app.js and project.js calls to avoid extra http request on inital page
|
||||||
'admin': defineAsyncComponent(() => import('@components/admin')),
|
'admin': defineAsyncComponent(() => import('@components/Admin')),
|
||||||
'upload': defineAsyncComponent(() => import('@components/upload'))
|
'upload': defineAsyncComponent(() => import('@components/Upload'))
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { createApp, reactive } from 'vue';
|
|||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
|
|
||||||
//Style
|
//Style
|
||||||
import '@styles/spot.scss';
|
import '@styles/livetrail.scss';
|
||||||
|
|
||||||
//App Configuration from PHP
|
//App Configuration from PHP
|
||||||
const appConfig = JSON.parse(document.getElementById('app-config').textContent);
|
const appConfig = JSON.parse(document.getElementById('app-config').textContent);
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<script>
|
<script>
|
||||||
import SpotIcon from '@components/spotIcon';
|
import AppIcon from '@components/AppIcon';
|
||||||
import SpotButton from '@components/spotButton';
|
import AppButton from '@components/AppButton';
|
||||||
import AdminInput from '@components/adminInput';
|
import AdminInput from '@components/AdminInput';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
SpotIcon,
|
AppIcon,
|
||||||
SpotButton,
|
AppButton,
|
||||||
AdminInput
|
AdminInput
|
||||||
},
|
},
|
||||||
inject: ['api', 'lang', 'getPrevAnchor'],
|
inject: ['api', 'lang', 'getPrevAnchor'],
|
||||||
@@ -115,7 +115,7 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div id="admin">
|
<div id="admin">
|
||||||
<a name="back" class="button" :href="getPrevAnchor()"><SpotIcon :icon="'back'" :text="l('action.back')" /></a>
|
<a name="back" class="button" :href="getPrevAnchor()"><AppIcon :icon="'back'" :text="l('action.back')" /></a>
|
||||||
<h1>{{ l('project.plural') }}</h1>
|
<h1>{{ l('project.plural') }}</h1>
|
||||||
<div>
|
<div>
|
||||||
<table>
|
<table>
|
||||||
@@ -138,11 +138,11 @@ export default {
|
|||||||
<td><AdminInput :type="'text'" :name="'codename'" :elem="project" /></td>
|
<td><AdminInput :type="'text'" :name="'codename'" :elem="project" /></td>
|
||||||
<td><AdminInput :type="'date'" :name="'active_from'" :elem="project" /></td>
|
<td><AdminInput :type="'date'" :name="'active_from'" :elem="project" /></td>
|
||||||
<td><AdminInput :type="'date'" :name="'active_to'" :elem="project" /></td>
|
<td><AdminInput :type="'date'" :name="'active_to'" :elem="project" /></td>
|
||||||
<td><SpotButton :icon="'close'" iconSize="lg" @click="deleteElem(project)" /></td>
|
<td><AppButton :icon="'close'" iconSize="lg" @click="deleteElem(project)" /></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<SpotButton :classes="'new'" :text="l('project.new')" :icon="'new'" @click="createElem('project')" />
|
<AppButton :classes="'new'" :text="l('project.new')" :icon="'new'" @click="createElem('project')" />
|
||||||
</div>
|
</div>
|
||||||
<h1>{{ l('feed.plural') }}</h1>
|
<h1>{{ l('feed.plural') }}</h1>
|
||||||
<div>
|
<div>
|
||||||
@@ -168,11 +168,11 @@ export default {
|
|||||||
<td>{{ feed.name }}</td>
|
<td>{{ feed.name }}</td>
|
||||||
<td>{{ feed.status }}</td>
|
<td>{{ feed.status }}</td>
|
||||||
<td>{{ feed.last_update }}</td>
|
<td>{{ feed.last_update }}</td>
|
||||||
<td><SpotButton :icon="'close'" iconSize="lg" @click="deleteElem(feed)" /></td>
|
<td><AppButton :icon="'close'" iconSize="lg" @click="deleteElem(feed)" /></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<SpotButton :classes="'new'" :text="l('feed.new')" :icon="'new'" @click="createElem('feed')" />
|
<AppButton :classes="'new'" :text="l('feed.new')" :icon="'new'" @click="createElem('feed')" />
|
||||||
</div>
|
</div>
|
||||||
<h1>{{ l('spot.plural') }}</h1>
|
<h1>{{ l('spot.plural') }}</h1>
|
||||||
<div>
|
<div>
|
||||||
@@ -222,7 +222,7 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
<h1>{{ l('admin.toolbox') }}</h1>
|
<h1>{{ l('admin.toolbox') }}</h1>
|
||||||
<div id="toolbox">
|
<div id="toolbox">
|
||||||
<SpotButton :classes="'refresh'" :text="l('project.update_messages')" :icon="'refresh'" @click="updateProject" />
|
<AppButton :classes="'refresh'" :text="l('project.update_messages')" :icon="'refresh'" @click="updateProject" />
|
||||||
</div>
|
</div>
|
||||||
<div id="feedback" class="feedback">
|
<div id="feedback" class="feedback">
|
||||||
<p v-for="feedback in feedbacks" :class="feedback.type">{{ feedback.msg }}</p>
|
<p v-for="feedback in feedbacks" :class="feedback.type">{{ feedback.msg }}</p>
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import SpotIcon from '@components/spotIcon';
|
import AppIcon from '@components/AppIcon';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
SpotIcon
|
AppIcon
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
classes: String,
|
classes: String,
|
||||||
@@ -15,5 +15,5 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<button :class="classes"><SpotIcon :icon="icon" :text="text" :classes="iconClasses" :size="iconSize" /></button>
|
<button :class="classes"><AppIcon :icon="icon" :text="text" :classes="iconClasses" :size="iconSize" /></button>
|
||||||
</template>
|
</template>
|
||||||
@@ -20,7 +20,7 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
iconClassNames() {
|
iconClassNames() {
|
||||||
return [
|
return [
|
||||||
'spot-icon',
|
'app-icon',
|
||||||
this.icon,
|
this.icon,
|
||||||
...(this.classes || '').split(/\s+/),
|
...(this.classes || '').split(/\s+/),
|
||||||
this.margin?'margin-'+this.margin:null
|
this.margin?'margin-'+this.margin:null
|
||||||
@@ -49,42 +49,42 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<span :title="title" :class="hasText?'spot-icon-with-text':null">
|
<span :title="title" :class="hasText?'app-icon-with-text':null">
|
||||||
<span class="spot-icon-symbol">
|
<span class="app-icon-symbol">
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
:icon="iconDefinition"
|
:icon="iconDefinition"
|
||||||
:class="['spot-icon', this.icon, this.classes, this.margin?'margin-'+this.margin:null]"
|
:class="['app-icon', this.icon, this.classes, this.margin?'margin-'+this.margin:null]"
|
||||||
:fixed-width="resolvedFixedWidth"
|
:fixed-width="resolvedFixedWidth"
|
||||||
:width-auto="resolvedAutoWidth"
|
:width-auto="resolvedAutoWidth"
|
||||||
:size="resolvedSize"
|
:size="resolvedSize"
|
||||||
:transform="resolvedTransform"
|
:transform="resolvedTransform"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="hasText" :class="['spot-icon-text', textClasses]">{{ text }}</span>
|
<span v-if="hasText" :class="['app-icon-text', textClasses]">{{ text }}</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@use "@styles/var";
|
@use "@styles/var";
|
||||||
|
|
||||||
.spot-icon-with-text {
|
.app-icon-with-text {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
gap: var.$text-spacing;
|
gap: var.$text-spacing;
|
||||||
|
|
||||||
.spot-icon-symbol {
|
.app-icon-symbol {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spot-icon-text {
|
.app-icon-text {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.spot-icon {
|
.app-icon {
|
||||||
&.margin-right {
|
&.margin-right {
|
||||||
margin-right: var.$text-spacing;
|
margin-right: var.$text-spacing;
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import { FontAwesomeLayers } from '@fortawesome/vue-fontawesome';
|
import { FontAwesomeLayers } from '@fortawesome/vue-fontawesome';
|
||||||
import spotIcon from '@components/spotIcon';
|
import appIcon from '@components/AppIcon';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
FontAwesomeLayers,
|
FontAwesomeLayers,
|
||||||
spotIcon
|
appIcon
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
mainClasses: String,
|
mainClasses: String,
|
||||||
@@ -18,7 +18,7 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
mainClass() {
|
mainClass() {
|
||||||
return 'spot-icon-stack clickable'+(this.mainClasses?' '+this.mainClasses:'');
|
return 'app-icon-stack clickable'+(this.mainClasses?' '+this.mainClasses:'');
|
||||||
},
|
},
|
||||||
iconMainClass() {
|
iconMainClass() {
|
||||||
return this.mergeClasses('main clickable', this.iconMainClasses);
|
return this.mergeClasses('main clickable', this.iconMainClasses);
|
||||||
@@ -44,8 +44,8 @@ export default {
|
|||||||
<template>
|
<template>
|
||||||
<span :class="mainClass">
|
<span :class="mainClass">
|
||||||
<FontAwesomeLayers>
|
<FontAwesomeLayers>
|
||||||
<spotIcon :icon="iconMain" :classes="iconMainClass" :transform="iconMainTransform" />
|
<appIcon :icon="iconMain" :classes="iconMainClass" :transform="iconMainTransform" />
|
||||||
<spotIcon v-if="iconSub" :icon="iconSub" :classes="iconSubClass" :transform="iconSubTransformValue" />
|
<appIcon v-if="iconSub" :icon="iconSub" :classes="iconSubClass" :transform="iconSubTransformValue" />
|
||||||
</FontAwesomeLayers>
|
</FontAwesomeLayers>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
@@ -7,11 +7,11 @@ import { createApp } from 'vue';
|
|||||||
|
|
||||||
import Lightbox from '@scripts/lightbox';
|
import Lightbox from '@scripts/lightbox';
|
||||||
|
|
||||||
import SpotIcon from '@components/spotIcon';
|
import AppIcon from '@components/AppIcon';
|
||||||
import SpotIconStack from '@components/spotIconStack';
|
import AppIconStack from '@components/AppIconStack';
|
||||||
import ProjectPopup from '@components/projectPopup';
|
import ProjectPopup from '@components/ProjectPopup';
|
||||||
import ProjectFeed from '@components/projectFeed';
|
import ProjectFeed from '@components/ProjectFeed';
|
||||||
import ProjectSettings from '@components/projectSettings';
|
import ProjectSettings from '@components/ProjectSettings';
|
||||||
|
|
||||||
setWorkerUrl(maplibreWorkerUrl);
|
setWorkerUrl(maplibreWorkerUrl);
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ class GroupedScaleControl {
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
SpotIcon,
|
AppIcon,
|
||||||
ProjectFeed,
|
ProjectFeed,
|
||||||
ProjectSettings
|
ProjectSettings
|
||||||
},
|
},
|
||||||
@@ -412,7 +412,7 @@ export default {
|
|||||||
},
|
},
|
||||||
addMarker(oMarker) {
|
addMarker(oMarker) {
|
||||||
const $Marker = document.createElement('div');
|
const $Marker = document.createElement('div');
|
||||||
oMarker.app = createApp(SpotIconStack, this.markerProps[oMarker.subtype]);
|
oMarker.app = createApp(AppIconStack, this.markerProps[oMarker.subtype]);
|
||||||
oMarker.app.mount($Marker);
|
oMarker.app.mount($Marker);
|
||||||
|
|
||||||
oMarker.marker = new Marker({element: $Marker, anchor: 'bottom', opacityWhenCovered: oMarker.opacityWhenCovered ?? 0})
|
oMarker.marker = new Marker({element: $Marker, anchor: 'bottom', opacityWhenCovered: oMarker.opacityWhenCovered ?? 0})
|
||||||
@@ -683,7 +683,7 @@ export default {
|
|||||||
<div id="space"></div>
|
<div id="space"></div>
|
||||||
<div id="submap">
|
<div id="submap">
|
||||||
<div class="loader">
|
<div class="loader">
|
||||||
<SpotIcon :icon="'map'" :classes="'flicker'" width="fixed" />
|
<AppIcon :icon="'map'" :classes="'flicker'" width="fixed" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="map"></div>
|
<div id="map"></div>
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import SpotButton from '@components/spotButton';
|
import AppButton from '@components/AppButton';
|
||||||
import SpotIcon from '@components/spotIcon';
|
import AppIcon from '@components/AppIcon';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
SpotButton,
|
AppButton,
|
||||||
SpotIcon
|
AppIcon
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -99,7 +99,7 @@ export default {
|
|||||||
<input type="email" name="email" id="email" :placeholder="lang.get('account.email_placeholder')" v-model="user.email" :disabled="loginLoading || loggedIn || passwordMode" @keyup.enter="manageLogin" />
|
<input type="email" name="email" id="email" :placeholder="lang.get('account.email_placeholder')" v-model="user.email" :disabled="loginLoading || loggedIn || passwordMode" @keyup.enter="manageLogin" />
|
||||||
<input v-if="passwordMode" type="password" name="password" id="password" :placeholder="lang.get('account.password')" v-model="password" :disabled="loginLoading" :autocomplete="settingPassword?'new-password':'current-password'" @keyup.enter="manageLogin" />
|
<input v-if="passwordMode" type="password" name="password" id="password" :placeholder="lang.get('account.password')" v-model="password" :disabled="loginLoading" :autocomplete="settingPassword?'new-password':'current-password'" @keyup.enter="manageLogin" />
|
||||||
<input v-if="settingPassword" type="password" name="password_confirmation" id="password-confirmation" :placeholder="lang.get('account.confirm_password')" v-model="passwordConfirmation" :disabled="loginLoading" autocomplete="new-password" @keyup.enter="manageLogin" />
|
<input v-if="settingPassword" type="password" name="password_confirmation" id="password-confirmation" :placeholder="lang.get('account.confirm_password')" v-model="passwordConfirmation" :disabled="loginLoading" autocomplete="new-password" @keyup.enter="manageLogin" />
|
||||||
<SpotButton :classes="buttonClasses" :title="lang.get('account.'+action)" :icon="action" @click="manageLogin" />
|
<AppButton :classes="buttonClasses" :title="lang.get('account.'+action)" :icon="action" @click="manageLogin" />
|
||||||
</div>
|
</div>
|
||||||
<div class="sub-section newsletter radio" v-if="loggedIn">
|
<div class="sub-section newsletter radio" v-if="loggedIn">
|
||||||
<input type="checkbox" id="account-newsletter" v-model="user.subscribed" :true-value="1" :false-value="0" :disabled="newsletterLoading" @change="manageSubscription" />
|
<input type="checkbox" id="account-newsletter" v-model="user.subscribed" :true-value="1" :false-value="0" :disabled="newsletterLoading" @change="manageSubscription" />
|
||||||
@@ -107,7 +107,7 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
<div v-if="feedbacks.length" class="sub-section feedback">
|
<div v-if="feedbacks.length" class="sub-section feedback">
|
||||||
<p v-for="feedback in feedbacks" :key="feedback.type + '-' + feedback.msg" :class="feedback.type">
|
<p v-for="feedback in feedbacks" :key="feedback.type + '-' + feedback.msg" :class="feedback.type">
|
||||||
<SpotIcon :icon="feedback.type" :text="feedback.msg" />
|
<AppIcon :icon="feedback.type" :text="feedback.msg" />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
<script>
|
<script>
|
||||||
import Simplebar from 'simplebar-vue';
|
import Simplebar from 'simplebar-vue';
|
||||||
|
|
||||||
import SpotIcon from '@components/spotIcon';
|
import AppIcon from '@components/AppIcon';
|
||||||
import ProjectPost from '@components/projectPost';
|
import ProjectPost from '@components/ProjectPost';
|
||||||
import { faHistory, faThumbTackSlash } from '@fortawesome/free-solid-svg-icons';
|
import { faHistory, faThumbTackSlash } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
SpotIcon,
|
AppIcon,
|
||||||
ProjectPost,
|
ProjectPost,
|
||||||
Simplebar
|
Simplebar
|
||||||
},
|
},
|
||||||
@@ -230,7 +230,7 @@ export default {
|
|||||||
</Simplebar>
|
</Simplebar>
|
||||||
<div v-if="project" :class="'panel-control panel-control-'+(isMobile()?'bottom':'top')" @click="toggle">
|
<div v-if="project" :class="'panel-control panel-control-'+(isMobile()?'bottom':'top')" @click="toggle">
|
||||||
<div class="panel-control-elem panel-control-icon">
|
<div class="panel-control-elem panel-control-icon">
|
||||||
<SpotIcon :icon="isOpen?'next':'post'" />
|
<AppIcon :icon="isOpen?'next':'post'" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import spotIcon from '@components/spotIcon';
|
import appIcon from '@components/AppIcon';
|
||||||
import projectRelTime from '@components/projectRelTime';
|
import projectRelTime from '@components/ProjectRelTime';
|
||||||
import projectMapLink from '@components/projectMapLink';
|
import projectMapLink from '@components/ProjectMapLink';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
spotIcon,
|
appIcon,
|
||||||
projectRelTime,
|
projectRelTime,
|
||||||
projectMapLink
|
projectMapLink
|
||||||
},
|
},
|
||||||
@@ -54,20 +54,20 @@ export default {
|
|||||||
:title="lang.get((options.subtype == 'video')?'media.click_watch':'media.click_zoom')"
|
:title="lang.get((options.subtype == 'video')?'media.click_watch':'media.click_zoom')"
|
||||||
class="clickable"
|
class="clickable"
|
||||||
/>
|
/>
|
||||||
<span class="drill-icon"><spotIcon :icon="'drill-'+options.subtype" /></span>
|
<span class="drill-icon"><appIcon :icon="'drill-'+options.subtype" /></span>
|
||||||
<div v-if="options.comment && type == 'post'" class="comment">
|
<div v-if="options.comment && type == 'post'" class="comment">
|
||||||
<p>
|
<p>
|
||||||
<spotIcon icon="post" :text="options.comment" size="lg" />
|
<appIcon icon="post" :text="options.comment" size="lg" />
|
||||||
</p>
|
</p>
|
||||||
<p v-if="!isMobile() && options.latitude && options.longitude">
|
<p v-if="!isMobile() && options.latitude && options.longitude">
|
||||||
<spotIcon icon="coords" margin="right" size="lg" />
|
<appIcon icon="coords" margin="right" size="lg" />
|
||||||
<projectMapLink :options="options" />
|
<projectMapLink :options="options" />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div style="display:none">
|
<div style="display:none">
|
||||||
<span v-if="options.comment" ref="comment" class="lb-caption-line comment desktop">
|
<span v-if="options.comment" ref="comment" class="lb-caption-line comment desktop">
|
||||||
<spotIcon icon="post" width="fixed" size="lg" text-classes="comment-text" :text="options.comment" />
|
<appIcon icon="post" width="fixed" size="lg" text-classes="comment-text" :text="options.comment" />
|
||||||
</span>
|
</span>
|
||||||
<span ref="postedon" class="lb-caption-line">
|
<span ref="postedon" class="lb-caption-line">
|
||||||
<projectRelTime
|
<projectRelTime
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
<script>
|
<script>
|
||||||
import projectMapLink from '@components/projectMapLink';
|
import projectMapLink from '@components/ProjectMapLink';
|
||||||
import spotIcon from '@components/spotIcon';
|
import appIcon from '@components/AppIcon';
|
||||||
import projectRelTime from '@components/projectRelTime';
|
import projectRelTime from '@components/ProjectRelTime';
|
||||||
import projectMediaLink from '@components/projectMediaLink';
|
import projectMediaLink from '@components/ProjectMediaLink';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
spotIcon,
|
appIcon,
|
||||||
projectMapLink,
|
projectMapLink,
|
||||||
projectMediaLink,
|
projectMediaLink,
|
||||||
projectRelTime
|
projectRelTime
|
||||||
@@ -55,7 +55,7 @@ export default {
|
|||||||
<div :class="options.type+' '+options.subtype">
|
<div :class="options.type+' '+options.subtype">
|
||||||
<div class="header" v-if="options.type == 'track' || options.type == 'project'">
|
<div class="header" v-if="options.type == 'track' || options.type == 'project'">
|
||||||
<h1>
|
<h1>
|
||||||
<spotIcon v-if="options.type == 'project'" :icon="options.subtype" :classes="'track-'+options.subtype" size="lg" :text="this.options.name" width="auto" />
|
<appIcon v-if="options.type == 'project'" :icon="options.subtype" :classes="'track-'+options.subtype" size="lg" :text="this.options.name" width="auto" />
|
||||||
<span v-else class="track" :title="lang.get('track.'+options.subtype)">
|
<span v-else class="track" :title="lang.get('track.'+options.subtype)">
|
||||||
<span class="line" :style="'background-color:'+hikes.colors[options.subtype]+';'"></span>
|
<span class="line" :style="'background-color:'+hikes.colors[options.subtype]+';'"></span>
|
||||||
<span class="desc">{{ this.options.name }}</span>
|
<span class="desc">{{ this.options.name }}</span>
|
||||||
@@ -66,37 +66,37 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
<div v-if="options.type=='track'">
|
<div v-if="options.type=='track'">
|
||||||
<div v-if="options.leg" class="section destination">
|
<div v-if="options.leg" class="section destination">
|
||||||
<spotIcon :title="lang.get('stats.from')" icon="start" width="fixed" size="lg" :text="options.leg.from" />
|
<appIcon :title="lang.get('stats.from')" icon="start" width="fixed" size="lg" :text="options.leg.from" />
|
||||||
<spotIcon :title="lang.get('stats.to')" icon="start" transform="rotate-180" width="fixed" size="lg" :text="options.leg.to" />
|
<appIcon :title="lang.get('stats.to')" icon="start" transform="rotate-180" width="fixed" size="lg" :text="options.leg.to" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="options.leg" class="separator"></div>
|
<div v-if="options.leg" class="separator"></div>
|
||||||
<div v-if="options.subtype!='hitchhiking'" class="section track-stats">
|
<div v-if="options.subtype!='hitchhiking'" class="section track-stats">
|
||||||
<spotIcon :title="lang.get('stats.distance')" icon="distance" width="fixed" size="lg" :text="options.distance+'km'" />
|
<appIcon :title="lang.get('stats.distance')" icon="distance" width="fixed" size="lg" :text="options.distance+'km'" />
|
||||||
<spotIcon :title="lang.get('stats.duration')" icon="time" width="fixed" size="lg" :text="options.duration" />
|
<appIcon :title="lang.get('stats.duration')" icon="time" width="fixed" size="lg" :text="options.duration" />
|
||||||
<spotIcon :title="lang.get('stats.elevation_gain')" icon="elev-gain" width="fixed" size="lg" :text="options.elev_gain+'m'" />
|
<appIcon :title="lang.get('stats.elevation_gain')" icon="elev-gain" width="fixed" size="lg" :text="options.elev_gain+'m'" />
|
||||||
<spotIcon :title="lang.get('stats.elevation_loss')" icon="elev-drop" width="fixed" size="lg" :text="options.elev_drop+'m'" />
|
<appIcon :title="lang.get('stats.elevation_loss')" icon="elev-drop" width="fixed" size="lg" :text="options.elev_drop+'m'" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="options.type=='project'" class="section year">{{ activeTimeInterval }}</div>
|
<div v-else-if="options.type=='project'" class="section year">{{ activeTimeInterval }}</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div class="section" v-if="options.comment">
|
<div class="section" v-if="options.comment">
|
||||||
<spotIcon icon="post" width="fixed" size="lg" :text="options.comment" />
|
<appIcon icon="post" width="fixed" size="lg" :text="options.comment" />
|
||||||
</div>
|
</div>
|
||||||
<div class="section time">
|
<div class="section time">
|
||||||
<projectRelTime :icon="timeinfo.icon" :localTime="localTime" :siteTime="timeinfo.site_time" :offset="timeinfo.offset" />
|
<projectRelTime :icon="timeinfo.icon" :localTime="localTime" :siteTime="timeinfo.site_time" :offset="timeinfo.offset" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!isMobile()" class="section coordinates">
|
<div v-if="!isMobile()" class="section coordinates">
|
||||||
<spotIcon icon="coords" width="fixed" size="lg" margin="right" />
|
<appIcon icon="coords" width="fixed" size="lg" margin="right" />
|
||||||
<projectMapLink :options="options" />
|
<projectMapLink :options="options" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="options.altitude" class="section altitude">
|
<div v-if="options.altitude" class="section altitude">
|
||||||
<spotIcon icon="altitude" width="fixed" size="lg" :text="options.altitude+'m'" />
|
<appIcon icon="altitude" width="fixed" size="lg" :text="options.altitude+'m'" />
|
||||||
</div>
|
</div>
|
||||||
<div class="section weather" v-if="options.weather_icon && options.weather_icon!='unknown'" :title="options.weather_cond==''?'':lang.get('weather.'+options.weather_icon)">
|
<div class="section weather" v-if="options.weather_icon && options.weather_icon!='unknown'" :title="options.weather_cond==''?'':lang.get('weather.'+options.weather_icon)">
|
||||||
<spotIcon :icon="options.weather_icon" width="fixed" size="lg" :text="options.weather_temp+'°C'" />
|
<appIcon :icon="options.weather_icon" width="fixed" size="lg" :text="options.weather_temp+'°C'" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="options.medias" class="section medias">
|
<div v-if="options.medias" class="section medias">
|
||||||
<spotIcon v-if="options.type=='message'" icon="media" width="fixed" size="lg" :text="lang.get('media.nearby')" />
|
<appIcon v-if="options.type=='message'" icon="media" width="fixed" size="lg" :text="lang.get('media.nearby')" />
|
||||||
<div class="medias-list">
|
<div class="medias-list">
|
||||||
<projectMediaLink v-for="media in options?.medias" :options="media" :type="'marker'" />
|
<projectMediaLink v-for="media in options?.medias" :options="media" :type="'marker'" />
|
||||||
</div>
|
</div>
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
<script>
|
<script>
|
||||||
import spotIcon from '@components/spotIcon';
|
import appIcon from '@components/AppIcon';
|
||||||
import spotIconStack from '@components/spotIconStack';
|
import appIconStack from '@components/AppIconStack';
|
||||||
import spotButton from '@components/spotButton';
|
import appButton from '@components/AppButton';
|
||||||
import projectMediaLink from '@components/projectMediaLink';
|
import projectMediaLink from '@components/ProjectMediaLink';
|
||||||
import projectMapLink from '@components/projectMapLink';
|
import projectMapLink from '@components/ProjectMapLink';
|
||||||
import projectRelTime from '@components/projectRelTime';
|
import projectRelTime from '@components/ProjectRelTime';
|
||||||
import { LngLat } from 'maplibre-gl';
|
import { LngLat } from 'maplibre-gl';
|
||||||
import { copyTextToClipboard } from '@scripts/common';
|
import { copyTextToClipboard } from '@scripts/common';
|
||||||
|
|
||||||
@@ -12,9 +12,9 @@
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
spotIcon,
|
appIcon,
|
||||||
spotIconStack,
|
appIconStack,
|
||||||
spotButton,
|
appButton,
|
||||||
projectMediaLink,
|
projectMediaLink,
|
||||||
projectMapLink,
|
projectMapLink,
|
||||||
projectRelTime
|
projectRelTime
|
||||||
@@ -175,9 +175,9 @@
|
|||||||
<div :class="postClass" :id="postId">
|
<div :class="postClass" :id="postId">
|
||||||
<div class="header" v-if="!options.headerless">
|
<div class="header" v-if="!options.headerless">
|
||||||
<div class="index">
|
<div class="index">
|
||||||
<spotIcon :icon="subType" :text="displayedId" width="auto" />
|
<appIcon :icon="subType" :text="displayedId" width="auto" />
|
||||||
<a v-if="anchorVisible" class="link desktop" @click="copyAnchor" ref="anchor" :href="anchorLink" :title="anchorTitle">
|
<a v-if="anchorVisible" class="link desktop" @click="copyAnchor" ref="anchor" :href="anchorLink" :title="anchorTitle">
|
||||||
<spotIcon :icon="anchorIcon" />
|
<appIcon :icon="anchorIcon" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="time" @mouseleave="mouseOverHeader = false" @mouseover="mouseOverHeader = true" :title="timeDiff?lang.get('time.local', absTimeLocal):''">
|
<div class="time" @mouseleave="mouseOverHeader = false" @mouseover="mouseOverHeader = true" :title="timeDiff?lang.get('time.local', absTimeLocal):''">
|
||||||
@@ -191,13 +191,13 @@
|
|||||||
<div v-if="options.type == 'message'" class="body-box">
|
<div v-if="options.type == 'message'" class="body-box">
|
||||||
<div class="drill" @click.prevent="panMapToMarker" @pointerenter="onMouseEnter" @pointerleave="onMouseLeave">
|
<div class="drill" @click.prevent="panMapToMarker" @pointerenter="onMouseEnter" @pointerleave="onMouseLeave">
|
||||||
<span v-if="options.weather_icon && options.weather_icon!='unknown'" class="weather clickable" :title="lang.get('weather.'+options.weather_icon)">
|
<span v-if="options.weather_icon && options.weather_icon!='unknown'" class="weather clickable" :title="lang.get('weather.'+options.weather_icon)">
|
||||||
<spotIcon :icon="options.weather_icon" :text="Math.round(options.weather_temp)+'°C'" text-classes="temperature" />
|
<appIcon :icon="options.weather_icon" :text="Math.round(options.weather_temp)+'°C'" text-classes="temperature" />
|
||||||
</span>
|
</span>
|
||||||
<img class="staticmap clickable" :title="lang.get('media.click_zoom')" :src="options.static_img_url" />
|
<img class="staticmap clickable" :title="lang.get('media.click_zoom')" :src="options.static_img_url" />
|
||||||
<spotIconStack mainClasses="message drill-icon" :iconMain="drillMainIcon" :iconSub="drillSubIcon" icon-sub-transform="rotate-270" />
|
<appIconStack mainClasses="message drill-icon" :iconMain="drillMainIcon" :iconSub="drillSubIcon" icon-sub-transform="rotate-270" />
|
||||||
<div class="comment" @click.stop>
|
<div class="comment" @click.stop>
|
||||||
<p v-if="!isMobile()">
|
<p v-if="!isMobile()">
|
||||||
<spotIcon :icon="'coords'" margin="right" size="lg" />
|
<appIcon :icon="'coords'" margin="right" size="lg" />
|
||||||
<projectMapLink :options="options" />
|
<projectMapLink :options="options" />
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
@@ -221,15 +221,15 @@
|
|||||||
<textarea ref="post" name="post" :placeholder="lang.get('post.message')" class="autoExpand" rows="1" v-model="postMessage"></textarea>
|
<textarea ref="post" name="post" :placeholder="lang.get('post.message')" class="autoExpand" rows="1" v-model="postMessage"></textarea>
|
||||||
<div class="poster-actions">
|
<div class="poster-actions">
|
||||||
<input type="text" name="name" :placeholder="lang.get('post.name')" v-model="user.name" />
|
<input type="text" name="name" :placeholder="lang.get('post.name')" v-model="user.name" />
|
||||||
<spotButton name="submit" :aria-label="lang.get('action.send')" :title="lang.get('action.send')" :icon="'send'" @click="send()" :iconClasses="sending?'flicker':''" />
|
<appButton name="submit" :aria-label="lang.get('action.send')" :title="lang.get('action.send')" :icon="'send'" @click="send()" :iconClasses="sending?'flicker':''" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="options.type == 'archived'">
|
<div v-else-if="options.type == 'archived'">
|
||||||
<p><spotIcon :icon="'success'" /></p>
|
<p><appIcon :icon="'success'" /></p>
|
||||||
<p>{{ lang.get('project.modes.histo') }}</p>
|
<p>{{ lang.get('project.modes.histo') }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="options.type == 'loading'">
|
<div v-else-if="options.type == 'loading'">
|
||||||
<p class="flicker"><spotIcon :icon="'post'" /></p>
|
<p class="flicker"><appIcon :icon="'post'" /></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import spotIcon from '@components/spotIcon';
|
import appIcon from '@components/AppIcon';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
spotIcon
|
appIcon
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
localTime: String,
|
localTime: String,
|
||||||
@@ -31,6 +31,6 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<spotIcon v-if="icon" :icon="icon" :title="title" :text="localTime" width="fixed" size="lg" />
|
<appIcon v-if="icon" :icon="icon" :title="title" :text="localTime" width="fixed" size="lg" />
|
||||||
<span v-else :class="classes" :title="title">{{ localTime }}</span>
|
<span v-else :class="classes" :title="title">{{ localTime }}</span>
|
||||||
</template>
|
</template>
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
<script>
|
<script>
|
||||||
import Simplebar from 'simplebar-vue';
|
import Simplebar from 'simplebar-vue';
|
||||||
|
|
||||||
import SpotIcon from '@components/spotIcon';
|
import AppIcon from '@components/AppIcon';
|
||||||
import ProjectAccount from '@components/projectAccount';
|
import ProjectAccount from '@components/ProjectAccount';
|
||||||
import logoIconUrl from '@images/icons/favicon.svg';
|
import logoIconUrl from '@images/icons/favicon.svg';
|
||||||
import logoTitleUrl from '@images/logo_title.svg';
|
import logoTitleUrl from '@images/logo_title.svg';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
SpotIcon,
|
AppIcon,
|
||||||
ProjectAccount,
|
ProjectAccount,
|
||||||
Simplebar
|
Simplebar
|
||||||
},
|
},
|
||||||
@@ -93,27 +93,27 @@ export default {
|
|||||||
<img :src="logoIconUrl" class="logo-icon clickable" :title="lang.get('project.overview')" @click="hash.items = []" />
|
<img :src="logoIconUrl" class="logo-icon clickable" :title="lang.get('project.overview')" @click="hash.items = []" />
|
||||||
<img :src="logoTitleUrl" class="logo-title" :alt="consts.title" />
|
<img :src="logoTitleUrl" class="logo-title" :alt="consts.title" />
|
||||||
<div class="last_update" v-if="project?.mode == consts.modes.blog && lastUpdate.unix_time > 0" :title="lastUpdate.formatted_time">
|
<div class="last_update" v-if="project?.mode == consts.modes.blog && lastUpdate.unix_time > 0" :title="lastUpdate.formatted_time">
|
||||||
<SpotIcon icon="find-me-spot" :text="lang.get('feed.last_update')+' '+lastUpdate.relative_time" />
|
<AppIcon icon="find-me-spot" :text="lang.get('feed.last_update')+' '+lastUpdate.relative_time" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settings-sections">
|
<div class="settings-sections">
|
||||||
<Simplebar id="settings-sections-scrollbox">
|
<Simplebar id="settings-sections-scrollbox">
|
||||||
<div class="settings-section settings-box">
|
<div class="settings-section settings-box">
|
||||||
<h1><SpotIcon :icon="'project'" width="fixed" :text="lang.get('project.hikes')" /></h1>
|
<h1><AppIcon :icon="'project'" width="fixed" :text="lang.get('project.hikes')" /></h1>
|
||||||
<div class="settings-section-body">
|
<div class="settings-section-body">
|
||||||
<div class="radio" v-for="project in projects" :key="'project-'+project.id">
|
<div class="radio" v-for="project in projects" :key="'project-'+project.id">
|
||||||
<input type="radio" :id="'project-'+project.id" :value="project.codename" v-model="projectCodeNameModel" :disabled="mapInitializing" />
|
<input type="radio" :id="'project-'+project.id" :value="project.codename" v-model="projectCodeNameModel" :disabled="mapInitializing" />
|
||||||
<label :for="'project-'+project.id">
|
<label :for="'project-'+project.id">
|
||||||
<span>{{ project.name }}</span>
|
<span>{{ project.name }}</span>
|
||||||
<a v-if="!isMobile() && project.gpxfilepath" class="download" :href="project.gpxfilepath" :download="project.codename + '.gpx'" :title="lang.get('track.download')" @click.stop="()=>{}">
|
<a v-if="!isMobile() && project.gpxfilepath" class="download" :href="project.gpxfilepath" :download="project.codename + '.gpx'" :title="lang.get('track.download')" @click.stop="()=>{}">
|
||||||
<SpotIcon :icon="'download'" margin="left" />
|
<AppIcon :icon="'download'" margin="left" />
|
||||||
</a>
|
</a>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settings-section settings-box">
|
<div class="settings-section settings-box">
|
||||||
<h1><SpotIcon :icon="'map'" width="fixed" :text="lang.get('map.title')" /></h1>
|
<h1><AppIcon :icon="'map'" width="fixed" :text="lang.get('map.title')" /></h1>
|
||||||
<div class="settings-section-body">
|
<div class="settings-section-body">
|
||||||
<div class="radio" v-for="bm in baseMaps" :key="'map-'+bm.id_map">
|
<div class="radio" v-for="bm in baseMaps" :key="'map-'+bm.id_map">
|
||||||
<input type="radio" :id="'map-'+bm.id_map" :value="bm.codename" v-model="baseMapModel" :disabled="mapInitializing" />
|
<input type="radio" :id="'map-'+bm.id_map" :value="bm.codename" v-model="baseMapModel" :disabled="mapInitializing" />
|
||||||
@@ -126,30 +126,30 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settings-section settings-box account">
|
<div class="settings-section settings-box account">
|
||||||
<h1><SpotIcon :icon="'account'" width="fixed" :text="lang.get('account.title')" /></h1>
|
<h1><AppIcon :icon="'account'" width="fixed" :text="lang.get('account.title')" /></h1>
|
||||||
<div class="settings-section-body">
|
<div class="settings-section-body">
|
||||||
<ProjectAccount />
|
<ProjectAccount />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settings-section settings-box admin" v-if="user.hasClearance(consts.clearances.admin)">
|
<div class="settings-section settings-box admin" v-if="user.hasClearance(consts.clearances.admin)">
|
||||||
<h1><SpotIcon :icon="'admin'" width="fixed" :text="lang.get('admin.title')" /></h1>
|
<h1><AppIcon :icon="'admin'" width="fixed" :text="lang.get('admin.title')" /></h1>
|
||||||
<div class="settings-section-body admin-actions">
|
<div class="settings-section-body admin-actions">
|
||||||
<a class="button" href="#admin"><SpotIcon :icon="'config'" :text="lang.get('admin.config')" /></a>
|
<a class="button" href="#admin"><AppIcon :icon="'config'" :text="lang.get('admin.config')" /></a>
|
||||||
<a class="button" href="#upload"><SpotIcon :icon="'upload'" :text="lang.get('admin.upload')" /></a>
|
<a class="button" href="#upload"><AppIcon :icon="'upload'" :text="lang.get('admin.upload')" /></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Simplebar>
|
</Simplebar>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!isMobile()" class="settings-footer">
|
<div v-if="!isMobile()" class="settings-footer">
|
||||||
<a href="https://git.lutran.fr/franzz/spot" :title="lang.get('credits.git')" target="_blank" rel="noopener">
|
<a href="https://git.lutran.fr/franzz/livetrail" :title="lang.get('credits.git')" target="_blank" rel="noopener">
|
||||||
<SpotIcon :icon="'credits'" width="auto" :text="lang.get('credits.project', consts.title)" />
|
<AppIcon :icon="'credits'" width="auto" :text="lang.get('credits.project', consts.title)" />
|
||||||
</a>
|
</a>
|
||||||
<span> {{ lang.get('credits.license') }}</span>
|
<span> {{ lang.get('credits.license') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="'panel-control panel-control-'+(isMobile()?'bottom':'top')">
|
<div :class="'panel-control panel-control-'+(isMobile()?'bottom':'top')">
|
||||||
<div class="panel-control-elem panel-control-icon" @click="toggle">
|
<div class="panel-control-elem panel-control-icon" @click="toggle">
|
||||||
<SpotIcon :icon="isOpen?'prev':'menu'" />
|
<AppIcon :icon="isOpen?'prev':'menu'" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="project?.id && !isMobile()" id="legend" class="panel-control panel-control-bottom">
|
<div v-if="project?.id && !isMobile()" id="legend" class="panel-control panel-control-bottom">
|
||||||
@@ -4,12 +4,12 @@ import Uppy from '@uppy/core';
|
|||||||
import XHRUpload from '@uppy/xhr-upload';
|
import XHRUpload from '@uppy/xhr-upload';
|
||||||
import '@uppy/core/css/style.min.css';
|
import '@uppy/core/css/style.min.css';
|
||||||
|
|
||||||
import SpotIcon from '@components/spotIcon';
|
import AppIcon from '@components/AppIcon';
|
||||||
import SpotButton from '@components/spotButton';
|
import AppButton from '@components/AppButton';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'upload',
|
name: 'upload',
|
||||||
components: { SpotButton, SpotIcon },
|
components: { AppButton, AppIcon },
|
||||||
inject: ['api', 'lang', 'projects', 'consts', 'user', 'getPrevAnchor'],
|
inject: ['api', 'lang', 'projects', 'consts', 'user', 'getPrevAnchor'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -120,7 +120,7 @@ export default {
|
|||||||
<template>
|
<template>
|
||||||
<div id="upload">
|
<div id="upload">
|
||||||
<div class="section header">
|
<div class="section header">
|
||||||
<a name="back" class="button" :href="getPrevAnchor()"><SpotIcon :icon="'back'" :text="lang.get('action.back')" /></a>
|
<a name="back" class="button" :href="getPrevAnchor()"><AppIcon :icon="'back'" :text="lang.get('action.back')" /></a>
|
||||||
<h1>{{ this.project.name }}</h1>
|
<h1>{{ this.project.name }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" v-if="project.editable">
|
<div class="section" v-if="project.editable">
|
||||||
@@ -136,12 +136,12 @@ export default {
|
|||||||
<div class="form">
|
<div class="form">
|
||||||
<input class="content" name="content" type="text" v-model="file.content" />
|
<input class="content" name="content" type="text" v-model="file.content" />
|
||||||
<input class="id" name="id" type="hidden" :value="file.id" />
|
<input class="id" name="id" type="hidden" :value="file.id" />
|
||||||
<SpotButton :classes="'save'" :icon="'save'" :text="lang.get('action.save')" @click="addComment(file)" />
|
<AppButton :classes="'save'" :icon="'save'" :text="lang.get('action.save')" @click="addComment(file)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="section location" v-if="project.editable">
|
<div class="section location" v-if="project.editable">
|
||||||
<h2>{{ lang.get('upload.position.title') }}</h2>
|
<h2>{{ lang.get('upload.position.title') }}</h2>
|
||||||
<SpotButton :icon="'marker'" :text="lang.get('upload.position.new')" @click="addPosition()" />
|
<AppButton :icon="'marker'" :text="lang.get('upload.position.new')" @click="addPosition()" />
|
||||||
</div>
|
</div>
|
||||||
<div class="section logs" v-if="logs.length > 0">
|
<div class="section logs" v-if="logs.length > 0">
|
||||||
<p class="log" v-for="log in logs">{{ log }}.</p>
|
<p class="log" v-for="log in logs">{{ log }}.</p>
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
transform="translate(-518.42466,-161.70322)">
|
transform="translate(-518.42466,-161.70322)">
|
||||||
<g
|
<g
|
||||||
id="g1"
|
id="g1"
|
||||||
inkscape:label="Spot"
|
inkscape:label="Livetrail"
|
||||||
transform="translate(9.9387949)">
|
transform="translate(9.9387949)">
|
||||||
<path
|
<path
|
||||||
d="m 512,258 c 0,-50.81 41.414,-92 92.5,-92 51.086,0 92.5,41.19 92.5,92 0,50.81 -41.414,92 -92.5,92 -51.086,0 -92.5,-41.19 -92.5,-92 z"
|
d="m 512,258 c 0,-50.81 41.414,-92 92.5,-92 51.086,0 92.5,41.19 92.5,92 0,50.81 -41.414,92 -92.5,92 -51.086,0 -92.5,-41.19 -92.5,-92 z"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -68,7 +68,7 @@
|
|||||||
</g>
|
</g>
|
||||||
<g
|
<g
|
||||||
id="g1"
|
id="g1"
|
||||||
inkscape:label="Spot"
|
inkscape:label="Livetrail"
|
||||||
transform="translate(9.9387949)">
|
transform="translate(9.9387949)">
|
||||||
<path
|
<path
|
||||||
d="m 512,258 c 0,-50.81 41.414,-92 92.5,-92 51.086,0 92.5,41.19 92.5,92 0,50.81 -41.414,92 -92.5,92 -51.086,0 -92.5,-41.19 -92.5,-92 z"
|
d="m 512,258 c 0,-50.81 41.414,-92 92.5,-92 51.086,0 92.5,41.19 92.5,92 0,50.81 -41.414,92 -92.5,92 -51.086,0 -92.5,-41.19 -92.5,-92 z"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
@@ -129,7 +129,7 @@
|
|||||||
</g>
|
</g>
|
||||||
<g
|
<g
|
||||||
id="g1"
|
id="g1"
|
||||||
inkscape:label="Spot"
|
inkscape:label="Livetrail"
|
||||||
transform="translate(9.9387949)">
|
transform="translate(9.9387949)">
|
||||||
<path
|
<path
|
||||||
d="m 512,258 c 0,-50.81 41.414,-92 92.5,-92 51.086,0 92.5,41.19 92.5,92 0,50.81 -41.414,92 -92.5,92 -51.086,0 -92.5,-41.19 -92.5,-92 z"
|
d="m 512,258 c 0,-50.81 41.414,-92 92.5,-92 51.086,0 92.5,41.19 92.5,92 0,50.81 -41.414,92 -92.5,92 -51.086,0 -92.5,-41.19 -92.5,-92 z"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@@ -111,7 +111,7 @@
|
|||||||
</g>
|
</g>
|
||||||
<g
|
<g
|
||||||
id="g1"
|
id="g1"
|
||||||
inkscape:label="Spot"
|
inkscape:label="Livetrail"
|
||||||
transform="matrix(1.9469599,0,0,1.9469599,-486.68371,-164.30074)">
|
transform="matrix(1.9469599,0,0,1.9469599,-486.68371,-164.30074)">
|
||||||
<path
|
<path
|
||||||
d="m 512,258 c 0,-50.81 41.414,-92 92.5,-92 51.086,0 92.5,41.19 92.5,92 0,50.81 -41.414,92 -92.5,92 -51.086,0 -92.5,-41.19 -92.5,-92 z"
|
d="m 512,258 c 0,-50.81 41.414,-92 92.5,-92 51.086,0 92.5,41.19 92.5,92 0,50.81 -41.414,92 -92.5,92 -51.086,0 -92.5,-41.19 -92.5,-92 z"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@@ -64,7 +64,7 @@ export default class Lightbox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderIcon(name, sClass=null) {
|
renderIcon(name, sClass=null) {
|
||||||
return icon(getIcon(name), {classes: ['spot-icon', name, sClass]}).html;
|
return icon(getIcon(name), {classes: ['app-icon', name, sClass]}).html;
|
||||||
}
|
}
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ body.lb-disable-scrolling {
|
|||||||
color: color.$over-img-hover;
|
color: color.$over-img-hover;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spot-icon {
|
.app-icon {
|
||||||
vertical-align: inherit;
|
vertical-align: inherit;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ $thumbnail-max-size: 60px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.maplibregl-marker {
|
.maplibregl-marker {
|
||||||
.spot-icon-stack:is(.media, .message, .project) {
|
.app-icon-stack:is(.media, .message, .project) {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
transform-origin: center bottom;
|
transform-origin: center bottom;
|
||||||
transition: transform var.$trans-quick;
|
transition: transform var.$trans-quick;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover .spot-icon-stack:is(.media, .message, .project) {
|
&:hover .app-icon-stack:is(.media, .message, .project) {
|
||||||
transform: scale(var.$zoom-scale);
|
transform: scale(var.$zoom-scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,7 +134,7 @@
|
|||||||
p {
|
p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
.spot-icon {
|
.app-icon {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
margin: var.$elem-spacing 0;
|
margin: var.$elem-spacing 0;
|
||||||
@@ -170,10 +170,10 @@
|
|||||||
top: var.$block-spacing;
|
top: var.$block-spacing;
|
||||||
right: var.$block-spacing;
|
right: var.$block-spacing;
|
||||||
|
|
||||||
.spot-icon-with-text {
|
.app-icon-with-text {
|
||||||
gap: 0;
|
gap: 0;
|
||||||
|
|
||||||
.spot-icon {
|
.app-icon {
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
height: var.$block-spacing;
|
height: var.$block-spacing;
|
||||||
|
|||||||
@@ -147,14 +147,14 @@ $panel-actual-width: min($panel-width, #{$panel-width-max});
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
.spot-icon {
|
.app-icon {
|
||||||
color: color.$default;
|
color: color.$default;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
background-color: color.$default-inv-bg;
|
background-color: color.$default-inv-bg;
|
||||||
|
|
||||||
.spot-icon {
|
.app-icon {
|
||||||
color: color.$default-inv;
|
color: color.$default-inv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,7 +163,7 @@ $panel-actual-width: min($panel-width, #{$panel-width-max});
|
|||||||
&:hover {
|
&:hover {
|
||||||
background-color: color.$default-inv-bg;
|
background-color: color.$default-inv-bg;
|
||||||
|
|
||||||
.spot-icon {
|
.app-icon {
|
||||||
color: color.$default-inv;
|
color: color.$default-inv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,7 +127,7 @@
|
|||||||
background-color: color.$main;
|
background-color: color.$main;
|
||||||
color: color.$post-input-bg;
|
color: color.$post-input-bg;
|
||||||
|
|
||||||
.spot-icon {
|
.app-icon {
|
||||||
@extend .flicker;
|
@extend .flicker;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
transform: translate(-50%, -100%);
|
transform: translate(-50%, -100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.spot-icon {
|
.app-icon {
|
||||||
transition: color var.$trans-quick, text-shadow var.$trans-quick;
|
transition: color var.$trans-quick, text-shadow var.$trans-quick;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
|
|
||||||
/* Icon Stack */
|
/* Icon Stack */
|
||||||
|
|
||||||
.spot-icon-stack {
|
.app-icon-stack {
|
||||||
&:not(.drill-icon) {
|
&:not(.drill-icon) {
|
||||||
font-size: 2.5em;
|
font-size: 2.5em;
|
||||||
filter: drop-shadow(var.$elem-shadow);
|
filter: drop-shadow(var.$elem-shadow);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default defineConfig(({ mode }) => {
|
|||||||
base: './',
|
base: './',
|
||||||
publicDir: false,
|
publicDir: false,
|
||||||
plugins: [
|
plugins: [
|
||||||
spotPublicAssets(),
|
livetrailPublicAssets(),
|
||||||
vue()
|
vue()
|
||||||
],
|
],
|
||||||
build: {
|
build: {
|
||||||
@@ -62,9 +62,9 @@ export default defineConfig(({ mode }) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
function spotPublicAssets() {
|
function livetrailPublicAssets() {
|
||||||
return {
|
return {
|
||||||
name: 'spot-public-assets',
|
name: 'livetrail-public-assets',
|
||||||
apply: 'build',
|
apply: 'build',
|
||||||
buildStart() {
|
buildStart() {
|
||||||
cleanGeneratedAssets();
|
cleanGeneratedAssets();
|
||||||
|
|||||||