Spaces:
Running
Running
Sample handbooks: one click starts the check
Browse files- README.md +1 -1
- index.html +4 -4
- static/app.js +13 -7
- static/style.css +3 -0
README.md
CHANGED
|
@@ -122,7 +122,7 @@ Whole rulebook: each state's questions were asked together, up to 25 per call, s
|
|
| 122 |
## Try it in 2 minutes
|
| 123 |
|
| 124 |
1. **See a finished report:** open the sample report (one made-up handbook checked for Texas, North Carolina and Oregon) or any of the 8 sample reports, each with its answer key. They load instantly and cost nothing.
|
| 125 |
-
2. **Run a live check, no code needed:** under "No handbook handy? Try a sample handbook", load one of the eight sample handbooks, change a sentence or two so they break a rule (for example "no more than four babies" to "up to six babies" in the Texas one), and
|
| 126 |
3. **Your own handbook** needs a free access code (one check a day, sent on request to hi@backpr.com). Checking the same file again is free.
|
| 127 |
|
| 128 |
This Space is a static page: the handbook is read, the rule pages are chosen and every quote is checked in your browser. A small Cloudflare Worker keeps the Beam token, checks the code, accepts only CareRules prompts, enforces spending limits and caches replies. The same page runs at [care.backpr.com](https://care.backpr.com).
|
|
|
|
| 122 |
## Try it in 2 minutes
|
| 123 |
|
| 124 |
1. **See a finished report:** open the sample report (one made-up handbook checked for Texas, North Carolina and Oregon) or any of the 8 sample reports, each with its answer key. They load instantly and cost nothing.
|
| 125 |
+
2. **Run a live check, no code needed:** under "No handbook handy? Try a sample handbook", load one of the eight sample handbooks, change a sentence or two so they break a rule (for example "no more than four babies" to "up to six babies" in the Texas one), and click "Check this handbook". Beam checks it against that state's rules in about 10 to 60 seconds. A planted Texas infant-ratio mistake took 10 seconds and about 1 cent.
|
| 126 |
3. **Your own handbook** needs a free access code (one check a day, sent on request to hi@backpr.com). Checking the same file again is free.
|
| 127 |
|
| 128 |
This Space is a static page: the handbook is read, the rule pages are chosen and every quote is checked in your browser. A small Cloudflare Worker keeps the Beam token, checks the code, accepts only CareRules prompts, enforces spending limits and caches replies. The same page runs at [care.backpr.com](https://care.backpr.com).
|
index.html
CHANGED
|
@@ -26,7 +26,7 @@
|
|
| 26 |
<meta name="twitter:title" content="Does your parent handbook break your state's licensing rules?">
|
| 27 |
<meta name="twitter:description" content="Sentences that break your state's child care licensing rules, missing policies and new wording. 22 states and DC. Free.">
|
| 28 |
<meta name="twitter:image" content="https://care.backpr.com/static/media/og.jpg">
|
| 29 |
-
<link rel="stylesheet" href="static/style.css?v=
|
| 30 |
<script type="application/ld+json">{"@context":"https://schema.org","@graph":[
|
| 31 |
{"@type":"WebApplication","@id":"https://care.backpr.com/#app","name":"CareRules","alternateName":"CareRules Handbook Inspector","url":"https://care.backpr.com/",
|
| 32 |
"description":"Checks a child care center's parent handbook against the official licensing rules of 22 states and DC, and lists conflicting sentences, missing required policies and suggested wording. Every quote is checked word for word. Not legal advice.",
|
|
@@ -234,9 +234,9 @@
|
|
| 234 |
<p class="small">See how it works. These made-up handbooks were written to follow their state's rules. Load one, change a sentence or two to break a rule (a ratio, a nap rule, a medicine rule), and see if CareRules catches it. No code needed: up to 3 checks a day, each against that handbook's state.</p>
|
| 235 |
<div class="access-row"><select id="test-states" aria-label="Sample handbook"></select><button type="button" class="btn btn-ghost" id="test-load">Load handbook</button></div>
|
| 236 |
<div id="test-edit" hidden>
|
| 237 |
-
<label class="label" for="test-text">
|
| 238 |
<textarea id="test-text" rows="12" spellcheck="false"></textarea>
|
| 239 |
-
<button type="button" class="btn
|
| 240 |
</div>
|
| 241 |
</details>
|
| 242 |
<div class="field">
|
|
@@ -352,6 +352,6 @@
|
|
| 352 |
</div>
|
| 353 |
</footer>
|
| 354 |
<script src="static/engine.js?v=ddf3462180"></script>
|
| 355 |
-
<script src="static/app.js?v=
|
| 356 |
</body>
|
| 357 |
</html>
|
|
|
|
| 26 |
<meta name="twitter:title" content="Does your parent handbook break your state's licensing rules?">
|
| 27 |
<meta name="twitter:description" content="Sentences that break your state's child care licensing rules, missing policies and new wording. 22 states and DC. Free.">
|
| 28 |
<meta name="twitter:image" content="https://care.backpr.com/static/media/og.jpg">
|
| 29 |
+
<link rel="stylesheet" href="static/style.css?v=409b4b1ba2">
|
| 30 |
<script type="application/ld+json">{"@context":"https://schema.org","@graph":[
|
| 31 |
{"@type":"WebApplication","@id":"https://care.backpr.com/#app","name":"CareRules","alternateName":"CareRules Handbook Inspector","url":"https://care.backpr.com/",
|
| 32 |
"description":"Checks a child care center's parent handbook against the official licensing rules of 22 states and DC, and lists conflicting sentences, missing required policies and suggested wording. Every quote is checked word for word. Not legal advice.",
|
|
|
|
| 234 |
<p class="small">See how it works. These made-up handbooks were written to follow their state's rules. Load one, change a sentence or two to break a rule (a ratio, a nap rule, a medicine rule), and see if CareRules catches it. No code needed: up to 3 checks a day, each against that handbook's state.</p>
|
| 235 |
<div class="access-row"><select id="test-states" aria-label="Sample handbook"></select><button type="button" class="btn btn-ghost" id="test-load">Load handbook</button></div>
|
| 236 |
<div id="test-edit" hidden>
|
| 237 |
+
<label class="label" for="test-text">Change a sentence or two below, then click "Check this handbook"</label>
|
| 238 |
<textarea id="test-text" rows="12" spellcheck="false"></textarea>
|
| 239 |
+
<button type="button" class="btn" id="test-use"><span>Check this handbook</span> <small>(no code needed)</small></button>
|
| 240 |
</div>
|
| 241 |
</details>
|
| 242 |
<div class="field">
|
|
|
|
| 352 |
</div>
|
| 353 |
</footer>
|
| 354 |
<script src="static/engine.js?v=ddf3462180"></script>
|
| 355 |
+
<script src="static/app.js?v=7626d1f43b"></script>
|
| 356 |
</body>
|
| 357 |
</html>
|
static/app.js
CHANGED
|
@@ -442,19 +442,23 @@ document.addEventListener("click", async (ev) => {
|
|
| 442 |
/* "Plant your own mistake": a compliant test handbook to edit and check */
|
| 443 |
$("#test-load").addEventListener("click", async () => {
|
| 444 |
const code = $("#test-states").value;
|
|
|
|
| 445 |
const text = await fetch(`samples/eval/${code}/clean.md`).then((r) => r.text());
|
| 446 |
$("#test-text").value = text;
|
| 447 |
$("#test-edit").hidden = false;
|
| 448 |
state.chosen = new Set([code]);
|
| 449 |
renderChips(); requestLink();
|
| 450 |
});
|
| 451 |
-
|
|
|
|
| 452 |
if (state.running) return; // a running check keeps its file
|
| 453 |
const code = $("#test-states").value;
|
| 454 |
-
|
|
|
|
|
|
|
| 455 |
state.chosen = new Set([code]); renderChips(); requestLink();
|
| 456 |
-
|
| 457 |
-
|
| 458 |
});
|
| 459 |
|
| 460 |
document.querySelectorAll(".choice").forEach((b) => b.addEventListener("click", () => {
|
|
@@ -483,11 +487,12 @@ drop.addEventListener("drop", (ev) => { if (ev.dataTransfer.files[0]) setFile(ev
|
|
| 483 |
|
| 484 |
const help = (text, bad = true) => { $("#go-help").textContent = text; $("#go-help").classList.toggle("bad", !!text && bad); };
|
| 485 |
|
| 486 |
-
|
|
|
|
| 487 |
if (!state.pages) { help(state.fileError || "Add your parent handbook first."); drop.classList.add("over"); setTimeout(() => drop.classList.remove("over"), 900); return; }
|
| 488 |
if (!state.chosen.size) { help("Pick your state first."); return; }
|
| 489 |
let code = $("#code").value.trim(), status;
|
| 490 |
-
const demo = !
|
| 491 |
if (!code && !demo) { $("#code").focus(); help(`Live checks need a free access code: email ${REQUEST_EMAIL}. Or try a sample handbook, no code needed.`); return; }
|
| 492 |
if (demo) {
|
| 493 |
code = "DEMO"; status = { max_states: 1 };
|
|
@@ -552,7 +557,8 @@ $("#go").addEventListener("click", async () => {
|
|
| 552 |
$("#progress").hidden = true; $("#go").disabled = false;
|
| 553 |
checkCode();
|
| 554 |
}
|
| 555 |
-
}
|
|
|
|
| 556 |
document.addEventListener("click", (ev) => { if (ev.target.id === "retry") $("#go").click(); });
|
| 557 |
|
| 558 |
const save = (blob, name) => {
|
|
|
|
| 442 |
/* "Plant your own mistake": a compliant test handbook to edit and check */
|
| 443 |
$("#test-load").addEventListener("click", async () => {
|
| 444 |
const code = $("#test-states").value;
|
| 445 |
+
if (!code) return; // the list is still loading
|
| 446 |
const text = await fetch(`samples/eval/${code}/clean.md`).then((r) => r.text());
|
| 447 |
$("#test-text").value = text;
|
| 448 |
$("#test-edit").hidden = false;
|
| 449 |
state.chosen = new Set([code]);
|
| 450 |
renderChips(); requestLink();
|
| 451 |
});
|
| 452 |
+
/* One click: read the edited sample handbook and start the live check at once (no code, its own state, Standard). */
|
| 453 |
+
$("#test-use").addEventListener("click", async () => {
|
| 454 |
if (state.running) return; // a running check keeps its file
|
| 455 |
const code = $("#test-states").value;
|
| 456 |
+
$("#test-use").disabled = true;
|
| 457 |
+
await setFile(new File([$("#test-text").value], `sample-handbook-${code}.md`, { type: "text/markdown" }), code);
|
| 458 |
+
$("#test-use").disabled = false;
|
| 459 |
state.chosen = new Set([code]); renderChips(); requestLink();
|
| 460 |
+
if (!state.pages) { help(state.fileError || "Couldn't read the edited handbook. Load it again and retry."); return; }
|
| 461 |
+
runCheck();
|
| 462 |
});
|
| 463 |
|
| 464 |
document.querySelectorAll(".choice").forEach((b) => b.addEventListener("click", () => {
|
|
|
|
| 487 |
|
| 488 |
const help = (text, bad = true) => { $("#go-help").textContent = text; $("#go-help").classList.toggle("bad", !!text && bad); };
|
| 489 |
|
| 490 |
+
async function runCheck() {
|
| 491 |
+
if (state.running) return;
|
| 492 |
if (!state.pages) { help(state.fileError || "Add your parent handbook first."); drop.classList.add("over"); setTimeout(() => drop.classList.remove("over"), 900); return; }
|
| 493 |
if (!state.chosen.size) { help("Pick your state first."); return; }
|
| 494 |
let code = $("#code").value.trim(), status;
|
| 495 |
+
const demo = !!state.demo; // a sample handbook: no code needed (a typed code isn't spent on it), its own state, Standard
|
| 496 |
if (!code && !demo) { $("#code").focus(); help(`Live checks need a free access code: email ${REQUEST_EMAIL}. Or try a sample handbook, no code needed.`); return; }
|
| 497 |
if (demo) {
|
| 498 |
code = "DEMO"; status = { max_states: 1 };
|
|
|
|
| 557 |
$("#progress").hidden = true; $("#go").disabled = false;
|
| 558 |
checkCode();
|
| 559 |
}
|
| 560 |
+
}
|
| 561 |
+
$("#go").addEventListener("click", runCheck);
|
| 562 |
document.addEventListener("click", (ev) => { if (ev.target.id === "retry") $("#go").click(); });
|
| 563 |
|
| 564 |
const save = (blob, name) => {
|
static/style.css
CHANGED
|
@@ -64,6 +64,9 @@ h2 { font-size: clamp(32px, 5vw, 56px); line-height: 1.08; margin: 0 0 18px; max
|
|
| 64 |
.ctas.center { justify-content: center; }
|
| 65 |
.btn { display: inline-flex; align-items: center; justify-content: center; min-height: 48px; padding: 12px 24px; border-radius: 999px; border: 0; background: var(--grad); color: #16121f; font-weight: 700; font-size: 16px; text-decoration: none; cursor: pointer; font-family: var(--sans); }
|
| 66 |
.btn:hover { filter: brightness(1.07); }
|
|
|
|
|
|
|
|
|
|
| 67 |
.btn-ghost { background: rgba(255,255,255,.06); color: var(--text); border: 1px solid rgba(255,255,255,.25); }
|
| 68 |
.btn-big { min-height: 54px; padding: 14px 30px; font-size: 17px; }
|
| 69 |
.btn[disabled] { opacity: .55; cursor: wait; }
|
|
|
|
| 64 |
.ctas.center { justify-content: center; }
|
| 65 |
.btn { display: inline-flex; align-items: center; justify-content: center; min-height: 48px; padding: 12px 24px; border-radius: 999px; border: 0; background: var(--grad); color: #16121f; font-weight: 700; font-size: 16px; text-decoration: none; cursor: pointer; font-family: var(--sans); }
|
| 66 |
.btn:hover { filter: brightness(1.07); }
|
| 67 |
+
.btn small { font-size: 13px; font-weight: 500; opacity: .75; }
|
| 68 |
+
.btn:has(small) { flex-wrap: wrap; column-gap: 6px; text-align: center; }
|
| 69 |
+
.btn:has(small) > * { white-space: nowrap; }
|
| 70 |
.btn-ghost { background: rgba(255,255,255,.06); color: var(--text); border: 1px solid rgba(255,255,255,.25); }
|
| 71 |
.btn-big { min-height: 54px; padding: 14px 30px; font-size: 17px; }
|
| 72 |
.btn[disabled] { opacity: .55; cursor: wait; }
|