slideck 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,475 @@
1
+ # Slideck
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/slideck.svg)][gem]
4
+ [![Actions CI](https://github.com/piotrmurach/slideck/workflows/CI/badge.svg?branch=master)][gh_actions_ci]
5
+ [![Build status](https://ci.appveyor.com/api/projects/status/kvlo53t54qimbfqy?svg=true)][appveyor]
6
+ [![Maintainability](https://api.codeclimate.com/v1/badges/c96e8367481519c38a06/maintainability)][codeclimate]
7
+ [![Coverage Status](https://coveralls.io/repos/github/piotrmurach/slideck/badge.svg)][coverage]
8
+
9
+ [gem]: https://badge.fury.io/rb/slideck
10
+ [gh_actions_ci]: https://github.com/piotrmurach/slideck/actions?query=workflow%3ACI
11
+ [appveyor]: https://ci.appveyor.com/project/piotrmurach/slideck
12
+ [codeclimate]:https://codeclimate.com/github/piotrmurach/slideck/maintainability
13
+ [coverage]: https://coveralls.io/github/piotrmurach/slideck
14
+
15
+ > Terminal tool for presenting Markdown-powered slide decks.
16
+
17
+ ## Features
18
+
19
+ * Write slides in the **Markdown** with extended syntax.
20
+ * Show code snippets in [fenced code blocks](https://www.markdownguide.org/extended-syntax/#fenced-code-blocks).
21
+ * Syntax highlight code for [over 200 languages](https://github.com/rouge-ruby/rouge/blob/master/docs/Languages.md).
22
+ * Create Markdown [tables](https://www.markdownguide.org/extended-syntax/#tables) with advanced formatting.
23
+ * [Align](#21-align) slide content with familiar CSS syntax.
24
+ * Add [margin](#23-margin) around content for all or a single slide.
25
+ * Track progress through the slides with a [pager](#24-pager).
26
+ * Display a [footer](#22-footer) at the bottom of every slide.
27
+ * Apply custom [symbols](#25-symbols) and style [theme](#26-theme) to content.
28
+ * Auto reload presentation when a file with slides changes.
29
+
30
+ ## Installation
31
+
32
+ **Slideck** will work with any version of Ruby greater than or equal to `2.0`.
33
+ Read [Installing Ruby](https://www.ruby-lang.org/en/documentation/installation/)
34
+ guide to choose the best installation method.
35
+
36
+ Once Ruby is set up, install the `slideck` with:
37
+
38
+ ```shell
39
+ $ gem install slideck
40
+ ```
41
+
42
+ ## Contents
43
+
44
+ * [1. Usage](#1-usage)
45
+ * [2. Configuration](#2-configuration)
46
+ * [2.1 align](#21-align)
47
+ * [2.2 footer](#22-footer)
48
+ * [2.3 margin](#23-margin)
49
+ * [2.4 pager](#24-pager)
50
+ * [2.5 symbols](#25-symbols)
51
+ * [2.6 theme](#26-theme)
52
+
53
+ ## 1. Usage
54
+
55
+ Open a text file and start writing slides in Markdown. Begin the document
56
+ by adding configuration for all slides in `YAML` format. Then to denote
57
+ a slide, separate its content with three dashes. Use the same configuration
58
+ settings to override the global settings for a slide. To do so, specify
59
+ settings with `YAML` flow mappings after the slide separator.
60
+
61
+ Here's a sample of a few slides with global and slide-specific configuration
62
+ settings:
63
+
64
+ ````markdown
65
+ align: center
66
+ margin: 2 5
67
+ footer:
68
+ align: center bottom
69
+ text: Footer content
70
+
71
+ --- margin: 0
72
+
73
+ # Welcome to Slideck
74
+
75
+ ## Built with TTY Toolkit
76
+
77
+ --- align: center top
78
+
79
+ # Code Block
80
+
81
+ ```ruby
82
+ puts "Welcome to Slideck"
83
+ ```
84
+
85
+ --- theme: {list: magenta}
86
+
87
+ # Unordered List
88
+
89
+ - Item 1
90
+ - Item 2
91
+ - Item 3
92
+
93
+ --- symbols: ascii
94
+
95
+ # Table
96
+
97
+ | A | B | C |
98
+ |---|---|---|
99
+ | a | b | c |
100
+ | a | b | c |
101
+ | a | b | c |
102
+
103
+ --- {pager: false, footer: false}
104
+
105
+ # The End
106
+ ````
107
+
108
+ To start presenting, for example, `slides.md` file in a terminal:
109
+
110
+ ```shell
111
+ $ slideck slides.md
112
+ ```
113
+
114
+ Use the `-h` or `--help` flag to see help about available presentation
115
+ controls and options:
116
+
117
+ ```shell
118
+ $ slideck --help
119
+ ```
120
+
121
+ Use the `-w` or `--watch` flag to automatically reload the presentation
122
+ with any update to the `slides.md` file:
123
+
124
+ ```shell
125
+ $ slideck slides.md --watch
126
+ ```
127
+
128
+ ## 2. Configuration
129
+
130
+ Configuration options can be global or slide-specific.
131
+
132
+ Add global configuration options in `YAML` format at the beginning
133
+ of a document.
134
+
135
+ For example, to configure [alignment](#21-align) and [margin](#23-margin)
136
+ for all slides:
137
+
138
+ ```markdown
139
+ align: center
140
+ margin: 2 5
141
+
142
+ ---
143
+
144
+ First Slide
145
+
146
+ ---
147
+
148
+ Second Slide
149
+
150
+ ---
151
+ ```
152
+
153
+ Use `YAML` flow mappings syntax to change the global configuration for a given
154
+ slide. This format is a series of key/value pairs separated by commas and
155
+ surrounded by curly braces. The semicolon with space follows a key and splits
156
+ it from value. Braces are optional for a single key/value pair.
157
+ A slide-specific configuration follows three dashes and needs to be on
158
+ the same line.
159
+
160
+ For example, to override [alignment](#21-align) and [margin](#23-margin)
161
+ for a given slide:
162
+
163
+ ```markdown
164
+ align: center
165
+ margin: 2 5
166
+
167
+ --- margin: 0
168
+
169
+ First Slide
170
+
171
+ --- {align: center top, margin: 1 3}
172
+
173
+ Second Slide
174
+
175
+ ---
176
+ ```
177
+
178
+ ### 2.1 Align
179
+
180
+ **Slideck** draws the slide's content from the left top of the terminal screen
181
+ by default. It positions the pager at the bottom right corner. When given, the
182
+ footer ends up at the bottom left corner. Use the `:align` configuration to
183
+ change the default positioning of content, [footer](#22-footer) and
184
+ [pager](#24-pager).
185
+
186
+ The `align` configuration takes either one or two values. The first value
187
+ specifies the horizontal alignment out of `left`, `center` and `right`.
188
+ The second value describes vertical alignment out of the `top`, `center`
189
+ and `bottom`. Skipping the second value will default the vertical alignment
190
+ to the `center`. Use a space, comma or both to separate two values.
191
+
192
+ For example, to position content at the top center of the screen
193
+ on every slide:
194
+
195
+ ```yaml
196
+ align: center top
197
+ ```
198
+
199
+ Or use shorthand to place content at the center left on every slide:
200
+
201
+ ```yaml
202
+ align: left
203
+ ```
204
+
205
+ Use the same configuration to change the alignment for a single slide. It
206
+ needs to follow after the slide separator and be on the same line.
207
+
208
+ For example, to place a given slide at the bottom left:
209
+
210
+ ```yaml
211
+ --- align: left bottom
212
+ ```
213
+
214
+ ### 2.2 Footer
215
+
216
+ **Slideck** doesn't show the footer by default. Use the `:footer` configuration
217
+ to add content to the bottom left of the screen for every slide.
218
+
219
+ For example, to display a footer on every slide:
220
+
221
+ ```yaml
222
+ footer: Footer content
223
+ ```
224
+
225
+ The footer supports `Markdown` syntax:
226
+
227
+ ```yaml
228
+ footer: **bold** content
229
+ ```
230
+
231
+ The footer can also span more than one line:
232
+
233
+ ```yaml
234
+ footer: "first line\nsecond line\nthird line"
235
+ ```
236
+
237
+ Use the `:align` key to change the footer alignment and the `:text` key
238
+ to specify its content.
239
+
240
+ For example, to specify a global footer at the bottom center of every slide:
241
+
242
+ ```yaml
243
+ footer:
244
+ align: center bottom
245
+ text: Footer content
246
+ ```
247
+
248
+ Use the same configuration to change the footer for a single slide. It needs
249
+ to follow after the slide separator and be on the same line.
250
+
251
+ For example, to place a footer at the bottom center of the screen:
252
+
253
+ ```yaml
254
+ --- footer: {align: center bottom, text: Footer content}
255
+ ```
256
+
257
+ Or, use a `false` value to hide a footer for a single slide:
258
+
259
+ ```yaml
260
+ --- footer: false
261
+ ```
262
+
263
+ ### 2.3 Margin
264
+
265
+ The `margin` specifies a distance from all four sides of the terminal screen.
266
+ It follows CSS rules and can have one, two, three or four integer values. Use
267
+ a space or comma to separate each integer value.
268
+
269
+ The following are all possible ways to specify a margin:
270
+
271
+ ```yaml
272
+ margin: 1 # the same margin of 1 for all sides
273
+ margin: 1 2 # 1 to the top and bottom, and 2 to the left and right
274
+ margin: 1 2 3 # 1 to the top, 2 to the left and right, and 3 to the bottom
275
+ margin: 1 2 3 4 # 1 to the top, 2 to the right, 3 to the bottom, 4 to the left
276
+ ```
277
+
278
+ Or, specify a margin with explicit side names:
279
+
280
+ ```yaml
281
+ margin:
282
+ top: 1
283
+ right: 2
284
+ bottom: 3
285
+ left: 4
286
+ ```
287
+
288
+ Like shorthand notation, specify names only for the configured sides.
289
+
290
+ For example, to add only the top margin and leave all the other sides with
291
+ their default values:
292
+
293
+ ```yaml
294
+ margin:
295
+ top: 1
296
+ ```
297
+
298
+ Use the same configuration to change the margin for a single slide. It needs
299
+ to follow after the slide separator and be on the same line.
300
+
301
+ For example, to zero out the margin for a given slide:
302
+
303
+ ```yaml
304
+ --- margin: 0
305
+ ```
306
+
307
+ ### 2.4 Pager
308
+
309
+ **Slideck** displays the `pager` in the bottom right corner of the terminal
310
+ screen. The display format is `%<page>d / %<total>d`, where the first
311
+ placeholder represents the current slide and the second is the total
312
+ number of slides.
313
+
314
+ For example, to change the pager display:
315
+
316
+ ```yaml
317
+ pager: "Page %<page>d of %<total>d"
318
+ ```
319
+
320
+ The pager supports `Markdown` syntax:
321
+
322
+ ```yaml
323
+ pager: "**Bold** %<total> pages"
324
+ ```
325
+
326
+ The pager can also span more than one line:
327
+
328
+ ```yaml
329
+ pager: "Page\n%<page>d\nof\n%<total>d"
330
+ ```
331
+
332
+ Use the `:align` key to change the pager alignment and the `:text` key
333
+ to specify its content.
334
+
335
+ For example, to place the pager at the bottom center of every slide:
336
+
337
+ ```yaml
338
+ pager:
339
+ align: center bottom
340
+ text: "Page %<page>d of %<total>d"
341
+ ```
342
+
343
+ Or, use a `false` value to hide a pager on all slides:
344
+
345
+ ```yaml
346
+ pager: false
347
+ ```
348
+
349
+ Use the same configuration to change the pager for a single slide. It needs
350
+ to follow after the slide separator and be on the same line.
351
+
352
+ For example, to place a pager at the bottom center of a given slide:
353
+
354
+ ```yaml
355
+ --- pager: {align: center bottom, text: "Page %<page>d of %<total>d"}
356
+ ```
357
+
358
+ Or, use a `false` value to hide a pager for a single slide:
359
+
360
+ ```yaml
361
+ --- pager: false
362
+ ```
363
+
364
+ ### 2.5 Symbols
365
+
366
+ **Slideck** decorates `Markdown` elements with `unicode` symbols by default.
367
+ Use the `:symbols` configuration to change the display of decorative
368
+ characters. It takes either a single value or key/value pairs. The single
369
+ value specifies a character set out of `ascii` or `unicode`. The key/value
370
+ pairs accept the `:base` and `:override` keys. Like a single value,
371
+ the `:base` key takes either `ascii` or `unicode`.
372
+
373
+ For example, to change the default symbols for all slides to `ascii`:
374
+
375
+ ```yaml
376
+ symbols: ascii
377
+ ```
378
+
379
+ Or, use the `:base` key to specify the `ascii` character set:
380
+
381
+ ```yaml
382
+ symbols:
383
+ base: ascii
384
+ ```
385
+
386
+ The `:override` key accepts key/value pairs, where the key is a symbol name
387
+ and the value is a decorative character. Please see the
388
+ [tty-markdown](https://github.com/piotrmurach/tty-markdown#24-symbols)
389
+ for a complete list of symbols.
390
+
391
+ For example, to change the `:bullet` symbol for every slide:
392
+
393
+ ```yaml
394
+ symbols:
395
+ override:
396
+ bullet: x
397
+ ```
398
+
399
+ Use the same configuration to change the symbols for a single slide. It needs
400
+ to follow after the slide separator and be on the same line.
401
+
402
+ For example, to change a character set to `ascii` for a single slide:
403
+
404
+ ```yaml
405
+ --- symbols: ascii
406
+ ```
407
+
408
+ Or, to change the `:bullet` symbol for a single slide:
409
+
410
+ ```yaml
411
+ --- symbols: {override: {bullet: x}}
412
+ ```
413
+
414
+ ### 2.6 Theme
415
+
416
+ **Slideck** displays `Markdown` elements with a default style theme. Use
417
+ the `:theme` configuration to change individual element styles. It takes
418
+ key/value pairs where the key is the element name, and the value is a single
419
+ style or list of styles. Please see the
420
+ [tty-markdown](https://github.com/piotrmurach/tty-markdown#22-theme)
421
+ for a complete list of element names and their styles.
422
+
423
+ For example, to change `em`, `link` and `list` element styles for every slide:
424
+
425
+ ```yaml
426
+ theme:
427
+ em: blue
428
+ link: cyan
429
+ list: magenta
430
+ ```
431
+
432
+ Use the same configuration to change the theme for a single slide. It needs
433
+ to follow after the slide separator and be on the same line.
434
+
435
+ For example, to change `em`, `link` and `list` element styles for
436
+ a single slide:
437
+
438
+ ```yaml
439
+ --- theme: {em: blue, link: cyan, list: magenta}
440
+ ```
441
+
442
+ ## Development
443
+
444
+ After checking out the repo, run `bin/setup` to install dependencies.
445
+ Then, run `rake spec` to run the tests. You can also run `bin/console`
446
+ for an interactive prompt that will allow you to experiment.
447
+
448
+ To install this gem onto your local machine, run `bundle exec rake install`.
449
+ To release a new version, update the version number in `version.rb`, and then
450
+ run `bundle exec rake release`, which will create a git tag for the version,
451
+ push git commits and the created tag, and push the `.gem` file to
452
+ [rubygems.org](https://rubygems.org).
453
+
454
+ ## Contributing
455
+
456
+ Bug reports and pull requests are welcome on GitHub at
457
+ https://github.com/piotrmurach/slideck. This project is intended to be a safe,
458
+ welcoming space for collaboration, and contributors are expected to adhere to
459
+ the [code of conduct](https://github.com/piotrmurach/slideck/blob/master/CODE_OF_CONDUCT.md).
460
+
461
+ ## License
462
+
463
+ The gem is available as open source under the terms of the
464
+ [GNU Affero General Public License v3.0](https://opensource.org/licenses/AGPL-3.0).
465
+
466
+ ## Code of Conduct
467
+
468
+ Everyone interacting in the Slideck project's codebases, issue trackers, chat
469
+ rooms and mailing lists is expected to follow the
470
+ [code of conduct](https://github.com/piotrmurach/slideck/blob/master/CODE_OF_CONDUCT.md).
471
+
472
+ ## Copyright
473
+
474
+ Copyright (c) 2022 Piotr Murach. See [LICENSE.txt](LICENSE.txt) for further
475
+ details.
data/exe/slideck ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/slideck"
4
+
5
+ Slideck.run
@@ -0,0 +1,201 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slideck
4
+ # Responsible for accessing alignment configuration
5
+ #
6
+ # @api private
7
+ class Alignment
8
+ # The allowed horizontal alignment values
9
+ #
10
+ # @return [Array<String>]
11
+ #
12
+ # @api private
13
+ HORIZONTAL_VALUES = %w[left center right].freeze
14
+ private_constant :HORIZONTAL_VALUES
15
+
16
+ # The allowed vertical alignment values
17
+ #
18
+ # @return [Array<String>]
19
+ #
20
+ # @api private
21
+ VERTICAL_VALUES = %w[top center bottom].freeze
22
+ private_constant :VERTICAL_VALUES
23
+
24
+ # Create an Alignment instance from a string
25
+ #
26
+ # @example
27
+ # Slideck::Alignment.from("right top")
28
+ #
29
+ # @example
30
+ # Slideck::Alignment.from("right,top")
31
+ #
32
+ # @param [String] value
33
+ # the value to extract alignments from
34
+ # @param [String] default
35
+ # the default vertical alignment
36
+ #
37
+ # @return [Slideck::Alignment]
38
+ #
39
+ # @api public
40
+ def self.from(value, default: "center")
41
+ horizontal, vertical = *value.split(/[ ,]+/)
42
+ vertical = default if vertical.nil?
43
+
44
+ new(horizontal, vertical)
45
+ end
46
+
47
+ # Create an Alignment instance with an array-like initialiser
48
+ #
49
+ # @example
50
+ # Slideck::Alignment["right", "top"]
51
+ #
52
+ # @param [String] horizontal
53
+ # the horizontal value
54
+ # @param [String] vertical
55
+ # the vertical value
56
+ #
57
+ # @return [Slideck::Alignment]
58
+ #
59
+ # @api public
60
+ def self.[](horizontal, vertical)
61
+ new(horizontal, vertical)
62
+ end
63
+
64
+ # The horizontal alignment
65
+ #
66
+ # @example
67
+ # alignemnt.horizontal
68
+ #
69
+ # @return [String]
70
+ #
71
+ # @api public
72
+ attr_reader :horizontal
73
+
74
+ # The vertical alignment
75
+ #
76
+ # @example
77
+ # alignment.vertical
78
+ #
79
+ # @return [String]
80
+ #
81
+ # @api public
82
+ attr_reader :vertical
83
+
84
+ # Create an Alignment
85
+ #
86
+ # @example
87
+ # Slideck::Alignment.new("left", "top")
88
+ #
89
+ # @param [String] horizontal
90
+ # the horizontal value
91
+ # @param [String] vertical
92
+ # the vertical value
93
+ #
94
+ # @raise [Slideck::InvalidArgumentError]
95
+ #
96
+ # @api private
97
+ def initialize(horizontal, vertical)
98
+ @horizontal = validate_horizontal(horizontal)
99
+ @vertical = validate_vertical(vertical)
100
+
101
+ freeze
102
+ end
103
+ private_class_method :new
104
+
105
+ # Determine equivalence with another object
106
+ #
107
+ # @example
108
+ # alignment == other
109
+ #
110
+ # @param [Object] other
111
+ # the other object to determine equivalence with
112
+ #
113
+ # @return [Boolean]
114
+ # true if this object is equivalent to the other, false otherwise
115
+ #
116
+ # @api public
117
+ def ==(other)
118
+ other.is_a?(self.class) &&
119
+ horizontal == other.horizontal && vertical == other.vertical
120
+ end
121
+
122
+ # Determine equality with another object
123
+ #
124
+ # @example
125
+ # alignment.eql?(other)
126
+ #
127
+ # @param [Object] other
128
+ # the other object to determine equality with
129
+ #
130
+ # @return [Boolean]
131
+ # true if this object is equal to the other, false otherwise
132
+ #
133
+ # @api public
134
+ def eql?(other)
135
+ instance_of?(other.class) &&
136
+ horizontal.eql?(other.horizontal) && vertical.eql?(other.vertical)
137
+ end
138
+
139
+ # Generate hash value of this alignment
140
+ #
141
+ # @example
142
+ # alignment.hash
143
+ #
144
+ # @return [Integer]
145
+ #
146
+ # @api public
147
+ def hash
148
+ [self.class, horizontal, vertical].hash
149
+ end
150
+
151
+ # Convert this alignment into an array
152
+ #
153
+ # @example
154
+ # alignment.to_a
155
+ #
156
+ # @return [Array<String, String>]
157
+ #
158
+ # @api public
159
+ def to_a
160
+ [horizontal, vertical]
161
+ end
162
+
163
+ private
164
+
165
+ # Check whether a value is allowed as horizontal alignment
166
+ #
167
+ # @param [String] value
168
+ # the horizontal alignment value to check
169
+ #
170
+ # @raise [Slideck::InvalidArgumentError]
171
+ #
172
+ # @return [String]
173
+ #
174
+ # @api private
175
+ def validate_horizontal(value)
176
+ return value if HORIZONTAL_VALUES.include?(value)
177
+
178
+ raise InvalidArgumentError,
179
+ "unknown '#{value}' horizontal alignment. " \
180
+ "Valid value is: left, center and right."
181
+ end
182
+
183
+ # Check whether a vlaue is allowed as vertical alignment
184
+ #
185
+ # @param [String] value
186
+ # the vertical alignment value to check
187
+ #
188
+ # @raise [Slideck::InvalidArgumentError]
189
+ #
190
+ # @return [String]
191
+ #
192
+ # @api private
193
+ def validate_vertical(value)
194
+ return value if VERTICAL_VALUES.include?(value)
195
+
196
+ raise InvalidArgumentError,
197
+ "unknown '#{value}' vertical alignment. " \
198
+ "Valid value is: top, center and bottom."
199
+ end
200
+ end # Alignment
201
+ end # Slideck