# 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)