From 621eea0446bce952e191ccdcbda8e3ed645a50e2 Mon Sep 17 00:00:00 2001 From: Kostas Kougios Date: Mon, 5 Feb 2024 16:57:41 +0000 Subject: [PATCH] - --- Readme.md | 4 + docs/images/tutorial/progress.png | Bin 0 -> 10728 bytes docs/tutorial.md | 150 ++++++++++++++++++ example-scripts/progress.sc | 30 ++++ .../components/chakra/ChakraElement.scala | 2 + 5 files changed, 186 insertions(+) create mode 100644 docs/images/tutorial/progress.png create mode 100644 docs/tutorial.md create mode 100755 example-scripts/progress.sc diff --git a/Readme.md b/Readme.md index 64c0e635..24fa6e4d 100644 --- a/Readme.md +++ b/Readme.md @@ -62,6 +62,10 @@ If we click in a cell, we will be able to change a value. And then use the "Save Now feel free to examine and run the rest of the scripts or create your own! You can have the server running and develop your scripts with your favorite IDE. Run the scripts within the IDE and view the UI in a browser. +# Tutorial + +To learn the basics of coding with terminal21, please see the [tutorial](docs/tutorial.md) + # Example scripts ```shell diff --git a/docs/images/tutorial/progress.png b/docs/images/tutorial/progress.png new file mode 100644 index 0000000000000000000000000000000000000000..9c78c2cdb1ef847969bbba722fd4ed9354f2885d GIT binary patch literal 10728 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 RkqS-}#W$+2t3YN!{{>BjlhXhI literal 0 HcmV?d00001 diff --git a/docs/tutorial.md b/docs/tutorial.md new file mode 100644 index 00000000..c8f751d1 --- /dev/null +++ b/docs/tutorial.md @@ -0,0 +1,150 @@ +# Terminal21 tutorial + +This tutorial assumes you have the terminal 21 server running (as described in the readme file of the project) and you would +like to learn how to create user interfaces. + +This tutorial will use `scala-cli` but the same applies for `sbt` or `mill` projects that use the terminal21 libraries. + +## Creating a folder for our scripts + +Create a folder and a file `project.scala` into it. This file will help us include the library dependencies and also +scala & jdk version. It should look like this: + +```scala +//> using jvm "21" +//> using scala 3 + +//> using dep io.github.kostaskougios::terminal21-ui-std:_VERSION_ +``` + +Change `_VERSION_` with the terminal 21 latest version. + +See [project.scala](../example-scripts/project.scala) + +## Creating a hello world app + +To do this we can create a [hello-world.sc](../example-scripts/hello-world.sc) in our folder. + +```scala +#!/usr/bin/env -S scala-cli project.scala + +import org.terminal21.client.* +import org.terminal21.client.components.* +import org.terminal21.client.components.std.* + +Sessions.withNewSession("hello-world", "Hello World Example"): session => + given ConnectedSession = session + + Paragraph(text = "Hello World!").render() + session.leaveSessionOpenAfterExiting() +``` + +The first line, `#!/usr/bin/env -S scala-cli project.scala`, makes our script runnable from the command line. + +```shell +chmod +x hello-world.sc + +./hello-world.sc +``` + +I had issues with intellij and this line, so you may want to comment it out while you develop your scripts. + +It starts `scala-cli` and also includes `project.scala` so that we get our dependencies, jdk 21 and scala 3 when running our code. + + +Next it creates a session. Each session has a unique id (globally unique across scripts), in this case `hello-world`. And a session +title, "Hello World Example", that will be displayed on the browser. + +```scala +Sessions.withNewSession("hello-world", "Hello World Example"): session => + ... +``` + +![hello-world](images/hello-world.png) + +Next is the actual user interface, in this example just a paragraph with a "Hello World!": + +```scala +Paragraph(text = "Hello World!").render() +``` + +The `render()` method sends the UI to the server which in turn sends it to the terminal21 UI so that it is rendered. + +Finally because this is just a presentation script (we don't expect any feedback from the user), we can terminate it but +inform terminal21 we want to leave the session open so that the user has a chance to see it. + +```scala +session.leaveSessionOpenAfterExiting() +``` + +When we run our code, it will compile, download dependencies (if needed) and run. It will exit straight away but the UI for our script +will be available in terminal21 UI. + +## Updating the UI + +Let's create a script that will display a progress bar for some process that will run for some time. The script will update +the progress bar and also give an informative message regarding which stage of the process it is performing. + +[progress.sc](../example-scripts/progress.sc) + +![progress](images/tutorial/progress.png) + +```scala +#!/usr/bin/env -S scala-cli project.scala + +import org.terminal21.client.* +import org.terminal21.client.components.* +import org.terminal21.client.components.std.* +import org.terminal21.client.components.chakra.* + +Sessions.withNewSession("universe-generation", "Universe Generation Progress"): session => + given ConnectedSession = session + + val msg = Paragraph(text = "Generating universe ...") + val progress = Progress(value = 1) + + Seq(msg, progress).render() + + for i <- 1 to 100 do + val p = progress.withValue(i) + val m = + if i < 10 then msg + else if i < 30 then msg.withText("Creating atoms") + else if i < 50 then msg.withText("Big bang!") + else if i < 80 then msg.withText("Inflating") + else msg.withText("Life evolution") + + Seq(p, m).renderChanges() + Thread.sleep(100) + + // clear UI + session.clear() + Paragraph(text = "Universe ready!").render() +``` + +Here we create a paragraph and a progress bar. + +```scala + val msg = Paragraph(text = "Generating universe ...") + val progress = Progress(value = 1) +``` + +Then we render them for the first time on screen. When we want to add a new element to the UI, we use the `render()` method. When +we want to update an existing element we use the `renderChanges()` method. + +```scala + Seq(msg, progress).render() +``` + +Then we have our main loop where the calculations occur. We just use a `Thread.sleep` to simulate that some important task is being calculated. And we +update the progress bar and the message in our paragraph. +```scala +val p = progress.withValue(i) +val m = ... msg.withText("Creating atoms") ... +``` + +Note the `e.withX()` methods. Those help us change a value on a UI element. We get a copy of the UI element which we can render as an update: + +```scala +Seq(p, m).renderChanges() +``` \ No newline at end of file diff --git a/example-scripts/progress.sc b/example-scripts/progress.sc new file mode 100755 index 00000000..29782daa --- /dev/null +++ b/example-scripts/progress.sc @@ -0,0 +1,30 @@ +#!/usr/bin/env -S scala-cli project.scala + +import org.terminal21.client.* +import org.terminal21.client.components.* +import org.terminal21.client.components.std.* +import org.terminal21.client.components.chakra.* + +Sessions.withNewSession("universe-generation", "Universe Generation Progress"): session => + given ConnectedSession = session + + val msg = Paragraph(text = "Generating universe ...") + val progress = Progress(value = 1) + + Seq(msg, progress).render() + + for i <- 1 to 100 do + val p = progress.withValue(i) + val m = + if i < 10 then msg + else if i < 30 then msg.withText("Creating atoms") + else if i < 50 then msg.withText("Big bang!") + else if i < 80 then msg.withText("Inflating") + else msg.withText("Life evolution") + + Seq(p, m).renderChanges() + Thread.sleep(100) + + // clear UI + session.clear() + Paragraph(text = "Universe ready!").render() diff --git a/terminal21-ui-std/src/main/scala/org/terminal21/client/components/chakra/ChakraElement.scala b/terminal21-ui-std/src/main/scala/org/terminal21/client/components/chakra/ChakraElement.scala index fe08e86a..ef601436 100644 --- a/terminal21-ui-std/src/main/scala/org/terminal21/client/components/chakra/ChakraElement.scala +++ b/terminal21-ui-std/src/main/scala/org/terminal21/client/components/chakra/ChakraElement.scala @@ -1755,6 +1755,8 @@ case class AlertDescription( def withKey(v: String) = copy(key = v) def withText(v: String) = copy(text = v) +/** https://chakra-ui.com/docs/components/progress + */ case class Progress( key: String = Keys.nextKey, value: Int = 50,