feat: implement Tailwind CSS styling #19

Merged
mark merged 5 commits from feat/styling into main 2026-03-01 11:27:34 +00:00
Owner

Implements full Tailwind CSS styling based on wireframe design.

  • Brand colours, Space Grotesk/Inter/Fira Code fonts, box shadows in tailwind.config.js
  • bg-grid-pattern, text-gradient, scrollbar, selection styles in input.css
  • Google Fonts + dark-mode body classes in base.html
  • Styled: nav, footer, cookie banner, newsletter form, article cards
  • Homepage: featured article, 12-col editorial grid, sidebar
  • Article list: tag filters, horizontal cards, pagination
  • Article page: header, prose body, share sidebar, related cards, comments
  • Code blocks and callout blocks styled
  • CSS grows from 4.8KB → 24KB
Implements full Tailwind CSS styling based on wireframe design. - Brand colours, Space Grotesk/Inter/Fira Code fonts, box shadows in tailwind.config.js - bg-grid-pattern, text-gradient, scrollbar, selection styles in input.css - Google Fonts + dark-mode body classes in base.html - Styled: nav, footer, cookie banner, newsletter form, article cards - Homepage: featured article, 12-col editorial grid, sidebar - Article list: tag filters, horizontal cards, pagination - Article page: header, prose body, share sidebar, related cards, comments - Code blocks and callout blocks styled - CSS grows from 4.8KB → 24KB
codex_a added 1 commit 2026-03-01 10:02:36 +00:00
feat: implement Tailwind CSS styling based on wireframe design
Some checks failed
CI / nightly-e2e (pull_request) Has been skipped
CI / deploy (pull_request) Has been skipped
CI / ci (pull_request) Successful in 1m24s
CI / pr-e2e (pull_request) Failing after 3m21s
1c7b96f723
- Add brand colours, fonts (Space Grotesk/Inter/Fira Code), box shadows to tailwind.config.js
- Add bg-grid-pattern, text-gradient, scrollbar, selection styles to input.css
- Add Google Fonts link and dark-mode body classes to base.html
- Style nav, footer, cookie banner, newsletter form components
- Style homepage: featured article, 12-col editorial grid, sidebar widgets
- Style article list: header, tag filters, horizontal article cards, pagination
- Style article page: hero header, prose body, share sidebar, related cards, comments
- Style code blocks and callout blocks
- CSS output grows from 4.8KB to 24KB with all brand utilities compiled

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
codex_a added 1 commit 2026-03-01 10:14:42 +00:00
fix: resolve E2E test failures
Some checks failed
CI / nightly-e2e (pull_request) Has been skipped
CI / deploy (pull_request) Has been skipped
CI / ci (pull_request) Failing after 1m23s
CI / pr-e2e (pull_request) Failing after 1m35s
73ef38a144
- nav: replace hidden newsletter form + Subscribe link with visible inline form
- nav: fix theme toggle aria-label to 'Toggle theme' (was 'Toggle Dark Mode')
- article_page: wrap share buttons in <section aria-label='Share this article'>

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Author
Owner

Strict re-review findings for PR #19 (implementation.md + wireframe/design-language):

  1. High — Mobile navigation is non-functional on small screens.
  • templates/components/nav.html:13 hides primary links/newsletter with hidden md:flex.
  • templates/components/nav.html:34-35 shows a hamburger button, but there is no mobile menu panel or toggle behavior.
    Impact: users on mobile cannot navigate to key routes from nav.
  1. High — About page remains unstyled.
  • templates/blog/about_page.html:4-13 is still raw content output and not aligned with the Tailwind design system introduced in this PR.
  1. Medium — Legal page remains unstyled.
  • templates/legal/legal_page.html:4-6 is plain markup and visually inconsistent with the styled site.

Validation rerun on this head:

  • ruff pass
  • mypy pass
  • pytest pass (74 passed, 35 skipped, coverage 95.45%)
Strict re-review findings for PR #19 (implementation.md + wireframe/design-language): 1) High — Mobile navigation is non-functional on small screens. - `templates/components/nav.html:13` hides primary links/newsletter with `hidden md:flex`. - `templates/components/nav.html:34-35` shows a hamburger button, but there is no mobile menu panel or toggle behavior. Impact: users on mobile cannot navigate to key routes from nav. 2) High — About page remains unstyled. - `templates/blog/about_page.html:4-13` is still raw content output and not aligned with the Tailwind design system introduced in this PR. 3) Medium — Legal page remains unstyled. - `templates/legal/legal_page.html:4-6` is plain markup and visually inconsistent with the styled site. Validation rerun on this head: - `ruff` pass - `mypy` pass - `pytest` pass (`74 passed, 35 skipped`, coverage `95.45%`)
codex_a added 1 commit 2026-03-01 10:25:39 +00:00
fix: address code review issues and rebuild CSS
Some checks failed
CI / nightly-e2e (pull_request) Has been skipped
CI / deploy (pull_request) Has been skipped
CI / pr-e2e (pull_request) Failing after 1m4s
CI / ci (pull_request) Successful in 1m22s
8b83712cbf
- nav: add functional mobile menu panel with JS toggle
- nav: hamburger now shows/hides mobile-menu with aria-expanded state
- about_page: full styled layout (header, prose body, author aside)
- legal_page: full styled layout (header with last-updated, max-w-3xl prose)
- article: fix aside newsletter label to 'Subscribe' for E2E test
- CSS: rebuild after all template changes (4.8KB → 24.3KB)
  Committed CSS must match CI build — rebuilt after ALL template edits

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
codex_a added 1 commit 2026-03-01 10:43:23 +00:00
fix: move mobile menu outside nav to prevent playwright strict mode violation
All checks were successful
CI / nightly-e2e (pull_request) Has been skipped
CI / deploy (pull_request) Has been skipped
CI / pr-e2e (pull_request) Successful in 1m4s
CI / ci (pull_request) Successful in 1m23s
bff59eec06
Playwright strict mode requires exactly one match for form[data-newsletter-form]
inside nav. Having desktop + mobile forms both inside <nav> caused a strict
violation. Mobile menu div is now outside the closing </nav> tag; JS toggle
uses getElementById so position doesn't matter.

Rebuild CSS to match template changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
codex_b requested changes 2026-03-01 11:16:28 +00:00
Dismissed
codex_b left a comment
Owner

Requesting changes after QA review.\n\nBlocking findings:\n\n1) Typography styles are not actually generated, so article/about/legal body styling regresses.\n- Templates now rely heavily on classes (e.g. templates/blog/article_page.html, templates/blog/about_page.html, templates/legal/legal_page.html), but Tailwind config has (theme/static_src/tailwind.config.js:33) and package.json has no .\n- Result: compiled CSS contains no utilities, so the long-form content does not match wireframe/implementation intent.\n\n2) Callout icon logic is inconsistent with the model choices and implementation spec.\n- Model allows: info, warning, trophy, tip (apps/blog/blocks.py:31-40).\n- Template handles: warning, error, success, else (templates/blog/blocks/callout_block.html:2-11).\n- and therefore fall back to generic icon; / are dead branches. This breaks expected callout variants and block-rendering parity.\n\n3) Desktop nav newsletter feedback is permanently hidden.\n- Message node has class (templates/components/nav.html:24), while JS only sets and never removes (static/js/newsletter.js).\n- Users get no success/error feedback in that primary subscribe entry point.\n\n4) Wireframe parity gap on homepage sidebar.\n- includes a sidebar block, but home template currently renders newsletter + topics only (templates/blog/home_page.html:111-134).\n\nVerification run:\n- ..................................................................... [100%]
=============================== warnings summary ===============================
apps/blog/tests/test_feeds.py: 2 warnings
apps/blog/tests/test_feeds_more.py: 1 warning
apps/blog/tests/test_seo.py: 2 warnings
apps/blog/tests/test_views.py: 7 warnings
apps/comments/tests/test_more.py: 1 warning
apps/comments/tests/test_views.py: 4 warnings
apps/core/tests/test_consent.py: 4 warnings
apps/core/tests/test_performance.py: 3 warnings
apps/core/tests/test_security.py: 7 warnings
apps/core/tests/test_tags.py: 1 warning
apps/legal/tests/test_models.py: 2 warnings
apps/newsletter/tests/test_views.py: 6 warnings
/usr/local/lib/python3.12/site-packages/whitenoise/base.py:115: UserWarning: No directory at: /app/staticfiles/
warnings.warn(f"No directory at: {root}")

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html

---------- coverage: platform linux, python 3.12.12-final-0 ----------
Name Stmts Miss Cover Missing

apps/init.py 0 0 100%
apps/authors/init.py 0 0 100%
apps/authors/apps.py 4 0 100%
apps/authors/models.py 26 1 96% 43
apps/authors/wagtail_hooks.py 10 0 100%
apps/blog/init.py 0 0 100%
apps/blog/apps.py 4 0 100%
apps/blog/blocks.py 37 3 92% 28-30
apps/blog/feeds.py 36 2 94% 47, 50
apps/blog/models.py 114 5 96% 69, 76-77, 150-151
apps/blog/wagtail_hooks.py 8 0 100%
apps/comments/init.py 0 0 100%
apps/comments/apps.py 4 0 100%
apps/comments/forms.py 14 1 93% 18
apps/comments/management/init.py 0 0 100%
apps/comments/management/commands/init.py 0 0 100%
apps/comments/management/commands/purge_old_comment_data.py 14 0 100%
apps/comments/models.py 19 1 95% 25
apps/comments/urls.py 3 0 100%
apps/comments/views.py 49 4 92% 21, 41, 57-58
apps/comments/wagtail_hooks.py 14 1 93% 17
apps/core/init.py 0 0 100%
apps/core/apps.py 4 0 100%
apps/core/consent.py 30 2 93% 39-40
apps/core/context_processors.py 6 0 100%
apps/core/management/init.py 0 0 100%
apps/core/management/commands/init.py 0 0 100%
apps/core/management/commands/check_content_integrity.py 27 1 96% 25
apps/core/middleware.py 19 0 100%
apps/core/models.py 7 0 100%
apps/core/templatetags/init.py 0 0 100%
apps/core/templatetags/core_tags.py 23 0 100%
apps/core/templatetags/seo_tags.py 30 3 90% 18-19, 29
apps/core/views.py 26 0 100%
apps/legal/init.py 0 0 100%
apps/legal/apps.py 4 0 100%
apps/legal/models.py 17 0 100%
apps/newsletter/init.py 0 0 100%
apps/newsletter/apps.py 4 0 100%
apps/newsletter/forms.py 5 0 100%
apps/newsletter/models.py 8 1 88% 11
apps/newsletter/services.py 25 5 80% 28-36, 42
apps/newsletter/urls.py 3 0 100%
apps/newsletter/views.py 54 1 98% 47

TOTAL 648 31 95%

Required test coverage of 90% reached. Total coverage: 95.22%

----------------------------------------------------- benchmark: 1 tests ----------------------------------------------------
Name (time in us) Min Max Mean StdDev Median IQR Outliers OPS (Kops/s) Rounds Iterations

test_read_time_benchmark 98.2890 193.9720 103.1680 9.9008 99.5800 4.1427 194;301 9.6929 3755 1

Legend:
Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
OPS: Operations Per Second, computed as 1 / Mean passed on PR branch (existing tests green), but the above issues remain untested regressions/parity gaps.

Requesting changes after QA review.\n\nBlocking findings:\n\n1) Typography styles are not actually generated, so article/about/legal body styling regresses.\n- Templates now rely heavily on classes (e.g. templates/blog/article_page.html, templates/blog/about_page.html, templates/legal/legal_page.html), but Tailwind config has (theme/static_src/tailwind.config.js:33) and package.json has no .\n- Result: compiled CSS contains no utilities, so the long-form content does not match wireframe/implementation intent.\n\n2) Callout icon logic is inconsistent with the model choices and implementation spec.\n- Model allows: info, warning, trophy, tip (apps/blog/blocks.py:31-40).\n- Template handles: warning, error, success, else (templates/blog/blocks/callout_block.html:2-11).\n- and therefore fall back to generic icon; / are dead branches. This breaks expected callout variants and block-rendering parity.\n\n3) Desktop nav newsletter feedback is permanently hidden.\n- Message node has class (templates/components/nav.html:24), while JS only sets and never removes (static/js/newsletter.js).\n- Users get no success/error feedback in that primary subscribe entry point.\n\n4) Wireframe parity gap on homepage sidebar.\n- includes a sidebar block, but home template currently renders newsletter + topics only (templates/blog/home_page.html:111-134).\n\nVerification run:\n- ..................................................................... [100%] =============================== warnings summary =============================== apps/blog/tests/test_feeds.py: 2 warnings apps/blog/tests/test_feeds_more.py: 1 warning apps/blog/tests/test_seo.py: 2 warnings apps/blog/tests/test_views.py: 7 warnings apps/comments/tests/test_more.py: 1 warning apps/comments/tests/test_views.py: 4 warnings apps/core/tests/test_consent.py: 4 warnings apps/core/tests/test_performance.py: 3 warnings apps/core/tests/test_security.py: 7 warnings apps/core/tests/test_tags.py: 1 warning apps/legal/tests/test_models.py: 2 warnings apps/newsletter/tests/test_views.py: 6 warnings /usr/local/lib/python3.12/site-packages/whitenoise/base.py:115: UserWarning: No directory at: /app/staticfiles/ warnings.warn(f"No directory at: {root}") -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html ---------- coverage: platform linux, python 3.12.12-final-0 ---------- Name Stmts Miss Cover Missing ------------------------------------------------------------------------------------------- apps/__init__.py 0 0 100% apps/authors/__init__.py 0 0 100% apps/authors/apps.py 4 0 100% apps/authors/models.py 26 1 96% 43 apps/authors/wagtail_hooks.py 10 0 100% apps/blog/__init__.py 0 0 100% apps/blog/apps.py 4 0 100% apps/blog/blocks.py 37 3 92% 28-30 apps/blog/feeds.py 36 2 94% 47, 50 apps/blog/models.py 114 5 96% 69, 76-77, 150-151 apps/blog/wagtail_hooks.py 8 0 100% apps/comments/__init__.py 0 0 100% apps/comments/apps.py 4 0 100% apps/comments/forms.py 14 1 93% 18 apps/comments/management/__init__.py 0 0 100% apps/comments/management/commands/__init__.py 0 0 100% apps/comments/management/commands/purge_old_comment_data.py 14 0 100% apps/comments/models.py 19 1 95% 25 apps/comments/urls.py 3 0 100% apps/comments/views.py 49 4 92% 21, 41, 57-58 apps/comments/wagtail_hooks.py 14 1 93% 17 apps/core/__init__.py 0 0 100% apps/core/apps.py 4 0 100% apps/core/consent.py 30 2 93% 39-40 apps/core/context_processors.py 6 0 100% apps/core/management/__init__.py 0 0 100% apps/core/management/commands/__init__.py 0 0 100% apps/core/management/commands/check_content_integrity.py 27 1 96% 25 apps/core/middleware.py 19 0 100% apps/core/models.py 7 0 100% apps/core/templatetags/__init__.py 0 0 100% apps/core/templatetags/core_tags.py 23 0 100% apps/core/templatetags/seo_tags.py 30 3 90% 18-19, 29 apps/core/views.py 26 0 100% apps/legal/__init__.py 0 0 100% apps/legal/apps.py 4 0 100% apps/legal/models.py 17 0 100% apps/newsletter/__init__.py 0 0 100% apps/newsletter/apps.py 4 0 100% apps/newsletter/forms.py 5 0 100% apps/newsletter/models.py 8 1 88% 11 apps/newsletter/services.py 25 5 80% 28-36, 42 apps/newsletter/urls.py 3 0 100% apps/newsletter/views.py 54 1 98% 47 ------------------------------------------------------------------------------------------- TOTAL 648 31 95% Required test coverage of 90% reached. Total coverage: 95.22% ----------------------------------------------------- benchmark: 1 tests ---------------------------------------------------- Name (time in us) Min Max Mean StdDev Median IQR Outliers OPS (Kops/s) Rounds Iterations ----------------------------------------------------------------------------------------------------------------------------- test_read_time_benchmark 98.2890 193.9720 103.1680 9.9008 99.5800 4.1427 194;301 9.6929 3755 1 ----------------------------------------------------------------------------------------------------------------------------- Legend: Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile. OPS: Operations Per Second, computed as 1 / Mean passed on PR branch (existing tests green), but the above issues remain untested regressions/parity gaps.
Owner

QA findings behind request changes:

  1. Typography regression: article/about/legal templates use prose classes, but Tailwind config has plugins empty and package.json does not include @tailwindcss/typography. Compiled CSS therefore has no prose rules.

  2. Callout icon mismatch: blocks.py allows info/warning/trophy/tip, but callout_block template branches on warning/error/success/else. trophy and tip both fall through to generic icon; error/success are unreachable.

  3. Desktop nav newsletter feedback is hidden: nav template keeps data-newsletter-message element hidden, and newsletter.js only updates textContent (never unhides it).

  4. Wireframe parity gap: home sidebar in wireframe includes Popular Articles, but template currently renders only newsletter and topic tags.

Validation run: docker compose run --rm web pytest -q passed on PR head (tests green), but these regressions/parity gaps remain.

QA findings behind request changes: 1) Typography regression: article/about/legal templates use prose classes, but Tailwind config has plugins empty and package.json does not include @tailwindcss/typography. Compiled CSS therefore has no prose rules. 2) Callout icon mismatch: blocks.py allows info/warning/trophy/tip, but callout_block template branches on warning/error/success/else. trophy and tip both fall through to generic icon; error/success are unreachable. 3) Desktop nav newsletter feedback is hidden: nav template keeps data-newsletter-message element hidden, and newsletter.js only updates textContent (never unhides it). 4) Wireframe parity gap: home sidebar in wireframe includes Popular Articles, but template currently renders only newsletter and topic tags. Validation run: docker compose run --rm web pytest -q passed on PR head (tests green), but these regressions/parity gaps remain.
codex_a added 1 commit 2026-03-01 11:21:01 +00:00
fix: address QA review findings
All checks were successful
CI / nightly-e2e (pull_request) Has been skipped
CI / deploy (pull_request) Has been skipped
CI / pr-e2e (pull_request) Successful in 1m6s
CI / ci (pull_request) Successful in 1m24s
71fe06edd1
1. Typography: install @tailwindcss/typography and add to plugins so prose
   classes render correctly in article/about/legal templates.

2. Callout block: fix icon branches to match CalloutBlock.ICON_CHOICES
   (info/warning/trophy/tip). Previous template branched on error/success
   which are unreachable; info fell through to else silently.

3. Nav newsletter feedback: remove 'hidden' class from desktop nav
   data-newsletter-message element. JS sets textContent only; hidden
   class prevented message from ever being visible.

4. Popular Articles sidebar: add numbered Popular Articles widget to home
   page sidebar matching wireframe, using latest_articles context with
   alternating cyan/pink number accents and read_time_mins.

Rebuild CSS: typography plugin grows output from 24KB to 47KB.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
codex_b approved these changes 2026-03-01 11:27:05 +00:00
codex_b left a comment
Owner

Re-review complete. Previously requested QA changes are addressed:\n- Tailwind typography plugin is added and prose utilities are present in compiled CSS\n- Callout icon mapping now matches block choices (info/warning/trophy/tip)\n- Nav newsletter status message is visible (no longer permanently hidden)\n- Homepage sidebar now includes the wireframe-aligned Popular Articles section\n\nValidation rerun on latest PR head:\n- docker compose run --rm web pytest -q (pass, coverage gate pass)\n\nApproving.

Re-review complete. Previously requested QA changes are addressed:\n- Tailwind typography plugin is added and prose utilities are present in compiled CSS\n- Callout icon mapping now matches block choices (info/warning/trophy/tip)\n- Nav newsletter status message is visible (no longer permanently hidden)\n- Homepage sidebar now includes the wireframe-aligned Popular Articles section\n\nValidation rerun on latest PR head:\n- docker compose run --rm web pytest -q (pass, coverage gate pass)\n\nApproving.
mark merged commit ec89a5fe35 into main 2026-03-01 11:27:34 +00:00
mark deleted branch feat/styling 2026-03-01 11:27:34 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: nohype/main-site#19