My challenge today was to come up with a way to provide easier
skinning for the blog4umbraco package. Today there's several
challenges if you want to get up to speed fast with the current
blog4umbraco package:
- The default skin is old
- There are layout quirks (such as the comment form doesn't align
- yikes!)
- Alternative skins for blog4umbraco are scattered and there's no
conventions
- Changing a skin requires good knowledge of Umbraco terms such
as doctypes, templates and macros. Not easy to get started
The problems above is not unique to blog4umbraco, but a general
thing with Umbraco as we like to see ourselves as a framework. This
- however - shouldn't prevent us from making it easier to get
quickly up to speed for newcomers. And as most people know, once
you got something that you can relate to, it's more motivating to
dive in.
Bring in the skin
The solution is to create a convention for skins that in the
current project benefits blog4umbraco, but over time could benefit
other projects such as Warren Buckleys
Creative Website Wizard, Runway and the hot new
Business Website Starter Pack.
As I'm a fan of keeping things simple and to the point and as
we're talking simple skinning (not fancy theming) I decided to keep
skins CSS+images only. If the markup is cool, the possibilities
with CSS alone is incredible and for more fancy stuff we have the
package format to take care of that. So without further ado, let me
introduce the new Skin format for Umbraco packages:
What is a skin?
Skins for Umbraco is a zip file containing CSS + images as well
as a manifest, a thumbnail and a preview image.
The structure of the zip must be:
- /thumbnail.png (a 100x100 pixel thumbnail in png format)
- /preview.png (a 500xYYY pixel preview in png format)
- /skin.xml (a manifest file containing meta data about you and
your skin. See example skin.xml
and grab the XSD
for Visual Studio intellisense)
- /css/style.css (your css file. Must be named 'style.css')
- /css/images/* (images for your css)
User experience
The idea is to host skins in the package repository and make
them relate to a specific project. That project can include a new
datatype (Skin Browser) which gets configured with some help text
as well as a URI that acts as the identifier to fetch skins from
the repository. To use skinning in a package all you need to do
(once you've got your project approved in the package repo by the
evil Umbraco HQ) is to place the Skin Browser data type on the root
page of your package content:

The skin browser will show you the current skin used and will
store the reference to the css file (ie. /css/pixel/style.css).
This can easily be used in templates by using the recursive option
when inserting an Umbraco field: <umbraco:Item runat="server"
id="skin" Field="css" recursive="true" />
When clicking the "Browse skins from Umbraco Package Server"
it'll query the repository for a list of skins that matches the
project:

When clicking on the "Use this skin" link, it'll download the
skin, extract it and update the css reference (the value of the
"Skin Browser" property). When you publish the page you'll then use
the new skin.
Nice Balsamiq Mockups - is this vapor?
Well, ehm. The Christmas Calendar manifest say that we can't use
more than an hour a day. I've spend three in total (which will make
it up for the coming Saturday and Sunday) and managed to make the
concept, mockups and formats. But not the datatype - that'll have
to wait for one of the coming days. But I did manage to build the
server part as well as the submit skin functionality which made me
positively surprised of the development speed I gain from Umbraco
(nice plug, aye ;-) - but bear with me, I almost don't do
implementations anymore).
On our package repository - which runs Umbraco of course - I
created a "skins" document type which will be the placeholder for a
project (such as "blog4umbraco") as well as a "skin" document type
that holds all the metadata:

Using XSLT it was really easy to make a feed that the coming
data type can use to fetch the different skins (see the
XSLT here) and using alternative templates I can now fetch the
list of skins by calling the URL of the project in the repository
combined with the alias of my listing template "getskinsasxml":
http://packages.umbraco.org/skins/blog4umbraco/getskinsasxml
Uploading a new skin
I also managed to make a nice little usercontrol that lets
you upload your skin (the zip file) and then extract all the
meta data and create a new skin as a content object. Using
notifications in Umbraco it'll automatically notify moderators to
review the submitted skin before publishing it (and thus, making it
publicly available in the feed). Again I used alternative templates
to make it easy to know which project to associate the uploaded
item for. I simply append "uploadskin" to the url and then I know
that the current page is the correct skin:
http://packages.umbraco.org/skins/blog4umbraco/uploadskin
One important thing when using alternative templates for
something like this that you're responsible for verifying that the
alternative template is used on the appropriate type (as
alternative templates bypasses the template rules on a doctype). To
do this I added a simple check in the Page Load event where I use
the nodefactory to verify that the current page indeed has a
document type of "skins" (ie. our project placeholder type):
if (Node.GetCurrent().NodeTypeAlias.ToLower() != "skins")
{
throw new Exception("Can only upload skins to
skin repositories");
}
So now we got the skinning infrastructure in place. All we need
to do next is building the custom data type using the
AbstractDataEditor which makes it easy to build a configurable
custom data type as opposed to just using the User Control Wrapper
data type which makes it super easy to build a custom data type,
but doesn't support configuration.
We also need to look at the markup for the blog4umbraco
templates to see if it's as good as it should be. If anyone wants
to help with that or help making skins - let us know!
Merry Christmas :)