feat: Add OurDigital custom skills package (10 skills)
Complete implementation of OurDigital skills with dual-platform support (Claude Desktop + Claude Code) following standardized structure. Skills created: - 01-ourdigital-brand-guide: Brand reference & style guidelines - 02-ourdigital-blog: Korean blog drafts (blog.ourdigital.org) - 03-ourdigital-journal: English essays (journal.ourdigital.org) - 04-ourdigital-research: Research prompts & workflows - 05-ourdigital-document: Notion-to-presentation pipeline - 06-ourdigital-designer: Visual/image prompt generation - 07-ourdigital-ad-manager: Ad copywriting & keyword research - 08-ourdigital-trainer: Training materials & workshop planning - 09-ourdigital-backoffice: Quotes, proposals, cost analysis - 10-ourdigital-skill-creator: Meta skill for creating new skills Features: - YAML frontmatter with "ourdigital" or "our" prefix triggers - Standardized directory structure (code/, desktop/, shared/, docs/) - Shared environment setup (_ourdigital-shared/) - Comprehensive reference documentation - Cross-skill integration support Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
168
custom-skills/05-ourdigital-document/code/scripts/apply_brand.py
Normal file
168
custom-skills/05-ourdigital-document/code/scripts/apply_brand.py
Normal file
@@ -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