diff --git a/app/base.tsx b/app/base.tsx index 9e7c63f..bcf77ee 100644 --- a/app/base.tsx +++ b/app/base.tsx @@ -269,8 +269,8 @@ function RenderedTreeNode({ return ; } case "markdown": { - const { body, lineClamp, ...args } = props; - return ; + const { body, lineClamp, tooltip, tooltip_direction, ...args } = props; + return ; } case "textarea": { return ; diff --git a/app/gooeyInput.tsx b/app/gooeyInput.tsx index 2836505..7517833 100644 --- a/app/gooeyInput.tsx +++ b/app/gooeyInput.tsx @@ -8,7 +8,7 @@ export function GooeyTextarea({ props: Record; state: Record; }) { - const { label, name, defaultValue, ...args } = props; + const { label, name, defaultValue, tooltip, tooltip_direction, ...args } = props; const [inputRef, value, setValue] = useGooeyStringInput({ state, name, @@ -18,7 +18,7 @@ export function GooeyTextarea({
{label && ( )}
@@ -45,7 +45,7 @@ export function GooeyInput({ state: Record; className: string; }) { - const { label, name, defaultValue, ...args } = props; + const { label, name, defaultValue, tooltip, tooltip_direction, ...args } = props; const [inputRef, value, setValue] = useGooeyStringInput({ state, name, @@ -53,11 +53,9 @@ export function GooeyInput({ }); return (
- {label && ( - - )} + ; className: string; }) { - const { label, name, defaultChecked, ...args } = props; + const { label, name, defaultChecked, tooltip, tooltip_direction, ...args } = props; const inputRef = useGooeyCheckedInput({ stateChecked: state[name], defaultChecked, @@ -135,7 +133,9 @@ export function GooeyCheckbox({ {...args} />
); @@ -152,7 +152,7 @@ export function GooeyRadio({ state: Record; className: string; }) { - const { label, name, value, defaultChecked, ...args } = props; + const { label, name, value, defaultChecked, tooltip, tooltip_direction, ...args } = props; const inputRef = useGooeyCheckedInput({ stateChecked: state[name] == value, defaultChecked, @@ -169,7 +169,9 @@ export function GooeyRadio({ {...args} />
); diff --git a/app/renderedHTML.tsx b/app/renderedHTML.tsx index 13321ee..cf48841 100644 --- a/app/renderedHTML.tsx +++ b/app/renderedHTML.tsx @@ -12,6 +12,7 @@ import { Link } from "@remix-run/react"; export function RenderedHTML({ body, lineClamp, + children, ...attrs }: { body: string; @@ -27,6 +28,7 @@ export function RenderedHTML({ {parsedElements} + {children} ); diff --git a/app/renderedMarkdown.tsx b/app/renderedMarkdown.tsx index cce91ce..9aa4172 100644 --- a/app/renderedMarkdown.tsx +++ b/app/renderedMarkdown.tsx @@ -1,17 +1,51 @@ import { marked } from "marked"; import { RenderedHTML } from "~/renderedHTML"; +export function GooeyTooltip(props: { + text: string; + direction?: "left"; + iconStyle?: Record; +}) { + return ( + + + + + + + ); +} + export function RenderedMarkdown({ body, lineClamp, + className, + tooltip, + tooltip_direction, + tooltip_iconStyle, ...attrs }: // allowUnsafeHTML, - { - body: string; - lineClamp?: number; - [attr: string]: any; - // allowUnsafeHTML?: boolean; - }) { +{ + body: string; + lineClamp?: number; + className?: string; + tooltip?: string; + tooltip_direction?: "left"; + tooltip_iconStyle?: Record; + [attr: string]: any; + // allowUnsafeHTML?: boolean; +}) { if (!body) return <>; let html = marked.parse(body, { gfm: true, @@ -25,8 +59,16 @@ export function RenderedMarkdown({ key={body} body={html} lineClamp={lineClamp} - className="gui-html-container gui-md-container" + className={className ?? "gui-html-container gui-md-container"} {...attrs} - /> + > + {tooltip && ( + + )} + ); } diff --git a/app/styles/custom.css b/app/styles/custom.css index 74c8655..e56236b 100644 --- a/app/styles/custom.css +++ b/app/styles/custom.css @@ -13,7 +13,8 @@ .streamlit-like-btn:hover, .streamlit-like-btn:active { cursor: pointer; - font-family: avenir-lt-w01_85-heavy1475544,avenir-lt-w05_85-heavy,"Space Grotesk", sans-serif; + font-family: avenir-lt-w01_85-heavy1475544, avenir-lt-w05_85-heavy, + "Space Grotesk", sans-serif; font-size: 15px; text-decoration: none !important; color: white !important; @@ -52,7 +53,8 @@ } .btn.btn-theme.replicate-nav.active:hover { - background: #a5ffee; /* mint */; + background: #a5ffee; + /* mint */ color: black; border: 1px solid transparent; } @@ -138,7 +140,8 @@ body { color: #000; } -.semobold, .semibold { +.semobold, +.semibold { font-weight: 600; } @@ -166,8 +169,14 @@ a:hover { text-decoration-thickness: 2px; } -h1, h2, h3, h4, h5, h6 { - font-family: avenir-lt-w01_85-heavy1475544,avenir-lt-w05_85-heavy,"avenir-lt-w05_85-heavy","Space Grotesk", sans-serif; +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: avenir-lt-w01_85-heavy1475544, avenir-lt-w05_85-heavy, + "avenir-lt-w05_85-heavy", "Space Grotesk", sans-serif; } h1 { font-size: 32px; @@ -511,7 +520,7 @@ textarea:disabled { .btn { margin: 0 0 0 1px; border-radius: 6px; - /* font-weight: 800; */ + /* font-weight: 800; */ } .btn.btn-theme { @@ -537,10 +546,10 @@ textarea:disabled { background-color: #fff0f5; color: #000; */ - border: 1px solid #c9c9c9; - transition: all .2s ease-in; - background-color: #fff; - color: black; + border: 1px solid #c9c9c9; + transition: all 0.2s ease-in; + background-color: #fff; + color: black; } .btn-theme.btn-secondary:hover { background-color: #fff0f5; /* #a5ffee; mint */ @@ -561,10 +570,6 @@ textarea:disabled { border: 1px solid transparent; } - - - - .bg-light { padding: 15px 20px; background-color: #f2f2f2 !important; @@ -753,4 +758,94 @@ a.text-primary:hover { } .cm-lineNumbers .cm-gutterElement { min-width: 36px !important; -} \ No newline at end of file +} + +/* Tooltip hide/show */ +.gui_tooltip { + position: relative; + font-size: 16px; +} + +.gui-md-container:has(> .gui_tooltip) { + display: flex; +} + +.gui_tooltip i { + vertical-align: bottom; + transform: translate(4px, 2.5px); +} + +.gui-input label .gui_tooltip p, +.gui_tooltip p { + margin: 0; + padding: 0; + color: black; +} + +.gui_tooltip .tooltip_text { + margin: 0; + padding: 0; +} + +.gui_tooltip .tooltip_text { + position: absolute; + width: max-content; + max-width: 70vw; + visibility: hidden; + background-color: white; + border: 1px solid whitesmoke; + padding: 10px; + border-radius: 8px; + z-index: 99999; + font-weight: lighter; + line-height: normal; + box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px; + inset: 0px auto auto 0px; +} + +.gui_tooltip:hover .tooltip_text { + visibility: visible; +} + +.tooltip_text .gui_tooltip--overflown { + top: 100%; + left: 50%; + margin-left: -100px; +} + +/* Tooltip positions */ +@media (max-width: 768px) { + .gui_tooltip .tooltip_text { + top: 100%; + left: 50%; + margin-left: -100px; + } +} + +@media (min-width: 768px) { + .gui_tooltip .tooltip_text { + max-width: 40vw; + } + + .gui_tooltip--right .tooltip_text { + top: -5px; + left: 150%; + } + + .gui_tooltip--left .tooltip_text { + top: -5px; + right: 105%; + } + + .gui_tooltip--top .tooltip_text { + bottom: 100%; + left: 50%; + margin-left: -60px; + } + + .gui_tooltip--bottom .tooltip_text { + top: 100%; + left: 50%; + margin-left: -60px; + } +} diff --git a/py/gooey_gui/components/common.py b/py/gooey_gui/components/common.py index 2a44f73..d1b610d 100644 --- a/py/gooey_gui/components/common.py +++ b/py/gooey_gui/components/common.py @@ -348,6 +348,8 @@ def text_area( placeholder: str = None, disabled: bool = False, label_visibility: LabelVisibility = "visible", + tooltip: str | None = None, + tooltip_direction: typing.Literal["left", "right"] = "right", **props, ) -> str: style = props.setdefault("style", {}) @@ -384,6 +386,8 @@ def text_area( help=help, placeholder=placeholder, disabled=disabled, + tooltip=tooltip, + tooltip_direction=tooltip_direction, **props, ), ).mount() @@ -935,6 +939,7 @@ def checkbox( key: str = None, help: str = None, *, + tooltip: str | None = None, disabled: bool = False, label_visibility: LabelVisibility = "visible", **props, @@ -948,6 +953,7 @@ def checkbox( disabled=disabled, label_visibility=label_visibility, default_value_attr="defaultChecked", + tooltip=tooltip, **props, ) return bool(value) @@ -963,6 +969,7 @@ def _input_widget( disabled: bool = False, label_visibility: LabelVisibility = "visible", default_value_attr: str = "defaultValue", + tooltip: str | None = None, **kwargs, ) -> typing.Any: # if key: @@ -982,6 +989,7 @@ def _input_widget( default_value_attr: value, "help": help, "disabled": disabled, + "tooltip": tooltip, **kwargs, }, ).mount()