refactor: Reorganize skill numbering and update documentation
Skill Numbering Changes: - 01-03: OurDigital core (was 30-32) - 31-32: Notion tools (was 01-02) - 99_archive: Renamed from _archive for sorting New Files: - AGENTS.md: Claude Code agent routing guide - requirements.txt for 00-claude-code-setting, 32-notion-writer, 43-jamie-youtube-manager Documentation Updates: - CLAUDE.md: Updated skill inventory (23 skills) - AUDIT_REPORT.md: Current completion status (91%) - Archived REFACTORING_PLAN.md (most tasks complete) Removed: - ga-agent-skills/ (moved to separate repo ~/Project/dintel-ga4-agent) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Apply brand styling to PowerPoint presentations
|
||||
Customizes colors, fonts, and visual elements based on brand guidelines
|
||||
"""
|
||||
|
||||
import json
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
# Note: In production, install python-pptx via pip
|
||||
try:
|
||||
from pptx import Presentation
|
||||
from pptx.dml.color import RGBColor
|
||||
from pptx.util import Pt
|
||||
except ImportError:
|
||||
print("📦 Please install python-pptx: pip install python-pptx")
|
||||
exit(1)
|
||||
|
||||
class BrandStyler:
|
||||
"""Apply brand guidelines to PowerPoint presentations"""
|
||||
|
||||
def __init__(self, brand_config_path: str):
|
||||
"""Load brand configuration"""
|
||||
with open(brand_config_path, 'r') as f:
|
||||
self.brand_config = json.load(f)
|
||||
|
||||
self.colors = self.brand_config.get('colors', {})
|
||||
self.fonts = self.brand_config.get('fonts', {})
|
||||
self.logos = self.brand_config.get('logos', {})
|
||||
|
||||
def apply_to_presentation(self, pptx_path: str, output_path: str = None):
|
||||
"""Apply brand styling to PowerPoint file"""
|
||||
|
||||
if not output_path:
|
||||
output_path = pptx_path.replace('.pptx', '_branded.pptx')
|
||||
|
||||
print(f"🎨 Applying brand styles to: {pptx_path}")
|
||||
|
||||
# Load presentation
|
||||
prs = Presentation(pptx_path)
|
||||
|
||||
# Apply styles to each slide
|
||||
for slide_num, slide in enumerate(prs.slides, 1):
|
||||
self.style_slide(slide, slide_num)
|
||||
|
||||
# Save branded version
|
||||
prs.save(output_path)
|
||||
print(f"✅ Branded presentation saved: {output_path}")
|
||||
|
||||
return output_path
|
||||
|
||||
def style_slide(self, slide, slide_num: int):
|
||||
"""Apply brand styling to individual slide"""
|
||||
|
||||
# Style text elements
|
||||
for shape in slide.shapes:
|
||||
if shape.has_text_frame:
|
||||
self.style_text_frame(shape.text_frame, slide_num)
|
||||
|
||||
# Style tables
|
||||
if shape.has_table:
|
||||
self.style_table(shape.table)
|
||||
|
||||
def style_text_frame(self, text_frame, slide_num: int):
|
||||
"""Apply brand fonts and colors to text"""
|
||||
|
||||
for paragraph in text_frame.paragraphs:
|
||||
for run in paragraph.runs:
|
||||
# Apply font
|
||||
if slide_num == 1: # Title slide
|
||||
run.font.name = self.fonts.get('heading', 'Arial')
|
||||
if paragraph.level == 0:
|
||||
run.font.size = Pt(44)
|
||||
else:
|
||||
run.font.name = self.fonts.get('body', 'Arial')
|
||||
|
||||
# Apply colors based on context
|
||||
if slide_num == 1: # Title slide - white text
|
||||
run.font.color.rgb = RGBColor(255, 255, 255)
|
||||
elif paragraph.level == 0: # Headings
|
||||
color_hex = self.colors.get('primary', '#1a73e8').lstrip('#')
|
||||
run.font.color.rgb = RGBColor(
|
||||
int(color_hex[0:2], 16),
|
||||
int(color_hex[2:4], 16),
|
||||
int(color_hex[4:6], 16)
|
||||
)
|
||||
else: # Body text
|
||||
color_hex = self.colors.get('text', '#3c4043').lstrip('#')
|
||||
run.font.color.rgb = RGBColor(
|
||||
int(color_hex[0:2], 16),
|
||||
int(color_hex[2:4], 16),
|
||||
int(color_hex[4:6], 16)
|
||||
)
|
||||
|
||||
def style_table(self, table):
|
||||
"""Apply brand styling to tables"""
|
||||
|
||||
# Style header row
|
||||
if len(table.rows) > 0:
|
||||
for cell in table.rows[0].cells:
|
||||
# Apply header background color
|
||||
if hasattr(cell, 'fill'):
|
||||
color_hex = self.colors.get('secondary', '#34a853').lstrip('#')
|
||||
# Note: python-pptx table cell fill is complex
|
||||
# This is simplified for example
|
||||
pass
|
||||
|
||||
# Style table text
|
||||
for row in table.rows:
|
||||
for cell in row.cells:
|
||||
if cell.text_frame:
|
||||
for paragraph in cell.text_frame.paragraphs:
|
||||
for run in paragraph.runs:
|
||||
run.font.name = self.fonts.get('body', 'Arial')
|
||||
run.font.size = Pt(14)
|
||||
|
||||
def add_logo(self, slide, position='top-right'):
|
||||
"""Add company logo to slide"""
|
||||
|
||||
logo_path = self.logos.get('primary')
|
||||
if not logo_path or not Path(logo_path).exists():
|
||||
return
|
||||
|
||||
# Position mappings
|
||||
positions = {
|
||||
'top-right': {'left': 8.5, 'top': 0.25, 'width': 1.5},
|
||||
'bottom-right': {'left': 8.5, 'top': 4.75, 'width': 1.5},
|
||||
'top-left': {'left': 0.25, 'top': 0.25, 'width': 1.5}
|
||||
}
|
||||
|
||||
pos = positions.get(position, positions['top-right'])
|
||||
|
||||
# Add logo image
|
||||
# Note: Requires python-pptx inches conversion
|
||||
# slide.shapes.add_picture(logo_path, left, top, width)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Apply brand styling to PowerPoint presentations"
|
||||
)
|
||||
parser.add_argument(
|
||||
"presentation",
|
||||
help="Path to PowerPoint presentation"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--config",
|
||||
default="assets/brand_config.json",
|
||||
help="Path to brand configuration JSON"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output",
|
||||
help="Output path for branded presentation"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Apply branding
|
||||
styler = BrandStyler(args.config)
|
||||
output_path = styler.apply_to_presentation(
|
||||
args.presentation,
|
||||
args.output
|
||||
)
|
||||
|
||||
print(f"✨ Brand styling complete: {output_path}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user