station 0.0.145 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nexmo_developer/Gemfile +6 -0
  3. data/lib/nexmo_developer/Gemfile.lock +8 -0
  4. data/lib/nexmo_developer/app/assets/stylesheets/{application.css → application.scss} +2 -0
  5. data/lib/nexmo_developer/app/assets/stylesheets/blog/badge.scss +245 -0
  6. data/lib/nexmo_developer/app/assets/stylesheets/blog/blog.scss +209 -0
  7. data/lib/nexmo_developer/app/controllers/blog/authors_controller.rb +8 -0
  8. data/lib/nexmo_developer/app/controllers/blog/blogpost_controller.rb +32 -0
  9. data/lib/nexmo_developer/app/controllers/blog/categories_controller.rb +8 -0
  10. data/lib/nexmo_developer/app/controllers/blog/main_controller.rb +9 -0
  11. data/lib/nexmo_developer/app/controllers/blog/tags_controller.rb +8 -0
  12. data/lib/nexmo_developer/app/helpers/blog_helper.rb +7 -0
  13. data/lib/nexmo_developer/app/models/blog/author.rb +59 -0
  14. data/lib/nexmo_developer/app/models/blog/blogpost.rb +68 -0
  15. data/lib/nexmo_developer/app/models/blog/category.rb +25 -0
  16. data/lib/nexmo_developer/app/services/author_parser.rb +61 -0
  17. data/lib/nexmo_developer/app/services/blogpost_parser.rb +57 -0
  18. data/lib/nexmo_developer/app/services/category_parser.rb +19 -0
  19. data/lib/nexmo_developer/app/services/tag_parser.rb +38 -0
  20. data/lib/nexmo_developer/app/views/blog/authors/_social_links.html.erb +67 -0
  21. data/lib/nexmo_developer/app/views/blog/authors/show.html.erb +46 -0
  22. data/lib/nexmo_developer/app/views/blog/blogpost/_blogpost.html.erb +74 -0
  23. data/lib/nexmo_developer/app/views/blog/blogpost/_blogpost_with_image.html.erb +59 -0
  24. data/lib/nexmo_developer/app/views/blog/blogpost/_tag_labels.html.erb +20 -0
  25. data/lib/nexmo_developer/app/views/blog/blogpost/index.html.erb +43 -0
  26. data/lib/nexmo_developer/app/views/blog/blogpost/show.html.erb +127 -0
  27. data/lib/nexmo_developer/app/views/blog/categories/show.html.erb +25 -0
  28. data/lib/nexmo_developer/app/views/blog/tags/show.html.erb +25 -0
  29. data/lib/nexmo_developer/app/views/layouts/application.html.erb +1 -1
  30. data/lib/nexmo_developer/app/views/layouts/partials/_header.html.erb +0 -3
  31. data/lib/nexmo_developer/config/application.rb +1 -0
  32. data/lib/nexmo_developer/config/routes.rb +9 -1
  33. data/lib/nexmo_developer/lib/tasks/blog.rake +12 -0
  34. data/lib/nexmo_developer/public/assets/.sprockets-manifest-3f3d4eafc3f8d9771fa4ba3f13084baf.json +1 -0
  35. data/lib/nexmo_developer/public/assets/application-aa88b3c7bd34ec529f43849541752fda7c9c202aa9fff905be578ef88d103b46.js.gz +0 -0
  36. data/lib/nexmo_developer/public/assets/{application-6e9186f7602070c57b5c60de9b45ad12f1fccdcf83e08ea28c809d7a5a42a232.css → application-d9ea3be5cba4feaa1cbe4f50a2d73a7cd19cbc1658778180d3cd3890a0dd6ed0.css} +1 -1
  37. data/lib/nexmo_developer/public/assets/application-d9ea3be5cba4feaa1cbe4f50a2d73a7cd19cbc1658778180d3cd3890a0dd6ed0.css.gz +0 -0
  38. data/lib/nexmo_developer/public/assets/manifest-b4bf6e57a53c2bdb55b8998cc94cd00883793c1c37c5e5aea3ef6749b4f6d92b.js.gz +0 -0
  39. data/lib/nexmo_developer/version.rb +1 -1
  40. metadata +31 -6
  41. data/lib/nexmo_developer/public/assets/.sprockets-manifest-cbc98735a38ce872d5ca075ef4d92ef7.json +0 -1
  42. 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 %>