Redesign homepage: navy and pink 'sentence is the layout' direction

Complete rebuild of the single page from the design-taste-frontend skill
(direction: sentence-as-layout, seed 1084447843). CSS and JS moved out of
the markup into css/site.css and js/site.js.

- navy field #1a2039 with pink ink #f9a3c0: no Odoo plum, no teal, no violet
- hero headline carries a 1689 world map inside the sentence
- claims as full-bleed switchable bands, tips table, module picker
- four archival Wikimedia pictures, credited in the footer
- inspector: 0 FAIL at 1440 / 768 / 390 (lint clean)
This commit is contained in:
Oliver committed 2026-10-23 14:26:27 +00:00
1 parent ed6d3c747b
commit 94eb541ac3
9 files changed
+1192 -790

No files matched your search

+148
View File
@@ -0,0 +1,148 @@
/* The OC Guy — page behaviour.
Everything here degrades: without JS the page still reads, the bands still
show their titles, the tips still list, the form still shows. */
(function () {
'use strict';
var doc = document.documentElement;
doc.classList.add('js');
var reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
/* ---------- signature move: the shutter on the hero photograph ---------- */
var hero = document.querySelector('.hero-line');
if (hero) {
if (reduce) {
hero.classList.add('shutter');
} else {
requestAnimationFrame(function () {
setTimeout(function () { hero.classList.add('shutter'); }, 120);
});
}
}
/* ---------- entrance for the parts of every section ---------- */
var targets = [];
document.querySelectorAll('.intro .statement, .open h2, .open p, .map-figure figcaption, .tips h2, .tips-note, .picker, .tips-list li, .about h2, .bio, .about-facts, .ask-line, .ask-note, .band-text, .foot-invite, .foot-links').forEach(function (el) {
targets.push(el);
});
if (!reduce && 'IntersectionObserver' in window) {
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (!entry.isIntersecting) return;
entry.target.classList.add('rv-in');
io.unobserve(entry.target);
});
}, { rootMargin: '0px 0px -12% 0px', threshold: 0.12 });
targets.forEach(function (el, i) {
el.setAttribute('data-rv', String((i % 4) + 1));
io.observe(el);
});
} else {
targets.forEach(function (el) { el.classList.add('rv-in'); });
}
/* ---------- switches: five claims ---------- */
document.querySelectorAll('.band-switch').forEach(function (btn) {
btn.addEventListener('click', function () {
var band = btn.closest('.band');
var on = btn.getAttribute('aria-checked') === 'true';
btn.setAttribute('aria-checked', String(!on));
band.setAttribute('data-on', String(!on));
});
});
/* ---------- the live thing: pick what the company does ---------- */
var chips = Array.prototype.slice.call(document.querySelectorAll('.chip'));
var out = document.querySelector('.picker-out');
var installOrder = ['Sales', 'CRM', 'Purchase', 'Manufacturing', 'Inventory', 'Project', 'Timesheets', 'Expenses', 'Invoicing', 'Accounting'];
function render(mods) {
if (!mods.length) {
out.textContent = 'Choose one, or several. The modules stack in the order you would install them.';
return;
}
out.innerHTML = '';
mods.forEach(function (name, i) {
var span = document.createElement('span');
span.className = 'mod';
span.textContent = name;
out.appendChild(span);
if (i < mods.length - 1) {
var arrow = document.createElement('span');
arrow.className = 'arrow';
arrow.textContent = ' → ';
out.appendChild(arrow);
}
});
var note = document.createElement('span');
note.className = 'arrow';
note.textContent = ' — that order, top to bottom.';
out.appendChild(note);
}
chips.forEach(function (chip) {
chip.setAttribute('aria-pressed', 'false');
chip.addEventListener('click', function () {
var pressed = chip.getAttribute('aria-pressed') === 'true';
chip.setAttribute('aria-pressed', String(!pressed));
var picked = chips.filter(function (c) { return c.getAttribute('aria-pressed') === 'true'; })
.reduce(function (all, c) {
c.dataset.modules.split(',').forEach(function (m) {
var name = m.trim();
if (all.indexOf(name) === -1) all.push(name);
});
return all;
}, []);
picked.sort(function (a, b) { return installOrder.indexOf(a) - installOrder.indexOf(b); });
render(picked);
});
});
/* ---------- ask: one question, by mail ---------- */
var send = document.querySelector('.ask-send');
var mail = document.getElementById('ask-mail');
if (send && mail) {
send.addEventListener('click', function () {
var addr = (mail.value || '').trim();
var body = 'My question about Odoo Community:\n\n\n';
if (addr) body += '\n— reply to: ' + addr + '\n';
var href = 'mailto:o.arnold@projektbox.de'
+ '?subject=' + encodeURIComponent('Odoo Community question')
+ '&body=' + encodeURIComponent(body);
if (addr && addr.indexOf('@') === -1) {
mail.focus();
mail.setAttribute('aria-invalid', 'true');
return;
}
mail.removeAttribute('aria-invalid');
window.location.href = href;
});
mail.addEventListener('keydown', function (e) {
if (e.key === 'Enter') send.click();
});
}
/* ---------- one moving picture: the world map drifts against the scroll ---------- */
var map = document.getElementById('worldmap');
if (map && !reduce) {
var ticking = false;
var update = function () {
var rect = map.getBoundingClientRect();
var vh = window.innerHeight || 800;
if (rect.bottom > -200 && rect.top < vh + 200) {
var progress = (rect.top + rect.height / 2 - vh / 2) / vh;
map.style.transform = 'translate3d(0,' + (progress * -26).toFixed(2) + 'px,0) scale(1.06)';
}
ticking = false;
};
window.addEventListener('scroll', function () {
if (!ticking) { ticking = true; requestAnimationFrame(update); }
}, { passive: true });
update();
}
})();