openvibers/openvibe.tools Commits

Text/Logo pages: shared navbar and footer on every page

OP OpenVibers committed 18 Sept 2026 · e88b2d4965 · 36 files, +176 −301

shared.js initPage() now boots OpenVibeNavbar (service from the hostname,
history + silent login) and OpenVibeFooter; each page's hand-rolled
<footer> became a #ov-footer mount that keeps its related-tool links via
data-related, hubs use the full variant. Body no longer reserves top
padding: the navbar is sticky and in flow.

Changes

ddiff --git a/apps/text/public/ascii.html b/apps/text/public/ascii.html
iindex 7ec6950..3540df7 100644
---- a/apps/text/public/ascii.html
++++ b/apps/text/public/ascii.html
@@@ -74,18 +74,11 @@
</ul>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://fancy.openvibe.tools">Fancy Text</a>
-- <a href="https://zalgo.openvibe.tools">Zalgo Text</a>
-- <a href="https://symbols.openvibe.tools">Symbols</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Fancy Text|https://fancy.openvibe.tools;Zalgo Text|https://zalgo.openvibe.tools;Symbols|https://symbols.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/badge.html b/apps/text/public/badge.html
iindex 1861a49..946eb29 100644
---- a/apps/text/public/badge.html
++++ b/apps/text/public/badge.html
@@@ -102,18 +102,11 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://logo.openvibe.tools">Logo Hub</a>
-- <a href="https://title.openvibe.tools">Title Cards</a>
-- <a href="https://wordmark.openvibe.tools">Wordmark</a>
-- <a href="https://text.openvibe.tools">Text.OpenVibe</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Title Cards|https://title.openvibe.tools;Wordmark|https://wordmark.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/logo-engine.js"></script>
ddiff --git a/apps/text/public/binary.html b/apps/text/public/binary.html
iindex 77d3a42..565f037 100644
---- a/apps/text/public/binary.html
++++ b/apps/text/public/binary.html
@@@ -48,17 +48,11 @@
<div id="binOutput" class="output-box" style="display:none;"></div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://morse.openvibe.tools">Morse Code</a>
-- <a href="https://escape.openvibe.tools">Escape / Unescape</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Morse Code|https://morse.openvibe.tools;Escape / Unescape|https://escape.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/bio.html b/apps/text/public/bio.html
iindex f7a6044..080ac3e 100644
---- a/apps/text/public/bio.html
++++ b/apps/text/public/bio.html
@@@ -44,17 +44,11 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://nickname.openvibe.tools">Nickname Generator</a>
-- <a href="https://fancy.openvibe.tools">Fancy Text</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Nickname Generator|https://nickname.openvibe.tools;Fancy Text|https://fancy.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/braille.html b/apps/text/public/braille.html
iindex 16cf73f..e40d03a 100644
---- a/apps/text/public/braille.html
++++ b/apps/text/public/braille.html
@@@ -50,17 +50,11 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://morse.openvibe.tools">Morse Code</a>
-- <a href="https://binary.openvibe.tools">Binary</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Morse Code|https://morse.openvibe.tools;Binary|https://binary.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/bubble.html b/apps/text/public/bubble.html
iindex 9d8026c..e0c7875 100644
---- a/apps/text/public/bubble.html
++++ b/apps/text/public/bubble.html
@@@ -39,17 +39,11 @@
<div id="output" class="output-grid"></div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://fancy.openvibe.tools">Fancy Text</a>
-- <a href="https://symbols.openvibe.tools">Symbols</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Fancy Text|https://fancy.openvibe.tools;Symbols|https://symbols.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/case.html b/apps/text/public/case.html
iindex 6c5090c..c4aea02 100644
---- a/apps/text/public/case.html
++++ b/apps/text/public/case.html
@@@ -39,18 +39,11 @@
<div id="output" class="output-grid" style="grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));"></div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://fancy.openvibe.tools">Fancy Text</a>
-- <a href="https://clean.openvibe.tools">Text Cleaner</a>
-- <a href="https://count.openvibe.tools">Text Counter</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Fancy Text|https://fancy.openvibe.tools;Text Cleaner|https://clean.openvibe.tools;Text Counter|https://count.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/clean.html b/apps/text/public/clean.html
iindex 67a052d..e39dd22 100644
---- a/apps/text/public/clean.html
++++ b/apps/text/public/clean.html
@@@ -58,17 +58,11 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://count.openvibe.tools">Text Counter</a>
-- <a href="https://escape.openvibe.tools">Escape / Unescape</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Text Counter|https://count.openvibe.tools;Escape / Unescape|https://escape.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/compare.html b/apps/text/public/compare.html
iindex 020c1cf..17abf44 100644
---- a/apps/text/public/compare.html
++++ b/apps/text/public/compare.html
@@@ -70,17 +70,11 @@ A brand new line was added.</textarea>
<div class="diff-output" id="output"></div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://clean.openvibe.tools">Clean Text</a>
-- <a href="https://sort.openvibe.tools">Sort Lines</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Clean Text|https://clean.openvibe.tools;Sort Lines|https://sort.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/shared.js"></script>
ddiff --git a/apps/text/public/count.html b/apps/text/public/count.html
iindex a9479ba..2f0b70d 100644
---- a/apps/text/public/count.html
++++ b/apps/text/public/count.html
@@@ -37,18 +37,11 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://clean.openvibe.tools">Text Cleaner</a>
-- <a href="https://sort.openvibe.tools">Sort Lines</a>
-- <a href="https://case.openvibe.tools">Case Converter</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Text Cleaner|https://clean.openvibe.tools;Sort Lines|https://sort.openvibe.tools;Case Converter|https://case.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/css/shared.css b/apps/text/public/css/shared.css
iindex 4437b58..b946f7c 100644
---- a/apps/text/public/css/shared.css
++++ b/apps/text/public/css/shared.css
@@@ -49,8 +49,7 @@ body {
color: var(--text-primary);
line-height: 1.6;
min-height: 100vh;
-- padding-top: var(--navbar-height);
-- overflow-x: hidden;
++ overflow-x: hidden; /* the shared navbar is sticky and in flow — no reserved top padding */
}
a { color: var(--accent); text-decoration: none; transition: color var(--transition); }
@@@ -698,6 +697,9 @@ textarea.large {
@keyframes toastOut { from { opacity: 1; } to { opacity: 0; transform: translateY(10px); } }
/* ── Footer ────────────────────────────────────────────────── */
++/* The footer itself is the shared OpenVibeFooter (mounted on #ov-footer by shared.js);
++ .site-note is the one-line disclaimer some pages keep above it. */
++.site-note { text-align: center; padding: 24px 24px 0; color: var(--text-muted); font-size: 0.82rem; margin-top: 40px; border-top: 1px solid var(--border); }
.site-footer {
text-align: center;
padding: 40px 24px;
ddiff --git a/apps/text/public/escape.html b/apps/text/public/escape.html
iindex de459c7..5bf509a 100644
---- a/apps/text/public/escape.html
++++ b/apps/text/public/escape.html
@@@ -48,17 +48,11 @@
<div class="escape-grid" id="grid"></div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://unicode.openvibe.tools">Unicode Inspector</a>
-- <a href="https://clean.openvibe.tools">Text Cleaner</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Unicode Inspector|https://unicode.openvibe.tools;Text Cleaner|https://clean.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/fancy.html b/apps/text/public/fancy.html
iindex 63906be..c35733f 100644
---- a/apps/text/public/fancy.html
++++ b/apps/text/public/fancy.html
@@@ -43,19 +43,11 @@
<div id="output" class="output-grid"></div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://zalgo.openvibe.tools">Zalgo Text</a>
-- <a href="https://ascii.openvibe.tools">ASCII Art</a>
-- <a href="https://case.openvibe.tools">Case Converter</a>
-- <a href="https://logo.openvibe.tools">Logo Maker</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Zalgo Text|https://zalgo.openvibe.tools;ASCII Art|https://ascii.openvibe.tools;Case Converter|https://case.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/ice.html b/apps/text/public/ice.html
iindex 53067ac..05a87c3 100644
---- a/apps/text/public/ice.html
++++ b/apps/text/public/ice.html
@@@ -154,7 +154,7 @@
@media print {
.printable { display: block !important; }
.tool-wrap { padding: 0; }
-- .site-footer, .pill-tabs, .alert-banner { display: none; }
++ .ovf, .site-note, .pill-tabs, .alert-banner { display: none; }
}
.tab-content { display: none; }
@@@ -464,18 +464,12 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://peso.openvibe.tools">OpenVibePeso</a>
-- <a href="https://spanish.openvibe.tools">OpenVibeSpanish</a>
-- <a href="https://slang.openvibe.tools">OpenVibeSlang</a>
-- </div>
-- <p>&copy; 2025 OpenVibe &mdash; This is informational only, not legal advice.</p>
-- </footer>
++ <p class="site-note">This is informational only, not legal advice.</p>
++ <div id="ov-footer" data-related="OpenVibePeso|https://peso.openvibe.tools;OpenVibeSpanish|https://spanish.openvibe.tools;OpenVibeSlang|https://slang.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/shared.js"></script>
ddiff --git a/apps/text/public/index.html b/apps/text/public/index.html
iindex acaa6d0..38e5d49 100644
---- a/apps/text/public/index.html
++++ b/apps/text/public/index.html
@@@ -223,25 +223,17 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://openvibe.network">openvibe.tools</a>
-- <a href="https://openvibe.live">openvibe.live</a>
-- <a href="https://openvibe.games">openvibe.games</a>
-- <a href="https://img.openvibe.tools">Img.OpenVibe</a>
-- <a href="https://audio.openvibe.tools">Audio.OpenVibe</a>
-- </div>
-- <p>&copy; OpenVibe — tools for the internet, run by its community.</p>
-- </footer>
++ <div id="ov-footer"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
<script src="/js/shared.js"></script>
<script>
-- OpenVibeUI.initPage();
++ OpenVibeUI.initPage({ footer: 'full' });
const input = document.getElementById('quickInput');
const preview = document.getElementById('quickPreview');
ddiff --git a/apps/text/public/js/shared.js b/apps/text/public/js/shared.js
iindex 8248ddf..9c01a0f 100644
---- a/apps/text/public/js/shared.js
++++ b/apps/text/public/js/shared.js
@@@ -129,9 +129,107 @@ async function shareText(text, title = 'Text.OpenVibe') {
}
}
++// ── Shared chrome: navbar + footer ───────────────────────────
++// Every page loads navbar.js / footer.js from openvibe.network; this is the one place that
++// boots them, so a page only needs a <div id="ov-footer" data-related="Name|url;…"> mount.
++const NETWORK = 'https://openvibe.network';
++const SILENT_LOGIN = 'https://openvibe.tools/auth/login?silent=1&next={url}';
++const LOGO_HOSTS = /^(logo|title|wordmark|textlogo|transparent|badge|sticker|thumbnail|cover|channelart|watermark|neon|overlay|lowerthird)\./;
++
++// The site's own tool list — the footer columns on the hubs, the "more tools" row elsewhere.
++const TEXT_TOOLS = [
++ { name: 'Fancy Text', url: 'https://fancy.openvibe.tools' },
++ { name: 'Zalgo Text', url: 'https://zalgo.openvibe.tools' },
++ { name: 'ASCII Art', url: 'https://ascii.openvibe.tools' },
++ { name: 'Symbols', url: 'https://symbols.openvibe.tools' },
++ { name: 'Kaomoji', url: 'https://kaomoji.openvibe.tools' },
++ { name: 'Case Converter', url: 'https://case.openvibe.tools' },
++ { name: 'Text Counter', url: 'https://count.openvibe.tools' },
++ { name: 'JSON Formatter', url: 'https://json.openvibe.tools' },
++ { name: 'Markdown Preview', url: 'https://markdown.openvibe.tools' },
++ { name: 'Diff Checker', url: 'https://compare.openvibe.tools' },
++ { name: 'Bio Generator', url: 'https://bio.openvibe.tools' },
++];
++const LOGO_TOOLS = [
++ { name: 'Title Cards', url: 'https://title.openvibe.tools' },
++ { name: 'Wordmark', url: 'https://wordmark.openvibe.tools' },
++ { name: 'Transparent PNG', url: 'https://transparent.openvibe.tools' },
++ { name: 'Badges & Stickers', url: 'https://badge.openvibe.tools' },
++ { name: 'Thumbnail Text', url: 'https://thumbnail.openvibe.tools' },
++ { name: 'Watermark', url: 'https://watermark.openvibe.tools' },
++];
++
++function getCookie(name) {
++ const m = document.cookie.match(new RegExp('(?:^|; )' + name + '=([^;]*)'));
++ return m ? decodeURIComponent(m[1]) : null;
++}
++
++function currentService() {
++ return LOGO_HOSTS.test(location.hostname) ? 'logo' : 'text';
++}
++
++/** The tool's name for history: "Case Converter — … | case.openvibe.tools" → "Case Converter — …". */
++function pageTitle() {
++ const h1 = document.querySelector('.page-header h1, .hub-hero h1');
++ const fromH1 = h1 ? h1.textContent.replace(/\s+/g, ' ').trim() : '';
++ return fromH1 || document.title.split('|')[0].trim();
++}
++
++function initNavbar() {
++ if (typeof OpenVibeNavbar === 'undefined') return;
++ const token = getCookie('ov_token') || localStorage.getItem('ov_token');
++ try {
++ OpenVibeNavbar.init({
++ service: currentService(),
++ apiBase: NETWORK,
++ token,
++ history: { type: 'tool', title: pageTitle() },
++ silentLogin: SILENT_LOGIN,
++ });
++ } catch (e) { /* the page works without the navbar */ }
++ if (typeof OpenVibeAccountSwitcher !== 'undefined') {
++ try { OpenVibeAccountSwitcher.init({ apiBase: NETWORK }); } catch (e) { /* optional */ }
++ }
++ if (token && typeof OpenVibeNotifications !== 'undefined') {
++ try {
++ OpenVibeNotifications.init({ token, apiBase: NETWORK });
++ const mount = OpenVibeNavbar.getBellMount && OpenVibeNavbar.getBellMount();
++ if (mount) { const bell = OpenVibeNotifications.createBell(); if (bell) mount.appendChild(bell); }
++ } catch (e) { /* optional */ }
++ }
++}
++
++/** Footer: related tools from the mount's data-related, then the site's own tool list. */
++function initFooter(opts = {}) {
++ if (typeof OpenVibeFooter === 'undefined') return;
++ const mount = document.getElementById('ov-footer');
++ if (!mount) return;
++ const related = (mount.dataset.related || '').split(';').map(s => s.trim()).filter(Boolean).map(pair => {
++ const [name, url] = pair.split('|');
++ return { name: (name || '').trim(), url: (url || '').trim() };
++ }).filter(l => l.name && l.url);
++ const service = currentService();
++ const links = [];
++ if (related.length) links.push({ heading: 'Related tools', items: related });
++ if (service === 'logo') {
++ links.push({ heading: 'Logo tools', items: LOGO_TOOLS });
++ links.push({ heading: 'Text tools', items: TEXT_TOOLS.slice(0, 6) });
++ } else {
++ links.push({ heading: 'Text tools', items: TEXT_TOOLS });
++ links.push({ heading: 'Logo tools', items: LOGO_TOOLS });
++ }
++ try {
++ OpenVibeFooter.init({ service, variant: opts.variant || 'compact', links, apiBase: NETWORK, mount: '#ov-footer' });
++ } catch (e) { /* optional */ }
++}
++
// ── Common page init ─────────────────────────────────────────
--// Called on every page to set up keyboard shortcuts, etc.
--function initPage() {
++// Called on every page: shared chrome, keyboard shortcuts, live-tool affordances.
++// opts.footer — 'full' on the hub pages, 'compact' (default) on tool pages
++function initPage(opts = {}) {
++ initNavbar();
++ initFooter({ variant: opts.footer });
++
// "/" key focuses input (when not already in a field)
document.addEventListener('keydown', (e) => {
if (e.key === '/' && !['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement?.tagName)) {
ddiff --git a/apps/text/public/json.html b/apps/text/public/json.html
iindex de3e4dc..eb5c1a2 100644
---- a/apps/text/public/json.html
++++ b/apps/text/public/json.html
@@@ -67,17 +67,11 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://escape.openvibe.tools">Escape / Unescape</a>
-- <a href="https://markdown.openvibe.tools">Markdown Preview</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Escape / Unescape|https://escape.openvibe.tools;Markdown Preview|https://markdown.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/shared.js"></script>
ddiff --git a/apps/text/public/kaomoji.html b/apps/text/public/kaomoji.html
iindex 1c6a454..9f2d740 100644
---- a/apps/text/public/kaomoji.html
++++ b/apps/text/public/kaomoji.html
@@@ -29,18 +29,11 @@
<div id="categories"></div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://symbols.openvibe.tools">Symbols</a>
-- <a href="https://bio.openvibe.tools">Bio Generator</a>
-- <a href="https://fancy.openvibe.tools">Fancy Text</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Symbols|https://symbols.openvibe.tools;Bio Generator|https://bio.openvibe.tools;Fancy Text|https://fancy.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/logo-hub.html b/apps/text/public/logo-hub.html
iindex a8d1961..b234024 100644
---- a/apps/text/public/logo-hub.html
++++ b/apps/text/public/logo-hub.html
@@@ -120,25 +120,17 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://openvibe.network">openvibe.tools</a>
-- <a href="https://text.openvibe.tools">Text.OpenVibe</a>
-- <a href="https://img.openvibe.tools">Img.OpenVibe</a>
-- <a href="https://audio.openvibe.tools">Audio.OpenVibe</a>
-- <a href="https://openvibe.live">OpenVibe.Live</a>
-- </div>
-- <p>&copy; OpenVibe — tools for the internet, run by its community.</p>
-- </footer>
++ <div id="ov-footer"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/logo-engine.js"></script>
<script src="/js/shared.js"></script>
<script>
-- OpenVibeUI.initPage();
++ OpenVibeUI.initPage({ footer: 'full' });
const input = document.getElementById('quickInput');
const canvas = document.getElementById('previewCanvas');
const presetGrid = document.getElementById('presetGrid');
ddiff --git a/apps/text/public/markdown.html b/apps/text/public/markdown.html
iindex 2e69a91..5fd7634 100644
---- a/apps/text/public/markdown.html
++++ b/apps/text/public/markdown.html
@@@ -88,17 +88,11 @@ Made with ♥ by the OpenVibe Network</textarea>
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://escape.openvibe.tools">Escape / Unescape</a>
-- <a href="https://count.openvibe.tools">Text Counter</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Escape / Unescape|https://escape.openvibe.tools;Text Counter|https://count.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/shared.js"></script>
ddiff --git a/apps/text/public/morse.html b/apps/text/public/morse.html
iindex 35d5320..b7ff94e 100644
---- a/apps/text/public/morse.html
++++ b/apps/text/public/morse.html
@@@ -50,17 +50,11 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://binary.openvibe.tools">Binary</a>
-- <a href="https://fancy.openvibe.tools">Fancy Text</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Binary|https://binary.openvibe.tools;Fancy Text|https://fancy.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/nickname.html b/apps/text/public/nickname.html
iindex 3c44b51..bad3b09 100644
---- a/apps/text/public/nickname.html
++++ b/apps/text/public/nickname.html
@@@ -43,17 +43,11 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://bio.openvibe.tools">Bio Generator</a>
-- <a href="https://fancy.openvibe.tools">Fancy Text</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Bio Generator|https://bio.openvibe.tools;Fancy Text|https://fancy.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/peso.html b/apps/text/public/peso.html
iindex 14b4087..0042eae 100644
---- a/apps/text/public/peso.html
++++ b/apps/text/public/peso.html
@@@ -178,18 +178,11 @@
</p>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://ice.openvibe.tools">ICE Alerts</a>
-- <a href="https://spanish.openvibe.tools">OpenVibeSpanish</a>
-- <a href="https://slang.openvibe.tools">OpenVibeSlang</a>
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="ICE Alerts|https://ice.openvibe.tools;OpenVibeSpanish|https://spanish.openvibe.tools;OpenVibeSlang|https://slang.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/shared.js"></script>
ddiff --git a/apps/text/public/reverse.html b/apps/text/public/reverse.html
iindex 2fc09d0..3645ebf 100644
---- a/apps/text/public/reverse.html
++++ b/apps/text/public/reverse.html
@@@ -39,17 +39,11 @@
<div id="output" class="output-grid"></div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://fancy.openvibe.tools">Fancy Text</a>
-- <a href="https://zalgo.openvibe.tools">Zalgo Text</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Fancy Text|https://fancy.openvibe.tools;Zalgo Text|https://zalgo.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/slang.html b/apps/text/public/slang.html
iindex fd331ef..73b1e03 100644
---- a/apps/text/public/slang.html
++++ b/apps/text/public/slang.html
@@@ -128,18 +128,11 @@
<div class="slang-list" id="slang-list"></div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://ice.openvibe.tools">ICE Alerts</a>
-- <a href="https://peso.openvibe.tools">OpenVibePeso</a>
-- <a href="https://spanish.openvibe.tools">OpenVibeSpanish</a>
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="ICE Alerts|https://ice.openvibe.tools;OpenVibePeso|https://peso.openvibe.tools;OpenVibeSpanish|https://spanish.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/shared.js"></script>
ddiff --git a/apps/text/public/slug.html b/apps/text/public/slug.html
iindex 65ba264..2fa063e 100644
---- a/apps/text/public/slug.html
++++ b/apps/text/public/slug.html
@@@ -46,17 +46,11 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://case.openvibe.tools">Case Converter</a>
-- <a href="https://clean.openvibe.tools">Text Cleaner</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Case Converter|https://case.openvibe.tools;Text Cleaner|https://clean.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/sort.html b/apps/text/public/sort.html
iindex d6ef44f..c1ec2ad 100644
---- a/apps/text/public/sort.html
++++ b/apps/text/public/sort.html
@@@ -56,17 +56,11 @@ elderberry</textarea>
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://clean.openvibe.tools">Text Cleaner</a>
-- <a href="https://count.openvibe.tools">Text Counter</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Text Cleaner|https://clean.openvibe.tools;Text Counter|https://count.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/spanish.html b/apps/text/public/spanish.html
iindex 6e936d9..d617fe7 100644
---- a/apps/text/public/spanish.html
++++ b/apps/text/public/spanish.html
@@@ -114,18 +114,11 @@
<div class="phrase-list" id="phrase-list"></div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://ice.openvibe.tools">ICE Alerts</a>
-- <a href="https://peso.openvibe.tools">OpenVibePeso</a>
-- <a href="https://slang.openvibe.tools">OpenVibeSlang</a>
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="ICE Alerts|https://ice.openvibe.tools;OpenVibePeso|https://peso.openvibe.tools;OpenVibeSlang|https://slang.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/shared.js"></script>
ddiff --git a/apps/text/public/symbols.html b/apps/text/public/symbols.html
iindex e34e734..334180a 100644
---- a/apps/text/public/symbols.html
++++ b/apps/text/public/symbols.html
@@@ -39,18 +39,11 @@
<div id="categories"></div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://kaomoji.openvibe.tools">Kaomoji</a>
-- <a href="https://fancy.openvibe.tools">Fancy Text</a>
-- <a href="https://unicode.openvibe.tools">Unicode Inspector</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Kaomoji|https://kaomoji.openvibe.tools;Fancy Text|https://fancy.openvibe.tools;Unicode Inspector|https://unicode.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/thumbnail.html b/apps/text/public/thumbnail.html
iindex 52a4d49..27d528a 100644
---- a/apps/text/public/thumbnail.html
++++ b/apps/text/public/thumbnail.html
@@@ -118,18 +118,11 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://logo.openvibe.tools">Logo Hub</a>
-- <a href="https://title.openvibe.tools">Title Cards</a>
-- <a href="https://watermark.openvibe.tools">Watermark</a>
-- <a href="https://openvibe.live">OpenVibe.Live</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Title Cards|https://title.openvibe.tools;Watermark|https://watermark.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/logo-engine.js"></script>
ddiff --git a/apps/text/public/title.html b/apps/text/public/title.html
iindex e136416..7099a13 100644
---- a/apps/text/public/title.html
++++ b/apps/text/public/title.html
@@@ -126,18 +126,11 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://logo.openvibe.tools">Logo Hub</a>
-- <a href="https://wordmark.openvibe.tools">Wordmark</a>
-- <a href="https://badge.openvibe.tools">Badge Maker</a>
-- <a href="https://text.openvibe.tools">Text.OpenVibe</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Wordmark|https://wordmark.openvibe.tools;Badge Maker|https://badge.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/logo-engine.js"></script>
ddiff --git a/apps/text/public/transparent.html b/apps/text/public/transparent.html
iindex cdeee95..8223f12 100644
---- a/apps/text/public/transparent.html
++++ b/apps/text/public/transparent.html
@@@ -83,18 +83,11 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://logo.openvibe.tools">Logo Hub</a>
-- <a href="https://title.openvibe.tools">Title Cards</a>
-- <a href="https://wordmark.openvibe.tools">Wordmark</a>
-- <a href="https://text.openvibe.tools">Text.OpenVibe</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Title Cards|https://title.openvibe.tools;Wordmark|https://wordmark.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/logo-engine.js"></script>
ddiff --git a/apps/text/public/unicode.html b/apps/text/public/unicode.html
iindex affdabf..40f08b2 100644
---- a/apps/text/public/unicode.html
++++ b/apps/text/public/unicode.html
@@@ -57,17 +57,11 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://clean.openvibe.tools">Text Cleaner</a>
-- <a href="https://binary.openvibe.tools">Binary</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Text Cleaner|https://clean.openvibe.tools;Binary|https://binary.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>
ddiff --git a/apps/text/public/watermark.html b/apps/text/public/watermark.html
iindex 041abf8..d97f327 100644
---- a/apps/text/public/watermark.html
++++ b/apps/text/public/watermark.html
@@@ -101,18 +101,11 @@
</div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://logo.openvibe.tools">Logo Hub</a>
-- <a href="https://title.openvibe.tools">Title Cards</a>
-- <a href="https://transparent.openvibe.tools">Transparent PNG</a>
-- <a href="https://img.openvibe.tools">Img.OpenVibe</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Title Cards|https://title.openvibe.tools;Transparent PNG|https://transparent.openvibe.tools;Img.OpenVibe|https://img.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/logo-engine.js"></script>
ddiff --git a/apps/text/public/wordmark.html b/apps/text/public/wordmark.html
iindex ba57edb..71bdcbc 100644
---- a/apps/text/public/wordmark.html
++++ b/apps/text/public/wordmark.html
@@@ -72,18 +72,11 @@
<div class="wordmark-grid" id="grid"></div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://logo.openvibe.tools">Logo Hub</a>
-- <a href="https://title.openvibe.tools">Title Cards</a>
-- <a href="https://badge.openvibe.tools">Badge Maker</a>
-- <a href="https://text.openvibe.tools">Text.OpenVibe</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Title Cards|https://title.openvibe.tools;Badge Maker|https://badge.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/logo-engine.js"></script>
ddiff --git a/apps/text/public/zalgo.html b/apps/text/public/zalgo.html
iindex b674ebc..2e390cd 100644
---- a/apps/text/public/zalgo.html
++++ b/apps/text/public/zalgo.html
@@@ -71,18 +71,11 @@
<div id="cleanOutput" class="output-box mono" style="display:none;"></div>
</div>
-- <footer class="site-footer">
-- <div class="footer-links">
-- <a href="https://text.openvibe.tools">Text.OpenVibe Hub</a>
-- <a href="https://fancy.openvibe.tools">Fancy Text</a>
-- <a href="https://clean.openvibe.tools">Text Cleaner</a>
-- <a href="https://symbols.openvibe.tools">Symbols</a>
-- </div>
-- <p>&copy; 2025 OpenVibe</p>
-- </footer>
++ <div id="ov-footer" data-related="Fancy Text|https://fancy.openvibe.tools;Text Cleaner|https://clean.openvibe.tools;Symbols|https://symbols.openvibe.tools"></div>
</div>
<script src="https://openvibe.network/shared/navbar.js"></script>
++ <script src="https://openvibe.network/shared/footer.js"></script>
<script src="https://openvibe.network/shared/notification-ui.js"></script>
<script src="https://openvibe.network/shared/account-switcher.js"></script>
<script src="/js/text-engine.js"></script>