feat: implement ChatGPT document theme for compact interactive reading (Issue #165)
Add comprehensive ChatGPT-style document theme optimized for modern interactive content: **Theme Features:** - Inter font family for clean, modern sans-serif typography - Compact 580px width for chat-like reading experience - High contrast (#1f1f1f text on white background) - ChatGPT signature green (#10a37f) accent color - Tight 1.5 line height for efficient information density - Modern 8px border radius for contemporary feel - Optimized code block styling with proper monospace fonts **Technical Implementation:** - Added 'chatgpt' theme to LAYERED_THEMES system (document scope) - Full backward compatibility with TEMPLATE_STYLES and LEGACY_THEME_MAPPING - CLI integration: `markitect md-render --theme chatgpt` - Proper theme layering support (combines with light/dark modes) **Quality Assurance:** - Comprehensive 9-test suite covering all functionality (9/9 passing) - Verified HTML generation and CSS styling - Tested CLI integration and theme combinations - Full compatibility with existing theme architecture Successfully closes Issue #165 with compact, readable layout optimized for interactive content following ChatGPT's interface design principles. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -201,6 +201,32 @@ LAYERED_THEMES = {
|
||||
'blockquote_color': '#666666'
|
||||
}
|
||||
},
|
||||
'chatgpt': {
|
||||
'scope': 'document',
|
||||
'properties': {
|
||||
'font_family': 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
||||
'heading_font_family': 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
||||
'max_width': '580px',
|
||||
'body_background': '#ffffff',
|
||||
'body_color': '#1f1f1f',
|
||||
'heading_color': '#1f1f1f',
|
||||
'text_align': 'left',
|
||||
'line_height': '1.5',
|
||||
'heading_style': 'minimal',
|
||||
'accent_color': '#10a37f',
|
||||
'link_color': '#10a37f',
|
||||
'link_hover_color': '#0d8c6d',
|
||||
'code_background': '#f7f7f7',
|
||||
'code_color': '#1f1f1f',
|
||||
'code_font_family': '"SF Mono", Monaco, Inconsolata, "Roboto Mono", Consolas, "Courier New", monospace',
|
||||
'font_size': '15px',
|
||||
'heading_margin': '1.2em 0 0.6em 0',
|
||||
'paragraph_margin': '1em 0',
|
||||
'border_radius': '8px',
|
||||
'blockquote_border': '#10a37f',
|
||||
'blockquote_color': '#6b7280'
|
||||
}
|
||||
},
|
||||
|
||||
# Branding Themes - Company/personal styling
|
||||
'corporate': {
|
||||
@@ -227,7 +253,8 @@ LEGACY_THEME_MAPPING = {
|
||||
'github': ['light', 'standard', 'github'],
|
||||
'dark': ['dark', 'standard', 'basic'],
|
||||
'academic': ['light', 'standard', 'academic'],
|
||||
'substack': ['light', 'standard', 'substack']
|
||||
'substack': ['light', 'standard', 'substack'],
|
||||
'chatgpt': ['light', 'standard', 'chatgpt']
|
||||
}
|
||||
|
||||
# Keep TEMPLATE_STYLES for backward compatibility in tests
|
||||
@@ -256,6 +283,11 @@ TEMPLATE_STYLES = {
|
||||
'body_color': '#333333',
|
||||
'font_family': 'Spectral, Georgia, "Times New Roman", serif',
|
||||
'max_width': '680px'
|
||||
},
|
||||
'chatgpt': {
|
||||
'body_color': '#1f1f1f',
|
||||
'font_family': 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
||||
'max_width': '580px'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
254
tests/test_issue_165_chatgpt_theme.py
Normal file
254
tests/test_issue_165_chatgpt_theme.py
Normal file
@@ -0,0 +1,254 @@
|
||||
"""
|
||||
Tests for Issue #165: Document theme that mimics ChatGPT chat interface fonts and fontsizes
|
||||
|
||||
This module tests the implementation of a ChatGPT-style document theme
|
||||
for compact, readable content optimized for interactive reading.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import tempfile
|
||||
import os
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch, MagicMock
|
||||
import json
|
||||
|
||||
# Add project root to path for imports
|
||||
import sys
|
||||
project_root = Path(__file__).parent.parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
|
||||
class TestIssue165ChatGPTTheme:
|
||||
"""Test ChatGPT theme implementation for compact, interactive reading."""
|
||||
|
||||
def setup_method(self):
|
||||
"""Set up test environment."""
|
||||
# Create temporary directory for test outputs
|
||||
self.temp_dir = tempfile.mkdtemp()
|
||||
self.markdown_content = """# AI-Powered Document Processing
|
||||
|
||||
This is a test document for validating the ChatGPT theme implementation.
|
||||
The theme should provide compact, efficient layout optimized for interactive reading.
|
||||
|
||||
## Key Features
|
||||
|
||||
The ChatGPT style emphasizes:
|
||||
- Sans-serif fonts for all text (Inter)
|
||||
- Compact layout with efficient spacing
|
||||
- High contrast for clarity
|
||||
- Modern system font stack
|
||||
|
||||
### Design Principles
|
||||
|
||||
1. **Efficiency First**: Compact layout maximizes information density
|
||||
2. **Clean Typography**: Modern sans-serif fonts for digital readability
|
||||
3. **High Contrast**: Dark text on light background for clarity
|
||||
4. **Interactive Feel**: Layout optimized for conversation-like reading
|
||||
|
||||
> "The best chat interfaces feel immediate and conversational."
|
||||
> — A principle guiding ChatGPT's interface design
|
||||
|
||||
```python
|
||||
def process_document(text):
|
||||
# Code blocks should use monospace fonts
|
||||
return enhanced_text
|
||||
```
|
||||
|
||||
This paragraph demonstrates how the theme handles body text with the compact
|
||||
spacing and modern typography that makes content feel immediate and engaging.
|
||||
"""
|
||||
|
||||
def teardown_method(self):
|
||||
"""Clean up test environment."""
|
||||
# Clean up temporary files
|
||||
import shutil
|
||||
shutil.rmtree(self.temp_dir, ignore_errors=True)
|
||||
|
||||
def test_chatgpt_theme_available_in_layered_themes(self):
|
||||
"""Test that chatgpt theme is available in LAYERED_THEMES - Issue #165."""
|
||||
from markitect.plugins.builtin.markdown_commands import LAYERED_THEMES
|
||||
|
||||
# ChatGPT theme should be available as a document theme
|
||||
assert 'chatgpt' in LAYERED_THEMES
|
||||
chatgpt_theme = LAYERED_THEMES['chatgpt']
|
||||
|
||||
# Should be scoped as a document theme
|
||||
assert chatgpt_theme['scope'] == 'document'
|
||||
|
||||
# Should have required typography properties
|
||||
properties = chatgpt_theme['properties']
|
||||
assert 'font_family' in properties
|
||||
assert 'max_width' in properties
|
||||
assert 'body_background' in properties
|
||||
assert 'heading_font_family' in properties
|
||||
|
||||
def test_chatgpt_theme_typography_properties(self):
|
||||
"""Test that chatgpt theme has correct typography properties - Issue #165."""
|
||||
from markitect.plugins.builtin.markdown_commands import LAYERED_THEMES
|
||||
|
||||
chatgpt_theme = LAYERED_THEMES['chatgpt']
|
||||
properties = chatgpt_theme['properties']
|
||||
|
||||
# Should use Inter font for body text
|
||||
assert 'Inter' in properties['font_family']
|
||||
|
||||
# Should use Inter for headings too (consistent sans-serif)
|
||||
assert 'Inter' in properties['heading_font_family']
|
||||
|
||||
# Should have compact max width for chat-like feel
|
||||
max_width = properties['max_width']
|
||||
# Convert to int if it has px suffix
|
||||
if max_width.endswith('px'):
|
||||
width_value = int(max_width[:-2])
|
||||
else:
|
||||
width_value = int(max_width)
|
||||
assert 550 <= width_value <= 620 # Compact range for chat-like reading
|
||||
|
||||
# Should have clean white background
|
||||
assert properties['body_background'] == '#ffffff'
|
||||
|
||||
# Should have dark text for high contrast
|
||||
assert properties['body_color'] == '#1f1f1f'
|
||||
|
||||
# Should have compact line height
|
||||
assert properties['line_height'] == '1.5'
|
||||
|
||||
# Should use ChatGPT's signature green accent
|
||||
assert properties['accent_color'] == '#10a37f'
|
||||
|
||||
def test_chatgpt_theme_code_styling(self):
|
||||
"""Test ChatGPT theme code block styling - Issue #165."""
|
||||
from markitect.plugins.builtin.markdown_commands import LAYERED_THEMES
|
||||
|
||||
chatgpt_theme = LAYERED_THEMES['chatgpt']
|
||||
properties = chatgpt_theme['properties']
|
||||
|
||||
# Should have monospace font for code
|
||||
assert 'code_font_family' in properties
|
||||
assert 'SF Mono' in properties['code_font_family'] or 'Monaco' in properties['code_font_family']
|
||||
|
||||
# Should have light gray code background
|
||||
assert properties['code_background'] == '#f7f7f7'
|
||||
assert properties['code_color'] == '#1f1f1f'
|
||||
|
||||
def test_chatgpt_theme_legacy_compatibility(self):
|
||||
"""Test that chatgpt theme works with legacy TEMPLATE_STYLES - Issue #165."""
|
||||
from markitect.plugins.builtin.markdown_commands import TEMPLATE_STYLES
|
||||
|
||||
# Should be available in legacy template styles for backward compatibility
|
||||
assert 'chatgpt' in TEMPLATE_STYLES
|
||||
chatgpt_legacy = TEMPLATE_STYLES['chatgpt']
|
||||
|
||||
# Should have required legacy properties
|
||||
assert 'body_color' in chatgpt_legacy
|
||||
assert 'font_family' in chatgpt_legacy
|
||||
assert 'max_width' in chatgpt_legacy
|
||||
|
||||
# Legacy values should match layered theme
|
||||
assert chatgpt_legacy['body_color'] == '#1f1f1f'
|
||||
assert 'Inter' in chatgpt_legacy['font_family']
|
||||
|
||||
def test_chatgpt_theme_legacy_mapping(self):
|
||||
"""Test ChatGPT theme legacy mapping - Issue #165."""
|
||||
from markitect.plugins.builtin.markdown_commands import LEGACY_THEME_MAPPING
|
||||
|
||||
# Should have legacy mapping
|
||||
assert 'chatgpt' in LEGACY_THEME_MAPPING
|
||||
mapping = LEGACY_THEME_MAPPING['chatgpt']
|
||||
|
||||
# Should map to light + standard + chatgpt
|
||||
assert mapping == ['light', 'standard', 'chatgpt']
|
||||
|
||||
def test_chatgpt_theme_cli_integration(self):
|
||||
"""Test ChatGPT theme through CLI md-render command - Issue #165."""
|
||||
input_file = Path(self.temp_dir) / "chatgpt_test.md"
|
||||
input_file.write_text(self.markdown_content)
|
||||
|
||||
output_file = Path(self.temp_dir) / "chatgpt_test.html"
|
||||
|
||||
from markitect.cli import cli
|
||||
from click.testing import CliRunner
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(cli, [
|
||||
'md-render',
|
||||
str(input_file),
|
||||
'--output', str(output_file),
|
||||
'--theme', 'chatgpt'
|
||||
])
|
||||
|
||||
assert result.exit_code == 0, f"CLI command failed: {result.output}"
|
||||
assert output_file.exists()
|
||||
|
||||
html_content = output_file.read_text()
|
||||
|
||||
# Should contain ChatGPT-specific styling
|
||||
assert 'Inter' in html_content # Font family
|
||||
assert '#1f1f1f' in html_content # Text color
|
||||
assert '#10a37f' in html_content # Accent color
|
||||
|
||||
def test_chatgpt_theme_html_generation(self):
|
||||
"""Test HTML generation with ChatGPT theme - Issue #165."""
|
||||
from markitect.plugins.builtin.markdown_commands import generate_html_with_embedded_markdown
|
||||
|
||||
test_markdown = "# AI Assistant\n\nThis is a test conversation for the ChatGPT theme."
|
||||
title = "ChatGPT Theme Test"
|
||||
|
||||
html = generate_html_with_embedded_markdown(
|
||||
test_markdown, title, "chatgpt", "", {}
|
||||
)
|
||||
|
||||
# Should generate valid HTML
|
||||
assert '<!DOCTYPE html>' in html
|
||||
assert title in html
|
||||
|
||||
# Should include ChatGPT styling
|
||||
assert 'Inter' in html # Font should be present
|
||||
assert '#1f1f1f' in html # Text color should be present
|
||||
assert '#10a37f' in html # Accent color should be present
|
||||
|
||||
def test_chatgpt_theme_layered_combination(self):
|
||||
"""Test ChatGPT theme combines properly with other layer themes - Issue #165."""
|
||||
from markitect.plugins.builtin.markdown_commands import parse_theme_string, combine_theme_properties
|
||||
|
||||
# Test combining chatgpt document theme with light mode and standard UI
|
||||
theme_list = parse_theme_string("light,standard,chatgpt")
|
||||
|
||||
assert 'light' in theme_list # Mode theme
|
||||
assert 'standard' in theme_list # UI theme
|
||||
assert 'chatgpt' in theme_list # Document theme
|
||||
|
||||
# Should be able to apply layered themes
|
||||
combined_styles = combine_theme_properties(theme_list)
|
||||
|
||||
# Should include properties from all themes
|
||||
assert 'body_background' in combined_styles # From light theme
|
||||
assert 'editor_panel_bg' in combined_styles # From standard UI theme
|
||||
assert 'font_family' in combined_styles # From chatgpt document theme
|
||||
|
||||
# ChatGPT-specific properties should be present
|
||||
assert 'Inter' in combined_styles['font_family']
|
||||
assert combined_styles['accent_color'] == '#10a37f'
|
||||
|
||||
def test_chatgpt_theme_compact_layout_properties(self):
|
||||
"""Test ChatGPT theme compact layout features - Issue #165."""
|
||||
from markitect.plugins.builtin.markdown_commands import LAYERED_THEMES
|
||||
|
||||
chatgpt_theme = LAYERED_THEMES['chatgpt']
|
||||
properties = chatgpt_theme['properties']
|
||||
|
||||
# Should have compact spacing properties
|
||||
assert 'font_size' in properties
|
||||
assert properties['font_size'] == '15px' # Standard readable size
|
||||
|
||||
# Should have minimal heading margins
|
||||
assert 'heading_margin' in properties
|
||||
assert '1.2em' in properties['heading_margin'] # Compact margins
|
||||
|
||||
# Should have compact paragraph spacing
|
||||
assert 'paragraph_margin' in properties
|
||||
assert '1em' in properties['paragraph_margin'] # Tight spacing
|
||||
|
||||
# Should have border radius for modern look
|
||||
assert 'border_radius' in properties
|
||||
assert properties['border_radius'] == '8px'
|
||||
Reference in New Issue
Block a user