# Frontend

This project uses **Vite** for bundling, **Tailwind CSS v4** for styling, and **DaisyUI** as the component library. All CSS and JavaScript live in a single Vite pipeline — there is no Sass, django-compressor, or jQuery on the frontend.

## Architecture

```
Root directory/
├── package.json                  # npm dependencies and scripts
├── vite.config.js                # Vite build configuration
├── tailwind.config.js            # Tailwind CSS configuration
└── postcss.config.js             # PostCSS configuration

apps/web/static/vendor/frontend/  # Source (committed)
├── css/
│   └── frontend.css              # Tailwind + DaisyUI imports and app styles (input)
└── js/
    ├── frontend.js               # Entry point (imports the css and all modules)
    ├── config.js                 # Reads server config from the document (lang, cookie version)
    ├── theme.js                  # Theme toggle
    ├── forms.js                  # Prevent double form submission
    ├── banners.js                # Banner tracking and carousel
    ├── cookie-consent.js         # Cookie consent banner and modal
    ├── gallery.js                # Image lightbox (GLightbox)
    ├── modals.js                 # Generic dialog opener
    └── service-worker.js         # Service worker registration

apps/web/static/frontend/         # Build output (generated by Vite, gitignored)
├── .vite/
│   └── manifest.json             # Asset manifest with hashed filenames
├── assets/
│   ├── frontend-[hash].css       # Final compiled CSS
│   └── fa-*-[hash].woff2         # Font Awesome webfonts (bundled by Vite)
└── frontend-[hash].js            # Final bundled JavaScript
```

The output lives inside `apps/web/static/` (a `STATICFILES_DIRS` entry) so Django serves it through the staticfiles finders in development and `collectstatic` gathers it in production.

## Build Commands

### Install dependencies (once)

```bash
make frontend-setup
# or
npm install
```

### Development with Watch Mode

```bash
make frontend-dev
# or
npm run frontend:dev
```

### Production Build (Minified)

```bash
make frontend-prod
# or
npm run frontend:prod
```

## Asset Manifest System

Vite generates `manifest.json` with hashed filenames. Django template tags resolve these paths automatically.

### Template Tags

`head.html` loads every entry from the manifest with:

```django
{% load pyaa_vite %}

{% vite_all_css %}
{% vite_all_js %}
```

These tags discover the entry points in the manifest and generate the `<link>` and `<script>` tags, so there is no need to reference hashed filenames manually.

## Workflow

### Development

1. Start the asset watcher: `make frontend-dev`
2. Start the Django server: `make run`
3. Edit templates, CSS, or JS files.
4. Vite rebuilds on save. Refresh the browser to see the change.

There is no HMR — saving rebuilds the bundle and you refresh the page.

### Build output is not committed

`apps/web/static/frontend/` is a build artifact and is gitignored. Do not commit it — the CI workflow builds it (`make frontend-setup` + `make frontend-prod`) before running tests, and the production build does the same before `collectstatic`. A fresh checkout has no styles until you build once.

## JavaScript

All behavior is written as ES modules under `apps/web/static/vendor/frontend/js/`, imported from `frontend.js`. There are no global functions and no inline `onclick`/`onsubmit` handlers — modules attach event listeners and read data from `data-*` attributes. To add behavior, create a module and import it in `frontend.js`.

To pass values from Django to the bundle (config, element data, translated strings, full JS i18n), see [Passing Data from Django to JavaScript](frontend-data.md).

The image lightbox uses **GLightbox** (vanilla, no jQuery) and detects image dimensions automatically. The Django admin keeps its own vendored jQuery stack, which is unrelated to this pipeline.

## Styling

### Custom styles

Add custom CSS directly to `frontend.css` (plain CSS with Tailwind v4 features). There is no Sass.

### Using DaisyUI

DaisyUI uses the `data-theme` attribute on `<html>`. The enabled themes are configured in `frontend.css`:

```css
@plugin "daisyui" {
    themes: lofi --default, black --prefersdark;
}
```

To add or change themes, edit that block. See [DaisyUI Components](https://daisyui.com/components) for the component reference.

### Theme switching

The toggle binds to the `.theme-controller` element (handled by `theme.js`):

```html
<label class="swap swap-rotate">
  <input type="checkbox" class="theme-controller" value="dark">
  <i class="swap-on fa-solid fa-sun"></i>
  <i class="swap-off fa-solid fa-moon"></i>
</label>
```

A small inline script in `head.html` applies the stored theme before paint to avoid a flash — this is the only inline script kept on purpose.

## Important Notes

### Do not edit output files

Files in `apps/web/static/frontend/` are auto-generated. Edit the source instead:

- `apps/web/static/vendor/frontend/css/frontend.css`
- `apps/web/static/vendor/frontend/js/*.js`

### Prefer DaisyUI components

Use semantic classes instead of custom CSS:

```html
<button class="btn btn-primary">Button</button>
```

## Troubleshooting

| Problem | Solution |
|---------|----------|
| CSS not appearing | Run `make frontend-prod` (or `make frontend-dev`), clear browser cache |
| Bundle not updating | Rebuild with `make frontend-prod` and hard refresh |
| Icons missing | Rebuild so Font Awesome webfonts are emitted under `assets/` |
| DaisyUI not working | Verify `@plugin "daisyui"` in `frontend.css` |
| Template tag errors / no manifest | Run `make frontend-prod` to generate the manifest |

## Resources

- [Tailwind CSS](https://tailwindcss.com/docs)
- [DaisyUI Components](https://daisyui.com/components)
- [DaisyUI Themes](https://daisyui.com/docs/themes)
- [Vite](https://vitejs.dev/guide/)
- [GLightbox](https://github.com/biati-digital/glightbox)
- [Font Awesome](https://fontawesome.com/icons)
