presently 0.25.0 → 0.26.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: 665a4ba800abf1cbeea2acd8073600273160613f32221277f8bc84e616023024
4
- data.tar.gz: ff0135c2c722ab5f447cc595fc7822320ead87b0ba303e8f08cf40e1ecda5c4c
3
+ metadata.gz: 57754e7cc66ec20e3ef797b20afbe147fda8979e96aafc14cdb9c35eaedb5495
4
+ data.tar.gz: 242278bc2177efc35609ece981bb3f6cb5fed099e628894d6c8ed9dcf77ce020
5
5
  SHA512:
6
- metadata.gz: 7a07dd02fe9c344ee29678e5d2b5037e91ae355d0f28c5a6eb57fa3121cc5ce90c170d4281de0b728c3526b61f21600182865487a0ddc7b3eac1952dd647020d
7
- data.tar.gz: 67322e24a739782b01f77396ee54e5940272b739fc31e11acb9ad77f4db2cc3bd1eb1d9b6542384cde3d8581737712a97b22ddb5a49fec4770c5dcc08c05a528
6
+ metadata.gz: 206d33b334f6d1ed9f4b7df2b328022bb5b332a43a53932840be6bd5c00a5b1a41d8df262b441309d04a17d0fc74bdf6120449f4ff1ec0f84228385856d3df9e
7
+ data.tar.gz: 42f72ece55c0c02160fd12b90006651f0cd3cb1d2b4a95fa12516dbc1d88172652d76afd5639a3ff7c7b8edd6e57eb7d7ba6fb6a6303a90109bcff005aefdb2a
checksums.yaml.gz.sig CHANGED
Binary file
@@ -89,6 +89,7 @@ module Presently
89
89
  end
90
90
 
91
91
  # The progress through the current slide's allocated time.
92
+ # Slides with durations of zero or less are complete once their expected start time is reached.
92
93
  # @returns [Float] A value between 0.0 and 1.0.
93
94
  def slide_progress
94
95
  return 0.0 unless @clock.started?
@@ -97,7 +98,11 @@ module Presently
97
98
  return 0.0 unless slide
98
99
 
99
100
  time_into_slide = @clock.elapsed - @presentation.expected_time_at(@current_index)
100
- (time_into_slide / slide.duration).clamp(0.0, 1.0)
101
+ if slide.duration <= 0
102
+ time_into_slide.negative? ? 0.0 : 1.0
103
+ else
104
+ (time_into_slide / slide.duration).clamp(0.0, 1.0)
105
+ end
101
106
  end
102
107
 
103
108
  # Reset the timer so that elapsed time matches the expected time for the current slide.
@@ -107,8 +112,9 @@ module Presently
107
112
  end
108
113
 
109
114
  # The current pacing status relative to the slide timing.
110
- # @returns [Symbol] One of `:on_time`, `:ahead`, or `:behind`.
115
+ # @returns [Symbol | Nil] One of `:on_time`, `:ahead`, or `:behind`, or `nil` when no presentation time is allocated.
111
116
  def pacing
117
+ return unless total_duration.positive?
112
118
  return :on_time unless @clock.started?
113
119
 
114
120
  elapsed = @clock.elapsed
@@ -137,19 +143,27 @@ module Presently
137
143
  # Navigate to a specific slide by index.
138
144
  # Ignores out-of-bounds indices. Notifies listeners on change.
139
145
  # @parameter index [Integer] The slide index to navigate to.
140
- def go_to(index)
141
- return if index < 0 || index >= slide_count
146
+ # @parameter timer [Boolean] Whether to apply the outgoing slide's timer action before notifying listeners.
147
+ # @returns [Boolean] Whether the destination index was valid.
148
+ def go_to(index, timer: false)
149
+ return false if index < 0 || index >= slide_count
142
150
 
151
+ advance_timer! if timer
143
152
  @current_index = index
144
153
  notify_listeners!
154
+ return true
145
155
  end
146
156
 
147
- # Advance to the next slide.
148
- def advance!
149
- go_to(@current_index + 1)
157
+ # Advance to the next slide, applying the current slide's timer action.
158
+ # Timer actions only run when there is a next slide.
159
+ # @parameter timer [Boolean] Whether to apply the outgoing slide's timer action.
160
+ # @returns [Boolean] Whether the presentation advanced to the next slide.
161
+ def advance!(timer: true)
162
+ go_to(@current_index + 1, timer: timer)
150
163
  end
151
164
 
152
165
  # Go back to the previous slide.
166
+ # @returns [Boolean] Whether the presentation moved to the previous slide.
153
167
  def retreat!
154
168
  go_to(@current_index - 1)
155
169
  end
@@ -180,6 +194,18 @@ module Presently
180
194
 
181
195
  private
182
196
 
197
+ # Apply the outgoing slide's timer action without resetting elapsed time.
198
+ def advance_timer!
199
+ case current_slide.timer
200
+ when "start"
201
+ @clock.start! unless @clock.started?
202
+ when "pause"
203
+ @clock.pause!
204
+ when "resume"
205
+ @clock.resume! if @clock.started?
206
+ end
207
+ end
208
+
183
209
  # Notify all registered listeners that the slide has changed, and persist state.
184
210
  def notify_listeners!
185
211
  @state&.save(self)
@@ -100,14 +100,14 @@ module Presently
100
100
  # @parameter builder [XRB::Builder] The HTML builder.
101
101
  # @parameter slide [Slide | Nil] The current slide.
102
102
  def render_timing(builder, slide)
103
- progress = (@controller.slide_progress * 100).round(1)
103
+ pacing = @controller.pacing
104
+ progress = pacing ? (@controller.slide_progress * 100).round(1) : 0.0
104
105
  next_slide = @controller.next_slide
105
106
  builder.tag(:div, class: "timing", style: "--slide-progress: #{progress}%") do
106
- pacing = @controller.pacing
107
107
  pacing_class = case pacing
108
108
  when :behind then "behind"
109
109
  when :ahead then "ahead"
110
- else "on-time"
110
+ when :on_time then "on-time"
111
111
  end
112
112
 
113
113
  builder.tag(:div, class: "toolbar timing-info #{pacing_class}") do
@@ -136,17 +136,19 @@ module Presently
136
136
  builder.text("Elapsed: #{format_duration(@controller.clock.elapsed)}")
137
137
  end
138
138
 
139
- builder.tag(:span, class: "remaining") do
140
- builder.text("Remaining: #{format_duration(@controller.time_remaining)}")
141
- end
142
-
143
- builder.tag(:span, class: "pacing-indicator") do
144
- indicator = case pacing
145
- when :behind then "⏩ Speed up"
146
- when :ahead then "⏪ Slow down"
147
- else "✓ On time"
139
+ if pacing
140
+ builder.tag(:span, class: "remaining") do
141
+ builder.text("Remaining: #{format_duration(@controller.time_remaining)}")
142
+ end
143
+
144
+ builder.tag(:span, class: "pacing-indicator") do
145
+ indicator = case pacing
146
+ when :behind then "⏩ Speed up"
147
+ when :ahead then "⏪ Slow down"
148
+ else "✓ On time"
149
+ end
150
+ builder.text(indicator)
148
151
  end
149
- builder.text(indicator)
150
152
  end
151
153
 
152
154
  if slide
@@ -49,7 +49,7 @@ module Presently
49
49
  def handle(event)
50
50
  case event.dig(:detail, :action)
51
51
  when "next"
52
- @controller.advance!
52
+ @controller.advance!(timer: false)
53
53
  when "previous"
54
54
  @controller.retreat!
55
55
  when "reload"
@@ -349,9 +349,23 @@ module Presently
349
349
  end
350
350
 
351
351
  # The expected duration of this slide in seconds.
352
- # @returns [Integer] The duration from front_matter, or `60`.
352
+ # Negative, invalid, or non-finite values are treated as zero.
353
+ # @returns [Float] A finite duration of at least `0.0`, defaulting to `0.0` when unspecified or null.
353
354
  def duration
354
- @front_matter&.fetch("duration", 60) || 60
355
+ if value = @front_matter&.fetch("duration", nil)
356
+ duration = Float(value, exception: false)
357
+ if duration&.finite?
358
+ return duration.clamp(0.0, nil)
359
+ end
360
+ end
361
+
362
+ return 0.0
363
+ end
364
+
365
+ # The timer action to apply when advancing from this slide.
366
+ # @returns [String | Nil] `"start"`, `"pause"`, `"resume"`, or `nil` when unspecified.
367
+ def timer
368
+ @front_matter&.fetch("timer", nil)
355
369
  end
356
370
 
357
371
  # Update the expected duration in the slide's YAML front matter.
@@ -5,5 +5,5 @@
5
5
 
6
6
  # @namespace
7
7
  module Presently
8
- VERSION = "0.25.0"
8
+ VERSION = "0.26.0"
9
9
  end
@@ -24,6 +24,10 @@ html, body {
24
24
  overflow: hidden;
25
25
  }
26
26
 
27
+ a {
28
+ color: var(--accent-light);
29
+ }
30
+
27
31
  /* ========================
28
32
  SHARED INTERFACE COMPONENTS
29
33
  ======================== */
data/readme.md CHANGED
@@ -67,6 +67,13 @@ The task records the presentation at 1920×1080 and 30 frames per second by defa
67
67
 
68
68
  Please see the [project releases](https://socketry.github.io/presently/releases/index) for all releases.
69
69
 
70
+ ### v0.26.0
71
+
72
+ - Add `timer: start`, `timer: pause`, and `timer: resume` slide metadata, applied when advancing away from a slide in the presenter or display.
73
+ - Normalize slide durations to finite, non-negative floating-point seconds. Missing or invalid durations now default to `0.0`, and negative durations are clamped to zero. Presentations relying on the previous 60-second default should set explicit durations.
74
+ - Handle zero-duration slide progress and hide pacing indicators, progress, and remaining-time estimates when a presentation has no allocated duration.
75
+ - Keep recorder navigation from changing the presentation timer.
76
+
70
77
  ### v0.24.1
71
78
 
72
79
  - Use legible, customizable link colors on the default dark slide background.
@@ -117,11 +124,6 @@ Please see the [project releases](https://socketry.github.io/presently/releases/
117
124
 
118
125
  - Fix slide rendering events for generated view identifiers that begin with a digit.
119
126
 
120
- ### v0.17.1
121
-
122
- - Add slide-scoped resource cleanup with `Slide#defer`, `Slide#signal`, and idempotent `Slide#dispose`. Existing tracked timeouts now use the same disposal lifecycle.
123
- - [Web Packages](https://socketry.github.io/presently/releases/index#web-packages)
124
-
125
127
  ## See Also
126
128
 
127
129
  - [lively](https://github.com/socketry/lively) — The real-time application framework that powers Presently.
data/releases.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Releases
2
2
 
3
+ ## v0.26.0
4
+
5
+ - Add `timer: start`, `timer: pause`, and `timer: resume` slide metadata, applied when advancing away from a slide in the presenter or display.
6
+ - Normalize slide durations to finite, non-negative floating-point seconds. Missing or invalid durations now default to `0.0`, and negative durations are clamped to zero. Presentations relying on the previous 60-second default should set explicit durations.
7
+ - Handle zero-duration slide progress and hide pacing indicators, progress, and remaining-time estimates when a presentation has no allocated duration.
8
+ - Keep recorder navigation from changing the presentation timer.
9
+
3
10
  ## v0.24.1
4
11
 
5
12
  - Use legible, customizable link colors on the default dark slide background.
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.25.0
4
+ version: 0.26.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
metadata.gz.sig CHANGED
Binary file