[ENG-3895] [ENG-3896] Update styling for shiki code block
This commit is contained in:
parent
e3cbe79c53
commit
e6cb4185b2
@ -7,16 +7,62 @@ from typing import Any, Literal, Optional, Union
|
|||||||
|
|
||||||
from reflex.base import Base
|
from reflex.base import Base
|
||||||
from reflex.components.component import Component, ComponentNamespace
|
from reflex.components.component import Component, ComponentNamespace
|
||||||
|
from reflex.components.core.colors import color
|
||||||
from reflex.components.core.cond import color_mode_cond
|
from reflex.components.core.cond import color_mode_cond
|
||||||
|
from reflex.components.el.elements.forms import Button
|
||||||
from reflex.components.lucide.icon import Icon
|
from reflex.components.lucide.icon import Icon
|
||||||
from reflex.components.radix.themes.components.button import Button
|
|
||||||
from reflex.components.radix.themes.layout.box import Box
|
from reflex.components.radix.themes.layout.box import Box
|
||||||
from reflex.event import set_clipboard
|
from reflex.event import call_script
|
||||||
from reflex.style import Style
|
from reflex.style import Style
|
||||||
from reflex.utils.imports import ImportVar
|
from reflex.utils.imports import ImportVar
|
||||||
from reflex.vars.base import LiteralVar, Var
|
from reflex.vars.base import LiteralVar, Var
|
||||||
from reflex.vars.function import FunctionStringVar
|
from reflex.vars.function import FunctionStringVar
|
||||||
|
|
||||||
|
|
||||||
|
def copy_script(id: str, code: str) -> Any:
|
||||||
|
"""Copy script for the code block.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id (str): The ID of the button element.
|
||||||
|
code (str): The code to be copied.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Any: The result of calling the script.
|
||||||
|
"""
|
||||||
|
return call_script(
|
||||||
|
f"""
|
||||||
|
const button = document.getElementById('{id}');
|
||||||
|
const icon = button.querySelector('svg');
|
||||||
|
const originalPath = icon.innerHTML;
|
||||||
|
const checkmarkPath = '<polyline points="20 6 9 17 4 12"></polyline>';
|
||||||
|
|
||||||
|
function transition(element, scale, opacity) {{
|
||||||
|
element.style.transform = `scale(${{scale}})`;
|
||||||
|
element.style.opacity = opacity;
|
||||||
|
}}
|
||||||
|
|
||||||
|
navigator.clipboard.writeText(`{code}`).then(() => {{
|
||||||
|
transition(icon, 0, '0');
|
||||||
|
|
||||||
|
setTimeout(() => {{
|
||||||
|
icon.innerHTML = checkmarkPath;
|
||||||
|
icon.setAttribute('viewBox', '0 0 24 24');
|
||||||
|
transition(icon, 1, '1');
|
||||||
|
setTimeout(() => {{
|
||||||
|
transition(icon, 0, '0');
|
||||||
|
setTimeout(() => {{
|
||||||
|
icon.innerHTML = originalPath;
|
||||||
|
transition(icon, 1, '1');
|
||||||
|
}}, 125);
|
||||||
|
}}, 600);
|
||||||
|
}}, 125);
|
||||||
|
}}).catch(err => {{
|
||||||
|
console.error('Failed to copy text: ', err);
|
||||||
|
}});
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
SHIKIJS_TRANSFORMER_FNS = {
|
SHIKIJS_TRANSFORMER_FNS = {
|
||||||
"transformerNotationDiff",
|
"transformerNotationDiff",
|
||||||
"transformerNotationHighlight",
|
"transformerNotationHighlight",
|
||||||
@ -32,7 +78,13 @@ SHIKIJS_TRANSFORMER_FNS = {
|
|||||||
"transformerRemoveNotationEscape",
|
"transformerRemoveNotationEscape",
|
||||||
}
|
}
|
||||||
LINE_NUMBER_STYLING = {
|
LINE_NUMBER_STYLING = {
|
||||||
"code": {"counter-reset": "step", "counter-increment": "step 0"},
|
"code": {
|
||||||
|
"counter-reset": "step",
|
||||||
|
"counter-increment": "step 0",
|
||||||
|
"display": "grid",
|
||||||
|
"line-height": "1.7",
|
||||||
|
"font-size": "0.875em",
|
||||||
|
},
|
||||||
"code .line::before": {
|
"code .line::before": {
|
||||||
"content": "counter(step)",
|
"content": "counter(step)",
|
||||||
"counter-increment": "step",
|
"counter-increment": "step",
|
||||||
@ -43,6 +95,15 @@ LINE_NUMBER_STYLING = {
|
|||||||
"color": "rgba(115,138,148,.4)",
|
"color": "rgba(115,138,148,.4)",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
BOX_PARENT_STYLING = {
|
||||||
|
"pre": {
|
||||||
|
"margin": "0",
|
||||||
|
"padding": "24px",
|
||||||
|
"background": "transparent",
|
||||||
|
"overflow-x": "auto",
|
||||||
|
"border-radius": "6px",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
THEME_MAPPING = {
|
THEME_MAPPING = {
|
||||||
"light": "one-light",
|
"light": "one-light",
|
||||||
@ -336,18 +397,81 @@ class ShikiJsTransformer(ShikiBaseTransformers):
|
|||||||
]
|
]
|
||||||
style: Optional[Style] = Style(
|
style: Optional[Style] = Style(
|
||||||
{
|
{
|
||||||
".line": {"display": "inline", "padding-bottom": "0"},
|
"code": {"line-height": "1.7", "font-size": "0.875em", "display": "grid"},
|
||||||
|
# Diffs
|
||||||
".diff": {
|
".diff": {
|
||||||
|
"margin": "0 -24px",
|
||||||
|
"padding": "0 24px",
|
||||||
|
"width": "calc(100% + 48px)",
|
||||||
"display": "inline-block",
|
"display": "inline-block",
|
||||||
"width": "100vw",
|
|
||||||
"margin": "0 -12px",
|
|
||||||
"padding": "0 12px",
|
|
||||||
},
|
},
|
||||||
".diff.add": {"background-color": "#0505"},
|
".diff.add": {
|
||||||
".diff.remove": {"background-color": "#8005"},
|
"background-color": "rgba(16, 185, 129, .14)",
|
||||||
".diff:before": {"position": "absolute", "left": "40px"},
|
"position": "relative",
|
||||||
".has-focused .line": {"filter": "blur(0.095rem)"},
|
},
|
||||||
".has-focused .focused": {"filter": "blur(0)"},
|
".diff.remove": {
|
||||||
|
"background-color": "rgba(244, 63, 94, .14)",
|
||||||
|
"opacity": "0.7",
|
||||||
|
"position": "relative",
|
||||||
|
},
|
||||||
|
".diff.remove:after": {
|
||||||
|
"position": "absolute",
|
||||||
|
"left": "10px",
|
||||||
|
"content": "'-'",
|
||||||
|
"color": "#b34e52",
|
||||||
|
},
|
||||||
|
".diff.add:after": {
|
||||||
|
"position": "absolute",
|
||||||
|
"left": "10px",
|
||||||
|
"content": "'+'",
|
||||||
|
"color": "#18794e",
|
||||||
|
},
|
||||||
|
# Highlight
|
||||||
|
".highlighted": {
|
||||||
|
"background-color": "rgba(142, 150, 170, .14)",
|
||||||
|
"margin": "0 -24px",
|
||||||
|
"padding": "0 24px",
|
||||||
|
"width": "calc(100% + 48px)",
|
||||||
|
"display": "inline-block",
|
||||||
|
},
|
||||||
|
".highlighted.error": {
|
||||||
|
"background-color": "rgba(244, 63, 94, .14)",
|
||||||
|
},
|
||||||
|
".highlighted.warning": {
|
||||||
|
"background-color": "rgba(234, 179, 8, .14)",
|
||||||
|
},
|
||||||
|
# Highlighted Word
|
||||||
|
".highlighted-word": {
|
||||||
|
"background-color": color("gray", 2),
|
||||||
|
"border": f"1px solid {color('gray', 5)}",
|
||||||
|
"padding": "1px 3px",
|
||||||
|
"margin": "-1px -3px",
|
||||||
|
"border-radius": "4px",
|
||||||
|
},
|
||||||
|
# Focused Lines
|
||||||
|
".has-focused .line:not(.focused)": {
|
||||||
|
"opacity": "0.7",
|
||||||
|
"filter": "blur(0.095rem)",
|
||||||
|
"transition": "filter .35s, opacity .35s",
|
||||||
|
},
|
||||||
|
".has-focused:hover .line:not(.focused)": {
|
||||||
|
"opacity": "1",
|
||||||
|
"filter": "none",
|
||||||
|
},
|
||||||
|
# White Space
|
||||||
|
# ".tab, .space": {
|
||||||
|
# "position": "relative",
|
||||||
|
# },
|
||||||
|
# ".tab::before": {
|
||||||
|
# "content": "'⇥'",
|
||||||
|
# "position": "absolute",
|
||||||
|
# "opacity": "0.3",
|
||||||
|
# },
|
||||||
|
# ".space::before": {
|
||||||
|
# "content": "'·'",
|
||||||
|
# "position": "absolute",
|
||||||
|
# "opacity": "0.3",
|
||||||
|
# },
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -362,9 +486,11 @@ class ShikiJsTransformer(ShikiBaseTransformers):
|
|||||||
style = kwargs.pop("style", None)
|
style = kwargs.pop("style", None)
|
||||||
if fns:
|
if fns:
|
||||||
kwargs["fns"] = [
|
kwargs["fns"] = [
|
||||||
FunctionStringVar.create(x)
|
(
|
||||||
if not isinstance(x, FunctionStringVar)
|
FunctionStringVar.create(x)
|
||||||
else x
|
if not isinstance(x, FunctionStringVar)
|
||||||
|
else x
|
||||||
|
)
|
||||||
for x in fns
|
for x in fns
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -441,7 +567,7 @@ class ShikiCodeBlock(Component):
|
|||||||
return Box.create(
|
return Box.create(
|
||||||
code_block,
|
code_block,
|
||||||
*children[1:],
|
*children[1:],
|
||||||
style=Style(transformer_styles),
|
style=Style({**transformer_styles, **BOX_PARENT_STYLING}),
|
||||||
**code_wrapper_props,
|
**code_wrapper_props,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -459,9 +585,11 @@ class ShikiCodeBlock(Component):
|
|||||||
imports[transformer.library].extend(
|
imports[transformer.library].extend(
|
||||||
[ImportVar(tag=str(fn)) for fn in transformer.fns]
|
[ImportVar(tag=str(fn)) for fn in transformer.fns]
|
||||||
)
|
)
|
||||||
self.lib_dependencies.append(
|
(
|
||||||
transformer.library
|
self.lib_dependencies.append(transformer.library)
|
||||||
) if transformer.library not in self.lib_dependencies else None
|
if transformer.library not in self.lib_dependencies
|
||||||
|
else None
|
||||||
|
)
|
||||||
return imports
|
return imports
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -582,13 +710,40 @@ class ShikiHighLevelCodeBlock(ShikiCodeBlock):
|
|||||||
|
|
||||||
if can_copy:
|
if can_copy:
|
||||||
code = children[0]
|
code = children[0]
|
||||||
|
button_id = (
|
||||||
|
f"copy-button-{hash(code)}" # Generate a unique ID for each button
|
||||||
|
)
|
||||||
copy_button = ( # type: ignore
|
copy_button = ( # type: ignore
|
||||||
copy_button
|
copy_button
|
||||||
if copy_button is not None
|
if copy_button is not None
|
||||||
else Button.create(
|
else Button.create(
|
||||||
Icon.create(tag="copy"),
|
Icon.create(tag="copy", size=16, color=color("gray", 11)),
|
||||||
on_click=set_clipboard(code),
|
id=button_id,
|
||||||
style=Style({"position": "absolute", "top": "0.5em", "right": "0"}),
|
on_click=copy_script(button_id, code),
|
||||||
|
style=Style(
|
||||||
|
{
|
||||||
|
"position": "absolute",
|
||||||
|
"top": "4px",
|
||||||
|
"right": "4px",
|
||||||
|
"background": color("gray", 3),
|
||||||
|
"border": "1px solid",
|
||||||
|
"border-color": color("gray", 5),
|
||||||
|
"border-radius": "6px",
|
||||||
|
"padding": "5px",
|
||||||
|
"opacity": "1",
|
||||||
|
"cursor": "pointer",
|
||||||
|
"_hover": {
|
||||||
|
"background": color("gray", 4),
|
||||||
|
},
|
||||||
|
"transition": "background 0.250s ease-out",
|
||||||
|
"&>svg": {
|
||||||
|
"transition": "transform 0.250s ease-out, opacity 0.250s ease-out",
|
||||||
|
},
|
||||||
|
"_active": {
|
||||||
|
"background": color("gray", 5),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
@ -12,6 +12,8 @@ from reflex.style import Style
|
|||||||
from reflex.vars.base import Var
|
from reflex.vars.base import Var
|
||||||
from reflex.vars.function import FunctionStringVar
|
from reflex.vars.function import FunctionStringVar
|
||||||
|
|
||||||
|
def copy_script(id: str, code: str) -> Any: ...
|
||||||
|
|
||||||
SHIKIJS_TRANSFORMER_FNS = {
|
SHIKIJS_TRANSFORMER_FNS = {
|
||||||
"transformerNotationDiff",
|
"transformerNotationDiff",
|
||||||
"transformerNotationHighlight",
|
"transformerNotationHighlight",
|
||||||
@ -25,7 +27,13 @@ SHIKIJS_TRANSFORMER_FNS = {
|
|||||||
"transformerRemoveNotationEscape",
|
"transformerRemoveNotationEscape",
|
||||||
}
|
}
|
||||||
LINE_NUMBER_STYLING = {
|
LINE_NUMBER_STYLING = {
|
||||||
"code": {"counter-reset": "step", "counter-increment": "step 0"},
|
"code": {
|
||||||
|
"counter-reset": "step",
|
||||||
|
"counter-increment": "step 0",
|
||||||
|
"display": "grid",
|
||||||
|
"line-height": "1.7",
|
||||||
|
"font-size": "0.875em",
|
||||||
|
},
|
||||||
"code .line::before": {
|
"code .line::before": {
|
||||||
"content": "counter(step)",
|
"content": "counter(step)",
|
||||||
"counter-increment": "step",
|
"counter-increment": "step",
|
||||||
@ -36,6 +44,15 @@ LINE_NUMBER_STYLING = {
|
|||||||
"color": "rgba(115,138,148,.4)",
|
"color": "rgba(115,138,148,.4)",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
BOX_PARENT_STYLING = {
|
||||||
|
"pre": {
|
||||||
|
"margin": "0",
|
||||||
|
"padding": "24px",
|
||||||
|
"background": "transparent",
|
||||||
|
"overflow-x": "auto",
|
||||||
|
"border-radius": "6px",
|
||||||
|
}
|
||||||
|
}
|
||||||
THEME_MAPPING = {
|
THEME_MAPPING = {
|
||||||
"light": "one-light",
|
"light": "one-light",
|
||||||
"dark": "one-dark-pro",
|
"dark": "one-dark-pro",
|
||||||
|
Loading…
Reference in New Issue
Block a user