comable_backend 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/comable/admin/application.coffee +53 -99
- data/app/assets/javascripts/comable/admin/categories.coffee +59 -0
- data/app/assets/javascripts/comable/admin/dashboard.coffee +32 -0
- data/app/assets/javascripts/comable/admin/dispatcher.coffee +21 -0
- data/app/assets/javascripts/comable/admin/orders.coffee +44 -0
- data/app/assets/javascripts/comable/admin/pages.coffee +69 -0
- data/app/assets/javascripts/comable/admin/products.coffee +21 -0
- data/app/assets/javascripts/comable/admin/search.coffee +35 -0
- data/app/assets/javascripts/comable/admin/themes.coffee +64 -0
- data/app/assets/stylesheets/comable/admin/_common.scss +1 -163
- data/app/assets/stylesheets/comable/admin/_overrides.scss +1 -0
- data/app/assets/stylesheets/comable/admin/_pages.scss +30 -0
- data/app/assets/stylesheets/comable/admin/_themes.scss +71 -0
- data/app/assets/stylesheets/comable/admin/_user_sessions.scss +4 -4
- data/app/assets/stylesheets/comable/admin/_variables.scss +16 -19
- data/app/assets/stylesheets/comable/admin/application.scss +6 -1
- data/app/assets/stylesheets/comable/admin/overrides/awesome_admin_layout.scss +25 -0
- data/app/assets/stylesheets/comable/admin/overrides/bootstrap.scss +5 -12
- data/app/controllers/comable/admin/orders_controller.rb +5 -1
- data/app/controllers/comable/admin/pages_controller.rb +72 -0
- data/app/controllers/comable/admin/themes_controller.rb +101 -0
- data/app/controllers/comable/admin/user_sessions_controller.rb +1 -0
- data/app/controllers/comable/admin/users_controller.rb +5 -0
- data/app/helpers/comable/admin/application_helper.rb +4 -4
- data/app/helpers/comable/admin/pages_helper.rb +6 -0
- data/app/helpers/comable/admin/themes_helper.rb +69 -0
- data/app/views/comable/admin/categories/index.slim +1 -52
- data/app/views/comable/admin/dashboard/show.slim +3 -23
- data/app/views/comable/admin/orders/_google_map.slim +26 -9
- data/app/views/comable/admin/orders/edit.slim +62 -4
- data/app/views/comable/admin/pages/_form.slim +69 -0
- data/app/views/comable/admin/pages/edit.slim +31 -0
- data/app/views/comable/admin/pages/index.slim +55 -0
- data/app/views/comable/admin/pages/new.slim +16 -0
- data/app/views/comable/admin/products/_form.slim +0 -16
- data/app/views/comable/admin/shared/_advanced_search.slim +0 -1
- data/app/views/comable/admin/shared/_notifier.slim +2 -2
- data/app/views/comable/admin/themes/_editor.slim +8 -0
- data/app/views/comable/admin/themes/_form.slim +31 -0
- data/app/views/comable/admin/themes/edit.slim +35 -0
- data/app/views/comable/admin/themes/index.slim +37 -0
- data/app/views/comable/admin/themes/new.slim +16 -0
- data/app/views/comable/admin/themes/show_file.slim +93 -0
- data/app/views/layouts/comable/admin/application.slim +19 -11
- data/config/initializers/awesome_admin_layout.rb +110 -0
- data/config/routes.rb +13 -0
- data/lib/comable/backend/engine.rb +8 -1
- metadata +117 -11
- data/app/assets/javascripts/comable/admin/products.js +0 -2
- data/app/views/comable/admin/shared/_header.slim +0 -31
- data/app/views/comable/admin/shared/_setup_search_form.slim +0 -14
- data/app/views/comable/admin/shared/_sidebar.slim +0 -54
@@ -1,21 +1,38 @@
|
|
1
|
-
|
2
|
-
=
|
1
|
+
javascript:
|
2
|
+
comable_google_map_element_id = "#{id}";
|
3
|
+
comable_google_map_address = "#{address.full_address}";
|
3
4
|
|
4
5
|
coffee:
|
5
|
-
window.
|
6
|
-
|
6
|
+
window.can_google_map = ->
|
7
|
+
return false unless comable_google_map_element_id?
|
8
|
+
return false unless comable_google_map_address?
|
9
|
+
return false unless $('#' + comable_google_map_element_id).length
|
10
|
+
true
|
11
|
+
|
12
|
+
window.initialize_google_map_api = ->
|
13
|
+
script = document.createElement('script')
|
14
|
+
script.type = 'text/javascript'
|
15
|
+
script.src = '//maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&callback=initialize_google_map'
|
16
|
+
script.async = true
|
17
|
+
document.body.appendChild(script)
|
18
|
+
|
19
|
+
window.initialize_google_map = ->
|
20
|
+
return unless can_google_map()
|
21
|
+
google_map = new google.maps.Map(document.getElementById(comable_google_map_element_id), { zoom: 15 })
|
7
22
|
google_geo = new google.maps.Geocoder()
|
8
|
-
google_geo.geocode({ address:
|
23
|
+
google_geo.geocode({ address: comable_google_map_address }, (result, status) =>
|
9
24
|
return if status != google.maps.GeocoderStatus.OK
|
10
25
|
location = result[0].geometry.location
|
11
26
|
google_map.setCenter(location)
|
12
27
|
new google.maps.Marker({ map: google_map, position: location })
|
13
28
|
)
|
14
29
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
30
|
+
$(document).ready(->
|
31
|
+
if google?
|
32
|
+
initialize_google_map()
|
33
|
+
else
|
34
|
+
initialize_google_map_api()
|
35
|
+
)
|
19
36
|
|
20
37
|
.comable-map
|
21
38
|
.comable-google-map id="#{id}"
|
@@ -33,9 +33,9 @@
|
|
33
33
|
= f.label :email
|
34
34
|
= f.email_field :email
|
35
35
|
|
36
|
-
hr
|
37
|
-
|
38
36
|
- if f.object.bill_address
|
37
|
+
hr
|
38
|
+
|
39
39
|
fieldset
|
40
40
|
.col-md-3
|
41
41
|
legend
|
@@ -72,9 +72,9 @@
|
|
72
72
|
= ff.label :phone_number
|
73
73
|
= ff.text_field :phone_number, max_length: 18
|
74
74
|
|
75
|
-
hr
|
76
|
-
|
77
75
|
- if f.object.ship_address
|
76
|
+
hr
|
77
|
+
|
78
78
|
fieldset
|
79
79
|
.col-md-3
|
80
80
|
legend
|
@@ -110,3 +110,61 @@
|
|
110
110
|
.form-group
|
111
111
|
= ff.label :phone_number
|
112
112
|
= ff.text_field :phone_number, max_length: 18
|
113
|
+
|
114
|
+
- if f.object.order_items
|
115
|
+
hr
|
116
|
+
|
117
|
+
fieldset
|
118
|
+
.col-md-3
|
119
|
+
legend
|
120
|
+
= f.object.class.human_attribute_name(:order_items)
|
121
|
+
.help-block
|
122
|
+
|
123
|
+
.col-md-9
|
124
|
+
table.table
|
125
|
+
thead
|
126
|
+
tr
|
127
|
+
th colspan="2"
|
128
|
+
= f.object.order_items.klass.human_attribute_name(:product)
|
129
|
+
th
|
130
|
+
= f.object.order_items.klass.human_attribute_name(:price)
|
131
|
+
th
|
132
|
+
= f.object.order_items.klass.human_attribute_name(:quantity)
|
133
|
+
th
|
134
|
+
= f.object.order_items.klass.human_attribute_name(:subtotal_price)
|
135
|
+
tbody
|
136
|
+
= f.fields_for :order_items do |ff|
|
137
|
+
tr.comable-order-items
|
138
|
+
td width="180"
|
139
|
+
= image_tag ff.object.image_url, width: '100%'
|
140
|
+
td
|
141
|
+
p
|
142
|
+
= ff.text_field :name, placeholder: ff.object.class.human_attribute_name(:name), data: { name: 'name' }
|
143
|
+
p.text-muted
|
144
|
+
= ff.text_field :code, placeholder: ff.object.class.human_attribute_name(:code), data: { name: 'code' }
|
145
|
+
td
|
146
|
+
= ff.text_field :price, placeholder: ff.object.class.human_attribute_name(:price), data: { name: 'price' }
|
147
|
+
td
|
148
|
+
= ff.text_field :quantity, placeholder: ff.object.class.human_attribute_name(:quantity), data: { name: 'quantity' }
|
149
|
+
td
|
150
|
+
= ff.text_field :subtotal_price, disabled: true, data: { name: 'subtotal_price' }
|
151
|
+
tr
|
152
|
+
th.text-right colspan="4"
|
153
|
+
= f.object.class.human_attribute_name(:item_total_price)
|
154
|
+
td
|
155
|
+
= f.text_field :item_total_price, disabled: true, data: { name: 'item_total_price' }
|
156
|
+
tr
|
157
|
+
th.text-right colspan="4"
|
158
|
+
= f.object.class.human_attribute_name(:payment_fee)
|
159
|
+
td
|
160
|
+
= f.text_field :payment_fee, data: { name: 'payment_fee' }
|
161
|
+
tr
|
162
|
+
th.text-right colspan="4"
|
163
|
+
= f.object.class.human_attribute_name(:shipment_fee)
|
164
|
+
td
|
165
|
+
= f.text_field :shipment_fee, data: { name: 'shipment_fee' }
|
166
|
+
tr
|
167
|
+
th.text-right colspan="4"
|
168
|
+
= f.object.class.human_attribute_name(:total_price)
|
169
|
+
td
|
170
|
+
= f.text_field :total_price, disabled: true, data: { name: 'total_price' }
|
@@ -0,0 +1,69 @@
|
|
1
|
+
= error_messages_for @page
|
2
|
+
|
3
|
+
- url = @page.new_record? ? comable.admin_pages_path : comable.admin_page_path(@page)
|
4
|
+
|
5
|
+
= form_for @page, url: url do |f|
|
6
|
+
.hidden
|
7
|
+
= f.submit
|
8
|
+
|
9
|
+
fieldset
|
10
|
+
.col-md-3
|
11
|
+
legend
|
12
|
+
= Comable.t('admin.nav.pages.general')
|
13
|
+
|
14
|
+
.col-md-9
|
15
|
+
.form-group
|
16
|
+
= f.label :title
|
17
|
+
= f.text_field :title
|
18
|
+
|
19
|
+
.form-group
|
20
|
+
= f.label :content
|
21
|
+
= f.text_area :content, rows: (f.object.content ? f.object.content.lines.count : nil)
|
22
|
+
|
23
|
+
hr
|
24
|
+
|
25
|
+
fieldset
|
26
|
+
.col-md-3
|
27
|
+
legend
|
28
|
+
= Comable.t('admin.nav.pages.seo')
|
29
|
+
|
30
|
+
.col-md-9
|
31
|
+
.form-group
|
32
|
+
= f.label :page_title
|
33
|
+
= f.text_field :page_title
|
34
|
+
|
35
|
+
.form-group
|
36
|
+
= f.label :meta_description
|
37
|
+
= f.text_field :meta_description
|
38
|
+
|
39
|
+
.form-group
|
40
|
+
= f.label :meta_keywords
|
41
|
+
= f.text_field :meta_keywords
|
42
|
+
|
43
|
+
.form-group
|
44
|
+
= f.label :slug
|
45
|
+
.slug
|
46
|
+
.slug-url
|
47
|
+
span
|
48
|
+
= comable.page_url(id: '')
|
49
|
+
.slug-body
|
50
|
+
= f.text_field :slug
|
51
|
+
|
52
|
+
hr
|
53
|
+
|
54
|
+
fieldset
|
55
|
+
.col-md-3
|
56
|
+
legend
|
57
|
+
= Comable.t('admin.nav.pages.visibility')
|
58
|
+
|
59
|
+
.col-md-9
|
60
|
+
.form-group
|
61
|
+
.radio-inline
|
62
|
+
label
|
63
|
+
= f.radio_button :published_at, :published, checked: @page.published_at.present?
|
64
|
+
= Comable.t('admin.nav.pages.published')
|
65
|
+
.radio-inline
|
66
|
+
label
|
67
|
+
= f.radio_button :published_at, :unpublished, checked: @page.published_at.blank?
|
68
|
+
= Comable.t('admin.nav.pages.unpublished')
|
69
|
+
= f.text_field :published_at, value: @page.published_at.try(:strftime, '%Y-%m-%d %H:%M'), class: 'datetimepicker'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
.comable-page
|
2
|
+
.comable-main-fixed-top
|
3
|
+
.comable-page-heading
|
4
|
+
ul.pull-right.list-inline
|
5
|
+
li
|
6
|
+
= link_to comable.page_path(@page), class: 'btn btn-default', target: '_blank' do
|
7
|
+
i.fa.fa-external-link>
|
8
|
+
= Comable.t('admin.preview')
|
9
|
+
li
|
10
|
+
= link_to_save
|
11
|
+
|
12
|
+
h1.page-header
|
13
|
+
ol.breadcrumb
|
14
|
+
li>
|
15
|
+
= link_to Comable.t('admin.nav.page'), comable.admin_pages_path
|
16
|
+
li.active
|
17
|
+
= @page.title
|
18
|
+
|
19
|
+
.comable-page-body
|
20
|
+
= render 'form'
|
21
|
+
hr
|
22
|
+
.panel.panel-danger
|
23
|
+
.panel-heading type="button" data-toggle="collapse" data-target="#comable-danger"
|
24
|
+
strong
|
25
|
+
span.fa.fa-angle-down>
|
26
|
+
= Comable.t('admin.actions.destroy')
|
27
|
+
#comable-danger.collapse
|
28
|
+
.panel-body
|
29
|
+
p
|
30
|
+
= Comable.t('admin.confirmation_to_remove_page')
|
31
|
+
= link_to Comable.t('admin.actions.destroy'), comable.admin_page_path(@page), method: :delete, class: 'btn btn-danger'
|
@@ -0,0 +1,55 @@
|
|
1
|
+
.comable-page
|
2
|
+
.comable-page-heading
|
3
|
+
ul.pull-right.list-inline
|
4
|
+
li
|
5
|
+
= link_to Comable.t('admin.actions.new'), comable.new_admin_page_path, class: 'btn btn-default'
|
6
|
+
h1.page-header
|
7
|
+
= Comable.t('admin.nav.page')
|
8
|
+
small<
|
9
|
+
| #{@pages.size} #{Comable.t('admin.results')}
|
10
|
+
|
11
|
+
.comable-page-body
|
12
|
+
.comable-search
|
13
|
+
= search_form_for @q, url: comable.admin_pages_path do |f|
|
14
|
+
.input-group
|
15
|
+
span.input-group-btn
|
16
|
+
button.btn.btn-default.dropdown-toggle type="button" data-toggle="dropdown"
|
17
|
+
i.fa.fa-search
|
18
|
+
span.caret<
|
19
|
+
ul.dropdown-menu role="menu"
|
20
|
+
li
|
21
|
+
= link_to Comable.t('admin.advanced_search'), 'javascript:void(0)', 'data-toggle' => 'collapse', 'data-target' => '#comable-advanced-search'
|
22
|
+
li
|
23
|
+
= link_to Comable.t('admin.clear_search_conditions'), comable.admin_pages_path
|
24
|
+
= f.text_field :title_cont, class: 'form-control'
|
25
|
+
span.input-group-btn
|
26
|
+
= f.submit Comable.t('admin.search'), class: 'btn btn-default'
|
27
|
+
|
28
|
+
= render 'comable/admin/shared/advanced_search', f: f
|
29
|
+
|
30
|
+
section
|
31
|
+
- if @pages.empty?
|
32
|
+
= Comable.t('admin.not_found')
|
33
|
+
- else
|
34
|
+
table.table.table-striped
|
35
|
+
thead
|
36
|
+
th
|
37
|
+
= sort_link [:comable, @q], :title
|
38
|
+
th
|
39
|
+
= sort_link [:comable, @q], :content
|
40
|
+
th
|
41
|
+
= sort_link [:comable, @q], :published_at
|
42
|
+
tbody
|
43
|
+
- @pages.each do |page|
|
44
|
+
tr
|
45
|
+
td
|
46
|
+
= link_to page.title, comable.admin_page_path(page)
|
47
|
+
small.text-muted<
|
48
|
+
| #{comable.page_path(page)}
|
49
|
+
td
|
50
|
+
= page.content.truncate(50)
|
51
|
+
td
|
52
|
+
- if page.published_at
|
53
|
+
= l page.published_at
|
54
|
+
- else
|
55
|
+
= Comable.t('admin.nav.pages.unpublished')
|
@@ -0,0 +1,16 @@
|
|
1
|
+
.comable-page
|
2
|
+
.comable-main-fixed-top
|
3
|
+
.comable-page-heading
|
4
|
+
ul.pull-right.list-inline
|
5
|
+
li
|
6
|
+
= link_to_save
|
7
|
+
|
8
|
+
h1.page-header
|
9
|
+
ol.breadcrumb
|
10
|
+
li>
|
11
|
+
= link_to Comable.t('admin.nav.page'), comable.admin_pages_path
|
12
|
+
li.active
|
13
|
+
= Comable.t('admin.actions.new')
|
14
|
+
|
15
|
+
.comable-page-body
|
16
|
+
= render 'form'
|
@@ -30,25 +30,9 @@
|
|
30
30
|
= f.label :price
|
31
31
|
= f.text_field :price
|
32
32
|
|
33
|
-
= stylesheet_link_tag 'http://rawgithub.com/aehlke/tag-it/master/css/jquery.tagit.css', media: 'all'
|
34
|
-
= stylesheet_link_tag 'http://rawgithub.com/aehlke/tag-it/master/css/tagit.ui-zendesk.css', media: 'all'
|
35
|
-
= javascript_include_tag 'http://rawgithub.com/aehlke/tag-it/master/js/tag-it.min.js'
|
36
|
-
|
37
33
|
/ TODO: Refactoring
|
38
34
|
javascript:
|
39
35
|
comable_tagit_available_tags = #{raw Comable::Category.all.map(&:path).map { |path| path.map(&:name).join(' > ') }.sort.to_json};
|
40
|
-
coffee:
|
41
|
-
$(document).ready(->
|
42
|
-
$("#comable-tagit").tagit({
|
43
|
-
fieldName: 'product[category_path_names][]',
|
44
|
-
availableTags: comable_tagit_available_tags,
|
45
|
-
autocomplete: { delay: 0, minLength: 0 },
|
46
|
-
showAutocompleteOnFocus: true,
|
47
|
-
removeConfirmation: true,
|
48
|
-
# Only allow available tags
|
49
|
-
beforeTagAdded: (event, ui) -> (comable_tagit_available_tags.indexOf(ui.tagLabel) != -1)
|
50
|
-
})
|
51
|
-
)
|
52
36
|
|
53
37
|
.form-group
|
54
38
|
= f.label :categories
|
@@ -1,5 +1,5 @@
|
|
1
1
|
- if flash[:alert] || flash[:notice]
|
2
2
|
#comable-notifier
|
3
3
|
javascript:
|
4
|
-
#{add_gritter(flash[:alert], image: :error) if flash[:alert]}
|
5
|
-
#{add_gritter(flash[:notice], image: :success) if flash[:notice]}
|
4
|
+
#{add_gritter(flash[:alert], image: :error, nodom_wrap: true) if flash[:alert]}
|
5
|
+
#{add_gritter(flash[:notice], image: :success, nodom_wrap: true) if flash[:notice]}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
#comable-theme-editor
|
2
|
+
.comable-theme-editor-filename
|
3
|
+
= params[:path]
|
4
|
+
.comable-theme-editor-window
|
5
|
+
= code
|
6
|
+
|
7
|
+
= form_tag comable.file_admin_theme_path(@theme, path: params[:path]), id: 'comable-theme-editor-form', method: :put do
|
8
|
+
= hidden_field_tag :code, nil
|
@@ -0,0 +1,31 @@
|
|
1
|
+
= error_messages_for @theme
|
2
|
+
|
3
|
+
= form_for [comable, :admin, @theme] do |f|
|
4
|
+
.hidden
|
5
|
+
= f.submit
|
6
|
+
|
7
|
+
fieldset
|
8
|
+
.col-md-3
|
9
|
+
legend
|
10
|
+
= Comable.t('admin.general')
|
11
|
+
|
12
|
+
.col-md-9
|
13
|
+
.form-group
|
14
|
+
= f.label :name
|
15
|
+
= f.text_field :name, disabled: f.object.persisted?
|
16
|
+
|
17
|
+
.form-group
|
18
|
+
= f.label :display
|
19
|
+
= f.text_field :display
|
20
|
+
|
21
|
+
.form-group
|
22
|
+
= f.label :version
|
23
|
+
= f.text_field :version
|
24
|
+
|
25
|
+
.form-group
|
26
|
+
= f.label :homepage
|
27
|
+
= f.text_field :homepage
|
28
|
+
|
29
|
+
.form-group
|
30
|
+
= f.label :author
|
31
|
+
= f.text_field :author
|
@@ -0,0 +1,35 @@
|
|
1
|
+
.comable-page
|
2
|
+
.comable-main-fixed-top
|
3
|
+
.comable-page-heading
|
4
|
+
ul.pull-right.list-inline
|
5
|
+
- if current_store.theme != @theme
|
6
|
+
= link_to comable.use_admin_theme_path(@theme), class: 'btn btn-default', method: 'put'
|
7
|
+
i.fa.fa-paint-brush>
|
8
|
+
= Comable.t('admin.use_this_theme')
|
9
|
+
li
|
10
|
+
= link_to comable.tree_admin_theme_path(@theme), class: 'btn btn-default'
|
11
|
+
i.fa.fa-files-o>
|
12
|
+
= Comable.t('admin.files')
|
13
|
+
li
|
14
|
+
= link_to_save
|
15
|
+
|
16
|
+
h1.page-header
|
17
|
+
ol.breadcrumb
|
18
|
+
li>
|
19
|
+
= link_to Comable.t('admin.nav.theme'), comable.admin_themes_path
|
20
|
+
li.active
|
21
|
+
= @theme.display_name
|
22
|
+
|
23
|
+
.comable-page-body
|
24
|
+
= render 'form'
|
25
|
+
hr
|
26
|
+
.panel.panel-danger
|
27
|
+
.panel-heading type="button" data-toggle="collapse" data-target="#comable-danger"
|
28
|
+
strong
|
29
|
+
span.fa.fa-angle-down>
|
30
|
+
= Comable.t('admin.actions.destroy')
|
31
|
+
#comable-danger.collapse
|
32
|
+
.panel-body
|
33
|
+
p
|
34
|
+
= Comable.t('admin.confirmation_to_remove_product')
|
35
|
+
= link_to Comable.t('admin.actions.destroy'), comable.admin_theme_path(@theme), method: :delete, class: 'btn btn-danger'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
.comable-page
|
2
|
+
.comable-page-heading
|
3
|
+
ul.pull-right.list-inline
|
4
|
+
li
|
5
|
+
= link_to Comable.t('admin.actions.new'), comable.new_admin_theme_path, class: 'btn btn-default'
|
6
|
+
|
7
|
+
h1.page-header
|
8
|
+
= Comable.t('admin.nav.theme')
|
9
|
+
small<
|
10
|
+
| #{@themes.size} #{Comable.t('admin.results')}
|
11
|
+
|
12
|
+
.comable-page-body
|
13
|
+
- if @themes.empty?
|
14
|
+
= Comable.t('admin.not_found')
|
15
|
+
- else
|
16
|
+
table.table.table-striped
|
17
|
+
thead
|
18
|
+
th
|
19
|
+
= @themes.klass.human_attribute_name(:name)
|
20
|
+
th
|
21
|
+
= @themes.klass.human_attribute_name(:version)
|
22
|
+
th
|
23
|
+
= @themes.klass.human_attribute_name(:author)
|
24
|
+
tbody
|
25
|
+
- @themes.each do |theme|
|
26
|
+
tr
|
27
|
+
td
|
28
|
+
= link_to theme.display_name, comable.tree_admin_theme_path(theme)
|
29
|
+
- if current_store.theme != theme
|
30
|
+
span.fa.fa-eye-slash.text-muted<
|
31
|
+
td
|
32
|
+
= theme.version
|
33
|
+
td
|
34
|
+
- if theme.homepage
|
35
|
+
= link_to (theme.author.presence || theme.homepage), theme.homepage
|
36
|
+
- else
|
37
|
+
= theme.author
|