diff --git a/src/web_generator.py b/src/web_generator.py index 5d1c1b9e..0a48c5bb 100644 --- a/src/web_generator.py +++ b/src/web_generator.py @@ -8,17 +8,80 @@ import tempfile from pathlib import Path -def get_numeral_color(number, config): - """Get color for numeral based on configuration.""" - if not config.get('colored_numerals', False): - return "#333" - +def get_colored_numeral_html(number, config): + """Generate HTML for numeral with appropriate coloring based on configuration.""" color_scheme = config.get('color_scheme', 'monochrome') - if color_scheme == 'monochrome': - return "#333" + + # For web display, automatically use colored numerals for non-monochrome schemes + use_colored = config.get('colored_numerals', False) or color_scheme != 'monochrome' + + if not use_colored or color_scheme == 'monochrome': + return str(number) + + # Use the same colors as in the Typst template + place_value_colors = [ + "#2E86AB", # ones - blue + "#A23B72", # tens - magenta + "#F18F01", # hundreds - orange + "#6A994E", # thousands - green + "#BC4B51", # ten-thousands - red + ] + + if color_scheme == 'place-value': + # Color each digit by its place value (right-to-left: rightmost is ones) + digits = str(number) + colored_spans = [] + + for i, digit in enumerate(digits): + place_idx = len(digits) - 1 - i # rightmost digit is place 0 (ones) + color_idx = place_idx % len(place_value_colors) + color = place_value_colors[color_idx] + colored_spans.append(f'{digit}') + + return ''.join(colored_spans) + elif color_scheme == 'heaven-earth': + # Use orange (heaven bead color) + return f'{number}' + elif color_scheme == 'alternating': + # For alternating, use blue for simplicity in web display + return f'{number}' else: - # For colored schemes, use a darker color for visibility - return "#222" + return str(number) + + +def get_numeral_color(number, config): + """Get single color for numeral (kept for backwards compatibility with tests).""" + color_scheme = config.get('color_scheme', 'monochrome') + + # For web display, automatically use colored numerals for non-monochrome schemes + use_colored = config.get('colored_numerals', False) or color_scheme != 'monochrome' + + if not use_colored or color_scheme == 'monochrome': + return "#333" + + # Use the same colors as in the Typst template + place_value_colors = [ + "#2E86AB", # ones - blue + "#A23B72", # tens - magenta + "#F18F01", # hundreds - orange + "#6A994E", # thousands - green + "#BC4B51", # ten-thousands - red + ] + + if color_scheme == 'place-value': + # For single color (used by tests), return highest place value color + digits = str(number) + place_idx = len(digits) - 1 # Most significant digit place + color_idx = place_idx % len(place_value_colors) + return place_value_colors[color_idx] + elif color_scheme == 'heaven-earth': + # Use orange (heaven bead color) + return "#F18F01" + elif color_scheme == 'alternating': + # For alternating, use blue for simplicity in web display + return "#1E88E5" + else: + return "#333" def generate_card_svgs(numbers, config): @@ -80,7 +143,7 @@ def generate_web_flashcards(numbers, config, output_path): cards_html = [] for i, number in enumerate(numbers): svg_content = card_svgs.get(number, f'Error') - numeral_color = get_numeral_color(number, config) + colored_numeral = get_colored_numeral_html(number, config) card_html = f'''
@@ -88,7 +151,7 @@ def generate_web_flashcards(numbers, config, output_path):
{svg_content}
-
{number}
+
{colored_numeral}
''' cards_html.append(card_html) diff --git a/templates/flashcards.typ b/templates/flashcards.typ index 83bcf2fd..21494be6 100644 --- a/templates/flashcards.typ +++ b/templates/flashcards.typ @@ -139,13 +139,13 @@ ) // Draw heaven bead - // Position inactive earth bead gap from reckoning bar: 19px you measured - // Convert to same gap for heaven: heaven-earth-gap - gap - bead-size/2 - #let earth-gap = 19pt // Exact same gap as earth beads + #let heaven-gap = 5pt // Gap between active/inactive beads or bar/inactive beads #let heaven-y = if heaven-active == 1 { - heaven-earth-gap - bead-size / 2 - 1pt // Active (center just above bar) + // Active heaven bead: positioned close to reckoning bar + heaven-earth-gap - bead-size / 2 - 1pt } else { - heaven-earth-gap - earth-gap - bead-size / 2 // Inactive (same gap as earth, measured from reckoning bar) + // Inactive heaven bead: positioned away from reckoning bar with gap + heaven-earth-gap - heaven-gap - bead-size / 2 } #let bead-color = if heaven-active == 1 { @@ -171,9 +171,17 @@ #for i in range(4) [ #let is-active = i < earth-active #let earth-y = if is-active { + // Active beads: positioned close to reckoning bar, in sequence heaven-earth-gap + bar-thickness + 1pt + bead-size / 2 + i * (bead-size + bead-spacing) } else { - total-height - (4 - i) * (bead-size + bead-spacing) - 5pt + bead-size / 2 + // Inactive beads: positioned after the active beads + gap, or after reckoning bar + gap if no active beads + if earth-active > 0 { + // Position after the last active bead + gap + heaven-earth-gap + bar-thickness + 1pt + bead-size / 2 + earth-active * (bead-size + bead-spacing) + heaven-gap + (i - earth-active) * (bead-size + bead-spacing) + } else { + // No active beads: position after reckoning bar + gap + heaven-earth-gap + bar-thickness + heaven-gap + bead-size / 2 + i * (bead-size + bead-spacing) + } } #let earth-bead-color = if is-active { diff --git a/tests/references/card_7_front.png b/tests/references/card_7_front.png index 06d3eb1b..32694387 100644 Binary files a/tests/references/card_7_front.png and b/tests/references/card_7_front.png differ diff --git a/tests/test_web_generation.py b/tests/test_web_generation.py index 417fda94..83cd697b 100644 --- a/tests/test_web_generation.py +++ b/tests/test_web_generation.py @@ -29,13 +29,21 @@ class TestWebGeneration: def test_get_numeral_color_place_value(self, sample_config): """Test numeral color for place-value scheme.""" config = {**sample_config, 'color_scheme': 'place-value', 'colored_numerals': True} - color = get_numeral_color(42, config) - assert color == "#222" # Darker color for visibility - # Without colored numerals, should return default - config['colored_numerals'] = False + # Test different place values + color = get_numeral_color(7, config) # ones place + assert color == "#2E86AB" # blue + + color = get_numeral_color(42, config) # tens place + assert color == "#A23B72" # magenta + + color = get_numeral_color(456, config) # hundreds place + assert color == "#F18F01" # orange + + # For place-value scheme, colored numerals are automatically enabled + config['colored_numerals'] = False color = get_numeral_color(42, config) - assert color == "#333" + assert color == "#A23B72" # Still colored because place-value auto-enables coloring @patch('generate.generate_cards_direct') def test_generate_card_svgs_success(self, mock_generate_cards_direct, sample_config, temp_dir):