@nationalarchives/frontend 0.1.9-prerelease → 0.1.11-prerelease

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.
Files changed (130) hide show
  1. package/README.md +3 -3
  2. package/govuk-prototype-kit.config.json +0 -3
  3. package/nationalarchives/_features.scss +4 -0
  4. package/nationalarchives/all.css +1 -1
  5. package/nationalarchives/all.css.map +1 -1
  6. package/nationalarchives/all.js +1 -1
  7. package/nationalarchives/all.js.map +1 -1
  8. package/nationalarchives/all.mjs +54 -3
  9. package/nationalarchives/all.scss +8 -4
  10. package/nationalarchives/assets/images/footer/facebook.svg +11 -0
  11. package/nationalarchives/assets/images/footer/flickr.svg +11 -0
  12. package/nationalarchives/assets/images/footer/instagram.svg +17 -0
  13. package/nationalarchives/assets/images/footer/rss.svg +13 -0
  14. package/nationalarchives/assets/images/footer/twitter.svg +14 -0
  15. package/nationalarchives/assets/images/footer/youtube.svg +12 -0
  16. package/nationalarchives/assets/images/tna-square-logo.svg +5 -24
  17. package/nationalarchives/components/_index.scss +13 -0
  18. package/nationalarchives/components/breadcrumbs/_index.scss +28 -6
  19. package/nationalarchives/components/breadcrumbs/breadcrumbs.stories.js +1 -2
  20. package/nationalarchives/components/breadcrumbs/fixtures.json +1 -1
  21. package/nationalarchives/components/breadcrumbs/macro.njk +1 -1
  22. package/nationalarchives/components/breadcrumbs/template.njk +14 -13
  23. package/nationalarchives/components/button/_index.scss +23 -11
  24. package/nationalarchives/components/button/button.stories.js +1 -2
  25. package/nationalarchives/components/button/fixtures.json +5 -5
  26. package/nationalarchives/components/button/macro.njk +1 -1
  27. package/nationalarchives/components/card/_index.scss +51 -7
  28. package/nationalarchives/components/card/card.js +2 -0
  29. package/nationalarchives/components/card/card.js.map +1 -0
  30. package/nationalarchives/components/card/card.mjs +45 -0
  31. package/nationalarchives/components/card/card.stories.js +18 -15
  32. package/nationalarchives/components/card/fixtures.json +14 -12
  33. package/nationalarchives/components/card/macro-options.json +18 -0
  34. package/nationalarchives/components/card/macro.njk +1 -1
  35. package/nationalarchives/components/card/template.njk +9 -4
  36. package/nationalarchives/components/filters/filters.stories.js +1 -2
  37. package/nationalarchives/components/filters/macro.njk +1 -1
  38. package/nationalarchives/components/filters/template.njk +2 -2
  39. package/nationalarchives/components/footer/_index.scss +68 -13
  40. package/nationalarchives/components/footer/fixtures.json +1 -1
  41. package/nationalarchives/components/footer/footer.stories.js +20 -23
  42. package/nationalarchives/components/footer/macro-options.json +12 -6
  43. package/nationalarchives/components/footer/macro.njk +1 -1
  44. package/nationalarchives/components/footer/template.njk +26 -16
  45. package/nationalarchives/components/grid/_index.scss +10 -12
  46. package/nationalarchives/components/grid/fixtures.json +12 -12
  47. package/nationalarchives/components/grid/grid.stories.js +56 -3
  48. package/nationalarchives/components/grid/macro-options.json +30 -0
  49. package/nationalarchives/components/grid/macro.njk +1 -1
  50. package/nationalarchives/components/grid/template.njk +17 -1
  51. package/nationalarchives/components/header/_index.scss +269 -60
  52. package/nationalarchives/components/header/header.js +1 -1
  53. package/nationalarchives/components/header/header.js.map +1 -1
  54. package/nationalarchives/components/header/header.mjs +7 -12
  55. package/nationalarchives/components/header/header.stories.js +156 -6
  56. package/nationalarchives/components/header/macro-options.json +83 -5
  57. package/nationalarchives/components/header/macro.njk +1 -1
  58. package/nationalarchives/components/header/template.njk +45 -36
  59. package/nationalarchives/components/hero/_index.scss +36 -6
  60. package/nationalarchives/components/hero/fixtures.json +16 -1
  61. package/nationalarchives/components/hero/hero.stories.js +32 -16
  62. package/nationalarchives/components/hero/macro-options.json +14 -2
  63. package/nationalarchives/components/hero/macro.njk +1 -1
  64. package/nationalarchives/components/hero/template.njk +7 -5
  65. package/nationalarchives/components/phase-banner/_index.scss +60 -0
  66. package/nationalarchives/components/phase-banner/fixtures.json +81 -0
  67. package/nationalarchives/components/phase-banner/macro-options.json +26 -0
  68. package/nationalarchives/components/phase-banner/macro.njk +3 -0
  69. package/nationalarchives/components/phase-banner/phase-banner.stories.js +64 -0
  70. package/nationalarchives/components/phase-banner/template.njk +16 -0
  71. package/nationalarchives/components/picture/_index.scss +77 -0
  72. package/nationalarchives/components/picture/fixtures.json +4 -0
  73. package/nationalarchives/components/picture/macro-options.json +88 -0
  74. package/nationalarchives/components/picture/macro.njk +3 -0
  75. package/nationalarchives/components/picture/picture.js +2 -0
  76. package/nationalarchives/components/picture/picture.js.map +1 -0
  77. package/nationalarchives/components/picture/picture.mjs +57 -0
  78. package/nationalarchives/components/picture/picture.stories.js +63 -0
  79. package/nationalarchives/components/picture/template.njk +42 -0
  80. package/nationalarchives/components/profile/_index.scss +2 -0
  81. package/nationalarchives/components/profile/fixtures.json +4 -0
  82. package/nationalarchives/components/profile/macro-options.json +14 -0
  83. package/nationalarchives/components/profile/macro.njk +3 -0
  84. package/nationalarchives/components/profile/profile.stories.js +32 -0
  85. package/nationalarchives/components/profile/template.njk +15 -0
  86. package/nationalarchives/components/sensitive-image/fixtures.json +3 -3
  87. package/nationalarchives/components/sensitive-image/macro.njk +1 -1
  88. package/nationalarchives/components/sensitive-image/sensitive-image.stories.js +1 -2
  89. package/nationalarchives/components/tabs/_index.scss +148 -0
  90. package/nationalarchives/components/tabs/fixtures.json +4 -0
  91. package/nationalarchives/components/tabs/macro-options.json +52 -0
  92. package/nationalarchives/components/tabs/macro.njk +3 -0
  93. package/nationalarchives/components/tabs/tabs.js +2 -0
  94. package/nationalarchives/components/tabs/tabs.js.map +1 -0
  95. package/nationalarchives/components/tabs/tabs.mjs +214 -0
  96. package/nationalarchives/components/tabs/tabs.stories.js +302 -0
  97. package/nationalarchives/components/tabs/template.njk +20 -0
  98. package/nationalarchives/patterns/_index.scss +1 -0
  99. package/nationalarchives/patterns/featured-collection/_index.scss +13 -0
  100. package/nationalarchives/patterns/featured-collection/featured-collection.stories.js +35 -0
  101. package/nationalarchives/patterns/featured-collection/macro-options.json +20 -0
  102. package/nationalarchives/patterns/featured-collection/macro.njk +3 -0
  103. package/nationalarchives/patterns/featured-collection/template.njk +96 -0
  104. package/nationalarchives/stories/development/contributing.mdx +39 -0
  105. package/nationalarchives/stories/development/dependencies.mdx +2 -0
  106. package/nationalarchives/stories/development/technologies.mdx +65 -0
  107. package/nationalarchives/stories/utilities/colour.stories.js +189 -0
  108. package/nationalarchives/stories/utilities/typography.mdx +1 -0
  109. package/nationalarchives/stories/utilities/typography.stories.js +15 -0
  110. package/nationalarchives/templates/layouts/_generic.njk +1 -1
  111. package/nationalarchives/tools/_assets.scss +5 -0
  112. package/nationalarchives/tools/_colour.scss +129 -0
  113. package/nationalarchives/tools/_grid.scss +2 -2
  114. package/nationalarchives/tools/_index.scss +5 -0
  115. package/nationalarchives/tools/_media.scss +12 -11
  116. package/nationalarchives/tools/_typography.scss +15 -0
  117. package/nationalarchives/utilities/_debug.scss +11 -0
  118. package/nationalarchives/utilities/_global.scss +120 -3
  119. package/nationalarchives/utilities/_index.scss +3 -0
  120. package/nationalarchives/utilities/_typography.scss +155 -111
  121. package/nationalarchives/variables/_assets.scss +1 -0
  122. package/nationalarchives/variables/_colour.scss +120 -11
  123. package/nationalarchives/variables/{_all.scss → _index.scss} +1 -0
  124. package/nationalarchives/variables/_media.scss +39 -11
  125. package/nationalarchives/variables/_typography.scss +1 -1
  126. package/package.json +18 -15
  127. package/nationalarchives/components/_all.scss +0 -7
  128. package/nationalarchives/stories/development/structure.mdx +0 -7
  129. package/nationalarchives/tools/_all.scss +0 -3
  130. package/nationalarchives/utilities/_all.scss +0 -2
@@ -0,0 +1,302 @@
1
+ import Tabs from "./template.njk";
2
+ import macroOptions from "./macro-options.json";
3
+ import { expect } from "@storybook/jest";
4
+ import { within, userEvent } from "@storybook/testing-library";
5
+
6
+ const argTypes = {
7
+ title: { control: "text" },
8
+ items: { control: "array" },
9
+ sticky: { control: "boolean" },
10
+ classes: { control: "text" },
11
+ attributes: { control: "object" },
12
+ };
13
+
14
+ Object.keys(argTypes).forEach((argType) => {
15
+ argTypes[argType].description = macroOptions.find(
16
+ (option) => option.name === argType,
17
+ )?.description;
18
+ });
19
+
20
+ export default {
21
+ title: "Work in progress/Components/Tabs",
22
+ argTypes,
23
+ };
24
+
25
+ const Template = ({ title, items, sticky, classes, attributes }) => {
26
+ return Tabs({
27
+ params: {
28
+ title,
29
+ items,
30
+ sticky,
31
+ classes,
32
+ attributes,
33
+ },
34
+ });
35
+ };
36
+
37
+ export const Standard = Template.bind({});
38
+ Standard.args = {
39
+ title: "Example tabs",
40
+ items: [
41
+ {
42
+ id: "unique-id-a",
43
+ title: "Alpha section",
44
+ body: "<h2>Alpha title</h2><p>Lorem ipsum</p>",
45
+ },
46
+ {
47
+ id: "unique-id-b",
48
+ title: "Beta section",
49
+ body: "<h2>Beta title</h2><p>Lorem ipsum</p>",
50
+ },
51
+ {
52
+ id: "unique-id-c",
53
+ title: "Gamma section",
54
+ body: "<h2>Gamma title</h2><p>Lorem ipsum</p>",
55
+ },
56
+ ],
57
+ classes: "tna-tabs--demo",
58
+ };
59
+
60
+ export const Test = Template.bind({});
61
+ Test.args = {
62
+ title: "Example tabs",
63
+ items: [
64
+ {
65
+ id: "unique-id-a",
66
+ title: "Alpha section",
67
+ body: "<h2>Alpha title</h2><p>Lorem ipsum</p>",
68
+ },
69
+ {
70
+ id: "unique-id-b",
71
+ title: "Beta section",
72
+ body: "<h2>Beta title</h2><p>Lorem ipsum</p>",
73
+ },
74
+ {
75
+ id: "unique-id-c",
76
+ title: "Gamma section",
77
+ body: "<h2>Gamma title</h2><p>Lorem ipsum</p>",
78
+ },
79
+ ],
80
+ classes: "tna-tabs--demo",
81
+ };
82
+
83
+ Test.play = async ({ args, canvasElement, step }) => {
84
+ const canvas = within(canvasElement);
85
+
86
+ const tablist = canvas.getByRole("tablist");
87
+ const [buttonA, buttonB, buttonC] = args.items.map((item) =>
88
+ canvas.getByText(item.title),
89
+ );
90
+ const [sectionA, sectionB, sectionC] = args.items.map((item) =>
91
+ canvasElement.querySelector(`#${item.id}`),
92
+ );
93
+
94
+ const expectButtonToBeCurrent = async (button) => {
95
+ await expect(button).toHaveAttribute("tabindex", "0");
96
+ await expect(button).toHaveAttribute("aria-selected", "true");
97
+ await expect(button).toHaveFocus();
98
+ };
99
+
100
+ const expectButtonNotToBeCurrent = async (button) => {
101
+ await expect(button).toHaveAttribute("tabindex", "-1");
102
+ await expect(button).toHaveAttribute("aria-selected", "false");
103
+ };
104
+
105
+ const expectSectionToBeCurrent = async (section) => {
106
+ await expect(section).toBeVisible();
107
+ await expect(section).toHaveAttribute("tabindex", "0");
108
+ };
109
+
110
+ const expectSectionNotToBeCurrent = async (section) => {
111
+ await expect(section).not.toBeVisible();
112
+ await expect(section).toHaveAttribute("tabindex", "-1");
113
+ };
114
+
115
+ const expectButtonAndSectionAToBeCurrent = async (section) => {
116
+ await step("Test tab buttons", async () => {
117
+ await expectButtonToBeCurrent(buttonA);
118
+ await expectButtonNotToBeCurrent(buttonB);
119
+ await expectButtonNotToBeCurrent(buttonC);
120
+ });
121
+
122
+ await step("Test tab sections", async () => {
123
+ await expectSectionToBeCurrent(sectionA);
124
+ await expectSectionNotToBeCurrent(sectionB);
125
+ await expectSectionNotToBeCurrent(sectionC);
126
+ });
127
+ };
128
+
129
+ const expectButtonAndSectionBToBeCurrent = async (section) => {
130
+ await step("Test tab buttons", async () => {
131
+ await expectButtonNotToBeCurrent(buttonA);
132
+ await expectButtonToBeCurrent(buttonB);
133
+ await expectButtonNotToBeCurrent(buttonC);
134
+ });
135
+
136
+ await step("Test tab sections", async () => {
137
+ await expectSectionNotToBeCurrent(sectionA);
138
+ await expectSectionToBeCurrent(sectionB);
139
+ await expectSectionNotToBeCurrent(sectionC);
140
+ });
141
+ };
142
+
143
+ const expectButtonAndSectionCToBeCurrent = async (section) => {
144
+ await step("Test tab buttons", async () => {
145
+ await expectButtonNotToBeCurrent(buttonA);
146
+ await expectButtonNotToBeCurrent(buttonB);
147
+ await expectButtonToBeCurrent(buttonC);
148
+ });
149
+
150
+ await step("Test tab sections", async () => {
151
+ await expectSectionNotToBeCurrent(sectionA);
152
+ await expectSectionNotToBeCurrent(sectionB);
153
+ await expectSectionToBeCurrent(sectionC);
154
+ });
155
+ };
156
+
157
+ await step("Initial load", async () => {
158
+ await step("Test tablist", async () => {
159
+ await expect(tablist).toBeDefined();
160
+ await expect(tablist).toBeVisible();
161
+ });
162
+
163
+ await step("Test tab buttons", async () => {
164
+ await step("First tab button", async () => {
165
+ await expect(buttonA).toBeVisible();
166
+ await expect(buttonA).toHaveAttribute("id", `${args.items[0].id}-tab`);
167
+ await expect(buttonA).toHaveAttribute("role", "tab");
168
+ await expect(buttonA).toHaveAttribute("tabindex", "0");
169
+ await expect(buttonA).toHaveAttribute("aria-selected", "true");
170
+ await expect(buttonA).toHaveAttribute(
171
+ "aria-controls",
172
+ args.items[0].id,
173
+ );
174
+ });
175
+
176
+ await step("Second tab button", async () => {
177
+ await expect(buttonB).toBeVisible();
178
+ await expect(buttonB).toHaveAttribute("id", `${args.items[1].id}-tab`);
179
+ await expect(buttonB).toHaveAttribute("role", "tab");
180
+ await expect(buttonB).toHaveAttribute("tabindex", "-1");
181
+ await expect(buttonB).toHaveAttribute("aria-selected", "false");
182
+ await expect(buttonB).toHaveAttribute(
183
+ "aria-controls",
184
+ args.items[1].id,
185
+ );
186
+ });
187
+
188
+ await step("Third tab button", async () => {
189
+ await expect(buttonC).toBeVisible();
190
+ await expect(buttonC).toHaveAttribute("id", `${args.items[2].id}-tab`);
191
+ await expect(buttonC).toHaveAttribute("role", "tab");
192
+ await expect(buttonC).toHaveAttribute("tabindex", "-1");
193
+ await expect(buttonC).toHaveAttribute("aria-selected", "false");
194
+ await expect(buttonC).toHaveAttribute(
195
+ "aria-controls",
196
+ args.items[2].id,
197
+ );
198
+ });
199
+ });
200
+
201
+ await step("Test tab sections", async () => {
202
+ await expect(sectionA).toBeVisible();
203
+ await expect(sectionA).toHaveAttribute("id", args.items[0].id);
204
+ await expect(sectionA).toHaveAttribute("role", "tabpanel");
205
+ await expect(sectionA).toHaveAttribute(
206
+ "aria-labelledby",
207
+ `${args.items[0].id}-tab`,
208
+ );
209
+ await expect(sectionA).toHaveAttribute("tabindex", "0");
210
+
211
+ await expect(sectionB).not.toBeVisible();
212
+ await expect(sectionB).toHaveAttribute("id", args.items[1].id);
213
+ await expect(sectionB).toHaveAttribute("role", "tabpanel");
214
+ await expect(sectionB).toHaveAttribute(
215
+ "aria-labelledby",
216
+ `${args.items[1].id}-tab`,
217
+ );
218
+ await expect(sectionB).toHaveAttribute("tabindex", "0");
219
+
220
+ await expect(sectionC).not.toBeVisible();
221
+ await expect(sectionC).toHaveAttribute("id", args.items[2].id);
222
+ await expect(sectionC).toHaveAttribute("role", "tabpanel");
223
+ await expect(sectionC).toHaveAttribute(
224
+ "aria-labelledby",
225
+ `${args.items[2].id}-tab`,
226
+ );
227
+ await expect(sectionC).toHaveAttribute("tabindex", "0");
228
+ });
229
+ });
230
+
231
+ await userEvent.click(buttonA);
232
+
233
+ await step("First tab (already selected)", async () => {
234
+ await userEvent.click(buttonA);
235
+ await expectButtonAndSectionAToBeCurrent();
236
+ });
237
+
238
+ await step("Second tab", async () => {
239
+ await userEvent.click(buttonB);
240
+ await expectButtonAndSectionBToBeCurrent();
241
+ });
242
+
243
+ await step("Third tab", async () => {
244
+ await userEvent.click(buttonC);
245
+ await expectButtonAndSectionCToBeCurrent();
246
+ });
247
+
248
+ await step("First tab", async () => {
249
+ await userEvent.click(buttonA);
250
+ await expectButtonAndSectionAToBeCurrent();
251
+ });
252
+
253
+ await step("Keyboard interaciton", async () => {
254
+ await step("Left/right", async () => {
255
+ await userEvent.click(buttonA);
256
+ await expectButtonAndSectionAToBeCurrent();
257
+
258
+ await userEvent.keyboard("[ArrowRight]");
259
+ await expectButtonAndSectionBToBeCurrent();
260
+
261
+ await userEvent.keyboard("[ArrowRight]");
262
+ await expectButtonAndSectionCToBeCurrent();
263
+
264
+ await userEvent.keyboard("[ArrowRight]");
265
+ await expectButtonAndSectionAToBeCurrent();
266
+
267
+ await userEvent.keyboard("[ArrowRight]");
268
+ await expectButtonAndSectionBToBeCurrent();
269
+
270
+ await userEvent.keyboard("[ArrowLeft]");
271
+ await expectButtonAndSectionAToBeCurrent();
272
+
273
+ await userEvent.keyboard("[ArrowLeft]");
274
+ await expectButtonAndSectionCToBeCurrent();
275
+
276
+ await userEvent.keyboard("[ArrowLeft]");
277
+ await expectButtonAndSectionBToBeCurrent();
278
+
279
+ await userEvent.keyboard("[ArrowLeft]");
280
+ await expectButtonAndSectionAToBeCurrent();
281
+ });
282
+
283
+ await step("Home/end", async () => {
284
+ await userEvent.click(buttonA);
285
+ await expectButtonAndSectionAToBeCurrent();
286
+
287
+ await userEvent.keyboard("[Home]");
288
+ await expectButtonAndSectionAToBeCurrent();
289
+
290
+ await userEvent.keyboard("[End]");
291
+ await expectButtonAndSectionCToBeCurrent();
292
+
293
+ await userEvent.keyboard("[End]");
294
+ await expectButtonAndSectionCToBeCurrent();
295
+
296
+ await userEvent.keyboard("[Home]");
297
+ await expectButtonAndSectionAToBeCurrent();
298
+ });
299
+
300
+ buttonA.blur();
301
+ });
302
+ };
@@ -0,0 +1,20 @@
1
+ {%- set containerClasses = [params.classes] if params.classes else [] -%}
2
+ {%- if params.sticky -%}
3
+ {%- set containerClasses = containerClasses.concat('tna-tabs--sticky') -%}
4
+ {%- endif -%}
5
+ <div class="tna-tabs {{ containerClasses | join(' ') }}" data-module="tna-tabs" {%- for attribute, value in params.attributes %} {{ attribute }}="{{ value }}"{% endfor %}>
6
+ <ul class="tna-tabs__list" aria-label="{{ params.title }}">
7
+ {% for item in params.items %}
8
+ <li class="tna-tabs__list-item">
9
+ <a href="#{{ item.id }}" class="tna-tabs__list-item-link" id="{{ item.id }}-tab">{{ item.title }}</a>
10
+ </li>
11
+ {% endfor %}
12
+ </ul>
13
+ <div class="tna-tabs__items">
14
+ {% for item in params.items %}
15
+ <section id="{{ item.id }}" class="tna-tabs__item">
16
+ {{ item.body | safe }}
17
+ </section>
18
+ {% endfor %}
19
+ </div>
20
+ </div>
@@ -0,0 +1 @@
1
+ @forward "featured-collection/index";
@@ -0,0 +1,13 @@
1
+ @use "../../variables/colour" as colourVars;
2
+
3
+ .tna-featured-collection {
4
+ padding-top: 2rem;
5
+ padding-bottom: 2rem;
6
+
7
+ background-color: colourVars.$tna-cream;
8
+
9
+ .tna-card {
10
+ margin-top: 1rem;
11
+ margin-bottom: 1rem;
12
+ }
13
+ }
@@ -0,0 +1,35 @@
1
+ import FeaturedCollection from "./template.njk";
2
+ import macroOptions from "./macro-options.json";
3
+
4
+ const argTypes = {
5
+ heading: { control: "text" },
6
+ classes: { control: "text" },
7
+ attributes: { control: "object" },
8
+ };
9
+
10
+ Object.keys(argTypes).forEach((argType) => {
11
+ argTypes[argType].description = macroOptions.find(
12
+ (option) => option.name === argType,
13
+ )?.description;
14
+ });
15
+
16
+ export default {
17
+ title: "Experimental/Patterns/Featured collection",
18
+ argTypes,
19
+ };
20
+
21
+ const Template = ({ heading, classes, attributes }) => {
22
+ return FeaturedCollection({
23
+ params: {
24
+ heading,
25
+ classes,
26
+ attributes,
27
+ },
28
+ });
29
+ };
30
+
31
+ export const Standard = Template.bind({});
32
+ Standard.args = {
33
+ heading: "Records from the collection",
34
+ classes: "tna-featured-collection--demo",
35
+ };
@@ -0,0 +1,20 @@
1
+ [
2
+ {
3
+ "name": "heading",
4
+ "type": "string",
5
+ "required": true,
6
+ "description": ""
7
+ },
8
+ {
9
+ "name": "classes",
10
+ "type": "string",
11
+ "required": false,
12
+ "description": "Classes to add to the featured collection."
13
+ },
14
+ {
15
+ "name": "attributes",
16
+ "type": "object",
17
+ "required": false,
18
+ "description": "HTML attributes (for example data attributes) to add to the featured collection."
19
+ }
20
+ ]
@@ -0,0 +1,3 @@
1
+ {% macro tnaFeaturedCollection(params) %}
2
+ {%- include "nationalarchives/patterns/featured-collection/template.njk" -%}
3
+ {% endmacro %}
@@ -0,0 +1,96 @@
1
+ {% from "nationalarchives/components/grid/macro.njk" import tnaGrid %}
2
+ {% from "nationalarchives/components/card/macro.njk" import tnaCard %}
3
+
4
+ {% set exampleCard = {
5
+ heading: {
6
+ title: "Card title",
7
+ level: 3,
8
+ size: "m",
9
+ singleSentence: true
10
+ },
11
+ href: "#",
12
+ image: {
13
+ src: "https://picsum.photos/id/29/640/360",
14
+ alt: "A placeholder image"
15
+ },
16
+ body: "<p>Card body</p>"
17
+ } %}
18
+
19
+ {%- set containerClasses = [params.classes] if params.classes else [] -%}
20
+ {%- set containerClasses = containerClasses.concat('tna-featured-collection') -%}
21
+
22
+ {{ tnaGrid({
23
+ columns: [
24
+ {
25
+ width: "full",
26
+ widthMedium: "full",
27
+ widthSmall: "full",
28
+ widthTiny: "full",
29
+ html: "<h2 class=\"tna-heading\">" + params.heading + "</h2>"
30
+ },
31
+ {
32
+ width: "1-2",
33
+ widthMedium: "2-3",
34
+ widthSmall: "1-2",
35
+ widthTiny: "full",
36
+ html: tnaCard({
37
+ heading: {
38
+ title: "Card title",
39
+ level: 3,
40
+ size: "m",
41
+ singleSentence: true
42
+ },
43
+ href: "#",
44
+ image: {
45
+ src: "https://picsum.photos/id/29/640/360",
46
+ alt: "A placeholder image",
47
+ label: "Feature"
48
+ },
49
+ body: "<p>Card body</p>"
50
+ })
51
+ },
52
+ {
53
+ width: "1-2",
54
+ widthMedium: "1-3",
55
+ widthSmall: "1-2",
56
+ widthTiny: "full",
57
+ html: tnaGrid({
58
+ columns: [
59
+ {
60
+ width: "1-2",
61
+ widthMedium: "full",
62
+ widthSmall: "full",
63
+ widthTiny: "full",
64
+ html: tnaCard(exampleCard)
65
+ },
66
+ {
67
+ width: "1-2",
68
+ widthMedium: "full",
69
+ widthSmall: "full",
70
+ widthTiny: "full",
71
+ html: tnaCard(exampleCard)
72
+ },
73
+ {
74
+ width: "1-2",
75
+ widthMedium: "full",
76
+ widthSmall: "full",
77
+ widthTiny: "full",
78
+ html: tnaCard(exampleCard)
79
+ },
80
+ {
81
+ width: "1-2",
82
+ widthMedium: "full",
83
+ widthSmall: "full",
84
+ widthTiny: "full",
85
+ html: tnaCard(exampleCard)
86
+ }
87
+ ],
88
+ noPadding: true
89
+ }),
90
+ noPadding: true
91
+ }
92
+ ],
93
+ htmlElement: "section",
94
+ classes: containerClasses | join(' '),
95
+ attributes: params.attributes
96
+ }) }}
@@ -0,0 +1,39 @@
1
+ import { Meta } from "@storybook/blocks";
2
+
3
+ <Meta title="Development/Contributing" />
4
+
5
+ # Contributing to the frontend styles
6
+
7
+ ## Adding a new component
8
+
9
+ 1. Create a new directory in `src/nationalarchives/components`
10
+ 1. Create an `_index.scss`, `fixtures.json`, `macro-options.json`, `macro.njk`, `template.njk` and a `[myComponent].stories.js` in the directory using other components as a guide
11
+ 1. Add the component SCSS to `src/nationalarchives/components/_all.scss`
12
+ 1. Update `tasks/test-package.js` to check for the files as part of the CI (`...componentFiles("myComponent", true)` where `true` ignores the check for any JavaScript files)
13
+ 1. Set the macro in `macro.njk` to be `tnaMyComponent` where "MyComponent" is the name of your component
14
+ 1. Add the component import and macro to the prototype kit test in `.github/workflows/ci.yml`
15
+
16
+ ### Files
17
+
18
+ - `_index.scss` - where you can add your [BEM](https://getbem.com/) SCSS styles for the component
19
+ - `fixtures.json` - these are snapshots of the rendered component's HTML in different scenarios which can be used by other implementations to test against
20
+ - `macro-options.json` - the options for the component which are rendered in the Design System as well as being copied in to the Storybook controls
21
+ - `macro.njk` - the Nunjucks macro easily allows us to include components in the prototype kit and other applications such as the Design System
22
+ - `template.njk` - this is the HTML for the component, written in [Nunjucks](https://mozilla.github.io/nunjucks/)
23
+ - `[myComponent].stories.js` - the stories that get rendered to Storybook
24
+
25
+ ### If you need JavaScript
26
+
27
+ 1. Create a `[myComponent].mjs` file in the component directory
28
+ 1. Ensure the top level element in your component has the attribute `data-module="tna-my-component"`
29
+ 1. Import and initialise your component as part of the `initAll` function in `src/nationalarchives/all.mjs`
30
+ 1. Update the check in `tasks/test-package.js` to remove the `true` and enable checking of the JavaScript file (`...componentFiles("myComponent")`)
31
+ 1. If your component uses JavaScript, ensure you add interaction tests using `@storybook/testing-library`
32
+
33
+ ### Best practices
34
+
35
+ [TODO]
36
+
37
+ ## Updating a component
38
+
39
+ [TODO]
@@ -6,4 +6,6 @@ import { Meta } from "@storybook/blocks";
6
6
 
7
7
  ```sh
8
8
  npx sb upgrade
9
+ # or
10
+ npx storybook@latest upgrade
9
11
  ```
@@ -0,0 +1,65 @@
1
+ import { Meta } from "@storybook/blocks";
2
+
3
+ <Meta title="Development/Technologies" />
4
+
5
+ # Technologies
6
+
7
+ ## Storybook
8
+
9
+ Most widely supported open source frontend workshop for building UI components, constantly updated, also used by TDR
10
+
11
+ ## ESNext JavaScript (not TypeScript)
12
+
13
+ JavaScript over TypeScript to allow in-project compilation and possible tree-shaking without extra libraries
14
+
15
+ ## Babel
16
+
17
+ De facto JavaScript compiler and transpiler, allows us to use most up-to-date JavaScript for increased efficiency and cleaner source code
18
+
19
+ ## SCSS
20
+
21
+ Most mature CSS preprocessor, used in other TNA projects, huge support
22
+
23
+ ## BEM
24
+
25
+ Agreed CSS methodology within TNA
26
+
27
+ ## Webpack
28
+
29
+ Already used in many TNA projects, most mature offering although arguably not the fastest - we could consider changing in the future
30
+
31
+ ## Nunjucks
32
+
33
+ Used by GDS and made by Mozilla, Nunjucks is simple and expandable and allows us to use components in the GOV.UK prototype kit
34
+
35
+ ## npm
36
+
37
+ Used by many TNA projects and provides highly available package repository, de facto standard for JavaScript packages
38
+
39
+ ## GitHub actions
40
+
41
+ Free actions not relying on external services, used on some TNA projects but will allow us to have more of a CI/CD methodology
42
+
43
+ ## Prettier
44
+
45
+ Opinionated code formatter for (S)CSS, JavaScript, JSON and other file types, intended to reduce bikeshedding
46
+
47
+ ## ESLint
48
+
49
+ De facto linter for JavaScript to catch potential issues
50
+
51
+ ## Stylelint
52
+
53
+ Most widely supported and mature (S)CSS linter
54
+
55
+ ## Jest
56
+
57
+ Lightweight and fast testing library, support for Storybook, easy learning curve
58
+
59
+ ## NVM
60
+
61
+ Ensures all developers can work on the same version of NodeJS, reduces differences between development environments
62
+
63
+ ## Chromatic.com
64
+
65
+ Suggested by Storybook for visual regression testing