2
0
Fork 0

feat: split up base templates into more sections (def blocks)

partly to allow easier customization, partly just for clarity
This commit is contained in:
Lance Edgar 2024-08-20 13:45:48 -05:00
parent fce0de5d30
commit 869963403d
3 changed files with 151 additions and 91 deletions

View file

@ -15,6 +15,10 @@
<whole-page /> <whole-page />
</div> </div>
## nb. sometimes a template needs to define something
## before the body content proper is rendered
${self.before_content()}
## content body from derived/child template ## content body from derived/child template
${self.body()} ${self.body()}
@ -26,8 +30,12 @@
</body> </body>
</html> </html>
## nb. this becomes part of the page <title> tag within <head>
## it also is used as default value for content_title() below
<%def name="title()"></%def> <%def name="title()"></%def>
## nb. this is the "content title" as shown on screen, within the
## "hero bar" just below the "index title"
<%def name="content_title()">${self.title()}</%def> <%def name="content_title()">${self.title()}</%def>
<%def name="header_core()"> <%def name="header_core()">
@ -41,7 +49,10 @@
${self.vuejs()} ${self.vuejs()}
${self.buefy()} ${self.buefy()}
${self.fontawesome()} ${self.fontawesome()}
${self.hamburger_menu_js()}
</%def>
<%def name="hamburger_menu_js()">
<script> <script>
## NOTE: this code was copied from ## NOTE: this code was copied from
@ -88,14 +99,21 @@
<%def name="core_styles()"> <%def name="core_styles()">
${self.buefy_styles()} ${self.buefy_styles()}
${self.base_styles()}
</%def>
<%def name="buefy_styles()">
${h.stylesheet_link(h.get_liburl(request, 'buefy.css'))}
</%def>
<%def name="base_styles()">
<style> <style>
/* ****************************** */ ##############################
/* page */ ## page
/* ****************************** */ ##############################
/* nb. helps force footer to bottom of screen */ ## nb. helps force footer to bottom of screen
html, body { html, body {
height: 100%; height: 100%;
} }
@ -106,12 +124,14 @@
} }
% endif % endif
/* nb. this refers to the "menu-sized" app title in far left of main menu */ ## nb. this refers to the "menu-sized" app title in far left of main menu
#global-header-title { #navbar-brand-title {
font-weight: bold; font-weight: bold;
} }
#current-context { #header-index-title {
display: flex;
gap: 1.5rem;
padding-left: 0.5rem; padding-left: 0.5rem;
} }
@ -132,10 +152,6 @@
</style> </style>
</%def> </%def>
<%def name="buefy_styles()">
${h.stylesheet_link(h.get_liburl(request, 'buefy.css'))}
</%def>
<%def name="extra_styles()"> <%def name="extra_styles()">
${base_meta.extra_styles()} ${base_meta.extra_styles()}
</%def> </%def>
@ -144,80 +160,36 @@
<%def name="render_vue_template_whole_page()"> <%def name="render_vue_template_whole_page()">
<script type="text/x-template" id="whole-page-template"> <script type="text/x-template" id="whole-page-template">
## nb. the whole-page contains 3 elements:
## 1) header-wrapper
## 2) content-wrapper
## 3) footer
<div id="whole-page" <div id="whole-page"
style="height: 100%; display: flex; flex-direction: column; justify-content: space-between;"> style="height: 100%; display: flex; flex-direction: column; justify-content: space-between;">
## nb. the header-wrapper contains 2 elements:
## 1) header proper (menu + index title area)
## 2) page/content title area
<div class="header-wrapper"> <div class="header-wrapper">
## nb. the header proper contains 2 elements:
## 1) menu bar
## 2) index title area
<header> <header>
## nb. this is the main menu bar
<nav class="navbar" role="navigation" aria-label="main navigation"> <nav class="navbar" role="navigation" aria-label="main navigation">
${self.render_navbar_brand()}
<div class="navbar-brand"> ${self.render_navbar_menu()}
<a class="navbar-item" href="${url('home')}">
<div style="display: flex; gap: 0.3rem; align-items: center;">
${base_meta.header_logo()}
<div id="global-header-title">
${base_meta.global_title()}
</div>
</div>
</a>
<a role="button" class="navbar-burger" data-target="navbar-menu" aria-label="menu" aria-expanded="false">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div class="navbar-menu" id="navbar-menu">
<div class="navbar-start">
% for topitem in menus:
% if topitem['is_link']:
${h.link_to(topitem['title'], topitem['url'], target=topitem['target'], class_='navbar-item')}
% else:
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">${topitem['title']}</a>
<div class="navbar-dropdown">
% for item in topitem['items']:
% if item['is_menu']:
<% item_hash = id(item) %>
<% toggle = 'menu_{}_shown'.format(item_hash) %>
<div>
<a class="navbar-link" @click.prevent="toggleNestedMenu('${item_hash}')">
${item['title']}
</a>
</div>
% for subitem in item['items']:
% if subitem['is_sep']:
<hr class="navbar-divider" v-show="${toggle}">
% else:
${h.link_to("{}".format(subitem['title']), subitem['url'], class_='navbar-item nested', target=subitem['target'], **{'v-show': toggle})}
% endif
% endfor
% else:
% if item['is_sep']:
<hr class="navbar-divider">
% else:
${h.link_to(item['title'], item['url'], class_='navbar-item', target=item['target'])}
% endif
% endif
% endfor
</div>
</div>
% endif
% endfor
</div><!-- navbar-start -->
${self.render_navbar_end()}
</div>
</nav> </nav>
## nb. this is the "index title" area
<nav class="level" style="margin: 0.5rem 0.5rem 0.5rem auto;"> <nav class="level" style="margin: 0.5rem 0.5rem 0.5rem auto;">
<div class="level-left">
## Current Context ## nb. this is the index title proper
<div id="current-context" class="level-item" <div class="level-left">
style="display: flex; gap: 1.5rem;"> <div id="header-index-title" class="level-item">
% if index_title: % if index_title:
% if index_url: % if index_url:
<h1 class="title">${h.link_to(index_title, index_url)}</h1> <h1 class="title">${h.link_to(index_title, index_url)}</h1>
@ -232,11 +204,12 @@
% endif % endif
% endif % endif
</div> </div>
</div>
</div><!-- level-left --> ## nb. this is a utility area for the master context
<div class="level-right"> <div class="level-right">
## Configure button
% if master and master.configurable and not master.configuring and master.has_perm('configure'): % if master and master.configurable and not master.configuring and master.has_perm('configure'):
<div class="level-item"> <div class="level-item">
<wutta-button once type="is-primary" <wutta-button once type="is-primary"
@ -246,11 +219,14 @@
</div> </div>
% endif % endif
</div> <!-- level-right --> ${self.render_theme_picker()}
</nav><!-- level --> ${self.render_feedback_button()}
</div>
</nav>
</header> </header>
## Page Title ## nb. the page / content title area (aka. hero bar)
% if capture(self.content_title): % if capture(self.content_title):
<section id="content-title" <section id="content-title"
class="has-background-primary"> class="has-background-primary">
@ -274,10 +250,9 @@
</div> <!-- header-wrapper --> </div> <!-- header-wrapper -->
## nb. the page content area
<div class="content-wrapper" <div class="content-wrapper"
style="flex-grow: 1; padding: 0.5rem;"> style="flex-grow: 1; padding: 0.5rem;">
## Page Body
<section id="page-body" style="height: 100%;"> <section id="page-body" style="height: 100%;">
% if request.session.peek_flash('error'): % if request.session.peek_flash('error'):
@ -308,10 +283,9 @@
${self.render_this_page_component()} ${self.render_this_page_component()}
</div> </div>
</section> </section>
</div><!-- content-wrapper --> </div><!-- content-wrapper -->
## Footer ## nb. the page footer
<footer class="footer"> <footer class="footer">
<div class="content"> <div class="content">
${base_meta.footer()} ${base_meta.footer()}
@ -322,10 +296,87 @@
</script> </script>
</%def> </%def>
<%def name="render_navbar_brand()">
<div class="navbar-brand">
<a class="navbar-item" href="${url('home')}">
<div style="display: flex; gap: 0.3rem; align-items: center;">
${base_meta.header_logo()}
<div id="navbar-brand-title">
${base_meta.global_title()}
</div>
</div>
</a>
<a role="button" class="navbar-burger" data-target="navbar-menu" aria-label="menu" aria-expanded="false">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
</%def>
<%def name="render_navbar_menu()">
<div class="navbar-menu" id="navbar-menu">
${self.render_navbar_start()}
${self.render_navbar_end()}
</div>
</%def>
<%def name="render_navbar_start()">
<div class="navbar-start">
% for topitem in menus:
% if topitem['is_link']:
${h.link_to(topitem['title'], topitem['url'], target=topitem['target'], class_='navbar-item')}
% else:
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">${topitem['title']}</a>
<div class="navbar-dropdown">
% for item in topitem['items']:
% if item['is_menu']:
<% item_hash = id(item) %>
<% toggle = 'menu_{}_shown'.format(item_hash) %>
<div>
<a class="navbar-link" @click.prevent="toggleNestedMenu('${item_hash}')">
${item['title']}
</a>
</div>
% for subitem in item['items']:
% if subitem['is_sep']:
<hr class="navbar-divider" v-show="${toggle}">
% else:
${h.link_to("{}".format(subitem['title']), subitem['url'], class_='navbar-item nested', target=subitem['target'], **{'v-show': toggle})}
% endif
% endfor
% else:
% if item['is_sep']:
<hr class="navbar-divider">
% else:
${h.link_to(item['title'], item['url'], class_='navbar-item', target=item['target'])}
% endif
% endif
% endfor
</div>
</div>
% endif
% endfor
</div>
</%def>
<%def name="render_navbar_end()">
<div class="navbar-end">
${self.render_user_menu()}
</div>
</%def>
<%def name="render_theme_picker()"></%def>
<%def name="render_feedback_button()"></%def>
<%def name="render_vue_script_whole_page()"> <%def name="render_vue_script_whole_page()">
<script> <script>
let WholePage = { const WholePage = {
template: '#whole-page-template', template: '#whole-page-template',
computed: {}, computed: {},
@ -360,8 +411,9 @@
}, },
} }
let WholePageData = { const WholePageData = {
contentTitleHTML: ${json.dumps(capture(self.content_title))|n}, contentTitleHTML: ${json.dumps(capture(self.content_title))|n},
referrer: location.href,
mountedHooks: [], mountedHooks: [],
} }
@ -379,16 +431,12 @@
</script> </script>
</%def> </%def>
<%def name="before_content()"></%def>
<%def name="render_this_page_component()"> <%def name="render_this_page_component()">
<this-page @change-content-title="changeContentTitle" /> <this-page @change-content-title="changeContentTitle" />
</%def> </%def>
<%def name="render_navbar_end()">
<div class="navbar-end">
${self.render_user_menu()}
</div>
</%def>
<%def name="render_user_menu()"> <%def name="render_user_menu()">
% if request.user: % if request.user:
<div class="navbar-item has-dropdown is-hoverable"> <div class="navbar-item has-dropdown is-hoverable">
@ -468,6 +516,10 @@
<%def name="render_prevnext_header_buttons()"></%def> <%def name="render_prevnext_header_buttons()"></%def>
##############################
## vue components + app
##############################
<%def name="render_vue_templates()"> <%def name="render_vue_templates()">
${self.render_vue_template_whole_page()} ${self.render_vue_template_whole_page()}
${self.render_vue_script_whole_page()} ${self.render_vue_script_whole_page()}

View file

@ -14,6 +14,10 @@
<%def name="render_vue_templates()"> <%def name="render_vue_templates()">
${parent.render_vue_templates()} ${parent.render_vue_templates()}
${self.render_vue_template_grid()}
</%def>
<%def name="render_vue_template_grid()">
% if grid is not Undefined: % if grid is not Undefined:
${grid.render_vue_template()} ${grid.render_vue_template()}
% endif % endif

View file

@ -6,6 +6,7 @@
<%def name="render_vue_templates()"> <%def name="render_vue_templates()">
${parent.render_vue_templates()} ${parent.render_vue_templates()}
${self.render_vue_template_this_page()} ${self.render_vue_template_this_page()}
${self.render_vue_script_this_page()}
</%def> </%def>
<%def name="render_vue_template_this_page()"> <%def name="render_vue_template_this_page()">
@ -14,6 +15,9 @@
${self.page_content()} ${self.page_content()}
</div> </div>
</script> </script>
</%def>
<%def name="render_vue_script_this_page()">
<script> <script>
const ThisPage = { const ThisPage = {