diff --git a/src/wuttaweb/templates/base.mako b/src/wuttaweb/templates/base.mako index 3c227dc..ddee561 100644 --- a/src/wuttaweb/templates/base.mako +++ b/src/wuttaweb/templates/base.mako @@ -15,6 +15,10 @@ + ## 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 @@ +## nb. this becomes part of the page 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,80 +160,36 @@ <%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> + + ## nb. this is the main menu bar <nav class="navbar" role="navigation" aria-label="main navigation"> - - <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"> - ${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> + ${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;"> - <div class="level-left"> - ## Current Context - <div id="current-context" class="level-item" - style="display: flex; gap: 1.5rem;"> + ## 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> @@ -232,11 +204,12 @@ % endif % endif </div> + </div> - </div><!-- level-left --> - + ## 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" @@ -246,11 +219,14 @@ </div> % endif - </div> <!-- level-right --> - </nav><!-- level --> + ${self.render_theme_picker()} + ${self.render_feedback_button()} + + </div> + </nav> </header> - ## Page Title + ## nb. the page / content title area (aka. hero bar) % if capture(self.content_title): <section id="content-title" class="has-background-primary"> @@ -274,10 +250,9 @@ </div> <!-- header-wrapper --> + ## nb. the page content area <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'): @@ -308,10 +283,9 @@ ${self.render_this_page_component()} </div> </section> - </div><!-- content-wrapper --> - ## Footer + ## nb. the page footer <footer class="footer"> <div class="content"> ${base_meta.footer()} @@ -322,10 +296,87 @@ </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="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()"> <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()} diff --git a/src/wuttaweb/templates/master/index.mako b/src/wuttaweb/templates/master/index.mako index 43e6142..a16aced 100644 --- a/src/wuttaweb/templates/master/index.mako +++ b/src/wuttaweb/templates/master/index.mako @@ -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 diff --git a/src/wuttaweb/templates/page.mako b/src/wuttaweb/templates/page.mako index be2aaae..840e918 100644 --- a/src/wuttaweb/templates/page.mako +++ b/src/wuttaweb/templates/page.mako @@ -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 = {