tramway-landing 1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +36 -0
- data/app/assets/config/tramway_landing_manifest.js +2 -0
- data/app/assets/javascripts/justified_images.js +284 -0
- data/app/assets/javascripts/tramway/landing/application.js.coffee +3 -0
- data/app/assets/javascripts/tramway/landing/footer.js.coffee +24 -0
- data/app/assets/stylesheets/tramway/landing/application.css.sass +16 -0
- data/app/assets/stylesheets/tramway/landing/collage.css.sass +36 -0
- data/app/assets/stylesheets/tramway/landing/justified.css +13 -0
- data/app/controllers/tramway/landing/application_controller.rb +11 -0
- data/app/decorators/tramway/landing/block_decorator.rb +26 -0
- data/app/decorators/tramway/landing/block_types/cards_decorator.rb +13 -0
- data/app/decorators/tramway/landing/block_types/features_decorator.rb +9 -0
- data/app/forms/tramway/landing/block_form.rb +15 -0
- data/app/helpers/tramway/landing/application_helper.rb +8 -0
- data/app/jobs/tramway/landing/application_job.rb +6 -0
- data/app/mailers/tramway/landing/application_mailer.rb +8 -0
- data/app/models/tramway/landing/application_record.rb +7 -0
- data/app/models/tramway/landing/block.rb +24 -0
- data/app/uploaders/tramway/landing/photo_versions.rb +15 -0
- data/app/views/layouts/tramway/landing/application.html.haml +28 -0
- data/app/views/tramway/landing/blocks/block_types/_cards.html.haml +36 -0
- data/app/views/tramway/landing/blocks/block_types/_contacts.html.haml +48 -0
- data/app/views/tramway/landing/blocks/block_types/_features.html.haml +26 -0
- data/app/views/tramway/landing/blocks/block_types/_footer.html.haml +16 -0
- data/app/views/tramway/landing/blocks/block_types/_header.html.haml +22 -0
- data/app/views/tramway/landing/blocks/block_types/_page.html.haml +9 -0
- data/config/initializers/assets.rb +1 -0
- data/config/initializers/tramway.rb +1 -0
- data/config/locales/models.yml +19 -0
- data/config/locales/state_machines.yml +15 -0
- data/config/routes.rb +2 -0
- data/lib/tasks/tramway/landing_tasks.rake +4 -0
- data/lib/tramway/landing.rb +7 -0
- data/lib/tramway/landing/engine.rb +7 -0
- data/lib/tramway/landing/generates/install_generator.rb +21 -0
- data/lib/tramway/landing/generates/templates/add_anchor_to_tramway_landing_blocks.rb +5 -0
- data/lib/tramway/landing/generates/templates/add_description_to_tramway_landing_blocks.rb +5 -0
- data/lib/tramway/landing/generates/templates/add_navbar_link_to_tramway_landing_blocks.rb +5 -0
- data/lib/tramway/landing/generates/templates/create_tramway_landing_blocks.rb +14 -0
- data/lib/tramway/landing/version.rb +5 -0
- metadata +86 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bc98a307ccf33e690b805a6adfeb1b7f110be1269bae2a02a90d3f7c1a0cc6e9
|
4
|
+
data.tar.gz: 5b85a0739fbc0da2ff548f1f79ff5a2dede5b5f0796f2e09fd36ce145825bf14
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e8fedc657c02b00f46af054ddf56a81c78acf2ef148b6eeb79ba375911702c0a7194e80de56f15743bd4aa4db4ce5474871db00eb596a9469e56eac06aedff9e
|
7
|
+
data.tar.gz: f8d3d47ccc3dc8f1787b1ed027ddbd3deecbde84031b1b42a1cb1f39d47543c42ca5372e3287e53b7147f551487f3a09d234303e3671f67458bdff3f28745a92
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2018 Pavel Kalashnikov
|
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.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Tramway::Landing
|
2
|
+
Short description and motivation.
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
How to use my plugin.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'tramway-landing'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
```bash
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
```bash
|
21
|
+
$ gem install tramway-landing
|
22
|
+
```
|
23
|
+
|
24
|
+
## Contributing
|
25
|
+
Contribution directions go here.
|
26
|
+
|
27
|
+
## License
|
28
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
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 = 'Tramway::Landing'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
|
21
|
+
load 'rails/tasks/statistics.rake'
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
require 'bundler/gem_tasks'
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
|
29
|
+
Rake::TestTask.new(:test) do |t|
|
30
|
+
t.libs << 'test'
|
31
|
+
t.pattern = 'test/**/*_test.rb'
|
32
|
+
t.verbose = false
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
task default: :test
|
@@ -0,0 +1,284 @@
|
|
1
|
+
/*jshint white:false*/
|
2
|
+
/* global jQuery: true*/
|
3
|
+
// the semi-colon before function invocation is a safety net against concatenated
|
4
|
+
// scripts and/or other plugins which may not be closed properly.
|
5
|
+
;
|
6
|
+
(function($, window, document, undefined) {
|
7
|
+
'use strict';
|
8
|
+
// undefined is used here as the undefined global variable in ECMAScript 3 is
|
9
|
+
// mutable (ie. it can be changed by someone else). undefined isn't really being
|
10
|
+
// passed in so we can ensure the value of it is truly undefined. In ES5, undefined
|
11
|
+
// can no longer be modified.
|
12
|
+
|
13
|
+
// window and document are passed through as local variable rather than global
|
14
|
+
// as this (slightly) quickens the resolution process and can be more efficiently
|
15
|
+
// minified (especially when both are regularly referenced in your plugin).
|
16
|
+
|
17
|
+
// Create the defaults once
|
18
|
+
var pluginName = 'justifiedImages';
|
19
|
+
|
20
|
+
|
21
|
+
// The actual plugin constructor
|
22
|
+
|
23
|
+
function Plugin(element, options) {
|
24
|
+
this.element = element;
|
25
|
+
this.$el = $(element);
|
26
|
+
this._name = pluginName;
|
27
|
+
this.init(options);
|
28
|
+
}
|
29
|
+
|
30
|
+
Plugin.prototype = {
|
31
|
+
defaults: {
|
32
|
+
template: function(data) {
|
33
|
+
return '<div class="photo-container" style="height:' + data.displayHeight + 'px;margin-right:' + data.marginRight + 'px;">' +
|
34
|
+
'<img class="image-thumb" src="' + data.src + '" style="width:' + data.displayWidth + 'px;height:' + data.displayHeight + 'px;" >' +
|
35
|
+
'</div>';
|
36
|
+
},
|
37
|
+
appendBlocks : function(){ return []; },
|
38
|
+
rowHeight: 150,
|
39
|
+
maxRowHeight: 350,
|
40
|
+
handleResize: false,
|
41
|
+
margin: 1,
|
42
|
+
imageSelector: 'image-thumb',
|
43
|
+
imageContainer: 'photo-container'
|
44
|
+
},
|
45
|
+
init: function(options) {
|
46
|
+
this.options = $.extend({}, this.defaults, options);
|
47
|
+
this.displayImages();
|
48
|
+
if (this.options.handleResize) {
|
49
|
+
this.handleResize();
|
50
|
+
}
|
51
|
+
},
|
52
|
+
getBlockInRow: function(rowNum){
|
53
|
+
var appendBlocks = this.options.appendBlocks();
|
54
|
+
for (var i = 0; i < appendBlocks.length; i++) {
|
55
|
+
var block = appendBlocks[i];
|
56
|
+
if(block.rowNum === rowNum){
|
57
|
+
return block;
|
58
|
+
}
|
59
|
+
}
|
60
|
+
},
|
61
|
+
displayImages: function() {
|
62
|
+
var self = this,
|
63
|
+
ws = [],
|
64
|
+
rowNum = 0,
|
65
|
+
baseLine = 0,
|
66
|
+
limit = this.options.images.length,
|
67
|
+
photos = this.options.images,
|
68
|
+
rows = [],
|
69
|
+
totalWidth = 0,
|
70
|
+
appendBlocks = this.options.appendBlocks();
|
71
|
+
var w = this.$el.width();
|
72
|
+
var border = parseInt(this.options.margin, 10);
|
73
|
+
var d = this.$el,
|
74
|
+
h = parseInt(this.options.rowHeight, 10);
|
75
|
+
|
76
|
+
$.each(this.options.images, function(index, image) {
|
77
|
+
var size = self.options.getSize(image);
|
78
|
+
var wt = parseInt(size.width, 10);
|
79
|
+
var ht = parseInt(size.height, 10);
|
80
|
+
if (ht !== h) {
|
81
|
+
wt = Math.floor(wt * (h / ht));
|
82
|
+
}
|
83
|
+
totalWidth += wt;
|
84
|
+
ws.push(wt);
|
85
|
+
});
|
86
|
+
|
87
|
+
$.each(appendBlocks, function(index, block){
|
88
|
+
totalWidth += block.width;
|
89
|
+
});
|
90
|
+
var perRowWidth = totalWidth / Math.ceil(totalWidth / w);
|
91
|
+
console.log('rows', Math.ceil(totalWidth / w));
|
92
|
+
var tw = 0;
|
93
|
+
while (baseLine < limit) {
|
94
|
+
var row = {
|
95
|
+
width: 0,
|
96
|
+
photos: []
|
97
|
+
},
|
98
|
+
c = 0,
|
99
|
+
block = this.getBlockInRow(rows.length + 1);
|
100
|
+
if(block){
|
101
|
+
row.width += block.width;
|
102
|
+
tw += block.width;
|
103
|
+
}
|
104
|
+
while ((tw + ws[baseLine + c] / 2 <= perRowWidth * (rows.length + 1)) && (baseLine + c < limit)) {
|
105
|
+
tw += ws[baseLine + c];
|
106
|
+
row.width += ws[baseLine + c];
|
107
|
+
row.photos.push({
|
108
|
+
width: ws[baseLine + c],
|
109
|
+
photo: photos[baseLine + c]
|
110
|
+
});
|
111
|
+
c++;
|
112
|
+
}
|
113
|
+
baseLine += c;
|
114
|
+
rows.push(row);
|
115
|
+
}
|
116
|
+
console.log(rows.length, rows);
|
117
|
+
/*for (var i = 1; i < rows.length; i++) {
|
118
|
+
var row = rows[i];
|
119
|
+
for (var j = 0; j < row.photos.length; j++) {
|
120
|
+
var photo = row.photos[j].photo;
|
121
|
+
};
|
122
|
+
}*/
|
123
|
+
for (var i = 0; i < rows.length; i++) {
|
124
|
+
var row = rows[i],
|
125
|
+
lastRow = false;
|
126
|
+
rowNum = i + 1;
|
127
|
+
if (this.options.maxRows && rowNum > this.options.maxRows) {
|
128
|
+
break;
|
129
|
+
}
|
130
|
+
if (i === rows.length - 1) {
|
131
|
+
lastRow = true;
|
132
|
+
}
|
133
|
+
tw = -1 * border;
|
134
|
+
var newBlock = this.getBlockInRow(lastRow ? -1 : rowNum), availableRowWidth = w;
|
135
|
+
if(newBlock){
|
136
|
+
availableRowWidth -= newBlock.width;
|
137
|
+
tw = 0;
|
138
|
+
}
|
139
|
+
|
140
|
+
// Ratio of actual width of row to total width of images to be used.
|
141
|
+
var r = availableRowWidth / row.width, //Math.min(w / row.width, this.options.maxScale),
|
142
|
+
c = row.photos.length;
|
143
|
+
|
144
|
+
// new height is not original height * ratio
|
145
|
+
var ht = Math.min(Math.floor(h * r), parseInt(this.options.maxRowHeight,10));
|
146
|
+
r = ht / this.options.rowHeight;
|
147
|
+
var domRow = $('<div/>', {
|
148
|
+
'class': 'picrow'
|
149
|
+
});
|
150
|
+
domRow.height(ht + border);
|
151
|
+
d.append(domRow);
|
152
|
+
|
153
|
+
var imagesHtml = '';
|
154
|
+
for (var j = 0; j < row.photos.length; j++) {
|
155
|
+
var photo = row.photos[j].photo;
|
156
|
+
// Calculate new width based on ratio
|
157
|
+
var wt = Math.floor(row.photos[j].width * r);
|
158
|
+
tw += wt + border;
|
159
|
+
|
160
|
+
imagesHtml += this.renderPhoto(photo, {
|
161
|
+
src: this.options.thumbnailPath(photo, wt, ht),
|
162
|
+
width: wt,
|
163
|
+
height: ht
|
164
|
+
}, newBlock ? false : j === row.photos.length - 1);
|
165
|
+
}
|
166
|
+
if(imagesHtml === ''){
|
167
|
+
domRow.remove();
|
168
|
+
continue;
|
169
|
+
}
|
170
|
+
|
171
|
+
domRow.html(imagesHtml);
|
172
|
+
|
173
|
+
|
174
|
+
|
175
|
+
if ((Math.abs(tw - availableRowWidth) < 0.05 * availableRowWidth)) {
|
176
|
+
// if total width is slightly smaller than
|
177
|
+
// actual div width then add 1 to each
|
178
|
+
// photo width till they match
|
179
|
+
var k = 0;
|
180
|
+
while (tw < availableRowWidth) {
|
181
|
+
var div1 = domRow.find('.' + this.options.imageContainer + ':nth-child(' + (k + 1) + ')'),
|
182
|
+
img1 = div1.find('.' + this.options.imageSelector);
|
183
|
+
img1.width(img1.width() + 1);
|
184
|
+
k = (k + 1) % c;
|
185
|
+
tw++;
|
186
|
+
}
|
187
|
+
// if total width is slightly bigger than
|
188
|
+
// actual div width then subtract 1 from each
|
189
|
+
// photo width till they match
|
190
|
+
k = 0;
|
191
|
+
while (tw > availableRowWidth) {
|
192
|
+
var div2 = domRow.find('.' + this.options.imageContainer + ':nth-child(' + (k + 1) + ')'),
|
193
|
+
img2 = div2.find('.' + this.options.imageSelector);
|
194
|
+
img2.width(img2.width() - 1);
|
195
|
+
k = (k + 1) % c;
|
196
|
+
tw--;
|
197
|
+
}
|
198
|
+
} else{
|
199
|
+
if( availableRowWidth - tw > 0.05 * availableRowWidth ){
|
200
|
+
var diff = availableRowWidth-tw,
|
201
|
+
adjustedDiff = 0,
|
202
|
+
images = domRow.find('.' + this.options.imageContainer),
|
203
|
+
marginTop = 0;
|
204
|
+
for(var l = 0 ; l < images.length ; l++ ){
|
205
|
+
var currentDiff = diff / (images.length),
|
206
|
+
imgDiv = images.eq(l),
|
207
|
+
img = imgDiv.find('.' + this.options.imageSelector),
|
208
|
+
imageWidth = img.width(),
|
209
|
+
imageHeight = img.height();
|
210
|
+
if( i === images.length - 1 ){
|
211
|
+
currentDiff = diff - adjustedDiff;
|
212
|
+
}
|
213
|
+
img.width( imageWidth + currentDiff );
|
214
|
+
img.height( ( imageHeight / imageWidth ) * (imageWidth + currentDiff) );
|
215
|
+
marginTop = (imageHeight - img.height()) / 2;
|
216
|
+
img.css('margin-top', marginTop);
|
217
|
+
adjustedDiff += currentDiff;
|
218
|
+
}
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
222
|
+
if(newBlock){
|
223
|
+
$('<div />', {
|
224
|
+
class : this.options.imageContainer + ' added-block',
|
225
|
+
css : {
|
226
|
+
width : newBlock.width,
|
227
|
+
height: ht
|
228
|
+
},
|
229
|
+
html : newBlock.html
|
230
|
+
}).appendTo(domRow);
|
231
|
+
}
|
232
|
+
}
|
233
|
+
},
|
234
|
+
renderPhoto: function(image, obj, isLast) {
|
235
|
+
var data = {},
|
236
|
+
d;
|
237
|
+
d = $.extend({}, image, {
|
238
|
+
src: obj.src,
|
239
|
+
displayWidth: obj.width,
|
240
|
+
displayHeight: obj.height,
|
241
|
+
marginRight: isLast ? 0 : this.options.margin
|
242
|
+
});
|
243
|
+
if (this.options.dataObject) {
|
244
|
+
data[this.options.dataObject] = d;
|
245
|
+
} else {
|
246
|
+
data = d;
|
247
|
+
}
|
248
|
+
return this.options.template(data);
|
249
|
+
},
|
250
|
+
handleResize: function() {},
|
251
|
+
refresh: function(options) {
|
252
|
+
this.options = $.extend({}, this.defaults, options);
|
253
|
+
this.$el.empty();
|
254
|
+
this.displayImages();
|
255
|
+
}
|
256
|
+
};
|
257
|
+
|
258
|
+
|
259
|
+
// A really lightweight plugin wrapper around the constructor,
|
260
|
+
// preventing against multiple instantiations
|
261
|
+
$.fn[pluginName] = function(option) {
|
262
|
+
var args = arguments,
|
263
|
+
result;
|
264
|
+
|
265
|
+
this.each(function() {
|
266
|
+
var $this = $(this),
|
267
|
+
data = $.data(this, 'plugin_' + pluginName),
|
268
|
+
options = typeof option === 'object' && option;
|
269
|
+
if (!data) {
|
270
|
+
$this.data('plugin_' + pluginName, (data = new Plugin(this, options)));
|
271
|
+
}else{
|
272
|
+
if (typeof option === 'string') {
|
273
|
+
result = data[option].apply(data, Array.prototype.slice.call(args, 1));
|
274
|
+
} else {
|
275
|
+
data.refresh.call(data, options);
|
276
|
+
}
|
277
|
+
}
|
278
|
+
});
|
279
|
+
|
280
|
+
// To enable plugin returns values
|
281
|
+
return result || this;
|
282
|
+
};
|
283
|
+
|
284
|
+
})(jQuery, window, document);
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#= require justified_images
|
2
|
+
|
3
|
+
$(document).ready ->
|
4
|
+
$('.logo_collage1').empty().justifiedImages
|
5
|
+
images: photos
|
6
|
+
rowHeight: 200
|
7
|
+
maxRowHeight: 400
|
8
|
+
thumbnailPath: (photo, width, height) ->
|
9
|
+
purl = photo.url_s
|
10
|
+
if photo.url_n and (width > photo.width_s * 1.2 or height > photo.height_s * 1.2)
|
11
|
+
purl = photo.url_n
|
12
|
+
if photo.url_m and (width > photo.width_n * 1.2 or height > photo.height_n * 1.2)
|
13
|
+
purl = photo.url_m
|
14
|
+
if photo.url_z and (width > photo.width_m * 1.2 or height > photo.height_m * 1.2)
|
15
|
+
purl = photo.url_z
|
16
|
+
if photo.url_l and (width > photo.width_z * 1.2 or height > photo.height_z * 1.2)
|
17
|
+
purl = photo.url_l
|
18
|
+
purl
|
19
|
+
getSize: (photo) ->
|
20
|
+
{
|
21
|
+
width: photo.width_s
|
22
|
+
height: photo.height_s
|
23
|
+
}
|
24
|
+
margin: 1
|
@@ -0,0 +1,16 @@
|
|
1
|
+
/*
|
2
|
+
*= require_tree .
|
3
|
+
*= require_self
|
4
|
+
*/
|
5
|
+
|
6
|
+
html, body, header, #intro
|
7
|
+
height: 100%
|
8
|
+
|
9
|
+
#intro
|
10
|
+
background-repeat: no-repeat
|
11
|
+
background-position: center center
|
12
|
+
background-attachment: fixed
|
13
|
+
-webkit-background-size: cover
|
14
|
+
-moz-background-size: cover
|
15
|
+
-o-background-size: cover
|
16
|
+
background-size: cover
|
@@ -0,0 +1,36 @@
|
|
1
|
+
.logo_collage
|
2
|
+
line-height: 0
|
3
|
+
-webkit-column-count: 5
|
4
|
+
-webkit-column-gap: 0px
|
5
|
+
-moz-column-count: 5
|
6
|
+
-moz-column-gap: 0px
|
7
|
+
column-count: 5
|
8
|
+
column-gap: 0px
|
9
|
+
img
|
10
|
+
width: 100% !important
|
11
|
+
height: auto !important
|
12
|
+
margin: 1px
|
13
|
+
|
14
|
+
@media (max-width: 1200px)
|
15
|
+
.logo_collage
|
16
|
+
-moz-column-count: 4
|
17
|
+
-webkit-column-count: 4
|
18
|
+
column-count: 4
|
19
|
+
|
20
|
+
@media (max-width: 1000px)
|
21
|
+
.logo_collage
|
22
|
+
-moz-column-count: 3
|
23
|
+
-webkit-column-count: 3
|
24
|
+
column-count: 3
|
25
|
+
|
26
|
+
@media (max-width: 800px)
|
27
|
+
.logo_collage
|
28
|
+
-moz-column-count: 2
|
29
|
+
-webkit-column-count: 2
|
30
|
+
column-count: 2
|
31
|
+
|
32
|
+
@media (max-width: 400px)
|
33
|
+
.logo_collage
|
34
|
+
-moz-column-count: 1
|
35
|
+
-webkit-column-count: 1
|
36
|
+
column-count: 1
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Tramway::Landing::BlockDecorator < ::Tramway::Core::ApplicationDecorator
|
2
|
+
class << self
|
3
|
+
def collections
|
4
|
+
[ :all ]
|
5
|
+
end
|
6
|
+
|
7
|
+
def list_attributes
|
8
|
+
[ :position, :view_state ]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
delegate :position, to: :object
|
13
|
+
|
14
|
+
def view_state
|
15
|
+
object.human_view_state_name
|
16
|
+
end
|
17
|
+
|
18
|
+
def view_state_button_color(event)
|
19
|
+
case event
|
20
|
+
when :publish
|
21
|
+
:primary
|
22
|
+
when :hide
|
23
|
+
:secondary
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Tramway::Landing::BlockForm < ::Tramway::Core::ApplicationForm
|
2
|
+
properties :title, :background, :view_state, :block_type, :position, :navbar_link, :anchor, :description
|
3
|
+
|
4
|
+
def initialize(object)
|
5
|
+
form_object = super object
|
6
|
+
form_properties title: :string,
|
7
|
+
background: :file,
|
8
|
+
position: :numeric,
|
9
|
+
block_type: :default,
|
10
|
+
navbar_link: :default,
|
11
|
+
anchor: :string,
|
12
|
+
description: :default
|
13
|
+
form_object
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Tramway::Landing::Block < ::Tramway::Landing::ApplicationRecord
|
2
|
+
enumerize :block_type, in: [ :header, :footer, :page, :cards, :features, :contacts, :news ]
|
3
|
+
enumerize :navbar_link, in: [ :exist, :not_exist ], default: :not_exist
|
4
|
+
|
5
|
+
mount_uploader :background, PhotoUploader
|
6
|
+
|
7
|
+
state_machine :view_state, initial: :published do
|
8
|
+
state :published
|
9
|
+
state :hidden
|
10
|
+
|
11
|
+
event :publish do
|
12
|
+
transition hidden: :published
|
13
|
+
end
|
14
|
+
|
15
|
+
event :hide do
|
16
|
+
transition published: :hidden
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
scope :on_main_page, -> { active.where(view_state: :published).order :position }
|
21
|
+
scope :with_navbar_link, -> { where navbar_link: :exist }
|
22
|
+
scope :header, -> { on_main_page.where(block_type: :header).first }
|
23
|
+
scope :footer, -> { on_main_page.where(block_type: :footer).first }
|
24
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Tramway::Landing::PhotoVersions
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
version :card do
|
6
|
+
process resize_to_fill: [400, 400, 'North']
|
7
|
+
end
|
8
|
+
|
9
|
+
version :horizontal do
|
10
|
+
process resize_to_fill: [1600, 700, 'Center']
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
PhotoUploader.include Tramway::Landing::PhotoVersions
|
@@ -0,0 +1,28 @@
|
|
1
|
+
!!!
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%meta{content: "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}
|
5
|
+
%title
|
6
|
+
= yield :title
|
7
|
+
= stylesheet_link_tag "tramway/landing/application", media: "all"
|
8
|
+
= javascript_include_tag "tramway/landing/application"
|
9
|
+
= javascript_include_tag "https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js", integrity: "sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl", crossorigin: "anonymous"
|
10
|
+
= javascript_include_tag "https://code.jquery.com/jquery-3.2.1.slim.min.js", integrity: "sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN", crossorigin: "anonymous"
|
11
|
+
= javascript_include_tag "https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js", integrity: "sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q", crossorigin: "anonymous"
|
12
|
+
= csrf_meta_tags
|
13
|
+
= yield :head_content
|
14
|
+
%body
|
15
|
+
= stylesheet_link_tag 'https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.4.5/css/mdb.min.css'
|
16
|
+
= javascript_include_tag 'https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.4.5/js/mdb.js'
|
17
|
+
= javascript_include_tag 'https://cdn.rawgit.com/CezarLuiz0/anchor.js/master/dist/anchor.min.js'
|
18
|
+
- if @blocks&.any?
|
19
|
+
= render "tramway/landing/blocks/block_types/header", block: @blocks.header
|
20
|
+
%main{ class: ('mt-5' if @blocks&.any?) }
|
21
|
+
.container
|
22
|
+
- if @blocks&.any?
|
23
|
+
- (@blocks - [@blocks.header] - [@blocks.footer]).each do |block|
|
24
|
+
= render "tramway/landing/blocks/block_types/#{block.block_type}", block: block
|
25
|
+
.container-fluid
|
26
|
+
= yield
|
27
|
+
- if @blocks&.any?
|
28
|
+
= render "tramway/landing/blocks/block_types/footer", block: @blocks.footer
|
@@ -0,0 +1,36 @@
|
|
1
|
+
.container.text-center
|
2
|
+
%h2.mb-4.font-weight-bold
|
3
|
+
= block.title
|
4
|
+
%p.grey-text
|
5
|
+
= block.description
|
6
|
+
.row{ id: block.anchor }
|
7
|
+
-# FIXME bad guy mode ON
|
8
|
+
- eval("@collection_#{block.anchor}").each do |item|
|
9
|
+
.col-lg-4.col-md-12.mb-4
|
10
|
+
- if item.path.present?
|
11
|
+
= link_to item.path do
|
12
|
+
.card.link
|
13
|
+
.view.overlay.hm-white-slight
|
14
|
+
= image_tag item.image, class: 'img-fluid'
|
15
|
+
= link_to '#' do
|
16
|
+
.mask
|
17
|
+
.card-body
|
18
|
+
%h4.card-title
|
19
|
+
= item.title
|
20
|
+
%p.card-text
|
21
|
+
= item.description
|
22
|
+
- if item.button.present?
|
23
|
+
= link_to item.button.text, item.button.url, class: 'btn btn-primary'
|
24
|
+
- else
|
25
|
+
.card
|
26
|
+
.view.overlay.hm-white-slight
|
27
|
+
= image_tag item.image, class: 'img-fluid'
|
28
|
+
= link_to '#' do
|
29
|
+
.mask
|
30
|
+
.card-body
|
31
|
+
%h4.card-title
|
32
|
+
= item.title
|
33
|
+
%p.card-text
|
34
|
+
= item.description
|
35
|
+
- if item.button.present?
|
36
|
+
= link_to item.button.text, item.button.url, class: 'btn btn-primary'
|
@@ -0,0 +1,48 @@
|
|
1
|
+
%script{ src: 'https://maps.google.com/maps/api/js?key=AIzaSyDC054dWb7cQ_mULJk3d1UBK6pN8msCx1g' }
|
2
|
+
:javascript
|
3
|
+
function regular_map() {
|
4
|
+
var var_location = new google.maps.LatLng(#{yield(:latitude)}, #{yield(:longtitude)});
|
5
|
+
|
6
|
+
var var_mapoptions = {
|
7
|
+
center: var_location,
|
8
|
+
zoom: 14
|
9
|
+
};
|
10
|
+
|
11
|
+
var var_map = new google.maps.Map(document.getElementById("map-container"),
|
12
|
+
var_mapoptions);
|
13
|
+
|
14
|
+
var var_marker = new google.maps.Marker({
|
15
|
+
position: var_location,
|
16
|
+
map: var_map,
|
17
|
+
title: "New York"
|
18
|
+
});
|
19
|
+
}
|
20
|
+
google.maps.event.addDomListener(window, 'load', regular_map);
|
21
|
+
#contact
|
22
|
+
%h2.mb-5.font-weight-bold.text-center
|
23
|
+
= block.title
|
24
|
+
.row
|
25
|
+
.col-lg-5.col-md-12
|
26
|
+
- @application.social_networks.each do |profile|
|
27
|
+
%ul.list-group
|
28
|
+
%li.list-group-item
|
29
|
+
= profile_link profile
|
30
|
+
.col-lg-7.col-md-12
|
31
|
+
.row.text-center
|
32
|
+
- if yield(:address).present?
|
33
|
+
.col-lg-4.col-md-12.mb-3
|
34
|
+
%p
|
35
|
+
= fa_icon :map, class: 'fa-lx mr-2 grey-text'
|
36
|
+
= yield :address
|
37
|
+
- if yield(:schedule).present?
|
38
|
+
.col-lg-4.col-md-6.mb-3
|
39
|
+
%p
|
40
|
+
= fa_icon :building, class: 'fa-lx mr-2 grey-text'
|
41
|
+
= yield :schedule
|
42
|
+
- if yield(:phone).present?
|
43
|
+
.col-lg-4.col-md-6.mb-3
|
44
|
+
%p
|
45
|
+
= tel_tag yield(:phone) do
|
46
|
+
= fa_icon :phone, class: 'fa-lx mr-2 grey-text'
|
47
|
+
= yield :phone
|
48
|
+
#map-container.z-depth-1-half.map-container{ style: 'height: 400px' }
|
@@ -0,0 +1,26 @@
|
|
1
|
+
%main.mt-5
|
2
|
+
.container
|
3
|
+
%section#best-features.text-center{ id: block.anchor }
|
4
|
+
%h2.mb-4.font-weight-bold
|
5
|
+
= block.title
|
6
|
+
.row.d-flex.justify-content-center.mb-4
|
7
|
+
.col-md-8
|
8
|
+
%p.grey-text
|
9
|
+
= block.description
|
10
|
+
.row
|
11
|
+
- eval("@collection_#{block.anchor}").each do |item|
|
12
|
+
.col-md-4.mb-1
|
13
|
+
- if item.icon.present?
|
14
|
+
%i.fa.fa-camera-retro.fa-4x.orange-text{ class: "fa-#{item.icon}" }
|
15
|
+
- else
|
16
|
+
= image_tag item.image
|
17
|
+
%h4.my-4
|
18
|
+
= item.title
|
19
|
+
%p.grey-text
|
20
|
+
= item.text
|
21
|
+
%hr.my-5/
|
22
|
+
%section#examples
|
23
|
+
%hr.my-5/
|
24
|
+
%section#gallery
|
25
|
+
%hr.my-5/
|
26
|
+
%section#contact
|
@@ -0,0 +1,16 @@
|
|
1
|
+
= javascript_include_tag 'tramway/landing/footer'
|
2
|
+
%footer.page-footer.indigo.center-on-small-only
|
3
|
+
.container-fluid
|
4
|
+
.row
|
5
|
+
.col-md-6
|
6
|
+
%h5.title
|
7
|
+
= yield :application_name
|
8
|
+
%p
|
9
|
+
= yield :application_tagline
|
10
|
+
.logo_collage.effect-parent
|
11
|
+
= yield :footer_logos
|
12
|
+
.col-md-6
|
13
|
+
= yield :footer_links
|
14
|
+
.footer-copyright
|
15
|
+
.container-fluid
|
16
|
+
= link_to copyright(2018, yield(:application_name)), yield(:application_url)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
%header
|
2
|
+
%nav.navbar.navbar-expand-lg.navbar-dark.indigo.scrolling-navbar.fixed-top
|
3
|
+
= link_to yield(:application_name), '#', class: 'navbar-brand'
|
4
|
+
|
5
|
+
%button.navbar-toggler{ type: :button, data: { toggle: :collapse, target: '#navbarSupportedContent' }, aria: { controls: 'navbarSupportedContent', expanded: 'false', label: 'Toggle navigation' } }
|
6
|
+
= fa_icon :bars
|
7
|
+
.collapse.navbar-collapse#navbarSupportedContent
|
8
|
+
%ul.navbar-nav.mr-auto
|
9
|
+
- @blocks.with_navbar_link.each do |block|
|
10
|
+
= menu_item block.title, "##{block.anchor}"
|
11
|
+
#intro.view.hm-black-strong{ style: "background-image: url('#{block.background.url}')" }
|
12
|
+
.container-fluid.full-bg-img.d-flex.align-items-center.justify-content-center
|
13
|
+
.row.d-flex.justify-content-center
|
14
|
+
.col-md-10.text-center
|
15
|
+
%h2.display-3.font-bold.white-text.mb-2
|
16
|
+
= yield(:application_name)
|
17
|
+
%hr.hr-light
|
18
|
+
%h4.white-text.my-4
|
19
|
+
= yield(:application_tagline)
|
20
|
+
- @blocks.with_navbar_link.each do |block|
|
21
|
+
%button.btn.btn-outline-white.waves-effect.waves-light.header-buttons{ type: :button, data: { anchor: "##{block.anchor}" } }
|
22
|
+
= block.title
|
@@ -0,0 +1 @@
|
|
1
|
+
Rails.application.config.assets.precompile += %w( tramway/landing/footer.js )
|
@@ -0,0 +1 @@
|
|
1
|
+
::Tramway::Admin.set_available_models ::Tramway::Landing::Block
|
@@ -0,0 +1,19 @@
|
|
1
|
+
ru:
|
2
|
+
activerecord:
|
3
|
+
models:
|
4
|
+
tramway/landing/block: Блок
|
5
|
+
attributes:
|
6
|
+
tramway/landing/block:
|
7
|
+
title: Название
|
8
|
+
background: Изображение на фоне
|
9
|
+
position: Позиция на странице
|
10
|
+
block_type: Тип блока
|
11
|
+
view_state: Видимость на сайте
|
12
|
+
cases:
|
13
|
+
tramway/landing/block:
|
14
|
+
plural: Блоки
|
15
|
+
genitive: блок
|
16
|
+
enumerize:
|
17
|
+
tramway/landing/block:
|
18
|
+
block_type:
|
19
|
+
header: Начальный
|
@@ -0,0 +1,15 @@
|
|
1
|
+
ru:
|
2
|
+
collections:
|
3
|
+
tramway/landing/block:
|
4
|
+
published: Опубликованные
|
5
|
+
hidden: Скрытые
|
6
|
+
activerecord:
|
7
|
+
state_machines:
|
8
|
+
tramway/landing/block:
|
9
|
+
view_state:
|
10
|
+
states:
|
11
|
+
published: Виден
|
12
|
+
hidden: Скрытый
|
13
|
+
events:
|
14
|
+
publish: Показать на сайте
|
15
|
+
hide: Скрыть с сайта
|
data/config/routes.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'tramway/core/generators/install_generator'
|
3
|
+
|
4
|
+
module Tramway::Landing::Generators
|
5
|
+
class InstallGenerator < ::Tramway::Core::Generators::InstallGenerator
|
6
|
+
include Rails::Generators::Migration
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
|
9
|
+
def self.next_migration_number(path)
|
10
|
+
next_migration_number = current_migration_number(path) + 1
|
11
|
+
ActiveRecord::Migration.next_migration_number next_migration_number
|
12
|
+
end
|
13
|
+
|
14
|
+
def copy_migrations
|
15
|
+
migration_template 'create_tramway_landing_blocks.rb', 'db/migrate/create_tramway_landing_blocks.rb'
|
16
|
+
migration_template 'add_navbar_link_to_tramway_landing_blocks.rb', 'db/migrate/add_navbar_link_to_tramway_landing_blocks.rb'
|
17
|
+
migration_template 'add_anchor_to_tramway_landing_blocks.rb', 'db/migrate/add_anchor_to_tramway_landing_blocks.rb'
|
18
|
+
migration_template 'add_description_to_tramway_landing_blocks.rb', 'db/migrate/add_description_to_tramway_landing_blocks.rb'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateTramwayLandingBlocks < ActiveRecord::Migration[5.1]
|
2
|
+
def change
|
3
|
+
create_table :tramway_landing_blocks do |t|
|
4
|
+
t.text :title
|
5
|
+
t.text :background
|
6
|
+
t.text :block_type
|
7
|
+
t.integer :position
|
8
|
+
t.text :state, default: :active
|
9
|
+
t.text :view_state, default: :hidden
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tramway-landing
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.0'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pavel Kalashnikov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-02-21 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Landing Engine for your Rails projects
|
14
|
+
email:
|
15
|
+
- kalashnikovisme@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- MIT-LICENSE
|
21
|
+
- README.md
|
22
|
+
- Rakefile
|
23
|
+
- app/assets/config/tramway_landing_manifest.js
|
24
|
+
- app/assets/javascripts/justified_images.js
|
25
|
+
- app/assets/javascripts/tramway/landing/application.js.coffee
|
26
|
+
- app/assets/javascripts/tramway/landing/footer.js.coffee
|
27
|
+
- app/assets/stylesheets/tramway/landing/application.css.sass
|
28
|
+
- app/assets/stylesheets/tramway/landing/collage.css.sass
|
29
|
+
- app/assets/stylesheets/tramway/landing/justified.css
|
30
|
+
- app/controllers/tramway/landing/application_controller.rb
|
31
|
+
- app/decorators/tramway/landing/block_decorator.rb
|
32
|
+
- app/decorators/tramway/landing/block_types/cards_decorator.rb
|
33
|
+
- app/decorators/tramway/landing/block_types/features_decorator.rb
|
34
|
+
- app/forms/tramway/landing/block_form.rb
|
35
|
+
- app/helpers/tramway/landing/application_helper.rb
|
36
|
+
- app/jobs/tramway/landing/application_job.rb
|
37
|
+
- app/mailers/tramway/landing/application_mailer.rb
|
38
|
+
- app/models/tramway/landing/application_record.rb
|
39
|
+
- app/models/tramway/landing/block.rb
|
40
|
+
- app/uploaders/tramway/landing/photo_versions.rb
|
41
|
+
- app/views/layouts/tramway/landing/application.html.haml
|
42
|
+
- app/views/tramway/landing/blocks/block_types/_cards.html.haml
|
43
|
+
- app/views/tramway/landing/blocks/block_types/_contacts.html.haml
|
44
|
+
- app/views/tramway/landing/blocks/block_types/_features.html.haml
|
45
|
+
- app/views/tramway/landing/blocks/block_types/_footer.html.haml
|
46
|
+
- app/views/tramway/landing/blocks/block_types/_header.html.haml
|
47
|
+
- app/views/tramway/landing/blocks/block_types/_page.html.haml
|
48
|
+
- config/initializers/assets.rb
|
49
|
+
- config/initializers/tramway.rb
|
50
|
+
- config/locales/models.yml
|
51
|
+
- config/locales/state_machines.yml
|
52
|
+
- config/routes.rb
|
53
|
+
- lib/tasks/tramway/landing_tasks.rake
|
54
|
+
- lib/tramway/landing.rb
|
55
|
+
- lib/tramway/landing/engine.rb
|
56
|
+
- lib/tramway/landing/generates/install_generator.rb
|
57
|
+
- lib/tramway/landing/generates/templates/add_anchor_to_tramway_landing_blocks.rb
|
58
|
+
- lib/tramway/landing/generates/templates/add_description_to_tramway_landing_blocks.rb
|
59
|
+
- lib/tramway/landing/generates/templates/add_navbar_link_to_tramway_landing_blocks.rb
|
60
|
+
- lib/tramway/landing/generates/templates/create_tramway_landing_blocks.rb
|
61
|
+
- lib/tramway/landing/version.rb
|
62
|
+
homepage: https://github.com/kalashnikovisme/tramway-landing
|
63
|
+
licenses:
|
64
|
+
- MIT
|
65
|
+
metadata: {}
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 2.7.3
|
83
|
+
signing_key:
|
84
|
+
specification_version: 4
|
85
|
+
summary: Landing Engine for your Rails projects
|
86
|
+
test_files: []
|