fix(daisy): ship both tags in daisyUI's documented CDN recipe - #58
Merged
fsecada01 merged 1 commit intoAug 1, 2026
Merged
Conversation
cf_ui_head(theme="daisy") emitted only the daisyUI stylesheet link.
daisyUI is a Tailwind plugin, so that bundle is the component layer
only (.btn{, .card{) with none of the utility classes (.flex{,
.w-full{, .gap-4{, .items-center{) the shipped daisy templates depend
on for layout. A consumer following the quickstart got styled buttons
and cards sitting in a completely inert layout, with no error and
nothing in the docs at the point of failure.
daisyUI's own CDN documentation (https://v4.daisyui.com/docs/cdn/)
pairs the stylesheet with Tailwind's Play CDN script, in that order.
cf-ui was shipping only the first tag; the E2E integration harness
(tests/integration/jinja_app/main.py) was hand-patching the second one
in via a _THEME_EXTRA_HEAD dict, which meant that tier never actually
exercised the shipped cf_ui_head tag.
Adds CF_UI_DAISY_CDN ("play" default, "off"), resolved by
themes.resolve_daisy_cdn and validated at Django startup the same way
CF_UI_THEME and CF_UI_COMPOSITION already are. "play" emits an
explanatory HTML comment, the daisyUI stylesheet, then the Tailwind
Play CDN script, in the vendor's order. "off" emits neither tag, for a
consumer running a real Tailwind build. The other four themes are
byte-identical to before. Jinja's cf_ui_head macro gains the matching
daisy_cdn="play" keyword argument.
"play" is the default rather than "off" because the failure this
fixes is a silently half-styled page, and defaulting to "off" just
relocates that same silent failure onto anyone who has not yet read
docs/daisyui.md. "play" instead gives that consumer a working page
plus a greppable, in-view-source signal pointing at the real answer.
Deletes the jinja_app integration harness's _THEME_EXTRA_HEAD
hand-patch and routes its gallery <head> through the real
cf_ui_head Jinja macro instead of a hand-maintained CDN URL table, so
the E2E daisy suite now proves the shipped tag rather than a
workaround for its absence. No django-cotton equivalent existed to
delete: the cotton E2E gallery templates never call cf_ui_head or load
any stylesheet at all, so that tier was never exposed to this bug.
Extends the Django-tag/Jinja-macro parity test in
tests/unit/test_asset_tags.py to cover the new script tag in both CDN
modes, and adds a regression tripwire pinning that the daisy
stylesheet alone is not sufficient.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NhqNRBg83czKfr8L6FF5xf
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #56.
cf_ui_head(theme="daisy")emitted only daisyUI'sfull.min.csslink — the component layer only, since daisyUI is a Tailwind plugin.The shipped daisy templates depend heavily on Tailwind utilities (
flex,w-full,gap-4,items-center,text-lg, …) that bundle does not contain.A consumer following the quickstart with
CF_UI_THEME = "daisy"got styled buttons and cards sitting in a completely inert layout, with no error anywhere.daisyUI's own CDN documentation (https://v4.daisyui.com/docs/cdn/) prescribes two tags, in order: the stylesheet link, then
<script src="https://cdn.tailwindcss.com"></script>(Tailwind's Play CDN). cf-ui was shipping only the first.Acceptance criteria (issue #56), item by item
"A consumer setting
CF_UI_THEME = "daisy"with no Tailwind build either gets working styling or gets an unmissable, actionable signal — never a silently half-styled page."Chose Option 1 from the issue (a bundle that includes utilities), via
CF_UI_DAISY_CDN = "play"(default):cf_ui_headnow emits the daisyUI stylesheet and the Tailwind Play CDN script, so a default install gets working layout. The emitted HTML also carries an explanatory comment, so the CDN mode is a visible, greppable signal in view-source even for a consumer who never opens the docs."A test pins whichever behaviour is chosen, so a future CDN version bump cannot quietly reintroduce the gap."
tests/unit/test_asset_tags.pygained: play-mode emits the script; the other four themes emit no<script>fromcf_ui_headat all; off-mode emits neither daisy tag but still emitscf_ui_axes.css/[x-cloak]; play-mode carries the explanatory comment; Jinja-macro/Django-tag parity for the script tag in both modes; an invalidCF_UI_DAISY_CDNraisesImproperlyConfiguredat startup naming the valid values; and a named regression tripwire (test_regression_daisy_stylesheet_alone_is_not_a_complete_head_issue_56) that fails if a future refactor drops the script while keeping the stylesheet."
docs/daisyui.mdand the quickstart state the daisy CDN caveat explicitly."docs/daisyui.mdgained a new section ("The CDN path needs two tags, not one") covering the two-tag recipe,CF_UI_DAISY_CDN, when to use each value, and the upstream "Play CDN is for development purposes only, and is not intended for production" label.docs/installation.md's DaisyUI warning callout anddocs/getting-started.md(§1 theme table intro and §3 Assets) no longer imply all five themes are CDN-uniform."The real-Tailwind-build path is unchanged and still documented as the production answer."
CF_UI_DAISY_CDN = "off"is exactly that path:cf_ui_heademits neither daisy tag, so a real Tailwind build supplies both layers itself. Nothing about the Tailwind content-glob guidance changed.Why
"play"is the default, not"off"The one outcome the issue forbids is a silently half-styled page. A default of
"off"does not avoid that failure, it just relocates it: anyone who setsCF_UI_THEME = "daisy", follows the quickstart, and has not yet readdocs/daisyui.mdgets the same unstyled layout with the same absence of an error."play"gives that same consumer a working page immediately, plus an unmissable, greppable signal in view-source (the HTML comment) pointing at the real answer.A consumer running a real Tailwind build is exactly the consumer who has read the docs and can flip
CF_UI_DAISY_CDNto"off"deliberately.Design notes
CF_UI_DAISY_CDNis resolved by a newthemes.resolve_daisy_cdn, right next toresolve_theme, using the sameThemeErrorand message idiom (unknown daisy CDN mode {value!r} — valid values are: play, off).CfUiConfig.ready()validates it at startup with the samef"cf-ui: {exc}. Check {SETTING} in settings."shape already used forCF_UI_THEME/CF_UI_COMPOSITION.cf_ui_headmacro gains a matchingdaisy_cdn="play"keyword argument. Vendor order is preserved: comment, then stylesheet<link>, then Play CDN<script>.theme == "daisy"path.The E2E workaround, deleted as proof
tests/integration/jinja_app/main.pyused to hand-build its<head>from a_THEME_CSSURL table plus a_THEME_EXTRA_HEAD["daisy"]entry that injected the exact Tailwind Play CDN scriptcf_ui_headwas supposed to emit but didn't.That meant the E2E daisy tier was exercising a workaround, never the shipped tag.
Both dicts are deleted. The gallery route's
<head>is now built by calling the realcf_ui_headJinja macro fromcf_ui/assets.jinja, so the E2E daisy suite (tests/e2e/test_daisy.py) now proves the shipped tag directly. Ran green after the change (pytest tests/e2e --browser chromium -k daisy→ 44 passed, 5 skipped; full E2E suite → 230 passed, 33 skipped).Finding, not forced: there was no django-cotton-side equivalent to delete. The cotton E2E gallery templates (
tests/integration/cotton_app/templates/cotton_gallery/*.html) never callcf_ui_headand never load a stylesheet or script at all — they render bare components and the cotton daisy E2E tests only assert markup/classes, never computed layout. That tier was never exposed to this bug and needed no change.Gate results
assets.jinja(src/cf_ui/templates/cf_ui/assets.jinja) is confirmed out of djLint's scope:.pre-commit-config.yamlscopes the djLint hooks totemplates/cotton/**andtemplates/jinja/**only, andprek run --all-filesleft it untouched.Test plan
tests/unit/test_asset_tags.py— new/extended tests confirmed red before implementation, green afterpytest tests/unit tests/integration -qruff check/ruff format --checkmkdocs build --strictprek run --all-filespytest tests/e2e --browser chromium -q(full suite + daisy-only)Co-Authored-By: Claude Opus 5 noreply@anthropic.com
https://claude.ai/code/session_01NhqNRBg83czKfr8L6FF5xf