abilian-ds 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.
Files changed (33) hide show
  1. abilian_ds-0.1.0/.gitignore +19 -0
  2. abilian_ds-0.1.0/CHANGES.md +71 -0
  3. abilian_ds-0.1.0/LICENSE +202 -0
  4. abilian_ds-0.1.0/PKG-INFO +128 -0
  5. abilian_ds-0.1.0/README.md +104 -0
  6. abilian_ds-0.1.0/TOKENS.md +425 -0
  7. abilian_ds-0.1.0/pyproject.toml +61 -0
  8. abilian_ds-0.1.0/src/abilian_ds/__init__.py +3 -0
  9. abilian_ds-0.1.0/src/abilian_ds/allowlist.txt +11 -0
  10. abilian_ds-0.1.0/src/abilian_ds/cli.py +291 -0
  11. abilian_ds-0.1.0/src/abilian_ds/css/ads.css +39 -0
  12. abilian_ds-0.1.0/src/abilian_ds/css/base.css +89 -0
  13. abilian_ds-0.1.0/src/abilian_ds/css/derive.css +242 -0
  14. abilian_ds-0.1.0/src/abilian_ds/css/knobs.css +113 -0
  15. abilian_ds-0.1.0/src/abilian_ds/css/parts/alert.css +25 -0
  16. abilian_ds-0.1.0/src/abilian_ds/css/parts/button.css +103 -0
  17. abilian_ds-0.1.0/src/abilian_ds/css/parts/card.css +123 -0
  18. abilian_ds-0.1.0/src/abilian_ds/css/parts/content.css +515 -0
  19. abilian_ds-0.1.0/src/abilian_ds/css/parts/forced-colors.css +62 -0
  20. abilian_ds-0.1.0/src/abilian_ds/css/parts/form.css +340 -0
  21. abilian_ds-0.1.0/src/abilian_ds/css/parts/indicator.css +391 -0
  22. abilian_ds-0.1.0/src/abilian_ds/css/parts/layout.css +320 -0
  23. abilian_ds-0.1.0/src/abilian_ds/css/parts/nav.css +249 -0
  24. abilian_ds-0.1.0/src/abilian_ds/css/parts/overlay.css +359 -0
  25. abilian_ds-0.1.0/src/abilian_ds/css/parts/shell.css +419 -0
  26. abilian_ds-0.1.0/src/abilian_ds/css/parts/table.css +116 -0
  27. abilian_ds-0.1.0/src/abilian_ds/lint.py +819 -0
  28. abilian_ds-0.1.0/src/abilian_ds/shell.js +231 -0
  29. abilian_ds-0.1.0/src/abilian_ds/situ.css +108 -0
  30. abilian_ds-0.1.0/src/abilian_ds/templates/ads/form.html +94 -0
  31. abilian_ds-0.1.0/src/abilian_ds/templates/ads/nav.html +52 -0
  32. abilian_ds-0.1.0/src/abilian_ds/templates/ads/shell.html +119 -0
  33. abilian_ds-0.1.0/src/abilian_ds/tokens.py +271 -0
@@ -0,0 +1,19 @@
1
+ __pycache__/
2
+ *.egg-info/
3
+ .venv/
4
+ node_modules/
5
+ .pytest_cache/
6
+
7
+ # Generated. `abilian-ds tokens` writes TOKENS.md and docs/src/reference/ — those ARE
8
+ # committed, because they are the menu. What is not is the built site.
9
+ docs/site/
10
+ docs/.cache/
11
+
12
+ # A 466 MB checkout of Tabler, kept locally as the calibration reference. The stylesheet
13
+ # the harness actually loads is poc/static/tabler.min.css, which is committed.
14
+ sandbox/
15
+
16
+ # Vendored into the pocs by `abilian-ds sync`. Scoped to pocs/ deliberately: a bare
17
+ # `templates/ads/` would also match demos/templates/ads/, which is real tracked content.
18
+ demos/static/css/ads/
19
+ demos/situ_demos/templates/ads/
@@ -0,0 +1,71 @@
1
+ # Changelog
2
+
3
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.1.0] - 2026-11-11
8
+
9
+ The first release.
10
+
11
+ ### Added
12
+
13
+ - **A menu button in the shell's top bar.** Wide, it folds the sidebar to a rail and back, and the reader's choice is remembered and restored before first paint. Below 48em it opens the sidebar as a panel from the start edge, closed by Escape or a click outside. `aria-expanded` holds the state. Asked for by the first outside adopter ([notes/issues/03](notes/issues/03-analytics-requests.md)), like the fixes below marked *(adopter)*.
14
+ - **Image logos in the brand.** A `brand_mark` holding an `<img>` or `<svg>` drops the coloured tile. *(adopter)*
15
+ - **Tabular numerals** in table cells and `.ads-metric`, so figures line up whatever the font. *(adopter)*
16
+ - **Figures:** `ads-band` (a row of headline figures divided by hairlines, items optionally `aria-pressed` buttons), `ads-change` (a toned delta with an arrow, `--up` or `--down`) and `ads-share` (a row's share as a pale fill, through `--share`). *(adopter)*
17
+ - **Four knobs.** `--ads-label-case` and `--ads-label-tracking` set the small labels (table headers, pretitles, nav sections and the rest) for a sentence-case brand. `--ads-font-figures` gives `.ads-metric` a separate face. `--ads-page-contrast` sets how far the page ground stands back from the surfaces on it, 0 for a flat look. *(adopter)*
18
+ - **Tables:** `ads-table--nowrap` keeps cells on one line, and `ads-col--secondary` and `ads-col--tertiary` drop columns when the table's wrapper is under 40rem and 30rem. A small button in a compact row no longer makes the row taller. *(adopter)*
19
+ - **`ads-list--columns`**, a list whose rows are subgrids of it, so cells line up across rows. *(adopter)*
20
+ - **Nav entries without an icon:** an entry can name an `image`. One with neither shows the label's initial in the folded rail. *(adopter)*
21
+ - **Documentation** for the figure components, sparklines, uptime strips, legends and the inline-SVG chart pattern, and the Python floor on the install page. *(adopter)*
22
+ - **`ads-split--fill`**, the inbox shape: each pane scrolls by itself and the page does not, with the shell bounding the main column whenever a page contains one. It fills only with room both ways (a container query in `rem`, so 200% text counts, and a minimum viewport height), and is an ordinary split otherwise, so reflow holds. From the first port of a real application ([notes/issues/02](notes/issues/02-a-mail-client-asks-for-three-things.md)).
23
+ - **`ads-media`**, a figure beside a block of text, aligned to the top and never wrapping: a mail row, a notification, a comment.
24
+ - **`ads-btn--mark`**, a toggle that marks the thing it sits on: a star, a flag, a pin. When pressed, it fills the outline glyph in the tone's ink, where the mode-switcher draws a box.
25
+ - **An install test.** `tests/test_install.py` builds the wheel and sdist, installs into a clean virtualenv, runs `sync`, renders a page on the packaged shell and lints it, on each `make check`.
26
+ - **`--ads-line-input`**, the edge of a control, which has to be found by eye. It is `--ads-n-500` in dark mode, and in light mode it moves from Tabler's hairline to `n-500` with `--ads-contrast`. `--ads-line` keeps the same job and value.
27
+ - **An application shell.** `sync` vendors `ads/shell.html` (extended in place, with navigation taken as **data**), plus `ads/nav.html` and `shell.js`, which `.ads-dropdown`, `.ads-drawer`, the theme toggle, the lightbox and the sidebar's memory need. The reference application's frame went from 308 lines to 99.
28
+ - **`llms.txt` and `llms-full.txt`** for agents adopting the system, generated from the documentation site's navigation so the index cannot list a page the site lacks.
29
+ - **`ads-split__head`**, a pane header that stays in view while the page scrolls under it.
30
+ - **`make help`** in all three Makefiles, plus `format`, `lint`, `types`, `test-cov`, `build` and `publish`.
31
+ - **Apache 2.0, a README and the packaging metadata** a first release needs.
32
+ - **`abilian-ds tokens --docs`** writes the documentation site's reference pages from the stylesheet, so the menu cannot drift from the system.
33
+ - **Five lint rules**: `modifier-without-block` (a modifier on an element without the block it modifies), `duplicate-rule` and `duplicate-token` (a selector or a custom property declared twice), `self-as-child` (an element that *is* the child its class expects to contain), and `path-missing` (a configured path that is not on disk, which used to be a traceback).
34
+ - **Components** found by porting applications the system did not grow around: `ads-tree` (hierarchy), `ads-viewport` (a fixed-height scrolling pane), `ads-bulkbar` (a selection bar any selection model can drive), and `--ads-tap`, the 24px pointer-target floor, which does not scale with the density knob.
35
+ - **Collapsible sidebar groups**, opened by the server for the current page and remembered per reader.
36
+ - **A documentation site** (Zensical) with a generated reference section.
37
+
38
+ ### Changed
39
+
40
+ - **`--ads-contrast` defaults to 1.** At Tabler's values the light theme failed WCAG AA on the system's badges, chips and muted text, so every adopter met the same audit finding. The knob also reaches further now: body ink from n-700 to n-800, the soft hairline from 12% to 18%, and a dark-mode brand ink lifted towards white. Set it to 0 for the reference's palette; the calibration frames do, and parity with Tabler still measures zero differences. *(adopter)*
41
+ - **Card heads share one height**, so the content of cards in a grid starts on one line; a head holding a control gives back the extra height. *(adopter)*
42
+ - **A segmented control stays on one line** and scrolls when short of room. Wrapped, it read as two controls. *(adopter)*
43
+ - **`.ads-card--status` takes its colour from `ads-tone-*`**, like every other toned component. `ads-card--status-success`, `-warning` and `-danger` are gone; write `ads-card--status ads-tone-success`. Used alone, as five demo pages did, those modifiers drew no stripe at all. *(adopter)*
44
+ - **The package ships the system it has.** `theme.css`, `examples/` and four Jinja macros described the Tailwind design this package used to be; `abilian-ds sync` vendored them and `TOKENS.md` documented them. All removed. `sync` now vendors the real stylesheet tree. The linter's Tailwind-CLI path is gone.
45
+ - **`situ.css` points at tokens that exist.** It had been aliasing `--color-*`, a namespace this package deleted.
46
+ - **Current-item styling keys off `aria-current`**, so the highlight cannot exist without the semantics. Same for `aria-pressed` and `aria-invalid`.
47
+ - **The sidebar is sticky and scrolls the overflow inside it.** Its height used to be the document's, so how far a page scrolled depended on which nav groups were open.
48
+ - `poc/` and `pocs/` merged into one `demos/` application.
49
+ - **`sync` vendors one stylesheet**, spliced from the parts in import order, so a page costs one request where it used to cost a fifteen-deep `@import` waterfall. Stale `.css` under the target is removed, so no one edits a file and wonders why nothing changes.
50
+ - **`ads-split` wraps on the split's width**, where it used to wrap on a viewport media query, which is why a split nested in a split kept three panes long after the third stopped being readable. The gap classes set `gap` directly. They used to set the inherited `--ads-gap`, which had been governing all the layout primitives below whatever held the class.
51
+ - **`unused-class` is opt-in.** It asks a question only the project owning the stylesheet can answer; a first adopter with one correct page got 224 findings. `duplicate-rule` now spans the whole sheet the way the cascade does (see [note 25](notes/25-a-check-is-a-scope.md)).
52
+ - **The sdist is the package**, without the rest of the repository: 604 kB to 81 kB.
53
+
54
+ ### Fixed
55
+
56
+ - **On a phone the sidebar was the whole first screen.** Below 48em it stacked above the page, sticky and a viewport tall, so a page opened on its menu. It is now the panel the menu button opens. *(adopter)*
57
+ - **A folded section heading drew a 24px grey block** where a hairline belongs: the tap-target floor beat the `height`. *(adopter)*
58
+ - **A table in its scroll wrapper inside a card** kept 16px of margin under the last row and its first column out of line with the card's title; the card rules only matched a bare table. Header and hovered rows at a card's top or bottom also painted square corners over the round ones. *(adopter)*
59
+ - **`table-overflow` never ran in an adopter's `lint`.** It lived only in `check_document`, which only this repository's tests called. It now runs on all templates, except for tables inside a `{% macro %}`. `heading-skip` still needs the rendered page; the linter docs show how to run `check_document` in an application's tests.
60
+ - **Control edges met no contrast floor, in either theme.** Inputs, selects, textareas, the drawn checkbox and radio, the switch, the colour input and the editor all took `--ads-line`, a divider at 1.2 : 1 against WCAG 1.4.11's 3 : 1. They read `--ads-line-input` now. Reported from a questionnaire in dark mode ([notes/issues/01](notes/issues/01-dark-mode.md)), and gated by `test_control_edges_meet_the_non_text_floor_in_both_themes`, because the text sweep has no text node to read on a checkbox.
61
+ - **An unanswered radio group looked answered.** `:indeterminate` matches a radio whose group has nothing checked, so each such radio wore the brand fill of a tri-state checkbox. The rule is qualified with `[type="checkbox"]`.
62
+ - Accessibility, each found by rendering a condition no one had rendered: a keyboard trap in the rich-text field (WCAG 2.1.2), three reflow failures at 320px (1.4.10), six pages overflowing at 200% text (1.4.4), twenty-four pointer targets under 24×24 (2.5.8), ten current-item markers invisible to assistive technology, and each page load moving focus to the end of the document (2.4.3).
63
+ - Forced-colors mode: meaning shown by colour alone now stays visible, marked with borders. `Highlight` fills were dropped, because the text backplate can hide them.
64
+ - The linter's vocabulary contained 48 fragments read out of decimals and SVG data-URIs, each one a class name a template could use and pass.
65
+
66
+ ### Documentation
67
+
68
+ - Guides for knobs, layout, shells, forms, data and lists, accessibility, dark mode and situ; a generated reference for knobs, tokens, components, macros and the CLI.
69
+ - The pre-system planning notes are archived in `notes/OLD/` with what replaced each.
70
+ - **One home per topic.** A dozen topics were explained on two to four pages each. The copies had drifted: the shell was still described as unpackaged, `sync` as writing two files, and the vocabulary's size disagreed across five pages. Each topic now lives on one page and the others link to it. The shells guide documents the packaged `ads/shell.html`: the blocks, navigation as data, the four layouts and `shell.js`.
71
+ - **The vocabulary's size is stated once**, on the About page, and `test_the_vocabulary_is_sized_once_and_correctly` holds it to the stylesheet and fails if another page states it. The generated reference pages compute the counts themselves.
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
@@ -0,0 +1,128 @@
1
+ Metadata-Version: 2.5
2
+ Name: abilian-ds
3
+ Version: 0.1.0
4
+ Summary: Abilian Design System — a closed token vocabulary for Litestar and Jinja
5
+ Project-URL: Homepage, https://ads.lab.abilian.com
6
+ Project-URL: Documentation, https://ads.lab.abilian.com
7
+ Project-URL: Source, https://github.com/abilian/abilian-ds
8
+ Project-URL: Issues, https://github.com/abilian/abilian-ds/issues
9
+ Project-URL: Changelog, https://github.com/abilian/abilian-ds/blob/main/CHANGES.md
10
+ Author-email: Stefane Fermigier <sf@abilian.com>
11
+ License-Expression: Apache-2.0
12
+ License-File: LICENSE
13
+ Keywords: accessibility,css,design-system,design-tokens,jinja,litestar
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Environment :: Web Environment
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: License :: OSI Approved :: Apache Software License
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Topic :: Software Development :: User Interfaces
20
+ Classifier: Topic :: Text Processing :: Markup :: HTML
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.11
23
+ Description-Content-Type: text/markdown
24
+
25
+ # Abilian Design System
26
+
27
+ This is a design system for business applications built on **Litestar and Jinja**, written in plain CSS with no front-end toolchain. A small set of knobs is the whole overridable surface; everything else is derived from them.
28
+
29
+ [Documentation](https://ads.lab.abilian.com) · [Token and class reference](https://ads.lab.abilian.com/reference/components/) · [llms.txt](https://ads.lab.abilian.com/llms.txt)
30
+
31
+ ```bash
32
+ pip install abilian-ds # or: uv add abilian-ds
33
+ abilian-ds sync
34
+ ```
35
+
36
+ It has no runtime dependencies and needs no build step.
37
+
38
+ ## The idea
39
+
40
+ Styling goes through a **closed vocabulary**: a `--ads-*` custom property or an `ads-*` class. There is no utility layer, no arbitrary-value syntax and no `style=` attribute. `bg-gray-100`, `p-4` and `text-[13px]` generate no CSS at all, and `abilian-ds lint` rejects them before they can sit in a template looking plausible.
41
+
42
+ That closure is what makes the rest possible:
43
+
44
+ - **Knobs are the overridable surface; everything else derives.** Set `--ads-brand` and its hover, active, tint, border and foreground shades follow. Set `--ads-space-scale` and every padding, gap, margin and control height follows. One declaration on `:root` changes 361 of 501 elements on a page.
45
+ - **Both themes in one value.** Every colour holds light and dark through `light-dark()`. There is no `dark:` variant anywhere and so no second styling pass to forget.
46
+ - **State that a person can perceive is an attribute.** The current item is `aria-current`, a toggle is `aria-pressed`, an invalid field is `aria-invalid`. The stylesheet keys off those, so the look cannot exist without the meaning.
47
+ - **Measured parity with [Tabler](https://tabler.io).** A harness compares the two property by property and reports **0 differences**.
48
+ - **Accessibility with tests behind it**: contrast in both themes, reflow at 320px, 200% text-only zoom, keyboard traversal, pointer target size and Windows high contrast, swept across every route on every run.
49
+
50
+ ## What `sync` gives you
51
+
52
+ ```
53
+ static/css/ads/ads.css the stylesheet — one file, one request
54
+ static/css/ads/shell.js what the dropdowns, drawers and theme toggle need
55
+ static/css/ads/situ.css only if you use situ
56
+ templates/ads/shell.html the application frame, extended not copied
57
+ templates/ads/nav.html navigation rendered from data
58
+ templates/ads/form.html field, select, textarea, checkbox, button macros
59
+ ```
60
+
61
+ Paths live in `[tool.abilian-ds]` in your `pyproject.toml`, so the commands take no flags:
62
+
63
+ ```toml
64
+ [tool.abilian-ds]
65
+ templates = ["templates"]
66
+ prefix = "ads-"
67
+ ```
68
+
69
+ ## A page
70
+
71
+ ```jinja
72
+ {% extends "ads/shell.html" %}
73
+ {% block title %}Contacts · Acme{% endblock %}
74
+ {% block brand_name %}Acme{% endblock %}
75
+ {% block heading %}Contacts{% endblock %}
76
+ {% block actions %}<button class="ads-btn ads-btn--primary">New contact</button>{% endblock %}
77
+ {% block body %}
78
+ <div class="ads-card"><div class="ads-card__body ads-stack">
79
+ <div class="ads-cluster">
80
+ <span class="ads-avatar ads-avatar--sm">AR</span>
81
+ <strong class="ads-truncate">Amélie Rousseau</strong>
82
+ <span class="ads-badge ads-tone-success">active</span>
83
+ </div>
84
+ </div></div>
85
+ {% endblock %}
86
+ ```
87
+
88
+ The navigation is data, because markup drifts:
89
+
90
+ ```python
91
+ nav = [{"section": "Directory",
92
+ "items": [{"href": "/contacts", "label": "Contacts", "icon": "users"}]}]
93
+ ```
94
+
95
+ Configure Jinja with `undefined=StrictUndefined`. It turns a misspelt component argument into an error, where it would otherwise yield an unstyled element.
96
+
97
+ ## The commands
98
+
99
+ | command | what it does |
100
+ |---|---|
101
+ | `abilian-ds sync` | vendor the stylesheet, the shell script and the macros into your project |
102
+ | `abilian-ds lint` | check templates against the design system |
103
+ | `abilian-ds tokens` | regenerate `TOKENS.md` from the stylesheet |
104
+
105
+ `lint` is the contract. Green means on-system:
106
+
107
+ ```
108
+ templates/page.html:1: unknown-class: bg-gray-100: not in the design system
109
+ templates/page.html:2: dark-variant: dark:text-white: colours carry both themes, there is no dark pass
110
+ templates/page.html:2: arbitrary-value: text-[13px]: bypasses the token scale
111
+ templates/page.html:2: inline-style: style='color: red': a decision belongs in CSS
112
+ ```
113
+
114
+ It also hashes every vendored file against what the package would produce, so a local edit to `ads.css` shows up as a finding.
115
+
116
+ ## What it does not do
117
+
118
+ - **No icon set.** The shell uses an `icon()` Jinja global if you register one; an icon set is a licence you cannot change once it is baked in. [How to wire one up.](https://ads.lab.abilian.com/getting-started/first-page/)
119
+ - **No JavaScript framework.** `shell.js` is a page of delegated event handlers with no dependencies. Components that need more (a rich data grid, a live region) are [situ](https://situ.hop3.abilian.com)'s job, and `situ.css` bridges the two palettes.
120
+ - **No CSS-in-JS, no theme builder UI, no component library for React.** This is Jinja and CSS.
121
+
122
+ ## Status
123
+
124
+ Beta. The vocabulary, the linter and the shell are stable enough to build on; the 0.x version number covers the rest. See [CHANGES.md](CHANGES.md).
125
+
126
+ ## Licence
127
+
128
+ Apache 2.0. Copyright © 2026 Abilian SAS.
@@ -0,0 +1,104 @@
1
+ # Abilian Design System
2
+
3
+ This is a design system for business applications built on **Litestar and Jinja**, written in plain CSS with no front-end toolchain. A small set of knobs is the whole overridable surface; everything else is derived from them.
4
+
5
+ [Documentation](https://ads.lab.abilian.com) · [Token and class reference](https://ads.lab.abilian.com/reference/components/) · [llms.txt](https://ads.lab.abilian.com/llms.txt)
6
+
7
+ ```bash
8
+ pip install abilian-ds # or: uv add abilian-ds
9
+ abilian-ds sync
10
+ ```
11
+
12
+ It has no runtime dependencies and needs no build step.
13
+
14
+ ## The idea
15
+
16
+ Styling goes through a **closed vocabulary**: a `--ads-*` custom property or an `ads-*` class. There is no utility layer, no arbitrary-value syntax and no `style=` attribute. `bg-gray-100`, `p-4` and `text-[13px]` generate no CSS at all, and `abilian-ds lint` rejects them before they can sit in a template looking plausible.
17
+
18
+ That closure is what makes the rest possible:
19
+
20
+ - **Knobs are the overridable surface; everything else derives.** Set `--ads-brand` and its hover, active, tint, border and foreground shades follow. Set `--ads-space-scale` and every padding, gap, margin and control height follows. One declaration on `:root` changes 361 of 501 elements on a page.
21
+ - **Both themes in one value.** Every colour holds light and dark through `light-dark()`. There is no `dark:` variant anywhere and so no second styling pass to forget.
22
+ - **State that a person can perceive is an attribute.** The current item is `aria-current`, a toggle is `aria-pressed`, an invalid field is `aria-invalid`. The stylesheet keys off those, so the look cannot exist without the meaning.
23
+ - **Measured parity with [Tabler](https://tabler.io).** A harness compares the two property by property and reports **0 differences**.
24
+ - **Accessibility with tests behind it**: contrast in both themes, reflow at 320px, 200% text-only zoom, keyboard traversal, pointer target size and Windows high contrast, swept across every route on every run.
25
+
26
+ ## What `sync` gives you
27
+
28
+ ```
29
+ static/css/ads/ads.css the stylesheet — one file, one request
30
+ static/css/ads/shell.js what the dropdowns, drawers and theme toggle need
31
+ static/css/ads/situ.css only if you use situ
32
+ templates/ads/shell.html the application frame, extended not copied
33
+ templates/ads/nav.html navigation rendered from data
34
+ templates/ads/form.html field, select, textarea, checkbox, button macros
35
+ ```
36
+
37
+ Paths live in `[tool.abilian-ds]` in your `pyproject.toml`, so the commands take no flags:
38
+
39
+ ```toml
40
+ [tool.abilian-ds]
41
+ templates = ["templates"]
42
+ prefix = "ads-"
43
+ ```
44
+
45
+ ## A page
46
+
47
+ ```jinja
48
+ {% extends "ads/shell.html" %}
49
+ {% block title %}Contacts · Acme{% endblock %}
50
+ {% block brand_name %}Acme{% endblock %}
51
+ {% block heading %}Contacts{% endblock %}
52
+ {% block actions %}<button class="ads-btn ads-btn--primary">New contact</button>{% endblock %}
53
+ {% block body %}
54
+ <div class="ads-card"><div class="ads-card__body ads-stack">
55
+ <div class="ads-cluster">
56
+ <span class="ads-avatar ads-avatar--sm">AR</span>
57
+ <strong class="ads-truncate">Amélie Rousseau</strong>
58
+ <span class="ads-badge ads-tone-success">active</span>
59
+ </div>
60
+ </div></div>
61
+ {% endblock %}
62
+ ```
63
+
64
+ The navigation is data, because markup drifts:
65
+
66
+ ```python
67
+ nav = [{"section": "Directory",
68
+ "items": [{"href": "/contacts", "label": "Contacts", "icon": "users"}]}]
69
+ ```
70
+
71
+ Configure Jinja with `undefined=StrictUndefined`. It turns a misspelt component argument into an error, where it would otherwise yield an unstyled element.
72
+
73
+ ## The commands
74
+
75
+ | command | what it does |
76
+ |---|---|
77
+ | `abilian-ds sync` | vendor the stylesheet, the shell script and the macros into your project |
78
+ | `abilian-ds lint` | check templates against the design system |
79
+ | `abilian-ds tokens` | regenerate `TOKENS.md` from the stylesheet |
80
+
81
+ `lint` is the contract. Green means on-system:
82
+
83
+ ```
84
+ templates/page.html:1: unknown-class: bg-gray-100: not in the design system
85
+ templates/page.html:2: dark-variant: dark:text-white: colours carry both themes, there is no dark pass
86
+ templates/page.html:2: arbitrary-value: text-[13px]: bypasses the token scale
87
+ templates/page.html:2: inline-style: style='color: red': a decision belongs in CSS
88
+ ```
89
+
90
+ It also hashes every vendored file against what the package would produce, so a local edit to `ads.css` shows up as a finding.
91
+
92
+ ## What it does not do
93
+
94
+ - **No icon set.** The shell uses an `icon()` Jinja global if you register one; an icon set is a licence you cannot change once it is baked in. [How to wire one up.](https://ads.lab.abilian.com/getting-started/first-page/)
95
+ - **No JavaScript framework.** `shell.js` is a page of delegated event handlers with no dependencies. Components that need more (a rich data grid, a live region) are [situ](https://situ.hop3.abilian.com)'s job, and `situ.css` bridges the two palettes.
96
+ - **No CSS-in-JS, no theme builder UI, no component library for React.** This is Jinja and CSS.
97
+
98
+ ## Status
99
+
100
+ Beta. The vocabulary, the linter and the shell are stable enough to build on; the 0.x version number covers the rest. See [CHANGES.md](CHANGES.md).
101
+
102
+ ## Licence
103
+
104
+ Apache 2.0. Copyright © 2026 Abilian SAS.