sapium-ui 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,20 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+
7
+ jobs:
8
+ commons:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: actions/setup-python@v5
13
+ with:
14
+ python-version: "3.13"
15
+ - name: Install dependencies
16
+ run: pip install -e ".[dev]"
17
+ - name: Lint
18
+ run: ruff check src/ && ruff format --check src/
19
+ - name: Test
20
+ run: pytest tests/
@@ -0,0 +1,24 @@
1
+ name: Publish
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ publish:
11
+ runs-on: ubuntu-latest
12
+ permissions:
13
+ contents: read
14
+ id-token: write
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: actions/setup-python@v5
18
+ with:
19
+ python-version: "3.13"
20
+ - name: Build package
21
+ run: |
22
+ pip install build
23
+ python -m build
24
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,16 @@
1
+ __pycache__
2
+ .pytest_cache
3
+ .venv
4
+ logs
5
+ *.egg-info
6
+ test.ipynb
7
+ _bmad*
8
+ .claude
9
+ deploy/.env
10
+ deploy/settings/
11
+ .coverage
12
+ CLAUDE.md
13
+ .github/skills
14
+ .github/agents
15
+ .agents
16
+ node_modules
@@ -0,0 +1,8 @@
1
+ Metadata-Version: 2.4
2
+ Name: sapium-ui
3
+ Version: 0.1.0
4
+ Summary: Sapium shared frontend layer — CSS, Jinja2 base template, and JS for all Sapium consoles
5
+ Requires-Python: >=3.12
6
+ Provides-Extra: dev
7
+ Requires-Dist: pytest; extra == 'dev'
8
+ Requires-Dist: ruff>=0.15.0; extra == 'dev'
@@ -0,0 +1,127 @@
1
+ # sapium-ui
2
+
3
+ Shared frontend layer for all Sapium consoles: compiled CSS, Jinja2 base template, and shared JS.
4
+
5
+ Consoles install this package and receive a pre-compiled stylesheet (Tailwind v4 + DaisyUI v5), a `base.html` shell to extend, and two JS files for theme toggling and confirm modal behaviour. No Node.js is required in any console's Dockerfile.
6
+
7
+ ## Package contents
8
+
9
+ ```
10
+ src/sapium_ui/
11
+ ├── __init__.py # get_static_dir(), get_templates_dir()
12
+ ├── static/
13
+ │ ├── css/
14
+ │ │ ├── custom.css # Tailwind source — reference copy
15
+ │ │ └── dist.css # pre-compiled output — checked in, shipped in wheel
16
+ │ └── js/
17
+ │ ├── theme.js # dark/light theme toggle
18
+ │ └── confirm.js # htmx:confirm → DaisyUI modal bridge
19
+ └── templates/
20
+ └── sapium_ui/
21
+ └── base.html # shared Jinja2 shell
22
+ ```
23
+
24
+ ## Using in a console
25
+
26
+ ### 1. Add the dependency
27
+
28
+ ```toml
29
+ # pyproject.toml
30
+ [project]
31
+ dependencies = ["sapium-ui"]
32
+ ```
33
+
34
+ ### 2. Wire up Jinja2 and static files
35
+
36
+ ```python
37
+ from jinja2 import ChoiceLoader, Environment, PackageLoader
38
+ import sapium_ui
39
+ from fastapi.staticfiles import StaticFiles
40
+
41
+ env = Environment(
42
+ loader=ChoiceLoader([
43
+ PackageLoader("sapium_my_console"), # console-local templates win
44
+ PackageLoader("sapium_ui"), # shared templates as fallback
45
+ ]),
46
+ autoescape=True,
47
+ )
48
+
49
+ app.mount("/static/ui", StaticFiles(directory=str(sapium_ui.get_static_dir())), name="ui-static")
50
+ ```
51
+
52
+ ### 3. Extend the base template
53
+
54
+ ```html
55
+ {% extends "sapium_ui/base.html" %}
56
+
57
+ {% block title %}My Console{% endblock %}
58
+ {% block product_name %}My Console{% endblock %}
59
+ {% block viewport_class %}xl{% endblock %}
60
+
61
+ {% block nav %}
62
+ <nav aria-label="Main navigation" class="flex-1 py-4 overflow-y-auto">
63
+ <ul class="space-y-1 px-2">
64
+ <li>
65
+ <a href="/" {{ nav_aria_current('/') }}
66
+ class="{{ nav_link_class('/') }} flex items-center gap-3 px-3 py-2 rounded text-sm transition-colors">
67
+ Dashboard
68
+ </a>
69
+ </li>
70
+ </ul>
71
+ </nav>
72
+ {% endblock %}
73
+
74
+ {% block content %}
75
+ {# page content #}
76
+ {% endblock %}
77
+ ```
78
+
79
+ ### Template context variables
80
+
81
+ | Variable | Required | Description |
82
+ |---|---|---|
83
+ | `theme_key` | No | `localStorage` key for theme persistence (default: `sapium-theme`) |
84
+ | `logo_url` | No | URL for the favicon and sidebar logo |
85
+ | `ui_static_url` | No | Base URL where sapium-ui static assets are mounted (default: `/static/ui`) |
86
+ | `viewport_class` | No | Minimum breakpoint: `xl` (1280px, fixed sidebar) or `lg` (1024px, icon sidebar) |
87
+
88
+ ### Template blocks
89
+
90
+ | Block | Purpose |
91
+ |---|---|
92
+ | `title` | `<title>` tag content |
93
+ | `product_name` | Name shown in sidebar header |
94
+ | `viewport_class` | Override minimum breakpoint (alternative to context variable) |
95
+ | `viewport_message` | Small-screen message text |
96
+ | `nav` | Sidebar navigation — receives `nav_link_class(href)` and `nav_aria_current(href)` macros |
97
+ | `breadcrumb` | Top header breadcrumb area |
98
+ | `page_action` | Top header right-side action button |
99
+ | `content` | Main page content |
100
+
101
+ ### Nav helper macros
102
+
103
+ The base template defines two macros accessible in `{% block nav %}` overrides:
104
+
105
+ - `nav_link_class(href)` — returns active/hover Tailwind classes based on the current URL path
106
+ - `nav_aria_current(href)` — returns `aria-current="page"` when the link is active
107
+
108
+ ## Rebuilding the CSS
109
+
110
+ The CSS build is a **maintainer-only step** run before cutting a release. Consumers receive the pre-compiled `dist.css` in the wheel.
111
+
112
+ ```bash
113
+ cd build
114
+ npm install
115
+ npm run build
116
+ ```
117
+
118
+ Dependencies: `@tailwindcss/cli@^4`, `daisyui@^5`
119
+
120
+ The compiled output is committed to the repo and included in the wheel.
121
+
122
+ ## Design system
123
+
124
+ - **Dark theme** (`business`): DaisyUI v5 built-in base surfaces provide depth. Only brand tokens are overridden (primary, neutral, status colours, shape).
125
+ - **Light theme**: same brand tokens plus `--color-base-200: white` for cards-on-white. Sidebar stays dark.
126
+ - **Sapium purple**: `oklch(38.5% 0.183 293.5)` — `#6a0dad`
127
+ - **WCAG AA**: error components force `color: var(--color-error-content)` to guarantee contrast.
@@ -0,0 +1,107 @@
1
+ @import "tailwindcss";
2
+ @plugin "daisyui";
3
+
4
+ /* ─── Business (dark) theme — brand tokens only; DaisyUI v5 handles base surfaces ─── */
5
+ :root,
6
+ [data-theme="business"] {
7
+ color-scheme: dark;
8
+
9
+ /* brand */
10
+ --color-primary: oklch(38.5% 0.183 293.5); /* #6a0dad — sapium purple */
11
+ --color-primary-content: oklch(100% 0 0); /* white on primary bg */
12
+
13
+ /* sidebar */
14
+ --color-neutral: oklch(19.59% 0.027 286.57); /* #2A2535 — sidebar bg */
15
+ --color-neutral-content: oklch(91.19% 0.022 291.29); /* #E5E0F0 — sidebar text */
16
+
17
+ /* status */
18
+ --color-success: oklch(72.32% 0.189 142.5); /* #22C55E */
19
+ --color-success-content: oklch(100% 0 0);
20
+ --color-error: oklch(50% 0.213 22.18); /* ~red-700; white text ≥4.5:1 */
21
+ --color-error-content: oklch(100% 0 0);
22
+ --color-warning: oklch(77.48% 0.154 74.45); /* #F59E0B */
23
+ --color-warning-content: oklch(15% 0 0);
24
+ --color-info: oklch(63.37% 0.19 255.5); /* #3B82F6 */
25
+ --color-info-content: oklch(100% 0 0);
26
+
27
+ /* shape (DaisyUI v5 names) */
28
+ --radius-box: 0.75rem;
29
+ --radius-selector: 0.5rem;
30
+ --radius-field: 0.375rem;
31
+ --size-selector: 0.25rem;
32
+ --size-field: 0.25rem;
33
+ --border: 1px;
34
+ --depth: 1;
35
+ --noise: 0;
36
+ }
37
+
38
+ /* ─── Light theme ─── */
39
+ [data-theme="light"] {
40
+ color-scheme: light;
41
+
42
+ /* pure white base-200 — makes cards-on-white work */
43
+ --color-base-200: oklch(100% 0 0); /* pure white */
44
+
45
+ /* brand */
46
+ --color-primary: oklch(38.5% 0.183 293.5); /* #6a0dad — sapium purple */
47
+ --color-primary-content: oklch(100% 0 0);
48
+
49
+ /* sidebar — stays dark in light mode */
50
+ --color-neutral: oklch(19.59% 0.027 286.57); /* #2A2535 — sidebar bg */
51
+ --color-neutral-content: oklch(91.19% 0.022 291.29); /* #E5E0F0 — sidebar text */
52
+
53
+ /* status */
54
+ --color-success: oklch(72.32% 0.189 142.5); /* #22C55E */
55
+ --color-success-content: oklch(100% 0 0);
56
+ --color-error: oklch(50% 0.213 22.18); /* red-700; white text ≥4.5:1 */
57
+ --color-error-content: oklch(100% 0 0);
58
+ --color-warning: oklch(77.48% 0.154 74.45); /* #F59E0B */
59
+ --color-warning-content: oklch(15% 0 0);
60
+ --color-info: oklch(63.37% 0.19 255.5); /* #3B82F6 */
61
+ --color-info-content: oklch(15% 0 0); /* dark text — white fails WCAG AA on ~63% L blue */
62
+
63
+ /* shape */
64
+ --radius-box: 0.75rem;
65
+ --radius-selector: 0.5rem;
66
+ --radius-field: 0.375rem;
67
+ --size-selector: 0.25rem;
68
+ --size-field: 0.25rem;
69
+ --border: 1px;
70
+ --depth: 0;
71
+ --noise: 0;
72
+ }
73
+
74
+ /* WCAG AA fix: DaisyUI v5 error components inherit color from --color-error
75
+ which can fail contrast on dark backgrounds. Force error-content (white). */
76
+ [data-theme="business"] .alert-error,
77
+ [data-theme="business"] .badge-error,
78
+ [data-theme="business"] .btn-error {
79
+ color: var(--color-error-content);
80
+ }
81
+
82
+ [data-theme="light"] .alert-error,
83
+ [data-theme="light"] .badge-error,
84
+ [data-theme="light"] .btn-error:not(.btn-outline) {
85
+ color: var(--color-error-content);
86
+ }
87
+
88
+ [data-theme="light"] .btn-outline.btn-error {
89
+ border-color: var(--color-error);
90
+ color: var(--color-error);
91
+ background-color: transparent;
92
+ }
93
+ [data-theme="light"] .btn-outline.btn-error:hover {
94
+ background-color: var(--color-error);
95
+ border-color: var(--color-error);
96
+ color: var(--color-error-content);
97
+ }
98
+
99
+ /* expand/collapse chevron — CSS-only rotate, no JS */
100
+ .card-chevron {
101
+ transition: transform 0.15s ease;
102
+ flex-shrink: 0;
103
+ transform: rotate(0deg);
104
+ }
105
+ details[open] summary .card-chevron {
106
+ transform: rotate(90deg);
107
+ }