From: Alexander Goussas Date: Sun, 31 May 2026 16:51:59 +0000 (-0500) Subject: feat: add web ui X-Git-Url: http://git.frustrated-labs.net/?a=commitdiff_plain;h=daf3234b59355d6b7e4efc221fe85c6d781999cd;p=larousseapi feat: add web ui --- diff --git a/build.gradle b/build.gradle index b5a4601..e4461d8 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,8 @@ repositories { } dependencies { + implementation 'io.quarkiverse.qute.web:quarkus-qute-web' + implementation 'io.quarkus:quarkus-rest-qute' implementation 'io.quarkus:quarkus-micrometer-opentelemetry' implementation 'io.quarkus:quarkus-opentelemetry' implementation 'io.quarkus:quarkus-kubernetes' diff --git a/src/main/java/net/frustratedfunctor/ExceptionMappers.java b/src/main/java/net/frustratedfunctor/ExceptionMappers.java index 1e2290e..f473355 100644 --- a/src/main/java/net/frustratedfunctor/ExceptionMappers.java +++ b/src/main/java/net/frustratedfunctor/ExceptionMappers.java @@ -7,7 +7,7 @@ import org.jboss.resteasy.reactive.server.ServerExceptionMapper; final public class ExceptionMappers { @ServerExceptionMapper public RestResponse mapException(InvalidWordException ex) { - Log.info("Got bad word"); + Log.infof("Got bad word: %s", ex.getMessage()); return RestResponse.status(400); } } diff --git a/src/main/java/net/frustratedfunctor/definitions/JsoupWordDefinitionRepository.java b/src/main/java/net/frustratedfunctor/definitions/JsoupWordDefinitionRepository.java index b1bb296..96e7d78 100644 --- a/src/main/java/net/frustratedfunctor/definitions/JsoupWordDefinitionRepository.java +++ b/src/main/java/net/frustratedfunctor/definitions/JsoupWordDefinitionRepository.java @@ -22,7 +22,7 @@ public class JsoupWordDefinitionRepository implements WordDefinitionRepository { .map(Element::ownText) .toList(); } catch (Exception e) { - Log.error("Error while fetching word definitions", e); + Log.error("Error while fetching word translations", e); return new ArrayList<>(); } } diff --git a/src/main/java/net/frustratedfunctor/definitions/WordDefinitionRepository.java b/src/main/java/net/frustratedfunctor/definitions/WordDefinitionRepository.java index de8dd35..f5e2d90 100644 --- a/src/main/java/net/frustratedfunctor/definitions/WordDefinitionRepository.java +++ b/src/main/java/net/frustratedfunctor/definitions/WordDefinitionRepository.java @@ -5,10 +5,10 @@ import java.util.List; public interface WordDefinitionRepository { /** - * Get a list of definitions for the given word. + * Get a list of translations for the given word. * - * @param word The word to get definitions for. - * @return A list of found definitions for the word. + * @param word The word to get translations for. + * @return A list of found translations for the word. */ List definitionsForWord(String word); diff --git a/src/main/java/net/frustratedfunctor/translations/WordTranslation.java b/src/main/java/net/frustratedfunctor/translations/WordTranslation.java index 85778fc..2ea5957 100644 --- a/src/main/java/net/frustratedfunctor/translations/WordTranslation.java +++ b/src/main/java/net/frustratedfunctor/translations/WordTranslation.java @@ -4,6 +4,6 @@ import java.util.List; public record WordTranslation( String word, - List definitions + List translations ) { } diff --git a/src/main/java/net/frustratedfunctor/translations/WordTranslationService.java b/src/main/java/net/frustratedfunctor/translations/WordTranslationService.java index b98c68d..6f547f9 100644 --- a/src/main/java/net/frustratedfunctor/translations/WordTranslationService.java +++ b/src/main/java/net/frustratedfunctor/translations/WordTranslationService.java @@ -14,7 +14,7 @@ public class WordTranslationService { public WordTranslation translate(String word) { if (word == null || word.isEmpty()) { - throw new InvalidWordException("The word cannot be empty"); + throw new InvalidWordException("The word cannot be empty:" + word); } final var wordDefs = repository.translationsForWord(word); diff --git a/src/main/java/net/frustratedfunctor/ui/UiResource.java b/src/main/java/net/frustratedfunctor/ui/UiResource.java new file mode 100644 index 0000000..0fe5dc2 --- /dev/null +++ b/src/main/java/net/frustratedfunctor/ui/UiResource.java @@ -0,0 +1,39 @@ +package net.frustratedfunctor.ui; + +import io.quarkus.qute.Location; +import io.quarkus.qute.Template; +import io.quarkus.qute.TemplateInstance; +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import net.frustratedfunctor.definitions.WordDefinitionService; +import net.frustratedfunctor.translations.WordTranslationService; + +@Path("/ui") +public class UiResource { + + private final WordDefinitionService definitions; + private final WordTranslationService translations; + + @Location("pub/index.html") + Template index; + + public UiResource(WordDefinitionService definitions, WordTranslationService translations) { + this.definitions = definitions; + this.translations = translations; + } + + @Path("getTranslationsDefinitions") + @POST + @Produces(MediaType.TEXT_HTML) + public TemplateInstance getTranslationsDefinitions(@FormParam("word") String word) { + final var data = new WordTranslationsDefinitions( + translations.translate(word).translations(), + definitions.define(word).definitions() + ); + return index.data("translationsDefinitions", data); + } + +} diff --git a/src/main/java/net/frustratedfunctor/ui/WordTranslationsDefinitions.java b/src/main/java/net/frustratedfunctor/ui/WordTranslationsDefinitions.java new file mode 100644 index 0000000..281a626 --- /dev/null +++ b/src/main/java/net/frustratedfunctor/ui/WordTranslationsDefinitions.java @@ -0,0 +1,9 @@ +package net.frustratedfunctor.ui; + +import java.util.List; + +public record WordTranslationsDefinitions( + List translations, + List definitions +) { +} diff --git a/src/main/resources/META-INF/resources/logo.png b/src/main/resources/META-INF/resources/logo.png new file mode 100644 index 0000000..764882d Binary files /dev/null and b/src/main/resources/META-INF/resources/logo.png differ diff --git a/src/main/resources/META-INF/resources/styles.css b/src/main/resources/META-INF/resources/styles.css new file mode 100644 index 0000000..756ece5 --- /dev/null +++ b/src/main/resources/META-INF/resources/styles.css @@ -0,0 +1,41 @@ +main { + max-width: 60%; + margin: auto; + margin-top: 48px; + min-height: 90vh; + + h1 { + text-align: center; + } +} + +fieldset { + width: 100%; + + input, button { + width: 100%; + margin-bottom: 2px; + } +} + +form { + margin-bottom: 10px; +} + +.card { + padding: 0.4rem !important; +} + +footer { + padding: 1rem; + background-color: black; + min-height: 10vh; + color: white; + text-align: center; +} + +@media only screen and (max-width: 600px) { + main { + max-width: 90%; + } +} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a2c0b74..11c18a6 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -9,3 +9,5 @@ quarkus.otel.exporter.otlp.endpoint=http://localhost:4317 quarkus.application.name=larousse-api quarkus.otel.simple=true %prod.quarkus.otel.simple=false +quarkus.qute.property-not-found-strategy=default +quarkus.qute.strict-rendering=false \ No newline at end of file diff --git a/src/main/resources/templates/pub/index.html b/src/main/resources/templates/pub/index.html new file mode 100644 index 0000000..e3a5cba --- /dev/null +++ b/src/main/resources/templates/pub/index.html @@ -0,0 +1,87 @@ +{@net.frustratedfunctor.ui.WordTranslationsDefinitions translationsDefinitions} + + + + +Frustrated Langs + + + + + + + + + + +
+ +
+ +
+

Frustrated Langs

+ +
+ + + Search for a word in the box below. + +
+
+ + +
+
+ {#if translationsDefinitions && !translationsDefinitions.translations.empty} +
+

Translations

+ {#each translationsDefinitions.translations} + {it} + {/each} +
+ {/if} + {#if translationsDefinitions && !translationsDefinitions.definitions.empty} +
+

Definitions

+ {#each translationsDefinitions.definitions} + {it} + {/each} +
+ {/if} +
+
+ + + + + \ No newline at end of file