Commit 765a17f0 authored by Jan Köster's avatar Jan Köster
Browse files

divider supprt

parent f4a8f79f
Loading
Loading
Loading
Loading
+112 −0
Changes for editor/widgets/container/container.cpp: 112 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -102,6 +102,15 @@ extern "C" {
            std::string verticalAlign = "";
            std::string m_verticalAlign = "";

            // Shape divider: a decorative SVG (wave/oval) cut into the
            // container's top or bottom edge, e.g. to end a hero background
            // without a hard horizontal line.
            std::string shapeDividerType     = "none"; // none, wave, oval
            std::string shapeDividerPosition = "bottom"; // top, bottom
            std::string shapeDividerColor    = "";
            std::string shapeDividerHeight   = "80px";
            bool shapeDividerFlip = false;

            // Box shadow
            std::string boxShadow       = "none";
            std::string boxShadowColor  = "";
@@ -331,6 +340,15 @@ extern "C" {
                addSpacingBox("padding", "Padding", "desktop");
                addSpacingBox("margin", "Margin", "desktop");
                addField("vertical_align", "Vertical Align", "select", nullptr, "desktop", mkOpts({"top","center","bottom"}));
                addField("shape_divider_type", "Shape Divider", "select", nullptr, "desktop", mkOpts({"none","wave","oval"}), "simple");
                addField("shape_divider_position", "Shape Divider Position", "select", nullptr, "desktop", mkOpts({"bottom","top"}), "simple");
                addField("shape_divider_color", "Shape Divider Color", "color_var", nullptr, "desktop", nullptr, "simple");
                addField("shape_divider_height", "Shape Divider Height", "text", "80px", "desktop");
                addField("shape_divider_flip", "Shape Divider Flip", "checkbox", nullptr, "desktop", nullptr, "simple");
                {
                    json_object *sdf = json_object_array_get_idx(arr, json_object_array_length(arr) - 1);
                    json_object_object_add(sdf, "default", json_object_new_boolean(false));
                }
                addField("box_shadow", "Box Shadow", "select", nullptr, "desktop", mkOpts({"none","sm","md","lg","card","float","inner"}));
                addField("box_shadow_color", "Box Shadow Color", "color_var", nullptr, "desktop");
                addField("box_shadow_custom", "Box Shadow Custom", "text", "e.g. 0 4px 20px rgba(0,0,0,0.5)", "desktop");
@@ -453,6 +471,14 @@ extern "C" {
                // Vertical alignment
                element->SetAttribute("vertical_align", verticalAlign.c_str());
                element->SetAttribute("m_vertical_align", m_verticalAlign.c_str());

                // Shape divider
                element->SetAttribute("shape_divider_type", shapeDividerType.c_str());
                element->SetAttribute("shape_divider_position", shapeDividerPosition.c_str());
                element->SetAttribute("shape_divider_color", shapeDividerColor.c_str());
                element->SetAttribute("shape_divider_height", shapeDividerHeight.c_str());
                element->SetAttribute("shape_divider_flip", shapeDividerFlip ? "true" : "false");

                element->SetAttribute("box_shadow", boxShadow.c_str());
                element->SetAttribute("box_shadow_color", boxShadowColor.c_str());
                element->SetAttribute("box_shadow_custom", boxShadowCustom.c_str());
@@ -622,6 +648,19 @@ extern "C" {
                if (loaded_va) verticalAlign = loaded_va;
                const char* loaded_m_va = xml_data->Attribute("m_vertical_align");
                if (loaded_m_va) m_verticalAlign = loaded_m_va;

                // Shape divider
                const char* loaded_sdt = xml_data->Attribute("shape_divider_type");
                if (loaded_sdt) shapeDividerType = loaded_sdt;
                const char* loaded_sdp = xml_data->Attribute("shape_divider_position");
                if (loaded_sdp) shapeDividerPosition = loaded_sdp;
                const char* loaded_sdc = xml_data->Attribute("shape_divider_color");
                if (loaded_sdc) shapeDividerColor = loaded_sdc;
                const char* loaded_sdh = xml_data->Attribute("shape_divider_height");
                if (loaded_sdh) shapeDividerHeight = loaded_sdh;
                const char* loaded_sdf = xml_data->Attribute("shape_divider_flip");
                if (loaded_sdf) shapeDividerFlip = (strcmp(loaded_sdf, "true") == 0);

                const char* loaded_bsh = xml_data->Attribute("box_shadow");
                if (loaded_bsh) boxShadow = loaded_bsh;
                const char* loaded_bsh_color = xml_data->Attribute("box_shadow_color");
@@ -705,6 +744,11 @@ extern "C" {
                json_object_object_add(obj, "m_height", json_object_new_string(m_height.c_str()));
                json_object_object_add(obj, "vertical_align", json_object_new_string(verticalAlign.c_str()));
                json_object_object_add(obj, "m_vertical_align", json_object_new_string(m_verticalAlign.c_str()));
                json_object_object_add(obj, "shape_divider_type", json_object_new_string(shapeDividerType.c_str()));
                json_object_object_add(obj, "shape_divider_position", json_object_new_string(shapeDividerPosition.c_str()));
                json_object_object_add(obj, "shape_divider_color", json_object_new_string(shapeDividerColor.c_str()));
                json_object_object_add(obj, "shape_divider_height", json_object_new_string(shapeDividerHeight.c_str()));
                json_object_object_add(obj, "shape_divider_flip", json_object_new_boolean(shapeDividerFlip));
                json_object_object_add(obj, "box_shadow", json_object_new_string(boxShadow.c_str()));
                json_object_object_add(obj, "box_shadow_color", json_object_new_string(boxShadowColor.c_str()));
                json_object_object_add(obj, "box_shadow_custom", json_object_new_string(boxShadowCustom.c_str()));
@@ -926,6 +970,30 @@ extern "C" {
                    val = json_object_get_string(val_obj);
                    if (val) m_verticalAlign = val;
                }
                if (json_object_object_get_ex(obj, "shape_divider_type", &val_obj)) {
                    val = json_object_get_string(val_obj);
                    if (val && val[0]) shapeDividerType = val;
                }
                if (json_object_object_get_ex(obj, "shape_divider_position", &val_obj)) {
                    val = json_object_get_string(val_obj);
                    if (val && val[0]) shapeDividerPosition = val;
                }
                if (json_object_object_get_ex(obj, "shape_divider_color", &val_obj)) {
                    val = json_object_get_string(val_obj);
                    if (val) shapeDividerColor = val;
                }
                if (json_object_object_get_ex(obj, "shape_divider_height", &val_obj)) {
                    val = json_object_get_string(val_obj);
                    if (val && val[0]) shapeDividerHeight = val;
                }
                if (json_object_object_get_ex(obj, "shape_divider_flip", &val_obj)) {
                    if (json_object_is_type(val_obj, json_type_string)) {
                        const char *s = json_object_get_string(val_obj);
                        shapeDividerFlip = (s && (strcmp(s, "true") == 0 || strcmp(s, "1") == 0));
                    } else {
                        shapeDividerFlip = json_object_get_boolean(val_obj);
                    }
                }
                if (json_object_object_get_ex(obj, "box_shadow", &val_obj)) {
                    val = json_object_get_string(val_obj);
                    if (val) boxShadow = val;
@@ -1061,6 +1129,10 @@ extern "C" {
                    std::string css = shadowCss(boxShadow, boxShadowColor);
                    if (!css.empty()) style += " box-shadow: " + css + ";";
                }
                bool hasShapeDivider = (shapeDividerType == "wave" || shapeDividerType == "oval");
                if (hasShapeDivider) {
                    style += " position: relative;";
                }
                if (hidden) {
                    style += " display: none;";
                }
@@ -1072,6 +1144,46 @@ extern "C" {
                }
                cnt.setAttribute("class", cls.c_str());

                // Shape divider: a decorative wave/oval SVG pinned to the
                // container's top or bottom edge (see member field comment).
                if (hasShapeDivider) {
                    std::string path;
                    if (shapeDividerType == "wave") {
                        path = "M0,0V46.29c47.79,22.2,103.59,32.17,158,28,70.36-5.37,136.33-33.31,206.8-37.5C438.64,32.43,"
                               "512.34,53.67,583,72.05c69.27,18,138.3,24.88,209.4,13.08,36.15-6,69.85-17.84,104.45-29.34"
                               "C989.49,25,1113,44.11,1200,89.66V0Z";
                    } else { // oval
                        path = "M0,0Q600,100,1200,0V120H0Z";
                    }

                    std::string dividerStyle = "position: absolute; left: 0; width: 100%; overflow: hidden;"
                                                " line-height: 0; pointer-events: none;";
                    dividerStyle += (shapeDividerPosition == "top") ? " top: 0;" : " bottom: 0;";
                    if (!shapeDividerHeight.empty()) dividerStyle += " height: " + shapeDividerHeight + ";";
                    std::string transform;
                    if (shapeDividerPosition == "top") transform += "rotate(180deg) ";
                    if (shapeDividerFlip) transform += "scaleX(-1) ";
                    if (!transform.empty()) dividerStyle += " transform: " + transform + ";";

                    libhtmlpp::HtmlElement dividerWrap("div");
                    dividerWrap.setAttribute("class", (responsiveClass + "-shape-divider").c_str());
                    dividerWrap.setAttribute("style", dividerStyle.c_str());

                    libhtmlpp::HtmlElement svg("svg");
                    svg.setAttribute("viewBox", "0 0 1200 120");
                    svg.setAttribute("preserveAspectRatio", "none");
                    svg.setAttribute("style", "display: block; width: 100%; height: 100%;");

                    libhtmlpp::HtmlElement svgPath("path");
                    svgPath.setAttribute("d", path.c_str());
                    std::string fill = shapeDividerColor.empty() ? "var(--blogi-bg)" : shapeDividerColor;
                    svgPath.setAttribute("fill", fill.c_str());

                    svg.appendChild(svgPath);
                    dividerWrap.appendChild(svg);
                    cnt.appendChild(dividerWrap);
                }

                // Mobile responsive overrides via media query
                std::string mobileCSS;
                if (!m_backgroundColor.empty() && m_backgroundColor != "none" && m_backgroundColor != "transparent") {
+5 −0
Changes for editor/widgets/container/translations.h: 5 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -79,6 +79,11 @@ namespace blogi { namespace webedit { namespace container_i18n {
            {"Mobile Width", "Breite (Mobil)"},
            {"Opacity", "Deckkraft"},
            {"Padding", "Innenabstand"},
            {"Shape Divider", "Formteiler"},
            {"Shape Divider Position", "Formteiler-Position"},
            {"Shape Divider Color", "Formteiler-Farbe"},
            {"Shape Divider Height", "Formteiler-Höhe"},
            {"Shape Divider Flip", "Formteiler spiegeln"},
            {"Vertical Align", "Vertikale Ausrichtung"},
            {"Width", "Breite"},
        };
+110 −0
Changes for editor/widgets/section/section.cpp: 110 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -99,6 +99,15 @@ extern "C" {
            std::string verticalAlign = "";
            std::string m_verticalAlign = "";

            // Shape divider: a decorative SVG (wave/oval) cut into the
            // section's top or bottom edge, e.g. to end a hero section
            // without a hard horizontal line.
            std::string shapeDividerType     = "none"; // none, wave, oval
            std::string shapeDividerPosition = "bottom"; // top, bottom
            std::string shapeDividerColor    = "";
            std::string shapeDividerHeight   = "80px";
            bool shapeDividerFlip = false;

            // Visibility
            bool hidden = false;
            bool m_hidden = false;
@@ -241,6 +250,15 @@ extern "C" {
                addField("border_style", "Border", "text", "e.g. 1px solid #ccc", "desktop");
                addField("opacity", "Opacity", "text", "0.0 - 1.0", "desktop");
                addField("vertical_align", "Vertical Align", "select", nullptr, "desktop", mkOpts({"top","center","bottom"}));
                addField("shape_divider_type", "Shape Divider", "select", nullptr, "desktop", mkOpts({"none","wave","oval"}), "simple");
                addField("shape_divider_position", "Shape Divider Position", "select", nullptr, "desktop", mkOpts({"bottom","top"}), "simple");
                addField("shape_divider_color", "Shape Divider Color", "color_var", nullptr, "desktop", nullptr, "simple");
                addField("shape_divider_height", "Shape Divider Height", "text", "80px", "desktop");
                addField("shape_divider_flip", "Shape Divider Flip", "checkbox", nullptr, "desktop", nullptr, "simple");
                {
                    json_object *sdf = json_object_array_get_idx(arr, json_object_array_length(arr) - 1);
                    json_object_object_add(sdf, "default", json_object_new_boolean(false));
                }
                addField("hidden", "Hidden", "checkbox", nullptr, "desktop", nullptr, "simple");
                {
                    json_object *hf = json_object_array_get_idx(arr, json_object_array_length(arr) - 1);
@@ -351,6 +369,13 @@ extern "C" {
                element->SetAttribute("vertical_align", verticalAlign.c_str());
                element->SetAttribute("m_vertical_align", m_verticalAlign.c_str());

                // Shape divider
                element->SetAttribute("shape_divider_type", shapeDividerType.c_str());
                element->SetAttribute("shape_divider_position", shapeDividerPosition.c_str());
                element->SetAttribute("shape_divider_color", shapeDividerColor.c_str());
                element->SetAttribute("shape_divider_height", shapeDividerHeight.c_str());
                element->SetAttribute("shape_divider_flip", shapeDividerFlip ? "true" : "false");

                // Visibility
                element->SetAttribute("hidden", hidden ? "true" : "false");
                element->SetAttribute("m_hidden", m_hidden ? "true" : "false");
@@ -504,6 +529,18 @@ extern "C" {
                val = xml_data->Attribute("m_vertical_align");
                if (val) m_verticalAlign = val;

                // Shape divider
                val = xml_data->Attribute("shape_divider_type");
                if (val) shapeDividerType = val;
                val = xml_data->Attribute("shape_divider_position");
                if (val) shapeDividerPosition = val;
                val = xml_data->Attribute("shape_divider_color");
                if (val) shapeDividerColor = val;
                val = xml_data->Attribute("shape_divider_height");
                if (val) shapeDividerHeight = val;
                val = xml_data->Attribute("shape_divider_flip");
                if (val) shapeDividerFlip = (strcmp(val, "true") == 0);

                // Visibility
                const char* loaded_hidden = xml_data->Attribute("hidden");
                if (loaded_hidden) hidden = (strcmp(loaded_hidden, "true") == 0);
@@ -568,6 +605,11 @@ extern "C" {
                json_object_object_add(obj, "m_height", json_object_new_string(m_height.c_str()));
                json_object_object_add(obj, "vertical_align", json_object_new_string(verticalAlign.c_str()));
                json_object_object_add(obj, "m_vertical_align", json_object_new_string(m_verticalAlign.c_str()));
                json_object_object_add(obj, "shape_divider_type", json_object_new_string(shapeDividerType.c_str()));
                json_object_object_add(obj, "shape_divider_position", json_object_new_string(shapeDividerPosition.c_str()));
                json_object_object_add(obj, "shape_divider_color", json_object_new_string(shapeDividerColor.c_str()));
                json_object_object_add(obj, "shape_divider_height", json_object_new_string(shapeDividerHeight.c_str()));
                json_object_object_add(obj, "shape_divider_flip", json_object_new_boolean(shapeDividerFlip));
                json_object_object_add(obj, "hidden", json_object_new_boolean(hidden));
                json_object_object_add(obj, "m_hidden", json_object_new_boolean(m_hidden));
                json_object_object_add(obj, "custom_css", json_object_new_string(customCss.c_str()));
@@ -767,6 +809,30 @@ extern "C" {
                    val = json_object_get_string(val_obj);
                    if (val) m_verticalAlign = val;
                }
                if (json_object_object_get_ex(obj, "shape_divider_type", &val_obj)) {
                    val = json_object_get_string(val_obj);
                    if (val && val[0]) shapeDividerType = val;
                }
                if (json_object_object_get_ex(obj, "shape_divider_position", &val_obj)) {
                    val = json_object_get_string(val_obj);
                    if (val && val[0]) shapeDividerPosition = val;
                }
                if (json_object_object_get_ex(obj, "shape_divider_color", &val_obj)) {
                    val = json_object_get_string(val_obj);
                    if (val) shapeDividerColor = val;
                }
                if (json_object_object_get_ex(obj, "shape_divider_height", &val_obj)) {
                    val = json_object_get_string(val_obj);
                    if (val && val[0]) shapeDividerHeight = val;
                }
                if (json_object_object_get_ex(obj, "shape_divider_flip", &val_obj)) {
                    if (json_object_is_type(val_obj, json_type_string)) {
                        const char *s = json_object_get_string(val_obj);
                        shapeDividerFlip = (s && (strcmp(s, "true") == 0 || strcmp(s, "1") == 0));
                    } else {
                        shapeDividerFlip = json_object_get_boolean(val_obj);
                    }
                }
                if (json_object_object_get_ex(obj, "hidden", &val_obj)) {
                    if (json_object_is_type(val_obj, json_type_string)) {
                        const char *s = json_object_get_string(val_obj);
@@ -857,6 +923,10 @@ extern "C" {
                    else if (verticalAlign == "center") style += " justify-content: center;";
                    else if (verticalAlign == "bottom") style += " justify-content: flex-end;";
                }
                bool hasShapeDivider = (shapeDividerType == "wave" || shapeDividerType == "oval");
                if (hasShapeDivider) {
                    style += " position: relative;";
                }
                if (hidden) {
                    style += " display: none;";
                }
@@ -868,6 +938,46 @@ extern "C" {
                }
                sect.setAttribute("class", cls.c_str());

                // Shape divider: a decorative wave/oval SVG pinned to the
                // section's top or bottom edge (see member field comment).
                if (hasShapeDivider) {
                    std::string path;
                    if (shapeDividerType == "wave") {
                        path = "M0,0V46.29c47.79,22.2,103.59,32.17,158,28,70.36-5.37,136.33-33.31,206.8-37.5C438.64,32.43,"
                               "512.34,53.67,583,72.05c69.27,18,138.3,24.88,209.4,13.08,36.15-6,69.85-17.84,104.45-29.34"
                               "C989.49,25,1113,44.11,1200,89.66V0Z";
                    } else { // oval
                        path = "M0,0Q600,100,1200,0V120H0Z";
                    }

                    std::string dividerStyle = "position: absolute; left: 0; width: 100%; overflow: hidden;"
                                                " line-height: 0; pointer-events: none;";
                    dividerStyle += (shapeDividerPosition == "top") ? " top: 0;" : " bottom: 0;";
                    if (!shapeDividerHeight.empty()) dividerStyle += " height: " + shapeDividerHeight + ";";
                    std::string transform;
                    if (shapeDividerPosition == "top") transform += "rotate(180deg) ";
                    if (shapeDividerFlip) transform += "scaleX(-1) ";
                    if (!transform.empty()) dividerStyle += " transform: " + transform + ";";

                    libhtmlpp::HtmlElement dividerWrap("div");
                    dividerWrap.setAttribute("class", (responsiveClass + "-shape-divider").c_str());
                    dividerWrap.setAttribute("style", dividerStyle.c_str());

                    libhtmlpp::HtmlElement svg("svg");
                    svg.setAttribute("viewBox", "0 0 1200 120");
                    svg.setAttribute("preserveAspectRatio", "none");
                    svg.setAttribute("style", "display: block; width: 100%; height: 100%;");

                    libhtmlpp::HtmlElement svgPath("path");
                    svgPath.setAttribute("d", path.c_str());
                    std::string fill = shapeDividerColor.empty() ? "var(--blogi-bg)" : shapeDividerColor;
                    svgPath.setAttribute("fill", fill.c_str());

                    svg.appendChild(svgPath);
                    dividerWrap.appendChild(svg);
                    sect.appendChild(dividerWrap);
                }

                // Mobile responsive overrides via media query
                std::string mobileCSS;
                if (!m_backgroundColor.empty() && m_backgroundColor != "none" && m_backgroundColor != "transparent") {
+5 −0
Changes for editor/widgets/section/translations.h: 5 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -70,6 +70,11 @@ namespace blogi { namespace webedit { namespace section_i18n {
            {"Mobile Width", "Breite (Mobil)"},
            {"Opacity", "Deckkraft"},
            {"Padding", "Innenabstand"},
            {"Shape Divider", "Formteiler"},
            {"Shape Divider Position", "Formteiler-Position"},
            {"Shape Divider Color", "Formteiler-Farbe"},
            {"Shape Divider Height", "Formteiler-Höhe"},
            {"Shape Divider Flip", "Formteiler spiegeln"},
            {"Vertical Align", "Vertikale Ausrichtung"},
            {"Width", "Breite"},
        };