From 6cb46fe7726907bd2ffce055c2e4cc18cbc86cd2 Mon Sep 17 00:00:00 2001 From: nudoragon Date: Tue, 26 May 2026 12:33:48 +0800 Subject: [PATCH] =?UTF-8?q?header=20and=20footer=EF=BC=88=E5=BE=85?= =?UTF-8?q?=E7=BA=8C=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __pycache__/main.cpython-313.pyc | Bin 34016 -> 34216 bytes main.py | 4 + static/Vvvebjs/new-page-blank-template.html | 23 +++- templates/project_dashboard.html | 28 +++++ websites/my-website/headerandfooter.html | 50 +++++++++ websites/my-website/headerandfooter2.html | 50 +++++++++ websites/my-website/project.json | 114 +++++++++++++++++--- websites/my-website/test.html | 32 ++++-- 8 files changed, 278 insertions(+), 23 deletions(-) create mode 100644 websites/my-website/headerandfooter.html create mode 100644 websites/my-website/headerandfooter2.html diff --git a/__pycache__/main.cpython-313.pyc b/__pycache__/main.cpython-313.pyc index bf25bc90025e5a29422762a0745596bddc315e3d..66232d3302458f5f2ab2ce357fcb2249ba36864d 100644 GIT binary patch delta 2479 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 KsU2F;Y4{hipNKF3 diff --git a/main.py b/main.py index 1207a23..7260303 100644 --- a/main.py +++ b/main.py @@ -167,6 +167,8 @@ def _normalize_page_tree(slug: str, tree: dict[str, Any]) -> dict[str, Any]: "show_in_nav": bool(item.get("show_in_nav", True)), "is_homepage": bool(item.get("is_homepage", False)), "requires_password": bool(item.get("requires_password", False)), + "has_header": item.get("has_header") is not False, + "has_footer": bool(item.get("has_footer", False)), }) elif item_type == "folder": name = item.get("name") @@ -194,6 +196,8 @@ def _normalize_page_tree(slug: str, tree: dict[str, Any]) -> dict[str, Any]: "show_in_nav": True, "is_homepage": rel == "index.html", "requires_password": False, + "has_header": True, + "has_footer": False, }) return normalized diff --git a/static/Vvvebjs/new-page-blank-template.html b/static/Vvvebjs/new-page-blank-template.html index 8821b1c..b065dfb 100644 --- a/static/Vvvebjs/new-page-blank-template.html +++ b/static/Vvvebjs/new-page-blank-template.html @@ -20,14 +20,31 @@ + + -
+
-

Bootstrap 5 start page

+

Bootstrap 5 start page

Start by dragging components to page or double click to edit text

-
+ + +
+
+ Editable footer content +
+
diff --git a/templates/project_dashboard.html b/templates/project_dashboard.html index dcd45e0..1846308 100644 --- a/templates/project_dashboard.html +++ b/templates/project_dashboard.html @@ -368,6 +368,8 @@ li.dataset.showInNav = item.show_in_nav !== false ? 'true' : 'false'; li.dataset.isHomepage = item.is_homepage ? 'true' : 'false'; li.dataset.requiresPassword = item.requires_password ? 'true' : 'false'; + li.dataset.hasHeader = item.has_header !== false ? 'true' : 'false'; + li.dataset.hasFooter = item.has_footer === true ? 'true' : 'false'; const titleWrap = document.createElement('span'); titleWrap.className = 'tree-title'; @@ -382,26 +384,40 @@ meta.innerHTML = ` + + `; const btnNav = meta.querySelector('.btn-nav'); const btnHome = meta.querySelector('.btn-homepage'); + const btnHeader = meta.querySelector('.btn-header'); + const btnFooter = meta.querySelector('.btn-footer'); const btnPassword = meta.querySelector('.btn-password'); const updateMetaState = () => { const showNav = li.dataset.showInNav === 'true'; const isHomepage = li.dataset.isHomepage === 'true'; const requiresPassword = li.dataset.requiresPassword === 'true'; + const hasHeader = li.dataset.hasHeader === 'true'; + const hasFooter = li.dataset.hasFooter === 'true'; btnNav.classList.toggle('active', showNav); btnNav.title = showNav ? '顯示於導覽列' : '從導覽列隱藏'; btnHome.classList.toggle('active', isHomepage); btnHome.title = isHomepage ? '首頁' : '設為首頁'; + btnHeader.classList.toggle('active', hasHeader); + btnHeader.title = hasHeader ? '包含頁首' : '不包含頁首'; + btnFooter.classList.toggle('active', hasFooter); + btnFooter.title = hasFooter ? '包含頁尾' : '不包含頁尾'; btnPassword.classList.toggle('active', requiresPassword); btnPassword.title = requiresPassword ? '需要密碼' : '不需要密碼'; if (li.dataset.type !== 'file') { btnHome.disabled = true; + btnHeader.disabled = true; + btnFooter.disabled = true; btnHome.title = '僅限單一頁面'; + btnHeader.title = '僅限單一頁面'; + btnFooter.title = '僅限單一頁面'; } }; @@ -415,6 +431,16 @@ li.dataset.requiresPassword = li.dataset.requiresPassword === 'true' ? 'false' : 'true'; updateMetaState(); }); + btnHeader.addEventListener('click', () => { + if (li.dataset.type !== 'file') return; + li.dataset.hasHeader = li.dataset.hasHeader === 'true' ? 'false' : 'true'; + updateMetaState(); + }); + btnFooter.addEventListener('click', () => { + if (li.dataset.type !== 'file') return; + li.dataset.hasFooter = li.dataset.hasFooter === 'true' ? 'false' : 'true'; + updateMetaState(); + }); btnHome.addEventListener('click', () => { if (li.dataset.type !== 'file') return; container.querySelectorAll('.tree-item').forEach(other => { @@ -500,6 +526,8 @@ show_in_nav: li.dataset.showInNav === 'true', is_homepage: li.dataset.isHomepage === 'true', requires_password: li.dataset.requiresPassword === 'true', + has_header: li.dataset.hasHeader === 'true', + has_footer: li.dataset.hasFooter === 'true', }; const childUl = li.querySelector(':scope > ul'); if (childUl) obj.children = walk(childUl); diff --git a/websites/my-website/headerandfooter.html b/websites/my-website/headerandfooter.html new file mode 100644 index 0000000..b065dfb --- /dev/null +++ b/websites/my-website/headerandfooter.html @@ -0,0 +1,50 @@ + + + + + + + + My page + + + + + + + + + + + +
+
+
+

Bootstrap 5 start page

+

Start by dragging components to page or double click to edit text

+
+
+
+ +
+
+ Editable footer content +
+
+ + diff --git a/websites/my-website/headerandfooter2.html b/websites/my-website/headerandfooter2.html new file mode 100644 index 0000000..b065dfb --- /dev/null +++ b/websites/my-website/headerandfooter2.html @@ -0,0 +1,50 @@ + + + + + + + + My page + + + + + + + + + + + +
+
+
+

Bootstrap 5 start page

+

Start by dragging components to page or double click to edit text

+
+
+
+ +
+
+ Editable footer content +
+
+ + diff --git a/websites/my-website/project.json b/websites/my-website/project.json index cc5a0ac..51fbdbb 100644 --- a/websites/my-website/project.json +++ b/websites/my-website/project.json @@ -8,42 +8,82 @@ { "name": "fold.html", "title": "Fold", - "type": "file" + "type": "file", + "show_in_nav": true, + "is_homepage": false, + "requires_password": false, + "has_header": true, + "has_footer": false }, { "name": "about-final.html", "title": "About Final", - "type": "file" + "type": "file", + "show_in_nav": true, + "is_homepage": false, + "requires_password": false, + "has_header": true, + "has_footer": false }, { "name": "index.html", "title": "Index", - "type": "file" + "type": "file", + "show_in_nav": true, + "is_homepage": false, + "requires_password": false, + "has_header": true, + "has_footer": false }, { "name": "my-page.html", "title": "My Page", - "type": "file" + "type": "file", + "show_in_nav": true, + "is_homepage": false, + "requires_password": false, + "has_header": true, + "has_footer": false }, { "name": "my-page3.html", "title": "My Page3", - "type": "file" + "type": "file", + "show_in_nav": true, + "is_homepage": false, + "requires_password": false, + "has_header": true, + "has_footer": false }, { "name": "my-page4.html", "title": "My Page4", - "type": "file" + "type": "file", + "show_in_nav": true, + "is_homepage": false, + "requires_password": false, + "has_header": true, + "has_footer": false }, { "name": "subfolder", "title": "Subfolder", "type": "folder", + "show_in_nav": true, + "is_homepage": false, + "requires_password": false, + "has_header": true, + "has_footer": false, "children": [ { "name": "subfolder/subpage-title.html", "title": "Subpage Title", - "type": "file" + "type": "file", + "show_in_nav": true, + "is_homepage": false, + "requires_password": false, + "has_header": true, + "has_footer": false } ] }, @@ -51,26 +91,51 @@ "name": "temp", "title": "Temp", "type": "folder", + "show_in_nav": true, + "is_homepage": false, + "requires_password": false, + "has_header": true, + "has_footer": false, "children": [ { "name": "temp/my-page5.html", "title": "My Page5", - "type": "file" + "type": "file", + "show_in_nav": true, + "is_homepage": false, + "requires_password": false, + "has_header": true, + "has_footer": false }, { "name": "temp/new.html", "title": "New", - "type": "file" + "type": "file", + "show_in_nav": true, + "is_homepage": false, + "requires_password": false, + "has_header": true, + "has_footer": false }, { "name": "subsubfolder", "title": "Subsubfolder", "type": "folder", + "show_in_nav": true, + "is_homepage": false, + "requires_password": false, + "has_header": true, + "has_footer": false, "children": [ { "name": "temp/subsubfolder/myname.html", "title": "Myname", - "type": "file" + "type": "file", + "show_in_nav": true, + "is_homepage": false, + "requires_password": false, + "has_header": true, + "has_footer": false } ] } @@ -79,9 +144,34 @@ { "name": "test.html", "title": "Test", - "type": "file" + "type": "file", + "show_in_nav": true, + "is_homepage": false, + "requires_password": false, + "has_header": true, + "has_footer": false + }, + { + "name": "headerandfooter.html", + "title": "Headerandfooter", + "type": "file", + "show_in_nav": true, + "is_homepage": false, + "requires_password": false, + "has_header": true, + "has_footer": false + }, + { + "name": "headerandfooter2.html", + "title": "Headerandfooter2", + "type": "file", + "show_in_nav": true, + "is_homepage": false, + "requires_password": false, + "has_header": true, + "has_footer": false } ] }, - "updated_at": "2026-05-26T04:12:23" + "updated_at": "2026-05-26T04:30:22" } \ No newline at end of file diff --git a/websites/my-website/test.html b/websites/my-website/test.html index 8821b1c..5e11707 100644 --- a/websites/my-website/test.html +++ b/websites/my-website/test.html @@ -1,6 +1,5 @@ - - + @@ -18,16 +17,33 @@ height:100%; } - + + + -
+
-

Bootstrap 5 start page

+

Bootstrap 5 start page

Start by dragging components to page or double click to edit text

-
- - + + + + + + \ No newline at end of file