vivlio_pack 0.1.1 → 0.2.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: dad86168df73b126aca21c4a18ec54215bb2834a7cc16fcb4f81ca1e8b30f7cb
4
- data.tar.gz: daa84caa01716c9569247a952e21a853a6f63983b250519c62cd928ed11f684d
3
+ metadata.gz: f3f7e8cb39772caa7b6b7540b0d27803f073754df8665fc3d20e582e213a9ec1
4
+ data.tar.gz: c044a43ce69b0647d33d0e5ebf04cb4fcdd1ca3e0835295c56286c16df92620d
5
5
  SHA512:
6
- metadata.gz: a5db257fffcea5809516044ffc6e97fdde1bbda0caa85b0032b6b53c1684bd8fa1ac867958b0781c3ff1556e427c189bf1199c34d51fce3e895c11595c394ea7
7
- data.tar.gz: 1526c89fe9ad367b6c63947faf4107bc7288c82a4f93ec792578045125413dad6b1082007093361b7dcf60d2e8cf54042dafc36912b878d902455b93befe2d66
6
+ metadata.gz: 5fab41d5e18430f80abd15794f6273d7b9f3eec9df8926dcb7688f540007d8989070e119331f92e33f5dd4523af87786c7659442b1746b321271cd4a093bcea0
7
+ data.tar.gz: da9c1312aa215c2f3ee9b0c6e278c264ab4ac43a96517f3520ac1c52816d0e500fd602278935e1ac2342be5bd8d16674a1fd063a1ded69db40b3a5e3dd35d28e
@@ -0,0 +1,653 @@
1
+ @import url('https://fonts.googleapis.com/css2?family=DotGothic16&family=IBM+Plex+Sans+JP:wght@100;200;300;400;500;600;700&family=Press+Start+2P&display=swap');
2
+
3
+ /* Continue 2P フォント(日本語対応ピクセルフォント) */
4
+ @font-face {
5
+ font-family: 'Continue 2P';
6
+ src: url('../fonts/ContiNeue2P-1.0.1.otf') format('opentype');
7
+ font-weight: normal;
8
+ font-style: normal;
9
+ }
10
+
11
+ @page {
12
+ size: B5;
13
+ bleed: 3mm;
14
+ /* marks: crop cross; */
15
+ margin: 8mm;
16
+ }
17
+
18
+ /** ページ数を表示 **/
19
+ @page :left {
20
+ margin-right: 5mm;
21
+ @bottom-left {
22
+ font-family: 'Press Start 2P', cursive;
23
+ font-size: 8px;
24
+ content: counter(page);
25
+ }
26
+ }
27
+
28
+ @page :right {
29
+ margin-left: 5mm;
30
+ @bottom-right {
31
+ font-family: 'Press Start 2P', cursive;
32
+ font-size: 8px;
33
+ content: counter(page);
34
+ }
35
+ }
36
+
37
+ /** 扉ページのノンブルを白に **/
38
+ @page tobira:left {
39
+ @bottom-left {
40
+ color: white;
41
+ }
42
+ }
43
+
44
+ @page tobira:right {
45
+ @bottom-right {
46
+ color: white;
47
+ }
48
+ }
49
+
50
+ /* 目次のリンクスタイル */
51
+ .toc a {
52
+ color: black;
53
+ text-decoration: underline;
54
+ }
55
+
56
+ /* 目次では扉絵の改行・装飾を無効化 */
57
+ .toc .tobira-text {
58
+ display: inline;
59
+ }
60
+
61
+ .toc br {
62
+ display: none;
63
+ }
64
+
65
+ /* 目次の章見出しを太字に */
66
+ .toc > nav > ol > li > a {
67
+ font-weight: bold;
68
+ }
69
+
70
+ /* 目次にページ数を表示 */
71
+ .toc a::after {
72
+ content: leader('.') target-counter(attr(href), page);
73
+ font-family: 'Press Start 2P', cursive;
74
+ font-size: 8px;
75
+ text-decoration: none;
76
+ }
77
+
78
+ ol {
79
+ counter-reset: section;
80
+ }
81
+
82
+ li {
83
+ list-style: none;
84
+ }
85
+
86
+ ol>li:before {
87
+ content : counters(section, '.') '. ';
88
+ counter-increment : section;
89
+ }
90
+
91
+ a {
92
+ text-decoration: none;
93
+ }
94
+
95
+ /* デフォルトフォント指定 */
96
+ * { }
97
+ p, h1, h2, h3, h4, li, table, .speech {
98
+ font-family: 'IBM Plex Sans JP', sans-serif;
99
+ }
100
+
101
+ p, table {
102
+ font-size: 12px;
103
+ text-indent: 1rem;
104
+ }
105
+
106
+ /* ----- 見出し -----*/
107
+ /* 章とびら */
108
+ h1 {
109
+ margin: -20mm;
110
+ page-break-before: always;
111
+ page-break-after: always;
112
+ break-inside: avoid;
113
+ display: block;
114
+ font-family: 'DotGothic16', sans-serif;
115
+ font-size: 20px;
116
+ font-weight: normal;
117
+ text-align: center;
118
+ height: 269mm;
119
+ padding: 90mm 35mm 0;
120
+ box-sizing: border-box;
121
+ border: none;
122
+ background-repeat: no-repeat;
123
+ background-size: cover;
124
+ background-position: center;
125
+ }
126
+
127
+ /* 扉絵タイトルテキスト(ページ分割防止) */
128
+ .tobira-text {
129
+ display: inline-block;
130
+ text-align: center;
131
+ }
132
+
133
+ /* 章扉絵(共通) */
134
+ h1#sec1, h1#sec2, h1#sec3, h1#sec4, h1#sec5, h1#sec6 {
135
+ page: tobira;
136
+ background-repeat: no-repeat, no-repeat;
137
+ background-size: 110mm 45mm, 188mm 263mm;
138
+ color: white;
139
+ }
140
+
141
+ /* 扉絵フレーム位置(1行タイトル) */
142
+ h1#sec1, h1#sec2 {
143
+ background-position: center 71mm, center center;
144
+ }
145
+
146
+ /* 扉絵フレーム位置(2行タイトル) */
147
+ h1#sec3, h1#sec4, h1#sec5, h1#sec6 {
148
+ background-position: center 74mm, center center;
149
+ }
150
+
151
+ /* 章扉絵(個別背景) */
152
+ h1#sec1 {
153
+ background-image: url("../images/tobira/tobira_frame.svg"), url("../images/tobira/1.jpg");
154
+ }
155
+
156
+ h1#sec2 {
157
+ background-image: url("../images/tobira/tobira_frame.svg"), url("../images/tobira/2.jpg");
158
+ }
159
+
160
+ h1#sec3 {
161
+ background-image: url("../images/tobira/tobira_frame.svg"), url("../images/tobira/3.jpg");
162
+ }
163
+
164
+ h1#sec4 {
165
+ background-image: url("../images/tobira/tobira_frame.svg"), url("../images/tobira/4.jpg");
166
+ }
167
+
168
+ h1#sec5 {
169
+ background-image: url("../images/tobira/tobira_frame.svg"), url("../images/tobira/5.jpg");
170
+ }
171
+
172
+ h1#sec6 {
173
+ background-image: url("../images/tobira/tobira_frame.svg"), url("../images/tobira/6.jpg");
174
+ }
175
+
176
+ /* 扉絵タイトル枠(ドット絵風RPGダイアログボックス) */
177
+ .tobira-title {
178
+ position: relative;
179
+ z-index: 1;
180
+ display: inline-block;
181
+ width: 110mm;
182
+ height: 45mm;
183
+ background-color: black;
184
+ background-image: url("../images/tobira/tobira_frame.svg");
185
+ background-repeat: no-repeat;
186
+ background-size: 100% 100%;
187
+ background-position: center;
188
+ color: white;
189
+ font-family: 'DotGothic16', sans-serif;
190
+ font-size: 18pt;
191
+ text-align: center;
192
+ line-height: 1.5;
193
+ padding-top: 12mm;
194
+ box-sizing: border-box;
195
+ }
196
+
197
+ /* はじめにページ */
198
+ @page hajimeni {
199
+ background-color: #ffffff;
200
+ }
201
+
202
+ @page hajimeni:left {
203
+ @bottom-left {
204
+ color: black;
205
+ }
206
+ }
207
+
208
+ @page hajimeni:right {
209
+ @bottom-right {
210
+ color: black;
211
+ }
212
+ }
213
+
214
+ .hajimeni {
215
+ page: hajimeni;
216
+ color: black;
217
+ }
218
+
219
+ .hajimeni::before {
220
+ content: '';
221
+ display: block;
222
+ width: 120px;
223
+ height: 120px;
224
+ margin: 0 auto 5mm;
225
+ background-image: url("../images/pixel_parts/ruby.png");
226
+ background-size: contain;
227
+ background-repeat: no-repeat;
228
+ }
229
+
230
+ .hajimeni p {
231
+ color: black;
232
+ text-indent: 1rem;
233
+ line-height: 2.2;
234
+ }
235
+
236
+ /* 目次の見出し */
237
+ .toc h1 {
238
+ height: auto;
239
+ box-sizing: content-box;
240
+ margin: 5mm 0 5mm 24px;
241
+ padding: 16px 0 8px;
242
+ font-family: 'Continue 2P', sans-serif;
243
+ font-size: 18px;
244
+ font-weight: normal;
245
+ text-align: center;
246
+ color: white;
247
+ page-break-before: avoid;
248
+ page-break-after: avoid;
249
+ background-image: url("../images/decorations/h1_toc.svg");
250
+ background-repeat: no-repeat;
251
+ background-size: 100% 100%;
252
+ background-position: center;
253
+ }
254
+
255
+ h2{
256
+ color: #000000; /* 文字色 */
257
+ padding: 13px 13px 13px 50px; /* 余白(枠線3px分を含む + 左にアイコン分スペース) */
258
+ position: relative;
259
+ break-after: avoid; /* 見出しの直後で改ページを避ける */
260
+ break-inside: avoid; /* 見出しの途中で改ページを避ける */
261
+ font-size: 16px;
262
+ width: 163mm;
263
+ box-sizing: border-box;
264
+ border: none;
265
+ /* 上下ライン(角込みSVG)+ 左右の縦線(CSS gradient)+ 白背景 */
266
+ background:
267
+ url("../images/decorations/h2_line_top.svg") top left / 163mm 9px no-repeat,
268
+ url("../images/decorations/h2_line_bottom.svg") bottom left / 163mm 9px no-repeat,
269
+ linear-gradient(#000, #000) left 0 top 9px / 3px calc(100% - 18px) no-repeat,
270
+ linear-gradient(#000, #000) right 0 top 9px / 3px calc(100% - 18px) no-repeat,
271
+ #ffffff;
272
+ }
273
+ /* h2 Rubyアイコン */
274
+ h2::before {
275
+ content: '';
276
+ position: absolute;
277
+ top: 50%;
278
+ left: 8px;
279
+ transform: translateY(-50%);
280
+ width: 40px;
281
+ height: 40px;
282
+ background-image: url(../images/pixel_parts/ruby.png);
283
+ background-size: contain;
284
+ background-repeat: no-repeat;
285
+ }
286
+
287
+ h3 {
288
+ position: relative;
289
+ padding: 0.2em 0 14px 34px;
290
+ border-bottom: none;
291
+ break-after: avoid; /* 見出しの直後で改ページを避ける */
292
+ break-inside: avoid; /* 見出しの途中で改ページを避ける */
293
+ font-size: 16px;
294
+ width: 163mm;
295
+ box-sizing: border-box;
296
+ background-image: url("../images/decorations/h3_pattern.svg");
297
+ background-repeat: repeat-x;
298
+ background-position: bottom;
299
+ background-size: auto 12px;
300
+ }
301
+
302
+ h3::after {
303
+ position: absolute;
304
+ content: '';
305
+ display: inline-block;
306
+ top: 0;
307
+ left: 0;
308
+ width: 30px;
309
+ height: 30px;
310
+ background-image: url(../images/pixel_parts/sword.png);
311
+ background-size: contain;
312
+ background-repeat: no-repeat;
313
+ vertical-align: middle;
314
+ }
315
+
316
+ h4 {
317
+ font-size: 14px;
318
+ font-weight: bold;
319
+ }
320
+
321
+ /* ----- リスト ----- */
322
+ ul, ol {
323
+ padding: 0.5em 0 0.5em 2em;
324
+ }
325
+
326
+ ul {
327
+ margin-left: 2.5em;
328
+ padding-bottom: 1em;
329
+ }
330
+
331
+ li {
332
+ font-size: 12px;
333
+ }
334
+
335
+ ul li {
336
+ position: relative;
337
+ list-style: none;
338
+ margin-left: 0;
339
+ padding-left: 0;
340
+ }
341
+
342
+ ul li::after {
343
+ display: block;
344
+ content: '';
345
+ position: absolute;
346
+ top: .5em;
347
+ left: -1em;
348
+ width: 6px;
349
+ height: 6px;
350
+ background-color: #e73828;
351
+ -webkit-transform: rotate(-45deg);
352
+ transform: rotate(-45deg);
353
+ }
354
+
355
+ ul li ul li::after { /* 2階層目 */
356
+ width: 4px;
357
+ height: 4px;
358
+ background-color: #CCC;
359
+ -webkit-transform: rotate(0deg);
360
+ transform: rotate(0deg);
361
+ }
362
+
363
+ /* ----- コード部分 ----- */
364
+ pre { /*pre要素のスタイルをリセット */
365
+ margin: 0;
366
+ padding: 0;
367
+ font-family: 'Courier New';
368
+ overflow: auto;
369
+ white-space: pre-wrap;
370
+ word-wrap: break-word; /* テキスト折り返す */
371
+ }
372
+
373
+ pre code {
374
+ padding: 1em;
375
+ margin: 0 0 0.8em 0;
376
+ font-size: 12px;
377
+ font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
378
+ border: solid 1px #555;
379
+ border-radius: 0;
380
+ display: block;
381
+ width: 163mm;
382
+ box-sizing: border-box;
383
+ height: auto;
384
+ overflow: auto;
385
+ white-space: pre-wrap;
386
+ word-wrap: break-word; /* テキスト折り返す */
387
+ }
388
+
389
+ code {
390
+ font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
391
+ }
392
+
393
+ .console code {
394
+ padding: 0.5em 1em;
395
+ margin: 0 0 0.5em 0;
396
+ color: #FFF;
397
+ background: #000;
398
+ border-radius: 4px;
399
+ width: 95%;
400
+ height: auto;
401
+ display: block;
402
+ }
403
+
404
+ .fit figure img {
405
+ width: 100%;
406
+ }
407
+
408
+ .screen-shot figure img {
409
+ width: 50mm;
410
+ }
411
+
412
+ .book figure, .screen-shot figure, .fit figure {
413
+ text-align: center;
414
+ }
415
+
416
+ .book figure img {
417
+ width: 28mm;
418
+ border: solid 0.4px;
419
+ }
420
+
421
+ .author figure img {
422
+ width: 50px;
423
+ margin-bottom: 2em;
424
+ border: solid 0.4px;
425
+ float: left;
426
+ }
427
+
428
+ .float_clear {
429
+ clear: both;
430
+ }
431
+
432
+ .manga figure {
433
+ margin: -8mm;
434
+ text-align: center;
435
+ }
436
+
437
+ .manga figure img {
438
+ margin: -8mm;
439
+ width: 100%;
440
+ height: auto;
441
+ }
442
+
443
+ .speech {
444
+ margin-bottom: 10px;
445
+ display: flex;
446
+ }
447
+
448
+ .speech .icon {
449
+ width: 48px;
450
+ height: 48px;
451
+ flex-basis: 48px;
452
+ border: solid 0.1px;
453
+ border-radius: 24px;
454
+ display: flex;
455
+ }
456
+
457
+ .speech.shinra .icon {
458
+ background-image: url(../images/icon_wakaba.png);
459
+ background-size: cover;
460
+ }
461
+
462
+ .speech.kuroneko .icon {
463
+ background-image: url(../images/icon_kuroneko.png);
464
+ background-size: cover;
465
+ }
466
+
467
+ .speech .baloon {
468
+ border: solid 0.1px;
469
+ border-radius: 4px;
470
+ background-color: #eeeeee;
471
+ padding: 10px;
472
+ margin-left: 10px;
473
+ display: inline-block;
474
+ width:440px;
475
+ }
476
+
477
+ .speech p {
478
+ display: inline;
479
+ align-items: center;
480
+ }
481
+
482
+ /* メモボックス */
483
+
484
+ .memobox {
485
+ position: relative;
486
+ margin: 3em 0;
487
+ padding: 0.5em 1em;
488
+ border: solid 3px #20b2aa;
489
+ }
490
+ .memobox .box-title {
491
+ position: absolute;
492
+ display: inline-block;
493
+ top: -27px;
494
+ left: -3px;
495
+ padding: 0 9px;
496
+ height: 25px;
497
+ line-height: 25px;
498
+ vertical-align: middle;
499
+ font-size: 15px;
500
+ background: #20b2aa;
501
+ color: #ffffff;
502
+ font-weight: bold;
503
+ border-radius: 5px 5px 0 0;
504
+ }
505
+ .memobox .box-text {
506
+ margin: 0;
507
+ padding: 0;
508
+ font-size: 12px;
509
+ text-indent: 1rem;
510
+ }
511
+
512
+ .file {
513
+ margin: 0 0 0.8em 0;
514
+ break-inside: avoid;
515
+ }
516
+
517
+ .file .filename {
518
+ break-after: avoid;
519
+ display: inline-block;
520
+ font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
521
+ font-size: small;
522
+ background: #555;
523
+ color: #fff;
524
+ padding: 0.2em 1em;
525
+ border-radius: 6px 6px 0 0;
526
+ margin: 0;
527
+ line-height: 1.4;
528
+ }
529
+
530
+ .file pre {
531
+ margin-top: 0;
532
+ }
533
+
534
+ .file pre code {
535
+ margin-top: 0;
536
+ border-top-left-radius: 0;
537
+ }
538
+
539
+ .code-line {
540
+ display: block;
541
+ padding-left: 4.4em;
542
+ background-image: linear-gradient(#999, #999);
543
+ background-position: 3.3em 0;
544
+ background-size: 1px 100%;
545
+ background-repeat: no-repeat;
546
+ line-height: 1.2;
547
+ margin: 0;
548
+ padding-top: 0;
549
+ padding-bottom: 0;
550
+ }
551
+
552
+ .line-number {
553
+ display: inline-block;
554
+ width: 3em;
555
+ margin-left: -4.4em;
556
+ margin-right: 0.4em;
557
+ padding-right: 0.4em;
558
+ color: #999;
559
+ text-align: right;
560
+ user-select: none;
561
+ }
562
+
563
+ .page-break {
564
+ page-break-before: always;
565
+ }
566
+
567
+ .footnote {
568
+ float: footnote;
569
+ font-size: 8pt;
570
+ counter-increment: footnote;
571
+ text-indent: 0;
572
+ }
573
+
574
+ .footnote::footnote-marker {
575
+ content: counter(footnote);
576
+ font-size: 8pt;
577
+ vertical-align: super;
578
+ }
579
+
580
+ .footnote::footnote-call {
581
+ content: counter(footnote);
582
+ font-size: 8pt;
583
+ vertical-align: super;
584
+ display: inline;
585
+ line-height: 1;
586
+ }
587
+
588
+ /* 画像サイズ指定(10%刻み) */
589
+ figure.img-10 img { width: 10%; }
590
+ figure.img-20 img { width: 20%; }
591
+ figure.img-30 img { width: 30%; }
592
+ figure.img-40 img { width: 40%; }
593
+ figure.img-50 img { width: 50%; }
594
+ figure.img-60 img { width: 60%; }
595
+ figure.img-70 img { width: 70%; }
596
+ figure.img-80 img { width: 80%; }
597
+ figure.img-90 img { width: 90%; }
598
+ figure.img-100 img { width: 100%; }
599
+
600
+ /* 図のキャプション */
601
+ figure {
602
+ counter-increment: figure;
603
+ text-align: center;
604
+ }
605
+
606
+ figcaption {
607
+ font-size: 9pt;
608
+ text-align: center;
609
+ }
610
+
611
+ figcaption::before {
612
+ content: "図" counter(figure) ": ";
613
+ }
614
+
615
+ /* コード例 */
616
+ span.example {
617
+ font-size: 10px;
618
+ font-weight: bold;
619
+ margin-left: -15px;
620
+ color: #14716c;
621
+ }
622
+
623
+ /* ワンポイント講座 */
624
+ .one-point {
625
+ width: 100%;
626
+ height: auto;
627
+ }
628
+
629
+ /* 表テーブル */
630
+ table {
631
+ width: 100%;
632
+ border-collapse: collapse;
633
+ }
634
+ table th,
635
+ table td {
636
+ text-align:left;
637
+ padding: 6px;
638
+ box-sizing:border-box;
639
+ border: 1px solid #555;
640
+ }
641
+ table th {
642
+ background:#eeeeee;
643
+ color:#000000;
644
+ }
645
+
646
+ table th:first-child {
647
+ width: 30%;
648
+ }
649
+
650
+ table td {
651
+ background:#ffffff;
652
+ color:#333333
653
+ }
@@ -8,8 +8,11 @@ module VivlioPack
8
8
  class Generator
9
9
  def initialize(workdir)
10
10
  @workdir = File.expand_path(workdir)
11
- @names = Psych.load_file("articles.yaml")
12
- @markdown = Redcarpet::Markdown.new(Renderer, autolink: true, tables: true, fenced_code_blocks: true, footnotes: true)
11
+ @names = Psych.load_file("#{@workdir}/articles.yaml")
12
+ if File.exist?("#{@workdir}/plugin.rb")
13
+ load "#{@workdir}/plugin.rb"
14
+ end
15
+ @markdown = Redcarpet::Markdown.new(Renderer, autolink: true, tables: true, fenced_code_blocks: true)
13
16
  end
14
17
 
15
18
  def generate(html_path)
@@ -37,7 +40,8 @@ module VivlioPack
37
40
 
38
41
  file_paths.each do |path|
39
42
  File.open(path, "r") do |file|
40
- html.write(@markdown.render(file.read))
43
+ content = preprocess_footnotes(file.read)
44
+ html.write(@markdown.render(content))
41
45
  end
42
46
  end
43
47
 
@@ -47,5 +51,24 @@ module VivlioPack
47
51
  HTML
48
52
  end
49
53
  end
54
+ private
55
+
56
+ def preprocess_footnotes(text)
57
+ footnotes = {}
58
+ # 脚注定義 [^N]: テキスト を収集して削除
59
+ text = text.gsub(/^\[\^(\w+)\]:\s*(.+)$/) do
60
+ footnotes[$1] = $2
61
+ ""
62
+ end
63
+ # 脚注参照 [^N] を本文中のインライン脚注spanに置換
64
+ text = text.gsub(/\[\^(\w+)\]/) do
65
+ if footnotes[$1]
66
+ "<span class='footnote'>#{footnotes[$1]}</span>"
67
+ else
68
+ "[^#{$1}]"
69
+ end
70
+ end
71
+ text
72
+ end
50
73
  end
51
74
  end
@@ -6,11 +6,21 @@ module VivlioPack
6
6
  class Renderer < Redcarpet::Render::HTML
7
7
  include Rouge::Plugins::Redcarpet
8
8
 
9
+ def self.add_plugin(name, mod)
10
+ (@plugins ||= {})[name] = mod
11
+ end
12
+
13
+ def self.plugin(name)
14
+ @plugins[name]
15
+ end
16
+
9
17
  def initialize
10
18
  super
11
19
  @sec = 0
12
20
  @ch = 0
13
21
  @para = 0
22
+ @state = []
23
+ @ring_buffer = []
14
24
  end
15
25
 
16
26
  def header(c, level)
@@ -33,43 +43,47 @@ module VivlioPack
33
43
  end
34
44
 
35
45
  def paragraph(text)
46
+ @ring_buffer.push text
47
+ @ring_buffer.shift if @ring_buffer.length > 5
36
48
  case text.strip
37
- when "[begin dialog]"
38
- @in_dialog = true
39
- return "<div class='dialog'>\n"
40
- when "[end dialog]"
41
- @in_dialog = false
42
- return "</div>\n"
49
+ when /\A\[file (?<filename>(\w+\/)*(\w+)\.(\w+))(:(?<lineno>\d+))?\]$/
50
+ @in_file = true
51
+ filename = $~[:filename]
52
+ @file_lineno = $~[:lineno] ? $~[:lineno].to_i : 1
53
+ @file_filename = filename
54
+ return ""
43
55
  when "[page break]"
44
56
  return "<div class='page-break'></div>\n"
45
- when "[begin one-point]"
46
- return "<div><img src='images/onepoint_before.png' class='one-point'>\n"
47
- when "[end one-point]"
48
- return "<img src='images/onepoint_after.png' class='one-point'></div>\n"
49
57
  when /\A%([a-z][a-z0-9\-]*):(.*)/m
50
58
  return "<div class='#{$1}'>#{$2}</div>\n"
59
+ when /\A\[begin (\w+)\]\z/
60
+ plugin_name = $~[1]
61
+ plugin = Renderer.plugin(plugin_name)
62
+ if plugin
63
+ @state.push plugin_name
64
+ result = plugin.process_begin
65
+ return result if result
66
+ end
67
+ when /\A\[end (\w+)\]\z/
68
+ plugin_name = $~[1]
69
+ plugin = Renderer.plugin(plugin_name)
70
+ if plugin
71
+ if @state.last == plugin_name
72
+ @state.pop
73
+ else
74
+ @ring_buffer.each do |line|
75
+ puts line
76
+ end
77
+ raise RuntimeError.new("plugin: #{plugin_name} の対応が合っていません")
78
+ end
79
+ end
51
80
  end
52
81
 
53
- if @in_dialog
54
- case text
55
- when /^わかばちゃん「(.+)」$/
56
- return <<~HTML
57
- <div class="speech shinra">
58
- <div class="icon"></div>
59
- <div class="baloon">
60
- <p>#{$1}</p>
61
- </div>
62
- </div>
63
- HTML
64
- when /^黒猫先生「(.+)」$/
65
- return <<~HTML
66
- <div class="speech kuroneko">
67
- <div class="icon"></div>
68
- <div class="baloon">
69
- <p>#{$1}</p>
70
- </div>
71
- </div>
72
- HTML
82
+ @state.reverse.each do |plugin_name|
83
+ plugin = Renderer.plugin(plugin_name)
84
+ if plugin
85
+ result = plugin.process_inner(text)
86
+ return result if result
73
87
  end
74
88
  end
75
89
 
@@ -77,24 +91,44 @@ module VivlioPack
77
91
  "<p>#{text.gsub(/ $/, "<br>\n")}</p>\n"
78
92
  end
79
93
 
80
- def footnotes(content)
81
- content
82
- end
83
-
84
- def footnote_def(content, number)
85
- "<span class='footnote'>#{content}</span>"
94
+ def block_code(code, language)
95
+ if @in_file
96
+ @in_file = false
97
+ lineno = @file_lineno || 1
98
+ lexer = Rouge::Lexer.find_fancy(language) || Rouge::Lexers::PlainText.new
99
+ formatter = Rouge::Formatters::HTML.new
100
+ lines = code.split("\n")
101
+ numbered_lines = lines.each_with_index.map do |line, i|
102
+ highlighted_line = formatter.format(lexer.lex(line))
103
+ "<span class='code-line'><span class='line-number'>#{(lineno + i).to_s.rjust(4)}</span>#{highlighted_line}</span>"
104
+ end
105
+ "<div class='file'><div class='filename'>#{@file_filename}:#{lineno}</div><pre class='highlight'><code>#{numbered_lines.join}</code></pre></div>\n"
106
+ else
107
+ super
108
+ end
86
109
  end
87
110
 
88
111
  def image(link, title, alt_text)
89
112
  name = File.basename(link, ".*")
113
+ size_class = ""
114
+ caption = alt_text
115
+ if alt_text =~ /\A(.+?)\s*"(\d+)%"\s*\z/
116
+ caption = $1.strip
117
+ size_class = "img-#{$2}"
118
+ end
119
+ figure_attr = size_class.empty? ? "" : " class=\"#{size_class}\""
90
120
  <<~HTML
91
- <figure>
92
- <img src="#{link}" alt="#{alt_text}" />
93
- <figcaption id="#{name}">#{alt_text}</figcaption>
121
+ <figure#{figure_attr}>
122
+ <img src="#{link}" alt="#{caption}" />
123
+ <figcaption id="#{name}">#{caption}</figcaption>
94
124
  </figure>
95
125
  HTML
96
126
  end
97
127
 
128
+ def hrule
129
+ "<div class='page-break'></div>\n"
130
+ end
131
+
98
132
  def onepoint(text)
99
133
  case text.strip
100
134
  when "[begin one-point]"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module VivlioPack
4
- VERSION = "0.1.1"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vivlio_pack
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - youchan
@@ -77,6 +77,7 @@ files:
77
77
  - LICENSE.txt
78
78
  - README.md
79
79
  - Rakefile
80
+ - assets/css/style.css
80
81
  - exe/vp_viewer
81
82
  - exe/vpack
82
83
  - lib/vivlio_pack.rb
@@ -109,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
110
  - !ruby/object:Gem::Version
110
111
  version: '0'
111
112
  requirements: []
112
- rubygems_version: 3.6.7
113
+ rubygems_version: 4.0.16
113
114
  specification_version: 4
114
115
  summary: Create books with vivliostyle.
115
116
  test_files: []