fix(freelancer-directory): card + forms — drop the count hedge, the 15-point sentence and the axis digits; kill every ", as declared"; rename Focus→Skill profile; languages on the shared chart; OCA becomes an "OCA Member Profile" badge; OCA filter re-added off OCA_link

- card count reads "4 clients on ODOO4projects" (no "— a number we recorded"); the
  lede says "our own count" for the same reason. Admin form hint left alone (it is
  an instruction to the operator, not a claim to the visitor).
- removed "15 points over five areas — nobody can be maximum in everything." from
  the card (build + runtime); the forms keep their own explanation.
- removed the visible axis digit (dev-axis-val) from both renderers; the five
  squares stay and each row carries its value as role="img" + aria-label="N of 5".
- removed every ", as declared" (10 on the served page) and rewrote the trust block
  so it no longer promises a label that no longer exists.
- "Focus profile" -> "Skill profile" on the card (build + runtime) and in both form
  legends. The separate `Focus` payload field is untouched.
- languages render through the same dev-axes chart as the skill profile (one
  component, two labels; no digit either).
- OCA becomes a clickable "OCA Member Profile" badge in the card header, once; the
  links row no longer carries it. Same predicate drives the re-added OCA filter
  (OCA_link under https://apps.odoo-community.org/community/), which is a facet in
  the existing filter row, renders only when the data supports it, and filters
  rather than ranks.
This commit is contained in:
webmaster committed 2026-11-03 13:38:12 +00:00
1 parent 5aa4782de7
commit 68dd48e506
2 files changed
+96 -110

No files matched your search

+1 -1
View File
@@ -612,7 +612,7 @@
<span class="hint">Stored as the ISO code (e.g. DE).</span> <span class="hint">Stored as the ISO code (e.g. DE).</span>
</div> </div>
<fieldset class="form-field full focus-field"> <fieldset class="form-field full focus-field">
<legend>Focus profile — five numbers, 0 to 5, totalling 15</legend> <legend>Skill profile — five numbers, 0 to 5, totalling 15</legend>
<div class="focus-axis"> <div class="focus-axis">
<label for="ad-axis-functional">Functional</label> <label for="ad-axis-functional">Functional</label>
<input type="range" id="ad-axis-functional" name="functional" min="0" max="5" step="1" value="0" /> <input type="range" id="ad-axis-functional" name="functional" min="0" max="5" step="1" value="0" />
+95 -109
View File
@@ -616,8 +616,8 @@
outline-color: var(--midnight); outline-color: var(--midnight);
} }
/* ---- 2026-11-03n — the focus profile, the languages line, the OCA chip, /* ---- 2026-11-03n — the skill profile (the shared chart), the OCA Member
the anonymous-contact modal, and the focus sliders (added by this change). ---- */ Profile badge, the anonymous-contact modal, and the focus sliders. ---- */
/* The one number we publish about a person: our own count. Rendered once, with /* The one number we publish about a person: our own count. Rendered once, with
real weight so a visitor can compare two cards — never as a score or a rank. */ real weight so a visitor can compare two cards — never as a score or a rank. */
@@ -633,19 +633,15 @@
color: var(--brass-deep); color: var(--brass-deep);
vertical-align: -0.12em; vertical-align: -0.12em;
} }
.dev-clients-note {
font-size: 0.78rem;
font-style: italic;
color: var(--ink-soft);
}
/* The self-assessed focus profile: one quiet row per axis. */ /* The one chart: five squares per row, used for the skill profile AND the
languages (one component, two labels). One quiet row per item; the row's value
lives in the squares' aria-label, since no digit is printed. */
.dev-profile { .dev-profile {
border-top: 1px solid var(--line); border-top: 1px solid var(--line);
padding-top: 0.55rem; padding-top: 0.55rem;
} }
.dev-profile-label, .dev-profile-label {
.dev-langs-label {
font-size: 0.78rem; font-size: 0.78rem;
letter-spacing: 0.05em; letter-spacing: 0.05em;
text-transform: uppercase; text-transform: uppercase;
@@ -687,48 +683,26 @@
background: var(--brass); background: var(--brass);
border-color: var(--brass-deep); border-color: var(--brass-deep);
} }
.dev-axis-val {
margin-left: auto;
font-variant-numeric: tabular-nums;
color: var(--ink);
}
.dev-profile-note {
margin: 0.5rem 0 0;
font-size: 0.78rem;
font-style: italic;
color: var(--ink-soft);
}
/* Languages: the per-language number, "(as declared)". */ /* The OCA Member Profile badge — a link built from a link the freelancer
.dev-langs { supplied. It sits with the name, not in the links row. Never colour alone:
margin: 0; it is a filled pill and its own words are the link text. */
font-size: 0.85rem; .dev-oca-badge {
color: var(--ink-soft);
}
/* The OCA member chip — FIRST and APART among the links. It must not be
distinguished by colour alone, so it is a filled pill with a leading dot and
its own label, not a bare coloured link. */
.dev-links a.dev-oca {
display: inline-block; display: inline-block;
font-size: 0.78rem; margin-top: 0.3rem;
font-size: 0.72rem;
line-height: 1.4; line-height: 1.4;
padding: 0.12rem 0.6rem; padding: 0.15rem 0.6rem;
border-radius: var(--radius-pill, 999px); border-radius: var(--radius-pill, 999px);
background: rgba(201, 162, 39, 0.2); background: rgba(201, 162, 39, 0.2);
border: 1px solid var(--brass-deep); border: 1px solid var(--brass-deep);
color: var(--midnight); color: var(--midnight);
font-weight: 600; font-weight: 600;
} }
.dev-links a.dev-oca:hover { .dev-oca-badge:hover {
background: rgba(201, 162, 39, 0.32); background: rgba(201, 162, 39, 0.32);
color: var(--midnight); color: var(--midnight);
} }
.dev-oca-tag {
font-weight: 400;
font-style: italic;
color: var(--ink-soft);
}
/* The anonymous-contact trigger (added by script only while its route is set). */ /* The anonymous-contact trigger (added by script only while its route is set). */
.dev-anon-btn { .dev-anon-btn {
@@ -1063,7 +1037,7 @@
<p><strong>You deal with the freelancer, not us.</strong> Each card carries the contact details they chose to publish, and the brief, the price and the delivery are settled between the two of you; we are not a party, as <a href="#listing-note">the note under the listings</a> says. Write to the freelancer whose card fits — the contact is theirs, and their answer comes straight back to you.</p> <p><strong>You deal with the freelancer, not us.</strong> Each card carries the contact details they chose to publish, and the brief, the price and the delivery are settled between the two of you; we are not a party, as <a href="#listing-note">the note under the listings</a> says. Write to the freelancer whose card fits — the contact is theirs, and their answer comes straight back to you.</p>
<p><strong>Nobody pays us to be listed here.</strong> There is no fee to the freelancer and no fee to you for using this page — we charge neither side for the introduction.</p> <p><strong>Nobody pays us to be listed here.</strong> There is no fee to the freelancer and no fee to you for using this page — we charge neither side for the introduction.</p>
<p><strong>We rank nobody.</strong> Nothing here is graded: no score, no ranking, no "best" order. A listing is not a recommendation from us.</p> <p><strong>We rank nobody.</strong> Nothing here is graded: no score, no ranking, no "best" order. A listing is not a recommendation from us.</p>
<p><strong>We verify nothing.</strong> A card is that person's own words. Where a line is the freelancer's own declaration (that they work alone, that they are an OCA member), we label it (as declared): we publish it as written, we do not check it.</p> <p><strong>We verify nothing.</strong> Everything on a card is that person's own words — including anything we add from a link they gave us, such as the OCA Member Profile badge. We pass it on, we do not check it.</p>
<p><strong>An invitation is one click to refuse.</strong> When a freelancer is suggested to us, we invite them once, we say who suggested them, and we give them a single click to opt out.</p> <p><strong>An invitation is one click to refuse.</strong> When a freelancer is suggested to us, we invite them once, we say who suggested them, and we give them a single click to opt out.</p>
</div> </div>
</div> </div>
@@ -1073,7 +1047,7 @@
<section class="section-dark" id="directory"> <section class="section-dark" id="directory">
<div class="container"> <div class="container">
<h2 class="section-title">Freelancers available</h2> <h2 class="section-title">Freelancers available</h2>
<p class="dir-lede">Listings are for freelancers who work on their own — that is the declaration we ask each of them for, and we do not verify it. Where a card shows a number of clients, that is a number we recorded — not a rating, a score or an endorsement. A card shows a photo whether the freelancer gave us a link to one or uploaded an image; otherwise it shows their initials. We make no claim about a freelancer beyond what they wrote and what we can count ourselves.</p> <p class="dir-lede">Listings are for freelancers who work on their own — that is the declaration we ask each of them for, and we do not verify it. Where a card shows a number of clients, that is our own count — not a rating, a score or an endorsement. A card shows a photo whether the freelancer gave us a link to one or uploaded an image; otherwise it shows their initials. We make no claim about a freelancer beyond what they wrote and what we can count ourselves.</p>
<!-- Rendered at build time from our freelancer webhook (one call, no CRM), <!-- Rendered at build time from our freelancer webhook (one call, no CRM),
so the list works with JavaScript disabled. The filter controls below are so the list works with JavaScript disabled. The filter controls below are
@@ -1088,6 +1062,7 @@
<!-- FILTERS-START --> <!-- FILTERS-START -->
<div class="dir-filter"><label for="f-country">Country</label><select id="f-country" data-field="country"><option value="">All</option><option value="py">Paraguay</option></select></div> <div class="dir-filter"><label for="f-country">Country</label><select id="f-country" data-field="country"><option value="">All</option><option value="py">Paraguay</option></select></div>
<div class="dir-filter"><label for="f-languages">Language</label><select id="f-languages" data-field="languages"><option value="">All</option><option value="english">English</option><option value="german">German</option><option value="spanish">Spanish</option></select></div> <div class="dir-filter"><label for="f-languages">Language</label><select id="f-languages" data-field="languages"><option value="">All</option><option value="english">English</option><option value="german">German</option><option value="spanish">Spanish</option></select></div>
<div class="dir-filter"><label for="f-oca">OCA member</label><select id="f-oca" data-field="oca"><option value="">All</option><option value="1">OCA member</option></select></div>
<div class="dir-filter"><label for="f-clients">Clients on ODOO4projects</label><select id="f-clients" data-field="clients" data-match="min"><option value="">All</option><option value="4">4+ clients</option></select></div> <div class="dir-filter"><label for="f-clients">Clients on ODOO4projects</label><select id="f-clients" data-field="clients" data-match="min"><option value="">All</option><option value="4">4+ clients</option></select></div>
<!-- FILTERS-END --> <!-- FILTERS-END -->
<div class="dir-filter dir-clear-wrap"> <div class="dir-filter dir-clear-wrap">
@@ -1097,39 +1072,44 @@
<p class="dir-count" id="dirCount" hidden></p> <p class="dir-count" id="dirCount" hidden></p>
<div class="dir-grid" id="dirGrid"> <div class="dir-grid" id="dirGrid">
<!-- DIRECTORY-LIST-START --> <!-- DIRECTORY-LIST-START -->
<article class="dev-card" data-search="oliver - the oc guy i love to see how far i can push the odoo community version for my clients. besides the module implementation i am quite happy with adding to odoo using hermes agent, n8n and progressive web apps agent automation, manufacturing, e-commerce english german spanish" data-id="2" data-name="Oliver - The OC Guy" data-country="py" data-languages="english|german|spanish" data-clients="4"> <article class="dev-card" data-search="oliver ginwwgnri vieoem " data-id="1" data-name="oliver" data-country="" data-languages="" data-oca="" data-clients="2">
<header class="dev-head">
<img class="dev-photo" src="data:image/jpeg;base64,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 truncated
<div class="dev-id">
<h3 class="dev-name">Oliver - The OC Guy</h3>
</div></header>
<p class="dev-clients"><span class="dev-clients-n">4</span> <span class="dev-clients-w">clients on ODOO4projects</span> <span class="dev-clients-note">— a number we recorded</span></p>
<p class="dev-focus">Agent Automation, Manufacturing, E-commerce</p>
<p class="dev-bio">I love to see how far I can push the ODOO Community version for my clients. Besides the module implementation i am quite happy with adding to odoo using Hermes Agent, N8N and Progressive Web Apps</p>
<div class="dev-profile">
<p class="dev-profile-label">Focus profile, as declared</p>
<ul class="dev-axes">
<li class="dev-axis"><span class="dev-axis-name">Functional</span><span class="dev-axis-squares" aria-hidden="true"><span class="dev-sq on"></span><span class="dev-sq"></span><span class="dev-sq"></span><span class="dev-sq"></span><span class="dev-sq"></span></span><span class="dev-axis-val">1</span></li>
<li class="dev-axis"><span class="dev-axis-name">System</span><span class="dev-axis-squares" aria-hidden="true"><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq"></span></span><span class="dev-axis-val">4</span></li>
<li class="dev-axis"><span class="dev-axis-name">Modules</span><span class="dev-axis-squares" aria-hidden="true"><span class="dev-sq on"></span><span class="dev-sq"></span><span class="dev-sq"></span><span class="dev-sq"></span><span class="dev-sq"></span></span><span class="dev-axis-val">1</span></li>
<li class="dev-axis"><span class="dev-axis-name">Integration</span><span class="dev-axis-squares" aria-hidden="true"><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq"></span></span><span class="dev-axis-val">4</span></li>
<li class="dev-axis"><span class="dev-axis-name">AI</span><span class="dev-axis-squares" aria-hidden="true"><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span></span><span class="dev-axis-val">5</span></li>
</ul>
<p class="dev-profile-note">15 points over five areas — nobody can be maximum in everything.</p>
</div>
<p class="dev-langs"><span class="dev-langs-label">Languages, as declared:</span> English 4 · German 5 · Spanish 1</p>
<p class="dev-links"><a class="dev-oca" href="https://apps.odoo-community.org/community/oliver-arnold" target="_blank" rel="noopener nofollow" aria-label="OCA member profile (as declared)">● OCA profile <span class="dev-oca-tag">(as declared)</span></a> · <a href="https://www.linkedin.com/in/oliver-arnold-2760278b/" target="_blank" rel="noopener nofollow">LinkedIn</a> · <a href="mailto:oliver@odoo4projects.com">Email this freelancer</a></p>
</article>
<article class="dev-card" data-search="oliver ginwwgnri vieoem " data-id="1" data-name="oliver" data-country="" data-languages="" data-clients="2">
<header class="dev-head"> <header class="dev-head">
<span class="dev-avatar" aria-hidden="true">OL</span> <span class="dev-avatar" aria-hidden="true">OL</span>
<div class="dev-id"> <div class="dev-id">
<h3 class="dev-name">oliver</h3> <h3 class="dev-name">oliver</h3>
</div></header> </div></header>
<p class="dev-clients"><span class="dev-clients-n">2</span> <span class="dev-clients-w">clients on ODOO4projects</span> <span class="dev-clients-note">— a number we recorded</span></p> <p class="dev-clients"><span class="dev-clients-n">2</span> <span class="dev-clients-w">clients on ODOO4projects</span></p>
<p class="dev-focus">vieoem</p> <p class="dev-focus">vieoem</p>
<p class="dev-bio">ginwwgnri</p> <p class="dev-bio">ginwwgnri</p>
<p class="dev-contact-none">No contact details published for this freelancer.</p> <p class="dev-contact-none">No contact details published for this freelancer.</p>
</article>
<article class="dev-card" data-search="oliver - the oc guy i love to see how far i can push the odoo community version for my clients. besides the module implementation i am quite happy with adding to odoo using hermes agent, n8n and progressive web apps agent automation, manufacturing, e-commerce english german spanish" data-id="2" data-name="Oliver - The OC Guy" data-country="py" data-languages="english|german|spanish" data-oca="1" data-clients="4">
<header class="dev-head">
<img class="dev-photo" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wgARCAMgAyADASIAAhEBAxEB/8QAHAAAAQUBAQEAAAAAAAAAAAAAAwECBAUGAAcI/8QAGwEAAwEBAQEBAAAAAAAAAAAAAAECAwQFBgf/2gAMAwEAAhADEAAAAd+J4/iP0bnsIPmmqHNqQgXm4CgWsg0Ga5lsI18oE4K3IAo3bMtrKDXGo2dJd6cKOYTl9RCPcSNXmcwSERuMp0mgPVrTxq0OXnAjXoHIThhFOEDMrrMjtxWt/n9E+YQ3B5fXIrOH0WaNh2vG5UZ+AahCyxFGe5BFNS6k+NGForCfRaaWhLWowqLn76p2zwerzWi9DwrWRVp5/uXEnN841Y88RzeDr2zU9jhzUl0NgXTKRxGjiUo27U1Giq9BVx6m+fRonex60oSa+TC6fI2MYjeP2JHP6RaC/rbzv4iz4KYsuM7CVSOJJKzjKyFVSWpkNiFSquzS84pVKZxHSImfZMPnpl4Wpq7nnMjxJC0lKCOKejEQaDCcyYWsGFuufiOdV2Ujs2bMqRu+zEuSSG7rWPKa6tLn1ymV8XTPTBiuzOA7rhjXwLxtoViyboa7Wtowcbfjswa7YxWMdukm8nV+idNecv8AQmswfbpHGGJuSBgW+gol58fdjToH3zEUJbiHWdTIh2WnMFb4/L6eXDrVKzB9GqrOw9Zw6Mtt03WPs2qoKyyp1RNLK08/Ct1cO7ohbUVxgNPj9vXJWi1acvdll06F5dNNnjYx3XRFOayQyq+tEHTAvIhrXDuCFVJrp1c9GDRjTziaIw8dXeg43XEltkdZpgtpFsubuAklZQKm8qndMOMXrzFHOGd7u5izOLYsdOUUzJUTpFq7ONbu5rJfIRzOUzg43c4rs8y/sau4x72IosurkahQ3kcAhyWIDxWAIFjHZDehhkchEmIRqG85ACkh7qBHmxdOfK3MGd2+NevezzvfVXuQikYJEIg2Kjgc17BMc5wWUqNKvzYdXbVF9Ngxg9o843Pnm504dByO8/01RioZm9RSV0Puay2cdyKc/NVg0BJGWxhGGknnK8Eezml5qg/FbXCbc8XZYvRaxpnify9D1EqS1dtUVWYNLm9M594SLfWyMtI550AcH156ePmpmtXBa2wnTQd3co5yNaj47WZXp8+5uKq1y7RNc3LsejQtGRGKpfRSkOe5rlAS444vKFaHdHelMSM5zwisVjJ0gBwraFtx5K1qNH1+VeCnR+H2YLorY3tQxuJlxxNKIVQBIYwYSUAMWmlVx785abm6a2YE658v3+O2WnHbDrpvD6748avdzYddM0u8lDiZ42b6B1Y3fU5wso1fXOr59CY00aUDXloOqGJXL6sZN15/o8rtzklpN1jQTcozn21fYdjW+yVVQawzM0FV6nmWQcwDfl0MWji7Y2saD15TCV6hc22RWdPXr7wbufp+hdT8nuy1+t4nzTr8dPey+cW3F26tubNnvcpTKy/ZnHub4dQ0q9dR8TZdCj1nZ1r3NTQtfNgkglojtmRxrNrhLS/ZTSlJWS21zpXWJFrmk0o2Uy3TWqCTauTrI984WfPfCrKiHMFry1pfRKXn9DIG9APWXmkrfvT88X0GtFhxy110GLW2mawj/Q7wy8Yr/a0a8Uf6P11gLuo01YVlP6eHD0fPm+oFeflRPUlF5070JirDJuFVYldsFPIrrnKsY3aqjAs2mNt1WIk4n0vKFTDB3eaVg1vNgTivNj06oTu4CorJtqp1Qvc8fPb0aTfafCyc/X9hSPkf2nyPf9XYZfP9ADZCjirJEEOpvai9JFFb1HX49hKhW2PU9wyc3U/n8KMGWF1FV4nohhkSO/iKGkR4RxSkHCSQAtXrJSCR7CVe19RiWrX+n8/67TXtJ5ntzzIpAWFSbK0cus/NRzAdtbOxqNByzGachmcg3PmpUWM+/wAv0Gdv+7yt69hOH1yK8jwFz+JG1XFB5ylvVznkFCtGxpGzUHzm4+bu7jSnfI9nwKzrCHeQ3iOxrSLLY55QhpKi1LSDcLkc1nK3hP5jyuVipmkQCTf0B618Z+seN7/ubszZeb69oJ3TUKvmV96uz+t8/wC3wtnaVs7k9CSisw6TEjyBDDIhOhxzDrRp4BAtXifEFcIpLStQGjWM7MUZkcNzSUc4N54mHYj9L531egvsd53vaKbS35nGadghyF5ThodovYpWjzGq52x7XzMrhiMayuvM8+3zLTZy67/K9KeMnD60gg31zk5nOFG8JQngfPRJcxjwL0Y6bop/JNM/MsUQPu+AEkx95N6eqedfolCi65iqgDlwmowjAvMbSdSdHnRkgq5LlFUiYFMwY1XnJCNLGmq9a8H7j9D67f4f6P5PsWcGFJz6W0NgPr8rTsg1fP1692MdGmyXDNc7uPi2s14co96aB+XMzclwZ4z3cfNx0aceWWovgVz27Z9K8V8tEWS/Zn5lTAknpejzthXYsM9G7m+dxw9FFh5RnqnZ+yjWYHo6cu1xgLjdH8vYn60DzUIvTa7Gnb5tpXaY6ONVPz3mNjFCbHbJVNZKInDbOIKH0wSRYkuuayPlU2H6fnwHdZ7ZRLzU3GPTh5OxkRpi5O3nTfnYfTEH5JU+5UbnxIHotLvy5NmgFc1INNJRjQ6ltLKm0YnFElwEVMWX1zWOlRag5oB5qb7T4jdYb+9ERnl+ujdZIxvKx9qirDRfRYtZ+fSbGPtkPrnXY6eeD9ADnvhJO1MGJZ6Od8/m8TS5Pq5bNbM3N6tWO/6VQvukKp+tkKrSTCKo4LdyViy9CcVUO4fNUjb96M67UtrHwv0DzP13qlsia3n6Y73tmjdxiGNTk+QvMEUYxyUiK3IaQKnpUEzZgGiNOMzqp3mXpHhW+Pl1ZLN6vkD9kfo+L1IoLF3P2w5ySExSulKnONJbr63QxayxeY9PodebzyN6DCucYzUPZm5GqkJ4yHu4TnARN9X3hiH6xGsHS+nZHbDL80XTxG5qNe57z5f+hPH+k3ZDj8j1mOKjBSQSHlhtDlydfL6hBr7TkcJ3LPUjm8E+fW3unm+ZUltkvQ4d2yUzg+gcVqyuVqDRhgunkgTBSFQYtcOW2vHiOOpSSBGeBY0uurLwb2HxX2bfotBShc28dziF8RXGURr2rZZIJjyhjlK3HdJcT0GzhExZQ5ho0E4V4xWzUd0fzB7z4D289P6Vm/YLXGNI4PXCQxhjdObUsPx2mnadykeajiriXZWqCv10RPCA1QWs7Ms2IqIVzHc0kC8FU0ke8hUV9BpAaZeW5/0TE93kwSKbTni6nMkWv17Pwe8+Y+wQ4yZ6MQpqyw0fQP6MzaCk0OEV6GbO4mmRU+1qJtcuPw26yvpePobKvsuH6F3K2AfNQowGxlrINDOKYsXnn6Cfx+/6fB9Bb5vbQ9i/ETU9f5/fZxrBeyeRbjY248iXGtUzMsdaVuLmLa/XJq3sZ2EK8dwvn7TLcMw4VtvExAg35sRHcegk8p6o9bXynqiR4p6J590vUb6vtOX0myHzc9xvnSLiCWWV5iIYmmMdZS1nHbIYiIUcw0iRpw5dHHtBzpBj2sQVGO0AFZHsIrVdFnw7UIMyNcUOB9SxHVwYfpCdfnDgzY9LX+ueA+q8PdtH1oOXe6NS2Sl6Q20rGMB4juisCYMMoOkhbLmuEQzmATo2GE/OYzizWVMm1eqrrGR0uK88pHm8b0iTpr5xG9Wcq8qkegqn55daZBZCH6Lw8NP2h5rAH2yp4t+w5LBSNpQtSS+Zeh3zwYGolx0YmRvSXHnZdzGjbGk2Dx4M235rLN1ZA8nzGmbtnrZaTOP0pEyOVwTmEqGlQ2kI16vNCtfUDe8LQjNWbEGQCdI7CCm2xCjHXqoRhC4TgNdOiXMSHYQLiLmdHU7c3n1doqbt8yE8jbyFuMXsYrYei+We/wDl+lSFtQcPo1WX9B8+2DWNJI0eyJNsObnz5bULdclicMvVXdM+0Tix9A1vT63POrlSCRmAhJBEWt0+QZMx2r807OP2RJLOf0wcQiqospAyRqVQA2SgRCSOGFy8kjxq0+jusazz31rHbHfjtJ0YuPWZpGViIBwTvykaNELJeYelRaz8X02Z25tYyCFw3BNC9o0cYLmaavDU3EmgfWd86pNWdgGEcTyxyDYwQJ0NHFFVEFBEOU2OND4zo1SWHIHSr402LWdXWWNftjmaLY53p8+oDMjbYRtXnNElefQXzf8ARnk+sRpA+b7cnA73D75wCBJ0Gz0WF2XEpEeQJc4ZccpVTSXdBfc+BLjasuwyGzyyiu7sV0uNMrJ2R0+Xt12Y2uX9DzfVZHdh0p3Na5idNu7kBFKgkR3UhK9UxoZwo+D3WZKoNZmtHpyX7+NPQxshjiGJ6Z9LCMkDfzG1lKGyDeXnO0zGox67IsQUuS3isAj0YzpbNJrmS21LLCtmNEVoxHINiBieAY489oquJZQRAGZGojSgJIwQmjwpYRUlfawd8aek09btzZiPYw9+OHdU+jEv0X4p7D5vpWgJqeZ7LMhuMjqs0SYDqmw22A1vLrfIj44ucrHNZmrmsfojBYw9GuvyGoyzMCwTPnrpksTQslpKCuh+S2+Q7fL3bcQkvaPxElrXtyMcnWhzxU7aRBgtWbMu640jsrCqd/L87JNeg1WbGFrqMJMee/Dj4U7bSvx4dM9SOk5OzCADUt9WNzeRWQprQXdfJ5PYEsGNeenPnrRu5PVTBSwk6piccTqBOjq5kRUGEkCIASBdTM4RZhsGXFJjRbOM1URrWqpOiiFUyGQuLine truncated
<div class="dev-id">
<h3 class="dev-name">Oliver - The OC Guy</h3>
<a class="dev-oca-badge" href="https://apps.odoo-community.org/community/oliver-arnold" target="_blank" rel="noopener nofollow">OCA Member Profile</a>
</div></header>
<p class="dev-clients"><span class="dev-clients-n">4</span> <span class="dev-clients-w">clients on ODOO4projects</span></p>
<p class="dev-focus">Agent Automation, Manufacturing, E-commerce</p>
<p class="dev-bio">I love to see how far I can push the ODOO Community version for my clients. Besides the module implementation i am quite happy with adding to odoo using Hermes Agent, N8N and Progressive Web Apps</p>
<div class="dev-profile">
<p class="dev-profile-label">Skill profile</p>
<ul class="dev-axes">
<li class="dev-axis"><span class="dev-axis-name">Functional</span><span class="dev-axis-squares" role="img" aria-label="1 of 5"><span class="dev-sq on"></span><span class="dev-sq"></span><span class="dev-sq"></span><span class="dev-sq"></span><span class="dev-sq"></span></span></li>
<li class="dev-axis"><span class="dev-axis-name">System</span><span class="dev-axis-squares" role="img" aria-label="4 of 5"><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq"></span></span></li>
<li class="dev-axis"><span class="dev-axis-name">Modules</span><span class="dev-axis-squares" role="img" aria-label="1 of 5"><span class="dev-sq on"></span><span class="dev-sq"></span><span class="dev-sq"></span><span class="dev-sq"></span><span class="dev-sq"></span></span></li>
<li class="dev-axis"><span class="dev-axis-name">Integration</span><span class="dev-axis-squares" role="img" aria-label="4 of 5"><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq"></span></span></li>
<li class="dev-axis"><span class="dev-axis-name">AI</span><span class="dev-axis-squares" role="img" aria-label="5 of 5"><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span></span></li>
</ul></div>
<div class="dev-profile">
<p class="dev-profile-label">Languages</p>
<ul class="dev-axes">
<li class="dev-axis"><span class="dev-axis-name">English</span><span class="dev-axis-squares" role="img" aria-label="4 of 5"><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq"></span></span></li>
<li class="dev-axis"><span class="dev-axis-name">German</span><span class="dev-axis-squares" role="img" aria-label="5 of 5"><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span><span class="dev-sq on"></span></span></li>
<li class="dev-axis"><span class="dev-axis-name">Spanish</span><span class="dev-axis-squares" role="img" aria-label="1 of 5"><span class="dev-sq on"></span><span class="dev-sq"></span><span class="dev-sq"></span><span class="dev-sq"></span><span class="dev-sq"></span></span></li>
</ul></div>
<p class="dev-links"><a href="https://www.linkedin.com/in/oliver-arnold-2760278b/" target="_blank" rel="noopener nofollow">LinkedIn</a> · <a href="mailto:oliver@odoo4projects.com">Email this freelancer</a></p>
</article> </article>
<!-- DIRECTORY-LIST-END --> <!-- DIRECTORY-LIST-END -->
</div> </div>
@@ -1432,7 +1412,7 @@
<span class="hint">Where you work from. Pick one — this becomes a filter in the directory.</span> <span class="hint">Where you work from. Pick one — this becomes a filter in the directory.</span>
</div> </div>
<fieldset class="form-field full focus-field"> <fieldset class="form-field full focus-field">
<legend>Focus profile — 15 points to distribute</legend> <legend>Skill profile — 15 points to distribute</legend>
<div class="focus-sliders" id="apFocusSliders" hidden> <div class="focus-sliders" id="apFocusSliders" hidden>
<div class="focus-axis"> <div class="focus-axis">
<label for="ap-axis-functional">Functional</label> <label for="ap-axis-functional">Functional</label>
@@ -1502,7 +1482,7 @@
<div class="form-field"> <div class="form-field">
<label for="apOca">OCA profile URL <span class="hint">(optional)</span></label> <label for="apOca">OCA profile URL <span class="hint">(optional)</span></label>
<input id="apOca" name="OCA_link" type="url" placeholder="https://apps.odoo-community.org/community/your-name" /> <input id="apOca" name="OCA_link" type="url" placeholder="https://apps.odoo-community.org/community/your-name" />
<span class="hint">Your OCA member profile link. Where we recognise it, a button leads to it from your card — labelled as your declaration, not as something we verified.</span> <span class="hint">Your OCA member profile link. Where we recognise it, an OCA Member Profile badge on your card links to it — taken from your link, not checked by us.</span>
</div> </div>
<div class="form-field"> <div class="form-field">
<label for="apLinkedin">LinkedIn URL <span class="hint">(optional)</span></label> <label for="apLinkedin">LinkedIn URL <span class="hint">(optional)</span></label>
@@ -2043,6 +2023,7 @@
var LIVE_FILTERS = [ var LIVE_FILTERS = [
["Country", "Country", "country", "value"], ["Country", "Country", "country", "value"],
["__langs__", "Language", "languages", "langnum"], ["__langs__", "Language", "languages", "langnum"],
["__oca__", "OCA member", "oca", "oca"],
["odoo4projects_clients", "Clients on ODOO4projects", "clients", "min"] ["odoo4projects_clients", "Clients on ODOO4projects", "clients", "min"]
]; ];
var LIVE_ALIASES = { Country: ["country"] }; var LIVE_ALIASES = { Country: ["country"] };
@@ -2109,6 +2090,30 @@
return v.indexOf(OCA_MEMBER_PREFIX) === 0 ? v : ""; return v.indexOf(OCA_MEMBER_PREFIX) === 0 ? v : "";
} }
/* One chart block — the SHARED component for the skill profile and the languages
(same squares, two labels; the data sources stay separate). No digit is printed:
five squares per row, and the row's value lives in the squares' accessible name
(role="img" + aria-label), so assistive tech still reads the number. */
function liveChart(label, rows) {
var wrap = liveEl("div", "dev-profile");
wrap.appendChild(liveEl("p", "dev-profile-label", label));
var ul = liveEl("ul", "dev-axes");
rows.forEach(function (row) {
var li = liveEl("li", "dev-axis");
li.appendChild(liveEl("span", "dev-axis-name", row[0]));
var sq = liveEl("span", "dev-axis-squares");
sq.setAttribute("role", "img");
sq.setAttribute("aria-label", row[1] + " of " + FOCUS_MAX);
for (var i = 0; i < FOCUS_MAX; i++) {
sq.appendChild(liveEl("span", "dev-sq" + (i < row[1] ? " on" : "")));
}
li.appendChild(sq);
ul.appendChild(li);
});
wrap.appendChild(ul);
return wrap;
}
function liveSearchText(rec) { function liveSearchText(rec) {
return fold([ return fold([
String(rec.Name || ""), String(rec.Name || ""),
@@ -2124,6 +2129,7 @@
var n = parseInt(rec[field], 10); var n = parseInt(rec[field], 10);
return isNaN(n) ? "" : String(n); return isNaN(n) ? "" : String(n);
} }
if (kind === "oca") return liveOcaLink(rec) ? "1" : "";
if (kind === "langnum") return liveLangsDeclared(rec).map(fold).join("|"); if (kind === "langnum") return liveLangsDeclared(rec).map(fold).join("|");
return liveValues(rec, field).map(fold).join("|"); return liveValues(rec, field).map(fold).join("|");
} }
@@ -2163,11 +2169,20 @@
var head = liveEl("header", "dev-head"); var head = liveEl("header", "dev-head");
var who = liveEl("div", "dev-id"); var who = liveEl("div", "dev-id");
who.appendChild(liveEl("h3", "dev-name", name)); who.appendChild(liveEl("h3", "dev-name", name));
// The OCA Member Profile badge lives with the name. Same predicate as the filter.
var member = liveOcaLink(rec);
if (member) {
var badge = liveEl("a", "dev-oca-badge", "OCA Member Profile");
badge.href = member;
badge.target = "_blank";
badge.rel = "noopener nofollow";
who.appendChild(badge);
}
head.appendChild(avatar); head.appendChild(avatar);
head.appendChild(who); head.appendChild(who);
card.appendChild(head); card.appendChild(head);
// The count we recorded ourselves — rendered ONCE, with weight, never a score. // Our own count — rendered ONCE, with weight, never a score.
var clients = parseInt(rec.odoo4projects_clients, 10); var clients = parseInt(rec.odoo4projects_clients, 10);
if (!isNaN(clients)) { if (!isNaN(clients)) {
var p = liveEl("p", "dev-clients"); var p = liveEl("p", "dev-clients");
@@ -2175,8 +2190,6 @@
p.appendChild(document.createTextNode(" ")); p.appendChild(document.createTextNode(" "));
p.appendChild(liveEl("span", "dev-clients-w", p.appendChild(liveEl("span", "dev-clients-w",
(clients === 1 ? "client" : "clients") + " on ODOO4projects")); (clients === 1 ? "client" : "clients") + " on ODOO4projects"));
p.appendChild(document.createTextNode(" "));
p.appendChild(liveEl("span", "dev-clients-note", "\u2014 a number we recorded"));
card.appendChild(p); card.appendChild(p);
} }
@@ -2188,53 +2201,22 @@
var rows = liveAxisRows(rec); var rows = liveAxisRows(rec);
if (rows.length) { if (rows.length) {
var wrap = liveEl("div", "dev-profile"); card.appendChild(liveChart("Skill profile", rows.map(function (row) {
wrap.appendChild(liveEl("p", "dev-profile-label", "Focus profile, as declared")); return [FOCUS_AXIS_LABELS[row[0]] || row[0], row[1]];
var ul = liveEl("ul", "dev-axes"); })));
rows.forEach(function (row) {
var li = liveEl("li", "dev-axis");
li.appendChild(liveEl("span", "dev-axis-name",
FOCUS_AXIS_LABELS[row[0]] || row[0]));
var sq = liveEl("span", "dev-axis-squares");
sq.setAttribute("aria-hidden", "true");
for (var i = 0; i < FOCUS_MAX; i++) {
sq.appendChild(liveEl("span", "dev-sq" + (i < row[1] ? " on" : "")));
}
li.appendChild(sq);
li.appendChild(liveEl("span", "dev-axis-val", String(row[1])));
ul.appendChild(li);
});
wrap.appendChild(ul);
wrap.appendChild(liveEl("p", "dev-profile-note",
"15 points over five areas \u2014 nobody can be maximum in everything."));
card.appendChild(wrap);
} }
var scores = liveLangScores(rec); var scores = liveLangScores(rec);
var declared = LANG_FIELDS.filter(function (p) { return scores[p[1]] > 0; }); var declared = LANG_FIELDS.filter(function (p) { return scores[p[1]] > 0; });
if (declared.length) { if (declared.length) {
var lp = liveEl("p", "dev-langs"); card.appendChild(liveChart("Languages", declared.map(function (p) {
lp.appendChild(liveEl("span", "dev-langs-label", "Languages, as declared:")); return [p[1], scores[p[1]]];
lp.appendChild(document.createTextNode(" " + declared.map(function (p) { })));
return p[1] + " " + scores[p[1]];
}).join(" \u00b7 ")));
card.appendChild(lp);
} }
var email = String(rec.email || "").trim(); var email = String(rec.email || "").trim();
var hasEmail = email.indexOf("@") !== -1; var hasEmail = email.indexOf("@") !== -1;
var links = []; var links = [];
var member = liveOcaLink(rec);
if (member) {
var chip = liveEl("a", "dev-oca");
chip.href = member;
chip.target = "_blank";
chip.rel = "noopener nofollow";
chip.setAttribute("aria-label", "OCA member profile (as declared)");
chip.appendChild(document.createTextNode("\u25cf OCA profile "));
chip.appendChild(liveEl("span", "dev-oca-tag", "(as declared)"));
links.push(chip);
}
[["Linkedin", "LinkedIn"], ["github", "GitHub"], ["upwork", "Upwork"], [["Linkedin", "LinkedIn"], ["github", "GitHub"], ["upwork", "Upwork"],
["fiverr", "Fiverr"]].forEach(function (pair) { ["fiverr", "Fiverr"]].forEach(function (pair) {
var val = String(rec[pair[0]] || "").trim(); var val = String(rec[pair[0]] || "").trim();
@@ -2305,6 +2287,10 @@
if (counts.length >= 2) { if (counts.length >= 2) {
options = counts.slice(1).map(function (c) { return [String(c), c + "+ clients"]; }); options = counts.slice(1).map(function (c) { return [String(c), c + "+ clients"]; });
} }
} else if (kind === "oca") {
if (records.some(function (r) { return liveOcaLink(r); })) {
options = [["1", "OCA member"]];
}
} else if (kind === "langnum") { } else if (kind === "langnum") {
var seenL = []; var seenL = [];
records.forEach(function (r) { records.forEach(function (r) {