From b93fa328916025ecf0965cfea80e9c3f3cf93d34 Mon Sep 17 00:00:00 2001 From: Jared White Date: Tue, 21 Apr 2020 02:20:48 -0700 Subject: [PATCH 1/3] Add new PrototypeGenerator --- .../lib/bridgetown-core/drops/url_drop.rb | 2 +- .../generators/prototype_generator.rb | 110 ++++++++++++++++++ bridgetown-core/test/test_excerpt.rb | 2 +- bridgetown-core/test/test_filters.rb | 4 +- bridgetown-core/test/test_generated_site.rb | 2 +- .../src/authors/{jared.html => author.html} | 29 +++-- .../src/categories/category.html | 20 ++++ 7 files changed, 149 insertions(+), 20 deletions(-) create mode 100644 bridgetown-core/lib/bridgetown-core/generators/prototype_generator.rb rename bridgetown-website/src/authors/{jared.html => author.html} (56%) create mode 100644 bridgetown-website/src/categories/category.html diff --git a/bridgetown-core/lib/bridgetown-core/drops/url_drop.rb b/bridgetown-core/lib/bridgetown-core/drops/url_drop.rb index d2898312d..ca58fc2ea 100644 --- a/bridgetown-core/lib/bridgetown-core/drops/url_drop.rb +++ b/bridgetown-core/lib/bridgetown-core/drops/url_drop.rb @@ -30,7 +30,7 @@ def slug def categories category_set = Set.new Array(@obj.data["categories"]).each do |category| - category_set << category.to_s.downcase + category_set << Utils.slugify(category.to_s) end category_set.to_a.join("/") end diff --git a/bridgetown-core/lib/bridgetown-core/generators/prototype_generator.rb b/bridgetown-core/lib/bridgetown-core/generators/prototype_generator.rb new file mode 100644 index 000000000..5c3e532be --- /dev/null +++ b/bridgetown-core/lib/bridgetown-core/generators/prototype_generator.rb @@ -0,0 +1,110 @@ +# frozen_string_literal: true + +module Bridgetown + class PrototypeGenerator < Generator + priority :low + + def generate(site) + @site = site + + # TODO: make this configurable + @configured_collection = "posts" + + prototype_pages = site.pages.select do |page| + page.data["prototype"].is_a?(Hash) + end + + if prototype_pages.length.positive? + site.pages.reject! do |page| + prototype_pages.include? page + end + + prototype_pages.each do |prototype_page| + search_term = prototype_page.data["prototype"]["term"] + next unless search_term.is_a?(String) + + terms_matching_pages(search_term).each do |term| + generate_new_page_from_prototype(prototype_page, search_term, term) + end + end + end + end + + def generate_new_page_from_prototype(prototype_page, search_term, term) + new_page = PrototypePage.new(prototype_page) + new_page.data[search_term] = term + + process_title_data_placeholder(new_page, prototype_page, search_term, term) + process_title_simple_placeholders(new_page, prototype_page, term) + + new_page.data["pagination"] = {} unless new_page.data["pagination"].is_a?(Hash) + new_page.data["pagination"]["enabled"] = true + new_page.data["pagination"]["where_query"] = [search_term, term] + new_page.slugify_term(term) + @site.pages << new_page + end + + def terms_matching_pages(search_term) + @site.documents.map do |document| + next unless document.respond_to?(:collection) + + document.data[search_term] if document.collection.label == @configured_collection + end.compact.uniq + end + + def process_title_data_placeholder(new_page, prototype_page, search_term, term) + if prototype_page["prototype"]["data"] + if new_page.data["title"]&.include?(":prototype-data-label") + related_data = @site.data[prototype_page["prototype"]["data"]].dig(term) + if related_data + new_page.data["#{search_term}_data"] = related_data + data_label = related_data[prototype_page["prototype"]["data_label"]] + new_page.data["title"] = new_page.data["title"].gsub( + ":prototype-data-label", data_label + ) + end + end + end + end + + def process_title_simple_placeholders(new_page, _prototype_page, term) + if new_page.data["title"]&.include?(":prototype-term-titleize") + new_page.data["title"] = new_page.data["title"].gsub( + ":prototype-term-titleize", Bridgetown::Utils.titleize_slug(term) + ) + end + + if new_page.data["title"]&.include?(":prototype-term") + new_page.data["title"] = new_page.data["title"].gsub( + ":prototype-term", term + ) + end + end + end + + class PrototypePage < Page + def initialize(prototype_page) + @site = prototype_page.site + @url = "" + @name = "index.html" + @path = prototype_page.path + + process(@name) + + self.data = Bridgetown::Utils.deep_merge_hashes prototype_page.data, {} + self.content = prototype_page.content + + # Perform some validation that is also performed in Bridgetown::Page + validate_data! prototype_page.path + validate_permalink! prototype_page.path + + @dir = Pathname.new(prototype_page.relative_path).dirname.to_s + @path = site.in_source_dir(@dir, @name) + end + + def slugify_term(term) + term_slug = Bridgetown::Utils.slugify(term) + @url = "/#{@dir}/#{term_slug}/" + end + end +end diff --git a/bridgetown-core/test/test_excerpt.rb b/bridgetown-core/test/test_excerpt.rb index 6609609a8..3ad208edb 100644 --- a/bridgetown-core/test/test_excerpt.rb +++ b/bridgetown-core/test/test_excerpt.rb @@ -98,7 +98,7 @@ def do_render(document) context "#to_liquid" do should "contain the proper page data to mimic the post liquid" do assert_equal "Post Excerpt with Layout", @excerpt.to_liquid["title"] - url = "/bar/baz/z_category/mixedcase/2013/07/22/post-excerpt-with-layout.html" + url = "/bar/baz/z-category/mixedcase/2013/07/22/post-excerpt-with-layout.html" assert_equal url, @excerpt.to_liquid["url"] assert_equal Time.parse("2013-07-22"), @excerpt.to_liquid["date"] assert_equal %w(bar baz z_category MixedCase), @excerpt.to_liquid["categories"] diff --git a/bridgetown-core/test/test_filters.rb b/bridgetown-core/test/test_filters.rb index e51a6abae..916c0625a 100644 --- a/bridgetown-core/test/test_filters.rb +++ b/bridgetown-core/test/test_filters.rb @@ -645,8 +645,8 @@ def select; end "previous" => nil, "output" => nil, "content" => "This should be published.\n", - "id" => "/publish_test/2008/02/02/published", - "url" => "/publish_test/2008/02/02/published.html", + "id" => "/publish-test/2008/02/02/published", + "url" => "/publish-test/2008/02/02/published.html", "relative_path" => "_posts/2008-02-02-published.markdown", "collection" => "posts", "excerpt" => "

This should be published.

\n", diff --git a/bridgetown-core/test/test_generated_site.rb b/bridgetown-core/test/test_generated_site.rb index 6bc4a072b..714297e24 100644 --- a/bridgetown-core/test/test_generated_site.rb +++ b/bridgetown-core/test/test_generated_site.rb @@ -32,7 +32,7 @@ class TestGeneratedSite < BridgetownUnitTest end should "hide unpublished posts" do - published = Dir[dest_dir("publish_test/2008/02/02/*.html")].map \ + published = Dir[dest_dir("publish-test/2008/02/02/*.html")].map \ { |f| File.basename(f) } assert_equal 1, published.size assert_equal "published.html", published.first diff --git a/bridgetown-website/src/authors/jared.html b/bridgetown-website/src/authors/author.html similarity index 56% rename from bridgetown-website/src/authors/jared.html rename to bridgetown-website/src/authors/author.html index 8e65a3c94..c89f75ef5 100644 --- a/bridgetown-website/src/authors/jared.html +++ b/bridgetown-website/src/authors/author.html @@ -1,27 +1,26 @@ --- layout: default -title: Articles by Jared -author: jared -pagination: - enabled: true - where_query: - - author - - jared +title: Articles by :prototype-data-label +prototype: + term: author + data: authors + data_label: name --- -{% assign author = site.data.authors[page.author] %} +{% assign author = page.author_data %}
-

{{ page.title }}

+

Articles by + {{ author.name | split: " " | first }}

- Connect with - {{ author.name }} - on the - Web - or - Twitter + Connect with + {{ author.name }} + on the + Web + or + Twitter

{% for post in paginator.documents %} diff --git a/bridgetown-website/src/categories/category.html b/bridgetown-website/src/categories/category.html new file mode 100644 index 000000000..46676fcc9 --- /dev/null +++ b/bridgetown-website/src/categories/category.html @@ -0,0 +1,20 @@ +--- +layout: default +title: "Browse Category: :prototype-term-titleize" +prototype: + term: category +--- + +
+
+
+

{{ page.title }}

+ + {% for post in paginator.documents %} + {% include news_item.html %} + {% endfor %} + + {% render "shared/pagination", paginator: paginator %} +
+
+
From e4e05cf064f5f8b3cb494aaa7a0c7c68d4abf674 Mon Sep 17 00:00:00 2001 From: Jared White Date: Tue, 21 Apr 2020 11:05:02 -0700 Subject: [PATCH 2/3] Enhance prototype pages for categories and tags And add a bunch of feature tests --- bridgetown-core/features/pagination.feature | 24 ++++++ .../features/prototype_pages.feature | 84 +++++++++++++++++++ .../features/site_configuration.feature | 14 ++++ bridgetown-core/features/step_definitions.rb | 56 +++++-------- .../lib/bridgetown-core/configuration.rb | 1 + .../lib/bridgetown-core/drops/url_drop.rb | 6 +- .../generators/prototype_generator.rb | 26 ++++-- .../bridgetown-paginate/pagination_indexer.rb | 2 +- 8 files changed, 171 insertions(+), 42 deletions(-) create mode 100644 bridgetown-core/features/prototype_pages.feature diff --git a/bridgetown-core/features/pagination.feature b/bridgetown-core/features/pagination.feature index 1828829f9..b9e7e1683 100644 --- a/bridgetown-core/features/pagination.feature +++ b/bridgetown-core/features/pagination.feature @@ -54,6 +54,30 @@ Feature: Site pagination | 3 | 1 | 6 | | 4 | 1 | 7 | + Scenario Outline: Paginate posts with tags + Given I have a configuration file with: + | key | value | + | pagination | { enabled: true, per_page: } | + And I have a _layouts directory + And I have an "index.html" page with pagination "{enabled: true, tag: scary}" that contains "{{ paginator.documents.size }} {{ paginator.documents[0].title }}" + And I have a _posts directory + And I have the following posts: + | title | date | layout | tags | content | + | Wargames | 2009-03-27 | default | strange difficult | The only winning move is not to play. | + | Wargames2 | 2009-04-27 | default | strange, scary | The only winning move is not to play2. | + | Wargames3 | 2009-05-27 | default | ["awful news", "scary"] | The only winning move is not to play3. | + | Wargames4 | 2009-06-27 | default | terrible; scary | The only winning move is not to play4. | + When I run bridgetown build + Then the output/page/ directory should exist + And the "output/page//index.html" file should exist + And I should see "" in "output/page//index.html" + And the "output/page//index.html" file should not exist + + Examples: + | num | exist | posts | not_exist | title | + | 1 | 3 | 1 | 4 | Wargames2 | + | 2 | 2 | 2 | 3 | Wargames3 | + # TODO: this isn't working currently…wondering if it "ever" worked Scenario Outline: Setting a custom pagination path with numbered html pages Given this scenario should be skipped diff --git a/bridgetown-core/features/prototype_pages.feature b/bridgetown-core/features/prototype_pages.feature new file mode 100644 index 000000000..9159683bc --- /dev/null +++ b/bridgetown-core/features/prototype_pages.feature @@ -0,0 +1,84 @@ +Feature: Prototype Pages + In order to auto-generate category, tag, etc. archives + As a blog's user + I want create a prototype page and then divide matching posts in several pages + + Scenario Outline: Generate category pages and paginate + Given I have a configuration file with: + | key | value | + | pagination | { enabled: true, per_page: } | + And I have a _layouts directory + And I have a categories directory + And I have an "categories/category.html" page with prototype "{term: category}" that contains "{{ paginator.documents.size }} {{ paginator.documents[0].title }}" + And I have a _posts directory + And I have the following posts: + | title | date | category | content | + | Wargames | 2009-03-27 | This Means War | The only winning move is not to play. | + | Wargames2 | 2009-04-27 | This Means War | The only winning move is not to play2. | + | Wargames3 | 2009-05-27 | This Means War | The only winning move is not to play3. | + | Wargames4 | 2009-06-27 | This Means War | The only winning move is not to play4. | + | Peace5 | 2009-07-27 | This Means Peace | Peace in our time. | + When I run bridgetown build + Then the output/categories/this-means-war/page/ directory should exist + And the "output/categories/this-means-war/page//index.html" file should exist + And I should see "" in "output/categories/this-means-war/page//index.html" + And the "output/categories/this-means-war/page//index.html" file should not exist + And the "output/categories/this-means-peace/index.html" file should exist + And the output/categories/this-means-peace/page/2 directory should not exist + + Examples: + | num | exist | posts | not_exist | title | + | 1 | 4 | 1 | 5 | Wargames | + | 2 | 2 | 2 | 3 | Wargames2 | + | 3 | 2 | 1 | 3 | Wargames3 | + + Scenario Outline: Generate tag pages and paginate + Given I have a configuration file with: + | key | value | + | pagination | { enabled: true, per_page: } | + And I have a _layouts directory + And I have a tags directory + And I have an "tags/tag.html" page with prototype "{term: tag}" that contains "{{ paginator.documents.size }} {{ paginator.documents[0].title }}" + And I have a _posts directory + And I have the following posts: + | title | date | tags | content | + | Wargames | 2009-03-27 | strange difficult | The only winning move is not to play. | + | Wargames2 | 2009-04-27 | strange, scary | The only winning move is not to play2. | + | Wargames3 | 2009-05-27 | ["awful news", "scary"] | The only winning move is not to play3. | + | Wargames4 | 2009-06-27 | terrible scary | The only winning move is not to play4. | + When I run bridgetown build + Then the output/tags/scary/page/ directory should exist + And the "output/tags/scary/page//index.html" file should exist + And I should see "" in "output/tags/scary/page//index.html" + And the "output/tags/scary/page//index.html" file should not exist + And the "output/tags/awful-news/index.html" file should exist + + Examples: + | num | exist | posts | not_exist | title | + | 1 | 3 | 1 | 4 | Wargames2 | + | 2 | 2 | 2 | 3 | Wargames3 | + + Scenario Outline: Generate author pages and paginate + Given I have a configuration file with: + | key | value | + | pagination | { enabled: true, per_page: } | + And I have a _layouts directory + And I have a authors directory + And I have an "authors/author.html" page with prototype "{term: author}" that contains "{{ paginator.documents.size }} {{ paginator.documents[0].title }}" + And I have a _posts directory + And I have the following posts: + | title | date | author | content | + | Wargames | 2009-03-27 | ["john doe", "jenny"] | The only winning move is not to play. | + | Wargames2 | 2009-04-27 | jackson | The only winning move is not to play2. | + | Wargames3 | 2009-05-27 | melinda, jackson | The only winning move is not to play3. | + | Wargames4 | 2009-06-27 | fred ; jackson | The only winning move is not to play4. | + When I run bridgetown build + Then the output/authors/jackson/page/ directory should exist + And the "output/authors/jackson/page//index.html" file should exist + And I should see "" in "output/authors/jackson/page//index.html" + And the "output/authors/jackson/page//index.html" file should not exist + + Examples: + | num | exist | posts | not_exist | title | + | 1 | 3 | 1 | 4 | Wargames2 | + | 2 | 2 | 2 | 3 | Wargames3 | diff --git a/bridgetown-core/features/site_configuration.feature b/bridgetown-core/features/site_configuration.feature index 72021500e..4256ad29f 100644 --- a/bridgetown-core/features/site_configuration.feature +++ b/bridgetown-core/features/site_configuration.feature @@ -282,3 +282,17 @@ Feature: Site configuration And the output directory should exist And I should see "FOO" in "output/index.html" And I should not see " " in "output/index.html" + + Scenario: Opt-out of slugified categories + Given I have a _posts directory + And I have the following post: + | title | date | category | content | + | Star Wars | 2009-03-27 | Big Reveals | Luke, I am your father. | + And I have a configuration file with: + | key | value | + | slugify_categories | false | + | permalink | simple | + When I run bridgetown build + Then I should get a zero exit status + And the output directory should exist + And I should see "I am your father" in "output/big reveals/star-wars/index.html" diff --git a/bridgetown-core/features/step_definitions.rb b/bridgetown-core/features/step_definitions.rb index 685e15492..79eb8e7a3 100644 --- a/bridgetown-core/features/step_definitions.rb +++ b/bridgetown-core/features/step_definitions.rb @@ -19,16 +19,14 @@ # -Given /skipped/ do +Given %r!skipped! do skip_this_scenario end # Given(%r!^I have a blank site in "(.*)"$!) do |path| - unless File.exist?(path) - then FileUtils.mkdir_p(path) - end + FileUtils.mkdir_p(path) unless File.exist?(path) end # @@ -40,9 +38,8 @@ # Given(%r!^I have an? "(.*)" page(?: with (.*) "(.*)")? that contains "(.*)"$!) do |file, key, value, text| - unless file.include?("srcsite") - FileUtils.mkdir_p("src") unless File.exist?("src") - File.write(File.join("src", file), <<~DATA) + if file.include?("srcsite") + File.write(file, <<~DATA) --- #{key || "layout"}: #{value || "none"} --- @@ -50,7 +47,8 @@ #{text} DATA else - File.write(file, <<~DATA) + FileUtils.mkdir_p("src") unless File.exist?("src") + File.write(File.join("src", file), <<~DATA) --- #{key || "layout"}: #{value || "none"} --- @@ -63,11 +61,11 @@ # Given(%r!^I have an? "(.*)" file that contains "(.*)"$!) do |file, text| - unless Paths.root_files.include?(file.split("/").first) + if Paths.root_files.include?(file.split("/").first) + File.write(file, text) + else FileUtils.mkdir_p("src") unless File.exist?("src") File.write(File.join("src", file), text) - else - File.write(file, text) end end @@ -84,11 +82,11 @@ # Given(%r!^I have an? "(.*)" file with content:$!) do |file, text| - unless Paths.root_files.include?(file.split("/").first) + if Paths.root_files.include?(file.split("/").first) + File.write(file, text) + else FileUtils.mkdir_p("src") unless File.exist?("src") File.write(File.join("src", file), text) - else - File.write(file, text) end end @@ -108,13 +106,11 @@ # Given(%r!^I have an? \"?(.*?)\"? directory$!) do |dir| - unless Paths.root_files.include?(dir) - dir_in_src = File.join("src", dir) - unless File.directory?(dir_in_src) - then FileUtils.mkdir_p(dir_in_src) - end - else + if Paths.root_files.include?(dir) FileUtils.mkdir_p(dir) + else + dir_in_src = File.join("src", dir) + FileUtils.mkdir_p(dir_in_src) unless File.directory?(dir_in_src) end end @@ -126,7 +122,7 @@ ext = input_hash["type"] || "markdown" filename = "#{title}.#{ext}" if %w(page).include?(status) before, after = location(folder, direction) - dest_folder = "_posts" if status == "post" + dest_folder = "_posts" if status == "post" dest_folder = "" if status == "page" if status == "post" @@ -239,27 +235,21 @@ When(%r!^I run bridgetown(.*)$!) do |args| run_bridgetown(args) - if args.include?("--verbose") || ENV["DEBUG"] - warn "\n#{bridgetown_run_output}\n" - end + warn "\n#{bridgetown_run_output}\n" if args.include?("--verbose") || ENV["DEBUG"] end # When(%r!^I run bundle(.*)$!) do |args| run_bundle(args) - if args.include?("--verbose") || ENV["DEBUG"] - warn "\n#{bridgetown_run_output}\n" - end + warn "\n#{bridgetown_run_output}\n" if args.include?("--verbose") || ENV["DEBUG"] end # When(%r!^I run gem(.*)$!) do |args| run_rubygem(args) - if args.include?("--verbose") || ENV["DEBUG"] - warn "\n#{bridgetown_run_output}\n" - end + warn "\n#{bridgetown_run_output}\n" if args.include?("--verbose") || ENV["DEBUG"] end # @@ -279,10 +269,10 @@ # When(%r!^I delete the file "(.*)"$!) do |file| - unless Paths.root_files.include?(file) - File.delete(File.join("src", file)) - else + if Paths.root_files.include?(file) File.delete(file) + else + File.delete(File.join("src", file)) end end diff --git a/bridgetown-core/lib/bridgetown-core/configuration.rb b/bridgetown-core/lib/bridgetown-core/configuration.rb index 15df4f079..1b318f1e3 100644 --- a/bridgetown-core/lib/bridgetown-core/configuration.rb +++ b/bridgetown-core/lib/bridgetown-core/configuration.rb @@ -25,6 +25,7 @@ class Configuration < Hash "encoding" => "utf-8", "markdown_ext" => "markdown,mkdown,mkdn,mkd,md", "strict_front_matter" => false, + "slugify_categories" => true, # Filtering Content "limit_posts" => 0, diff --git a/bridgetown-core/lib/bridgetown-core/drops/url_drop.rb b/bridgetown-core/lib/bridgetown-core/drops/url_drop.rb index ca58fc2ea..0bcf54fb3 100644 --- a/bridgetown-core/lib/bridgetown-core/drops/url_drop.rb +++ b/bridgetown-core/lib/bridgetown-core/drops/url_drop.rb @@ -30,7 +30,11 @@ def slug def categories category_set = Set.new Array(@obj.data["categories"]).each do |category| - category_set << Utils.slugify(category.to_s) + category_set << if @obj.site.config["slugify_categories"] + Utils.slugify(category.to_s) + else + category.to_s.downcase + end end category_set.to_a.join("/") end diff --git a/bridgetown-core/lib/bridgetown-core/generators/prototype_generator.rb b/bridgetown-core/lib/bridgetown-core/generators/prototype_generator.rb index 5c3e532be..71ad856cc 100644 --- a/bridgetown-core/lib/bridgetown-core/generators/prototype_generator.rb +++ b/bridgetown-core/lib/bridgetown-core/generators/prototype_generator.rb @@ -20,16 +20,25 @@ def generate(site) end prototype_pages.each do |prototype_page| - search_term = prototype_page.data["prototype"]["term"] - next unless search_term.is_a?(String) + search_term = validate_search_term(prototype_page) + next if search_term.nil? terms_matching_pages(search_term).each do |term| - generate_new_page_from_prototype(prototype_page, search_term, term) + generate_new_page_from_prototype(prototype_page, search_term, term).data end end end end + def validate_search_term(prototype_page) + search_term = prototype_page.data["prototype"]["term"] + return nil unless search_term.is_a?(String) + + # Categories and Tags are unique in that singular and plural front matter + # can be present for each + search_term.sub(%r!^category$!, "categories").sub(%r!^tag$!, "tags") + end + def generate_new_page_from_prototype(prototype_page, search_term, term) new_page = PrototypePage.new(prototype_page) new_page.data[search_term] = term @@ -42,14 +51,17 @@ def generate_new_page_from_prototype(prototype_page, search_term, term) new_page.data["pagination"]["where_query"] = [search_term, term] new_page.slugify_term(term) @site.pages << new_page + new_page end def terms_matching_pages(search_term) - @site.documents.map do |document| - next unless document.respond_to?(:collection) + selected_docs = @site.documents.select do |document| + document.respond_to?(:collection) && document.collection.label == @configured_collection + end - document.data[search_term] if document.collection.label == @configured_collection - end.compact.uniq + Bridgetown::Paginate::Generator::PaginationIndexer.index_documents_by( + selected_docs, search_term + ).keys end def process_title_data_placeholder(new_page, prototype_page, search_term, term) diff --git a/bridgetown-paginate/lib/bridgetown-paginate/pagination_indexer.rb b/bridgetown-paginate/lib/bridgetown-paginate/pagination_indexer.rb index f2697a0a0..2809bb5cf 100644 --- a/bridgetown-paginate/lib/bridgetown-paginate/pagination_indexer.rb +++ b/bridgetown-paginate/lib/bridgetown-paginate/pagination_indexer.rb @@ -30,7 +30,7 @@ def self.index_documents_by(all_documents, index_key) # Only tags and categories come as premade arrays, locale does not, # so convert any data elements that are strings into arrays document_data = document.data[index_key] - document_data = document_data.split(%r!;|,|\s!) if document_data.is_a?(String) + document_data = document_data.split(%r!;|,!) if document_data.is_a?(String) document_data.each do |key| key = key.to_s.downcase.strip From a546ed265da6490810cefafd6804f1ea3fba77eb Mon Sep 17 00:00:00 2001 From: Jared White Date: Tue, 21 Apr 2020 12:03:34 -0700 Subject: [PATCH 3/3] Add Prototype Pages documentation --- .prettierignore | 2 + CHANGELOG.md | 19 +++ .../features/prototype_pages.feature | 3 +- .../generators/prototype_generator.rb | 10 +- .../lib/bridgetown-core/version.rb | 2 +- .../src/_docs/content/pagination.md | 2 +- .../src/_docs/frontend-assets.md | 2 +- bridgetown-website/src/_docs/jamstack.md | 2 +- bridgetown-website/src/_docs/liquid.md | 2 +- bridgetown-website/src/_docs/philosophy.md | 2 +- .../src/_docs/prototype_pages.md | 127 ++++++++++++++++++ bridgetown-website/src/_docs/static_files.md | 2 +- bridgetown-website/src/_docs/variables.md | 2 +- 13 files changed, 165 insertions(+), 12 deletions(-) create mode 100644 .prettierignore create mode 100644 bridgetown-website/src/_docs/prototype_pages.md diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..d2ac72766 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +*.md +*.html diff --git a/CHANGELOG.md b/CHANGELOG.md index 02b251b3e..f577706b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # master +# 0.11.0 / 2020-04-21 + +**Prototype Pages** + +You can now create a page, say `categories/category.html`, and add a `prototype` config +to the Front Matter: + +```yaml +layout: default +title: Posts in category :prototype-term +prototype: + term: category +``` + +And then all the site's different categories will have archives pages at this location +(e.g. `categories/awesome-movies`, `categories/my-cool-vacation`, etc.) It enables +pagination automatically, so you'd just use `paginator.documents` to loop through the +posts. + # 0.10.2 / 2020-04-19 **Automatic Yarn Step for New Plugins** diff --git a/bridgetown-core/features/prototype_pages.feature b/bridgetown-core/features/prototype_pages.feature index 9159683bc..a9d2b3d0c 100644 --- a/bridgetown-core/features/prototype_pages.feature +++ b/bridgetown-core/features/prototype_pages.feature @@ -38,7 +38,7 @@ Feature: Prototype Pages | pagination | { enabled: true, per_page: } | And I have a _layouts directory And I have a tags directory - And I have an "tags/tag.html" page with prototype "{term: tag}" that contains "{{ paginator.documents.size }} {{ paginator.documents[0].title }}" + And I have an "tags/tag.html" page with prototype "{term: tag}" that contains "#{{ page.tag }} {{ paginator.documents.size }} {{ paginator.documents[0].title }}" And I have a _posts directory And I have the following posts: | title | date | tags | content | @@ -49,6 +49,7 @@ Feature: Prototype Pages When I run bridgetown build Then the output/tags/scary/page/ directory should exist And the "output/tags/scary/page//index.html" file should exist + And I should see "#scary" in "output/tags/scary/page//index.html" And I should see "" in "output/tags/scary/page//index.html" And the "output/tags/scary/page//index.html" file should not exist And the "output/tags/awful-news/index.html" file should exist diff --git a/bridgetown-core/lib/bridgetown-core/generators/prototype_generator.rb b/bridgetown-core/lib/bridgetown-core/generators/prototype_generator.rb index 71ad856cc..4e1c46745 100644 --- a/bridgetown-core/lib/bridgetown-core/generators/prototype_generator.rb +++ b/bridgetown-core/lib/bridgetown-core/generators/prototype_generator.rb @@ -6,8 +6,6 @@ class PrototypeGenerator < Generator def generate(site) @site = site - - # TODO: make this configurable @configured_collection = "posts" prototype_pages = site.pages.select do |page| @@ -34,6 +32,10 @@ def validate_search_term(prototype_page) search_term = prototype_page.data["prototype"]["term"] return nil unless search_term.is_a?(String) + if prototype_page.data["prototype"]["collection"] + @configured_collection = prototype_page.data["prototype"]["collection"] + end + # Categories and Tags are unique in that singular and plural front matter # can be present for each search_term.sub(%r!^category$!, "categories").sub(%r!^tag$!, "tags") @@ -41,13 +43,15 @@ def validate_search_term(prototype_page) def generate_new_page_from_prototype(prototype_page, search_term, term) new_page = PrototypePage.new(prototype_page) - new_page.data[search_term] = term + # Use the original specified term so we get "tag" back, not "tags": + new_page.data[prototype_page.data["prototype"]["term"]] = term process_title_data_placeholder(new_page, prototype_page, search_term, term) process_title_simple_placeholders(new_page, prototype_page, term) new_page.data["pagination"] = {} unless new_page.data["pagination"].is_a?(Hash) new_page.data["pagination"]["enabled"] = true + new_page.data["pagination"]["collection"] = @configured_collection new_page.data["pagination"]["where_query"] = [search_term, term] new_page.slugify_term(term) @site.pages << new_page diff --git a/bridgetown-core/lib/bridgetown-core/version.rb b/bridgetown-core/lib/bridgetown-core/version.rb index ae695d625..aaac1598d 100644 --- a/bridgetown-core/lib/bridgetown-core/version.rb +++ b/bridgetown-core/lib/bridgetown-core/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Bridgetown - VERSION = "0.10.2" + VERSION = "0.11.0" end diff --git a/bridgetown-website/src/_docs/content/pagination.md b/bridgetown-website/src/_docs/content/pagination.md index f14e900ca..44794cf16 100644 --- a/bridgetown-website/src/_docs/content/pagination.md +++ b/bridgetown-website/src/_docs/content/pagination.md @@ -2,7 +2,7 @@ title: Pagination hide_in_toc: true order: 0 -category: content +category: posts --- {% render "docs/help_needed", page: page %} diff --git a/bridgetown-website/src/_docs/frontend-assets.md b/bridgetown-website/src/_docs/frontend-assets.md index 684a5839c..64ce6deef 100644 --- a/bridgetown-website/src/_docs/frontend-assets.md +++ b/bridgetown-website/src/_docs/frontend-assets.md @@ -1,6 +1,6 @@ --- title: Frontend Assets (Webpack) -order: 16 +order: 17 top_section: Content category: frontendassets --- diff --git a/bridgetown-website/src/_docs/jamstack.md b/bridgetown-website/src/_docs/jamstack.md index b85a127dc..30c45ef1a 100644 --- a/bridgetown-website/src/_docs/jamstack.md +++ b/bridgetown-website/src/_docs/jamstack.md @@ -1,6 +1,6 @@ --- title: What’s a Jamstack? -order: 20 +order: 21 top_section: Philosophy category: jamstack --- diff --git a/bridgetown-website/src/_docs/liquid.md b/bridgetown-website/src/_docs/liquid.md index 7abae596b..0ee3e5bd5 100644 --- a/bridgetown-website/src/_docs/liquid.md +++ b/bridgetown-website/src/_docs/liquid.md @@ -1,6 +1,6 @@ --- title: Liquid -order: 17 +order: 18 top_section: Templates category: liquid --- diff --git a/bridgetown-website/src/_docs/philosophy.md b/bridgetown-website/src/_docs/philosophy.md index cbc638d3f..03d83be1a 100644 --- a/bridgetown-website/src/_docs/philosophy.md +++ b/bridgetown-website/src/_docs/philosophy.md @@ -1,6 +1,6 @@ --- title: Project Goals -order: 19 +order: 20 top_section: Philosophy category: philosophy --- diff --git a/bridgetown-website/src/_docs/prototype_pages.md b/bridgetown-website/src/_docs/prototype_pages.md new file mode 100644 index 000000000..b137fc866 --- /dev/null +++ b/bridgetown-website/src/_docs/prototype_pages.md @@ -0,0 +1,127 @@ +--- +title: Prototype Pages +order: 15 +top_section: Content +category: prototype_pages +--- + +This feature builds upon the [Pagination functionality](/docs/content/pagination/) and +lets you create automatically generated, paginated archives of your content filtered by +the search terms provides. For instance you could set it up so every category has its +own page, or every tag, or some other search term. + +Note that this **requires** enabling `pagination` in your site's `bridgetown.config.yml`. + +# Simple Usage + +All you need to do is create a page, say `categories/category.html`, and add a +`prototype` config to the Front Matter: + +```yaml +--- +layout: default +title: Posts in category :prototype +prototype: + term: category +``` + +And then all the site's different categories will have archives pages at this location +(e.g. `categories/awesome-movies`, `categories/my-cool-vacation`, etc.). And it enables +pagination automatically, so you'd just use `paginator.documents` to loop through the +posts like on any normal paginated page. + +You can do the same thing with tags—just use `term: tag` and create a `tags/tag.html` +file. The exact folder/filename doesn't actually matter—you could create +`my-super-awesome-tagged-content/groovy.html` and it would still work. (The filename +always gets replaced by the search term itself.) + +If you want to "titleize" the search term in the processed `title` variable, use +`:prototype-term-titleize`. Thus given the category "cool-vacation": + +```yaml +--- +title: Posts in category :prototype-term-titleize +prototype: + term: category +``` + +You'd get `Posts in category Cool Vacation` as the page title. + +In addition, the search term used for each generated page is placed into a Liquid +variable, so you can use that as well in your template: `page.category`, or `page.tag`, +etc. + +## Searching in Collections + +You can also search in collections other than the default (posts) by including that in +the prototype configuration: + +`tigers/countries/country.html` +```yaml +--- +title: Tigers in country :prototype-term-titleize +prototype: + term: country + collection: tigers +``` + +/_tigers/bengal.md` +```yaml +--- +title: Bengal Tiger +country: India +``` + +Which would produce a generated `tigers/countries/india` page that loops through +all the tigers in `India`. + + +# Pulling in Site Data + +Prototype pages can be configured to load in extra data from [data files](/docs/datafiles/) +that are matched with the search term. This is great for common uses like listing out +every post by each of the authors in the site. + +Here's an example of how that works: + +`_posts/2020-04-10-article-by-jared.md` +```liquid +--- +title: I'm an article +author: jared +--- + +Content goes here. +``` + +`_data/authors.yml` +```yaml +jared: + name: Jared White + twitter: jaredcwhite +``` + +`authors/author.html` +{% raw %} +```liquid +--- +layout: default +title: Articles by :prototype-data-label +prototype: + term: author + data: authors + data_label: name +--- + + +

{{ page.title }}

<-- Articles by Jared White --> + +

Twitter: @{{ page.author_data.twitter }}

+ + + +{% for post in paginator.documents %} + {% include post.html %} +{% endfor %} +``` +{% endraw %} diff --git a/bridgetown-website/src/_docs/static_files.md b/bridgetown-website/src/_docs/static_files.md index 8e23eb648..cd52ab51e 100644 --- a/bridgetown-website/src/_docs/static_files.md +++ b/bridgetown-website/src/_docs/static_files.md @@ -1,6 +1,6 @@ --- title: Static Files -order: 15 +order: 16 top_section: Content category: staticfiles --- diff --git a/bridgetown-website/src/_docs/variables.md b/bridgetown-website/src/_docs/variables.md index 05b43a3ee..7e06e2aad 100644 --- a/bridgetown-website/src/_docs/variables.md +++ b/bridgetown-website/src/_docs/variables.md @@ -1,6 +1,6 @@ --- title: Variables -order: 18 +order: 19 top_section: Templates category: variables ---