Major refactoring of ourdigital-custom-skills with new numbering system: ## Structure Changes - Each skill now has code/ (Claude Code) and desktop/ (Claude Desktop) versions - New progressive numbering: 01-09 General, 10-19 SEO, 20-29 GTM, 30-39 OurDigital, 40-49 Jamie ## Skill Reorganization - 01-notion-organizer (from 02) - 10-18: SEO tools split into focused skills (technical, on-page, local, schema, vitals, gsc, gateway) - 20-21: GTM audit and manager - 30-32: OurDigital designer, research, presentation - 40-41: Jamie brand editor and audit ## New Files - .claude/commands/: Slash command definitions for all skills - CLAUDE.md: Updated with new skill structure documentation - REFACTORING_PLAN.md: Migration documentation - COMPATIBILITY_REPORT.md, SKILLS_COMPARISON.md: Analysis docs ## Removed - Old skill directories (02-05, 10-14, 20-21 old numbering) - Consolidated into new structure with _archive/ for reference 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
169 lines
5.7 KiB
Python
169 lines
5.7 KiB
Python
#!/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()
|