aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpolo <ordipolo@gmx.fr>2025-10-22 15:28:02 +0200
committerpolo <ordipolo@gmx.fr>2025-10-22 15:28:02 +0200
commitc9aff025aa7e01badaad8467af6165b400cdaac4 (patch)
treec6e56a3f13db401c9f75bf9f8e4169f50aaf25b9
parent426a1a69cb73007538336debc31b34c4348e1ba1 (diff)
downloadcms-c9aff025aa7e01badaad8467af6165b400cdaac4.zip
possibilité d'éditer le texte dans header et footer, class JS InputText, Model::findWhateverNode
-rw-r--r--public/assets/close-nb.svg1
-rw-r--r--public/assets/close.svg37
-rw-r--r--public/css/body.css4
-rw-r--r--public/css/calendar.css1
-rw-r--r--public/css/foot.css14
-rw-r--r--public/css/head.css12
-rw-r--r--public/js/InputText.js47
-rw-r--r--src/controller/HeadFootController.php33
-rw-r--r--src/model/Model.php18
-rw-r--r--src/router.php7
-rw-r--r--src/view/FooterBuilder.php15
-rw-r--r--src/view/HeadBuilder.php5
-rw-r--r--src/view/HeaderBuilder.php27
-rw-r--r--src/view/templates/footer.php27
-rw-r--r--src/view/templates/header.php27
15 files changed, 250 insertions, 25 deletions
diff --git a/public/assets/close-nb.svg b/public/assets/close-nb.svg
new file mode 100644
index 0000000..c5a6b6b
--- /dev/null
+++ b/public/assets/close-nb.svg
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M11.9997 10.5865L16.9495 5.63672L18.3637 7.05093L13.4139 12.0007L18.3637 16.9504L16.9495 18.3646L11.9997 13.4149L7.04996 18.3646L5.63574 16.9504L10.5855 12.0007L5.63574 7.05093L7.04996 5.63672L11.9997 10.5865Z"></path></svg> \ No newline at end of file
diff --git a/public/assets/close.svg b/public/assets/close.svg
new file mode 100644
index 0000000..4dfee8c
--- /dev/null
+++ b/public/assets/close.svg
@@ -0,0 +1,37 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg
3 viewBox="0 0 24 24"
4 fill="currentColor"
5 version="1.1"
6 id="svg1"
7 sodipodi:docname="close.svg"
8 inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
9 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
10 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11 xmlns="http://www.w3.org/2000/svg"
12 xmlns:svg="http://www.w3.org/2000/svg">
13 <defs
14 id="defs1" />
15 <sodipodi:namedview
16 id="namedview1"
17 pagecolor="#ffffff"
18 bordercolor="#000000"
19 borderopacity="0.25"
20 inkscape:showpageshadow="2"
21 inkscape:pageopacity="0.0"
22 inkscape:pagecheckerboard="0"
23 inkscape:deskcolor="#d1d1d1"
24 inkscape:zoom="16.333333"
25 inkscape:cx="13.071429"
26 inkscape:cy="14.785714"
27 inkscape:window-width="1916"
28 inkscape:window-height="1032"
29 inkscape:window-x="0"
30 inkscape:window-y="0"
31 inkscape:window-maximized="1"
32 inkscape:current-layer="svg1" />
33 <path
34 style="fill:#dd3333;stroke:#dd3333;stroke-width:0.2314"
35 d="m 6.3513525,17.616704 -0.6567632,-0.658806 2.4486238,-2.44805 c 1.346743,-1.346427 2.4486239,-2.475604 2.4486239,-2.509281 0,-0.03368 -1.1022132,-1.163696 -2.4493624,-2.5111538 L 5.6931123,7.0394909 6.3673453,6.3673486 7.0415783,5.6952062 9.5207892,8.1738503 12,10.652494 l 2.479211,-2.4786437 2.47921,-2.4786441 0.674234,0.6721424 0.674233,0.6721423 -2.449362,2.4499223 C 14.510376,10.836871 13.408163,11.966635 13.408163,12 c 0,0.03337 1.102213,1.163129 2.449363,2.510587 l 2.449362,2.449922 -0.674233,0.672142 -0.674234,0.672143 L 14.479211,15.82615 12,13.347506 9.5354343,15.811508 c -1.3555112,1.355201 -2.4786851,2.464002 -2.4959421,2.464002 -0.017257,0 -0.3269198,-0.296462 -0.6881397,-0.658806 z"
36 id="path2" />
37</svg>
diff --git a/public/css/body.css b/public/css/body.css
index 95f30d4..8ad3a52 100644
--- a/public/css/body.css
+++ b/public/css/body.css
@@ -188,7 +188,7 @@ button .action_icon:hover
188{ 188{
189 margin-right: 2px; 189 margin-right: 2px;
190} 190}
191section button, section input[type=submit] 191button, section input[type=submit]
192{ 192{
193 color: #ff1d04; 193 color: #ff1d04;
194 font-size: medium; 194 font-size: medium;
@@ -196,7 +196,7 @@ section button, section input[type=submit]
196 background-color: white; 196 background-color: white;
197 border: lightgrey 2px outset; /* rend identiques les boutons firefox et chromium */ 197 border: lightgrey 2px outset; /* rend identiques les boutons firefox et chromium */
198} 198}
199section button:hover, section input[type=submit]:hover 199button:hover, section input[type=submit]:hover
200{ 200{
201 background-color: yellow; 201 background-color: yellow;
202 border-radius: 4px; 202 border-radius: 4px;
diff --git a/public/css/calendar.css b/public/css/calendar.css
index 2ff5640..d011f03 100644
--- a/public/css/calendar.css
+++ b/public/css/calendar.css
@@ -10,7 +10,6 @@
10#calendar_zone{ 10#calendar_zone{
11 display: flex; 11 display: flex;
12 gap: 5px; 12 gap: 5px;
13 /*padding: 15px;*/
14 max-width: 1170px; 13 max-width: 1170px;
15} 14}
16#calendar{ 15#calendar{
diff --git a/public/css/foot.css b/public/css/foot.css
index ad86305..8d0a94d 100644
--- a/public/css/foot.css
+++ b/public/css/foot.css
@@ -11,11 +11,15 @@ footer
11} 11}
12footer > div 12footer > div
13{ 13{
14 margin: auto;
15 max-width: 1200px; 14 max-width: 1200px;
16 display: flex; 15 display: flex;
17 justify-content: space-around; 16 justify-content: space-around;
18} 17}
18
19.contact
20{
21 margin: 16px 0; /* alignement avec la <p> autour du logo */
22}
19.contact a 23.contact a
20{ 24{
21 color: unset; 25 color: unset;
@@ -69,11 +73,6 @@ footer > div
69 margin: 0 3px; 73 margin: 0 3px;
70}*/ 74}*/
71 75
72.contact
73{
74 padding: 0 15px;
75}
76
77.footer_logo img 76.footer_logo img
78{ 77{
79 max-width: 288px; 78 max-width: 288px;
@@ -115,8 +114,7 @@ footer > div
115} 114}
116.logged_out 115.logged_out
117{ 116{
118 /*display: none;*/ 117 justify-content: start; /* écrase le space-around dans footer > div */
119 justify-content: start;
120} 118}
121.logged_out a 119.logged_out a
122{ 120{
diff --git a/public/css/head.css b/public/css/head.css
index be938bb..b173077 100644
--- a/public/css/head.css
+++ b/public/css/head.css
@@ -24,6 +24,8 @@ header
24 grid-template-columns: 1fr 1fr 1fr; 24 grid-template-columns: 1fr 1fr 1fr;
25 align-items: end; 25 align-items: end;
26} 26}
27/*.header_left_col
28{}*/
27@media screen and (max-width: 1000px){ 29@media screen and (max-width: 1000px){
28 .header-content{ 30 .header-content{
29 padding: 18px 0; 31 padding: 18px 0;
@@ -36,7 +38,7 @@ header
36 display: block; 38 display: block;
37 padding: 18px; 39 padding: 18px;
38 } 40 }
39 .head_logo 41 #header_logo
40 { 42 {
41 display: none; 43 display: none;
42 } 44 }
@@ -74,12 +76,18 @@ header a
74 color: unset; /* ne plus hériter */ 76 color: unset; /* ne plus hériter */
75 text-decoration: none; 77 text-decoration: none;
76} 78}
79#edit_favicon_zone
80{
81 margin-bottom: 10px;
82}
83/*.header_right_col
84{}*/
77.social 85.social
78{ 86{
79 /*align-self: end;*/ 87 /*align-self: end;*/
80 /*padding: 4px;*/ 88 /*padding: 4px;*/
81} 89}
82.social img 90.social a img
83{ 91{
84 width: 25px; 92 width: 25px;
85 background-color: #ffffffb3; 93 background-color: #ffffffb3;
diff --git a/public/js/InputText.js b/public/js/InputText.js
new file mode 100644
index 0000000..ba7e8e4
--- /dev/null
+++ b/public/js/InputText.js
@@ -0,0 +1,47 @@
1// s'en servir dans menu et chemin
2class InputText{
3 constructor(name){
4 this.name = name;
5 this.parent = document.getElementById(name);
6 }
7 openTextInput(){
8 this.parent.querySelector('#' + this.name + '_span').classList.add('hidden');
9 this.parent.querySelector('#' + this.name + '_input').classList.remove('hidden');
10 this.parent.querySelector('#' + this.name + '_open').classList.add('hidden');
11 this.parent.querySelector('#' + this.name + '_submit').classList.remove('hidden');
12 this.parent.querySelector('#' + this.name + '_cancel').classList.remove('hidden');
13 }
14 closeTextInput(){
15 this.parent.querySelector('#' + this.name + '_span').classList.remove('hidden');
16 this.parent.querySelector('#' + this.name + '_input').classList.add('hidden');
17 this.parent.querySelector('#' + this.name + '_open').classList.remove('hidden');
18 this.parent.querySelector('#' + this.name + '_submit').classList.add('hidden');
19 this.parent.querySelector('#' + this.name + '_cancel').classList.add('hidden');
20 }
21 submitTextInput(){
22 const new_text = this.parent.querySelector('#' + this.name + '_input').value;
23
24 fetch('index.php?entire_site_edit=' + this.name, {
25 method: 'POST',
26 headers: { 'Content-Type': 'application/json' },
27 body: JSON.stringify({new_text: new_text})
28 })
29 .then(response => response.json())
30 .then(data => {
31 if(data.success){
32 this.parent.querySelector('#' + this.name + '_span').innerHTML = new_text;
33 this.closeTextInput(this.name);
34 }
35 else{
36 console.error("Erreur: le serveur n'a pas enregistré le nouveau texte.");
37 }
38 })
39 .catch(error => {
40 console.error('Erreur:', error);
41 });
42 }
43 cancelTextInput(){
44 this.parent.querySelector('#' + this.name + '_input').value = this.parent.querySelector('#' + this.name + '_span').innerHTML;
45 this.closeTextInput(this.name);
46 }
47} \ No newline at end of file
diff --git a/src/controller/HeadFootController.php b/src/controller/HeadFootController.php
new file mode 100644
index 0000000..c7a9cec
--- /dev/null
+++ b/src/controller/HeadFootController.php
@@ -0,0 +1,33 @@
1<?php
2// src/controller/HeadFootController.php
3
4declare(strict_types=1);
5
6//use App\Entity\Node;
7//use App\Entity\NodeData;
8//use App\Entity\Image;
9//use Doctrine\Common\Collections\ArrayCollection;
10use Doctrine\ORM\EntityManager;
11
12class HeadFootController
13{
14 static public function setTextData(EntityManager $entityManager, array $request_params, array $json): void
15 {
16 if(count($request_params) !== 2){
17 echo json_encode(['success' => false]);
18 die;
19 }
20
21 $model = new Model($entityManager);
22 if($model->findWhateverNode('name_node', $request_params[0])){
23 $node_data = $model->getNode()->getNodeData();
24 $node_data->updateData($request_params[1], htmlspecialchars($json['new_text'])); // $request_params[1] n'est pas contrôlé
25 $entityManager->flush();
26 echo json_encode(['success' => true]);
27 }
28 else{
29 echo json_encode(['success' => false]);
30 }
31 die;
32 }
33} \ No newline at end of file
diff --git a/src/model/Model.php b/src/model/Model.php
index ea8ef71..16061e7 100644
--- a/src/model/Model.php
+++ b/src/model/Model.php
@@ -185,6 +185,24 @@ class Model
185 $this->node = $this->entityManager->find('App\Entity\Node', $id); 185 $this->node = $this->entityManager->find('App\Entity\Node', $id);
186 return $this->node === null ? false : true; 186 return $this->node === null ? false : true;
187 } 187 }
188 public function findWhateverNode(string $field, string $value): bool
189 {
190 $queryBuilder = $this->entityManager->createQueryBuilder();
191 $queryBuilder
192 ->select('n')
193 ->from('App\Entity\Node', 'n')
194 ->where("n.$field = :value") // avec le querybuilder, ce truc sale reste sécurisé
195 ->setParameter('value', $value);
196 $result = $queryBuilder->getQuery()->getOneOrNullResult();
197
198 if($result === null){
199 return false;
200 }
201 else{
202 $this->node = $result;
203 return true;
204 }
205 }
188 206
189 // récupération d'un article pour modification 207 // récupération d'un article pour modification
190 public function makeArticleNode(string $id = '', bool $get_section = false): bool 208 public function makeArticleNode(string $id = '', bool $get_section = false): bool
diff --git a/src/router.php b/src/router.php
index 7459a0d..1127c81 100644
--- a/src/router.php
+++ b/src/router.php
@@ -141,11 +141,16 @@ elseif($request->getMethod() === 'POST'){
141 } 141 }
142 } 142 }
143 143
144 /* -- site entier (header, footer, favicon) -- */
145 elseif($request->query->has('entire_site_edit')){
146 $request_params = explode('_', $request->query->get('entire_site_edit')); // header_title, header_description, footer_text, etc
147 HeadFootController::setTextData($entityManager, $request_params, $json);
148 }
144 149
145 /* -- page Menu et chemins -- */ 150 /* -- page Menu et chemins -- */
146 elseif(isset($_GET['menu_edit'])) 151 elseif(isset($_GET['menu_edit']))
147 { 152 {
148 // ne suit pas la règle, faire ça dans un contrôleur 153 // ne suit pas la règle, faire ça dans un contrôleur?
149 Model::$menu_data = new Menu($entityManager); // récupération des données 154 Model::$menu_data = new Menu($entityManager); // récupération des données
150 155
151 // flèche gauche <=: position = position du parent + 1, parent = grand-parent, recalculer les positions 156 // flèche gauche <=: position = position du parent + 1, parent = grand-parent, recalculer les positions
diff --git a/src/view/FooterBuilder.php b/src/view/FooterBuilder.php
index 0a3f55c..c1e0f7a 100644
--- a/src/view/FooterBuilder.php
+++ b/src/view/FooterBuilder.php
@@ -26,6 +26,17 @@ class FooterBuilder extends AbstractBuilder
26 $empty_admin_zone = ''; 26 $empty_admin_zone = '';
27 if($_SESSION['admin']) 27 if($_SESSION['admin'])
28 { 28 {
29 $buttons_footer_name = '<img id="footer_name_open" class="action_icon" src="assets/edit.svg" onclick="footer_name.openTextInput()">
30 <img id="footer_name_submit" class="action_icon hidden" src="assets/save.svg" onclick="footer_name.submitTextInput()">
31 <img id="footer_name_cancel" class="action_icon hidden" src="assets/close.svg" onclick="footer_name.cancelTextInput()">';
32 $buttons_footer_address = '<img id="footer_address_open" class="action_icon" src="assets/edit.svg" onclick="footer_address.openTextInput()">
33 <img id="footer_address_submit" class="action_icon hidden" src="assets/save.svg" onclick="footer_address.submitTextInput()">
34 <img id="footer_address_cancel" class="action_icon hidden" src="assets/close.svg" onclick="footer_address.cancelTextInput()">';
35 $buttons_footer_email = '<img id="footer_email_open" class="action_icon" src="assets/edit.svg" onclick="footer_email.openTextInput()">
36 <img id="footer_email_submit" class="action_icon hidden" src="assets/save.svg" onclick="footer_email.submitTextInput()">
37 <img id="footer_email_cancel" class="action_icon hidden" src="assets/close.svg" onclick="footer_email.cancelTextInput()">';
38
39 // zone admin
29 $empty_admin_zone = 'empty_admin_zone'; 40 $empty_admin_zone = 'empty_admin_zone';
30 if(MainBuilder::$modif_mode){ 41 if(MainBuilder::$modif_mode){
31 $mode = 'modification de page'; 42 $mode = 'modification de page';
@@ -61,6 +72,10 @@ class FooterBuilder extends AbstractBuilder
61 $url->addParams(['id' => $_GET['id']]); 72 $url->addParams(['id' => $_GET['id']]);
62 } 73 }
63 $zone_admin = '<button><a href="' . $url . '">Mode admin</a></button>'; 74 $zone_admin = '<button><a href="' . $url . '">Mode admin</a></button>';
75
76 $buttons_footer_name = '';
77 $buttons_footer_address = '';
78 $buttons_footer_email = '';
64 } 79 }
65 80
66 ob_start(); 81 ob_start();
diff --git a/src/view/HeadBuilder.php b/src/view/HeadBuilder.php
index b1dfacb..978d9ed 100644
--- a/src/view/HeadBuilder.php
+++ b/src/view/HeadBuilder.php
@@ -33,8 +33,11 @@ class HeadBuilder extends AbstractBuilder
33 $js .= '<script src="' . self::versionedFileURL('js', 'modif_page') . '"></script>' . "\n"; 33 $js .= '<script src="' . self::versionedFileURL('js', 'modif_page') . '"></script>' . "\n";
34 } 34 }
35 35
36 // tinymce, nécéssite un script de copie dans composer.json
37 if($_SESSION['admin']){ 36 if($_SESSION['admin']){
37 // édition éléments sur toutes les pages (header, footer et favicon)
38 $js .= '<script src="' . self::versionedFileURL('js', 'InputText') . '"></script>' . "\n";
39
40 // tinymce, nécéssite un script de copie dans composer.json
38 $css .= '<link rel="stylesheet" href="' . self::versionedFileURL('css', 'tinymce') . '">' . "\n"; 41 $css .= '<link rel="stylesheet" href="' . self::versionedFileURL('css', 'tinymce') . '">' . "\n";
39 $js .= '<script src="' . self::versionedFileURL('js', 'tinymce/tinymce.min') . '"></script>' . "\n"; // pour js/tinymce/tinymce.min.js 42 $js .= '<script src="' . self::versionedFileURL('js', 'tinymce/tinymce.min') . '"></script>' . "\n"; // pour js/tinymce/tinymce.min.js
40 $js .= '<script src="' . self::versionedFileURL('js', 'tinymce') . '"></script>' . "\n"; 43 $js .= '<script src="' . self::versionedFileURL('js', 'tinymce') . '"></script>' . "\n";
diff --git a/src/view/HeaderBuilder.php b/src/view/HeaderBuilder.php
index dc4aec4..5492340 100644
--- a/src/view/HeaderBuilder.php
+++ b/src/view/HeaderBuilder.php
@@ -77,6 +77,33 @@ class HeaderBuilder extends AbstractBuilder
77 <img src="assets/' . $one_key . '.svg" alt="' . $one_key . '_alt"></a>'; 77 <img src="assets/' . $one_key . '.svg" alt="' . $one_key . '_alt"></a>';
78 } 78 }
79 79
80 // boutons mode admin
81 if($_SESSION['admin']){
82 $edit_favicon_hidden = 'hidden';
83 $button_favicon = '';
84 $button_header_logo = '';
85 //$edit_favicon_hidden = '';
86 //$favicon = 'assets/favicon48x48.png'; // double le code dans HeadBuilder
87 //$button_favicon = '<button onclick="editFavicon()"><img class="action_icon" src="' . $favicon . '"> Favicon</button>';
88 //$button_header_logo = '<img class="action_icon" src="assets/edit.svg" onclick="editHeaderLogo()">';
89 $buttons_header_title = '<img id="header_title_open" class="action_icon" src="assets/edit.svg" onclick="header_title.openTextInput()">
90 <img id="header_title_submit" class="action_icon hidden" src="assets/save.svg" onclick="header_title.submitTextInput()">
91 <img id="header_title_cancel" class="action_icon hidden" src="assets/close.svg" onclick="header_title.cancelTextInput()">';
92 $buttons_header_description = '<img id="header_description_open" class="action_icon" src="assets/edit.svg" onclick="header_description.openTextInput()">
93 <img id="header_description_submit" class="action_icon hidden" src="assets/save.svg" onclick="header_description.submitTextInput()">
94 <img id="header_description_cancel" class="action_icon hidden" src="assets/close.svg" onclick="header_description.cancelTextInput()">';
95 //$buttons_social_networks = '<img class="action_icon" src="assets/edit.svg" onclick="editSocialNetworks()">';
96 $buttons_social_networks = '';
97 }
98 else{
99 $edit_favicon_hidden = 'hidden';
100 $button_favicon = '';
101 $button_header_logo = '';
102 $buttons_header_title = '';
103 $buttons_header_description = '';
104 $buttons_social_networks = '';
105 }
106
80 ob_start(); 107 ob_start();
81 require $viewFile; 108 require $viewFile;
82 $this->html .= ob_get_clean(); 109 $this->html .= ob_get_clean();
diff --git a/src/view/templates/footer.php b/src/view/templates/footer.php
index 1b63edf..dbace6a 100644
--- a/src/view/templates/footer.php
+++ b/src/view/templates/footer.php
@@ -1,11 +1,28 @@
1<?php declare(strict_types=1); ?> 1<?php declare(strict_types=1); ?>
2 <footer> 2 <footer>
3<?= $breadcrumb ?> 3<?= $breadcrumb ?>
4 <div> 4 <div class="data">
5 <p class="contact"><?= $contact_nom ?><br> 5 <div class="contact">
6 <?= $adresse ?><br> 6 <div id="footer_name">
7 <a href="mailto:<?= $e_mail ?>"><?= $e_mail ?></a></p> 7 <script>let footer_name = new InputText('footer_name');</script>
8 <p class="footer_logo"><img src="<?= $footer_logo ?>" alt="logo"><p> 8 <span id="footer_name_span"><?= htmlspecialchars($name ?? '') ?></span>
9 <input type="text" id="footer_name_input" class="hidden" value="<?= htmlspecialchars($name ?? '') ?>" size="30">
10 <?= $buttons_footer_name ?>
11 </div>
12 <div id="footer_address">
13 <script>let footer_address = new InputText('footer_address');</script>
14 <span id="footer_address_span"><?= htmlspecialchars($adresse ?? '') ?></span>
15 <input type="text" id="footer_address_input" class="hidden" value="<?= htmlspecialchars($adresse ?? '') ?>" size="30">
16 <?= $buttons_footer_address ?>
17 </div>
18 <div id="footer_email">
19 <script>let footer_email = new InputText('footer_email');</script>
20 <a href="mailto:<?= $e_mail ?>"><span id="footer_email_span"><?= htmlspecialchars($email ?? '') ?></span></a>
21 <input type="text" id="footer_email_input" class="hidden" value="<?= htmlspecialchars($email ?? '') ?>" size="30">
22 <?= $buttons_footer_email ?>
23 </div>
24 </div>
25 <p class="footer_logo"><img src="<?= $footer_logo ?>" alt="logo"></p>
9 </div> 26 </div>
10 <div class="<?= $empty_admin_zone ?>"></div> 27 <div class="<?= $empty_admin_zone ?>"></div>
11 <div class="<?= $div_admin ?>"> 28 <div class="<?= $div_admin ?>">
diff --git a/src/view/templates/header.php b/src/view/templates/header.php
index d419a12..7977ef3 100644
--- a/src/view/templates/header.php
+++ b/src/view/templates/header.php
@@ -7,19 +7,36 @@
7 </div> 7 </div>
8 8
9 <div class="header-content"> 9 <div class="header-content">
10 <div class="head_logo"> 10 <div class="header_left_col">
11 <a href="<?= new URL ?>"><img src="<?= $header_logo ?>" alt="logo_alt"></a> 11 <div id="edit_favicon_zone" class="<?= $edit_favicon_hidden ?>">
12 <?= $button_favicon ?>
13 </div>
14 <div>
15 <a href="<?= new URL ?>"><img id="header_logo" src="<?= $header_logo ?>" alt="logo_alt"></a>
16 <?= $button_header_logo ?>
17 </div>
12 </div> 18 </div>
13 <div class="nav_button"> 19 <div class="nav_button">
14 <button>MENU</button> 20 <button>MENU</button>
15 </div> 21 </div>
16 <div class="site_title"> 22 <div class="site_title">
17 <a href="<?= new URL ?>"><h1><?= $title ?></h1></a> 23 <h1 id="header_title">
18 <h2><?= $description ?></h2> 24 <script>let header_title = new InputText('header_title');</script>
25 <a href="<?= new URL ?>"><span id="header_title_span"><?= htmlspecialchars($title ?? '') ?></span></a>
26 <input type="text" id="header_title_input" class="hidden" value="<?= htmlspecialchars($title ?? '') ?>" size="30">
27 <?= $buttons_header_title ?>
28 </h1>
29 <h2 id="header_description">
30 <script>let header_description = new InputText('header_description');</script>
31 <span id="header_description_span"><?= htmlspecialchars($description ?? '') ?></span>
32 <input type="text" id="header_description_input" class="hidden" value="<?= htmlspecialchars($description ?? '') ?>" size="30">
33 <?= $buttons_header_description ?>
34 </h2>
19 </div> 35 </div>
20 <div> 36 <div class="header_right_col">
21 <div class="social"> 37 <div class="social">
22 <?= $social_networks ?> 38 <?= $social_networks ?>
39 <?= $buttons_social_networks ?>
23 </div> 40 </div>
24 <?= $breadcrumb ?? '' ?> 41 <?= $breadcrumb ?? '' ?>
25 </div> 42 </div>