Sprint 5: dark mode CSS, alternate conjugation forms, README releases link fix

- add @media (prefers-color-scheme: dark) block to CARD_CSS covering all hardcoded colors
- _parse_table: add table_el param to parse a specific table directly
- _extract_conjugations: detect second active conjugation table; store alternate_forms
- build_conj_deck: show "primary / alternate" when alternate form exists for a key
- README: fix dead ../../releases link → git.nevo.engineer/nevo/pealim/releases

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Sochen 2026-03-04 07:07:28 +00:00
parent 372680be3c
commit 6cd42b1e12
4 changed files with 226 additions and 181 deletions

View file

@ -21,7 +21,7 @@ All card data comes from open or academic sources:
## Just give me the flashcards
1. Download the `.apkg` files from [Releases](../../releases)
1. Download the `.apkg` files from [Releases](https://git.nevo.engineer/nevo/pealim/releases)
2. Double-click to import into [Anki](https://apps.ankiweb.net/) (free, cross-platform)
3. Start studying

View file

@ -159,6 +159,18 @@ CARD_CSS = """
margin: 2px 0;
font-size: 15px;
}
@media (prefers-color-scheme: dark) {
.card { color: #e8e8e8; background: #1c1c1e; }
.hebrew { color: #f0f0f0; }
.hebrew-sm { color: #ddd; }
.meaning { color: #82b0ff; }
.root-info { color: #aaa; }
.sec-label { color: #aaa; }
.voice-label { color: #888; }
.example { color: #bbb; border-right-color: #555; }
.divider { border-top-color: #333; }
.freq-badge { color: #888; border-color: #444; }
}
"""
# ──────────────────────────────────────────────────────────────────────────────
@ -575,8 +587,12 @@ def build_conj_deck(
deck.add_note(note)
note_count += 1
alternate_forms = data.get("alternate_forms", {})
for form_key, form_data in forms.items():
conj_form = form_data.get("form", "")
primary_form = form_data.get("form", "")
alt_form = alternate_forms.get(form_key, "")
conj_form = f"{primary_form} / {alt_form}" if alt_form else primary_form
audio_url_for_key = form_data.get("audio_url", "")
# Infinitive: shown on card front as reference — skip as a quiz form

View file

@ -218,10 +218,11 @@ def _get_menukad(cell) -> tuple[str, str]:
return "", audio_url
def _parse_table(soup: BeautifulSoup, passive: bool = False) -> dict[str, dict]:
def _parse_table(soup: BeautifulSoup, passive: bool = False, table_el=None) -> dict[str, dict]:
"""
Parse the pealim conjugation table and return form_key -> {form, audio_url} mapping.
If passive=True, look for the passive table (after "Passive" heading).
If table_el is provided (and passive=False), parse that table directly.
"""
if passive:
# Find <h3> containing "Passive"
@ -240,6 +241,8 @@ def _parse_table(soup: BeautifulSoup, passive: bool = False) -> dict[str, dict]:
break
if not table:
return {}
elif table_el is not None:
table = table_el
else:
table = soup.find("table", class_="conjugation-table")
@ -480,6 +483,32 @@ def _extract_conjugations(slug: str, search_term: str, is_3ms_search: bool = Fal
"tense": TENSE_DESCRIPTION.get(key, ""),
}
# Check for a second conjugation table (alternate paradigm, e.g. להתגלות)
# Collect all active tables (exclude passive tables which follow the "Passive" h3)
passive_h3 = next(
(h for h in soup.find_all("h3") if "passive" in h.get_text(strip=True).lower()),
None,
)
passive_table_ids = {
id(t) for t in (passive_h3.find_all_next("table", class_="conjugation-table") if passive_h3 else [])
}
active_tables = [
t for t in soup.find_all("table", class_="conjugation-table")
if id(t) not in passive_table_ids
]
if len(active_tables) >= 2:
alt_raw = _parse_table(soup, passive=False, table_el=active_tables[1])
alternate_forms = {}
for key, form_data in alt_raw.items():
if key in PRONOUN_LABELS:
alt_form = form_data["form"]
primary_form = forms_raw.get(key, {}).get("form", "")
if alt_form and alt_form != primary_form:
alternate_forms[key] = alt_form
if alternate_forms:
result["alternate_forms"] = alternate_forms
logger.info(f" Found {len(alternate_forms)} alternate forms for {search_term}")
logger.info(f" Extracted {len(result['forms'])} forms for {search_term}")
return result

View file

@ -8667,184 +8667,6 @@
}
}
},
"להתגלות": {
"infinitive": "להתגלות",
"slug": "332-lehitgalot",
"root": "ג - ל - ה",
"binyan": "Hitpa'el",
"is_passive": false,
"reference_form": "לְהִתְגַּלּוֹת",
"forms": {
"present_ms": {
"form": "מִתְגַּלֶּה",
"audio_url": "https://audio.pealim.com/v0/17/17aik28prm3ox.mp3",
"pronoun": "",
"tense": "הוֹוֶה"
},
"present_fs": {
"form": "מִתְגַּלָּה",
"audio_url": "https://audio.pealim.com/v0/17/17a2ezsn3tstn.mp3",
"pronoun": "",
"tense": "הוֹוֶה"
},
"present_mp": {
"form": "מִתְגַּלִּים",
"audio_url": "https://audio.pealim.com/v0/ic/ic1fbwv4cmec.mp3",
"pronoun": "",
"tense": "הוֹוֶה"
},
"present_fp": {
"form": "מִתְגַּלּוֹת",
"audio_url": "https://audio.pealim.com/v0/1x/1xkipm6geolmn.mp3",
"pronoun": "",
"tense": "הוֹוֶה"
},
"past_1s": {
"form": "נִתְגַּלֵּיתִי",
"audio_url": "https://audio.pealim.com/v0/8s/8slivd19nhsg.mp3",
"pronoun": "אֲנִי",
"tense": "עָבָר"
},
"past_1p": {
"form": "נִתְגַּלֵּינוּ",
"audio_url": "https://audio.pealim.com/v0/9r/9r6dsilbbfoq.mp3",
"pronoun": "אֲנַחְנוּ",
"tense": "עָבָר"
},
"past_2ms": {
"form": "נִתְגַּלֵּיתָ",
"audio_url": "https://audio.pealim.com/v0/1e/1ephuiupr8yqt.mp3",
"pronoun": "אַתָּה",
"tense": "עָבָר"
},
"past_2fs": {
"form": "נִתְגַּלֵּית",
"audio_url": "https://audio.pealim.com/v0/xb/xbkrr0255b0s.mp3",
"pronoun": "אַתְּ",
"tense": "עָבָר"
},
"past_2mp": {
"form": "נִתְגַּלֵּיתֶם",
"audio_url": "https://audio.pealim.com/v0/ht/ht8tvie1mfln.mp3",
"pronoun": "אַתֶּם",
"tense": "עָבָר"
},
"past_2fp": {
"form": "נִתְגַּלֵּיתֶן",
"audio_url": "https://audio.pealim.com/v0/5u/5udjkfd31qpk.mp3",
"pronoun": "אַתֶּן",
"tense": "עָבָר"
},
"past_3ms": {
"form": "נִתְגַּלָּה",
"audio_url": "https://audio.pealim.com/v0/1y/1y107sic2yaoe.mp3",
"pronoun": "הוּא",
"tense": "עָבָר"
},
"past_3fs": {
"form": "נִתְגַּלְּתָה",
"audio_url": "https://audio.pealim.com/v0/11/11zheoh29qyfq.mp3",
"pronoun": "הִיא",
"tense": "עָבָר"
},
"past_3p": {
"form": "נִתְגַּלּוּ",
"audio_url": "https://audio.pealim.com/v0/1x/1xuof8hxr9c8d.mp3",
"pronoun": "הֵם / הֵן",
"tense": "עָבָר"
},
"future_1s": {
"form": "אֶתְגַּלֶּה",
"audio_url": "https://audio.pealim.com/v0/1g/1gnwp3ylk9wr8.mp3",
"pronoun": "אֲנִי",
"tense": "עָתִיד"
},
"future_1p": {
"form": "נִתְגַּלֶּה",
"audio_url": "https://audio.pealim.com/v0/1y/1y1gcuyeqqljo.mp3",
"pronoun": "אֲנַחְנוּ",
"tense": "עָתִיד"
},
"future_2ms": {
"form": "תִּתְגַּלֶּה",
"audio_url": "https://audio.pealim.com/v0/1k/1kk6fs1tcnua2.mp3",
"pronoun": "אַתָּה",
"tense": "עָתִיד"
},
"future_2fs": {
"form": "תִּתְגַּלִּי",
"audio_url": "https://audio.pealim.com/v0/1k/1kjrlkkpqslgf.mp3",
"pronoun": "אַתְּ",
"tense": "עָתִיד"
},
"future_2mp": {
"form": "תִּתְגַּלּוּ",
"audio_url": "https://audio.pealim.com/v0/1k/1kqydeiac53ld.mp3",
"pronoun": "אַתֶּם",
"tense": "עָתִיד"
},
"future_2fp": {
"form": "תִּתְגַּלֶּינָה",
"audio_url": "https://audio.pealim.com/v0/te/tetf67m6olwq.mp3",
"pronoun": "אַתֶּן",
"tense": "עָתִיד"
},
"future_3ms": {
"form": "יִתְגַּלֶּה",
"audio_url": "https://audio.pealim.com/v0/nk/nktxxd761qhj.mp3",
"pronoun": "הוּא",
"tense": "עָתִיד"
},
"future_3fs": {
"form": "תִּתְגַּלֶּה",
"audio_url": "https://audio.pealim.com/v0/1k/1kk6fs1tcnua2.mp3",
"pronoun": "הִיא",
"tense": "עָתִיד"
},
"future_3mp": {
"form": "יִתְגַּלּוּ",
"audio_url": "https://audio.pealim.com/v0/nr/nrlvjto5izsu.mp3",
"pronoun": "הֵם",
"tense": "עָתִיד"
},
"future_3fp": {
"form": "תִּתְגַּלֶּינָה",
"audio_url": "https://audio.pealim.com/v0/te/tetf67m6olwq.mp3",
"pronoun": "הֵן",
"tense": "עָתִיד"
},
"imperative_ms": {
"form": "הִתְגַּלֵּה!",
"audio_url": "https://audio.pealim.com/v0/1d/1dpfnmygco8oz.mp3",
"pronoun": "אַתָּה",
"tense": "צִוּוּי"
},
"imperative_fs": {
"form": "הִתְגַּלִּי!",
"audio_url": "https://audio.pealim.com/v0/1d/1dpmfb7imnc19.mp3",
"pronoun": "אַתְּ",
"tense": "צִוּוּי"
},
"imperative_mp": {
"form": "הִתְגַּלּוּ!",
"audio_url": "https://audio.pealim.com/v0/1d/1difnh9y1atwb.mp3",
"pronoun": "אַתֶּם",
"tense": "צִוּוּי"
},
"imperative_fp": {
"form": "הִתְגַּלֶּינָה!",
"audio_url": "https://audio.pealim.com/v0/wx/wxh6vsca0qyi.mp3",
"pronoun": "אַתֶּן",
"tense": "צִוּוּי"
},
"infinitive": {
"form": "לְהִתְגַּלּוֹת",
"audio_url": "https://audio.pealim.com/v0/1o/1ocngj7nlgsu7.mp3",
"pronoun": "",
"tense": "מְקוֹר"
}
}
},
"להתקלקל": {
"infinitive": "להתקלקל",
"slug": "1906-lehitkalkel",
@ -14720,5 +14542,183 @@
"tense": "מְקוֹר"
}
}
},
"להתגלות": {
"infinitive": "להתגלות",
"slug": "332-lehitgalot",
"root": "ג - ל - ה",
"binyan": "Hitpa'el",
"is_passive": false,
"reference_form": "לְהִתְגַּלּוֹת",
"forms": {
"present_ms": {
"form": "מִתְגַּלֶּה",
"audio_url": "https://audio.pealim.com/v0/17/17aik28prm3ox.mp3",
"pronoun": "",
"tense": "הוֹוֶה"
},
"present_fs": {
"form": "מִתְגַּלָּה",
"audio_url": "https://audio.pealim.com/v0/17/17a2ezsn3tstn.mp3",
"pronoun": "",
"tense": "הוֹוֶה"
},
"present_mp": {
"form": "מִתְגַּלִּים",
"audio_url": "https://audio.pealim.com/v0/ic/ic1fbwv4cmec.mp3",
"pronoun": "",
"tense": "הוֹוֶה"
},
"present_fp": {
"form": "מִתְגַּלּוֹת",
"audio_url": "https://audio.pealim.com/v0/1x/1xkipm6geolmn.mp3",
"pronoun": "",
"tense": "הוֹוֶה"
},
"past_1s": {
"form": "נִתְגַּלֵּיתִי",
"audio_url": "https://audio.pealim.com/v0/8s/8slivd19nhsg.mp3",
"pronoun": "אֲנִי",
"tense": "עָבָר"
},
"past_1p": {
"form": "נִתְגַּלֵּינוּ",
"audio_url": "https://audio.pealim.com/v0/9r/9r6dsilbbfoq.mp3",
"pronoun": "אֲנַחְנוּ",
"tense": "עָבָר"
},
"past_2ms": {
"form": "נִתְגַּלֵּיתָ",
"audio_url": "https://audio.pealim.com/v0/1e/1ephuiupr8yqt.mp3",
"pronoun": "אַתָּה",
"tense": "עָבָר"
},
"past_2fs": {
"form": "נִתְגַּלֵּית",
"audio_url": "https://audio.pealim.com/v0/xb/xbkrr0255b0s.mp3",
"pronoun": "אַתְּ",
"tense": "עָבָר"
},
"past_2mp": {
"form": "נִתְגַּלֵּיתֶם",
"audio_url": "https://audio.pealim.com/v0/ht/ht8tvie1mfln.mp3",
"pronoun": "אַתֶּם",
"tense": "עָבָר"
},
"past_2fp": {
"form": "נִתְגַּלֵּיתֶן",
"audio_url": "https://audio.pealim.com/v0/5u/5udjkfd31qpk.mp3",
"pronoun": "אַתֶּן",
"tense": "עָבָר"
},
"past_3ms": {
"form": "נִתְגַּלָּה",
"audio_url": "https://audio.pealim.com/v0/1y/1y107sic2yaoe.mp3",
"pronoun": "הוּא",
"tense": "עָבָר"
},
"past_3fs": {
"form": "נִתְגַּלְּתָה",
"audio_url": "https://audio.pealim.com/v0/11/11zheoh29qyfq.mp3",
"pronoun": "הִיא",
"tense": "עָבָר"
},
"past_3p": {
"form": "נִתְגַּלּוּ",
"audio_url": "https://audio.pealim.com/v0/1x/1xuof8hxr9c8d.mp3",
"pronoun": "הֵם / הֵן",
"tense": "עָבָר"
},
"future_1s": {
"form": "אֶתְגַּלֶּה",
"audio_url": "https://audio.pealim.com/v0/1g/1gnwp3ylk9wr8.mp3",
"pronoun": "אֲנִי",
"tense": "עָתִיד"
},
"future_1p": {
"form": "נִתְגַּלֶּה",
"audio_url": "https://audio.pealim.com/v0/1y/1y1gcuyeqqljo.mp3",
"pronoun": "אֲנַחְנוּ",
"tense": "עָתִיד"
},
"future_2ms": {
"form": "תִּתְגַּלֶּה",
"audio_url": "https://audio.pealim.com/v0/1k/1kk6fs1tcnua2.mp3",
"pronoun": "אַתָּה",
"tense": "עָתִיד"
},
"future_2fs": {
"form": "תִּתְגַּלִּי",
"audio_url": "https://audio.pealim.com/v0/1k/1kjrlkkpqslgf.mp3",
"pronoun": "אַתְּ",
"tense": "עָתִיד"
},
"future_2mp": {
"form": "תִּתְגַּלּוּ",
"audio_url": "https://audio.pealim.com/v0/1k/1kqydeiac53ld.mp3",
"pronoun": "אַתֶּם",
"tense": "עָתִיד"
},
"future_2fp": {
"form": "תִּתְגַּלֶּינָה",
"audio_url": "https://audio.pealim.com/v0/te/tetf67m6olwq.mp3",
"pronoun": "אַתֶּן",
"tense": "עָתִיד"
},
"future_3ms": {
"form": "יִתְגַּלֶּה",
"audio_url": "https://audio.pealim.com/v0/nk/nktxxd761qhj.mp3",
"pronoun": "הוּא",
"tense": "עָתִיד"
},
"future_3fs": {
"form": "תִּתְגַּלֶּה",
"audio_url": "https://audio.pealim.com/v0/1k/1kk6fs1tcnua2.mp3",
"pronoun": "הִיא",
"tense": "עָתִיד"
},
"future_3mp": {
"form": "יִתְגַּלּוּ",
"audio_url": "https://audio.pealim.com/v0/nr/nrlvjto5izsu.mp3",
"pronoun": "הֵם",
"tense": "עָתִיד"
},
"future_3fp": {
"form": "תִּתְגַּלֶּינָה",
"audio_url": "https://audio.pealim.com/v0/te/tetf67m6olwq.mp3",
"pronoun": "הֵן",
"tense": "עָתִיד"
},
"imperative_ms": {
"form": "הִתְגַּלֵּה!",
"audio_url": "https://audio.pealim.com/v0/1d/1dpfnmygco8oz.mp3",
"pronoun": "אַתָּה",
"tense": "צִוּוּי"
},
"imperative_fs": {
"form": "הִתְגַּלִּי!",
"audio_url": "https://audio.pealim.com/v0/1d/1dpmfb7imnc19.mp3",
"pronoun": "אַתְּ",
"tense": "צִוּוּי"
},
"imperative_mp": {
"form": "הִתְגַּלּוּ!",
"audio_url": "https://audio.pealim.com/v0/1d/1difnh9y1atwb.mp3",
"pronoun": "אַתֶּם",
"tense": "צִוּוּי"
},
"imperative_fp": {
"form": "הִתְגַּלֶּינָה!",
"audio_url": "https://audio.pealim.com/v0/wx/wxh6vsca0qyi.mp3",
"pronoun": "אַתֶּן",
"tense": "צִוּוּי"
},
"infinitive": {
"form": "לְהִתְגַּלּוֹת",
"audio_url": "https://audio.pealim.com/v0/1o/1ocngj7nlgsu7.mp3",
"pronoun": "",
"tense": "מְקוֹר"
}
}
}
}