feat: split up base templates into more sections (def blocks)
partly to allow easier customization, partly just for clarity
This commit is contained in:
parent
fce0de5d30
commit
869963403d
|
@ -15,6 +15,10 @@
|
|||
<whole-page />
|
||||
</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
|
||||
${self.body()}
|
||||
|
||||
|
@ -26,8 +30,12 @@
|
|||
</body>
|
||||
</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>
|
||||
|
||||
## 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="header_core()">
|
||||
|
@ -41,7 +49,10 @@
|
|||
${self.vuejs()}
|
||||
${self.buefy()}
|
||||
${self.fontawesome()}
|
||||
${self.hamburger_menu_js()}
|
||||
</%def>
|
||||
|
||||
<%def name="hamburger_menu_js()">
|
||||
<script>
|
||||
|
||||
## NOTE: this code was copied from
|
||||
|
@ -88,14 +99,21 @@
|
|||
|
||||
<%def name="core_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>
|
||||
|
||||
/* ****************************** */
|
||||
/* page */
|
||||
/* ****************************** */
|
||||
##############################
|
||||
## page
|
||||
##############################
|
||||
|
||||
/* nb. helps force footer to bottom of screen */
|
||||
## nb. helps force footer to bottom of screen
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
@ -106,12 +124,14 @@
|
|||
}
|
||||
% endif
|
||||
|
||||
/* nb. this refers to the "menu-sized" app title in far left of main menu */
|
||||
#global-header-title {
|
||||
## nb. this refers to the "menu-sized" app title in far left of main menu
|
||||
#navbar-brand-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#current-context {
|
||||
#header-index-title {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
|
@ -132,10 +152,6 @@
|
|||
</style>
|
||||
</%def>
|
||||
|
||||
<%def name="buefy_styles()">
|
||||
${h.stylesheet_link(h.get_liburl(request, 'buefy.css'))}
|
||||
</%def>
|
||||
|
||||
<%def name="extra_styles()">
|
||||
${base_meta.extra_styles()}
|
||||
</%def>
|
||||
|
@ -144,19 +160,148 @@
|
|||
|
||||
<%def name="render_vue_template_whole_page()">
|
||||
<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"
|
||||
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">
|
||||
|
||||
## nb. the header proper contains 2 elements:
|
||||
## 1) menu bar
|
||||
## 2) index title area
|
||||
<header>
|
||||
<nav class="navbar" role="navigation" aria-label="main navigation">
|
||||
|
||||
## nb. this is the main menu bar
|
||||
<nav class="navbar" role="navigation" aria-label="main navigation">
|
||||
${self.render_navbar_brand()}
|
||||
${self.render_navbar_menu()}
|
||||
</nav>
|
||||
|
||||
## nb. this is the "index title" area
|
||||
<nav class="level" style="margin: 0.5rem 0.5rem 0.5rem auto;">
|
||||
|
||||
## nb. this is the index title proper
|
||||
<div class="level-left">
|
||||
<div id="header-index-title" class="level-item">
|
||||
% if index_title:
|
||||
% if index_url:
|
||||
<h1 class="title">${h.link_to(index_title, index_url)}</h1>
|
||||
% else:
|
||||
<h1 class="title">${index_title}</h1>
|
||||
% endif
|
||||
% if master and master.creatable and not master.creating and master.has_perm('create'):
|
||||
<wutta-button once type="is-primary"
|
||||
tag="a" href="${url(f'{route_prefix}.create')}"
|
||||
icon-left="plus"
|
||||
label="Create New" />
|
||||
% endif
|
||||
% endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## nb. this is a utility area for the master context
|
||||
<div class="level-right">
|
||||
|
||||
## Configure button
|
||||
% if master and master.configurable and not master.configuring and master.has_perm('configure'):
|
||||
<div class="level-item">
|
||||
<wutta-button once type="is-primary"
|
||||
tag="a" href="${url(f'{route_prefix}.configure')}"
|
||||
icon-left="cog"
|
||||
label="Configure" />
|
||||
</div>
|
||||
% endif
|
||||
|
||||
${self.render_theme_picker()}
|
||||
${self.render_feedback_button()}
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
## nb. the page / content title area (aka. hero bar)
|
||||
% if capture(self.content_title):
|
||||
<section id="content-title"
|
||||
class="has-background-primary">
|
||||
<div style="display: flex; align-items: center; padding: 0.5rem;">
|
||||
|
||||
<h1 class="title has-text-white"
|
||||
v-html="contentTitleHTML">
|
||||
</h1>
|
||||
|
||||
<div style="flex-grow: 1; display: flex; gap: 0.5rem;">
|
||||
${self.render_instance_header_title_extras()}
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 0.5rem;">
|
||||
${self.render_instance_header_buttons()}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
% endif
|
||||
|
||||
</div> <!-- header-wrapper -->
|
||||
|
||||
## nb. the page content area
|
||||
<div class="content-wrapper"
|
||||
style="flex-grow: 1; padding: 0.5rem;">
|
||||
<section id="page-body" style="height: 100%;">
|
||||
|
||||
% if request.session.peek_flash('error'):
|
||||
% for error in request.session.pop_flash('error'):
|
||||
<b-notification type="is-warning">
|
||||
${error}
|
||||
</b-notification>
|
||||
% endfor
|
||||
% endif
|
||||
|
||||
% if request.session.peek_flash('warning'):
|
||||
% for msg in request.session.pop_flash('warning'):
|
||||
<b-notification type="is-warning">
|
||||
${msg}
|
||||
</b-notification>
|
||||
% endfor
|
||||
% endif
|
||||
|
||||
% if request.session.peek_flash():
|
||||
% for msg in request.session.pop_flash():
|
||||
<b-notification type="is-info">
|
||||
${msg}
|
||||
</b-notification>
|
||||
% endfor
|
||||
% endif
|
||||
|
||||
<div style="height: 100%;">
|
||||
${self.render_this_page_component()}
|
||||
</div>
|
||||
</section>
|
||||
</div><!-- content-wrapper -->
|
||||
|
||||
## nb. the page footer
|
||||
<footer class="footer">
|
||||
<div class="content">
|
||||
${base_meta.footer()}
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</script>
|
||||
</%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="global-header-title">
|
||||
<div id="navbar-brand-title">
|
||||
${base_meta.global_title()}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -167,8 +312,16 @@
|
|||
<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:
|
||||
|
@ -207,125 +360,23 @@
|
|||
% endif
|
||||
% endfor
|
||||
|
||||
</div><!-- navbar-start -->
|
||||
${self.render_navbar_end()}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<nav class="level" style="margin: 0.5rem 0.5rem 0.5rem auto;">
|
||||
<div class="level-left">
|
||||
|
||||
## Current Context
|
||||
<div id="current-context" class="level-item"
|
||||
style="display: flex; gap: 1.5rem;">
|
||||
% if index_title:
|
||||
% if index_url:
|
||||
<h1 class="title">${h.link_to(index_title, index_url)}</h1>
|
||||
% else:
|
||||
<h1 class="title">${index_title}</h1>
|
||||
% endif
|
||||
% if master and master.creatable and not master.creating and master.has_perm('create'):
|
||||
<wutta-button once type="is-primary"
|
||||
tag="a" href="${url(f'{route_prefix}.create')}"
|
||||
icon-left="plus"
|
||||
label="Create New" />
|
||||
% endif
|
||||
% endif
|
||||
</div>
|
||||
|
||||
</div><!-- level-left -->
|
||||
|
||||
<div class="level-right">
|
||||
|
||||
% if master and master.configurable and not master.configuring and master.has_perm('configure'):
|
||||
<div class="level-item">
|
||||
<wutta-button once type="is-primary"
|
||||
tag="a" href="${url(f'{route_prefix}.configure')}"
|
||||
icon-left="cog"
|
||||
label="Configure" />
|
||||
</div>
|
||||
% endif
|
||||
|
||||
</div> <!-- level-right -->
|
||||
</nav><!-- level -->
|
||||
</header>
|
||||
|
||||
## Page Title
|
||||
% if capture(self.content_title):
|
||||
<section id="content-title"
|
||||
class="has-background-primary">
|
||||
<div style="display: flex; align-items: center; padding: 0.5rem;">
|
||||
|
||||
<h1 class="title has-text-white"
|
||||
v-html="contentTitleHTML">
|
||||
</h1>
|
||||
|
||||
<div style="flex-grow: 1; display: flex; gap: 0.5rem;">
|
||||
${self.render_instance_header_title_extras()}
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 0.5rem;">
|
||||
${self.render_instance_header_buttons()}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
% endif
|
||||
|
||||
</div> <!-- header-wrapper -->
|
||||
|
||||
<div class="content-wrapper"
|
||||
style="flex-grow: 1; padding: 0.5rem;">
|
||||
|
||||
## Page Body
|
||||
<section id="page-body" style="height: 100%;">
|
||||
|
||||
% if request.session.peek_flash('error'):
|
||||
% for error in request.session.pop_flash('error'):
|
||||
<b-notification type="is-warning">
|
||||
${error}
|
||||
</b-notification>
|
||||
% endfor
|
||||
% endif
|
||||
|
||||
% if request.session.peek_flash('warning'):
|
||||
% for msg in request.session.pop_flash('warning'):
|
||||
<b-notification type="is-warning">
|
||||
${msg}
|
||||
</b-notification>
|
||||
% endfor
|
||||
% endif
|
||||
|
||||
% if request.session.peek_flash():
|
||||
% for msg in request.session.pop_flash():
|
||||
<b-notification type="is-info">
|
||||
${msg}
|
||||
</b-notification>
|
||||
% endfor
|
||||
% endif
|
||||
|
||||
<div style="height: 100%;">
|
||||
${self.render_this_page_component()}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div><!-- content-wrapper -->
|
||||
|
||||
## Footer
|
||||
<footer class="footer">
|
||||
<div class="content">
|
||||
${base_meta.footer()}
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
</script>
|
||||
</%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()">
|
||||
<script>
|
||||
|
||||
let WholePage = {
|
||||
const WholePage = {
|
||||
template: '#whole-page-template',
|
||||
computed: {},
|
||||
|
||||
|
@ -360,8 +411,9 @@
|
|||
},
|
||||
}
|
||||
|
||||
let WholePageData = {
|
||||
const WholePageData = {
|
||||
contentTitleHTML: ${json.dumps(capture(self.content_title))|n},
|
||||
referrer: location.href,
|
||||
mountedHooks: [],
|
||||
}
|
||||
|
||||
|
@ -379,16 +431,12 @@
|
|||
</script>
|
||||
</%def>
|
||||
|
||||
<%def name="before_content()"></%def>
|
||||
|
||||
<%def name="render_this_page_component()">
|
||||
<this-page @change-content-title="changeContentTitle" />
|
||||
</%def>
|
||||
|
||||
<%def name="render_navbar_end()">
|
||||
<div class="navbar-end">
|
||||
${self.render_user_menu()}
|
||||
</div>
|
||||
</%def>
|
||||
|
||||
<%def name="render_user_menu()">
|
||||
% if request.user:
|
||||
<div class="navbar-item has-dropdown is-hoverable">
|
||||
|
@ -468,6 +516,10 @@
|
|||
|
||||
<%def name="render_prevnext_header_buttons()"></%def>
|
||||
|
||||
##############################
|
||||
## vue components + app
|
||||
##############################
|
||||
|
||||
<%def name="render_vue_templates()">
|
||||
${self.render_vue_template_whole_page()}
|
||||
${self.render_vue_script_whole_page()}
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
|
||||
<%def name="render_vue_templates()">
|
||||
${parent.render_vue_templates()}
|
||||
${self.render_vue_template_grid()}
|
||||
</%def>
|
||||
|
||||
<%def name="render_vue_template_grid()">
|
||||
% if grid is not Undefined:
|
||||
${grid.render_vue_template()}
|
||||
% endif
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<%def name="render_vue_templates()">
|
||||
${parent.render_vue_templates()}
|
||||
${self.render_vue_template_this_page()}
|
||||
${self.render_vue_script_this_page()}
|
||||
</%def>
|
||||
|
||||
<%def name="render_vue_template_this_page()">
|
||||
|
@ -14,6 +15,9 @@
|
|||
${self.page_content()}
|
||||
</div>
|
||||
</script>
|
||||
</%def>
|
||||
|
||||
<%def name="render_vue_script_this_page()">
|
||||
<script>
|
||||
|
||||
const ThisPage = {
|
||||
|
|
Loading…
Reference in a new issue