AgentSkillsCN

wagtailify

将 HTML 线框图转换为 Wagtail 主题。验证线框图结构,新建区块,搭建主题框架,并实现模板设计。

SKILL.md
--- frontmatter
name: wagtailify
description: Convert HTML wireframe to Wagtail theme. Validates wireframe structure, creates new blocks, scaffolds theme, and implements templates.
argument-hint: <theme-name>
allowed-tools: Read, Write, Edit, Bash, Glob, Grep, Task

Wagtailify Skill

Convert annotated HTML wireframes into functional Wagtail themes for SUM Platform.

Prerequisites

Before invoking this skill, ensure:

  1. Wireframe exists at docs/dev/design/wireframes/{theme}/compiled/
  2. Wireframe is annotated with data-section-id, data-block-type, and data-owner attributes (see Phase 0 in THEME-GUIDE.md)
  3. NEW block schemas documented for any NEW:* block types

Invocation

bash
/wagtailify <theme-name>

Example: /wagtailify theme_b

Phases Overview

PhaseNameHuman CheckpointOutput
1AuditNoJSON inventory
2PlanYesConfirmed work plan
3ScaffoldNoTheme directory
4aAnalyze NEW BlocksNoSchema proposals
4bReview SchemasYesApproved schemas
4cGenerate BlocksNoBlock classes
4dValidate & MigrateNoClean lint, migrations
5Extract TokensNotailwind.config.js
6Create CSSNoinput.css
7Chrome TemplatesNobase.html, header, footer
8Block TemplatesNoBlock HTML overrides
9Page TemplatesNoPage type templates
10JavaScriptNomain.js
11Build & TestYesWorking theme

Phase 1: Audit

Goal: Extract and validate wireframe structure.

Process

  1. Run the audit script:

    bash
    python .claude/skills/wagtailify/scripts/audit_wireframe.py {theme}
    
  2. The script will:

    • Locate wireframe at docs/dev/design/wireframes/{theme}/compiled/
    • Parse all HTML files
    • Extract every element with data-section-id
    • Validate each has data-block-type and data-owner
    • Generate structured JSON report
  3. Review the output for:

    • Validation errors (missing attributes)
    • Unknown block types
    • NEW blocks that need creation

Exit Criteria

  • All sections have required attributes
  • Section IDs are unique
  • Block types are valid (existing key, NEW:*, or template)

If validation fails, stop and ask the human to fix the wireframe.


Phase 2: Plan

Goal: Confirm block mapping and work items with human.

Process

Present the audit results in this format:

code
EXISTING BLOCKS (need theme template override):
- hero_image (6 sections)
- stats (2 sections)
- manifesto (1 section)
...

NEW BLOCKS (need class + template):
- ValuePropositionBlock
  - Owner: ServiceIndexPage.intro
  - Source: services-04
  - Fields to extract: heading, body, stats[], ctas[], image

TEMPLATE-OWNED SECTIONS:
- global-banner → base.html (AlertBanner snippet)
- global-header → header.html
- global-footer → footer.html
...

Proceed? [Y/n]

Exit Criteria

Human confirms the plan before proceeding.


Phase 3: Scaffold

Goal: Create theme directory structure.

Process

  1. Run the scaffold script:

    bash
    bash .claude/skills/wagtailify/scripts/scaffold_theme.sh {theme}
    
  2. The script creates:

    code
    themes/{theme}/
    ├── VERSION (set to 0.0.0)
    ├── theme.json
    ├── tailwind/
    │   ├── package.json
    │   ├── npm-shrinkwrap.json
    │   ├── postcss.config.js
    │   └── tailwind.config.js (placeholder)
    ├── static/{theme}/
    │   ├── css/
    │   └── js/
    └── templates/
        ├── theme/
        │   └── includes/
        └── sum_core/
            └── blocks/
    
  3. Run npm ci in tailwind directory

Exit Criteria

  • Directory structure exists
  • npm dependencies installed

Phase 4a: Analyze NEW Block Structure

Goal: Propose field schemas for NEW blocks.

Process

For each NEW:* block:

  1. Locate the section in wireframe HTML by data-section-id

  2. Analyze HTML structure:

    • Text content → CharBlock or TextBlock
    • Rich text with formatting → RichTextBlock
    • Images → ImageChooserBlock
    • Links → UniversalLinkBlock
    • Repeated items → ListBlock
    • Nested structures → child StructBlock
  3. Generate schema proposal:

    json
    {
      "block_name": "ValuePropositionBlock",
      "target_file": "services.py",
      "group": "Sections",
      "fields": [
        {"name": "heading", "type": "RichTextBlock", "features": ["italic", "bold"], "required": true},
        {"name": "body", "type": "RichTextBlock", "features": ["bold", "italic", "link", "ul", "ol"], "required": true},
        {"name": "stats", "type": "ListBlock", "child": "ValuePropositionStatBlock", "min_num": 2, "max_num": 2}
      ],
      "child_blocks": [
        {"name": "ValuePropositionStatBlock", "fields": [...]}
      ]
    }
    
  4. Determine target file based on block group:

    • Hero blocks → hero.py
    • Service blocks → services.py
    • Content blocks → content.py
    • Form blocks → forms.py

Exit Criteria

Schema proposal generated for all NEW blocks.


Phase 4b: Human Review (CHECKPOINT)

Goal: Get human approval on field schemas.

Process

Present each NEW block schema:

code
NEW BLOCK: ValuePropositionBlock
Target file: core/sum_core/blocks/services.py
Group: Sections

PROPOSED FIELDS:
| Field | Type | Required | Notes |
|-------|------|----------|-------|
| heading | RichTextBlock(bold, italic) | Yes | |
| body | RichTextBlock(full) | Yes | |
| primary_cta | CtaLinkBlock | No | |
| secondary_cta | CtaLinkBlock | No | |
| stats | ListBlock(StatBlock) | Yes | min=2, max=4 |
| image | ImageChooserBlock | No | |
| image_quote | CharBlock(200) | No | |

CHILD BLOCK: StatBlock
| Field | Type | Required |
|-------|------|----------|
| value | CharBlock(20) | Yes |
| label | CharBlock(80) | Yes |

Approve schema? [Y/modify/skip]

Exit Criteria

Human approves or modifies all schemas.


Phase 4c: Generate Block Classes

Goal: Create block classes using approved schemas.

Process

For each approved schema:

  1. Generate block class using the Jinja template at templates/block_class.py.jinja

    • Render the template with the approved schema
    • The template generates imports and properly formatted block classes
  2. Add generated code to target file in core/sum_core/blocks/

  3. Register in PageStreamBlock in core/sum_core/blocks/base.py

  4. Create minimal core template in core/sum_core/templates/sum_core/blocks/

Exit Criteria

All NEW blocks created and registered.


Phase 4d: Validate and Migrate

Goal: Ensure code is valid and migrations are generated.

Process

  1. Run linter:

    bash
    make lint
    
  2. Check for needed migrations:

    bash
    python core/sum_core/test_project/manage.py makemigrations sum_core --dry-run
    
  3. If migrations needed, generate them:

    bash
    python core/sum_core/test_project/manage.py makemigrations sum_core
    
  4. Run tests:

    bash
    make test
    

Exit Criteria

  • make lint passes
  • Migrations generated (if needed)
  • make test passes

Phase 5: Extract Tokens

Goal: Create tailwind.config.js with CSS variable bridging.

Process

  1. Read wireframe's inline Tailwind config (in <script>tailwind.config = {...}</script>)

  2. Extract:

    • Color palette
    • Font families
    • Custom breakpoints
    • Animations
  3. Convert to CSS variable pattern:

    js
    // Wireframe: sage: { terra: '#A0563B' }
    // Becomes:
    'sage-terra': 'hsl(var(--brand-h, 16) var(--brand-s, 46%) var(--brand-l, 43%) / <alpha-value>)'
    
  4. Add content paths for template scanning

  5. Write to themes/{theme}/tailwind/tailwind.config.js

Exit Criteria

Config file exists and is valid JS.


Phase 6: Create CSS

Goal: Create input.css with variable defaults and component classes.

Process

  1. Extract CSS variable defaults from wireframe colors (HSL conversion)

  2. Extract component classes from wireframe's static/style.css:

    • Button styles
    • Section layouts
    • Card styles
    • Navigation styles
    • Reveal animations
  3. Write to themes/{theme}/static/{theme}/css/input.css

Exit Criteria

npm run build succeeds in tailwind directory.


Phase 7: Chrome Templates

Goal: Implement base template and global chrome.

Templates to Create

  1. templates/theme/base.html — Master layout
  2. templates/theme/includes/header.html — Navigation
  3. templates/theme/includes/footer.html — Footer
  4. templates/theme/includes/sticky_cta.html — Mobile sticky CTA
  5. templates/sum_core/includes/cookie_banner.html — Cookie banner override

Process

For each template:

  1. Copy HTML structure from wireframe (locate by data-section-id)
  2. Replace hardcoded content with template tags:
    • {% branding_css %}, {% branding_fonts %}
    • {% header_nav as nav %}, {% footer_nav as footer %}
    • {% get_site_settings as site_settings %}
  3. Add conditional rendering ({% if %})
  4. Add accessibility attributes

Exit Criteria

Base template loads without errors.


Phase 8: Block Templates

Goal: Create theme override for every mapped block.

Process

For each block in the audit:

  1. Locate section in wireframe HTML by data-section-id
  2. Copy HTML structure
  3. Replace hardcoded content with block field references:
    • {{ self.heading|richtext }}
    • {{ self.image }}
    • {% for item in self.items %}
  4. Apply theme component classes
  5. Add reveal animations
  6. Save to templates/sum_core/blocks/{block_key}.html

Exit Criteria

All blocks have theme templates.


Phase 9: Page Templates

Goal: Create templates for template-owned sections.

Templates (varies by theme)

  • templates/theme/home_page.html
  • templates/theme/standard_page.html
  • templates/theme/service_index_page.html
  • templates/theme/blog_index_page.html
  • templates/theme/blog_post_page.html
  • etc.

Process

  1. Identify template-owned sections from audit
  2. Create page template extending base.html
  3. Implement template-owned sections directly
  4. Loop through StreamField for block-owned content

Exit Criteria

All page types have templates.


Phase 10: JavaScript

Goal: Extract and adapt JS interactions.

Process

  1. Read wireframe's static/script.js

  2. Identify interactions:

    • Header scroll effect
    • Mobile menu
    • Mega menu
    • Accordion
    • Reveal animations
    • Modal/lightbox
  3. Adapt to theme structure

  4. Add error boundaries (try/catch)

  5. Add reduced motion support

  6. Save to themes/{theme}/static/{theme}/js/main.js

Exit Criteria

No console errors, interactions work.


Phase 11: Build & Test (CHECKPOINT)

Goal: Verify theme works end-to-end.

Process

  1. Build CSS:

    bash
    cd themes/{theme}/tailwind && npm run build
    
  2. Update fingerprint:

    bash
    python themes/{theme}/build_fingerprint.py
    
  3. Run linter:

    bash
    make lint
    
  4. Run contract tests:

    bash
    ACTIVE_THEME_SLUG={theme} pytest tests/themes/contracts/ -v
    
  5. Start dev server:

    bash
    make dev-reset THEME={theme} PROFILE=sage-stone
    make run THEME={theme}
    
  6. Visual inspection with human

Exit Criteria

  • CSS builds without errors
  • Lint passes
  • Contract tests pass
  • Site renders correctly
  • Human confirms visual fidelity

State Management

The skill maintains state in .wagtailify-state.json:

json
{
  "theme": "theme_b",
  "current_phase": 4,
  "phases_completed": [1, 2, 3],
  "audit_output": "...",
  "new_blocks": [...],
  "errors": []
}

Use --resume to continue from last checkpoint:

bash
/wagtailify theme_b --resume

Use --rollback to undo to a specific phase:

bash
/wagtailify theme_b --rollback 3

Reference Files

  • scripts/audit_wireframe.py — Extracts and validates wireframe attributes
  • scripts/scaffold_theme.sh — Creates theme directory structure
  • templates/block_class.py.jinja — Block class template
  • reference/block-quick-ref.md — Block key → class → required fields
  • reference/wireframe-attributes.md — Data attribute specification

Troubleshooting

"Wireframe not found"

Ensure wireframe is at docs/dev/design/wireframes/{theme}/compiled/

"Missing data attributes"

Add required data-section-id, data-block-type, data-owner to wireframe sections. See Phase 0 in THEME-GUIDE.md.

"Unknown block type"

Check docs/dev/blocks-reference.md for valid block keys. Use NEW:ClassName for new blocks.

"Lint failures after block creation"

Review generated code for import errors. Ensure all referenced blocks exist.

"Contract tests fail"

Check theme template paths match expected structure. Ensure all required templates exist.