feat(cpp,bash): app_about + Settings submenu, ensure_repo_synced pipeline

cpp/core: nuevo modulo app_about — ventana About con project/version/desc,
componible via about_window_set_info() en el init de la app y rendererizada
automaticamente por fn::run_app al final de cada frame.

app_menubar: el item top-level "Settings..." pasa a ser un BeginMenu
"Settings" con dos subitems: "Settings..." (existente) y "About..." (nuevo).

bash/infra: nueva pipeline ensure_repo_synced que compone gitea_create_repo
y gitea_push_directory para garantizar repo Gitea existente + sync de un
directorio local en una sola llamada idempotente.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-28 22:05:31 +02:00
parent dc5e3266ed
commit 424e913566
9 changed files with 327 additions and 7 deletions
+1
View File
@@ -100,6 +100,7 @@ add_library(fn_framework STATIC
functions/core/tokens.cpp
functions/core/icon_font.cpp
functions/core/app_settings.cpp
functions/core/app_about.cpp
functions/core/fps_overlay.cpp
functions/core/panel_menu.cpp
functions/core/layouts_menu.cpp
+4
View File
@@ -8,6 +8,7 @@
#include "core/tokens.h"
#include "core/icon_font.h"
#include "core/app_settings.h"
#include "core/app_about.h"
#include "core/fps_overlay.h"
#include <GLFW/glfw3.h>
@@ -131,6 +132,9 @@ int run_app(AppConfig config, std::function<void()> render_fn) {
// Ventana de Settings (no-op si esta cerrada).
fn_ui::settings_window_render();
// Ventana About (no-op si esta cerrada).
fn_ui::about_window_render();
// FPS overlay si esta activado en Settings.
if (fn_ui::settings().show_fps) {
fps_overlay();
+68
View File
@@ -0,0 +1,68 @@
#include "core/app_about.h"
#include "imgui.h"
#include <string>
namespace fn_ui {
namespace {
std::string g_project = "fn_registry app";
std::string g_version = "";
std::string g_description = "";
bool g_open = false;
} // namespace
void about_window_set_info(const char* project,
const char* version,
const char* description) {
if (project) g_project = project;
if (version) g_version = version;
if (description) g_description = description;
}
bool about_window_is_open() { return g_open; }
void about_window_set_open(bool v) { g_open = v; }
void about_window_toggle() { g_open = !g_open; }
bool about_window_menu_item(const char* label) {
if (ImGui::MenuItem(label)) {
g_open = true;
return true;
}
return false;
}
void about_window_render() {
if (!g_open) return;
ImGui::SetNextWindowSize(ImVec2(420, 220), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("About", &g_open, ImGuiWindowFlags_NoCollapse)) {
ImGui::End();
return;
}
ImGui::TextUnformatted(g_project.c_str());
if (!g_version.empty()) {
ImGui::SameLine();
ImGui::TextDisabled("v%s", g_version.c_str());
}
if (!g_description.empty()) {
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
ImGui::TextWrapped("%s", g_description.c_str());
}
ImGui::Spacing();
ImGui::Separator();
ImGui::TextDisabled("fn_registry");
ImGui::End();
}
} // namespace fn_ui
+37
View File
@@ -0,0 +1,37 @@
#pragma once
// Ventana flotante "About" para apps del registry. Muestra nombre del proyecto,
// version y descripcion opcional. Se abre desde el MenuItem "About..." en el
// submenu "Settings" de la MainMenuBar (ver app_menubar).
//
// Lifecycle:
// - app llama about_window_set_info(name, version, [description]) en su init
// - app_menubar() incluye el MenuItem "About..." en el submenu "Settings"
// - end of frame: about_window_render() — invocado por fn::run_app
//
// Apps que NO usan fn::run_app deben llamar about_window_render() manualmente
// despues del render_fn.
namespace fn_ui {
// Setea la informacion mostrada en la ventana About. Llamar una vez en el init
// de la app, antes de fn::run_app. Si no se llama, la ventana muestra valores
// por defecto ("fn_registry app", sin version).
void about_window_set_info(const char* project,
const char* version,
const char* description = "");
// Estado abierto/cerrado de la ventana.
bool about_window_is_open();
void about_window_set_open(bool v);
void about_window_toggle();
// MenuItem componible. Llamar dentro de un BeginMenu/BeginMainMenuBar exitoso.
// Click → abre la ventana. Returns true si el usuario clico.
bool about_window_menu_item(const char* label = "About...");
// Render de la ventana. No-op si is_open == false. Llamada por fn::run_app al
// final del frame, despues del render_fn de la app.
void about_window_render();
} // namespace fn_ui
+60
View File
@@ -0,0 +1,60 @@
---
name: app_about
kind: function
lang: cpp
domain: core
version: "1.0.0"
purity: impure
signature: "void fn_ui::about_window_set_info(const char* project, const char* version, const char* description = \"\"); bool fn_ui::about_window_is_open(); void fn_ui::about_window_set_open(bool); void fn_ui::about_window_toggle(); bool fn_ui::about_window_menu_item(const char* label = \"About...\"); void fn_ui::about_window_render()"
description: "Ventana flotante About para apps del registry con nombre del proyecto, version y descripcion. Se abre desde el submenu Settings -> About... de la MainMenuBar. Render automatico via fn::run_app."
tags: [imgui, about, window, ui, version]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: [imgui, string]
tested: false
tests: []
test_file_path: ""
file_path: "cpp/functions/core/app_about.cpp"
framework: imgui
params:
- name: project
desc: "Nombre del proyecto/app mostrado como titulo en la ventana About"
- name: version
desc: "Cadena de version (ej. '0.2.0') mostrada al lado del nombre del proyecto"
- name: description
desc: "Descripcion opcional mostrada debajo del titulo. Vacio = no se muestra"
- name: label
desc: "Texto del MenuItem en la menubar (default 'About...')"
output: "about_window_set_info muta el estado global del modulo. about_window_render es no-op si la ventana esta cerrada. about_window_menu_item retorna true si el usuario clico"
---
# app_about
Ventana flotante About para apps C++ del registry. Funciona en pareja con `app_settings`: ambas se exponen bajo el menu `Settings` de la MainMenuBar via `app_menubar`.
## Uso
```cpp
#include "core/app_about.h"
int main() {
fn_ui::about_window_set_info(
"Mi App",
"1.2.3",
"Descripcion corta de la app."
);
return fn::run_app({.title = "Mi App"}, render);
}
```
`fn::run_app` se encarga de invocar `about_window_render()` al final de cada frame.
## Integracion con app_menubar
`app_menubar` añade un menu `Settings` con dos items:
- `Settings...` — abre la ventana de `app_settings`
- `About...` — abre la ventana de `app_about`
+8 -3
View File
@@ -19,9 +19,14 @@ bool app_menubar(const PanelToggle* panels, std::size_t count,
changed |= layouts_menu_items("Layouts", *layouts_cb);
}
// MenuItem "Settings..." — siempre. Abre la ventana flotante; el render
// ocurre al final del frame en fn::run_app.
changed |= settings_window_menu_item("Settings...");
// Menu "Settings" — siempre. Submenus: Settings... y About...
// Las ventanas se renderizan al final del frame en fn::run_app.
if (ImGui::BeginMenu("Settings")) {
changed |= settings_window_menu_item("Settings...");
ImGui::Separator();
changed |= about_window_menu_item("About...");
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
return changed;
+7 -4
View File
@@ -3,22 +3,25 @@
#include "core/panel_menu.h"
#include "core/layouts_menu.h"
#include "core/app_settings.h"
#include "core/app_about.h"
namespace fn_ui {
// Renderiza una MainMenuBar completa con:
// * Menu "View" (panel_menu_items con los toggles dados) [si panels]
// * Menu "Layouts" (layouts_menu_items con las callbacks dadas) [si layouts_cb]
// * MenuItem "Settings..." (abre la ventana de settings) [siempre]
// * Menu "Settings" con submenus: [siempre]
// - "Settings..." → abre la ventana de settings
// - "About..." → abre la ventana About
//
// Llamar despues de NewFrame() y antes del DockSpaceOverViewport.
// Si layouts_cb es nullptr, omite Layouts.
// Si panels es nullptr o count == 0, omite View.
// El item Settings siempre aparece — la ventana se renderiza al final del
// frame en fn::run_app via settings_window_render().
// Las ventanas Settings y About se renderizan al final del frame en
// fn::run_app via settings_window_render() y about_window_render().
//
// Returns: true si el usuario togglo paneles, disparo accion de layouts,
// o abrio la ventana de settings este frame.
// o abrio una ventana este frame.
bool app_menubar(const PanelToggle* panels, std::size_t count,
LayoutCallbacks* layouts_cb);