Files
Adminive/backend/library/include/adminive/composition.hpp
T
2026-08-08 11:14:50 +08:00

158 lines
5.2 KiB
C++

#pragma once
#include <cstddef>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
namespace adminive {
enum class Composition_Node_Kind {
slot,
heading,
vertical,
horizontal,
flow,
grid,
group,
card,
tabs,
tab
};
struct Composition_Node {
Composition_Node_Kind kind{Composition_Node_Kind::vertical};
std::string slot;
std::string title;
std::string description;
std::string visible_on;
std::string accent_color;
std::size_t columns{};
bool collapsible{};
bool collapsed{};
std::vector<Composition_Node> children;
Composition_Node titled(std::string value) const {
auto result = *this;
result.title = std::move(value);
return result;
}
Composition_Node described(std::string value) const {
auto result = *this;
result.description = std::move(value);
return result;
}
Composition_Node visible_when(std::string value) const {
auto result = *this;
result.visible_on = std::move(value);
return result;
}
Composition_Node accent(std::string value) const {
auto result = *this;
result.accent_color = std::move(value);
return result;
}
Composition_Node collapsible_when(bool value = true, bool initially_collapsed = false) const {
auto result = *this;
result.collapsible = value;
result.collapsed = value && initially_collapsed;
return result;
}
};
namespace compose {
inline Composition_Node slot(std::string name) {
Composition_Node result;
result.kind = Composition_Node_Kind::slot;
result.slot = std::move(name);
return result;
}
inline Composition_Node heading(std::string title) {
Composition_Node result;
result.kind = Composition_Node_Kind::heading;
result.title = std::move(title);
return result;
}
template <class... Children>
Composition_Node make_container(Composition_Node_Kind kind, Children&&... children) {
Composition_Node result;
result.kind = kind;
result.children.reserve(sizeof...(Children));
(result.children.push_back(std::forward<Children>(children)), ...);
return result;
}
template <class... Children>
Composition_Node vertical(Children&&... children) {
return make_container(Composition_Node_Kind::vertical, std::forward<Children>(children)...);
}
template <class... Children>
Composition_Node horizontal(Children&&... children) {
return make_container(Composition_Node_Kind::horizontal, std::forward<Children>(children)...);
}
template <class... Children>
Composition_Node flow(Children&&... children) {
return make_container(Composition_Node_Kind::flow, std::forward<Children>(children)...);
}
template <class... Children>
Composition_Node grid(std::size_t columns, Children&&... children) {
auto result = make_container(Composition_Node_Kind::grid, std::forward<Children>(children)...);
result.columns = columns;
return result;
}
template <class... Children>
Composition_Node group(std::string title, Children&&... children) {
auto result = make_container(Composition_Node_Kind::group, std::forward<Children>(children)...);
result.title = std::move(title);
return result;
}
template <class... Children>
Composition_Node card(std::string title, Children&&... children) {
auto result = make_container(Composition_Node_Kind::card, std::forward<Children>(children)...);
result.title = std::move(title);
return result;
}
template <class... Children>
Composition_Node tab(std::string title, Children&&... children) {
auto result = make_container(Composition_Node_Kind::tab, std::forward<Children>(children)...);
result.title = std::move(title);
return result;
}
template <class... Children>
Composition_Node tabs(Children&&... children) {
return make_container(Composition_Node_Kind::tabs, std::forward<Children>(children)...);
}
}
struct Composition_View {
std::string name;
std::string title;
Composition_Node body;
Composition_View titled(std::string value) const {
auto result = *this;
result.title = std::move(value);
return result;
}
};
inline Composition_View composition_view(std::string name, Composition_Node body) {
return Composition_View{std::move(name), {}, std::move(body)};
}
inline void validate_composition_node(const Composition_Node& node) {
if(node.kind == Composition_Node_Kind::slot && node.slot.empty()) {
throw std::invalid_argument("composition slot name must not be empty");
}
if(node.kind == Composition_Node_Kind::grid && node.columns == 0) {
throw std::invalid_argument("composition grid requires at least one column");
}
if(node.kind == Composition_Node_Kind::tabs) {
for(const auto& child : node.children) {
if(child.kind != Composition_Node_Kind::tab) {
throw std::invalid_argument("composition tabs accepts only tab children");
}
}
}
for(const auto& child : node.children) {
validate_composition_node(child);
}
}
inline void validate_composition_view(const Composition_View& view) {
if(view.name.empty()) {
throw std::invalid_argument("composition view name must not be empty");
}
validate_composition_node(view.body);
}
}