bridgetown_writebook 0.1.0 → 0.1.0.2

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: 2c25aa1ad6696109457b735df53aed475b1c7c2b3797c26d13c35b106ae900b6
4
- data.tar.gz: 3f7d2626aa3e8b136d3e08ceac6da90953165840a0a5a4e14bf809a817a6eb74
3
+ metadata.gz: 706790ac167218b2e3e12b4765c83d2e3868a9b0fc0b8635af7e5937234415b1
4
+ data.tar.gz: 662a770b9c397cf80b0e69a2681d04f9214becd91ceadf01187d924c8c17e11e
5
5
  SHA512:
6
- metadata.gz: 9bad682e488ee4de5377045ab507bf59d0e636ab707bc4321550a32140e7feaeecf68ccbc5fa248acbd0cfec6800f0dbe3a5f1c3cfe302c54b3474049febfefd
7
- data.tar.gz: bcb3a49ad89e9c122d1aa6d681df9c18b3c4687c70489d931f2b52e2308d6bd4b8bc93fcada0b148161a0eb0b1ac5a7aa24cad81047b28b4fdf798a23ca3f655
6
+ metadata.gz: b3541f4eb36f74d64154d0135dca1db9db45ba50242d27e5a6dab171104fbea56ce855c8000f5f166276b342f90251da1b8b200e54e1322058347656baf0094d
7
+ data.tar.gz: 3d5aa8046824c16b3d4cea27298214270d65b301267d2ca755f7093379575903d729e3b75f84784723f6902615efa43886414cac7dc57defb159a184194bd53d
data/.idea/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
4
+ # Editor-based HTTP Client requests
5
+ /httpRequests/
6
+ # Datasource local storage ignored files
7
+ /dataSources/
8
+ /dataSources.local.xml
@@ -0,0 +1,111 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="RUBY_MODULE" version="4">
3
+ <component name="ModuleRunConfigurationManager">
4
+ <shared />
5
+ </component>
6
+ <component name="NewModuleRootManager">
7
+ <content url="file://$MODULE_DIR$" />
8
+ <orderEntry type="jdk" jdkName="asdf: 3.3.3" jdkType="RUBY_SDK" />
9
+ <orderEntry type="sourceFolder" forTests="false" />
10
+ <orderEntry type="library" scope="PROVIDED" name="activemodel (v7.2.2.2, asdf: 3.3.3) [gem]" level="application" />
11
+ <orderEntry type="library" scope="PROVIDED" name="activesupport (v7.2.2.2, asdf: 3.3.3) [gem]" level="application" />
12
+ <orderEntry type="library" scope="PROVIDED" name="addressable (v2.8.7, asdf: 3.3.3) [gem]" level="application" />
13
+ <orderEntry type="library" scope="PROVIDED" name="amazing_print (v1.8.1, asdf: 3.3.3) [gem]" level="application" />
14
+ <orderEntry type="library" scope="PROVIDED" name="ansi (v1.5.0, asdf: 3.3.3) [gem]" level="application" />
15
+ <orderEntry type="library" scope="PROVIDED" name="ast (v2.4.3, asdf: 3.3.3) [gem]" level="application" />
16
+ <orderEntry type="library" scope="PROVIDED" name="base64 (v0.3.0, asdf: 3.3.3) [gem]" level="application" />
17
+ <orderEntry type="library" scope="PROVIDED" name="benchmark (v0.4.1, asdf: 3.3.3) [gem]" level="application" />
18
+ <orderEntry type="library" scope="PROVIDED" name="bigdecimal (v3.2.2, asdf: 3.3.3) [gem]" level="application" />
19
+ <orderEntry type="library" scope="PROVIDED" name="bridgetown (v1.3.4, asdf: 3.3.3) [gem]" level="application" />
20
+ <orderEntry type="library" scope="PROVIDED" name="bridgetown-builder (v1.3.4, asdf: 3.3.3) [gem]" level="application" />
21
+ <orderEntry type="library" scope="PROVIDED" name="bridgetown-core (v1.3.4, asdf: 3.3.3) [gem]" level="application" />
22
+ <orderEntry type="library" scope="PROVIDED" name="bridgetown-paginate (v1.3.4, asdf: 3.3.3) [gem]" level="application" />
23
+ <orderEntry type="library" scope="PROVIDED" name="builder (v3.3.0, asdf: 3.3.3) [gem]" level="application" />
24
+ <orderEntry type="library" scope="PROVIDED" name="bundler (v2.7.1, asdf: 3.3.3) [gem]" level="application" />
25
+ <orderEntry type="library" scope="PROVIDED" name="colorator (v1.1.0, asdf: 3.3.3) [gem]" level="application" />
26
+ <orderEntry type="library" scope="PROVIDED" name="concurrent-ruby (v1.3.5, asdf: 3.3.3) [gem]" level="application" />
27
+ <orderEntry type="library" scope="PROVIDED" name="connection_pool (v2.5.3, asdf: 3.3.3) [gem]" level="application" />
28
+ <orderEntry type="library" scope="PROVIDED" name="csv (v3.3.5, asdf: 3.3.3) [gem]" level="application" />
29
+ <orderEntry type="library" scope="PROVIDED" name="drb (v2.2.3, asdf: 3.3.3) [gem]" level="application" />
30
+ <orderEntry type="library" scope="PROVIDED" name="erubi (v1.13.1, asdf: 3.3.3) [gem]" level="application" />
31
+ <orderEntry type="library" scope="PROVIDED" name="faraday (v2.13.4, asdf: 3.3.3) [gem]" level="application" />
32
+ <orderEntry type="library" scope="PROVIDED" name="faraday-follow_redirects (v0.3.0, asdf: 3.3.3) [gem]" level="application" />
33
+ <orderEntry type="library" scope="PROVIDED" name="faraday-net_http (v3.4.1, asdf: 3.3.3) [gem]" level="application" />
34
+ <orderEntry type="library" scope="PROVIDED" name="ffi (v1.17.2, asdf: 3.3.3) [gem]" level="application" />
35
+ <orderEntry type="library" scope="PROVIDED" name="hash_with_dot_access (v1.2.0, asdf: 3.3.3) [gem]" level="application" />
36
+ <orderEntry type="library" scope="PROVIDED" name="i18n (v1.14.7, asdf: 3.3.3) [gem]" level="application" />
37
+ <orderEntry type="library" scope="PROVIDED" name="json (v2.13.2, asdf: 3.3.3) [gem]" level="application" />
38
+ <orderEntry type="library" scope="PROVIDED" name="kramdown (v2.5.1, asdf: 3.3.3) [gem]" level="application" />
39
+ <orderEntry type="library" scope="PROVIDED" name="kramdown-parser-gfm (v1.1.0, asdf: 3.3.3) [gem]" level="application" />
40
+ <orderEntry type="library" scope="PROVIDED" name="language_server-protocol (v3.17.0.5, asdf: 3.3.3) [gem]" level="application" />
41
+ <orderEntry type="library" scope="PROVIDED" name="lint_roller (v1.1.0, asdf: 3.3.3) [gem]" level="application" />
42
+ <orderEntry type="library" scope="PROVIDED" name="liquid (v5.4.0, asdf: 3.3.3) [gem]" level="application" />
43
+ <orderEntry type="library" scope="PROVIDED" name="listen (v3.9.0, asdf: 3.3.3) [gem]" level="application" />
44
+ <orderEntry type="library" scope="PROVIDED" name="logger (v1.7.0, asdf: 3.3.3) [gem]" level="application" />
45
+ <orderEntry type="library" scope="PROVIDED" name="minitest (v5.25.5, asdf: 3.3.3) [gem]" level="application" />
46
+ <orderEntry type="library" scope="PROVIDED" name="minitest-profile (v0.0.2, asdf: 3.3.3) [gem]" level="application" />
47
+ <orderEntry type="library" scope="PROVIDED" name="minitest-reporters (v1.7.1, asdf: 3.3.3) [gem]" level="application" />
48
+ <orderEntry type="library" scope="PROVIDED" name="net-http (v0.6.0, asdf: 3.3.3) [gem]" level="application" />
49
+ <orderEntry type="library" scope="PROVIDED" name="parallel (v1.27.0, asdf: 3.3.3) [gem]" level="application" />
50
+ <orderEntry type="library" scope="PROVIDED" name="parser (v3.3.9.0, asdf: 3.3.3) [gem]" level="application" />
51
+ <orderEntry type="library" scope="PROVIDED" name="prism (v1.4.0, asdf: 3.3.3) [gem]" level="application" />
52
+ <orderEntry type="library" scope="PROVIDED" name="public_suffix (v6.0.2, asdf: 3.3.3) [gem]" level="application" />
53
+ <orderEntry type="library" scope="PROVIDED" name="racc (v1.8.1, asdf: 3.3.3) [gem]" level="application" />
54
+ <orderEntry type="library" scope="PROVIDED" name="rack (v3.2.0, asdf: 3.3.3) [gem]" level="application" />
55
+ <orderEntry type="library" scope="PROVIDED" name="rainbow (v3.1.1, asdf: 3.3.3) [gem]" level="application" />
56
+ <orderEntry type="library" scope="PROVIDED" name="rake (v13.3.0, asdf: 3.3.3) [gem]" level="application" />
57
+ <orderEntry type="library" scope="PROVIDED" name="rb-fsevent (v0.11.2, asdf: 3.3.3) [gem]" level="application" />
58
+ <orderEntry type="library" scope="PROVIDED" name="rb-inotify (v0.11.1, asdf: 3.3.3) [gem]" level="application" />
59
+ <orderEntry type="library" scope="PROVIDED" name="regexp_parser (v2.11.2, asdf: 3.3.3) [gem]" level="application" />
60
+ <orderEntry type="library" scope="PROVIDED" name="rexml (v3.4.2, asdf: 3.3.3) [gem]" level="application" />
61
+ <orderEntry type="library" scope="PROVIDED" name="roda (v3.95.0, asdf: 3.3.3) [gem]" level="application" />
62
+ <orderEntry type="library" scope="PROVIDED" name="rouge (v4.6.0, asdf: 3.3.3) [gem]" level="application" />
63
+ <orderEntry type="library" scope="PROVIDED" name="rubocop (v1.80.0, asdf: 3.3.3) [gem]" level="application" />
64
+ <orderEntry type="library" scope="PROVIDED" name="rubocop-ast (v1.46.0, asdf: 3.3.3) [gem]" level="application" />
65
+ <orderEntry type="library" scope="PROVIDED" name="rubocop-bridgetown (v0.6.1, asdf: 3.3.3) [gem]" level="application" />
66
+ <orderEntry type="library" scope="PROVIDED" name="rubocop-performance (v1.25.0, asdf: 3.3.3) [gem]" level="application" />
67
+ <orderEntry type="library" scope="PROVIDED" name="ruby-progressbar (v1.13.0, asdf: 3.3.3) [gem]" level="application" />
68
+ <orderEntry type="library" scope="PROVIDED" name="securerandom (v0.4.1, asdf: 3.3.3) [gem]" level="application" />
69
+ <orderEntry type="library" scope="PROVIDED" name="serbea (v1.0.1, asdf: 3.3.3) [gem]" level="application" />
70
+ <orderEntry type="library" scope="PROVIDED" name="thor (v1.4.0, asdf: 3.3.3) [gem]" level="application" />
71
+ <orderEntry type="library" scope="PROVIDED" name="tilt (v2.6.1, asdf: 3.3.3) [gem]" level="application" />
72
+ <orderEntry type="library" scope="PROVIDED" name="tzinfo (v2.0.6, asdf: 3.3.3) [gem]" level="application" />
73
+ <orderEntry type="library" scope="PROVIDED" name="unicode-display_width (v3.1.5, asdf: 3.3.3) [gem]" level="application" />
74
+ <orderEntry type="library" scope="PROVIDED" name="unicode-emoji (v4.0.4, asdf: 3.3.3) [gem]" level="application" />
75
+ <orderEntry type="library" scope="PROVIDED" name="uri (v1.0.3, asdf: 3.3.3) [gem]" level="application" />
76
+ <orderEntry type="library" scope="PROVIDED" name="zeitwerk (v2.7.3, asdf: 3.3.3) [gem]" level="application" />
77
+ </component>
78
+ <component name="RakeTasksCache-v2">
79
+ <option name="myRootTask">
80
+ <RakeTaskImpl id="rake">
81
+ <subtasks>
82
+ <RakeTaskImpl description="Build bridgetown_writebook-0.1.0.gem into the pkg directory" fullCommand="build" id="build" />
83
+ <RakeTaskImpl id="build">
84
+ <subtasks>
85
+ <RakeTaskImpl description="Generate SHA512 checksum of bridgetown_writebook-0.1.0.gem into the checksums directory" fullCommand="build:checksum" id="checksum" />
86
+ </subtasks>
87
+ </RakeTaskImpl>
88
+ <RakeTaskImpl description="Remove any temporary products" fullCommand="clean" id="clean" />
89
+ <RakeTaskImpl description="Remove any generated files" fullCommand="clobber" id="clobber" />
90
+ <RakeTaskImpl description="Build and install bridgetown_writebook-0.1.0.gem into system gems" fullCommand="install" id="install" />
91
+ <RakeTaskImpl id="install">
92
+ <subtasks>
93
+ <RakeTaskImpl description="Build and install bridgetown_writebook-0.1.0.gem into system gems without network access" fullCommand="install:local" id="local" />
94
+ </subtasks>
95
+ </RakeTaskImpl>
96
+ <RakeTaskImpl description="Create tag v0.1.0 and build and push bridgetown_writebook-0.1.0.gem to rubygems.org" fullCommand="release[remote]" id="release[remote]" />
97
+ <RakeTaskImpl description="Run tests" fullCommand="test" id="test" />
98
+ <RakeTaskImpl description="" fullCommand="default" id="default" />
99
+ <RakeTaskImpl description="" fullCommand="release" id="release" />
100
+ <RakeTaskImpl id="release">
101
+ <subtasks>
102
+ <RakeTaskImpl description="" fullCommand="release:guard_clean" id="guard_clean" />
103
+ <RakeTaskImpl description="" fullCommand="release:rubygem_push" id="rubygem_push" />
104
+ <RakeTaskImpl description="" fullCommand="release:source_control_push" id="source_control_push" />
105
+ </subtasks>
106
+ </RakeTaskImpl>
107
+ </subtasks>
108
+ </RakeTaskImpl>
109
+ </option>
110
+ </component>
111
+ </module>
data/.idea/modules.xml ADDED
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/bridgetown_writebook.iml" filepath="$PROJECT_DIR$/.idea/bridgetown_writebook.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
data/.idea/vcs.xml ADDED
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="" vcs="Git" />
5
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
6
+ </component>
7
+ </project>
@@ -50,8 +50,27 @@
50
50
  #
51
51
  # Read the Automations documentation: https://www.bridgetownrb.com/docs/automations
52
52
 
53
- append_to_file "config/boot.rb" do
53
+ if File.exist?("config/boot.rb")
54
+ append_to_file "config/boot.rb" do
55
+ <<~RUBY
56
+
57
+ require "bridgetown_writebook/commands"
58
+ RUBY
59
+ end
60
+ else
61
+ create_file "config/boot.rb" do
62
+ <<~RUBY
63
+ # frozen_string_literal: true
64
+
65
+ require "bridgetown_writebook/commands"
66
+ RUBY
67
+ end
68
+ end
69
+
70
+ create_file "config/boot.rb" do
54
71
  <<~RUBY
72
+ # frozen_string_literal: true
55
73
 
56
- RUBY
74
+ require "bridgetown_writebook/commands"
75
+ RUBY
57
76
  end
@@ -6,6 +6,10 @@ module BridgetownWritebook
6
6
  liquid_tag "bridgetown_writebook" do
7
7
  "This plugin works!"
8
8
  end
9
+
10
+ liquid_tag "what" do
11
+ "is going on"
12
+ end
9
13
  end
10
14
  end
11
15
  end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_all "bridgetown-core/commands/concerns"
4
+ require_relative "chapter"
5
+
6
+ module BridgetownWritebook
7
+ module Commands
8
+ class Book < Thor
9
+ desc "setup", "Setup folders and files for books"
10
+ def setup
11
+ create_books_folder
12
+ add_books_collection_to_config
13
+ end
14
+
15
+ desc "new", "Create a new book"
16
+ option :title, type: :string, required: true, desc: "Title of the book"
17
+ def new
18
+ title = options[:title]
19
+ folder_path = File.join("src", "_books", title.parameterize)
20
+
21
+ if Dir.exist?(folder_path)
22
+ Bridgetown.logger.info "Folder already exists: #{folder_path}"
23
+ else
24
+ FileUtils.mkdir_p(folder_path)
25
+ Bridgetown.logger.info "Folder created: #{folder_path}"
26
+ end
27
+
28
+ file_path = File.join(folder_path, "00-meta.md")
29
+ content = <<~MARKDOWN
30
+ ---
31
+ title: #{text title}
32
+ subtitle:
33
+ authors: [ ]
34
+ ---
35
+ MARKDOWN
36
+
37
+ File.write(file_path, content)
38
+ Bridgetown.logger.info "Creating a new book with title: #{title}"
39
+ end
40
+
41
+ # Register Chapters as a nested subcommand
42
+ desc "chapters <command>", "Manage chapters of a book"
43
+ subcommand "chapters", Chapter
44
+
45
+ private
46
+
47
+ def create_books_folder
48
+ folder_path = File.join("src", "_books")
49
+
50
+ if Dir.exist?(folder_path)
51
+ Bridgetown.logger.info "Folder already exists: #{folder_path}"
52
+ else
53
+ FileUtils.mkdir_p(folder_path)
54
+ Bridgetown.logger.info "Folder created: #{folder_path}"
55
+ end
56
+ end
57
+
58
+ def add_books_collection_to_config
59
+ config_file = "bridgetown.config.yml"
60
+ unless File.exist?(config_file)
61
+ Bridgetown.logger.info "Config file not found: #{config_file}"
62
+ return
63
+ end
64
+
65
+ content = File.read(config_file)
66
+ if content.include?("books:")
67
+ Bridgetown.logger.info "'books' collection already exists, skipping..."
68
+ return
69
+ end
70
+
71
+ config = YAML.load_file(config_file) || {}
72
+ config["collections"] ||= {}
73
+ config["collections"]["books"] = {
74
+ "output" => true,
75
+ "permalink" => "/books/:path/",
76
+ }
77
+
78
+ File.write(config_file, config.to_yaml)
79
+ Bridgetown.logger.info "'books' collection added/updated in #{config_file}"
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BridgetownWritebook
4
+ module Commands
5
+ class Chapter < Thor
6
+ desc "add", "Add a new chapter to a book"
7
+ option :book, type: :string, required: true, desc: "Title of the book"
8
+ option :title, type: :string, required: true, desc: "Title of the chapter"
9
+ def add
10
+ book_title = options[:book]
11
+ chapter_title = options[:title]
12
+ @folder_path = File.join("src", "_books", book_title.parameterize)
13
+
14
+ unless Dir.exist?(@folder_path)
15
+ Bridgetown.logger.info "Book not found: #{book_title}"
16
+ return
17
+ end
18
+
19
+ chapter_file = File.join(@folder_path, "#{new_chapter_number}-#{chapter_title.parameterize}.md")
20
+
21
+ content = <<~MARKDOWN
22
+ ---
23
+ title: #{text chapter_title}
24
+ ---
25
+ MARKDOWN
26
+
27
+ File.write(chapter_file, content)
28
+ Bridgetown.logger.info "Chapter created: #{chapter_file}"
29
+ end
30
+
31
+ private
32
+
33
+ def new_chapter_number
34
+ existing_chapters = Dir.children(@folder_path)
35
+ .grep(%r{^\d{2}-.*\.md$})
36
+ .sort
37
+ last_number = if existing_chapters.empty?
38
+ 0
39
+ else
40
+ existing_chapters.last.split("-").first.to_i
41
+ end
42
+
43
+ format("%02d", last_number + 1)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_all "bridgetown-core/commands/concerns"
4
+ require_relative "commands/book"
5
+
6
+ module BridgetownWritebook
7
+ class Commands
8
+ include Bridgetown::Commands::ConfigurationOverridable
9
+
10
+ Bridgetown::Commands::Registrations.register do
11
+ desc "book <command>", "Take me to the book"
12
+ subcommand "book", Book
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BridgetownWritebook
4
+ module Models
5
+ class Book
6
+ attr_accessor :name, :subtitle, :resource, :meta, :chapters
7
+
8
+ delegate :id, to: :resource
9
+ alias_method :title, :name
10
+
11
+ def initialize(book, chapters:, meta:)
12
+ @resource = book
13
+ @meta = meta
14
+ @chapters = []
15
+
16
+ chapters.each do |chapter|
17
+ @chapters << Chapter.new(chapter, booxk: self)
18
+ end
19
+
20
+ extract_metadata
21
+ end
22
+
23
+ #TODO: support other formats as well.
24
+ def cover
25
+ "/#{resource.path.split(".").first}/cover.png"
26
+ end
27
+
28
+ def authors?
29
+ @authors.present?
30
+ end
31
+
32
+ def authors
33
+ "by #{@authors.join(", ")}" if authors?
34
+ end
35
+
36
+ def extract_metadata
37
+ @name = @meta&.data&.title || slug.titleize
38
+ @subtitle = @meta&.data&.subtitle
39
+ @authors = @meta&.data&.authors
40
+ end
41
+
42
+ def slug
43
+ id.split("/").last.split(".md").first
44
+ end
45
+
46
+ def link
47
+ resource.relative_url
48
+ end
49
+
50
+ def chapter_ids
51
+ chapters.map(&:id)
52
+ end
53
+
54
+ def generate
55
+ resource.data.layout = :book
56
+ resource.data.title = title
57
+ resource.data.cover = cover
58
+ resource.data.subtitle = subtitle
59
+ resource.data.authors = authors
60
+ resource.content = content
61
+
62
+ chapters.each(&:generate)
63
+ end
64
+
65
+ def content
66
+ <<~HTML
67
+ <ul class="pl-0" data-controller="bookmark" data-bookmark-chapter-outlet='.chapter' data-bookmark-book-value="#{text id}">
68
+ #{html chapters.map do |chapter|
69
+ li chapter
70
+ end.join }
71
+ </ul>
72
+ HTML
73
+ end
74
+
75
+ # TODO: may be convert these into compenents or partials.
76
+ # TODO: Move them to the template, add it to the metadata and move it to the template.
77
+ def li(chapter)
78
+ <<~HTML
79
+ <li class='chapter flex justify-between items-end gap-4'
80
+ data-controller='chapter'
81
+ data-chapter-id-value='#{text chapter.id}'
82
+ data-chapter-ellipsis-class="text-orange-500"
83
+ >
84
+ <a href='#{text chapter.link}' class="text-nowrap">#{text chapter.title}</a>
85
+ <span class="grow overflow-hidden border-b border-dotted border-black mb-1.5" data-chapter-target="ellipsis"></span>
86
+ <span class="text-nowrap">#{text chapter.word_count}</span>
87
+ </li>
88
+ HTML
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BridgetownWritebook
4
+ module Models
5
+ class Chapter
6
+ attr_accessor :name, :slug, :resource, :book
7
+
8
+ delegate :id, :data, to: :resource
9
+
10
+ def initialize(chapter, book:)
11
+ @resource = chapter
12
+ @book = book
13
+
14
+ # Populate the word count before adding the stimulus controller
15
+ calculate_word_count
16
+ end
17
+
18
+ def calculate_word_count
19
+ words_array = resource.content.split - %w[#]
20
+ @word_count = words_array.size
21
+ end
22
+
23
+ def delimited_word_count
24
+ @word_count.to_fs(:delimited)
25
+ end
26
+
27
+ def word_count
28
+ return "#{delimited_word_count} words" if @word_count > 1
29
+
30
+ "#{delimited_word_count} word"
31
+ end
32
+
33
+ def link
34
+ resource.relative_url
35
+ end
36
+
37
+ def title
38
+ data.title
39
+ end
40
+
41
+ def next_chapter
42
+ book.chapters[book.chapters.index(self) + 1]
43
+ end
44
+
45
+ def generate
46
+ resource.data.layout = "chapter"
47
+ resource.data.book_title = book.name
48
+ resource.data.book_link = book.link
49
+ resource.data.next_chapter_title = next_chapter&.title
50
+ resource.data.next_chapter_link = next_chapter&.link
51
+ resource.data.word_count = word_count
52
+ resource.content = <<~HTML
53
+ #{html resource.content}
54
+ <div data-controller="reading"
55
+ data-reading-id-value="#{text id}"
56
+ data-reading-book-value="#{text book.id}">
57
+ </div>
58
+ HTML
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,63 @@
1
+ require 'active_support/core_ext/numeric/conversions'
2
+
3
+ # frozen_string_literal: true
4
+ class Builders::Books < SiteBuilder
5
+ def initialize(name = nil, current_site = nil)
6
+ super
7
+ @books = []
8
+ end
9
+
10
+ def build
11
+ generator do
12
+ create_book_objects
13
+ generate_books
14
+ generate_index_page_for_books
15
+ end
16
+ end
17
+
18
+ def generate_index_page_for_books
19
+ books = @books
20
+ book_covers = books.map { |book| cover_for(book) }.join
21
+ add_resource nil, "books.md" do
22
+ layout "default"
23
+ permalink "/books/"
24
+ content <<-HTML
25
+ <ul class="list-none flex justify-center sm:grid sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-y-6 py-10 px-0 flex-wrap">
26
+ #{book_covers}
27
+ </ul>
28
+ HTML
29
+ end
30
+ end
31
+
32
+ def cover_for(book)
33
+ chapters_json = book.chapter_ids.to_json.gsub('"', '&quot;')
34
+
35
+ <<-HTML
36
+ <li data-controller="book" data-book-id-value="#{book.id}" data-book-chapters-value="#{chapters_json}" >
37
+ <a class="flex flex-col gap-2 max-w-[236px]" href="#{book.link}">
38
+ <div class="max-h-[378px] border rounded relative box-border" data-book-target="cover">
39
+ <img src="#{book.cover}" class="max-h-[378px] max-w-[236px] rounded">
40
+ </div>
41
+ <div class="text-center">#{book.name}</div>
42
+ <div class="text-sm text-center">#{book.authors}</div>
43
+ </a>
44
+ </li>
45
+ HTML
46
+ end
47
+
48
+ def create_book_objects
49
+ site.collections.books.resources
50
+ .group_by { |b| b.id.split("_books/").last.split("/").first }
51
+ .each do |book_id, chapters|
52
+ meta_file = chapters.find { |c| c.relative_path.to_s.end_with?('00-meta.md') }
53
+ regular_chapters = chapters.reject { |c| c.relative_path.to_s.end_with?('00-meta.md') }
54
+
55
+ resource = add_resource(:book, "books/#{book_id}.md") { permalink "/books/:slug/" }
56
+ @books << Book.new(resource, chapters: regular_chapters, meta: meta_file)
57
+ end
58
+ end
59
+
60
+ def generate_books
61
+ @books.each(&:generate)
62
+ end
63
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BridgetownWritebook
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.0.2"
5
5
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "bridgetown"
4
4
  require "bridgetown_writebook/builder"
5
+ require_relative "bridgetown_writebook/commands"
5
6
 
6
7
  # @param config [Bridgetown::Configuration::ConfigurationDSL]
7
8
  Bridgetown.initializer :bridgetown_writebook do |config|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bridgetown_writebook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bridgetown Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-08-26 00:00:00.000000000 Z
11
+ date: 2025-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bridgetown
@@ -80,6 +80,10 @@ extra_rdoc_files: []
80
80
  files:
81
81
  - ".github/workflows/tests.yml"
82
82
  - ".gitignore"
83
+ - ".idea/.gitignore"
84
+ - ".idea/bridgetown_writebook.iml"
85
+ - ".idea/modules.xml"
86
+ - ".idea/vcs.xml"
83
87
  - ".rubocop.yml"
84
88
  - CHANGELOG.md
85
89
  - Gemfile
@@ -95,6 +99,12 @@ files:
95
99
  - layouts/bridgetown_writebook/layout.html
96
100
  - lib/bridgetown_writebook.rb
97
101
  - lib/bridgetown_writebook/builder.rb
102
+ - lib/bridgetown_writebook/commands.rb
103
+ - lib/bridgetown_writebook/commands/book.rb
104
+ - lib/bridgetown_writebook/commands/chapter.rb
105
+ - lib/bridgetown_writebook/models/book.rb
106
+ - lib/bridgetown_writebook/models/chapter.rb
107
+ - lib/bridgetown_writebook/models/something.rb
98
108
  - lib/bridgetown_writebook/version.rb
99
109
  - package.json
100
110
  homepage: https://github.com/username/bridgetown_writebook