eidosui 0.3.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 +369 -33
- 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.3.0.dist-info/METADATA +0 -127
- eidosui-0.3.0.dist-info/RECORD +0 -22
- {eidosui-0.3.0.dist-info → eidosui-0.5.0.dist-info}/WHEEL +0 -0
- {eidosui-0.3.0.dist-info → eidosui-0.5.0.dist-info}/licenses/LICENSE +0 -0
eidos/tags.py
CHANGED
@@ -1,99 +1,435 @@
|
|
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
|
9
|
+
__all__ = [
|
10
|
+
# Custom EidosUI components
|
11
|
+
"Button",
|
12
|
+
"H1",
|
13
|
+
"H2",
|
14
|
+
"H3",
|
15
|
+
"H4",
|
16
|
+
"H5",
|
17
|
+
"H6",
|
18
|
+
"Body",
|
19
|
+
# Semantic components with styling
|
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",
|
51
|
+
# Pass-through HTML tags from air.tags
|
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",
|
126
|
+
]
|
127
|
+
|
128
|
+
|
129
|
+
def Button(
|
130
|
+
*content: Any,
|
131
|
+
class_: str | list[str] | None = styles.buttons.primary,
|
132
|
+
**kwargs: Any,
|
133
|
+
) -> air.Tag:
|
134
|
+
"""
|
135
|
+
Args:
|
136
|
+
content: The content of the button.
|
137
|
+
class_: The class of the button.
|
138
|
+
**kwargs: Additional keyword arguments passed to the button tag.
|
139
|
+
|
140
|
+
Returns:
|
141
|
+
air.Tag: The button tag.
|
142
|
+
|
143
|
+
Example:
|
144
|
+
Button("Click me", class_=styles.buttons.primary)
|
145
|
+
"""
|
7
146
|
return air.Button(*content, class_=stringify(styles.buttons.base, class_), **kwargs)
|
8
147
|
|
9
|
-
|
148
|
+
|
149
|
+
def H1(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
150
|
+
"""
|
151
|
+
Args:
|
152
|
+
content: The content of the h1 tag.
|
153
|
+
class_: The class of the h1 tag.
|
154
|
+
**kwargs: Additional keyword arguments passed to the h1 tag.
|
155
|
+
|
156
|
+
Returns:
|
157
|
+
air.Tag: The h1 tag.
|
158
|
+
|
159
|
+
Example:
|
160
|
+
H1("Hello, world!")
|
161
|
+
"""
|
10
162
|
return air.H1(*content, class_=stringify(styles.typography.h1, class_), **kwargs)
|
11
163
|
|
12
|
-
|
164
|
+
|
165
|
+
def H2(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
166
|
+
"""
|
167
|
+
Args:
|
168
|
+
content: The content of the h2 tag.
|
169
|
+
class_: The class of the h2 tag.
|
170
|
+
**kwargs: Additional keyword arguments passed to the h2 tag.
|
171
|
+
|
172
|
+
Returns:
|
173
|
+
air.Tag: The h2 tag.
|
174
|
+
|
175
|
+
Example:
|
176
|
+
H2("Hello, world!")
|
177
|
+
"""
|
13
178
|
return air.H2(*content, class_=stringify(styles.typography.h2, class_), **kwargs)
|
14
179
|
|
15
|
-
|
180
|
+
|
181
|
+
def H3(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
182
|
+
"""
|
183
|
+
Args:
|
184
|
+
content: The content of the h3 tag.
|
185
|
+
class_: The class of the h3 tag.
|
186
|
+
**kwargs: Additional keyword arguments passed to the h3 tag.
|
187
|
+
|
188
|
+
Returns:
|
189
|
+
air.Tag: The h3 tag.
|
190
|
+
|
191
|
+
Example:
|
192
|
+
H3("Hello, world!")
|
193
|
+
"""
|
16
194
|
return air.H3(*content, class_=stringify(styles.typography.h3, class_), **kwargs)
|
17
195
|
|
18
|
-
|
196
|
+
|
197
|
+
def H4(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
19
198
|
return air.H4(*content, class_=stringify(styles.typography.h4, class_), **kwargs)
|
20
199
|
|
21
|
-
|
200
|
+
|
201
|
+
def H5(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
22
202
|
return air.H5(*content, class_=stringify(styles.typography.h5, class_), **kwargs)
|
23
203
|
|
24
|
-
|
204
|
+
|
205
|
+
def H6(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
25
206
|
return air.H6(*content, class_=stringify(styles.typography.h6, class_), **kwargs)
|
26
207
|
|
27
|
-
|
208
|
+
|
209
|
+
def Body(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
28
210
|
return air.Body(*content, class_=stringify(styles.Theme.body, class_), **kwargs)
|
29
211
|
|
212
|
+
|
30
213
|
# Semantic HTML Elements
|
31
214
|
|
32
|
-
|
215
|
+
|
216
|
+
def Strong(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
33
217
|
return air.Strong(*content, class_=stringify(styles.semantic.strong, class_), **kwargs)
|
34
218
|
|
35
|
-
|
219
|
+
|
220
|
+
def I(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
36
221
|
return air.I(*content, class_=stringify(styles.semantic.i, class_), **kwargs)
|
37
222
|
|
38
|
-
|
223
|
+
|
224
|
+
def Small(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
39
225
|
return air.Small(*content, class_=stringify(styles.semantic.small, class_), **kwargs)
|
40
226
|
|
41
|
-
|
227
|
+
|
228
|
+
def Del(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
42
229
|
return air.Del(*content, class_=stringify(styles.semantic.del_, class_), **kwargs)
|
43
230
|
|
44
|
-
|
231
|
+
|
232
|
+
def Abbr(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
233
|
+
"""
|
234
|
+
Args:
|
235
|
+
content: The content of the abbr tag.
|
236
|
+
class_: The class of the abbr tag.
|
237
|
+
**kwargs: Additional keyword arguments passed to the abbr tag.
|
238
|
+
|
239
|
+
Returns:
|
240
|
+
air.Tag: The abbr tag.
|
241
|
+
|
242
|
+
Example:
|
243
|
+
Abbr("HTML", title="Hyper Text Markup Language")
|
244
|
+
"""
|
45
245
|
return air.Abbr(*content, class_=stringify(styles.semantic.abbr, class_), **kwargs)
|
46
246
|
|
47
|
-
|
247
|
+
|
248
|
+
def Var(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
48
249
|
return air.Var(*content, class_=stringify(styles.semantic.var, class_), **kwargs)
|
49
250
|
|
50
|
-
|
251
|
+
|
252
|
+
def Mark(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
51
253
|
return air.Mark(*content, class_=stringify(styles.semantic.mark, class_), **kwargs)
|
52
254
|
|
53
|
-
|
255
|
+
|
256
|
+
def Time(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
54
257
|
return air.Time(*content, class_=stringify(styles.semantic.time, class_), **kwargs)
|
55
258
|
|
56
|
-
|
259
|
+
|
260
|
+
def Code(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
57
261
|
return air.Code(*content, class_=stringify(styles.semantic.code, class_), **kwargs)
|
58
262
|
|
59
|
-
|
263
|
+
|
264
|
+
def Pre(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
60
265
|
return air.Pre(*content, class_=stringify(styles.semantic.pre, class_), **kwargs)
|
61
266
|
|
62
|
-
|
267
|
+
|
268
|
+
def Kbd(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
63
269
|
return air.Kbd(*content, class_=stringify(styles.semantic.kbd, class_), **kwargs)
|
64
270
|
|
65
|
-
|
271
|
+
|
272
|
+
def Samp(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
66
273
|
return air.Samp(*content, class_=stringify(styles.semantic.samp, class_), **kwargs)
|
67
274
|
|
68
|
-
|
275
|
+
|
276
|
+
def Blockquote(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
69
277
|
return air.Blockquote(*content, class_=stringify(styles.semantic.blockquote, class_), **kwargs)
|
70
278
|
|
71
|
-
|
279
|
+
|
280
|
+
def Cite(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
72
281
|
return air.Cite(*content, class_=stringify(styles.semantic.cite, class_), **kwargs)
|
73
282
|
|
74
|
-
|
283
|
+
|
284
|
+
def Address(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
75
285
|
return air.Address(*content, class_=stringify(styles.semantic.address, class_), **kwargs)
|
76
286
|
|
77
|
-
|
287
|
+
|
288
|
+
def Hr(class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
78
289
|
return air.Hr(class_=stringify(styles.semantic.hr, class_), **kwargs)
|
79
290
|
|
80
|
-
|
291
|
+
|
292
|
+
def Details(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
81
293
|
return air.Details(*content, class_=stringify(styles.semantic.details, class_), **kwargs)
|
82
294
|
|
83
|
-
|
295
|
+
|
296
|
+
def Summary(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
84
297
|
return air.Summary(*content, class_=stringify(styles.semantic.summary, class_), **kwargs)
|
85
298
|
|
86
|
-
|
299
|
+
|
300
|
+
def Dl(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
87
301
|
return air.Dl(*content, class_=stringify(styles.semantic.dl, class_), **kwargs)
|
88
302
|
|
89
|
-
|
303
|
+
|
304
|
+
def Dt(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
90
305
|
return air.Dt(*content, class_=stringify(styles.semantic.dt, class_), **kwargs)
|
91
306
|
|
92
|
-
|
307
|
+
|
308
|
+
def Dd(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
93
309
|
return air.Dd(*content, class_=stringify(styles.semantic.dd, class_), **kwargs)
|
94
310
|
|
95
|
-
|
311
|
+
|
312
|
+
def Figure(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
96
313
|
return air.Figure(*content, class_=stringify(styles.semantic.figure, class_), **kwargs)
|
97
314
|
|
98
|
-
|
99
|
-
|
315
|
+
|
316
|
+
def Figcaption(*content: Any, class_: str | list[str] | None = None, **kwargs: Any) -> air.Tag:
|
317
|
+
return air.Figcaption(*content, class_=stringify(styles.semantic.figcaption, class_), **kwargs)
|
318
|
+
|
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
|
+
|
358
|
+
# Pass-through tags from air.tags
|
359
|
+
# Import all standard HTML tags that don't have custom styling
|
360
|
+
from air.tags import (
|
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
|