coursegen 0.7.6 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
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" 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 as 1 page pdf, include name and homework #')
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-100" 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:cursive; font-weight:bold; 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