refinerycms-theming 0.9.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/app/helpers/themes_helper.rb +34 -0
- data/app/models/theme.rb +7 -0
- data/features/step_definitions/theme_generator_steps.rb +15 -0
- data/features/theme_generator.feature +16 -0
- data/lib/gemspec.rb +29 -0
- data/lib/generators/refinery_theme/README +17 -0
- data/lib/generators/refinery_theme/Rakefile +11 -0
- data/lib/generators/refinery_theme/USAGE +2 -0
- data/lib/generators/refinery_theme/refinery_theme_generator.rb +23 -0
- data/lib/generators/refinery_theme/templates/stylesheets/application.css +5 -0
- data/lib/generators/refinery_theme/templates/stylesheets/formatting.css +7 -0
- data/lib/generators/refinery_theme/templates/stylesheets/home.css +5 -0
- data/lib/generators/refinery_theme/templates/views/layouts/application.html.erb +21 -0
- data/lib/generators/refinery_theme/templates/views/pages/home.html.erb +4 -0
- data/lib/generators/refinery_theme/templates/views/pages/show.html.erb +4 -0
- data/lib/refinerycms-theming.rb +47 -0
- data/lib/theme_server.rb +32 -0
- data/lib/theming.rb +2 -0
- data/license.md +21 -0
- data/readme.md +118 -0
- data/refinerycms-theming.gemspec +88 -0
- data/themes/demolicious/LICENSE +21 -0
- data/themes/demolicious/README +1 -0
- data/themes/demolicious/images/footer_background.png +0 -0
- data/themes/demolicious/images/header_background.png +0 -0
- data/themes/demolicious/stylesheets/application.css +105 -0
- data/themes/demolicious/stylesheets/formatting.css +36 -0
- data/themes/demolicious/stylesheets/home.css +5 -0
- data/themes/demolicious/stylesheets/ie6.css +0 -0
- data/themes/demolicious/stylesheets/ie7.css +0 -0
- data/themes/demolicious/views/layouts/application.html.erb +27 -0
- data/themes/demolicious/views/pages/home.html.erb +1 -0
- data/themes/demolicious/views/pages/show.html.erb +1 -0
- data/themes/hemingway/LICENSE +7 -0
- data/themes/hemingway/README +3 -0
- data/themes/hemingway/images/archives.gif +0 -0
- data/themes/hemingway/images/footer_black.gif +0 -0
- data/themes/hemingway/images/kyle-header.jpg +0 -0
- data/themes/hemingway/images/readon_black.gif +0 -0
- data/themes/hemingway/images/search.gif +0 -0
- data/themes/hemingway/images/spinner.gif +0 -0
- data/themes/hemingway/images/trackback_pingback.gif +0 -0
- data/themes/hemingway/stylesheets/application.css +713 -0
- data/themes/hemingway/stylesheets/formatting.css +1 -0
- data/themes/hemingway/stylesheets/home.css +1 -0
- data/themes/hemingway/views/layouts/application.html.erb +45 -0
- metadata +127 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
module ThemesHelper
|
2
|
+
def image_tag(source, options={})
|
3
|
+
theme = (options.delete(:theme) == true)
|
4
|
+
tag = super
|
5
|
+
# inject /theme/ into the image tag src if this is themed.
|
6
|
+
tag.gsub!(/src=[\"|\']/) { |m| "#{m}/theme/" }.gsub!("//", "/") if theme
|
7
|
+
tag.gsub(/theme=(.+?)\ /, '') # we need to remove any addition of theme='false' etc.
|
8
|
+
end
|
9
|
+
|
10
|
+
def javascript_include_tag(*sources)
|
11
|
+
theme = (arguments = sources.dup).extract_options![:theme] == true # don't ruin the current sources object
|
12
|
+
tag = super
|
13
|
+
# inject /theme/ into the javascript include tag src if this is themed.
|
14
|
+
tag.gsub!(/\/javascripts\//, "/theme/javascripts/") if theme
|
15
|
+
tag.gsub(/theme=(.+?)\ /, '') # we need to remove any addition of theme='false' etc.
|
16
|
+
end
|
17
|
+
|
18
|
+
def stylesheet_link_tag(*sources)
|
19
|
+
theme = (arguments = sources.dup).extract_options![:theme] == true # don't ruin the current sources object
|
20
|
+
tag = super
|
21
|
+
# inject /theme/ into the stylesheet link tag href if this is themed.
|
22
|
+
tag.gsub!(/\/stylesheets\//, "/theme/stylesheets/") if theme
|
23
|
+
tag.gsub(/theme=(.+?)\ /, '') # we need to remove any addition of theme='false' etc.
|
24
|
+
end
|
25
|
+
|
26
|
+
def image_submit_tag(source, options = {})
|
27
|
+
theme = (options.delete(:theme) == true)
|
28
|
+
|
29
|
+
tag = super
|
30
|
+
# inject /theme/ into the image tag src if this is themed.
|
31
|
+
tag.gsub!(/src=[\"|\']/) { |m| "#{m}/theme/" }.gsub!("//", "/") if theme
|
32
|
+
tag.gsub(/theme=(.+?)\ /, '') # we need to remove any addition of theme='false' etc.
|
33
|
+
end
|
34
|
+
end
|
data/app/models/theme.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Before do
|
2
|
+
@theme_generator_root = File.join(File.dirname(__FILE__), "/../../")
|
3
|
+
@tmp_refinery_app_name = "tmp_refinery_app"
|
4
|
+
@tmp_refinery_app_root = File.join(@theme_generator_root, @tmp_refinery_app_name)
|
5
|
+
@app_root = @tmp_refinery_app_root
|
6
|
+
Rails::Generator::Base.append_sources(Rails::Generator::PathSource.new(:theme, "#{@theme_generator_root}/generators/"))
|
7
|
+
end
|
8
|
+
|
9
|
+
After do
|
10
|
+
FileUtils.rm_rf(@tmp_refinery_app_root)
|
11
|
+
end
|
12
|
+
|
13
|
+
When /^I generate a theme with the name of "([^"]*)"$/ do |name|
|
14
|
+
Rails::Generator::Scripts::Generate.new.run(['refinery_theme', name], {:quiet => true, :destination => @app_root})
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
Feature: Theme generation
|
2
|
+
In order to create my own theme
|
3
|
+
As a refinery user
|
4
|
+
I want to generate a basic theme directory structure
|
5
|
+
|
6
|
+
Scenario: Generating a theme with a name
|
7
|
+
Given I have a refinery application
|
8
|
+
When I generate a theme with the name of "modern"
|
9
|
+
Then I should have a directory "themes/modern"
|
10
|
+
And I should have a file "themes/modern/stylesheets/application.css"
|
11
|
+
And I should have a file "themes/modern/stylesheets/home.css"
|
12
|
+
And I should have a file "themes/modern/stylesheets/formatting.css"
|
13
|
+
And I should have a file "themes/modern/views/layouts/application.html.erb"
|
14
|
+
And I should have a file "themes/modern/views/pages/home.html.erb"
|
15
|
+
And I should have a file "themes/modern/views/pages/show.html.erb"
|
16
|
+
And I should have a directory "themes/modern/javascripts"
|
data/lib/gemspec.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
version = '0.9.8'
|
3
|
+
raise "Could not get version so gemspec can not be built" if version.nil?
|
4
|
+
files = Dir[%q{**/*}].flatten.reject{|f| f =~ /\.gem$/}
|
5
|
+
|
6
|
+
gemspec = <<EOF
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = %q{refinerycms-theming}
|
9
|
+
s.version = %q{#{version}}
|
10
|
+
s.description = %q{Theming functionality for the Refinery CMS project, extracted from Refinery CMS core.}
|
11
|
+
s.date = %q{#{Time.now.strftime('%Y-%m-%d')}}
|
12
|
+
s.summary = %q{Theming functionality for the Refinery CMS project.}
|
13
|
+
s.email = %q{info@refinerycms.com}
|
14
|
+
s.homepage = %q{http://refinerycms.com}
|
15
|
+
s.authors = %w(Resolve\\ Digital)
|
16
|
+
s.require_paths = %w(lib)
|
17
|
+
|
18
|
+
s.files = [
|
19
|
+
'#{files.join("',\n '")}'
|
20
|
+
]
|
21
|
+
#{"s.test_files = [
|
22
|
+
'#{Dir.glob("test/**/*.rb").join("',\n '")}'
|
23
|
+
]" if File.directory?("test")}
|
24
|
+
|
25
|
+
s.add_dependency('refinerycms', '>= 0.9.8')
|
26
|
+
end
|
27
|
+
EOF
|
28
|
+
|
29
|
+
File.open(File.expand_path("../../refinerycms-theming.gemspec", __FILE__), 'w').puts(gemspec)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
== Refinery Theme Generator
|
2
|
+
|
3
|
+
== Description
|
4
|
+
|
5
|
+
Generate a new barebones Refinery theme.
|
6
|
+
|
7
|
+
If you want this new theme to be the current theme used, set the "theme"
|
8
|
+
setting in the Refinery backend to the name of this theme.
|
9
|
+
|
10
|
+
== Usage
|
11
|
+
rails generate refinery_theme theme_name
|
12
|
+
|
13
|
+
== Example
|
14
|
+
rails generate refinery_theme modern
|
15
|
+
|
16
|
+
Results in:
|
17
|
+
create /themes/modern/...
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Generate documentation for the Refinery Theme Generator plugin.'
|
6
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
7
|
+
rdoc.rdoc_dir = 'rdoc'
|
8
|
+
rdoc.title = 'Refinery Theme Generator'
|
9
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
10
|
+
rdoc.rdoc_files.include('README')
|
11
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class RefineryThemeGenerator < Rails::Generators::Base
|
2
|
+
source_root File.expand_path('../templates', __FILE__)
|
3
|
+
argument :theme_name, :type => :string
|
4
|
+
|
5
|
+
def create_theme
|
6
|
+
copy_file "stylesheets/application.css", "themes/#{theme_name}/stylesheets/application.css"
|
7
|
+
copy_file "stylesheets/formatting.css", "themes/#{theme_name}/stylesheets/formatting.css"
|
8
|
+
copy_file "stylesheets/home.css", "themes/#{theme_name}/stylesheets/home.css"
|
9
|
+
|
10
|
+
copy_file "views/layouts/application.html.erb", "themes/#{theme_name}/views/layouts/application.html.erb"
|
11
|
+
|
12
|
+
copy_file "views/pages/show.html.erb", "themes/#{theme_name}/views/pages/show.html.erb"
|
13
|
+
copy_file "views/pages/home.html.erb", "themes/#{theme_name}/views/pages/home.html.erb"
|
14
|
+
|
15
|
+
if RefinerySetting.get(:theme).nil?
|
16
|
+
RefinerySetting.set(:theme, theme_name)
|
17
|
+
puts "NOTE: \"theme\" setting created and set to #{theme_name}"
|
18
|
+
else
|
19
|
+
puts 'NOTE: If you want this new theme to be the current theme used, set the "theme" setting in the Refinery backend to the name of this theme.' unless RAILS_ENV == "test"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
@import url('/stylesheets/refinery/formatting.css');
|
2
|
+
/*
|
3
|
+
Override default refinery formatting below.
|
4
|
+
Formatting applies to backend WYSIWYG editors and all frontend.
|
5
|
+
This is the best place to put your heading and text related styles
|
6
|
+
like colours, fonts and line-height.
|
7
|
+
*/
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<%= render :partial => "/shared/head", :locals => {:theme => true} %>
|
4
|
+
<body>
|
5
|
+
<%= render :partial => "/shared/site_bar" %>
|
6
|
+
<div id='page_container'>
|
7
|
+
<div id='page'>
|
8
|
+
<%= render :partial => "/shared/ie6check" if request.env['HTTP_USER_AGENT'] =~ /MSIE/ -%>
|
9
|
+
<div id='header'>
|
10
|
+
<%= render :partial => "/shared/header" %>
|
11
|
+
</div>
|
12
|
+
<div id='body' class='clearfix'>
|
13
|
+
<%= yield %>
|
14
|
+
</div>
|
15
|
+
<div id='footer'>
|
16
|
+
<%= render :partial => "/shared/footer" %>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
</body>
|
21
|
+
</html>
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.expand_path('../theming', __FILE__)
|
2
|
+
|
3
|
+
module Refinery
|
4
|
+
class ThemingEngine < ::Rails::Engine
|
5
|
+
|
6
|
+
config.to_prepare do
|
7
|
+
::ApplicationController.module_eval do
|
8
|
+
|
9
|
+
# Add or remove theme paths to/from Refinery application
|
10
|
+
prepend_before_filter :attach_theme_to_refinery
|
11
|
+
|
12
|
+
def attach_theme_to_refinery
|
13
|
+
# remove any paths relating to any theme.
|
14
|
+
view_paths.reject! { |v| v.to_s =~ %r{^themes/} }
|
15
|
+
|
16
|
+
# add back theme paths if there is a theme present.
|
17
|
+
if (theme = ::Theme.current_theme(request.env)).present?
|
18
|
+
# Set up view path again for the current theme.
|
19
|
+
view_paths.unshift Rails.root.join("themes", theme, "views").to_s
|
20
|
+
|
21
|
+
# Ensure that routes within the application are top priority.
|
22
|
+
# Here we grab all the routes that are under the application's view folder
|
23
|
+
# and promote them ahead of any other path.
|
24
|
+
view_paths.select{|p| p.to_s =~ %r{^#{Rails.root.join('app', 'views')}}}.each do |app_path|
|
25
|
+
view_paths.unshift app_path
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Set up menu caching for this theme or lack thereof
|
30
|
+
if RefinerySetting.table_exists? and
|
31
|
+
RefinerySetting.get(:refinery_menu_cache_action_suffix) != (suffix = "#{"#{theme}_" if theme.present?}site_menu")
|
32
|
+
RefinerySetting.set(:refinery_menu_cache_action_suffix, suffix)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
protected :attach_theme_to_refinery
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
::ApplicationHelper.send :include, ::ThemesHelper
|
40
|
+
end
|
41
|
+
|
42
|
+
initializer 'themes.middleware' do |app|
|
43
|
+
app.config.middleware.insert_before ::ActionDispatch::Static, ::Refinery::ThemeServer
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
data/lib/theme_server.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Allow the metal piece to run in isolation
|
2
|
+
require File.expand_path('../../../config/environment', __FILE__) unless defined?(Rails)
|
3
|
+
|
4
|
+
# Serves theme files from the theme directory without touching Rails too much
|
5
|
+
module Refinery
|
6
|
+
class ThemeServer
|
7
|
+
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
if env["PATH_INFO"] =~ /^\/theme\/(stylesheets|javascripts|images)/ and (theme = Theme.current_theme(env)).present?
|
14
|
+
env["PATH_INFO"].gsub!(/^\/theme\//, '')
|
15
|
+
if (file_path = (dir = Rails.root.join("themes", theme)).join(env["PATH_INFO"])).exist?
|
16
|
+
etag = Digest::MD5.hexdigest("#{file_path.to_s}#{file_path.mtime}")
|
17
|
+
unless (etag == env["HTTP_IF_NONE_MATCH"])
|
18
|
+
status, headers, body = Rack::File.new(dir).call(env)
|
19
|
+
[status, headers.update({"ETag" => etag}), body]
|
20
|
+
else
|
21
|
+
[304, {"ETag" => etag}, []]
|
22
|
+
end
|
23
|
+
else
|
24
|
+
[404, {}, []]
|
25
|
+
end
|
26
|
+
else
|
27
|
+
@app.call(env)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
data/lib/theming.rb
ADDED
data/license.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2005-2010 [Resolve Digital Ltd.](http://www.resolvedigital.co.nz)
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/readme.md
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
# Themes
|
2
|
+
|
3
|
+
## Introduction
|
4
|
+
|
5
|
+
__Themes allow you to wrap up the design of your Refinery site into a single folder that is portable.__
|
6
|
+
|
7
|
+
Refinery doesn't force you to learn a special templating language, but rather just uses the regular
|
8
|
+
ERB views you're used to in Rails. This means creating a theme from your existing site is extremely easy.
|
9
|
+
|
10
|
+
Think of a theme as your ``app/views`` directory with a few extra things like images, css and javascript.
|
11
|
+
|
12
|
+
It's worth noting you don't need to use a theme if you don't want to. Placing files in the ``app/views`` directory like any other Rails app will work just fine. It's only if you want to wrap your design up into a single location that you would use a theme or allow your client to easily change between designs.
|
13
|
+
|
14
|
+
## The Structure of a Theme
|
15
|
+
|
16
|
+
Themes sit in your Rails app like this
|
17
|
+
|
18
|
+
app/
|
19
|
+
config/
|
20
|
+
db/
|
21
|
+
lib/
|
22
|
+
public/
|
23
|
+
themes/
|
24
|
+
|- mytheme/
|
25
|
+
|- othertheme/
|
26
|
+
plugins/
|
27
|
+
tests/
|
28
|
+
|
29
|
+
Let's take the ``mytheme`` example theme shown above. This is how the theme is structured:
|
30
|
+
|
31
|
+
mytheme/
|
32
|
+
|- images
|
33
|
+
| |- whatever.png
|
34
|
+
| |- foo.jpg
|
35
|
+
|- javascripts
|
36
|
+
| |- whatever.js
|
37
|
+
|- LICENSE
|
38
|
+
|- README
|
39
|
+
|- stylesheets/
|
40
|
+
| |- application.css
|
41
|
+
| |- whatever.css
|
42
|
+
|- views
|
43
|
+
|- pages
|
44
|
+
| |- show.html.erb
|
45
|
+
| |- index.html.erb
|
46
|
+
|- layouts
|
47
|
+
|- application.html.erb
|
48
|
+
|
49
|
+
|
50
|
+
### Images
|
51
|
+
|
52
|
+
Usually this would be just what you have in ``public/images`` except we move that to the theme instead.
|
53
|
+
|
54
|
+
### Javascripts
|
55
|
+
|
56
|
+
Same with javascripts, just what you normally have in ``public/javascripts`` but in this theme directory instead.
|
57
|
+
|
58
|
+
### Readme
|
59
|
+
|
60
|
+
The ``README`` file is just a description of your theme.
|
61
|
+
|
62
|
+
### Views
|
63
|
+
|
64
|
+
This is exactly the same as how you lay your views out in ``app/views/`` just instead of putting them in ``app/views/`` you put them into ``themes/mytheme/views/``
|
65
|
+
|
66
|
+
## How do I make my own Theme?
|
67
|
+
|
68
|
+
Simply use the Theme generator to make the basic structure of a new theme.
|
69
|
+
|
70
|
+
rails generate refinery_theme name_of_theme
|
71
|
+
|
72
|
+
Don't forget to "activate" this new theme by setting the theme setting to the name of this new theme.
|
73
|
+
|
74
|
+
## How do I select which Theme Refinery should use?
|
75
|
+
|
76
|
+
In the admin area of Refinery go to the "Settings" area, locate the setting called "theme" and edit it.
|
77
|
+
|
78
|
+
Set the value of that setting to the name of your themes folder. For example, if your theme is sitting in:
|
79
|
+
|
80
|
+
themes/my_theme
|
81
|
+
|
82
|
+
set it to ``my_theme`` and hit save.
|
83
|
+
|
84
|
+
## How do I install someone else's Theme?
|
85
|
+
|
86
|
+
Just copy their theme directory into your themes folder and Refinery will see it.
|
87
|
+
|
88
|
+
## How can I Convert my Current Views into a Theme?
|
89
|
+
|
90
|
+
This should be fairly straightforward, just follow the directory structure outlined in 'The structure of a Theme'.
|
91
|
+
|
92
|
+
But there is one important difference that need to be addressed to convert your current site into a theme.
|
93
|
+
|
94
|
+
If you have some CSS which refers to an image or URL:
|
95
|
+
|
96
|
+
#footer {
|
97
|
+
background: url('/images/footer_background.png') repeat-x;
|
98
|
+
}
|
99
|
+
|
100
|
+
You need to update the URL so it requests ``/theme/images/`` instead of just ``/images``. This tells Refinery we need to actually load this image from the theme and not just the public directory.
|
101
|
+
|
102
|
+
So the result is simply:
|
103
|
+
|
104
|
+
#footer {
|
105
|
+
background: url('/theme/images/footer_background.png') repeat-x;
|
106
|
+
}
|
107
|
+
|
108
|
+
This is the same with linking to Javascript and Stylesheets in your view. Say our ``application.html.erb`` layout had something like this:
|
109
|
+
|
110
|
+
<%= stylesheet_link_tag 'application' %>
|
111
|
+
|
112
|
+
You just need to change that to:
|
113
|
+
|
114
|
+
<%= stylesheet_link_tag 'application', :theme => true %>
|
115
|
+
|
116
|
+
## I'm Stuck, is there an Example Theme?
|
117
|
+
|
118
|
+
Yep, there is an example theme called "demolicious" that comes with Refinery located in ``/themes/demolicious``. If you find yourself getting stuck, just check out that theme and get a feel for how it works.
|