dfc4c403fa
- extend_footer.html: убран inline display:none у блока соцсетей (перебивал
CSS при переносе); слова логотипа = site.Taxonomies.tags (топ-24 по числу
постов, без служебных тегов) вместо [params.typewriter].words
- typewriter.css: скрытие #__social-icons{display:none} (JS снимает id при
переносе в nav -> блок видим через класс), order:2 у .social-icons-inline
- hugo.toml: удалён устаревший [params.typewriter]
103 lines
4.4 KiB
HTML
103 lines
4.4 KiB
HTML
{{- /* dedinit() typewriter: animated topics inside logo parens.
|
|
Pure JS + CSS, no Alpine. Progressive enhancement — no-JS keeps
|
|
the plain "dedinit()" logo. Words = live site tags (popularity
|
|
first), so the logo always reflects the actual blog taxonomy.
|
|
Also: moves theme toggle to the right end of .nav and injects
|
|
social icons (from [params.socialIcons]) next to the menu.
|
|
Icons are rendered server-side via the theme's svg.html partial. */ -}}
|
|
{{- /* Слова для печати: реальные теги сайта, популярные первыми.
|
|
Исключаем служебные/технические теги, которых много и они неинтересны. */ -}}
|
|
{{- $skip := slice "deprecated" "frontmatter" "google-analytics" "aux" "hermes" "herdr" "howto" -}}
|
|
{{- $tags := slice -}}
|
|
{{- range $t, $pages := site.Taxonomies.tags -}}
|
|
{{- if not (in $skip $t) -}}
|
|
{{- $tags = $tags | append (dict "name" $t "count" (len $pages)) -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
{{- $tags = sort $tags "count" "desc" -}}
|
|
{{- if gt (len $tags) 24 }}{{- $tags = first 24 $tags -}}{{- end -}}
|
|
{{- $tw_words := slice -}}
|
|
{{- range $tags -}}{{- $tw_words = $tw_words | append .name -}}{{- end -}}
|
|
{{- $social := site.Params.socialIcons | default (slice) -}}
|
|
<script>
|
|
(() => {
|
|
/* 1) typewriter */
|
|
const LOGO_SEL = 'header .logo a, .logo a';
|
|
const queue = [() => {
|
|
const a = document.querySelector(LOGO_SEL);
|
|
if (!a || a.dataset.twDone) return;
|
|
a.dataset.twDone = '1';
|
|
const text = a.textContent.trim();
|
|
const open = text.lastIndexOf('(');
|
|
const close = text.lastIndexOf(')');
|
|
if (open < 0 || close < open) return;
|
|
const words = {{ $tw_words | jsonify | safeJS }};
|
|
const box = document.createElement('span');
|
|
box.id = 'dedinit-typewriter';
|
|
box.className = 'tw';
|
|
box.appendChild(Object.assign(document.createElement('span'), { className: 'tw-cursor' }));
|
|
a.textContent = '';
|
|
a.appendChild(document.createTextNode(text.slice(0, open + 1)));
|
|
a.appendChild(box);
|
|
a.appendChild(document.createTextNode(text.slice(close)));
|
|
|
|
const TYPE = 90, ERASE = 50, HOLD = 1400, GAP = 400;
|
|
let w = 0, i = 0, dir = 1;
|
|
box.querySelector('.tw-cursor').style.display = 'inline-block';
|
|
const tick = () => {
|
|
const word = words[w];
|
|
box.replaceChildren(document.createTextNode(word.slice(0, i)), box.querySelector('.tw-cursor'));
|
|
let delay;
|
|
if (dir === 1) {
|
|
if (i < word.length) { i++; delay = TYPE; }
|
|
else { dir = -1; delay = HOLD; }
|
|
} else {
|
|
if (i > 0) { i--; delay = ERASE; }
|
|
else { dir = 1; w = (w + 1) % words.length; delay = GAP; }
|
|
}
|
|
setTimeout(tick, delay);
|
|
};
|
|
tick();
|
|
}];
|
|
|
|
/* 2) move theme toggle (logo-switches) to the end of .nav, after #menu.
|
|
It is nested inside .logo in the theme; appending to .nav moves it
|
|
visually to the far right (flex order handled by CSS). */
|
|
const toggleQueue = [() => {
|
|
const nav = document.querySelector('header .nav, .nav');
|
|
const sw = nav && nav.querySelector('.logo-switches');
|
|
if (!nav || !sw || sw.dataset.moved) return;
|
|
sw.dataset.moved = '1';
|
|
nav.appendChild(sw);
|
|
}];
|
|
|
|
/* 3) social icons: a hidden server-rendered container is moved into nav
|
|
next to the menu. The icons are rendered by Hugo (theme svg.html),
|
|
so no client-side icon data is needed. */
|
|
const socialQueue = [() => {
|
|
const nav = document.querySelector('header .nav, .nav');
|
|
const box = document.getElementById('__social-icons');
|
|
if (!nav || !box) return;
|
|
box.id = '';
|
|
const menu = nav.querySelector('#menu');
|
|
if (menu) menu.after(box);
|
|
else nav.appendChild(box);
|
|
}];
|
|
|
|
const run = () => { queue.shift()(); toggleQueue.shift()(); socialQueue.shift()(); };
|
|
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', run);
|
|
else run();
|
|
})();
|
|
</script>
|
|
{{- /* server-rendered social icons; moved into the nav by the JS above.
|
|
display:none so no-JS visitors never see a stray block. */ -}}
|
|
{{- if $social -}}
|
|
<div id="__social-icons" class="social-icons-inline">
|
|
{{- range $social -}}
|
|
<a href="{{ trim .url " " | safeURL }}" target="_blank" rel="noopener noreferrer me"
|
|
title="{{ (.title | default .name) | title }}" class="social-icon">
|
|
{{- partial "svg.html" . -}}
|
|
</a>
|
|
{{- end -}}
|
|
</div>
|
|
{{- end -}} |