mirror of
https://github.com/HananoshikaYomaru/openfreebooks.git
synced 2026-11-13 21:15:54 +00:00
Refactor math chapter structure and styling: Update .gitignore to exclude specific CSS directories, enhance CONTRIBUTING.md with new guidelines for subject-specific assets, and streamline chapter content organization. Modify curriculum data to include new chapter dependencies and improve frontend logic for loading shared styles and scripts. Adjust styles for better visual consistency across math chapters.
This commit is contained in:
parent
5175811579
commit
a2679aa4de
24 changed files with 2104 additions and 530 deletions
|
|
@ -37,34 +37,7 @@
|
|||
color: var(--muted);
|
||||
}
|
||||
|
||||
// Dot pictures for compare chains (same idea as counting chapter)
|
||||
.notation-dots {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.notation-dots__dot {
|
||||
display: block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
background: #0f766e;
|
||||
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.12);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.notation-dots--chain {
|
||||
max-width: 88px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.notation-dots--decimal .notation-dots__dot {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
// notation-dots: content/math/subject.scss
|
||||
|
||||
.notation-compare-chain {
|
||||
margin: 1.25rem 0;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
+++
|
||||
title = "Counting and numbers"
|
||||
description = "Count from zero, spot patterns, add, multiply, and divide; then meet place value and big numbers from hundreds to billions."
|
||||
description = "Count objects, spot patterns, add, multiply, and divide; then meet place value and big numbers from hundreds to billions."
|
||||
template = "chapter.html"
|
||||
weight = 0
|
||||
weight = 1
|
||||
[extra]
|
||||
subject = "math"
|
||||
chapter_id = "counting-and-numbers"
|
||||
|
|
@ -11,10 +11,11 @@ strand = "Number & Algebra"
|
|||
|
||||
<div class="book-prose">
|
||||
<p>
|
||||
Look around you. How many birds? How many cups? You can answer by
|
||||
<strong>counting</strong> — pointing at one thing at a time until everything has been pointed at.
|
||||
This chapter uses <strong>pictures of dots</strong> to stand for real things, like marbles or
|
||||
fingers.
|
||||
You already met <strong>0</strong> and <strong>1</strong> in
|
||||
<a href="/math/zero-and-one/">Zero and one</a>. Now look around: how many birds? how many cups?
|
||||
You answer by <strong>counting</strong> — pointing at one thing at a time until everything has
|
||||
been pointed at. This chapter uses <strong>pictures of dots</strong> to stand for real things,
|
||||
like marbles or fingers.
|
||||
</p>
|
||||
|
||||
<h2 id="what-is-counting" class="book-prose__heading">What is counting?</h2>
|
||||
|
|
@ -27,20 +28,13 @@ strand = "Number & Algebra"
|
|||
the number of fingers matches the number of objects.
|
||||
</p>
|
||||
|
||||
<h2 id="zero" class="book-prose__heading">Zero</h2>
|
||||
<h2 id="zero" class="book-prose__heading">Zero and one (recap)</h2>
|
||||
<p>
|
||||
When there is <strong>nothing</strong> to point at, we write <strong>0</strong> and say
|
||||
<strong>zero</strong>. An empty plate, no toys in the box — zero dots:
|
||||
<strong>0</strong> means nothing to count; <strong>1</strong> means exactly one. When you count
|
||||
aloud you still say zero before one, then two, and so on. If you want the full picture of
|
||||
nothing versus one — and how that pairs with false and true — revisit
|
||||
<a href="/math/zero-and-one/#zero">Zero and one</a>.
|
||||
</p>
|
||||
<p class="counting-dots counting-dots--empty" aria-label="zero dots">
|
||||
<span class="counting-dots__none">(none)</span>
|
||||
</p>
|
||||
<p>Zero comes before one when we count: first nothing, then one, then two, and so on.</p>
|
||||
|
||||
<div class="book-callout" role="note">
|
||||
<p class="book-callout__label">Remember</p>
|
||||
<p>Zero means “none here,” not “forgot to count.”</p>
|
||||
</div>
|
||||
|
||||
<h2 id="numbers-one-to-ten" class="book-prose__heading">Numbers 1 to 10</h2>
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -1,77 +1,4 @@
|
|||
// Figurative dots and patterns in chapter prose
|
||||
.counting-dots {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.counting-dots__dot {
|
||||
display: block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: #0f766e;
|
||||
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.12);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.counting-dots--empty .counting-dots__none {
|
||||
font-size: 0.85rem;
|
||||
font-style: italic;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.counting-dots--compare {
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
.counting-dots--pair {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.counting-dots__pair {
|
||||
display: inline-flex;
|
||||
gap: 4px;
|
||||
padding: 4px 6px;
|
||||
border-radius: 6px;
|
||||
background: rgba(20, 184, 166, 0.12);
|
||||
border: 1px dashed rgba(15, 118, 110, 0.35);
|
||||
}
|
||||
|
||||
.counting-dots--odd {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
max-width: 220px;
|
||||
}
|
||||
|
||||
.counting-dots__singleton {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
background: rgba(234, 88, 12, 0.14);
|
||||
border: 2px solid rgba(180, 83, 9, 0.45);
|
||||
}
|
||||
|
||||
.counting-dots__singleton .counting-dots__dot {
|
||||
background: #c2410c;
|
||||
}
|
||||
|
||||
.counting-pattern-ladder--odd .counting-pattern-step {
|
||||
background: rgba(234, 88, 12, 0.06);
|
||||
}
|
||||
|
||||
.counting-number-table td:last-child {
|
||||
min-width: 110px;
|
||||
}
|
||||
// counting-dots and shared dot rules: content/math/subject.scss
|
||||
|
||||
.counting-compare {
|
||||
display: flex;
|
||||
|
|
@ -473,235 +400,314 @@
|
|||
gap: 6px;
|
||||
}
|
||||
|
||||
// Big numbers scale widget
|
||||
.big-numbers-scale__picker {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
// Big numbers scale widget (canvas + audio)
|
||||
.book-prose .math-widget-mount:has(.big-numbers-scale) {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.big-numbers-scale__btn {
|
||||
padding: 6px 12px;
|
||||
.big-numbers-scale {
|
||||
--big-scale-canvas-bg: var(--paper);
|
||||
--big-scale-grid: color-mix(in srgb, var(--line) 70%, transparent);
|
||||
--big-scale-star: color-mix(in srgb, var(--soft-ink) 48%, transparent);
|
||||
|
||||
width: min(1320px, 96vw);
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .big-numbers-scale,
|
||||
:root:not([data-theme="light"]) .big-numbers-scale {
|
||||
--big-scale-canvas-bg: color-mix(in srgb, var(--card-bg) 90%, black);
|
||||
--big-scale-grid: color-mix(in srgb, var(--line) 78%, rgba(148, 163, 184, 0.2));
|
||||
--big-scale-star: color-mix(in srgb, var(--soft-ink) 62%, rgba(255, 255, 255, 0.18));
|
||||
}
|
||||
|
||||
.big-numbers-scale__layout {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.big-numbers-scale__canvas-panel,
|
||||
.big-numbers-scale__controls,
|
||||
.big-numbers-scale__section {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.big-numbers-scale__canvas-panel {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 12px;
|
||||
background: var(--paper);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.big-numbers-scale__toolbar,
|
||||
.big-numbers-scale__slider-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
padding: 10px 12px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.big-numbers-scale__slider-wrap {
|
||||
border-top: 1px solid var(--line);
|
||||
border-bottom: 0;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.big-numbers-scale__slider-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-family: var(--mono);
|
||||
font-size: 0.75rem;
|
||||
color: var(--soft-ink);
|
||||
}
|
||||
|
||||
.big-numbers-scale__slider {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.big-numbers-scale__tool-btn,
|
||||
.big-numbers-scale__autoplay-btn,
|
||||
.speed-btn,
|
||||
.preset-step-btn {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
font-family: var(--mono);
|
||||
font-size: 0.8rem;
|
||||
background: var(--card-bg);
|
||||
color: var(--ink);
|
||||
font-family: var(--mono);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.big-numbers-scale__btn--active {
|
||||
border-color: #0f766e;
|
||||
.big-numbers-scale__tool-btn,
|
||||
.big-numbers-scale__autoplay-btn {
|
||||
padding: 7px 10px;
|
||||
font-size: 0.76rem;
|
||||
}
|
||||
|
||||
.big-numbers-scale__autoplay-btn {
|
||||
border-color: rgba(20, 184, 166, 0.45);
|
||||
background: rgba(20, 184, 166, 0.15);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.big-numbers-scale__display {
|
||||
margin: 16px 0 8px;
|
||||
text-align: center;
|
||||
.big-numbers-scale__autoplay-btn--pause {
|
||||
border-color: rgba(234, 88, 12, 0.45);
|
||||
background: rgba(234, 88, 12, 0.16);
|
||||
}
|
||||
|
||||
.big-numbers-scale__number {
|
||||
.big-numbers-scale__badge {
|
||||
padding: 3px 7px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--line);
|
||||
font-family: var(--mono);
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.big-numbers-scale__compare {
|
||||
margin: 0 0 12px;
|
||||
font-size: 0.9rem;
|
||||
text-align: center;
|
||||
font-size: 0.72rem;
|
||||
color: var(--soft-ink);
|
||||
}
|
||||
|
||||
.big-numbers-scale__visual {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
min-height: 120px;
|
||||
margin: 12px 0;
|
||||
padding: 16px;
|
||||
border: 1px dashed var(--line);
|
||||
.big-numbers-scale__hud {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 8px;
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.big-numbers-scale__hud-card {
|
||||
padding: 8px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 10px;
|
||||
background: color-mix(in srgb, var(--card-bg) 84%, #0b1220);
|
||||
}
|
||||
|
||||
.big-numbers-scale__hud-card--right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.big-numbers-scale__hud-label {
|
||||
display: block;
|
||||
font-size: 0.7rem;
|
||||
color: var(--soft-ink);
|
||||
}
|
||||
|
||||
.big-numbers-scale__hud-value {
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
font-family: var(--mono);
|
||||
font-size: 1.35rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.big-numbers-scale__hud-value--small {
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.big-numbers-scale__hud-sub {
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
font-size: 0.72rem;
|
||||
color: var(--soft-ink);
|
||||
}
|
||||
|
||||
.big-numbers-scale__tier-badge {
|
||||
display: inline-block;
|
||||
margin-top: 4px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 6px;
|
||||
font-size: 0.66rem;
|
||||
font-family: var(--mono);
|
||||
font-weight: 700;
|
||||
color: #08111f;
|
||||
background: #14b8a6;
|
||||
}
|
||||
|
||||
.big-numbers-scale__tier-badge--green {
|
||||
background: #14b8a6;
|
||||
}
|
||||
.big-numbers-scale__tier-badge--purple {
|
||||
background: #8b5cf6;
|
||||
}
|
||||
.big-numbers-scale__tier-badge--orange {
|
||||
background: #f97316;
|
||||
}
|
||||
.big-numbers-scale__tier-badge--yellow {
|
||||
background: #f59e0b;
|
||||
}
|
||||
.big-numbers-scale__tier-badge--cyan {
|
||||
background: #06b6d4;
|
||||
}
|
||||
|
||||
.big-numbers-scale__canvas-wrap {
|
||||
position: relative;
|
||||
height: 400px;
|
||||
background: var(--big-scale-canvas-bg);
|
||||
}
|
||||
|
||||
.big-numbers-scale__canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.big-numbers-scale__canvas:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.big-numbers-scale__status {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
bottom: 12px;
|
||||
padding: 6px 10px;
|
||||
border-radius: 8px;
|
||||
background: rgba(2, 6, 23, 0.85);
|
||||
border: 1px solid var(--line);
|
||||
color: var(--soft-ink);
|
||||
font-size: 0.74rem;
|
||||
opacity: 0;
|
||||
transform: translateY(5px);
|
||||
transition: opacity 160ms ease, transform 160ms ease;
|
||||
}
|
||||
|
||||
.big-numbers-scale__status--visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.big-numbers-scale__controls {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.big-numbers-scale__section {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 10px;
|
||||
background: var(--card-bg);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.big-numbers-scale__grid {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.big-numbers-scale__grid--small .big-numbers-scale__cell {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
.big-numbers-scale__cell {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
background: #0f766e;
|
||||
}
|
||||
|
||||
.big-numbers-scale__blocks {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
justify-content: center;
|
||||
max-width: 280px;
|
||||
}
|
||||
|
||||
.big-numbers-scale__block {
|
||||
padding: 6px 8px;
|
||||
border-radius: 4px;
|
||||
font-family: var(--mono);
|
||||
font-size: 0.65rem;
|
||||
font-weight: 700;
|
||||
background: rgba(20, 184, 166, 0.2);
|
||||
border: 1px solid rgba(15, 118, 110, 0.35);
|
||||
}
|
||||
|
||||
.big-numbers-scale__block--hundred {
|
||||
min-width: 36px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.big-numbers-scale__visual-caption {
|
||||
flex: 1 1 100%;
|
||||
margin: 10px 0 0;
|
||||
.big-numbers-scale__section-title {
|
||||
margin: 0 0 8px;
|
||||
font-size: 0.82rem;
|
||||
line-height: 1.45;
|
||||
text-align: center;
|
||||
color: var(--soft-ink);
|
||||
}
|
||||
|
||||
.big-numbers-scale__visual-caption--inline {
|
||||
margin: 8px 0 0;
|
||||
}
|
||||
|
||||
.big-numbers-scale__math-hint {
|
||||
font-family: var(--mono);
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
// 1 million: 100 × 10,000
|
||||
.big-numbers-scale__million {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.big-numbers-scale__mega-grid {
|
||||
.big-numbers-scale__preset-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(10, 1fr);
|
||||
gap: 3px;
|
||||
max-width: 280px;
|
||||
margin: 0 auto;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.big-numbers-scale__mega-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 22px;
|
||||
border-radius: 3px;
|
||||
font-family: var(--mono);
|
||||
font-size: 0.5rem;
|
||||
font-weight: 700;
|
||||
color: #0f766e;
|
||||
background: rgba(20, 184, 166, 0.22);
|
||||
border: 1px solid rgba(15, 118, 110, 0.35);
|
||||
}
|
||||
|
||||
// 1 billion: mini million × 1000 → grid of 1M
|
||||
.big-numbers-scale__billion {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.big-numbers-scale__billion-compare {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px 14px;
|
||||
}
|
||||
|
||||
.big-numbers-scale__billion-unit {
|
||||
.preset-step-btn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 8px;
|
||||
border-radius: 8px;
|
||||
background: rgba(20, 184, 166, 0.06);
|
||||
border: 1px solid var(--line);
|
||||
align-items: flex-start;
|
||||
gap: 2px;
|
||||
padding: 7px;
|
||||
min-height: 58px;
|
||||
}
|
||||
|
||||
.big-numbers-scale__billion-unit--wide {
|
||||
flex: 1 1 200px;
|
||||
max-width: 320px;
|
||||
background: rgba(234, 88, 12, 0.06);
|
||||
border-color: rgba(180, 83, 9, 0.35);
|
||||
.preset-step-btn__power {
|
||||
font-size: 0.65rem;
|
||||
color: var(--soft-ink);
|
||||
font-family: var(--mono);
|
||||
}
|
||||
|
||||
.big-numbers-scale__billion-unit-label {
|
||||
font-size: 0.72rem;
|
||||
.preset-step-btn__label {
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.preset-step-btn--active {
|
||||
border-color: rgba(20, 184, 166, 0.55);
|
||||
background: rgba(20, 184, 166, 0.15);
|
||||
}
|
||||
|
||||
.big-numbers-scale__speed-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.speed-btn {
|
||||
padding: 6px 8px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.speed-btn--active {
|
||||
border-color: rgba(20, 184, 166, 0.55);
|
||||
background: rgba(20, 184, 166, 0.18);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.big-numbers-scale__nav-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 6px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.big-numbers-scale__stat-text,
|
||||
.big-numbers-scale__analogy {
|
||||
margin: 0;
|
||||
font-size: 0.78rem;
|
||||
color: var(--soft-ink);
|
||||
}
|
||||
|
||||
.big-numbers-scale__mini-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.big-numbers-scale__mini-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 18px;
|
||||
border-radius: 2px;
|
||||
.big-numbers-scale__stat-value {
|
||||
margin: 8px 0;
|
||||
padding: 8px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--line);
|
||||
font-family: var(--mono);
|
||||
font-size: 0.45rem;
|
||||
font-weight: 700;
|
||||
color: #0f766e;
|
||||
background: rgba(20, 184, 166, 0.25);
|
||||
}
|
||||
|
||||
.big-numbers-scale__billion-times {
|
||||
font-family: var(--mono);
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.big-numbers-scale__billion-equals {
|
||||
font-family: var(--mono);
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.big-numbers-scale__giga-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(10, 1fr);
|
||||
gap: 2px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.big-numbers-scale__giga-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 18px;
|
||||
border-radius: 2px;
|
||||
font-family: var(--mono);
|
||||
font-size: 0.48rem;
|
||||
font-weight: 700;
|
||||
color: #9a3412;
|
||||
background: rgba(234, 88, 12, 0.28);
|
||||
border: 1px solid rgba(180, 83, 9, 0.4);
|
||||
@media (min-width: 960px) {
|
||||
.big-numbers-scale__layout {
|
||||
grid-template-columns: minmax(0, 3fr) minmax(280px, 2fr);
|
||||
}
|
||||
.big-numbers-scale__hud {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
<div class="book-prose">
|
||||
<p>
|
||||
Look around you. How many birds? How many cups? You can answer by
|
||||
<strong>counting</strong> — pointing at one thing at a time until everything has been pointed at.
|
||||
This chapter uses <strong>pictures of dots</strong> to stand for real things, like marbles or
|
||||
fingers.
|
||||
You already met <strong>0</strong> and <strong>1</strong> in
|
||||
<a href="/math/zero-and-one/">Zero and one</a>. Now look around: how many birds? how many cups?
|
||||
You answer by <strong>counting</strong> — pointing at one thing at a time until everything has
|
||||
been pointed at. This chapter uses <strong>pictures of dots</strong> to stand for real things,
|
||||
like marbles or fingers.
|
||||
</p>
|
||||
|
||||
<h2 id="what-is-counting" class="book-prose__heading">What is counting?</h2>
|
||||
|
|
@ -16,20 +17,13 @@
|
|||
the number of fingers matches the number of objects.
|
||||
</p>
|
||||
|
||||
<h2 id="zero" class="book-prose__heading">Zero</h2>
|
||||
<h2 id="zero" class="book-prose__heading">Zero and one (recap)</h2>
|
||||
<p>
|
||||
When there is <strong>nothing</strong> to point at, we write <strong>0</strong> and say
|
||||
<strong>zero</strong>. An empty plate, no toys in the box — zero dots:
|
||||
<strong>0</strong> means nothing to count; <strong>1</strong> means exactly one. When you count
|
||||
aloud you still say zero before one, then two, and so on. If you want the full picture of
|
||||
nothing versus one — and how that pairs with false and true — revisit
|
||||
<a href="/math/zero-and-one/#zero">Zero and one</a>.
|
||||
</p>
|
||||
<p class="counting-dots counting-dots--empty" aria-label="zero dots">
|
||||
<span class="counting-dots__none">(none)</span>
|
||||
</p>
|
||||
<p>Zero comes before one when we count: first nothing, then one, then two, and so on.</p>
|
||||
|
||||
<div class="book-callout" role="note">
|
||||
<p class="book-callout__label">Remember</p>
|
||||
<p>Zero means “none here,” not “forgot to count.”</p>
|
||||
</div>
|
||||
|
||||
<h2 id="numbers-one-to-ten" class="book-prose__heading">Numbers 1 to 10</h2>
|
||||
<p>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
106
content/math/subject.scss
Normal file
106
content/math/subject.scss
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// Shared styles for all mathematics chapters (compiled to /css/subjects/math.css).
|
||||
// Chapter-specific rules stay in each chapter's chapter.scss.
|
||||
|
||||
// --- Figurative dot pictures (counting, zero/one, tables) ---
|
||||
.counting-dots {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.counting-dots__dot {
|
||||
display: block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: #0f766e;
|
||||
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.12);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.counting-dots--empty .counting-dots__none {
|
||||
font-size: 0.85rem;
|
||||
font-style: italic;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.counting-dots--compare {
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
.counting-dots--pair {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.counting-dots__pair {
|
||||
display: inline-flex;
|
||||
gap: 4px;
|
||||
padding: 4px 6px;
|
||||
border-radius: 6px;
|
||||
background: rgba(20, 184, 166, 0.12);
|
||||
border: 1px dashed rgba(15, 118, 110, 0.35);
|
||||
}
|
||||
|
||||
.counting-dots--odd {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
max-width: 220px;
|
||||
}
|
||||
|
||||
.counting-dots__singleton {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
background: rgba(234, 88, 12, 0.14);
|
||||
border: 2px solid rgba(180, 83, 9, 0.45);
|
||||
}
|
||||
|
||||
.counting-dots__singleton .counting-dots__dot {
|
||||
background: #c2410c;
|
||||
}
|
||||
|
||||
.counting-pattern-ladder--odd .counting-pattern-step {
|
||||
background: rgba(234, 88, 12, 0.06);
|
||||
}
|
||||
|
||||
.counting-number-table td:last-child {
|
||||
min-width: 110px;
|
||||
}
|
||||
|
||||
// --- Notation chapter dot chains ---
|
||||
.notation-dots {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.notation-dots__dot {
|
||||
display: block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
background: #0f766e;
|
||||
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.12);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.notation-dots--chain {
|
||||
max-width: 88px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.notation-dots--decimal .notation-dots__dot {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
12
content/math/subject.ts
Normal file
12
content/math/subject.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* Shared JavaScript for all mathematics chapters.
|
||||
* Loaded on every /math/{slug}/ page via main.tsx + generated subject-modules.ts.
|
||||
*/
|
||||
|
||||
/** Normalize checkpoint markup and run any math-only setup on the chapter article. */
|
||||
export function initMathSubject(root: HTMLElement): void {
|
||||
for (const panel of root.querySelectorAll<HTMLElement>(".book-question__answer")) {
|
||||
panel.classList.remove("book-question__answer");
|
||||
panel.classList.add("book-question__solution");
|
||||
}
|
||||
}
|
||||
137
content/math/zero-and-one/_index.md
Normal file
137
content/math/zero-and-one/_index.md
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
+++
|
||||
title = "Zero and one"
|
||||
description = "0 is nothing; 1 is one. Learn to tell them apart — the same skill as telling false from true — before counting larger amounts."
|
||||
template = "chapter.html"
|
||||
weight = 0
|
||||
[extra]
|
||||
subject = "math"
|
||||
chapter_id = "zero-and-one"
|
||||
strand = "Number & Algebra"
|
||||
+++
|
||||
|
||||
<div class="book-prose">
|
||||
<p>
|
||||
Mathematics begins with a simple question: <strong>how many?</strong> The smallest answers are
|
||||
<strong>0</strong> and <strong>1</strong>. Before you count birds, cups, or billions, you need to
|
||||
be sure you can tell <strong>nothing</strong> from <strong>one</strong>.
|
||||
</p>
|
||||
|
||||
<h2 id="zero" class="book-prose__heading">Zero — nothing</h2>
|
||||
<p>
|
||||
When there is <strong>nothing</strong> to point at, we write <strong>0</strong> and say
|
||||
<strong>zero</strong>. An empty tray, a switched-off light with no glow, silence — no dot to
|
||||
count:
|
||||
</p>
|
||||
<p class="counting-dots counting-dots--empty" aria-label="zero dots">
|
||||
<span class="counting-dots__none">(none)</span>
|
||||
</p>
|
||||
<p>
|
||||
Zero is not “forgot to look.” It means <strong>none here</strong> — the answer when the amount
|
||||
is nothing.
|
||||
</p>
|
||||
|
||||
<h2 id="one" class="book-prose__heading">One — exactly one</h2>
|
||||
<p>
|
||||
When there is a single thing to point at once, we write <strong>1</strong> and say
|
||||
<strong>one</strong>. One apple on the plate, one tap, one dot:
|
||||
</p>
|
||||
<p class="counting-dots" role="img" aria-label="one dot">
|
||||
<span class="counting-dots__dot"></span>
|
||||
</p>
|
||||
<p>One is not “a few” and not “many.” It is <strong>exactly one</strong>.</p>
|
||||
|
||||
<h2 id="compare" class="book-prose__heading">Tell them apart</h2>
|
||||
<p>0 and 1 sit side by side. Mixing them up changes the whole answer.</p>
|
||||
<div class="zero-one-compare" role="group" aria-label="Zero compared with one">
|
||||
<div class="zero-one-compare__cell zero-one-compare__cell--zero">
|
||||
<p class="zero-one-compare__digit">0</p>
|
||||
<p class="zero-one-compare__word">zero</p>
|
||||
<p class="counting-dots counting-dots--empty" aria-hidden="true">
|
||||
<span class="counting-dots__none">none</span>
|
||||
</p>
|
||||
<p class="zero-one-compare__hint">nothing to count</p>
|
||||
</div>
|
||||
<div class="zero-one-compare__cell zero-one-compare__cell--one">
|
||||
<p class="zero-one-compare__digit">1</p>
|
||||
<p class="zero-one-compare__word">one</p>
|
||||
<p class="counting-dots" aria-hidden="true">
|
||||
<span class="counting-dots__dot"></span>
|
||||
</p>
|
||||
<p class="zero-one-compare__hint">one thing to count</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 id="true-and-false" class="book-prose__heading">True and false</h2>
|
||||
<p>
|
||||
You can also ask whether a <strong>statement</strong> matches the world. “The cup is on the
|
||||
table.” — if it is there, the statement is <strong>true</strong>. If the cup is not there, the
|
||||
statement is <strong>false</strong>.
|
||||
</p>
|
||||
<p>
|
||||
For a single yes-or-no question about <strong>one</strong> thing, the same care applies:
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>False</strong> fits when the answer is <strong>no</strong> — none of what we named, like <strong>0</strong>.</li>
|
||||
<li><strong>True</strong> fits when the answer is <strong>yes, exactly once</strong> — like <strong>1</strong> when we mean one clear match.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Later you will meet longer counts and trickier logic. The habit starts here: look carefully, then
|
||||
decide — is it <strong>0 or 1</strong>? <strong>false or true</strong>?
|
||||
</p>
|
||||
|
||||
<div class="book-callout" role="note">
|
||||
<p class="book-callout__label">The essence</p>
|
||||
<p>
|
||||
Telling <strong>0</strong> from <strong>1</strong> is the same kind of attention as telling
|
||||
<strong>false</strong> from <strong>true</strong>. That distinction is the foundation for every
|
||||
number and for understanding claims about the world.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="math-widget-mount" data-widget="zero-one-board" data-pagefind-ignore></div>
|
||||
|
||||
<p>
|
||||
When you are steady with 0 and 1, continue to
|
||||
<a href="/math/counting-and-numbers/">Counting and numbers</a> to count past one and meet larger
|
||||
amounts.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="book-prose">
|
||||
<h2 id="history" class="book-prose__heading">History</h2>
|
||||
<p>
|
||||
People counted with fingers and marks long before anyone wrote <strong>0</strong> as a number.
|
||||
In ancient India and among the Maya, thinkers found a symbol for <strong>nothing</strong> — not
|
||||
just “empty space on the page,” but a number you could calculate with.
|
||||
</p>
|
||||
<p>
|
||||
That step mattered: without zero, place value and modern arithmetic are much harder. The idea
|
||||
“nothing is something we can name” is as deep as the idea “one is one.”
|
||||
</p>
|
||||
|
||||
<h2 id="checkpoints" class="book-prose__heading">Checkpoints</h2>
|
||||
<details class="book-question">
|
||||
<summary class="book-question__prompt">You look in a box and see no dots. How many?</summary>
|
||||
<div class="book-question__solution">
|
||||
<p><strong>Answer:</strong> \(0\) (zero) — nothing to count.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="book-question">
|
||||
<summary class="book-question__prompt">You see exactly one dot. How many?</summary>
|
||||
<div class="book-question__solution">
|
||||
<p><strong>Answer:</strong> \(1\) (one).</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="book-question">
|
||||
<summary class="book-question__prompt">Is the sentence “2 is less than 1” true or false?</summary>
|
||||
<div class="book-question__solution">
|
||||
<p><strong>Answer:</strong> False — two is not less than one.</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<h2 id="references" class="book-prose__heading">References</h2>
|
||||
<ul>
|
||||
<li>Ifrah, Georges — <em>The Universal History of Numbers</em> (origins of zero and counting).</li>
|
||||
<li>Crossley & Henry — early Indian arithmetic including zero.</li>
|
||||
</ul>
|
||||
</div>
|
||||
123
content/math/zero-and-one/chapter.scss
Normal file
123
content/math/zero-and-one/chapter.scss
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
// Dot pictures: counting-dots in subject.scss
|
||||
|
||||
.zero-one-compare {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
margin: 20px 0;
|
||||
padding: 16px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 12px;
|
||||
background: var(--card-bg);
|
||||
}
|
||||
|
||||
.zero-one-compare__cell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 14px 10px;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.zero-one-compare__cell--zero {
|
||||
background: rgba(100, 116, 139, 0.08);
|
||||
border: 1px dashed var(--line);
|
||||
}
|
||||
|
||||
.zero-one-compare__cell--one {
|
||||
background: rgba(20, 184, 166, 0.1);
|
||||
border: 1px solid rgba(15, 118, 110, 0.35);
|
||||
}
|
||||
|
||||
.zero-one-compare__digit {
|
||||
margin: 0;
|
||||
font-family: var(--mono);
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.zero-one-compare__word {
|
||||
margin: 0;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
color: var(--soft-ink);
|
||||
}
|
||||
|
||||
.zero-one-compare__hint {
|
||||
margin: 0;
|
||||
font-size: 0.85rem;
|
||||
color: var(--soft-ink);
|
||||
}
|
||||
|
||||
.zero-one-board__scenario {
|
||||
margin: 0 0 12px;
|
||||
font-size: 1.05rem;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.zero-one-board__visual {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 72px;
|
||||
margin: 12px 0;
|
||||
padding: 16px;
|
||||
border: 1px dashed var(--line);
|
||||
border-radius: 10px;
|
||||
background: var(--card-bg);
|
||||
transition: border-color 0.15s ease, background 0.15s ease;
|
||||
}
|
||||
|
||||
.zero-one-board__visual--correct {
|
||||
border-color: rgba(15, 118, 110, 0.55);
|
||||
background: rgba(20, 184, 166, 0.08);
|
||||
}
|
||||
|
||||
.zero-one-board__visual--incorrect {
|
||||
border-color: rgba(180, 83, 9, 0.45);
|
||||
background: rgba(234, 88, 12, 0.06);
|
||||
}
|
||||
|
||||
.zero-one-board__count {
|
||||
margin: 0;
|
||||
font-family: var(--mono);
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.zero-one-board__choices {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.zero-one-board__choice--active {
|
||||
border-color: #0f766e;
|
||||
background: rgba(20, 184, 166, 0.15);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.zero-one-board__feedback {
|
||||
margin: 12px 0 0;
|
||||
min-height: 1.4em;
|
||||
text-align: center;
|
||||
font-size: 0.95rem;
|
||||
color: var(--soft-ink);
|
||||
}
|
||||
|
||||
.zero-one-board__feedback--ok {
|
||||
color: #0f766e;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.zero-one-board__feedback--nope {
|
||||
color: #9a3412;
|
||||
font-weight: 600;
|
||||
}
|
||||
87
content/math/zero-and-one/core.html
Normal file
87
content/math/zero-and-one/core.html
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
<div class="book-prose">
|
||||
<p>
|
||||
Mathematics begins with a simple question: <strong>how many?</strong> The smallest answers are
|
||||
<strong>0</strong> and <strong>1</strong>. Before you count birds, cups, or billions, you need to
|
||||
be sure you can tell <strong>nothing</strong> from <strong>one</strong>.
|
||||
</p>
|
||||
|
||||
<h2 id="zero" class="book-prose__heading">Zero — nothing</h2>
|
||||
<p>
|
||||
When there is <strong>nothing</strong> to point at, we write <strong>0</strong> and say
|
||||
<strong>zero</strong>. An empty tray, a switched-off light with no glow, silence — no dot to
|
||||
count:
|
||||
</p>
|
||||
<p class="counting-dots counting-dots--empty" aria-label="zero dots">
|
||||
<span class="counting-dots__none">(none)</span>
|
||||
</p>
|
||||
<p>
|
||||
Zero is not “forgot to look.” It means <strong>none here</strong> — the answer when the amount
|
||||
is nothing.
|
||||
</p>
|
||||
|
||||
<h2 id="one" class="book-prose__heading">One — exactly one</h2>
|
||||
<p>
|
||||
When there is a single thing to point at once, we write <strong>1</strong> and say
|
||||
<strong>one</strong>. One apple on the plate, one tap, one dot:
|
||||
</p>
|
||||
<p class="counting-dots" role="img" aria-label="one dot">
|
||||
<span class="counting-dots__dot"></span>
|
||||
</p>
|
||||
<p>One is not “a few” and not “many.” It is <strong>exactly one</strong>.</p>
|
||||
|
||||
<h2 id="compare" class="book-prose__heading">Tell them apart</h2>
|
||||
<p>0 and 1 sit side by side. Mixing them up changes the whole answer.</p>
|
||||
<div class="zero-one-compare" role="group" aria-label="Zero compared with one">
|
||||
<div class="zero-one-compare__cell zero-one-compare__cell--zero">
|
||||
<p class="zero-one-compare__digit">0</p>
|
||||
<p class="zero-one-compare__word">zero</p>
|
||||
<p class="counting-dots counting-dots--empty" aria-hidden="true">
|
||||
<span class="counting-dots__none">none</span>
|
||||
</p>
|
||||
<p class="zero-one-compare__hint">nothing to count</p>
|
||||
</div>
|
||||
<div class="zero-one-compare__cell zero-one-compare__cell--one">
|
||||
<p class="zero-one-compare__digit">1</p>
|
||||
<p class="zero-one-compare__word">one</p>
|
||||
<p class="counting-dots" aria-hidden="true">
|
||||
<span class="counting-dots__dot"></span>
|
||||
</p>
|
||||
<p class="zero-one-compare__hint">one thing to count</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 id="true-and-false" class="book-prose__heading">True and false</h2>
|
||||
<p>
|
||||
You can also ask whether a <strong>statement</strong> matches the world. “The cup is on the
|
||||
table.” — if it is there, the statement is <strong>true</strong>. If the cup is not there, the
|
||||
statement is <strong>false</strong>.
|
||||
</p>
|
||||
<p>
|
||||
For a single yes-or-no question about <strong>one</strong> thing, the same care applies:
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>False</strong> fits when the answer is <strong>no</strong> — none of what we named, like <strong>0</strong>.</li>
|
||||
<li><strong>True</strong> fits when the answer is <strong>yes, exactly once</strong> — like <strong>1</strong> when we mean one clear match.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Later you will meet longer counts and trickier logic. The habit starts here: look carefully, then
|
||||
decide — is it <strong>0 or 1</strong>? <strong>false or true</strong>?
|
||||
</p>
|
||||
|
||||
<div class="book-callout" role="note">
|
||||
<p class="book-callout__label">The essence</p>
|
||||
<p>
|
||||
Telling <strong>0</strong> from <strong>1</strong> is the same kind of attention as telling
|
||||
<strong>false</strong> from <strong>true</strong>. That distinction is the foundation for every
|
||||
number and for understanding claims about the world.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="math-widget-mount" data-widget="zero-one-board" data-pagefind-ignore></div>
|
||||
|
||||
<p>
|
||||
When you are steady with 0 and 1, continue to
|
||||
<a href="/math/counting-and-numbers/">Counting and numbers</a> to count past one and meet larger
|
||||
amounts.
|
||||
</p>
|
||||
</div>
|
||||
38
content/math/zero-and-one/supplement.html
Normal file
38
content/math/zero-and-one/supplement.html
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<div class="book-prose">
|
||||
<h2 id="history" class="book-prose__heading">History</h2>
|
||||
<p>
|
||||
People counted with fingers and marks long before anyone wrote <strong>0</strong> as a number.
|
||||
In ancient India and among the Maya, thinkers found a symbol for <strong>nothing</strong> — not
|
||||
just “empty space on the page,” but a number you could calculate with.
|
||||
</p>
|
||||
<p>
|
||||
That step mattered: without zero, place value and modern arithmetic are much harder. The idea
|
||||
“nothing is something we can name” is as deep as the idea “one is one.”
|
||||
</p>
|
||||
|
||||
<h2 id="checkpoints" class="book-prose__heading">Checkpoints</h2>
|
||||
<details class="book-question">
|
||||
<summary class="book-question__prompt">You look in a box and see no dots. How many?</summary>
|
||||
<div class="book-question__solution">
|
||||
<p><strong>Answer:</strong> \(0\) (zero) — nothing to count.</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="book-question">
|
||||
<summary class="book-question__prompt">You see exactly one dot. How many?</summary>
|
||||
<div class="book-question__solution">
|
||||
<p><strong>Answer:</strong> \(1\) (one).</p>
|
||||
</div>
|
||||
</details>
|
||||
<details class="book-question">
|
||||
<summary class="book-question__prompt">Is the sentence “2 is less than 1” true or false?</summary>
|
||||
<div class="book-question__solution">
|
||||
<p><strong>Answer:</strong> False — two is not less than one.</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<h2 id="references" class="book-prose__heading">References</h2>
|
||||
<ul>
|
||||
<li>Ifrah, Georges — <em>The Universal History of Numbers</em> (origins of zero and counting).</li>
|
||||
<li>Crossley & Henry — early Indian arithmetic including zero.</li>
|
||||
</ul>
|
||||
</div>
|
||||
218
content/math/zero-and-one/widgets/zero-one-board.tsx
Normal file
218
content/math/zero-and-one/widgets/zero-one-board.tsx
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
import { createMemo, createSignal, For } from "solid-js";
|
||||
|
||||
type Scenario = {
|
||||
id: string;
|
||||
prompt: string;
|
||||
correctAmount: 0 | 1;
|
||||
showTruth?: boolean;
|
||||
correctTruth?: boolean;
|
||||
};
|
||||
|
||||
const SCENARIOS: Scenario[] = [
|
||||
{
|
||||
id: "empty-box",
|
||||
prompt: "The box has no marbles inside.",
|
||||
correctAmount: 0,
|
||||
},
|
||||
{
|
||||
id: "one-apple",
|
||||
prompt: "There is exactly one apple on the plate.",
|
||||
correctAmount: 1,
|
||||
},
|
||||
{
|
||||
id: "light-off",
|
||||
prompt: "The lamp is off — no light showing.",
|
||||
correctAmount: 0,
|
||||
},
|
||||
{
|
||||
id: "light-on",
|
||||
prompt: "The lamp is on — one steady light.",
|
||||
correctAmount: 1,
|
||||
},
|
||||
{
|
||||
id: "statement-false",
|
||||
prompt: "Statement: “The door is open.” (The door is shut.)",
|
||||
correctAmount: 0,
|
||||
showTruth: true,
|
||||
correctTruth: false,
|
||||
},
|
||||
{
|
||||
id: "statement-true",
|
||||
prompt: "Statement: “There is one bell ringing.” (You hear one bell.)",
|
||||
correctAmount: 1,
|
||||
showTruth: true,
|
||||
correctTruth: true,
|
||||
},
|
||||
];
|
||||
|
||||
function ZeroOneBoard() {
|
||||
const [index, setIndex] = createSignal(0);
|
||||
const [picked, setPicked] = createSignal<0 | 1 | null>(null);
|
||||
const [truthPicked, setTruthPicked] = createSignal<boolean | null>(null);
|
||||
|
||||
const scenario = createMemo(() => SCENARIOS[index() % SCENARIOS.length]);
|
||||
const atEnd = createMemo(() => index() >= SCENARIOS.length - 1);
|
||||
|
||||
const amountCorrect = createMemo(() => {
|
||||
const p = picked();
|
||||
return p !== null && p === scenario().correctAmount;
|
||||
});
|
||||
|
||||
const truthCorrect = createMemo(() => {
|
||||
const s = scenario();
|
||||
if (!s.showTruth) return true;
|
||||
const t = truthPicked();
|
||||
return t !== null && t === s.correctTruth;
|
||||
});
|
||||
|
||||
const answered = createMemo(() => {
|
||||
const s = scenario();
|
||||
if (picked() === null) return false;
|
||||
if (s.showTruth && truthPicked() === null) return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
const allCorrect = createMemo(() => answered() && amountCorrect() && truthCorrect());
|
||||
|
||||
const feedback = createMemo(() => {
|
||||
if (!answered()) return "Choose how many, then Next when you are ready.";
|
||||
if (allCorrect()) {
|
||||
return atEnd()
|
||||
? "Well done — you can tell 0 from 1. Continue to Counting and numbers."
|
||||
: "Correct. Try the next situation.";
|
||||
}
|
||||
if (!amountCorrect()) {
|
||||
return picked() === 0
|
||||
? "Not quite — this situation is one, not zero."
|
||||
: "Not quite — this situation is zero, not one.";
|
||||
}
|
||||
return truthPicked() === true
|
||||
? "Check the statement again — it does not match the world (false)."
|
||||
: "Check the statement again — it matches the world (true).";
|
||||
});
|
||||
|
||||
const pickAmount = (n: 0 | 1) => {
|
||||
setPicked(n);
|
||||
};
|
||||
|
||||
const pickTruth = (value: boolean) => {
|
||||
setTruthPicked(value);
|
||||
};
|
||||
|
||||
const goNext = () => {
|
||||
if (!answered() || !allCorrect()) return;
|
||||
if (atEnd()) return;
|
||||
setIndex((i) => i + 1);
|
||||
setPicked(null);
|
||||
setTruthPicked(null);
|
||||
};
|
||||
|
||||
const resetAll = () => {
|
||||
setIndex(0);
|
||||
setPicked(null);
|
||||
setTruthPicked(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<section class="math-widget zero-one-board" aria-labelledby="zero-one-board-title">
|
||||
<h2 id="zero-one-board-title" class="math-widget__title">
|
||||
Practice: zero or one
|
||||
</h2>
|
||||
<div class="math-widget__body">
|
||||
<p class="math-widget__caption">
|
||||
Situation {index() + 1} of {SCENARIOS.length}. Pick the amount that fits. When a statement
|
||||
is shown, also pick true or false.
|
||||
</p>
|
||||
<p class="zero-one-board__scenario">{scenario().prompt}</p>
|
||||
|
||||
<div
|
||||
class="zero-one-board__visual"
|
||||
classList={{
|
||||
"zero-one-board__visual--correct": answered() && allCorrect(),
|
||||
"zero-one-board__visual--incorrect": answered() && !allCorrect(),
|
||||
}}
|
||||
aria-live="polite"
|
||||
>
|
||||
<p class="zero-one-board__count">
|
||||
{picked() === null ? "?" : picked()}
|
||||
</p>
|
||||
<span class="counting-dots" role="img" aria-hidden="true">
|
||||
<For each={picked() === 1 ? [0] : []}>
|
||||
{() => <span class="counting-dots__dot" />}
|
||||
</For>
|
||||
{picked() === 0 ? (
|
||||
<span class="counting-dots__none">none</span>
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="zero-one-board__choices" role="group" aria-label="How many?">
|
||||
<button
|
||||
type="button"
|
||||
class="scenario-demo__btn zero-one-board__choice"
|
||||
classList={{ "zero-one-board__choice--active": picked() === 0 }}
|
||||
onClick={() => pickAmount(0)}
|
||||
>
|
||||
Nothing (0)
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="scenario-demo__btn scenario-demo__btn--primary zero-one-board__choice"
|
||||
classList={{ "zero-one-board__choice--active": picked() === 1 }}
|
||||
onClick={() => pickAmount(1)}
|
||||
>
|
||||
One (1)
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{scenario().showTruth ? (
|
||||
<div class="zero-one-board__choices" role="group" aria-label="True or false?">
|
||||
<button
|
||||
type="button"
|
||||
class="scenario-demo__btn zero-one-board__choice"
|
||||
classList={{ "zero-one-board__choice--active": truthPicked() === false }}
|
||||
onClick={() => pickTruth(false)}
|
||||
>
|
||||
False
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="scenario-demo__btn scenario-demo__btn--primary zero-one-board__choice"
|
||||
classList={{ "zero-one-board__choice--active": truthPicked() === true }}
|
||||
onClick={() => pickTruth(true)}
|
||||
>
|
||||
True
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<p
|
||||
class="zero-one-board__feedback"
|
||||
classList={{
|
||||
"zero-one-board__feedback--ok": answered() && allCorrect(),
|
||||
"zero-one-board__feedback--nope": answered() && !allCorrect(),
|
||||
}}
|
||||
aria-live="polite"
|
||||
>
|
||||
{feedback()}
|
||||
</p>
|
||||
|
||||
<div class="scenario-demo__actions">
|
||||
<button type="button" class="scenario-demo__btn" onClick={resetAll}>
|
||||
Start over
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="scenario-demo__btn scenario-demo__btn--primary"
|
||||
onClick={goNext}
|
||||
disabled={!answered() || !allCorrect() || atEnd()}
|
||||
>
|
||||
Next situation
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default ZeroOneBoard;
|
||||
Loading…
Add table
Add a link
Reference in a new issue