Glossary slider: move nav arrows below cards, add 'N / 14' counter
This commit is contained in:
parent
e0daa85982
commit
66e831f07f
83
index.html
83
index.html
@ -767,17 +767,17 @@ main {
|
|||||||
/* ── GLOSSARY (horizontal slider) ── */
|
/* ── GLOSSARY (horizontal slider) ── */
|
||||||
.glossary-slider {
|
.glossary-slider {
|
||||||
margin-top: 40px;
|
margin-top: 40px;
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.glossary {
|
.glossary {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
scroll-snap-type: x mandatory;
|
scroll-snap-type: x mandatory;
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
scroll-padding-left: 8px;
|
padding: 4px 4px 12px;
|
||||||
padding: 4px 4px 16px; /* breathing room + scrollbar gutter */
|
width: 100%;
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
}
|
}
|
||||||
.glossary::-webkit-scrollbar { height: 6px; }
|
.glossary::-webkit-scrollbar { height: 6px; }
|
||||||
@ -790,34 +790,47 @@ main {
|
|||||||
background: #fff;
|
background: #fff;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 0 0 280px; /* fixed card width */
|
flex: 0 0 280px;
|
||||||
|
width: 280px;
|
||||||
scroll-snap-align: start;
|
scroll-snap-align: start;
|
||||||
min-height: 180px;
|
min-height: 200px;
|
||||||
}
|
}
|
||||||
@media (min-width: 640px) { .gloss-item { flex-basis: 320px; min-height: 200px; } }
|
@media (min-width: 640px) { .gloss-item { flex-basis: 320px; width: 320px; min-height: 220px; } }
|
||||||
|
|
||||||
/* nav buttons */
|
/* nav controls: arrows + counter, centered below cards */
|
||||||
.gloss-nav {
|
.gloss-nav {
|
||||||
display: none; /* mobile: rely on swipe */
|
margin-top: 20px;
|
||||||
position: absolute;
|
display: flex;
|
||||||
top: -52px; right: 0;
|
align-items: center;
|
||||||
gap: 8px;
|
justify-content: center;
|
||||||
|
gap: 16px;
|
||||||
}
|
}
|
||||||
@media (min-width: 640px) { .gloss-nav { display: flex; } }
|
|
||||||
|
|
||||||
.gloss-nav-btn {
|
.gloss-nav-btn {
|
||||||
width: 36px; height: 36px;
|
width: 40px; height: 40px;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
display: flex; align-items: center; justify-content: center;
|
display: flex; align-items: center; justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 150ms ease, opacity 150ms ease;
|
transition: background 150ms ease, opacity 150ms ease, border-color 150ms ease;
|
||||||
color: var(--text-65);
|
color: var(--text-65);
|
||||||
}
|
}
|
||||||
.gloss-nav-btn:hover:not(:disabled) { background: var(--hover); color: var(--text); }
|
.gloss-nav-btn:hover:not(:disabled) {
|
||||||
|
background: var(--blue);
|
||||||
|
color: #fff;
|
||||||
|
border-color: var(--blue);
|
||||||
|
}
|
||||||
.gloss-nav-btn:disabled { opacity: 0.3; cursor: not-allowed; }
|
.gloss-nav-btn:disabled { opacity: 0.3; cursor: not-allowed; }
|
||||||
.gloss-nav-btn svg { width: 16px; height: 16px; }
|
.gloss-nav-btn svg { width: 18px; height: 18px; }
|
||||||
|
|
||||||
|
.gloss-counter {
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
color: var(--text-55);
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
min-width: 64px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.gloss-trigger {
|
.gloss-trigger {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -1435,15 +1448,16 @@ footer {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="glossary-slider">
|
<div class="glossary-slider">
|
||||||
|
<div class="glossary" id="glossary-list"></div>
|
||||||
<div class="gloss-nav">
|
<div class="gloss-nav">
|
||||||
<button type="button" id="gloss-prev" class="gloss-nav-btn" aria-label="Назад">
|
<button type="button" id="gloss-prev" class="gloss-nav-btn" aria-label="Назад">
|
||||||
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="10,3 5,8 10,13"/></svg>
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="10,3 5,8 10,13"/></svg>
|
||||||
</button>
|
</button>
|
||||||
|
<span class="gloss-counter" id="gloss-counter">1 / 14</span>
|
||||||
<button type="button" id="gloss-next" class="gloss-nav-btn" aria-label="Вперёд">
|
<button type="button" id="gloss-next" class="gloss-nav-btn" aria-label="Вперёд">
|
||||||
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6,3 11,8 6,13"/></svg>
|
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6,3 11,8 6,13"/></svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="glossary" id="glossary-list"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -1730,22 +1744,39 @@ const SCHEDULE = [
|
|||||||
// Slider controls
|
// Slider controls
|
||||||
const glossPrev = document.getElementById('gloss-prev');
|
const glossPrev = document.getElementById('gloss-prev');
|
||||||
const glossNext = document.getElementById('gloss-next');
|
const glossNext = document.getElementById('gloss-next');
|
||||||
function scrollByCard(direction) {
|
const glossCounter = document.getElementById('gloss-counter');
|
||||||
|
const totalCards = GLOSSARY.length;
|
||||||
|
|
||||||
|
function cardStep() {
|
||||||
const firstCard = glossaryEl.querySelector('.gloss-item');
|
const firstCard = glossaryEl.querySelector('.gloss-item');
|
||||||
if (!firstCard) return;
|
if (!firstCard) return 0;
|
||||||
const step = firstCard.getBoundingClientRect().width + 12; // card + gap
|
const cs = window.getComputedStyle(glossaryEl);
|
||||||
glossaryEl.scrollBy({ left: direction * step, behavior: 'smooth' });
|
const gap = parseFloat(cs.columnGap || cs.gap || '12');
|
||||||
|
return firstCard.getBoundingClientRect().width + gap;
|
||||||
|
}
|
||||||
|
function currentIndex() {
|
||||||
|
const step = cardStep();
|
||||||
|
return step ? Math.round(glossaryEl.scrollLeft / step) : 0;
|
||||||
|
}
|
||||||
|
function scrollToIndex(i) {
|
||||||
|
const step = cardStep();
|
||||||
|
const clamped = Math.max(0, Math.min(totalCards - 1, i));
|
||||||
|
glossaryEl.scrollTo({ left: clamped * step, behavior: 'smooth' });
|
||||||
}
|
}
|
||||||
function updateGlossNav() {
|
function updateGlossNav() {
|
||||||
const maxScroll = glossaryEl.scrollWidth - glossaryEl.clientWidth - 2;
|
const idx = currentIndex();
|
||||||
|
glossCounter.textContent = `${idx + 1} / ${totalCards}`;
|
||||||
|
const maxScroll = glossaryEl.scrollWidth - glossaryEl.clientWidth;
|
||||||
glossPrev.disabled = glossaryEl.scrollLeft <= 2;
|
glossPrev.disabled = glossaryEl.scrollLeft <= 2;
|
||||||
glossNext.disabled = glossaryEl.scrollLeft >= maxScroll;
|
glossNext.disabled = glossaryEl.scrollLeft >= maxScroll - 2;
|
||||||
}
|
}
|
||||||
glossPrev.addEventListener('click', () => scrollByCard(-1));
|
|
||||||
glossNext.addEventListener('click', () => scrollByCard(1));
|
glossPrev.addEventListener('click', () => scrollToIndex(currentIndex() - 1));
|
||||||
|
glossNext.addEventListener('click', () => scrollToIndex(currentIndex() + 1));
|
||||||
glossaryEl.addEventListener('scroll', updateGlossNav, { passive: true });
|
glossaryEl.addEventListener('scroll', updateGlossNav, { passive: true });
|
||||||
window.addEventListener('resize', updateGlossNav);
|
window.addEventListener('resize', updateGlossNav);
|
||||||
updateGlossNav();
|
// initial state after layout settles
|
||||||
|
requestAnimationFrame(updateGlossNav);
|
||||||
|
|
||||||
// Render projects
|
// Render projects
|
||||||
const projectsEl = document.getElementById('projects-grid');
|
const projectsEl = document.getElementById('projects-grid');
|
||||||
|
|||||||
Reference in New Issue
Block a user