changeset 102:f872c643b056

Updates to snippet functionality (see details) Sorry about the large commit, but it was difficult to break it up as a lot of new functionality was introduced. Most of it is specific to the snippet feature but there are some other changes as well. Commit highlights: * Added the ability to switch the syntax highlighting colour scheme when viewing a snippet. This is currently done on a per-snippet basis only, but eventually it will be possible to set a default in your profile to have all the snippets you view use that colour scheme. There are currently 8 different colour schemes, all of which were taken from the default pygments stylesheets (some were modified). * Added a "num_views" field to the Snippet model, with the field being incremented any time the snippet view is called (raw or regular view). * Created a simple "explore" view that lists the recently-posted snippets. Will implement pagination and sorting by other attributes ("popularity", for example, based on number of views) as well. * Added a post-save hook to the User model to ensure that a Profile is created for every user as soon as the User itself is created. This alleviates the need for a get_profile method that checks if the user has a profile or not and creates one if necessary. (The code is currently still there, will be cleaned up soon). * Added back the wordwrap toggling feature. Currently, if you want to enable word-wrapping, the line numbers have to be hidden in order to ensure that the lines and their numbers don't go out of sync. This will be fixed soon. * History/diff view is back * And some other minor cosmetic changes. Note: since some existing models have been changed, you'll likely need to delete the existing sqlite database before running syncdb. The alternative is to determine the necessary column changes/additions and run the SQL query yourself.
author dellsystem <ilostwaldo@gmail.com>
date Fri, 31 Aug 2012 02:53:22 -0400
parents a8da60d611f7
children 9d6b313af86f
files apps/profile/models.py apps/pygments_style/__init__.py apps/pygments_style/fixtures/initial_data.json apps/pygments_style/models.py apps/snippet/models.py apps/snippet/views.py settings.py static/css/agora.less static/css/code.less static/css/code/autumn.less static/css/code/borland.less static/css/code/fruity.less static/css/code/monokai.less static/css/code/native.less static/css/code/tango.less static/css/code/vibrant.less static/css/code/vs.less static/css/imports.less static/css/mixins.less static/css/variables.less templates/base.djhtml templates/snippet/explore.html templates/snippet/snippet_details.djhtml templates/snippet/snippet_details.js templates/snippet/snippet_new.djhtml
diffstat 25 files changed, 1024 insertions(+), 184 deletions(-) [+]
line wrap: on
line diff
--- a/apps/profile/models.py
+++ b/apps/profile/models.py
@@ -2,13 +2,24 @@
 from django.contrib.auth.models import User
 
 from agora.apps.free_license.models import FreeLicense
+from agora.apps.pygments_style.models import PygmentsStyle
 
 
 class Profile(models.Model):
     user = models.OneToOneField(User)
-    preferred_license = models.ForeignKey(FreeLicense)
-    interests = models.CharField(max_length=512)
-    blurb = models.TextField(max_length=16384)
+    preferred_license = models.ForeignKey(FreeLicense, default=1)
+    interests = models.CharField(max_length=512, null=True, blank=True)
+    blurb = models.TextField(max_length=16384, null=True, blank=True)
+    pygments_style = models.ForeignKey(PygmentsStyle, default=1)
 
     def __unicode__(self):
         return self.user.username
+
+
+# Defines a post_save hook to ensure that a profile is created for each user
+# This also ensures that the admin user (created when running syncdb) has one
+def create_user_profile(sender, instance, created, **kwards):
+    if created:
+        Profile.objects.create(user=instance)
+
+models.signals.post_save.connect(create_user_profile, sender=User)
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/apps/pygments_style/fixtures/initial_data.json
@@ -0,0 +1,66 @@
+[
+    {
+        "pk": 1,
+        "model": "pygments_style.pygmentsstyle",
+        "fields": {
+            "class_name": "tango",
+            "description": null
+        }
+    },
+    {
+        "pk": 2,
+        "model": "pygments_style.pygmentsstyle",
+        "fields": {
+            "class_name": "autumn",
+            "description": null
+        }
+    },
+    {
+        "pk": 3,
+        "model": "pygments_style.pygmentsstyle",
+        "fields": {
+            "class_name": "borland",
+            "description": null
+        }
+    },
+    {
+        "pk": 4,
+        "model": "pygments_style.pygmentsstyle",
+        "fields": {
+            "class_name": "fruity",
+            "description": null
+        }
+    },
+    {
+        "pk": 5,
+        "model": "pygments_style.pygmentsstyle",
+        "fields": {
+            "class_name": "monokai",
+            "description": null
+        }
+    },
+    {
+        "pk": 6,
+        "model": "pygments_style.pygmentsstyle",
+        "fields": {
+            "class_name": "native",
+            "description": null
+        }
+    },
+    {
+        "pk": 7,
+        "model": "pygments_style.pygmentsstyle",
+        "fields": {
+            "class_name": "vs",
+            "description": null
+        }
+    },
+    {
+        "pk": 8,
+        "model": "pygments_style.pygmentsstyle",
+        "fields": {
+            "class_name": "vibrant",
+            "description": null
+        }
+    }
+]
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/apps/pygments_style/models.py
@@ -0,0 +1,16 @@
+from django.db import models
+
+
+class PygmentsStyle(models.Model):
+    """
+    For allowing users to choose between syntax highlighting styles.
+
+    Affects viewing snippets but not creating them. Users can set a
+    default and can change the style when viewing specific snippets or
+    files if necessary.
+    """
+    class_name = models.CharField(max_length=20)
+    description = models.TextField(null=True, blank=True)
+
+    def __unicode__(self):
+        return self.class_name
--- a/apps/snippet/models.py
+++ b/apps/snippet/models.py
@@ -30,6 +30,7 @@
     expires = models.DateTimeField(_(u'Expires'), blank=True, help_text='asdf')
     parent = models.ForeignKey('self', null=True, blank=True,
                                related_name='children')
+    num_views = models.IntegerField(default=0)
 
     class Meta:
         ordering = ('-published',)
--- a/apps/snippet/views.py
+++ b/apps/snippet/views.py
@@ -1,7 +1,7 @@
 import difflib
 
 from django.shortcuts import render_to_response, \
-     get_object_or_404, get_list_or_404
+     get_object_or_404, get_list_or_404, render
 from django.template.context \
      import RequestContext
 from django.http \
@@ -21,7 +21,11 @@
 
 
 def snippet_explore(request):
-    pass
+    context = {
+        'recent_snippets': Snippet.objects.all()[:20]
+    }
+
+    return render(request, 'snippet/explore.html', context)
 
 
 def snippet_new(request, template_name='snippet/snippet_new.djhtml'):
@@ -59,12 +63,15 @@
                     is_raw=False):
 
     snippet = get_object_or_404(Snippet, secret_id=snippet_id)
+    snippet.num_views += 1
+    snippet.save()
 
     tree = snippet.get_root()
     tree = tree.get_descendants(include_self=True)
 
     new_snippet_initial = {
         'content': snippet.content,
+        'lexer': snippet.lexer,
     }
 
     if request.method == "POST":
@@ -75,7 +82,13 @@
             request, new_snippet = snippet_form.save(parent=snippet)
             return HttpResponseRedirect(new_snippet.get_absolute_url())
     else:
-        snippet_form = SnippetForm(initial=new_snippet_initial, request=request)
+        snippet_form = SnippetForm(initial=new_snippet_initial,
+                                   request=request)
+
+    if request.user.is_authenticated():
+        default_pygments_style = request.user.get_profile().pygments_style
+    else:
+        default_pygments_style = PygmentsStyle.objects.get(pk=1)
 
     template_context = {
         'snippet_form': snippet_form,
@@ -83,6 +96,9 @@
         'lines': range(snippet.get_linecount()),
         'tree': tree,
         'language': dict(LEXER_LIST)[snippet.lexer],
+        'pygments_styles': PygmentsStyle.objects.all(),
+        'default_style': default_pygments_style,
+        'no_descendants': len(tree) == 1,
     }
 
     response = render_to_response(
--- a/settings.py
+++ b/settings.py
@@ -144,6 +144,7 @@
     'agora.apps.snippet',
     'agora.apps.bundle',
     'agora.apps.free_license',
+    'agora.apps.pygments_style',
     'agora.apps.mptt',
 )
 
--- a/static/css/agora.less
+++ b/static/css/agora.less
@@ -146,6 +146,7 @@
 #breadcrumbs {
     border-bottom: 1px solid @lightGrey;
     margin-bottom: 10px;
+    padding-bottom: 5px;
 }
 
 #info-box {
@@ -202,10 +203,11 @@
 }
 
 #sidebar {
-    width: @sidebarWidth - @sidebarPadding * 2;
+    margin-top: 10px;
+    width: @sidebarWidth - @sidebarPadding * 2 - 2;
+    border: 1px solid @lightGrey;
     padding: @sidebarPadding;
-    min-height: 300px;
-    background: @lighterGrey;
+    background: @offWhite;
     .inline-block;
 }
 
@@ -219,15 +221,47 @@
 .hint {
     border: 1px solid @lightBlue;
     background: lighten(@mediumBlue, 40%);
-    padding-left: 10px;
+    padding: 10px;
     margin-bottom: 10px;
-    padding-top: 10px;
 }
 
 hr {
     border: 0;
     border-top: 1px solid @mediumGrey;
-    & + p {
-        margin-top: 10px;
+    margin: 5px 0;
+}
+
+.tree {
+    ul {
+        list-style-type: none;
     }
 }
+
+#diff {
+    .hidden;
+    border: 1px solid @lightGrey;
+    padding: 10px;
+    background: @offWhite;
+
+    .gi {
+        background: #DFD;
+    }
+
+    .gu {
+        color: @mediumGrey;
+    }
+
+    .gd {
+        background: #FDD;
+    }
+}
+
+table &.default {
+    width: 100%;
+    border: 1px solid @lightGrey;
+
+    thead th {
+        padding: 5px 0;
+        border-bottom: 1px solid @lightGrey;
+    }
+}
--- a/static/css/code.less
+++ b/static/css/code.less
@@ -1,1 +1,27 @@
-// Nothing yet
+// For all syntax-highlighted code
+.highlight {
+    width: 650px;
+	padding: 10px;
+	.border-radius(7px);
+    overflow-x: auto;
+    border: 1px solid @lightGrey;
+
+    &.wrap {
+        white-space: pre-wrap;
+        width: 688px;
+    }
+}
+
+.numbers, .highlight {
+    line-height: 18px;
+}
+
+#line-numbers {
+    vertical-align: top;
+    padding-top: 11px;
+    width: 40px;
+}
+
+.snippet table {
+    border-spacing: 0;
+}
new file mode 100644
--- /dev/null
+++ b/static/css/code/autumn.less
@@ -0,0 +1,60 @@
+.highlight &.autumn {
+    .hll { background-color: #ffffcc }
+    .c { color: #aaaaaa; font-style: italic } /* Comment */
+    .err { color: #F00000; background-color: #F0A0A0 } /* Error */
+    .k { color: #0000aa } /* Keyword */
+    .cm { color: #aaaaaa; font-style: italic } /* Comment.Multiline */
+    .cp { color: #4c8317 } /* Comment.Preproc */
+    .c1 { color: #aaaaaa; font-style: italic } /* Comment.Single */
+    .cs { color: #0000aa; font-style: italic } /* Comment.Special */
+    .gd { color: #aa0000 } /* Generic.Deleted */
+    .ge { font-style: italic } /* Generic.Emph */
+    .gr { color: #aa0000 } /* Generic.Error */
+    .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+    .gi { color: #00aa00 } /* Generic.Inserted */
+    .go { color: #888888 } /* Generic.Output */
+    .gp { color: #555555 } /* Generic.Prompt */
+    .gs { font-weight: bold } /* Generic.Strong */
+    .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+    .gt { color: #aa0000 } /* Generic.Traceback */
+    .kc { color: #0000aa } /* Keyword.Constant */
+    .kd { color: #0000aa } /* Keyword.Declaration */
+    .kn { color: #0000aa } /* Keyword.Namespace */
+    .kp { color: #0000aa } /* Keyword.Pseudo */
+    .kr { color: #0000aa } /* Keyword.Reserved */
+    .kt { color: #00aaaa } /* Keyword.Type */
+    .m { color: #009999 } /* Literal.Number */
+    .s { color: #aa5500 } /* Literal.String */
+    .na { color: #1e90ff } /* Name.Attribute */
+    .nb { color: #00aaaa } /* Name.Builtin */
+    .nc { color: #00aa00; text-decoration: underline } /* Name.Class */
+    .no { color: #aa0000 } /* Name.Constant */
+    .nd { color: #888888 } /* Name.Decorator */
+    .ni { color: #800000; font-weight: bold } /* Name.Entity */
+    .nf { color: #00aa00 } /* Name.Function */
+    .nn { color: #00aaaa; text-decoration: underline } /* Name.Namespace */
+    .nt { color: #1e90ff; font-weight: bold } /* Name.Tag */
+    .nv { color: #aa0000 } /* Name.Variable */
+    .ow { color: #0000aa } /* Operator.Word */
+    .w { color: #bbbbbb } /* Text.Whitespace */
+    .mf { color: #009999 } /* Literal.Number.Float */
+    .mh { color: #009999 } /* Literal.Number.Hex */
+    .mi { color: #009999 } /* Literal.Number.Integer */
+    .mo { color: #009999 } /* Literal.Number.Oct */
+    .sb { color: #aa5500 } /* Literal.String.Backtick */
+    .sc { color: #aa5500 } /* Literal.String.Char */
+    .sd { color: #aa5500 } /* Literal.String.Doc */
+    .s2 { color: #aa5500 } /* Literal.String.Double */
+    .se { color: #aa5500 } /* Literal.String.Escape */
+    .sh { color: #aa5500 } /* Literal.String.Heredoc */
+    .si { color: #aa5500 } /* Literal.String.Interpol */
+    .sx { color: #aa5500 } /* Literal.String.Other */
+    .sr { color: #009999 } /* Literal.String.Regex */
+    .s1 { color: #aa5500 } /* Literal.String.Single */
+    .ss { color: #0000aa } /* Literal.String.Symbol */
+    .bp { color: #00aaaa } /* Name.Builtin.Pseudo */
+    .vc { color: #aa0000 } /* Name.Variable.Class */
+    .vg { color: #aa0000 } /* Name.Variable.Global */
+    .vi { color: #aa0000 } /* Name.Variable.Instance */
+    .il { color: #009999 } /* Literal.Number.Integer.Long */
+}
new file mode 100644
--- /dev/null
+++ b/static/css/code/borland.less
@@ -0,0 +1,48 @@
+.highlight &.borland {
+    .hll { background-color: #ffffcc }
+    .c { color: #008800; font-style: italic } /* Comment */
+    .err { color: #a61717; background-color: #e3d2d2 } /* Error */
+    .k { color: #000080; font-weight: bold } /* Keyword */
+    .cm { color: #008800; font-style: italic } /* Comment.Multiline */
+    .cp { color: #008080 } /* Comment.Preproc */
+    .c1 { color: #008800; font-style: italic } /* Comment.Single */
+    .cs { color: #008800; font-weight: bold } /* Comment.Special */
+    .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
+    .ge { font-style: italic } /* Generic.Emph */
+    .gr { color: #aa0000 } /* Generic.Error */
+    .gh { color: #999999 } /* Generic.Heading */
+    .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
+    .go { color: #888888 } /* Generic.Output */
+    .gp { color: #555555 } /* Generic.Prompt */
+    .gs { font-weight: bold } /* Generic.Strong */
+    .gu { color: #aaaaaa } /* Generic.Subheading */
+    .gt { color: #aa0000 } /* Generic.Traceback */
+    .kc { color: #000080; font-weight: bold } /* Keyword.Constant */
+    .kd { color: #000080; font-weight: bold } /* Keyword.Declaration */
+    .kn { color: #000080; font-weight: bold } /* Keyword.Namespace */
+    .kp { color: #000080; font-weight: bold } /* Keyword.Pseudo */
+    .kr { color: #000080; font-weight: bold } /* Keyword.Reserved */
+    .kt { color: #000080; font-weight: bold } /* Keyword.Type */
+    .m { color: #0000FF } /* Literal.Number */
+    .s { color: #0000FF } /* Literal.String */
+    .na { color: #FF0000 } /* Name.Attribute */
+    .nt { color: #000080; font-weight: bold } /* Name.Tag */
+    .ow { font-weight: bold } /* Operator.Word */
+    .w { color: #bbbbbb } /* Text.Whitespace */
+    .mf { color: #0000FF } /* Literal.Number.Float */
+    .mh { color: #0000FF } /* Literal.Number.Hex */
+    .mi { color: #0000FF } /* Literal.Number.Integer */
+    .mo { color: #0000FF } /* Literal.Number.Oct */
+    .sb { color: #0000FF } /* Literal.String.Backtick */
+    .sc { color: #800080 } /* Literal.String.Char */
+    .sd { color: #0000FF } /* Literal.String.Doc */
+    .s2 { color: #0000FF } /* Literal.String.Double */
+    .se { color: #0000FF } /* Literal.String.Escape */
+    .sh { color: #0000FF } /* Literal.String.Heredoc */
+    .si { color: #0000FF } /* Literal.String.Interpol */
+    .sx { color: #0000FF } /* Literal.String.Other */
+    .sr { color: #0000FF } /* Literal.String.Regex */
+    .s1 { color: #0000FF } /* Literal.String.Single */
+    .ss { color: #0000FF } /* Literal.String.Symbol */
+    .il { color: #0000FF } /* Literal.Number.Integer.Long */
+}
new file mode 100644
--- /dev/null
+++ b/static/css/code/fruity.less
@@ -0,0 +1,73 @@
+.highlight &.fruity {
+    background: @almostBlack;
+
+    .hll { background-color: #333333 }
+    .c { color: #008800; font-style: italic; } /* Comment */
+    .err { color: #ffffff } /* Error */
+    .g { color: #ffffff } /* Generic */
+    .k { color: #fb660a; font-weight: bold } /* Keyword */
+    .l { color: #ffffff } /* Literal */
+    .n { color: #ffffff } /* Name */
+    .o { color: #ffffff } /* Operator */
+    .x { color: #ffffff } /* Other */
+    .p { color: #ffffff } /* Punctuation */
+    .cm { color: #008800; font-style: italic; } /* Comment.Multiline */
+    .cp { color: #ff0007; font-weight: bold; font-style: italic; } /* Comment.Preproc */
+    .c1 { color: #008800; font-style: italic; } /* Comment.Single */
+    .cs { color: #008800; font-style: italic; } /* Comment.Special */
+    .gd { color: #ffffff } /* Generic.Deleted */
+    .ge { color: #ffffff } /* Generic.Emph */
+    .gr { color: #ffffff } /* Generic.Error */
+    .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */
+    .gi { color: #ffffff } /* Generic.Inserted */
+    .go { color: #444444; background-color: #222222 } /* Generic.Output */
+    .gp { color: #ffffff } /* Generic.Prompt */
+    .gs { color: #ffffff } /* Generic.Strong */
+    .gu { color: #ffffff; font-weight: bold } /* Generic.Subheading */
+    .gt { color: #ffffff } /* Generic.Traceback */
+    .kc { color: #fb660a; font-weight: bold } /* Keyword.Constant */
+    .kd { color: #fb660a; font-weight: bold } /* Keyword.Declaration */
+    .kn { color: #fb660a; font-weight: bold } /* Keyword.Namespace */
+    .kp { color: #fb660a } /* Keyword.Pseudo */
+    .kr { color: #fb660a; font-weight: bold } /* Keyword.Reserved */
+    .kt { color: #cdcaa9; font-weight: bold } /* Keyword.Type */
+    .ld { color: #ffffff } /* Literal.Date */
+    .m { color: #0086f7; font-weight: bold } /* Literal.Number */
+    .s { color: #0086d2 } /* Literal.String */
+    .na { color: #ff0086; font-weight: bold } /* Name.Attribute */
+    .nb { color: #ffffff } /* Name.Builtin */
+    .nc { color: #ffffff } /* Name.Class */
+    .no { color: #0086d2 } /* Name.Constant */
+    .nd { color: #ffffff } /* Name.Decorator */
+    .ni { color: #ffffff } /* Name.Entity */
+    .ne { color: #ffffff } /* Name.Exception */
+    .nf { color: #ff0086; font-weight: bold } /* Name.Function */
+    .nl { color: #ffffff } /* Name.Label */
+    .nn { color: #ffffff } /* Name.Namespace */
+    .nx { color: #ffffff } /* Name.Other */
+    .py { color: #ffffff } /* Name.Property */
+    .nt { color: #fb660a; font-weight: bold } /* Name.Tag */
+    .nv { color: #fb660a } /* Name.Variable */
+    .ow { color: #ffffff } /* Operator.Word */
+    .w { color: #888888 } /* Text.Whitespace */
+    .mf { color: #0086f7; font-weight: bold } /* Literal.Number.Float */
+    .mh { color: #0086f7; font-weight: bold } /* Literal.Number.Hex */
+    .mi { color: #0086f7; font-weight: bold } /* Literal.Number.Integer */
+    .mo { color: #0086f7; font-weight: bold } /* Literal.Number.Oct */
+    .sb { color: #0086d2 } /* Literal.String.Backtick */
+    .sc { color: #0086d2 } /* Literal.String.Char */
+    .sd { color: #0086d2 } /* Literal.String.Doc */
+    .s2 { color: #0086d2 } /* Literal.String.Double */
+    .se { color: #0086d2 } /* Literal.String.Escape */
+    .sh { color: #0086d2 } /* Literal.String.Heredoc */
+    .si { color: #0086d2 } /* Literal.String.Interpol */
+    .sx { color: #0086d2 } /* Literal.String.Other */
+    .sr { color: #0086d2 } /* Literal.String.Regex */
+    .s1 { color: #0086d2 } /* Literal.String.Single */
+    .ss { color: #0086d2 } /* Literal.String.Symbol */
+    .bp { color: #ffffff } /* Name.Builtin.Pseudo */
+    .vc { color: #fb660a } /* Name.Variable.Class */
+    .vg { color: #fb660a } /* Name.Variable.Global */
+    .vi { color: #fb660a } /* Name.Variable.Instance */
+    .il { color: #0086f7; font-weight: bold } /* Literal.Number.Integer.Long */
+}
new file mode 100644
--- /dev/null
+++ b/static/css/code/monokai.less
@@ -0,0 +1,64 @@
+.highlight &.monokai {
+    background: #272822;
+    color: #F8F8F2;
+
+    .hll { background-color: #49483e }
+    .c { color: #75715e } /* Comment */
+    .err { color: #960050; background-color: #1e0010 } /* Error */
+    .k { color: #66d9ef } /* Keyword */
+    .l { color: #ae81ff } /* Literal */
+    .n { color: #f8f8f2 } /* Name */
+    .o { color: #f92672 } /* Operator */
+    .p { color: #f8f8f2 } /* Punctuation */
+    .cm { color: #75715e } /* Comment.Multiline */
+    .cp { color: #75715e } /* Comment.Preproc */
+    .c1 { color: #75715e } /* Comment.Single */
+    .cs { color: #75715e } /* Comment.Special */
+    .ge { font-style: italic } /* Generic.Emph */
+    .gs { font-weight: bold } /* Generic.Strong */
+    .kc { color: #66d9ef } /* Keyword.Constant */
+    .kd { color: #66d9ef } /* Keyword.Declaration */
+    .kn { color: #f92672 } /* Keyword.Namespace */
+    .kp { color: #66d9ef } /* Keyword.Pseudo */
+    .kr { color: #66d9ef } /* Keyword.Reserved */
+    .kt { color: #66d9ef } /* Keyword.Type */
+    .ld { color: #e6db74 } /* Literal.Date */
+    .m { color: #ae81ff } /* Literal.Number */
+    .s { color: #e6db74 } /* Literal.String */
+    .na { color: #a6e22e } /* Name.Attribute */
+    .nb { color: #f8f8f2 } /* Name.Builtin */
+    .nc { color: #a6e22e } /* Name.Class */
+    .no { color: #66d9ef } /* Name.Constant */
+    .nd { color: #a6e22e } /* Name.Decorator */
+    .ni { color: #f8f8f2 } /* Name.Entity */
+    .ne { color: #a6e22e } /* Name.Exception */
+    .nf { color: #a6e22e } /* Name.Function */
+    .nl { color: #f8f8f2 } /* Name.Label */
+    .nn { color: #f8f8f2 } /* Name.Namespace */
+    .nx { color: #a6e22e } /* Name.Other */
+    .py { color: #f8f8f2 } /* Name.Property */
+    .nt { color: #f92672 } /* Name.Tag */
+    .nv { color: #f8f8f2 } /* Name.Variable */
+    .ow { color: #f92672 } /* Operator.Word */
+    .w { color: #f8f8f2 } /* Text.Whitespace */
+    .mf { color: #ae81ff } /* Literal.Number.Float */
+    .mh { color: #ae81ff } /* Literal.Number.Hex */
+    .mi { color: #ae81ff } /* Literal.Number.Integer */
+    .mo { color: #ae81ff } /* Literal.Number.Oct */
+    .sb { color: #e6db74 } /* Literal.String.Backtick */
+    .sc { color: #e6db74 } /* Literal.String.Char */
+    .sd { color: #e6db74 } /* Literal.String.Doc */
+    .s2 { color: #e6db74 } /* Literal.String.Double */
+    .se { color: #ae81ff } /* Literal.String.Escape */
+    .sh { color: #e6db74 } /* Literal.String.Heredoc */
+    .si { color: #e6db74 } /* Literal.String.Interpol */
+    .sx { color: #e6db74 } /* Literal.String.Other */
+    .sr { color: #e6db74 } /* Literal.String.Regex */
+    .s1 { color: #e6db74 } /* Literal.String.Single */
+    .ss { color: #e6db74 } /* Literal.String.Symbol */
+    .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
+    .vc { color: #f8f8f2 } /* Name.Variable.Class */
+    .vg { color: #f8f8f2 } /* Name.Variable.Global */
+    .vi { color: #f8f8f2 } /* Name.Variable.Instance */
+    .il { color: #ae81ff } /* Literal.Number.Integer.Long */
+}
new file mode 100644
--- /dev/null
+++ b/static/css/code/native.less
@@ -0,0 +1,73 @@
+.highlight &.native {
+    background: @almostBlack;
+
+    .hll { background-color: #404040 }
+    .c { color: #999999; font-style: italic } /* Comment */
+    .err { color: #a61717; background-color: #e3d2d2 } /* Error */
+    .g { color: #d0d0d0 } /* Generic */
+    .k { color: #6ab825; font-weight: bold } /* Keyword */
+    .l { color: #d0d0d0 } /* Literal */
+    .n { color: #d0d0d0 } /* Name */
+    .o { color: #d0d0d0 } /* Operator */
+    .x { color: #d0d0d0 } /* Other */
+    .p { color: #d0d0d0 } /* Punctuation */
+    .cm { color: #999999; font-style: italic } /* Comment.Multiline */
+    .cp { color: #cd2828; font-weight: bold } /* Comment.Preproc */
+    .c1 { color: #999999; font-style: italic } /* Comment.Single */
+    .cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */
+    .gd { color: #d22323 } /* Generic.Deleted */
+    .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */
+    .gr { color: #d22323 } /* Generic.Error */
+    .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */
+    .gi { color: #589819 } /* Generic.Inserted */
+    .go { color: #cccccc } /* Generic.Output */
+    .gp { color: #aaaaaa } /* Generic.Prompt */
+    .gs { color: #d0d0d0; font-weight: bold } /* Generic.Strong */
+    .gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */
+    .gt { color: #d22323 } /* Generic.Traceback */
+    .kc { color: #6ab825; font-weight: bold } /* Keyword.Constant */
+    .kd { color: #6ab825; font-weight: bold } /* Keyword.Declaration */
+    .kn { color: #6ab825; font-weight: bold } /* Keyword.Namespace */
+    .kp { color: #6ab825 } /* Keyword.Pseudo */
+    .kr { color: #6ab825; font-weight: bold } /* Keyword.Reserved */
+    .kt { color: #6ab825; font-weight: bold } /* Keyword.Type */
+    .ld { color: #d0d0d0 } /* Literal.Date */
+    .m { color: #3677a9 } /* Literal.Number */
+    .s { color: #ed9d13 } /* Literal.String */
+    .na { color: #bbbbbb } /* Name.Attribute */
+    .nb { color: #24909d } /* Name.Builtin */
+    .nc { color: #447fcf; text-decoration: underline } /* Name.Class */
+    .no { color: #40ffff } /* Name.Constant */
+    .nd { color: #ffa500 } /* Name.Decorator */
+    .ni { color: #d0d0d0 } /* Name.Entity */
+    .ne { color: #bbbbbb } /* Name.Exception */
+    .nf { color: #447fcf } /* Name.Function */
+    .nl { color: #d0d0d0 } /* Name.Label */
+    .nn { color: #447fcf; text-decoration: underline } /* Name.Namespace */
+    .nx { color: #d0d0d0 } /* Name.Other */
+    .py { color: #d0d0d0 } /* Name.Property */
+    .nt { color: #6ab825; font-weight: bold } /* Name.Tag */
+    .nv { color: #40ffff } /* Name.Variable */
+    .ow { color: #6ab825; font-weight: bold } /* Operator.Word */
+    .w { color: #666666 } /* Text.Whitespace */
+    .mf { color: #3677a9 } /* Literal.Number.Float */
+    .mh { color: #3677a9 } /* Literal.Number.Hex */
+    .mi { color: #3677a9 } /* Literal.Number.Integer */
+    .mo { color: #3677a9 } /* Literal.Number.Oct */
+    .sb { color: #ed9d13 } /* Literal.String.Backtick */
+    .sc { color: #ed9d13 } /* Literal.String.Char */
+    .sd { color: #ed9d13 } /* Literal.String.Doc */
+    .s2 { color: #ed9d13 } /* Literal.String.Double */
+    .se { color: #ed9d13 } /* Literal.String.Escape */
+    .sh { color: #ed9d13 } /* Literal.String.Heredoc */
+    .si { color: #ed9d13 } /* Literal.String.Interpol */
+    .sx { color: #ffa500 } /* Literal.String.Other */
+    .sr { color: #ed9d13 } /* Literal.String.Regex */
+    .s1 { color: #ed9d13 } /* Literal.String.Single */
+    .ss { color: #ed9d13 } /* Literal.String.Symbol */
+    .bp { color: #24909d } /* Name.Builtin.Pseudo */
+    .vc { color: #40ffff } /* Name.Variable.Class */
+    .vg { color: #40ffff } /* Name.Variable.Global */
+    .vi { color: #40ffff } /* Name.Variable.Instance */
+    .il { color: #3677a9 } /* Literal.Number.Integer.Long */
+}
new file mode 100644
--- /dev/null
+++ b/static/css/code/tango.less
@@ -0,0 +1,71 @@
+.highlight &.tango {
+    .hll { background-color: #ffffcc }
+    .c { color: #8f5902; font-style: italic } /* Comment */
+    .err { color: #a40000; border: 1px solid #ef2929 } /* Error */
+    .g { color: #000000 } /* Generic */
+    .k { color: #204a87; font-weight: bold } /* Keyword */
+    .l { color: #000000 } /* Literal */
+    .n { color: #000000 } /* Name */
+    .o { color: #ce5c00; font-weight: bold } /* Operator */
+    .x { color: #000000 } /* Other */
+    .p { color: #000000; font-weight: bold } /* Punctuation */
+    .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */
+    .cp { color: #8f5902; font-style: italic } /* Comment.Preproc */
+    .c1 { color: #8f5902; font-style: italic } /* Comment.Single */
+    .cs { color: #8f5902; font-style: italic } /* Comment.Special */
+    .gd { color: #a40000 } /* Generic.Deleted */
+    .ge { color: #000000; font-style: italic } /* Generic.Emph */
+    .gr { color: #ef2929 } /* Generic.Error */
+    .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+    .gi { color: #00A000 } /* Generic.Inserted */
+    .go { color: #000000; font-style: italic } /* Generic.Output */
+    .gp { color: #8f5902 } /* Generic.Prompt */
+    .gs { color: #000000; font-weight: bold } /* Generic.Strong */
+    .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+    .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */
+    .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */
+    .kd { color: #204a87; font-weight: bold } /* Keyword.Declaration */
+    .kn { color: #204a87; font-weight: bold } /* Keyword.Namespace */
+    .kp { color: #204a87; font-weight: bold } /* Keyword.Pseudo */
+    .kr { color: #204a87; font-weight: bold } /* Keyword.Reserved */
+    .kt { color: #204a87; font-weight: bold } /* Keyword.Type */
+    .ld { color: #000000 } /* Literal.Date */
+    .m { color: #0000cf; font-weight: bold } /* Literal.Number */
+    .s { color: #4e9a06 } /* Literal.String */
+    .na { color: #c4a000 } /* Name.Attribute */
+    .nb { color: #204a87 } /* Name.Builtin */
+    .nc { color: #000000 } /* Name.Class */
+    .no { color: #000000 } /* Name.Constant */
+    .nd { color: #5c35cc; font-weight: bold } /* Name.Decorator */
+    .ni { color: #ce5c00 } /* Name.Entity */
+    .ne { color: #cc0000; font-weight: bold } /* Name.Exception */
+    .nf { color: #000000 } /* Name.Function */
+    .nl { color: #f57900 } /* Name.Label */
+    .nn { color: #000000 } /* Name.Namespace */
+    .nx { color: #000000 } /* Name.Other */
+    .py { color: #000000 } /* Name.Property */
+    .nt { color: #204a87; font-weight: bold } /* Name.Tag */
+    .nv { color: #000000 } /* Name.Variable */
+    .ow { color: #204a87; font-weight: bold } /* Operator.Word */
+    .w { color: #f8f8f8; text-decoration: underline } /* Text.Whitespace */
+    .mf { color: #0000cf; font-weight: bold } /* Literal.Number.Float */
+    .mh { color: #0000cf; font-weight: bold } /* Literal.Number.Hex */
+    .mi { color: #0000cf; font-weight: bold } /* Literal.Number.Integer */
+    .mo { color: #0000cf; font-weight: bold } /* Literal.Number.Oct */
+    .sb { color: #4e9a06 } /* Literal.String.Backtick */
+    .sc { color: #4e9a06 } /* Literal.String.Char */
+    .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */
+    .s2 { color: #4e9a06 } /* Literal.String.Double */
+    .se { color: #4e9a06 } /* Literal.String.Escape */
+    .sh { color: #4e9a06 } /* Literal.String.Heredoc */
+    .si { color: #4e9a06 } /* Literal.String.Interpol */
+    .sx { color: #4e9a06 } /* Literal.String.Other */
+    .sr { color: #4e9a06 } /* Literal.String.Regex */
+    .s1 { color: #4e9a06 } /* Literal.String.Single */
+    .ss { color: #4e9a06 } /* Literal.String.Symbol */
+    .bp { color: #3465a4 } /* Name.Builtin.Pseudo */
+    .vc { color: #000000 } /* Name.Variable.Class */
+    .vg { color: #000000 } /* Name.Variable.Global */
+    .vi { color: #000000 } /* Name.Variable.Instance */
+    .il { color: #0000cf; font-weight: bold } /* Literal.Number.Integer.Long */
+}
new file mode 100644
--- /dev/null
+++ b/static/css/code/vibrant.less
@@ -0,0 +1,240 @@
+// Modified version of the vibrant pygments stylesheet
+.highlight &.vibrant {
+    color: @white;
+    background: @almostBlack;
+    .box-shadow(inset 0 0 40px rgba(0, 0, 0, 0.7));
+
+    // Comments
+    .c {
+        color: #3A6EF2;
+        font-style: italic;
+    }
+
+    // Errors
+    .err {
+        color: #A61717;
+        background-color: #E3D2D2;
+    }
+
+    // Keywords
+    .k {
+        color: @white;
+        font-weight: bold;
+    }
+
+    // Operator
+    .o {
+        color: @white;
+        font-weight: bold;
+    }
+
+    // Multi-line comment
+    .cm {
+        color: #3A6EF2;
+        font-style: italic;
+    }
+
+    // Preprocessor comment
+    .cp {
+        color: #3A6EF2;
+        font-weight: bold;
+    }
+
+    // Inline comment
+    .c1 {
+        color: #3A6EF2;
+        font-style: italic;
+    }
+
+    // Special comment
+    .cs {
+        color: #3A6EF2;
+        font-weight: bold;
+        font-style: italic;
+    }
+
+    // Generic deletion
+    .gd {
+        color: @black;
+        background-color: #FFDDDD;
+    }
+
+    // Generic deletion (specific)
+    .gd .x {
+        background-color: #FFAAAA;
+    }
+
+    // Generic emphasis
+    .ge {
+        font-style: italic;
+    }
+
+    // Generic error
+    .gr {
+        color: #AA0000;
+    }
+
+    // Generic heading
+    .gh {
+        color: #999999;
+    }
+
+    // Generic insertion
+    .gi {
+        color: @black;
+        background-color: #DDFFDD;
+    }
+
+    // Generic insertion (specific)
+    .gi .x {
+        background-color: #AAFFAA;
+    }
+
+    // Generic output
+    .go {
+        color: #888;
+    }
+
+    // Generic prompt
+    .gp {
+        color: #555;
+    }
+
+    // Generic strong
+    .gs {
+        font-weight: bold;
+    }
+
+    // Generic subheading
+    .gu {
+        font-weight: #AAA;
+    }
+
+    // Generic traceback
+    .gt {
+        color: #AA0000;
+    }
+
+    // Keyword.Constant
+    .kc {
+        font-weight: bold;
+    }
+
+    // Keyword.Declaration
+    .kd {
+        font-weight: bold;
+    }
+
+    // Keyword.Pseudo
+    .kp {
+        font-weight: bold;
+    }
+
+    // Keyword.Reserved
+    .kr {
+        font-weight: bold;
+    }
+
+    // Keyword.Type
+    .kt {
+        color: #445588;
+        font-weight: bold;
+    }
+
+    // Literal.Number
+    .m {
+        color: #009999;
+    }
+
+    // Literal.String
+    .s {
+        color: #66FF00;
+    }
+
+    // Name.Attribute
+    .na {
+        color: #99CC99;
+    }
+
+    // Name.Builtin
+    .nb {
+        color: #00AA00;
+    }
+
+    // Name.Class
+    .nc {
+        color: @white;
+        font-weight: bold;
+    }
+
+    // Name.Constant
+    .no {
+        color: @white;
+    }
+
+    // Name.Entity
+    .ni {
+        color: #339999;
+    }
+
+    // Name.Exception
+    .ne {
+        color: #FF0000;
+        font-weight: bold;
+    }
+
+    // Name.Function
+    .nf {
+        color: #FFCC00;
+        font-weight: bold;
+    }
+
+    // Name.Namespace
+    .nn {
+        color: #AAA;
+    }
+
+    // Name.Tag
+    .nt {
+        color: #FF6600;
+    }
+
+    // Name.Variable
+    .nv {
+        color: #BBB;
+    }
+
+    // Operator.Word
+    .ow {
+        font-weight: bold;
+    }
+
+    // Text.Whitespace
+    .w {
+        color: #BBB;
+    }
+
+    // Literal.Number.Float
+    .mf {
+        color: #CCFF33;
+    }
+    .mh { color: #CCFF33 } /* Literal.Number.Hex */
+    .mi { color: #CCFF33 } /* Literal.Number.Integer */
+    .mo { color: #CCFF33 } /* Literal.Number.Oct */
+    .sb { background: #CCCC33; color: #000000 } /* Literal.String.Backtick */
+    .sc { color: #66FF00 } /* Literal.String.Char */
+    .sd { color: #66FF00 } /* Literal.String.Doc */
+    .s2 { color: #66FF00 } /* Literal.String.Double */
+    .se { color: #66FF00 } /* Literal.String.Escape */
+    .sh { color: #66FF00 } /* Literal.String.Heredoc */
+    .si { color: #d555555 } /* Literal.String.Interpol */
+    .sx { color: #66FF00 } /* Literal.String.Other */
+    .sr { color: #009926 } /* Literal.String.Regex */
+    .s1 { color: #66FF00 } /* Literal.String.Single */
+    .ss { color: #339999 } /* Literal.String.Symbol */
+    .bp { color: @lightBlue; font-weight: bold; } /* Name.Builtin.Pseudo */
+    .vc { color: #008080 } /* Name.Variable.Class */
+    .vg { color: #008080 } /* Name.Variable.Global */
+    .vi { color: #008080 } /* Name.Variable.Instance */
+    .il { color: #009999 } /* Literal.Number.Integer.Long */
+}
new file mode 100644
--- /dev/null
+++ b/static/css/code/vs.less
@@ -0,0 +1,35 @@
+.highlight &.vs {
+    .hll { background-color: #ffffcc }
+    .c { color: #008000 } /* Comment */
+    .err { border: 1px solid #FF0000 } /* Error */
+    .k { color: #0000ff } /* Keyword */
+    .cm { color: #008000 } /* Comment.Multiline */
+    .cp { color: #0000ff } /* Comment.Preproc */
+    .c1 { color: #008000 } /* Comment.Single */
+    .cs { color: #008000 } /* Comment.Special */
+    .ge { font-style: italic } /* Generic.Emph */
+    .gh { font-weight: bold } /* Generic.Heading */
+    .gp { font-weight: bold } /* Generic.Prompt */
+    .gs { font-weight: bold } /* Generic.Strong */
+    .gu { font-weight: bold } /* Generic.Subheading */
+    .kc { color: #0000ff } /* Keyword.Constant */
+    .kd { color: #0000ff } /* Keyword.Declaration */
+    .kn { color: #0000ff } /* Keyword.Namespace */
+    .kp { color: #0000ff } /* Keyword.Pseudo */
+    .kr { color: #0000ff } /* Keyword.Reserved */
+    .kt { color: #2b91af } /* Keyword.Type */
+    .s { color: #a31515 } /* Literal.String */
+    .nc { color: #2b91af } /* Name.Class */
+    .ow { color: #0000ff } /* Operator.Word */
+    .sb { color: #a31515 } /* Literal.String.Backtick */
+    .sc { color: #a31515 } /* Literal.String.Char */
+    .sd { color: #a31515 } /* Literal.String.Doc */
+    .s2 { color: #a31515 } /* Literal.String.Double */
+    .se { color: #a31515 } /* Literal.String.Escape */
+    .sh { color: #a31515 } /* Literal.String.Heredoc */
+    .si { color: #a31515 } /* Literal.String.Interpol */
+    .sx { color: #a31515 } /* Literal.String.Other */
+    .sr { color: #a31515 } /* Literal.String.Regex */
+    .s1 { color: #a31515 } /* Literal.String.Single */
+    .ss { color: #a31515 } /* Literal.String.Symbol */
+}
--- a/static/css/imports.less
+++ b/static/css/imports.less
@@ -1,5 +1,15 @@
 @import "variables.less";
 @import "mixins.less";
-@import "code.less";
 @import "agora.less";
 @import "grid.less";
+@import "code.less";
+
+// Add extra stylesheets here
+@import "code/vibrant.less";
+@import "code/autumn.less";
+@import "code/borland.less";
+@import "code/fruity.less";
+@import "code/tango.less";
+@import "code/native.less";
+@import "code/vs.less";
+@import "code/monokai.less";
--- a/static/css/mixins.less
+++ b/static/css/mixins.less
@@ -91,3 +91,7 @@
         .box-shadow(inset 0 0 2px 0 @lightBlue);
     }
 }
+
+.hidden {
+    display: none;
+}
--- a/static/css/variables.less
+++ b/static/css/variables.less
@@ -1,5 +1,6 @@
 // Colour scheme
 @black:             #000;
+@almostBlack:       #1B1B1B;
 @darkerGrey:        #333;
 @darkGrey:          #555;
 @mediumGrey:        #AAA;
@@ -21,7 +22,7 @@
 @fixedWidth:        960px;
 @headerHeight:      100px;
 @headerIconHoverY:  -60px;
-@sidebarWidth:      250px;
+@sidebarWidth:      230px;
 @sidebarLeftSpace:  20px;
 @nonSidebarWidth:   @fixedWidth - @sidebarWidth - @sidebarLeftSpace;
 @inputPadding:      5px;
--- a/templates/base.djhtml
+++ b/templates/base.djhtml
@@ -90,9 +90,10 @@
         <a href="http://inversethought.com/hg/hgwebdir.cgi/agora/">source</a>
         and start contributing. :: About
     </p>
+  </div>
+  <!-- END #footer -->
+    <script src="/static/js/jquery.min.js"></script>
     {% block script_footer %}
     {% endblock %}
-  </div>
-  <!-- END #footer -->
   </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/templates/snippet/explore.html
@@ -0,0 +1,45 @@
+{% extends "snippet/base.djhtml" %}
+
+{% load i18n %}
+
+{% block title %}
+Explore
+{% endblock %}
+
+{% block content %}
+<h2>{% trans "Recent snippets" %}</h2>
+
+{% if recent_snippets %}
+<table class="default">
+    <thead>
+        <tr>
+            <th>{% trans "Snippet title" %}</th>
+            <th>{% trans "Language" %}</th>
+            <th>{% trans "Created on" %}</th>
+            <th>{% trans "User" %}</th>
+        </tr>
+    </thead>
+    <tbody>
+        {% for snippet in recent_snippets %}
+        <tr>
+            <td><a href="{{ snippet.get_absolute_url }}">
+                {{ snippet.get_title }}
+            </a></td>
+            <td>{{ snippet.get_lexer_display }}
+            <td>N/A</td>
+            <td>{% if snippet.author %}
+                <a href="{{ snippet.author.get_absolute_url }}">
+                    {{ snippet.author }}
+                </a>
+                {% else %}
+                {% trans "anonymous" %}
+                {% endif %}
+            </td>
+        </tr>
+    </tbody>
+    {% endfor %}
+</table>
+{% else %}
+<p>{% trans "No snippets have been created yet!" %}</p>
+{% endif %}
+{% endblock %}
--- a/templates/snippet/snippet_details.djhtml
+++ b/templates/snippet/snippet_details.djhtml
@@ -5,7 +5,7 @@
 {% block extrahead %}
 {% if request.session.userprefs %}
 <style type="text/css" media="all">
-  .code{
+  .highlight {
   {# FIXME: Thats stupid #}
   {% ifnotequal request.session.userprefs.font_family "None" %}
   font-family: {{ request.session.userprefs.font_family }} !important;
@@ -22,7 +22,7 @@
 {% endblock %}
 
 {% block title %}
-{% trans "Snippet" %} #{{ snippet.pk }}
+Viewing snippet — {{ snippet.get_title }}
 {% endblock title %}
 
 {% block headline %}
@@ -42,97 +42,84 @@
 {% load snippet_tags %}
 
 {% block content %}
-
-<h2>Snippet view</h2>
-
-<div class="accordion">
-  <div class="info">
-
-    <div id="diff" style="display:none;">
-      diff
+<div id="non-sidebar">
+    <div id="diff">
     </div>
 
-    <h3>
-      {% if snippet.title %}
-      {{ snippet.title }}
-      {% else %}
-      {% trans "Snippet" %} #{{ snippet.id}}
-      {% endif %}
-    </h3>
-
-    <div class="whitebox">
-
-      <div class="snippet-options">
+    <h1>{{ snippet.get_title }}</h1>
+    <div class="snippet-options">
         <abbr title="{% trans "Time to live" %}"
               >TTL:
         </abbr>
         {{ snippet.expires|timeuntil  }}
         &mdash;
         {% if snippet.pk|in_list:request.session.snippet_list %}
-        <a onclick="return confirm('{% trans "Really delete this snippet?" %}')" 
+        <a onclick="return confirm('{% trans "Really delete this snippet?" %}')"
            href="{% url snippet_delete snippet.secret_id %}">
-          Delete now!
+            Delete this snippet
         </a>
         &mdash;
         {% endif %}
-        <a id="toggleWordwrap" href="#">{% trans "Wordwrap" %}</a>
+        <a id="toggle-wordwrap" href="#">{% trans "Toggle wordwrap" %}</a>
+        &mdash;
+        Syntax highlighting style:
+        <select id="change-highlighting"
+                data-default="{{ default_style }}">
+            {% for pygments_style in pygments_styles %}
+            <option name="{{ pygments_style }}">
+                {{ pygments_style }}
+                {% if pygments_style == default_style %}
+                (default)
+                {% endif %}
+            </option>
+            {% endfor %}
+        </select>
         <div>
-         Author:
-         {% if snippet.author %}
-         <a href="{% url agora.apps.profile.views.showprofile snippet.author %}">
-           {{ snippet.author }}
-         </a>
-         {% else %}
-         anonymous
-         {% endif %}
-         &mdash;
-         Language: {{language}}
+            Author:
+            {% if snippet.author %}
+            <a href="{% url agora.apps.profile.views.showprofile snippet.author %}">
+            {{ snippet.author }}
+            </a>
+            {% else %}
+            anonymous
+            {% endif %}
+            &mdash;
+            Language: {{language}}
         </div>
-      </div>
-
-      <br />
-
-      <div class="snippet">
+    </div>
+    <br />
+    <div class="snippet">
         <table>
-          <tr>
-            <th>
-              {# this has to look like this due to the pre tags #}
-              <pre class="code">{% for l in lines %}<a href="#l{{ forloop.counter }}" id="l{{ forloop.counter }}">{{ forloop.counter }}</a> 
-{% endfor %}</pre>
-            </th>
-            <td>
-              {# this has to look like this due to the pre tags #}
-              <pre class="code">{% for line in snippet.content_splitted %}<span class="line" id="l{{ forloop.counter }}">{% if line %}{{ line|safe }}{% else %}&nbsp;{% endif %}</span>
+            <tr>
+                <th id="line-numbers">
+                    {# this has to look like this due to the pre tags #}
+                    <pre class="numbers">{% for l in lines %}<a href="#l{{ forloop.counter }}" id="l{{ forloop.counter }}">{{ forloop.counter }}</a>
 {% endfor %}</pre>
-            </td>
-          </tr>
+                </th>
+                <td>
+                    {# this has to look like this due to the pre tags #}
+                    <pre class="highlight {{ default_style }}">{% for line in snippet.content_splitted %}<span class="line" id="l{{ forloop.counter }}">{% if line %}{{ line|safe }}{% else %}&nbsp;{% endif %}</span>
+{% endfor %}</pre>
+                </td>
+            </tr>
         </table>
-      </div>
+    </div>
 
-    </div> {#whitebox#}
-
-  </div> {# info #}
+    <br />
 
-  <div class="info">
-    <h3>{% trans "Write an answer" %} &rarr;</h3>
-    <div class="accordion" style="display: none;">
-      <div class="whitebox">
-        {% include "snippet/snippet_form.djhtml" %}
-      </div>
-    </div>
-  </div>
-</div>
-{% endblock %}
+    <h2 id="revise">{% trans "Revise this snippet" %}</h2>
 
-
-
-{% block content-related %}
-<div class="info">
-
-  <h3>{% trans "History" %}</h3>
-
-  <div class="whitebox">
-
+    {% include "snippet/snippet_form.djhtml" %}
+</div><div id="sidebar">
+    <h2>{% trans "History" %}</h2>
+    {% if no_descendants %}
+        <p>{% trans "This snippet has no children!" %}</p>
+        <p>
+            <a href="#revise">
+            {% trans "Make one" %} &raquo;
+            </a>
+        </p>
+    {% else %}
     <form method="get" id="diffform" action="{% url snippet_diff %}">
       <div class="tree">
         {% for tree_item,structure in tree|tree_info %}
@@ -158,21 +145,11 @@
                        {% endifequal %}/>
               </span>
               {% ifequal snippet tree_item %}
-              <strong>
-                {% if tree_item.title %}
-                {{ tree_item.title }}
-                {% else %}
-                {% trans "Snippet" %} #{{ tree_item.id }}
-                {% endif %}
-              </strong>
+                <strong>{{ tree_item.get_title }}</strong>
               {% else %}
-              <a href="{{ tree_item.get_absolute_url }}">
-                {% if tree_item.title %}
-                {{ tree_item.title }}
-                {% else %}
-                {% trans "Snippet" %} #{{ tree_item.id }}
-                {% endif %}
-              </a>
+                <a href="{{ tree_item.get_absolute_url }}">
+                    {{ tree_item.get_title }}
+                </a>
               {% endifequal %}
             </div>
             {% for level in structure.closed_levels %}
@@ -185,25 +162,17 @@
         </div>
       </div>
     </form>
-
-  </div> {# whitebox #}
-
-</div> {# info #}
-
-<div class="info">
-  <h3>{% trans "Options" %}</h3>
-  <div class="whitebox">
-       <p>
-         <a href="{% url snippet_details_raw snippet.secret_id %}">
-           {% trans "View raw" %}
-         </a>
-       </p>
+    {% endif %}
+    <br />
+    <h2>{% trans "Options" %}</h2>
+    <a href="{% url snippet_details_raw snippet.secret_id %}">
+       {% trans "View raw" %}
+     </a>
 </div>
-{% endblock content-related %}
+</div>
+{% endblock %}
 
 {% block script_footer %}
-<script src="/static/jquery.min.js"></script>
-<script src="/static/jquery-ui.min.js"></script>
 <script type="text/javascript">
 {%include "snippet/snippet_details.js" %}
 </script>
--- a/templates/snippet/snippet_details.js
+++ b/templates/snippet/snippet_details.js
@@ -1,18 +1,10 @@
-
-jQuery(document).ready(function(){
+jQuery(document).ready(function () {
 
     curLine = document.location.hash;
     if(curLine.substring(0,2) == '#l'){
         $('div.snippet div.line'+curLine).addClass('marked');
     }
 
-    $("div.accordion").accordion({
-       autoHeight: false,
-       header: 'h3',
-       animation: 'bounceslide',
-       duration: 2000
-    });
-
     /**
     * Diff Ajax Call
     */
@@ -27,18 +19,28 @@
     });
 
     /**
-    * Wordwrap
+    * Word wrap
     */
-    $('#toggleWordwrap').toggle(
-        function(){
-            $('div.snippet pre.code').css('white-space', 'pre-wrap');
-            return false;
-        },
-        function(){
-            $('div.snippet pre.code').css('white-space', 'pre');
-            return false;
-        }
-    );
+    $('#toggle-wordwrap').click(function () {
+        // Hide the line numbers (otherwise they could be wrong)
+        $('#line-numbers').toggle();
+
+        // Toggle the wrapping on the highlighted code
+        $('.highlight').toggleClass('wrap');
+
+        return false;
+    });
+
+    /**
+    * Changing syntax highlighting colours
+    */
+    var currentStyle = $('#change-highlighting').attr('data-default');
+    $('#change-highlighting').change(function () {
+        var newStyle = $(this).find(':selected').attr('name');
+
+        $('.highlight').removeClass(currentStyle).addClass(newStyle);
+        currentStyle = newStyle;
+    });
 
     /**
     * Line Highlighting
--- a/templates/snippet/snippet_new.djhtml
+++ b/templates/snippet/snippet_new.djhtml
@@ -6,60 +6,33 @@
 {% block content %}
     <div id="non-sidebar">
         <h1>{% trans "Paste a new snippet" %}</h1>
-        <p class="hint">Snippets are a lorem ipsum</p>
+        <p class="hint">{% trans "Snippets provide a way to quickly share pieces of code, complete with line-numbering and syntax-highlighting." %} {% if not user.is_authenticated %}{% trans "Although registration is not required, only registered users can delete their own snippets after ending a session or have them linked to their profile." %}{% endif %}</p>
         {% include "snippet/snippet_form.djhtml" %}
     </div><div id="sidebar">
         <h2>Recent snippets</h2>
         {% for snippet in recent_snippets %}
         <hr />
-        <p><a href="{% url snippet_details snippet %}">
-        {% if snippet.title %}
-        {{ snippet.title }}
-        {% else %}
-        Snippet #{{ snippet.id }}
-        {% endif %}
-        </a>
-        <br />
-        by
-        {% if snippet.author %}
-            <a href="{% url show_profile snippet.author %}">{{ snippet.author }}</a>
-        {% else %}
+        <p>
+            <a href="{{ snippet.get_absolute_url }}">
+                {{ snippet.get_title }}
+            </a>
+            <br />
+            by
+            {% if snippet.author %}
+                <a href="{{ snippet.author.get_absolute_url }}">
+                    {{ snippet.author }}
+                </a>
+            {% else %}
             anonymous
-        {% endif %}
+            {% endif %}
         </p>
         {% endfor %}
+        <p class="right-float"><a href="{% url snippet_explore %}">
+            {% trans "View more" %} &raquo;
+        </a></p>
     </div>
 {% endblock %}
 
-
-{% block content-related %}
-    <h2>Recent snippets</h2>
-    <div class="whitebox">
-      <ul>
-        {% for r in recent %}
-        <li>
-          <a href="{% url snippet_details r %}">
-            {% if r.title %}
-            {{r.title}}
-            {% else %}
-            Snippet #{{r.pk}}
-            {% endif %}
-          </a>
-        by
-          {% if r.author %}
-          <a href="{% url agora.apps.profile.views.showprofile r.author %}">
-            {{r.author}}
-          </a>
-          {% else %}
-          anonymous
-          {% endif %}
-          {% endfor %}
-        </li>
-      </ul>
-    </div>
-{% endblock %}
-
-
 {% block script_footer %}
 <script src="/static/jquery.min.js"></script>
 <script type="text/javascript">