feat: use colors in gdocs
This commit is contained in:
@@ -9,12 +9,54 @@ from typing import Dict, Any, Optional, Tuple
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def _normalize_color(color: Any, param_name: str) -> Optional[Dict[str, float]]:
|
||||
"""
|
||||
Normalize a user-supplied color into Docs API rgbColor format.
|
||||
|
||||
Supports:
|
||||
- Hex strings: "#RRGGBB" or "RRGGBB"
|
||||
- Tuple/list of 3 ints (0-255) or floats (0-1)
|
||||
"""
|
||||
if color is None:
|
||||
return None
|
||||
|
||||
def _to_component(value: Any) -> float:
|
||||
if isinstance(value, int):
|
||||
if value < 0 or value > 255:
|
||||
raise ValueError(f"{param_name} components must be 0-255 when using integers")
|
||||
return value / 255
|
||||
if isinstance(value, float):
|
||||
if value < 0 or value > 1:
|
||||
raise ValueError(f"{param_name} components must be between 0 and 1 when using floats")
|
||||
return value
|
||||
raise ValueError(f"{param_name} components must be int (0-255) or float (0-1)")
|
||||
|
||||
if isinstance(color, str):
|
||||
hex_color = color.lstrip('#')
|
||||
if len(hex_color) != 6 or any(c not in '0123456789abcdefABCDEF' for c in hex_color):
|
||||
raise ValueError(f"{param_name} must be a hex string like '#RRGGBB'")
|
||||
r = int(hex_color[0:2], 16) / 255
|
||||
g = int(hex_color[2:4], 16) / 255
|
||||
b = int(hex_color[4:6], 16) / 255
|
||||
return {'red': r, 'green': g, 'blue': b}
|
||||
|
||||
if isinstance(color, (list, tuple)) and len(color) == 3:
|
||||
r = _to_component(color[0])
|
||||
g = _to_component(color[1])
|
||||
b = _to_component(color[2])
|
||||
return {'red': r, 'green': g, 'blue': b}
|
||||
|
||||
raise ValueError(f"{param_name} must be a hex string or RGB tuple/list")
|
||||
|
||||
|
||||
def build_text_style(
|
||||
bold: bool = None,
|
||||
italic: bool = None,
|
||||
underline: bool = None,
|
||||
font_size: int = None,
|
||||
font_family: str = None
|
||||
font_family: str = None,
|
||||
text_color: Any = None,
|
||||
background_color: Any = None
|
||||
) -> tuple[Dict[str, Any], list[str]]:
|
||||
"""
|
||||
Build text style object for Google Docs API requests.
|
||||
@@ -25,6 +67,8 @@ def build_text_style(
|
||||
underline: Whether text should be underlined
|
||||
font_size: Font size in points
|
||||
font_family: Font family name
|
||||
text_color: Text color as hex string or RGB tuple/list
|
||||
background_color: Background (highlight) color as hex string or RGB tuple/list
|
||||
|
||||
Returns:
|
||||
Tuple of (text_style_dict, list_of_field_names)
|
||||
@@ -51,6 +95,16 @@ def build_text_style(
|
||||
if font_family is not None:
|
||||
text_style['weightedFontFamily'] = {'fontFamily': font_family}
|
||||
fields.append('weightedFontFamily')
|
||||
|
||||
if text_color is not None:
|
||||
rgb = _normalize_color(text_color, "text_color")
|
||||
text_style['foregroundColor'] = {'color': {'rgbColor': rgb}}
|
||||
fields.append('foregroundColor')
|
||||
|
||||
if background_color is not None:
|
||||
rgb = _normalize_color(background_color, "background_color")
|
||||
text_style['backgroundColor'] = {'color': {'rgbColor': rgb}}
|
||||
fields.append('backgroundColor')
|
||||
|
||||
return text_style, fields
|
||||
|
||||
@@ -121,7 +175,9 @@ def create_format_text_request(
|
||||
italic: bool = None,
|
||||
underline: bool = None,
|
||||
font_size: int = None,
|
||||
font_family: str = None
|
||||
font_family: str = None,
|
||||
text_color: Any = None,
|
||||
background_color: Any = None
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Create an updateTextStyle request for Google Docs API.
|
||||
@@ -134,11 +190,15 @@ def create_format_text_request(
|
||||
underline: Whether text should be underlined
|
||||
font_size: Font size in points
|
||||
font_family: Font family name
|
||||
text_color: Text color as hex string or RGB tuple/list
|
||||
background_color: Background (highlight) color as hex string or RGB tuple/list
|
||||
|
||||
Returns:
|
||||
Dictionary representing the updateTextStyle request, or None if no styles provided
|
||||
"""
|
||||
text_style, fields = build_text_style(bold, italic, underline, font_size, font_family)
|
||||
text_style, fields = build_text_style(
|
||||
bold, italic, underline, font_size, font_family, text_color, background_color
|
||||
)
|
||||
|
||||
if not text_style:
|
||||
return None
|
||||
@@ -318,4 +378,3 @@ def validate_operation(operation: Dict[str, Any]) -> Tuple[bool, str]:
|
||||
return False, f"Missing required field: {field}"
|
||||
|
||||
return True, ""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user