Skip to content

Commit

Permalink
Add grid and card rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
harryy94 committed Feb 6, 2025
1 parent 7119ee6 commit 2584208
Show file tree
Hide file tree
Showing 18 changed files with 378 additions and 12 deletions.
1 change: 1 addition & 0 deletions src/web/CareLeavers.Web/CareLeavers.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<PackageReference Include="GovUk.Frontend.AspNetCore" Version="2.8.0" />
<PackageReference Include="Joonasw.AspNetCore.SecurityHeaders" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.12" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.7" />
<PackageReference Include="Serilog" Version="4.2.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
<PackageReference Include="Serilog.Sinks.ApplicationInsights" Version="4.0.0" />
Expand Down
19 changes: 19 additions & 0 deletions src/web/CareLeavers.Web/Contentful/ContentfulEntityResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using CareLeavers.Web.Models.Content;
using Contentful.Core.Configuration;

namespace CareLeavers.Web.Contentful;

public class ContentfulEntityResolver : IContentTypeResolver
{
private Dictionary<string, Type> _types = new()
{
{ Page.ContentType, typeof(Page) },
{ Grid.ContentType, typeof(Grid) },
{ Card.ContentType, typeof(Card) }
};

public Type? Resolve(string contentTypeId)
{
return _types.TryGetValue(contentTypeId, out var type) ? type : null;
}
}
35 changes: 35 additions & 0 deletions src/web/CareLeavers.Web/ContentfulRenderers/GDSGridRenderer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using CareLeavers.Web.Models.Content;
using Contentful.Core.Models;

namespace CareLeavers.Web.ContentfulRenderers;

public class GDSGridRenderer(IServiceProvider serviceProvider) : GDSRazorContentRenderer(serviceProvider)
{
public override bool SupportsContent(IContent content)
{
if (content is EntryStructure { NodeType: "embedded-entry-block" } entryStructure)
{
if (entryStructure.Data.Target is Grid)
{
return true;
}
}

return content is Grid;
}

public override Task<string> RenderAsync(IContent content)
{
Grid? grid;
if (content is Grid)
{
grid = content as Grid;
}
else
{
grid = (content as EntryStructure)?.Data.Target as Grid;
}

return RenderToString("Shared/Grid", grid);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Contentful.AspNetCore.Authoring;
using Contentful.Core.Models;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.ViewFeatures;

namespace CareLeavers.Web.ContentfulRenderers;

public abstract class GDSRazorContentRenderer(
IServiceProvider serviceProvider)
: RazorContentRenderer(
serviceProvider.GetRequiredService<IRazorViewEngine>(),
serviceProvider.GetRequiredService<ITempDataProvider>(),
serviceProvider)
{
public override string Render(IContent content)
{
var result = RenderAsync(content);
result.Wait();
return result.Result;
}
}
25 changes: 18 additions & 7 deletions src/web/CareLeavers.Web/Controllers/ContentfulController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Text;
using System.Xml.Linq;
using CareLeavers.Web.Caching;
using CareLeavers.Web.Contentful;
using CareLeavers.Web.Models.Content;
using Contentful.Core;
using Contentful.Core.Configuration;
Expand All @@ -15,10 +16,19 @@
namespace CareLeavers.Web.Controllers;

[Route("/")]
public class ContentfulController(
IDistributedCache distributedCache,
IContentfulClient contentfulClient) : Controller
public class ContentfulController : Controller
{
private readonly IDistributedCache _distributedCache;
private readonly IContentfulClient _contentfulClient;

public ContentfulController(IDistributedCache distributedCache, IContentfulClient contentfulClient)
{
_distributedCache = distributedCache;
_contentfulClient = contentfulClient;

_contentfulClient.ContentTypeResolver = new ContentfulEntityResolver();
}

private static readonly JsonSerializerSettings ContentfulSerializerSettings = new()
{
ContractResolver = new CamelCasePropertyNamesContractResolver
Expand Down Expand Up @@ -83,13 +93,13 @@ public async Task<IActionResult> Sitemap([FromServices] IConfiguration configura
return BadRequest();
}

var page = await distributedCache.GetOrSetAsync($"content:sitemap", async () =>
var page = await _distributedCache.GetOrSetAsync($"content:sitemap", async () =>
{
var pages = new QueryBuilder<Page>()
.ContentTypeIs("page")
.SelectFields(x => new {x.Slug});

var pageEntries = await contentfulClient.GetEntries(pages);
var pageEntries = await _contentfulClient.GetEntries(pages);

XNamespace ns = "http://www.sitemaps.org/schemas/sitemap/0.9";

Expand All @@ -112,14 +122,15 @@ public async Task<IActionResult> Sitemap([FromServices] IConfiguration configura

private Task<Page?> GetContentfulPage(string slug)
{
return distributedCache.GetOrSetAsync($"content:{slug}", async () =>
return _distributedCache.GetOrSetAsync($"content:{slug}", async () =>
{
var pages = new QueryBuilder<Page>()
.ContentTypeIs(Page.ContentType)
.FieldEquals(c => c.Slug, slug)
.Include(10)
.Limit(1);

var pageEntries = await contentfulClient.GetEntries(pages);
var pageEntries = await _contentfulClient.GetEntries(pages);

return pageEntries.FirstOrDefault();
});
Expand Down
20 changes: 20 additions & 0 deletions src/web/CareLeavers.Web/Models/Content/Card.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Contentful.Core.Models;

namespace CareLeavers.Web.Models.Content;

public class Card : ContentfulContent
{
public static string ContentType { get; } = "card";

public string? Title { get; set; }

public string? Text { get; set; }

public Asset? Image { get; set; }

public Page? Link { get; set; }

public List<string> Types { get; set; } = [];

public int Position { get; set; } = 0;
}
19 changes: 19 additions & 0 deletions src/web/CareLeavers.Web/Models/Content/Grid.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using CareLeavers.Web.Models.Enums;
using Contentful.Core.Models;

namespace CareLeavers.Web.Models.Content;

public class Grid : ContentfulContent
{
public static string ContentType { get; } = "grid";

public string? Title { get; set; }

public GridType? GridType { get; set; }

public bool ShowTitle { get; set; }

public List<IContent>? Content { get; set; }

public string? CssClass { get; set; } = "govuk-grid-column-full";
}
27 changes: 25 additions & 2 deletions src/web/CareLeavers.Web/Models/Content/Page.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using CareLeavers.Web.Models.Enums;
using Contentful.Core.Models;

namespace CareLeavers.Web.Models.Content;
Expand All @@ -6,9 +7,31 @@ public class Page : ContentfulContent
{
public static string ContentType { get; } = "page";

public Page? Parent { get; set; }

public string? SeoTitle { get; set; }

public string? SeoDescription { get; set; }

public Asset? SeoImage { get; set; }

public PageWidth Width { get; set; }

public PageType? Type { get; set; }

public string? Title { get; set; }

public string? Slug { get; set; }

public Document? Content { get; set; }
}
public bool ShowContentsBlock { get; set; }

public bool ShowLastUpdated { get; set; }

public Document? Header { get; set; }

public Document? Footer { get; set; }

public Document? MainContent { get; set; }

public Document? SecondaryContent { get; set; }
}
15 changes: 15 additions & 0 deletions src/web/CareLeavers.Web/Models/Enums/GridType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Runtime.Serialization;

namespace CareLeavers.Web.Models.Enums;

public enum GridType
{
Cards,
[EnumMember(Value = "Alternating Image and Text")]
AlternatingImageAndText,
[EnumMember(Value = "External Links")]
ExternalLinks,
Banner,
[EnumMember(Value = "Small Banner")]
SmallBanner
}
7 changes: 7 additions & 0 deletions src/web/CareLeavers.Web/Models/Enums/PageType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace CareLeavers.Web.Models.Enums;

public enum PageType
{
Guide,
Advice
}
11 changes: 11 additions & 0 deletions src/web/CareLeavers.Web/Models/Enums/PageWidth.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Runtime.Serialization;

namespace CareLeavers.Web.Models.Enums;

public enum PageWidth
{
[EnumMember(Value = "Two Thirds")]
TwoThirds,
[EnumMember(Value = "Full Width")]
FullWidth
}
3 changes: 2 additions & 1 deletion src/web/CareLeavers.Web/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@

builder.Services.AddHealthChecks();

builder.Services.AddTransient<HtmlRenderer>((c) =>
builder.Services.AddTransient<HtmlRenderer>(serviceProvider =>
{
var renderer = new HtmlRenderer(new HtmlRendererOptions
{
Expand All @@ -71,6 +71,7 @@
renderer.AddRenderer(new GDSParagraphRenderer(renderer.Renderers));
renderer.AddRenderer(new GDSHeaderRenderer(renderer.Renderers));
renderer.AddRenderer(new GDSAssetRenderer(renderer.Renderers));
renderer.AddRenderer(new GDSGridRenderer(serviceProvider));

return renderer;
});
Expand Down
33 changes: 31 additions & 2 deletions src/web/CareLeavers.Web/Views/Contentful/Page.cshtml
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
@using CareLeavers.Web.Models.Enums
@using Microsoft.AspNetCore.Mvc.TagHelpers
@model CareLeavers.Web.Models.Content.Page

@{
ViewBag.Title = Model.Title;
Layout = "_Layout";

var pageWidth = Model.Width switch
{
PageWidth.TwoThirds => "govuk-grid-column-two-thirds",
_ => "govuk-grid-column-full"
};
}

@section BeforeGDSContent
Expand All @@ -12,12 +20,33 @@
<h1 class="govuk-heading-xl">
@Model.Title
</h1>

@if (Model.Header != null)
{
<gds-contentful-rich-text document="@Model.Header"></gds-contentful-rich-text>
}
</div>
</div>
}

<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<gds-contentful-rich-text document="@Model.Content"></gds-contentful-rich-text>
<div class="@pageWidth">
@if (Model.Type.HasValue)
{
<span class="govuk-caption-m">@Model.Type</span>
}
@* ShowCOntentBlock *@
<gds-contentful-rich-text document="@Model.MainContent"></gds-contentful-rich-text>
@if (Model.ShowLastUpdated)
{
<hr/>
<partial name="_LastUpdated" model="@Model.Sys"/>
}
</div>
@if (Model.SecondaryContent != null && Model.Width != PageWidth.FullWidth)
{
<div class="govuk-grid-column-one-third">
<gds-contentful-rich-text document="@Model.SecondaryContent"></gds-contentful-rich-text>
</div>
}
</div>
Loading

0 comments on commit 2584208

Please sign in to comment.