GUI css writer: change your page style and rewrite your css on the fly

I have seen a lot of theme pickers out there, but not one that gives you 100% control like this

While working on a recent project, I had a complaint about the colors... I hate colors and I am no good at picking them, and when I do find some colors that I think are nice, apparently everyone else thinks they are crap.  This is why I truly respect web designers, as that is a true skill.  But to my chagrin I do not have a web designer, so I did the next best thing: get the blame off my back.  That's right, if you think you are so good with colors, why don't you pick them Mr. User?

 

So I went ahead and used the Farbtastic jQuery color picker Plug-in that I recently fell in love with, along with some nice Linq, XML, some good old .Net IO and a dash of clever css writing, and I was able to put together a (almost) fool-proof theme-designer with a friendly GUI.

 

First thing first, I needed both jQuery and the Farbtastic jQuery color picker Plug-in I just mentioned to be downloaded and called in my <head>.  Once I ran the Farbtastic demo to make sure everything was working fine, I set out on my adventure.

 

Next, I had to seperate my css into two distinct sheets, one: main_style.css would be jsut that, the main style; this never changes and is static.  Then, I made another stylesheet: theme.css that will hold my changing data and be re-written.  By using some clever techniques like not relying on any css border properties, I will be able to minimize the amount of code i have to re-write and be able to produce what looks like borders without actually using borders.  So instead of

/*theme.css*/
div.border { border: solid 5px Black; }

<!--html-->
<div class="border">some stuff with a border</div>

 

I will instead use something like this:

/*main_style.css*/
.border { padding:5px; }

/*theme.css*/
.border_color { background-color:Black; }
.content_color { background:White; }

<!--html-->
<div class="border border_color">
  <div class="inner_color">some stuff with a border</div>
</div>

 

These both produce what looks to be the exact same, the difference being that the second one does not actually have a border, it just looks like it with the padding and background color.  Now I know that the second one is more code, but that is the price you pay to have less code in your css and have your website be maintainable.  Once you write teh css writer one time, you will never have to touch the code again.  You can easily incorporate borders into the re-written css if you would like, that is just not the path I am going.

 

Now that that is understood, I can put in the color picker and the related TextBox controls to correspond to what colors I will be changing.  To do that, simply put this isnot your page where you want the picker: <div id="picker"></div> and then add your TextBox controls where you need them; each TextBox is the class 'colorwell' that allows them to be accessed easier by jQuery.  Once that is done, add a Button to submit everything.  So far, mine looks like the picture at the top of the post.  You will have to bind everything with jQuery now:

[code:js]

 <script type="text/javascript" charset="utf-8">
     $(document).ready(function() {
         var f = $.farbtastic('#picker');
         var p = $('#picker').css('opacity', 0.25);
         var selected;
         $('.colorwell')
      .each(function() { f.linkTo(this); $(this).css('opacity', 0.75); })
      .focus(function() {
          if (selected) {
              $(selected).css('opacity', 0.75).removeClass('colorwell-selected');
          }
          f.linkTo(this);
          p.css('opacity', 1);
          $(selected = this).css('opacity', 1).addClass('colorwell-selected');
      });
     });
 </script>

[/code]

 

Now comes the code-behind.  First thing I decided is that I am going to hold the data in an xml file; you could easily do this in a SQL database as well.  I named the file theme.xml and it looks like this:

<?xml version="1.0" encoding="utf-8"?>
<theme>
  <text>#444444</text>
  <borders>#4a4a4a</borders>
  <body>#ffffff</body>
  <links>#ff7700</links>
  <link_hover>#ffa500</link_hover>
  <button_text>#ffffff</button_text>
  <headers>#ffffff</headers>
  <background>#a53c3c</background>
</theme>

 

I populated it with my default color values of what will be changing.  Next, I made a class that will help me interact with the xml using Linq, I named this file xmlHelper.cs and placed it in my App_Code folder:

public static XElement getElement(XElement x, string element)
{ return (from e in x.Descendants(element) select e).First(); }

public static void writeElement(XElement x, string element, string value)
{
    XElement xe = getElement(x, element);
    xe.Value = value;
}

 

Now in my Page_Load I made a Dictionary<string, TextBox> and populated it with all of my TextBox controls and their corresponding xml Element name.  Now each time the page loads fresh, I simply load my values into the TextBox controls like this:

if (!IsPostBack)
{
    foreach (var v in colors)
        v.Value.Text = xmlHelper.getElement(x, v.Key).Value;
}

 

Now every time the page loads, it pulls the values out of the xml file and populates the TextBox controls.  Now that I have that, I need a way to write to the css file and the xml file.  A iadd that to my btnSubmit_Click event.  Once again, I can look through the Dictionary I had set up to this time use my xmlHelper class and write to the xml file.  That is done like this:

protected void btnSubmit_Click(object sender, EventArgs e)
{
    foreach (var v in colors) xmlHelper.writeElement(x, v.Key, v.Value.Text);
    x.Save(themePath);
    //writeCss(); //this will be used in a moment
}

 

Now the xml is written, we need to write the css.  For this I just use the old IO and StringBuilder to write my css and overwrite the old file:

protected void writeCss()
{
    string cssThemeFile = Server.MapPath("~") + "\\css\\theme.css";
    StringBuilder sb = new StringBuilder();
    sb.Append("html{background-color:" + txtBg.Text + ";}");
    sb.Append(".border_color{ background-color:" + txtBorders.Text + ";}");
    sb.Append(".content_color{ background-color:" + txtBody.Text + ";}");
    sb.Append(".header_text{color:" + txtHeader.Text + ";}");
    sb.Append("a{color:" + txtLink.Text + ";}");
    sb.Append("a:hover{color:" + txtLinkHover.Text + ";}");
    sb.Append(".button:hover{background-color:" + txtLinkHover.Text + ";}");
    sb.Append(".button{background:" + txtLink.Text + ";color:" + txtButtonText.Text + ";}");
    File.Delete(cssThemeFile);
    TextWriter tw = new StreamWriter(cssThemeFile);
    tw.WriteLine(sb.ToString());
    tw.Close();
}

 

That will write my theme.css file, and that is that.  Now on every click, the values will be written to the xml file (this is unneccessary, but it loads the previous settings up for your user).  After that, the css file is re-written and immediately used by your page.  This does require that you have write permissions to whatever directory/directories you house your theme.css and theme.xml files in.  This also is easy to implement with each user profile having their own saved style (easier with SQL).  I hope this comes in handy for someone, I love it and have used it on a few projects now.

 

...And now they see it's not soo easy picking colors that actually look good :)

 

 

Add comment

Loading