border styles
This commit is contained in:
@@ -18,6 +18,7 @@ TODO:
|
|||||||
9. Installer should register **gurt://** as a valid protocol thru the registry.
|
9. Installer should register **gurt://** as a valid protocol thru the registry.
|
||||||
10. < input type=**datetime** />, essentially a type "date" but with a vertical separator, then `mm | ss | FORMAT` layout for time.
|
10. < input type=**datetime** />, essentially a type "date" but with a vertical separator, then `mm | ss | FORMAT` layout for time.
|
||||||
11. **< table >** component. [🔗 Related Godot proposal](https://github.com/godotengine/godot-proposals/issues/97)
|
11. **< table >** component. [🔗 Related Godot proposal](https://github.com/godotengine/godot-proposals/issues/97)
|
||||||
|
12. **< canvas >** component should be theoretically impossible by exposing Godot `_draw()` APIs to Lua.
|
||||||
|
|
||||||
Issues:
|
Issues:
|
||||||
1. **< br />** counts as 1 element in **WebsiteContainer**, therefore despite being (0,0) in size, it counts as double in spacing
|
1. **< br />** counts as 1 element in **WebsiteContainer**, therefore despite being (0,0) in size, it counts as double in spacing
|
||||||
|
|||||||
@@ -508,6 +508,86 @@ static func parse_utility_class_internal(rule: CSSRule, utility_name: String) ->
|
|||||||
rule.properties["my-auto"] = true
|
rule.properties["my-auto"] = true
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Apply border properties
|
||||||
|
var apply_border = func(side: String, width: String = "", color = null, style: String = "solid"):
|
||||||
|
var prefix = "border" + ("-" + side if side != "" else "")
|
||||||
|
if width != "":
|
||||||
|
rule.properties[prefix + "-width"] = width
|
||||||
|
if color != null:
|
||||||
|
rule.properties[prefix + "-color"] = color
|
||||||
|
if style != "":
|
||||||
|
rule.properties[prefix + "-style"] = style
|
||||||
|
|
||||||
|
# Handle border utilities
|
||||||
|
if utility_name == "border":
|
||||||
|
apply_border.call("", "1px", Color.BLACK)
|
||||||
|
return
|
||||||
|
|
||||||
|
if utility_name == "border-none":
|
||||||
|
rule.properties["border-style"] = "none"
|
||||||
|
return
|
||||||
|
|
||||||
|
# Individual border sides - pattern: border-{side}-{value}
|
||||||
|
var border_sides = ["t", "r", "b", "l"]
|
||||||
|
var side_map = {"t": "top", "r": "right", "b": "bottom", "l": "left"}
|
||||||
|
|
||||||
|
for side in border_sides:
|
||||||
|
var short_side = side
|
||||||
|
var full_side = side_map[side]
|
||||||
|
|
||||||
|
# Basic side border (e.g., border-t)
|
||||||
|
if utility_name == "border-" + short_side:
|
||||||
|
apply_border.call(full_side, "1px")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Side with value (e.g., border-t-2, border-t-red-500)
|
||||||
|
if utility_name.begins_with("border-" + short_side + "-"):
|
||||||
|
var val = utility_name.substr(9) # after "border-X-"
|
||||||
|
|
||||||
|
# Check for bracket notation first
|
||||||
|
if utility_name.begins_with("border-" + short_side + "-[") and utility_name.ends_with("]"):
|
||||||
|
var value = SizeUtils.extract_bracket_content(utility_name, 9)
|
||||||
|
if value.begins_with("#") or ColorUtils.parse_color(value) != null:
|
||||||
|
apply_border.call(full_side, "", ColorUtils.parse_color(value))
|
||||||
|
else:
|
||||||
|
apply_border.call(full_side, value)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check if it's a numeric width
|
||||||
|
if val.is_valid_int():
|
||||||
|
apply_border.call(full_side, str(int(val)) + "px")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check if it's a color
|
||||||
|
var color = ColorUtils.get_color(val)
|
||||||
|
if color != null:
|
||||||
|
apply_border.call(full_side, "", color)
|
||||||
|
return
|
||||||
|
|
||||||
|
# General border width (e.g., border-2)
|
||||||
|
if utility_name.begins_with("border-"):
|
||||||
|
var val = utility_name.substr(7)
|
||||||
|
|
||||||
|
# Custom border width like border-[2px]
|
||||||
|
if utility_name.begins_with("border-[") and utility_name.ends_with("]"):
|
||||||
|
var value = SizeUtils.extract_bracket_content(utility_name, 7)
|
||||||
|
if value.begins_with("#"):
|
||||||
|
apply_border.call("", "", ColorUtils.parse_color(value))
|
||||||
|
else:
|
||||||
|
apply_border.call("", value)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Numeric width
|
||||||
|
if val.is_valid_int():
|
||||||
|
apply_border.call("", str(int(val)) + "px")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Color name
|
||||||
|
var color = ColorUtils.get_color(val)
|
||||||
|
if color != null:
|
||||||
|
apply_border.call("", "", color)
|
||||||
|
return
|
||||||
|
|
||||||
# Handle more utility classes as needed
|
# Handle more utility classes as needed
|
||||||
# Add more cases here for other utilities
|
# Add more cases here for other utilities
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ pre { text-xl font-mono }
|
|||||||
button { bg-[#1b1b1b] rounded-md text-white hover:bg-[#2a2a2a] active:bg-[#101010] }
|
button { bg-[#1b1b1b] rounded-md text-white hover:bg-[#2a2a2a] active:bg-[#101010] }
|
||||||
"""
|
"""
|
||||||
|
|
||||||
var HTML_CONTENT = """<head>
|
var HTML_CONTENT2 = """<head>
|
||||||
<title>My Custom Dashboard</title>
|
<title>My Custom Dashboard</title>
|
||||||
<icon src="https://cdn-icons-png.flaticon.com/512/1828/1828774.png">
|
<icon src="https://cdn-icons-png.flaticon.com/512/1828/1828774.png">
|
||||||
<meta name="theme-color" content="#1a202c">
|
<meta name="theme-color" content="#1a202c">
|
||||||
@@ -99,7 +99,7 @@ var HTML_CONTENT = """<head>
|
|||||||
|
|
||||||
</body>
|
</body>
|
||||||
""".to_utf8_buffer()
|
""".to_utf8_buffer()
|
||||||
var HTML_CONTENT2 = """<head>
|
var HTML_CONTENT = """<head>
|
||||||
<title>My cool web</title>
|
<title>My cool web</title>
|
||||||
<icon src=\"https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Google_%22G%22_logo.svg/768px-Google_%22G%22_logo.svg.png\">
|
<icon src=\"https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Google_%22G%22_logo.svg/768px-Google_%22G%22_logo.svg.png\">
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ var HTML_CONTENT2 = """<head>
|
|||||||
<code>this is code<span> THIS IS A SPAN AND SHOULDNT BE ANY DIFFERENT</span></code>
|
<code>this is code<span> THIS IS A SPAN AND SHOULDNT BE ANY DIFFERENT</span></code>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a href=\"https://youtube.com\">Hello gang</a>
|
<a href="https://youtube.com">Hello gang</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
@@ -152,9 +152,36 @@ both spaces and
|
|||||||
line breaks
|
line breaks
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p style=\"text-center w-32 h-32\">
|
<p style="text-center w-32 h-32">
|
||||||
So
|
So
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<!-- Border examples -->
|
||||||
|
<div style="border p-2 mb-2">border</div>
|
||||||
|
<div style="border-2 p-2 mb-2">border-2</div>
|
||||||
|
<div style="border-4 p-2 mb-2">border-4</div>
|
||||||
|
<div style="border-2 border-red-500 p-2 mb-2">border-2 border-red-500</div>
|
||||||
|
<div style="border p-2 mb-2">border-solid</div>
|
||||||
|
<div style="border border-dashed p-2 mb-2">border-dashed</div>
|
||||||
|
<div style="border border-dotted p-2 mb-2">border-dotted</div>
|
||||||
|
<div style="border-none p-2 mb-2">border-none</div>
|
||||||
|
<div style="border-t p-2 mb-2">border-t</div>
|
||||||
|
<div style="border-r p-2 mb-2">border-r</div>
|
||||||
|
<div style="border-b p-2 mb-2">border-b</div>
|
||||||
|
<div style="border-l p-2 mb-2">border-l</div>
|
||||||
|
<div style="border-t-4 p-2 mb-2">border-t-4</div>
|
||||||
|
<div style="border-b-2 p-2 mb-2">border-b-2</div>
|
||||||
|
<div style="border-l-6 p-2 mb-2">border-l-6</div>
|
||||||
|
<div style="border-t-3 border-green-500 p-2 mb-2">border-t-3 border-green-500</div>
|
||||||
|
<div style="border border-white p-2 mb-2">border-white</div>
|
||||||
|
<div style="border border-black p-2 mb-2">border-black</div>
|
||||||
|
<div style="border border-transparent p-2 mb-2">border-transparent</div>
|
||||||
|
<div style="border border-gray-400 p-2 mb-2">border-gray-400</div>
|
||||||
|
<div style="border border-slate-700 p-2 mb-2">border-slate-700</div>
|
||||||
|
<div style="border border-red-500 p-2 mb-2">border-red-500</div>
|
||||||
|
<div style="border border-green-600 p-2 mb-2">border-green-600</div>
|
||||||
|
<div style="border border-blue-400 p-2 mb-2">border-blue-400</div>
|
||||||
|
<div style="border border-yellow-300 p-2 mb-2">border-yellow-300</div>
|
||||||
|
|
||||||
<select style=\"text-center max-w-5 max-h-32\">
|
<select style=\"text-center max-w-5 max-h-32\">
|
||||||
<option value=\"test1\">Test 1</option>
|
<option value=\"test1\">Test 1</option>
|
||||||
|
|||||||
@@ -84,14 +84,30 @@ static func apply_element_styles(node: Control, element: HTMLParser.HTMLElement,
|
|||||||
if label and label != node:
|
if label and label != node:
|
||||||
label.anchors_preset = Control.PRESET_FULL_RECT
|
label.anchors_preset = Control.PRESET_FULL_RECT
|
||||||
|
|
||||||
# Apply background color and border radius
|
# Apply background color, border radius, borders
|
||||||
if styles.has("background-color") or styles.has("border-radius"):
|
var needs_styling = styles.has("background-color") or styles.has("border-radius") or styles.has("border-width") or styles.has("border-top-width") or styles.has("border-right-width") or styles.has("border-bottom-width") or styles.has("border-left-width") or styles.has("border-color")
|
||||||
|
|
||||||
|
if needs_styling:
|
||||||
var target_node_for_bg = node if node is FlexContainer else label
|
var target_node_for_bg = node if node is FlexContainer else label
|
||||||
if target_node_for_bg:
|
if target_node_for_bg:
|
||||||
if styles.has("background-color"):
|
if styles.has("background-color"):
|
||||||
target_node_for_bg.set_meta("custom_css_background_color", styles["background-color"])
|
target_node_for_bg.set_meta("custom_css_background_color", styles["background-color"])
|
||||||
if styles.has("border-radius"):
|
if styles.has("border-radius"):
|
||||||
target_node_for_bg.set_meta("custom_css_border_radius", styles["border-radius"])
|
target_node_for_bg.set_meta("custom_css_border_radius", styles["border-radius"])
|
||||||
|
|
||||||
|
# Border properties
|
||||||
|
if styles.has("border-width"):
|
||||||
|
target_node_for_bg.set_meta("custom_css_border_width", styles["border-width"])
|
||||||
|
if styles.has("border-color"):
|
||||||
|
target_node_for_bg.set_meta("custom_css_border_color", styles["border-color"])
|
||||||
|
|
||||||
|
# Individual border sides
|
||||||
|
var border_sides = ["top", "right", "bottom", "left"]
|
||||||
|
for side in border_sides:
|
||||||
|
var width_key = "border-" + side + "-width"
|
||||||
|
if styles.has(width_key):
|
||||||
|
target_node_for_bg.set_meta("custom_css_" + width_key.replace("-", "_"), styles[width_key])
|
||||||
|
|
||||||
if target_node_for_bg.has_method("add_background_rect"):
|
if target_node_for_bg.has_method("add_background_rect"):
|
||||||
target_node_for_bg.call_deferred("add_background_rect")
|
target_node_for_bg.call_deferred("add_background_rect")
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,60 @@ static func create_stylebox_from_styles(styles: Dictionary = {}, container: Cont
|
|||||||
style_box.corner_radius_bottom_left = radius
|
style_box.corner_radius_bottom_left = radius
|
||||||
style_box.corner_radius_bottom_right = radius
|
style_box.corner_radius_bottom_right = radius
|
||||||
|
|
||||||
|
# Border properties
|
||||||
|
var has_border = false
|
||||||
|
|
||||||
|
style_box.border_width_top = 0
|
||||||
|
style_box.border_width_right = 0
|
||||||
|
style_box.border_width_bottom = 0
|
||||||
|
style_box.border_width_left = 0
|
||||||
|
|
||||||
|
var general_border_width = null
|
||||||
|
if styles.has("border-width"):
|
||||||
|
general_border_width = styles["border-width"]
|
||||||
|
elif container and container.has_meta("custom_css_border_width"):
|
||||||
|
general_border_width = container.get_meta("custom_css_border_width")
|
||||||
|
|
||||||
|
if general_border_width:
|
||||||
|
has_border = true
|
||||||
|
var parsed_width = StyleManager.parse_size(general_border_width)
|
||||||
|
style_box.border_width_top = parsed_width
|
||||||
|
style_box.border_width_right = parsed_width
|
||||||
|
style_box.border_width_bottom = parsed_width
|
||||||
|
style_box.border_width_left = parsed_width
|
||||||
|
|
||||||
|
var individual_border_keys = [
|
||||||
|
["border-top-width", "border_width_top"],
|
||||||
|
["border-right-width", "border_width_right"],
|
||||||
|
["border-bottom-width", "border_width_bottom"],
|
||||||
|
["border-left-width", "border_width_left"]
|
||||||
|
]
|
||||||
|
|
||||||
|
for pair in individual_border_keys:
|
||||||
|
var style_key = pair[0]
|
||||||
|
var property_name = pair[1]
|
||||||
|
var width = null
|
||||||
|
var meta_key = "custom_css_" + style_key.replace("-", "_")
|
||||||
|
|
||||||
|
if styles.has(style_key):
|
||||||
|
width = styles[style_key]
|
||||||
|
elif container and container.has_meta(meta_key):
|
||||||
|
width = container.get_meta(meta_key)
|
||||||
|
|
||||||
|
if width:
|
||||||
|
has_border = true
|
||||||
|
var parsed_width = StyleManager.parse_size(width)
|
||||||
|
style_box.set(property_name, parsed_width)
|
||||||
|
|
||||||
|
var border_color = Color.BLACK
|
||||||
|
if styles.has("border-color"):
|
||||||
|
border_color = styles["border-color"]
|
||||||
|
elif container and container.has_meta("custom_css_border_color"):
|
||||||
|
border_color = container.get_meta("custom_css_border_color")
|
||||||
|
|
||||||
|
if has_border:
|
||||||
|
style_box.border_color = border_color
|
||||||
|
|
||||||
# Padding as content margins
|
# Padding as content margins
|
||||||
var has_padding = false
|
var has_padding = false
|
||||||
if styles.size() > 0:
|
if styles.size() > 0:
|
||||||
@@ -114,4 +168,4 @@ static func create_panel_container_with_background(styles: Dictionary) -> PanelC
|
|||||||
return panel_container
|
return panel_container
|
||||||
|
|
||||||
static func needs_background_wrapper(styles: Dictionary) -> bool:
|
static func needs_background_wrapper(styles: Dictionary) -> bool:
|
||||||
return styles.has("background-color") or styles.has("border-radius") or styles.has("padding") or styles.has("padding-top") or styles.has("padding-right") or styles.has("padding-bottom") or styles.has("padding-left")
|
return styles.has("background-color") or styles.has("border-radius") or styles.has("padding") or styles.has("padding-top") or styles.has("padding-right") or styles.has("padding-bottom") or styles.has("padding-left") or styles.has("border-width") or styles.has("border-top-width") or styles.has("border-right-width") or styles.has("border-bottom-width") or styles.has("border-left-width") or styles.has("border-color") or styles.has("border-style") or styles.has("border-top-color") or styles.has("border-right-color") or styles.has("border-bottom-color") or styles.has("border-left-color")
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ extends RefCounted
|
|||||||
|
|
||||||
static var compiled_patterns: Array = []
|
static var compiled_patterns: Array = []
|
||||||
|
|
||||||
|
# TODO: hardcoded colors gotta be swapped with Tailwind colors. stuff like "text-red-500" is considered a selector class
|
||||||
static func init_patterns():
|
static func init_patterns():
|
||||||
if compiled_patterns.size() == 0:
|
if compiled_patterns.size() == 0:
|
||||||
var utility_patterns = [
|
var utility_patterns = [
|
||||||
@@ -28,6 +29,15 @@ static func init_patterns():
|
|||||||
"^rounded", # border radius
|
"^rounded", # border radius
|
||||||
"^basis-", # flex basis
|
"^basis-", # flex basis
|
||||||
"^(mx|my|m)-auto$", # margin auto for centering
|
"^(mx|my|m)-auto$", # margin auto for centering
|
||||||
|
"^border$", # general border
|
||||||
|
"^border-\\d+$", # border width (e.g., border-2)
|
||||||
|
"^border-\\[.*\\]$", # custom border width/color (e.g., border-[2px], border-[#ff0000])
|
||||||
|
"^border-none$", # border styles
|
||||||
|
"^border-(t|r|b|l)$", # individual border sides (e.g., border-t)
|
||||||
|
"^border-(t|r|b|l)-\\d+$", # individual border side widths (e.g., border-t-2)
|
||||||
|
"^border-(t|r|b|l)-\\[.*\\]$", # custom individual border sides (e.g., border-t-[2px])
|
||||||
|
"^border-(t|r|b|l)-(white|black|transparent|slate-\\d+|gray-\\d+|red-\\d+|green-\\d+|blue-\\d+|yellow-\\d+)$", # individual border side colors
|
||||||
|
"^border-(white|black|transparent|slate-\\d+|gray-\\d+|red-\\d+|green-\\d+|blue-\\d+|yellow-\\d+)$", # border colors
|
||||||
"^(hover|active):", # pseudo classes
|
"^(hover|active):", # pseudo classes
|
||||||
]
|
]
|
||||||
for pattern in utility_patterns:
|
for pattern in utility_patterns:
|
||||||
|
|||||||
@@ -132,6 +132,13 @@ func contains_hyperlink(element: HTMLParser.HTMLElement) -> bool:
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
func is_text_only_element(element: HTMLParser.HTMLElement) -> bool:
|
||||||
|
if element.children.size() == 0:
|
||||||
|
var text = element.get_collapsed_text()
|
||||||
|
return not text.is_empty()
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
func create_element_node(element: HTMLParser.HTMLElement, parser: HTMLParser) -> Control:
|
func create_element_node(element: HTMLParser.HTMLElement, parser: HTMLParser) -> Control:
|
||||||
var styles = parser.get_element_styles_with_inheritance(element, "", [])
|
var styles = parser.get_element_styles_with_inheritance(element, "", [])
|
||||||
var is_flex_container = styles.has("display") and ("flex" in styles["display"])
|
var is_flex_container = styles.has("display") and ("flex" in styles["display"])
|
||||||
@@ -269,7 +276,7 @@ func create_element_node_internal(element: HTMLParser.HTMLElement, parser: HTMLP
|
|||||||
node.init(element, parser)
|
node.init(element, parser)
|
||||||
"span", "b", "i", "u", "small", "mark", "code", "a":
|
"span", "b", "i", "u", "small", "mark", "code", "a":
|
||||||
node = SPAN.instantiate()
|
node = SPAN.instantiate()
|
||||||
node.init(element)
|
node.init(element, parser)
|
||||||
"ul":
|
"ul":
|
||||||
node = UL.instantiate()
|
node = UL.instantiate()
|
||||||
website_container.add_child(node)
|
website_container.add_child(node)
|
||||||
@@ -282,24 +289,37 @@ func create_element_node_internal(element: HTMLParser.HTMLElement, parser: HTMLP
|
|||||||
return node
|
return node
|
||||||
"li":
|
"li":
|
||||||
node = LI.instantiate()
|
node = LI.instantiate()
|
||||||
node.init(element)
|
node.init(element, parser)
|
||||||
"select":
|
"select":
|
||||||
node = SELECT.instantiate()
|
node = SELECT.instantiate()
|
||||||
node.init(element)
|
node.init(element)
|
||||||
"option":
|
"option":
|
||||||
node = OPTION.instantiate()
|
node = OPTION.instantiate()
|
||||||
node.init(element)
|
node.init(element, parser)
|
||||||
"textarea":
|
"textarea":
|
||||||
node = TEXTAREA.instantiate()
|
node = TEXTAREA.instantiate()
|
||||||
node.init(element)
|
node.init(element)
|
||||||
"div":
|
"div":
|
||||||
var styles = parser.get_element_styles_with_inheritance(element, "", [])
|
var styles = parser.get_element_styles_with_inheritance(element, "", [])
|
||||||
|
|
||||||
|
# Create div container
|
||||||
if BackgroundUtils.needs_background_wrapper(styles):
|
if BackgroundUtils.needs_background_wrapper(styles):
|
||||||
node = BackgroundUtils.create_panel_container_with_background(styles)
|
node = BackgroundUtils.create_panel_container_with_background(styles)
|
||||||
else:
|
else:
|
||||||
node = VBoxContainer.new()
|
node = DIV.instantiate()
|
||||||
node.name = "Div"
|
node.init(element)
|
||||||
|
|
||||||
|
var has_only_text = is_text_only_element(element)
|
||||||
|
|
||||||
|
if has_only_text:
|
||||||
|
var p_node = P.instantiate()
|
||||||
|
p_node.init(element)
|
||||||
|
|
||||||
|
var container_for_children = node
|
||||||
|
if node is PanelContainer and node.get_child_count() > 0:
|
||||||
|
container_for_children = node.get_child(0) # The VBoxContainer inside
|
||||||
|
|
||||||
|
safe_add_child(container_for_children, p_node)
|
||||||
_:
|
_:
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user