Browse Source

- Fancy rank styles
- "Team Online" replaced with more versalite solution
- Board Index template updated
- Mark all forums read button added
- Updated ranks fixture

Ralfp 12 years ago
parent
commit
f585a4157f

+ 2 - 1
misago/authn/decorators.py

@@ -1,10 +1,10 @@
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
-from misago.views import error403
 
 
 def block_authenticated(f):
 def block_authenticated(f):
     def decorator(*args, **kwargs):
     def decorator(*args, **kwargs):
         request = args[0]
         request = args[0]
         if not request.firewall.admin and request.user.is_authenticated():
         if not request.firewall.admin and request.user.is_authenticated():
+            from misago.views import error403
             return error403(request, _("%(username)s, this page is not available to signed in users.") % {'username': request.user.username})
             return error403(request, _("%(username)s, this page is not available to signed in users.") % {'username': request.user.username})
         return f(*args, **kwargs)
         return f(*args, **kwargs)
     return decorator
     return decorator
@@ -14,6 +14,7 @@ def block_guest(f):
     def decorator(*args, **kwargs):
     def decorator(*args, **kwargs):
         request = args[0]
         request = args[0]
         if not request.user.is_authenticated():
         if not request.user.is_authenticated():
+            from misago.views import error403
             return error403(request, _("Dear Guest, only signed in members are allowed to access this page. Please sign in or register and try again."))
             return error403(request, _("Dear Guest, only signed in members are allowed to access this page. Please sign in or register and try again."))
         return f(*args, **kwargs)
         return f(*args, **kwargs)
     return decorator
     return decorator

+ 1 - 1
misago/csrf/decorators.py

@@ -1,10 +1,10 @@
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
-from misago.views import error403
 
 
 def check_csrf(f):
 def check_csrf(f):
     def decorator(*args, **kwargs):
     def decorator(*args, **kwargs):
         request = args[0]
         request = args[0]
         if not request.csrf.request_secure(request):
         if not request.csrf.request_secure(request):
+            from misago.views import error403
             return error403(request, _("Request authorization is invalid. Please try again."))
             return error403(request, _("Request authorization is invalid. Please try again."))
         return f(*args, **kwargs)
         return f(*args, **kwargs)
     return decorator
     return decorator

+ 35 - 34
misago/ranks/fixtures.py

@@ -3,41 +3,42 @@ from misago.utils import ugettext_lazy as _
 from misago.utils import get_msgid
 from misago.utils import get_msgid
 
 
 def load_fixtures():
 def load_fixtures():
-    Rank.create(
+    Rank.objects.create(
-                name=_("Forum Team").message,
+                        name=_("Forum Team").message,
-                name_slug='forum_team',
+                        name_slug='forum_team',
-                title=_("Forum Team").message,
+                        title=_("Forum Team").message,
-                style='rank-team',
+                        style='rank-team',
-                special=True,
+                        special=True,
-                order=0,
+                        order=0,
-                as_tab=True,
+                        as_tab=True,
-                )
+                        on_index=True,
+                        )
     
     
-    Rank.create(
+    Rank.objects.create(
-                name=_("Most Valueable Posters").message,
+                        name=_("Most Valueable Posters").message,
-                title=_("MVP").message,
+                        title=_("MVP").message,
-                style='rank-mpv',
+                        style='rank-mvp',
-                special=True,
+                        special=True,
-                order=1,
+                        order=1,
-                as_tab=True,
+                        as_tab=True,
-                )
+                        )
     
     
-    Rank.create(
+    Rank.objects.create(
-                name=_("Lurkers").message,
+                        name=_("Lurkers").message,
-                order=1,
+                        order=1,
-                criteria="100%"
+                        criteria="100%"
-                )
+                        )
     
     
-    Rank.create(
+    Rank.objects.create(
-                name=_("Members").message,
+                        name=_("Members").message,
-                order=2,
+                        order=2,
-                criteria="75%"
+                        criteria="75%"
-                )
+                        )
     
     
-    Rank.create(
+    Rank.objects.create(
-                name=_("Active Members").message,
+                        name=_("Active Members").message,
-                style='rank-active',
+                        style='rank-active',
-                order=3,
+                        order=3,
-                criteria="10%",
+                        criteria="10%",
-                as_tab=True,
+                        as_tab=True,
-                )
+                        )

+ 3 - 1
misago/ranks/forms.py

@@ -14,6 +14,7 @@ class RankForm(Form):
     style = forms.CharField(max_length=255,required=False)
     style = forms.CharField(max_length=255,required=False)
     special = forms.BooleanField(widget=YesNoSwitch,required=False)
     special = forms.BooleanField(widget=YesNoSwitch,required=False)
     as_tab = forms.BooleanField(widget=YesNoSwitch,required=False)
     as_tab = forms.BooleanField(widget=YesNoSwitch,required=False)
+    on_index = forms.BooleanField(widget=YesNoSwitch,required=False)
     criteria = forms.CharField(max_length=255,initial='0',validators=[RegexValidator(regex='^(\d+)(%?)$',message=_('This is incorrect rank match rule.'))],required=False)
     criteria = forms.CharField(max_length=255,initial='0',validators=[RegexValidator(regex='^(\d+)(%?)$',message=_('This is incorrect rank match rule.'))],required=False)
     
     
     layout = (
     layout = (
@@ -22,7 +23,8 @@ class RankForm(Form):
                (
                (
                 ('name', {'label': _("Rank Name"), 'help_text': _("Rank Name is used to identify rank in Admin Control Panel and is used as page and tab title if you decide to make this rank act as tab on users list.")}),
                 ('name', {'label': _("Rank Name"), 'help_text': _("Rank Name is used to identify rank in Admin Control Panel and is used as page and tab title if you decide to make this rank act as tab on users list.")}),
                 ('description', {'label': _("Rank Description"), 'help_text': _("If this rank acts as tab on users list, here you can enter optional description that will be displayed above list of users with this rank.")}),
                 ('description', {'label': _("Rank Description"), 'help_text': _("If this rank acts as tab on users list, here you can enter optional description that will be displayed above list of users with this rank.")}),
-                ('as_tab', {'label': _("As Tab"), 'help_text': _("Should this rank have its own page on users list, containing rank's description and list of users that have it? This is good option for rank used by forum team members or members that should be visible and easily reachable.")}),
+                ('as_tab', {'label': _("As Tab on Users List"), 'help_text': _("Should this rank have its own page on users list, containing rank's description and list of users that have it? This is good option for rank used by forum team members or members that should be visible and easily reachable.")}),
+                ('on_index', {'label': _("Display members online"), 'help_text': _("Should users online with this rank be displayed on board index?")}),
                )
                )
               ),
               ),
               (
               (

+ 1 - 0
misago/ranks/models.py

@@ -14,6 +14,7 @@ class Rank(models.Model):
     title = models.CharField(max_length=255,null=True,blank=True)
     title = models.CharField(max_length=255,null=True,blank=True)
     special = models.BooleanField(default=False)
     special = models.BooleanField(default=False)
     as_tab = models.BooleanField(default=False)
     as_tab = models.BooleanField(default=False)
+    on_index = models.BooleanField(default=False)
     order = models.IntegerField(default=0)
     order = models.IntegerField(default=0)
     criteria = models.CharField(max_length=255,null=True,blank=True)
     criteria = models.CharField(max_length=255,null=True,blank=True)
     
     

+ 3 - 0
misago/ranks/views.py

@@ -89,6 +89,7 @@ class New(FormWidget):
                       title = form.cleaned_data['title'],
                       title = form.cleaned_data['title'],
                       special = form.cleaned_data['special'],
                       special = form.cleaned_data['special'],
                       as_tab = form.cleaned_data['as_tab'],
                       as_tab = form.cleaned_data['as_tab'],
+                      on_index = form.cleaned_data['on_index'],
                       order = (last_rank.order + 1 if last_rank else 0),
                       order = (last_rank.order + 1 if last_rank else 0),
                       criteria = form.cleaned_data['criteria']
                       criteria = form.cleaned_data['criteria']
                      )
                      )
@@ -120,6 +121,7 @@ class Edit(FormWidget):
                 'title': model.title,
                 'title': model.title,
                 'special': model.special,
                 'special': model.special,
                 'as_tab': model.as_tab,
                 'as_tab': model.as_tab,
+                'on_index': model.on_index,
                 'criteria': model.criteria
                 'criteria': model.criteria
                 }
                 }
     
     
@@ -131,6 +133,7 @@ class Edit(FormWidget):
         target.title = form.cleaned_data['title']
         target.title = form.cleaned_data['title']
         target.special = form.cleaned_data['special']
         target.special = form.cleaned_data['special']
         target.as_tab = form.cleaned_data['as_tab']
         target.as_tab = form.cleaned_data['as_tab']
+        target.on_index = form.cleaned_data['on_index']
         target.criteria = form.cleaned_data['criteria']
         target.criteria = form.cleaned_data['criteria']
         target.save(force_update=True)
         target.save(force_update=True)
         return target, Message(_('Changes in rank "%(name)s" have been saved.') % {'name': self.original_name}, 'success')
         return target, Message(_('Changes in rank "%(name)s" have been saved.') % {'name': self.original_name}, 'success')

+ 1 - 0
misago/sessions/models.py

@@ -10,6 +10,7 @@ class Session(models.Model):
     start = models.DateTimeField()
     start = models.DateTimeField()
     last = models.DateTimeField()
     last = models.DateTimeField()
     team = models.BooleanField(default=False)
     team = models.BooleanField(default=False)
+    rank = models.ForeignKey('ranks.Rank', related_name='sessions', null=True, on_delete=models.SET_NULL)
     admin = models.BooleanField(default=False)
     admin = models.BooleanField(default=False)
     matched = models.BooleanField(default=False)
     matched = models.BooleanField(default=False)
     hidden = models.BooleanField(default=False)
     hidden = models.BooleanField(default=False)

+ 2 - 0
misago/sessions/sessions.py

@@ -119,6 +119,7 @@ class SessionHuman(SessionMisago):
         self.expired = False
         self.expired = False
         self.hidden = False
         self.hidden = False
         self.team = False
         self.team = False
+        self.rank = None
         self.remember_me = None
         self.remember_me = None
         self._user = None
         self._user = None
         self._ip = self.get_ip(request)
         self._ip = self.get_ip(request)
@@ -197,6 +198,7 @@ class SessionHuman(SessionMisago):
         self._session_rk.user = self._user
         self._session_rk.user = self._user
         self._session_rk.hidden = self.hidden
         self._session_rk.hidden = self.hidden
         self._session_rk.team = self.team
         self._session_rk.team = self.team
+        self._session_rk.rank_id = self.rank
         super(SessionHuman, self).save()
         super(SessionHuman, self).save()
         
         
     def human_session(self):
     def human_session(self):

+ 1 - 0
misago/urls.py

@@ -16,6 +16,7 @@ urlpatterns = patterns('',
     url(r'^redirect/(?P<slug>(\w|-)+)-(?P<forum>\d+)/$', 'misago.views.redirection', name="redirect"),
     url(r'^redirect/(?P<slug>(\w|-)+)-(?P<forum>\d+)/$', 'misago.views.redirection', name="redirect"),
     url(r'^markdown/preview/$', 'misago.markdown.views.preview', name="md_preview"),
     url(r'^markdown/preview/$', 'misago.markdown.views.preview', name="md_preview"),
     url(r'^$', 'misago.views.home', name="index"),
     url(r'^$', 'misago.views.home', name="index"),
+    url(r'^read/$', 'misago.views.read_all', name="read_all"),
 )
 )
 
 
 # Include admin patterns
 # Include admin patterns

+ 5 - 3
misago/users/middleware.py

@@ -15,12 +15,14 @@ def set_timezone(new_tz):
 class UserMiddleware(object):
 class UserMiddleware(object):
     def process_request(self, request):
     def process_request(self, request):
         if request.user.is_authenticated():
         if request.user.is_authenticated():
-            # Set user timezone
+            # Set user timezone and rank
+            request.session.rank = request.user.rank_id
             set_timezone(request.user.timezone)
             set_timezone(request.user.timezone)
             
             
             # Display "welcome back!" message
             # Display "welcome back!" message
             if request.session.remember_me:
             if request.session.remember_me:
                 request.messages.set_message(_("Welcome back, %(username)s! We've signed you in automatically for your convenience.") % {'username': request.user.username}, 'info')
                 request.messages.set_message(_("Welcome back, %(username)s! We've signed you in automatically for your convenience.") % {'username': request.user.username}, 'info')
         else:
         else:
-            # Set guest's timezone
+            # Set guest's timezone and empty rank
-            set_timezone(request.settings['default_timezone'])
+            set_timezone(request.settings['default_timezone'])
+            request.session.rank = None

+ 46 - 9
misago/views.py

@@ -2,9 +2,15 @@ from django.core.cache import cache
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.template import RequestContext
 from django.template import RequestContext
+from django.utils import timezone
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
+from misago.authn.decorators import block_guest
+from misago.csrf.decorators import check_csrf
 from misago.forums.models import Forum
 from misago.forums.models import Forum
+from misago.messages import Message
+from misago.readstracker.models import Record
 from misago.readstracker.trackers import ForumsTracker
 from misago.readstracker.trackers import ForumsTracker
+from misago.ranks.models import Rank
 from misago.sessions.models import Session
 from misago.sessions.models import Session
 from misago.threads.models import Thread
 from misago.threads.models import Thread
 
 
@@ -14,21 +20,36 @@ def home(request):
     if popular_threads == 'nada' and request.settings['thread_ranking_size'] > 0:
     if popular_threads == 'nada' and request.settings['thread_ranking_size'] > 0:
         popular_threads = []
         popular_threads = []
         for thread in Thread.objects.filter(moderated=False).filter(deleted=False).filter(forum__in=request.acl.threads.get_readable_forums(request.acl)).prefetch_related('forum').order_by('-score')[:request.settings['thread_ranking_size']]:
         for thread in Thread.objects.filter(moderated=False).filter(deleted=False).filter(forum__in=request.acl.threads.get_readable_forums(request.acl)).prefetch_related('forum').order_by('-score')[:request.settings['thread_ranking_size']]:
+            thread.forum_name = thread.forum.name
+            thread.forum_slug = thread.forum.slug
             popular_threads.append(thread)
             popular_threads.append(thread)
-        cache.set('thread_ranking_%s' % request.user.make_acl_key(), popular_threads, request.settings['thread_ranking_refresh'])  
+        cache.set('thread_ranking_%s' % request.user.make_acl_key(), popular_threads, request.settings['thread_ranking_refresh'])
-    # Team online
+          
-    team_online = []
+    # Ranks online
-    team_pks = []
+    ranks_list = cache.get('users_online', 'nada')
-    for session in Session.objects.filter(team=1).filter(admin=0).filter(user__isnull=False).order_by('-start').select_related('user', 'user__rank'):
+    if ranks_list == 'nada':
-        if session.user.pk not in team_pks:
+        ranks_dict = {}
-            team_pks.append(session.user.pk)
+        ranks_list = []
-            team_online.append(session.user)
+        users_list = []
+        for rank in Rank.objects.filter(on_index=True).order_by('order'):
+            rank_entry = {'name': rank.name, 'style': rank.style, 'title': rank.title, 'online': []}
+            ranks_list.append(rank_entry)
+            ranks_dict[rank.pk] = rank_entry
+        if ranks_dict:
+            for session in Session.objects.select_related('user').filter(rank__in=ranks_dict.keys()).filter(user__isnull=False):
+                if not session.user_id in users_list:
+                    ranks_dict[session.user.rank_id]['online'].append(session.user)
+                    users_list.append(session.user_id)
+            del ranks_dict
+            del users_list
+        cache.set('ranks_list', ranks_list, 15)
+            
     # Render page with forums list
     # Render page with forums list
     reads_tracker = ForumsTracker(request.user)
     reads_tracker = ForumsTracker(request.user)
     return request.theme.render_to_response('index.html',
     return request.theme.render_to_response('index.html',
                                             {
                                             {
                                              'forums_list': Forum.objects.treelist(request.acl.forums, tracker=reads_tracker),
                                              'forums_list': Forum.objects.treelist(request.acl.forums, tracker=reads_tracker),
-                                             'team_online': team_online,
+                                             'ranks_online': ranks_list,
                                              'popular_threads': popular_threads,
                                              'popular_threads': popular_threads,
                                              },
                                              },
                                             context_instance=RequestContext(request));
                                             context_instance=RequestContext(request));
@@ -68,6 +89,22 @@ def redirection(request, forum, slug):
         return error404(request)
         return error404(request)
 
 
 
 
+@block_guest
+@check_csrf
+def read_all(request):
+    Record.objects.filter(user=request.user).delete()
+    now = timezone.now()
+    bulk = []
+    for forum in request.acl.forums.known_forums():
+        new_record = Record(user=request.user, forum_id=forum, updated=now, cleared=now)
+        new_record.set_threads({})
+        bulk.append(new_record)
+    if bulk:
+        Record.objects.bulk_create(bulk)
+    request.messages.set_flash(Message(_("All forums have been marked as read.")), 'success')
+    return redirect(reverse('index'))
+
+
 def redirect_message(request, message, type='info', owner=None):
 def redirect_message(request, message, type='info', owner=None):
     request.messages.set_flash(message, type, owner)
     request.messages.set_flash(message, type, owner)
     return redirect(reverse('index'))
     return redirect(reverse('index'))

+ 71 - 0
static/sora/css/ranks.less

@@ -0,0 +1,71 @@
+// Ranks styles
+// -------------------------
+
+// .rank-team
+.well-post.rank-team {
+  border: 1px solid lighten(@linkColor, 5%);
+  .box-shadow(0px 0px 0px 3px lighten(@linkColor, 30%));
+}
+
+.team-online.rank-team ul {
+  li {
+    background-color: @linkColor;
+     
+    div {
+      a {
+        color: @white;
+        text-shadow: 0px 1px 0px darken(@blue, 40%);
+      }
+      
+      .muted {
+        color: darken(@blue, 25%);
+      }
+    }
+  }
+}
+
+// .rank-mvp
+.well-post.rank-mvp {
+  border: 1px solid lighten(@purple, 5%);
+  .box-shadow(0px 0px 0px 3px lighten(@purple, 30%));
+}
+
+.team-online.rank-mvp ul {
+  li {
+    background-color: lighten(@purple, 10%);
+     
+    div {
+      a {
+        color: @white;
+        text-shadow: 0px 1px 0px darken(@purple, 40%);
+      }
+      
+      .muted {
+        color: darken(@purple, 25%);
+      }
+    }
+  }
+}
+
+// .rank-active
+.well-post.rank-active {
+  border: 1px solid lighten(@orange, 5%);
+  .box-shadow(0px 0px 0px 3px lighten(@orange, 30%));
+}
+
+.team-online.rank-active ul {
+  li {
+    background-color: @orange;
+     
+    div {
+      a {
+        color: @white;
+        text-shadow: 0px 1px 0px darken(@orange, 40%);
+      }
+      
+      .muted {
+        color: darken(@orange, 25%);
+      }
+    }
+  }
+}

+ 22 - 4
static/sora/css/sora.css

@@ -826,9 +826,9 @@ a.label:hover,a.badge:hover{color:#ffffff;text-decoration:none;cursor:pointer;}
 .invisible{visibility:hidden;}
 .invisible{visibility:hidden;}
 .affix{position:fixed;}
 .affix{position:fixed;}
 @media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} .row:after{clear:both;} [class*="span"]{float:left;min-height:1px;margin-left:20px;} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px;} .span12{width:724px;} .span11{width:662px;} .span10{width:600px;} .span9{width:538px;} .span8{width:476px;} .span7{width:414px;} .span6{width:352px;} .span5{width:290px;} .span4{width:228px;} .span3{width:166px;} .span2{width:104px;} .span1{width:42px;} .offset12{margin-left:764px;} .offset11{margin-left:702px;} .offset10{margin-left:640px;} .offset9{margin-left:578px;} .offset8{margin-left:516px;} .offset7{margin-left:454px;} .offset6{margin-left:392px;} .offset5{margin-left:330px;} .offset4{margin-left:268px;} .offset3{margin-left:206px;} .offset2{margin-left:144px;} .offset1{margin-left:82px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} .row-fluid:after{clear:both;} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;} .row-fluid [class*="span"]:first-child{margin-left:0;} .row-fluid .span12{width:100%;*width:99.94680851063829%;} .row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%;} .row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%;} .row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%;} .row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%;} .row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%;} .row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%;} .row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%;} .row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%;} .row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%;} .row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%;} .row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%;} .row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%;} .row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%;} .row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%;} .row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%;} .row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%;} .row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%;} .row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%;} .row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%;} .row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%;} .row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%;} .row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%;} .row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%;} .row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%;} .row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%;} .row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%;} .row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%;} .row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%;} .row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%;} .row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%;} .row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%;} .row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%;} .row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%;} .row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%;} .row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%;} input,textarea,.uneditable-input{margin-left:0;} .controls-row [class*="span"]+[class*="span"]{margin-left:20px;} input.span12, textarea.span12, .uneditable-input.span12{width:710px;} input.span11, textarea.span11, .uneditable-input.span11{width:648px;} input.span10, textarea.span10, .uneditable-input.span10{width:586px;} input.span9, textarea.span9, .uneditable-input.span9{width:524px;} input.span8, textarea.span8, .uneditable-input.span8{width:462px;} input.span7, textarea.span7, .uneditable-input.span7{width:400px;} input.span6, textarea.span6, .uneditable-input.span6{width:338px;} input.span5, textarea.span5, .uneditable-input.span5{width:276px;} input.span4, textarea.span4, .uneditable-input.span4{width:214px;} input.span3, textarea.span3, .uneditable-input.span3{width:152px;} input.span2, textarea.span2, .uneditable-input.span2{width:90px;} input.span1, textarea.span1, .uneditable-input.span1{width:28px;}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} .row:after{clear:both;} [class*="span"]{float:left;min-height:1px;margin-left:30px;} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px;} .span12{width:1170px;} .span11{width:1070px;} .span10{width:970px;} .span9{width:870px;} .span8{width:770px;} .span7{width:670px;} .span6{width:570px;} .span5{width:470px;} .span4{width:370px;} .span3{width:270px;} .span2{width:170px;} .span1{width:70px;} .offset12{margin-left:1230px;} .offset11{margin-left:1130px;} .offset10{margin-left:1030px;} .offset9{margin-left:930px;} .offset8{margin-left:830px;} .offset7{margin-left:730px;} .offset6{margin-left:630px;} .offset5{margin-left:530px;} .offset4{margin-left:430px;} .offset3{margin-left:330px;} .offset2{margin-left:230px;} .offset1{margin-left:130px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} .row-fluid:after{clear:both;} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;} .row-fluid [class*="span"]:first-child{margin-left:0;} .row-fluid .span12{width:100%;*width:99.94680851063829%;} .row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%;} .row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%;} .row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%;} .row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%;} .row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%;} .row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%;} .row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%;} .row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%;} .row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%;} .row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%;} .row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%;} .row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%;} .row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%;} .row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%;} .row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%;} .row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%;} .row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%;} .row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%;} .row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%;} .row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%;} .row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%;} .row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%;} .row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%;} .row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%;} .row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%;} .row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%;} .row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%;} .row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%;} .row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%;} .row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%;} .row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%;} .row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%;} .row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%;} .row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%;} .row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%;} input,textarea,.uneditable-input{margin-left:0;} .controls-row [class*="span"]+[class*="span"]{margin-left:30px;} input.span12, textarea.span12, .uneditable-input.span12{width:1156px;} input.span11, textarea.span11, .uneditable-input.span11{width:1056px;} input.span10, textarea.span10, .uneditable-input.span10{width:956px;} input.span9, textarea.span9, .uneditable-input.span9{width:856px;} input.span8, textarea.span8, .uneditable-input.span8{width:756px;} input.span7, textarea.span7, .uneditable-input.span7{width:656px;} input.span6, textarea.span6, .uneditable-input.span6{width:556px;} input.span5, textarea.span5, .uneditable-input.span5{width:456px;} input.span4, textarea.span4, .uneditable-input.span4{width:356px;} input.span3, textarea.span3, .uneditable-input.span3{width:256px;} input.span2, textarea.span2, .uneditable-input.span2{width:156px;} input.span1, textarea.span1, .uneditable-input.span1{width:56px;} .thumbnails{margin-left:-30px;} .thumbnails>li{margin-left:30px;} .row-fluid .thumbnails{margin-left:0;}}.breadcrumb .active{color:#333333;}
 @media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} .row:after{clear:both;} [class*="span"]{float:left;min-height:1px;margin-left:20px;} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px;} .span12{width:724px;} .span11{width:662px;} .span10{width:600px;} .span9{width:538px;} .span8{width:476px;} .span7{width:414px;} .span6{width:352px;} .span5{width:290px;} .span4{width:228px;} .span3{width:166px;} .span2{width:104px;} .span1{width:42px;} .offset12{margin-left:764px;} .offset11{margin-left:702px;} .offset10{margin-left:640px;} .offset9{margin-left:578px;} .offset8{margin-left:516px;} .offset7{margin-left:454px;} .offset6{margin-left:392px;} .offset5{margin-left:330px;} .offset4{margin-left:268px;} .offset3{margin-left:206px;} .offset2{margin-left:144px;} .offset1{margin-left:82px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} .row-fluid:after{clear:both;} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;} .row-fluid [class*="span"]:first-child{margin-left:0;} .row-fluid .span12{width:100%;*width:99.94680851063829%;} .row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%;} .row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%;} .row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%;} .row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%;} .row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%;} .row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%;} .row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%;} .row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%;} .row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%;} .row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%;} .row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%;} .row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%;} .row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%;} .row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%;} .row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%;} .row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%;} .row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%;} .row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%;} .row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%;} .row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%;} .row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%;} .row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%;} .row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%;} .row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%;} .row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%;} .row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%;} .row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%;} .row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%;} .row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%;} .row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%;} .row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%;} .row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%;} .row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%;} .row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%;} .row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%;} input,textarea,.uneditable-input{margin-left:0;} .controls-row [class*="span"]+[class*="span"]{margin-left:20px;} input.span12, textarea.span12, .uneditable-input.span12{width:710px;} input.span11, textarea.span11, .uneditable-input.span11{width:648px;} input.span10, textarea.span10, .uneditable-input.span10{width:586px;} input.span9, textarea.span9, .uneditable-input.span9{width:524px;} input.span8, textarea.span8, .uneditable-input.span8{width:462px;} input.span7, textarea.span7, .uneditable-input.span7{width:400px;} input.span6, textarea.span6, .uneditable-input.span6{width:338px;} input.span5, textarea.span5, .uneditable-input.span5{width:276px;} input.span4, textarea.span4, .uneditable-input.span4{width:214px;} input.span3, textarea.span3, .uneditable-input.span3{width:152px;} input.span2, textarea.span2, .uneditable-input.span2{width:90px;} input.span1, textarea.span1, .uneditable-input.span1{width:28px;}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} .row:after{clear:both;} [class*="span"]{float:left;min-height:1px;margin-left:30px;} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px;} .span12{width:1170px;} .span11{width:1070px;} .span10{width:970px;} .span9{width:870px;} .span8{width:770px;} .span7{width:670px;} .span6{width:570px;} .span5{width:470px;} .span4{width:370px;} .span3{width:270px;} .span2{width:170px;} .span1{width:70px;} .offset12{margin-left:1230px;} .offset11{margin-left:1130px;} .offset10{margin-left:1030px;} .offset9{margin-left:930px;} .offset8{margin-left:830px;} .offset7{margin-left:730px;} .offset6{margin-left:630px;} .offset5{margin-left:530px;} .offset4{margin-left:430px;} .offset3{margin-left:330px;} .offset2{margin-left:230px;} .offset1{margin-left:130px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} .row-fluid:after{clear:both;} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;} .row-fluid [class*="span"]:first-child{margin-left:0;} .row-fluid .span12{width:100%;*width:99.94680851063829%;} .row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%;} .row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%;} .row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%;} .row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%;} .row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%;} .row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%;} .row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%;} .row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%;} .row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%;} .row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%;} .row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%;} .row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%;} .row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%;} .row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%;} .row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%;} .row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%;} .row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%;} .row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%;} .row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%;} .row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%;} .row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%;} .row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%;} .row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%;} .row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%;} .row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%;} .row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%;} .row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%;} .row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%;} .row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%;} .row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%;} .row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%;} .row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%;} .row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%;} .row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%;} .row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%;} input,textarea,.uneditable-input{margin-left:0;} .controls-row [class*="span"]+[class*="span"]{margin-left:30px;} input.span12, textarea.span12, .uneditable-input.span12{width:1156px;} input.span11, textarea.span11, .uneditable-input.span11{width:1056px;} input.span10, textarea.span10, .uneditable-input.span10{width:956px;} input.span9, textarea.span9, .uneditable-input.span9{width:856px;} input.span8, textarea.span8, .uneditable-input.span8{width:756px;} input.span7, textarea.span7, .uneditable-input.span7{width:656px;} input.span6, textarea.span6, .uneditable-input.span6{width:556px;} input.span5, textarea.span5, .uneditable-input.span5{width:456px;} input.span4, textarea.span4, .uneditable-input.span4{width:356px;} input.span3, textarea.span3, .uneditable-input.span3{width:256px;} input.span2, textarea.span2, .uneditable-input.span2{width:156px;} input.span1, textarea.span1, .uneditable-input.span1{width:56px;} .thumbnails{margin-left:-30px;} .thumbnails>li{margin-left:30px;} .row-fluid .thumbnails{margin-left:0;}}.breadcrumb .active{color:#333333;}
-.breadcrumb.bottom{margin-top:24px;margin-bottom:0px;}
+.breadcrumb.bottom{background-color:#e3e3e3;margin-top:24px;margin-bottom:0px;}
 .page-header .breadcrumb{background:none;padding:0px;margin-bottom:0px;}
 .page-header .breadcrumb{background:none;padding:0px;margin-bottom:0px;}
-footer{padding-top:12px;padding-bottom:32px;color:#b0b0b0;}footer a,footer a:link,footer a:active,footer a:visited{color:#b0b0b0;text-decoration:underline;}
+footer{padding-top:12px;padding-bottom:32px;color:#a3a3a3;}footer a,footer a:link,footer a:active,footer a:visited{color:#b0b0b0;text-decoration:underline;}
 footer a:hover{color:#7d7d7d;}
 footer a:hover{color:#7d7d7d;}
 footer .go-to-top{float:right;}footer .go-to-top,footer .go-to-top:link,footer .go-to-top:active,footer .go-to-top:visited{text-decoration:none;}footer .go-to-top i,footer .go-to-top:link i,footer .go-to-top:active i,footer .go-to-top:visited i{opacity:0.4;filter:alpha(opacity=40);}
 footer .go-to-top{float:right;}footer .go-to-top,footer .go-to-top:link,footer .go-to-top:active,footer .go-to-top:visited{text-decoration:none;}footer .go-to-top i,footer .go-to-top:link i,footer .go-to-top:active i,footer .go-to-top:visited i{opacity:0.4;filter:alpha(opacity=40);}
 footer .go-to-top:hover i{opacity:0.65;filter:alpha(opacity=65);}
 footer .go-to-top:hover i{opacity:0.65;filter:alpha(opacity=65);}
@@ -948,7 +948,19 @@ td.lead-cell{color:#555555;font-weight:bold;}
 .nav-tabs .tab-search form{marging:0px;margin-bottom:-4px;}
 .nav-tabs .tab-search form{marging:0px;margin-bottom:-4px;}
 .nav-tabs .tab-search.tab-search-no-tabs{position:relative;bottom:12px;}
 .nav-tabs .tab-search.tab-search-no-tabs{position:relative;bottom:12px;}
 .nav-tabs button{padding-left:7px;padding-right:7px;}
 .nav-tabs button{padding-left:7px;padding-right:7px;}
+.list-empty{margin-top:32px;font-size:180%;}
+.index-block{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;padding:8px;margin-top:8px;margin-bottom:24px;}.index-block h3{border-bottom:1px solid #bfbfbf;color:#999999;font-size:120%;margin-top:-6px;padding-top:0px;}
+.index-block ul{margin:0px;margin-top:-10px;padding:0px;}.index-block ul li{border-bottom:1px solid #d9d9d9;margin:0px;overflow:auto;}
+.team-online{margin-bottom:0px;padding-bottom:0px;}.team-online h3{border-bottom:none;margin-bottom:0px;color:#c8c8c8;}
+.team-online ul{margin:0px -6px;}.team-online ul li{background-color:#eeeeee;border:none;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;margin-bottom:8px;padding:6px;}
+.team-online div{float:left;position:relative;top:4px;font-weight:bold;}.team-online div a{display:block;color:#333333;font-size:160%;}
+.team-online div .muted{color:#999999;}
+.team-online img{float:left;margin-right:12px;width:48px;height:48px;}
+.thread-ranking{margin-bottom:8px;}.thread-ranking li{padding:8px 0px;}
+.thread-ranking a{color:#999999;}.thread-ranking a.lead{display:block;margin:0px;margin-bottom:-4px;padding:0px;color:#333333;font-size:120%;font-weight:bold;}
+.forum-stats{color:#b3b3b3;}.forum-stats strong{padding-left:8px;color:#555555;font-size:170%;}
 .forums-list{padding-top:4px;}.forums-list .category h2{color:#666666;font-size:110%;margin-bottom:0px;}.forums-list .category h2 small{color:#a6a6a6;font-size:100%;}
 .forums-list{padding-top:4px;}.forums-list .category h2{color:#666666;font-size:110%;margin-bottom:0px;}.forums-list .category h2 small{color:#a6a6a6;font-size:100%;}
+.forums-list .category h2 .form-inline{float:right;margin:0px;padding:0px;}.forums-list .category h2 .form-inline .btn-link{opacity:0.25;filter:alpha(opacity=25);}.forums-list .category h2 .form-inline .btn-link:hover,.forums-list .category h2 .form-inline .btn-link:active{background-color:#dc4e44;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;opacity:1;filter:alpha(opacity=100);color:#ffffff;}.forums-list .category h2 .form-inline .btn-link:hover i,.forums-list .category h2 .form-inline .btn-link:active i{background-image:url("../img/glyphicons-halflings-white.png");}
 .forums-list .category-important .well-forum{border:1px solid #0099e6;-webkit-box-shadow:0px 0px 0px 3px #66ccff;-moz-box-shadow:0px 0px 0px 3px #66ccff;box-shadow:0px 0px 0px 3px #66ccff;}
 .forums-list .category-important .well-forum{border:1px solid #0099e6;-webkit-box-shadow:0px 0px 0px 3px #66ccff;-moz-box-shadow:0px 0px 0px 3px #66ccff;box-shadow:0px 0px 0px 3px #66ccff;}
 .forums-list .well-forum{margin-bottom:14px;overflow:auto;padding:12px 8px;padding-bottom:8px;}.forums-list .well-forum .row .span3{margin-left:0px;padding-left:16px;}
 .forums-list .well-forum{margin-bottom:14px;overflow:auto;padding:12px 8px;padding-bottom:8px;}.forums-list .well-forum .row .span3{margin-left:0px;padding-left:16px;}
 .forums-list .well-forum .forum-icon{background-color:#eeeeee;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;float:left;padding:3px 6px;position:relative;bottom:4px;margin-bottom:-4px;}
 .forums-list .well-forum .forum-icon{background-color:#eeeeee;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;float:left;padding:3px 6px;position:relative;bottom:4px;margin-bottom:-4px;}
@@ -1017,6 +1029,12 @@ td.lead-cell{color:#555555;font-weight:bold;}
 .profile-header .avatar-height .lead{color:#555555;}.profile-header .avatar-height .lead .muted{color:#959595;}
 .profile-header .avatar-height .lead{color:#555555;}.profile-header .avatar-height .lead .muted{color:#959595;}
 .profile-header .nav-tabs{margin-top:-22px;margin-bottom:0px;padding-left:142px;}
 .profile-header .nav-tabs{margin-top:-22px;margin-bottom:0px;padding-left:142px;}
 .avatar-menu h3{margin-top:0px;}
 .avatar-menu h3{margin-top:0px;}
-.board-team{font-weight:bold;}.board-team a:link,.board-team a:active,.board-team a:visited,.board-team a:hover{color:#333333;font-size:130%;}
-.board-stat{font-size:180%;}.board-stat small{color:#999999;font-size:70%;}
 .well-post.rank-team{border:1px solid #0099e6;-webkit-box-shadow:0px 0px 0px 3px #66ccff;-moz-box-shadow:0px 0px 0px 3px #66ccff;box-shadow:0px 0px 0px 3px #66ccff;}
 .well-post.rank-team{border:1px solid #0099e6;-webkit-box-shadow:0px 0px 0px 3px #66ccff;-moz-box-shadow:0px 0px 0px 3px #66ccff;box-shadow:0px 0px 0px 3px #66ccff;}
+.team-online.rank-team ul li{background-color:#0088cc;}.team-online.rank-team ul li div a{color:#ffffff;text-shadow:0px 1px 0px #000d13;}
+.team-online.rank-team ul li div .muted{color:#02435e;}
+.well-post.rank-mvp{border:1px solid #8753c0;-webkit-box-shadow:0px 0px 0px 3px #c8b0e2;-moz-box-shadow:0px 0px 0px 3px #c8b0e2;box-shadow:0px 0px 0px 3px #c8b0e2;}
+.team-online.rank-mvp ul li{background-color:#9466c6;}.team-online.rank-mvp ul li div a{color:#ffffff;text-shadow:0px 1px 0px #160c21;}
+.team-online.rank-mvp ul li div .muted{color:#3c2159;}
+.well-post.rank-active{border:1px solid #fa9f1e;-webkit-box-shadow:0px 0px 0px 3px #fdd49a;-moz-box-shadow:0px 0px 0px 3px #fdd49a;box-shadow:0px 0px 0px 3px #fdd49a;}
+.team-online.rank-active ul li{background-color:#f89406;}.team-online.rank-active ul li div a{color:#ffffff;text-shadow:0px 1px 0px #311d01;}
+.team-online.rank-active ul li div .muted{color:#7c4a03;}

+ 3 - 1
static/sora/css/sora.less

@@ -80,12 +80,14 @@
 @import "sora/avatars.less";
 @import "sora/avatars.less";
 @import "sora/navs.less";
 @import "sora/navs.less";
 @import "sora/navbar.less";
 @import "sora/navbar.less";
+@import "sora/index.less";
 @import "sora/forums.less";
 @import "sora/forums.less";
 @import "sora/threads.less";
 @import "sora/threads.less";
 
 
 @import "sora/editor.less";
 @import "sora/editor.less";
 @import "sora/markdown.less";
 @import "sora/markdown.less";
 @import "sora/utilities.less";
 @import "sora/utilities.less";
-@import "sora/ranks.less";
 
 
+// Keep ranks last for easy overrides!
+@import "ranks.less";
 @import "jquery.Jcrop.min.css";
 @import "jquery.Jcrop.min.css";

+ 22 - 0
static/sora/css/sora/forums.less

@@ -13,6 +13,28 @@
         color: lighten(@textColor, 45%);
         color: lighten(@textColor, 45%);
         font-size: 100%;
         font-size: 100%;
       }
       }
+      
+      .form-inline {
+        float: right;
+        margin: 0px;
+        padding: 0px;
+        
+        .btn-link {
+          .opacity(25);
+          
+          &:hover, &:active {
+            background-color: lighten(@red, 20%);
+            .border-radius(3px);
+            .opacity(100);
+                      
+            color: @white;
+            
+            i {
+              background-image: url("@{iconWhiteSpritePath}");
+            }
+          }
+        } 
+      }
     }
     }
   }
   }
   
   

+ 121 - 0
static/sora/css/sora/index.less

@@ -0,0 +1,121 @@
+// Board index
+// -------------------------
+
+.list-empty {
+  margin-top: 32px;
+  
+  font-size: 180%;
+}
+
+.index-block {
+  .border-radius(3px);
+  padding: 8px;
+  margin-top: 8px;
+  margin-bottom: 24px;
+  
+  h3 {
+    border-bottom: 1px solid lighten(@grayLight, 15%);
+    
+    color: @grayLight;
+    font-size: 120%;
+    margin-top: -6px;
+    padding-top: 0px;
+  }
+  
+  ul {
+    margin: 0px;
+    margin-top: -10px;
+    padding: 0px;
+    
+    li {
+      border-bottom: 1px solid lighten(@grayLight, 25%);
+      margin: 0px;
+      overflow: auto;
+    }
+  }
+}
+
+.team-online {
+  margin-bottom: 0px;
+  padding-bottom: 0px;
+  
+  h3 {
+    border-bottom: none;
+    margin-bottom: 0px;
+    
+    color: darken(@grayLighter, 15%);
+  }
+  
+  ul {
+    margin: 0px -6px;
+    
+    li {
+      background-color: @grayLighter;
+      border: none;
+      .border-radius(3px);
+      margin-bottom: 8px;
+      padding: 6px;
+    } 
+  }
+   
+  div {
+    float: left;
+    position: relative;
+    top: 4px;
+    font-weight: bold;
+    
+    a {
+      display: block;
+      
+      color: @grayDark;
+      font-size: 160%;
+    }
+    
+    .muted {
+      color: @grayLight;
+    }
+  }
+  
+  img {
+    float: left;
+    margin-right: 12px;
+    width: 48px;
+    height: 48px;
+  }
+}
+
+.thread-ranking {
+  margin-bottom: 8px;
+  
+  li {
+    padding: 8px 0px;
+  }
+  
+  a {
+    color: @grayLight;
+    
+    &.lead {
+      display: block;
+      margin: 0px;
+      margin-bottom: -4px;
+      padding: 0px;
+      
+      color: @textColor;
+      font-size: 120%;
+      font-weight: bold;
+    }
+  }
+}
+
+.forum-stats {  
+  color: lighten(@grayLight, 10%);
+  
+  strong {
+    padding-left: 8px;
+    
+    color: @gray;
+    font-size: 170%;
+  }
+}
+
+.cookie-message {}

+ 0 - 12
static/sora/css/sora/ranks.less

@@ -1,12 +0,0 @@
-// Ranks styles
-// -------------------------
-
-// .rank-team
-.well-post.rank-team {
-  border: 1px solid lighten(@linkColor, 5%);
-  .box-shadow(0px 0px 0px 3px lighten(@linkColor, 30%));
-}
-
-// .rank-mvp
-
-// .rank-active

+ 2 - 1
static/sora/css/sora/scaffolding.less

@@ -8,6 +8,7 @@
   }
   }
   
   
   &.bottom {
   &.bottom {
+    background-color: darken(@bodyBackground, 10%);
     margin-top: 24px;
     margin-top: 24px;
     margin-bottom: 0px;
     margin-bottom: 0px;
   }
   }
@@ -26,7 +27,7 @@ footer {
   padding-top: 12px;
   padding-top: 12px;
   padding-bottom: 32px;
   padding-bottom: 32px;
   
   
-  color: darken(@bodyBackground, 30%);
+  color: darken(@bodyBackground, 35%);
   
   
   a, a:link, a:active, a:visited {
   a, a:link, a:active, a:visited {
     color: darken(@bodyBackground, 30%);
     color: darken(@bodyBackground, 30%);

+ 1 - 19
static/sora/css/sora/utilities.less

@@ -43,22 +43,4 @@
   h3 {
   h3 {
     margin-top: 0px;
     margin-top: 0px;
   }
   }
-}
+}
-
-.board-team {
-  font-weight: bold;
-    
-  a:link, a:active, a:visited, a:hover {
-    color: @textColor;
-    font-size: 130%;
-  }
-}
-
-.board-stat {
-  font-size: 180%;
-  
-  small {
-    color: @grayLight;
-    font-size: 70%;
-  }
-}

+ 1 - 1
templates/admin/ranks/list.html

@@ -11,7 +11,7 @@
 
 
 {% block table_row scoped %}
 {% block table_row scoped %}
   <td class="lead-cell">
   <td class="lead-cell">
-  	<strong>{{ item.name }}</strong>{% if item.special %} <span class="label label-info">{% trans %}Special{% endtrans %}</span>{% endif %}{% if item.as_tab %} <span class="label label-inverse">{% trans %}Tab{% endtrans %}</span>{% endif %}
+  	<strong>{{ item.name }}</strong>{% if item.special %} <span class="label label-info">{% trans %}Special{% endtrans %}</span>{% endif %}{% if item.as_tab %} <span class="label label-inverse">{% trans %}Tab{% endtrans %}</span>{% endif %}{% if item.on_index %} <span class="label label-orange">{% trans %}On Index{% endtrans %}</span>{% endif %}
   </td>
   </td>
   <td class="span2">
   <td class="span2">
   	{{ form_theme.field_widget(table_form['pos_' + item.pk|string], attrs={'form': 'table_form'}, width=2) }}
   	{{ form_theme.field_widget(table_form['pos_' + item.pk|string], attrs={'form': 'table_form'}, width=2) }}

+ 48 - 19
templates/sora/index.html

@@ -15,34 +15,63 @@
     <div class="forums-list">
     <div class="forums-list">
       {% for category in forums_list %}{% if category.subforums %}
       {% for category in forums_list %}{% if category.subforums %}
       <div class="category{% if category.style %} {{ category.style }}{% endif %}">
       <div class="category{% if category.style %} {{ category.style }}{% endif %}">
-        <h2>{{ category.name }}{% if category.description %} <small><strong>{{ category.description }}</strong></small>{% endif %}</h2>
+        <h2>{{ category.name }}{% if category.description %} <small><strong>{{ category.description }}</strong></small>{% endif %}
+        {%- if user.is_authenticated() -%}
+        <form action="{% url 'read_all' %}" method="post" class="form-inline">
+          <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
+          <button type"submit" class="btn btn-link"><i class="icon-ok"></i> {% trans %}Mark forums read{% endtrans %}</button>
+        </form>
+        {%- endif %}</h2>
         {{ macros.draw_forums(category, 8) }}
         {{ macros.draw_forums(category, 8) }}
-      </div>{% endif %}{% endfor %}
+      </div>{% endif %}
+      {% else %}
+      <p class="list-empty">{% trans %}Looks like there are no forums that you have permission to see.{% endtrans %}</p>
+      {% endfor %}
     </div>
     </div>
   </div>
   </div>
   <div class="span4 forum-list-side">
   <div class="span4 forum-list-side">
-    {% if team_online %}
+    
-    <h3>{% trans %}Team Online{% endtrans %}</h3>
+    {% for rank in ranks_online %}{% if rank.online %}
-    {% for user in team_online %}
+    <div class="index-block team-online{% if rank.style %} {{ rank.style }}{% endif %}">
-    <div class="board-team">
+      <h3>{% trans rank_name=_(rank.name) %}{{ rank_name }} Online{% endtrans %}</h3>
-      <img src="{{ user.get_avatar(28) }}" alt="" class="avatar-small"> <a href="{% url 'user' username=user.username_slug, user=user.pk %}">{{ user.username }}</a>{% if user.get_title() %} <span class="muted">{{ _(user.get_title()) }}</span>{% endif %}
+      <ul class="unstyled">
+        {% for user in rank.online %}
+        <li>
+          <img src="{{ user.get_avatar(48) }}" alt="" class="avatar-small">
+          <div>
+            <a href="{% url 'user' username=user.username_slug, user=user.pk %}">{{ user.username }}</a>
+            {% if rank.title or user.title %}<span class="muted">{% if user.title %}{{ user.title }}{% else %}{{ _(rank.title) }}{% endif %}</span>{% endif %}
+          </div>
+        </li>
+        {% endfor %}
+      </ul>
     </div>
     </div>
-    <hr>
+    {% endif %}{% endfor %}
-    {% endfor %}
-    {% endif %}
     
     
     {% if popular_threads %}
     {% if popular_threads %}
-    <h3>{% trans %}Popular Threads{% endtrans %}</h3>
+    <div class="index-block thread-ranking">
-    {% for thread in popular_threads %}
+      <h3>{% trans %}Popular Threads{% endtrans %}</h3>
-    <a href="{% url 'thread' thread=thread.pk, slug=thread.slug %}" class="lead">{{ thread.name }}</a><br />
+      <ul class="unstyled">
-    <a href="{% url 'forum' forum=thread.forum.pk, slug=thread.forum.slug %}">{{ thread.forum.name }}</a> - {{ thread.last|reltimesince }}
+        {% for thread in popular_threads %}
-    <hr>
+        <li>
-    {% endfor %}
+          <a href="{% url 'thread' thread=thread.pk, slug=thread.slug %}" class="lead">{{ thread.name }}</a>
+          <div class="muted"><a href="{% url 'forum' forum=thread.forum_id, slug=thread.forum_slug %}">{{ thread.forum_name }}</a> - {{ thread.last|reltimesince }}</div>
+        </li>
+        {% endfor %}
+      </ul>
+    </div>
     {% endif %}
     {% endif %}
     
     
-    <h3>{% trans %}Forum Stats{% endtrans %}</h3>
+    <div class="row forum-stats">
-    <p class="lead board-stat">{{ monitor.posts|int|intcomma }} <small>{% trans %}Posts{% endtrans %}</small></p>
+      <div class="span2">
-    <p class="lead board-stat">{{ monitor.users|int|intcomma }} <small>{% trans %}Members{% endtrans %}</small></p>
+        <strong>{{ monitor.posts|int|intcomma }}</strong>
+        {% trans %}Posts{% endtrans %}
+      </div>
+      <div class="span2">
+        <strong>{{ monitor.users|int|intcomma }}</strong>
+        {% trans %}Members{% endtrans %}
+      </div>
+    </div>
   </div>
   </div>
 </div>
 </div>
 {% endblock %}
 {% endblock %}