Loading editor/widgets/timeline/timeline.cpp +50 −2 Changes for editor/widgets/timeline/timeline.cpp: 50 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -603,6 +603,18 @@ extern "C" { line.setAttribute("style", lineStyle.c_str()); stepsWrap.appendChild(line); // Progress marker: slides down the line as the page is scrolled libhtmlpp::HtmlElement progress("div"); progress.setAttribute("class", (rc + "-tl-progress").c_str()); std::string progressStyle = "position: absolute; left: 50%; top: 0;" " transform: translate(-50%, -50%); border-radius: 50%;" " z-index: 3; pointer-events: none; transition: top 0.1s linear;"; if (validCss(dotSize)) progressStyle += " width: " + dotSize + "; height: " + dotSize + ";"; if (validCss(dotColor)) progressStyle += " background: " + dotColor + ";"; if (validCss(dotBorderColor)) progressStyle += " box-shadow: 0 0 0 4px " + dotBorderColor + ";"; progress.setAttribute("style", progressStyle.c_str()); stepsWrap.appendChild(progress); for (size_t i = 0; i < items.size(); ++i) { const auto &item = items[i]; bool onRight = (i % 2) == 0; Loading Loading @@ -712,6 +724,7 @@ extern "C" { mediaCSS += "." + rc + "-tl-content{width:100% !important; flex:none !important;" " padding-left:calc(" + mobileDotSize + " * 1.8) !important;}"; mediaCSS += "." + rc + "-tl-dot{left:calc(" + mobileDotSize + " / 2) !important;}"; mediaCSS += "." + rc + "-tl-progress{left:calc(" + mobileDotSize + " / 2) !important;}"; if (validCss(m_imageHeight)) mediaCSS += "." + rc + "-tl-content img{height:" + m_imageHeight + " !important;}"; if (m_hidden) mediaCSS += "." + rc + "-tl{display:none !important;}"; else if (hidden) mediaCSS += "." + rc + "-tl{display:block !important;}"; Loading @@ -721,8 +734,14 @@ extern "C" { std::string lightCSS; if (validCss(l_titleColor)) lightCSS += "." + rc + "-tl-title{color:" + l_titleColor + " !important;}"; if (validCss(l_lineColor)) lightCSS += "." + rc + "-tl-line{background:" + l_lineColor + " !important;}"; if (validCss(l_dotColor)) lightCSS += "." + rc + "-tl-dot{background:" + l_dotColor + " !important;}"; if (validCss(l_dotBorderColor)) lightCSS += "." + rc + "-tl-dot{box-shadow:0 0 0 4px " + l_dotBorderColor + " !important;}"; if (validCss(l_dotColor)) { lightCSS += "." + rc + "-tl-dot{background:" + l_dotColor + " !important;}"; lightCSS += "." + rc + "-tl-progress{background:" + l_dotColor + " !important;}"; } if (validCss(l_dotBorderColor)) { lightCSS += "." + rc + "-tl-dot{box-shadow:0 0 0 4px " + l_dotBorderColor + " !important;}"; lightCSS += "." + rc + "-tl-progress{box-shadow:0 0 0 4px " + l_dotBorderColor + " !important;}"; } if (validCss(l_headingColor)) lightCSS += "." + rc + "-tl-content h3{color:" + l_headingColor + " !important;}"; if (validCss(l_textColor)) lightCSS += "." + rc + "-tl-content p{color:" + l_textColor + " !important;}"; Loading @@ -741,6 +760,35 @@ extern "C" { cssStyle.appendChild(libhtmlpp::TextElement(customCss.c_str())); el.appendChild(cssStyle); } // Scroll behaviour: move the progress marker down the line as the // section scrolls past the viewport's vertical center. std::string progressJs = "(function(){\n" " var wrap=document.querySelector('." + rc + "-tl-steps');\n" " var marker=document.querySelector('." + rc + "-tl-progress');\n" " if(!wrap||!marker) return;\n" " var ticking=false;\n" " function update(){\n" " var rect=wrap.getBoundingClientRect();\n" " var vh=window.innerHeight||document.documentElement.clientHeight;\n" " var pos=(vh*0.5)-rect.top;\n" " if(pos<0) pos=0;\n" " if(pos>rect.height) pos=rect.height;\n" " marker.style.top=pos+'px';\n" " ticking=false;\n" " }\n" " function onScroll(){\n" " if(!ticking){ window.requestAnimationFrame(update); ticking=true; }\n" " }\n" " window.addEventListener('scroll', onScroll, {passive:true});\n" " window.addEventListener('resize', onScroll);\n" " update();\n" "})();"; libhtmlpp::ScriptElement js; js.setScript(progressJs.c_str()); el.appendChild(js); } // Timeline manages its steps internally — no editor tree children Loading Loading
editor/widgets/timeline/timeline.cpp +50 −2 Changes for editor/widgets/timeline/timeline.cpp: 50 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -603,6 +603,18 @@ extern "C" { line.setAttribute("style", lineStyle.c_str()); stepsWrap.appendChild(line); // Progress marker: slides down the line as the page is scrolled libhtmlpp::HtmlElement progress("div"); progress.setAttribute("class", (rc + "-tl-progress").c_str()); std::string progressStyle = "position: absolute; left: 50%; top: 0;" " transform: translate(-50%, -50%); border-radius: 50%;" " z-index: 3; pointer-events: none; transition: top 0.1s linear;"; if (validCss(dotSize)) progressStyle += " width: " + dotSize + "; height: " + dotSize + ";"; if (validCss(dotColor)) progressStyle += " background: " + dotColor + ";"; if (validCss(dotBorderColor)) progressStyle += " box-shadow: 0 0 0 4px " + dotBorderColor + ";"; progress.setAttribute("style", progressStyle.c_str()); stepsWrap.appendChild(progress); for (size_t i = 0; i < items.size(); ++i) { const auto &item = items[i]; bool onRight = (i % 2) == 0; Loading Loading @@ -712,6 +724,7 @@ extern "C" { mediaCSS += "." + rc + "-tl-content{width:100% !important; flex:none !important;" " padding-left:calc(" + mobileDotSize + " * 1.8) !important;}"; mediaCSS += "." + rc + "-tl-dot{left:calc(" + mobileDotSize + " / 2) !important;}"; mediaCSS += "." + rc + "-tl-progress{left:calc(" + mobileDotSize + " / 2) !important;}"; if (validCss(m_imageHeight)) mediaCSS += "." + rc + "-tl-content img{height:" + m_imageHeight + " !important;}"; if (m_hidden) mediaCSS += "." + rc + "-tl{display:none !important;}"; else if (hidden) mediaCSS += "." + rc + "-tl{display:block !important;}"; Loading @@ -721,8 +734,14 @@ extern "C" { std::string lightCSS; if (validCss(l_titleColor)) lightCSS += "." + rc + "-tl-title{color:" + l_titleColor + " !important;}"; if (validCss(l_lineColor)) lightCSS += "." + rc + "-tl-line{background:" + l_lineColor + " !important;}"; if (validCss(l_dotColor)) lightCSS += "." + rc + "-tl-dot{background:" + l_dotColor + " !important;}"; if (validCss(l_dotBorderColor)) lightCSS += "." + rc + "-tl-dot{box-shadow:0 0 0 4px " + l_dotBorderColor + " !important;}"; if (validCss(l_dotColor)) { lightCSS += "." + rc + "-tl-dot{background:" + l_dotColor + " !important;}"; lightCSS += "." + rc + "-tl-progress{background:" + l_dotColor + " !important;}"; } if (validCss(l_dotBorderColor)) { lightCSS += "." + rc + "-tl-dot{box-shadow:0 0 0 4px " + l_dotBorderColor + " !important;}"; lightCSS += "." + rc + "-tl-progress{box-shadow:0 0 0 4px " + l_dotBorderColor + " !important;}"; } if (validCss(l_headingColor)) lightCSS += "." + rc + "-tl-content h3{color:" + l_headingColor + " !important;}"; if (validCss(l_textColor)) lightCSS += "." + rc + "-tl-content p{color:" + l_textColor + " !important;}"; Loading @@ -741,6 +760,35 @@ extern "C" { cssStyle.appendChild(libhtmlpp::TextElement(customCss.c_str())); el.appendChild(cssStyle); } // Scroll behaviour: move the progress marker down the line as the // section scrolls past the viewport's vertical center. std::string progressJs = "(function(){\n" " var wrap=document.querySelector('." + rc + "-tl-steps');\n" " var marker=document.querySelector('." + rc + "-tl-progress');\n" " if(!wrap||!marker) return;\n" " var ticking=false;\n" " function update(){\n" " var rect=wrap.getBoundingClientRect();\n" " var vh=window.innerHeight||document.documentElement.clientHeight;\n" " var pos=(vh*0.5)-rect.top;\n" " if(pos<0) pos=0;\n" " if(pos>rect.height) pos=rect.height;\n" " marker.style.top=pos+'px';\n" " ticking=false;\n" " }\n" " function onScroll(){\n" " if(!ticking){ window.requestAnimationFrame(update); ticking=true; }\n" " }\n" " window.addEventListener('scroll', onScroll, {passive:true});\n" " window.addEventListener('resize', onScroll);\n" " update();\n" "})();"; libhtmlpp::ScriptElement js; js.setScript(progressJs.c_str()); el.appendChild(js); } // Timeline manages its steps internally — no editor tree children Loading