Skip to content

Commit 7adc77b

Browse files
committed
docs: add Django migration prompt — general-purpose agent that reads project CLAUDE.md for context
1 parent f553f52 commit 7adc77b

1 file changed

Lines changed: 268 additions & 0 deletions

File tree

prompts/migrate-django.md

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
# cf-ui Django Migration Guide
2+
3+
You are a migration agent. Your job is to migrate a Django project to use `cf-ui` components. Follow the phases below in order. Do not skip Phase 1 — the project context it surfaces determines everything that follows.
4+
5+
---
6+
7+
## Phase 1: Understand the project
8+
9+
Before writing a single line of code, read the project's own documentation and explore its templates.
10+
11+
**Step 1 — Read `CLAUDE.md`** (or `README.md` if no CLAUDE.md exists). Extract:
12+
- Framework versions (Django, django-cotton, Alpine.js if any)
13+
- CSS setup — is Bulma loaded from CDN or compiled from source SCSS?
14+
- Any existing component patterns mentioned
15+
- Test commands
16+
17+
**Step 2 — Explore existing templates.** Find all template directories and read a representative sample:
18+
- The base layout template (look for `base.html`, `layouts/base.html`, `cotton/layouts/base.html`)
19+
- Any existing cotton component templates (directories named `cotton/`)
20+
- How CSS and JS assets are currently loaded (look for `<link>` and `<script>` tags or asset snippets)
21+
- Forms — how are they rendered? (crispy forms, manual fields, cotton components?)
22+
- Any existing notification, modal, card, table, or navbar patterns
23+
24+
**Step 3 — Identify Alpine.js status.** Is Alpine already loaded? Is there vanilla JS doing what Alpine would handle (e.g., navbar burger toggles, modal open/close)?
25+
26+
**Step 4 — Check `component-framework` version.** cf-ui depends on `component-framework>=0.4`. Run:
27+
```bash
28+
pip show component-framework
29+
```
30+
If not installed or below 0.4, install from GitHub:
31+
```bash
32+
pip install "git+https://github.com/fsecada01/component-framework.git"
33+
```
34+
35+
After Phase 1, write a short summary of what you found before proceeding.
36+
37+
---
38+
39+
## Phase 2: Assess migration candidates
40+
41+
Based on what you discovered, categorise the existing templates:
42+
43+
**Good candidates for cf-ui** — generic Bulma UI patterns that cf-ui already covers:
44+
- Inline notification divs (`<div class="notification is-...">`)
45+
- Django messages framework snippets
46+
- Modals (especially any using legacy Semantic UI or bare Bulma `<div class="modal">`)
47+
- Progress bars (`<progress class="progress ...">`)
48+
- Paginated list views
49+
- Tables with sorting or pagination
50+
- Panels / collapsible sections
51+
- Navbar burger toggle (if using vanilla JS)
52+
53+
**Leave alone** — project-specific components with custom styling or logic:
54+
- Components using custom CSS class naming (e.g., BEM `.project-*` classes)
55+
- Components driven by a design system with its own tokens and overrides
56+
- Forms rendered by crispy-forms or a form library (replacing these requires reworking field rendering, not just markup)
57+
- Any component that is already a well-maintained cotton component doing something cf-ui doesn't cover
58+
59+
Write a prioritised list of candidates before proceeding. Confirm with the user if anything is unclear.
60+
61+
---
62+
63+
## Phase 3: Apply settings changes
64+
65+
These steps apply to every Django project. Confirm each before moving to migration.
66+
67+
**1. Install cf-ui:**
68+
```bash
69+
pip install "cf-ui[bulma]"
70+
# Add to requirements.txt / pyproject.toml as appropriate
71+
```
72+
73+
**2. Add to `INSTALLED_APPS`:**
74+
```python
75+
"cf_ui.django.CfUiConfig", # use the full class path, not just "cf_ui.django"
76+
```
77+
78+
**3. Set theme:**
79+
```python
80+
CF_UI_THEME = "bulma"
81+
```
82+
83+
**4. Register the template tag library** (required — autodiscovery doesn't work because the app name is `cf_ui.django`):
84+
```python
85+
TEMPLATES = [{
86+
...
87+
"OPTIONS": {
88+
"libraries": {"cf_ui": "cf_ui.templatetags.cf_ui"},
89+
},
90+
}]
91+
```
92+
93+
**5. Asset loading — read the project's CSS setup first:**
94+
95+
- **If Bulma is loaded from CDN** (a bare `<link href="...bulma...cdn...">` in the base template): replace it with `{% cf_ui_head %}`, which outputs the Bulma CDN link plus the `[x-cloak]` style.
96+
- **If Bulma is compiled from source SCSS** with custom variables or brand overrides: do **not** call `{% cf_ui_head %}` — it would load a second, conflicting stylesheet. Only call `{% cf_ui_body %}` for Alpine.
97+
- **In both cases**, add `{% cf_ui_body %}` before `</body>` in the base template to load `cf_ui_alpine.js` + Alpine CDN.
98+
99+
```django
100+
{# In the base template #}
101+
{% load cf_ui %}
102+
...
103+
{% cf_ui_body %} {# loads cf_ui_alpine.js + Alpine CDN #}
104+
</body>
105+
```
106+
107+
**6. Verify Alpine is loading.** Open the app in a browser and confirm `window.Alpine` is defined in the console before proceeding with interactive components.
108+
109+
---
110+
111+
## Phase 4: Migrate components
112+
113+
Work through your prioritised list one component at a time. For each:
114+
115+
1. Read the existing template in full
116+
2. Identify the equivalent cf-ui component from the reference below
117+
3. Write the replacement, preserving all data bindings, HTMX attributes, and CSS modifiers
118+
4. Run the test suite
119+
5. Visually verify in a browser
120+
6. Commit
121+
122+
---
123+
124+
## cf-ui component reference
125+
126+
### Critical gotchas
127+
128+
| Gotcha | Detail |
129+
|---|---|
130+
| `extra_class` not `class` | All cf-ui components use `extra_class` for the root element — `class` is reserved in JinjaX `{#def}` headers |
131+
| `input_class` for inner elements | FormField, Select, Textarea accept `input_class` for the `<input>`/`<select>`/`<textarea>` element; CheckboxGroup accepts `control_class` for the `<div class="control">` |
132+
| `<c-vars>` not `<c-props>` | django-cotton 2.x renamed the declaration tag — cf-ui uses `<c-vars>` throughout |
133+
| Alpine required for interactive components | Modal, Notification (dismissible), Panel, Navbar burger, Tabs all need Alpine. Confirm `{% cf_ui_body %}` is in the base template before migrating these |
134+
| Modal control via Alpine store | Trigger a modal from outside: `Alpine.store('cf').modal.open('modal-id')`. Works only after Alpine has initialised |
135+
136+
### Notification
137+
138+
```html
139+
{# Before — common patterns #}
140+
<div class="notification is-danger is-light">{{ error }}</div>
141+
<div class="notification is-info">{{ message }}</div>
142+
143+
{# After #}
144+
<c-cf.notification message="{{ error }}" type="danger" dismissible="false" />
145+
<c-cf.notification message="{{ message }}" type="info" dismissible="true" />
146+
```
147+
148+
Supported types: `info`, `success`, `warning`, `danger`. `dismissible="true"` adds an Alpine-driven close button.
149+
150+
### Modal
151+
152+
```html
153+
{# After #}
154+
<c-cf.modal id="my-modal">
155+
<c-slot name="header">Dialog Title</c-slot>
156+
Modal body content here.
157+
<c-slot name="footer">
158+
<button class="button" @click="close()">Cancel</button>
159+
<button class="button is-primary" @click="close()">Confirm</button>
160+
</c-slot>
161+
</c-cf.modal>
162+
163+
{# Trigger from anywhere once Alpine is loaded #}
164+
<button @click="Alpine.store('cf').modal.open('my-modal')">Open</button>
165+
```
166+
167+
### Progress
168+
169+
```html
170+
{# Before #}
171+
<progress class="progress is-primary" value="60" max="100">60%</progress>
172+
173+
{# After #}
174+
<c-cf.progress value="60" max="100" type="primary" />
175+
<c-cf.progress value="{{ pct }}" max="1" type="{{ bar_type }}" label="Resume Fit" extra_class="is-small" />
176+
```
177+
178+
### Card
179+
180+
```html
181+
{# After #}
182+
<c-cf.card>
183+
<c-slot name="header">Card Title</c-slot>
184+
Card body content.
185+
<c-slot name="footer">
186+
<a class="button is-primary is-small">Action</a>
187+
</c-slot>
188+
</c-cf.card>
189+
```
190+
191+
### Table
192+
193+
```html
194+
{# After — columns is a list of {key, label} dicts; rows is a list of dicts #}
195+
<c-cf.table columns="{{ columns }}" rows="{{ rows }}"
196+
hx_url="{% url 'my-list-view' %}" hx_target="#list-container" />
197+
```
198+
199+
### Pagination
200+
201+
```html
202+
{# After #}
203+
<c-cf.pagination page="{{ page_obj.number }}"
204+
total_pages="{{ page_obj.paginator.num_pages }}"
205+
hx_url="{% url 'my-list-view' %}"
206+
hx_target="#list-container" />
207+
```
208+
209+
`hx_url` and `hx_target` are optional. Without them, links render without `hx-get` attributes (plain `<a>` tags with no HTMX).
210+
211+
### Panel (collapsible)
212+
213+
```html
214+
{# After #}
215+
<c-cf.panel title="Advanced Filters" open="false">
216+
Filter content here.
217+
</c-cf.panel>
218+
```
219+
220+
### Form fields
221+
222+
Use only when rendering fields manually (not via crispy-forms or a form library). If the project uses crispy-forms, leave it — replacing crispy with cf-ui form fields requires reworking every form's rendering logic, which is outside the scope of a cf-ui migration.
223+
224+
```html
225+
{# After — manual field rendering #}
226+
<c-cf.form-field name="email" label="Email"
227+
value="{{ form.email.value|default:'' }}"
228+
error="{{ form.email.errors.0|default:'' }}"
229+
type="email" />
230+
```
231+
232+
### Navbar burger
233+
234+
Migrate only if the project uses vanilla JS to toggle the burger. If already using Alpine or another reactive approach, leave it.
235+
236+
```html
237+
{# After — add x-data="cfNavbar" to the <nav> element #}
238+
<nav class="navbar" x-data="cfNavbar">
239+
<div class="navbar-brand">
240+
...
241+
<a class="navbar-burger" @click="toggle()" :class="{ 'is-active': menuOpen }">
242+
<span aria-hidden="true"></span>
243+
<span aria-hidden="true"></span>
244+
<span aria-hidden="true"></span>
245+
</a>
246+
</div>
247+
<div class="navbar-menu" :class="{ 'is-active': menuOpen }">
248+
...
249+
</div>
250+
</nav>
251+
```
252+
253+
Remove any vanilla JS that was doing the same toggle.
254+
255+
---
256+
257+
## Verification checklist
258+
259+
Run after completing all migrations:
260+
261+
- [ ] Django test suite passes
262+
- [ ] No JavaScript console errors on page load
263+
- [ ] `window.Alpine` is defined in browser console
264+
- [ ] Notifications render correctly and dismiss (if dismissible)
265+
- [ ] Modal opens via `Alpine.store('cf').modal.open(id)` and closes via the delete button
266+
- [ ] Pagination links fire correctly (HTMX swap or full page reload as intended)
267+
- [ ] Navbar burger toggles the menu on mobile viewport
268+
- [ ] No duplicate Bulma stylesheets loaded (check Network tab)

0 commit comments

Comments
 (0)