eidosui 0.4.0__py3-none-any.whl → 0.5.0__py3-none-any.whl
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.
- eidos/__init__.py +270 -0
- eidos/components/__init__.py +10 -0
- eidos/components/headers.py +16 -14
- eidos/components/navigation.py +44 -35
- eidos/components/table.py +84 -0
- eidos/css/styles.css +48 -0
- eidos/plugins/__init__.py +1 -1
- eidos/plugins/markdown/__init__.py +3 -3
- eidos/plugins/markdown/components.py +10 -22
- eidos/plugins/markdown/extensions/__init__.py +1 -1
- eidos/plugins/markdown/extensions/alerts.py +68 -78
- eidos/plugins/markdown/renderer.py +19 -24
- eidos/styles.py +33 -9
- eidos/tags.py +296 -55
- eidos/utils.py +42 -38
- eidosui-0.5.0.dist-info/METADATA +113 -0
- eidosui-0.5.0.dist-info/RECORD +24 -0
- eidosui-0.4.0.dist-info/METADATA +0 -127
- eidosui-0.4.0.dist-info/RECORD +0 -22
- {eidosui-0.4.0.dist-info → eidosui-0.5.0.dist-info}/WHEEL +0 -0
- {eidosui-0.4.0.dist-info → eidosui-0.5.0.dist-info}/licenses/LICENSE +0 -0
eidos/tags.py
CHANGED
@@ -1,29 +1,136 @@
|
|
1
|
-
from typing import
|
1
|
+
from typing import Any
|
2
|
+
|
2
3
|
import air
|
4
|
+
|
3
5
|
from . import styles
|
4
6
|
from .utils import stringify
|
5
7
|
|
6
8
|
# Define exports for this module
|
7
9
|
__all__ = [
|
8
10
|
# Custom EidosUI components
|
9
|
-
|
11
|
+
"Button",
|
12
|
+
"H1",
|
13
|
+
"H2",
|
14
|
+
"H3",
|
15
|
+
"H4",
|
16
|
+
"H5",
|
17
|
+
"H6",
|
18
|
+
"Body",
|
10
19
|
# Semantic components with styling
|
11
|
-
|
12
|
-
|
13
|
-
|
20
|
+
"Strong",
|
21
|
+
"I",
|
22
|
+
"Small",
|
23
|
+
"Del",
|
24
|
+
"Abbr",
|
25
|
+
"Var",
|
26
|
+
"Mark",
|
27
|
+
"Time",
|
28
|
+
"Code",
|
29
|
+
"Pre",
|
30
|
+
"Kbd",
|
31
|
+
"Samp",
|
32
|
+
"Blockquote",
|
33
|
+
"Cite",
|
34
|
+
"Address",
|
35
|
+
"Hr",
|
36
|
+
"Details",
|
37
|
+
"Summary",
|
38
|
+
"Dl",
|
39
|
+
"Dt",
|
40
|
+
"Dd",
|
41
|
+
"Figure",
|
42
|
+
"Figcaption",
|
43
|
+
# Table components with styling
|
44
|
+
"Table",
|
45
|
+
"Thead",
|
46
|
+
"Tbody",
|
47
|
+
"Tfoot",
|
48
|
+
"Tr",
|
49
|
+
"Th",
|
50
|
+
"Td",
|
14
51
|
# Pass-through HTML tags from air.tags
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
52
|
+
"A",
|
53
|
+
"Area",
|
54
|
+
"Article",
|
55
|
+
"Aside",
|
56
|
+
"Audio",
|
57
|
+
"B",
|
58
|
+
"Base",
|
59
|
+
"Bdi",
|
60
|
+
"Bdo",
|
61
|
+
"Br",
|
62
|
+
"Canvas",
|
63
|
+
"Caption",
|
64
|
+
"Col",
|
65
|
+
"Colgroup",
|
66
|
+
"Data",
|
67
|
+
"Datalist",
|
68
|
+
"Dfn",
|
69
|
+
"Dialog",
|
70
|
+
"Div",
|
71
|
+
"Em",
|
72
|
+
"Embed",
|
73
|
+
"Fieldset",
|
74
|
+
"Footer",
|
75
|
+
"Form",
|
76
|
+
"Head",
|
77
|
+
"Header",
|
78
|
+
"Hgroup",
|
79
|
+
"Html",
|
80
|
+
"Iframe",
|
81
|
+
"Img",
|
82
|
+
"Input",
|
83
|
+
"Ins",
|
84
|
+
"Label",
|
85
|
+
"Legend",
|
86
|
+
"Li",
|
87
|
+
"Link",
|
88
|
+
"Main",
|
89
|
+
"Map",
|
90
|
+
"Menu",
|
91
|
+
"Meta",
|
92
|
+
"Meter",
|
93
|
+
"Nav",
|
94
|
+
"Noscript",
|
95
|
+
"Object",
|
96
|
+
"Ol",
|
97
|
+
"Optgroup",
|
98
|
+
"Option",
|
99
|
+
"Output",
|
100
|
+
"P",
|
101
|
+
"Param",
|
102
|
+
"Picture",
|
103
|
+
"Progress",
|
104
|
+
"Q",
|
105
|
+
"Rp",
|
106
|
+
"Rt",
|
107
|
+
"Ruby",
|
108
|
+
"S",
|
109
|
+
"Script",
|
110
|
+
"Search",
|
111
|
+
"Section",
|
112
|
+
"Select",
|
113
|
+
"Source",
|
114
|
+
"Span",
|
115
|
+
"Style",
|
116
|
+
"Sub",
|
117
|
+
"Sup",
|
118
|
+
"Template",
|
119
|
+
"Textarea",
|
120
|
+
"Title",
|
121
|
+
"Track",
|
122
|
+
"U",
|
123
|
+
"Ul",
|
124
|
+
"Video",
|
125
|
+
"Wbr",
|
24
126
|
]
|
25
127
|
|
26
|
-
|
128
|
+
|
129
|
+
def Button(
|
130
|
+
*content: Any,
|
131
|
+
class_: str | list[str] | None = styles.buttons.primary,
|
132
|
+
**kwargs: Any,
|
133
|
+
) -> air.Tag:
|
27
134
|
"""
|
28
135
|
Args:
|
29
136
|
content: The content of the button.
|
@@ -38,7 +145,8 @@ def Button(*content: Any, class_: Optional[Union[str, list[str]]] = styles.butto
|
|
38
145
|
"""
|
39
146
|
return air.Button(*content, class_=stringify(styles.buttons.base, class_), **kwargs)
|
40
147
|
|
41
|
-
|
148
|
+
|
149
|
+
def H1(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
42
150
|
"""
|
43
151
|
Args:
|
44
152
|
content: The content of the h1 tag.
|
@@ -53,7 +161,8 @@ def H1(*content: Any, class_: Optional[Union[str, list[str]]] = None, **kwargs:
|
|
53
161
|
"""
|
54
162
|
return air.H1(*content, class_=stringify(styles.typography.h1, class_), **kwargs)
|
55
163
|
|
56
|
-
|
164
|
+
|
165
|
+
def H2(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
57
166
|
"""
|
58
167
|
Args:
|
59
168
|
content: The content of the h2 tag.
|
@@ -68,7 +177,8 @@ def H2(*content: Any, class_: Optional[Union[str, list[str]]] = None, **kwargs:
|
|
68
177
|
"""
|
69
178
|
return air.H2(*content, class_=stringify(styles.typography.h2, class_), **kwargs)
|
70
179
|
|
71
|
-
|
180
|
+
|
181
|
+
def H3(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
72
182
|
"""
|
73
183
|
Args:
|
74
184
|
content: The content of the h3 tag.
|
@@ -83,33 +193,43 @@ def H3(*content: Any, class_: Optional[Union[str, list[str]]] = None, **kwargs:
|
|
83
193
|
"""
|
84
194
|
return air.H3(*content, class_=stringify(styles.typography.h3, class_), **kwargs)
|
85
195
|
|
86
|
-
|
196
|
+
|
197
|
+
def H4(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
87
198
|
return air.H4(*content, class_=stringify(styles.typography.h4, class_), **kwargs)
|
88
199
|
|
89
|
-
|
200
|
+
|
201
|
+
def H5(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
90
202
|
return air.H5(*content, class_=stringify(styles.typography.h5, class_), **kwargs)
|
91
203
|
|
92
|
-
|
204
|
+
|
205
|
+
def H6(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
93
206
|
return air.H6(*content, class_=stringify(styles.typography.h6, class_), **kwargs)
|
94
207
|
|
95
|
-
|
208
|
+
|
209
|
+
def Body(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
96
210
|
return air.Body(*content, class_=stringify(styles.Theme.body, class_), **kwargs)
|
97
211
|
|
212
|
+
|
98
213
|
# Semantic HTML Elements
|
99
214
|
|
100
|
-
|
215
|
+
|
216
|
+
def Strong(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
101
217
|
return air.Strong(*content, class_=stringify(styles.semantic.strong, class_), **kwargs)
|
102
218
|
|
103
|
-
|
219
|
+
|
220
|
+
def I(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
104
221
|
return air.I(*content, class_=stringify(styles.semantic.i, class_), **kwargs)
|
105
222
|
|
106
|
-
|
223
|
+
|
224
|
+
def Small(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
107
225
|
return air.Small(*content, class_=stringify(styles.semantic.small, class_), **kwargs)
|
108
226
|
|
109
|
-
|
227
|
+
|
228
|
+
def Del(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
110
229
|
return air.Del(*content, class_=stringify(styles.semantic.del_, class_), **kwargs)
|
111
230
|
|
112
|
-
|
231
|
+
|
232
|
+
def Abbr(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
113
233
|
"""
|
114
234
|
Args:
|
115
235
|
content: The content of the abbr tag.
|
@@ -124,71 +244,192 @@ def Abbr(*content: Any, class_: Optional[Union[str, list[str]]] = None, **kwargs
|
|
124
244
|
"""
|
125
245
|
return air.Abbr(*content, class_=stringify(styles.semantic.abbr, class_), **kwargs)
|
126
246
|
|
127
|
-
|
247
|
+
|
248
|
+
def Var(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
128
249
|
return air.Var(*content, class_=stringify(styles.semantic.var, class_), **kwargs)
|
129
250
|
|
130
|
-
|
251
|
+
|
252
|
+
def Mark(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
131
253
|
return air.Mark(*content, class_=stringify(styles.semantic.mark, class_), **kwargs)
|
132
254
|
|
133
|
-
|
255
|
+
|
256
|
+
def Time(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
134
257
|
return air.Time(*content, class_=stringify(styles.semantic.time, class_), **kwargs)
|
135
258
|
|
136
|
-
|
259
|
+
|
260
|
+
def Code(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
137
261
|
return air.Code(*content, class_=stringify(styles.semantic.code, class_), **kwargs)
|
138
262
|
|
139
|
-
|
263
|
+
|
264
|
+
def Pre(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
140
265
|
return air.Pre(*content, class_=stringify(styles.semantic.pre, class_), **kwargs)
|
141
266
|
|
142
|
-
|
267
|
+
|
268
|
+
def Kbd(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
143
269
|
return air.Kbd(*content, class_=stringify(styles.semantic.kbd, class_), **kwargs)
|
144
270
|
|
145
|
-
|
271
|
+
|
272
|
+
def Samp(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
146
273
|
return air.Samp(*content, class_=stringify(styles.semantic.samp, class_), **kwargs)
|
147
274
|
|
148
|
-
|
275
|
+
|
276
|
+
def Blockquote(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
149
277
|
return air.Blockquote(*content, class_=stringify(styles.semantic.blockquote, class_), **kwargs)
|
150
278
|
|
151
|
-
|
279
|
+
|
280
|
+
def Cite(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
152
281
|
return air.Cite(*content, class_=stringify(styles.semantic.cite, class_), **kwargs)
|
153
282
|
|
154
|
-
|
283
|
+
|
284
|
+
def Address(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
155
285
|
return air.Address(*content, class_=stringify(styles.semantic.address, class_), **kwargs)
|
156
286
|
|
157
|
-
|
287
|
+
|
288
|
+
def Hr(class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
158
289
|
return air.Hr(class_=stringify(styles.semantic.hr, class_), **kwargs)
|
159
290
|
|
160
|
-
|
291
|
+
|
292
|
+
def Details(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
161
293
|
return air.Details(*content, class_=stringify(styles.semantic.details, class_), **kwargs)
|
162
294
|
|
163
|
-
|
295
|
+
|
296
|
+
def Summary(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
164
297
|
return air.Summary(*content, class_=stringify(styles.semantic.summary, class_), **kwargs)
|
165
298
|
|
166
|
-
|
299
|
+
|
300
|
+
def Dl(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
167
301
|
return air.Dl(*content, class_=stringify(styles.semantic.dl, class_), **kwargs)
|
168
302
|
|
169
|
-
|
303
|
+
|
304
|
+
def Dt(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
170
305
|
return air.Dt(*content, class_=stringify(styles.semantic.dt, class_), **kwargs)
|
171
306
|
|
172
|
-
|
307
|
+
|
308
|
+
def Dd(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
173
309
|
return air.Dd(*content, class_=stringify(styles.semantic.dd, class_), **kwargs)
|
174
310
|
|
175
|
-
|
311
|
+
|
312
|
+
def Figure(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
176
313
|
return air.Figure(*content, class_=stringify(styles.semantic.figure, class_), **kwargs)
|
177
314
|
|
178
|
-
|
315
|
+
|
316
|
+
def Figcaption(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
179
317
|
return air.Figcaption(*content, class_=stringify(styles.semantic.figcaption, class_), **kwargs)
|
180
318
|
|
181
319
|
|
320
|
+
# Table elements with styling
|
321
|
+
|
322
|
+
|
323
|
+
def Table(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
324
|
+
"""Styled table element."""
|
325
|
+
return air.Table(*content, class_=stringify(styles.tables.table, class_), **kwargs)
|
326
|
+
|
327
|
+
|
328
|
+
def Thead(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
329
|
+
"""Styled table head element."""
|
330
|
+
return air.Thead(*content, class_=stringify(styles.tables.thead, class_), **kwargs)
|
331
|
+
|
332
|
+
|
333
|
+
def Tbody(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
334
|
+
"""Styled table body element."""
|
335
|
+
return air.Tbody(*content, class_=stringify(styles.tables.tbody, class_), **kwargs)
|
336
|
+
|
337
|
+
|
338
|
+
def Tfoot(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
339
|
+
"""Styled table footer element."""
|
340
|
+
return air.Tfoot(*content, class_=stringify(styles.tables.tfoot, class_), **kwargs)
|
341
|
+
|
342
|
+
|
343
|
+
def Tr(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
344
|
+
"""Styled table row element."""
|
345
|
+
return air.Tr(*content, class_=stringify(styles.tables.tr, class_), **kwargs)
|
346
|
+
|
347
|
+
|
348
|
+
def Th(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
349
|
+
"""Styled table header cell element."""
|
350
|
+
return air.Th(*content, class_=stringify(styles.tables.th, class_), **kwargs)
|
351
|
+
|
352
|
+
|
353
|
+
def Td(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
354
|
+
"""Styled table data cell element."""
|
355
|
+
return air.Td(*content, class_=stringify(styles.tables.td, class_), **kwargs)
|
356
|
+
|
357
|
+
|
182
358
|
# Pass-through tags from air.tags
|
183
359
|
# Import all standard HTML tags that don't have custom styling
|
184
360
|
from air.tags import (
|
185
|
-
A,
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
361
|
+
A,
|
362
|
+
Area,
|
363
|
+
Article,
|
364
|
+
Aside,
|
365
|
+
Audio,
|
366
|
+
B,
|
367
|
+
Base,
|
368
|
+
Bdi,
|
369
|
+
Bdo,
|
370
|
+
Br,
|
371
|
+
Canvas,
|
372
|
+
Caption,
|
373
|
+
Col,
|
374
|
+
Colgroup,
|
375
|
+
Data,
|
376
|
+
Datalist,
|
377
|
+
Dfn,
|
378
|
+
Dialog,
|
379
|
+
Div,
|
380
|
+
Em,
|
381
|
+
Embed,
|
382
|
+
Fieldset,
|
383
|
+
Footer,
|
384
|
+
Form,
|
385
|
+
Head,
|
386
|
+
Header,
|
387
|
+
Hgroup,
|
388
|
+
Html,
|
389
|
+
Iframe,
|
390
|
+
Img,
|
391
|
+
Input,
|
392
|
+
Ins,
|
393
|
+
Label,
|
394
|
+
Legend,
|
395
|
+
Li,
|
396
|
+
Link,
|
397
|
+
Main,
|
398
|
+
Map,
|
399
|
+
Menu,
|
400
|
+
Meta,
|
401
|
+
Meter,
|
402
|
+
Nav,
|
403
|
+
Noscript,
|
404
|
+
Object,
|
405
|
+
Ol,
|
406
|
+
Optgroup,
|
407
|
+
Option,
|
408
|
+
Output,
|
409
|
+
P,
|
410
|
+
Param,
|
411
|
+
Picture,
|
412
|
+
Progress,
|
413
|
+
Q,
|
414
|
+
Rp,
|
415
|
+
Rt,
|
416
|
+
Ruby,
|
417
|
+
S,
|
418
|
+
Script,
|
419
|
+
Search,
|
420
|
+
Section,
|
421
|
+
Select,
|
422
|
+
Source,
|
423
|
+
Span,
|
424
|
+
Style,
|
425
|
+
Sub,
|
426
|
+
Sup,
|
427
|
+
Template,
|
428
|
+
Textarea,
|
429
|
+
Title,
|
430
|
+
Track,
|
431
|
+
U,
|
432
|
+
Ul,
|
433
|
+
Video,
|
434
|
+
Wbr,
|
435
|
+
)
|
eidos/utils.py
CHANGED
@@ -1,32 +1,30 @@
|
|
1
1
|
"""Core utility functions for EidosUI."""
|
2
2
|
|
3
|
-
from
|
4
|
-
import os
|
5
|
-
import sys
|
3
|
+
from pathlib import Path
|
6
4
|
|
7
5
|
|
8
|
-
def stringify(*classes:
|
6
|
+
def stringify(*classes: str | list[str] | None) -> str:
|
9
7
|
"""
|
10
8
|
Concatenate CSS classes, filtering out None values and flattening lists.
|
11
|
-
|
9
|
+
|
12
10
|
Args:
|
13
11
|
*classes: Variable number of class strings, lists of strings, or None values
|
14
|
-
|
12
|
+
|
15
13
|
Returns:
|
16
14
|
A single space-separated string of CSS classes
|
17
|
-
|
15
|
+
|
18
16
|
Examples:
|
19
17
|
>>> stringify("btn", "btn-primary")
|
20
18
|
"btn btn-primary"
|
21
|
-
|
19
|
+
|
22
20
|
>>> stringify("btn", None, "btn-lg")
|
23
21
|
"btn btn-lg"
|
24
|
-
|
22
|
+
|
25
23
|
>>> stringify(["btn", "btn-primary"], "mt-4")
|
26
24
|
"btn btn-primary mt-4"
|
27
25
|
"""
|
28
|
-
result = []
|
29
|
-
|
26
|
+
result: list[str] = []
|
27
|
+
|
30
28
|
for class_ in classes:
|
31
29
|
if class_ is None:
|
32
30
|
continue
|
@@ -35,38 +33,44 @@ def stringify(*classes: Optional[Union[str, List[str]]]) -> str:
|
|
35
33
|
result.extend(c for c in class_ if c)
|
36
34
|
elif isinstance(class_, str) and class_.strip():
|
37
35
|
result.append(class_.strip())
|
38
|
-
|
36
|
+
|
39
37
|
return " ".join(result)
|
40
38
|
|
41
39
|
|
42
|
-
def
|
40
|
+
def get_eidos_static_files(markdown: bool = False) -> dict:
|
43
41
|
"""
|
44
|
-
Get
|
45
|
-
|
46
|
-
This
|
47
|
-
|
48
|
-
|
49
|
-
|
42
|
+
Get a dictionary mapping URL paths to static file directories.
|
43
|
+
|
44
|
+
This provides a safe way to mount only specific static assets
|
45
|
+
without exposing Python source files.
|
46
|
+
|
47
|
+
Args:
|
48
|
+
markdown: Whether to include markdown plugin CSS (default: False)
|
49
|
+
|
50
50
|
Returns:
|
51
|
-
|
52
|
-
|
51
|
+
Dict mapping mount paths to directory paths
|
52
|
+
|
53
53
|
Example:
|
54
54
|
>>> from fastapi.staticfiles import StaticFiles
|
55
|
-
>>> from eidos.utils import
|
56
|
-
>>>
|
55
|
+
>>> from eidos.utils import get_eidos_static_files
|
56
|
+
>>> # Basic usage - just core CSS and JS
|
57
|
+
>>> for mount_path, directory in get_eidos_static_files().items():
|
58
|
+
... app.mount(mount_path, StaticFiles(directory=directory), name=mount_path.strip('/'))
|
59
|
+
>>>
|
60
|
+
>>> # Include markdown CSS
|
61
|
+
>>> for mount_path, directory in get_eidos_static_files(markdown=True).items():
|
62
|
+
... app.mount(mount_path, StaticFiles(directory=directory), name=mount_path.strip('/'))
|
57
63
|
"""
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
# Fallback for development or if importlib.resources fails
|
72
|
-
return os.path.dirname(os.path.abspath(__file__))
|
64
|
+
# Use pathlib for cleaner path handling
|
65
|
+
base_path = Path(__file__).parent.absolute()
|
66
|
+
|
67
|
+
static_files = {
|
68
|
+
"/eidos/css": str(base_path / "css"),
|
69
|
+
"/eidos/js": str(base_path / "js"),
|
70
|
+
}
|
71
|
+
|
72
|
+
# Only include markdown CSS if requested
|
73
|
+
if markdown:
|
74
|
+
static_files["/eidos/plugins/markdown/css"] = str(base_path / "plugins" / "markdown" / "css")
|
75
|
+
|
76
|
+
return static_files
|
@@ -0,0 +1,113 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: eidosui
|
3
|
+
Version: 0.5.0
|
4
|
+
Summary: A modern, Tailwind CSS-based UI library for air development
|
5
|
+
Project-URL: Homepage, https://github.com/isaac-flath/EidosUI
|
6
|
+
Project-URL: Repository, https://github.com/isaac-flath/EidosUI
|
7
|
+
Project-URL: Issues, https://github.com/isaac-flath/EidosUI/issues
|
8
|
+
Project-URL: Documentation, https://github.com/isaac-flath/EidosUI#readme
|
9
|
+
Author: Isaac Flath
|
10
|
+
License-Expression: MIT
|
11
|
+
License-File: LICENSE
|
12
|
+
Keywords: air,components,css,fastapi,tailwind,ui,web
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
14
|
+
Classifier: Intended Audience :: Developers
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
21
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
23
|
+
Requires-Python: >=3.10
|
24
|
+
Requires-Dist: air>=0.12
|
25
|
+
Requires-Dist: fastapi[standard]
|
26
|
+
Requires-Dist: uvicorn
|
27
|
+
Provides-Extra: dev
|
28
|
+
Requires-Dist: black; extra == 'dev'
|
29
|
+
Requires-Dist: isort; extra == 'dev'
|
30
|
+
Requires-Dist: mypy; extra == 'dev'
|
31
|
+
Requires-Dist: pytest; extra == 'dev'
|
32
|
+
Requires-Dist: ruff; extra == 'dev'
|
33
|
+
Provides-Extra: markdown
|
34
|
+
Requires-Dist: markdown>=3.4; extra == 'markdown'
|
35
|
+
Description-Content-Type: text/markdown
|
36
|
+
|
37
|
+
# EidosUI
|
38
|
+
|
39
|
+
Modern UI library for Python web frameworks. Built on Air and Tailwind CSS.
|
40
|
+
|
41
|
+
> [!CAUTION]
|
42
|
+
> This library is in alpha, and may have semi-frequent breaking changes. I'd love for you to try it an contribute feedback or PRs!
|
43
|
+
|
44
|
+
## Installation
|
45
|
+
|
46
|
+
```bash
|
47
|
+
pip install eidosui
|
48
|
+
```
|
49
|
+
|
50
|
+
## Quick Start
|
51
|
+
|
52
|
+
```python
|
53
|
+
from eidos import *
|
54
|
+
import air
|
55
|
+
|
56
|
+
app = air.Air()
|
57
|
+
|
58
|
+
@app.get("/")
|
59
|
+
def home():
|
60
|
+
return Html(
|
61
|
+
Head(
|
62
|
+
Title("My App"),
|
63
|
+
*EidosHeaders() # Required CSS/JS
|
64
|
+
),
|
65
|
+
Body(
|
66
|
+
H1("Welcome"),
|
67
|
+
P("Build modern web apps with Python."),
|
68
|
+
DataTable.from_lists(
|
69
|
+
[["Alice", "30"], ["Bob", "25"]],
|
70
|
+
headers=["Name", "Age"]
|
71
|
+
)
|
72
|
+
)
|
73
|
+
)
|
74
|
+
|
75
|
+
app.run()
|
76
|
+
```
|
77
|
+
|
78
|
+
## Features
|
79
|
+
|
80
|
+
- **Styled HTML tags** - Pre-styled versions of all HTML elements
|
81
|
+
- **Components** - DataTable, NavBar, and more
|
82
|
+
- **Themes** - Light/dark themes via CSS variables
|
83
|
+
- **Type hints** - Full type annotations
|
84
|
+
- **Air integration** - Works seamlessly with Air framework
|
85
|
+
|
86
|
+
## Plugins
|
87
|
+
|
88
|
+
### Markdown
|
89
|
+
|
90
|
+
```bash
|
91
|
+
pip install "eidosui[markdown]"
|
92
|
+
```
|
93
|
+
|
94
|
+
```python
|
95
|
+
from eidos.plugins.markdown import Markdown, MarkdownCSS
|
96
|
+
|
97
|
+
Head(
|
98
|
+
*EidosHeaders(),
|
99
|
+
MarkdownCSS() # Add markdown styles
|
100
|
+
)
|
101
|
+
|
102
|
+
Body(
|
103
|
+
Markdown("# Hello\n\nSupports **GitHub Flavored Markdown**")
|
104
|
+
)
|
105
|
+
```
|
106
|
+
|
107
|
+
## Documentation
|
108
|
+
|
109
|
+
Full documentation: https://eidosui.readthedocs.io
|
110
|
+
|
111
|
+
## License
|
112
|
+
|
113
|
+
MIT
|