station 0.0.145 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/nexmo_developer/Gemfile +6 -0
- data/lib/nexmo_developer/Gemfile.lock +8 -0
- data/lib/nexmo_developer/app/assets/stylesheets/{application.css → application.scss} +2 -0
- data/lib/nexmo_developer/app/assets/stylesheets/blog/badge.scss +245 -0
- data/lib/nexmo_developer/app/assets/stylesheets/blog/blog.scss +209 -0
- data/lib/nexmo_developer/app/controllers/blog/authors_controller.rb +8 -0
- data/lib/nexmo_developer/app/controllers/blog/blogpost_controller.rb +32 -0
- data/lib/nexmo_developer/app/controllers/blog/categories_controller.rb +8 -0
- data/lib/nexmo_developer/app/controllers/blog/main_controller.rb +9 -0
- data/lib/nexmo_developer/app/controllers/blog/tags_controller.rb +8 -0
- data/lib/nexmo_developer/app/helpers/blog_helper.rb +7 -0
- data/lib/nexmo_developer/app/models/blog/author.rb +59 -0
- data/lib/nexmo_developer/app/models/blog/blogpost.rb +68 -0
- data/lib/nexmo_developer/app/models/blog/category.rb +25 -0
- data/lib/nexmo_developer/app/services/author_parser.rb +61 -0
- data/lib/nexmo_developer/app/services/blogpost_parser.rb +57 -0
- data/lib/nexmo_developer/app/services/category_parser.rb +19 -0
- data/lib/nexmo_developer/app/services/tag_parser.rb +38 -0
- data/lib/nexmo_developer/app/views/blog/authors/_social_links.html.erb +67 -0
- data/lib/nexmo_developer/app/views/blog/authors/show.html.erb +46 -0
- data/lib/nexmo_developer/app/views/blog/blogpost/_blogpost.html.erb +74 -0
- data/lib/nexmo_developer/app/views/blog/blogpost/_blogpost_with_image.html.erb +59 -0
- data/lib/nexmo_developer/app/views/blog/blogpost/_tag_labels.html.erb +20 -0
- data/lib/nexmo_developer/app/views/blog/blogpost/index.html.erb +43 -0
- data/lib/nexmo_developer/app/views/blog/blogpost/show.html.erb +127 -0
- data/lib/nexmo_developer/app/views/blog/categories/show.html.erb +25 -0
- data/lib/nexmo_developer/app/views/blog/tags/show.html.erb +25 -0
- data/lib/nexmo_developer/app/views/layouts/application.html.erb +1 -1
- data/lib/nexmo_developer/app/views/layouts/partials/_header.html.erb +0 -3
- data/lib/nexmo_developer/config/application.rb +1 -0
- data/lib/nexmo_developer/config/routes.rb +9 -1
- data/lib/nexmo_developer/lib/tasks/blog.rake +12 -0
- data/lib/nexmo_developer/public/assets/.sprockets-manifest-3f3d4eafc3f8d9771fa4ba3f13084baf.json +1 -0
- data/lib/nexmo_developer/public/assets/application-aa88b3c7bd34ec529f43849541752fda7c9c202aa9fff905be578ef88d103b46.js.gz +0 -0
- data/lib/nexmo_developer/public/assets/{application-6e9186f7602070c57b5c60de9b45ad12f1fccdcf83e08ea28c809d7a5a42a232.css → application-d9ea3be5cba4feaa1cbe4f50a2d73a7cd19cbc1658778180d3cd3890a0dd6ed0.css} +1 -1
- data/lib/nexmo_developer/public/assets/application-d9ea3be5cba4feaa1cbe4f50a2d73a7cd19cbc1658778180d3cd3890a0dd6ed0.css.gz +0 -0
- data/lib/nexmo_developer/public/assets/manifest-b4bf6e57a53c2bdb55b8998cc94cd00883793c1c37c5e5aea3ef6749b4f6d92b.js.gz +0 -0
- data/lib/nexmo_developer/version.rb +1 -1
- metadata +31 -6
- data/lib/nexmo_developer/public/assets/.sprockets-manifest-cbc98735a38ce872d5ca075ef4d92ef7.json +0 -1
- data/lib/nexmo_developer/public/assets/application-6e9186f7602070c57b5c60de9b45ad12f1fccdcf83e08ea28c809d7a5a42a232.css.gz +0 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
class Blog::Blogpost
|
2
|
+
attr_accessor :title, :description, :thumbnail, :author, :published, :published_at,
|
3
|
+
:updated_at, :category, :tags, :link, :locale, :slug, :spotlight,
|
4
|
+
:filename, :content, :header_img_url
|
5
|
+
|
6
|
+
CLOUDFRONT_BLOG_URL = 'https://d226lax1qjow5r.cloudfront.net/blog/'.freeze
|
7
|
+
DEFAULT_HEADER_IMG_URL = 'https://s3.eu-west-1.amazonaws.com/developer.vonage.com/vonage-logo-images/vonage-wide-logo.png'.freeze
|
8
|
+
|
9
|
+
def initialize(attributes)
|
10
|
+
@title = attributes['title']
|
11
|
+
@description = attributes['description']
|
12
|
+
@thumbnail = attributes['thumbnail'] || ''
|
13
|
+
@published = attributes['published'] || false
|
14
|
+
@published_at = attributes['published_at']
|
15
|
+
@updated_at = attributes['updated_at']
|
16
|
+
@tags = attributes['tags'] || []
|
17
|
+
@link = attributes['link'] || ''
|
18
|
+
@filename = attributes['filename']
|
19
|
+
@locale = attributes['locale'] || 'en'
|
20
|
+
@outdated = attributes['outdated'] || false
|
21
|
+
@spotlight = attributes['spotlight'] || false
|
22
|
+
|
23
|
+
@author = Blog::Author.new(attributes['author'] || {}) # TODO: DEFAULT AUTHOR
|
24
|
+
@category = Blog::Category.new(attributes['category'])
|
25
|
+
|
26
|
+
@content = ''
|
27
|
+
@header_img_url = build_header_img_url
|
28
|
+
|
29
|
+
@replacement_url = attributes['replacement_url']
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.build_blogpost_from_path(path, locale)
|
33
|
+
return if path.blank?
|
34
|
+
|
35
|
+
path = "#{Rails.configuration.blog_path}/blogposts/#{locale}/#{path}.md"
|
36
|
+
|
37
|
+
default_not_found_page(path) unless File.exist?(path)
|
38
|
+
|
39
|
+
document = File.read(path)
|
40
|
+
|
41
|
+
blogpost = new(BlogpostParser.build_show_with_locale(path, locale))
|
42
|
+
blogpost.content = Nexmo::Markdown::Renderer.new({}).call(document)
|
43
|
+
|
44
|
+
blogpost
|
45
|
+
end
|
46
|
+
|
47
|
+
def build_header_img_url
|
48
|
+
require 'net/http'
|
49
|
+
require 'addressable'
|
50
|
+
|
51
|
+
url = Addressable::URI.parse("#{Blog::Blogpost::CLOUDFRONT_BLOG_URL}blogposts/#{thumbnail.gsub('/content/blog/', '')}")
|
52
|
+
|
53
|
+
Net::HTTP.start(url.host, url.port) do |http|
|
54
|
+
if http.head(url.request_uri)['Content-Type'].start_with? 'image'
|
55
|
+
url
|
56
|
+
else
|
57
|
+
DEFAULT_HEADER_IMG_URL
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.default_not_found_page(path)
|
63
|
+
# TODO: - default not found page
|
64
|
+
# get '*unmatched_route', to: 'application#not_found'
|
65
|
+
# is already taking care of any wrong route
|
66
|
+
"<h1>No such blog</h1><p>#{path}</p>"
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Blog::Category
|
2
|
+
attr_reader :name, :plural, :slug, :color
|
3
|
+
attr_accessor :blogposts
|
4
|
+
|
5
|
+
def initialize(attributes)
|
6
|
+
# attributes.each {|k, v| self.instance_variable_set("@#{k}", v)}
|
7
|
+
|
8
|
+
@name = attributes['name']
|
9
|
+
@plural = attributes['plural']
|
10
|
+
@slug = attributes['slug']
|
11
|
+
@color = attributes['color']
|
12
|
+
|
13
|
+
@blogposts = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def build_n_blogposts_by_category(blogposts_json, num = 0)
|
17
|
+
bp = blogposts_json.select { |b| b['category']['slug'].downcase == @slug.downcase }
|
18
|
+
|
19
|
+
bp = bp.first(num) if num.positive?
|
20
|
+
|
21
|
+
@blogposts = bp.map { |b| Blog::Blogpost.new b }
|
22
|
+
|
23
|
+
self
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
class AuthorParser
|
4
|
+
PATH_TO_AUTHORS = "#{Rails.configuration.blog_path}/authors/".freeze
|
5
|
+
|
6
|
+
def self.fetch_all_authors
|
7
|
+
authors = {}
|
8
|
+
|
9
|
+
authors_folder_path = Dir.glob("#{PATH_TO_AUTHORS}*.json")
|
10
|
+
|
11
|
+
authors_folder_path.each do |filename|
|
12
|
+
document = File.read(filename)
|
13
|
+
|
14
|
+
author_hash = YAML.safe_load(document)
|
15
|
+
|
16
|
+
short_name = File.basename(filename, '.json')
|
17
|
+
|
18
|
+
author_hash.merge!({ 'short_name' => short_name })
|
19
|
+
|
20
|
+
authors[short_name.to_sym] = author_hash
|
21
|
+
end
|
22
|
+
|
23
|
+
authors
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.fetch_author(name)
|
27
|
+
author_json_path = "#{PATH_TO_AUTHORS}#{name}.json"
|
28
|
+
|
29
|
+
return unless File.exist?(author_json_path)
|
30
|
+
|
31
|
+
file = File.read(author_json_path)
|
32
|
+
|
33
|
+
short_name = File.basename(author_json_path, '.json')
|
34
|
+
|
35
|
+
JSON.parse(file).merge!({ 'short_name' => short_name })
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.fetch_all_blogposts_from(author)
|
39
|
+
blogposts_hash = JSON.parse(File.read(BlogpostParser::PATH_TO_INDEX))
|
40
|
+
|
41
|
+
blogposts_hash.select { |blogpost| blogpost['author'] == author }
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.asset_exist?(path)
|
45
|
+
if Rails.configuration.assets.compile
|
46
|
+
Rails.application.precompiled_assets.include? path
|
47
|
+
else
|
48
|
+
Rails.application.assets_manifest.assets[path].present?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# :"abdul-ajetunmobi"=>
|
54
|
+
# {"team"=>true,
|
55
|
+
# "name"=>"Abdul Ajetunmobi",
|
56
|
+
# "image_url"=>"https://github.com/abdulajet.png",
|
57
|
+
# "bio"=>
|
58
|
+
# "Abdul is a Developer Advocate for Vonage. He has a background working in consumer products as an iOS Engineer. In his spare time, he enjoys biking, listening to music and mentoring those who are just beginning their journey in tech",
|
59
|
+
# "website_url"=>"https://abdulajet.me",
|
60
|
+
# "twitter"=>"abdulajet",
|
61
|
+
# "title"=>"Vonage Developer Advocate"},
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
class BlogpostParser
|
4
|
+
PATH_TO_INDEX = "#{Rails.configuration.blog_path}/blogposts/blogposts_info.json".freeze
|
5
|
+
|
6
|
+
def self.fetch_all
|
7
|
+
# Add Rescue from error
|
8
|
+
file = File.read(PATH_TO_INDEX)
|
9
|
+
|
10
|
+
JSON.parse(file)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.build
|
14
|
+
all_blogposts = []
|
15
|
+
|
16
|
+
['en', 'cn', 'it'].each { |locale| all_blogposts += build_index_with_locale(locale) }
|
17
|
+
|
18
|
+
# Sort by DATE
|
19
|
+
all_blogposts = all_blogposts.sort_by { |k| k['published_at'] }.reverse
|
20
|
+
|
21
|
+
# Write content
|
22
|
+
File.write(PATH_TO_INDEX, JSON.pretty_generate(all_blogposts))
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.build_index_with_locale(locale = 'en')
|
26
|
+
blogposts_locale_path = Dir.glob("#{ENV['BLOG_PATH']}/blogposts/#{locale}/*.md")
|
27
|
+
|
28
|
+
# TODO: - fix the issue with this blogpost
|
29
|
+
blogposts_locale_path -= ["#{Rails.configuration.blog_path}/blogposts/en/add-video-capabilities-to-zendesk-with-vonage-video-api.md"]
|
30
|
+
|
31
|
+
blogposts_locale_path.map { |filename| build_show_with_locale(filename, locale) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.build_custom_attributes(frontmatter, filename, locale)
|
35
|
+
frontmatter.except!('comments', 'redirect', 'canonical', 'old_categories')
|
36
|
+
|
37
|
+
filename = File.basename(filename, '.md')
|
38
|
+
year, month, day = frontmatter['published_at'].strftime('%y %m %d').split
|
39
|
+
|
40
|
+
{
|
41
|
+
'locale' => locale,
|
42
|
+
'link' => "blog/#{locale == 'en' ? '' : "#{locale}/"}#{year}/#{month}/#{day}/#{filename}",
|
43
|
+
'filename' => File.basename(filename, '.md'),
|
44
|
+
'author' => AuthorParser.fetch_author(frontmatter['author']),
|
45
|
+
'category' => CategoryParser.fetch_category(frontmatter['category']),
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.build_show_with_locale(filename, locale = 'en')
|
50
|
+
document = File.read(filename)
|
51
|
+
|
52
|
+
# body = Nexmo::Markdown::Renderer.new.call(document)
|
53
|
+
frontmatter = YAML.safe_load(document, [Time])
|
54
|
+
|
55
|
+
frontmatter.merge!(build_custom_attributes(frontmatter, filename, locale))
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
class CategoryParser
|
4
|
+
PATH_TO_CATEGORIES = "#{Rails.configuration.blog_path}/categories.json".freeze
|
5
|
+
|
6
|
+
def self.fetch_all_categories
|
7
|
+
JSON.parse(File.read(PATH_TO_CATEGORIES))['categories']
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.fetch_category(slug)
|
11
|
+
fetch_all_categories.find { |c| c['slug'] == slug.downcase }
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.fetch_blogposts_with_category(category)
|
15
|
+
blogposts_hash = JSON.parse(File.read(BlogpostParser::PATH_TO_INDEX))
|
16
|
+
|
17
|
+
blogposts_hash.select { |blogpost| blogpost['category'] == category }
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
class TagParser
|
4
|
+
# PATH_TO_CATEGORIES = "#{Rails.configuration.blog_path}/categories.json"
|
5
|
+
|
6
|
+
# def self.fetch_all_categories
|
7
|
+
# JSON.parse(File.read(PATH_TO_CATEGORIES))
|
8
|
+
# end
|
9
|
+
|
10
|
+
TAGS_WITH_ICON = [
|
11
|
+
'dispatch-api',
|
12
|
+
'messages-api',
|
13
|
+
'messages-api-sandbox',
|
14
|
+
'number-insight-api',
|
15
|
+
'number-api',
|
16
|
+
'reports-api',
|
17
|
+
'account-api',
|
18
|
+
'pricing-api',
|
19
|
+
'external-accounts-api',
|
20
|
+
'redact-api',
|
21
|
+
'audit-api',
|
22
|
+
'verify-api',
|
23
|
+
'media-api',
|
24
|
+
'voice-api',
|
25
|
+
'conversation-api',
|
26
|
+
'video-api',
|
27
|
+
'sms-api',
|
28
|
+
'station',
|
29
|
+
'spotlight',
|
30
|
+
'voyagers',
|
31
|
+
].freeze
|
32
|
+
|
33
|
+
def self.fetch_blogposts_with_tag(tag)
|
34
|
+
blogposts_hash = JSON.parse(File.read(BlogpostParser::PATH_TO_INDEX))
|
35
|
+
|
36
|
+
blogposts_hash.select { |b| b['tags'].include?(tag) && b['published'] && !b['outdated'] }
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
<div class="social-links">
|
2
|
+
|
3
|
+
<% if author.website_url.present? %>
|
4
|
+
<%= link_to author.website_url, target: '_blank', rel: "noopener" do %>
|
5
|
+
<div class="Vlt-btn Vlt-btn--white Vlt-btn--icon">
|
6
|
+
<svg><use xlink:href="/symbol/volta-icons.svg#Vlt-icon-world"/></svg>
|
7
|
+
</div>
|
8
|
+
<% end %>
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<% if author.twitter.present? %>
|
12
|
+
<%= link_to "https://www.twitter.com/#{author.twitter}", target: '_blank', rel: "noopener" do %>
|
13
|
+
<div class="Vlt-btn Vlt-btn--white Vlt-btn--icon">
|
14
|
+
<svg><use xlink:href="/symbol/volta-brand-icons.svg#Brand-icon-twitter-color"/></svg>
|
15
|
+
</div>
|
16
|
+
<% end %>
|
17
|
+
<% end %>
|
18
|
+
|
19
|
+
<% if author.linkedin_url.present? %>
|
20
|
+
<%= link_to author.linkedin_url, target: '_blank', rel: "noopener" do %>
|
21
|
+
<div class="Vlt-btn Vlt-btn--white Vlt-btn--icon">
|
22
|
+
<svg><use xlink:href="/symbol/volta-brand-icons.svg#Brand-icon-linkedin-color"/></svg>
|
23
|
+
</div>
|
24
|
+
<% end %>
|
25
|
+
<% end %>
|
26
|
+
|
27
|
+
<% if author.github_url.present? %>
|
28
|
+
<%= link_to author.github_url, target: '_blank', rel: "noopener" do %>
|
29
|
+
<div class="Vlt-btn Vlt-btn--white Vlt-btn--icon">
|
30
|
+
<svg><use xlink:href="/symbol/volta-brand-icons.svg#Brand-icon-github-color"/></svg>
|
31
|
+
</div>
|
32
|
+
<% end %>
|
33
|
+
<% end %>
|
34
|
+
|
35
|
+
<% if author.youtube_url.present? %>
|
36
|
+
<%= link_to author.youtube_url, target: '_blank', rel: "noopener" do %>
|
37
|
+
<div class="Vlt-btn Vlt-btn--white Vlt-btn--icon">
|
38
|
+
<svg><use xlink:href="/symbol/volta-brand-icons.svg#Brand-icon-youtube-color"/></svg>
|
39
|
+
</div>
|
40
|
+
<% end %>
|
41
|
+
<% end %>
|
42
|
+
|
43
|
+
<% if author.facebook_url.present? %>
|
44
|
+
<%= link_to author.facebook_url, target: '_blank', rel: "noopener" do %>
|
45
|
+
<div class="Vlt-btn Vlt-btn--white Vlt-btn--icon">
|
46
|
+
<svg><use xlink:href="/symbol/volta-brand-icons.svg#Brand-icon-facebook-color"/></svg>
|
47
|
+
</div>
|
48
|
+
<% end %>
|
49
|
+
<% end %>
|
50
|
+
|
51
|
+
<% if author.twitch_url.present? %>
|
52
|
+
<%= link_to author.twitch_url, target: '_blank', rel: "noopener" do %>
|
53
|
+
<div class="Vlt-btn Vlt-btn--white Vlt-btn--icon">
|
54
|
+
<svg><use xlink:href="/symbol/volta-brand-icons.svg#Brand-icon-twitch-color"/></svg>
|
55
|
+
</div>
|
56
|
+
<% end %>
|
57
|
+
<% end %>
|
58
|
+
|
59
|
+
<% if author.stackoverflow_url.present? %>
|
60
|
+
<%= link_to author.stackoverflow_url, target: '_blank', rel: "noopener" do %>
|
61
|
+
<div class="Vlt-btn Vlt-btn--white Vlt-btn--icon">
|
62
|
+
<svg><use xlink:href="/symbol/volta-brand-icons.svg#Brand-icon-stackoverflow-color"/></svg>
|
63
|
+
</div>
|
64
|
+
<% end %>
|
65
|
+
<% end %>
|
66
|
+
|
67
|
+
</div>
|
@@ -0,0 +1,46 @@
|
|
1
|
+
<div class="max-w-screen-xl mx-auto">
|
2
|
+
|
3
|
+
<div style="display: flex; justify-content: space-between">
|
4
|
+
|
5
|
+
<!-- Author -->
|
6
|
+
<div class="Vlt-card Vlt-bg-white" style="width:28%;height: fit-content;">
|
7
|
+
<div class="Vlt-card__image" style="background-image: url('<%= @author.url %>'); background-size: cover; min-height: 40vh; background-position: center;"></div>
|
8
|
+
|
9
|
+
<div class="Vlt-card__content">
|
10
|
+
<h2 class="Vlt-title--icon center-author-name">
|
11
|
+
<svg class="Vlt-icon Vlt-icon--larger">
|
12
|
+
<use xlink:href="/symbol/volta-icons.svg#Vlt-icon-pentool" />
|
13
|
+
</svg>
|
14
|
+
<%= @author.name %>
|
15
|
+
</h2>
|
16
|
+
|
17
|
+
<p class="author-title"><code><small><%= @author.title %></small></code></p>
|
18
|
+
|
19
|
+
<p style="opacity:.8;font-weight: bold;">
|
20
|
+
<%= @author.bio if @author.bio.present? %>
|
21
|
+
</p>
|
22
|
+
</div>
|
23
|
+
|
24
|
+
<%= render partial: 'blog/authors/social_links', locals: { author: @author} %>
|
25
|
+
</div>
|
26
|
+
|
27
|
+
<!-- Blogposts -->
|
28
|
+
<div style="width:70%;">
|
29
|
+
<% unless @author.blogposts.count.positive? %>
|
30
|
+
<div class="Vlt-callout Vlt-callout--warning">
|
31
|
+
<div class="Vlt-callout__content">No Blogpost available</div>
|
32
|
+
</div>
|
33
|
+
<% else %>
|
34
|
+
|
35
|
+
<div class="my-3col-grid">
|
36
|
+
<% @author.blogposts.in_groups(2) do |blogposts| %>
|
37
|
+
<%= render partial: 'blog/blogpost/blogpost', collection: blogposts, as: :blogpost,
|
38
|
+
locals: { show_category_label: true, show_author: false, show_tag_labels: true } %>
|
39
|
+
<% end %>
|
40
|
+
</div>
|
41
|
+
|
42
|
+
<% end %>
|
43
|
+
</div>
|
44
|
+
</div>
|
45
|
+
|
46
|
+
</div>
|
@@ -0,0 +1,74 @@
|
|
1
|
+
<% if blogpost %>
|
2
|
+
<% author = blogpost.author %>
|
3
|
+
<% category = blogpost.category %>
|
4
|
+
|
5
|
+
|
6
|
+
<div class="Vlt-card Vlt-card--border d-flex-column">
|
7
|
+
|
8
|
+
<!-- CATEGORY -->
|
9
|
+
<% if show_category_label %>
|
10
|
+
<a href="<%= blog_category_path(category.slug)%>" class="category-name" style="color: <%= category.color %>;padding:0 0 16px 0;">
|
11
|
+
< <%= category.name %> />
|
12
|
+
</a>
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
<!-- TOP TAGs label -->
|
16
|
+
<%= render partial: 'blog/blogpost/tag_labels', locals: { blogpost: blogpost } %>
|
17
|
+
|
18
|
+
<!-- CONTENT -->
|
19
|
+
<div class="blogpost_card_content">
|
20
|
+
<div class="">
|
21
|
+
<a href="/<%= blogpost.link %>">
|
22
|
+
<p class="p-large"><b><%= blogpost.title %></b></p>
|
23
|
+
</a>
|
24
|
+
|
25
|
+
<p><%= blogpost.description.truncate(150) %></p>
|
26
|
+
</div>
|
27
|
+
|
28
|
+
|
29
|
+
<!-- AUTHOR -->
|
30
|
+
<% if author && author.name && show_author %>
|
31
|
+
<div class="">
|
32
|
+
|
33
|
+
<a href="/<%= blogpost.link %>" class="Vlt-blue-darker">
|
34
|
+
[<%= t('read_more') %>]
|
35
|
+
</a>
|
36
|
+
|
37
|
+
<hr class="hr--short">
|
38
|
+
|
39
|
+
<div style='display:flex; justify-content: flex-start;'>
|
40
|
+
|
41
|
+
<% if author.image_url %>
|
42
|
+
<%= image_tag author.url, style: "display: block; width: 4.5rem; height: 4.5rem; border-radius: 50%;" %>
|
43
|
+
<% end %>
|
44
|
+
|
45
|
+
<div style='margin-left: 1.5rem;'>
|
46
|
+
<h5>
|
47
|
+
<%= link_to author.name, blog_author_path(author.short_name) %>
|
48
|
+
|
49
|
+
<p class='Vlt-grey-darker'><strong><%= Date.parse(blogpost.published_at).strftime('%b %d, %Y') %></strong></p>
|
50
|
+
</h5>
|
51
|
+
</div>
|
52
|
+
|
53
|
+
</div>
|
54
|
+
|
55
|
+
</div>
|
56
|
+
|
57
|
+
<% else %>
|
58
|
+
<!-- NO AUTHOR -->
|
59
|
+
<div class="">
|
60
|
+
|
61
|
+
<div style="display: flex;justify-content: space-between;">
|
62
|
+
<a href="/<%= blogpost.link %>" class="Vlt-blue-darker">
|
63
|
+
[<%= t('read_more') %>]
|
64
|
+
</a>
|
65
|
+
<p class='Vlt-grey-darker'><strong><%= Date.parse(blogpost.published_at).strftime('%b %d, %Y') %></strong></p>
|
66
|
+
</div>
|
67
|
+
|
68
|
+
</div>
|
69
|
+
<% end # if author && author.name && show_author %>
|
70
|
+
|
71
|
+
</div>
|
72
|
+
</div>
|
73
|
+
|
74
|
+
<% end %>
|
@@ -0,0 +1,59 @@
|
|
1
|
+
<% if blogpost %>
|
2
|
+
<% author = blogpost.author %>
|
3
|
+
<% category = blogpost.category %>
|
4
|
+
|
5
|
+
|
6
|
+
<div class="Vlt-card Vlt-card--border Vlt-col d-flex-column" style="padding:0;">
|
7
|
+
|
8
|
+
<a href="/<%= blogpost.link %>" class="Vlt-blue-darker">
|
9
|
+
<div class="Vlt-card--border border-radius-top card-header-image" style="background-image: url(<%= blogpost.header_img_url %>);"></div>
|
10
|
+
</a>
|
11
|
+
|
12
|
+
<a href="<%= blog_category_path(category.slug)%>" class="category-name" style="color: <%= category.color %>">
|
13
|
+
< <%= category.name %> />
|
14
|
+
</a>
|
15
|
+
|
16
|
+
<div class="blogpost_card_content Vlt-card--lesspadding">
|
17
|
+
<div class="">
|
18
|
+
<a href="/<%= blogpost.link %>">
|
19
|
+
<p class="p-large"><b><%= blogpost.title %></b></p>
|
20
|
+
</a>
|
21
|
+
|
22
|
+
<p><%= blogpost.description %></p>
|
23
|
+
</div>
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
<% if author && author.name %>
|
28
|
+
<div class="card-footer">
|
29
|
+
|
30
|
+
<a href="/<%= blogpost.link %>" class="Vlt-blue-darker">
|
31
|
+
[<%= t('read_more') %>]
|
32
|
+
</a>
|
33
|
+
|
34
|
+
<hr class="hr--short">
|
35
|
+
|
36
|
+
<div style='display:flex; justify-content: flex-start;'>
|
37
|
+
|
38
|
+
<% if author.image_url %>
|
39
|
+
<%= image_tag author.url, class: "image-tag-author" %>
|
40
|
+
<% end %>
|
41
|
+
|
42
|
+
<div style='margin-left: 1.5rem;'>
|
43
|
+
<h5>
|
44
|
+
<%= link_to author.name, blog_author_path(author.short_name) %>
|
45
|
+
|
46
|
+
<p class='Vlt-grey-darker'>
|
47
|
+
<strong><%= Date.parse(blogpost.published_at).strftime('%b %d, %Y') %></strong>
|
48
|
+
</p>
|
49
|
+
</h5>
|
50
|
+
</div>
|
51
|
+
|
52
|
+
</div>
|
53
|
+
</div>
|
54
|
+
<% end %>
|
55
|
+
|
56
|
+
</div>
|
57
|
+
</div>
|
58
|
+
|
59
|
+
<% end %>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<% if blogpost.tags.count > 0 %>
|
2
|
+
<div style='margin-bottom: 1.5rem;'>
|
3
|
+
<% blogpost.tags.each do |tag| %>
|
4
|
+
<% next if tag.empty? %>
|
5
|
+
<a href="<%= blog_tag_path(tag.downcase)%>">
|
6
|
+
<small class="Vlt-badge Vlt-badge--<%= tag.downcase %> Vlt-badge--transparent">
|
7
|
+
<% if TagParser::TAGS_WITH_ICON.include? tag %>
|
8
|
+
<span class="fix-position-V-icon">
|
9
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" style="width: 1em;" class="Vlt-white">
|
10
|
+
<path d="M9.3 11.6L4.7 1.5H0l6.8 15.3s.1.1.1 0l2.4-5.2zm9.9-10.1s-6.1 13.9-6.9 15.6c-1.8 4.1-3.2 5.1-4.6 5.3H12c1.9 0 3.2-1.3 5.1-5.3.6-1.4 6.9-15.6 6.9-15.6h-4.8z" />
|
11
|
+
</svg>
|
12
|
+
</span>
|
13
|
+
<% else %>
|
14
|
+
#
|
15
|
+
<% end %>
|
16
|
+
<%= tag == "Objective_C" ? "Objective-C" : tag.downcase %></small>
|
17
|
+
</a>
|
18
|
+
<% end %>
|
19
|
+
</div>
|
20
|
+
<% end %>
|
@@ -0,0 +1,43 @@
|
|
1
|
+
<% unless @categories_with_blogposts.present? %>
|
2
|
+
|
3
|
+
<div class="Vlt-callout Vlt-callout--warning">
|
4
|
+
<i></i>
|
5
|
+
<div class="Vlt-callout__content">
|
6
|
+
No Blogpost available
|
7
|
+
</div>
|
8
|
+
</div>
|
9
|
+
|
10
|
+
<% else %>
|
11
|
+
|
12
|
+
|
13
|
+
<div class="max-w-screen-xl mx-auto">
|
14
|
+
|
15
|
+
<div class="header-separator hr--tall Vlt-text-separator Vlt-text-separator--big">
|
16
|
+
<span>LATEST POSTS</span>
|
17
|
+
</div>
|
18
|
+
|
19
|
+
<div class="my-2col-grid">
|
20
|
+
<%= render partial: 'blog/blogpost/blogpost_with_image', collection: @latest_blogposts, as: :blogpost %>
|
21
|
+
</div>
|
22
|
+
|
23
|
+
|
24
|
+
<% @categories_with_blogposts.each do |category| %>
|
25
|
+
|
26
|
+
<div class="header-separator hr--tall Vlt-text-separator Vlt-text-separator--big">
|
27
|
+
<span>< <%= category.plural.upcase %> /></span>
|
28
|
+
</div>
|
29
|
+
|
30
|
+
<div class="my-3col-grid">
|
31
|
+
<% category.blogposts.compact.in_groups(3) do |blogposts| %>
|
32
|
+
<%# cache blogpost do %>
|
33
|
+
<%= render partial: 'blog/blogpost/blogpost', collection: blogposts, as: :blogpost, locals: { show_category_label: false, show_author: true } %>
|
34
|
+
<%# end %>
|
35
|
+
<% end %>
|
36
|
+
</div>
|
37
|
+
|
38
|
+
<% end # @categories_with_blogposts.each %>
|
39
|
+
|
40
|
+
</div>
|
41
|
+
|
42
|
+
|
43
|
+
<% end %>
|