work on sections

This commit is contained in:
bkfox 2015-10-04 22:05:10 +02:00
parent 60478aaf88
commit cfdc9b6de0
12 changed files with 372 additions and 211 deletions

View File

@ -1,10 +1,41 @@
body { padding: 0; margin: 0; } body {
padding: 0;
nav.menu_top { margin: 0;
width: 100%
position: absolute;
border-bottom: 1px grey solid;
} }
.page {
display: flex;
}
.page .menu {
width: 15em;
}
.page .menu_left { margin-right: 0.5em; }
.page .menu_right { margin-left: 0.5em; }
.page main {
flex-grow: 1;
}
main .section {
width: calc(50% - 1em);
float: left;
padding: 0.5em;
}
main .section .section_content {
font-size: 0.95em;
}
main .section h1 {
font-size: 1.2em;
}
main .section * {
max-width: 100%;
}

View File

@ -0,0 +1,9 @@
<{{ tag }} class="section {{ classes }}"
{% for key, value in attrs.items %}{{ key }} = "{{ value|addslashes }}"
{% endfor %} >
{% block content %}
{{ content|safe }}
{% endblock %}
</{{ tag }}>

View File

@ -8,22 +8,23 @@
<meta name="description" content="{{ website.description }}"> <meta name="description" content="{{ website.description }}">
<meta name="keywords" content="{{ website.tags }}"> <meta name="keywords" content="{{ website.tags }}">
<link rel="stylesheet" href="{% static "aircox_aircox_cms/styles.css" %}" type="text/css"> <link rel="stylesheet" href="{% static "aircox_cms/styles.css" %}" type="text/css">
{% if website.styles %}
<link rel="stylesheet" href="{% static website.styles %}" type="text/css">
{% endif %}
<title>{{ website.name }} {% if title %}- {{ title }} {% endif %}</title> <title>{{ website.name }} {% if title %}- {{ title }} {% endif %}</title>
</head> </head>
<body> <body>
{% block header %}
{% if menus.header %}
{{ menus.header|safe }}
{% endif %}
{% endblock %}
{% if menus.top %} {% if menus.top %}
{{ menus.top|safe }} {{ menus.top|safe }}
{% endif %} {% endif %}
{% block header %}
{% if menus.header %}
<header>
{{ menus.header|safe }}
</header>
{% endif %}
{% endblock %}
<div class="page"> <div class="page">
{% if menus.left %} {% if menus.left %}
{{ menus.left|safe }} {{ menus.left|safe }}
@ -50,11 +51,13 @@
{% endif %} {% endif %}
</div> </div>
{% if menus.page_bottom %}
{{ menus.page_bottom|safe }}
{% endif %}
{% block footer %} {% block footer %}
{% if menus.footer %} {% if menus.footer %}
<footer>
{{ menus.footer|safe }} {{ menus.footer|safe }}
</footer>
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@ -1,10 +1,10 @@
<nav class="menu menu_{{ position }} {{ classes }}" {% if name %} <{{ tag }} class="menu menu_{{ position }} {{ classes }}" {% if name %}
name="menu_{{ name }}" name="{{ name }}"
id="menu_{{ name }}" id="{{ name }}"
{% endif %}> {% endif %}>
{% for section in sections %} {% for section in sections %}
{{ section|safe }} {{ section|safe }}
{% endfor %} {% endfor %}
</nav> </{{ tag }}>

View File

@ -1,4 +1,6 @@
<div class="section {{ classes }}"> {% extends "aircox_cms/base_section.html" %}
{% block content %}
{% if title %} {% if title %}
<h1> <h1>
{% block section_title %} {% block section_title %}
@ -28,6 +30,5 @@
{% endblock %} {% endblock %}
</div> </div>
{% endif %} {% endif %}
</div> {% endblock %}

View File

@ -1,9 +1,14 @@
import re
from django.templatetags.static import static
from django.shortcuts import render from django.shortcuts import render
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.views.generic import ListView, DetailView from django.views.generic import ListView, DetailView
from django.views.generic.base import View, TemplateResponseMixin from django.views.generic.base import View, TemplateResponseMixin
from django.core import serializers from django.core import serializers
from django.utils.translation import ugettext as _, ugettext_lazy from django.utils.translation import ugettext as _, ugettext_lazy
from django.utils.html import escape
import aircox_cms.routes as routes import aircox_cms.routes as routes
@ -29,12 +34,8 @@ class PostBaseView:
context['menus'] = { context['menus'] = {
k: v.get(self.request) k: v.get(self.request)
for k, v in { for k, v in {
'top': self.website.get_menu('top'), k: self.website.get_menu(k)
'left': self.website.get_menu('left'), for k in self.website.menu_layouts
'bottom': self.website.get_menu('bottom'),
'right': self.website.get_menu('right'),
'header': self.website.get_menu('header'),
'footer': self.website.get_menu('footer'),
}.items() if v }.items() if v
} }
@ -162,46 +163,14 @@ class PostDetailView (DetailView, PostBaseView):
return context return context
class ViewSet:
"""
A ViewSet is a class helper that groups detail and list views that can be
used to generate views and routes given a model and a name used for the
routing.
"""
model = None
list_view = PostListView
list_routes = []
detail_view = PostDetailView
detail_sections = []
def __init__ (self, website = None):
self.detail_sections = [
section()
for section in self.detail_sections
]
self.detail_view = self.detail_view.as_view(
model = self.model,
sections = self.detail_sections,
website = website,
)
self.list_view = self.list_view.as_view(
model = self.model,
website = website,
)
self.urls = [ route.as_url(self.model, self.list_view)
for route in self.list_routes ] + \
[ routes.DetailRoute.as_url(self.model, self.detail_view ) ]
class Menu (View): class Menu (View):
template_name = 'aircox_cms/menu.html' template_name = 'aircox_cms/menu.html'
name = '' name = ''
tag = 'nav'
enabled = True enabled = True
classes = '' classes = ''
position = '' # top, left, bottom, right, header, footer position = '' # top, left, bottom, right, header, footer, page_top, page_bottom
sections = None sections = None
def __init__ (self, *args, **kwargs): def __init__ (self, *args, **kwargs):
@ -211,6 +180,7 @@ class Menu (View):
def get_context_data (self, **kwargs): def get_context_data (self, **kwargs):
return { return {
'name': self.name, 'name': self.name,
'tag': self.tag,
'classes': self.classes, 'classes': self.classes,
'position': self.position, 'position': self.position,
'sections': [ 'sections': [
@ -225,39 +195,84 @@ class Menu (View):
return render_to_string(self.template_name, context) return render_to_string(self.template_name, context)
class Section (View):
class BaseSection (View):
""" """
Base class for sections. Sections are view that can be used in detail view Base class for sections. Sections are view that can be used in detail view
in order to have extra content about a post. in order to have extra content about a post, or in menus.
""" """
template_name = 'aircox_cms/section.html' template_name = 'aircox_cms/base_section.html'
require_object = False tag = 'div' # container tags
object = None classes = '' # container classes
classes = '' attrs = '' # container extra attributes
title = '' content = '' # content
content = ''
header = ''
bottom = ''
def get_context_data (self, **kwargs): def get_context_data (self, **kwargs):
context = { return {
'title': self.title, 'tag': self.tag,
'header': self.header,
'content': self.content,
'bottom': self.bottom,
'classes': self.classes, 'classes': self.classes,
'attrs': self.attrs,
'content': self.content,
} }
return context
def get (self, request, **kwargs): def get (self, request, **kwargs):
self.object = kwargs.get('object') or self.object
self.request = request self.request = request
context = self.get_context_data(**kwargs) context = self.get_context_data(**kwargs)
return render_to_string(self.template_name, context) return render_to_string(self.template_name, context)
class Section (BaseSection):
template_name = 'aircox_cms/section.html'
require_object = False
object = None
title = ''
header = ''
bottom = ''
class ListSection (Section): def get_context_data (self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({
'title': self.title,
'header': self.header,
'bottom': self.bottom,
})
return context
def get (self, request, **kwargs):
self.object = kwargs.get('object') or self.object
return super().get(request, **kwargs)
class Sections:
class Image (BaseSection):
url = None # relative url to the image
@property
def content (self):
return '<img src="{}">'.format(
static(self.url),
)
class PostContent (Section):
@property
def content (self):
content = escape(self.object.content)
content = re.sub(r'(^|\n\n)((\n?[^\n])+)', r'<p>\2</p>', content)
content = re.sub(r'\n', r'<br>', content)
return content
class PostImage (Section):
@property
def content (self):
return '<img src="{}" class="post_image">'.format(
self.object.image.url
)
class List (Section):
""" """
Section to render list. The context item 'object_list' is used as list of Section to render list. The context item 'object_list' is used as list of
items to render. items to render.
@ -289,13 +304,13 @@ class ListSection (Section):
return context return context
class UrlListSection (ListSection): class UrlList (List):
classes = 'section_urls' classes = 'section_urls'
targets = None targets = None
def get_object_list (self, request, **kwargs): def get_object_list (self, request, **kwargs):
return [ return [
ListSection.Item( List.Item(
target.image or None, target.image or None,
'<a href="{}">{}</a>'.format(target.detail_url(), target.title) '<a href="{}">{}</a>'.format(target.detail_url(), target.title)
) )
@ -303,7 +318,7 @@ class UrlListSection (ListSection):
] ]
class PostListSection (PostListView): class PostList (PostListView):
route = None route = None
model = None model = None
embed = True embed = True
@ -319,7 +334,41 @@ class PostListSection (PostListView):
response = super().dispatch(request, *args, **kwargs) response = super().dispatch(request, *args, **kwargs)
return str(response.content) return str(response.content)
# TODO:
# - get_title: pass object / queryset
class ViewSet:
"""
A ViewSet is a class helper that groups detail and list views that can be
used to generate views and routes given a model and a name used for the
routing.
"""
model = None
list_view = PostListView
list_routes = []
detail_view = PostDetailView
detail_sections = [
Sections.PostContent,
Sections.PostImage,
]
def __init__ (self, website = None):
self.detail_sections = [
section()
for section in self.detail_sections
]
self.detail_view = self.detail_view.as_view(
model = self.model,
sections = self.detail_sections,
website = website,
)
self.list_view = self.list_view.as_view(
model = self.model,
website = website,
)
self.urls = [ route.as_url(self.model, self.list_view)
for route in self.list_routes ] + \
[ routes.DetailRoute.as_url(self.model, self.detail_view ) ]

View File

@ -6,38 +6,46 @@ class Website:
description = 'An aircox website' # public description (used in meta info) description = 'An aircox website' # public description (used in meta info)
tags = 'aircox,radio,music' # public keywords (used in meta info) tags = 'aircox,radio,music' # public keywords (used in meta info)
logo = None styles = '' # relative url to stylesheet file
menus = None menus = None # list of menus
menu_layouts = ['top', 'left', # available positions
'right', 'bottom',
'header', 'footer']
router = None router = None
@property
def urls (self):
return self.router.get_urlpatterns()
def __init__ (self, **kwargs): def __init__ (self, **kwargs):
self.__dict__.update(kwargs) self.__dict__.update(kwargs)
if not self.router: if not self.router:
self.router = routes.Router() self.router = routes.Router()
def register_set (self, view_set): def register_set (self, view_set):
"""
Register a ViewSet (or subclass) to the router,
and connect it to self.
"""
view_set = view_set(website = self) view_set = view_set(website = self)
self.router.register_set(view_set) self.router.register_set(view_set)
def get_menu (self, position): def get_menu (self, position):
"""
Get an enabled menu by its position
"""
for menu in self.menus: for menu in self.menus:
if menu.enabled and menu.position == position: if menu.enabled and menu.position == position:
self.check_menu_tag(menu)
return menu return menu
def get_top_menu (self): def check_menu_tag (self, menu):
return self.get_menu('top') """
Update menu tag if it is a footer or a header
def get_left_menu (self): """
return self.get_menu('left') if menu.position in ('footer','header'):
menu.tag = menu.position
def get_bottom_menu (self): if menu.position in ('left', 'right'):
return self.get_menu('bottom') menu.tag = 'side'
def get_right_menu (self):
return self.get_menu('right')
@property
def urls (self):
return self.router.get_urlpatterns()

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@ -0,0 +1,44 @@
body {
background-color: #F2F2F2;
font-family: "Myriad Pro",Calibri,Helvetica,Arial,sans-serif;
}
h1, h2, h3 {
font-family: "Myriad Pro",Calibri,Helvetica,Arial,sans-serif
}
nav.menu {
padding: 0.5em;
}
nav.menu_top {
background-color: #212121;
color: #007EDF;
font-size: 1.1em;
}
header {
height: 9em;
}
header img {
height: 100%;
float: left;
}
header .colony {
position: fixed;
top: 0em;
right: 0;
z-index: -1;
}
.page {
width: 100%;
background-color: rgba(255, 255, 255, 0.8);
}

View File

@ -4,7 +4,7 @@ from website.models import *
from website.views import * from website.views import *
from aircox_cms.models import Article from aircox_cms.models import Article
from aircox_cms.views import ViewSet, Menu, Section from aircox_cms.views import Menu, Section, Sections, ViewSet
from aircox_cms.routes import * from aircox_cms.routes import *
from aircox_cms.website import Website from aircox_cms.website import Website
@ -17,8 +17,8 @@ class ProgramSet (ViewSet):
DateRoute, DateRoute,
] ]
detail_sections = [ detail_sections = ViewSet.detail_sections + [
ScheduleSection ScheduleSection,
] ]
class EpisodeSet (ViewSet): class EpisodeSet (ViewSet):
@ -42,17 +42,33 @@ class ArticleSet (ViewSet):
website = Website( website = Website(
name = 'RadioCampus', name = 'RadioCampus',
styles = 'website/styles.css',
menus = [ menus = [
Menu(
position = 'header',
sections = [
Sections.Image(url = 'website/logo.png'),
Sections.Image(url = 'website/colony.png', classes='colony'),
]
),
Menu( Menu(
position = 'top', position = 'top',
sections = [ sections = [
Section(content = "Radio Campus le SITE") Section(content = "Radio Campus le SITE")
] ]
) ),
Menu(
position = 'left',
sections = [
Section(content = 'loool<br>blob')
],
),
], ],
) )
website.register_set(ProgramSet) website.register_set(ProgramSet)
website.register_set(EpisodeSet) website.register_set(EpisodeSet)
website.register_set(ArticleSet) website.register_set(ArticleSet)

View File

@ -6,21 +6,21 @@ from django.core import serializers
from django.utils.translation import ugettext as _, ugettext_lazy from django.utils.translation import ugettext as _, ugettext_lazy
import aircox_programs.models as programs import aircox_programs.models as programs
from aircox_cms.views import ListSection from aircox_cms.views import Sections
class PlaylistSection (ListSection): class PlayListSection (Sections.List):
title = _('Playlist') title = _('Playlist')
def get_object_list (self): def get_object_list (self):
tracks = programs.Track.objects \ tracks = programs.Track.objects \
.filter(episode = self.object) \ .filter(episode = self.object) \
.order_by('position') .order_by('position')
return [ ListSection.Item(None, track.title, track.artist) return [ Sections.List.Item(None, track.title, track.artist)
for track in tracks ] for track in tracks ]
class ScheduleSection (ListSection): class ScheduleSection (Sections.List):
title = _('Schedule') title = _('Schedule')
def get_object_list (self): def get_object_list (self):
@ -28,7 +28,7 @@ class ScheduleSection (ListSection):
.filter(program = self.object.pk) .filter(program = self.object.pk)
return [ return [
ListSection.Item(None, sched.get_frequency_display(), Sections.List.Item(None, sched.get_frequency_display(),
_('rerun') if sched.rerun else None) _('rerun') if sched.rerun else None)
for sched in scheds for sched in scheds
] ]