directory: hide the clients line at 0, and profile links are logo only

Clients line: a count of 0 (or an absent count) now renders NO line at all —
never "0 clients", never a dash. The >=1 rules (the plural, the plain number)
are unchanged. Same rule in the runtime renderer and in build-directory.py.

Links row: LinkedIn/GitHub/Upwork/Fiverr now render as LOGO ONLY. The four marks
are one uniform monochrome set (Simple Icons v13, 24x24, single-path), inlined so
the row makes no request and each mark inherits currentColor. Self-hosted copies
in static/icons/. Each link keeps its accessible name (aria-label + title, e.g.
"GitHub profile"); the inline SVG is aria-hidden + focusable=false; the hit area
is 36x36 around a 24px mark, with a visible focus ring.

A null/blank link value still renders no anchor (no empty icon).
This commit is contained in:
webmaster committed 2026-11-03 21:19:00 +00:00
1 parent 1f8179d562
commit c83186f809
6 files changed
+72 -9

No files matched your search

+46 -9
View File
@@ -552,14 +552,33 @@
margin: 0.1rem 0 0;
color: var(--ink-soft);
}
/* Profile links are LOGO ONLY — no visible name. One uniform monochrome SVG set,
inlined (zero requests). The link's accessible name comes from its aria-label.
Each hit area is 36px around a 24px mark, so the row clears the WCAG 2.2 24px
target-size minimum with room to spare. */
.dev-links {
margin: 0;
font-size: 0.85rem;
color: var(--ink-soft);
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.3rem;
}
.dev-links a {
color: var(--brass-deep);
color: var(--midnight);
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border-radius: 50%;
line-height: 0;
}
.dev-links a:hover { color: var(--brass-deep); }
.dev-links a:focus-visible {
outline: 3px solid var(--brass-deep);
outline-offset: 2px;
}
.dev-links svg { display: block; width: 24px; height: 24px; }
/* The "Ask question anonymously" trigger — added by script only while its route is
set. Styled as a link so it sits in the links row where the mailto chip was. */
.dev-links button {
@@ -2461,7 +2480,10 @@
// Our own count — rendered ONCE, with weight, never a score.
var clients = parseInt(rec.odoo4projects_clients, 10);
if (!isNaN(clients)) {
// A count of 0 — or an absent count — shows NO line at all. Not "0 clients",
// not a dash: 0 is not a fact worth printing about a freelancer. The plural
// rules for >= 1 are unchanged ("1 client" / "N clients", the plain number).
if (!isNaN(clients) && clients >= 1) {
var p = liveEl("p", "dev-clients");
p.appendChild(liveEl("span", "dev-clients-n", String(clients)));
p.appendChild(document.createTextNode(" "));
@@ -2495,11 +2517,18 @@
[["Linkedin", "LinkedIn"], ["github", "GitHub"], ["upwork", "Upwork"],
["fiverr", "Fiverr"]].forEach(function (pair) {
var val = String(rec[pair[0]] || "").trim();
var label = pair[1];
if (isLink(val)) {
var a = liveEl("a", null, pair[1]);
// Logo only: the visible content is the SVG, so the link keeps its name in
// the accessibility tree (aria-label + title) and never ships as an empty or
// unnamed anchor. A null/blank value renders NO anchor at all.
var a = liveEl("a", null);
a.href = val;
a.target = "_blank";
a.rel = "noopener nofollow";
a.setAttribute("aria-label", label + " profile");
a.setAttribute("title", label + " profile");
a.innerHTML = LINK_ICONS[label]; // a static constant, never data from a record
links.push(a);
}
});
@@ -2510,10 +2539,7 @@
if (canAsk(rec)) card.setAttribute("data-relay", "1");
if (links.length) {
var row = liveEl("p", "dev-links");
links.forEach(function (a, i) {
if (i) row.appendChild(document.createTextNode(" \u00b7 "));
row.appendChild(a);
});
links.forEach(function (a) { row.appendChild(a); });
card.appendChild(row);
}
if (!canAsk(rec)) {
@@ -2784,6 +2810,17 @@
' stroke-linejoin="round"><circle cx="12" cy="12" r="3"/>' +
'<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>';
/* The four profile marks — ONE uniform monochrome SVG set (Simple Icons, 24 x 24:
same grid, same internal padding, same weight), self-hosted copies in
static/icons/. Inlined so the row makes NO request and the mark inherits
currentColor. The mark is decorative (aria-hidden); the link carries the name. */
var LINK_ICONS = {
LinkedIn: '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>',
GitHub: '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>',
Upwork: '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor"><path d="M18.561 13.158c-1.102 0-2.135-.467-3.074-1.227l.228-1.076.008-.042c.207-1.143.849-3.06 2.839-3.06 1.492 0 2.703 1.212 2.703 2.703-.001 1.489-1.212 2.702-2.704 2.702zm0-8.14c-2.539 0-4.51 1.649-5.31 4.366-1.22-1.834-2.148-4.036-2.687-5.892H7.828v7.112c-.002 1.406-1.141 2.546-2.547 2.548-1.405-.002-2.543-1.143-2.545-2.548V3.492H0v7.112c0 2.914 2.37 5.303 5.281 5.303 2.913 0 5.283-2.389 5.283-5.303v-1.19c.529 1.107 1.182 2.229 1.974 3.221l-1.673 7.873h2.797l1.213-5.71c1.063.679 2.285 1.109 3.686 1.109 3 0 5.439-2.452 5.439-5.45 0-3-2.439-5.439-5.439-5.439z"/></svg>',
Fiverr: '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="currentColor"><path d="M23.004 15.588a.995.995 0 1 0 .002-1.99.995.995 0 0 0-.002 1.99zm-.996-3.705h-.85c-.546 0-.84.41-.84 1.092v2.466h-1.61v-3.558h-.684c-.547 0-.84.41-.84 1.092v2.466h-1.61v-4.874h1.61v.74c.264-.574.626-.74 1.163-.74h1.972v.74c.264-.574.625-.74 1.162-.74h.527v1.316zm-6.786 1.501h-3.359c.088.546.43.858 1.006.858.43 0 .732-.175.83-.487l1.425.4c-.351.848-1.22 1.364-2.255 1.364-1.748 0-2.549-1.355-2.549-2.515 0-1.14.703-2.505 2.45-2.505 1.856 0 2.471 1.384 2.471 2.408 0 .224-.01.37-.02.477zm-1.562-.945c-.04-.42-.342-.81-.889-.81-.508 0-.81.225-.908.81h1.797zM7.508 15.44h1.416l1.767-4.874h-1.62l-.86 2.837-.878-2.837H5.72l1.787 4.874zm-6.6 0H2.51v-3.558h1.524v3.558h1.591v-4.874H2.51v-.302c0-.332.235-.536.606-.536h.918V8.412H2.85c-1.162 0-1.943.712-1.943 1.755v.4H0v1.316h.908v3.558z"/></svg>'
};
/* Add the self-service controls to one card, in ONE row ABOVE the links so the
contact action comes first:
· "Ask question anonymously" — only while its route is set AND the card is
+22
View File
@@ -0,0 +1,22 @@
# static/icons — the profile-link icon set
Four monochrome brand marks shown in the freelancer directory card's links row
(`/odoo-community-developers/`): LinkedIn, GitHub, Upwork, Fiverr.
**Source:** [Simple Icons](https://simpleicons.org) v13 — one uniform set, so the four
share one visual language by construction: the same 24 × 24 grid, the same internal
padding, the same monochrome mass, single-path art. Nothing here is hand-drawn and
nothing is fetched from a third party at runtime.
**How the page uses them.** The card inlines the same path data (see `LINK_ICONS` in the
page's script and in `work/build-directory.py`), so the links row makes **zero requests**
and each mark inherits the link's `currentColor`. These files are the self-hosted,
drop-in copy of that set — identical geometry — for any host that prefers a file over an
inline `<svg>`.
**Brand rule.** A brand mark is never redrawn and never restyled beyond a single
monochrome fill. The one styling the page applies is `fill="currentColor"`.
The `role`/`aria-label` here are for standalone use; the card strips them and marks the
inline SVG `aria-hidden="true" focusable="false"`, putting the accessible name on the
link (`aria-label` + `title`, e.g. "GitHub profile").
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-label="Fiverr"><path fill="currentColor" d="M23.004 15.588a.995.995 0 1 0 .002-1.99.995.995 0 0 0-.002 1.99zm-.996-3.705h-.85c-.546 0-.84.41-.84 1.092v2.466h-1.61v-3.558h-.684c-.547 0-.84.41-.84 1.092v2.466h-1.61v-4.874h1.61v.74c.264-.574.626-.74 1.163-.74h1.972v.74c.264-.574.625-.74 1.162-.74h.527v1.316zm-6.786 1.501h-3.359c.088.546.43.858 1.006.858.43 0 .732-.175.83-.487l1.425.4c-.351.848-1.22 1.364-2.255 1.364-1.748 0-2.549-1.355-2.549-2.515 0-1.14.703-2.505 2.45-2.505 1.856 0 2.471 1.384 2.471 2.408 0 .224-.01.37-.02.477zm-1.562-.945c-.04-.42-.342-.81-.889-.81-.508 0-.81.225-.908.81h1.797zM7.508 15.44h1.416l1.767-4.874h-1.62l-.86 2.837-.878-2.837H5.72l1.787 4.874zm-6.6 0H2.51v-3.558h1.524v3.558h1.591v-4.874H2.51v-.302c0-.332.235-.536.606-.536h.918V8.412H2.85c-1.162 0-1.943.712-1.943 1.755v.4H0v1.316h.908v3.558z"/></svg>

After

Width:  |  Height:  |  Size: 912 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-label="GitHub"><path fill="currentColor" d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>

After

Width:  |  Height:  |  Size: 842 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-label="LinkedIn"><path fill="currentColor" d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>

After

Width:  |  Height:  |  Size: 630 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-label="Upwork"><path fill="currentColor" d="M18.561 13.158c-1.102 0-2.135-.467-3.074-1.227l.228-1.076.008-.042c.207-1.143.849-3.06 2.839-3.06 1.492 0 2.703 1.212 2.703 2.703-.001 1.489-1.212 2.702-2.704 2.702zm0-8.14c-2.539 0-4.51 1.649-5.31 4.366-1.22-1.834-2.148-4.036-2.687-5.892H7.828v7.112c-.002 1.406-1.141 2.546-2.547 2.548-1.405-.002-2.543-1.143-2.545-2.548V3.492H0v7.112c0 2.914 2.37 5.303 5.281 5.303 2.913 0 5.283-2.389 5.283-5.303v-1.19c.529 1.107 1.182 2.229 1.974 3.221l-1.673 7.873h2.797l1.213-5.71c1.063.679 2.285 1.109 3.686 1.109 3 0 5.439-2.452 5.439-5.45 0-3-2.439-5.439-5.439-5.439z"/></svg>

After

Width:  |  Height:  |  Size: 689 B