237 lines
12 KiB
Markdown
237 lines
12 KiB
Markdown
---
|
|
phase: 42-wallpapers-social-format-conversion-voice
|
|
plan: 05
|
|
type: execute
|
|
wave: 3
|
|
depends_on: [42-02]
|
|
files_modified:
|
|
- ui/src/components/WallpaperGeneratePanel.tsx
|
|
- ui/src/components/WallpaperPreview.tsx
|
|
- ui/src/components/SocialPostPanel.tsx
|
|
- ui/src/components/SocialPostResult.tsx
|
|
- ui/src/pages/ContentStudio.tsx
|
|
autonomous: true
|
|
requirements: [WALL-01, WALL-02, WALL-03, WALL-04, SOCIAL-01, SOCIAL-02, SOCIAL-03]
|
|
must_haves:
|
|
truths:
|
|
- "User can type a prompt, select a platform, and generate a wallpaper/social image"
|
|
- "Platform selector shows all 12 platform options grouped by Desktop/Mobile/Social/App"
|
|
- "Wallpaper preview shows the image with download button after job completes"
|
|
- "App icon/favicon shows multi-size grid with individual download links"
|
|
- "Social post panel shows character count that turns red over limit"
|
|
- "Generated post shows copy button and clickable hashtag chips"
|
|
- "Instagram carousel shows numbered collapsible slide sections"
|
|
- "ContentStudio has Wallpapers and Social tabs"
|
|
artifacts:
|
|
- path: "ui/src/components/WallpaperGeneratePanel.tsx"
|
|
provides: "Prompt input + platform selector + generate button"
|
|
contains: "PLATFORM_DIMENSIONS"
|
|
- path: "ui/src/components/WallpaperPreview.tsx"
|
|
provides: "Image display + download button + multi-size grid for icons"
|
|
contains: "Download PNG"
|
|
- path: "ui/src/components/SocialPostPanel.tsx"
|
|
provides: "Prompt input + platform selector + character count"
|
|
contains: "PLATFORM_CHAR_LIMITS"
|
|
- path: "ui/src/components/SocialPostResult.tsx"
|
|
provides: "Post display + copy button + hashtag chips + carousel slides"
|
|
contains: "Copy Post"
|
|
- path: "ui/src/pages/ContentStudio.tsx"
|
|
provides: "Wallpapers and Social tabs added to TabsList"
|
|
contains: "wallpapers"
|
|
key_links:
|
|
- from: "ui/src/components/WallpaperGeneratePanel.tsx"
|
|
to: "ui/src/hooks/useContentJob.ts"
|
|
via: "useContentJob hook for SSE job tracking"
|
|
pattern: "useContentJob"
|
|
- from: "ui/src/components/SocialPostPanel.tsx"
|
|
to: "ui/src/hooks/useContentJob.ts"
|
|
via: "useContentJob hook for SSE job tracking"
|
|
pattern: "useContentJob"
|
|
- from: "ui/src/pages/ContentStudio.tsx"
|
|
to: "ui/src/components/WallpaperGeneratePanel.tsx"
|
|
via: "TabsContent for wallpapers"
|
|
pattern: "WallpaperGeneratePanel"
|
|
---
|
|
|
|
<objective>
|
|
Build the Wallpaper and Social UI panels and extend ContentStudio with new tabs.
|
|
|
|
Purpose: This surfaces the wallpaper and social renderers (Plan 02) to users through the ContentStudio interface.
|
|
Output: Four new UI components + updated ContentStudio tabs.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
|
@$HOME/.claude/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/phases/42-wallpapers-social-format-conversion-voice/42-RESEARCH.md
|
|
@.planning/phases/42-wallpapers-social-format-conversion-voice/42-UI-SPEC.md
|
|
@.planning/phases/42-wallpapers-social-format-conversion-voice/42-02-SUMMARY.md
|
|
|
|
@ui/src/pages/ContentStudio.tsx
|
|
@ui/src/components/DiagramGeneratePanel.tsx
|
|
@ui/src/components/IconGeneratePanel.tsx
|
|
@ui/src/hooks/useContentJob.ts
|
|
@ui/src/api/contentJobs.ts
|
|
</context>
|
|
|
|
<interfaces>
|
|
From server/src/services/renderers/wallpaper-renderer.ts (Plan 02):
|
|
```typescript
|
|
export const PLATFORM_DIMENSIONS: Record<string, { width: number; height: number; label: string }>;
|
|
export const APP_ICON_SIZES: readonly [1024, 512, 256, 64, 32];
|
|
```
|
|
|
|
From server/src/services/renderers/social-renderer.ts (Plan 02):
|
|
```typescript
|
|
export const PLATFORM_CHAR_LIMITS: Record<string, number>;
|
|
// "twitter-x": 280, "linkedin": 3000, "instagram-caption": 2200, "instagram-carousel": 300
|
|
```
|
|
|
|
From ui/src/hooks/useContentJob.ts:
|
|
```typescript
|
|
export function useContentJob(companyId: string | null): {
|
|
job: ContentJob | null;
|
|
submit: (jobType: string, input: Record<string, unknown>) => Promise<void>;
|
|
status: string;
|
|
};
|
|
```
|
|
|
|
Bundle types (job.bundle after status === 'done'):
|
|
```typescript
|
|
interface WallpaperBundle { type: "wallpaper-bundle"; platform: string; width: number; height: number; pngBase64: string; prompt: string; }
|
|
interface AppIconBundle { type: "app-icon-bundle"; sizes: Array<{ size: number; pngBase64: string }>; prompt: string; }
|
|
interface SocialPostBundle { type: "social-post-bundle"; platform: string; post: string; hashtags: string[]; slides?: string[]; charLimit: number; }
|
|
```
|
|
</interfaces>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Create WallpaperGeneratePanel and WallpaperPreview components</name>
|
|
<files>ui/src/components/WallpaperGeneratePanel.tsx, ui/src/components/WallpaperPreview.tsx</files>
|
|
<read_first>ui/src/components/DiagramGeneratePanel.tsx, ui/src/components/IconGeneratePanel.tsx, ui/src/hooks/useContentJob.ts, ui/src/api/contentJobs.ts</read_first>
|
|
<action>
|
|
1. Create WallpaperGeneratePanel.tsx following the DiagramGeneratePanel pattern:
|
|
- Props: { companyId: string }
|
|
- Define PLATFORM_DIMENSIONS as a local constant (same values as server — 12 entries). Group into categories: Desktop, Mobile, Social, App.
|
|
- State: prompt (string), platform (string, default "desktop-hd")
|
|
- Use useContentJob(companyId) hook for job submission and tracking
|
|
- Render a Card with:
|
|
- Textarea (4 rows, placeholder: "Describe the scene, mood, or concept...")
|
|
- Select component for platform. Use optgroup-style grouping (shadcn Select supports groups via SelectGroup + SelectLabel). Each option shows the label with dimensions in text-xs font-mono text-muted-foreground.
|
|
- "Generate Wallpaper" Button (primary, full-width). Disabled while job is in progress. Shows spinner + "Generating..." when active.
|
|
- Progress bar (shadcn progress) below button — driven by job.progress from SSE
|
|
- On submit: call job.submit("wallpaper", { prompt, platform })
|
|
- When job.status === "done": render WallpaperPreview with job.bundle
|
|
|
|
2. Create WallpaperPreview.tsx:
|
|
- Props: { bundle: WallpaperBundle | AppIconBundle }
|
|
- For WallpaperBundle (type === "wallpaper-bundle"):
|
|
- Render image in `max-h-80 object-contain` container
|
|
- Image alt text: prompt truncated to 100 chars
|
|
- Below image: "Download PNG" Button (primary) + resolution badge (text-xs font-mono text-muted-foreground showing "{width} x {height}")
|
|
- Download: create blob URL from base64, trigger download via anchor click
|
|
- For AppIconBundle (type === "app-icon-bundle"):
|
|
- Render a grid of size entries. Each cell: size label (e.g. "32 x 32") + Download link
|
|
- Grid uses responsive columns: 2 cols on mobile, 3 on md, 5 on lg
|
|
- Empty state: heading "No image yet", body "Describe a scene or mood and pick a platform size to generate a ready-to-use image."
|
|
|
|
Per UI spec: all copy matches the Copywriting Contract exactly.
|
|
</action>
|
|
<verify>
|
|
<automated>cd /opt/nexus/ui && npx tsc --noEmit 2>&1 | head -20</automated>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- grep "PLATFORM_DIMENSIONS" ui/src/components/WallpaperGeneratePanel.tsx
|
|
- grep "Generate Wallpaper" ui/src/components/WallpaperGeneratePanel.tsx
|
|
- grep "useContentJob" ui/src/components/WallpaperGeneratePanel.tsx
|
|
- grep "Download PNG" ui/src/components/WallpaperPreview.tsx
|
|
- grep "app-icon-bundle" ui/src/components/WallpaperPreview.tsx
|
|
- grep "No image yet" ui/src/components/WallpaperPreview.tsx
|
|
- grep "2560" ui/src/components/WallpaperGeneratePanel.tsx
|
|
</acceptance_criteria>
|
|
<done>Wallpaper panel allows prompt + platform selection, shows progress, displays result with download. App icon shows multi-size grid.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Create SocialPostPanel, SocialPostResult, and extend ContentStudio tabs</name>
|
|
<files>ui/src/components/SocialPostPanel.tsx, ui/src/components/SocialPostResult.tsx, ui/src/pages/ContentStudio.tsx</files>
|
|
<read_first>ui/src/pages/ContentStudio.tsx, ui/src/components/DiagramGeneratePanel.tsx</read_first>
|
|
<action>
|
|
1. Create SocialPostPanel.tsx following DiagramGeneratePanel pattern:
|
|
- Props: { companyId: string }
|
|
- Define PLATFORM_CHAR_LIMITS as local constant: { "twitter-x": 280, "linkedin": 3000, "instagram-caption": 2200, "instagram-carousel": 300 }
|
|
- State: prompt (string), platform (string, default "twitter-x"), charCount (number tracking textarea length)
|
|
- Use useContentJob(companyId) hook
|
|
- Render Card with:
|
|
- Textarea (4 rows, placeholder: "Describe the topic or paste existing content to adapt...")
|
|
- onChange: update prompt and charCount
|
|
- Platform selector (Select): "Twitter/X", "LinkedIn", "Instagram Caption", "Instagram Carousel"
|
|
- Character count below textarea, right-aligned: `text-xs text-muted-foreground`. Format: "{N} / {limit}". When over limit: add `text-destructive` class and append " - over limit"
|
|
- Character count has `aria-live="polite"` for screen readers
|
|
- "Generate Post" Button (primary). Enabled even when over limit (AI may trim). Shows spinner + "Generating..." when active.
|
|
- Progress bar below button
|
|
- On submit: call job.submit("social-post", { prompt, platform })
|
|
- When job.status === "done": render SocialPostResult with job.bundle
|
|
|
|
2. Create SocialPostResult.tsx:
|
|
- Props: { bundle: SocialPostBundle }
|
|
- Post text in read-only Card (bg-card, rounded-lg, p-4)
|
|
- Character count badge inline (text-xs font-mono text-muted-foreground)
|
|
- "Copy Post" Button (secondary, full-width). On click: copy bundle.post to clipboard. Change text to "Copied!" for 2 seconds then revert.
|
|
- Hashtag section below copy button: render bundle.hashtags as chips in rounded-full badges (bg-muted text-muted-foreground). Each chip has role="button" and aria-label="Copy hashtag {tag}". On click: copy tag to clipboard. Show CheckCheck icon (12px) for 1.5s then revert to text.
|
|
- For carousel (bundle.slides exists and length > 0): render numbered collapsible sections using shadcn Collapsible. "Slide 1", "Slide 2" etc. Each section shows the slide text.
|
|
- Empty state: heading "No post yet", body "Describe your topic and choose a platform to generate a ready-to-publish post."
|
|
|
|
3. Update ContentStudio.tsx:
|
|
- Add two new TabsTrigger entries to the existing TabsList: "Wallpapers" (value: wallpapers), "Social" (value: social)
|
|
- Add two new TabsContent sections:
|
|
- wallpapers: renders WallpaperGeneratePanel with companyId
|
|
- social: renders SocialPostPanel with companyId
|
|
- Import WallpaperGeneratePanel and SocialPostPanel
|
|
- Follow the exact same pattern as the existing diagrams/icons/themes tabs
|
|
|
|
Per UI spec copywriting contract: match ALL copy strings exactly.
|
|
</action>
|
|
<verify>
|
|
<automated>cd /opt/nexus/ui && npx tsc --noEmit 2>&1 | head -20</automated>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- grep "PLATFORM_CHAR_LIMITS" ui/src/components/SocialPostPanel.tsx
|
|
- grep "Generate Post" ui/src/components/SocialPostPanel.tsx
|
|
- grep "aria-live" ui/src/components/SocialPostPanel.tsx
|
|
- grep "Copy Post" ui/src/components/SocialPostResult.tsx
|
|
- grep "hashtags" ui/src/components/SocialPostResult.tsx
|
|
- grep "Collapsible" ui/src/components/SocialPostResult.tsx
|
|
- grep "wallpapers" ui/src/pages/ContentStudio.tsx
|
|
- grep "social" ui/src/pages/ContentStudio.tsx
|
|
- grep "WallpaperGeneratePanel" ui/src/pages/ContentStudio.tsx
|
|
- grep "SocialPostPanel" ui/src/pages/ContentStudio.tsx
|
|
</acceptance_criteria>
|
|
<done>Social panel with character count, hashtag chips, carousel support. ContentStudio extended with Wallpapers and Social tabs.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
- `cd /opt/nexus/ui && npx tsc --noEmit` passes
|
|
- ContentStudio shows 5 tabs: Diagrams, Icons, Themes, Wallpapers, Social
|
|
- All UI copy matches the UI spec copywriting contract
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- Wallpaper panel: prompt + 12-platform selector + generate + download
|
|
- Social panel: prompt + 4-platform selector + live character count + generate
|
|
- Social result: copy post + hashtag chips + carousel collapsibles
|
|
- ContentStudio has Wallpapers and Social tabs
|
|
- tsc compiles cleanly
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/42-wallpapers-social-format-conversion-voice/42-05-SUMMARY.md`
|
|
</output>
|