changelog shortlog graph tags branches files raw help

Mercurial > demo / changeset: ui work

changeset 17: e4c9ec452eb6
parent 16: af615d1895cb
child 18: a1137af05c8d
author: ellis <ellis@rwest.io>
date: Sat, 27 May 2023 21:07:55 -0400
files: tools/deps.nu ui/Cargo.toml ui/build.rs ui/config.slint ui/img/ayo.jpeg ui/img/treez.png ui/index.html ui/lib.rs ui/main.rs ui/pages.slint ui/pages/about.slint ui/pages/controls.slint ui/pages/list_view.slint ui/pages/page.slint ui/pages/table_view.slint ui/pages/text_edit.slint ui/sidebar.slint ui/src/lib.rs ui/src/main.rs ui/ui.slint www/boot.html www/bootstrap.html www/css/w3.css www/favicon.ico www/robots.txt
description: ui work
     1.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2+++ b/tools/deps.nu	Sat May 27 21:07:55 2023 -0400
     1.3@@ -0,0 +1,13 @@
     1.4+
     1.5+pacman -Sy sbcl
     1.6+curl -o /tmp/ql.lisp http://beta.quicklisp.org/quicklisp.lisp
     1.7+sbcl --no-sysinit --no-userinit --load /tmp/ql.lisp \
     1.8+       --eval '(quicklisp-quickstart:install :path "~/.quicklisp")' \
     1.9+       --eval '(ql:add-to-init-file)' \
    1.10+       --quit
    1.11+sbcl --eval '(ql:quickload :quicklisp-slime-helper)' --quit
    1.12+# (load (expand-file-name "~/.quicklisp/slime-helper.el"))
    1.13+# (setq inferior-lisp-program "sbcl")
    1.14+curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    1.15+cargo install cbindgen --force
    1.16+cargo install slint-lsp --git https://github.com/slint-ui/slint --force
    1.17\ No newline at end of file
     2.1--- a/ui/Cargo.toml	Fri May 26 21:59:40 2023 -0400
     2.2+++ b/ui/Cargo.toml	Sat May 27 21:07:55 2023 -0400
     2.3@@ -2,28 +2,22 @@
     2.4 name = "ui"
     2.5 version = "0.1.0"
     2.6 edition = "2021"
     2.7+build = "build.rs"
     2.8 [lib]
     2.9-path = "src/lib.rs"
    2.10+path = "lib.rs"
    2.11 crate-type = ["rlib","cdylib"]
    2.12 [[bin]]
    2.13 name = "demo-ui"
    2.14-path = "src/main.rs"
    2.15+path = "main.rs"
    2.16+[build-dependencies]
    2.17+slint-build = "1.0.2"
    2.18 [dependencies]
    2.19-wgpu = "0.16.1"
    2.20-winit = "0.28.6"
    2.21 obj = {version = "0.1.0",path = "../obj"}
    2.22 fig = {version = "0.1.0",path = "../fig"}
    2.23 env_logger = "0.10.0"
    2.24 log = "0.4.17"
    2.25-cfg-if = "1.0.0"
    2.26+slint = "1.0.2"
    2.27 [target.'cfg(target_arch = "wasm32")'.dependencies]
    2.28-console_error_panic_hook = "0.1.6"
    2.29-console_log = "0.2.0"
    2.30-wgpu = { version = "0.15", features = ["webgl"]}
    2.31-wasm-bindgen = "0.2"
    2.32-wasm-bindgen-futures = "0.4.30"
    2.33-web-sys = { version = "0.3", features = [
    2.34-    "Document",
    2.35-    "Window",
    2.36-    "Element",
    2.37-]}
    2.38+wasm-bindgen = { version = "0.2" }
    2.39+web-sys = { version = "0.3", features=["console"] }
    2.40+console_error_panic_hook = "0.1.5"
     3.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2+++ b/ui/build.rs	Sat May 27 21:07:55 2023 -0400
     3.3@@ -0,0 +1,3 @@
     3.4+fn main() {
     3.5+    slint_build::compile("ui.slint").unwrap();
     3.6+}
     4.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2+++ b/ui/config.slint	Sat May 27 21:07:55 2023 -0400
     4.3@@ -0,0 +1,3 @@
     4.4+export global UiConfig  {
     4.5+    in property<bool> widgets-disabled: false;
     4.6+}
     4.7\ No newline at end of file
     5.1Binary file ui/img/ayo.jpeg has changed
     6.1Binary file ui/img/treez.png has changed
     7.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2+++ b/ui/index.html	Sat May 27 21:07:55 2023 -0400
     7.3@@ -0,0 +1,9 @@
     7.4+<html>
     7.5+  <body>
     7.6+    <canvas id="canvas">>/canvas>
     7.7+    <script type="module">
     7.8+      import init from './pkg/ui.js';
     7.9+      init();
    7.10+    </script>
    7.11+  </body>
    7.12+</html>
     8.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2+++ b/ui/lib.rs	Sat May 27 21:07:55 2023 -0400
     8.3@@ -0,0 +1,69 @@
     8.4+#![deny(unsafe_code)]
     8.5+
     8.6+#[cfg(target_arch = "wasm32")]
     8.7+use wasm_bindgen::prelude::*;
     8.8+
     8.9+slint::include_modules!();
    8.10+
    8.11+use std::rc::Rc;
    8.12+
    8.13+use slint::{Model, StandardListViewItem, VecModel};
    8.14+
    8.15+#[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))]
    8.16+pub fn run() {
    8.17+    // This provides better error messages in debug mode.
    8.18+    // It's disabled in release mode so it doesn't bloat up the file size.
    8.19+    #[cfg(all(debug_assertions, target_arch = "wasm32"))]
    8.20+    console_error_panic_hook::set_once();
    8.21+
    8.22+    let app = App::new().unwrap();
    8.23+
    8.24+    let row_data: Rc<VecModel<slint::ModelRc<StandardListViewItem>>> = Rc::new(VecModel::default());
    8.25+
    8.26+    for r in 1..101 {
    8.27+        let items = Rc::new(VecModel::default());
    8.28+
    8.29+        for c in 1..5 {
    8.30+            items.push(slint::format!("Item {r}.{c}").into());
    8.31+        }
    8.32+
    8.33+        row_data.push(items.into());
    8.34+    }
    8.35+
    8.36+    app.global::<TableViewPageAdapter>().set_row_data(row_data.clone().into());
    8.37+
    8.38+    app.global::<TableViewPageAdapter>().on_sort_ascending({
    8.39+        let app_weak = app.as_weak();
    8.40+        let row_data = row_data.clone();
    8.41+        move |index| {
    8.42+            let row_data = row_data.clone();
    8.43+
    8.44+            let sort_model = Rc::new(row_data.sort_by(move |r_a, r_b| {
    8.45+                let c_a = r_a.row_data(index as usize).unwrap();
    8.46+                let c_b = r_b.row_data(index as usize).unwrap();
    8.47+
    8.48+                c_a.text.cmp(&c_b.text)
    8.49+            }));
    8.50+
    8.51+            app_weak.unwrap().global::<TableViewPageAdapter>().set_row_data(sort_model.into());
    8.52+        }
    8.53+    });
    8.54+
    8.55+    app.global::<TableViewPageAdapter>().on_sort_descending({
    8.56+        let app_weak = app.as_weak();
    8.57+        move |index| {
    8.58+            let row_data = row_data.clone();
    8.59+
    8.60+            let sort_model = Rc::new(row_data.sort_by(move |r_a, r_b| {
    8.61+                let c_a = r_a.row_data(index as usize).unwrap();
    8.62+                let c_b = r_b.row_data(index as usize).unwrap();
    8.63+
    8.64+                c_b.text.cmp(&c_a.text)
    8.65+            }));
    8.66+
    8.67+            app_weak.unwrap().global::<TableViewPageAdapter>().set_row_data(sort_model.into());
    8.68+        }
    8.69+    });
    8.70+
    8.71+    app.run().unwrap();
    8.72+}
     9.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2+++ b/ui/main.rs	Sat May 27 21:07:55 2023 -0400
     9.3@@ -0,0 +1,4 @@
     9.4+use ui::run;
     9.5+fn main() {
     9.6+  run();
     9.7+}
    10.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2+++ b/ui/pages.slint	Sat May 27 21:07:55 2023 -0400
    10.3@@ -0,0 +1,7 @@
    10.4+import { AboutPage } from "pages/about.slint";
    10.5+import { ControlsPage } from "pages/controls.slint";
    10.6+import { ListViewPage } from "pages/list_view.slint";
    10.7+import { TableViewPage, TableViewPageAdapter } from "pages/table_view.slint";
    10.8+import { TextEditPage } from "pages/text_edit.slint";
    10.9+
   10.10+export { AboutPage, ControlsPage, ListViewPage, TextEditPage, TableViewPage, TableViewPageAdapter }
   10.11\ No newline at end of file
    11.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2+++ b/ui/pages/about.slint	Sat May 27 21:07:55 2023 -0400
    11.3@@ -0,0 +1,10 @@
    11.4+import { AboutSlint } from "std-widgets.slint";
    11.5+import { UiConfig } from "../config.slint";
    11.6+import { Page } from "page.slint";
    11.7+
    11.8+export component AboutPage inherits Page {
    11.9+    title: "About";
   11.10+    description: "Are you curious now? Check out the docs and gettings start from the Github repository and the website https://slint-ui.com and try it yourself.";
   11.11+
   11.12+    AboutSlint {}
   11.13+}
   11.14\ No newline at end of file
    12.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2+++ b/ui/pages/controls.slint	Sat May 27 21:07:55 2023 -0400
    12.3@@ -0,0 +1,145 @@
    12.4+import { Button, GroupBox, SpinBox, ComboBox, CheckBox, LineEdit, TabWidget, VerticalBox, HorizontalBox,
    12.5+    Slider, SpinBox } from "std-widgets.slint";
    12.6+import { UiConfig } from "../config.slint";
    12.7+import { Page } from "page.slint";
    12.8+
    12.9+export component ControlsPage inherits Page {
   12.10+    title: "Controls";
   12.11+    description: "This page gives an overview of the default widget set provided by Slint. The widgets are available in different styles native, fluent-(dark/light) and material-(dark/light). The widgets can be imported from \"std-widgets.slint\".";
   12.12+
   12.13+    GroupBox {
   12.14+        vertical-stretch: 0;
   12.15+        title: "Buttons";
   12.16+
   12.17+        HorizontalLayout {
   12.18+            spacing: 8px;
   12.19+            alignment: start;
   12.20+
   12.21+            Button {
   12.22+                text: "Regular Button";
   12.23+                enabled: !UiConfig.widgets-disabled;
   12.24+            }
   12.25+
   12.26+            Button {
   12.27+                text: "Button with Icon";
   12.28+                icon: @image-url("../img/treez.png");
   12.29+                enabled: !UiConfig.widgets-disabled;
   12.30+            }
   12.31+
   12.32+            Button {
   12.33+                checkable: true;
   12.34+                text: self.checked ? "ON" : "OFF";
   12.35+                enabled: !UiConfig.widgets-disabled;
   12.36+            }
   12.37+        }
   12.38+    }
   12.39+
   12.40+    GroupBox {
   12.41+        title: "CheckBox - SpinBox - ComboBox";
   12.42+        vertical-stretch: 0;
   12.43+
   12.44+        HorizontalBox {
   12.45+            alignment: start;
   12.46+            checkbox := CheckBox {
   12.47+                text: checkbox.checked ? "(checked)" : "(unchecked)";
   12.48+                checked: true;
   12.49+                enabled: !UiConfig.widgets-disabled;
   12.50+            }
   12.51+
   12.52+
   12.53+        SpinBox {
   12.54+            vertical-stretch: 0;
   12.55+            value: 42;
   12.56+            enabled: !UiConfig.widgets-disabled;
   12.57+        }
   12.58+
   12.59+            ComboBox {
   12.60+                model: ["Select Something", "From this", "Combobox"];
   12.61+                enabled: !UiConfig.widgets-disabled;
   12.62+            }
   12.63+        }
   12.64+
   12.65+
   12.66+    }
   12.67+
   12.68+    GroupBox {
   12.69+        title: "LineEdit";
   12.70+        vertical-stretch: 0;
   12.71+
   12.72+        LineEdit {
   12.73+            placeholder-text: "Enter some text";
   12.74+            enabled: !UiConfig.widgets-disabled;
   12.75+        }
   12.76+    }
   12.77+
   12.78+    GroupBox {
   12.79+        title: "Slider";
   12.80+        vertical-stretch: 0;
   12.81+
   12.82+        Slider {
   12.83+            min-width: 160px;
   12.84+            minimum: -100;
   12.85+            maximum: 100;
   12.86+            value: 42;
   12.87+            enabled: !UiConfig.widgets-disabled;
   12.88+        }
   12.89+    }
   12.90+
   12.91+    GroupBox {
   12.92+        title: "TabWidget";
   12.93+
   12.94+        TabWidget {
   12.95+            Tab {
   12.96+                title: "Tab 1";
   12.97+
   12.98+                VerticalBox {
   12.99+                    alignment: start;
  12.100+
  12.101+                    GroupBox {
  12.102+                        title: "Content of tab 1";
  12.103+
  12.104+                        HorizontalBox {
  12.105+                            alignment: start;
  12.106+
  12.107+                            Button {
  12.108+                                text: "Click me";
  12.109+                                enabled: !UiConfig.widgets-disabled;
  12.110+                            }
  12.111+                        }
  12.112+                    }
  12.113+                }
  12.114+            }
  12.115+
  12.116+            Tab {
  12.117+                title: "Tab 2";
  12.118+
  12.119+                VerticalBox {
  12.120+                    alignment: start;
  12.121+
  12.122+                    GroupBox {
  12.123+                        title: "Content of tab 2";
  12.124+
  12.125+                        VerticalBox {
  12.126+                            alignment: start;
  12.127+
  12.128+                            CheckBox {
  12.129+                                text: "Check me";
  12.130+                                enabled: !UiConfig.widgets-disabled;
  12.131+                            }
  12.132+                        }
  12.133+                    }
  12.134+                }
  12.135+            }
  12.136+
  12.137+            Tab {
  12.138+                title: "Tab 3";
  12.139+
  12.140+                VerticalBox {
  12.141+                    Text {
  12.142+                        text: "Content of tab 3";
  12.143+                    }
  12.144+                }
  12.145+            }
  12.146+        }
  12.147+    }
  12.148+}
  12.149\ No newline at end of file
    13.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2+++ b/ui/pages/list_view.slint	Sat May 27 21:07:55 2023 -0400
    13.3@@ -0,0 +1,45 @@
    13.4+import { HorizontalBox, VerticalBox, ListView, StandardListView, GroupBox } from "std-widgets.slint";
    13.5+import { UiConfig } from "../config.slint";
    13.6+import { Page } from "page.slint";
    13.7+
    13.8+export component ListViewPage inherits Page {
    13.9+    title: "ListView";
   13.10+    description: "ListViews can be used to display a list of elements. The StandardListBox is like the default ListView just with a default text based definition of the visual items. Both can be imported from \"std-widgets.slint\"";
   13.11+
   13.12+    HorizontalBox {
   13.13+        vertical-stretch: 1;
   13.14+        GroupBox {
   13.15+            title: "ListView";
   13.16+
   13.17+            ListView {
   13.18+                vertical-stretch: 0;
   13.19+                for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] : HorizontalBox {
   13.20+                   Image {
   13.21+                        width: 24px;
   13.22+                        source: @image-url("../img/ayo.jpeg");
   13.23+                   }
   13.24+                   Text {
   13.25+                        text: "Item " + i;
   13.26+                   }
   13.27+                }
   13.28+            }
   13.29+        }
   13.30+
   13.31+        GroupBox {
   13.32+            title: "StandardListView";
   13.33+            vertical-stretch: 0;
   13.34+
   13.35+            StandardListView {
   13.36+                model: [
   13.37+                    {text: "Lorem"}, {text: "ipsum"},{text: "dolor"},{text: "sit"},{text: "amet"},{text: "consetetur"},
   13.38+                    {text: "Lorem"}, {text: "ipsum"},{text: "dolor"},{text: "sit"},{text: "amet"},{text: "consetetur"},
   13.39+                    {text: "Lorem"}, {text: "ipsum"},{text: "dolor"},{text: "sit"},{text: "amet"},{text: "consetetur"},
   13.40+                    {text: "Lorem"}, {text: "ipsum"},{text: "dolor"},{text: "sit"},{text: "amet"},{text: "consetetur"},
   13.41+                    {text: "Lorem"}, {text: "ipsum"},{text: "dolor"},{text: "sit"},{text: "amet"},{text: "consetetur"},
   13.42+                    {text: "Lorem"}, {text: "ipsum"},{text: "dolor"},{text: "sit"},{text: "amet"},{text: "consetetur"},
   13.43+                    {text: "Lorem"}, {text: "ipsum"},{text: "dolor"},{text: "sit"},{text: "amet"},{text: "consetetur"},
   13.44+                ];
   13.45+            }
   13.46+        }
   13.47+    }
   13.48+}
   13.49\ No newline at end of file
    14.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2+++ b/ui/pages/page.slint	Sat May 27 21:07:55 2023 -0400
    14.3@@ -0,0 +1,27 @@
    14.4+import { CheckBox, GridBox, ListView, ScrollView, VerticalBox } from "std-widgets.slint";
    14.5+
    14.6+import { UiConfig } from "../config.slint";
    14.7+
    14.8+export component Page inherits VerticalBox {
    14.9+    in property<string> title: "title";
   14.10+    in property<string> description: "description";
   14.11+
   14.12+    HorizontalLayout {
   14.13+        height: 24px;
   14.14+        Text {
   14.15+            font-size: 20px;
   14.16+            text <=> root.title;
   14.17+        }
   14.18+
   14.19+        // Spacer
   14.20+        Rectangle {}
   14.21+
   14.22+        CheckBox {
   14.23+            horizontal-stretch: 0;
   14.24+            text: "Disable widgets";
   14.25+            checked <=> UiConfig.widgets-disabled;
   14.26+        }
   14.27+    }
   14.28+
   14.29+    @children
   14.30+}
   14.31\ No newline at end of file
    15.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2+++ b/ui/pages/table_view.slint	Sat May 27 21:07:55 2023 -0400
    15.3@@ -0,0 +1,48 @@
    15.4+import { HorizontalBox, VerticalBox, StandardTableView, GroupBox} from "std-widgets.slint";
    15.5+import { UiConfig } from "../config.slint";
    15.6+import { Page } from "page.slint";
    15.7+
    15.8+export global TableViewPageAdapter  {
    15.9+    callback sort_ascending(int);
   15.10+    callback sort_descending(int);
   15.11+    in property <[[StandardListViewItem]]> row_data: [
   15.12+        [ { text: "Item 1.1" }, { text: "Item 1.2" }, { text: "Item 1.3" }, { text: "Item 1.4" }, ],
   15.13+        [ { text: "Item 2.1" }, { text: "Item 2.2" }, { text: "Item 2.3" }, { text: "Item 2.4" }, ],
   15.14+        [ { text: "Item 3.1" }, { text: "Item 3.2" }, { text: "Item 3.3" }, { text: "Item 3.4" }, ],
   15.15+        [ { text: "Item 4.1" }, { text: "Item 4.2" }, { text: "Item 4.3" }, { text: "Item 4.4" }, ],
   15.16+        [ { text: "Item 5.1" }, { text: "Item 5.2" }, { text: "Item 5.3" }, { text: "Item 5.4" }, ],
   15.17+        [ { text: "Item 6.1" }, { text: "Item 6.2" }, { text: "Item 6.3" }, { text: "Item 6.4" }, ],
   15.18+    ];
   15.19+}
   15.20+
   15.21+export component TableViewPage inherits Page {
   15.22+    title: "TableView";
   15.23+    description: "StandardTableView can be used to display a list of text elements in columns and rows. It can be imported from \"std-widgets.slint\"";
   15.24+
   15.25+    HorizontalBox {
   15.26+        vertical-stretch: 1;
   15.27+
   15.28+        GroupBox {
   15.29+            title: "StandardTableView";
   15.30+            vertical-stretch: 0;
   15.31+
   15.32+            StandardTableView {
   15.33+                sort-ascending(index) => {
   15.34+                    TableViewPageAdapter.sort_ascending(index);
   15.35+                }
   15.36+
   15.37+                sort-descending(index) => {
   15.38+                    TableViewPageAdapter.sort-descending(index);
   15.39+                }
   15.40+
   15.41+                columns: [
   15.42+                    { title: "Header 1" },
   15.43+                    { title: "Header 2" },
   15.44+                    { title: "Header 3" },
   15.45+                    { title: "Header 4" },
   15.46+                ];
   15.47+                rows: TableViewPageAdapter.row_data;
   15.48+            }
   15.49+        }
   15.50+    }
   15.51+}
   15.52\ No newline at end of file
    16.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2+++ b/ui/pages/text_edit.slint	Sat May 27 21:07:55 2023 -0400
    16.3@@ -0,0 +1,32 @@
    16.4+import { HorizontalBox, GroupBox, TextEdit } from "std-widgets.slint";
    16.5+import { UiConfig } from "../config.slint";
    16.6+import { Page } from "page.slint";
    16.7+
    16.8+export component TextEditPage inherits Page {
    16.9+    title: "TextEdit";
   16.10+    description: "Similar to LineEdit, but can be used to enter several lines of text. The widget can be imported from \"std-widgets.slint\".";
   16.11+
   16.12+    HorizontalBox {
   16.13+        GroupBox {
   16.14+            vertical-stretch: 0;
   16.15+            title: "Word-Wrap";
   16.16+            te1 := TextEdit {
   16.17+                min-width: 200px;
   16.18+                text: "This is our TextEdit widget, which allows for editing text that spans over multiple paragraphs.\nFor example this line starts in a new paragraph.\n\nWhen the amount of lines - due to wrapping and number of paragraphs - exceeds the available vertical height, a vertical scrollbar is shown that allows scrolling.\nYou may want to enter a bit of text here then in order to make them visible.";
   16.19+                wrap: word-wrap;
   16.20+                enabled: !UiConfig.widgets-disabled;
   16.21+            }
   16.22+        }
   16.23+
   16.24+        GroupBox {
   16.25+            title: "No-Wrap";
   16.26+            vertical-stretch: 0;
   16.27+            te2 := TextEdit {
   16.28+                min-width: 200px;
   16.29+                text <=> te1.text;
   16.30+                wrap: no-wrap;
   16.31+                enabled: !UiConfig.widgets-disabled;
   16.32+            }
   16.33+        }
   16.34+    }
   16.35+}
   16.36\ No newline at end of file
    17.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2+++ b/ui/sidebar.slint	Sat May 27 21:07:55 2023 -0400
    17.3@@ -0,0 +1,127 @@
    17.4+import { StyleMetrics } from "std-widgets.slint";
    17.5+
    17.6+component SideBarItem inherits Rectangle {
    17.7+    callback clicked <=> touch.clicked;
    17.8+    in-out property<string> text <=> label.text;
    17.9+    in property<bool> selected;
   17.10+    in property<bool> has-focus;
   17.11+
   17.12+    min-height: l.preferred-height;
   17.13+
   17.14+    state := Rectangle {
   17.15+        opacity: 0;
   17.16+        background: StyleMetrics.window-background;
   17.17+
   17.18+        animate opacity { duration: 150ms; }
   17.19+    }
   17.20+
   17.21+    l := HorizontalLayout {
   17.22+        y: (parent.height - self.height) / 2;
   17.23+        padding: StyleMetrics.layout-padding;
   17.24+        spacing: 0px;
   17.25+
   17.26+        label := Text {
   17.27+            color: StyleMetrics.default-text-color;
   17.28+            vertical-alignment: center;
   17.29+         }
   17.30+    }
   17.31+
   17.32+    touch := TouchArea {
   17.33+        width: 100%;
   17.34+        height: 100%;
   17.35+    }
   17.36+
   17.37+    states [
   17.38+        pressed when touch.pressed : {
   17.39+            state.opacity: 0.8;
   17.40+        }
   17.41+        hover when touch.has-hover : {
   17.42+            state.opacity: 0.6;
   17.43+        }
   17.44+        selected when root.selected : {
   17.45+            state.opacity: 1;
   17.46+        }
   17.47+        focused when root.has-focus : {
   17.48+            state.opacity: 0.8;
   17.49+        }
   17.50+    ]
   17.51+}
   17.52+
   17.53+export component SideBar inherits Rectangle {
   17.54+    in property<[string]> model: [];
   17.55+    out property<int> current-item: 0;
   17.56+    in property<string> title <=> label.text;
   17.57+    out property<int> current-focused: fs.has-focus ? fs.focused-tab : -1; // The currently focused tab
   17.58+    width: 180px;
   17.59+
   17.60+    forward-focus: fs;
   17.61+
   17.62+    accessible-role: tab;
   17.63+    accessible-delegate-focus: root.current-focused >= 0 ? root.current-focused : root.current-item;
   17.64+
   17.65+    Rectangle {
   17.66+        background: StyleMetrics.window-background.darker(0.2);
   17.67+
   17.68+        fs := FocusScope {
   17.69+            x:0;
   17.70+            width: 0px; // Do not react on clicks
   17.71+            property<int> focused-tab: 0;
   17.72+
   17.73+            key-pressed(event) => {
   17.74+                if (event.text == "\n") {
   17.75+                     root.current-item = root.current-focused;
   17.76+                     return accept;
   17.77+                }
   17.78+                if (event.text == Key.UpArrow) {
   17.79+                     self.focused-tab = Math.max(self.focused-tab - 1,  0);
   17.80+                     return accept;
   17.81+                }
   17.82+                if (event.text == Key.DownArrow) {
   17.83+                     self.focused-tab = Math.min(self.focused-tab + 1, root.model.length - 1);
   17.84+                     return accept;
   17.85+                }
   17.86+                return reject;
   17.87+            }
   17.88+
   17.89+            key-released(event) => {
   17.90+                if (event.text == " ") {
   17.91+                     root.current-item = root.current-focused;
   17.92+                     return accept;
   17.93+                }
   17.94+                return reject;
   17.95+            }
   17.96+        }
   17.97+    }
   17.98+
   17.99+    VerticalLayout {
  17.100+        padding-top: StyleMetrics.layout-padding;
  17.101+        padding-bottom: StyleMetrics.layout-padding;
  17.102+        spacing: StyleMetrics.layout-spacing;
  17.103+        alignment: start;
  17.104+
  17.105+        label := Text {
  17.106+            font-size: 16px;
  17.107+            horizontal-alignment: center;
  17.108+        }
  17.109+
  17.110+        navigation := VerticalLayout {
  17.111+            alignment: start;
  17.112+            vertical-stretch: 0;
  17.113+            for item[index] in root.model : SideBarItem {
  17.114+                has-focus: index == root.current-focused;
  17.115+                text: item;
  17.116+                selected: index == root.current-item;
  17.117+                clicked => { root.current-item = index; }
  17.118+            }
  17.119+        }
  17.120+
  17.121+        VerticalLayout {
  17.122+            bottom := VerticalLayout {
  17.123+                padding-left: StyleMetrics.layout-padding;
  17.124+                padding-right: StyleMetrics.layout-padding;
  17.125+
  17.126+                @children
  17.127+             }
  17.128+        }
  17.129+    }
  17.130+}
  17.131\ No newline at end of file
    18.1--- a/ui/src/lib.rs	Fri May 26 21:59:40 2023 -0400
    18.2+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.3@@ -1,59 +0,0 @@
    18.4-#[cfg(target_arch="wasm32")]
    18.5-use wasm_bindgen::prelude::*;
    18.6-use winit::{
    18.7-    event::*,
    18.8-    event_loop::{ControlFlow, EventLoop},
    18.9-    window::WindowBuilder,
   18.10-};
   18.11-
   18.12-#[cfg_attr(target_arch="wasm32", wasm_bindgen(start))]
   18.13-pub fn run() {
   18.14-  cfg_if::cfg_if! {
   18.15-    if #[cfg(target_arch = "wasm32")] {
   18.16-      std::panic::set_hook(Box::new(console_error_panic_hook::hook));
   18.17-      console_log::init_with_level(log::Level::Warn).expect("Couldn't initialize logger");
   18.18-    } else {
   18.19-      env_logger::init();
   18.20-    }
   18.21-  }
   18.22-  let event_loop = EventLoop::new();
   18.23-  let window = WindowBuilder::new().build(&event_loop).unwrap();
   18.24-
   18.25-  #[cfg(target_arch = "wasm32")]
   18.26-{
   18.27-    // Winit prevents sizing with CSS, so we have to set
   18.28-    // the size manually when on web.
   18.29-    use winit::dpi::PhysicalSize;
   18.30-    window.set_inner_size(PhysicalSize::new(450, 400));
   18.31-    
   18.32-    use winit::platform::web::WindowExtWebSys;
   18.33-    web_sys::window()
   18.34-        .and_then(|win| win.document())
   18.35-        .and_then(|doc| {
   18.36-            let dst = doc.get_element_by_id("wasm-example")?;
   18.37-            let canvas = web_sys::Element::from(window.canvas());
   18.38-            dst.append_child(&canvas).ok()?;
   18.39-            Some(())
   18.40-        })
   18.41-        .expect("Couldn't append canvas to document body.");
   18.42-}
   18.43-    event_loop.run(move |event, _, control_flow| match event {
   18.44-        Event::WindowEvent {
   18.45-            ref event,
   18.46-            window_id,
   18.47-        } if window_id == window.id() => match event {
   18.48-            WindowEvent::CloseRequested
   18.49-            | WindowEvent::KeyboardInput {
   18.50-                input:
   18.51-                    KeyboardInput {
   18.52-                        state: ElementState::Pressed,
   18.53-                        virtual_keycode: Some(VirtualKeyCode::Escape),
   18.54-                        ..
   18.55-                    },
   18.56-                ..
   18.57-            } => *control_flow = ControlFlow::Exit,
   18.58-            _ => {}
   18.59-        },
   18.60-        _ => {}
   18.61-    });
   18.62-}
    19.1--- a/ui/src/main.rs	Fri May 26 21:59:40 2023 -0400
    19.2+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.3@@ -1,4 +0,0 @@
    19.4-use ui::run;
    19.5-pub fn main() {
    19.6-    run();
    19.7-}
    20.1--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2+++ b/ui/ui.slint	Sat May 27 21:07:55 2023 -0400
    20.3@@ -0,0 +1,18 @@
    20.4+import {CheckBox, StandardListView, StyleMetrics} from "std-widgets.slint";
    20.5+import {AboutPage, ControlsPage, ListViewPage, TableViewPage, TableViewPageAdapter, TextEditPage} from "pages.slint";
    20.6+import {UiConfig} from "config.slint";
    20.7+import {SideBar} from "sidebar.slint";
    20.8+export {TableViewPageAdapter}
    20.9+export component App inherits Window {
   20.10+  title: "Demo";
   20.11+  icon: @image-url("img/treez.png");
   20.12+  HorizontalLayout {
   20.13+    side-bar := SideBar {
   20.14+      title: "Demo";
   20.15+      model: ["Controls", "ListView", "About"];
   20.16+    }
   20.17+    if(side-bar.current-item == 0) : ControlsPage {}
   20.18+    if(side-bar.current-item == 1) : ListViewPage {}
   20.19+    if(side-bar.current-item == 2) : AboutPage {}
   20.20+  }
   20.21+}
   20.22\ No newline at end of file
    21.1--- a/www/boot.html	Fri May 26 21:59:40 2023 -0400
    21.2+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.3@@ -1,17 +0,0 @@
    21.4-<!doctype HTML>
    21.5-<HTML>
    21.6-   <HEAD>
    21.7-      <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
    21.8-      <meta http-equiv="Pragma" content="no-cache" />
    21.9-      <meta http-equiv="Expires" content="0" />
   21.10-      <meta charset="utf-8">
   21.11-      <meta name="viewport" content="width=device-width, initial-scale=1">
   21.12-      <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
   21.13-      <script src="/js/boot.js" type="text/javascript"></script>
   21.14-      <noscript><%= (@ meta) %></noscript>
   21.15-   </HEAD>
   21.16-<BODY>
   21.17-  <noscript><%= (@ body) %></noscript>
   21.18-</BODY>
   21.19-<noscript>Your browser must support JavaScript and be HTML 5 compilant to see this site.</noscript>
   21.20-</HTML>
    22.1--- a/www/bootstrap.html	Fri May 26 21:59:40 2023 -0400
    22.2+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.3@@ -1,19 +0,0 @@
    22.4-<!doctype HTML>
    22.5-<HTML>
    22.6-   <HEAD>
    22.7-      <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
    22.8-      <meta http-equiv="Pragma" content="no-cache" />
    22.9-      <meta http-equiv="Expires" content="0" />
   22.10-      <meta charset="utf-8">
   22.11-      <meta name="viewport" content="width=device-width, initial-scale=1">
   22.12-      <script src="/js/jquery.min.js" type="text/javascript"></script>
   22.13-      <script src="/js/boot.js" type="text/javascript"></script>
   22.14-      <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
   22.15-      <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.min.js" crossorigin="anonymous"></script>
   22.16-      <noscript><%= (@ meta) %></noscript>
   22.17-   </HEAD>
   22.18-<BODY>
   22.19-  <noscript><%= (@ body) %></noscript>
   22.20-</BODY>
   22.21-<noscript>Your browser must support JavaScript and be HTML 5 compilant to see this site.</noscript>
   22.22-</HTML>
    23.1--- a/www/css/w3.css	Fri May 26 21:59:40 2023 -0400
    23.2+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.3@@ -1,235 +0,0 @@
    23.4-/* W3.CSS 4.15 December 2020 by Jan Egil and Borge Refsnes */
    23.5-html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
    23.6-/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
    23.7-html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
    23.8-article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}summary{display:list-item}
    23.9-audio,canvas,progress,video{display:inline-block}progress{vertical-align:baseline}
   23.10-audio:not([controls]){display:none;height:0}[hidden],template{display:none}
   23.11-a{background-color:transparent}a:active,a:hover{outline-width:0}
   23.12-abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}
   23.13-b,strong{font-weight:bolder}dfn{font-style:italic}mark{background:#ff0;color:#000}
   23.14-small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
   23.15-sub{bottom:-0.25em}sup{top:-0.5em}figure{margin:1em 40px}img{border-style:none}
   23.16-code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}hr{box-sizing:content-box;height:0;overflow:visible}
   23.17-button,input,select,textarea,optgroup{font:inherit;margin:0}optgroup{font-weight:bold}
   23.18-button,input{overflow:visible}button,select{text-transform:none}
   23.19-button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}
   23.20-button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}
   23.21-button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}
   23.22-fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em}
   23.23-legend{color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}
   23.24-[type=checkbox],[type=radio]{padding:0}
   23.25-[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}
   23.26-[type=search]{-webkit-appearance:textfield;outline-offset:-2px}
   23.27-[type=search]::-webkit-search-decoration{-webkit-appearance:none}
   23.28-::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}
   23.29-/* End extract */
   23.30-html,body{font-family:Verdana,sans-serif;font-size:15px;line-height:1.5}html{overflow-x:hidden}
   23.31-h1{font-size:36px}h2{font-size:30px}h3{font-size:24px}h4{font-size:20px}h5{font-size:18px}h6{font-size:16px}
   23.32-.w3-serif{font-family:serif}.w3-sans-serif{font-family:sans-serif}.w3-cursive{font-family:cursive}.w3-monospace{font-family:monospace}
   23.33-h1,h2,h3,h4,h5,h6{font-family:"Segoe UI",Arial,sans-serif;font-weight:400;margin:10px 0}.w3-wide{letter-spacing:4px}
   23.34-hr{border:0;border-top:1px solid #eee;margin:20px 0}
   23.35-.w3-image{max-width:100%;height:auto}img{vertical-align:middle}a{color:inherit}
   23.36-.w3-table,.w3-table-all{border-collapse:collapse;border-spacing:0;width:100%;display:table}.w3-table-all{border:1px solid #ccc}
   23.37-.w3-bordered tr,.w3-table-all tr{border-bottom:1px solid #ddd}.w3-striped tbody tr:nth-child(even){background-color:#f1f1f1}
   23.38-.w3-table-all tr:nth-child(odd){background-color:#fff}.w3-table-all tr:nth-child(even){background-color:#f1f1f1}
   23.39-.w3-hoverable tbody tr:hover,.w3-ul.w3-hoverable li:hover{background-color:#ccc}.w3-centered tr th,.w3-centered tr td{text-align:center}
   23.40-.w3-table td,.w3-table th,.w3-table-all td,.w3-table-all th{padding:8px 8px;display:table-cell;text-align:left;vertical-align:top}
   23.41-.w3-table th:first-child,.w3-table td:first-child,.w3-table-all th:first-child,.w3-table-all td:first-child{padding-left:16px}
   23.42-.w3-btn,.w3-button{border:none;display:inline-block;padding:8px 16px;vertical-align:middle;overflow:hidden;text-decoration:none;color:inherit;background-color:inherit;text-align:center;cursor:pointer;white-space:nowrap}
   23.43-.w3-btn:hover{box-shadow:0 8px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}
   23.44-.w3-btn,.w3-button{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}   
   23.45-.w3-disabled,.w3-btn:disabled,.w3-button:disabled{cursor:not-allowed;opacity:0.3}.w3-disabled *,:disabled *{pointer-events:none}
   23.46-.w3-btn.w3-disabled:hover,.w3-btn:disabled:hover{box-shadow:none}
   23.47-.w3-badge,.w3-tag{background-color:#000;color:#fff;display:inline-block;padding-left:8px;padding-right:8px;text-align:center}.w3-badge{border-radius:50%}
   23.48-.w3-ul{list-style-type:none;padding:0;margin:0}.w3-ul li{padding:8px 16px;border-bottom:1px solid #ddd}.w3-ul li:last-child{border-bottom:none}
   23.49-.w3-tooltip,.w3-display-container{position:relative}.w3-tooltip .w3-text{display:none}.w3-tooltip:hover .w3-text{display:inline-block}
   23.50-.w3-ripple:active{opacity:0.5}.w3-ripple{transition:opacity 0s}
   23.51-.w3-input{padding:8px;display:block;border:none;border-bottom:1px solid #ccc;width:100%}
   23.52-.w3-select{padding:9px 0;width:100%;border:none;border-bottom:1px solid #ccc}
   23.53-.w3-dropdown-click,.w3-dropdown-hover{position:relative;display:inline-block;cursor:pointer}
   23.54-.w3-dropdown-hover:hover .w3-dropdown-content{display:block}
   23.55-.w3-dropdown-hover:first-child,.w3-dropdown-click:hover{background-color:#ccc;color:#000}
   23.56-.w3-dropdown-hover:hover > .w3-button:first-child,.w3-dropdown-click:hover > .w3-button:first-child{background-color:#ccc;color:#000}
   23.57-.w3-dropdown-content{cursor:auto;color:#000;background-color:#fff;display:none;position:absolute;min-width:160px;margin:0;padding:0;z-index:1}
   23.58-.w3-check,.w3-radio{width:24px;height:24px;position:relative;top:6px}
   23.59-.w3-sidebar{height:100%;width:200px;background-color:#fff;position:fixed!important;z-index:1;overflow:auto}
   23.60-.w3-bar-block .w3-dropdown-hover,.w3-bar-block .w3-dropdown-click{width:100%}
   23.61-.w3-bar-block .w3-dropdown-hover .w3-dropdown-content,.w3-bar-block .w3-dropdown-click .w3-dropdown-content{min-width:100%}
   23.62-.w3-bar-block .w3-dropdown-hover .w3-button,.w3-bar-block .w3-dropdown-click .w3-button{width:100%;text-align:left;padding:8px 16px}
   23.63-.w3-main,#main{transition:margin-left .4s}
   23.64-.w3-modal{z-index:3;display:none;padding-top:100px;position:fixed;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:rgb(0,0,0);background-color:rgba(0,0,0,0.4)}
   23.65-.w3-modal-content{margin:auto;background-color:#fff;position:relative;padding:0;outline:0;width:600px}
   23.66-.w3-bar{width:100%;overflow:hidden}.w3-center .w3-bar{display:inline-block;width:auto}
   23.67-.w3-bar .w3-bar-item{padding:8px 16px;float:left;width:auto;border:none;display:block;outline:0}
   23.68-.w3-bar .w3-dropdown-hover,.w3-bar .w3-dropdown-click{position:static;float:left}
   23.69-.w3-bar .w3-button{white-space:normal}
   23.70-.w3-bar-block .w3-bar-item{width:100%;display:block;padding:8px 16px;text-align:left;border:none;white-space:normal;float:none;outline:0}
   23.71-.w3-bar-block.w3-center .w3-bar-item{text-align:center}.w3-block{display:block;width:100%}
   23.72-.w3-responsive{display:block;overflow-x:auto}
   23.73-.w3-container:after,.w3-container:before,.w3-panel:after,.w3-panel:before,.w3-row:after,.w3-row:before,.w3-row-padding:after,.w3-row-padding:before,
   23.74-.w3-cell-row:before,.w3-cell-row:after,.w3-clear:after,.w3-clear:before,.w3-bar:before,.w3-bar:after{content:"";display:table;clear:both}
   23.75-.w3-col,.w3-half,.w3-third,.w3-twothird,.w3-threequarter,.w3-quarter{float:left;width:100%}
   23.76-.w3-col.s1{width:8.33333%}.w3-col.s2{width:16.66666%}.w3-col.s3{width:24.99999%}.w3-col.s4{width:33.33333%}
   23.77-.w3-col.s5{width:41.66666%}.w3-col.s6{width:49.99999%}.w3-col.s7{width:58.33333%}.w3-col.s8{width:66.66666%}
   23.78-.w3-col.s9{width:74.99999%}.w3-col.s10{width:83.33333%}.w3-col.s11{width:91.66666%}.w3-col.s12{width:99.99999%}
   23.79-@media (min-width:601px){.w3-col.m1{width:8.33333%}.w3-col.m2{width:16.66666%}.w3-col.m3,.w3-quarter{width:24.99999%}.w3-col.m4,.w3-third{width:33.33333%}
   23.80-.w3-col.m5{width:41.66666%}.w3-col.m6,.w3-half{width:49.99999%}.w3-col.m7{width:58.33333%}.w3-col.m8,.w3-twothird{width:66.66666%}
   23.81-.w3-col.m9,.w3-threequarter{width:74.99999%}.w3-col.m10{width:83.33333%}.w3-col.m11{width:91.66666%}.w3-col.m12{width:99.99999%}}
   23.82-@media (min-width:993px){.w3-col.l1{width:8.33333%}.w3-col.l2{width:16.66666%}.w3-col.l3{width:24.99999%}.w3-col.l4{width:33.33333%}
   23.83-.w3-col.l5{width:41.66666%}.w3-col.l6{width:49.99999%}.w3-col.l7{width:58.33333%}.w3-col.l8{width:66.66666%}
   23.84-.w3-col.l9{width:74.99999%}.w3-col.l10{width:83.33333%}.w3-col.l11{width:91.66666%}.w3-col.l12{width:99.99999%}}
   23.85-.w3-rest{overflow:hidden}.w3-stretch{margin-left:-16px;margin-right:-16px}
   23.86-.w3-content,.w3-auto{margin-left:auto;margin-right:auto}.w3-content{max-width:980px}.w3-auto{max-width:1140px}
   23.87-.w3-cell-row{display:table;width:100%}.w3-cell{display:table-cell}
   23.88-.w3-cell-top{vertical-align:top}.w3-cell-middle{vertical-align:middle}.w3-cell-bottom{vertical-align:bottom}
   23.89-.w3-hide{display:none!important}.w3-show-block,.w3-show{display:block!important}.w3-show-inline-block{display:inline-block!important}
   23.90-@media (max-width:1205px){.w3-auto{max-width:95%}}
   23.91-@media (max-width:600px){.w3-modal-content{margin:0 10px;width:auto!important}.w3-modal{padding-top:30px}
   23.92-.w3-dropdown-hover.w3-mobile .w3-dropdown-content,.w3-dropdown-click.w3-mobile .w3-dropdown-content{position:relative}	
   23.93-.w3-hide-small{display:none!important}.w3-mobile{display:block;width:100%!important}.w3-bar-item.w3-mobile,.w3-dropdown-hover.w3-mobile,.w3-dropdown-click.w3-mobile{text-align:center}
   23.94-.w3-dropdown-hover.w3-mobile,.w3-dropdown-hover.w3-mobile .w3-btn,.w3-dropdown-hover.w3-mobile .w3-button,.w3-dropdown-click.w3-mobile,.w3-dropdown-click.w3-mobile .w3-btn,.w3-dropdown-click.w3-mobile .w3-button{width:100%}}
   23.95-@media (max-width:768px){.w3-modal-content{width:500px}.w3-modal{padding-top:50px}}
   23.96-@media (min-width:993px){.w3-modal-content{width:900px}.w3-hide-large{display:none!important}.w3-sidebar.w3-collapse{display:block!important}}
   23.97-@media (max-width:992px) and (min-width:601px){.w3-hide-medium{display:none!important}}
   23.98-@media (max-width:992px){.w3-sidebar.w3-collapse{display:none}.w3-main{margin-left:0!important;margin-right:0!important}.w3-auto{max-width:100%}}
   23.99-.w3-top,.w3-bottom{position:fixed;width:100%;z-index:1}.w3-top{top:0}.w3-bottom{bottom:0}
  23.100-.w3-overlay{position:fixed;display:none;width:100%;height:100%;top:0;left:0;right:0;bottom:0;background-color:rgba(0,0,0,0.5);z-index:2}
  23.101-.w3-display-topleft{position:absolute;left:0;top:0}.w3-display-topright{position:absolute;right:0;top:0}
  23.102-.w3-display-bottomleft{position:absolute;left:0;bottom:0}.w3-display-bottomright{position:absolute;right:0;bottom:0}
  23.103-.w3-display-middle{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%)}
  23.104-.w3-display-left{position:absolute;top:50%;left:0%;transform:translate(0%,-50%);-ms-transform:translate(-0%,-50%)}
  23.105-.w3-display-right{position:absolute;top:50%;right:0%;transform:translate(0%,-50%);-ms-transform:translate(0%,-50%)}
  23.106-.w3-display-topmiddle{position:absolute;left:50%;top:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
  23.107-.w3-display-bottommiddle{position:absolute;left:50%;bottom:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
  23.108-.w3-display-container:hover .w3-display-hover{display:block}.w3-display-container:hover span.w3-display-hover{display:inline-block}.w3-display-hover{display:none}
  23.109-.w3-display-position{position:absolute}
  23.110-.w3-circle{border-radius:50%}
  23.111-.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
  23.112-.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
  23.113-.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
  23.114-.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
  23.115-.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
  23.116-.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
  23.117-.w3-card,.w3-card-2{box-shadow:0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12)}
  23.118-.w3-card-4,.w3-hover-shadow:hover{box-shadow:0 4px 10px 0 rgba(0,0,0,0.2),0 4px 20px 0 rgba(0,0,0,0.19)}
  23.119-.w3-spin{animation:w3-spin 2s infinite linear}@keyframes w3-spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}
  23.120-.w3-animate-fading{animation:fading 10s infinite}@keyframes fading{0%{opacity:0}50%{opacity:1}100%{opacity:0}}
  23.121-.w3-animate-opacity{animation:opac 0.8s}@keyframes opac{from{opacity:0} to{opacity:1}}
  23.122-.w3-animate-top{position:relative;animation:animatetop 0.4s}@keyframes animatetop{from{top:-300px;opacity:0} to{top:0;opacity:1}}
  23.123-.w3-animate-left{position:relative;animation:animateleft 0.4s}@keyframes animateleft{from{left:-300px;opacity:0} to{left:0;opacity:1}}
  23.124-.w3-animate-right{position:relative;animation:animateright 0.4s}@keyframes animateright{from{right:-300px;opacity:0} to{right:0;opacity:1}}
  23.125-.w3-animate-bottom{position:relative;animation:animatebottom 0.4s}@keyframes animatebottom{from{bottom:-300px;opacity:0} to{bottom:0;opacity:1}}
  23.126-.w3-animate-zoom {animation:animatezoom 0.6s}@keyframes animatezoom{from{transform:scale(0)} to{transform:scale(1)}}
  23.127-.w3-animate-input{transition:width 0.4s ease-in-out}.w3-animate-input:focus{width:100%!important}
  23.128-.w3-opacity,.w3-hover-opacity:hover{opacity:0.60}.w3-opacity-off,.w3-hover-opacity-off:hover{opacity:1}
  23.129-.w3-opacity-max{opacity:0.25}.w3-opacity-min{opacity:0.75}
  23.130-.w3-greyscale-max,.w3-grayscale-max,.w3-hover-greyscale:hover,.w3-hover-grayscale:hover{filter:grayscale(100%)}
  23.131-.w3-greyscale,.w3-grayscale{filter:grayscale(75%)}.w3-greyscale-min,.w3-grayscale-min{filter:grayscale(50%)}
  23.132-.w3-sepia{filter:sepia(75%)}.w3-sepia-max,.w3-hover-sepia:hover{filter:sepia(100%)}.w3-sepia-min{filter:sepia(50%)}
  23.133-.w3-tiny{font-size:10px!important}.w3-small{font-size:12px!important}.w3-medium{font-size:15px!important}.w3-large{font-size:18px!important}
  23.134-.w3-xlarge{font-size:24px!important}.w3-xxlarge{font-size:36px!important}.w3-xxxlarge{font-size:48px!important}.w3-jumbo{font-size:64px!important}
  23.135-.w3-left-align{text-align:left!important}.w3-right-align{text-align:right!important}.w3-justify{text-align:justify!important}.w3-center{text-align:center!important}
  23.136-.w3-border-0{border:0!important}.w3-border{border:1px solid #ccc!important}
  23.137-.w3-border-top{border-top:1px solid #ccc!important}.w3-border-bottom{border-bottom:1px solid #ccc!important}
  23.138-.w3-border-left{border-left:1px solid #ccc!important}.w3-border-right{border-right:1px solid #ccc!important}
  23.139-.w3-topbar{border-top:6px solid #ccc!important}.w3-bottombar{border-bottom:6px solid #ccc!important}
  23.140-.w3-leftbar{border-left:6px solid #ccc!important}.w3-rightbar{border-right:6px solid #ccc!important}
  23.141-.w3-section,.w3-code{margin-top:16px!important;margin-bottom:16px!important}
  23.142-.w3-margin{margin:16px!important}.w3-margin-top{margin-top:16px!important}.w3-margin-bottom{margin-bottom:16px!important}
  23.143-.w3-margin-left{margin-left:16px!important}.w3-margin-right{margin-right:16px!important}
  23.144-.w3-padding-small{padding:4px 8px!important}.w3-padding{padding:8px 16px!important}.w3-padding-large{padding:12px 24px!important}
  23.145-.w3-padding-16{padding-top:16px!important;padding-bottom:16px!important}.w3-padding-24{padding-top:24px!important;padding-bottom:24px!important}
  23.146-.w3-padding-32{padding-top:32px!important;padding-bottom:32px!important}.w3-padding-48{padding-top:48px!important;padding-bottom:48px!important}
  23.147-.w3-padding-64{padding-top:64px!important;padding-bottom:64px!important}
  23.148-.w3-padding-top-64{padding-top:64px!important}.w3-padding-top-48{padding-top:48px!important}
  23.149-.w3-padding-top-32{padding-top:32px!important}.w3-padding-top-24{padding-top:24px!important}
  23.150-.w3-left{float:left!important}.w3-right{float:right!important}
  23.151-.w3-button:hover{color:#000!important;background-color:#ccc!important}
  23.152-.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
  23.153-.w3-hover-none:hover{box-shadow:none!important}
  23.154-/* Colors */
  23.155-.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
  23.156-.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
  23.157-.w3-blue,.w3-hover-blue:hover{color:#fff!important;background-color:#2196F3!important}
  23.158-.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important}
  23.159-.w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important}
  23.160-.w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important}
  23.161-.w3-blue-grey,.w3-hover-blue-grey:hover,.w3-blue-gray,.w3-hover-blue-gray:hover{color:#fff!important;background-color:#607d8b!important}
  23.162-.w3-green,.w3-hover-green:hover{color:#fff!important;background-color:#4CAF50!important}
  23.163-.w3-light-green,.w3-hover-light-green:hover{color:#000!important;background-color:#8bc34a!important}
  23.164-.w3-indigo,.w3-hover-indigo:hover{color:#fff!important;background-color:#3f51b5!important}
  23.165-.w3-khaki,.w3-hover-khaki:hover{color:#000!important;background-color:#f0e68c!important}
  23.166-.w3-lime,.w3-hover-lime:hover{color:#000!important;background-color:#cddc39!important}
  23.167-.w3-orange,.w3-hover-orange:hover{color:#000!important;background-color:#ff9800!important}
  23.168-.w3-deep-orange,.w3-hover-deep-orange:hover{color:#fff!important;background-color:#ff5722!important}
  23.169-.w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important}
  23.170-.w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important}
  23.171-.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important}
  23.172-.w3-red,.w3-hover-red:hover{color:#fff!important;background-color:#f44336!important}
  23.173-.w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important}
  23.174-.w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important}
  23.175-.w3-yellow,.w3-hover-yellow:hover{color:#000!important;background-color:#ffeb3b!important}
  23.176-.w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important}
  23.177-.w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important}
  23.178-.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
  23.179-.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
  23.180-.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
  23.181-.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
  23.182-.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
  23.183-.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
  23.184-.w3-pale-blue,.w3-hover-pale-blue:hover{color:#000!important;background-color:#ddffff!important}
  23.185-.w3-text-amber,.w3-hover-text-amber:hover{color:#ffc107!important}
  23.186-.w3-text-aqua,.w3-hover-text-aqua:hover{color:#00ffff!important}
  23.187-.w3-text-blue,.w3-hover-text-blue:hover{color:#2196F3!important}
  23.188-.w3-text-light-blue,.w3-hover-text-light-blue:hover{color:#87CEEB!important}
  23.189-.w3-text-brown,.w3-hover-text-brown:hover{color:#795548!important}
  23.190-.w3-text-cyan,.w3-hover-text-cyan:hover{color:#00bcd4!important}
  23.191-.w3-text-blue-grey,.w3-hover-text-blue-grey:hover,.w3-text-blue-gray,.w3-hover-text-blue-gray:hover{color:#607d8b!important}
  23.192-.w3-text-green,.w3-hover-text-green:hover{color:#4CAF50!important}
  23.193-.w3-text-light-green,.w3-hover-text-light-green:hover{color:#8bc34a!important}
  23.194-.w3-text-indigo,.w3-hover-text-indigo:hover{color:#3f51b5!important}
  23.195-.w3-text-khaki,.w3-hover-text-khaki:hover{color:#b4aa50!important}
  23.196-.w3-text-lime,.w3-hover-text-lime:hover{color:#cddc39!important}
  23.197-.w3-text-orange,.w3-hover-text-orange:hover{color:#ff9800!important}
  23.198-.w3-text-deep-orange,.w3-hover-text-deep-orange:hover{color:#ff5722!important}
  23.199-.w3-text-pink,.w3-hover-text-pink:hover{color:#e91e63!important}
  23.200-.w3-text-purple,.w3-hover-text-purple:hover{color:#9c27b0!important}
  23.201-.w3-text-deep-purple,.w3-hover-text-deep-purple:hover{color:#673ab7!important}
  23.202-.w3-text-red,.w3-hover-text-red:hover{color:#f44336!important}
  23.203-.w3-text-sand,.w3-hover-text-sand:hover{color:#fdf5e6!important}
  23.204-.w3-text-teal,.w3-hover-text-teal:hover{color:#009688!important}
  23.205-.w3-text-yellow,.w3-hover-text-yellow:hover{color:#d2be0e!important}
  23.206-.w3-text-white,.w3-hover-text-white:hover{color:#fff!important}
  23.207-.w3-text-black,.w3-hover-text-black:hover{color:#000!important}
  23.208-.w3-text-grey,.w3-hover-text-grey:hover,.w3-text-gray,.w3-hover-text-gray:hover{color:#757575!important}
  23.209-.w3-text-light-grey,.w3-hover-text-light-grey:hover,.w3-text-light-gray,.w3-hover-text-light-gray:hover{color:#f1f1f1!important}
  23.210-.w3-text-dark-grey,.w3-hover-text-dark-grey:hover,.w3-text-dark-gray,.w3-hover-text-dark-gray:hover{color:#3a3a3a!important}
  23.211-.w3-border-amber,.w3-hover-border-amber:hover{border-color:#ffc107!important}
  23.212-.w3-border-aqua,.w3-hover-border-aqua:hover{border-color:#00ffff!important}
  23.213-.w3-border-blue,.w3-hover-border-blue:hover{border-color:#2196F3!important}
  23.214-.w3-border-light-blue,.w3-hover-border-light-blue:hover{border-color:#87CEEB!important}
  23.215-.w3-border-brown,.w3-hover-border-brown:hover{border-color:#795548!important}
  23.216-.w3-border-cyan,.w3-hover-border-cyan:hover{border-color:#00bcd4!important}
  23.217-.w3-border-blue-grey,.w3-hover-border-blue-grey:hover,.w3-border-blue-gray,.w3-hover-border-blue-gray:hover{border-color:#607d8b!important}
  23.218-.w3-border-green,.w3-hover-border-green:hover{border-color:#4CAF50!important}
  23.219-.w3-border-light-green,.w3-hover-border-light-green:hover{border-color:#8bc34a!important}
  23.220-.w3-border-indigo,.w3-hover-border-indigo:hover{border-color:#3f51b5!important}
  23.221-.w3-border-khaki,.w3-hover-border-khaki:hover{border-color:#f0e68c!important}
  23.222-.w3-border-lime,.w3-hover-border-lime:hover{border-color:#cddc39!important}
  23.223-.w3-border-orange,.w3-hover-border-orange:hover{border-color:#ff9800!important}
  23.224-.w3-border-deep-orange,.w3-hover-border-deep-orange:hover{border-color:#ff5722!important}
  23.225-.w3-border-pink,.w3-hover-border-pink:hover{border-color:#e91e63!important}
  23.226-.w3-border-purple,.w3-hover-border-purple:hover{border-color:#9c27b0!important}
  23.227-.w3-border-deep-purple,.w3-hover-border-deep-purple:hover{border-color:#673ab7!important}
  23.228-.w3-border-red,.w3-hover-border-red:hover{border-color:#f44336!important}
  23.229-.w3-border-sand,.w3-hover-border-sand:hover{border-color:#fdf5e6!important}
  23.230-.w3-border-teal,.w3-hover-border-teal:hover{border-color:#009688!important}
  23.231-.w3-border-yellow,.w3-hover-border-yellow:hover{border-color:#ffeb3b!important}
  23.232-.w3-border-white,.w3-hover-border-white:hover{border-color:#fff!important}
  23.233-.w3-border-black,.w3-hover-border-black:hover{border-color:#000!important}
  23.234-.w3-border-grey,.w3-hover-border-grey:hover,.w3-border-gray,.w3-hover-border-gray:hover{border-color:#9e9e9e!important}
  23.235-.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
  23.236-.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
  23.237-.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
  23.238-.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
    25.1--- a/www/robots.txt	Fri May 26 21:59:40 2023 -0400
    25.2+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.3@@ -1,2 +0,0 @@
    25.4-User-agent: *
    25.5-Disallow: