Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 63 additions & 21 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@
]}
</script>
<script>(function(){try{var s=localStorage.getItem('theme');var d=s?s==='dark':matchMedia('(prefers-color-scheme: dark)').matches;if(d)document.documentElement.classList.add('dark')}catch(e){}})();</script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
:root{
--bg:#ffffff; --bg-alt:#f6f6f7; --bg-soft:#f6f6f7; --bg-mute:#f1f1f2; --bg-elv:#ffffff;
Expand Down Expand Up @@ -93,14 +90,16 @@
.nav-r{display:flex;align-items:center;gap:8px}
.icon-btn{width:36px;height:36px;border-radius:8px;display:grid;place-items:center;color:var(--t2);transition:background .25s,color .25s}
.icon-btn:hover{background:var(--bg-soft);color:var(--t1)}
.icon-btn svg{width:20px;height:20px;fill:currentColor}
.switch{position:relative;width:40px;height:22px;border-radius:11px;border:1px solid var(--divider);background:var(--bg-mute);transition:border-color .25s,background .25s;flex:none;margin-left:8px}
.switch:hover{border-color:var(--t3)}
.switch .knob{position:absolute;top:1px;left:1px;width:18px;height:18px;border-radius:50%;background:var(--bg-elv);box-shadow:var(--shadow);transition:transform .25s;display:grid;place-items:center}
html.dark .switch .knob{transform:translateX(18px)}
.switch svg{width:12px;height:12px;fill:var(--t2)}
.switch .sun{display:block} .switch .moon{display:none}
html.dark .switch .sun{display:none} html.dark .switch .moon{display:block}
.icon-btn svg{width:20px;height:20px}
/* кнопка темы вместо ползунка (v1 тоже): луна в светлой, солнце в тёмной */
.theme-btn .sun{display:none}
html.dark .theme-btn .sun{display:block}
html.dark .theme-btn .moon{display:none}
/* версия v2→v1 скрыта на v1; в v2-скине включается */
.ver-btn{display:none!important}
html.v2 .ver-btn{display:grid!important}
/* старый ползунок темы больше не используется */
.switch{display:none!important}
.menu-btn{display:none}

/* sidebar */
Expand Down Expand Up @@ -216,9 +215,10 @@

/* language dropdown */
.lang-dd{position:relative}
.lang-dd>summary{list-style:none;cursor:pointer;display:grid;place-items:center;gap:5px;height:36px;border-radius:8px;border:0;background:none;grid-auto-flow:column;grid-template-columns:auto 10px;align-items:center;padding:0 8px;width:auto;transition:background .25s,color .25s}
.lang-dd>summary{list-style:none;cursor:pointer;display:grid;place-items:center;gap:5px;height:36px;border-radius:8px;border:0;background:none;grid-auto-flow:column;grid-template-columns:auto auto;column-gap:4px;align-items:center;padding:0 8px;width:auto;min-width:32px;transition:background .25s,color .25s}
.lang-dd>summary::-webkit-details-marker{display:none}
.lang-dd>summary svg{width:12px;height:12px;color:var(--t3)}
#lang-label{font:600 12px/1 var(--sans);letter-spacing:.08em}
.lang-dd[open]>summary{background:var(--bg-soft);color:var(--t1)}
.lang-menu{position:absolute;right:0;top:calc(100% + 6px);background:var(--bg-elv);border:1px solid var(--divider);border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.18);padding:4px;min-width:120px;z-index:50}
.lang-menu button{display:block;width:100%;text-align:left;padding:7px 12px;border:0;border-radius:7px;background:none;color:var(--t1);font:inherit;font-size:13px;cursor:pointer;white-space:nowrap}
Expand All @@ -241,24 +241,26 @@ <h1>Пособие по выгодной жизни</h1>

<header class="nav">
<div class="nav-in">
<button class="icon-btn menu-btn" id="menu" aria-label="Открыть фильтры" aria-expanded="false"><svg viewBox="0 0 24 24"><path d="M4 6h16v2H4zm0 5h16v2H4zm0 5h16v2H4z"/></svg></button>
<button class="icon-btn menu-btn" id="menu" aria-label="Открыть фильтры" aria-expanded="false"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="4" x2="20" y1="6" y2="6"/><line x1="4" x2="20" y1="12" y2="12"/><line x1="4" x2="20" y1="18" y2="18"/></svg></button>
<a class="title" href="./"><span class="logo" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M6 12.5l4 4 8-9.5" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/></svg></span><span>Пособие по выгодной жизни</span></a>
<label class="search">
<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5" stroke-linecap="round"/></svg>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
<input id="q" type="search" placeholder="Поиск по рекомендациям" autocomplete="off" aria-label="Поиск по рекомендациям">
<kbd>/</kbd>
</label>
<div class="nav-r">
<details class="lang-dd" id="lang">
<summary class="icon-btn" title="Language / Язык / 语言" aria-label="Выбрать язык"><span id="lang-label">🌐</span><svg viewBox="0 0 24 24" aria-hidden="true"><path d="m7 10 5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></summary>
<summary class="icon-btn" title="Language / Язык / 语言" aria-label="Выбрать язык"><span id="lang-label">РУ</span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></summary>
<div class="lang-menu" role="menu">
<button role="menuitem" data-lang="ru">Русский</button>
<button role="menuitem" data-lang="en">English</button>
<button role="menuitem" data-lang="zh">中文</button>
</div>
</details> <a class="icon-btn" href="README.ru.md" title="Открыть README.ru" aria-label="README"><svg viewBox="0 0 24 24"><path d="M6 2h9l5 5v15H6zm8 1.5V8h4.5zM8 12h8v1.5H8zm0 3.5h8V17H8z"/></svg></a>
<a class="icon-btn" href="https://github.com/dlgrv/HowToLiveBetter" target="_blank" rel="noopener" title="Исходный репозиторий на GitHub" aria-label="GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .3a12 12 0 0 0-3.8 23.4c.6.1.8-.3.8-.6v-2c-3.3.7-4-1.6-4-1.6-.6-1.4-1.4-1.8-1.4-1.8-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1.1 1.8 2.8 1.3 3.5 1 .1-.8.4-1.3.8-1.6-2.7-.3-5.5-1.3-5.5-5.9 0-1.3.5-2.4 1.2-3.2-.1-.3-.5-1.5.1-3.2 0 0 1-.3 3.3 1.2a11.5 11.5 0 0 1 6 0C17.3 5.6 18.3 6 18.3 6c.6 1.7.2 2.9.1 3.2.8.8 1.2 1.9 1.2 3.2 0 4.6-2.8 5.6-5.5 5.9.4.4.8 1.1.8 2.2v3.3c0 .3.2.7.8.6A12 12 0 0 0 12 .3"/></svg></a>
<button class="switch" id="theme" aria-label="Переключить тёмную тему" title="Переключить тёмную тему"><span class="knob"><svg class="sun" viewBox="0 0 24 24"><path d="M12 4a1 1 0 0 1 1 1v1a1 1 0 1 1-2 0V5a1 1 0 0 1 1-1zm0 13a1 1 0 0 1 1 1v1a1 1 0 1 1-2 0v-1a1 1 0 0 1 1-1zm8-6a1 1 0 1 1 0 2h-1a1 1 0 1 1 0-2zM5 11a1 1 0 1 1 0 2H4a1 1 0 1 1 0-2zm12.07-5.07a1 1 0 0 1 0 1.41l-.7.71a1 1 0 1 1-1.42-1.41l.71-.71a1 1 0 0 1 1.41 0zM8.05 16.95a1 1 0 0 1 0 1.41l-.7.71a1 1 0 1 1-1.42-1.41l.71-.71a1 1 0 0 1 1.41 0zm9.02 0l.7.71a1 1 0 1 1-1.41 1.41l-.71-.7a1 1 0 0 1 1.42-1.42zM6.34 5.93l.71.71a1 1 0 0 1-1.41 1.41l-.71-.7a1 1 0 0 1 1.41-1.42zM12 8a4 4 0 1 1 0 8 4 4 0 0 1 0-8z"/></svg><svg class="moon" viewBox="0 0 24 24"><path d="M12.1 22c-5.5 0-10-4.5-10-10 0-4.8 3.4-8.9 8-9.8.5-.1.9.4.7.9A8 8 0 0 0 20.9 13c.5-.2 1 .2.9.7-.9 4.7-5 8.3-9.7 8.3z"/></svg></span></button>
</details>
<a class="icon-btn ic-doc" href="README.ru.md" title="Открыть README.ru" aria-label="README"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M10 9H8"/><path d="M16 13H8"/><path d="M16 17H8"/></svg></a>
<a class="icon-btn ic-gh" href="https://github.com/dlgrv/HowToLiveBetter" target="_blank" rel="noopener" title="Исходный репозиторий на GitHub" aria-label="GitHub"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"/><path d="M9 18c-4.51 2-5-2-7-2"/></svg></a>
<button class="icon-btn ver-btn" id="ver-switch" title="Старая версия сайта" aria-label="Переключить на старую версию"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/><path d="M12 7v5l4 2"/></svg></button>
<button class="icon-btn theme-btn" id="theme" aria-label="Переключить тёмную тему" title="Переключить тёмную тему"><svg class="sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m19.07 4.93-1.41 1.41"/><path d="m6.34 17.66-1.41 1.41"/></svg><svg class="moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/></svg></button>
</div>
</div>
</header>
Expand Down Expand Up @@ -410,7 +412,7 @@ <h1>Пособие по выгодной жизни</h1>
cap:true,
allSections:'Все разделы',
readmeHref:'README.ru.md', readmeTitle:'Открыть README.ru',
menuAria:'Открыть фильтры', themeAria:'Переключить тёмную тему', ghTitle:'Исходный репозиторий на GitHub', ddTitle:'Выбрать язык',
menuAria:'Открыть фильтры', themeAria:'Переключить тёмную тему', ghTitle:'Исходный репозиторий на GitHub', ddTitle:'Выбрать язык', verTitle:'Старая версия сайта',
metaDesc:'Руководство, отсортированное по соотношению «результат/затраты»: 528 рекомендаций — здоровье и долголетие, первая помощь, деньги, защита от мошенников, правовые красные линии, работа, семья. У каждой — стоимость, эффект, уровень доказательности и первоисточник; фильтры по деньгам, времени и силе воли.',
keywords:'здоровье,долголетие,доказательная медицина,смертность,экономия,финансы,мошенники,первая помощь,право,психология',
author:'Как жить выгодно (перевод HowToLiveBetter)',
Expand Down Expand Up @@ -447,7 +449,7 @@ <h1>Пособие по выгодной жизни</h1>
cap:true,
allSections:'All sections',
readmeHref:'README.md', readmeTitle:'Open README',
menuAria:'Open filters', themeAria:'Toggle dark theme', ghTitle:'Source repository on GitHub', ddTitle:'Choose language',
menuAria:'Open filters', themeAria:'Toggle dark theme', ghTitle:'Source repository on GitHub', ddTitle:'Choose language', verTitle:'Old site version',
metaDesc:'A guide sorted by value for money: 528 recommendations — health and longevity, first aid, money, fraud protection, legal red lines, work, family. Each states its cost, benefit, evidence grade, and primary source; filter by money, time, and willpower.',
keywords:'health,longevity,evidence-based medicine,mortality,saving money,personal finance,fraud,first aid,law,psychology',
author:'HowToLiveBetter (English translation)',
Expand Down Expand Up @@ -484,7 +486,7 @@ <h1>Пособие по выгодной жизни</h1>
cap:false,
allSections:'全部小节',
readmeHref:'README.zh.md', readmeTitle:'打开 README.zh',
menuAria:'打开筛选栏', themeAria:'切换深色模式', ghTitle:'GitHub 仓库', ddTitle:'选择语言',
menuAria:'打开筛选栏', themeAria:'切换深色模式', ghTitle:'GitHub 仓库', ddTitle:'选择语言', verTitle:'旧版网站',
metaDesc:'按性价比排序的人生指南:528 条建议——健康长寿、急救、省钱、防骗、法律红线、工作、家庭。每条写明成本、收益、证据等级与原始出处,可按花钱、花时间、要毅力筛选。',
keywords:'健康,长寿,循证医学,死亡率,省钱,个人理财,防骗,急救,法律,心理',
author:'高性价比人生指南',
Expand Down Expand Up @@ -544,6 +546,7 @@ <h1>Пособие по выгодной жизни</h1>
const ddS=document.querySelector('.lang-dd > summary'); if(ddS) ddS.title=t.ddTitle;
const menu=document.getElementById('menu'); if(menu) menu.setAttribute('aria-label',t.menuAria);
const th=document.getElementById('theme'); if(th){ th.setAttribute('aria-label',t.themeAria); th.setAttribute('title',t.themeAria); }
const vb=document.getElementById('ver-switch'); if(vb){ vb.setAttribute('title',t.verTitle); vb.setAttribute('aria-label',t.verTitle); }
const gh=document.querySelector('.nav-r a[href*="github.com/dlgrv"]'); if(gh) gh.setAttribute('title',t.ghTitle);
const rm=document.querySelector('.nav-r a[href^="README"]'); if(rm){ rm.setAttribute('href',t.readmeHref); rm.setAttribute('title',t.readmeTitle); }
// head meta / social cards / JSON-LD
Expand Down Expand Up @@ -805,6 +808,11 @@ <h1>Пособие по выгодной жизни</h1>
<div class="k" data-k="note"></div><div class="v note"></div>
</div>
<details class="src"><summary></summary><div class="body"></div></details>`;
if (window.__HTLB_V2__){
const mg = document.createElement('aside'); mg.className = 'marg';
mg.innerHTML = `<span class="k"></span><span class="mt"></span>`;
c.appendChild(mg);
}
c.querySelector('[data-k="cost"]').textContent = T().kCost;
c.querySelector('[data-k="gain"]').textContent = T().kGain;
c.querySelector('[data-k="note"]').textContent = T().kNote;
Expand Down Expand Up @@ -867,6 +875,8 @@ <h1>Пособие по выгодной жизни</h1>
if (e.human) renderText(f.human, e.human, terms);
renderText(f.gain, e.gain, terms);
renderText(f.note, e.note, terms);
const mg = f.note.closest('.card')?.querySelector('.marg');
if (mg){ mg.querySelector('.k').textContent = T().kNote; renderText(mg.querySelector('.mt'), e.note, terms); }
renderText(f.src, e.src, terms);
const inBody = (e.title+e.human+e.cost+e.gain+e.note).toLowerCase();
f.details.open = terms.length > 0 && terms.some(t => e.src.toLowerCase().includes(t)) && !terms.some(t => inBody.includes(t));
Expand Down Expand Up @@ -904,6 +914,24 @@ <h1>Пособие по выгодной жизни</h1>
PERF.log('apply', t0, `найдено ${shown}, перерисовано ${rerender}`);
}

/* ---------- scroll-spy: подсветка текущего раздела в сайдбаре ---------- */
let SPY_LINKS = null;
function spyTick(){
if (!SPY_LINKS) return;
const navH = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--nav-h')) || 0;
const probe = navH + 120;
let cur = '';
for (const b of BLOCKS){
if (b.el.hidden) continue;
const r = b.el.getBoundingClientRect();
if (r.top <= probe) cur = b.n; else break;
}
for (const {n, btn} of SPY_LINKS){
const on = n === cur;
if (btn.dataset.spy !== String(on)){ btn.dataset.spy = String(on); btn.classList.toggle('spy-on', on); }
}
}

/* ---------- 事件 ---------- */
function wire(){
const sb = document.getElementById('sidebar'), bd = document.getElementById('backdrop'), mb = document.getElementById('menu');
Expand Down Expand Up @@ -948,6 +976,11 @@ <h1>Пособие по выгодной жизни</h1>
document.documentElement.classList.toggle('dark', dark);
try { localStorage.setItem('theme', dark ? 'dark' : 'light'); } catch (e) {}
});
// v2 → v1: та же страница без /v2/, с сохранением запроса и якоря
const vb = document.getElementById('ver-switch');
if (vb) vb.addEventListener('click', () => {
location.href = location.pathname.replace('/v2/', '/') + location.search + location.hash;
});
}

/* ---------- 启动 ---------- */
Expand Down Expand Up @@ -976,6 +1009,15 @@ <h1>Пособие по выгодной жизни</h1>
status.remove();
const t2 = performance.now(); build(sections); PERF.log('построение DOM', t2, CARDS.length + ' карточек');
buildGlossary(); readUrl(); wire(); apply();
// scroll-spy: только в v2-скине, после первой раскладки
if (window.__HTLB_V2__ && BLOCKS.length){
SPY_LINKS = [...document.querySelectorAll('#f-sec .sec-link:not(.all)')].map(btn => ({ n: btn.dataset.v, btn }));
let spyPending = false;
const onScroll = () => { if (spyPending) return; spyPending = true; requestAnimationFrame(() => { spyPending = false; spyTick(); }); };
window.addEventListener('scroll', onScroll, { passive: true });
window.addEventListener('resize', onScroll, { passive: true });
spyTick();
}
PERF.mark(`DOM-узлов ${document.getElementsByTagName('*').length}, терминов ${GLOSS.length}`);
if (location.hash){
const target = document.getElementById(location.hash.slice(1));
Expand Down
Loading