Creating new Themes from scratch

Topics: Writing modules, Writing themes
Dec 8, 2013 at 4:30 PM
I'm finding it hard to find and tutorials on creating a new theme from nothing. I dont want to copy an existing theme and then spend hours trying to work out what half of the bits do.

Most tutorials I can find just seem to show you how to edit and change small parts of already created ones without really explaining whats going on.

I see lots of stuff like

string CalcuClassify(string[] zoneNames, string classNamePrefix) {.....

Func<dynamic, dynamic> Zone = x => Display(x);

var asideClass = CalcuClassify(new [] {"Sidebar"}, "aside-");


which I cannot find any explanation for.

Billy
Developer
Dec 8, 2013 at 4:42 PM
Hi Billy,

Although you can hardly call this a tutorial, but this is what needs to be done to create a theme from scratch:
  1. Generate a new Theme project using the Orchard.exe command line.
  2. In the Views folder, create a file called Layout.cshtml. This file will only contain the markup you need in the <body> element. Orchard will provide a shape called Document.cshtml out of the box (which you could copy into your theme should you wish more control over its HMTL).
  3. At the very minimum, in Layout.cshtml, add the following line: @Display(Model.Content). This will render anything that Orchard adds to the Content zone.
  4. Define the Content zone in your theme's manifest (Theme.txt). Look at TheThemeMachine how this looks if you're unsure.
That's it. What remains is adding markup, stylesheets and scripts, and most likely overriding views from modules. Use the Shape Tracer feature to find shapes you wish to customize. And of course look at existing themes to see how certain things are done, such as including scripts and styles from your views without having to override Document.cshtml (which is not bad if you must, but generally unnecessary). As a hint, use Script.Include("my-script.js") to include scripts and Style.Include("my-style.css") to include styles.

Hope this helps you at least get started.
Dec 8, 2013 at 4:59 PM
Edited Dec 8, 2013 at 5:01 PM
Thanks for that but again this is exactly my problem.

I have pretty much worked out how to do the above. But this is the equivalent to a 'Hello world' demo (nice but useless). It quickly gets something on screen but it doesn't really explain in depth how to create a full blown theme.

I can find plenty of simple lets get started tutorials but nothing more advanced.

Lets take the TheThemeMachine for example. There is a hell of a lot more going on in there than just a simple @Display(Model.Content). How do you alter / change / create different zones?

Whats all this \/ about.

string CalcuClassify(string[] zoneNames, string classNamePrefix) {.....

Func<dynamic, dynamic> Zone = x => Display(x);

I could spend hours debugging through the source but I would much prefer a good tutorial.


Billy
Developer
Dec 8, 2013 at 5:26 PM
Edited Dec 8, 2013 at 5:27 PM
Perhaps this video might help you to at least get started with something more advanced: http://www.youtube.com/watch?v=rk1iJJJ9Itg.
As for your questions on an existing theme called TheThemeMachine:
  1. CalcuClassify essentially creates a class name based on a list of zone names, which renders a CSS class with a count for the specified zones that have content. Using CSS, you can then provide proper styles when for example a div element contains just 2 children, instead of 4. For example, TheThemeMachine renders FooterQuadFirst, FooterQuadSecond, FooterQuadThird and FooterQuadFourth zones, each with a fixed with. However, if the user adds content to just FooterQuadFirst, we want to have that zone take up the entire width, instead of 1/4th. So we render a class called "quad-1" on the wrapper div. If two of those zones have content, a class called "quad-2" would be rendered, for which CSS exists to specify proper widths. One thing to understand here is that you don't have to reuse this at all in your own theme. It's just an idea you could reuse.
  2. Func<dynamic, dynamic> Zone = x => Display(x); is just a C# lambda assigned to a variable called Zone, essentially creating an alias for the Display method, so you can use @Zone(Model.MyZoneName) instead of @Display(Model.MyZoneName). Same as with #1: you can copy this to your theme, or just stick with @Display and don't bother.
If you have specific questions, just ask.
Dec 8, 2013 at 6:17 PM
Thank you. I shall look over than now :-)
Dec 11, 2013 at 5:28 PM
Inside the edit view of a widget you get a

Title and the option to 'Render the title on the front-end'

If you render that title it is displayed inside an <h1></h1>.

How would I render that into an <h2> I dont appear to be able to do this with a shape (if that's the terminology).

I really like this system but there also doesn't seem to be any clear direction on whether a thing should be a widget a content type (made into a widget) a module etc.
Coordinator
Dec 11, 2013 at 5:35 PM
Developer
Dec 11, 2013 at 5:42 PM
The way to do that is by copying the Razor file responsible for rendering that specific shape into your theme, from where you will apply the desired change.
To find out which shape you want to override, enable the Shape Tracing feature. When enabled, you'll see a small toolbar on the bottom of the page which you can expand. When expanded, you can hover your mouse cursor onto the thing you want to override. The Shape Tracer will show you which alternates are available, and provides an option to create a Razor file for the desired alternate in your theme, which you can then customize as you see fit.

Regarding your remark, think of it like this:
  • A Module is like a reusable/portable MVC area and provides controllers, classes, scripts, styles, filters, migrations, views, etc.
  • A Widget IS a content type. Whether you turn a content type into a widget depends on whether you want the admin user to be able to place content items of this type into zones other than the Content zone (and whether you want him to enable to add multiple items of that type to zones).
Dec 11, 2013 at 7:03 PM
Edited Dec 11, 2013 at 8:20 PM
Turning the Title of a widget when displayed from <h1> to <h2>

For anybody Curious this is how I did it

I added the file Widget.{MY_WIDGET_NAME}.cshtml

and put in that file the following
@* This overrides the default widget wrapper *@

@using Orchard.ContentManagement
@using Orchard.Widgets.Models

@{
  Model.Metadata.Wrappers.Remove("Widget_Wrapper");
  var widgetPart = ((IContent)Model.ContentItem).As<WidgetPart>();
  var tag = Tag(Model, "article");
}

@tag.StartElement
  @if ((widgetPart.RenderTitle && HasText(widgetPart.Title)) || Model.Header != null) {
    <header>
      @if ((widgetPart.RenderTitle && HasText(widgetPart.Title))) {
        <h2>@widgetPart.Title</h2>
      }
      @Display(Model.Header)
    </header>
  }
  @Display(Model.Content)
  @if(Model.Footer != null) {
    <footer>
      @Display(Model.Footer)
    </footer>
  }
@tag.EndElement