megatron 0.0.1
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +24 -0
- data/app/controllers/megatron/errors_controller.rb +11 -0
- data/app/helpers/megatron/application_helper.rb +59 -0
- data/app/helpers/megatron/breadcrumb_helper.rb +19 -0
- data/app/helpers/megatron/button_helper.rb +42 -0
- data/app/helpers/megatron/example_helper.rb +111 -0
- data/app/helpers/megatron/form_helper.rb +29 -0
- data/app/helpers/megatron/grid_helper.rb +60 -0
- data/app/helpers/megatron/layout_helper.rb +66 -0
- data/app/helpers/megatron/navigation_helper.rb +68 -0
- data/app/helpers/megatron/tab_helper.rb +27 -0
- data/app/helpers/megatron/toggler_help.rb +7 -0
- data/app/views/layouts/megatron/application.html.slim +61 -0
- data/app/views/layouts/megatron/errors.html.slim +20 -0
- data/app/views/megatron/errors/bad_request.html.slim +2 -0
- data/app/views/megatron/errors/forbidden.html.slim +2 -0
- data/app/views/megatron/errors/internal_server_error.html.slim +2 -0
- data/app/views/megatron/errors/method_not_allowed.html.slim +2 -0
- data/app/views/megatron/errors/not_acceptable.html.slim +2 -0
- data/app/views/megatron/errors/not_found.html.slim +2 -0
- data/app/views/megatron/errors/not_implemented.html.slim +2 -0
- data/app/views/megatron/errors/unauthorized.html.slim +2 -0
- data/app/views/megatron/errors/unprocessable_entity.html.slim +2 -0
- data/app/views/megatron/shared/_main_content.html.slim +4 -0
- data/app/views/megatron/shared/_primary_nav.html.slim +6 -0
- data/config/routes.rb +2 -0
- data/lib/megatron.rb +9 -0
- data/lib/megatron/engine.rb +12 -0
- data/lib/megatron/form.rb +129 -0
- data/lib/megatron/version.rb +3 -0
- data/lib/tasks/megatron_tasks.rake +4 -0
- metadata +134 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c29978c3775d1ef4eacebb255c21e717d30e7baf
|
4
|
+
data.tar.gz: 596acec8c262a2f155bc624185727a8d221ca7c6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: eb0c1505b3782bcf2b6f2cffe6c8fe4c0cfda5f4b4d13f0598c8db6df5e197eec1c99e34efedd90a17efbd9c9f0199fd6c622070ce89696aa95de47c4e2826d4
|
7
|
+
data.tar.gz: 153f235601841477756ab8885f7cf4a6b53a51e750ebf66a4987bccfc37b909560d0a7b8627f914b308bd6f84582605fcdfa0ca33ea0291ba06fe2437029be0a
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2015 Jerome Gravel-Niquet
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Megatron'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
load 'rails/tasks/statistics.rake'
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
Bundler::GemHelper.install_tasks
|
24
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Megatron::ErrorsController < ApplicationController
|
2
|
+
include Gaffe::Errors
|
3
|
+
layout 'megatron/errors'
|
4
|
+
|
5
|
+
# Render the correct template based on the exception “standard” code.
|
6
|
+
# Eg. For a 404 error, the `errors/not_found` template will be rendered.
|
7
|
+
def show
|
8
|
+
# Here, the `@exception` variable contains the original raised error
|
9
|
+
render "megatron/errors/#{@rescue_response}", status: @status_code
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Megatron
|
2
|
+
module ApplicationHelper
|
3
|
+
def megatron_asset_path(asset)
|
4
|
+
url = Rails.env.production? && !ENV['LOCAL_MEGATRON'] ? "https://app.compose.io/assets/megatron/#{asset}" : "/assets/megatron/#{asset}"
|
5
|
+
end
|
6
|
+
|
7
|
+
def megatron_assets_tags
|
8
|
+
favicon_link_tag(megatron_asset_path('favicon.ico')) +
|
9
|
+
stylesheet_link_tag(megatron_asset_path('megatron')) +
|
10
|
+
javascript_include_tag(megatron_asset_path('megatron'))
|
11
|
+
end
|
12
|
+
|
13
|
+
def icon(name)
|
14
|
+
content_tag(:span, class: "#{name}_icon", 'aria-hidden' => true) { }
|
15
|
+
end
|
16
|
+
|
17
|
+
def options_from_args(args)
|
18
|
+
if args.last.is_a? Hash
|
19
|
+
args.pop
|
20
|
+
else
|
21
|
+
{}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def embed_svg(filename, options = {})
|
26
|
+
group = 0
|
27
|
+
file = File.read(Engine.root.join('app', 'assets', 'images', filename))
|
28
|
+
.gsub(/<!--.+-->/, '')
|
29
|
+
.gsub(/^\t{2,}\s*<\/?g>/, '')
|
30
|
+
.gsub(/width=".+?"/, 'width="312"')
|
31
|
+
.gsub(/\sheight.+$/, '')
|
32
|
+
.gsub(/\t/, ' ')
|
33
|
+
.gsub(/\n{3,}/m, "\n")
|
34
|
+
.gsub(/^\s{2}<g>.+?^\s{2}<\/g>/m) { |g|
|
35
|
+
g.gsub(/^\s{4,}\s+/, ' ')
|
36
|
+
}
|
37
|
+
.gsub(/^<g>.+?^<\/g>/m) { |g|
|
38
|
+
group += 1
|
39
|
+
count = 0
|
40
|
+
g.gsub(/^\s{2}<g>/) { |g|
|
41
|
+
count += 1
|
42
|
+
%Q{ <g id="group-#{group}-cube-#{count}">}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
# doc = Nokogiri::HTML::DocumentFragment.parse file
|
46
|
+
# svg = doc.at_css 'svg'
|
47
|
+
# if options[:class].present?
|
48
|
+
# svg['class'] = options[:class]
|
49
|
+
# end
|
50
|
+
file.html_safe
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_class(string, *classes)
|
54
|
+
string ||= ''
|
55
|
+
string << " #{classes.join(' ')}"
|
56
|
+
string
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Megatron
|
2
|
+
module BreadcrumbHelper
|
3
|
+
class Breadcrumbs < BlockHelpers::Base
|
4
|
+
def crumb(text, href = nil, options={})
|
5
|
+
options[:class] = add_class(options[:class], 'breadcrumb')
|
6
|
+
|
7
|
+
if href.nil?
|
8
|
+
content_tag(:span, options) { text }
|
9
|
+
else
|
10
|
+
link_to(href, options){ text }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def display(body)
|
15
|
+
content_tag(:nav, class: 'breadcrumbs') { body }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Megatron
|
2
|
+
module ButtonHelper
|
3
|
+
def button(text, options = {})
|
4
|
+
tag_name = options[:href].present? ? :a : :button
|
5
|
+
opts = {
|
6
|
+
class: button_classes(options)
|
7
|
+
}
|
8
|
+
opts[:href] = options[:href] if options[:href]
|
9
|
+
content_tag tag_name, opts do
|
10
|
+
if options[:icon]
|
11
|
+
concat icon(options[:icon])
|
12
|
+
concat ' '
|
13
|
+
end
|
14
|
+
concat text
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def primary_button(text, options = {})
|
19
|
+
button(text, options.merge(type: :primary))
|
20
|
+
end
|
21
|
+
|
22
|
+
def destroy_button(text, options = {})
|
23
|
+
button(text, options.merge(type: :destroy))
|
24
|
+
end
|
25
|
+
|
26
|
+
def primary_destroy_button(text, options={})
|
27
|
+
button(text, options.merge(type: :primary_destroy))
|
28
|
+
end
|
29
|
+
|
30
|
+
def text_button(text, options = {})
|
31
|
+
button(text, options.merge(type: :text))
|
32
|
+
end
|
33
|
+
|
34
|
+
def button_classes(options)
|
35
|
+
button_type = options[:type] || options[:color]
|
36
|
+
classes = button_type.present? ? ["#{button_type.to_s.gsub('_','-')}-btn"] : ["btn"]
|
37
|
+
classes << options[:size].to_s.gsub(/xlarge/, 'x-large') if options[:size]
|
38
|
+
classes << 'disabled' if options[:disabled]
|
39
|
+
classes
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Megatron
|
2
|
+
module ExampleHelper
|
3
|
+
|
4
|
+
DEMO_DEFAULTS = {
|
5
|
+
type: :slim,
|
6
|
+
class: 'demo',
|
7
|
+
tag: :div
|
8
|
+
}
|
9
|
+
|
10
|
+
def demo(title=nil, options={}, &block)
|
11
|
+
if title.is_a? Hash
|
12
|
+
options = title
|
13
|
+
title = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
options = DEMO_DEFAULTS.merge(options)
|
17
|
+
|
18
|
+
content_tag options[:tag], class: options[:class] do
|
19
|
+
rand = SecureRandom.hex(5)
|
20
|
+
|
21
|
+
concat content_tag(:header, class: 'demo-header') {
|
22
|
+
if title
|
23
|
+
concat content_tag(:h3, class: 'demo-heading', id: heading_id(title)){ title }
|
24
|
+
end
|
25
|
+
|
26
|
+
if options[:toggle]
|
27
|
+
concat content_tag(:a, href: '#', class: 'demo-source-toggle', 'data-toggle' => "#source-#{rand}, #demo-#{rand}"){ 'source' }
|
28
|
+
else
|
29
|
+
concat content_tag(:a, href: '#', class: 'demo-source-toggle', 'data-toggle' => "#source-#{rand}"){ 'source' }
|
30
|
+
end
|
31
|
+
}
|
32
|
+
|
33
|
+
concat code(options[:type], id: "source-#{rand}", class: 'hidden') {
|
34
|
+
lines = extract_code(block)
|
35
|
+
}
|
36
|
+
concat content_tag(:div, id: "demo-#{rand}", &block)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def demo_box(title, options={}, &block)
|
41
|
+
options[:class] = "#{options[:class]} demo-box"
|
42
|
+
options[:class] << ' padded' unless options[:padded] == false
|
43
|
+
options[:toggle] = true
|
44
|
+
demo(title, options, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def strip_description(lines)
|
48
|
+
start = lines.find_index{|x| x=~/=\s*demo_description/}
|
49
|
+
if start
|
50
|
+
spaces = spaces_at_beginning(lines[start])
|
51
|
+
count = lines[start+1 .. -1].take_while { |line|
|
52
|
+
spaces_at_beginning(line) > spaces
|
53
|
+
}.size
|
54
|
+
|
55
|
+
lines.slice!(start..start+count)
|
56
|
+
end
|
57
|
+
lines
|
58
|
+
end
|
59
|
+
|
60
|
+
# Ouptut a linkable heading
|
61
|
+
#
|
62
|
+
def heading(*args)
|
63
|
+
content = args.pop
|
64
|
+
|
65
|
+
# Default to h3
|
66
|
+
tag = args.pop || :h3
|
67
|
+
content_tag(tag.to_sym, class: 'link-heading', id: heading_id(content)) do
|
68
|
+
concat content
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def heading_id(title)
|
73
|
+
title.gsub(/\W/, '-').downcase
|
74
|
+
end
|
75
|
+
|
76
|
+
def demo_description(&block)
|
77
|
+
content_tag :div, class: 'demo-description', &block
|
78
|
+
end
|
79
|
+
|
80
|
+
def code(lang, options = {}, &block)
|
81
|
+
classes = ["language-#{lang}"]
|
82
|
+
classes << options.delete(:class) if options[:class]
|
83
|
+
content_tag(:pre, options.merge(class: classes), &block)
|
84
|
+
end
|
85
|
+
|
86
|
+
def extract_code(block)
|
87
|
+
filename, start_line = block.source_location
|
88
|
+
lines = File.readlines(filename)
|
89
|
+
|
90
|
+
start_line -= 1
|
91
|
+
|
92
|
+
until lines[start_line] =~ /demo_box/
|
93
|
+
start_line += 1
|
94
|
+
end
|
95
|
+
|
96
|
+
spaces = spaces_at_beginning(lines[start_line])
|
97
|
+
|
98
|
+
lines = lines[start_line + 1 .. -1]
|
99
|
+
|
100
|
+
lines = lines.take_while { |line|
|
101
|
+
spaces_at_beginning(line) > spaces || line.match(/^\n\s*$/)
|
102
|
+
}
|
103
|
+
.map { |line| line.sub(%r{^\s{#{spaces + 2}}}, '') }
|
104
|
+
strip_description(lines).join("")
|
105
|
+
end
|
106
|
+
|
107
|
+
def spaces_at_beginning(str)
|
108
|
+
str[/\A */].size
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Megatron
|
2
|
+
module FormHelper
|
3
|
+
def table_form_for(record, options = {}, &block)
|
4
|
+
form_for record, options do |f|
|
5
|
+
table_form_tag f, &block
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def table_form_tag(form = nil)
|
10
|
+
form.style = 'table' if form
|
11
|
+
content_tag :div, class: ['table', 'table-form'] do
|
12
|
+
yield form if block_given?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def stacked_form_for(record, options = {}, &block)
|
17
|
+
form_for record, options do |f|
|
18
|
+
stacked_form_tag f, &block
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def stacked_form_tag(form = nil)
|
23
|
+
form.style = 'stacked' if form
|
24
|
+
content_tag :div, class: 'stacked-form' do
|
25
|
+
yield form if block_given?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Megatron
|
2
|
+
module GridHelper
|
3
|
+
class Grid < BlockHelpers::Base
|
4
|
+
|
5
|
+
DEFAULTS = {
|
6
|
+
tag: :div,
|
7
|
+
match_gutters: false
|
8
|
+
}
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = DEFAULTS.merge(options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def display(body)
|
15
|
+
content_tag(@options[:tag], class: grid_classes) { body }
|
16
|
+
end
|
17
|
+
|
18
|
+
def cell(*args, &block)
|
19
|
+
options = options_from_args(args)
|
20
|
+
options[:tag] ||= :div
|
21
|
+
content_tag options[:tag], class: cell_classes(args, options), &block
|
22
|
+
end
|
23
|
+
|
24
|
+
def cell_classes(args, options={})
|
25
|
+
classes = ['grid-cell']
|
26
|
+
if !args.empty? or !options.empty?
|
27
|
+
classes << width(*args) if !args.empty?
|
28
|
+
classes << options[:class] if options[:class]
|
29
|
+
|
30
|
+
classes << add_media_classes(:xsmall, options[:xsmall]) if options[:xsmall]
|
31
|
+
classes << add_media_classes(:small, options[:small]) if options[:small]
|
32
|
+
classes << add_media_classes(:medium, options[:medium]) if options[:medium]
|
33
|
+
classes << add_media_classes(:large, options[:large]) if options[:large]
|
34
|
+
classes << add_media_classes(:xlarge, options[:xlarge]) if options[:xlarge]
|
35
|
+
end
|
36
|
+
classes
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_media_classes(breakpoint, sizes)
|
40
|
+
sizes.empty? ? '' : width(*[breakpoint, *sizes])
|
41
|
+
end
|
42
|
+
|
43
|
+
def grid_classes
|
44
|
+
classes = ['grid']
|
45
|
+
classes << "align-#{@options[:valign]}" if @options[:valign]
|
46
|
+
classes << "align-#{@options[:align]}" if @options[:align]
|
47
|
+
classes << 'match-gutters' if @options[:match_gutters]
|
48
|
+
if @options[:gutters]
|
49
|
+
if @options[:gutters].to_s == 'none'
|
50
|
+
@options[:gutters] = 'no'
|
51
|
+
end
|
52
|
+
classes << "#{@options[:gutters]}-gutter" unless @options[:gutters].to_s == 'medium'
|
53
|
+
end
|
54
|
+
classes << @options[:class] if @options[:class]
|
55
|
+
classes
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Megatron
|
2
|
+
module LayoutHelper
|
3
|
+
|
4
|
+
def megatron_layout(layout='application', options={}, &block)
|
5
|
+
@custom_nav = options[:custom_nav]
|
6
|
+
yield
|
7
|
+
render template: "layouts/megatron/#{layout}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def page_header(title = nil, &block)
|
11
|
+
header :page_header, title, &block
|
12
|
+
end
|
13
|
+
|
14
|
+
def main_header(title = nil, &block)
|
15
|
+
header :main_header, title, &block
|
16
|
+
end
|
17
|
+
|
18
|
+
def header(type, title = nil, &block)
|
19
|
+
if title
|
20
|
+
content_for(type) { content_tag :h2, title }
|
21
|
+
elsif !title && block_given?
|
22
|
+
content_for type, &block
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def main(options={}, &block)
|
27
|
+
@wide_layout = options[:wide]
|
28
|
+
content_for :main, &block
|
29
|
+
end
|
30
|
+
|
31
|
+
def sidebar(&block)
|
32
|
+
content_for :sidebar, &block
|
33
|
+
end
|
34
|
+
|
35
|
+
def javascripts(&block)
|
36
|
+
content_for :javascripts, &block
|
37
|
+
end
|
38
|
+
|
39
|
+
def stylesheets(&block)
|
40
|
+
content_for :stylesheets, &block
|
41
|
+
end
|
42
|
+
|
43
|
+
def size(*args, &block)
|
44
|
+
options = options_from_args(args)
|
45
|
+
tag = options[:tag] || :div
|
46
|
+
content_tag tag, class: [width(*args), options[:class]], &block
|
47
|
+
end
|
48
|
+
|
49
|
+
def width(*sizes)
|
50
|
+
media = ''
|
51
|
+
sizes.flatten!
|
52
|
+
if sizes.first.is_a?(Symbol) || sizes.first.is_a?(String)
|
53
|
+
media = "#{sizes.shift.to_s.sub(/^x/, 'x-')}-"
|
54
|
+
end
|
55
|
+
|
56
|
+
classes = "#{media}#{sizes[0].to_words}-of-#{sizes[1].to_words}"
|
57
|
+
|
58
|
+
if sizes.last.is_a? Hash
|
59
|
+
classes << " #{sizes.last[:class]}"
|
60
|
+
end
|
61
|
+
|
62
|
+
classes
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Megatron
|
2
|
+
module NavigationHelper
|
3
|
+
class Nav < BlockHelpers::Base
|
4
|
+
def item(text, href, options = {})
|
5
|
+
options[:class] = add_class(options[:class], "#{nav_class}-item")
|
6
|
+
nav_icon = options.delete(:icon)
|
7
|
+
link_to href, options do
|
8
|
+
concat icon(nav_icon)
|
9
|
+
concat ' '
|
10
|
+
if options[:link_label] == false
|
11
|
+
concat icon_label(text)
|
12
|
+
else
|
13
|
+
concat link_label(text)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def link_label(text)
|
19
|
+
content_tag(:span, class: 'link_label icon_label') { text }
|
20
|
+
end
|
21
|
+
|
22
|
+
def icon_label(text)
|
23
|
+
content_tag(:span, class: 'icon_label') { text }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class PrimaryNav < Nav
|
28
|
+
def nav_class
|
29
|
+
'primary_nav'
|
30
|
+
end
|
31
|
+
|
32
|
+
def display(body)
|
33
|
+
content_for(:primary_nav) { body }
|
34
|
+
end
|
35
|
+
|
36
|
+
def sign_out(href='/session/destroy', options={})
|
37
|
+
content_tag :div, class: 'primary_nav-top' do
|
38
|
+
options[:data] = {
|
39
|
+
trigger: 'dialog',
|
40
|
+
title: 'Are you sure you want to sign out?',
|
41
|
+
message: 'Click cancel if you want to stay',
|
42
|
+
continue: 'Sign out',
|
43
|
+
close: 'Cancel',
|
44
|
+
follow: href,
|
45
|
+
}.merge(options[:data] || {})
|
46
|
+
|
47
|
+
options[:text] ||= 'Sign out'
|
48
|
+
options[:icon] ||= :power
|
49
|
+
options[:link_label] = false
|
50
|
+
|
51
|
+
concat item(options[:text], '#', options)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
class SecondaryNav < Nav
|
58
|
+
def nav_class
|
59
|
+
'secondary_nav'
|
60
|
+
end
|
61
|
+
|
62
|
+
def display(body)
|
63
|
+
content_for(:secondary_nav) { body }
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Megatron
|
2
|
+
module TabHelper
|
3
|
+
class Tabs < BlockHelpers::Base
|
4
|
+
def tab(text, href)
|
5
|
+
content_tag :a, class: 'tab', href: href do
|
6
|
+
text
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def tab_button(text, href)
|
11
|
+
content_tag :a, class: %w{tab-btn btn medium}, href: href do
|
12
|
+
text
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def display(body)
|
17
|
+
content_tag(:nav, class: 'tabs') { body }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class BoxTabs < Tabs
|
22
|
+
def display(body)
|
23
|
+
content_tag(:nav, class: 'box-tabs') { body }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
html
|
3
|
+
head
|
4
|
+
- if @title.present?
|
5
|
+
title #{@title} | Compose
|
6
|
+
- else
|
7
|
+
title Compose
|
8
|
+
meta name="viewport" content="width=device-width,initial-scale=1"
|
9
|
+
meta charset="utf-8"
|
10
|
+
= csrf_meta_tags
|
11
|
+
= megatron_assets_tags
|
12
|
+
= yield :stylesheets
|
13
|
+
= yield :javascripts
|
14
|
+
body
|
15
|
+
- if flash[:notice]
|
16
|
+
.form-flash.hidden data-type="action"= flash[:notice]
|
17
|
+
- if flash[:success]
|
18
|
+
.form-flash.hidden data-type="success"= flash[:success]
|
19
|
+
- if flash[:error]
|
20
|
+
.form-flash.hidden data-type="error"= flash[:error]
|
21
|
+
|
22
|
+
.site
|
23
|
+
header.site-header role="banner" data-no-turbolink=true
|
24
|
+
button.nav_toggle onclick="toggleNav(); this.blur()"
|
25
|
+
span.icon
|
26
|
+
span.hidden_label View Navigation
|
27
|
+
a.header_logo.logo_icon href="/"
|
28
|
+
span.hidden_label Compose
|
29
|
+
.site-content
|
30
|
+
- if !@custom_nav
|
31
|
+
= render 'megatron/shared/primary_nav'
|
32
|
+
- if content_for?(:primary_nav)
|
33
|
+
nav.primary_nav role="navigation" data-no-turbolink=true
|
34
|
+
= yield :primary_nav
|
35
|
+
.page
|
36
|
+
= yield
|
37
|
+
- if content_for?(:main)
|
38
|
+
header.page-header
|
39
|
+
= yield :page_header
|
40
|
+
.page-content
|
41
|
+
- if content_for?(:secondary_nav)
|
42
|
+
nav.secondary_nav
|
43
|
+
= yield :secondary_nav
|
44
|
+
- if content_for?(:sidebar)
|
45
|
+
.main.with-sidebar
|
46
|
+
.main-content
|
47
|
+
- if @wide_layout
|
48
|
+
.wide
|
49
|
+
= render 'megatron/shared/main_content'
|
50
|
+
- else
|
51
|
+
= render 'megatron/shared/main_content'
|
52
|
+
.main-sidebar
|
53
|
+
= yield :sidebar
|
54
|
+
- else
|
55
|
+
.main
|
56
|
+
.main-content
|
57
|
+
- if @wide_layout
|
58
|
+
.wide
|
59
|
+
= render 'megatron/shared/main_content'
|
60
|
+
- else
|
61
|
+
= render 'megatron/shared/main_content'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
html.error-layout
|
3
|
+
head
|
4
|
+
title Error #{@status_code}: #{@rescue_response.to_s.humanize} - Compose
|
5
|
+
meta name="viewport" content="width=device-width,initial-scale=1"
|
6
|
+
meta charset="utf-8"
|
7
|
+
= favicon_link_tag(megatron_asset_path('favicon.ico'))
|
8
|
+
= stylesheet_link_tag(megatron_asset_path('error-pages'))
|
9
|
+
|
10
|
+
body
|
11
|
+
.error-page class="error-#{@status_code} #{('reverse-stack' if @status_code == 404)}"
|
12
|
+
= embed_svg("megatron/errors/#{@status_code}.svg")
|
13
|
+
.error-message
|
14
|
+
= yield
|
15
|
+
footer.support-links
|
16
|
+
nav
|
17
|
+
a href='mailto:support@compose.io' Contact Support
|
18
|
+
a href='https://status.compose.io' Compose Status
|
19
|
+
a.compose-logo href='https://compose.io'
|
20
|
+
span.hidden_label Compose
|
@@ -0,0 +1,6 @@
|
|
1
|
+
- primary_nav do |nav|
|
2
|
+
= nav.item 'Deployments', "/#{current_account.slug}/deployments", icon: 'deployments'
|
3
|
+
= nav.item 'Account', "/account", icon: 'account_circle'
|
4
|
+
= nav.item 'Alerts', "/#{current_account.slug}/alerts", icon: 'alerts'
|
5
|
+
= nav.item 'Support', "/#{current_account.slug}/tickets", icon: 'question_line'
|
6
|
+
= nav.sign_out
|
data/config/routes.rb
ADDED
data/lib/megatron.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
module Megatron
|
2
|
+
class Form < ActionView::Helpers::FormBuilder
|
3
|
+
|
4
|
+
attr_accessor :style
|
5
|
+
|
6
|
+
def initialize(object_name, object, template, options)
|
7
|
+
super
|
8
|
+
@style = options.delete(:style) || "table"
|
9
|
+
end
|
10
|
+
|
11
|
+
def stacked_form(&block)
|
12
|
+
content_tag :div, class: 'stacked-form', &block
|
13
|
+
end
|
14
|
+
|
15
|
+
def table_form(&block)
|
16
|
+
content_tag :div, class: ['table', 'table-form'], &block
|
17
|
+
end
|
18
|
+
|
19
|
+
def text_field(method, options = {})
|
20
|
+
if errors_on?(method)
|
21
|
+
options[:class] ||= ""
|
22
|
+
options[:class] += " error"
|
23
|
+
end
|
24
|
+
|
25
|
+
wrapper method, options.delete(:label) || method.to_s.humanize, super(method, options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def password_field(method, options = {})
|
29
|
+
if errors_on?(method)
|
30
|
+
options[:class] ||= ""
|
31
|
+
options[:class] += " error"
|
32
|
+
end
|
33
|
+
|
34
|
+
wrapper method, options.delete(:label) || method.to_s.humanize, super(method, options)
|
35
|
+
end
|
36
|
+
|
37
|
+
def text_area(method, options = {})
|
38
|
+
if errors_on?(method)
|
39
|
+
options[:class] ||= ""
|
40
|
+
options[:class] += " error"
|
41
|
+
end
|
42
|
+
|
43
|
+
wrapper method, options.delete(:label) || method.to_s.humanize, super(method, options)
|
44
|
+
end
|
45
|
+
|
46
|
+
def select(method, choices = nil, options = {}, html_options = {}, &block)
|
47
|
+
if errors_on?(method)
|
48
|
+
html_options[:class] ||= ""
|
49
|
+
html_options[:class] += " error"
|
50
|
+
end
|
51
|
+
|
52
|
+
field = content_tag(:div, class: 'select_box') { super(method, choices, options, html_options, &block) }
|
53
|
+
|
54
|
+
wrapper method, options.delete(:label) || method.to_s.humanize, field
|
55
|
+
end
|
56
|
+
|
57
|
+
def submit(btn_text, args = {})
|
58
|
+
text = "<footer class='form-footer'>".html_safe
|
59
|
+
text << button(btn_text, {class: "primary-btn"}.merge(args))
|
60
|
+
text << "</footer>".html_safe
|
61
|
+
|
62
|
+
text
|
63
|
+
end
|
64
|
+
|
65
|
+
def method_missing(method, *args, &block)
|
66
|
+
@template.send(method, *args, &block)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def wrapper(*args)
|
72
|
+
send("#{@style}_wrapper".to_sym, *args)
|
73
|
+
rescue NoMethodError
|
74
|
+
Bugsnag.notify($!)
|
75
|
+
raise "Could not find Megatron::Form form style '#{@style}'."
|
76
|
+
end
|
77
|
+
|
78
|
+
def table_row(&block)
|
79
|
+
content_tag(:div, class: 'table-row', &block)
|
80
|
+
end
|
81
|
+
|
82
|
+
def table_cell(&block)
|
83
|
+
content_tag(:div, class: 'table-cell', &block)
|
84
|
+
end
|
85
|
+
|
86
|
+
def table_wrapper(method, label, field)
|
87
|
+
concat(table_row {
|
88
|
+
concat(table_cell {
|
89
|
+
label(method, label, class: [('red-text' if errors_on?(method))])
|
90
|
+
})
|
91
|
+
concat(table_cell { field })
|
92
|
+
})
|
93
|
+
|
94
|
+
if errors_on?(method)
|
95
|
+
concat(table_row {
|
96
|
+
concat(table_cell { ' ' })
|
97
|
+
concat(table_cell {
|
98
|
+
content_tag :p, class: 'red-text' do
|
99
|
+
@object.errors[method].to_sentence
|
100
|
+
end
|
101
|
+
})
|
102
|
+
})
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def errors_on?(method)
|
107
|
+
@object.present? && @object.errors[method].present?
|
108
|
+
end
|
109
|
+
|
110
|
+
def stacked_row(&block)
|
111
|
+
content_tag :div, class: 'form-row', &block
|
112
|
+
end
|
113
|
+
|
114
|
+
def stacked_wrapper(method, label, field)
|
115
|
+
concat(stacked_row {
|
116
|
+
concat label(method, label, class: [('red-text' if errors_on?(method))])
|
117
|
+
concat field
|
118
|
+
})
|
119
|
+
|
120
|
+
if errors_on?(method)
|
121
|
+
concat(stacked_row {
|
122
|
+
content_tag :span, class: ['red-text', 'small-text'] do
|
123
|
+
@object.errors[method].to_sentence
|
124
|
+
end
|
125
|
+
})
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
metadata
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: megatron
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jerome Gravel-Niquet
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-08-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: block_helpers
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.3.3
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.3.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: to_words
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.1.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.1.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: slim-rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 4.2.3
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 4.2.3
|
69
|
+
description: Hotness.
|
70
|
+
email:
|
71
|
+
- jeromegn@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- MIT-LICENSE
|
77
|
+
- README.rdoc
|
78
|
+
- Rakefile
|
79
|
+
- app/controllers/megatron/errors_controller.rb
|
80
|
+
- app/helpers/megatron/application_helper.rb
|
81
|
+
- app/helpers/megatron/breadcrumb_helper.rb
|
82
|
+
- app/helpers/megatron/button_helper.rb
|
83
|
+
- app/helpers/megatron/example_helper.rb
|
84
|
+
- app/helpers/megatron/form_helper.rb
|
85
|
+
- app/helpers/megatron/grid_helper.rb
|
86
|
+
- app/helpers/megatron/layout_helper.rb
|
87
|
+
- app/helpers/megatron/navigation_helper.rb
|
88
|
+
- app/helpers/megatron/tab_helper.rb
|
89
|
+
- app/helpers/megatron/toggler_help.rb
|
90
|
+
- app/views/layouts/megatron/application.html.slim
|
91
|
+
- app/views/layouts/megatron/errors.html.slim
|
92
|
+
- app/views/megatron/errors/bad_request.html.slim
|
93
|
+
- app/views/megatron/errors/forbidden.html.slim
|
94
|
+
- app/views/megatron/errors/internal_server_error.html.slim
|
95
|
+
- app/views/megatron/errors/method_not_allowed.html.slim
|
96
|
+
- app/views/megatron/errors/not_acceptable.html.slim
|
97
|
+
- app/views/megatron/errors/not_found.html.slim
|
98
|
+
- app/views/megatron/errors/not_implemented.html.slim
|
99
|
+
- app/views/megatron/errors/unauthorized.html.slim
|
100
|
+
- app/views/megatron/errors/unprocessable_entity.html.slim
|
101
|
+
- app/views/megatron/shared/_main_content.html.slim
|
102
|
+
- app/views/megatron/shared/_primary_nav.html.slim
|
103
|
+
- config/routes.rb
|
104
|
+
- lib/megatron.rb
|
105
|
+
- lib/megatron/engine.rb
|
106
|
+
- lib/megatron/form.rb
|
107
|
+
- lib/megatron/version.rb
|
108
|
+
- lib/tasks/megatron_tasks.rake
|
109
|
+
homepage: https://www.compose.io
|
110
|
+
licenses:
|
111
|
+
- MIT
|
112
|
+
metadata: {}
|
113
|
+
post_install_message:
|
114
|
+
rdoc_options: []
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
requirements: []
|
128
|
+
rubyforge_project:
|
129
|
+
rubygems_version: 2.4.7
|
130
|
+
signing_key:
|
131
|
+
specification_version: 4
|
132
|
+
summary: Megatron view helpers
|
133
|
+
test_files: []
|
134
|
+
has_rdoc:
|