nexus/.planning/phases/42-wallpapers-social-format-conversion-voice/42-05-PLAN.md

12 KiB

phase plan type wave depends_on files_modified autonomous requirements must_haves
42-wallpapers-social-format-conversion-voice 05 execute 3
42-02
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
true
WALL-01
WALL-02
WALL-03
WALL-04
SOCIAL-01
SOCIAL-02
SOCIAL-03
truths artifacts key_links
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
path provides contains
ui/src/components/WallpaperGeneratePanel.tsx Prompt input + platform selector + generate button PLATFORM_DIMENSIONS
path provides contains
ui/src/components/WallpaperPreview.tsx Image display + download button + multi-size grid for icons Download PNG
path provides contains
ui/src/components/SocialPostPanel.tsx Prompt input + platform selector + character count PLATFORM_CHAR_LIMITS
path provides contains
ui/src/components/SocialPostResult.tsx Post display + copy button + hashtag chips + carousel slides Copy Post
path provides contains
ui/src/pages/ContentStudio.tsx Wallpapers and Social tabs added to TabsList wallpapers
from to via pattern
ui/src/components/WallpaperGeneratePanel.tsx ui/src/hooks/useContentJob.ts useContentJob hook for SSE job tracking useContentJob
from to via pattern
ui/src/components/SocialPostPanel.tsx ui/src/hooks/useContentJob.ts useContentJob hook for SSE job tracking useContentJob
from to via pattern
ui/src/pages/ContentStudio.tsx ui/src/components/WallpaperGeneratePanel.tsx TabsContent for wallpapers WallpaperGeneratePanel
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.

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_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

From server/src/services/renderers/wallpaper-renderer.ts (Plan 02): ```typescript export const PLATFORM_DIMENSIONS: Record; export const APP_ICON_SIZES: readonly [1024, 512, 256, 64, 32]; ```

From server/src/services/renderers/social-renderer.ts (Plan 02):

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:

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'):

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; }
Task 1: Create WallpaperGeneratePanel and WallpaperPreview components ui/src/components/WallpaperGeneratePanel.tsx, ui/src/components/WallpaperPreview.tsx ui/src/components/DiagramGeneratePanel.tsx, ui/src/components/IconGeneratePanel.tsx, ui/src/hooks/useContentJob.ts, ui/src/api/contentJobs.ts 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
  1. 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. cd /opt/nexus/ui && npx tsc --noEmit 2>&1 | head -20 <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> Wallpaper panel allows prompt + platform selection, shows progress, displays result with download. App icon shows multi-size grid.

Task 2: Create SocialPostPanel, SocialPostResult, and extend ContentStudio tabs ui/src/components/SocialPostPanel.tsx, ui/src/components/SocialPostResult.tsx, ui/src/pages/ContentStudio.tsx ui/src/pages/ContentStudio.tsx, ui/src/components/DiagramGeneratePanel.tsx 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
  1. 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."
  2. 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. cd /opt/nexus/ui && npx tsc --noEmit 2>&1 | head -20 <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> Social panel with character count, hashtag chips, carousel support. ContentStudio extended with Wallpapers and Social tabs.

- `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

<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>
After completion, create `.planning/phases/42-wallpapers-social-format-conversion-voice/42-05-SUMMARY.md`