From 4bd797cb60630e06a84a87d7976f9d678a9d5447 Mon Sep 17 00:00:00 2001 From: dzikoysk Date: Sun, 27 Oct 2024 20:31:53 +0100 Subject: [PATCH] GH-2254 Initialize ui based on jte + htmx + tailwindcss + preact (optional) --- .gitignore | 1 + reposilite-backend/build.gradle.kts | 5 ++ .../main/kotlin/com/reposilite/ui/UiPlugin.kt | 35 ++++++++++++ .../ui/jtx/JtexDictionaryCodeResolver.kt | 13 +++++ .../com/reposilite/ui/jtx/JtexPlugin.kt | 55 +++++++++++++++++++ ...com.reposilite.plugin.api.ReposilitePlugin | 3 +- .../src/main/resources/ui/.jteroot | 0 .../src/main/resources/ui/README.md | 12 ++++ .../src/main/resources/ui/component/Foo.jte | 26 +++++++++ .../main/resources/ui/component/Footer.jte | 3 + .../src/main/resources/ui/component/Head.jte | 11 ++++ .../main/resources/ui/component/Header.jte | 5 ++ .../src/main/resources/ui/index.jte | 16 ++++++ .../src/main/resources/ui/lib/DevMode.jte | 7 +++ .../src/main/resources/ui/lib/HTMX.jte | 1 + .../src/main/resources/ui/lib/Tailwind.jte | 1 + .../src/main/resources/ui/lib/fonts/Inter.jte | 7 +++ 17 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 reposilite-backend/src/main/kotlin/com/reposilite/ui/UiPlugin.kt create mode 100755 reposilite-backend/src/main/kotlin/com/reposilite/ui/jtx/JtexDictionaryCodeResolver.kt create mode 100755 reposilite-backend/src/main/kotlin/com/reposilite/ui/jtx/JtexPlugin.kt create mode 100755 reposilite-backend/src/main/resources/ui/.jteroot create mode 100644 reposilite-backend/src/main/resources/ui/README.md create mode 100755 reposilite-backend/src/main/resources/ui/component/Foo.jte create mode 100755 reposilite-backend/src/main/resources/ui/component/Footer.jte create mode 100755 reposilite-backend/src/main/resources/ui/component/Head.jte create mode 100755 reposilite-backend/src/main/resources/ui/component/Header.jte create mode 100755 reposilite-backend/src/main/resources/ui/index.jte create mode 100755 reposilite-backend/src/main/resources/ui/lib/DevMode.jte create mode 100755 reposilite-backend/src/main/resources/ui/lib/HTMX.jte create mode 100755 reposilite-backend/src/main/resources/ui/lib/Tailwind.jte create mode 100755 reposilite-backend/src/main/resources/ui/lib/fonts/Inter.jte diff --git a/.gitignore b/.gitignore index be2837373..26d057231 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ reposilite-test/workspace/javadocs/ reposilite-test/workspace/logs/ reposilite-test/workspace/plugins/*.jar reposilite-backend/src/generated/kotlin/com/reposilite/ReposiliteProperties.kt +.build/ ### Kotlin ### .kotlin/ diff --git a/reposilite-backend/build.gradle.kts b/reposilite-backend/build.gradle.kts index 27479b2b5..a6ee29636 100644 --- a/reposilite-backend/build.gradle.kts +++ b/reposilite-backend/build.gradle.kts @@ -43,6 +43,7 @@ dependencies { val javalin = "6.3.0" api("io.javalin:javalin:$javalin") + implementation("io.javalin:javalin-rendering:$javalin") val javalinOpenApi = "6.3.0" api("io.javalin.community.openapi:javalin-openapi-plugin:$javalinOpenApi") @@ -51,6 +52,10 @@ dependencies { val javalinRouting = "6.3.0" api("io.javalin.community.routing:routing-dsl:$javalinRouting") + val jte = "3.1.13" + implementation("gg.jte:jte:$jte") + implementation("gg.jte:jte-watcher:$jte") + val bcrypt = "0.10.2" implementation("at.favre.lib:bcrypt:$bcrypt") diff --git a/reposilite-backend/src/main/kotlin/com/reposilite/ui/UiPlugin.kt b/reposilite-backend/src/main/kotlin/com/reposilite/ui/UiPlugin.kt new file mode 100644 index 000000000..2894b9477 --- /dev/null +++ b/reposilite-backend/src/main/kotlin/com/reposilite/ui/UiPlugin.kt @@ -0,0 +1,35 @@ +package com.reposilite.ui + +import com.reposilite.plugin.api.Facade +import com.reposilite.plugin.api.Plugin +import com.reposilite.plugin.api.ReposilitePlugin +import com.reposilite.plugin.event +import com.reposilite.ui.jtx.JtexConfig +import com.reposilite.ui.jtx.JtexPlugin +import com.reposilite.web.api.HttpServerConfigurationEvent +import io.javalin.http.Context +import io.javalin.router.JavalinDefaultRouting + +@Plugin(name = "ui") +internal class UiPlugin : ReposilitePlugin() { + + override fun initialize(): Facade? { + event { event: HttpServerConfigurationEvent -> + event.config.registerPlugin( + JtexPlugin { + it.mode = JtexConfig.Mode.RESOURCE + it.path = "ui" + } + ) + + event.config.router.mount { routing: JavalinDefaultRouting -> + routing + .get("/") { ctx: Context -> ctx.render("index.jte") } + .post("/clicked") { ctx: Context -> ctx.result("Panda") } + } + } + + return null + } + +} \ No newline at end of file diff --git a/reposilite-backend/src/main/kotlin/com/reposilite/ui/jtx/JtexDictionaryCodeResolver.kt b/reposilite-backend/src/main/kotlin/com/reposilite/ui/jtx/JtexDictionaryCodeResolver.kt new file mode 100755 index 000000000..832acb500 --- /dev/null +++ b/reposilite-backend/src/main/kotlin/com/reposilite/ui/jtx/JtexDictionaryCodeResolver.kt @@ -0,0 +1,13 @@ +package com.reposilite.ui.jtx + +import gg.jte.resolve.DirectoryCodeResolver +import java.nio.file.Path + +class JtexDictionaryCodeResolver(path: Path) : DirectoryCodeResolver(path) { + + override fun resolveRequired(name: String?): String { + val content = super.resolveRequired(name) + return content + } + +} \ No newline at end of file diff --git a/reposilite-backend/src/main/kotlin/com/reposilite/ui/jtx/JtexPlugin.kt b/reposilite-backend/src/main/kotlin/com/reposilite/ui/jtx/JtexPlugin.kt new file mode 100755 index 000000000..6ada657c4 --- /dev/null +++ b/reposilite-backend/src/main/kotlin/com/reposilite/ui/jtx/JtexPlugin.kt @@ -0,0 +1,55 @@ +package com.reposilite.ui.jtx + +import gg.jte.ContentType +import gg.jte.TemplateEngine +import gg.jte.resolve.DirectoryCodeResolver +import gg.jte.resolve.ResourceCodeResolver +import gg.jte.watcher.DirectoryWatcher +import io.javalin.config.JavalinConfig +import io.javalin.plugin.Plugin +import io.javalin.rendering.template.JavalinJte +import java.nio.file.Paths +import java.util.function.Consumer + +class JtexConfig { + + enum class Mode { + RESOURCE, + DIRECTORY, + } + + @JvmField var mode: Mode = Mode.RESOURCE + @JvmField var path: String = "src/main/resources" + @JvmField var sseRefreshEndpoint: String = "/refreshDevMode" +} + +class JtexPlugin(userConfig: Consumer) : Plugin(userConfig = userConfig, defaultConfig = JtexConfig()) { + + override fun onStart(config: JavalinConfig) { + val codeResolver = when(pluginConfig.mode) { + JtexConfig.Mode.RESOURCE -> ResourceCodeResolver(pluginConfig.path) + JtexConfig.Mode.DIRECTORY -> JtexDictionaryCodeResolver(Paths.get(pluginConfig.path).toAbsolutePath().normalize()) + } + Paths.get("jte-classes") + val templatingEngine = TemplateEngine.create(codeResolver, Paths.get(".build"), ContentType.Html) + templatingEngine.setProjectNamespace(".compiled") + config.fileRenderer(JavalinJte(templatingEngine)) + + config.router.mount { + it.sse(pluginConfig.sseRefreshEndpoint) { sseClient -> + if (codeResolver is DirectoryCodeResolver) { + val watcher = DirectoryWatcher(templatingEngine, codeResolver) + + watcher.start { templates -> + System.out.println("[watcher] Template changed, available at http://localhost:${config.jetty.defaultPort}") + sseClient.sendEvent("refresh", "Template changed, refresh browser event") + } + + sseClient.onClose(watcher::stop) + sseClient.keepAlive() + } + } + } + } + +} \ No newline at end of file diff --git a/reposilite-backend/src/main/resources/META-INF/services/com.reposilite.plugin.api.ReposilitePlugin b/reposilite-backend/src/main/resources/META-INF/services/com.reposilite.plugin.api.ReposilitePlugin index 43ec7eb01..0a2501962 100644 --- a/reposilite-backend/src/main/resources/META-INF/services/com.reposilite.plugin.api.ReposilitePlugin +++ b/reposilite-backend/src/main/resources/META-INF/services/com.reposilite.plugin.api.ReposilitePlugin @@ -10,4 +10,5 @@ com.reposilite.status.application.StatusPlugin com.reposilite.storage.StoragePlugin com.reposilite.status.application.FailurePlugin com.reposilite.token.application.AccessTokenPlugin -com.reposilite.web.application.WebPlugin \ No newline at end of file +com.reposilite.web.application.WebPlugin +com.reposilite.ui.UiPlugin \ No newline at end of file diff --git a/reposilite-backend/src/main/resources/ui/.jteroot b/reposilite-backend/src/main/resources/ui/.jteroot new file mode 100755 index 000000000..e69de29bb diff --git a/reposilite-backend/src/main/resources/ui/README.md b/reposilite-backend/src/main/resources/ui/README.md new file mode 100644 index 000000000..e7d4e779d --- /dev/null +++ b/reposilite-backend/src/main/resources/ui/README.md @@ -0,0 +1,12 @@ +# UI + +# Option 1 + +1. Run application as usual and open http://localhost:8080 in your browser. +2. Whenever a JTE file is changes, hit CTRL + SHIFT + F9 to recompile the template. +3. Refresh the browser to see the changes. + +# Option 2 + +1. Run JtexPlugin in directory mode and provide absolute path to the UI directory in resources +2. Whenever a JTE file changes, the page will be reloaded automatically \ No newline at end of file diff --git a/reposilite-backend/src/main/resources/ui/component/Foo.jte b/reposilite-backend/src/main/resources/ui/component/Foo.jte new file mode 100755 index 000000000..b49fac865 --- /dev/null +++ b/reposilite-backend/src/main/resources/ui/component/Foo.jte @@ -0,0 +1,26 @@ +
+ + + +@raw + +@endraw \ No newline at end of file diff --git a/reposilite-backend/src/main/resources/ui/component/Footer.jte b/reposilite-backend/src/main/resources/ui/component/Footer.jte new file mode 100755 index 000000000..5649d4c6d --- /dev/null +++ b/reposilite-backend/src/main/resources/ui/component/Footer.jte @@ -0,0 +1,3 @@ +
+ +
\ No newline at end of file diff --git a/reposilite-backend/src/main/resources/ui/component/Head.jte b/reposilite-backend/src/main/resources/ui/component/Head.jte new file mode 100755 index 000000000..b17d14587 --- /dev/null +++ b/reposilite-backend/src/main/resources/ui/component/Head.jte @@ -0,0 +1,11 @@ +@param String title + + + + + ${title} + + @template.lib.HTMX() + @template.lib.Tailwind() + @template.lib.DevMode() + \ No newline at end of file diff --git a/reposilite-backend/src/main/resources/ui/component/Header.jte b/reposilite-backend/src/main/resources/ui/component/Header.jte new file mode 100755 index 000000000..1c3ee8c7d --- /dev/null +++ b/reposilite-backend/src/main/resources/ui/component/Header.jte @@ -0,0 +1,5 @@ +@param String title + +
+

${title}

+
\ No newline at end of file diff --git a/reposilite-backend/src/main/resources/ui/index.jte b/reposilite-backend/src/main/resources/ui/index.jte new file mode 100755 index 000000000..0061f837f --- /dev/null +++ b/reposilite-backend/src/main/resources/ui/index.jte @@ -0,0 +1,16 @@ + + + @template.component.Head(title = "Reposilite") + + + @template.component.Header(title = "Reposilite") + + + + @template.component.Foo() + + @template.component.Footer() + + \ No newline at end of file diff --git a/reposilite-backend/src/main/resources/ui/lib/DevMode.jte b/reposilite-backend/src/main/resources/ui/lib/DevMode.jte new file mode 100755 index 000000000..31794b090 --- /dev/null +++ b/reposilite-backend/src/main/resources/ui/lib/DevMode.jte @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/reposilite-backend/src/main/resources/ui/lib/HTMX.jte b/reposilite-backend/src/main/resources/ui/lib/HTMX.jte new file mode 100755 index 000000000..cc581ef71 --- /dev/null +++ b/reposilite-backend/src/main/resources/ui/lib/HTMX.jte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/reposilite-backend/src/main/resources/ui/lib/Tailwind.jte b/reposilite-backend/src/main/resources/ui/lib/Tailwind.jte new file mode 100755 index 000000000..a0d43a750 --- /dev/null +++ b/reposilite-backend/src/main/resources/ui/lib/Tailwind.jte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/reposilite-backend/src/main/resources/ui/lib/fonts/Inter.jte b/reposilite-backend/src/main/resources/ui/lib/fonts/Inter.jte new file mode 100755 index 000000000..261500af4 --- /dev/null +++ b/reposilite-backend/src/main/resources/ui/lib/fonts/Inter.jte @@ -0,0 +1,7 @@ + + + \ No newline at end of file