diff --git a/__pycache__/main.cpython-313.pyc b/__pycache__/main.cpython-313.pyc index bf25bc9..66232d3 100644 Binary files a/__pycache__/main.cpython-313.pyc and b/__pycache__/main.cpython-313.pyc differ 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

-
+ + + 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

+
+
+
+ + + + 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

+
+
+
+ + + + 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