-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make EOSdash use UI components from MonsterUI to ease further development. - Add a first menu with some dummy pages and the configuration page. - Make the configuration scrollable. - Add markdown component that uses markdown-it-py (same as used by the myth-parser for documentation generation). - Add a footer that displays connection status with EOS server - Add logo and favicon Update EOS server: - Provide health endpoint for alive checking. - Move error message generation to extra module Signed-off-by: Bobby Noelte <[email protected]> Signed-off-by: Bobby Noelte <[email protected]>
- Loading branch information
Showing
22 changed files
with
883 additions
and
204 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Binary file added
BIN
+22.2 KB
src/akkudoktoreos/server/dash/assets/favicon/android-chrome-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+112 KB
src/akkudoktoreos/server/dash/assets/favicon/android-chrome-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
from typing import Any, Optional, Union | ||
|
||
from fasthtml.common import H1, Div, Li | ||
|
||
# from mdit_py_plugins import plugin1, plugin2 | ||
from monsterui.foundations import stringify | ||
from monsterui.franken import Button, ButtonT, Card, Container, ContainerT, TabContainer | ||
|
||
scrollbar_viewport_styles = ( | ||
"scrollbar-width: none; -ms-overflow-style: none; -webkit-overflow-scrolling: touch;" | ||
) | ||
|
||
scrollbar_cls = "flex touch-none select-none transition-colors p-[1px]" | ||
|
||
|
||
def ScrollArea( | ||
*c: Any, cls: Optional[Union[str, tuple]] = None, orientation: str = "vertical", **kwargs: Any | ||
) -> Div: | ||
"""Creates a styled scroll area. | ||
Args: | ||
orientation (str): The orientation of the scroll area. Defaults to vertical. | ||
""" | ||
new_cls = "relative overflow-hidden" | ||
if cls: | ||
new_cls += f" {stringify(cls)}" | ||
kwargs["cls"] = new_cls | ||
|
||
content = Div( | ||
Div(*c, style="min-width:100%;display:table;"), | ||
style=f"overflow: {'hidden scroll' if orientation == 'vertical' else 'scroll'}; {scrollbar_viewport_styles}", | ||
cls="w-full h-full rounded-[inherit]", | ||
data_ref="viewport", | ||
) | ||
|
||
scrollbar = Div( | ||
Div(cls="bg-border rounded-full hidden relative flex-1", data_ref="thumb"), | ||
cls=f"{scrollbar_cls} flex-col h-2.5 w-full border-t border-t-transparent" | ||
if orientation == "horizontal" | ||
else f"{scrollbar_cls} w-2.5 h-full border-l border-l-transparent", | ||
data_ref="scrollbar", | ||
style=f"position: absolute;{'right:0; top:0;' if orientation == 'vertical' else 'bottom:0; left:0;'}", | ||
) | ||
|
||
return Div( | ||
content, | ||
scrollbar, | ||
role="region", | ||
tabindex="0", | ||
data_orientation=orientation, | ||
data_ref_scrollarea=True, | ||
aria_label="Scrollable content", | ||
**kwargs, | ||
) | ||
|
||
|
||
def DashboardHeader(title: Optional[str]) -> Div: | ||
"""Creates a styled header with a title. | ||
Args: | ||
title (Optional[str]): The title text for the header. | ||
Returns: | ||
Div: A styled `Div` element containing the header. | ||
""" | ||
if title is None: | ||
return Div("", cls="header") | ||
return Div(H1(title, cls="text-2xl font-bold mb-4"), cls="header") | ||
|
||
|
||
def DashboardFooter(*c: Any, path: str) -> Card: | ||
"""Creates a styled footer with the provided information. | ||
The footer content is reloaded every 5 seconds from path. | ||
Args: | ||
path (str): Path to reload footer content from | ||
Returns: | ||
Card: A styled `Card` element containing the footer. | ||
""" | ||
return Card( | ||
Container(*c, id="footer-content"), | ||
hx_get=f"{path}", | ||
hx_trigger="every 5s", | ||
hx_target="#footer-content", | ||
hx_swap="innerHTML", | ||
) | ||
|
||
|
||
def DashboardTrigger(*c: Any, cls: Optional[Union[str, tuple]] = None, **kwargs: Any) -> Button: | ||
"""Creates a styled button for the dashboard trigger. | ||
Args: | ||
*c: Positional arguments to pass to the button. | ||
cls (Optional[str]): Additional CSS classes for styling. Defaults to None. | ||
**kwargs: Additional keyword arguments for the button. | ||
Returns: | ||
Button: A styled `Button` component. | ||
""" | ||
new_cls = f"{ButtonT.primary}" | ||
if cls: | ||
new_cls += f" {stringify(cls)}" | ||
kwargs["cls"] = new_cls | ||
return Button(*c, submit=False, **kwargs) | ||
|
||
|
||
def DashboardTabs(dashboard_items: dict[str, str]) -> Card: | ||
"""Creates a dashboard tab with dynamic dashboard items. | ||
Args: | ||
dashboard_items (dict[str, str]): A dictionary of dashboard items where keys are item names | ||
and values are paths for navigation. | ||
Returns: | ||
Card: A styled `Card` component containing the dashboard tabs. | ||
""" | ||
dash_items = [ | ||
Li( | ||
DashboardTrigger( | ||
menu, | ||
hx_get=f"{path}", | ||
hx_target="#page-content", | ||
hx_swap="innerHTML", | ||
), | ||
) | ||
for menu, path in dashboard_items.items() | ||
] | ||
return Card(TabContainer(*dash_items, cls="gap-4"), alt=True) | ||
|
||
|
||
def DashboardContent(content: Any) -> Card: | ||
"""Creates a content section within a styled card. | ||
Args: | ||
content (Any): The content to display. | ||
Returns: | ||
Card: A styled `Card` element containing the content. | ||
""" | ||
return Card(ScrollArea(Container(content, id="page-content"), cls="h-[75vh] w-full rounded-md")) | ||
|
||
|
||
def Page( | ||
title: Optional[str], | ||
dashboard_items: dict[str, str], | ||
content: Any, | ||
footer_content: Any, | ||
footer_path: str, | ||
) -> Div: | ||
"""Generates a full-page layout with a header, dashboard items, content, and footer. | ||
Args: | ||
title (Optional[str]): The page title. | ||
dashboard_items (dict[str, str]): A dictionary of dashboard items. | ||
content (Any): The main content for the page. | ||
footer_content (Any): Footer content. | ||
footer_path (Any): Path to reload footer content from. | ||
Returns: | ||
Div: A `Div` element representing the entire page layout. | ||
""" | ||
return Container( | ||
DashboardHeader(title), | ||
DashboardTabs(dashboard_items), | ||
DashboardContent(content), | ||
DashboardFooter(footer_content, path=footer_path), | ||
cls=("bg-background text-foreground w-screen p-4 space-y-4", ContainerT.xl), | ||
) |
Oops, something went wrong.