presently 0.4.0 → 0.6.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3991c95331fdcabd96b64dd78833690a52468f2a1e570eddf3234fd5e9bfa7ac
4
- data.tar.gz: 816e1de43c33929e12424659455e116891294d79dcc3d2ea41cc8df9b13317dd
3
+ metadata.gz: 806fa6100505250fcb875b1d751bd96df78108d835bb60ad65c0484e0850e296
4
+ data.tar.gz: 723cdf3db680519971054969cff462752b85b7df67cab51c0bc50f8585c00890
5
5
  SHA512:
6
- metadata.gz: bc5afae0aaeb288b51b4ccd6c8e66a562acd44898a49a3777299865ccff1a400258e88dd1fa3950071db8949b107fa076eac2d5042ccdd847e11d8d395801892
7
- data.tar.gz: e0b1a9f6e5743beecdb4745469335c5ed8ad154e74bd5fdf2c745f54ce83532c1d81af3014c67ff8c9480e878b09a21e0df50cf73805e2a5676c0516a8ef807a
6
+ metadata.gz: 12e369d511548176c671fbd42718cd136d3d628f173d0c6901f36c805fa87612067765ca1a29d808ec806b223c11ce2f2ea0c59d879b6eb97fa13e27828fd935
7
+ data.tar.gz: 10b3df45c9ed1e72e2dd01bae21daef286cea851e2f5630f7684b0de32771295bbce64a05ee81a028d20992ccb5235151277d2c3515df8cb469253d78d5b2a30
checksums.yaml.gz.sig CHANGED
Binary file
@@ -33,6 +33,40 @@ def notes(slides_root: "slides")
33
33
  return nil
34
34
  end
35
35
 
36
+ # Print a timing breakdown grouped by speaker.
37
+ #
38
+ # Loads every slide in the slides directory and groups them by the `speaker`
39
+ # front matter key. For each speaker, prints each of their slides with its
40
+ # individual duration, followed by a total. Slides with no `speaker` key are
41
+ # grouped under `(no speaker)`. Slides are listed in presentation order.
42
+ #
43
+ # @parameter slides_root [String] The slides directory. Default: `slides`.
44
+ def speakers(slides_root: "slides")
45
+ require "presently"
46
+
47
+ presentation = Presently::Presentation.load(slides_root)
48
+
49
+ # Group slides by speaker, preserving presentation order within each group.
50
+ groups = {}
51
+ presentation.slides.each do |slide|
52
+ key = slide.speaker || "(no speaker)"
53
+ (groups[key] ||= []) << slide
54
+ end
55
+
56
+ groups.each do |speaker, slides|
57
+ total_seconds = slides.sum(&:duration)
58
+ puts "#{speaker} — #{format_duration(total_seconds)}"
59
+
60
+ slides.each do |slide|
61
+ puts " #{format_duration(slide.duration)} #{slide.title} (#{File.basename(slide.path)})"
62
+ end
63
+
64
+ puts
65
+ end
66
+
67
+ return nil
68
+ end
69
+
36
70
  # Renumber slide files sequentially with a consistent step size.
37
71
  #
38
72
  # Renames all `.md` files in the slides directory to have sequential
@@ -89,3 +123,13 @@ def renumber(slides_root: "slides", step: 10)
89
123
 
90
124
  puts "Renumbered #{renames.length} slides."
91
125
  end
126
+
127
+ private
128
+
129
+ # Format a number of seconds as `M:SS`.
130
+ # @parameter seconds [Integer]
131
+ # @returns [String]
132
+ def format_duration(seconds)
133
+ seconds = seconds.to_i
134
+ "%d:%02d" % [seconds / 60, seconds % 60]
135
+ end
@@ -101,6 +101,7 @@ module Presently
101
101
  # @parameter slide [Slide | Nil] The current slide.
102
102
  def render_timing(builder, slide)
103
103
  progress = (@controller.slide_progress * 100).round(1)
104
+ next_slide = @controller.next_slide
104
105
  builder.tag(:div, class: "timing", style: "--slide-progress: #{progress}%") do
105
106
  pacing = @controller.pacing
106
107
  pacing_class = case pacing
@@ -153,6 +154,21 @@ module Presently
153
154
  builder.text("Slide: #{format_duration(slide.duration)}")
154
155
  end
155
156
  end
157
+
158
+ # Speaker display — only shown when front matter includes a `speaker` key.
159
+ if (current_speaker = slide&.speaker)
160
+ builder.tag(:span, class: "speaker-info") do
161
+ builder.tag(:span, class: "speaker-label"){builder.text("🎤")}
162
+ builder.text(" #{current_speaker}")
163
+
164
+ # Show upcoming speaker only when they differ from the current one.
165
+ if (next_speaker = next_slide&.speaker) && next_speaker != current_speaker
166
+ builder.tag(:span, class: "next-speaker") do
167
+ builder.text(" → #{next_speaker}")
168
+ end
169
+ end
170
+ end
171
+ end
156
172
  end
157
173
  end
158
174
  end
@@ -213,6 +213,12 @@ module Presently
213
213
  @front_matter&.fetch("transition", nil)
214
214
  end
215
215
 
216
+ # The name of the speaker presenting this slide.
217
+ # @returns [String | Nil] The speaker name from front_matter, or `nil` if not specified.
218
+ def speaker
219
+ @front_matter&.fetch("speaker", nil)
220
+ end
221
+
216
222
  # The line range to focus on for code slides.
217
223
  # @returns [Array(Integer, Integer) | Nil] The `[start, end]` line numbers (1-based), or `nil`.
218
224
  def focus
@@ -5,5 +5,5 @@
5
5
 
6
6
  # @namespace
7
7
  module Presently
8
- VERSION = "0.4.0"
8
+ VERSION = "0.6.0"
9
9
  end
@@ -675,6 +675,23 @@ html[data-transition="morph"]::view-transition-new(slide-container) {
675
675
  margin-left: auto;
676
676
  }
677
677
 
678
+ .timing-info .speaker-info {
679
+ display: flex;
680
+ align-items: center;
681
+ gap: 0.25rem;
682
+ font-size: 0.9rem;
683
+ background: rgba(255, 255, 255, 0.08);
684
+ border: 1px solid rgba(255, 255, 255, 0.12);
685
+ border-radius: 6px;
686
+ padding: 0.2rem 0.6rem;
687
+ white-space: nowrap;
688
+ }
689
+
690
+ .timing-info .next-speaker {
691
+ opacity: 0.6;
692
+ font-style: italic;
693
+ }
694
+
678
695
  /* Notes */
679
696
  .notes {
680
697
  background: var(--surface);
data/readme.md CHANGED
@@ -29,6 +29,14 @@ Please see the [project documentation](https://socketry.github.io/presently/) fo
29
29
 
30
30
  Please see the [project releases](https://socketry.github.io/presently/releases/index) for all releases.
31
31
 
32
+ ### v0.6.0
33
+
34
+ - Add `bake presently:slides:speakers` task to print a timing breakdown grouped by speaker. Each speaker's slides are listed in presentation order with individual and total durations, making it easy to balance talk time in multi-speaker presentations. Slides without a `speaker` key are grouped under `(no speaker)`.
35
+
36
+ ### v0.5.0
37
+
38
+ - Add optional `speaker` front matter key to slides. When present, the current speaker's name is shown in the timing bar. If the next slide has a different speaker, a handoff indicator (e.g. `→ Next Speaker`) is shown alongside, giving presenters an at-a-glance cue for tag-team talks.
39
+
32
40
  ### v0.4.0
33
41
 
34
42
  - Add `bake presently:slides:notes` task to extract all presenter notes into a single Markdown document, with each slide's file path as a heading. Useful for reviewing or sharing speaker notes outside of the presentation.
data/releases.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Releases
2
2
 
3
+ ## v0.6.0
4
+
5
+ - Add `bake presently:slides:speakers` task to print a timing breakdown grouped by speaker. Each speaker's slides are listed in presentation order with individual and total durations, making it easy to balance talk time in multi-speaker presentations. Slides without a `speaker` key are grouped under `(no speaker)`.
6
+
7
+ ## v0.5.0
8
+
9
+ - Add optional `speaker` front matter key to slides. When present, the current speaker's name is shown in the timing bar. If the next slide has a different speaker, a handoff indicator (e.g. `→ Next Speaker`) is shown alongside, giving presenters an at-a-glance cue for tag-team talks.
10
+
3
11
  ## v0.4.0
4
12
 
5
13
  - Add `bake presently:slides:notes` task to extract all presenter notes into a single Markdown document, with each slide's file path as a heading. Useful for reviewing or sharing speaker notes outside of the presentation.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: presently
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
metadata.gz.sig CHANGED
Binary file