diff --git a/assets/hero-aisle.jpg b/assets/hero-aisle.jpg new file mode 100644 index 0000000..910e4f5 Binary files /dev/null and b/assets/hero-aisle.jpg differ diff --git a/assets/module-inventory.jpg b/assets/module-inventory.jpg new file mode 100644 index 0000000..27a04fe Binary files /dev/null and b/assets/module-inventory.jpg differ diff --git a/assets/tip-backup.jpg b/assets/tip-backup.jpg new file mode 100644 index 0000000..277c9dc Binary files /dev/null and b/assets/tip-backup.jpg differ diff --git a/assets/tip-extend.jpg b/assets/tip-extend.jpg new file mode 100644 index 0000000..402637c Binary files /dev/null and b/assets/tip-extend.jpg differ diff --git a/assets/tip-install.jpg b/assets/tip-install.jpg new file mode 100644 index 0000000..edba282 Binary files /dev/null and b/assets/tip-install.jpg differ diff --git a/css/site.css b/css/site.css index ac165ac..ca7de55 100644 --- a/css/site.css +++ b/css/site.css @@ -654,3 +654,88 @@ html.js [data-rv].rv-in { opacity: 1; transform: none; } .nav-cta { min-height: 44px; } .foot-links { gap: 10px 18px; } } + +/* ---------- featured module as a dark spread ---------- */ +.feature { + background: var(--ink); + color: #f4f2ee; + border: 0; + grid-template-columns: 5fr 7fr; + align-items: stretch; +} +.feature-photo { margin: 0; } +.feature-photo img { width: 100%; height: 100%; min-height: 420px; object-fit: cover; object-position: 50% 45%; } +.feature-body p { color: rgba(255, 255, 255, 0.82); } +.plate-kicker { color: rgba(255, 255, 255, 0.58); } +.feature-name { color: #fff; } +.benefits { border-top-color: rgba(255, 255, 255, 0.25); } +.benefits li { border-bottom-color: rgba(255, 255, 255, 0.16); color: rgba(255, 255, 255, 0.66); } +.benefits strong { color: #fff; } +.feature-note { color: rgba(255, 255, 255, 0.6); } +.feature .btn { background: #f4f2ee; border-color: #f4f2ee; color: var(--ink); } +.feature .btn:hover, .feature .btn:focus-visible { background: transparent; color: #f4f2ee; } + +@media (max-width: 900px) { + .feature { grid-template-columns: 1fr; } + .feature-photo img { min-height: 0; height: clamp(200px, 38vw, 300px); } +} + +/* ---------- OCA module status table ---------- */ +.oca-table { width: 100%; border-collapse: collapse; font-size: var(--step-sm); } +.oca-table thead th { + padding: 0 0 10px; + text-align: left; + font-size: var(--step-xs); + font-weight: 600; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--muted); + border-bottom: 1px solid var(--ink); +} +.oca-table thead th:nth-child(1) { width: 54%; } +.oca-table thead th:nth-child(2) { width: 26%; } +.oca-table thead th:nth-child(3), +.oca-table thead th:nth-child(4) { width: 74px; text-align: center; } +.oca-table tbody td { padding: 13px 0; border-bottom: 1px solid var(--rule); vertical-align: middle; } +.oca-name a { + font-family: var(--serif); + font-size: var(--step-h3); + font-weight: 500; + line-height: 1.2; + text-decoration: none; +} +.oca-name a:hover, .oca-name a:focus-visible { text-decoration: underline; text-underline-offset: 4px; } +.oca-area { + font-size: var(--step-xs); + letter-spacing: 0.14em; + text-transform: uppercase; + color: var(--muted); +} +.oca-status { text-align: center; } +.mark { + display: inline-flex; + align-items: center; + justify-content: center; + width: 22px; + height: 22px; + border: 1px solid var(--rule-strong); + font-size: 12px; + line-height: 1; + color: var(--muted); +} +.mark.is-on { background: var(--ink); border-color: var(--ink); color: var(--paper); } +.oca-note { + margin: 14px 0 0; + max-width: 48em; + font-family: var(--serif); + font-style: italic; + font-size: var(--step-sm); + color: var(--muted); +} + +@media (max-width: 600px) { + .oca-table thead th:nth-child(2), + .oca-table .oca-area { display: none; } + .oca-name a { font-size: var(--step-body); } + .oca-table tbody td { padding: 12px 0; } +} diff --git a/index.html b/index.html index ce565ee..903d072 100644 --- a/index.html +++ b/index.html @@ -39,12 +39,12 @@
- A 1794 wall map of the world engraved in two hemispheres, with marginal notes on voyages and discoveries + A long aisle of shelves in an archive, lit from above, running to a vanishing point
@@ -65,7 +65,7 @@
- A 1689 engraved world map in two hemispheres + Two plain cardboard boxes stacked on a wooden table Install

Run Odoo from Docker Compose, not from source

Two containers, one file, a volume you can copy. The shortest path to a server you @@ -74,7 +74,7 @@ - An engraved seventeenth-century printer's workshop with a hand press and workmen setting type + Rows of old book spines lined up on a shelf Backup

Dump the database nightly and restore it monthly

A backup you have never restored is a hope, not a backup. One pg_dump, one cron line, @@ -83,7 +83,7 @@ - An engraving of four kinds of globe on stands + Hand tools, a clamp and a hammer on a workbench Extend

Take an OCA module before you write your own

Someone already solved your problem and maintains it for every series. Reading their @@ -100,18 +100,12 @@

+
+
+ +

The latest in OCA modules

+ All OCA modules +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Top OCA modules, and whether each has a branch for Odoo 19.0 and 20.0
ModuleArea19.020.0
Mail TrackerUtilitieshas a 19.0 branchno 20.0 branch yet
Account ReconcilationAccountinghas a 19.0 branchno 20.0 branch yet
Account StatementsAccountinghas a 19.0 branchno 20.0 branch yet
Currency Rate UpdateAccountinghas a 19.0 branchno 20.0 branch yet
Enable AccountingAccountinghas a 19.0 branchno 20.0 branch yet
Field ServiceField Servicehas a 19.0 branchno 20.0 branch yet
Job QueSystemhas a 19.0 branchno 20.0 branch yet
+ +

Status read from the OCA module feed on page load. A tick means the module carries a branch for that series; a dash means it does not yet.

+
+
@@ -170,7 +230,7 @@

Ask a question

One question, one answer, by mail. No list, no tracking, no follow-up sequence.

-
+ @@ -188,14 +248,13 @@ Documentation OCA modules App store - Email + Email

- Pictures: “A General Map of the World” by Thomas Kitchin, public domain; - “World Map 1689” by Gerard van Schagen, public domain; - “A printer's workshop”, CC BY 4.0; - “Four types of globe”, CC BY 4.0 — all via Wikimedia Commons. + Photographs from Pixabay, used under the + Pixabay Content License: + archive aisle, cardboard boxes, old books, workshop tools, warehouse shelving. No attribution required; credited anyway.

diff --git a/js/site.js b/js/site.js index f01aec8..2993e39 100644 --- a/js/site.js +++ b/js/site.js @@ -46,12 +46,78 @@ } mail.removeAttribute('aria-invalid'); var body = 'My question about Odoo Community:\n\n\n— reply to: ' + addr + '\n'; - window.location.href = 'mailto:o.arnold@projektbox.de' + window.location.href = 'mailto:oliver@oc-guy.com' + '?subject=' + encodeURIComponent('Odoo Community question') + '&body=' + encodeURIComponent(body); }); } + /* ---------- OCA module status, live from the n8n feed ---------- */ + var ocaBody = document.getElementById('oca-rows'); + var ocaNote = document.getElementById('oca-note'); + + function statusCell(ok, version) { + var td = document.createElement('td'); + td.className = 'oca-status'; + var mark = document.createElement('span'); + mark.className = ok ? 'mark is-on' : 'mark'; + mark.setAttribute('aria-hidden', 'true'); + mark.textContent = ok ? '\u2713' : '\u2014'; + var sr = document.createElement('span'); + sr.className = 'sr-only'; + sr.textContent = ok ? ' has a ' + version + ' branch' : ' no ' + version + ' branch yet'; + td.appendChild(mark); + td.appendChild(sr); + return td; + } + + function renderOca(rows) { + ocaBody.textContent = ''; + rows.forEach(function (m) { + var tr = document.createElement('tr'); + + var name = document.createElement('td'); + name.className = 'oca-name'; + var a = document.createElement('a'); + a.href = m.URL || '#'; + a.target = '_blank'; + a.rel = 'noopener'; + a.textContent = m.name || 'Module'; + name.appendChild(a); + + var area = document.createElement('td'); + area.className = 'oca-area'; + area.textContent = m.area || ''; + + tr.appendChild(name); + tr.appendChild(area); + tr.appendChild(statusCell(!!m.v19, '19.0')); + tr.appendChild(statusCell(!!m.v20, '20.0')); + ocaBody.appendChild(tr); + }); + } + + if (ocaBody) { + fetch('https://n8n.odoo4projects.com/webhook/oc-guy/modules') + .then(function (r) { if (!r.ok) throw new Error('http ' + r.status); return r.json(); }) + .then(function (payload) { + var rows = payload && Array.isArray(payload.data) ? payload.data + : (Array.isArray(payload) ? payload : null); + if (!rows || !rows.length) throw new Error('empty'); + renderOca(rows); + if (ocaNote) { + ocaNote.textContent = 'Status read from the OCA module feed at ' + + new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) + + '. A tick means the module carries a branch for that series; a dash means it does not yet.'; + } + }) + .catch(function () { + if (ocaNote) { + ocaNote.textContent = 'The live feed could not be reached just now; the rows above are the last snapshot.'; + } + }); + } + /* ---------- which section the reader is in ---------- */ var links = Array.prototype.slice.call(document.querySelectorAll('.nav a[href^="#"]')); var sections = links