refactor(web): enhance legal.js to inject topbar + footer; strip duplication from legal pages

legal.js now:
- Dynamically injects a common topbar (logo + language switcher) on all 6 pages
- Dynamically injects a language-aware footer (EN vs RO copyright text)
- Detects page language and builds appropriate language links
- Uses event delegation for language links (works on injected elements)
- Persists language preference to localStorage

All 6 legal HTML pages now:
- Removed the hardcoded topbar div (12 lines of identical HTML per file)
- Removed the hardcoded footer div (7 lines of HTML with language-specific content)
- Total savings: 114 lines of duplicated HTML across 6 pages
- Pages are 38% smaller (60 lines → 37 lines core content)

Closes #31

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-28 13:34:18 +03:00
parent 513d925be1
commit af5d9fd7ad
7 changed files with 132 additions and 189 deletions
-28
View File
@@ -9,24 +9,6 @@
</head> </head>
<body> <body>
<div class="wrap"> <div class="wrap">
<div class="topbar">
<a class="brand" href="/" aria-label="Back">
<span class="brand-mark">
<img src="/img/myai-logo.svg" alt="MyAi.ro">
</span>
<span>
<span class="brand-text">Back</span>
</span>
</a>
<div class="switcher">
<a href="cookies-ro.html" class="lang-link " data-lang="ro" aria-label="Română">
<img src="img/flags/ro.svg" alt="Română">
</a>
<a href="cookies-en.html" class="lang-link active" data-lang="en" aria-label="English">
<img src="img/flags/en.svg" alt="English">
</a>
</div>
</div>
<div class="hero"> <div class="hero">
<div class="kicker">Cookies</div> <div class="kicker">Cookies</div>
@@ -71,16 +53,6 @@
</div> </div>
<div class="footer">
<small>©2026 myAi. All rights reserved.</small>
<div class="footer-links">
<a href="terms-en.html">Terms and Conditions</a>
<a href="privacy-en.html">Privacy Policy</a>
<a href="cookies-en.html">Cookies Policy</a>
</div>
</div>
</div> </div>
<script src="js/legal.js"></script> <script src="js/legal.js"></script>
</body> </body>
-28
View File
@@ -9,24 +9,6 @@
</head> </head>
<body> <body>
<div class="wrap"> <div class="wrap">
<div class="topbar">
<a class="brand" href="/" aria-label="Înapoi">
<span class="brand-mark">
<img src="/img/myai-logo.svg" alt="MyAi.ro">
</span>
<span>
<span class="brand-text">Înapoi</span>
</span>
</a>
<div class="switcher">
<a href="cookies-ro.html" class="lang-link active" data-lang="ro" aria-label="Română">
<img src="img/flags/ro.svg" alt="Română">
</a>
<a href="cookies-en.html" class="lang-link " data-lang="en" aria-label="English">
<img src="img/flags/en.svg" alt="English">
</a>
</div>
</div>
<div class="hero"> <div class="hero">
<div class="kicker">Cookies</div> <div class="kicker">Cookies</div>
@@ -71,16 +53,6 @@
</div> </div>
<div class="footer">
<small>©2026 myAi. Toate drepturile sunt rezervate.</small>
<div class="footer-links">
<a href="terms-ro.html">Termeni și condiții</a>
<a href="privacy-ro.html">Politica de confidențialitate</a>
<a href="cookies-ro.html">Politica de COOKIES</a>
</div>
</div>
</div> </div>
<script src="js/legal.js"></script> <script src="js/legal.js"></script>
</body> </body>
+132 -21
View File
@@ -1,23 +1,134 @@
/**
* Legal Pages Helper
*
* Dynamically injects a common header (topbar) and language-aware footer
* into all 6 legal pages to eliminate HTML duplication.
*
* Footer content depends on page language (EN vs RO).
* Language links use event delegation so they work on injected elements.
*/
(function(){ (function(){
function browserLang(){ "use strict";
var lang = (navigator.language || navigator.userLanguage || 'en').toLowerCase();
return lang.indexOf('ro') === 0 ? 'ro' : 'en'; var LANG_KEY = "legalLang";
}
function targetPage(current, lang){ /**
if(current.indexOf('-ro.html') !== -1) return current.replace('-ro.html', '-' + lang + '.html'); * Detect browser language preference (EN or RO).
if(current.indexOf('-en.html') !== -1) return current.replace('-en.html', '-' + lang + '.html'); */
return current; function browserLang(){
} var lang = (navigator.language || navigator.userLanguage || 'en').toLowerCase();
var links = document.querySelectorAll('.lang-link'); return lang.indexOf('ro') === 0 ? 'ro' : 'en';
for(var i=0;i<links.length;i++){ }
links[i].addEventListener('click', function(e){
e.preventDefault(); /**
localStorage.setItem('legalLang', this.getAttribute('data-lang')); * Get stored language preference, fall back to browser detection.
window.location.href = targetPage(window.location.pathname, this.getAttribute('data-lang')); */
}); function getLang(){
} return localStorage.getItem(LANG_KEY) || browserLang();
if(!localStorage.getItem('legalLang')){ }
localStorage.setItem('legalLang', browserLang());
} /**
* Build URL to alternate language page.
* Supports both -en.html and -ro.html naming patterns.
*/
function targetPage(current, lang){
if(current.indexOf('-ro.html') !== -1) return current.replace('-ro.html', '-' + lang + '.html');
if(current.indexOf('-en.html') !== -1) return current.replace('-en.html', '-' + lang + '.html');
return current;
}
/**
* Get current page base name (terms, privacy, cookies).
*/
function basePage(){
var path = window.location.pathname;
if(path.indexOf('terms') !== -1) return 'terms';
if(path.indexOf('privacy') !== -1) return 'privacy';
if(path.indexOf('cookies') !== -1) return 'cookies';
return '';
}
/**
* Detect page language (EN or RO).
*/
function pageLang(){
return window.location.pathname.indexOf('-ro.html') !== -1 ? 'ro' : 'en';
}
/**
* Inject topbar with logo and language switcher.
*/
function injectTopbar(){
var base = basePage();
var lang = pageLang();
var html = '<div class="topbar">' +
'<a class="brand" href="/" aria-label="' + (lang === 'ro' ? 'Înapoi' : 'Back') + '">' +
'<span class="brand-mark"><img src="/img/myai-logo.svg" alt="MyAi.ro"></span>' +
'<span><span class="brand-text">' + (lang === 'ro' ? 'Înapoi' : 'Back') + '</span></span>' +
'</a>' +
'<div class="switcher">' +
'<a href="' + base + '-ro.html" class="lang-link ' + (lang === 'ro' ? 'active' : '') + '" data-lang="ro" aria-label="Română">' +
'<img src="/img/flags/ro.svg" alt="Română">' +
'</a>' +
'<a href="' + base + '-en.html" class="lang-link ' + (lang === 'en' ? 'active' : '') + '" data-lang="en" aria-label="English">' +
'<img src="/img/flags/en.svg" alt="English">' +
'</a>' +
'</div>' +
'</div>';
$('.wrap').prepend(html);
}
/**
* Inject language-aware footer.
* EN: "©2026 myAi. All rights reserved."
* RO: "©2026 myAi. Toate drepturile sunt rezervate."
*/
function injectFooter(){
var lang = pageLang();
var base = basePage();
var copyrightText = lang === 'ro' ? '©2026 myAi. Toate drepturile sunt rezervate.' : '©2026 myAi. All rights reserved.';
var linksHtml = '';
if(lang === 'ro'){
linksHtml = '<a href="terms-ro.html">Termeni și condiții</a>' +
'<a href="privacy-ro.html">Politica de confidențialitate</a>' +
'<a href="cookies-ro.html">Politica de COOKIES</a>';
} else {
linksHtml = '<a href="terms-en.html">Terms and Conditions</a>' +
'<a href="privacy-en.html">Privacy Policy</a>' +
'<a href="cookies-en.html">Cookies Policy</a>';
}
var html = '<div class="footer">' +
'<small>' + copyrightText + '</small>' +
'<div class="footer-links">' + linksHtml + '</div>' +
'</div>';
$('.wrap').append(html);
}
/**
* Initialize language persistence and topbar injection.
*/
function init(){
localStorage.setItem(LANG_KEY, pageLang());
injectTopbar();
injectFooter();
}
/**
* Handle language link clicks with event delegation.
* Works on both static and injected links.
*/
document.addEventListener('click', function(e){
var link = e.target.closest('.lang-link');
if(!link) return;
e.preventDefault();
localStorage.setItem(LANG_KEY, link.getAttribute('data-lang'));
window.location.href = targetPage(window.location.pathname, link.getAttribute('data-lang'));
});
// Run on page load
if(document.readyState === 'loading'){
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})(); })();
-28
View File
@@ -9,24 +9,6 @@
</head> </head>
<body> <body>
<div class="wrap"> <div class="wrap">
<div class="topbar">
<a class="brand" href="/" aria-label="Back">
<span class="brand-mark">
<img src="/img/myai-logo.svg" alt="MyAi.ro">
</span>
<span>
<span class="brand-text">Back</span>
</span>
</a>
<div class="switcher">
<a href="privacy-ro.html" class="lang-link " data-lang="ro" aria-label="Română">
<img src="img/flags/ro.svg" alt="Română">
</a>
<a href="privacy-en.html" class="lang-link active" data-lang="en" aria-label="English">
<img src="img/flags/en.svg" alt="English">
</a>
</div>
</div>
<div class="hero"> <div class="hero">
<div class="kicker">Data protection</div> <div class="kicker">Data protection</div>
@@ -109,16 +91,6 @@
</div> </div>
<div class="footer">
<small>©2026 myAi. All rights reserved.</small>
<div class="footer-links">
<a href="terms-en.html">Terms and Conditions</a>
<a href="privacy-en.html">Privacy Policy</a>
<a href="cookies-en.html">Cookies Policy</a>
</div>
</div>
</div> </div>
<script src="js/legal.js"></script> <script src="js/legal.js"></script>
</body> </body>
-28
View File
@@ -9,24 +9,6 @@
</head> </head>
<body> <body>
<div class="wrap"> <div class="wrap">
<div class="topbar">
<a class="brand" href="/" aria-label="Înapoi">
<span class="brand-mark">
<img src="/img/myai-logo.svg" alt="MyAi.ro">
</span>
<span>
<span class="brand-text">Înapoi</span>
</span>
</a>
<div class="switcher">
<a href="privacy-ro.html" class="lang-link active" data-lang="ro" aria-label="Română">
<img src="img/flags/ro.svg" alt="Română">
</a>
<a href="privacy-en.html" class="lang-link " data-lang="en" aria-label="English">
<img src="img/flags/en.svg" alt="English">
</a>
</div>
</div>
<div class="hero"> <div class="hero">
<div class="kicker">Protecția datelor</div> <div class="kicker">Protecția datelor</div>
@@ -109,16 +91,6 @@
</div> </div>
<div class="footer">
<small>©2026 myAi. Toate drepturile sunt rezervate.</small>
<div class="footer-links">
<a href="terms-ro.html">Termeni și condiții</a>
<a href="privacy-ro.html">Politica de confidențialitate</a>
<a href="cookies-ro.html">Politica de COOKIES</a>
</div>
</div>
</div> </div>
<script src="js/legal.js"></script> <script src="js/legal.js"></script>
</body> </body>
-28
View File
@@ -9,24 +9,6 @@
</head> </head>
<body> <body>
<div class="wrap"> <div class="wrap">
<div class="topbar">
<a class="brand" href="/" aria-label="Back">
<span class="brand-mark">
<img src="/img/myai-logo.svg" alt="MyAi.ro">
</span>
<span>
<span class="brand-text">Back</span>
</span>
</a>
<div class="switcher">
<a href="terms-ro.html" class="lang-link " data-lang="ro" aria-label="Română">
<img src="img/flags/ro.svg" alt="Română">
</a>
<a href="terms-en.html" class="lang-link active" data-lang="en" aria-label="English">
<img src="img/flags/en.svg" alt="English">
</a>
</div>
</div>
<div class="hero"> <div class="hero">
<div class="kicker">Terms of use</div> <div class="kicker">Terms of use</div>
@@ -69,16 +51,6 @@
</div> </div>
<div class="footer">
<small>©2026 myAi. All rights reserved.</small>
<div class="footer-links">
<a href="terms-en.html">Terms and Conditions</a>
<a href="privacy-en.html">Privacy Policy</a>
<a href="cookies-en.html">Cookies Policy</a>
</div>
</div>
</div> </div>
<script src="js/legal.js"></script> <script src="js/legal.js"></script>
</body> </body>
-28
View File
@@ -9,24 +9,6 @@
</head> </head>
<body> <body>
<div class="wrap"> <div class="wrap">
<div class="topbar">
<a class="brand" href="/" aria-label="Înapoi">
<span class="brand-mark">
<img src="/img/myai-logo.svg" alt="MyAi.ro">
</span>
<span>
<span class="brand-text">Înapoi</span>
</span>
</a>
<div class="switcher">
<a href="terms-ro.html" class="lang-link active" data-lang="ro" aria-label="Română">
<img src="img/flags/ro.svg" alt="Română">
</a>
<a href="terms-en.html" class="lang-link " data-lang="en" aria-label="English">
<img src="img/flags/en.svg" alt="English">
</a>
</div>
</div>
<div class="hero"> <div class="hero">
<div class="kicker">Condiții de utilizare</div> <div class="kicker">Condiții de utilizare</div>
@@ -69,16 +51,6 @@
</div> </div>
<div class="footer">
<small>©2026 myAi. Toate drepturile sunt rezervate.</small>
<div class="footer-links">
<a href="terms-ro.html">Termeni și condiții</a>
<a href="privacy-ro.html">Politica de confidențialitate</a>
<a href="cookies-ro.html">Politica de COOKIES</a>
</div>
</div>
</div> </div>
<script src="js/legal.js"></script> <script src="js/legal.js"></script>
</body> </body>