diff --git a/tbx/core/blocks.py b/tbx/core/blocks.py
index 018e8b083..8d2ff43ee 100644
--- a/tbx/core/blocks.py
+++ b/tbx/core/blocks.py
@@ -368,6 +368,24 @@ class Meta:
)
+class LinkColumnsBlock(blocks.StructBlock):
+ """
+ Displays a list of links in columns.
+ Used on the service area page.
+ """
+
+ title = blocks.CharBlock(max_length=255, required=False)
+ intro = blocks.RichTextBlock(
+ features=settings.NO_HEADING_RICH_TEXT_FEATURES, required=False
+ )
+ links = LinkBlock(max_num=None, min_num=1)
+
+ class Meta:
+ group = "Custom"
+ icon = "link"
+ template = "patterns/molecules/streamfield/blocks/link_columns_block.html"
+
+
class PartnersBlock(blocks.StructBlock):
title = blocks.CharBlock(max_length=255, required=False)
partner_logos = blocks.ListBlock(CustomImageChooserBlock(), label="Logos")
diff --git a/tbx/project_styleguide/templates/patterns/_pattern_library_only/streamfield/service_area_story_container.html b/tbx/project_styleguide/templates/patterns/_pattern_library_only/streamfield/service_area_story_container.html
index 1b5a2829a..41b269845 100644
--- a/tbx/project_styleguide/templates/patterns/_pattern_library_only/streamfield/service_area_story_container.html
+++ b/tbx/project_styleguide/templates/patterns/_pattern_library_only/streamfield/service_area_story_container.html
@@ -4,3 +4,4 @@
{% include "patterns/molecules/streamfield/blocks/work_chooser_block.html" %}
{% include "patterns/molecules/streamfield/blocks/pullquote_block.html" %}
{% include "patterns/molecules/streamfield/blocks/blog_chooser_block.html" %}
+{% include "patterns/molecules/streamfield/blocks/link_columns_block.html" %}
diff --git a/tbx/project_styleguide/templates/patterns/molecules/streamfield/blocks/link_columns_block.html b/tbx/project_styleguide/templates/patterns/molecules/streamfield/blocks/link_columns_block.html
new file mode 100644
index 000000000..0eb81ef44
--- /dev/null
+++ b/tbx/project_styleguide/templates/patterns/molecules/streamfield/blocks/link_columns_block.html
@@ -0,0 +1,17 @@
+{% load wagtailcore_tags wagtailimages_tags %}
+
+
+ {% include "patterns/atoms/motif-heading/motif-heading.html" with heading_level=2 heading=value.title classes="motif-heading--two motif-heading--static link-columns__title " %}
+ {% if value.intro %}
+
{{ value.intro|richtext }}
+ {% endif %}
+
+
+
+
diff --git a/tbx/project_styleguide/templates/patterns/molecules/streamfield/blocks/link_columns_block.yaml b/tbx/project_styleguide/templates/patterns/molecules/streamfield/blocks/link_columns_block.yaml
new file mode 100644
index 000000000..e062f2e11
--- /dev/null
+++ b/tbx/project_styleguide/templates/patterns/molecules/streamfield/blocks/link_columns_block.yaml
@@ -0,0 +1,38 @@
+context:
+ value:
+ title: Optional section title (Link columns)
+ intro: 'Optional section intro
'
+ links:
+ - value:
+ text: Digital marketing for charities
+ url: '#'
+ - value:
+ text: Search engine optimisation (SEO)
+ url: '#'
+ - value:
+ text: Website design and development
+ url: '#'
+ - value:
+ text: Strategy, innovation and AI
+ url: '#'
+ - value:
+ text: Google Ad Grants management
+ url: '#'
+ - value:
+ text: Digital marketing creative
+ url: '#'
+ - value:
+ text: Digital marketing training
+ url: '#'
+ - value:
+ text: Wagtail CMS services
+ url: '#'
+ - value:
+ text: Email marketing
+ url: '#'
+ - value:
+ text: Pay-per-click (PPC)
+ url: '#'
+ - value:
+ text: Social media management
+ url: '#'
diff --git a/tbx/project_styleguide/templates/patterns/styleguide/components/components.html b/tbx/project_styleguide/templates/patterns/styleguide/components/components.html
index efeffc60a..2ec0bb4bb 100644
--- a/tbx/project_styleguide/templates/patterns/styleguide/components/components.html
+++ b/tbx/project_styleguide/templates/patterns/styleguide/components/components.html
@@ -209,6 +209,11 @@ Table block
{% include "patterns/molecules/streamfield/blocks/typed_table_block.html" %}
+
+
Link columns block
+ {% include "patterns/molecules/streamfield/blocks/link_columns_block.html" %}
+
+
Division signpost block
{% include "patterns/molecules/streamfield/blocks/division_signpost_block.html" %}
diff --git a/tbx/services/blocks.py b/tbx/services/blocks.py
index 93cae28c9..24a4a9130 100644
--- a/tbx/services/blocks.py
+++ b/tbx/services/blocks.py
@@ -6,6 +6,7 @@
FeaturedCaseStudyBlock,
FourPhotoCollageBlock,
ImageWithAltTextBlock,
+ LinkColumnsBlock,
PartnersBlock,
PhotoCollageBlock,
PromoBlock,
@@ -70,4 +71,5 @@ class ServiceStoryBlock(StoryBlock):
class ServiceAreaStoryBlock(StoryBlock):
blog_chooser = BlogChooserBlock()
four_photo_collage = FourPhotoCollageBlock()
+ link_columns = LinkColumnsBlock()
work_chooser = WorkChooserBlock()
diff --git a/tbx/static_src/sass/components/_grid.scss b/tbx/static_src/sass/components/_grid.scss
index f3e4e9d8b..816491f3e 100644
--- a/tbx/static_src/sass/components/_grid.scss
+++ b/tbx/static_src/sass/components/_grid.scss
@@ -111,6 +111,7 @@
&__related-posts-simple,
&__team-listing,
+ &__link-columns,
&__stats-group {
grid-column: 2 / span 4;
diff --git a/tbx/static_src/sass/components/_link-columns.scss b/tbx/static_src/sass/components/_link-columns.scss
new file mode 100644
index 000000000..dd30ddbbd
--- /dev/null
+++ b/tbx/static_src/sass/components/_link-columns.scss
@@ -0,0 +1,64 @@
+@use 'config' as *;
+
+.link-columns {
+ &__header {
+ margin-bottom: $spacer-half;
+ }
+
+ &__links {
+ @include media-query(medium) {
+ columns: 2;
+ column-gap: $spacer-large;
+ }
+
+ @include media-query(large) {
+ columns: 3;
+ column-gap: $spacer-half;
+ }
+ }
+
+ &__item {
+ padding: $spacer-mini-plus 0;
+ border-top: 1px solid var(--color--border);
+ }
+
+ &__link {
+ display: block;
+ width: fit-content;
+
+ &:focus {
+ @include focus-style();
+ }
+ }
+
+ &__link-text {
+ @include font-size(size-six);
+ @include link-styles(
+ $color: var(--color--link),
+ $interaction-color: var(--color--theme-primary),
+ $offset: 5px
+ );
+
+ &:hover {
+ transition: color $transition-quick;
+
+ @include reduced-motion() {
+ transition: none;
+ }
+ }
+ }
+
+ &__tail {
+ // Keep the arrow attached to the last word so it's not orphaned on a new line
+ white-space: nowrap;
+ display: inline;
+ }
+
+ &__arrow {
+ @include arrow-link-icon-styles(
+ $width: 18px,
+ $interaction-color: var(--color--theme-primary)
+ );
+ color: var(--color--theme-primary);
+ }
+}
diff --git a/tbx/static_src/sass/config/_mixins.scss b/tbx/static_src/sass/config/_mixins.scss
index 225c0352a..36e097c66 100755
--- a/tbx/static_src/sass/config/_mixins.scss
+++ b/tbx/static_src/sass/config/_mixins.scss
@@ -192,13 +192,15 @@
@mixin arrow-link-icon-styles(
$mobile-hidden: false,
$color: var(--color--decoration),
- $interaction-color: var(--color--link-interaction)
+ $interaction-color: var(--color--link-interaction),
+ $width: 72px,
+ $height: 22px
) {
// Apply all common styles regardless of mobile-hidden
display: inline-block;
color: $color;
- width: 72px;
- height: 22px;
+ width: $width;
+ height: $height;
transition: transform, $transition-quick;
@include reduced-motion() {
diff --git a/tbx/static_src/sass/main.scss b/tbx/static_src/sass/main.scss
index 20b3d85c4..40eb86cfd 100755
--- a/tbx/static_src/sass/main.scss
+++ b/tbx/static_src/sass/main.scss
@@ -36,6 +36,7 @@
@use 'components/image';
@use 'components/instagram-gallery';
@use 'components/intro-with-images';
+@use 'components/link-columns';
@use 'components/link';
@use 'components/listing';
@use 'components/listing-avatar';