Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Landing pages backend scaffold #4247

Draft
wants to merge 25 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c85c2ab
Update ContentItem factory to handle different subclasses of ContentItem
KludgeKML Oct 2, 2024
b6d8492
WIP - Add landing_page controller, routes, and basic view
KludgeKML Oct 2, 2024
3342552
WIP: add prototype paragraph block
KludgeKML Oct 2, 2024
c2c3502
WIP - add prototype tabs block
KludgeKML Oct 2, 2024
b77c4f0
WIP - dummy landing page content yaml
KludgeKML Oct 2, 2024
206ae0f
Add simple layouts
KludgeKML Oct 2, 2024
d02fa52
WIP - Add blocks as models
KludgeKML Oct 2, 2024
1b5928f
Convert to use new block item
KludgeKML Oct 2, 2024
71c1767
Add Block::TwoColumnLayout model
KludgeKML Oct 2, 2024
578f019
Replace paragraph block with govspeak block
KludgeKML Oct 3, 2024
a5dce0e
Update yaml to use new block type
KludgeKML Oct 3, 2024
89ebcbb
Add layout_base
KludgeKML Oct 3, 2024
4319acf
Update layout yaml with new two_column_layout format
KludgeKML Oct 3, 2024
e406ca3
Add big_number type
KludgeKML Oct 3, 2024
688d6ce
Add columns layout
KludgeKML Oct 3, 2024
dcd1913
Update columns to add class size based on column count
KludgeKML Oct 3, 2024
6a2e24a
WIP - add assymetric column helper to move presentational code out of…
KludgeKML Oct 3, 2024
b3e7221
WIP - example of multi-line HTML in govspeak component
KludgeKML Oct 3, 2024
a68703c
Add scaffolding comments to show when we can remove various methods
KludgeKML Oct 3, 2024
fa7d2a5
Update to allow more than one landing-page route
KludgeKML Oct 3, 2024
0fbbb49
Add sub-page and links
KludgeKML Oct 3, 2024
7db8df6
WIP - don't always override with fake data - try getting the content …
KludgeKML Oct 3, 2024
4fa5662
Add routing constraint as backup
KludgeKML Oct 3, 2024
a450f54
FIX - allow a blank page with a warning if there isn't a YAML file or…
KludgeKML Oct 3, 2024
2e339e3
Don't override blocks in content-store response if present
KludgeKML Oct 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions app/controllers/landing_page_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
class LandingPageController < ContentItemsController
# SCAFFOLDING: can be removed when basic content items are available
# from content-store
def request_content_item(_base_path)
GdsApi.content_store.content_item(request.path)
rescue StandardError
fake_data
end

# SCAFFOLDING: can be removed when basic content items are available
# from content-store
def fake_data
{
"base_path" => request.path,
"title" => "Landing Page",
"description" => "A landing page example",
"locale" => "en",
"document_type" => "landing_page",
"schema_name" => "landing_page",
"publishing_app" => "whitehall",
"rendering_app" => "frontend",
"update_type" => "major",
"details" => {},
"routes" => [
{
"type" => "exact",
"path" => request.path,
},
],
}
end
end
45 changes: 45 additions & 0 deletions app/helpers/block_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
module BlockHelper
def tab_items_to_component_format(tab_items)
tab_items.map do |ti|
{
id: ti["id"],
label: ti["label"],
content: sanitize("<p class=\"govuk-body-m\">#{ti['content']}</p>"),
}
end
end

def column_class_for_equal_columns(number_of_columns)
case number_of_columns
when 1
"govuk-grid-column"
when 2
"govuk-grid-column-one-half"
when 3
"govuk-grid-column-one-third"
else
"govuk-grid-column-one-quarter"
end
end

def column_class_for_assymetric_columns(number_of_columns, column_size)
case number_of_columns
when 3
case column_size
when 1
"govuk-grid-column-one-third"
when 2
"govuk-grid-column-two-thirds"
end
when 4
case column_size
when 1
"govuk-grid-column-one-quarter"
when 2
"govuk-grid-column-two-quarters"
when 3
"govuk-grid-column-three-quarters"
end
end
end
end
11 changes: 11 additions & 0 deletions app/models/block/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Block
class Base
attr_reader :id, :type, :data

def initialize(block_hash)
@data = block_hash
@id = data["id"]
@type = data["type"]
end
end
end
5 changes: 5 additions & 0 deletions app/models/block/columns_layout.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Block
class ColumnsLayout < Block::LayoutBase
alias_method :columns, :blocks
end
end
11 changes: 11 additions & 0 deletions app/models/block/layout_base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Block
class LayoutBase < Block::Base
attr_reader :blocks

def initialize(block_hash)
super(block_hash)

@blocks = data["blocks"].map { |subblock_hash| BlockFactory.build(subblock_hash) }
end
end
end
26 changes: 26 additions & 0 deletions app/models/block/two_column_layout.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module Block
class TwoColumnLayout < Block::LayoutBase
attr_reader :left, :right, :theme
alias_method :columns, :blocks

def initialize(block_hash)
super(block_hash)

@left = columns[0]
@right = columns[1]
@theme = data["theme"]
end

def left_column_size
theme == "two_thirds_one_third" ? 2 : 1
end

def right_column_size
theme == "one_third_two_thirds" ? 2 : 1
end

def total_columns
left_column_size + right_column_size
end
end
end
12 changes: 12 additions & 0 deletions app/models/block_factory.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class BlockFactory
def self.build(block_hash)
block_class(block_hash["type"]).new(block_hash)
end

def self.block_class(type)
klass = "Block::#{type.camelize}".constantize
klass.ancestors.include?(Block::Base) ? klass : Block::Base
rescue StandardError
Block::Base
end
end
7 changes: 5 additions & 2 deletions app/models/content_item_factory.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
class ContentItemFactory
def self.build(content_hash)
content_item_class(content_hash).new(content_hash)
content_item_class(content_hash["document_type"]).new(content_hash)
end

def self.content_item_class(_content_hash)
def self.content_item_class(document_type)
klass = document_type.camelize.constantize
klass.superclass == ContentItem ? klass : ContentItem
rescue StandardError
ContentItem
end
end
25 changes: 25 additions & 0 deletions app/models/landing_page.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class LandingPage < ContentItem
attr_reader :blocks

def initialize(content_store_response)
if content_store_response.dig("details", "blocks")
super(content_store_response)
else
super(content_store_response.deep_merge(load_additional_content(content_store_response["base_path"])))
end

@blocks = (@content_store_response.dig("details", "blocks") || []).map { |block_hash| BlockFactory.build(block_hash) }
end

private

# SCAFFOLDING: can be removed (and reference above) when full content items
# including block details are available from content-store
def load_additional_content(base_path)
file_slug = base_path.split("/").last.gsub("-", "_")
filename = Rails.root.join("lib/data/landing_page_content_items/#{file_slug}.yaml")
return { "details" => {} } unless File.exist?(filename)

{ "details" => YAML.load(File.read(filename)) }
end
end
4 changes: 4 additions & 0 deletions app/views/landing_page/blocks/_big_number.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<%= render "govuk_publishing_components/components/big_number", {
number: block.data["number"],
label: block.data["label"],
} %>
5 changes: 5 additions & 0 deletions app/views/landing_page/blocks/_columns_layout.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="govuk-grid-row">
<% block.columns.each do |column| %>
<div class="<%= column_class_for_equal_columns(block.columns.count) %>"><%= render "landing_page/blocks/#{column.type}", block: column %></div>
<% end %>
</div>
4 changes: 4 additions & 0 deletions app/views/landing_page/blocks/_govspeak.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<%= render "govuk_publishing_components/components/govspeak", {
} do %>
<%= block.data["content"].html_safe %>
<% end %>
3 changes: 3 additions & 0 deletions app/views/landing_page/blocks/_tabs.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<%= render "govuk_publishing_components/components/tabs", {
tabs: tab_items_to_component_format(block.data["tab_items"]),
} %>
8 changes: 8 additions & 0 deletions app/views/landing_page/blocks/_two_column_layout.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div class="govuk-grid-row">
<div class="<%= column_class_for_assymetric_columns(block.total_columns, block.left_column_size) %>">
<%= render "landing_page/blocks/#{block.left.type}", block: block.left %>
</div>
<div class="<%= column_class_for_assymetric_columns(block.total_columns, block.right_column_size) %>">
<%= render "landing_page/blocks/#{block.right.type}", block: block.right %>
</div>
</div>
9 changes: 9 additions & 0 deletions app/views/landing_page/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

<div class="landing-page">
<% @content_item.blocks.each do |block| %>
<%= render "landing_page/blocks/#{block.type}", block: %>
<% end %>
<% if @content_item.blocks.empty? %>
Warning: No blocks specified for this page
<% end %>
</div>
9 changes: 9 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@

get "/foreign-travel-advice", to: "travel_advice#index", as: :travel_advice

scope "/landing-page" do
get "/", to: "landing_page#show"
get "/*any", to: "landing_page#show"
end

constraints FormatRoutingConstraint.new("landing_page") do
get ":slug", to: "landing_page#show"
end

# Accounts
get "/sign-in", to: "help#sign_in"
get "/sign-in/redirect", to: "sessions#create"
Expand Down
43 changes: 43 additions & 0 deletions lib/data/landing_page_content_items/landing_page.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
blocks:
- type: govspeak
content: |
<h2>Here's a heading</h2>
<p>Here's some content!</p>
<p>Here's some more content</p>
<ul>
<li>What?</li>
<li>When?</li>
</ul>
<a href="/landing-page/sub-page-1">Visit sub-page 1</a>
- type: tabs
id: landing-pages-item-selector
tab_items:
- id: tab-1
label: Item 1
content: Here's the content for item one
- id: tab-2
label: Item 2
content: Here's the content for item two
- type: govspeak
content: <p>Here's some more content!</p>
- type: two_column_layout
theme: two_thirds_one_third
blocks:
- type: govspeak
content: <p>Left content!</p>
- type: govspeak
content: <p>Right content!</p>
- type: govspeak
content: <h2>Statistics</h2>
- type: columns_layout
blocks:
- type: big_number
number: £75m
label: amount of money that looks big
- type: big_number
number: 100%
label: increase in the number of big_number components added to the columns at this point
- type: big_number
number: £43
label: Cost of a cup of coffee in Covent Garden

5 changes: 5 additions & 0 deletions lib/data/landing_page_content_items/sub_page_1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
blocks:
- type: govspeak
content: |
<h2>Sub Page 1</h2>
<a href="/landing-page">Back to main landing page</a>
Loading