Skip to content

Refactor UI with DaisyUI v5 and htmx#143

Merged
LordSimal merged 2 commits intomasterfrom
refactor-with-daisyui-and-htmx
Apr 5, 2026
Merged

Refactor UI with DaisyUI v5 and htmx#143
LordSimal merged 2 commits intomasterfrom
refactor-with-daisyui-and-htmx

Conversation

@josbeir
Copy link
Copy Markdown
Contributor

@josbeir josbeir commented Apr 5, 2026

This PR replaces the previous frontend stack with a modern, component-driven UI using DaisyUI v5 and htmx, resulting in a significantly improved user experience across the package listing.

What's changed

UI / UX

  • DaisyUI v5 theme — custom cakephp theme with near-white base colors, replacing ad-hoc slate-* Tailwind utilities throughout
  • htmx-powered search & filtering — search and pagination now update the package list without full page reloads; browser URL is updated via hx-push-url
  • Responsive navbar — Docs/API links collapse into a hamburger dropdown on mobile
  • Paginator redesigned with icon-only prev/next/first/last controls and a compact package count badge in the heading
  • Package cards updated to use DaisyUI base color tokens instead of hardcoded slate-* classes
  • CakePHP compatibility section replaced with compact 5.x 4.x 3.x buttons that open a single modal showing all filterable minor versions with active/inactive toggle states
  • Featured badge repositioned to avoid wrapping with long package names
  • Featured slider navigation buttons now use btn-primary to follow the theme color; pagination dots added

Dependencies

  • Added htmx.org and slim-select as bundled JS dependencies (previously loaded externally)
  • Swiper pagination module enabled
  • Vite config updated
image image

Copilot AI review requested due to automatic review settings April 5, 2026 09:29
@josbeir josbeir force-pushed the refactor-with-daisyui-and-htmx branch from b1f5e7d to 7a3b9a2 Compare April 5, 2026 09:33
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR modernizes the frontend by adopting DaisyUI v5 for consistent theming and using htmx to make package listing interactions (search/filter/pagination) update without full page reloads.

Changes:

  • Introduces a DaisyUI-based theme and updates templates/components to use DaisyUI tokens/classes.
  • Adds htmx + SlimSelect (bundled) and wires up dynamic UI re-initialization after htmx swaps.
  • Updates Vite configuration and adds local DDEV phpMyAdmin addon configuration.

Reviewed changes

Copilot reviewed 14 out of 16 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
vite.config.js Adds dev server watch ignores, SlimSelect CSS alias, and suppresses the htmx EVAL Rollup warning.
templates/Packages/index.php Refactors packages index to support htmx swapping, featured slider placement, updated filters/sort, and paginator templating.
templates/layout/default.php Rebuilds navbar with DaisyUI and adds an htmx-enabled global search form + loading indicator overlay.
templates/element/Packages/package-tile.php Restyles package cards and replaces compatibility display with major-version buttons + modal-based filtering.
resources/js/app.js Bundles/imports htmx + SlimSelect, adds Swiper pagination, and re-inits UI on htmx updates.
resources/css/style.css Adds DaisyUI plugin/theme config, imports SlimSelect + Swiper pagination CSS, and adds htmx loading overlay styles.
package.json Adds daisyui, htmx.org, and slim-select dependencies.
package-lock.json Locks new frontend dependencies and transitive updates.
config/form-templates.php Updates button template styling to DaisyUI classes.
.ddev/docker-compose.phpmyadmin.yaml Adds phpMyAdmin service for local dev.
.ddev/docker-compose.phpmyadmin_norouter.yaml DDEV router-omission companion file for phpMyAdmin addon.
.ddev/config.yaml Disables Xdebug by default.
.ddev/commands/host/phpmyadmin Adds a host command to launch phpMyAdmin.
.ddev/addon-metadata/phpmyadmin/manifest.yaml Adds DDEV addon manifest metadata for phpMyAdmin.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

</div>
</template>

<?php $featuredPackageNames = array_column((array)$featuredPackages, 'package'); ?>
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$featuredPackageNames is built with array_column() over an array of Package entities. array_column() only reads arrays/public properties, so for CakePHP entities this will return an array of nulls and the featured-package exclusion (in_array(...)) won’t work. Use array_map(fn($p) => $p->package, (array)$featuredPackages) or extract via a Collection instead.

Suggested change
<?php $featuredPackageNames = array_column((array)$featuredPackages, 'package'); ?>
<?php $featuredPackageNames = array_map(fn($package) => $package->package, (array)$featuredPackages); ?>

Copilot uses AI. Check for mistakes.
Comment on lines +156 to 161
<div class="join">
<?= $this->Paginator->first('« ' . __('first')) ?>
<?= $this->Paginator->prev('‹ ' . __('previous')) ?>
<!-- <?= $this->Paginator->prev('‹ ' . __('previous')) ?> -->
<?= $this->Paginator->numbers() ?>
<?= $this->Paginator->next(__('next') . ' ›') ?>
<!-- <?= $this->Paginator->next(__('next') . ' ›') ?> -->
<?= $this->Paginator->last(__('last') . ' »') ?>
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The paginator here only renders first, numbers, and last; prev/next are commented out and the controls are text-based. This doesn’t match the PR description’s “icon-only prev/next/first/last controls”. Either update the implementation to include the intended controls (with icons) or adjust the PR description to reflect the actual UI.

Copilot uses AI. Check for mistakes.
<div class="flex flex-wrap gap-2">
<?php foreach ($tagGroups as $majorVersion => $tags): ?>
<?php
$groupSlugs = array_keys(array_column($tags, null, 'slug'));
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$groupSlugs is computed via array_column($tags, null, 'slug'), but $tags is an array of Tag entities. array_column() won’t read CakePHP entity fields (they’re not public properties), so $groupSlugs will be wrong and $isActive will never reflect the actual active filter state. Build the slug list with array_map(fn($t) => $t->slug, $tags) (or a Collection extract) instead.

Suggested change
$groupSlugs = array_keys(array_column($tags, null, 'slug'));
$groupSlugs = array_map(static fn($tag) => $tag->slug, $tags);

Copilot uses AI. Check for mistakes.
Comment on lines +60 to +65
<dialog id="<?= h($dialogId) ?>" class="modal">
<div class="modal-box max-w-md">
<h3 class="mb-1 text-base font-semibold"><?= h($package->package) ?></h3>
<p class="mb-4 text-xs opacity-50"><?= __('Filter by CakePHP version') ?></p>
<div class="space-y-4">
<?php foreach ($tagGroups as $majorVersion => $tags): ?>
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This renders a full <dialog> (including all version links) for every package tile. On pages with many packages/tags this can significantly inflate DOM size and slow down rendering/htmx swaps. Consider using a single shared modal (populated on demand) or lazy-rendering the modal content only when opened.

Copilot uses AI. Check for mistakes.
window.htmx = htmx

const initializeSelects = (root = document) => {
const selects = document.querySelectorAll('select')
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initializeSelects() accepts a root parameter but ignores it and always queries document.querySelectorAll('select'). This makes the root argument misleading and prevents scoping initialization to newly swapped content (also doing extra work on every htmx update). Use root.querySelectorAll('select') instead.

Suggested change
const selects = document.querySelectorAll('select')
const selects = root.querySelectorAll('select')

Copilot uses AI. Check for mistakes.
Comment on lines +89 to +97
// Track loading state
let isLoading = false
document.body.addEventListener('htmx:beforeRequest', () => {
isLoading = true
document.body.classList.add('is-htmx-loading')
})

document.body.addEventListener('htmx:afterRequest', () => {
isLoading = false
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isLoading is set in the htmx request event handlers but never read. This is dead state that adds noise; remove it or use it for something (e.g., to avoid duplicate toggles or to expose loading state elsewhere).

Suggested change
// Track loading state
let isLoading = false
document.body.addEventListener('htmx:beforeRequest', () => {
isLoading = true
document.body.classList.add('is-htmx-loading')
})
document.body.addEventListener('htmx:afterRequest', () => {
isLoading = false
document.body.addEventListener('htmx:beforeRequest', () => {
document.body.classList.add('is-htmx-loading')
})
document.body.addEventListener('htmx:afterRequest', () => {

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +9
name: phpmyadmin
repository: ddev/ddev-phpmyadmin
version: v1.0.2
install_date: "2026-04-04T16:48:16+02:00"
project_files:
- docker-compose.phpmyadmin.yaml
- docker-compose.phpmyadmin_norouter.yaml
- commands/host/phpmyadmin
global_files: []
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The added PhpMyAdmin addon metadata (including install_date) isn’t mentioned in the PR description and is typically local-environment state. If this is intentional, please call it out in the PR description; otherwise consider excluding addon-metadata from version control to avoid noisy diffs for unrelated UI changes.

Copilot uses AI. Check for mistakes.

DDEV_PHPMYADMIN_PORT=8036
DDEV_PHPMYADMIN_HTTPS_PORT=8037
if [ ${DDEV_PRIMARY_URL%://*} = "http" ] || [ -n "${GITPOD_WORKSPACE_ID:-}" ] || [ "${CODESPACES:-}" = "true" ]; then
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script uses unquoted parameter expansion ([ ${DDEV_PRIMARY_URL%://*} = "http" ]). If DDEV_PRIMARY_URL is unset/empty this can cause a test syntax error, and unquoted expansions are generally brittle. Quote the expansion (or use a safer conditional) to avoid unexpected failures.

Suggested change
if [ ${DDEV_PRIMARY_URL%://*} = "http" ] || [ -n "${GITPOD_WORKSPACE_ID:-}" ] || [ "${CODESPACES:-}" = "true" ]; then
if [ "${DDEV_PRIMARY_URL%://*}" = "http" ] || [ -n "${GITPOD_WORKSPACE_ID:-}" ] || [ "${CODESPACES:-}" = "true" ]; then

Copilot uses AI. Check for mistakes.
Comment on lines +17 to +22
- PMA_USER=root
- PMA_PASSWORD=root
- PMA_HOST=db
- PMA_PORT=3306
- VIRTUAL_HOST=$DDEV_HOSTNAME
- UPLOAD_LIMIT=4000M
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This phpMyAdmin compose file hardcodes PMA_USER=root / PMA_PASSWORD=root and a very large UPLOAD_LIMIT. Even in a dev-only setup, it’s safer to source credentials from the existing ddev DB env (or document why root/root is required) and to keep upload limits conservative.

Suggested change
- PMA_USER=root
- PMA_PASSWORD=root
- PMA_HOST=db
- PMA_PORT=3306
- VIRTUAL_HOST=$DDEV_HOSTNAME
- UPLOAD_LIMIT=4000M
- PMA_USER=${DDEV_DATABASE_USER:-db}
- PMA_PASSWORD=${DDEV_DATABASE_PASSWORD:-db}
- PMA_HOST=db
- PMA_PORT=3306
- VIRTUAL_HOST=$DDEV_HOSTNAME
- UPLOAD_LIMIT=256M

Copilot uses AI. Check for mistakes.
Comment on lines 4 to 7
php_version: "8.4"
webserver_type: nginx-fpm
xdebug_enabled: true
xdebug_enabled: false
additional_hostnames: []
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xdebug_enabled was changed to false, but the PR description focuses on the UI refactor and doesn’t mention this dev-environment change. If this is intentional, please note it in the PR description (or split it into a separate PR) to avoid surprising developers who rely on Xdebug being enabled by default.

Copilot uses AI. Check for mistakes.
@LordSimal LordSimal merged commit a63a527 into master Apr 5, 2026
0 of 3 checks passed
@LordSimal LordSimal deleted the refactor-with-daisyui-and-htmx branch April 5, 2026 21:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants