python-fasthtml 0.0.11__tar.gz → 0.0.14__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.
- {python-fasthtml-0.0.11/python_fasthtml.egg-info → python-fasthtml-0.0.14}/PKG-INFO +2 -1
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/fasthtml/__init__.py +1 -1
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/fasthtml/_modidx.py +4 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/fasthtml/all.py +3 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/fasthtml/components.py +35 -8
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/fasthtml/core.py +17 -5
- python-fasthtml-0.0.14/fasthtml/js.py +48 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/fasthtml/xtend.py +21 -1
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14/python_fasthtml.egg-info}/PKG-INFO +2 -1
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/python_fasthtml.egg-info/requires.txt +1 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/settings.ini +2 -2
- python-fasthtml-0.0.11/fasthtml/js.py +0 -29
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/LICENSE +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/MANIFEST.in +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/README.md +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/fasthtml/authmw.py +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/fasthtml/cli.py +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/fasthtml/components.pyi +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/fasthtml/fastapp.py +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/fasthtml/live_reload.py +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/fasthtml/oauth.py +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/fasthtml/starlette.py +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/fasthtml/xtend.pyi +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/python_fasthtml.egg-info/SOURCES.txt +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/python_fasthtml.egg-info/dependency_links.txt +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/python_fasthtml.egg-info/entry_points.txt +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/python_fasthtml.egg-info/not-zip-safe +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/python_fasthtml.egg-info/top_level.txt +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/setup.cfg +0 -0
- {python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-fasthtml
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.14
|
|
4
4
|
Summary: The fastest way to create an HTML app
|
|
5
5
|
Home-page: https://github.com/AnswerDotAI/fasthtml
|
|
6
6
|
Author: Jeremy Howard
|
|
@@ -24,6 +24,7 @@ Requires-Dist: uvicorn[standard]
|
|
|
24
24
|
Requires-Dist: httpx
|
|
25
25
|
Requires-Dist: fastlite>=0.0.6
|
|
26
26
|
Requires-Dist: python-multipart
|
|
27
|
+
Requires-Dist: beautifulsoup4
|
|
27
28
|
Provides-Extra: dev
|
|
28
29
|
Requires-Dist: ipython; extra == "dev"
|
|
29
30
|
Requires-Dist: lxml; extra == "dev"
|
|
@@ -13,6 +13,7 @@ d = { 'settings': { 'branch': 'main',
|
|
|
13
13
|
'fasthtml.components.fill_dataclass': ('components.html#fill_dataclass', 'fasthtml/components.py'),
|
|
14
14
|
'fasthtml.components.fill_form': ('components.html#fill_form', 'fasthtml/components.py'),
|
|
15
15
|
'fasthtml.components.find_inputs': ('components.html#find_inputs', 'fasthtml/components.py'),
|
|
16
|
+
'fasthtml.components.html2xt': ('components.html#html2xt', 'fasthtml/components.py'),
|
|
16
17
|
'fasthtml.components.show': ('components.html#show', 'fasthtml/components.py'),
|
|
17
18
|
'fasthtml.components.xt_html': ('components.html#xt_html', 'fasthtml/components.py'),
|
|
18
19
|
'fasthtml.components.xt_hx': ('components.html#xt_hx', 'fasthtml/components.py')},
|
|
@@ -43,5 +44,8 @@ d = { 'settings': { 'branch': 'main',
|
|
|
43
44
|
'fasthtml.xtend.Group': ('xtend.html#group', 'fasthtml/xtend.py'),
|
|
44
45
|
'fasthtml.xtend.Hidden': ('xtend.html#hidden', 'fasthtml/xtend.py'),
|
|
45
46
|
'fasthtml.xtend.Html': ('xtend.html#html', 'fasthtml/xtend.py'),
|
|
47
|
+
'fasthtml.xtend.Script': ('xtend.html#script', 'fasthtml/xtend.py'),
|
|
46
48
|
'fasthtml.xtend.Search': ('xtend.html#search', 'fasthtml/xtend.py'),
|
|
49
|
+
'fasthtml.xtend.Style': ('xtend.html#style', 'fasthtml/xtend.py'),
|
|
50
|
+
'fasthtml.xtend.jsd': ('xtend.html#jsd', 'fasthtml/xtend.py'),
|
|
47
51
|
'fasthtml.xtend.set_pico_cls': ('xtend.html#set_pico_cls', 'fasthtml/xtend.py')}}}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/01_components.ipynb.
|
|
2
2
|
|
|
3
3
|
# %% auto 0
|
|
4
|
-
__all__ = ['named', 'html_attrs', 'hx_attrs', 'show', 'xt_html', 'xt_hx', 'fill_form', 'fill_dataclass', 'find_inputs', '
|
|
5
|
-
'Head', 'Title', 'Meta', 'Link', 'Style', 'Body', 'Pre', 'Code', 'Div', 'Span', 'P', 'H1', 'H2',
|
|
6
|
-
'H5', 'H6', 'Strong', 'Em', 'B', 'I', 'U', 'S', 'Strike', 'Sub', 'Sup', 'Hr', 'Br', 'Img', 'Nav',
|
|
7
|
-
'Li', 'Dl', 'Dt', 'Dd', 'Table', 'Thead', 'Tbody', 'Tfoot', 'Tr', 'Th', 'Td', 'Caption', 'Col',
|
|
8
|
-
'Form', 'Input', 'Textarea', 'Button', 'Select', 'Option', 'Label', 'Fieldset', 'Legend',
|
|
9
|
-
'Dialog', 'Summary', 'Main', 'Header', 'Footer', 'Section', 'Article', 'Aside', 'Figure',
|
|
10
|
-
'Mark', 'Small', 'Iframe', 'Object', 'Embed', 'Param', 'Video', 'Audio', 'Source', 'Canvas',
|
|
11
|
-
'Script', 'Noscript', 'Template', 'Slot']
|
|
4
|
+
__all__ = ['named', 'html_attrs', 'hx_attrs', 'show', 'xt_html', 'xt_hx', 'fill_form', 'fill_dataclass', 'find_inputs', 'html2xt',
|
|
5
|
+
'Html', 'Head', 'Title', 'Meta', 'Link', 'Style', 'Body', 'Pre', 'Code', 'Div', 'Span', 'P', 'H1', 'H2',
|
|
6
|
+
'H3', 'H4', 'H5', 'H6', 'Strong', 'Em', 'B', 'I', 'U', 'S', 'Strike', 'Sub', 'Sup', 'Hr', 'Br', 'Img', 'Nav',
|
|
7
|
+
'Ul', 'Ol', 'Li', 'Dl', 'Dt', 'Dd', 'Table', 'Thead', 'Tbody', 'Tfoot', 'Tr', 'Th', 'Td', 'Caption', 'Col',
|
|
8
|
+
'Colgroup', 'Form', 'Input', 'Textarea', 'Button', 'Select', 'Option', 'Label', 'Fieldset', 'Legend',
|
|
9
|
+
'Details', 'Dialog', 'Summary', 'Main', 'Header', 'Footer', 'Section', 'Article', 'Aside', 'Figure',
|
|
10
|
+
'Figcaption', 'Mark', 'Small', 'Iframe', 'Object', 'Embed', 'Param', 'Video', 'Audio', 'Source', 'Canvas',
|
|
11
|
+
'Svg', 'Math', 'Script', 'Noscript', 'Template', 'Slot']
|
|
12
12
|
|
|
13
13
|
# %% ../nbs/01_components.ipynb 2
|
|
14
14
|
from dataclasses import dataclass, asdict, is_dataclass, make_dataclass, replace, astuple, MISSING
|
|
15
15
|
|
|
16
|
+
from bs4 import BeautifulSoup
|
|
17
|
+
|
|
16
18
|
from fastcore.utils import *
|
|
17
19
|
from fastcore.xml import *
|
|
18
20
|
from fastcore.meta import use_kwargs, delegates
|
|
@@ -105,3 +107,28 @@ def __getattr__(tag):
|
|
|
105
107
|
if tag.startswith('_') or tag[0].islower(): raise AttributeError
|
|
106
108
|
def _f(*c, target_id=None, **kwargs): return xt_hx(tag, *c, target_id=target_id, **kwargs)
|
|
107
109
|
return _f
|
|
110
|
+
|
|
111
|
+
# %% ../nbs/01_components.ipynb 22
|
|
112
|
+
def html2xt(html):
|
|
113
|
+
rev_map = {'class': 'cls', 'for': 'fr'}
|
|
114
|
+
|
|
115
|
+
def _parse(elm, lvl=0):
|
|
116
|
+
if isinstance(elm, str): return repr(elm.strip()) if elm.strip() else ''
|
|
117
|
+
if isinstance(elm, list): return '\n'.join(_parse(o, lvl) for o in elm)
|
|
118
|
+
tag_name = elm.name.capitalize()
|
|
119
|
+
if tag_name=='[document]': return _parse(list(elm.children), lvl)
|
|
120
|
+
cts = elm.contents
|
|
121
|
+
cs = [repr(c.strip()) if isinstance(c, str) else _parse(c, lvl+1)
|
|
122
|
+
for c in cts if str(c).strip()]
|
|
123
|
+
attrs = []
|
|
124
|
+
for key, value in elm.attrs.items():
|
|
125
|
+
if isinstance(value,(tuple,list)): value = " ".join(value)
|
|
126
|
+
attrs.append(f'{rev_map.get(key, key)}={value!r}')
|
|
127
|
+
spc = " "*lvl*2
|
|
128
|
+
onlychild = not cts or (len(cts)==1 and isinstance(cts[0],str))
|
|
129
|
+
j = ', ' if onlychild else f',\n{spc}'
|
|
130
|
+
inner = j.join(filter(None, cs+attrs))
|
|
131
|
+
if onlychild: return f'{tag_name}({inner})'
|
|
132
|
+
return f'{tag_name}(\n{spc}{inner}\n{" "*(lvl-1)*2})'
|
|
133
|
+
|
|
134
|
+
return _parse(BeautifulSoup(html.strip(), 'html.parser'), 1)
|
|
@@ -2,6 +2,7 @@ import json,dateutil,uuid,inspect
|
|
|
2
2
|
|
|
3
3
|
from fastcore.utils import *
|
|
4
4
|
from fastcore.xml import *
|
|
5
|
+
from fasthtml.xtend import *
|
|
5
6
|
|
|
6
7
|
from types import UnionType, SimpleNamespace as ns
|
|
7
8
|
from typing import Optional, get_type_hints, get_args, get_origin, Union, Mapping, TypedDict, List
|
|
@@ -13,6 +14,7 @@ from functools import wraps, partialmethod
|
|
|
13
14
|
|
|
14
15
|
from .starlette import *
|
|
15
16
|
|
|
17
|
+
__all__ = "is_typeddict is_namedtuple date snake2hyphens htmx_hdrs HtmxHeaders str2int HttpHeader form2dict RouteX RouterX FastHTML htmx_hdrs reg_re_param MiddlewareBase Beforeware get_key".split()
|
|
16
18
|
|
|
17
19
|
empty = Parameter.empty
|
|
18
20
|
|
|
@@ -124,7 +126,6 @@ async def _find_p(req, arg:str, p):
|
|
|
124
126
|
if res is empty or res is None: res = req.headers.get(snake2hyphens(arg), None)
|
|
125
127
|
if res is empty or res is None: res = nested_idx(req.scope, 'session', arg) or None
|
|
126
128
|
if res is empty or res is None:
|
|
127
|
-
#import pdb; pdb.set_trace()
|
|
128
129
|
frm = await req.form()
|
|
129
130
|
res = frm.getlist(arg)
|
|
130
131
|
if res:
|
|
@@ -141,12 +142,20 @@ async def _wrap_req(req, params):
|
|
|
141
142
|
@dataclass
|
|
142
143
|
class HttpHeader: k:str;v:str
|
|
143
144
|
|
|
145
|
+
def flat_xt(lst):
|
|
146
|
+
result = []
|
|
147
|
+
for item in lst:
|
|
148
|
+
if isinstance(item, (list,tuple)) and not isinstance(item, XT): result.extend(item)
|
|
149
|
+
else: result.append(item)
|
|
150
|
+
return result
|
|
151
|
+
|
|
144
152
|
def _xt_resp(req, resp, hdrs, **bodykw):
|
|
145
153
|
http_hdrs,resp = partition(resp, risinstance(HttpHeader))
|
|
146
154
|
http_hdrs = {o.k:str(o.v) for o in http_hdrs}
|
|
147
155
|
titles,bdy = partition(resp, lambda o: getattr(o, 'tag', '')=='title')
|
|
148
|
-
if resp and 'hx-request' not in req.headers and
|
|
149
|
-
|
|
156
|
+
if resp and 'hx-request' not in req.headers and not any(getattr(o, 'tag', '')=='html' for o in resp):
|
|
157
|
+
if not titles: titles = [Title('FastHTML page')]
|
|
158
|
+
resp = Html(Head(titles[0], *flat_xt(hdrs)), Body(bdy, **bodykw))
|
|
150
159
|
return HTMLResponse(to_xml(resp), headers=http_hdrs)
|
|
151
160
|
|
|
152
161
|
def _wrap_resp(req, resp, cls, hdrs, **bodykw):
|
|
@@ -208,6 +217,8 @@ class RouterX(Router):
|
|
|
208
217
|
htmxscr = Script(
|
|
209
218
|
src="https://unpkg.com/htmx.org@1.9.12", crossorigin="anonymous",
|
|
210
219
|
integrity="sha384-ujb1lZYygJmzgSwoxRggbCHcjc0rB2XoQrxeTUQyRjrOnlCoYta87iKBWq3EsdM2")
|
|
220
|
+
surrsrc = Script(src="https://cdn.jsdelivr.net/gh/gnat/surreal/surreal.js")
|
|
221
|
+
scopesrc = Script(src="https://cdn.jsdelivr.net/gh/gnat/css-scope-inline/script.js")
|
|
211
222
|
|
|
212
223
|
def get_key(key=None, fname='.sesskey'):
|
|
213
224
|
if key: return key
|
|
@@ -221,7 +232,7 @@ def _list(o): return [] if not o else o if isinstance(o, (tuple,list)) else [o]
|
|
|
221
232
|
|
|
222
233
|
class FastHTML(Starlette):
|
|
223
234
|
def __init__(self, debug=False, routes=None, middleware=None, exception_handlers=None,
|
|
224
|
-
on_startup=None, on_shutdown=None, lifespan=None, hdrs=None, before=None,
|
|
235
|
+
on_startup=None, on_shutdown=None, lifespan=None, hdrs=None, before=None, default_hdrs=True,
|
|
225
236
|
secret_key=None, session_cookie='session_', max_age=365*24*3600, sess_path='/',
|
|
226
237
|
same_site='lax', sess_https_only=False, sess_domain=None, key_fname='.sesskey', **bodykw):
|
|
227
238
|
middleware,before = _list(middleware),_list(before)
|
|
@@ -231,7 +242,8 @@ class FastHTML(Starlette):
|
|
|
231
242
|
https_only=sess_https_only, domain=sess_domain)
|
|
232
243
|
middleware.append(sess)
|
|
233
244
|
super().__init__(debug, routes, middleware, exception_handlers, on_startup, on_shutdown, lifespan=lifespan)
|
|
234
|
-
hdrs = list([] if hdrs is None else hdrs)
|
|
245
|
+
hdrs = list([] if hdrs is None else hdrs)
|
|
246
|
+
if default_hdrs: hdrs = [htmxscr,surrsrc,scopesrc] + hdrs
|
|
235
247
|
self.router = RouterX(routes, on_startup=on_startup, on_shutdown=on_shutdown, lifespan=lifespan, hdrs=hdrs,
|
|
236
248
|
before=before, **bodykw)
|
|
237
249
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from fastcore.utils import *
|
|
2
|
+
from fasthtml.xtend import Script,jsd,Style
|
|
3
|
+
|
|
4
|
+
def light_media(css): return Style('@media (prefers-color-scheme: light) {%s}' %css)
|
|
5
|
+
def dark_media(css): return Style('@media (prefers-color-scheme: dark) {%s}' %css)
|
|
6
|
+
|
|
7
|
+
def MarkdownJS(sel='.marked'):
|
|
8
|
+
src = """
|
|
9
|
+
import { marked } from "https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js";
|
|
10
|
+
import { proc_htmx} from "https://cdn.jsdelivr.net/gh/answerdotai/fasthtml-js/fasthtml.js";
|
|
11
|
+
proc_htmx('%s', e => e.innerHTML = marked.parse(e.textContent));
|
|
12
|
+
""" % sel
|
|
13
|
+
return Script(src, type='module')
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def HighlightJS(sel='pre code', langs='python', light='atom-one-light', dark='atom-one-dark'):
|
|
17
|
+
src = """
|
|
18
|
+
hljs.addPlugin(new CopyButtonPlugin());
|
|
19
|
+
hljs.configure({'cssSelector': '%s'});
|
|
20
|
+
htmx.onLoad(hljs.highlightAll);""" % sel
|
|
21
|
+
hjs = 'highlightjs','cdn-release', 'build'
|
|
22
|
+
hjc = 'arronhunt' ,'highlightjs-copy', 'dist'
|
|
23
|
+
if isinstance(langs, str): langs = [langs]
|
|
24
|
+
langjs = [jsd(*hjs, f'languages/{lang}.min.js') for lang in langs]
|
|
25
|
+
return [jsd(*hjs, f'styles/{dark}.css', typ='css', media="(prefers-color-scheme: dark)"),
|
|
26
|
+
jsd(*hjs, f'styles/{light}.css', typ='css', media="(prefers-color-scheme: light)"),
|
|
27
|
+
jsd(*hjs, f'highlight.min.js'),
|
|
28
|
+
jsd(*hjc, 'highlightjs-copy.min.js'),
|
|
29
|
+
jsd(*hjc, 'highlightjs-copy.min.css', typ='css'),
|
|
30
|
+
light_media('.hljs-copy-button {background-color: #2d2b57;}'),
|
|
31
|
+
*langjs, Script(src, type='module')]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def SortableJS(sel='.sortable', ghost_class='blue-background-class'):
|
|
35
|
+
src = """
|
|
36
|
+
import {Sortable} from 'https://cdn.jsdelivr.net/npm/sortablejs/+esm';
|
|
37
|
+
import {proc_htmx} from "https://cdn.jsdelivr.net/gh/answerdotai/fasthtml-js/fasthtml.js";
|
|
38
|
+
proc_htmx('%s', elm => {
|
|
39
|
+
const s = new Sortable(elm, {
|
|
40
|
+
animation: 150, ghostClass: '%s', filter: ".htmx-indicator",
|
|
41
|
+
onMove: e => !e.related.classList.contains('htmx-indicator'),
|
|
42
|
+
onEnd: () => s.option("disabled", true),
|
|
43
|
+
});
|
|
44
|
+
htmx.on("htmx:afterSwap", () => s.option("disabled", false), elm);
|
|
45
|
+
});
|
|
46
|
+
""" % (sel, ghost_class)
|
|
47
|
+
return Script(src, type='module')
|
|
48
|
+
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# %% auto 0
|
|
4
4
|
__all__ = ['picocss', 'picolink', 'picocondcss', 'picocondlink', 'set_pico_cls', 'Html', 'A', 'AX', 'Checkbox', 'Card', 'Group',
|
|
5
|
-
'Search', 'Grid', 'DialogX', 'Hidden']
|
|
5
|
+
'Search', 'Grid', 'DialogX', 'Hidden', 'Script', 'Style', 'jsd']
|
|
6
6
|
|
|
7
7
|
# %% ../nbs/02_xtend.ipynb 2
|
|
8
8
|
from dataclasses import dataclass, asdict
|
|
@@ -96,3 +96,23 @@ def DialogX(*c, open=None, header=None, footer=None, id=None, **kwargs):
|
|
|
96
96
|
@delegates(xt_hx, keep=True)
|
|
97
97
|
def Hidden(value:str="", **kwargs):
|
|
98
98
|
return Input(type="hidden", value=value, **kwargs)
|
|
99
|
+
|
|
100
|
+
# %% ../nbs/02_xtend.ipynb 28
|
|
101
|
+
@delegates(xt_html, keep=True)
|
|
102
|
+
def Script(code:str="", **kwargs):
|
|
103
|
+
"A Script tag that doesn't escape its code"
|
|
104
|
+
return xt_html('script', NotStr(code), **kwargs)
|
|
105
|
+
|
|
106
|
+
# %% ../nbs/02_xtend.ipynb 29
|
|
107
|
+
@delegates(xt_html, keep=True)
|
|
108
|
+
def Style(css:str="", **kwargs):
|
|
109
|
+
"A Style tag that doesn't escape its code"
|
|
110
|
+
return xt_html('style', NotStr(css), **kwargs)
|
|
111
|
+
|
|
112
|
+
# %% ../nbs/02_xtend.ipynb 30
|
|
113
|
+
def jsd(org, repo, root, path, typ='script', ver=None, esm=False, **kwargs):
|
|
114
|
+
"jsdelivr `Script` or CSS `Link` tag, or URL"
|
|
115
|
+
ver = '@'+ver if ver else ''
|
|
116
|
+
s = f'https://cdn.jsdelivr.net/gh/{org}/{repo}{ver}/{root}/{path}'
|
|
117
|
+
if esm: s += '/+esm'
|
|
118
|
+
return Script(src=s, **kwargs) if typ=='script' else Link(rel='stylesheet', href=s, **kwargs) if typ=='css' else s
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-fasthtml
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.14
|
|
4
4
|
Summary: The fastest way to create an HTML app
|
|
5
5
|
Home-page: https://github.com/AnswerDotAI/fasthtml
|
|
6
6
|
Author: Jeremy Howard
|
|
@@ -24,6 +24,7 @@ Requires-Dist: uvicorn[standard]
|
|
|
24
24
|
Requires-Dist: httpx
|
|
25
25
|
Requires-Dist: fastlite>=0.0.6
|
|
26
26
|
Requires-Dist: python-multipart
|
|
27
|
+
Requires-Dist: beautifulsoup4
|
|
27
28
|
Provides-Extra: dev
|
|
28
29
|
Requires-Dist: ipython; extra == "dev"
|
|
29
30
|
Requires-Dist: lxml; extra == "dev"
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[DEFAULT]
|
|
2
2
|
repo = fasthtml
|
|
3
3
|
lib_name = fasthtml
|
|
4
|
-
version = 0.0.
|
|
4
|
+
version = 0.0.14
|
|
5
5
|
min_python = 3.10
|
|
6
6
|
license = apache2
|
|
7
|
-
requirements = fastcore>=1.5.45 python-dateutil starlette oauthlib itsdangerous uvicorn[standard] httpx fastlite>=0.0.6 python-multipart
|
|
7
|
+
requirements = fastcore>=1.5.45 python-dateutil starlette oauthlib itsdangerous uvicorn[standard] httpx fastlite>=0.0.6 python-multipart beautifulsoup4
|
|
8
8
|
dev_requirements = ipython lxml
|
|
9
9
|
black_formatting = False
|
|
10
10
|
conda_user = fastai
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
from fastcore.utils import *
|
|
2
|
-
from fasthtml.components import Script
|
|
3
|
-
|
|
4
|
-
def MarkdownJS(sel):
|
|
5
|
-
src = """
|
|
6
|
-
import { marked } from "https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js";
|
|
7
|
-
htmx.onLoad(elt => htmx.findAll(elt, "%s").forEach(e => e.innerHTML = marked.parse(e.textContent)));
|
|
8
|
-
""" % sel
|
|
9
|
-
return Script(NotStr(src), type='module')
|
|
10
|
-
|
|
11
|
-
def SortableJS(sel='.sortable', ghost_class='blue-background-class'):
|
|
12
|
-
src = """
|
|
13
|
-
import {Sortable} from 'https://cdn.jsdelivr.net/npm/sortablejs/+esm';
|
|
14
|
-
|
|
15
|
-
htmx.onLoad(content => {
|
|
16
|
-
content.querySelectorAll("%s").forEach(elm => {
|
|
17
|
-
const s = new Sortable(elm, {
|
|
18
|
-
animation: 150,
|
|
19
|
-
ghostClass: '%s',
|
|
20
|
-
filter: ".htmx-indicator",
|
|
21
|
-
onMove: e => !e.related.classList.contains('htmx-indicator'),
|
|
22
|
-
onEnd: () => s.option("disabled", true),
|
|
23
|
-
});
|
|
24
|
-
htmx.on("htmx:afterSwap", () => s.option("disabled", false), elm);
|
|
25
|
-
});
|
|
26
|
-
})
|
|
27
|
-
""" % (sel, ghost_class)
|
|
28
|
-
return Script(NotStr(src), type='module')
|
|
29
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python-fasthtml-0.0.11 → python-fasthtml-0.0.14}/python_fasthtml.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|