coursegen 0.7.7 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/pr.yml +19 -0
  3. data/.gitignore +3 -0
  4. data/Gemfile.lock +90 -45
  5. data/README.md +285 -69
  6. data/Rakefile +10 -1
  7. data/coursegen.gemspec +26 -26
  8. data/lib/coursegen.rb +5 -2
  9. data/lib/coursegen/cli.rb +49 -14
  10. data/lib/coursegen/course/data/citem.rb +10 -1
  11. data/lib/coursegen/course/data/data_adaptor.rb +16 -6
  12. data/lib/coursegen/course/data/section.rb +1 -1
  13. data/lib/coursegen/course/helpers/bootstrap_markup.rb +15 -15
  14. data/lib/coursegen/course/helpers/content_helpers.rb +173 -100
  15. data/lib/coursegen/course/helpers/formatting_helpers.rb +6 -10
  16. data/lib/coursegen/course/helpers/ical_feed_helpers.rb +2 -1
  17. data/lib/coursegen/course/helpers/lecture_helpers.rb +3 -2
  18. data/lib/coursegen/course/helpers/list_of.rb +40 -20
  19. data/lib/coursegen/course/helpers/list_of_helpers.rb +20 -14
  20. data/lib/coursegen/course/helpers/logging_helpers.rb +13 -12
  21. data/lib/coursegen/course/helpers/navigation_helpers.rb +63 -20
  22. data/lib/coursegen/course/helpers/sidebar_helpers.rb +19 -18
  23. data/lib/coursegen/course/helpers/table_helpers.rb +5 -4
  24. data/lib/coursegen/course/schedule/scheduler.rb +52 -19
  25. data/lib/coursegen/templates.rb +30 -23
  26. data/lib/coursegen/version.rb +3 -1
  27. data/spec/lectures_spec.rb +60 -50
  28. data/spec/play_spec.rb +24 -12
  29. data/spec/scheduler_spec.rb +87 -27
  30. data/tech_debt.md +5 -0
  31. data/templates/Rules +14 -19
  32. data/templates/cg_config.rb +105 -21
  33. data/templates/content/bootstrap/css/custom.css +87 -151
  34. data/templates/content/bootstrap/css/full-width-pics.css +8 -64
  35. data/templates/content/bootstrap/css/postit.css +7 -0
  36. data/templates/content/bootstrap/css/toasty.css +3 -0
  37. data/templates/content/content/index.md.erb +1 -1
  38. data/templates/content/content/intro/course_toc.md.erb +0 -1
  39. data/templates/content/content/intro/welcome.md.erb +1 -3
  40. data/templates/content/content/lectures/part1/02_here_we_go.md.erb +22 -1
  41. data/templates/content/content/lectures/part2/01_start_part2.md.erb +2 -1
  42. data/templates/content/content/lectures/part2/02_continue_part2.md.erb +3 -2
  43. data/templates/layouts/banner.html.erb +4 -4
  44. data/templates/layouts/body_footer.html +3 -4
  45. data/templates/layouts/body_header.html.erb +25 -7
  46. data/templates/layouts/bottom_includes.html.erb +21 -10
  47. data/templates/layouts/course.html.erb +7 -21
  48. data/templates/layouts/helpful_box.html +1 -1
  49. data/templates/layouts/nav-menus.html.erb +16 -36
  50. data/templates/layouts/sidebar.html.erb +9 -8
  51. data/templates/layouts/slides.html.erb +69 -0
  52. data/templates/layouts/top_includes.html.erb +24 -23
  53. metadata +33 -24
  54. data/.DS_Store +0 -0
  55. data/templates/.DS_Store +0 -0
  56. data/templates/Guardfile +0 -9
  57. data/templates/content/bootstrap/css/tipuesearch.css +0 -163
  58. data/templates/content/bootstrap/js/tipuesearch.js +0 -379
  59. data/templates/content/bootstrap/js/tipuesearch.min.js +0 -12
  60. data/templates/content/bootstrap/js/tipuesearch_content.js +0 -13
  61. data/templates/content/bootstrap/js/tipuesearch_set.js +0 -23
  62. data/templates/layouts/main_navbar.html.erb +0 -21
data/Rakefile CHANGED
@@ -1 +1,10 @@
1
- require "bundler/gem_tasks"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec'
5
+
6
+ begin
7
+ require 'rspec/core/rake_task'
8
+ RSpec::Core::RakeTask.new(:spec)
9
+ rescue LoadError
10
+ end
@@ -1,37 +1,37 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require 'coursegen/version'
5
4
 
6
5
  Gem::Specification.new do |spec|
7
- spec.name = "coursegen"
6
+ spec.name = 'coursegen'
8
7
  spec.version = Coursegen::VERSION
9
- spec.authors = ["Pito Salas"]
10
- spec.email = ["pitosalas@gmail.com"]
11
- spec.summary = "Use Nanoc to build courses and deploy them to S3"
12
- spec.description = "Use Nanoc to build courses and deploy them to S3"
13
- spec.homepage = ""
14
- spec.license = "MIT"
8
+ spec.authors = ['Pito Salas']
9
+ spec.email = ['pitosalas@gmail.com']
10
+ spec.summary = 'Use Nanoc to build courses and deploy them to S3'
11
+ spec.description = 'Use Nanoc to build courses and deploy them to S3'
12
+ spec.homepage = ''
13
+ spec.license = 'MIT'
15
14
 
16
15
  spec.files = `git ls-files -z`.split("\x0")
17
16
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
18
+ spec.require_paths = ['lib']
20
19
 
21
- spec.add_development_dependency "bundler"
22
- spec.add_development_dependency "rake"
23
-
24
- spec.add_dependency "nanoc"
25
- spec.add_dependency "thor"
26
- spec.add_dependency "rubytree"
27
- spec.add_dependency "cri"
28
- spec.add_dependency "nokogiri"
29
- spec.add_dependency "activesupport"
30
- spec.add_dependency "kramdown"
31
- spec.add_dependency "adsf"
32
- spec.add_dependency "guard"
33
- spec.add_dependency "guard-shell"
34
- spec.add_dependency "tzinfo"
35
- spec.add_dependency "icalendar"
36
- spec.add_dependency "byebug"
20
+ spec.add_development_dependency 'bundler'
21
+ spec.add_development_dependency 'rake'
22
+ spec.add_development_dependency 'rspec'
23
+
24
+ spec.add_dependency 'activesupport'
25
+ spec.add_dependency 'adsf'
26
+ spec.add_dependency 'byebug'
27
+ spec.add_dependency 'cri'
28
+ spec.add_dependency 'guard'
29
+ spec.add_dependency 'guard-shell'
30
+ spec.add_dependency 'icalendar'
31
+ spec.add_dependency 'kramdown'
32
+ spec.add_dependency 'nanoc'
33
+ spec.add_dependency 'nokogiri'
34
+ spec.add_dependency 'rubytree'
35
+ spec.add_dependency 'thor'
36
+ spec.add_dependency 'tzinfo'
37
37
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'nokogiri'
2
4
 
3
5
  require 'coursegen/version'
@@ -25,7 +27,8 @@ require 'coursegen/course/helpers/list_of'
25
27
  require 'coursegen/course/helpers/ical_feed_helpers'
26
28
  require 'coursegen/course/lib/helpers_'
27
29
 
28
-
30
+ # Coursegen is a course curriculum site generator based on nanoc, with
31
+ # support for sections, lectures, code examples, homeworks, course
32
+ # calendar and lots more.
29
33
  module Coursegen
30
- # Your code goes here...
31
34
  end
@@ -1,46 +1,81 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thor'
2
4
  require 'coursegen/templates'
3
5
  require 'nanoc'
4
6
  require './cg_config.rb' if File.exist? 'cg_config.rb'
5
7
 
6
8
  module CourseGen
9
+ # Class CLI provides a command line utility for creating, building, and
10
+ # deploying a Coursegen site.
7
11
  class CLI < Thor
8
12
  include Thor::Actions
9
13
 
10
- desc "new COURSE", "Create a new course by calling nanoc. Argument is name of the COURSE"
14
+ # New creates a new nanoc site.
15
+ #
16
+ # By default, the new site does not contain any course template.
17
+ # To generate a course template within the newly created nanoc site,
18
+ # run: `cg prepare`.
19
+ #
20
+ # See: https://nanoc.ws/doc/reference/commands/#create-site
21
+ desc 'new COURSE',
22
+ 'Create a new course by calling nanoc. Argument is name of the COURSE'
11
23
  def new(course)
12
24
  run("nanoc create-site #{course}")
13
25
  end
14
26
 
15
- desc "prepare", "Update with the latest coursegen code and templates."
27
+ # Prepare generates a new course template within a nanoc site.
28
+ desc 'prepare',
29
+ 'Update with the latest coursegen code and templates.'
16
30
  def prepare
17
31
  check_valid_directory
18
32
  tplt = CourseGen::Templates.new
19
33
  tplt.generate_all
20
34
  end
21
35
 
22
- desc "compile", "build the course and put resultant site into output directory"
36
+ # Compile builds the course site and outputs it to a local directory.
37
+ #
38
+ # By default, it outputs the course site to ./output.
39
+ #
40
+ # See: https://nanoc.ws/doc/reference/commands/#compile
41
+ desc 'compile',
42
+ 'build the course and put resultant site into output directory'
23
43
  def compile
24
- run("nanoc compile")
44
+ run 'nanoc compile'
25
45
  end
26
46
 
27
- desc "serve", "start local web server to test the course web site"
47
+ # Serve starts a static web server that serves the course site.
48
+ #
49
+ # By default, the web server serves from ./output.
50
+ #
51
+ # See: https://nanoc.ws/doc/reference/commands/#view
52
+ desc 'serve',
53
+ 'start local web server to test the course web site'
28
54
  def serve
29
- run("nanoc view")
55
+ run 'nanoc view'
30
56
  end
31
57
 
32
- desc "reset", "reset all generated content to bring the course back to a base state."
58
+ # Reset removes all generated contents.
59
+ desc 'reset',
60
+ 'reset all generated content to bring the course back to a base state.'
33
61
  def reset
34
- run "rm -frd tmp"
35
- run "rm -frd output"
62
+ run 'rm -frd tmp'
63
+ run 'rm -frd output'
36
64
  end
37
65
 
38
- desc "view", "view course site locally in browser"
66
+ # View opens an browser to the running course site.
67
+ desc 'view',
68
+ 'view course site locally in browser'
39
69
  def view
40
- run "open http://0.0.0.0:3000"
70
+ run 'open http://0.0.0.0:3000'
41
71
  end
42
72
 
43
- desc "deploy", "Deploy course to S3"
73
+ # Deploy deploys the course site to AWS S3.
74
+ #
75
+ # Note: `s3cmd` needs to be properly setup before this can work. Refer
76
+ # to README.md for detailed instructions.
77
+ desc 'deploy',
78
+ 'Deploy course to S3'
44
79
  def deploy
45
80
  run "s3cmd sync --delete-removed output/ s3://#{AWS_BUCKET}/"
46
81
  end
@@ -48,9 +83,9 @@ module CourseGen
48
83
  no_commands do
49
84
  def check_valid_directory
50
85
  if CourseGen::Templates.new.valid_cg_directory?
51
- say("Valid cg directory")
86
+ say 'Valid cg directory'
52
87
  else
53
- error("Invalid cg directory")
88
+ error 'Invalid cg directory'
54
89
  end
55
90
  end
56
91
  end
@@ -6,7 +6,8 @@ require 'active_support/inflector'
6
6
  #
7
7
  class CItem
8
8
  attr_reader :order, :section, :subsection, :subsection_citem, :title,
9
- :type, :identifier, :short_name, :status, :nitem, :css_class, :homework, :desc, :cat, :assigned
9
+ :type, :identifier, :short_name, :status, :nitem, :css_class,
10
+ :homework, :hwref, :desc, :cat, :assigned, :slides, :lectref, :reading, :due
10
11
  attr_accessor :lecture_number, :lecture_date, :start_time, :end_time
11
12
 
12
13
  # Callable with nitem=nil to create a mock
@@ -53,6 +54,7 @@ class CItem
53
54
 
54
55
  def schedule_start_date_time
55
56
  return if @lecture_date.nil?
57
+
56
58
  # schedule = Toc.instance.section(@section).schedule
57
59
  # lecture_date + schedule.start_time
58
60
  lecture_date + @start_time
@@ -60,6 +62,7 @@ class CItem
60
62
 
61
63
  def schedule_end_date_time
62
64
  return if @lecture_date.nil?
65
+
63
66
  # schedule = Toc.instance.section(@section).schedule
64
67
  # lecture_date + schedule.end_time
65
68
  lecture_date + @end_time
@@ -85,7 +88,13 @@ class CItem
85
88
  @homework = @nitem[:homework]
86
89
  @desc = @nitem[:desc]
87
90
  @cat = @nitem[:cat]
91
+ @hwref = @nitem[:hwref]
88
92
  @assigned = @nitem[:assigned]
93
+ @slides = @nitem[:slides]
94
+ @lectref = @nitem[:lectref]
95
+ @reading = @nitem[:reading]
96
+ @due = @nitem[:due]
97
+
89
98
  end
90
99
 
91
100
  def parse_identifier(ident)
@@ -5,8 +5,8 @@ class DataAdaptor
5
5
  end
6
6
 
7
7
  # column_selector is one of: :number, :date, :title, :homework
8
- COL_NAMES = {number: "#", date: "lecture date", title: "title",
9
- homework: "homework", desc: "description", cat: "category"}
8
+ COL_NAMES = { number: '#', date: 'lecture date', title: 'title',
9
+ homework: 'homework', desc: 'description', cat: 'category', hwref: 'homework', lectref: 'topics', reading: 'reading' }
10
10
 
11
11
  def column_name(column_selector)
12
12
  COL_NAMES[column_selector]
@@ -30,6 +30,8 @@ class DataAdaptor
30
30
  citem.identifier
31
31
  when :desc
32
32
  citem.desc
33
+ when :due
34
+ citem.due
33
35
  when :homework
34
36
  citem.homework
35
37
  when :assigned
@@ -39,13 +41,21 @@ class DataAdaptor
39
41
  when :end_date_time
40
42
  citem.schedule_end_date_time
41
43
  when :full_desc
42
- desc = citem.desc || ""
43
- hw = citem.homework || ""
44
- desc + ". HW: " + hw
44
+ desc = citem.desc || ''
45
+ hw = citem.homework || ''
46
+ desc + '. HW: ' + hw
45
47
  when :cat
46
48
  citem.cat
49
+ when :lectref
50
+ citem.lectref
51
+ when :hwref
52
+ citem.hwref
53
+ when :reading
54
+ citem.reading
55
+ when :order
56
+ citem.order
47
57
  else
48
- "error!"
58
+ 'error!'
49
59
  end
50
60
  end
51
61
  end
@@ -60,7 +60,7 @@ class Section
60
60
  def lookup_citem_by_identifier identifier
61
61
  res = @citems.select { |i| i.identifier.to_s == identifier }
62
62
  fail "TOC#lookup_citem_by_identifier failed to find: '#{identifier}'" if res.length != 1
63
- # binding.pry if res.length != 1
63
+ byebug if res.length != 1
64
64
  res[0]
65
65
  end
66
66
 
@@ -1,32 +1,32 @@
1
+ # Class BootstrapMarkup provides methods for using Bootstrap specific HTML
2
+ # markups.
1
3
  class BootstrapMarkup
2
4
  def initialize
3
- @str = ""
5
+ @str = ''
4
6
  end
5
7
 
6
- def table_begin(css_class = "table-condensed")
7
- puts css_class.class
8
+ def table_begin(css_class = 'table-condensed')
8
9
  @str << "<table class=\"table x #{css_class}\">"
9
- puts @str
10
10
  end
11
11
 
12
12
  def table_end
13
- @str << "</table>"
13
+ @str << '</table>'
14
14
  end
15
15
 
16
16
  def headers_begin
17
- @str << "<thead><tr>"
17
+ @str << '<thead><tr>'
18
18
  end
19
19
 
20
20
  def headers_end
21
- @str << "</tr></thead>"
21
+ @str << '</tr></thead>'
22
22
  end
23
23
 
24
24
  def header_begin
25
- @str << "<th>"
25
+ @str << '<th>'
26
26
  end
27
27
 
28
28
  def header_end
29
- @str << "</th>"
29
+ @str << '</th>'
30
30
  end
31
31
 
32
32
  def header_content(str)
@@ -34,27 +34,27 @@ class BootstrapMarkup
34
34
  end
35
35
 
36
36
  def row_begin
37
- @str << "<tr>"
37
+ @str << '<tr>'
38
38
  end
39
39
 
40
40
  def row_end
41
- @str << "</tr>"
41
+ @str << '</tr>'
42
42
  end
43
43
 
44
44
  def cell_begin
45
- @str << "<td>"
45
+ @str << '<td>'
46
46
  end
47
47
 
48
48
  def cell_end
49
- @str << "</td>"
49
+ @str << '</td>'
50
50
  end
51
51
 
52
52
  def bigcell_begin
53
- @str << "<td colspan=\"3\"><h5>"
53
+ @str << '<td colspan="3"><h5>'
54
54
  end
55
55
 
56
56
  def bigcell_end
57
- @str << "</h5></td>"
57
+ @str << '</h5></td>'
58
58
  end
59
59
 
60
60
  def cell_content(str)
@@ -1,23 +1,22 @@
1
- # Helpers to be used to annotate content
2
- require 'byebug'
1
+ # ContentHelpers is used to annotate content.
3
2
  module ContentHelpers
4
3
  def include_topic(item_symbol)
5
- incorporated_topic = lookup_nitem("topics", item_symbol.to_s)
4
+ incorporated_topic = lookup_nitem('topics', item_symbol.to_s)
6
5
  items[incorporated_topic.identifier.to_s].compiled_content
7
6
  end
8
7
 
9
8
  def include_page(item_symbol)
10
- incorporated_topic = lookup_nitem("pages", item_symbol.to_s)
9
+ incorporated_topic = lookup_nitem('pages', item_symbol.to_s)
11
10
  items[incorporated_topic.identifier.to_s].compiled_content
12
11
  end
13
12
 
14
13
  def include_background(item_symbol)
15
- incorporated_topic = lookup_nitem("background", item_symbol.to_s)
14
+ incorporated_topic = lookup_nitem('background', item_symbol.to_s)
16
15
  items[incorporated_topic.identifier.to_s].compiled_content
17
16
  end
18
17
 
19
18
  def include_intro(item_symbol)
20
- incorporated_topic = lookup_nitem("intro", item_symbol.to_s)
19
+ incorporated_topic = lookup_nitem('intro', item_symbol.to_s)
21
20
  items[incorporated_topic.identifier.to_s].compiled_content
22
21
  end
23
22
 
@@ -47,77 +46,101 @@ module ContentHelpers
47
46
  " *#{string}*{: style=\"color: red\"} "
48
47
  end
49
48
 
50
- def ir(string); italic_red(string); end
49
+ def ir(string)
50
+ italic_red(string)
51
+ end
52
+
53
+ def callout_1(title, body)
54
+ <<~HTMLSTRING
55
+ <div class="well well-sm callout">
56
+ <span class="themebg label label-primary">#{title}</span>#{body}
57
+ </div>
58
+ HTMLSTRING
59
+ end
60
+
61
+ def callout_2(title, body)
62
+ <<~HTMLSTRING
63
+ <div class="callout border border-primary rounded p-2 m-3">
64
+ <span class="badge badge-pill badge-primary">#{title}</span>#{body}
65
+ </div>
66
+ HTMLSTRING
67
+ end
51
68
 
52
69
  def callout(title, body)
53
- <<-HTMLSTRING
54
- <div class="well well-sm">
55
- <span class="themebg label label-primary">#{title}</span>#{body}
56
- </div>
57
- HTMLSTRING
70
+ %(<div class="jumbotron py-1 border border-primary border-rounded-lg">
71
+ <h1 class="display-5">#{title}</h1>
72
+ <p class="lead">#{body}</p></div>)
58
73
  end
59
74
 
75
+ def iconbadge1(icon, tooltip)
76
+ %(<img src="/bootstrap/bootstrap-icons-1.0.0/#{icon}.svg" title="#{tooltip}" class="iconbadge">)
77
+ end
78
+
79
+ def iconbadge(icon, tooltip)
80
+ %(<svg class="bi iconbadge" title="#{tooltip}" data-placement="top" data-title="#{tooltip}" data-toggle="tooltip" fill="blue"><use xlink:href="/bootstrap/bootstrap-icons-1.0.0/bootstrap-icons.svg##{icon}"/></svg>)
81
+ end
82
+
60
83
  def textbadge(text, tooltip)
61
84
  %(<span class="label label-info" data-toggle="tooltip" data-placement="top" title="#{tooltip}">#{text}</span>)
62
85
  end
63
86
 
64
- def iconbadge(icon, tooltip)
65
- %(<span class="glyphicon glyphicon-#{icon} themefg" data-toggle="tooltip" data-placement="top" title="#{tooltip}"></span>)
87
+ def iconbadge2(icon, tooltip)
88
+ %(<span class="fas fa-#{icon} themefg" data-toggle="tooltip" data-placement="top" title="#{tooltip}"></span>)
66
89
  end
67
90
 
68
91
  def pdfbadge
69
- iconbadge("file", "Submit as 1 page pdf, include name and homework #")
92
+ iconbadge('file-earmark-richtext-fill', 'Submit a pdf file')
70
93
  end
71
94
 
72
95
  def codebadge
73
- iconbadge("cloud", "Work on code in your portfolio")
96
+ iconbadge('file-code-fill', 'Work on code in your portfolio')
74
97
  end
75
98
 
76
99
  def cloudbadge
77
- codebadge
100
+ iconbadge('cloud-fill', 'Work on code in your portfolio')
78
101
  end
79
102
 
80
103
  def zipbadge
81
- iconbadge("briefcase", "Submit work as an attachment")
104
+ iconbadge('file-earmark-zip-fill', 'Submit work as an attachment')
82
105
  end
83
106
 
84
107
  def partbadge
85
- iconbadge("check", "Graded for participation only - pass/fail")
108
+ iconbadge('heart-half', 'Graded for participation only - pass/fail')
86
109
  end
87
110
 
88
111
  def timebadge
89
- iconbadge("time", "Must be submitted first thing on day of class")
112
+ iconbadge('alarm-fill', 'Must be submitted first thing on day of class')
90
113
  end
91
114
 
92
115
  def teambadge
93
- iconbadge("tent", "Team Deliverable")
116
+ iconbadge('people-fill', 'Team Deliverable')
94
117
  end
95
118
 
96
119
  def include_image_old(filename_string, extra_class: nil)
97
- css_class = "img-responsive"
98
- css_class += " img-" + extra_class unless extra_class.nil?
120
+ css_class = 'img-responsive'
121
+ css_class += ' img-' + extra_class unless extra_class.nil?
99
122
  <<-HTMLSTRING
100
123
  <img src="#{filename_string}" class=\"%s\" />" % css_class
101
124
  HTMLSTRING
102
125
  end
103
126
 
104
- def include_image(filename_string, extra: "")
105
- <<-HTMLSTRING
106
- <div class="row">
107
- <div class="col-md-offset-2 col-md-8">
108
- <img src="#{filename_string}" class="img-responsive img-thumbnail" #{extra}/>
109
- </div>
110
- </div>
111
- HTMLSTRING
127
+ def include_image(filename_string, extra: '')
128
+ <<~HTMLSTRING
129
+ <div class="row">
130
+ <div class="col-md-offset-2 col-md-8">
131
+ <img src="#{filename_string}" class="img-responsive img-thumbnail" #{extra}/>
132
+ </div>
133
+ </div>
134
+ HTMLSTRING
112
135
  end
113
136
 
114
- def image(filename_string, extra: "")
115
- <<-HTMLSTRING
116
- <img src="/content/topics/images/#{filename_string}" class="img-responsive img-thumbnail" #{extra}/>
137
+ def image(filename_string, extra: '')
138
+ <<~HTMLSTRING
139
+ <img src="/content/topics/images/#{filename_string}" class="img-responsive img-thumbnail" #{extra}/>
117
140
  HTMLSTRING
118
141
  end
119
142
 
120
- def important(string = ":")
143
+ def important(string = ':')
121
144
  <<-HTMLSTRING
122
145
  <div class="cg-important">
123
146
  #{string}
@@ -125,26 +148,26 @@ HTMLSTRING
125
148
  HTMLSTRING
126
149
  end
127
150
 
128
- def nb(string = ":")
151
+ def nb(string = ':')
129
152
  <<-HTMLSTRING
130
153
  <div class="label label-info">#{string}</div>
131
154
  HTMLSTRING
132
155
  end
133
156
 
134
- def tbd(string = "")
157
+ def tbd(string = '')
135
158
  "*[TO BE DETERMINED#{string}]*{: style=\"color: red\"}"
136
159
  end
137
160
 
138
- def deliverable(string, append = "")
161
+ def deliverable(string, append = '')
139
162
  "*Deliverable:*{: style=\"color: red\"} #{string + append} "
140
163
  end
141
164
 
142
165
  def deliverable_po(string)
143
- deliverable(string, " *(graded for participation only)*")
166
+ deliverable(string, ' *(graded for participation only)*')
144
167
  end
145
168
 
146
169
  def deliverable_popdf(string)
147
- deliverable(string, " *(pdf with name and hw number, graded for participation only)*")
170
+ deliverable(string, ' *(pdf with name and hw number, graded for participation only)*')
148
171
  end
149
172
 
150
173
  def team_deliverable(string)
@@ -160,54 +183,84 @@ HTMLSTRING
160
183
  end
161
184
 
162
185
  def homework_hdr(show_legend: :on)
163
- body = "#### Homework due for today"
186
+ body = '## Homework due for today'
164
187
  legend = "\n**Legend**: #{partbadge}: Participation (pass/fail) | #{pdfbadge}: PDF | #{teambadge}: Team | #{zipbadge}: Attachment"
165
188
  body += legend if show_legend == :on
166
189
  body
167
190
  end
168
191
 
169
- def carousel(filenames)
170
- body = %(<div id="myCarousel" class="carousel slide" style="width: 500px; margin: 0 auto;">
171
- <div class="carousel-inner" style="margin: 20px; ">)
172
- counter = 0
173
- filenames.each do |nam|
174
- body << counter == 0 ? %(div class="item active">) : body << %(<div class="item">~
175
- body << %~<img src=")
176
- body << "/content/images/#{nam}"
177
- body << %(" class="img-polaroid" alt=""></div>)
178
- counter += 1
192
+ # def carousel(filenames)
193
+ # body = %(<div id="myCarousel" class="carousel slide" style="width: 500px; margin: 0 auto;">
194
+ # <div class="carousel-inner" style="margin: 20px; ">)
195
+ # counter = 0
196
+ # filenames.each do |nam|
197
+ # body << counter == 0 ? %(div class="item active">) : body << %(<div class="item">~
198
+ # body << %~<img src=")
199
+ # body << "/content/images/#{nam}"
200
+ # body << %(" class="img-polaroid" alt=""></div>)
201
+ # counter += 1
202
+ # end
203
+ # body << %(</div> <a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>
204
+ # <a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>
205
+ # </div>)
206
+ # body
207
+ # end
208
+
209
+ # def carousel_new(filenames)
210
+ # carousel_work(filenames.map { |filename| "/content/topics/images/" + filename })
211
+ # end
212
+
213
+ # def carousel_work(filenames)
214
+ # body = %(<div id="myCarousel" class="carousel slide" data-ride="carousel" style="width: 500px; margin: 0 auto;">
215
+ # <div class="carousel-inner" role="listbox" style="margin: 20px; ">)
216
+ # counter = 0
217
+ # filenames.each do |nam|
218
+ # ci = counter == 0 ? %(<div class="item active">) : %(<div class="item">)
219
+ # body << ci
220
+ # body << %(<img src=")
221
+ # body << nam
222
+ # body << %("/>"></div>)
223
+ # counter += 1
224
+ # end
225
+ # body << %(</div> <a class="left carousel-control" role="button" href="#myCarousel" data-slide="prev">
226
+ # <span class="glyphicon glyphicon-chevron-left"></span>
227
+ # <span class="sr-only">Previous</span>
228
+ # </a>
229
+ # <a class="right carousel-control" role="button" href="#myCarousel" data-slide="next">
230
+ # <span class="glyphicon glyphicon-chevron-right"></span>
231
+ # <span class="sr-only">Next</span>
232
+ # </a>
233
+ # </div>)
234
+ # body
235
+ # end
236
+
237
+ def carousel_V4(filenames)
238
+ body = <<~HEREDOC
239
+ <div id="carouselExampleControls" class="carousel slide" data-ride="carousel">
240
+ <div class="carousel-inner">
241
+ HEREDOC
242
+ count = 0
243
+ filenames.each do |fname|
244
+ active = count == 0 ? 'active' : ''
245
+ body << <<~HEREDOC
246
+ <div class="carousel-item #{active}">
247
+ <img class="d-block w-80" src="/content/topics/images/#{fname}">
248
+ </div>
249
+ HEREDOC
250
+ count += 1
179
251
  end
180
- body << %(</div> <a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>
181
- <a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>
182
- </div>)
183
- body
184
- end
185
-
186
- def carousel_new(filenames)
187
- carousel_work(filenames.map { |filename| "/content/topics/images/" + filename })
188
- end
189
-
190
- def carousel_work(filenames)
191
- body = %(<div id="myCarousel" class="carousel slide" data-ride="carousel" style="width: 500px; margin: 0 auto;">
192
- <div class="carousel-inner" role="listbox" style="margin: 20px; ">)
193
- counter = 0
194
- filenames.each do |nam|
195
- ci = counter == 0 ? %(<div class="item active">) : %(<div class="item">)
196
- body << ci
197
- body << %(<img src=")
198
- body << nam
199
- body << %("/>"></div>)
200
- counter += 1
201
- end
202
- body << %(</div> <a class="left carousel-control" role="button" href="#myCarousel" data-slide="prev">
203
- <span class="glyphicon glyphicon-chevron-left"></span>
204
- <span class="sr-only">Previous</span>
205
- </a>
206
- <a class="right carousel-control" role="button" href="#myCarousel" data-slide="next">
207
- <span class="glyphicon glyphicon-chevron-right"></span>
208
- <span class="sr-only">Next</span>
209
- </a>
210
- </div>)
252
+ body << <<~HEREDOC
253
+ </div>
254
+ <a class="carousel-control-prev" href="#carouselExampleControls" role="button" data-slide="prev">
255
+ <span class="carousel-control-prev-icon" aria-hidden="true"></span>
256
+ <span class="sr-only">Previous</span>
257
+ </a>
258
+ <a class="carousel-control-next" href="#carouselExampleControls" role="button" data-slide="next">
259
+ <span class="carousel-control-next-icon" aria-hidden="true"></span>
260
+ <span class="sr-only">Next</span>
261
+ </a>
262
+ </div>
263
+ HEREDOC
211
264
  body
212
265
  end
213
266
 
@@ -236,13 +289,13 @@ HTMLSTRING
236
289
  end
237
290
 
238
291
  def include_ruby(name)
239
- filename = Dir.pwd + "/content/content/topics/scripts/" + name.to_s + ".rb"
292
+ filename = Dir.pwd + '/content/content/topics/scripts/' + name.to_s + '.rb'
240
293
  filecontents = File.new(filename).read
241
294
  ruby_string filecontents
242
295
  end
243
296
 
244
297
  def include_python(name)
245
- filename = Dir.pwd + "/content/content/topics/robotcode/" + name.to_s + ".py"
298
+ filename = Dir.pwd + '/content/content/topics/robotcode/' + name.to_s + '.py'
246
299
  filecontents = File.new(filename).read
247
300
  ruby_string filecontents
248
301
  end
@@ -251,11 +304,9 @@ HTMLSTRING
251
304
  "\n~~~~~~"
252
305
  end
253
306
 
254
- def code_end(lang = "")
307
+ def code_end(lang = '')
255
308
  str = "~~~~~~\n"
256
- if ["ruby", "css", "java", "html"].include? lang
257
- str += "{: .language-#{lang}}"
258
- end
309
+ str += "{: .language-#{lang}}" if %w[ruby css java html].include? lang
259
310
  str
260
311
  end
261
312
 
@@ -264,42 +315,64 @@ HTMLSTRING
264
315
  end
265
316
 
266
317
  def include_code(name)
267
- filename = Dir.pwd + "/content/content/topics/scripts/" + name
318
+ filename = Dir.pwd + '/content/content/topics/scripts/' + name
268
319
  filecontents = File.new(filename).read
269
320
  code_string filecontents
270
321
  end
271
322
 
272
- def postit_begin title
273
- "<div class=\"postit\">" + "<h5>" + title + "</h5>"
323
+ def source_begin(language)
324
+ "<pre class=\"#{language}\">"
325
+ end
326
+
327
+ def source_end
328
+ '</pre>'
329
+ end
330
+
331
+ def postit_begin(title)
332
+ '<div class="postit">' + '<h5>' + title + '</h5>'
274
333
  end
275
334
 
276
335
  def postit_end
277
- "</div>"
336
+ '</div>'
278
337
  end
279
338
 
280
339
  def ul_begin
281
- "<ul>"
340
+ '<ul>'
282
341
  end
283
342
 
284
343
  def ul_end
285
- "</ul>"
344
+ '</ul>'
286
345
  end
287
346
 
288
- def ul body
347
+ def ul(body)
289
348
  "<ul>#{body}</ul>"
290
349
  end
291
350
 
292
- def list_items *items
293
- items.reduce("") do |s, i|
294
- if i.start_with?("<ul>")
351
+ def slide
352
+ '<slide_break></slide_break>'
353
+ end
354
+
355
+ def list_items(*items)
356
+ items.reduce('') do |s, i|
357
+ if i.start_with?('<ul>')
295
358
  s + i
296
359
  else
297
- s + "<li>" + i + "</li>"
360
+ s + '<li>' + i + '</li>'
298
361
  end
299
362
  end
300
363
  end
301
364
 
302
365
  def lab_note(title)
303
- "<h5 style=\"font-family:'Permanent Marker'; font-szie:18px; color: red;\">#{title}</h5>"
366
+ "<h3 style=\"font-family:'Permanent Marker'; font-szie:18px; color: red;\">#{title}</h3>"
367
+ end
368
+
369
+ def toasty(header, *items)
370
+ str = %(<div class="border border-info rounded w-75 mx-auto p-2 m-3">
371
+ <h5>#{header}</h5><ul>)
372
+ items.each do |itm|
373
+ str += '<li>' + itm + '</li>'
374
+ end
375
+ str += '</ul></div>'
376
+ str
304
377
  end
305
378
  end