Metadata-Version: 2.4
Name: coffeehouse-ui
Version: 0.9.3
Summary: Shared UI components, theme, and static assets for the Coffee House ecosystem
Author-email: Ruben Sukiasyan <rubsksn@gmail.com>
License: MIT License
        
        Copyright (c) 2026 Ruben Sukiasyan
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/coffeehouse-tools/coffeehouse-ui
Project-URL: Repository, https://github.com/coffeehouse-tools/coffeehouse-ui
Project-URL: Issues, https://github.com/coffeehouse-tools/coffeehouse-ui/issues
Project-URL: Changelog, https://github.com/coffeehouse-tools/coffeehouse-ui/blob/master/CHANGELOG.md
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: jinja2>=3.1.0
Requires-Dist: starlette>=0.38.0
Provides-Extra: dev
Requires-Dist: pytest==9.0.3; extra == "dev"
Requires-Dist: pytest-cov==7.1.0; extra == "dev"
Requires-Dist: ruff==0.15.11; extra == "dev"
Requires-Dist: mypy==1.20.1; extra == "dev"
Requires-Dist: bandit==1.9.4; extra == "dev"
Requires-Dist: pip-audit==2.10.0; extra == "dev"
Requires-Dist: pre-commit==3.8.0; extra == "dev"
Dynamic: license-file

# coffeehouse-ui

Shared UI package for the [Coffee House digital ecosystem](https://github.com/rubencfh/coffeehouse-ecosystem). Pip-installable Python package providing Jinja2 base templates, shared components, CSS theme, JS utilities, brand assets, and the **unified permission UX** used by Digi, Grind, and Beany (`compute_effective(dept ∪ grants − revokes)` resolver + three shared Jinja macros for the dept-matrix / role-tri-state / simulate admin pages).

## Quick Start

Install in your app's `requirements.txt`:

```
coffeehouse-ui @ git+https://github.com/rubencfh/coffeehouse-ui.git@v0.4.0
```

Integrate in your FastAPI/Starlette app:

```python
from coffeehouse_ui import TEMPLATE_DIR as UI_TEMPLATE_DIR, STATIC_DIR as UI_STATIC_DIR
from starlette.templating import Jinja2Templates
from starlette.staticfiles import StaticFiles

templates = Jinja2Templates(directory=[str(app_templates_dir), str(UI_TEMPLATE_DIR)])
templates.env.globals["app_name"] = "YourApp"
app.mount("/ui", StaticFiles(directory=str(UI_STATIC_DIR)), name="ui_static")
```

Your app's `base.html` extends `ui_base.html`:

```html
{% extends "ui_base.html" %}
{% block title %}My Page{% endblock %}
{% block content %}...{% endblock %}
```

## What's Included

### Templates

- **`ui_base.html`** — Canonical base template with Inter font, DaisyUI, Tailwind, custom theme, dark mode, HTMX, skip-to-content, toast container, CSRF/toast/loading JS
- **12 shared components** — navbar, sidebar, app_switcher, flash, page_header, data_table, empty_state, stat_card, pagination, form_field, confirm_modal, loading

### Static Assets

- **CSS**: `coffeehouse.min.css` (purged Tailwind 3 + DaisyUI 4, 18KB gzip) + `coffeehouse-theme.css`
- **JS**: `theme.js`, `toast.js`, `loading.js`, `csrf.js`, `htmx.min.js` (v2.0.4), `culori.min.js` (color conversion for Auth brand admin)
- **Images**: `favicon.svg` (coffee cup)

### Theme

Custom DaisyUI themes `coffeehouse` (light) and `coffeehouse-dark` (dark) with a warm espresso/brown palette. Dark mode toggle persists to localStorage.

## CSS Build

CSS is built from `src/input.css` using Tailwind 3 + DaisyUI 4. The Tailwind config scans templates across all ecosystem apps.

```bash
npm install          # First time only
npm run build        # Rebuild after adding new Tailwind classes
npm run watch        # Watch mode for development
```

Rebuild when a new Tailwind utility class is used in any app template that wasn't previously in the CSS bundle.

## Template Linter

```bash
python scripts/lint_templates.py --all
```

Checks all ecosystem templates for CDN links, missing `role="alert"`, missing `scope="col"`, and hardcoded color classes.

## Project Structure

```
coffeehouse_ui/
├── __init__.py              # Exports TEMPLATE_DIR, STATIC_DIR, __version__
├── templates/
│   ├── ui_base.html
│   └── components/          # 12 shared Jinja2 components
└── static/
    ├── css/                 # Built Tailwind + theme CSS
    ├── js/                  # Theme, toast, loading, CSRF, HTMX
    └── img/                 # Favicon
```

## Consumer Apps

| App | Repo |
|-----|------|
| Auth | [rubencfh/coffeehouse-auth](https://github.com/rubencfh/coffeehouse-auth) |
| Beany/KMS | [rubencfh/Beany](https://github.com/rubencfh/Beany) |
| Digi | [rubencfh/Digi](https://github.com/rubencfh/Digi) |
| Grind | [rubencfh/Grind](https://github.com/rubencfh/Grind) |
| CHQR | [rubencfh/CHQR](https://github.com/rubencfh/CHQR) |

## Development

First-time setup:

```bash
pip install -e ".[dev]"
pip install -r requirements-dev.txt   # pulls coffeehouse-common[testing] + pinned tooling
pre-commit install                    # wires ruff-format + ruff + hygiene hooks on each commit
```

Run the checks that CI runs:

```bash
pytest                                  # unit + integration tests with coverage
ruff format --check . && ruff check .   # format + lint
mypy coffeehouse_ui                     # lenient typecheck
bandit -c pyproject.toml -r coffeehouse_ui scripts -ll  # SAST
```

`pre-commit run --all-files` runs the on-commit subset in one go. gitleaks runs in CI only (Windows Application Control blocks the Go-built local hook; install the native binary manually if you want local secret scanning).

The full pipeline (lint / typecheck / pytest w/ coverage / secret-scan / SAST / SCA) runs on every push and PR via `.github/workflows/ci.yml`, which is a thin caller of `rubencfh/coffeehouse-ecosystem/.github/workflows/reusable-python-ci.yml@master`. **As of the TBD cutover (2026-04-22), the suite is a merge gate on `master`**: 6 CI jobs + CodeRabbit review = 7 required status checks. Direct `git push origin master` is blocked; changes land through short-lived feature branches + PRs.

## Branch Strategy — Trunk-Based Development

- `master` is the single long-lived branch (renamed from `dev` on 2026-04-22 for ecosystem-wide naming consistency; previously this repo shipped from `dev`).
- Every change goes through a short-lived feature branch off `master` + PR + squash merge. Feature branches auto-delete on merge.
- Tag releases as `v0.x.0` on `master` for consumer apps to pin.
- See `agents/shared/50-dev-workflow.md` and `agents/shared/97-pr-workflow.md` for the full flow.

## Version

Current: **0.3.1**

### Brand API (optional)

Set `templates.env.globals["auth_service_url"]` to your Auth base URL (e.g. `https://auth.coffeehouse.tools`). `ui_base.html` then loads active brand CSS and images from `GET {auth_service_url}/api/brand/active` on each session (cached in `sessionStorage` for 30 seconds). Omit or leave empty if you do not use the shared brand feature.
