feat(cpp/core): primitivas UI estilo Mantine

Anade 9 primitivas reutilizables al registry C++ que replican el comportamiento
de los componentes correspondientes de @fn_library / Mantine v9, todas
estilizadas con tokens_cpp_core (colores Mantine dark + indigo):

- button_cpp_core         (component, pure)  variantes primary/secondary/subtle/danger + sm/md/lg
- icon_button_cpp_core    (component, pure)  cuadrado 28x28 con glyph centrado + tooltip
- toolbar_cpp_core        (component, pure)  grupo horizontal de acciones con separadores
- modal_dialog_cpp_core   (component, pure)  popup modal centrada + close con Escape
- text_input_cpp_core     (component, impure) InputText con label muted + placeholder
- select_cpp_core         (component, impure) dropdown con label + opcion '(none)' opcional
- toast_cpp_core          (component, impure) notificaciones efimeras + inbox con badge
- tree_view_cpp_core      (component, impure) jerarquia low-level con tree_node_clicked helper
- process_runner_cpp_core (component, impure) tarea en std::thread + spinner inline

Cada primitiva tiene su .md con frontmatter completo (params/output) y se
indexa via fn index. Son la base del primitives_gallery y de cualquier
app fn_ui futura.
This commit is contained in:
2026-04-25 21:25:39 +02:00
parent 79591daef2
commit dff0d735c1
27 changed files with 1601 additions and 0 deletions
+74
View File
@@ -0,0 +1,74 @@
#include "core/button.h"
#include "core/tokens.h"
#include <imgui.h>
namespace fn_ui {
namespace {
struct VariantColors {
ImVec4 bg;
ImVec4 bg_hover;
ImVec4 bg_active;
ImVec4 text;
ImVec4 border;
float border_size; // 0 = sin borde
};
VariantColors colors_for(ButtonVariant v) {
using namespace fn_tokens::colors;
switch (v) {
case ButtonVariant::Primary:
return {primary, primary_hover, primary, text, primary, 0.0f};
case ButtonVariant::Secondary:
return {surface, surface_hover, surface, text, border, 1.0f};
case ButtonVariant::Subtle:
return {ImVec4(0,0,0,0), surface_hover, surface, primary, ImVec4(0,0,0,0),0.0f};
case ButtonVariant::Danger:
return {error, error, error, text, error, 0.0f};
}
return {surface, surface_hover, surface, text, border, 1.0f};
}
ImVec2 padding_for(ButtonSize s) {
using namespace fn_tokens::spacing;
switch (s) {
case ButtonSize::Sm: return ImVec2(md, xs + 2.0f);
case ButtonSize::Md: return ImVec2(lg, sm);
case ButtonSize::Lg: return ImVec2(xl, md);
}
return ImVec2(lg, sm);
}
float font_scale_for(ButtonSize s) {
return (s == ButtonSize::Lg) ? 1.1f : 1.0f;
}
} // namespace
bool button(const char* label, ButtonVariant variant, ButtonSize size) {
using namespace fn_tokens;
const VariantColors c = colors_for(variant);
const ImVec2 pad = padding_for(size);
const float fs = font_scale_for(size);
ImGui::PushStyleColor(ImGuiCol_Button, c.bg);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, c.bg_hover);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, c.bg_active);
ImGui::PushStyleColor(ImGuiCol_Text, c.text);
ImGui::PushStyleColor(ImGuiCol_Border, c.border);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, radius::sm);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, c.border_size);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, pad);
if (fs != 1.0f) ImGui::SetWindowFontScale(fs);
const bool clicked = ImGui::Button(label);
if (fs != 1.0f) ImGui::SetWindowFontScale(1.0f);
ImGui::PopStyleVar(3);
ImGui::PopStyleColor(5);
return clicked;
}
} // namespace fn_ui