rustploy-gui 0.1.21

Rustploy — desktop client (glacier-ui) for the Rustploy PaaS daemon
// Janela "Novo projeto": motor Glacier próprio, aberto por open_window a partir
// do app principal (handlers/projects.luau → open_new_project_window), que semeia
// a conexão (api_url/api_token) via open_window({ data = ...
screen(title = "Novo projeto — Rustploy") {
  resources {
    style """
    .dialog__wrap  { width: fill; height: fill; padding: 24; spacing: 18; }
    .dialog__head  { width: fill; spacing: 5; }
    .dialog__title { size: 20; bold: true; color: var(--text); }
    """

    script(src = "scripts/new_project_window.luau")
  }

  column(class = dialog__screen) {
    row(class = titlebar) {
      row(class = titlebar__drag, on_press = window:drag) {
        text(class = titlebar__dot, content = "●")
        text(class = titlebar__title, content = "Novo projeto — Rustploy")
      }

      button(class = titlebar__btn, on_click = window:minimize, text = "—")
      button(class = "titlebar__btn titlebar__btn--close", on_click = window:close, text = "✕")
    }

    column(class = dialog__wrap) {
      column(class = dialog__head) {
        text(class = dialog__title, content = "Novo projeto")

        text(
          class = u-muted,
          content = "Cadastre um projeto no cluster conectado.",
        )
      }

      form(
        name = new_project_form,
        on_submit = submit_project,
        on_validation_error = new_project_show_validation_errors,
        width = fill,
        spacing = 14,
      ) {
        column(class = field) {
          text(class = field__label, content = "NOME")

          input(
            class = dialog__input,
            form_control = new_project_name,
            rules = required,
            msg = "informe um nome",
            placeholder = "Nome do projeto",
          )

          text(
            class = u-error,
            if = @error_new_project_name,
            not_empty,
            content = "@error_new_project_name",
          )
        }

        column(class = field) {
          text(class = field__label, content = "DESCRIÇÃO (OPCIONAL)")

          input(
            class = dialog__input,
            form_control = new_project_description,
            placeholder = Descrição,
          )
        }

        // Erros de rede/RPC (não de campo) e o status "criando…" — spinner
        // enquanto o RPC está no ar ({new_project_busy}).
        text(if = @new_project_error, not_equals = "", class = u-error, content = "@new_project_error")

        row(class = busy-row, if = @new_project_message, not_equals = "") {
          spinner(class = busy-row__spin, if = @new_project_busy)
          text(class = u-muted, content = "@new_project_message")
        }

        row(class = dialog__actions) {
          column(class = u-fill)
          button(class = "btn btn--ghost", on_click = cancel, disabled = @busy_cancel, text = Cancelar)
          button(type = submit, disabled = @busy_submit_project, class = "btn btn--primary", text = "Criar projeto")
        }
      }
    }
  }
}