default merge dev-dc
authorDamien Correia
Tue, 10 Jul 2018 12:17:34 +0200
branchdev-dc
changeset 81 170cf23172b4
parent 52 d80fc625e4d8 (current diff)
parent 80 9563247eb2f1 (diff)
child 82 29e43fc3a6a0
default merge
src/pyams_default_theme/component/keynumber/portlet/templates/render.pt
--- a/.hgtags	Fri Jun 15 18:17:42 2018 +0200
+++ b/.hgtags	Tue Jul 10 12:17:34 2018 +0200
@@ -4,3 +4,4 @@
 1a8ae80d426c50d10ed976df7703f2b805a1c4cb 0.1.3
 10d9fbc9908f3bcfdd1cb28cfec3d20175a0feb3 0.1.4
 b2c3949bb5b8c7bcdf77a6d417cb1e84771db830 0.1.5
+c1e5ec49def40a740580aec8c7fc2ead2266ded3 0.1.6
--- a/buildout.cfg	Fri Jun 15 18:17:42 2018 +0200
+++ b/buildout.cfg	Tue Jul 10 12:17:34 2018 +0200
@@ -79,4 +79,4 @@
 eggs = pyams_default_theme [test]
 
 [versions]
-pyams_default_theme = 0.1.6
+pyams_default_theme = 0.1.7
--- a/docs/HISTORY.txt	Fri Jun 15 18:17:42 2018 +0200
+++ b/docs/HISTORY.txt	Tue Jul 10 12:17:34 2018 +0200
@@ -1,6 +1,14 @@
 History
 =======
 
+0.1.6
+-----
+ - use shared content renderer interface
+ - use custom preview layout for paragraph preview
+ - use new "thumbnail" TALES extension to generate images thumbnails
+ - added "key numbers" portlet
+ - added custom preview layout
+
 0.1.5
 -----
  - added header and footer content providers
--- a/setup.py	Fri Jun 15 18:17:42 2018 +0200
+++ b/setup.py	Tue Jul 10 12:17:34 2018 +0200
@@ -22,7 +22,7 @@
 README = os.path.join(DOCS, 'README.txt')
 HISTORY = os.path.join(DOCS, 'HISTORY.txt')
 
-version = '0.1.6'
+version = '0.1.7'
 long_description = open(README).read() + '\n\n' + open(HISTORY).read()
 
 tests_require = []
--- a/src/pyams_default_theme.egg-info/PKG-INFO	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme.egg-info/PKG-INFO	Tue Jul 10 12:17:34 2018 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: pyams-default-theme
-Version: 0.1.5
+Version: 0.1.6
 Summary: PyAMS default theme
 Home-page: http://hg.ztfy.org/pyams/pyams_default_theme
 Author: Thierry Florac
@@ -12,6 +12,14 @@
         History
         =======
         
+        0.1.6
+        -----
+         - use shared content renderer interface
+         - use custom preview layout for paragraph preview
+         - use new "thumbnail" TALES extension to generate images thumbnails
+         - added "key numbers" portlet
+         - added custom preview layout
+        
         0.1.5
         -----
          - added header and footer content providers
--- a/src/pyams_default_theme.egg-info/SOURCES.txt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme.egg-info/SOURCES.txt	Tue Jul 10 12:17:34 2018 +0200
@@ -26,6 +26,10 @@
 src/pyams_default_theme/component/illustration/templates/illustration-default.pt
 src/pyams_default_theme/component/illustration/templates/illustration-left.pt
 src/pyams_default_theme/component/illustration/templates/illustration-right.pt
+src/pyams_default_theme/component/keynumber/__init__.py
+src/pyams_default_theme/component/keynumber/portlet/__init__.py
+src/pyams_default_theme/component/keynumber/portlet/templates/horizontal-render.pt
+src/pyams_default_theme/component/keynumber/portlet/templates/vertical-render.pt
 src/pyams_default_theme/component/paragraph/__init__.py
 src/pyams_default_theme/component/paragraph/contact.py
 src/pyams_default_theme/component/paragraph/frame.py
@@ -56,6 +60,14 @@
 src/pyams_default_theme/features/__init__.py
 src/pyams_default_theme/features/footer/__init__.py
 src/pyams_default_theme/features/header/__init__.py
+src/pyams_default_theme/features/menu/__init__.py
+src/pyams_default_theme/features/menu/portlet/__init__.py
+src/pyams_default_theme/features/menu/portlet/navigation/__init__.py
+src/pyams_default_theme/features/menu/portlet/navigation/interfaces.py
+src/pyams_default_theme/features/menu/portlet/navigation/templates/double-select.pt
+src/pyams_default_theme/features/menu/portlet/navigation/templates/double-vertical.pt
+src/pyams_default_theme/features/menu/portlet/navigation/templates/simple-horizontal-tabs.pt
+src/pyams_default_theme/features/menu/portlet/navigation/templates/simple-horizontal.pt
 src/pyams_default_theme/locales/pyams_default_theme.pot
 src/pyams_default_theme/locales/fr/LC_MESSAGES/pyams_default_theme.mo
 src/pyams_default_theme/locales/fr/LC_MESSAGES/pyams_default_theme.po
@@ -76,8 +88,10 @@
 src/pyams_default_theme/shared/view/__init__.py
 src/pyams_default_theme/shared/view/portlet/__init__.py
 src/pyams_default_theme/shared/view/portlet/templates/view-items-list.pt
+src/pyams_default_theme/shared/view/templates/render.pt
 src/pyams_default_theme/templates/index.pt
 src/pyams_default_theme/templates/layout.pt
+src/pyams_default_theme/templates/preview-layout.pt
 src/pyams_default_theme/tests/__init__.py
 src/pyams_default_theme/tests/test_utilsdocs.py
 src/pyams_default_theme/tests/test_utilsdocstrings.py
\ No newline at end of file
--- a/src/pyams_default_theme/component/gallery/templates/renderer-default.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/component/gallery/templates/renderer-default.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -1,7 +1,7 @@
 <div i18n:domain="pyams_content">
 	<tal:loop repeat="image context.get_visible_medias()">
 		<picture tal:define="image_data i18n:image.data;
-							 image_url extension:absolute_url(image_data);
+							 image_url tales:absolute_url(image_data);
 							 base_width 100 / 12;
 							 width 12;">
 			<source media="(min-width: 1200px)"
--- a/src/pyams_default_theme/component/illustration/templates/illustration-default.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/component/illustration/templates/illustration-default.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -1,5 +1,5 @@
 <div class="text-center margin-y-5">
-	<picture tal:define="image_url extension:absolute_url(view.data);
+	<picture tal:define="image_url tales:absolute_url(view.data);
 						 base_width 100 / 12;
 						 width 12;">
 		<source media="(min-width: 1200px)"
--- a/src/pyams_default_theme/component/illustration/templates/illustration-left.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/component/illustration/templates/illustration-left.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -2,11 +2,11 @@
 	<a class="fancybox" data-toggle
 	   data-ams-fancybox-type="image"
 	   tal:omit-tag="not:view.settings.zoom_on_click"
-	   tal:define="thumbnails extension:thumbnails(view.data);
+	   tal:define="thumbnails tales:thumbnails(view.data);
 				   target thumbnails.get_thumbnail('800x600');
 				   thumb thumbnails.get_thumbnail('300x200');"
-	   tal:attributes="href extension:absolute_url(target)">
-		<img tal:attributes="src extension:absolute_url(thumb);
+	   tal:attributes="href tales:absolute_url(target)">
+		<img tal:attributes="src tales:absolute_url(thumb);
 							 alt view.alt_title;" /><br />
 		<span tal:content="view.title">legend</span>
 	</a><br />
--- a/src/pyams_default_theme/component/illustration/templates/illustration-right.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/component/illustration/templates/illustration-right.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -2,11 +2,11 @@
 	<a class="fancybox" data-toggle
 	   data-ams-fancybox-type="image"
 	   tal:omit-tag="not:view.settings.zoom_on_click"
-	   tal:define="thumbnails extension:thumbnails(view.data);
+	   tal:define="thumbnails tales:thumbnails(view.data);
 				   target thumbnails.get_thumbnail('800x600');
 				   thumb thumbnails.get_thumbnail('300x200');"
-	   tal:attributes="href extension:absolute_url(target)">
-		<img tal:attributes="src extension:absolute_url(thumb);
+	   tal:attributes="href tales:absolute_url(target)">
+		<img tal:attributes="src tales:absolute_url(thumb);
 							 alt view.alt_title" /><br />
 		<span tal:content="view.title">legend</span>
 	</a><br />
--- a/src/pyams_default_theme/component/keynumber/portlet/__init__.py	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/component/keynumber/portlet/__init__.py	Tue Jul 10 12:17:34 2018 +0200
@@ -12,25 +12,36 @@
 
 __docformat__ = 'restructuredtext'
 
+
 # import standard library
 
 # import interfaces
-from pyams_content.component.keynumber.portlet import IKeyNumberPortletSettings
+from pyams_content.component.keynumber.portlet.interfaces import IKeyNumberPortletSettings
 from pyams_portal.interfaces import IPortalContext, IPortletRenderer
-from pyams_portal.portlet import PortletRenderer
 from pyams_skin.layer import IPyAMSLayer
 
 # import packages
+from pyams_portal.portlet import PortletRenderer
 from pyams_template.template import template_config
 from pyams_utils.adapter import adapter_config
+from zope.interface import Interface
 
-from zope.interface import Interface
 from pyams_default_theme import _
 
 
-@adapter_config(context=(IPortalContext, IPyAMSLayer, Interface, IKeyNumberPortletSettings), provides=IPortletRenderer)
-@template_config(template='templates/render.pt', layer=IPyAMSLayer)
-class KeyNumberPortletRenderer(PortletRenderer):
-    """New portlet renderer"""
+@adapter_config(context=(IPortalContext, IPyAMSLayer, Interface, IKeyNumberPortletSettings),
+                provides=IPortletRenderer)
+@template_config(template='templates/horizontal-render.pt', layer=IPyAMSLayer)
+class KeyNumberPortletHorizontalRenderer(PortletRenderer):
+    """Key numbers portlet horizontal renderer"""
+
+    label = _("Horizontal list with carousel")
 
-    label = _("Vertical list of key numbers")
+
+@adapter_config(name='vertical', context=(IPortalContext, IPyAMSLayer, Interface, IKeyNumberPortletSettings),
+                provides=IPortletRenderer)
+@template_config(template='templates/vertical-render.pt', layer=IPyAMSLayer)
+class KeyNumberPortletVerticalRenderer(PortletRenderer):
+    """Key numbers portlet vertical renderer"""
+
+    label = _("Vertical list")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/component/keynumber/portlet/templates/horizontal-render.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -0,0 +1,20 @@
+<div tal:define="settings view.settings" i18n:domain="pyams_content">
+	<strong tal:define="title i18n:settings.title"
+			tal:condition="title">
+		<tal:var content="title"/><br /></strong>
+	<div tal:define="teaser i18n:settings.teaser"
+		 tal:content="structure tales:html(teaser)">Teaser</div>
+	<ul>
+		<li tal:repeat="number settings.keynumbers.get_visible_items()">
+			<span tal:define="label i18n:number.label"
+				  tal:condition="label">
+				<tal:var content="label" /> : </span>
+			<span class="badge"
+				  tal:content="i18n:number.number">Number</span>
+			<span tal:define="unit i18n:number.unit"
+				  tal:condition="unit"
+				  tal:content="unit">Unit</span>
+			<span tal:content="i18n:number.text">text</span>
+		</li>
+	</ul>
+</div>
--- a/src/pyams_default_theme/component/keynumber/portlet/templates/render.pt	Fri Jun 15 18:17:42 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-<div tal:define="settings view.settings" i18n:domain="pyams_content">
-    <strong tal:define="title i18n:settings.title"
-            tal:condition="title"
-            tal:content="title + ' : '">Title</strong>
-    <span tal:content="settings.teaser"></span>
-    <ul>
-	    <li tal:repeat="number settings.keynumbers.get_visible_items()">
-			<span tal:define="label i18n:number.label"
-                  tal:condition="label"
-				  tal:content="label + ' : '">label</span>
-			<span tal:define="number i18n:number.number"
-				  tal:content="number or '--'" class="badge">Number</span>
-			<span tal:define="unit i18n:number.unit"
-				  tal:content="unit or '......'">Unit</span>
-			<span tal:define="txt i18n:number.text"
-				  tal:content="txt">text</span>
-		</li>
-	</ul>
-</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/component/keynumber/portlet/templates/vertical-render.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -0,0 +1,20 @@
+<div tal:define="settings view.settings" i18n:domain="pyams_content">
+	<strong tal:define="title i18n:settings.title"
+			tal:condition="title">
+		<tal:var content="title"/><br /></strong>
+	<div tal:define="teaser i18n:settings.teaser"
+		 tal:content="structure tales:html(teaser)">Teaser</div>
+	<ul>
+		<li tal:repeat="number settings.keynumbers.get_visible_items()">
+			<span tal:define="label i18n:number.label"
+				  tal:condition="label">
+				<tal:var content="label" /> : </span>
+			<span class="badge"
+				  tal:content="i18n:number.number">Number</span>
+			<span tal:define="unit i18n:number.unit"
+				  tal:condition="unit"
+				  tal:content="unit">Unit</span>
+			<span tal:content="i18n:number.text">text</span>
+		</li>
+	</ul>
+</div>
--- a/src/pyams_default_theme/component/paragraph/templates/contact-default.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/component/paragraph/templates/contact-default.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -3,7 +3,7 @@
 	<h3 tal:content="view.title">Contact title</h3>
 	<div tal:condition="settings.can_display_photo"
 		 tal:attributes="class string:thumbnail photo pull-${settings.photo_position}">
-		<img tal:attributes="src extension:absolute_url(view.photo, '++thumb++w128')" />
+		<img tal:attributes="src tales:absolute_url(view.photo, '++thumb++w128')" />
 	</div>
 	<div tal:condition="settings.can_display_map"
 		 tal:attributes="class string:map pull-${settings.map_position}">
--- a/src/pyams_default_theme/component/paragraph/templates/header-default.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/component/paragraph/templates/header-default.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -1,2 +1,2 @@
 <div class="strong margin-bottom-10"
-	 tal:content="structure extension:html(view.header)">header</div>
+	 tal:content="structure tales:html(view.header)">header</div>
--- a/src/pyams_default_theme/component/paragraph/templates/html-default.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/component/paragraph/templates/html-default.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -1,3 +1,3 @@
 <h3 tal:content="view.title">title</h3>
-<div tal:content="structure view.body">body</div>
+<div tal:content="structure tales:html(view.body, 'oid_to_href')">body</div>
 <tal:var content="structure view.render_illustration()">Illustration</tal:var>
--- a/src/pyams_default_theme/component/paragraph/templates/verbatim-default.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/component/paragraph/templates/verbatim-default.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -10,11 +10,11 @@
 			<span tal:content="view.charge">Charge</span>
 		</div>
 		<div class="quote col-md-5"
-			 tal:content="extension:html(view.quote)">Quote</div>
+			 tal:content="tales:html(view.quote)">Quote</div>
 	</tal:if>
 	<tal:if condition="not:display_illustration">
 		<div class="quote"
-			 tal:content="extension:html(view.quote)">Quote</div>
+			 tal:content="tales:html(view.quote)">Quote</div>
 		<div class="author">
 			<span tal:content="view.author">Author</span>
 			<tal:if condition="view.charge">&ndash;</tal:if>
--- a/src/pyams_default_theme/component/paragraph/templates/verbatim-left.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/component/paragraph/templates/verbatim-left.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -6,7 +6,7 @@
 		 tal:replace="structure view.illustration_renderer.render() if view.illustration_renderer is not None else None">
 	</div>
 	<div class="quote"
-		 tal:content="structure extension:html(view.quote)">Quote</div>
+		 tal:content="structure tales:html(view.quote)">Quote</div>
 	<div class="author">
 		<span tal:content="view.author">Author</span>
 		<tal:if condition="view.charge">
--- a/src/pyams_default_theme/component/paragraph/templates/verbatim-right.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/component/paragraph/templates/verbatim-right.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -6,7 +6,7 @@
 		 tal:replace="structure view.illustration_renderer.render() if view.illustration_renderer is not None else None">
 	</div>
 	<div class="quote"
-		 tal:content="structure extension:html(view.quote)">Quote</div>
+		 tal:content="structure tales:html(view.quote)">Quote</div>
 	<div class="author">
 		<span tal:content="view.author">Author</span>
 		<tal:if condition="view.charge">
--- a/src/pyams_default_theme/component/paragraph/templates/video-default.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/component/paragraph/templates/video-default.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -1,28 +1,29 @@
 <h3 tal:condition="view.title"
 	tal:content="view.title">title</h3>
 <div tal:condition="view.description"
-	 tal:content="structure extension:html(view.description)">Description</div>
+	 tal:content="structure tales:html(view.description)">Description</div>
 <div class="flowplayer"
 	 data-ams-plugins="flowplayer"
 	 data-ams-plugin-flowplayer-async="false"
 	 data-ams-callback="PyAMS_media.initPlayer"
-	 tal:attributes="data-ams-plugin-flowplayer-src extension:resource_path('pyams_media.skin:flowplayer');
-					 data-ams-plugin-flowplayer-css extension:resource_path('pyams_media.skin:functional_css');
-					 data-ams-callback-source extension:resource_path('pyams_media.skin:pyams_media');">
+	 tal:condition="view.data"
+	 tal:attributes="data-ams-plugin-flowplayer-src tales:resource_path('pyams_media.skin:flowplayer');
+					 data-ams-plugin-flowplayer-css tales:resource_path('pyams_media.skin:functional_css');
+					 data-ams-callback-source tales:resource_path('pyams_media.skin:pyams_media');">
 	<video
 		tal:define="video view.data;
-					href extension:absolute_url(video);
-					thumbnails extension:thumbnails(video);
-					conversions extension:conversions(video);
+					href tales:absolute_url(video);
+					thumbnails tales:thumbnails(video);
+					conversions tales:conversions(video);
 					size thumbnails.get_image_size();"
 		tal:attributes="poster string:${href}/++thumb++${size[0]}x${size[1]}.png">
 		<tal:loop repeat="conversion conversions.get_conversions(order=('video/webm','video/mp4','video/x-flv'))">
 			<source type="video/mp4"
 					tal:define="media_width conversions.get_conversion_width(conversion.__name__);
-								video_type extension:video_type(conversion);"
+								video_type tales:video_type(conversion);"
 					tal:condition="video_type"
 					tal:attributes="type video_type;
-									src extension:absolute_url(conversion);
+									src tales:absolute_url(conversion);
 									media 'all and (max-width: {0}px)'.format(media_width) if media_width else None;" />
 		</tal:loop>
 	</video>
--- a/src/pyams_default_theme/component/video/templates/video-default.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/component/video/templates/video-default.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -1,5 +1,5 @@
 <h3 tal:condition="view.title"
 	tal:content="view.title">title</h3>
 <div tal:condition="view.description"
-	 tal:content="structure extension:html(view.description)">Description</div>
+	 tal:content="structure tales:html(view.description)">Description</div>
 <tal:var replace="structure view.render_video()" />
--- a/src/pyams_default_theme/features/header/__init__.py	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/features/header/__init__.py	Tue Jul 10 12:17:34 2018 +0200
@@ -17,11 +17,21 @@
 
 # import interfaces
 from pyams_content.features.header.interfaces import IHeaderTarget, IHeaderSettings
+from pyams_content.features.menu.interfaces import IMenuLinksContainerTarget, IMenuLinksContainer
+from pyams_default_theme.features.header.interfaces import ISimpleHeaderRendererSettings, ISimpleHeaderTabsMenu
 from pyams_default_theme.layer import IPyAMSDefaultLayer
+from zope.location.interfaces import ISublocations
 
 # import packages
+from persistent import Persistent
+from pyams_content.component.association.interfaces import ASSOCIATION_CONTAINER_KEY
+from pyams_content.features.menu import Menu
+from pyams_file.property import FileProperty
+from pyams_utils.adapter import get_annotation_adapter, adapter_config, ContextAdapter
 from pyams_utils.traversing import get_parent
 from pyams_viewlet.viewlet import contentprovider_config, ViewContentProvider
+from zope.interface import implementer
+from zope.location import Location, locate
 
 
 @contentprovider_config(name='pyams.header', layer=IPyAMSDefaultLayer)
@@ -29,16 +39,52 @@
     """Header content provider"""
 
     header = None
+    renderer = None
 
     def update(self):
         parent = get_parent(self.context, IHeaderTarget)
         if parent is not None:
-            self.header = IHeaderSettings(parent, None)
+            header = self.header = IHeaderSettings(parent, None)
+            if header is not None:
+                renderer = self.renderer = header.get_renderer(self.request)
+                if renderer is not None:
+                    renderer.update()
 
     def render(self):
-        if self.header is None:
+        if (self.header is None) or (self.renderer is None):
             return ''
-        renderer = self.header.get_renderer(self.request)
-        if renderer is None:
-            return ''
-        return renderer.render()
+        return self.renderer.render()
+
+
+#
+# Simple header renderer settings
+#
+
+SIMPLE_HEADER_TABS_KEY = '{0}::tabs'.format(ASSOCIATION_CONTAINER_KEY)
+
+
+@implementer(ISimpleHeaderRendererSettings, IMenuLinksContainerTarget)
+class SimpleHeaderRendererSettings(Persistent, Location):
+    """Simple header renderer settings"""
+
+    banner = FileProperty(ISimpleHeaderRendererSettings['banner'])
+    logo = FileProperty(ISimpleHeaderRendererSettings['logo'])
+
+    @property
+    def tabs(self):
+        return get_annotation_adapter(self, SIMPLE_HEADER_TABS_KEY, Menu,
+                                      markers=ISimpleHeaderTabsMenu, name='++ass++tabs')
+
+
+@adapter_config(name='tabs', context=ISimpleHeaderRendererSettings, provides=IMenuLinksContainer)
+def simple_header_tabs_links_adapter(context):
+    """Simple header tabs links adapter"""
+    return context.tabs
+
+
+@adapter_config(name='links', context=ISimpleHeaderRendererSettings, provides=ISublocations)
+class SimpleHeaderRendererSettingsSublocations(ContextAdapter):
+    """Simple header renderer settings sub-locations adapter"""
+
+    def sublocations(self):
+        return self.context.tabs.values()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/features/header/interfaces.py	Tue Jul 10 12:17:34 2018 +0200
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2008-2018 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_content.features.header.interfaces import IHeaderRendererSettings
+
+# import packages
+from pyams_file.schema import ImageField
+from zope.interface import Interface, Attribute
+
+from pyams_default_theme import _
+
+
+class ISimpleHeaderRendererSettings(IHeaderRendererSettings):
+    """Simple header renderer settings"""
+
+    banner = ImageField(title=_("Banner image"),
+                        description=_("Image displayed as header background"),
+                        required=False)
+
+    logo = ImageField(title=_("Logo"),
+                      description=_("Logo displayed in header"),
+                      required=False)
+
+    tabs = Attribute("Top tabs list")
+
+
+class ISimpleHeaderTabsMenu(Interface):
+    """Simple header menu marker interface"""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/features/header/skin/__init__.py	Tue Jul 10 12:17:34 2018 +0200
@@ -0,0 +1,75 @@
+#
+# Copyright (c) 2008-2018 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_content.component.association.interfaces import IAssociationInfo
+from pyams_content.component.links.interfaces import IInternalLink
+from pyams_content.features.header.interfaces import IHeaderTarget, IHeaderRenderer, IHeaderSettings, \
+    IHeaderRendererSettings
+from pyams_default_theme.features.header.interfaces import ISimpleHeaderRendererSettings
+from pyams_skin.layer import IPyAMSLayer
+
+# import packages
+from pyams_content.features.header.skin import BaseHeaderRenderer
+from pyams_default_theme.features.header import SimpleHeaderRendererSettings
+from pyams_template.template import template_config
+from pyams_utils.adapter import adapter_config
+from pyramid.location import lineage
+
+from pyams_default_theme import _
+
+
+SIMPLE_HEADER_RENDERER_NAME = 'PyAMS simple header'
+
+
+#
+# Simple header renderer
+#
+
+@adapter_config(name=SIMPLE_HEADER_RENDERER_NAME, context=(IHeaderTarget, IPyAMSLayer), provides=IHeaderRenderer)
+@adapter_config(name=SIMPLE_HEADER_RENDERER_NAME, context=(IHeaderSettings, IPyAMSLayer), provides=IHeaderRenderer)
+@template_config(template='templates/simple-header.pt', layer=IPyAMSLayer)
+class SimpleHeaderRenderer(BaseHeaderRenderer):
+    """Simple header renderer"""
+
+    name = SIMPLE_HEADER_RENDERER_NAME
+    label = _("PyAMS simple header with banner and tabs")
+    weight = 1
+
+    settings_key = 'PyAMS::simple'
+    settings_interface = ISimpleHeaderRendererSettings
+
+    def update(self):
+        super(SimpleHeaderRenderer, self).update()
+        self.request.annotations['REQUEST_PATH'] = list(lineage(self.request.context))
+
+    @staticmethod
+    def get_link_info(link):
+        return IAssociationInfo(link)
+
+    def is_active(self, link):
+        if IInternalLink.providedBy(link):
+            target = link.get_target()
+            if target is not None:
+                return target in self.request.annotations['REQUEST_PATH']
+        return False
+
+
+@adapter_config(context=SimpleHeaderRenderer, provides=IHeaderRendererSettings)
+def simple_header_renderer_settings_factory(context):
+    """Simple header renderer settings factory"""
+    return SimpleHeaderRendererSettings()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/features/header/skin/templates/simple-header.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -0,0 +1,16 @@
+<div class="header header-simple"
+	 tal:define="settings view.settings" i18n:domain="pyams_default_theme">
+	<tal:var replace="structure provider:pyams.banner" />
+	<ul class="nav nav-tabs" role="tablist">
+		<tal:loop repeat="link settings.tabs.get_visible_items()">
+			<li role="presentation"
+				tal:attributes="class 'active' if view.is_active(link) else ''">
+				<a tal:define="info view.get_link_info(link);
+							   href link.get_url(request);"
+				   tal:condition="href"
+				   tal:content="info.user_title"
+				   tal:attributes="href href">Link</a>
+			</li>
+		</tal:loop>
+	</ul>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/features/header/zmi/__init__.py	Tue Jul 10 12:17:34 2018 +0200
@@ -0,0 +1,84 @@
+#
+# Copyright (c) 2008-2018 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_default_theme.features.header import ISimpleHeaderRendererSettings, ISimpleHeaderTabsMenu
+from pyams_form.interfaces.form import IInnerSubForm
+from pyams_portal.interfaces import MANAGE_TEMPLATE_PERMISSION
+from pyams_skin.layer import IPyAMSLayer
+from transaction.interfaces import ITransactionManager
+
+# import packages
+from pyams_content.features.header.zmi import HeaderSettingsRendererSettingsEditForm
+from pyams_content.features.menu.zmi import LinksTable, IMenuLinksView, MenuLinksView
+from pyams_skin.event import get_json_widget_refresh_event
+from pyams_utils.adapter import adapter_config
+from pyams_zmi.form import InnerAdminEditForm
+from z3c.form import field
+
+from pyams_default_theme import _
+
+
+@adapter_config(name='simple-header-properties',
+                context=(ISimpleHeaderRendererSettings, IPyAMSLayer, HeaderSettingsRendererSettingsEditForm),
+                provides=IInnerSubForm)
+class SimpleHeaderPropertiesEditForm(InnerAdminEditForm):
+    """Simple header properties edit form"""
+
+    legend = None
+    edit_permission = MANAGE_TEMPLATE_PERMISSION
+    weight = 1
+
+    fields = field.Fields(ISimpleHeaderRendererSettings)
+
+    def get_ajax_output(self, changes):
+        output = super(SimpleHeaderPropertiesEditForm, self).get_ajax_output(changes)
+        updated = changes.get(ISimpleHeaderRendererSettings, ())
+        if updated:
+            ITransactionManager(self.context).commit()
+            if 'banner' in updated:
+                output.setdefault('events', []).append(
+                    get_json_widget_refresh_event(self.context, self.request,
+                                                  SimpleHeaderPropertiesEditForm, 'banner'))
+            if 'logo' in updated:
+                output.setdefault('events', []).append(
+                    get_json_widget_refresh_event(self.context, self.request,
+                                                  SimpleHeaderPropertiesEditForm, 'logo'))
+        return output
+
+
+#
+# Header top tabs table view
+#
+
+class TabsAssociationsTable(LinksTable):
+    """Simple header tabs associations table"""
+
+    associations_name = 'tabs'
+
+
+@adapter_config(name='simple-header-tabs',
+                context=(ISimpleHeaderRendererSettings, IPyAMSLayer, HeaderSettingsRendererSettingsEditForm),
+                provides=IInnerSubForm)
+@adapter_config(name='++ass++tabs', context=(ISimpleHeaderTabsMenu, IPyAMSLayer), provides=IMenuLinksView)
+class SimpleHeaderTabsView(MenuLinksView):
+    """Simple header tabs view"""
+
+    title = _("Top tabs")
+
+    table_class = TabsAssociationsTable
+    weight = 10
--- a/src/pyams_default_theme/features/menu/portlet/navigation/__init__.py	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/features/menu/portlet/navigation/__init__.py	Tue Jul 10 12:17:34 2018 +0200
@@ -18,14 +18,20 @@
 # import interfaces
 from pyams_content.features.menu.portlet.navigation.interfaces.double import IDoubleNavigationPortletSettings
 from pyams_content.features.menu.portlet.navigation.interfaces.simple import ISimpleNavigationPortletSettings
-from pyams_portal.interfaces import IPortalContext, IPortletRenderer
+from pyams_default_theme.features.menu.portlet.navigation.interfaces import \
+    IDoubleNavigationPortletSelectMenusRendererSettings
+from pyams_portal.interfaces import IPortalContext, IPortletRenderer, PORTLET_RENDERER_SETTINGS_KEY
 from pyams_skin.layer import IPyAMSLayer
 
 # import packages
+from persistent import Persistent
 from pyams_portal.portlet import PortletRenderer
 from pyams_template.template import template_config
 from pyams_utils.adapter import adapter_config
+from pyams_utils.factory import factory_config
 from zope.interface import implementer, Interface
+from zope.location.location import Location
+from zope.schema.fieldproperty import FieldProperty
 
 from pyams_default_theme import _
 
@@ -37,20 +43,55 @@
 @adapter_config(context=(IPortalContext, IPyAMSLayer, Interface, ISimpleNavigationPortletSettings),
                 provides=IPortletRenderer)
 @template_config(template='templates/simple-horizontal.pt', layer=IPyAMSLayer)
-class SimpleNavigationDefaultPortletRenderer(PortletRenderer):
-    """Simple navigation default portlet renderer"""
+class SimpleNavigationPortletHorizontalRenderer(PortletRenderer):
+    """Simple navigation horizontal portlet renderer"""
 
     label = _("Horizontal list with vertical illustrations")
 
 
+@adapter_config(name='horizontal-tabs',
+                context=(IPortalContext, IPyAMSLayer, Interface, ISimpleNavigationPortletSettings),
+                provides=IPortletRenderer)
+@template_config(template='templates/simple-horizontal-tabs.pt', layer=IPyAMSLayer)
+class SimpleNavigationPortletHorizontalTabsRenderer(PortletRenderer):
+    """Simple navigation horizontal portlet renderer with tabs"""
+
+    label = _("Horizontal list with tabs and horizontal illustrations")
+
+
 #
-# Double navigation portlet renderers
+# Double navigation portlet default renderer
 #
 
 @adapter_config(context=(IPortalContext, IPyAMSLayer, Interface, IDoubleNavigationPortletSettings),
                 provides=IPortletRenderer)
 @template_config(template='templates/double-vertical.pt', layer=IPyAMSLayer)
-class DoubleNavigationDefaultPortletRenderer(PortletRenderer):
-    """Double navigation default portlet renderer"""
+class DoubleNavigationPortletDefaultRenderer(PortletRenderer):
+    """Double navigation portlet default renderer"""
 
     label = _("Vertical list with small horizontal menus illustrations")
+
+
+#
+# Double navigation portlet "double-select" renderer
+#
+
+@implementer(IDoubleNavigationPortletSelectMenusRendererSettings)
+@factory_config(provided=IDoubleNavigationPortletSelectMenusRendererSettings)
+class DoubleNavigationPortletSelectMenusRendererSettings(Persistent, Location):
+    """Double navigation portlet select menus renderer settings"""
+
+    first_level_label = FieldProperty(IDoubleNavigationPortletSelectMenusRendererSettings['first_level_label'])
+    second_level_label = FieldProperty(IDoubleNavigationPortletSelectMenusRendererSettings['second_level_label'])
+
+
+@adapter_config(name='double-select',
+                context=(IPortalContext, IPyAMSLayer, Interface, IDoubleNavigationPortletSettings),
+                provides=IPortletRenderer)
+@template_config(template='templates/double-select.pt', layer=IPyAMSLayer)
+class DoubleNavigationPortletSelectMenusRenderer(PortletRenderer):
+    """Double navigation portlet menus renderer"""
+
+    label = _("Double-level selection navigation")
+
+    settings_interface = IDoubleNavigationPortletSelectMenusRendererSettings
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/features/menu/portlet/navigation/interfaces.py	Tue Jul 10 12:17:34 2018 +0200
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2008-2018 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+
+# import packages
+from pyams_i18n.schema import I18nTextLineField
+from zope.interface import Interface
+
+from pyams_default_theme import _
+
+
+class IDoubleNavigationPortletSelectMenusRendererSettings(Interface):
+    """Double navigation portlet select menus renderer settings interface"""
+
+    first_level_label = I18nTextLineField(title=_("First menu label"),
+                                          description=_("Label associated with first level options menu"),
+                                          required=True)
+
+    second_level_label = I18nTextLineField(title=_("Second menu label"),
+                                           description=_("Label associated with second level options menu"),
+                                           required=True)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/features/menu/portlet/navigation/templates/double-select.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -0,0 +1,3 @@
+<tal:var define="settings view.settings">
+	<strong tal:content="i18n:settings.title" />
+</tal:var>
Binary file src/pyams_default_theme/locales/fr/LC_MESSAGES/pyams_default_theme.mo has changed
--- a/src/pyams_default_theme/locales/fr/LC_MESSAGES/pyams_default_theme.po	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/locales/fr/LC_MESSAGES/pyams_default_theme.po	Tue Jul 10 12:17:34 2018 +0200
@@ -5,7 +5,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE 1.0\n"
-"POT-Creation-Date: 2018-06-13 14:45+0200\n"
+"POT-Creation-Date: 2018-07-03 09:32+0200\n"
 "PO-Revision-Date: 2017-06-07 12:41+0200\n"
 "Last-Translator: Thierry Florac <tflorac@ulthar.net>\n"
 "Language-Team: French\n"
@@ -18,12 +18,20 @@
 
 #: src/pyams_default_theme/skin.py:35
 msgid "PyAMS default skin"
-msgstr "Skin par défaut PyAMS"
+msgstr "Skin par défaut (PyAMS)"
 
 #: src/pyams_default_theme/component/gallery/__init__.py:40
 msgid "Default gallery renderer"
 msgstr "Par défaut"
 
+#: src/pyams_default_theme/component/keynumber/portlet/__init__.py:37
+msgid "Horizontal list with carousel"
+msgstr "Liste horizontale (par défaut)"
+
+#: src/pyams_default_theme/component/keynumber/portlet/__init__.py:46
+msgid "Vertical list"
+msgstr "Liste verticale"
+
 #: src/pyams_default_theme/component/illustration/__init__.py:72
 msgid "Centered illustration"
 msgstr "Illustration centrée (par défaut)"
@@ -189,8 +197,8 @@
 #: src/pyams_default_theme/shared/view/templates/render.pt:3
 msgid "WARNING: items displayed in this preview are out of context!!"
 msgstr ""
-"ATTENTION : la sélection des éléments affichés dans cet aperçu ne tient pas compte du "
-"contexte éventuellement paramétré dans la vue"
+"ATTENTION : la sélection des éléments affichés dans cet aperçu ne tient pas "
+"compte du contexte éventuellement paramétré dans la vue"
 
 #: src/pyams_default_theme/shared/view/portlet/__init__.py:37
 msgid "Simple list view"
@@ -208,6 +216,62 @@
 msgid "Default logos renderer"
 msgstr "Par défaut"
 
+#: src/pyams_default_theme/features/menu/portlet/navigation/__init__.py:49
+msgid "Horizontal list with vertical illustrations"
+msgstr "Liste horizontale avec illustrations verticales (par défaut)"
+
+#: src/pyams_default_theme/features/menu/portlet/navigation/__init__.py:59
+msgid "Horizontal list with tabs and horizontal illustrations"
+msgstr "Liste horizontale avec onglets et illustrations panoramiques"
+
+#: src/pyams_default_theme/features/menu/portlet/navigation/__init__.py:72
+msgid "Vertical list with small horizontal menus illustrations"
+msgstr "Liste verticale avec illustrations horizontales"
+
+#: src/pyams_default_theme/features/menu/portlet/navigation/__init__.py:95
+msgid "Double-level selection navigation"
+msgstr "Navigation par sélection à deux niveaux"
+
+#: src/pyams_default_theme/features/menu/portlet/navigation/interfaces.py:30
+msgid "First menu label"
+msgstr "Libellé sélection 1"
+
+#: src/pyams_default_theme/features/menu/portlet/navigation/interfaces.py:31
+msgid "Label associated with first level options menu"
+msgstr "Libellé associé au premier niveau de sélection"
+
+#: src/pyams_default_theme/features/menu/portlet/navigation/interfaces.py:34
+msgid "Second menu label"
+msgstr "Libellé sélection 2"
+
+#: src/pyams_default_theme/features/menu/portlet/navigation/interfaces.py:35
+msgid "Label associated with second level options menu"
+msgstr "Libellé associé au second niveau de sélection"
+
+#: src/pyams_default_theme/features/header/interfaces.py:31
+msgid "Banner image"
+msgstr "Bandeau"
+
+#: src/pyams_default_theme/features/header/interfaces.py:32
+msgid "Image displayed as header background"
+msgstr "Image affichée en tête de page"
+
+#: src/pyams_default_theme/features/header/interfaces.py:35
+msgid "Logo"
+msgstr "Logo"
+
+#: src/pyams_default_theme/features/header/interfaces.py:36
+msgid "Logo displayed in header"
+msgstr "Logo superposé au bandeau"
+
+#: src/pyams_default_theme/features/header/zmi/__init__.py:81
+msgid "Top tabs"
+msgstr "Onglets de navigation"
+
+#: src/pyams_default_theme/features/header/skin/__init__.py:48
+msgid "PyAMS simple header with banner and tabs"
+msgstr "PyAMS: en-tête simple avec bandeau et onglets de navigation"
+
 #~ msgid "Search..."
 #~ msgstr "Chercher..."
 
--- a/src/pyams_default_theme/locales/pyams_default_theme.pot	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/locales/pyams_default_theme.pot	Tue Jul 10 12:17:34 2018 +0200
@@ -6,7 +6,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE 1.0\n"
-"POT-Creation-Date: 2018-06-13 14:45+0200\n"
+"POT-Creation-Date: 2018-07-03 09:32+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -24,6 +24,14 @@
 msgid "Default gallery renderer"
 msgstr ""
 
+#: ./src/pyams_default_theme/component/keynumber/portlet/__init__.py:37
+msgid "Horizontal list with carousel"
+msgstr ""
+
+#: ./src/pyams_default_theme/component/keynumber/portlet/__init__.py:46
+msgid "Vertical list"
+msgstr ""
+
 #: ./src/pyams_default_theme/component/illustration/__init__.py:72
 msgid "Centered illustration"
 msgstr ""
@@ -190,3 +198,59 @@
 #: ./src/pyams_default_theme/shared/logo/__init__.py:39
 msgid "Default logos renderer"
 msgstr ""
+
+#: ./src/pyams_default_theme/features/menu/portlet/navigation/__init__.py:49
+msgid "Horizontal list with vertical illustrations"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/menu/portlet/navigation/__init__.py:59
+msgid "Horizontal list with tabs and horizontal illustrations"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/menu/portlet/navigation/__init__.py:72
+msgid "Vertical list with small horizontal menus illustrations"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/menu/portlet/navigation/__init__.py:95
+msgid "Double-level selection navigation"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/menu/portlet/navigation/interfaces.py:30
+msgid "First menu label"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/menu/portlet/navigation/interfaces.py:31
+msgid "Label associated with first level options menu"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/menu/portlet/navigation/interfaces.py:34
+msgid "Second menu label"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/menu/portlet/navigation/interfaces.py:35
+msgid "Label associated with second level options menu"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/header/interfaces.py:31
+msgid "Banner image"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/header/interfaces.py:32
+msgid "Image displayed as header background"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/header/interfaces.py:35
+msgid "Logo"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/header/interfaces.py:36
+msgid "Logo displayed in header"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/header/zmi/__init__.py:81
+msgid "Top tabs"
+msgstr ""
+
+#: ./src/pyams_default_theme/features/header/skin/__init__.py:48
+msgid "PyAMS simple header with banner and tabs"
+msgstr ""
--- a/src/pyams_default_theme/resources/css/pyams-default.css	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/resources/css/pyams-default.css	Tue Jul 10 12:17:34 2018 +0200
@@ -1,3 +1,19 @@
+body {
+  max-width: 950px;
+  margin: 0 auto;
+}
+body .header-simple .regularbanner {
+  position: relative;
+}
+body .header-simple .regularbanner img.regularbanner__media {
+  width: 100%;
+}
+body .header-simple .regularbanner img.logo {
+  position: absolute;
+  top: 10px;
+  left: 10px;
+  max-height: calc(80%);
+}
 @media only screen and (min-width: 1200px) {
   .portal-page .slot.col-lg-0 {
     display: none;
@@ -18,3 +34,4 @@
     display: none;
   }
 }
+/*# sourceMappingURL=pyams-default.css.map */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/resources/css/pyams-default.css.map	Tue Jul 10 12:17:34 2018 +0200
@@ -0,0 +1,1 @@
+{"version":3,"sources":["../../../../../../../../../home/tflorac/Dropbox/src/PyAMS/pyams_default_theme/src/pyams_default_theme/resources/less/pyams-default.less"],"names":[],"mappings":"AAAA;EACC,gBAAA;EACA,cAAA;;AAFD,IAIC,eACC;EACC,kBAAA;;AAGC,IALH,eACC,eAGC,IACE;EACA,WAAA;;AAED,IARH,eACC,eAGC,IAIE;EACA,kBAAA;EACA,SAAA;EACA,UAAA;EACA,YAAY,SAAZ;;AAUH,wBAA2C;EAC1C,YAFF,MAEG;IACA,aAAA;;;AAGF,wBAA0C,uBAAwB;EACjE,YAPF,MAOG;IACA,aAAA;;;AAGF,wBAA0C,uBAAuB;EAChE,YAZF,MAYG;IACA,aAAA;;;AAGF,wBAA0C;EACzC,YAjBF,MAiBG;IACA,aAAA","file":"pyams-default.css"}
\ No newline at end of file
--- a/src/pyams_default_theme/resources/css/pyams-default.min.css	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/resources/css/pyams-default.min.css	Tue Jul 10 12:17:34 2018 +0200
@@ -1,1 +1,1 @@
-@media only screen and (min-width:1200px){.portal-page .slot.col-lg-0{display:none}}@media only screen and (min-width:992px) and (max-width:1199px){.portal-page .slot.col-md-0{display:none}}@media only screen and (min-width:768px) and (max-width:991px){.portal-page .slot.col-sm-0{display:none}}@media only screen and (max-width:767px){.portal-page .slot.col-xs-0{display:none}}
\ No newline at end of file
+body{max-width:950px;margin:0 auto}body .header-simple .regularbanner{position:relative}body .header-simple .regularbanner img.regularbanner__media{width:100%}body .header-simple .regularbanner img.logo{position:absolute;top:10px;left:10px;max-height:calc(80%)}@media only screen and (min-width:1200px){.portal-page .slot.col-lg-0{display:none}}@media only screen and (min-width:992px) and (max-width:1199px){.portal-page .slot.col-md-0{display:none}}@media only screen and (min-width:768px) and (max-width:991px){.portal-page .slot.col-sm-0{display:none}}@media only screen and (max-width:767px){.portal-page .slot.col-xs-0{display:none}}
--- a/src/pyams_default_theme/resources/less/pyams-default.less	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/resources/less/pyams-default.less	Tue Jul 10 12:17:34 2018 +0200
@@ -1,3 +1,26 @@
+body {
+	max-width: 950px;
+	margin: 0 auto;
+
+	.header-simple {
+		.regularbanner {
+			position: relative;
+
+			img {
+				&.regularbanner__media {
+					width: 100%;
+				}
+				&.logo {
+					position: absolute;
+					top: 10px;
+					left: 10px;
+					max-height: calc(100% - 20px);
+				}
+			}
+		}
+	}
+}
+
 .portal-page {
 
 	.slot {
--- a/src/pyams_default_theme/shared/imagemap/templates/imagemap-default.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/shared/imagemap/templates/imagemap-default.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -2,10 +2,10 @@
 <div class="no-padding" i18n:domain="pyams_content"
 	 data-ams-plugins="pyams_content"
 	 tal:define="imagemap context.get_target()"
-	 tal:attributes="data-ams-plugin-pyams_content-src extension:resource_path('pyams_content.skin:pyams_content')">
+	 tal:attributes="data-ams-plugin-pyams_content-src tales:resource_path('pyams_content.skin:pyams_content')">
 	<img usemap="#imagemap_preview"
 		 tal:define="image i18n:imagemap.image"
-		 tal:attributes="src extension:absolute_url(image);
+		 tal:attributes="src tales:absolute_url(image);
 						 usemap string:#imagemap_preview_${context.__name__}"
 		 data-ams-callback="PyAMS_content.imgmap.initPreview" />
 	<map name="imagemap_preview"
--- a/src/pyams_default_theme/shared/imagemap/templates/render.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/shared/imagemap/templates/render.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -3,7 +3,7 @@
 	<div>
 		<img usemap="#imagemap_preview"
 			 tal:define="image i18n:context.image"
-			 tal:attributes="src extension:absolute_url(image);" />
+			 tal:attributes="src tales:absolute_url(image);" />
 		<map name="imagemap_preview">
 			<tal:loop repeat="area context.areas.values()">
 				<tal:var define="item context.get_association(area)"
--- a/src/pyams_default_theme/shared/logo/templates/logos-default.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/shared/logo/templates/logos-default.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -4,10 +4,7 @@
 		<tal:if condition="logo is not None">
 			<a tal:omit-tag="not:logo.url"
 			   tal:attributes="href logo.url" target="_blank">
-				<img class="thumbnail margin-10"
-					 tal:define="thumbnails extension:thumbnails(logo.image);
-								 thumbnail thumbnails.get_thumbnail('200x200');"
-					 tal:attributes="src extension:absolute_url(thumbnail)" />
+				<tal:var content="structure tales:thumbnail(logo.image, 200, 'auto', 'display-inline margin-10')" />
 			</a>
 		</tal:if>
 	</tal:loop>
--- a/src/pyams_default_theme/shared/view/__init__.py	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/shared/view/__init__.py	Tue Jul 10 12:17:34 2018 +0200
@@ -34,4 +34,4 @@
 
     @property
     def items(self):
-        return self.context.get_results(self.context)
+        return self.context.get_results(self.context, ignore_cache=True)
--- a/src/pyams_default_theme/shared/view/portlet/templates/view-items-list.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/shared/view/portlet/templates/view-items-list.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -1,5 +1,6 @@
 <ul>
-	<li tal:repeat="item view.settings.get_items(context)">
-		<tal:var content="i18n:item.title" />
+	<li tal:repeat="item view.settings.get_items(request)">
+		<a tal:attributes="href tales:relative_url(item)"
+		   tal:content="i18n:item.title">Title</a>
 	</li>
 </ul>
--- a/src/pyams_default_theme/templates/layout.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/templates/layout.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -1,21 +1,19 @@
 <!DOCTYPE html>
 <html lang="en" i18n:domain="pyams_default_theme"
-	  tal:define="config extension:configuration;
-				  anonymous request.principal.id == '__none__';"
+	  tal:define="config tales:configuration;"
 	  tal:attributes="lang request.locale_name">
-<head>
-	<tal:var replace="structure extension:metas" />
+<head prefix="og: http://ogp.me/ns# article: http://ogp.me/ns/article#">
+	<tal:var replace="structure tales:metas" />
 
-	<title tal:attributes="data-ams-title-prefix config.get_title_prefix(request)"
-		   tal:content="config.title"></title>
-
-	<tal:if define="icon config.icon | nothing; url extension:absolute_url(icon);" condition="icon">
+	<tal:if define="icon config.icon | nothing; url tales:absolute_url(icon);" condition="icon">
 		<!-- Favorite icon -->
 		<link rel="shortcut icon" tal:attributes="href url" type="image/x-icon">
 		<link rel="icon" tal:attributes="href url" type="image/x-icon">
 	</tal:if>
 
-	<tal:var replace="extension:resources" />
+	<link rel="canonical" tal:attributes="href tales:canonical_url(context)" />
+
+	<tal:var replace="tales:resources" />
 
 	<!-- Javascript extensions -->
 	<tal:var content="structure provider:pyams.jsextensions" />
@@ -24,28 +22,33 @@
 </head>
 <body class="no-margin no-padding">
 
-	<!-- Page header -->
-	<div id="page-header" tal:content="structure provider:pyams.header">Header</div>
-	<!-- End page header -->
+	<div class="page">
 
-	<!-- Main panel -->
-	<div id="main" class="no-margin" role="main">
+		<!-- Page header -->
+		<tal:var content="structure provider:pyams.header">Header</tal:var>
+		<tal:var content="structure provider:pyams.banner">Banner</tal:var>
+		<!-- End page header -->
+
+		<!-- Main panel -->
+		<div id="main" class="no-margin" role="main">
 
-		<!-- Content -->
-		<div id="content" style="opacity: 1;">
-			<!--[if lt IE 9]>
-			<h1 i18n:translate="">Your browser is too old. Please install version 9 or higher of Internet Explorer.</h1>
-			<![endif]-->
-			<tal:var content="structure provider:pagelet" />
+			<!-- Content -->
+			<div id="content" style="opacity: 1;">
+				<!--[if lt IE 9]>
+				<h1 i18n:translate="">Your browser is too old. Please install version 9 or higher of Internet Explorer.</h1>
+				<![endif]-->
+				<tal:var content="structure provider:pagelet" />
+			</div>
+			<!-- end content -->
+
 		</div>
-		<!-- end content -->
+		<!-- end main panel -->
 
-	</div>
-	<!-- end main panel -->
+		<!-- Page footer -->
+		<tal:var content="structure provider:pyams.footer">Header</tal:var>
+		<!-- End page footer -->
 
-	<!-- Page footer -->
-	<div id="page-footer" tal:content="structure provider:pyams.footer">Header</div>
-	<!-- End page footer -->
+	</div>  <!-- page -->
 
 </body>
 </html>
--- a/src/pyams_default_theme/templates/preview-layout.pt	Fri Jun 15 18:17:42 2018 +0200
+++ b/src/pyams_default_theme/templates/preview-layout.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -1,43 +1,46 @@
 <!DOCTYPE html>
-<html lang="en" i18n:domain="pyams_default_theme"
-	  tal:define="config extension:configuration;
+<html class="no-js" lang="en" i18n:domain="pyams_default_theme"
+	  tal:define="config tales:configuration;
 				  anonymous request.principal.id == '__none__';"
 	  tal:attributes="lang request.locale_name">
 <head>
-	<tal:var replace="structure extension:metas" />
+	<tal:var replace="structure tales:metas" />
 
-	<title tal:attributes="data-ams-title-prefix config.get_title_prefix(request)"
-		   tal:content="config.title"></title>
-
-	<tal:if define="icon config.icon | nothing; url extension:absolute_url(icon);" condition="icon">
+	<tal:if define="icon config.icon | nothing; url tales:absolute_url(icon);" condition="icon">
 		<!-- Favorite icon -->
 		<link rel="shortcut icon" tal:attributes="href url" type="image/x-icon">
 		<link rel="icon" tal:attributes="href url" type="image/x-icon">
 	</tal:if>
 
-	<tal:var replace="extension:resources" />
+	<link rel="canonical" tal:attributes="href tales:canonical_url(context)" />
+
+	<tal:var replace="tales:resources" />
 
 	<!-- Javascript extensions -->
 	<tal:var content="structure provider:pyams.jsextensions" />
 	<!-- end javascript extensions -->
 
 </head>
-<body class="no-margin no-padding">
+<body class="alert--enabled">
 
-	<!-- Main panel -->
-	<div id="main" class="no-margin" role="main">
+	<div class="page">
+
+		<!-- Main panel -->
+		<div id="main" class="no-margin" role="main">
 
-		<!-- Content -->
-		<div id="content" style="opacity: 1;">
-			<!--[if lt IE 9]>
-			<h1 i18n:translate="">Your browser is too old. Please install version 9 or higher of Internet Explorer.</h1>
-			<![endif]-->
-			<tal:var content="structure provider:pagelet" />
+			<!-- Content -->
+			<div id="content" style="opacity: 1;">
+				<!--[if lt IE 9]>
+				<h1 i18n:translate="">Your browser is too old. Please install version 9 or higher of Internet Explorer.</h1>
+				<![endif]-->
+				<tal:var content="structure provider:pagelet" />
+			</div>
+			<!-- end content -->
+
 		</div>
-		<!-- end content -->
+		<!-- end main panel -->
 
-	</div>
-	<!-- end main panel -->
+	</div>  <!-- page -->
 
 </body>
 </html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/viewlet/__init__.py	Tue Jul 10 12:17:34 2018 +0200
@@ -0,0 +1,19 @@
+#
+# Copyright (c) 2008-2017 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+# import standard library
+
+# import interfaces
+
+# import packages
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/viewlet/banner/__init__.py	Tue Jul 10 12:17:34 2018 +0200
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2008-2018 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_content.features.header.interfaces import IHeaderTarget, IHeaderSettings
+from pyams_default_theme.features.header.interfaces import ISimpleHeaderRendererSettings
+from pyams_skin.layer import IPyAMSUserLayer
+
+# import packages
+from pyams_template.template import template_config
+from pyams_utils.traversing import get_parent
+from pyams_viewlet.viewlet import contentprovider_config, ViewContentProvider
+from zope.interface import Interface
+
+
+@contentprovider_config(name='pyams.banner', layer=IPyAMSUserLayer, view=Interface)
+@template_config(template='templates/banner.pt', layer=IPyAMSUserLayer)
+class Banner(ViewContentProvider):
+    """Banner content provider"""
+
+    @property
+    def settings(self):
+        target = get_parent(self.context, IHeaderTarget)
+        return ISimpleHeaderRendererSettings(IHeaderSettings(target).settings, None)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/viewlet/banner/templates/banner.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -0,0 +1,12 @@
+<section class="wrapper-regularbanner" i18n:domain="onf_website"
+		 tal:define="settings view.settings"
+		 tal:condition="settings and settings.banner">
+	<div class="regularbanner">
+		<div class="regularbanner__bg">
+			<img alt="" class="regularbanner__media"
+				 tal:define="image settings.banner"
+				 tal:attributes="src tales:absolute_url(image, '++thumb++w1320')" />
+		</div>  <!-- /.regularbanner__bg -->
+		<tal:var content="structure provider:pyams.logo" />
+	</div>  <!-- /.regularbanner -->
+</section>  <!-- /.wrapper-regularbanner -->
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/viewlet/logo/__init__.py	Tue Jul 10 12:17:34 2018 +0200
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2008-2017 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+# import standard library
+
+# import interfaces
+from pyams_content.features.header.interfaces import IHeaderTarget, IHeaderSettings
+from pyams_default_theme.features.header import ISimpleHeaderRendererSettings
+from pyams_skin.layer import IPyAMSUserLayer
+
+# import packages
+from pyams_template.template import template_config
+from pyams_utils.traversing import get_parent
+from pyams_viewlet.viewlet import contentprovider_config, ViewContentProvider
+from zope.interface import Interface
+
+
+@contentprovider_config(name='pyams.logo', layer=IPyAMSUserLayer, view=Interface)
+@template_config(template='templates/logo.pt', layer=IPyAMSUserLayer)
+class LogoContentProvider(ViewContentProvider):
+    """Logo content provider"""
+
+    @property
+    def settings(self):
+        target = get_parent(self.context, IHeaderTarget)
+        return ISimpleHeaderRendererSettings(IHeaderSettings(target).settings, None)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_default_theme/viewlet/logo/templates/logo.pt	Tue Jul 10 12:17:34 2018 +0200
@@ -0,0 +1,11 @@
+<tal:var define="settings view.settings"
+		 condition="settings" i18n:domain="pyams_default_theme">
+	<tal:if define="logo settings.logo"
+			condition="logo">
+		<a href="/" title="Back home" i18n:attributes="title">
+			<img class="logo"
+				 tal:define="src tales:absolute_url(settings.logo, '++thumb++200x200')"
+				 tal:attributes="src string:${src}?_=${tales:timestamp(logo)}" />
+		</a>
+	</tal:if>
+</tal:var>