jolie beau et ajax
This commit is contained in:
parent
7475c3ce49
commit
42ec68178a
11 changed files with 242 additions and 76 deletions
1
.env
1
.env
|
|
@ -8,3 +8,4 @@ DB_PASSWORD=
|
||||||
|
|
||||||
IMG_PROJECT_PATH = uploads/projects/
|
IMG_PROJECT_PATH = uploads/projects/
|
||||||
IMG_USER_PATH = uploads/profiles/
|
IMG_USER_PATH = uploads/profiles/
|
||||||
|
HEHE=HAHA
|
||||||
|
|
@ -10,7 +10,12 @@ body {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
padding: 0.8rem 2rem;
|
padding: 0.8rem 2rem;
|
||||||
|
min-height: 64px;
|
||||||
|
max-height: 64px;
|
||||||
}
|
}
|
||||||
|
.navbar .navbar-collapse {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.navbar-brand {
|
.navbar-brand {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
|
|
@ -29,7 +34,13 @@ body {
|
||||||
margin: 0 0.2rem;
|
margin: 0 0.2rem;
|
||||||
transition: color 0.3s;
|
transition: color 0.3s;
|
||||||
}
|
}
|
||||||
|
.nav-avatar {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
.navbar-nav .nav-link:hover {
|
.navbar-nav .nav-link:hover {
|
||||||
color: #0d6efd;
|
color: #0d6efd;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
env
2
env
|
|
@ -1,7 +1,7 @@
|
||||||
# config BDD
|
# config BDD
|
||||||
|
|
||||||
DB_CONNECTION=mysql
|
DB_CONNECTION=mysql
|
||||||
DB_HOSTNAME=boulayoune.com
|
DB_HOSTNAME=localhost
|
||||||
DB_DATABASE=projet_folliow
|
DB_DATABASE=projet_folliow
|
||||||
DB_USERNAME=
|
DB_USERNAME=
|
||||||
DB_PASSWORD=
|
DB_PASSWORD=
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
|
|
||||||
$strRq = "SELECT project.*,
|
$strRq = "SELECT project.*,
|
||||||
CONCAT(user_firstname, ' ', user_name) AS 'project_creatorname',
|
user_pseudo AS 'project_creatorname',
|
||||||
user_image
|
user_image
|
||||||
FROM project
|
FROM project
|
||||||
INNER JOIN users ON user_id = project_user_id
|
INNER JOIN users ON user_id = project_user_id
|
||||||
|
|
|
||||||
112
views/_partial/apigeo.tpl
Normal file
112
views/_partial/apigeo.tpl
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
<!-- Script d'autocomplétion ville/département — API Géo (gouvernement français) -->
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
const input = document.getElementById('user_location');
|
||||||
|
const suggestions = document.getElementById('location-suggestions');
|
||||||
|
let debounceTimer = null;
|
||||||
|
|
||||||
|
// Ferme la liste si on clique ailleurs
|
||||||
|
document.addEventListener('click', function (e) {
|
||||||
|
if (!input.contains(e.target) && !suggestions.contains(e.target)) {
|
||||||
|
hideSuggestions();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
input.addEventListener('input', function () {
|
||||||
|
const query = this.value.trim();
|
||||||
|
|
||||||
|
clearTimeout(debounceTimer);
|
||||||
|
|
||||||
|
if (query.length < 2) {
|
||||||
|
hideSuggestions();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Délai de 300 ms pour éviter trop d'appels API
|
||||||
|
debounceTimer = setTimeout(function () {
|
||||||
|
fetchCities(query);
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Navigation clavier dans la liste
|
||||||
|
input.addEventListener('keydown', function (e) {
|
||||||
|
const items = suggestions.querySelectorAll('.list-group-item');
|
||||||
|
const active = suggestions.querySelector('.list-group-item.active');
|
||||||
|
let index = Array.from(items).indexOf(active);
|
||||||
|
|
||||||
|
if (e.key === 'ArrowDown') {
|
||||||
|
e.preventDefault();
|
||||||
|
if (index < items.length - 1) setActive(items, index + 1);
|
||||||
|
} else if (e.key === 'ArrowUp') {
|
||||||
|
e.preventDefault();
|
||||||
|
if (index > 0) setActive(items, index - 1);
|
||||||
|
} else if (e.key === 'Enter' && active) {
|
||||||
|
e.preventDefault();
|
||||||
|
selectItem(active.dataset.value);
|
||||||
|
} else if (e.key === 'Escape') {
|
||||||
|
hideSuggestions();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function fetchCities(query) {
|
||||||
|
// On cherche par nom de commune, on récupère aussi le département
|
||||||
|
const url = 'https://geo.api.gouv.fr/communes?nom=' + encodeURIComponent(query)
|
||||||
|
+ '&fields=nom,departement&boost=population&limit=8';
|
||||||
|
|
||||||
|
fetch(url)
|
||||||
|
.then(function (res) { return res.json(); })
|
||||||
|
.then(function (data) { renderSuggestions(data); })
|
||||||
|
.catch(function () { hideSuggestions(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSuggestions(cities) {
|
||||||
|
suggestions.innerHTML = '';
|
||||||
|
|
||||||
|
if (!cities || cities.length === 0) {
|
||||||
|
hideSuggestions();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cities.forEach(function (city) {
|
||||||
|
const dept = city.departement
|
||||||
|
? city.departement.nom + ' (' + city.departement.code + ')'
|
||||||
|
: '';
|
||||||
|
const label = city.nom + (dept ? ' — ' + dept : '');
|
||||||
|
// Valeur stockée : "Ville (Département)"
|
||||||
|
const value = city.nom + (city.departement ? ' (' + city.departement.nom + ')' : '');
|
||||||
|
|
||||||
|
const li = document.createElement('li');
|
||||||
|
li.className = 'list-group-item list-group-item-action py-2 px-3';
|
||||||
|
li.style.cursor = 'pointer';
|
||||||
|
li.dataset.value = value;
|
||||||
|
li.textContent = label;
|
||||||
|
|
||||||
|
li.addEventListener('mousedown', function (e) {
|
||||||
|
// mousedown avant blur pour éviter que la liste disparaisse avant le clic
|
||||||
|
e.preventDefault();
|
||||||
|
selectItem(value);
|
||||||
|
});
|
||||||
|
|
||||||
|
suggestions.appendChild(li);
|
||||||
|
});
|
||||||
|
|
||||||
|
suggestions.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectItem(value) {
|
||||||
|
input.value = value;
|
||||||
|
hideSuggestions();
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideSuggestions() {
|
||||||
|
suggestions.style.display = 'none';
|
||||||
|
suggestions.innerHTML = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function setActive(items, index) {
|
||||||
|
items.forEach(function (item) { item.classList.remove('active'); });
|
||||||
|
items[index].classList.add('active');
|
||||||
|
input.value = items[index].dataset.value;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
@ -5,29 +5,34 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="stylesheet" href="assests/css/style.css">
|
<link rel="stylesheet" href="assests/css/style.css">
|
||||||
<link rel="shortcut icon" href="assests/img/Group-49.ico" type="image/x-icon">
|
<link rel="shortcut icon" href="assests/img/Group-49.ico" type="image/x-icon">
|
||||||
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> -->
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
|
||||||
<script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous"></script>
|
<script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous"></script>
|
||||||
<title>Folliow{block name="title"}{/block}</title>
|
<title>Folliow{block name="title"}{/block}</title>
|
||||||
</head>
|
</head>
|
||||||
<body class="d-flex flex-column min-vh-100">
|
<body class="d-flex flex-column min-vh-100">
|
||||||
|
|
||||||
<nav class="navbar navbar-expand-lg navbar-light">
|
<nav class="navbar navbar-expand-lg navbar-light">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
|
||||||
|
<!-- Logo -->
|
||||||
<a class="navbar-brand d-flex align-items-center" href="index.php">
|
<a class="navbar-brand d-flex align-items-center" href="index.php">
|
||||||
<img src="assests/img/logo.png" alt="Logo" class="logo-image">
|
<img src="assests/img/logo.png" alt="Logo" class="logo-image">
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
<!-- Bouton hamburger mobile -->
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||||
|
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<!-- Liens de navigation -->
|
||||||
<div class="collapse navbar-collapse" id="navbarNav">
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
<ul class="navbar-nav me-auto">
|
|
||||||
|
|
||||||
|
<!-- Liens gauche -->
|
||||||
|
<ul class="navbar-nav me-auto mb-0">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="?ctrl=page&action=about">À propos</a>
|
<a class="nav-link" href="?ctrl=page&action=about">À propos</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="?ctrl=project&action=search">Rechercher</a>
|
<a class="nav-link" href="?ctrl=project&action=search">Rechercher</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -43,48 +48,51 @@
|
||||||
{/if}
|
{/if}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<nav class="col-4 d-flex justify-content-end align-items-center" aria-label="Connexion utilisateur">
|
<!-- Liens droite (connexion / profil) -->
|
||||||
|
<nav aria-label="Connexion utilisateur">
|
||||||
{if !isset($smarty.session.user)}
|
{if !isset($smarty.session.user)}
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav d-flex flex-row align-items-center gap-1 mb-0">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="index.php?ctrl=user&action=signup" title="Créer un compte" aria-label="Créer un compte">
|
<a class="nav-link" href="index.php?ctrl=user&action=signup"
|
||||||
|
title="Créer un compte" aria-label="Créer un compte">
|
||||||
S'inscrire
|
S'inscrire
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="index.php?ctrl=user&action=login" title="Se connecter" aria-label="Se connecter">
|
<a class="nav-link" href="index.php?ctrl=user&action=login"
|
||||||
|
title="Se connecter" aria-label="Se connecter">
|
||||||
Se connecter
|
Se connecter
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{else}
|
{else}
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav d-flex flex-row align-items-center gap-2 mb-0">
|
||||||
<li class="nav-item">
|
<li class="nav-item d-flex align-items-center">
|
||||||
<a class="nav-link" href="index.php?ctrl=user&action=user&pseudo={$smarty.session.user.user_pseudo}" title="Modifier mon compte" aria-label="Modifier mon compte">
|
<a class="nav-link p-0" href="index.php?ctrl=user&action=user&pseudo={$smarty.session.user.user_pseudo}"
|
||||||
<img src={$smarty.env.IMG_USER_PATH}{if ($smarty.env.IMG_USER_PATH|cat:($smarty.session.user.user_image))|file_exists}{$smarty.session.user.user_image}{else}images.jpg{/if}
|
title="Modifier mon compte" aria-label="Modifier mon compte">
|
||||||
class="rounded-circle flex-shrink-0 mt-2 ml-5"
|
<img
|
||||||
style="width: 36px; height: 36px; object-fit: cover;"
|
src="{$smarty.env.IMG_USER_PATH}{if ($smarty.env.IMG_USER_PATH|cat:($smarty.session.user.user_image))|file_exists}{$smarty.session.user.user_image}{else}images.jpg{/if}"
|
||||||
alt="Photo de profil">
|
class="nav-avatar"
|
||||||
|
alt="Photo de profil"
|
||||||
|
>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item d-flex align-items-center">
|
||||||
<li>
|
<a class="nav-link" href="index.php?ctrl=user&action=logout"
|
||||||
<a class="nav-link" href="index.php?ctrl=user&action=logout" title="Se déconnecter" aria-label="Se déconnecter">
|
title="Se déconnecter" aria-label="Se déconnecter">
|
||||||
Se déconnecter
|
Se déconnecter
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{/if}
|
{/if}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<main id="main-content" class="container my-4">
|
<main id="main-content" class="container my-4">
|
||||||
<section
|
<section class="p-4 mb-4 text-center txt_title" aria-labelledby="page-title">
|
||||||
class="p-4 mb-4 text-center txt_title "
|
|
||||||
aria-labelledby="page-title"
|
|
||||||
>
|
|
||||||
<div class="col-lg-8 mx-auto">
|
<div class="col-lg-8 mx-auto">
|
||||||
<h2 id="page-title" class="display-5 fw-semibold mb-3">
|
<h2 id="page-title" class="display-5 fw-semibold mb-3">
|
||||||
{block name="h2"}{/block}
|
{block name="h2"}{/block}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
<div class="card-body p-3 bg-light">
|
<div class="card-body p-3 bg-light">
|
||||||
<div class="d-flex align-items-start gap-3">
|
<div class="d-flex align-items-start gap-3">
|
||||||
<a href="index.php?ctrl=user&action=user&id={$objProject->getUser_id()}">
|
<a href="index.php?ctrl=user&action=user&pseudo={$objProject->getCreatorname()}">
|
||||||
<img src="{$smarty.env.IMG_USER_PATH}{if ($smarty.env.IMG_USER_PATH|cat:($objProject->getUser_image()))|file_exists}{$objProject->getUser_image()}{else}images.jpg{/if}"
|
<img src="{$smarty.env.IMG_USER_PATH}{if ($smarty.env.IMG_USER_PATH|cat:($objProject->getUser_image()))|file_exists}{$objProject->getUser_image()}{else}images.jpg{/if}"
|
||||||
class="rounded-circle flex-shrink-0 border border-2 border-white"
|
class="rounded-circle flex-shrink-0 border border-2 border-white"
|
||||||
style="width: 64px; height: 64px; object-fit: cover; margin-top: 8px;"
|
style="width: 64px; height: 64px; object-fit: cover; margin-top: 8px;"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
{block name="content"}
|
{block name="content"}
|
||||||
<!-- Page : Inscription -->
|
<!-- Page : Inscription -->
|
||||||
|
|
||||||
<div class="py-5">
|
<div class="py-5">
|
||||||
|
|
||||||
<!-- Centrage horizontal du formulaire -->
|
<!-- Centrage horizontal du formulaire -->
|
||||||
|
|
@ -150,13 +149,23 @@
|
||||||
<label class="form-label" for="user_location">
|
<label class="form-label" for="user_location">
|
||||||
Localisation
|
Localisation
|
||||||
</label>
|
</label>
|
||||||
|
<div class="position-relative">
|
||||||
<input
|
<input
|
||||||
class="form-control"
|
class="form-control"
|
||||||
type="text"
|
type="text"
|
||||||
id="user_location"
|
id="user_location"
|
||||||
name="user_location"
|
name="user_location"
|
||||||
value="{$objUser->getLocation()|default:''}"
|
value="{$objUser->getLocation()|default:''}"
|
||||||
|
autocomplete="off"
|
||||||
|
placeholder="Ex : Paris, Lyon..."
|
||||||
>
|
>
|
||||||
|
<!-- Liste déroulante des suggestions -->
|
||||||
|
<ul
|
||||||
|
id="location-suggestions"
|
||||||
|
class="list-group position-absolute w-100 shadow-sm"
|
||||||
|
style="z-index: 1000; display: none; max-height: 220px; overflow-y: auto; top: 100%; left: 0;"
|
||||||
|
></ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Champ optionnel : phrase d'accroche -->
|
<!-- Champ optionnel : phrase d'accroche -->
|
||||||
|
|
@ -168,9 +177,8 @@
|
||||||
class="form-control"
|
class="form-control"
|
||||||
id="user_description"
|
id="user_description"
|
||||||
name="user_description"
|
name="user_description"
|
||||||
value="{$objUser->getDescription()|default:''}"
|
|
||||||
rows="3"
|
rows="3"
|
||||||
></textarea>
|
>{$objUser->getDescription()|default:''}</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Bouton de soumission du formulaire -->
|
<!-- Bouton de soumission du formulaire -->
|
||||||
|
|
@ -199,4 +207,5 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
{include file="views/_partial/apigeo.tpl"}
|
||||||
{/block}
|
{/block}
|
||||||
|
|
@ -15,14 +15,26 @@
|
||||||
<p class="text-muted">{$user->getMail()}</p>
|
<p class="text-muted">{$user->getMail()}</p>
|
||||||
|
|
||||||
{if $user->getWork()}
|
{if $user->getWork()}
|
||||||
<p>{$user->getWork()}</p>
|
<div class="d-flex align-items-center gap-2 mt-3">
|
||||||
|
<i class="fa-solid fa-briefcase"></i>
|
||||||
|
<p class="mb-0">{$user->getWork()}</p>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{if $user->getLocation()}
|
{if $user->getLocation()}
|
||||||
<p>{$user->getLocation()}</p>
|
|
||||||
|
<div class="d-flex align-items-center gap-2 mt-3">
|
||||||
|
<i class="fa-solid fa-location-dot"></i>
|
||||||
|
<p class="mb-0">{$user->getLocation()}</p>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{if $user->getLocation()}
|
||||||
|
|
||||||
|
<div class="d-flex align-items-center gap-2 mt-3">
|
||||||
|
<i class="fa-regular fa-note-sticky"></i> <p class="mb-0">{$user->getDescription()}</p>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<p class="mt-3">{$user->getDescription()}</p>
|
|
||||||
{if $smarty.session.user.user_id == $user->getId()}
|
{if $smarty.session.user.user_id == $user->getId()}
|
||||||
<a class="btn btn-sm btn-primary flex-fill"
|
<a class="btn btn-sm btn-primary flex-fill"
|
||||||
href="?ctrl=user&action=edit">Edit account</a>
|
href="?ctrl=user&action=edit">Edit account</a>
|
||||||
|
|
|
||||||
|
|
@ -132,17 +132,28 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Champ optionnel : localisation de l'utilisateur -->
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<label class="form-label" for="user_location">
|
<label class="form-label" for="user_location">
|
||||||
Localisation
|
Localisation
|
||||||
</label>
|
</label>
|
||||||
|
<div class="position-relative">
|
||||||
<input
|
<input
|
||||||
class="form-control"
|
class="form-control"
|
||||||
type="text"
|
type="text"
|
||||||
id="user_location"
|
id="user_location"
|
||||||
name="user_location"
|
name="user_location"
|
||||||
value="{$objUser->getLocation()}"
|
value="{$objUser->getLocation()}"
|
||||||
|
autocomplete="off"
|
||||||
|
placeholder="Ex : Paris, Lyon..."
|
||||||
>
|
>
|
||||||
|
<!-- Liste déroulante des suggestions -->
|
||||||
|
<ul
|
||||||
|
id="location-suggestions"
|
||||||
|
class="list-group position-absolute w-100 shadow-sm"
|
||||||
|
style="z-index: 1000; display: none; max-height: 220px; overflow-y: auto; top: 100%; left: 0;"
|
||||||
|
></ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -176,4 +187,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
{include file="views/_partial/apigeo.tpl"}
|
||||||
{/block}
|
{/block}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue