AItool's picture
Upload 81 files
d467ea7 verified
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/01_core.ipynb.
# %% auto 0
__all__ = ['HEADER_URLS', 'daisy_styles', 'scrollspy_style', 'fast_app', 'FastHTML', 'ThemeRadii', 'ThemeShadows', 'ThemeFont',
'Theme']
# %% ../nbs/01_core.ipynb
import fasthtml.common as fh
from .foundations import *
from fasthtml.common import FastHTML, fast_app
from enum import Enum, auto
from fastcore.all import *
import httpx
from pathlib import Path
# %% ../nbs/01_core.ipynb
@delegates(fh.fast_app, but=['pico'])
def fast_app(*args, pico=False, **kwargs):
"Create a FastHTML or FastHTMLWithLiveReload app with `bg-background text-foreground` to bodykw for frankenui themes"
if 'bodykw' not in kwargs: kwargs['bodykw'] = {}
if 'class' not in kwargs['bodykw']: kwargs['bodykw']['class'] = ''
kwargs['bodykw']['class'] = stringify((kwargs['bodykw']['class'],'bg-background text-foreground'))
return fh.fast_app(*args, pico=pico, **kwargs)
# %% ../nbs/01_core.ipynb
@delegates(fh.FastHTML, but=['pico'])
def FastHTML(*args, pico=False, **kwargs):
"Create a FastHTML app and adds `bg-background text-foreground` to bodykw for frankenui themes"
if 'bodykw' not in kwargs: kwargs['bodykw'] = {}
if 'class' not in kwargs['bodykw']: kwargs['bodykw']['class'] = ''
kwargs['bodykw']['class'] = stringify((kwargs['bodykw']['class'],'bg-background text-foreground'))
bodykw = kwargs.pop('bodykw',{})
return fh.FastHTML(*args, pico=pico, **bodykw, **kwargs)
# %% ../nbs/01_core.ipynb
class ThemeRadii(VEnum):
none = 'uk-radii-none'
sm = 'uk-radii-sm'
md = 'uk-radii-md'
lg = 'uk-radii-lg'
class ThemeShadows:
none = 'uk-shadows-none'
sm = 'uk-shadows-sm'
md = 'uk-shadows-md'
lg = 'uk-shadows-lg'
class ThemeFont:
sm = 'uk-font-sm'
default = 'uk-font-base'
# %% ../nbs/01_core.ipynb
def _headers_theme(color, mode='auto', radii=ThemeRadii.sm, shadows=ThemeShadows.sm, font=ThemeFont.sm):
franken_init = '''
const __FRANKEN__ = JSON.parse(localStorage.getItem("__FRANKEN__") || "{}");
'''
mode_script = {
'auto': f'''
{franken_init}
if (
__FRANKEN__.mode === "dark" ||
(!__FRANKEN__.mode &&
window.matchMedia("(prefers-color-scheme: dark)").matches)
) {{
htmlElement.classList.add("dark");
}} else {{
htmlElement.classList.remove("dark");
}}
''',
'light': f'{franken_init}\nhtmlElement.classList.remove("dark");',
'dark': f'{franken_init}\nhtmlElement.classList.add("dark");'
}
return fh.Script(f'''
const htmlElement = document.documentElement;
{mode_script[mode]}
htmlElement.classList.add(__FRANKEN__.theme || "uk-theme-{color}");
htmlElement.classList.add(__FRANKEN__.radii || "{radii}");
htmlElement.classList.add(__FRANKEN__.shadows || "{shadows}");
htmlElement.classList.add(__FRANKEN__.font || "{font}");
''')
# %% ../nbs/01_core.ipynb
HEADER_URLS = {
'franken_css': "https://cdn.jsdelivr.net/npm/franken-ui@2.0.0/dist/css/core.min.css",
'franken_js_core': "https://cdn.jsdelivr.net/npm/franken-ui@2.0.0/dist/js/core.iife.js",
'franken_icons': "https://cdn.jsdelivr.net/npm/franken-ui@2.0.0/dist/js/icon.iife.js",
'tailwind': "https://cdn.tailwindcss.com/3.4.16",
'daisyui': "https://cdn.jsdelivr.net/npm/daisyui@4.12.24/dist/full.min.css",
'apex_charts': "https://cdn.jsdelivr.net/npm/franken-ui@2.0.0/dist/js/chart.iife.js",
'highlight_js': "https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/highlight.min.js",
'highlight_python': "https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/languages/python.min.js",
'highlight_light_css': "https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/atom-one-light.css",
'highlight_dark_css': "https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/atom-one-dark.css",
'highlight_copy': "https://cdn.jsdelivr.net/gh/arronhunt/highlightjs-copy/dist/highlightjs-copy.min.js",
'highlight_copy_css': "https://cdn.jsdelivr.net/gh/arronhunt/highlightjs-copy/dist/highlightjs-copy.min.css",
}
def _download_resource(url, static_dir):
"Download a single resource and return its local path"
static = Path(static_dir)
fname = static/f"{url[0]}.{'js' if 'js' in url[1] else 'css'}"
content = httpx.get(url[1], follow_redirects=True).content
fname.write_bytes(content)
return (url[0], f"/{static_dir}/{fname.name}")
# %% ../nbs/01_core.ipynb
daisy_styles = Style("""
:root {
--b1: from hsl(var(--background)) l c h;
--bc: from hsl(var(--foreground)) l c h;
--m: from hsl(var(--muted)) l c h;
--mc: from hsl(var(--muted-foreground)) l c h;
--po: from hsl(var(--popover)) l c h;
--poc: from hsl(var(--popover-foreground)) l c h;
--b2: from hsl(var(--card)) l c h;
--b2c: from hsl(var(--card-foreground)) l c h;
--br: from hsl(var(--border)) l c h;
--in: from hsl(var(--input)) l c h;
--p: from hsl(var(--primary)) l c h;
--pc: from hsl(var(--primary-foreground)) l c h;
--s: from hsl(var(--secondary)) l c h;
--sc: from hsl(var(--secondary-foreground)) l c h;
--a: from hsl(var(--accent)) l c h;
--ac: from hsl(var(--accent-foreground)) l c h;
--er: from hsl(var(--destructive)) l c h;
--erc: from hsl(var(--destructive-foreground)) l c h;
--b3: from hsl(var(--ring)) l c h;
--ch1: from hsl(var(--chart-1)) l c h;
--ch2: from hsl(var(--chart-2)) l c h;
--ch3: from hsl(var(--chart-3)) l c h;
--ch4: from hsl(var(--chart-4)) l c h;
--ch5: from hsl(var(--chart-5)) l c h;
--rd: var(--radius);
}
""")
# %% ../nbs/01_core.ipynb
scrollspy_style= Style('''
.monster-navbar.navbar-bold a {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.monster-navbar.navbar-bold a.uk-active {
transform: scale(1.15) ;
font-weight: bold;
text-shadow: 0 0 12px rgba(var(--p-rgb), 0.4);
letter-spacing: 0.02em;
color: hsl(var(--p) / 1);
}
.monster-navbar.navbar-underline a.uk-active { position: relative; }
.monster-navbar.navbar-underline a.uk-active::after {
content: '';
position: absolute;
left: 0;
bottom: -2px;
width: 100%;
height: 2px;
background: currentColor;
animation: slideIn 0.3s ease forwards;
}
@keyframes slideIn {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
''')
# %% ../nbs/01_core.ipynb
class Theme(Enum):
"Selector to choose theme and get all headers needed for app. Includes frankenui + tailwind + daisyui + highlight.js options"
def _generate_next_value_(name, start, count, last_values): return name
slate = auto()
stone = auto()
gray = auto()
neutral = auto()
red = auto()
rose = auto()
orange = auto()
green = auto()
blue = auto()
yellow = auto()
violet = auto()
zinc = auto()
def _create_headers(self, urls, mode='auto', icons=True, daisy=True, highlightjs=False, katex=False, apex_charts=False, radii=ThemeRadii.sm, shadows=ThemeShadows.sm, font=ThemeFont.sm):
"Create header elements with given URLs"
hdrs = [
fh.Link(rel="stylesheet", href=urls['franken_css']),
fh.Script(type="module", src=urls['franken_js_core']),
fh.Script(src=urls['tailwind']),
fh.Script("""
tailwind.config = {
darkMode: 'selector',
}
"""),
_headers_theme(self.value, mode=mode, radii=radii, shadows=shadows, font=font),
scrollspy_style]
if icons: hdrs.append(fh.Script(type="module", src=urls['franken_icons']))
if daisy: hdrs += [fh.Link(rel="stylesheet", href=urls['daisyui']), daisy_styles]
if apex_charts: hdrs += [fh.Script(type='module', src=urls['apex_charts'])]
if highlightjs:
hdrs += [
fh.Script(src=urls['highlight_js']),
fh.Script(src=urls['highlight_python']),
fh.Link(rel="stylesheet", href=urls['highlight_light_css'], id='hljs-light'),
fh.Link(rel="stylesheet", href=urls['highlight_dark_css'], id='hljs-dark'),
fh.Script(src=urls['highlight_copy']),
fh.Link(rel="stylesheet", href=urls['highlight_copy_css']),
fh.Script('''
hljs.addPlugin(new CopyButtonPlugin());
hljs.configure({
cssSelector: 'pre code',
languages: ['python'],
ignoreUnescapedHTML: true
});
function updateTheme() {
const isDark = document.documentElement.classList.contains('dark');
document.getElementById('hljs-dark').disabled = !isDark;
document.getElementById('hljs-light').disabled = isDark;
}
new MutationObserver(mutations =>
mutations.forEach(m => m.target.tagName === 'HTML' &&
m.attributeName === 'class' && updateTheme())
).observe(document.documentElement, { attributes: true });
updateTheme();
htmx.onLoad(hljs.highlightAll);
''', type='module'),
]
if katex:
hdrs += [
fh.Link(rel="stylesheet",
href="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.css"),
fh.Script("""
import katex from 'https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.mjs';
import autoRender from 'https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/contrib/auto-render.mjs';
const options = {
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false}
],
ignoredClasses: ['nomath']
};
document.addEventListener('htmx:load', evt => {
const element = evt.detail.elt || document.body;
autoRender(element,options);
});
""",type="module"),
]
return hdrs
def headers(self, mode='auto', icons=True, daisy=True, highlightjs=False, katex=False, apex_charts=False, radii=ThemeRadii.sm, shadows=ThemeShadows.sm, font=ThemeFont.sm ):
"Create frankenui and tailwind cdns"
return self._create_headers(HEADER_URLS, mode=mode, icons=icons, daisy=daisy, highlightjs=highlightjs, katex=katex, apex_charts=apex_charts, radii=radii, shadows=shadows, font=font)
def local_headers(self, mode='auto', static_dir='static', icons=True, daisy=True, highlightjs=False, katex=False, apex_charts=False, radii='md', shadows='sm', font='sm'):
"Create headers using local files downloaded from CDNs"
Path(static_dir).mkdir(exist_ok=True)
local_urls = dict([_download_resource(url, static_dir) for url in HEADER_URLS.items()])
return self._create_headers(local_urls, mode=mode, icons=icons, daisy=daisy, highlightjs=highlightjs, katex=katex, apex_charts=apex_charts, radii=radii, shadows=shadows, font=font)