Public Access
feat(feedback): three-step progress bar + "Sign up here" link
A real <ol> whose current step carries aria-current="step" and whose done step is marked by a tick (never colour alone), following the page state — step 1 when seats are available, step 1 done / step 2 current when a seat is claimed, and no bar at all in the cohort-full and count-unavailable states. The bar states no count and no deadline: both come from the wire. The claimed state gains the signup link: "Sign up here", target="_blank" rel="noopener noreferrer", pointing at the directory page's own #apply form — the one place the application lives, no invented URL. Secondary to any button; the accessible text says it opens a new window. Untouched: the four states, the consent gate, the claim body, the leftKeys contract, the leak rules, the 15 questions, the corrected copy.
This commit is contained in:
1 parent
28d95b4dcd
commit
bb963850b1
1 file changed
+100
-1
+100
-1
@@ -145,6 +145,51 @@
|
||||
.steps { margin: 0.4rem 0 0; padding-left: 1.2rem; font-size: 0.92rem; }
|
||||
.steps li { margin: 0 0 0.3rem; }
|
||||
|
||||
/* ---- Progress bar (three steps) ---- */
|
||||
.progress { margin: 0 0 1.15rem; }
|
||||
.steps-bar {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.3rem 0.6rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.steps-bar .step { display: flex; align-items: center; gap: 0.4rem; color: var(--ink-soft); }
|
||||
.steps-bar .step + .step::before { content: "·"; margin-right: 0.6rem; color: var(--line-brass); }
|
||||
.step-mark {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 1.55rem;
|
||||
height: 1.55rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--line);
|
||||
background: #fff;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1;
|
||||
}
|
||||
/* The current step is the brass pill; a done step carries the ✓ mark (see the script) —
|
||||
the tick is the non-colour cue, so a done step is never colour alone. */
|
||||
.steps-bar .step-current { color: var(--ink); font-weight: 600; }
|
||||
.steps-bar .step-current .step-mark { background: var(--brass); border-color: var(--brass); color: var(--midnight); }
|
||||
.steps-bar .step-done .step-mark { background: var(--success); border-color: var(--success); color: #fff; }
|
||||
.link-signup { color: var(--brass-deep); font-weight: 600; }
|
||||
/* Visually hidden, still read aloud. */
|
||||
.vh {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
clip: rect(0 0 0 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* ---- Feedback list (cohort full) ---- */
|
||||
.fb { border-top: 1px solid var(--line); padding: 1rem 0 0; margin: 1rem 0 0; }
|
||||
.fb:first-of-type { border-top: 0; padding-top: 0.2rem; margin-top: 0.4rem; }
|
||||
@@ -258,6 +303,9 @@
|
||||
var C = window.O4F;
|
||||
var app = document.getElementById("app");
|
||||
var claimedUpwork = ""; // the seat claim: an identifier, kept in memory, never in the URL
|
||||
// The application form on the directory page — the anchor the page's own "Get listed"
|
||||
// triggers use. There is no separate login or account page, so this is the one target.
|
||||
var SIGNUP_URL = "https://odoo4projects.com/odoo-community-developers/#apply";
|
||||
|
||||
function el(tag, cls, text) {
|
||||
var n = document.createElement(tag);
|
||||
@@ -320,6 +368,42 @@
|
||||
return b;
|
||||
}
|
||||
|
||||
// ---- Progress bar (three steps) ---------------------------------------------------------
|
||||
// Which step is current follows the page state — it is not decoration. It renders only
|
||||
// where there is something to do: seats available (step 1 current) and seat claimed
|
||||
// (step 1 done, step 2 current, step 3 visible as what comes next). The cohort-full and
|
||||
// count-unavailable states render no bar at all. The bar states no count and no deadline:
|
||||
// both come from the wire and are printed elsewhere, from the wire alone.
|
||||
var STEP_LABELS = ["Claim seat", "Sign up", "Fill out feedback"];
|
||||
function progressBar(current) {
|
||||
var nav = el("nav", "progress");
|
||||
nav.setAttribute("aria-label", "Signup progress");
|
||||
var ol = el("ol", "steps-bar");
|
||||
STEP_LABELS.forEach(function (label, i) {
|
||||
var n = i + 1;
|
||||
var li = el("li", "step");
|
||||
var mark = el("span", "step-mark");
|
||||
mark.setAttribute("aria-hidden", "true");
|
||||
// A done step shows the ✓ mark; the current and upcoming steps show their number.
|
||||
mark.textContent = n < current ? "\u2713" : String(n);
|
||||
li.appendChild(mark);
|
||||
li.appendChild(el("span", "step-label", label));
|
||||
if (n === current) {
|
||||
li.className = "step step-current";
|
||||
li.setAttribute("aria-current", "step");
|
||||
} else if (n < current) {
|
||||
// Done is the ✓ mark AND a word for screen readers — never colour alone.
|
||||
li.className = "step step-done";
|
||||
li.appendChild(el("span", "vh", " (completed)"));
|
||||
} else {
|
||||
li.className = "step step-next";
|
||||
}
|
||||
ol.appendChild(li);
|
||||
});
|
||||
nav.appendChild(ol);
|
||||
return nav;
|
||||
}
|
||||
|
||||
// ---- The four states -----------------------------------------------------------------
|
||||
// 1. Seats available. The number is read from the wire; a cap is not a remaining count.
|
||||
function stateAvailable(seats, total) {
|
||||
@@ -394,6 +478,7 @@
|
||||
});
|
||||
|
||||
show([
|
||||
progressBar(1),
|
||||
panel([h, el("p", "detail", "One seat per freelancer, and there is a fixed number for this cohort.")]),
|
||||
panel([el("h2", "", "Claim your seat"), form])
|
||||
]);
|
||||
@@ -427,7 +512,21 @@
|
||||
}
|
||||
claimed.appendChild(steps);
|
||||
|
||||
show([claimed, feedbackPanel()]);
|
||||
// The one thing to do while a seat is held: go and finish the signup. A link, never a
|
||||
// second button — the page keeps one primary action at a time, and the target is the
|
||||
// application form the page's own "Get listed" triggers use.
|
||||
var signup = el("p", "detail");
|
||||
var up = el("a", "link-signup");
|
||||
up.href = SIGNUP_URL;
|
||||
up.target = "_blank";
|
||||
up.rel = "noopener noreferrer";
|
||||
up.appendChild(document.createTextNode("Sign up here"));
|
||||
// Say it opens a new window, so a screen-reader user is not surprised by a new tab.
|
||||
up.appendChild(el("span", "", " (opens in a new window)"));
|
||||
signup.appendChild(up);
|
||||
claimed.appendChild(signup);
|
||||
|
||||
show([progressBar(2), claimed, feedbackPanel()]);
|
||||
}
|
||||
|
||||
function clockTime(iso) {
|
||||
|
||||
Reference in new issue
Block a user