Git Product home page Git Product logo

navigasmic's Introduction

Navigasmic

Semantic navigation; a semantic way to build beautifully simple navigation structures in Rails.

The Story

Most of the navigation styles I’ve done over the years pretty much boil down to this idea: Use simple markup, and do the rest with css (and javascript if you need it). So, yeah, the default markup is beautifully simple (UL and LI tags).

Ok, so navigation is easy right? Until you start managing active/highlighted, disabled states, and more if you may need them. This can quickly become a mess, and all too often it just stays in the views with whatever logic tossed on top of it as people go. I’ve seen it too many times, and I wanted to do something about it.

I went in with these requirements:

  • Should be simple
  • Should be easily customizable
  • Should handle active/highlighted states
  • Should handle disabled states
  • Should be pleasant to use
  • Should use less code to create than it generates

And then I wrote a DSL that met those requirements:

  <% semantic_navigation :main do |n| %>
    <%= n.group 'Media' do %>
      <%= n.item 'Image Gallery', :link => '/media/images', :highlights_on => '/media/videos' %>
      <%= n.item 'Videos', :link => '/media/videos', :disabled_if => proc { true } %>
      <%= n.item 'Contact Us' # auto links to the contact_us_path if it exists %>
    <% end %>
  <% end %>

Since I clearly needed something that allowed for customization I ended up emulating the way Rails uses form builders. With some ideas taken from formtastic, I setup navigasmic to use builders. There are two builders that are provided (HTML for ERB, HAML, etc. and XML for ERB, Builder, etc), and these builders can be extended or replaced if you need more custom markup.

Currently the HTML builder generates UL and LI tags, which helps with SEO, and the XML builder generates tags that can be used for XML site maps.

Installation

The gem is hosted on gemcutter, so if you haven’t already, add it as a gem source:

  sudo gem sources -a http://gemcutter.org/

Then install the navigasmic gem:

  sudo gem install navigasmic

Usage

HAML

Simple Usage

  - semantic_navigation :main do |n|
    = n.group 'Media', :html => {:class => 'media'} do
      = n.item 'Image Gallery', :link => {:controller => 'media/images'}
      = n.item 'Videos', :link => {:controller => 'media/videos'}
    = n.group 'Info' do
      = n.item 'About Us', :link => '/about_us', :html => {:title => 'we are the coolest'}
      = n.item 'Nothing Here'
…produces…
  <ul id="main" class="semantic-navigation">
    <li class="media with-group">
      <span>Media<span>
      <ul>
        <li id="image_gallery"><a href="/media/images"><span>Image Gallery</span></a></li>
        <li id="videos"><a href="/media/videos"><span>Videos</span></a></li>
      </ul>
    </li>
    <li class="with-group">
      <span>Info<span>
      <ul>
        <li id="about_us" title="we are the coolest"><a href="/about_us/"><span>About Us</span></a></li>
        <li id="videos"><span>Nothing Here</span></li>
      </ul>
    </li>
  </ul>

Nesting of items and additional markup

  - semantic_navigation :main, :html => { :class => 'primary' } do |n|
    = n.group 'Media' do
      = n.item 'Image Gallery', :link => {:controller => 'media/images', :action => 'index'}
      = n.item 'Videos', :link => {:controller => 'media/videos'}
    .secondary
      = n.group 'Info' do
        = n.item 'About Us', :link => '/about_us' do
          %ul
            = n.item 'Nothing Here'
…produces…
  <ul id="main" class="primary semantic-navigation">
    <li id="media" class="with-group">
      <span>Media</span>
      <ul>
        <li id="image_gallery"><a href="/media/images"><span>Image Gallery</span></a></li>
        <li id="videos"><a href="/media/videos"><span>Videos</span></a></li>
      </ul>
    </li>
    <div class="secondary">
      <li id="info" class="with-group">
        <span>Info</span>
        <ul>
          <li id="about_us">
            <a href="/about_us"><span>About Us</span></a>
            <ul>
              <li id="nothing_here"><span>Nothing Here</span></li>
            </ul>
          </li>
        </ul>
      </li>
    </div>
  </ul>

Highlighting — highlights on the media controller (or any that inherit from it), on the /images path, and on mondays

  - semantic_navigation :main do
    = n.item 'Image Gallery', :link => 'media/images'
            :highlights_on => [{:controller => 'media'}, '/images', proc { Time.now.wday == 1 }]
…produces
  <ul id="main" class="semantic-navigation">
    <li id="image_gallery" class="highlighted"><a href="/media/images"><span>Image Gallery</span></a></li>
  </ul>

Disabling — disabled on tuesdays, and when not logged in

  - semantic_navigation :main do
    = n.item 'Image Gallery', :link => 'media/images'
            :disabled_if => proc { Time.now.wday == 2 || !logged_in? }
…produces
  <ul id="main" class="semantic-navigation">
    <li id="image_gallery" class="disabled"><span>Image Gallery</span></li>
  </ul>

ERB

Nesting of items and additional markup

  <% semantic_navigation :main, :html => { :class => 'primary' } do |n| %>
    <%= n.group 'Media' do %>
      <%= n.item 'Image Gallery', :link => {:controller => 'media/images', :action => 'index'} %>
      <%= n.item 'Videos', :link => {:controller => 'media/videos'} %>
    <% end %>
    <div class="secondary">
      <%= n.group 'Info' do %>
        <%= n.item 'About Us', :link => '/about_us' do %>
          <ul><%= n.item 'Nothing Here' %></ul>
        <% end %>
      <% end %>
    </div>
  <% end %>
…produces…
  <ul id="main" class="primary semantic-navigation">
    <li id="media" class="with-group">
      <span>Media</span>
      <ul>
        <li id="image_gallery"><a href="/media/images"><span>Image Gallery</span></a></li>
        <li id="videos"><a href="/media/videos"><span>Videos</span></a></li>
      </ul>
    </li>
    <div class="secondary">
      <li id="info" class="with-group">
        <span>Info</span>
        <ul>
          <li id="about_us">
            <a href="/about_us"><span>About Us</span></a>
            <ul>
              <li id="nothing_here"><span>Nothing Here</span></li>
            </ul>
          </li>
        </ul>
      </li>
    </div>
  </ul>  

XML

The XML Builder isn’t hashed out completely, but it more or less generates google sitemap style xml. I don’t know if the format is entirely correct in terms of nesting (it would make sense if it is), and I’d invite anyone who would like to hash it out more to do so.

Simple Usage Using Builder

  xml.instruct! :xml, :version => '1.0', :encoding => 'UTF-8'
  semantic_navigation :primary, :builder => Navigasmic::XmlNavigationBuilder do |n|
    n.group 'Media' do
      n.item 'Image Gallery', :link => {:controller => 'media/images', :action => 'index'}
      n.item 'Videos', :link => {:controller => 'media/videos'}, :changefreq => 'monthly'
    end
	end
…produces…
  <?xml version="1.0" encoding="UTF-8"?>
  <urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
    <urlset>
      <url>
        <loc>http://host:port/media/images</loc>
        <changefreq>yearly</changefreq>
      </url>
      <url>
        <loc>http://host:port/media/videos</loc>
        <changefreq>monthly</changefreq>
      </url>
    </urlset>
  </urlset>

Simple Usage Using HAML

  - semantic_navigation :primary, :builder => Navigasmic::XmlNavigationBuilder, :changefreq => 'daily' do |n|
    = n.item 'Image Gallery', :link => {:controller => 'media/images', :action => 'index'}
    = n.item 'Videos', :link => {:controller => 'media/videos'}, :changefreq => 'monthly'
…produces…
  <urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
    <url>
      <loc>http://host:port/media/images</loc>
      <changefreq>daily</changefreq>
    </url>
    <url>
      <loc>http://host:port/media/videos</loc>
      <changefreq>monthly</changefreq>
    </url>
  </urlset>

Tip: You can check the template_format and use the XML Builder when it’s :xml, and the HTML Builder if not.
:builder => template_format == :xml ? Navigasmic::XmlNavigationBuilder : nil

Other

You can always create your own builder by extending one of the existing ones, or creating one from scratch.

Then just specify your builder, or do it as a configuration.

semantic_navigation :main, :builder => MyCustomBuilder do

Navigasmic::SemanticNavigationHelper.builder = MyCustomBuilder

Documentation

RDoc documentation should be automatically generated after each commit and made available on the rdoc.info website.

Compatibility

I’m only testing with the latest Rails 3.x stable release, and it should work under Rails 2.3.x as well. Feel free to add backwards compatibility if you need it.

Project Info

Navigasmic is hosted on Github: http://github.com/jejacks0n/navigasmic, and the gem is available on Gemcutter: http://gemcutter.org/gems/navigasmic

Copyright © Jeremy Jackson, released under the MIT license.

navigasmic's People

Contributors

jejacks0n avatar jondoveston avatar kevinold avatar sborsje avatar pengwynn avatar

Stargazers

Fabio Kreusch avatar

Watchers

Fabio Kreusch avatar James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.