wani 0.1.10 → 0.1.12

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: f85a23004f1df4d2bbbbc63f5f0b1390fc23476719bdf53af05d493a2c2cbc2d
4
- data.tar.gz: dc2c7fbeed8adceb6c10ce6efb0f8c3bc418625e82878845426c203a20a8bfd6
3
+ metadata.gz: eb4630588cc6addc11f3c475f87077fa22f3cb40dae0346d7c549f48cc039ab7
4
+ data.tar.gz: 46a52d864d36039806fe31b6b8a118b994b8d2752c966a748364ae1a1b8b7d44
5
5
  SHA512:
6
- metadata.gz: b75c77c939e09c3e195a63b119f4e6e5c8557bcb5f120edf5496a00a2ee20da64b70cae8b18d8a87a98dd0e70299fe1e9881ebbfbdbdf6f94e2995725b531a56
7
- data.tar.gz: e207c8c3ae8ceb6906702ce73a2dbca34005b09c7a2a80b178cf1f9c832f4abeb75fcb48844e31e46738cb128bc03eaa5431c3ebc0ac41683bacda36a9075f01
6
+ metadata.gz: 976a114f82b6f43a13bda767ad0b6f2cde0632e646671a03c8fed6c1baaca8a1216a137a339fe29120bd255fa92c2bc203442a344c90c2fbcb7449a39dee1b38
7
+ data.tar.gz: c0dd0f5f1e4ef80c4a008ad452cce5cb195aee8931c017314b6c2d77a892c71fdbd455a28c9d49d9a876a4b9c682fe81be5c3ddb84f85173ea3833d86fddc43c
data/README.md CHANGED
@@ -25,7 +25,7 @@ npm ci
25
25
  bundle exec rake build:wasm
26
26
 
27
27
  gem build wani.gemspec
28
- gem install ./wani-0.1.10.gem
28
+ gem install ./wani-0.1.12.gem
29
29
 
30
30
  wani new my-talk
31
31
  cd my-talk
@@ -130,7 +130,10 @@ Ctrl+P でも印刷できます。
130
130
 
131
131
  ## 発表タイマー
132
132
 
133
- スライドの読み込み完了から計測し、既定では5分で時間切れ画面を表示します。
133
+ hashなしのURLで開くと、最初のスライドに半透明の黒いベールと「スタート」ボタンを表示します。
134
+ 待機中はページ移動と計測を止め、ボタンを押すとベールが消えてタイマーが始まります。Fキーで全画面にして待機できます。
135
+ `#slide=1` などのhash付きURLでは、読み込み完了から計測します。
136
+ 既定では5分で時間切れ画面を表示します。
134
137
  Front Matter の `time_limit` に分数を指定して変更できます(小数も可)。
135
138
  `time_limit: 0` でタイマーを無効にします。
136
139
 
@@ -138,12 +141,13 @@ Front Matter の `time_limit` に分数を指定して変更できます(小
138
141
  残り5秒は中央に数字を表示し、画面の短辺に対して20%・40%・60%・80%・100%と強調サイズを増やします。
139
142
  各数字は0.8秒で通常サイズに戻ります。動きを減らす設定では拡大アニメーションを省略します。
140
143
  時間切れになると、兎柄フードをくわえたワニ(さめ)の画像を表示します。
144
+ 画像は軽量なWebP形式で配布し、発表開始前に読み込みとデコードを済ませて、時間切れの文字と同時に表示します。
141
145
  左右キーまたは「スライドに戻る」ボタンで、時間切れ直前のスライドに戻れます。
142
146
  戻った後は通常通りページを移動でき、時間切れ画面は再表示しません。
143
147
  最終スライドの表示中はタイマーを一時停止し、カウントダウンも時間切れ画面も表示しません。
144
148
  前のスライドに戻ると、停止前の残り時間から再開します。1ページだけの場合も停止します。
145
149
  ページを再読み込みするとタイマーも最初から始まります。
146
- タイマーと時間切れ画面はPDFには含めません。
150
+ 開始待ち画面、タイマー、時間切れ画面はPDFには含めません。
147
151
 
148
152
  ## 同梱フォント
149
153
 
data/assets/build.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "0.1.10",
3
- "source_sha256": "b66ef1d534e169a73a33bf97aacbb95049b982a006fc6487baf5969a897b6dc9",
2
+ "version": "0.1.12",
3
+ "source_sha256": "de684716a467e77a389554e50aad08062f9b9a270b67d7fd53929b49806e0447",
4
4
  "loader_commit": "dc6b0ffd5800ed9bfc49268ed8021d456f10ddf8",
5
- "wasm_sha256": "0b632b9dc039dfa2e6a76f5ab54938788a334ffe24aaeb07570f0e23f0ac2215"
5
+ "wasm_sha256": "8911ce2363c89117cd7318c3b7712c9cf1571d68c62986bdead646418943e613"
6
6
  }
data/assets/index.html CHANGED
@@ -24,10 +24,13 @@
24
24
  <p id="status" role="status">Ruby を読み込んでいます…</p>
25
25
  <aside id="warnings" role="status" hidden></aside>
26
26
  <div id="viewport"><main id="stage" aria-label="スライド"></main></div>
27
+ <section id="start-overlay" role="dialog" aria-modal="true" aria-label="発表の開始" hidden>
28
+ <button id="start-presentation">スタート</button>
29
+ </section>
27
30
  <output id="countdown" aria-live="off" aria-label="発表の残り時間" hidden></output>
28
31
  <section id="time-expired" role="dialog" aria-modal="true" aria-labelledby="time-expired-title" hidden>
29
32
  <h1 id="time-expired-title">時間切れです!</h1>
30
- <div class="time-expired-image" role="img" aria-label="兎柄フードをくわえるワニ(さめ)"></div>
33
+ <img id="time-expired-image" class="time-expired-image" src="/assets/time-expired.webp" width="1086" height="724" alt="兎柄フードをくわえるワニ(さめ)">
31
34
  <p>← または → キーで元のスライドに戻れます</p>
32
35
  <button id="resume-slides">スライドに戻る</button>
33
36
  </section>
data/assets/style.css CHANGED
@@ -34,6 +34,10 @@ button:focus-visible, a:focus-visible { outline: 2px solid #557e64; outline-offs
34
34
  .title { margin: 0 0 36px; white-space: nowrap; flex: 0 0 160px; font-weight: 700; line-height: 1.12; overflow: hidden; letter-spacing: -.025em; }
35
35
  .body { flex: 1 1 0; min-height: 0; overflow: hidden; line-height: 1.3; }
36
36
  .body p { margin: 0 0 .35em; }
37
+ .titleless .body { display: flex; flex-direction: column; justify-content: safe center; text-align: center; }
38
+ .titleless .body > * { flex-shrink: 0; }
39
+ .titleless .body > :last-child { margin-bottom: 0; }
40
+ .titleless .body img { margin-inline: auto; }
37
41
  .body ul, .body ol { margin: .2em 0 .4em; padding-left: 1.35em; }
38
42
  .body pre { margin: .3em 0; padding: .4em .55em; background: #f3f6f2; white-space: pre-wrap; tab-size: 2; }
39
43
  .body code { font-family: ui-monospace, "IBM Plex Sans JP", monospace; font-size: .8em; }
@@ -89,7 +93,7 @@ button:focus-visible, a:focus-visible { outline: 2px solid #557e64; outline-offs
89
93
  #time-expired { position: fixed; inset: 0; z-index: 30; display: flex; flex-direction: column; align-items: center; justify-content: center; background: white; color: #20352e; padding: 16px; overflow: auto; }
90
94
  #time-expired[hidden], #countdown[hidden] { display: none; }
91
95
  #time-expired h1 { margin: 0; font-size: clamp(24px, 4vw, 56px); }
92
- .time-expired-image { width: min(90vw, calc(65vh * 1024 / 683)); aspect-ratio: 1024 / 683; flex-shrink: 0; background: url('/assets/time-expired.png') right center / 200% 100% no-repeat; }
96
+ .time-expired-image { width: min(90vw, calc(65vh * 1086 / 724)); aspect-ratio: 1086 / 724; height: auto; flex-shrink: 0; }
93
97
  #time-expired p { margin: 8px 0; text-align: center; }
94
98
  @media print { #countdown, #time-expired { display: none !important; } }
95
99
 
@@ -102,3 +106,8 @@ button:focus-visible, a:focus-visible { outline: 2px solid #557e64; outline-offs
102
106
  .island-left { left: 0; }
103
107
  .island-right { right: 0; }
104
108
  .rabbit-position { z-index: 2; }
109
+
110
+ #start-overlay { position: fixed; inset: 0; z-index: 30; display: flex; align-items: center; justify-content: center; background: rgb(0 0 0 / 60%); }
111
+ #start-overlay[hidden] { display: none; }
112
+ #start-presentation { padding: 18px 48px; font-size: clamp(24px, 4vw, 40px); font-weight: 700; border-radius: 12px; }
113
+ @media print { #start-overlay { display: none !important; } }
Binary file
data/assets/wani.wasm CHANGED
Binary file
@@ -26,11 +26,19 @@ module Wani
26
26
  @layout.wait_assets(element("stage"))
27
27
  @sections.each_with_index { |section, index| @layout.fit_slide(section, index + 1) }
28
28
  prepare_pages(false)
29
+ prepare_timer_image
29
30
  bind_events
31
+ @waiting_to_start = JS.global[:location][:hash].to_s.empty?
30
32
  go(hash_index)
31
33
  %w[previous next fullscreen speaker print print-notes].each { |id| element(id)[:disabled] = false }
32
34
  update_buttons
33
- start_timer
35
+ if @waiting_to_start
36
+ element("start-overlay")[:hidden] = false
37
+ element("viewport")[:inert] = true
38
+ element("start-presentation").focus
39
+ else
40
+ start_timer
41
+ end
34
42
  element("status")[:textContent] = "準備できました"
35
43
  end
36
44
 
@@ -55,6 +63,15 @@ module Wani
55
63
  end
56
64
 
57
65
  def bind_events
66
+ element("start-presentation").addEventListener("click") do
67
+ next unless @waiting_to_start
68
+ @waiting_to_start = false
69
+ element("start-overlay")[:hidden] = true
70
+ element("viewport")[:inert] = false
71
+ element("start-presentation").blur
72
+ go(0)
73
+ start_timer
74
+ end
58
75
  element("previous").addEventListener("click") { go(@index - 1) }
59
76
  element("next").addEventListener("click") { go(@index + 1) }
60
77
  element("fullscreen").addEventListener("click") { fullscreen }
@@ -65,6 +82,7 @@ module Wani
65
82
  target = event[:target]
66
83
  next if event[:ctrlKey] == JS::True || event[:altKey] == JS::True || event[:metaKey] == JS::True
67
84
  next if %w[INPUT TEXTAREA SELECT].include?(target[:tagName].to_s) || target[:isContentEditable] == JS::True
85
+ next if @waiting_to_start && !%w[f F Escape n N].include?(event[:key].to_s)
68
86
  handled = true
69
87
  case event[:key].to_s
70
88
  when "ArrowRight", " ", "PageDown" then go(@index + 1)
@@ -89,6 +107,8 @@ module Wani
89
107
  end
90
108
 
91
109
  def go(index)
110
+ return if @waiting_to_start && @active_number
111
+
92
112
  if @time_expired
93
113
  @time_expired = false
94
114
  element("time-expired")[:hidden] = true
@@ -102,7 +122,7 @@ module Wani
102
122
  @active_number = @index + 1
103
123
  element("position")[:textContent] = "#{@index + 1} / #{@sections.length}"
104
124
  desired = "#slide=#{@index + 1}"
105
- JS.global[:history].replaceState(JS::Null, "", desired) unless JS.global[:location][:hash].to_s == desired
125
+ JS.global[:history].replaceState(JS::Null, "", desired) unless @waiting_to_start || JS.global[:location][:hash].to_s == desired
106
126
  update_buttons
107
127
  @layout.scale
108
128
  sync_speaker
@@ -3,6 +3,15 @@ module Wani
3
3
  class Application
4
4
  private
5
5
 
6
+ # Decode the actual displayed image before enabling presentation controls.
7
+ def prepare_timer_image
8
+ return if @presentation.time_limit.zero?
9
+
10
+ element("time-expired-image").decode.await
11
+ rescue JS::Error
12
+ warn("時間切れの画像を読み込めませんでした")
13
+ end
14
+
6
15
  def start_timer
7
16
  return if @presentation.time_limit.zero?
8
17
 
@@ -13,7 +13,10 @@ module Wani
13
13
  section.setAttribute("aria-label", "スライド #{slide.number}")
14
14
  title = child(section, "h1", "title")
15
15
  title[:textContent] = notes ? "ノート #{slide.number}" : slide.title
16
- title[:style][:display] = "none" if title[:textContent].to_s.empty?
16
+ if title[:textContent].to_s.empty?
17
+ title[:style][:display] = "none"
18
+ section[:className] = "slide titleless"
19
+ end
17
20
  body = child(section, "div", "body")
18
21
  body[:innerHTML] = notes ? slide.notes_html : slide.html
19
22
  resolve_links(body)
@@ -7,7 +7,7 @@ module Wani
7
7
  module Server
8
8
  # Only the selected Markdown, images below its directory and fixed gem assets are public.
9
9
  class Application
10
- ASSETS = %w[index.html style.css highlight.css rouge.LICENSE bootstrap.rb speaker.html rabbit.svg shark.svg time-expired.png runtime.pr672.js wani.wasm runtime.LICENSE runtime.NOTICE build.json
10
+ ASSETS = %w[index.html style.css highlight.css rouge.LICENSE bootstrap.rb speaker.html rabbit.svg shark.svg time-expired.webp runtime.pr672.js wani.wasm runtime.LICENSE runtime.NOTICE build.json
11
11
  fonts/IBMPlexSansJP-Regular.woff2 fonts/IBMPlexSansJP-Bold.woff2].freeze
12
12
  TYPES = { ".html" => "text/html; charset=utf-8", ".css" => "text/css; charset=utf-8", ".rb" => "text/plain; charset=utf-8", ".js" => "text/javascript", ".wasm" => "application/wasm", ".md" => "text/plain; charset=utf-8", ".svg" => "image/svg+xml", ".png" => "image/png", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".webp" => "image/webp", ".json" => "application/json", ".woff2" => "font/woff2" }.freeze
13
13
  IMAGES = %w[.png .jpg .jpeg .webp .svg].freeze
data/lib/wani/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Wani
2
- VERSION = "0.1.10"
2
+ VERSION = "0.1.12"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wani
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.1.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - ledsun
@@ -100,7 +100,7 @@ files:
100
100
  - assets/shark.svg
101
101
  - assets/speaker.html
102
102
  - assets/style.css
103
- - assets/time-expired.png
103
+ - assets/time-expired.webp
104
104
  - assets/wani.wasm
105
105
  - exe/wani
106
106
  - lib/wani.rb
Binary file