This website is built entirely using Java

Objectos Way allows you to create complete web applications using nothing but the Java programming language.

Live Objectos Way Demo

This demo is written entirely in Java using Objectos Way, JDK 23 and the H2 database engine.
The main panel displays the application itself, while the secondary panel shows the source code used to generate the view.

/* * Copyright (C) 2024-2025 Objectos Software LTDA. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package demo.landing.app;import java.util.List;import objectos.way.Html;import objectos.way.Http;import objectos.way.Sql;/** * The "Now Showing" controller. */final class NowShowing implements Kino.GET {  private final Kino.Ctx ctx;  NowShowing(Kino.Ctx ctx) {    this.ctx = ctx;  }  @Override  public final Html.Component get(Http.Exchange http) {    final Sql.Transaction trx;    trx = http.get(Sql.Transaction.class);    final List<NowShowingModel> items;    items = NowShowingModel.query(trx);    return Shell.create(shell -> {      shell.appFrame = shell.sourceFrame = "now-showing";      shell.app = new NowShowingView(ctx, items);      shell.sources(          Source.NowShowing,          Source.NowShowingModel,          Source.NowShowingView      );    });  }}
/* * Copyright (C) 2024-2025 Objectos Software LTDA. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package demo.landing.app;import java.sql.ResultSet;import java.sql.SQLException;import java.util.List;import objectos.way.Sql;/** * Represents a movie in the "Now Showing" view. */record NowShowingModel(    int id,    String title) {  private NowShowingModel(ResultSet rs, int idx) throws SQLException {    this(        rs.getInt(idx++),        rs.getString(idx++)    );  }  public static List<NowShowingModel> query(Sql.Transaction trx) {    trx.sql("""    select      MOVIE.MOVIE_ID,      MOVIE.TITLE    from      MOVIE    order by      MOVIE_ID    """);    return trx.query(NowShowingModel::new);  }}
/* * Copyright (C) 2024-2025 Objectos Software LTDA. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package demo.landing.app;import java.util.List;import objectos.way.Css;/** * Renders the "Now Showing" view. */@Css.Sourcefinal class NowShowingView extends Kino.View {  private final Kino.Ctx ctx;  private final List<NowShowingModel> items;  NowShowingView(Kino.Ctx ctx, List<NowShowingModel> items) {    this.ctx = ctx;    this.items = items;  }  @Override  protected final void render() {    div(        css("""        margin-bottom:32rx        """),        h2(            text("Now Showing")        ),        p(            text("Please choose a movie")        )    );    ul(        css("""        display:flex        flex-wrap:wrap        gap:16rx        justify-content:space-evenly        """),        renderFragment(this::renderItems)    );  }  private void renderItems() {    for (NowShowingModel item : items) {      li(          css("""          flex:0_0_128rx          """),          a(              css("""              group              """),              dataOnClick(this::navigate),              href(ctx.href(Kino.Page.MOVIE, item.id())),              rel("nofollow"),              img(                  css("""                  aspect-ratio:2/3                  background-color:neutral-400                  border-radius:6rx                  group-hover:outline:2px_solid_gray-500                  """),                  src("/demo/landing/poster" + item.id() + ".jpg")              ),              h3(                  css("""                  font-size:14rx                  line-height:18rx                  text-align:center                  padding-top:8rx                  group-hover:text-decoration:underline                  """),                  text(                      testableField("movie.title", item.title())                  )              )          )      );    }  }}
/* * Copyright (C) 2024-2025 Objectos Software LTDA. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package demo.landing.app;import demo.landing.LandingDemo;import demo.landing.LandingDemoConfig;import java.time.Clock;import java.time.LocalDateTime;import java.util.Objects;import objectos.way.Css;import objectos.way.Html;import objectos.way.Http;import objectos.way.Note;import objectos.way.Script;import objectos.way.Sql;/** * Demo entry point. */public final class Kino implements LandingDemo {  private final Ctx ctx;  private Kino(Ctx ctx) {    this.ctx = ctx;  }  /**   * Creates a new {@code Demo} instance with the specified configuration.   */  public static Kino create(LandingDemoConfig config) {    Objects.requireNonNull(config, "config == null");    final Ctx ctx;    ctx = Ctx.of(config);    return new Kino(ctx);  }  /**   * Handles a GET request.   *   * <p>   * Typically this would be a {@code Http.Handler} instance. However, as this   * will be embedded in another application, we return a HTML component   * instead.   */  @Override  public final Html.Component get(Http.Exchange http) {    final Query query;    query = ctx.decode(http);    // based on the 'demo' value we create our controller    final GET controller;    controller = switch (query.page) {      case CONFIRM -> new Confirm(ctx);      case MOVIE -> new Movie(ctx);      case NOW_SHOWING -> new NowShowing(ctx);      case SEATS -> new Seats(ctx);      case TICKET -> new Ticket();      case BAD_REQUEST -> new NotFound();    };    // we intercept all controllers even though    // not all require DB access strictly speaking    return ctx.transactional(http, controller);  }  /**   * Handles a POST request.   */  @Override  public final Kino.PostResult post(Http.Exchange http) {    final Query query;    query = ctx.decode(http);    final POST controller;    controller = switch (query.page) {      case CONFIRM -> new Confirm(ctx);      case SEATS -> new Seats(ctx);      default -> new NotFound();    };    return ctx.transactional(http, controller);  }  //  // UI related classes  //  /**   * SVG icons from the Lucide project.   */  enum Icon {    ARROW_LEFT("""    <path d="m12 19-7-7 7-7"/><path d="M19 12H5"/>"""),    CALENDAR_CHECK("""    <path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/><path d="m9 16 2 2 4-4"/>"""),    CLOCK("""    <circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>"""),    CREDIT_CARD("""    <rect width="20" height="14" x="2" y="5" rx="2"/><line x1="2" x2="22" y1="10" y2="10"/>"""),    FILM(        """    <rect width="18" height="18" x="3" y="3" rx="2"/><path d="M7 3v18"/><path d="M3 7.5h4"/><path d="M3 12h18"/><path d="M3 16.5h4"/><path d="M17 3v18"/><path d="M17 7.5h4"/><path d="M17 16.5h4"/>"""),    FROWN("""    <circle cx="12" cy="12" r="10"/><path d="M16 16s-1.5-2-4-2-4 2-4 2"/><line x1="9" x2="9.01" y1="9" y2="9"/><line x1="15" x2="15.01" y1="9" y2="9"/>"""),    INFO("""    <circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/>"""),    PROJECTOR(        """    <path d="M5 7 3 5"/><path d="M9 6V3"/><path d="m13 7 2-2"/><circle cx="9" cy="13" r="3"/><path d="M11.83 12H20a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2h2.17"/><path d="M16 16h2"/>"""),    RECEIPT("""    <path d="M4 2v20l2-1 2 1 2-1 2 1 2-1 2 1 2-1 2 1V2l-2 1-2-1-2 1-2-1-2 1-2-1-2 1Z"/><path d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8"/><path d="M12 17.5v-11"/>"""),    TICKET("""    <path d="M2 9a3 3 0 0 1 0 6v2a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-2a3 3 0 0 1 0-6V7a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2Z"/><path d="M13 5v2"/><path d="M13 17v2"/><path d="M13 11v2"/>""");    final String contents;    Icon(String contents) {      this.contents = contents;    }  }  /**   * Base HTML template of the application. Provides a utility methods for   * rendering UI fragments common to the application.   */  @Css.Source // Indicates to the CSS Generator that it should scan this class for CSS utilities.  static abstract class View extends Html.Template {    static final Html.ClassName PRIMARY = Html.ClassName.ofText("""    appearance:none    background-color:btn-primary    color:btn-primary-text    cursor:pointer    display:flex    font-size:14rx    min-height:48rx    padding:14rx_63rx_14rx_15rx    active:background-color:btn-primary-active    hover:background-color:btn-primary-hover    """);    //    // component methods    //    /**     * Renders the "Go Back" link.     */    final Html.Instruction.OfElement backLink(Ctx ctx, Page page) {      testableField("back-link", page.name());      return backLink(ctx.href(page));    }    /**     * Renders the "Go Back" link.     */    final Html.Instruction.OfElement backLink(Ctx ctx, Page page, long id) {      testableField("back-link", page.name() + ":" + id);      return backLink(ctx.href(page, id));    }    /**     * Renders the "Go Back" link.     */    final Html.Instruction.OfElement backLink(Ctx ctx, Page page, long id, int aux) {      testableField("back-link", page.name() + ":" + id + ":" + aux);      Query query = page.query(id, aux);      return backLink(ctx.href(query));    }    /**     * Renders the "Go Back" link.     */    final Html.Instruction.OfElement backLink(String href) {      return a(          css("""          border-radius:9999px          padding:6rx          margin:6rx_0_0_-6rx          position:absolute          active:background-color:btn-ghost-active          hover:background-color:btn-ghost-hover          """),          dataOnClick(this::navigate),          href(href),          rel("nofollow"),          icon(              Kino.Icon.ARROW_LEFT,              css("""              height:20rx              width:20rx              """)          )      );    }    final Html.Instruction.OfAttribute formAction(Ctx ctx, Page page, long id) {      testableField("action", page.name() + ":" + id);      return action(ctx.action(page, id));    }    final Html.Instruction.OfAttribute formAction(Ctx ctx, Page page, long id, int aux) {      testableField("action", page.name() + ":" + id + ":" + aux);      return action(ctx.action(page, id, aux));    }    /**     * Renders a Lucide SVG icon.     */    final Html.Instruction icon(Kino.Icon icon, Html.Instruction... more) {      return svg(          xmlns("http://www.w3.org/2000/svg"), width("24"), height("24"), viewBox("0 0 24 24"),          fill("none"), stroke("currentColor"), strokeWidth("2"), strokeLinecap("round"), strokeLinejoin("round"),          flatten(more),          raw(icon.contents)      );    }    /*     * Typically we would use Script::navigate for "boosted" links.     * But a regular Script::navigate performs a scrollTo(0,0) after     * the request is completed. We don't want that as this demo is     * embedded in another page. In other words, we want the scroll     * position to remain the same after, e.g., we click on a movie.     */    final void navigate(Script script) {      var el = script.element();      script.request(req -> {        req.method(Script.GET);        req.url(el.attr(Html.AttributeName.HREF));        req.onSuccess(() -> {          var shell = script.elementById(Shell.APP);          shell.scroll(0, 0);        });      });    }  }  //  // Configuration related classes  //  /**   * Application-level context.   */  record Ctx(      Clock clock,      KinoCodec codec,      Note.Sink noteSink,      Reservation reservation,      Transactional transactional  ) {    static Ctx of(LandingDemoConfig config) {      final Clock clock;      clock = config.clock;      final byte[] codecKey;      codecKey = config.codecKey();      final KinoCodec codec;      codec = new KinoCodec(clock, codecKey);      final Note.Sink noteSink;      noteSink = config.noteSink;      final Reservation reservation;      reservation = new Reservation(clock, config.reservationEpoch, config.reservationRandom);      final Transactional transactional;      transactional = new Transactional(config.stage, config.database);      return new Ctx(clock, codec, noteSink, reservation, transactional);    }    final String action(Page page, long id) {      return action(page, id, 0);    }    final String action(Page page, long id, int aux) {      Query query;      query = page.query(id, aux);      String demo;      demo = codec.encode(query);      return "/demo/landing?demo=" + demo;    }    final String href(Page page) {      return href(page, 0L);    }    final String href(Page page, long id) {      Query query;      query = page.query(id);      return href(query);    }    final String href(Query query) {      String demo;      demo = codec.encode(query);      return "/index.html?demo=" + demo;    }    final long nextReservation() {      return reservation.next();    }    final <T1> void send(Note.Ref1<T1> note, T1 v1) {      noteSink.send(note, v1);    }    final LocalDateTime today() {      return LocalDateTime.now(clock);    }    final Html.Component transactional(Http.Exchange http, GET action) {      return transactional.get(http, action);    }    final PostResult transactional(Http.Exchange http, POST action) {      return transactional.post(http, action);    }    private Query decode(Http.Exchange http) {      // We cannot rely on the path to render the different pages      // of the application because this demo will be embedded in another page.      // So, we use an URL query parameter.      final String demo;      demo = http.queryParam("demo");      // the query parameter value is encoded/obfuscated.      // we use the codec to decode it.      final Query query;      query = codec.decode(demo);      http.set(Query.class, query);      return query;    }  }  //  // SQL related classes  //  private static final class Transactional {    private final Kino.Stage stage;    private final Sql.Database db;    Transactional(Kino.Stage stage, Sql.Database db) {      this.stage = stage;      this.db = db;    }    public final Html.Component get(Http.Exchange http, Kino.GET action) {      return execute(http, action::get);    }    public final Kino.PostResult post(Http.Exchange http, Kino.POST action) {      return execute(http, action::post);    }    private <T> T execute(Http.Exchange http, Action<T> action) {      return switch (stage) {        case DEFAULT -> {          final Sql.Transaction trx;          trx = db.beginTransaction(Sql.READ_COMMITED);          try {            trx.sql("set schema CINEMA");            trx.update();            http.set(Sql.Transaction.class, trx);            final T result;            result = action.execute(http);            trx.commit();            yield result;          } catch (Throwable e) {            throw trx.rollbackAndWrap(e);          } finally {            trx.close();          }        }        // this is a no-op during testing.        case TESTING -> action.execute(http);      };    }  }  //  // Embedded related classes  //  // Most Objectos Way applications will not require the classes in this section.  // They are required because this demo will be embedded in another application.  //  /**   * Represents an HTTP action in the demo application.   */  @FunctionalInterface  private interface Action<T> {    T execute(Http.Exchange http);  }  /**   * Handles a GET request. Similar to a {@code Http.Handler} instance, but for   * an embedded application.   */  interface GET {    Html.Component get(Http.Exchange http);  }  /**   * Handles a POST request. Similar to a {@code Http.Handler} instance, but for   * an embedded application.   */  interface POST {    PostResult post(Http.Exchange http);  }  /**   * The pages of this application.   *   * <p>   * As a reminder, as this application will be embedded in another one, it does   * not have actual pages.   */  enum Page {    NOW_SHOWING,    MOVIE,    SEATS,    CONFIRM,    TICKET,    BAD_REQUEST;    final Query query() {      return new Query(this, 0L, 0);    }    final Query query(long id) {      return new Query(this, id, 0);    }    final Query query(long id, int aux) {      return new Query(this, id, aux);    }  }  /**   * Represents the demo query parameter.   */  record Query(Page page, long id, int aux) {    final int idAsInt() {      return (int) id;    }  }}
/* * Copyright (C) 2024-2025 Objectos Software LTDA. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package demo.landing.app;import java.util.ArrayList;import java.util.List;import java.util.Objects;import java.util.function.Consumer;import objectos.way.Css;import objectos.way.Html;import objectos.way.Syntax;/** * The demo UI shell responsible for displaying the application on the * top/right and the source code on the bottom/left. */@Css.Source // Indicates to the CSS Generator that it should scan this class for CSS utilities.final class Shell extends Kino.View {  static final class Builder {    String appFrame;    Html.Component app;    String sourceFrame;    private final List<SourceModel> sources = new ArrayList<>();    private Builder() {}    final void sources(SourceModel... values) {      for (SourceModel value : values) {        sources.add(value);      }    }    private Shell build() {      Objects.requireNonNull(appFrame, "appFrame == null");      Objects.requireNonNull(app, "app == null");      Objects.requireNonNull(sourceFrame, "sourceFrame == null");      sources.add(Source.Kino);      sources.add(Source.Shell);      sources.add(Source.SourceModel_);      return new Shell(this);    }  }  static final Html.Id APP = Html.Id.of("demo-app");  private final Builder builder;  private Shell(Builder builder) {    this.builder = builder;  }  public static Shell create(Consumer<Builder> config) {    final Builder builder;    builder = new Builder();    config.accept(builder);    return builder.build();  }  private final Html.Id sourceFrame = Html.Id.of("source-frame");  private final Html.AttributeName dataButton = Html.AttributeName.of("data-button");  private final Html.AttributeName dataPanel = Html.AttributeName.of("data-panel");  private final Html.AttributeName dataSelected = Html.AttributeName.of("data-selected");  @Override  protected final void render() {    // the demo container    div(        css("""        display:grid        grid-template:'a'_448rx_'b'_auto_'c'_448rx_/_1fr        lg:grid-template:'c_a'_512rx_'b_b'_auto_/_1fr_1fr        xl:grid-template:'b_c_a'_512rx_/_200rx_1fr_1fr        """),        renderFragment(this::renderApp),        renderFragment(this::renderSourceMenu),        renderFragment(this::renderSourceCode)    );  }  private void renderApp() {    // the app container    div(        APP,        css("""        border:1px_solid_border        overflow:auto        grid-area:a        position:relative        lg:border-bottom-width:1px        lg:border-left-width:0px        """),        div(            css("""            align-items:center            background-color:layer            color:gray-500            display:flex            height:64rx            justify-content:space-between            padding:0_16rx            position:sticky            top:0px            z-index:8000            """),            a(                css("""                align-items:center                display:flex                gap:6rx                height:100%                """),                href("/index.html"),                dataOnClick(this::navigate),                objectosLogo(),                span(                    css("""                    font-size:24rx                    font-weight:300                    line-height:1                    transform:translateY(-1px)                    """),                    text("kino")                )            ),            a(                css("""                align-items:center                border-radius:6rx                display:flex                padding:8rx                active:background-color:btn-ghost-active                hover:background-color:btn-ghost-hover                """),                href("https://github.com/objectos/demo.landing"),                gitHubLogo()            )        ),        div(            css("""            padding:0_16rx_16rx            h2:font-size:36rx            h2:font-weight:200            h2:line-height:1            h2:padding:48rx_0_8rx            """),            dataFrame("demo-app", builder.appFrame),            renderComponent(builder.app)        )    );  }  private Html.Instruction objectosLogo() {    return svg(        css("""        width:auto        height:24rx        fill:logo        transition:fill_300ms_ease        """),        xmlns("http://www.w3.org/2000/svg"), width("200"), height("49.28"), viewBox("0 0 200 49.28"),        path(            d("m189.6 38.21q-2.53 0-5.3-0.932-2.76-0.903-4.6-3.087-0.38-0.495-0.35-1.02 0.12-0.582 0.64-0.99 0.5-0.32 1.02-0.233 0.58 0.09 0.93 0.524 1.4 1.66 3.38 2.33 2.04 0.641 4.43 0.641 4.08 0 5.77-1.456 1.71-1.456 1.71-3.408 0-1.893-1.86-3.087-1.78-1.281-5.56-1.806-4.87-0.669-7.2-2.621-2.33-1.951-2.33-4.514 0-2.417 1.23-4.077 1.19-1.689 3.29-2.534 2.12-0.874 4.86-0.874 3.29 0 5.56 1.223 2.31 1.165 3.7 3.146 0.38 0.495 0.24 1.077-0.1 0.525-0.73 0.874-0.47 0.233-1.02 0.146-0.53-0.09-0.9-0.583-1.23-1.543-2.97-2.33-1.69-0.815-3.99-0.815-3.06 0-4.75 1.31-1.69 1.311-1.69 3.146 0 1.252 0.67 2.242 0.73 0.903 2.33 1.602 1.6 0.612 4.28 1.02 3.64 0.466 5.71 1.63 2.15 1.165 3.03 2.738 0.9 1.485 0.9 3.233 0 2.301-1.46 3.99-1.45 1.689-3.81 2.621-2.39 0.874-5.16 0.874zm-27.97 0q-3.9 0-6.99-1.748-3.05-1.805-4.85-4.863-1.75-3.088-1.75-6.932 0-3.873 1.75-6.931 1.8-3.117 4.85-4.864 3.09-1.806 6.99-1.806 3.89 0 6.95 1.806 3.05 1.747 4.8 4.864 1.81 3.058 1.81 6.931 0 3.844-1.81 6.932-1.75 3.058-4.8 4.863-3.06 1.748-6.95 1.748zm0-2.709q3.07 0 5.43-1.427 2.45-1.456 3.79-3.873 1.42-2.476 1.42-5.592 0-3.058-1.42-5.475-1.34-2.476-3.79-3.874-2.36-1.456-5.43-1.456-3.03 0-5.45 1.456-2.41 1.398-3.83 3.874-1.4 2.417-1.4 5.533 0 3.058 1.4 5.534 1.42 2.417 3.83 3.873 2.42 1.427 5.45 1.427zm-19.01 2.418q-2.65-0.06-4.75-1.224-2.09-1.194-3.26-3.291-1.16-2.126-1.16-4.805v-24.17q0-0.67 0.4-1.078 0.44-0.436 1.05-0.436 0.7 0 1.08 0.436 0.44 0.408 0.44 1.078v24.17q0 2.825 1.74 4.601 1.75 1.748 4.52 1.748h1.08q0.67 0 1.05 0.437 0.43 0.407 0.43 1.077 0 0.641-0.43 1.078-0.38 0.379-1.05 0.379zm-12.96-22.95q-0.58 0-0.96-0.35-0.35-0.378-0.35-0.961 0-0.582 0.35-0.932 0.38-0.378 0.96-0.378h13.16q0.59 0 0.94 0.378 0.38 0.35 0.38 0.932 0 0.583-0.38 0.961-0.35 0.35-0.94 0.35zm-13.09 23.24q-3.78 0-6.79-1.806-2.96-1.776-4.71-4.834-1.7-3.059-1.7-6.903 0-3.873 1.6-6.931t4.42-4.806q2.81-1.806 6.45-1.806 3.1 0 5.7 1.224 2.56 1.165 4.45 3.582 0.38 0.495 0.29 1.019-0.1 0.525-0.64 0.874-0.44 0.349-0.96 0.291-0.52-0.09-0.93-0.582-3.09-3.699-7.91-3.699-2.86 0-5.04 1.427-2.14 1.398-3.35 3.815-1.17 2.447-1.17 5.592 0 3.058 1.31 5.534 1.31 2.417 3.59 3.873 2.33 1.427 5.39 1.427 1.99 0 3.74-0.582 1.81-0.583 3.12-1.806 0.44-0.379 0.96-0.437 0.52-0.06 0.93 0.35 0.47 0.437 0.47 1.019 0.1 0.524-0.38 0.903-3.55 3.262-8.84 3.262zm-27.69-0.06q-3.84 0-6.85-1.69-2.96-1.747-4.66-4.805t-1.7-6.99q0-3.99 1.61-6.99 1.6-3.058 4.41-4.805 2.82-1.748 6.46-1.748 3.59 0 6.36 1.69 2.76 1.66 4.31 4.63 1.56 2.913 1.56 6.728 0 0.641-0.39 1.019-0.39 0.35-1.02 0.35h-21.35v-2.534h22.13l-2.14 1.602q0.1-3.146-1.07-5.563-1.16-2.446-3.35-3.786-2.13-1.427-5.04-1.427-2.77 0-4.95 1.427-2.14 1.34-3.4 3.786-1.21 2.417-1.21 5.621 0 3.146 1.31 5.592 1.31 2.417 3.64 3.815 2.33 1.369 5.34 1.369 1.89 0 3.78-0.641 1.94-0.67 3.06-1.747 0.39-0.379 0.92-0.379 0.58-0.06 0.97 0.291 0.54 0.437 0.54 0.962 0 0.553-0.44 0.99-1.55 1.398-4.08 2.33-2.47 0.903-4.75 0.903zm-30.93 11.13q-0.64 0-1.07-0.44-0.44-0.38-0.44-1.02 0-0.67 0.44-1.1 0.43-0.41 1.07-0.41 2.47 0 4.31-1.05 1.9-1.08 2.97-2.97 1.06-1.89 1.06-4.313v-25.16q0-0.67 0.39-1.049 0.44-0.408 1.07-0.408 0.68 0 1.07 0.408 0.43 0.379 0.43 1.049v25.16q0 3.291-1.45 5.821-1.46 2.57-4.03 4.02-2.52 1.46-5.82 1.46zm9.75-43.48q-0.92 0-1.6-0.641-0.63-0.67-0.63-1.66 0-1.107 0.68-1.631 0.73-0.582 1.6-0.582 0.82 0 1.5 0.582 0.73 0.524 0.73 1.631 0 0.99-0.68 1.66-0.63 0.641-1.6 0.641zm-21.55 32.42q-3.79 0-6.84-1.748-3.06-1.747-4.86-4.747-1.75-3.029-1.84-6.815v-23.44q0-0.67 0.39-1.048 0.43-0.408 1.06-0.408 0.68 0 1.07 0.408 0.39 0.378 0.39 1.048v15.14q1.55-2.505 4.32-4.019 2.82-1.515 6.31-1.515 3.88 0 6.94 1.806 3.11 1.747 4.85 4.805 1.8 3.058 1.8 6.932 0 3.902-1.8 6.99-1.74 3.058-4.85 4.863-3.06 1.748-6.94 1.748zm0-2.709q3.06 0 5.44-1.427 2.42-1.456 3.83-3.873 1.41-2.476 1.41-5.592 0-3.087-1.41-5.534-1.41-2.417-3.83-3.815-2.38-1.456-5.44-1.456-3.01 0-5.44 1.456-2.42 1.398-3.83 3.815-1.36 2.447-1.36 5.534 0 3.116 1.36 5.592 1.41 2.417 3.83 3.873 2.43 1.427 5.44 1.427zm-32.53 2.709q-3.88 0-6.99-1.748-3.06-1.805-4.85-4.863-1.75-3.088-1.75-6.932 0-3.873 1.75-6.931 1.79-3.117 4.85-4.864 3.11-1.806 6.99-1.806t6.94 1.806q3.06 1.747 4.8 4.864 1.8 3.058 1.8 6.931 0 3.844-1.8 6.932-1.74 3.058-4.8 4.863-3.06 1.748-6.94 1.748zm0-2.709q3.06 0 5.44-1.427 2.42-1.456 3.78-3.873 1.41-2.476 1.41-5.592 0-3.058-1.41-5.475-1.36-2.476-3.78-3.874-2.38-1.456-5.44-1.456-3.01 0-5.44 1.456-2.42 1.398-3.83 3.874-1.41 2.417-1.41 5.533 0 3.058 1.41 5.534 1.41 2.417 3.83 3.873 2.43 1.427 5.44 1.427z"),            strokeWidth(".9101")        )    );  }  private Html.Instruction gitHubLogo() {    return svg(        css("""        width:auto        height:24rx        fill:logo        """),        xmlns("http://www.w3.org/2000/svg"), width("98"), height("96"), viewBox("0 0 98 96"),        path(            fillRule("evenodd"), clipRule("evenodd"), d(                "M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z")        )    );  }  private void renderSourceMenu() {    final List<SourceModel> items;    items = builder.sources;    final SourceModel first;    first = items.getFirst();    // the source file selector    div(        sourceFrame,        css("""        border-left:1px_solid_border        border-right:1px_solid_border        display:flex        font-size:14rx        gap:4rx_8rx        grid-area:b        padding:16rx        overflow-x:auto        lg:border-bottom:1px_solid_border        xl:border-top:1px_solid_border        xl:border-right-width:0px        xl:flex-direction:column        """),        dataFrame("demo-source-menu", builder.sourceFrame),        // stores the current selected button in the data-button attribute        attr(dataButton, first.button().value()),        // stores the current selected panel in the data-panel attribute        attr(dataPanel, first.panel().value()),        renderFragment(this::renderSourceMenuItems)    );  }  private void renderSourceMenuItems() {    final List<SourceModel> items;    items = builder.sources;    for (int idx = 0, size = items.size(); idx < size; idx++) {      final SourceModel item;      item = items.get(idx);      button(          item.button(),          css("""          border-radius:6rx          cursor:pointer          padding:4rx_8rx          [data-selected=true]:background-color:btn-ghost-active          active:background-color:btn-ghost-active          hover:background-color:btn-ghost-hover          """),          attr(dataSelected, Boolean.toString(idx == 0)),          dataOnClick(script -> {            // 'deselects' current            var frame = script.elementById(sourceFrame);            var selectedButton = script.elementById(frame.attr(dataButton));            selectedButton.attr(dataSelected, "false");            var selectedPanel = script.elementById(frame.attr(dataPanel));            selectedPanel.attr(dataSelected, "false");            // 'selects' self            var selfButton = script.elementById(item.button());            selfButton.attr(dataSelected, "true");            var selfPanel = script.elementById(item.panel());            selfPanel.attr(dataSelected, "true");            // stores selected            frame.attr(dataButton, item.button().value());            frame.attr(dataPanel, item.panel().value());          }),          text(item.name())      );    }  }  private void renderSourceCode() {    // the Java source code display    div(        css("""        border:1px_solid_border        display:flex        flex-direction:column        grid-area:c        """),        css("""        flex:1        min-height:0        overflow:auto        """),        dataFrame("demo-source-code", builder.sourceFrame),        renderFragment(this::renderSourceCodeItems)    );  }  private void renderSourceCodeItems() {    final List<SourceModel> items;    items = builder.sources;    for (int idx = 0, size = items.size(); idx < size; idx++) {      final SourceModel item;      item = items.get(idx);      final String source;      source = item.value();      pre(          item.panel(),          css("""          display:none          font-family:mono          font-size:13rx          line-height:18.6rx          padding:16rx          [data-selected=true]:display:flex          span:[data-line]:display:block          span:[data-line]:min-height:1lh          span:[data-line]:nth-child(-n+15):display:none          span:[data-high=annotation]:color:high-meta          span:[data-high=comment]:color:high-comment          span:[data-high=comment]:font-style:italic          span:[data-high=keyword]:color:high-keyword          span:[data-high=string]:color:high-string          """),          attr(dataSelected, Boolean.toString(idx == 0)),          code(              css("""              flex-grow:1              """),              renderComponent(                  Syntax.highlight(Syntax.JAVA, source)              )          )      );    }  }}
/* * Copyright (C) 2024-2025 Objectos Software LTDA. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package demo.landing.app;import objectos.way.Html;record SourceModel(String name, String value, Html.Id button, Html.Id panel) {  private static int INDEX = 0;  public static SourceModel create(String name, String value) {    final int index;    index = INDEX++;    return new SourceModel(        name,        value,        Html.Id.of("src-btn-" + index),        Html.Id.of("src-panel-" + index)    );  }}