diff --git a/README.md b/README.md index 6ddcdcf..7a8aaaf 100644 --- a/README.md +++ b/README.md @@ -431,7 +431,7 @@ solverforge-ui/ │ ├── 16-rail-blocks.css # rail blocks, changeovers, unassigned styles │ ├── 17-gantt-layout.css # split layout, grid table, view controls │ └── 18-gantt-bars.css # Frappe bar overrides, pinned/highlighted bars -├── js-src/ # 15 JS source files +├── js-src/ # 16 JS source files │ ├── 00-core.js # SF namespace, escHtml, el() │ ├── 01-score.js # score parsing │ ├── 02-colors.js # Tango palette + project colors @@ -444,9 +444,10 @@ solverforge-ui/ │ ├── 09-toast.js # showToast(), showError() │ ├── 10-backend.js # createBackend() — axum/tauri/fetch │ ├── 11-solver.js # createSolver() — SSE state machine -│ ├── 12-api-guide.js # createApiGuide(), createFooter() +│ ├── 12-api-guide.js # createApiGuide() │ ├── 13-rail.js # timeline rail header, cards, blocks, changeovers -│ └── 14-gantt.js # Frappe Gantt wrapper (split pane, grid, chart) +│ ├── 14-gantt.js # Frappe Gantt wrapper (split pane, grid, chart) +│ └── 15-footer.js # createFooter() └── static/sf/ # Embedded assets (include_dir!) ├── sf.css # concatenated from css-src/ ├── sf.js # concatenated from js-src/ diff --git a/js-src/12-api-guide.js b/js-src/12-api-guide.js index 82f266f..fe61746 100644 --- a/js-src/12-api-guide.js +++ b/js-src/12-api-guide.js @@ -42,21 +42,4 @@ return guide; }; - - sf.createFooter = function (config) { - sf.assert(config, 'createFooter(config) requires a configuration object'); - - var footer = sf.el('footer', { className: 'sf-footer' }); - if (config.links) { - config.links.forEach(function (link, i) { - if (i > 0) footer.appendChild(sf.el('span', { className: 'sf-vr' })); - footer.appendChild(sf.el('a', { href: link.url, target: '_blank' }, link.label)); - }); - } - if (config.version) { - footer.appendChild(sf.el('span', { style: { marginLeft: 'auto' } }, config.version)); - } - return footer; - }; - })(SF); diff --git a/js-src/15-footer.js b/js-src/15-footer.js new file mode 100644 index 0000000..8073767 --- /dev/null +++ b/js-src/15-footer.js @@ -0,0 +1,24 @@ +/* ============================================================================ + SolverForge UI — Footer Factory + ============================================================================ */ + +(function (sf) { + 'use strict'; + + sf.createFooter = function (config) { + sf.assert(config, 'createFooter(config) requires a configuration object'); + + var footer = sf.el('footer', { className: 'sf-footer' }); + if (config.links) { + config.links.forEach(function (link, i) { + if (i > 0) footer.appendChild(sf.el('span', { className: 'sf-vr' })); + footer.appendChild(sf.el('a', { href: link.url, target: '_blank' }, link.label)); + }); + } + if (config.version) { + footer.appendChild(sf.el('span', { style: { marginLeft: 'auto' } }, config.version)); + } + return footer; + }; + +})(SF); diff --git a/static/sf/sf.0.1.0.js b/static/sf/sf.0.1.0.js index fbbe110..dc2ae7c 100644 --- a/static/sf/sf.0.1.0.js +++ b/static/sf/sf.0.1.0.js @@ -1137,23 +1137,6 @@ const SF = (function () { return guide; }; - - sf.createFooter = function (config) { - sf.assert(config, 'createFooter(config) requires a configuration object'); - - var footer = sf.el('footer', { className: 'sf-footer' }); - if (config.links) { - config.links.forEach(function (link, i) { - if (i > 0) footer.appendChild(sf.el('span', { className: 'sf-vr' })); - footer.appendChild(sf.el('a', { href: link.url, target: '_blank' }, link.label)); - }); - } - if (config.version) { - footer.appendChild(sf.el('span', { style: { marginLeft: 'auto' } }, config.version)); - } - return footer; - }; - })(SF); /* ============================================================================ SolverForge UI — Timeline Rail @@ -1873,3 +1856,27 @@ const SF = (function () { }; })(SF); +/* ============================================================================ + SolverForge UI — Footer Factory + ============================================================================ */ + +(function (sf) { + 'use strict'; + + sf.createFooter = function (config) { + sf.assert(config, 'createFooter(config) requires a configuration object'); + + var footer = sf.el('footer', { className: 'sf-footer' }); + if (config.links) { + config.links.forEach(function (link, i) { + if (i > 0) footer.appendChild(sf.el('span', { className: 'sf-vr' })); + footer.appendChild(sf.el('a', { href: link.url, target: '_blank' }, link.label)); + }); + } + if (config.version) { + footer.appendChild(sf.el('span', { style: { marginLeft: 'auto' } }, config.version)); + } + return footer; + }; + +})(SF); diff --git a/static/sf/sf.js b/static/sf/sf.js index fbbe110..dc2ae7c 100644 --- a/static/sf/sf.js +++ b/static/sf/sf.js @@ -1137,23 +1137,6 @@ const SF = (function () { return guide; }; - - sf.createFooter = function (config) { - sf.assert(config, 'createFooter(config) requires a configuration object'); - - var footer = sf.el('footer', { className: 'sf-footer' }); - if (config.links) { - config.links.forEach(function (link, i) { - if (i > 0) footer.appendChild(sf.el('span', { className: 'sf-vr' })); - footer.appendChild(sf.el('a', { href: link.url, target: '_blank' }, link.label)); - }); - } - if (config.version) { - footer.appendChild(sf.el('span', { style: { marginLeft: 'auto' } }, config.version)); - } - return footer; - }; - })(SF); /* ============================================================================ SolverForge UI — Timeline Rail @@ -1873,3 +1856,27 @@ const SF = (function () { }; })(SF); +/* ============================================================================ + SolverForge UI — Footer Factory + ============================================================================ */ + +(function (sf) { + 'use strict'; + + sf.createFooter = function (config) { + sf.assert(config, 'createFooter(config) requires a configuration object'); + + var footer = sf.el('footer', { className: 'sf-footer' }); + if (config.links) { + config.links.forEach(function (link, i) { + if (i > 0) footer.appendChild(sf.el('span', { className: 'sf-vr' })); + footer.appendChild(sf.el('a', { href: link.url, target: '_blank' }, link.label)); + }); + } + if (config.version) { + footer.appendChild(sf.el('span', { style: { marginLeft: 'auto' } }, config.version)); + } + return footer; + }; + +})(SF);