Skip to content

Commit

Permalink
Docs updates
Browse files Browse the repository at this point in the history
  • Loading branch information
Isaac-Flath committed Dec 26, 2024
1 parent 10e44a7 commit 3fae33c
Show file tree
Hide file tree
Showing 7 changed files with 1,193 additions and 731 deletions.
83 changes: 65 additions & 18 deletions docs/api_reference/api_reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from fasthtml.common import *
from monsterui.all import *
from nbdev.showdoc import *
# from nbdev.showdoc import *
from utils import create_flippable_card, fn2code_string
from enum import EnumType
from collections.abc import Callable
Expand All @@ -12,17 +12,60 @@
These are automatically added to the docs sidebar so you don't have to do anything other than add the function using create_doc_section.
'''
from inspect import signature, getdoc, getsourcefile, getsourcelines

# Utilities
def get_github_url(func):
"Create GitHub URL for function, assuming AnswerDotAI/MonsterUI repo"
file = getsourcefile(func).split('MonsterUI/')[-1]
line = getsourcelines(func)[-1]
return f"https://github.com/AnswerDotAI/MonsterUI/blob/main/{file}#L{line}"

from fastcore.docments import docments, docstring, get_name
def show_doc(func) -> str:
"Convert a Google-style docstring to markdown"
params = docments(func, args_kwargs=True)
funcname = get_name(func)
doc = docstring(func)
par, ret = None, None
if params:
par = Div(Strong('Params'),
Ul(*[Li(render_md(f"`{name}` {desc if desc else ''}",class_map_mods={'p':'leading-relaxed'}), cls='') for name, desc in params.items() if name != 'return'], cls='uk-list-disc space-y-2 mb-6 ml-6'))
if 'return' in params and params['return']: ret = render_md(f"**Returns:** {params['return']}")
return Div(
# DivFullySpaced(H3(func.__name__, cls='uk-h3 text-2xl font-semibold mt-8 mb-4'),A("Source", href=get_github_url(func), cls='text-primary hover:text-primary-focus underline')),
DivFullySpaced(render_md(f"### {func.__name__}"),A("Source", href=get_github_url(func), cls='text-primary hover:text-primary-focus underline')),
Div(Pre(Code(f"{funcname}{signature(func)}",
cls='hljs language-python px-1 block overflow-x-auto'),
cls='bg-base-200 rounded-lg p-4 mb-6')),
Div(Blockquote(render_md(doc), cls='pl-4 border-l-4 border-primary mb-6'), par, ret, cls='ml-10'))

def enum_to_html_table(enum_class):
headers = ["Option", "Value"]
rows = [[name, value.value] for name, value in enum_class.__members__.items()]
"Creates a compact multi-column table display for enum documentation"
items = list(enum_class.__members__.items())
n_cols = min(4, max(2, round((len(items) ** 0.5))))

# Create header/cell pairs with borders
def make_pair(opt, val, i):
border = 'border-l border-base-300 pl-4' if i > 0 else ''
return [Th('Option', cls=border), Th('Value')] if opt == 'header' else [Td(opt, cls=border), Td(val)]

# Build rows with padding for incomplete final row
rows = []
for i in range(0, len(items), n_cols):
cells = []
for j in range(n_cols):
name, val = items[i + j] if i + j < len(items) else ('', '')
cells.extend(make_pair(name, val.value if val else '', j))
rows.append(Tr(*cells))

return Div(
Hr(cls='uk-divider-icon my-4'),
H3(enum_class.__name__,cls='my-4'),
P(I(enum_class.__doc__)),
TableFromLists(headers, rows, cls=(TableT.hover, 'uk-table-small')),)
Hr(cls='uk-divider-icon my-2'),
DivFullySpaced(H3(enum_class.__name__, cls='my-2'), P(I(enum_class.__doc__), cls='text-sm')),
Table(
Thead(Tr(*make_pair('header', '', 0) * n_cols)),
Tbody(*rows),
cls=(TableT.hover, 'uk-table-small uk-table-justify uk-table-middle')))

def render_content(c):
"Renders content by type"
Expand All @@ -33,8 +76,9 @@ def render_content(c):
extra_cls = c[2] if len(tuple(c)) == 3 else None
return create_flippable_card(c[0], c[1], extra_cls)
elif isinstance(c, Callable): # Callables are rendered as documentation via show_doc
_html = show_doc(c, renderer=BasicHtmlRenderer)._repr_html_()
return NotStr(apply_classes(_html, class_map_mods={"table":'uk-table uk-table-hover uk-table-small'}))
return show_doc(c)
# _html = show_doc(c, renderer=BasicHtmlRenderer)._repr_html_()
# return NotStr(apply_classes(_html, class_map_mods={"table":'uk-table uk-table-hover uk-table-small'}))
else: return c

def create_doc_section(*content, title):
Expand Down Expand Up @@ -66,7 +110,6 @@ def ex_links():
Button,
fn2code_string(ex_buttons),
ButtonT,
A,
AT,
fn2code_string(ex_links),
title="Buttons & Links")
Expand Down Expand Up @@ -172,7 +215,7 @@ def ex_other():
TextFont,
TextT,
H1, H2, H3, H4, Titled,
P, PParagraph, PLarge, PLead, PSmall, PMuted,
PParagraph, PLarge, PLead, PSmall, PMuted,
CodeSpan, Blockquote,
title="Text Style")

Expand Down Expand Up @@ -312,7 +355,7 @@ def team_member(name, role, location="Remote"):
fn2code_string(ex_card3),
CardTitle,
CardT,
"The remainder of these are only needed if you're doing something really special. They are used in the `Card` function to generate the boilerplate for you.",
P("The remainder of these are only needed if you're doing something really special. They are used in the `Card` function to generate the boilerplate for you.", cls='my-6'),
CardContainer,
CardHeader,
CardBody,
Expand Down Expand Up @@ -408,6 +451,14 @@ def ex_form():
fn2code_string(ex_formlabel),
Input,
fn2code_string(ex_input),
LabelInput,
LabelCheckboxX,
LabelSwitch,
LabelRange,
LabelTextArea,
LabelRadio,
LabelSelect,
LabelUkSelect,
Progress,
fn2code_string(ex_progress),
Radio,
Expand Down Expand Up @@ -682,9 +733,8 @@ def ex_tabs2():
P("A tabs can use any method of navigation (htmx, or href). However, often these are use in conjunction with switchers do to this client side", cls=TextFont.muted_sm),
fn2code_string(ex_tabs1),
H1("API Docs"),
Nav,
NavT,
NavContainer,
NavT,
NavCloseLi,
NavSubtitle,
NavHeaderLi,
Expand Down Expand Up @@ -772,10 +822,7 @@ def body_render(k, v):
TableT,
Tbody,
Th,
Td,
Tfoot,
Thead,
Tr,
Td,
title="Tables")

# Icons
Expand Down
2 changes: 1 addition & 1 deletion docs/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def _create_page(content, # The content to display (without the layout/sidebar)

def with_layout(sidebar_section, content):
"Puts the sidebar and content into a layout"
return Title(f"MonsterUI {sidebar_section.removeprefix('docs_')}"), Div(cls="flex flex-col md:flex-row w-full")(
return Title(f"MonsterUI"), Div(cls="flex flex-col md:flex-row w-full")(
Button(UkIcon("menu",50,50,cls='mt-4'), cls="md:hidden mb-4", uk_toggle="target: #mobile-sidebar"),
Div(sidebar(sidebar_section), id='mobile-sidebar', hidden=True),
Div(cls="md:flex w-full")(
Expand Down
1 change: 0 additions & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ fastcore
fh_matplotlib
numpy
matplotlib
nbdev
pysymbol_llm
mistletoe
lxml
83 changes: 39 additions & 44 deletions docs/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,46 @@ def get_last_statement(code): return ast.unparse(ast.parse(code).body[-1])
from pathlib import Path


hjs = (Style('html.dark .hljs-copy-button {background-color: #e0e0e0; color: #2d2b57;}'),
Link(rel='stylesheet', href='https://cdn.jsdelivr.net/gh/highlightjs/cdn-release/build/styles/atom-one-dark.css', disabled=True),
Link(rel='stylesheet', href='https://cdn.jsdelivr.net/gh/highlightjs/cdn-release/build/styles/atom-one-light.css', disabled=True),
Script(src='https://cdn.jsdelivr.net/gh/highlightjs/cdn-release/build/highlight.min.js'),
Script(src='https://cdn.jsdelivr.net/gh/arronhunt/highlightjs-copy/dist/highlightjs-copy.min.js'),
Link(rel='stylesheet', href='https://cdn.jsdelivr.net/gh/arronhunt/highlightjs-copy/dist/highlightjs-copy.min.css'),
Style('.hljs-copy-button {background-color: #2d2b57;}'),
Script(src='https://cdn.jsdelivr.net/gh/highlightjs/cdn-release/build/languages/python.min.js'),
Script("hljs.addPlugin(new CopyButtonPlugin());\r\nhljs.configure({'cssSelector': 'pre code'});\r\nhtmx.onLoad(hljs.highlightAll);", type='module'),
Script('''htmx.on("htmx:beforeHistorySave", () => {document.querySelectorAll("uk-icon").forEach((elt) => {elt.innerHTML = '';});});'''),

Script('''hljs.configure({
ignoreUnescapedHTML: true
});'''),
Script('''const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.target.tagName === 'HTML' && mutation.attributeName === 'class') {
const isDark = mutation.target.classList.contains('dark');
document.querySelector('link[href*="atom-one-dark.css"]').disabled = !isDark;
document.querySelector('link[href*="atom-one-light.css"]').disabled = isDark;
}
});
});
hjs = (
# Core highlight.js and copy plugin
Script(src='https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/highlight.min.js'),
Script(src='https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/languages/python.min.js'),
Script(src='https://cdn.jsdelivr.net/gh/arronhunt/highlightjs-copy/dist/highlightjs-copy.min.js'),

# Themes and styles
Link(rel='stylesheet', href='https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/atom-one-dark.css', id='hljs-dark'),
Link(rel='stylesheet', href='https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/atom-one-light.css', id='hljs-light'),
Link(rel='stylesheet', href='https://cdn.jsdelivr.net/gh/arronhunt/highlightjs-copy/dist/highlightjs-copy.min.css'),


# Initialization script
Script('''
// Initialize highlight.js with copy plugin
hljs.addPlugin(new CopyButtonPlugin());
hljs.configure({
cssSelector: 'pre code',
languages: ['python'],
ignoreUnescapedHTML: true
});
observer.observe(document.documentElement, { attributes: true });
// Theme switching logic
function updateTheme() {
const isDark = document.documentElement.classList.contains('dark');
document.getElementById('hljs-dark').disabled = !isDark;
document.getElementById('hljs-light').disabled = isDark;
}
// Initial setup
const isDark = document.documentElement.classList.contains('dark');
document.querySelector('link[href*="atom-one-dark.css"]').disabled = !isDark;
document.querySelector('link[href*="atom-one-light.css"]').disabled = isDark;
'''))
// Watch for theme changes
new MutationObserver(mutations =>
mutations.forEach(m => m.target.tagName === 'HTML' &&
m.attributeName === 'class' && updateTheme())
).observe(document.documentElement, { attributes: true });
// Initial setup
updateTheme();
htmx.onLoad(hljs.highlightAll);
''', type='module')
)
def create_flippable_card(content, source_code, extra_cls=None):
"Creates a card that flips between content and source code"
_id = 'f'+str(unqid())
Expand All @@ -57,24 +65,11 @@ def create_flippable_card(content, source_code, extra_cls=None):
DivFullySpaced(UkIcon('corner-down-right', 20, 20, 3),"See Output"),
uk_toggle=f"target: #{_id}", id=_id, cls=ButtonT.primary, hidden=True),
Div(content, id=_id),
Div(Pre(Code(source_code, cls="hljs language-python")), id=_id, hidden=True, cls="mockup-code"),
Div(Pre(Code(source_code, cls="hljs language-python")), id=_id, hidden=True),
cls='my-8')
return Div(_card, cls=extra_cls) if extra_cls else _card

def fn2code_string(fn: Callable) -> tuple: return fn(), extract_function_body(fn)

def extract_function_body(func):
source = inspect.getsource(func)
return source
body_start = source.index(':') + 1
body = source[body_start:]
lines = body.split('\n')
# Remove empty lines at the start
while lines and not lines[0].strip():
lines.pop(0)
# Remove first 4 spaces from each line
body = '\n'.join(line[4:] if line.startswith(' ') else line for line in lines)
return body.replace('return ', '', 1)
def fn2code_string(fn: Callable) -> tuple: return fn(), inspect.getsource(fn)


def render_nb(path):
Expand Down
4 changes: 0 additions & 4 deletions monsterui/_modidx.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@
'monsterui.franken.H2': ('franken.html#h2', 'monsterui/franken.py'),
'monsterui.franken.H3': ('franken.html#h3', 'monsterui/franken.py'),
'monsterui.franken.H4': ('franken.html#h4', 'monsterui/franken.py'),
'monsterui.franken.HTMXModalCloseButton': ('franken.html#htmxmodalclosebutton', 'monsterui/franken.py'),
'monsterui.franken.Input': ('franken.html#input', 'monsterui/franken.py'),
'monsterui.franken.Label': ('franken.html#label', 'monsterui/franken.py'),
'monsterui.franken.LabelCheckboxX': ('franken.html#labelcheckboxx', 'monsterui/franken.py'),
Expand All @@ -116,7 +115,6 @@
'monsterui.franken.ListT': ('franken.html#listt', 'monsterui/franken.py'),
'monsterui.franken.ListT._generate_next_value_': ( 'franken.html#listt._generate_next_value_',
'monsterui/franken.py'),
'monsterui.franken.Main': ('franken.html#main', 'monsterui/franken.py'),
'monsterui.franken.Modal': ('franken.html#modal', 'monsterui/franken.py'),
'monsterui.franken.ModalBody': ('franken.html#modalbody', 'monsterui/franken.py'),
'monsterui.franken.ModalCloseButton': ('franken.html#modalclosebutton', 'monsterui/franken.py'),
Expand Down Expand Up @@ -182,9 +180,7 @@
'monsterui.franken.TextT._generate_next_value_': ( 'franken.html#textt._generate_next_value_',
'monsterui/franken.py'),
'monsterui.franken.Th': ('franken.html#th', 'monsterui/franken.py'),
'monsterui.franken.Thead': ('franken.html#thead', 'monsterui/franken.py'),
'monsterui.franken.Titled': ('franken.html#titled', 'monsterui/franken.py'),
'monsterui.franken.Tr': ('franken.html#tr', 'monsterui/franken.py'),
'monsterui.franken.UkFormSection': ('franken.html#ukformsection', 'monsterui/franken.py'),
'monsterui.franken.UkIcon': ('franken.html#ukicon', 'monsterui/franken.py'),
'monsterui.franken.UkIconLink': ('franken.html#ukiconlink', 'monsterui/franken.py'),
Expand Down
Loading

0 comments on commit 3fae33c

Please sign in to comment.