diff --git a/stoptime.rb b/stoptime.rb index c3c4d6e..d30bd09 100644 --- a/stoptime.rb +++ b/stoptime.rb @@ -16,6 +16,7 @@ require "camping" require "markaby" require "mime/types" require "pathname" +require "sass/plugin/rack" Markaby::Builder.set(:indent, 2) Camping.goes :StopTime @@ -27,6 +28,9 @@ unless defined? PUBLIC_DIR # Set up the locales. I18n.load_path += Dir[ File.join('locale', '*.yml') ] + # Set up SASS. + Sass::Plugin.options[:template_location] = "templates/sass" + # Set the default date(/time) format. ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!( :default => "%Y-%m-%d %H:%M", @@ -522,11 +526,11 @@ module StopTime::Controllers elsif @format == "tex" tex_file = PUBLIC_DIR + "#{@number}.tex" _generate_invoice_tex(@number) unless tex_file.exist? - redirect(StaticX, tex_file.basename) + redirect(Static, tex_file.basename) elsif @format == "pdf" pdf_file = PUBLIC_DIR + "#{@number}.pdf" _generate_invoice_pdf(@number) unless pdf_file.exist? - redirect(StaticX, pdf_file.basename) + redirect(Static, pdf_file.basename) end end @@ -705,7 +709,7 @@ module StopTime::Controllers end end - class StaticX + class Static < R '/static/(.+)' def get(path) mime_type = MIME::Types.type_for(path).first @headers['Content-Type'] = mime_type.nil? ? "text/plain" : mime_type.to_s @@ -726,6 +730,8 @@ module StopTime::Views xhtml_strict do head do title "Stop… Camping Time!" + link :rel => "stylesheet", :type => "text/css", + :media => "screen", :href => R(Static, "stylesheets/style.css") end body do div.wrapper! do @@ -766,8 +772,11 @@ module StopTime::Views a "here", :href => R(CustomersNTasksNew, customer.id) end else - table do + table.overview do @tasks[customer].each do |task| + col.task {} + col.hours {} + col.amount {} tr do td do a task.name, @@ -777,10 +786,10 @@ module StopTime::Views case task.type when "fixed_rate" td "" - td { "€ %.2f" % summary[2] } + td.right { "€ %.2f" % summary[2] } when "hourly_rate" - td { "%.2fh" % summary[0] } - td { "€ %.2f" % summary[2] } + td.right { "%.2fh" % summary[0] } + td.right { "€ %.2f" % summary[2] } end end end @@ -792,10 +801,15 @@ module StopTime::Views def time_entries h2 "Timeline" - table do + table.timeline do + col.task {} + col.start_time {} + col.end_time {} + col.comment {} + col.hours {} + col.flag {} tr do - th "Customer" - th "Project/task" + th "Project/Task" th "Start time" th "End time" th "Comment" @@ -875,8 +889,13 @@ module StopTime::Views end def customers - h2 "List of customers" - table do + h2 "Customers" + table.customers do + col.name {} + col.short_name {} + col.address {} + col.email {} + col.phone {} tr do th "Name" th "Short name" @@ -901,13 +920,13 @@ module StopTime::Views end end end - p do - a "Add a new customer", :href=> R(CustomersNew) - end + + a "Add a new customer", :href=> R(CustomersNew) end def customer_form - form :action => R(*@target), :method => :post do + form.float_left :action => R(*@target), :method => :post do + h2 "Customer information" ol do li { _form_input_with_label("Name", "name", :text) } li { _form_input_with_label("Short name", "short_name", :text) } @@ -935,15 +954,18 @@ module StopTime::Views end end end - input :type => :submit, :name => "edit", :value => "Edit" - input :type => :submit, :name => "delete", :value => "Delete" + div do + input :type => :submit, :name => "edit", :value => "Edit" + input :type => :submit, :name => "delete", :value => "Delete" + a "Add a new project/task", :href => R(CustomersNTasksNew, @customer.id) + end end - a "Add a new project/task", :href => R(CustomersNTasksNew, @customer.id) - - h2 "Invoices" - _invoice_list(@invoices) - a "Create a new invoice", :href => R(CustomersNInvoicesNew, @customer.id) + div.clear do + h2 "Invoices" + _invoice_list(@invoices) + a "Create a new invoice", :href => R(CustomersNInvoicesNew, @customer.id) + end end end @@ -951,7 +973,11 @@ module StopTime::Views if invoices.empty? p "None!" else - table do + table.invoices do + col.number {} + col.date {} + col.period {} + col.flag {} tr do th "Number" th "Date" @@ -964,7 +990,7 @@ module StopTime::Views a invoice.number, :href => R(CustomersNInvoicesX, @customer.id, invoice.number) end - td { invoice.created_at } + td { invoice.created_at.to_formatted_s(:date_only) } td { _format_period(invoice.period) } # FIXME: really retrieve the payed flag. td { _form_input_checkbox("payed_#{invoice.number}") } @@ -984,9 +1010,10 @@ module StopTime::Views def task_form form :action => R(*@target), :method => :post do - ul do + ol do li { _form_input_with_label("Name", "name", :text) } li do + label "Project/Task type" ol.radio do li do _form_input_radio("type", "hourly_rate", default=true) @@ -1025,20 +1052,20 @@ module StopTime::Views :method => :post do table do tr do - td { b "Number" } - td { @invoice.number } + td.key { b "Number" } + td.val { @invoice.number } end tr do - td { b "Date" } - td { @invoice.created_at.to_formatted_s(:date_only) } + td.key { b "Date" } + td.val { @invoice.created_at.to_formatted_s(:date_only) } end tr do - td { b "Period" } - td { _format_period(@invoice.period) } + td.key { b "Period" } + td.val { _format_period(@invoice.period) } end tr do - td { b "Payed" } - td do + td.key { b "Payed" } + td.val do _form_input_checkbox("payed") input :type => :submit, :name => "update", :value => "Update" end @@ -1046,25 +1073,29 @@ module StopTime::Views end end - table do + table.tasks do + col.task {} + col.hours {} + col.hourly_rate {} + col.amount {} tr do - th { "Description" } - th { "Number of hours" } - th { "Hourly rate" } - th { "Amount" } + th { "Project/Task" } + th.right { "Registered time" } + th.right { "Hourly rate" } + th.right { "Amount" } end subtotal = 0.0 @tasks.each do |task, line| tr do td { task } if line[0].nil? and line[1].nil? - td "–" - td "–" + td.right "–" + td.right "–" else - td { "%.2fh" % line[0] } - td { "€ %.2f" % line[1] } + td.right { "%.2fh" % line[0] } + td.right { "€ %.2f" % line[1] } end - td { "€ %.2f" % line[2] } + td.right { "€ %.2f" % line[2] } end subtotal += line[2] end @@ -1075,21 +1106,21 @@ module StopTime::Views td { i "Sub-total" } td "" td "" - td { "€ %.2f" % subtotal } + td.right { "€ %.2f" % subtotal } end vat = subtotal * VATRate/100 tr do td { i "VAT #{VATRate}%" } td "" td "" - td { "€ %.2f" % vat } + td.right { "€ %.2f" % vat } end end - tr do + tr.total do td { b "Total amount" } td "" td "" - td { "€ %.2f" % (subtotal + vat) } + td.right { "€ %.2f" % (subtotal + vat) } end end @@ -1103,14 +1134,20 @@ module StopTime::Views form :action => R(CustomersNInvoices, @customer.id), :method => :post do unless @hourly_rate_tasks.empty? h2 "Registered time" - table do + table.time_entries do + col.flag {} + col.start_time {} + col.end_time {} + col.comment {} + col.hours {} + col.amount {} tr do th "" - th "Start" - th "End" + th "Start time" + th "End time" th "Comment" - th "Total" - th "Amount" + th.right "Total time" + th.right "Amount" end @hourly_rate_tasks.keys.each do |task| tr.task do @@ -1123,8 +1160,8 @@ module StopTime::Views td { label entry.start, :for => "time_entries[]_#{entry.id}" } td { entry.end } td { entry.comment } - td { "%.2fh" % entry.hours_total } - td { "€ %.2f" % (entry.hours_total * entry.task.hourly_rate) } + td.right { "%.2fh" % entry.hours_total } + td.right { "€ %.2f" % (entry.hours_total * entry.task.hourly_rate) } end end end @@ -1133,10 +1170,14 @@ module StopTime::Views unless @fixed_cost_tasks.empty? h2 "Fixed cost tasks" - table do + table.tasks do + col.flag {} + col.task {} + col.hours {} + col.amount {} tr do th "" - th "Task" + th "Project/Task" th "Registered time" th "Amount" end @@ -1144,8 +1185,8 @@ module StopTime::Views tr do td { _form_input_checkbox("tasks[]", task.id) } td { label task.name, :for => "tasks[]_#{task.id}" } - td { "%.2fh" % @fixed_cost_tasks[task] } - td { task.fixed_cost } + td.right { "%.2fh" % @fixed_cost_tasks[task] } + td.right { task.fixed_cost } end end end diff --git a/templates/sass/style.sass b/templates/sass/style.sass new file mode 100644 index 0000000..e6e862d --- /dev/null +++ b/templates/sass/style.sass @@ -0,0 +1,145 @@ +/* CSS file for Stop… Camping Time! */ + +// Colours +$light-grey: #efefef +$dark-grey: #9f9f9f +$dark-red: #990000 + +/* General classes */ +.right + text-align: right + +.float_left + float: left + margin-right: 50px + +.clear + clear: both + padding-top: 10px + +/* Basic elements */ +a + text-decoration: none + color: $dark-red + + &:hover + text-decoration: underline + +body + font-family: sans-serif + font-size: 13px + margin: 0px + +/* Main layout */ +#wrapper + width: auto + height: auto + margin: 10px 10px + +#content + padding: 10px + border: 1px solid + background: $light-grey + +ol#menu + list-style: none + padding: 0px + margin: 5px + + li + display: inline + border: solid black + border-width: 1px 1px 0 1px + padding: 5px 10px + margin: 0px 0.5em 0px 0px + + &.selected + padding-bottom: 6px + background: $light-grey + +/* Table layout */ +table + padding: 3px 0px + border-spacing: 0px 4px + + col.amount, col.hours, col.hourly_rate + width: 15% + col.flag + width: 3% + col.start_time, col.end_time + width: 15% + col.comment + width: 30% + col.task + width: 25% + col.name, col.period + width: 25% + col.short_name + width: 20% + col.address + width: 20% + col.email, col.phone, col.date + width: 15% + col.number + width: 7% + + &.overview + width: 50% + + &.timeline + width: 100% + + &.tasks + width: 60% + + &.customers + width: 75% + + &.invoices + width: 50% + + td + vertical-align: top + + th + text-align: left + background: $dark-grey + + tr.total + border-top: solid black + + td.key + font-weight: bold + width: 80px + padding-bottom: 5px + +/* Form layout */ +form + ol + list-style: none + padding: 10px + + label + width: 180px + margin: 5px + margin-right: 10px + float: left + + input, select + width: 250px + + ol.radio + margin-left: 195px + padding: 0px + + label + float: none + + input + width: auto + + select + width: 300px + + input[type="submit"], input[type="reset"] + width: auto