diff --git a/README.md b/README.md index a09d98a..1b55a44 100644 --- a/README.md +++ b/README.md @@ -19,51 +19,16 @@ TODO: 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) 12. **< canvas >** component should be theoretically impossible by exposing Godot `_draw()` APIs to Lua. +13. `grid` display property for CSS, using `GridContainer` in Godot. Issues: 1. **< br />** counts as 1 element in **WebsiteContainer**, therefore despite being (0,0) in size, it counts as double in spacing 2. **Tween** API doesn't modify CSS, it operates independently at Godot level. 3. Certain properties like `scale` and `rotate` don't apply to the `active` pseudo-class because they rely on mouse_enter and mouse_exit events 4. `
Box
` something like this has the "Box" text (presumably the PanelContainer) as the target of the hover, not the div itself (which has the w/h size) +5. font in button doesn't comply with CSS, its the projects default Notes: - **< input />** is sort-of inline in normal web. We render it as a block element (new-line). - A single `RichTextLabel` for inline text tags should stop, we should use invididual ones so it's easier to style and achieve separation through a `vboxcontainer`. - Fonts use **Flash of Unstyled Text (FOUT)** as opposed to **Flash of Invisible Text (FOIT)**, meaning the text with custom fonts will render with a generic font (sans-serif) while the custom ones downloads. - -Supported styles: - -- **Font style:** - - `font-bold` - - `font-italic` - - `underline` -- **Font size:** - - `text-xs` → 12 - - `text-sm` → 14 - - `text-base` → 16 - - `text-lg` → 18 - - `text-xl` → 20 - - `text-2xl` → 24 - - `text-3xl` → 30 - - `text-4xl` → 36 - - `text-5xl` → 48 - - `text-6xl` → 60 -- **Font family:** - - `font-mono` -- **Text color:** - - `text-[color]` -- **Background color:** - - `bg-[color]` -- **Flexbox** -- `flex` / `inline-flex` (display: flex/inline-flex) -- `flex-row`, `flex-row-reverse`, `flex-col`, `flex-col-reverse` (flex-direction) -- `flex-nowrap`, `flex-wrap`, `flex-wrap-reverse` (flex-wrap) -- `justify-start`, `justify-end`, `justify-center`, `justify-between`, `justify-around`, `justify-evenly` (justify-content) -- `items-start`, `items-end`, `items-center`, `items-baseline`, `items-stretch` (align-items) -- `content-start`, `content-end`, `content-center`, `content-between`, `content-around`, `content-evenly`, `content-stretch` (align-content) -- `gap-{size}`, `row-gap-{size}`, `col-gap-{size}` (gap, row-gap, column-gap) -- `flex-grow-{n}` (flex-grow) -- `flex-shrink-{n}` (flex-shrink) -- `basis-{size}` (flex-basis) -- `self-auto`, `self-start`, `self-end`, `self-center`, `self-stretch`, `self-baseline` (align-self) -- `order-{n}` (order) diff --git a/flumi/Assets/Icons/checkbox_white.svg b/flumi/Assets/Icons/checkbox_white.svg new file mode 100644 index 0000000..7abd527 --- /dev/null +++ b/flumi/Assets/Icons/checkbox_white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flumi/Assets/Icons/checkbox_white.svg.import b/flumi/Assets/Icons/checkbox_white.svg.import new file mode 100644 index 0000000..8069288 --- /dev/null +++ b/flumi/Assets/Icons/checkbox_white.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://blskvfjswul1d" +path="res://.godot/imported/checkbox_white.svg-3c05c756132e06b6df4f4ae643f84518.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/checkbox_white.svg" +dest_files=["res://.godot/imported/checkbox_white.svg-3c05c756132e06b6df4f4ae643f84518.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/flumi/Assets/Icons/download.svg b/flumi/Assets/Icons/download.svg new file mode 100644 index 0000000..b228cb9 --- /dev/null +++ b/flumi/Assets/Icons/download.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flumi/Assets/Icons/download.svg.import b/flumi/Assets/Icons/download.svg.import new file mode 100644 index 0000000..55417e9 --- /dev/null +++ b/flumi/Assets/Icons/download.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cbwitcygwoqdo" +path="res://.godot/imported/download.svg-a21cd5d191a2f0c8e42168f24a4d40ed.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/download.svg" +dest_files=["res://.godot/imported/download.svg-a21cd5d191a2f0c8e42168f24a4d40ed.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/flumi/Assets/Icons/ellipsis-vertical.svg b/flumi/Assets/Icons/ellipsis-vertical.svg new file mode 100644 index 0000000..4285526 --- /dev/null +++ b/flumi/Assets/Icons/ellipsis-vertical.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flumi/Assets/Icons/ellipsis-vertical.svg.import b/flumi/Assets/Icons/ellipsis-vertical.svg.import new file mode 100644 index 0000000..6dfe332 --- /dev/null +++ b/flumi/Assets/Icons/ellipsis-vertical.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cklatjc4m38dy" +path="res://.godot/imported/ellipsis-vertical.svg-294910634c008df812f7ef47e8a8a214.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/ellipsis-vertical.svg" +dest_files=["res://.godot/imported/ellipsis-vertical.svg-294910634c008df812f7ef47e8a8a214.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/flumi/Assets/Icons/external-link.svg b/flumi/Assets/Icons/external-link.svg new file mode 100644 index 0000000..3011ad2 --- /dev/null +++ b/flumi/Assets/Icons/external-link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flumi/Assets/Icons/external-link.svg.import b/flumi/Assets/Icons/external-link.svg.import new file mode 100644 index 0000000..dbfd633 --- /dev/null +++ b/flumi/Assets/Icons/external-link.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://du24f6em2nqwq" +path="res://.godot/imported/external-link.svg-075235ddf5518da7b64a7c5332224a40.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/external-link.svg" +dest_files=["res://.godot/imported/external-link.svg-075235ddf5518da7b64a7c5332224a40.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/flumi/Assets/Icons/hat-glasses.svg b/flumi/Assets/Icons/hat-glasses.svg new file mode 100644 index 0000000..2941f1a --- /dev/null +++ b/flumi/Assets/Icons/hat-glasses.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flumi/Assets/Icons/hat-glasses.svg.import b/flumi/Assets/Icons/hat-glasses.svg.import new file mode 100644 index 0000000..f5961df --- /dev/null +++ b/flumi/Assets/Icons/hat-glasses.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dwxquqmmd6dqx" +path="res://.godot/imported/hat-glasses.svg-a7dbfb316472ae1702496a78a0ce47e7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/hat-glasses.svg" +dest_files=["res://.godot/imported/hat-glasses.svg-a7dbfb316472ae1702496a78a0ce47e7.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/flumi/Assets/Icons/history.svg b/flumi/Assets/Icons/history.svg new file mode 100644 index 0000000..9482942 --- /dev/null +++ b/flumi/Assets/Icons/history.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flumi/Assets/Icons/history.svg.import b/flumi/Assets/Icons/history.svg.import new file mode 100644 index 0000000..16b4cea --- /dev/null +++ b/flumi/Assets/Icons/history.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bcaoarwrwqbby" +path="res://.godot/imported/history.svg-ce846a8aaa80f3d2f2a595f430c7ab7c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/history.svg" +dest_files=["res://.godot/imported/history.svg-ce846a8aaa80f3d2f2a595f430c7ab7c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/flumi/Assets/Icons/log-out.svg b/flumi/Assets/Icons/log-out.svg new file mode 100644 index 0000000..67644b8 --- /dev/null +++ b/flumi/Assets/Icons/log-out.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flumi/Assets/Icons/log-out.svg.import b/flumi/Assets/Icons/log-out.svg.import new file mode 100644 index 0000000..a7df223 --- /dev/null +++ b/flumi/Assets/Icons/log-out.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cilwaxcv5dr1i" +path="res://.godot/imported/log-out.svg-85530e4e6b0167a15c809830d3302ef2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/log-out.svg" +dest_files=["res://.godot/imported/log-out.svg-85530e4e6b0167a15c809830d3302ef2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/flumi/Assets/Icons/message-circle-question-mark.svg b/flumi/Assets/Icons/message-circle-question-mark.svg new file mode 100644 index 0000000..8ec2a50 --- /dev/null +++ b/flumi/Assets/Icons/message-circle-question-mark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flumi/Assets/Icons/message-circle-question-mark.svg.import b/flumi/Assets/Icons/message-circle-question-mark.svg.import new file mode 100644 index 0000000..d445cfe --- /dev/null +++ b/flumi/Assets/Icons/message-circle-question-mark.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://c5pr3tb8rwxb8" +path="res://.godot/imported/message-circle-question-mark.svg-6e0198922e95be66aacb1420c83ea704.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/message-circle-question-mark.svg" +dest_files=["res://.godot/imported/message-circle-question-mark.svg-6e0198922e95be66aacb1420c83ea704.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/flumi/Assets/Icons/settings.svg b/flumi/Assets/Icons/settings.svg new file mode 100644 index 0000000..36b6fcf --- /dev/null +++ b/flumi/Assets/Icons/settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flumi/Assets/Icons/settings.svg.import b/flumi/Assets/Icons/settings.svg.import new file mode 100644 index 0000000..d017cce --- /dev/null +++ b/flumi/Assets/Icons/settings.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://mjr3nwamrqon" +path="res://.godot/imported/settings.svg-2aa0f389da6ad0a7e346738ae84fd469.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/settings.svg" +dest_files=["res://.godot/imported/settings.svg-2aa0f389da6ad0a7e346738ae84fd469.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/flumi/Assets/Icons/square.svg b/flumi/Assets/Icons/square.svg new file mode 100644 index 0000000..e96246e --- /dev/null +++ b/flumi/Assets/Icons/square.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flumi/Assets/Icons/square.svg.import b/flumi/Assets/Icons/square.svg.import new file mode 100644 index 0000000..da7952d --- /dev/null +++ b/flumi/Assets/Icons/square.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://81l2fi381yub" +path="res://.godot/imported/square.svg-64faf57e7837716ed0ed796cd3df54d8.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/square.svg" +dest_files=["res://.godot/imported/square.svg-64faf57e7837716ed0ed796cd3df54d8.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/flumi/Assets/Icons/star.svg b/flumi/Assets/Icons/star.svg new file mode 100644 index 0000000..4bdba35 --- /dev/null +++ b/flumi/Assets/Icons/star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flumi/Assets/Icons/star.svg.import b/flumi/Assets/Icons/star.svg.import new file mode 100644 index 0000000..e8e9a65 --- /dev/null +++ b/flumi/Assets/Icons/star.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://codete2cbsqo2" +path="res://.godot/imported/star.svg-680978d494bec0663c353c2873105a07.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/star.svg" +dest_files=["res://.godot/imported/star.svg-680978d494bec0663c353c2873105a07.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/flumi/Assets/Inter-VariableFont_opsz,wght.ttf b/flumi/Assets/Inter-VariableFont_opsz,wght.ttf new file mode 100644 index 0000000..e31b51e Binary files /dev/null and b/flumi/Assets/Inter-VariableFont_opsz,wght.ttf differ diff --git a/flumi/Assets/Inter-VariableFont_opsz,wght.ttf.import b/flumi/Assets/Inter-VariableFont_opsz,wght.ttf.import new file mode 100644 index 0000000..2cade4f --- /dev/null +++ b/flumi/Assets/Inter-VariableFont_opsz,wght.ttf.import @@ -0,0 +1,35 @@ +[remap] + +importer="font_data_dynamic" +type="FontFile" +uid="uid://fij84uxfqh4h" +path="res://.godot/imported/Inter-VariableFont_opsz,wght.ttf-c02350de2ed9338f034e978775e464ff.fontdata" + +[deps] + +source_file="res://Assets/Inter-VariableFont_opsz,wght.ttf" +dest_files=["res://.godot/imported/Inter-VariableFont_opsz,wght.ttf-c02350de2ed9338f034e978775e464ff.fontdata"] + +[params] + +Rendering=null +antialiasing=1 +generate_mipmaps=false +disable_embedded_bitmaps=true +multichannel_signed_distance_field=false +msdf_pixel_range=8 +msdf_size=48 +allow_system_fallback=true +force_autohinter=false +hinting=1 +subpixel_positioning=4 +keep_rounding_remainders=true +oversampling=0.0 +Fallbacks=null +fallbacks=[] +Compress=null +compress=true +preload=[] +language_support={} +script_support={} +opentype_features={} diff --git a/flumi/Scenes/BrowserMenus/history.tscn b/flumi/Scenes/BrowserMenus/history.tscn new file mode 100644 index 0000000..67fc4c5 --- /dev/null +++ b/flumi/Scenes/BrowserMenus/history.tscn @@ -0,0 +1,326 @@ +[gd_scene load_steps=15 format=3 uid="uid://cn24pafwdpb1q"] + +[ext_resource type="Texture2D" uid="uid://ctpe0lbehepen" path="res://Assets/gurted.svg" id="1_occ3h"] +[ext_resource type="Script" uid="uid://ektopbvnhfga" path="res://Scripts/history.gd" id="1_yn8i4"] +[ext_resource type="PackedScene" uid="uid://3smiker6ni50" path="res://Scenes/BrowserMenus/history_entry.tscn" id="2_a5287"] +[ext_resource type="Texture2D" uid="uid://gq8g7t4s3ryg" path="res://Assets/Icons/x.svg" id="2_ijpe2"] +[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="3_yoadi"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ijpe2"] +content_margin_left = 15.0 +content_margin_top = 5.0 +content_margin_right = 15.0 +content_margin_bottom = 5.0 +bg_color = Color(0.105882, 0.105882, 0.105882, 1) +corner_radius_top_left = 15 +corner_radius_top_right = 15 +corner_radius_bottom_right = 15 +corner_radius_bottom_left = 15 + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_yn8i4"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_a8gu8"] +bg_color = Color(0.169245, 0.169245, 0.169245, 1) +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.247059, 0.466667, 0.807843, 1) +corner_radius_top_left = 25 +corner_radius_top_right = 25 +corner_radius_bottom_right = 25 +corner_radius_bottom_left = 25 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_31fx5"] +draw_center = false +border_width_left = 2 +border_width_top = 2 +border_width_right = 2 +border_width_bottom = 2 +border_color = Color(0.247059, 0.466667, 0.807843, 1) +corner_radius_top_left = 25 +corner_radius_top_right = 25 +corner_radius_bottom_right = 25 +corner_radius_bottom_left = 25 + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_8gbba"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_8gbba"] +bg_color = Color(0.168627, 0.168627, 0.168627, 1) +corner_radius_top_left = 15 +corner_radius_top_right = 15 +corner_radius_bottom_right = 15 +corner_radius_bottom_left = 15 +expand_margin_left = 40.0 + +[sub_resource type="Theme" id="Theme_ijpe2"] +LineEdit/styles/focus = SubResource("StyleBoxEmpty_8gbba") +LineEdit/styles/normal = SubResource("StyleBoxFlat_8gbba") + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_a5287"] +content_margin_left = 10.0 +bg_color = Color(0.219501, 0.219501, 0.219501, 1) +corner_radius_top_left = 15 +corner_radius_top_right = 15 +corner_radius_bottom_right = 15 +corner_radius_bottom_left = 15 + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_yn8i4"] +content_margin_left = 15.0 +content_margin_top = 15.0 +content_margin_right = 15.0 +content_margin_bottom = 5.0 +bg_color = Color(0.105882, 0.105882, 0.105882, 1) +corner_radius_top_left = 15 +corner_radius_top_right = 15 +corner_radius_bottom_right = 15 +corner_radius_bottom_left = 15 + +[node name="History" type="MarginContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_left = 20 +theme_override_constants/margin_top = 20 +theme_override_constants/margin_right = 20 +script = ExtResource("1_yn8i4") + +[node name="Control" type="Control" parent="."] +custom_minimum_size = Vector2(400, 100) +layout_mode = 2 + +[node name="TextureRect" type="TextureRect" parent="Control"] +layout_mode = 1 +offset_right = 417.0 +offset_bottom = 417.0 +scale = Vector2(0.105, 0.105) +texture = ExtResource("1_occ3h") +stretch_mode = 2 + +[node name="RichTextLabel" type="RichTextLabel" parent="Control"] +layout_mode = 0 +offset_left = 50.0 +offset_top = 9.0 +offset_right = 339.0 +offset_bottom = 85.0 +theme_override_font_sizes/bold_font_size = 26 +bbcode_enabled = true +text = "[b]History[/b]" + +[node name="Main" type="VBoxContainer" parent="."] +custom_minimum_size = Vector2(600, 0) +layout_mode = 2 +size_flags_horizontal = 4 +theme_override_constants/separation = 15 + +[node name="DeleteMenu" type="PanelContainer" parent="Main"] +visible = false +layout_mode = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_ijpe2") + +[node name="HBoxContainer" type="HBoxContainer" parent="Main/DeleteMenu"] +layout_mode = 2 + +[node name="CancelButton" type="Button" parent="Main/DeleteMenu/HBoxContainer"] +layout_mode = 2 +mouse_default_cursor_shape = 2 +theme_override_styles/focus = SubResource("StyleBoxEmpty_yn8i4") +icon = ExtResource("2_ijpe2") +flat = true +icon_alignment = 1 + +[node name="RichTextLabel" type="RichTextLabel" parent="Main/DeleteMenu/HBoxContainer"] +custom_minimum_size = Vector2(200, 0) +layout_mode = 2 +text = "1 selected" +fit_content = true +vertical_alignment = 1 + +[node name="DeleteButton" type="Button" parent="Main/DeleteMenu/HBoxContainer"] +custom_minimum_size = Vector2(80, 35) +layout_mode = 2 +size_flags_horizontal = 10 +mouse_default_cursor_shape = 2 +theme = ExtResource("3_yoadi") +theme_override_colors/font_color = Color(0.781065, 0.858202, 0.977018, 1) +theme_override_styles/hover = SubResource("StyleBoxFlat_a8gu8") +theme_override_styles/normal = SubResource("StyleBoxFlat_31fx5") +text = "Delete" + +[node name="LineEdit" type="LineEdit" parent="Main"] +custom_minimum_size = Vector2(0, 45) +layout_mode = 2 +size_flags_horizontal = 3 +theme = SubResource("Theme_ijpe2") +theme_override_styles/normal = SubResource("StyleBoxFlat_a5287") +placeholder_text = "Search history..." +caret_blink = true + +[node name="HSeparator" type="HSeparator" parent="Main"] +layout_mode = 2 + +[node name="PanelContainer2" type="PanelContainer" parent="Main"] +layout_mode = 2 +size_flags_vertical = 3 +theme_override_styles/panel = SubResource("StyleBoxFlat_yn8i4") + +[node name="ScrollContainer" type="ScrollContainer" parent="Main/PanelContainer2"] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="HistoryEntryContainer" type="VBoxContainer" parent="Main/PanelContainer2/ScrollContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +alignment = 1 + +[node name="HistoryEntry" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry2" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry3" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry4" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry5" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry6" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry7" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry8" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry9" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry10" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry11" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry12" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry13" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry14" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry15" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry16" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry17" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry18" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry19" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry20" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry21" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry22" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry23" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry24" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry25" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry26" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry27" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry28" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry29" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry30" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry31" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry32" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry33" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry34" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry35" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry36" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry37" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry38" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry39" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry40" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry41" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry42" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry43" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry44" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry45" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry46" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry47" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry48" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[node name="HistoryEntry49" parent="Main/PanelContainer2/ScrollContainer/HistoryEntryContainer" instance=ExtResource("2_a5287")] +layout_mode = 2 + +[connection signal="pressed" from="Main/DeleteMenu/HBoxContainer/CancelButton" to="." method="_on_cancel_button_pressed"] diff --git a/flumi/Scenes/BrowserMenus/history_entry.tscn b/flumi/Scenes/BrowserMenus/history_entry.tscn new file mode 100644 index 0000000..6cc6f91 --- /dev/null +++ b/flumi/Scenes/BrowserMenus/history_entry.tscn @@ -0,0 +1,42 @@ +[gd_scene load_steps=5 format=3 uid="uid://3smiker6ni50"] + +[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="1_4plhl"] +[ext_resource type="Script" uid="uid://bw5pr4wrf780h" path="res://Scripts/history_entry.gd" id="1_h5c6k"] +[ext_resource type="Texture2D" uid="uid://blskvfjswul1d" path="res://Assets/Icons/checkbox_white.svg" id="2_h5c6k"] +[ext_resource type="Texture2D" uid="uid://bqpx2lgo0yecb" path="res://Assets/Icons/globe.svg" id="2_k4hqm"] + +[node name="HistoryEntry" type="HBoxContainer"] +theme_override_constants/separation = 10 +script = ExtResource("1_h5c6k") + +[node name="CheckBox" type="CheckBox" parent="."] +layout_mode = 2 +theme = ExtResource("1_4plhl") +theme_override_icons/unchecked = ExtResource("2_h5c6k") +flat = true + +[node name="RichTextLabel" type="RichTextLabel" parent="."] +custom_minimum_size = Vector2(60, 0) +layout_mode = 2 +text = "2:00PM" +fit_content = true +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="Spacer" type="Control" parent="."] +custom_minimum_size = Vector2(50, 0) +layout_mode = 2 + +[node name="TextureRect" type="TextureRect" parent="."] +custom_minimum_size = Vector2(24, 24) +layout_mode = 2 +texture = ExtResource("2_k4hqm") +stretch_mode = 3 + +[node name="RichTextLabel2" type="RichTextLabel" parent="."] +custom_minimum_size = Vector2(350, 0) +layout_mode = 2 +text = "Selection - Google Fonts" +vertical_alignment = 1 + +[connection signal="toggled" from="CheckBox" to="." method="_on_check_box_toggled"] diff --git a/flumi/Scenes/Styles/BrowserText.tres b/flumi/Scenes/Styles/BrowserText.tres index f0b4990..f179456 100644 --- a/flumi/Scenes/Styles/BrowserText.tres +++ b/flumi/Scenes/Styles/BrowserText.tres @@ -112,10 +112,10 @@ content_margin_top = 15.0 content_margin_right = 15.0 content_margin_bottom = 15.0 bg_color = Color(0.168627, 0.168627, 0.168627, 1) -corner_radius_top_left = 15 -corner_radius_top_right = 15 -corner_radius_bottom_right = 15 -corner_radius_bottom_left = 15 +corner_radius_top_left = 10 +corner_radius_top_right = 10 +corner_radius_bottom_right = 10 +corner_radius_bottom_left = 10 [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ya683"] content_margin_left = 15.0 diff --git a/flumi/Scenes/Tags/p.tscn b/flumi/Scenes/Tags/p.tscn index cbece4c..a529b6e 100644 --- a/flumi/Scenes/Tags/p.tscn +++ b/flumi/Scenes/Tags/p.tscn @@ -8,6 +8,7 @@ anchors_preset = 10 anchor_right = 1.0 offset_bottom = 19.0 grow_horizontal = 2 +size_flags_horizontal = 3 focus_mode = 2 mouse_default_cursor_shape = 1 theme = ExtResource("2_1glvj") @@ -15,5 +16,6 @@ theme_override_colors/default_color = Color(0, 0, 0, 1) bbcode_enabled = true text = "Placeholder" fit_content = true +vertical_alignment = 1 selection_enabled = true script = ExtResource("1_pnbfg") diff --git a/flumi/Scenes/main.tscn b/flumi/Scenes/main.tscn index a72adce..1e0c479 100644 --- a/flumi/Scenes/main.tscn +++ b/flumi/Scenes/main.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=27 format=3 uid="uid://bytm7bt2s4ak8"] +[gd_scene load_steps=40 format=3 uid="uid://bytm7bt2s4ak8"] [ext_resource type="Script" uid="uid://bg5iqnwic1rio" path="res://Scripts/main.gd" id="1_8q3xr"] [ext_resource type="Texture2D" uid="uid://df1m4j7uxi63v" path="res://Assets/Icons/chevron-down.svg" id="2_6bp64"] @@ -9,8 +9,21 @@ [ext_resource type="PackedScene" uid="uid://sqhcxhcre081" path="res://Scenes/Tab.tscn" id="4_344ge"] [ext_resource type="Texture2D" uid="uid://cu4hjoba6etf" path="res://Assets/Icons/rotate-cw.svg" id="5_344ge"] [ext_resource type="Texture2D" uid="uid://cehbtwq6gq0cn" path="res://Assets/Icons/plus.svg" id="5_ynf5e"] +[ext_resource type="Texture2D" uid="uid://cklatjc4m38dy" path="res://Assets/Icons/ellipsis-vertical.svg" id="10_6iyac"] [ext_resource type="Script" uid="uid://bgqglerkcylxx" path="res://addons/SmoothScroll/SmoothScrollContainer.gd" id="10_d1ilt"] [ext_resource type="Script" uid="uid://b7h0k2h2qwlqv" path="res://addons/SmoothScroll/scroll_damper/expo_scroll_damper.gd" id="11_6iyac"] +[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="11_ee4r6"] +[ext_resource type="Script" uid="uid://vjjhljlftlbk" path="res://Scripts/OptionButton.gd" id="11_gt3je"] +[ext_resource type="Texture2D" uid="uid://du24f6em2nqwq" path="res://Assets/Icons/external-link.svg" id="12_gt3je"] +[ext_resource type="Texture2D" uid="uid://81l2fi381yub" path="res://Assets/Icons/square.svg" id="13_3pmx8"] +[ext_resource type="Texture2D" uid="uid://dwxquqmmd6dqx" path="res://Assets/Icons/hat-glasses.svg" id="14_u50mg"] +[ext_resource type="Texture2D" uid="uid://bcaoarwrwqbby" path="res://Assets/Icons/history.svg" id="15_cbgmd"] +[ext_resource type="Texture2D" uid="uid://cbwitcygwoqdo" path="res://Assets/Icons/download.svg" id="16_1w6v2"] +[ext_resource type="Texture2D" uid="uid://codete2cbsqo2" path="res://Assets/Icons/star.svg" id="17_ueoa1"] +[ext_resource type="Texture2D" uid="uid://c5pr3tb8rwxb8" path="res://Assets/Icons/message-circle-question-mark.svg" id="18_6vcvc"] +[ext_resource type="Texture2D" uid="uid://mjr3nwamrqon" path="res://Assets/Icons/settings.svg" id="19_7k868"] +[ext_resource type="Texture2D" uid="uid://cilwaxcv5dr1i" path="res://Assets/Icons/log-out.svg" id="20_hpc6h"] +[ext_resource type="PackedScene" uid="uid://cn24pafwdpb1q" path="res://Scenes/BrowserMenus/history.tscn" id="24_3pmx8"] [sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_344ge"] @@ -49,9 +62,9 @@ corner_radius_bottom_left = 50 bg_color = Color(0.6, 0.6, 0.6, 0) draw_center = false -[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_8gbba"] +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_u50mg"] -[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_8gbba"] +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_cbgmd"] bg_color = Color(0.168627, 0.168627, 0.168627, 1) corner_radius_top_left = 15 corner_radius_top_right = 15 @@ -60,8 +73,8 @@ corner_radius_bottom_left = 15 expand_margin_left = 40.0 [sub_resource type="Theme" id="Theme_jjvhh"] -LineEdit/styles/focus = SubResource("StyleBoxEmpty_8gbba") -LineEdit/styles/normal = SubResource("StyleBoxFlat_8gbba") +LineEdit/styles/focus = SubResource("StyleBoxEmpty_u50mg") +LineEdit/styles/normal = SubResource("StyleBoxFlat_cbgmd") [sub_resource type="Resource" id="Resource_fdnlq"] script = ExtResource("11_6iyac") @@ -200,6 +213,59 @@ scale = Vector2(0.85, 0.85) texture = ExtResource("3_8gbba") stretch_mode = 5 +[node name="OptionsButton" type="Button" parent="VBoxContainer/HBoxContainer"] +custom_minimum_size = Vector2(45, 0) +layout_mode = 2 +theme_override_styles/focus = SubResource("StyleBoxEmpty_d1ilt") +theme_override_styles/hover = SubResource("StyleBoxFlat_fdnlq") +theme_override_styles/pressed = SubResource("StyleBoxFlat_d1ilt") +theme_override_styles/normal = SubResource("StyleBoxFlat_d1ilt") +icon = ExtResource("10_6iyac") +icon_alignment = 1 +script = ExtResource("11_gt3je") + +[node name="OptionsMenu" type="PopupMenu" parent="VBoxContainer/HBoxContainer/OptionsButton"] +unique_name_in_owner = true +position = Vector2i(1510, 125) +size = Vector2i(408, 360) +theme = ExtResource("11_ee4r6") +theme_override_constants/v_separation = 10 +item_count = 11 +item_0/text = "New tab (CTRL T)" +item_0/icon = ExtResource("12_gt3je") +item_0/id = 0 +item_1/text = "New window (CTRL N)" +item_1/icon = ExtResource("13_3pmx8") +item_1/id = 1 +item_2/text = "New Incognito Window (CTRL SHIFT N)" +item_2/icon = ExtResource("14_u50mg") +item_2/id = 2 +item_3/id = 3 +item_3/separator = true +item_4/text = "History (CTRL H)" +item_4/icon = ExtResource("15_cbgmd") +item_4/id = 4 +item_5/text = "Downloads (CTRL J)" +item_5/icon = ExtResource("16_1w6v2") +item_5/id = 5 +item_6/text = "Bookmarks (CTRL SHIFT B)" +item_6/icon = ExtResource("17_ueoa1") +item_6/id = 7 +item_7/id = 7 +item_7/separator = true +item_8/text = "Help" +item_8/icon = ExtResource("18_6vcvc") +item_8/id = 8 +item_9/text = "Settings" +item_9/icon = ExtResource("19_7k868") +item_9/id = 9 +item_10/text = "Exit" +item_10/icon = ExtResource("20_hpc6h") +item_10/id = 10 + +[node name="Control2" type="Control" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 + [node name="Spacer3" type="Control" parent="VBoxContainer"] custom_minimum_size = Vector2(0, 2) layout_mode = 2 @@ -216,12 +282,17 @@ metadata/_custom_type_script = "uid://bgqglerkcylxx" [node name="WebsiteContainer" type="VBoxContainer" parent="VBoxContainer/ScrollContainer"] unique_name_in_owner = true -custom_minimum_size = Vector2(200, 200) layout_mode = 2 size_flags_horizontal = 3 size_flags_vertical = 3 theme_override_constants/separation = 22 +[node name="HistoryContainer" parent="VBoxContainer/ScrollContainer" instance=ExtResource("24_3pmx8")] +visible = false +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + [node name="WebsiteBackground" type="Panel" parent="."] unique_name_in_owner = true z_index = -1 @@ -259,3 +330,8 @@ mouse_filter = 2 theme_override_styles/panel = SubResource("StyleBoxFlat_21xkr") [connection signal="pressed" from="VBoxContainer/TabContainer/NewTabButton" to="VBoxContainer/TabContainer" method="_on_new_tab_button_pressed"] +[connection signal="focus_entered" from="VBoxContainer/HBoxContainer/LineEdit" to="." method="_on_search_focus_entered"] +[connection signal="focus_exited" from="VBoxContainer/HBoxContainer/LineEdit" to="." method="_on_search_focus_exited"] +[connection signal="text_submitted" from="VBoxContainer/HBoxContainer/LineEdit" to="." method="_on_search_submitted"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/OptionsButton" to="VBoxContainer/HBoxContainer/OptionsButton" method="_on_pressed"] +[connection signal="id_pressed" from="VBoxContainer/HBoxContainer/OptionsButton/OptionsMenu" to="VBoxContainer/HBoxContainer/OptionsButton" method="_on_options_menu_id_pressed"] diff --git a/flumi/Scripts/B9/HTMLParser.gd b/flumi/Scripts/B9/HTMLParser.gd index 3d21cba..50bf971 100644 --- a/flumi/Scripts/B9/HTMLParser.gd +++ b/flumi/Scripts/B9/HTMLParser.gd @@ -151,7 +151,7 @@ func get_element_styles_with_inheritance(element: HTMLElement, event: String = " styles[property] = inline_parsed[property] # Inherit certain properties from parent elements - var inheritable_properties = ["width", "height", "font-size", "color", "font-family", "cursor"] + var inheritable_properties = ["width", "height", "font-size", "color", "font-family", "cursor", "font-bold", "font-italic", "underline"] var parent_element = element.parent while parent_element: var parent_styles = get_element_styles_internal(parent_element, event) diff --git a/flumi/Scripts/B9/Lua.gd b/flumi/Scripts/B9/Lua.gd index 843e46c..5f786d2 100644 --- a/flumi/Scripts/B9/Lua.gd +++ b/flumi/Scripts/B9/Lua.gd @@ -28,6 +28,7 @@ func _init(): timeout_manager = LuaTimeoutManager.new() threaded_vm = ThreadedLuaVM.new() threaded_vm.script_completed.connect(_on_threaded_script_completed) + threaded_vm.script_error.connect(func(e): print(e)) threaded_vm.dom_operation_request.connect(_handle_dom_operation) threaded_vm.print_output.connect(_on_print_output) diff --git a/flumi/Scripts/Constants.gd b/flumi/Scripts/Constants.gd index db50667..db9fb60 100644 --- a/flumi/Scripts/Constants.gd +++ b/flumi/Scripts/Constants.gd @@ -2794,4 +2794,108 @@ audio.play() # Set the active HTML content to use the audio demo func _ready(): - HTML_CONTENT = HTML_CONTENT_AUDIO_TEST + HTML_CONTENT = """ + Login + + + + + + + + + + + + +
+

Login

+
+ + + +
+

Don't have an account? Register here

+ +

+
+""".to_utf8_buffer() diff --git a/flumi/Scripts/GurtProtocol.gd b/flumi/Scripts/GurtProtocol.gd new file mode 100644 index 0000000..5407148 --- /dev/null +++ b/flumi/Scripts/GurtProtocol.gd @@ -0,0 +1,198 @@ +extends RefCounted +class_name GurtProtocol + +const DNS_API_URL = "http://localhost:8080" + +static func is_gurt_domain(url: String) -> bool: + if url.begins_with("gurt://"): + return true + + var parts = url.split(".") + return parts.size() == 2 and not url.contains("://") + +static func parse_gurt_domain(url: String) -> Dictionary: + print("Parsing URL: ", url) + + var domain_part = url + + if url.begins_with("gurt://"): + domain_part = url.substr(7) # Remove "gurt://" + + var parts = domain_part.split(".") + if parts.size() != 2: + print("Invalid domain format: ", domain_part) + return {} + + print("Parsed domain - name: ", parts[0], ", tld: ", parts[1]) + return { + "name": parts[0], + "tld": parts[1], + "display_url": domain_part + } + +static func fetch_domain_info(name: String, tld: String) -> Dictionary: + print("Fetching domain info for: ", name, ".", tld) + + var http_request = HTTPRequest.new() + var tree = Engine.get_main_loop() + tree.current_scene.add_child(http_request) + + http_request.timeout = 5.0 + + var url = DNS_API_URL + "/domain/" + name + "/" + tld + print("DNS API URL: ", url) + + var error = http_request.request(url) + + if error != OK: + print("HTTP request failed with error: ", error) + http_request.queue_free() + return {"error": "Failed to make DNS request"} + + var response = await http_request.request_completed + http_request.queue_free() + + if response[1] == 0 and response[3].size() == 0: + print("DNS API request timed out") + return {"error": "DNS server is not responding"} + + var http_code = response[1] + var body = response[3] + + print("DNS API response code: ", http_code) + print("DNS API response body: ", body.get_string_from_utf8()) + + if http_code != 200: + return {"error": "Domain not found or not approved"} + + var json = JSON.new() + var parse_result = json.parse(body.get_string_from_utf8()) + + if parse_result != OK: + print("JSON parse error: ", parse_result) + return {"error": "Invalid JSON response from DNS server"} + + print("Domain info retrieved: ", json.data) + return json.data + +static func fetch_index_html(ip: String) -> String: + print("Fetching index.html from IP: ", ip) + + var http_request = HTTPRequest.new() + var tree = Engine.get_main_loop() + tree.current_scene.add_child(http_request) + + http_request.timeout = 5.0 + + var url = "http://" + ip + "/index.html" + print("Fetching from URL: ", url) + + var error = http_request.request(url) + + if error != OK: + print("HTTP request to IP failed with error: ", error) + http_request.queue_free() + return "" + + var response = await http_request.request_completed + http_request.queue_free() + + if response[1] == 0 and response[3].size() == 0: + print("Index.html request timed out") + return "" + + var http_code = response[1] + var body = response[3] + + print("IP response code: ", http_code) + + if http_code != 200: + print("Failed to fetch index.html, HTTP code: ", http_code) + return "" + + var html_content = body.get_string_from_utf8() + print("Successfully fetched HTML content (", html_content.length(), " characters)") + return html_content + +static func handle_gurt_domain(url: String) -> Dictionary: + print("Handling GURT domain: ", url) + + var parsed = parse_gurt_domain(url) + if parsed.is_empty(): + return {"error": "Invalid domain format. Use: domain.tld", "html": create_error_page("Invalid domain format. Use: domain.tld")} + + var domain_info = await fetch_domain_info(parsed.name, parsed.tld) + if domain_info.has("error"): + return {"error": domain_info.error, "html": create_error_page(domain_info.error)} + + var html_content = await fetch_index_html(domain_info.ip) + if html_content.is_empty(): + var error_msg = "Failed to fetch index.html from " + domain_info.ip + return {"error": error_msg, "html": create_error_page(error_msg)} + + return {"html": html_content, "display_url": parsed.display_url} + +static func get_error_type(error_message: String) -> Dictionary: + if "DNS server is not responding" in error_message or "Domain not found" in error_message: + return {"code": "ERR_NAME_NOT_RESOLVED", "title": "This site can't be reached", "icon": "🌐"} + elif "timeout" in error_message.to_lower() or "timed out" in error_message.to_lower(): + return {"code": "ERR_CONNECTION_TIMED_OUT", "title": "This site can't be reached", "icon": "⏰"} + elif "Failed to fetch" in error_message or "HTTP request failed" in error_message: + return {"code": "ERR_CONNECTION_REFUSED", "title": "This site can't be reached", "icon": "🚫"} + elif "Invalid domain format" in error_message: + return {"code": "ERR_INVALID_URL", "title": "This page isn't working", "icon": "⚠️"} + else: + return {"code": "ERR_UNKNOWN", "title": "Something went wrong", "icon": "❌"} + +static func create_error_page(error_message: String) -> String: + var error_info = get_error_type(error_message) + + return """ + """ + error_info.title + """ - GURT + + + + + + +
+

""" + error_info.icon + """

+ +

""" + error_info.title + """

+ +

""" + error_message + """

+ +
""" + error_info.code + """
+ +
+

Try:

+
    +
  • Checking if the domain is correctly registered
  • +
  • Verifying your DNS server is running
  • +
  • Checking your internet connection
  • +
+
+ + +
+""" diff --git a/flumi/Scripts/GurtProtocol.gd.uid b/flumi/Scripts/GurtProtocol.gd.uid new file mode 100644 index 0000000..858789e --- /dev/null +++ b/flumi/Scripts/GurtProtocol.gd.uid @@ -0,0 +1 @@ +uid://clhivwjs3eujk diff --git a/flumi/Scripts/OptionButton.gd b/flumi/Scripts/OptionButton.gd new file mode 100644 index 0000000..258aeb6 --- /dev/null +++ b/flumi/Scripts/OptionButton.gd @@ -0,0 +1,18 @@ +extends Button + +@onready var tab_container: TabManager = $"../../TabContainer" +@onready var website_background: Panel = %WebsiteBackground + +func _on_pressed() -> void: + %OptionsMenu.show() + +func _on_options_menu_id_pressed(id: int) -> void: + if id == 0: # new tab + tab_container.create_tab() + if id == 1: # new window + OS.create_process(OS.get_executable_path(), []) + if id == 2: # new ingonito window + # TODO: handle incognito + OS.create_process(OS.get_executable_path(), ["--incognito"]) + if id == 4: # history + website_background.modulate = Constants.SECONDARY_COLOR diff --git a/flumi/Scripts/OptionButton.gd.uid b/flumi/Scripts/OptionButton.gd.uid new file mode 100644 index 0000000..b14d10a --- /dev/null +++ b/flumi/Scripts/OptionButton.gd.uid @@ -0,0 +1 @@ +uid://vjjhljlftlbk diff --git a/flumi/Scripts/StyleManager.gd b/flumi/Scripts/StyleManager.gd index bd21331..ba8a069 100644 --- a/flumi/Scripts/StyleManager.gd +++ b/flumi/Scripts/StyleManager.gd @@ -318,16 +318,23 @@ static func apply_margin_wrapper(node: Control, styles: Dictionary) -> Control: var margin_container = MarginContainer.new() margin_container.name = "MarginWrapper_" + node.name - # Copy size flags from the original node - margin_container.size_flags_horizontal = node.size_flags_horizontal - margin_container.size_flags_vertical = node.size_flags_vertical + var has_explicit_width = styles.has("width") + var has_explicit_height = styles.has("height") + + if has_explicit_width: + margin_container.size_flags_horizontal = node.size_flags_horizontal + else: + margin_container.size_flags_horizontal = node.size_flags_horizontal + node.size_flags_horizontal = Control.SIZE_EXPAND_FILL + + if has_explicit_height: + margin_container.size_flags_vertical = node.size_flags_vertical + else: + margin_container.size_flags_vertical = node.size_flags_vertical + node.size_flags_vertical = Control.SIZE_EXPAND_FILL apply_margin_styles_to_container(margin_container, styles) - # Reset the original node's size flags since they're now handled by the wrapper - node.size_flags_horizontal = Control.SIZE_EXPAND_FILL - node.size_flags_vertical = Control.SIZE_EXPAND_FILL - # Handle reparenting properly var original_parent = node.get_parent() if original_parent: @@ -542,9 +549,22 @@ static func parse_radius(radius_str: String) -> int: static func apply_font_to_label(label: RichTextLabel, font_resource: Font) -> void: label.add_theme_font_override("normal_font", font_resource) - label.add_theme_font_override("bold_font", font_resource) - label.add_theme_font_override("italics_font", font_resource) - label.add_theme_font_override("bold_italics_font", font_resource) + + var bold_font = SystemFont.new() + bold_font.font_names = font_resource.font_names if font_resource is SystemFont else ["Arial"] + bold_font.font_weight = 700 # Bold weight + label.add_theme_font_override("bold_font", bold_font) + + var italic_font = SystemFont.new() + italic_font.font_names = font_resource.font_names if font_resource is SystemFont else ["Arial"] + italic_font.font_italic = true + label.add_theme_font_override("italics_font", italic_font) + + var bold_italic_font = SystemFont.new() + bold_italic_font.font_names = font_resource.font_names if font_resource is SystemFont else ["Arial"] + bold_italic_font.font_weight = 700 # Bold weight + bold_italic_font.font_italic = true + label.add_theme_font_override("bold_italics_font", bold_italic_font) static func apply_font_to_button(button: Button, styles: Dictionary) -> void: if styles.has("font-family"): diff --git a/flumi/Scripts/Tab.gd b/flumi/Scripts/Tab.gd index 8b2040b..62181fb 100644 --- a/flumi/Scripts/Tab.gd +++ b/flumi/Scripts/Tab.gd @@ -47,6 +47,10 @@ func set_icon(new_icon: Texture) -> void: icon.rotation = 0 func update_icon_from_url(icon_url: String) -> void: + if icon_url.is_empty(): + stop_loading() + return + const LOADER_CIRCLE = preload("res://Assets/Icons/loader-circle.svg") loading_tween = create_tween() @@ -68,9 +72,7 @@ func update_icon_from_url(icon_url: String) -> void: # Only update if tab still exists if is_instance_valid(self): set_icon(icon_resource) - if loading_tween: - loading_tween.kill() - loading_tween = null + stop_loading() func _on_button_mouse_entered() -> void: mouse_over_tab = true @@ -82,6 +84,27 @@ func _on_button_mouse_exited() -> void: if is_active: return gradient_texture.texture = TAB_GRADIENT_DEFAULT +func start_loading() -> void: + const LOADER_CIRCLE = preload("res://Assets/Icons/loader-circle.svg") + + stop_loading() + + loading_tween = create_tween() + set_icon(LOADER_CIRCLE) + loading_tween.set_loops() + icon.pivot_offset = Vector2(11.5, 11.5) + loading_tween.tween_method(func(angle): + if !is_instance_valid(icon): + if loading_tween: loading_tween.kill() + return + icon.rotation = angle + , 0.0, TAU, 1.0) + +func stop_loading() -> void: + if loading_tween: + loading_tween.kill() + loading_tween = null + func _exit_tree(): if loading_tween: loading_tween.kill() diff --git a/flumi/Scripts/Tags/button.gd b/flumi/Scripts/Tags/button.gd index 8f768fb..02a817d 100644 --- a/flumi/Scripts/Tags/button.gd +++ b/flumi/Scripts/Tags/button.gd @@ -189,10 +189,23 @@ func apply_padding_to_stylebox(style_box: StyleBoxFlat, styles: Dictionary) -> v func apply_size_and_flags(ctrl: Control, width: Variant, height: Variant) -> void: if width != null or height != null: - ctrl.custom_minimum_size = Vector2( - width if width != null else 0, - height if height != null else 0 - ) + var new_width = 0 + var new_height = 0 + + if width != null: + if SizingUtils.is_percentage(width): + new_width = SizingUtils.calculate_percentage_size(width, SizingUtils.DEFAULT_VIEWPORT_WIDTH) + else: + new_width = width + + if height != null: + if SizingUtils.is_percentage(height): + new_height = SizingUtils.calculate_percentage_size(height, SizingUtils.DEFAULT_VIEWPORT_HEIGHT) + else: + new_height = height + + ctrl.custom_minimum_size = Vector2(new_width, new_height) + if width != null: ctrl.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN if height != null: diff --git a/flumi/Scripts/Tags/input.gd b/flumi/Scripts/Tags/input.gd index 0ddeca0..69de921 100644 --- a/flumi/Scripts/Tags/input.gd +++ b/flumi/Scripts/Tags/input.gd @@ -404,10 +404,22 @@ func apply_input_styles(element: HTMLParser.HTMLElement, parser: HTMLParser) -> if active_child: if width or height: # Explicit sizing from CSS - var new_child_size = Vector2( - width if width else active_child.custom_minimum_size.x, - height if height else max(active_child.custom_minimum_size.y, active_child.size.y) - ) + var new_width = active_child.custom_minimum_size.x + var new_height = max(active_child.custom_minimum_size.y, active_child.size.y) + + if width: + if SizingUtils.is_percentage(width): + new_width = SizingUtils.calculate_percentage_size(width, SizingUtils.DEFAULT_VIEWPORT_WIDTH) + else: + new_width = width + + if height: + if SizingUtils.is_percentage(height): + new_height = SizingUtils.calculate_percentage_size(height, SizingUtils.DEFAULT_VIEWPORT_HEIGHT) + else: + new_height = height + + var new_child_size = Vector2(new_width, new_height) active_child.custom_minimum_size = new_child_size diff --git a/flumi/Scripts/Tags/p.gd b/flumi/Scripts/Tags/p.gd index 0934f41..2c53f53 100644 --- a/flumi/Scripts/Tags/p.gd +++ b/flumi/Scripts/Tags/p.gd @@ -7,9 +7,38 @@ func init(element: HTMLParser.HTMLElement, parser: HTMLParser) -> void: # Allow mouse events to pass through to parent containers for hover effects while keeping text selection mouse_filter = Control.MOUSE_FILTER_PASS - # NOTE: estimate width/height because FlexContainer removes our anchor preset (sets 0 width) - var plain_text = element.get_collapsed_text() - var estimated_height = 30 - var estimated_width = min(200, max(100, plain_text.length() * 12)) + autowrap_mode = TextServer.AUTOWRAP_WORD_SMART - custom_minimum_size = Vector2(estimated_width, estimated_height) + call_deferred("_auto_resize_to_content") + + size_flags_horizontal = Control.SIZE_EXPAND_FILL + set_anchors_and_offsets_preset(Control.PRESET_TOP_WIDE) + +func _auto_resize_to_content(): + if not is_inside_tree(): + await tree_entered + + var min_width = 20 + var max_width = 800 + var min_height = 30 + + fit_content = true + + var original_autowrap = autowrap_mode + autowrap_mode = TextServer.AUTOWRAP_OFF + + await get_tree().process_frame + + var natural_width = size.x + var desired_width = clampf(natural_width, min_width, max_width) + + autowrap_mode = original_autowrap + + await get_tree().process_frame + + var content_height = get_content_height() + var explicit_height = custom_minimum_size.y if custom_minimum_size.y > 0 else null + var final_height = explicit_height if explicit_height != null else max(content_height, min_height) + custom_minimum_size = Vector2(desired_width, final_height) + + queue_redraw() diff --git a/flumi/Scripts/history.gd b/flumi/Scripts/history.gd new file mode 100644 index 0000000..d45676c --- /dev/null +++ b/flumi/Scripts/history.gd @@ -0,0 +1,39 @@ +extends MarginContainer + +@onready var history_entry_container: VBoxContainer = $Main/PanelContainer2/ScrollContainer/HistoryEntryContainer +@onready var delete_menu: PanelContainer = $Main/DeleteMenu +@onready var line_edit: LineEdit = $Main/LineEdit +@onready var entries_label: RichTextLabel = $Main/DeleteMenu/HBoxContainer/RichTextLabel +@onready var cancel_button: Button = $Main/DeleteMenu/HBoxContainer/CancelButton + +var toggled_entries = [] + +func _ready(): + for entry in history_entry_container.get_children(): + entry.connect("checkbox_toggle", history_toggle.bind(entry)) + +func history_toggle(toggled: bool, entry) -> void: + print('toggling ', entry, ' to :', toggled) + if toggled: + toggled_entries.append(entry) + else: + toggled_entries.remove_at(toggled_entries.find(entry)) + + entries_label.text = str(toggled_entries.size()) + " selected" + + if toggled_entries.size() != 0: + delete_menu.show() + line_edit.hide() + else: + delete_menu.hide() + line_edit.show() + +func _on_cancel_button_pressed() -> void: + var entries_to_reset = toggled_entries.duplicate() + toggled_entries.clear() + + for entry in entries_to_reset: + entry.reset() + + delete_menu.hide() + line_edit.show() diff --git a/flumi/Scripts/history.gd.uid b/flumi/Scripts/history.gd.uid new file mode 100644 index 0000000..f075c10 --- /dev/null +++ b/flumi/Scripts/history.gd.uid @@ -0,0 +1 @@ +uid://ektopbvnhfga diff --git a/flumi/Scripts/history_entry.gd b/flumi/Scripts/history_entry.gd new file mode 100644 index 0000000..3d5631c --- /dev/null +++ b/flumi/Scripts/history_entry.gd @@ -0,0 +1,10 @@ +extends HBoxContainer +signal checkbox_toggle + +@onready var check_box: CheckBox = $CheckBox + +func reset() -> void: + check_box.set_pressed_no_signal(false) + +func _on_check_box_toggled(toggled_on: bool) -> void: + checkbox_toggle.emit(toggled_on) diff --git a/flumi/Scripts/history_entry.gd.uid b/flumi/Scripts/history_entry.gd.uid new file mode 100644 index 0000000..b157564 --- /dev/null +++ b/flumi/Scripts/history_entry.gd.uid @@ -0,0 +1 @@ +uid://bw5pr4wrf780h diff --git a/flumi/Scripts/main.gd b/flumi/Scripts/main.gd index 197de52..8a7d53f 100644 --- a/flumi/Scripts/main.gd +++ b/flumi/Scripts/main.gd @@ -4,6 +4,8 @@ extends Control @onready var website_container: Control = %WebsiteContainer @onready var website_background: Control = %WebsiteBackground @onready var tab_container: TabManager = $VBoxContainer/TabContainer +@onready var search_bar: LineEdit = $VBoxContainer/HBoxContainer/LineEdit + const LOADER_CIRCLE = preload("res://Assets/Icons/loader-circle.svg") const AUTO_SIZING_FLEX_CONTAINER = preload("res://Scripts/AutoSizingFlexContainer.gd") @@ -53,6 +55,8 @@ func _ready(): DisplayServer.window_set_min_size(MIN_SIZE) get_viewport().size_changed.connect(_on_viewport_size_changed) + + call_deferred("render") func _on_viewport_size_changed(): recalculate_percentage_elements(website_container) @@ -64,7 +68,49 @@ func recalculate_percentage_elements(node: Node): for child in node.get_children(): recalculate_percentage_elements(child) +var current_domain = "" # Store current domain for display + +func _on_search_submitted(url: String) -> void: + print("Search submitted: ", url) + + if GurtProtocol.is_gurt_domain(url): + print("Processing as GURT domain") + + var tab = tab_container.tabs[tab_container.active_tab] + tab.start_loading() + + var result = await GurtProtocol.handle_gurt_domain(url) + + if result.has("error"): + print("GURT domain error: ", result.error) + const GLOBE_ICON = preload("res://Assets/Icons/globe.svg") + tab.stop_loading() + tab.set_icon(GLOBE_ICON) + + var html_bytes = result.html.to_utf8_buffer() + render_content(html_bytes) + + if result.has("display_url"): + current_domain = result.display_url + if not search_bar.has_focus(): + search_bar.text = current_domain + else: + print("Non-GURT URL entered: ", url) + +func _on_search_focus_entered() -> void: + if not current_domain.is_empty(): + search_bar.text = "gurt://" + current_domain + +func _on_search_focus_exited() -> void: + if not current_domain.is_empty(): + search_bar.text = current_domain + + func render() -> void: + render_content(Constants.HTML_CONTENT) + +func render_content(html_bytes: PackedByteArray) -> void: + # Clear existing content for child in website_container.get_children(): child.queue_free() @@ -73,8 +119,6 @@ func render() -> void: FontManager.clear_fonts() FontManager.set_refresh_callback(refresh_fonts) - var html_bytes = Constants.HTML_CONTENT - var parser: HTMLParser = HTMLParser.new(html_bytes) var parse_result = parser.parse() @@ -109,57 +153,59 @@ func render() -> void: add_child(lua_api) var i = 0 - while i < body.children.size(): - var element: HTMLParser.HTMLElement = body.children[i] - - if should_group_as_inline(element): - # Create an HBoxContainer for consecutive inline elements - var inline_elements: Array[HTMLParser.HTMLElement] = [] - - while i < body.children.size() and should_group_as_inline(body.children[i]): - inline_elements.append(body.children[i]) - i += 1 - - var hbox = HBoxContainer.new() - hbox.add_theme_constant_override("separation", 4) - - for inline_element in inline_elements: - var inline_node = await create_element_node(inline_element, parser) - if inline_node: - # Input elements register their own DOM nodes in their init() function - if inline_element.tag_name not in ["input", "textarea", "select", "button", "audio"]: - parser.register_dom_node(inline_element, inline_node) - - safe_add_child(hbox, inline_node) - # Handle hyperlinks for all inline elements - if contains_hyperlink(inline_element) and inline_node is RichTextLabel: - inline_node.meta_clicked.connect(func(meta): OS.shell_open(str(meta))) - else: - print("Failed to create inline element node: ", inline_element.tag_name) - - safe_add_child(website_container, hbox) - continue - - var element_node = await create_element_node(element, parser) - if element_node: - # Input elements register their own DOM nodes in their init() function - if element.tag_name not in ["input", "textarea", "select", "button", "audio"]: - parser.register_dom_node(element, element_node) + if body: + while i < body.children.size(): + var element: HTMLParser.HTMLElement = body.children[i] - # ul/ol handle their own adding - if element.tag_name != "ul" and element.tag_name != "ol": - safe_add_child(website_container, element_node) + if should_group_as_inline(element): + # Create an HBoxContainer for consecutive inline elements + var inline_elements: Array[HTMLParser.HTMLElement] = [] - # Handle hyperlinks for all elements - if contains_hyperlink(element): - if element_node is RichTextLabel: - element_node.meta_clicked.connect(func(meta): OS.shell_open(str(meta))) - elif element_node.has_method("get") and element_node.get("rich_text_label"): - element_node.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta))) - else: - print("Couldn't parse unsupported HTML tag \"%s\"" % element.tag_name) - - i += 1 + while i < body.children.size() and should_group_as_inline(body.children[i]): + inline_elements.append(body.children[i]) + i += 1 + + var hbox = HBoxContainer.new() + hbox.add_theme_constant_override("separation", 4) + + for inline_element in inline_elements: + var inline_node = await create_element_node(inline_element, parser) + if inline_node: + + # Input elements register their own DOM nodes in their init() function + if inline_element.tag_name not in ["input", "textarea", "select", "button", "audio"]: + parser.register_dom_node(inline_element, inline_node) + + safe_add_child(hbox, inline_node) + # Handle hyperlinks for all inline elements + if contains_hyperlink(inline_element) and inline_node is RichTextLabel: + inline_node.meta_clicked.connect(func(meta): OS.shell_open(str(meta))) + else: + print("Failed to create inline element node: ", inline_element.tag_name) + + safe_add_child(website_container, hbox) + continue + + var element_node = await create_element_node(element, parser) + if element_node: + + # Input elements register their own DOM nodes in their init() function + if element.tag_name not in ["input", "textarea", "select", "button", "audio"]: + parser.register_dom_node(element, element_node) + + # ul/ol handle their own adding + if element.tag_name != "ul" and element.tag_name != "ol": + safe_add_child(website_container, element_node) + + if contains_hyperlink(element): + if element_node is RichTextLabel: + element_node.meta_clicked.connect(func(meta): OS.shell_open(str(meta))) + elif element_node.has_method("get") and element_node.get("rich_text_label"): + element_node.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta))) + else: + print("Couldn't parse unsupported HTML tag \"%s\"" % element.tag_name) + + i += 1 if scripts.size() > 0 and lua_api: parser.process_scripts(lua_api, null) @@ -381,6 +427,9 @@ func create_element_node_internal(element: HTMLParser.HTMLElement, parser: HTMLP var p_node = P.instantiate() p_node.init(element, parser) + var div_styles = parser.get_element_styles_with_inheritance(element, "", []) + StyleManager.apply_styles_to_label(p_node, div_styles, element, parser) + 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 diff --git a/flumi/project.godot b/flumi/project.godot index 47204fc..041210f 100644 --- a/flumi/project.godot +++ b/flumi/project.godot @@ -39,6 +39,10 @@ folder_colors={ "res://Scripts/": "blue" } +[gui] + +theme/custom_font="uid://fij84uxfqh4h" + [input] NewTab={