## Backend Changes:
- Enhanced PluginTemplate.save() to auto-parse template variables from plugin code
- Updated PluginInstallationSerializer to expose template metadata (description, category, version, author, logo, template_variables)
- Fixed template variable parser to handle nested {{ }} braces in default values
- Added brace-counting algorithm to properly extract variables with insertion codes
- Fixed explicit type parameter detection (textarea, text, email, etc.)
- Made scheduled_task optional on PluginInstallation model
- Added EventPlugin through model for event-plugin relationships
- Added Event.execute_plugins() method for plugin automation
## Frontend Changes:
- Created Tasks.tsx page for managing scheduled tasks
- Enhanced MyPlugins page with clickable plugin cards
- Added edit configuration modal with dynamic form generation
- Implemented escape sequence handling (convert \n, \', etc. for display)
- Added plugin logos to My Plugins page
- Updated type definitions for PluginInstallation interface
- Added insertion code documentation to Plugin Docs
## Plugin System:
- All platform plugins now have editable email templates with textarea support
- Template variables properly parsed with full default values
- Insertion codes ({{CUSTOMER_NAME}}, {{BUSINESS_NAME}}, etc.) documented
- Plugin logos displayed in marketplace and My Plugins
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
78 lines
2.7 KiB
Python
78 lines
2.7 KiB
Python
import os
|
|
import sys
|
|
|
|
try:
|
|
from PIL import Image, ImageDraw
|
|
except ImportError:
|
|
print("Error: Pillow library not found.")
|
|
print("Please install it using: pip install Pillow")
|
|
sys.exit(1)
|
|
|
|
# Configuration
|
|
OUTPUT_PATH = "/home/poduck/Desktop/smoothschedule2/frontend/public/plugin-logos/daily-appointment-summary.png"
|
|
SIZE = (144, 144) # Generated at 3x resolution (144px) for high quality on 48px displays
|
|
BG_COLOR = "#4f46e5" # Indigo/Blue
|
|
ICON_COLOR = "white"
|
|
|
|
def create_logo():
|
|
# Create a new image with a transparent background
|
|
img = Image.new('RGBA', SIZE, (0, 0, 0, 0))
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
# 1. Draw Background (Rounded Square)
|
|
radius = 30
|
|
rect_bounds = [0, 0, SIZE[0], SIZE[1]]
|
|
draw.rounded_rectangle(rect_bounds, radius=radius, fill=BG_COLOR)
|
|
|
|
# 2. Draw Envelope Icon (Email concept)
|
|
# Centered, slightly offset up to make room for calendar
|
|
env_w = 90
|
|
env_h = 60
|
|
env_x = (SIZE[0] - env_w) // 2
|
|
env_y = (SIZE[1] - env_h) // 2 - 10
|
|
|
|
# Envelope body
|
|
draw.rectangle([env_x, env_y, env_x + env_w, env_y + env_h], outline=ICON_COLOR, width=5)
|
|
|
|
# Envelope flap (V shape)
|
|
draw.line([env_x, env_y, env_x + env_w // 2, env_y + env_h // 2 + 5], fill=ICON_COLOR, width=5)
|
|
draw.line([env_x + env_w, env_y, env_x + env_w // 2, env_y + env_h // 2 + 5], fill=ICON_COLOR, width=5)
|
|
|
|
# 3. Draw Calendar Badge (Scheduling concept)
|
|
# Bottom right corner
|
|
cal_size = 50
|
|
cal_x = env_x + env_w - (cal_size // 2)
|
|
cal_y = env_y + env_h - (cal_size // 2)
|
|
|
|
# Clear background behind calendar for separation
|
|
border = 4
|
|
draw.rounded_rectangle(
|
|
[cal_x - border, cal_y - border, cal_x + cal_size + border, cal_y + cal_size + border],
|
|
radius=10, fill=BG_COLOR
|
|
)
|
|
|
|
# Calendar body
|
|
draw.rounded_rectangle([cal_x, cal_y, cal_x + cal_size, cal_y + cal_size], radius=8, fill="white")
|
|
|
|
# Calendar red header (using a lighter indigo/blue to match theme)
|
|
header_h = 14
|
|
draw.rounded_rectangle(
|
|
[cal_x, cal_y, cal_x + cal_size, cal_y + header_h],
|
|
radius=8, corners=(True, True, False, False), fill="#818cf8"
|
|
)
|
|
|
|
# Calendar 'lines'
|
|
line_x = cal_x + 10
|
|
line_w = cal_size - 20
|
|
draw.line([line_x, cal_y + 22, line_x + line_w, cal_y + 22], fill=BG_COLOR, width=3)
|
|
draw.line([line_x, cal_y + 32, line_x + line_w, cal_y + 32], fill=BG_COLOR, width=3)
|
|
draw.line([line_x, cal_y + 42, line_x + line_w * 0.6, cal_y + 42], fill=BG_COLOR, width=3)
|
|
|
|
# Save the file
|
|
os.makedirs(os.path.dirname(OUTPUT_PATH), exist_ok=True)
|
|
img.save(OUTPUT_PATH)
|
|
print(f"Success! Logo saved to: {OUTPUT_PATH}")
|
|
|
|
if __name__ == "__main__":
|
|
create_logo()
|