@rmdes/indiekit-frontend 1.0.0-beta.25

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 (213) hide show
  1. package/README.md +10 -0
  2. package/assets/app-icon-any.svg +5 -0
  3. package/assets/app-icon-maskable.svg +5 -0
  4. package/assets/icon.svg +3 -0
  5. package/assets/not-found.svg +7 -0
  6. package/assets/offline.svg +7 -0
  7. package/assets/plug-in.svg +4 -0
  8. package/components/actions/macro.njk +3 -0
  9. package/components/actions/styles.css +19 -0
  10. package/components/actions/template.njk +19 -0
  11. package/components/add-another/index.js +170 -0
  12. package/components/add-another/macro.njk +3 -0
  13. package/components/add-another/styles.css +63 -0
  14. package/components/add-another/template.njk +39 -0
  15. package/components/app/styles.css +45 -0
  16. package/components/authorize/macro.njk +3 -0
  17. package/components/authorize/styles.css +23 -0
  18. package/components/authorize/template.njk +14 -0
  19. package/components/avatar/macro.njk +3 -0
  20. package/components/avatar/styles.css +23 -0
  21. package/components/avatar/template.njk +1 -0
  22. package/components/back-link/macro.njk +3 -0
  23. package/components/back-link/styles.css +46 -0
  24. package/components/back-link/template.njk +5 -0
  25. package/components/badge/macro.njk +3 -0
  26. package/components/badge/styles.css +85 -0
  27. package/components/badge/template.njk +7 -0
  28. package/components/bookmarklet/macro.njk +3 -0
  29. package/components/bookmarklet/styles.css +18 -0
  30. package/components/bookmarklet/template.njk +1 -0
  31. package/components/button/macro.njk +3 -0
  32. package/components/button/styles.css +108 -0
  33. package/components/button/template.njk +17 -0
  34. package/components/card/macro.njk +3 -0
  35. package/components/card/styles.css +93 -0
  36. package/components/card/template.njk +46 -0
  37. package/components/card-grid/macro.njk +3 -0
  38. package/components/card-grid/styles.css +9 -0
  39. package/components/card-grid/template.njk +8 -0
  40. package/components/character-count/index.js +185 -0
  41. package/components/character-count/macro.njk +3 -0
  42. package/components/character-count/styles.css +3 -0
  43. package/components/character-count/template.njk +14 -0
  44. package/components/checkboxes/index.js +130 -0
  45. package/components/checkboxes/macro.njk +3 -0
  46. package/components/checkboxes/styles.css +96 -0
  47. package/components/checkboxes/template.njk +96 -0
  48. package/components/details/macro.njk +3 -0
  49. package/components/details/styles.css +24 -0
  50. package/components/details/template.njk +12 -0
  51. package/components/error-message/macro.njk +3 -0
  52. package/components/error-message/styles.css +5 -0
  53. package/components/error-message/template.njk +9 -0
  54. package/components/error-summary/index.js +147 -0
  55. package/components/error-summary/macro.njk +3 -0
  56. package/components/error-summary/styles.css +24 -0
  57. package/components/error-summary/template.njk +27 -0
  58. package/components/event-duration/index.js +26 -0
  59. package/components/event-duration/styles.css +7 -0
  60. package/components/field/macro.njk +3 -0
  61. package/components/field/styles.css +14 -0
  62. package/components/field/template.njk +4 -0
  63. package/components/fieldset/macro.njk +3 -0
  64. package/components/fieldset/styles.css +27 -0
  65. package/components/fieldset/template.njk +13 -0
  66. package/components/file-input/index.js +123 -0
  67. package/components/file-input/macro.njk +3 -0
  68. package/components/file-input/styles.css +3 -0
  69. package/components/file-input/template.njk +45 -0
  70. package/components/footer/macro.njk +3 -0
  71. package/components/footer/styles.css +18 -0
  72. package/components/footer/template.njk +8 -0
  73. package/components/geo-input/index.js +105 -0
  74. package/components/geo-input/macro.njk +3 -0
  75. package/components/geo-input/styles.css +3 -0
  76. package/components/geo-input/template.njk +35 -0
  77. package/components/header/macro.njk +3 -0
  78. package/components/header/styles.css +60 -0
  79. package/components/header/template.njk +11 -0
  80. package/components/heading/macro.njk +3 -0
  81. package/components/heading/styles.css +24 -0
  82. package/components/heading/template.njk +20 -0
  83. package/components/hint/macro.njk +3 -0
  84. package/components/hint/styles.css +10 -0
  85. package/components/hint/template.njk +3 -0
  86. package/components/icon/styles.css +14 -0
  87. package/components/input/macro.njk +3 -0
  88. package/components/input/styles.css +111 -0
  89. package/components/input/template.njk +45 -0
  90. package/components/label/macro.njk +3 -0
  91. package/components/label/styles.css +4 -0
  92. package/components/label/template.njk +4 -0
  93. package/components/logo/macro.njk +3 -0
  94. package/components/logo/styles.css +24 -0
  95. package/components/logo/template.njk +3 -0
  96. package/components/main/styles.css +14 -0
  97. package/components/mention/macro.njk +3 -0
  98. package/components/mention/styles.css +9 -0
  99. package/components/mention/template.njk +6 -0
  100. package/components/navigation/macro.njk +3 -0
  101. package/components/navigation/styles.css +19 -0
  102. package/components/navigation/template.njk +11 -0
  103. package/components/notification-banner/index.js +24 -0
  104. package/components/notification-banner/macro.njk +3 -0
  105. package/components/notification-banner/styles.css +49 -0
  106. package/components/notification-banner/template.njk +20 -0
  107. package/components/pagination/macro.njk +3 -0
  108. package/components/pagination/styles.css +91 -0
  109. package/components/pagination/template.njk +42 -0
  110. package/components/progress/macro.njk +3 -0
  111. package/components/progress/styles.css +38 -0
  112. package/components/progress/template.njk +10 -0
  113. package/components/prose/macro.njk +3 -0
  114. package/components/prose/styles.css +12 -0
  115. package/components/prose/template.njk +3 -0
  116. package/components/radios/index.js +83 -0
  117. package/components/radios/macro.njk +3 -0
  118. package/components/radios/styles.css +104 -0
  119. package/components/radios/template.njk +87 -0
  120. package/components/section/macro.njk +3 -0
  121. package/components/section/styles.css +12 -0
  122. package/components/section/template.njk +19 -0
  123. package/components/select/macro.njk +3 -0
  124. package/components/select/styles.css +37 -0
  125. package/components/select/template.njk +48 -0
  126. package/components/share-preview/index.js +54 -0
  127. package/components/share-preview/macro.njk +3 -0
  128. package/components/share-preview/styles.css +36 -0
  129. package/components/share-preview/template.njk +14 -0
  130. package/components/skip-link/macro.njk +3 -0
  131. package/components/skip-link/styles.css +12 -0
  132. package/components/skip-link/template.njk +3 -0
  133. package/components/summary/macro.njk +3 -0
  134. package/components/summary/styles.css +60 -0
  135. package/components/summary/template.njk +19 -0
  136. package/components/tag/macro.njk +3 -0
  137. package/components/tag/styles.css +14 -0
  138. package/components/tag/template.njk +5 -0
  139. package/components/tag-input/index.js +69 -0
  140. package/components/tag-input/macro.njk +3 -0
  141. package/components/tag-input/sanitizer.js +27 -0
  142. package/components/tag-input/styles.css +161 -0
  143. package/components/tag-input/template.njk +29 -0
  144. package/components/textarea/index.js +298 -0
  145. package/components/textarea/macro.njk +3 -0
  146. package/components/textarea/styles.css +42 -0
  147. package/components/textarea/template.njk +40 -0
  148. package/components/user/macro.njk +3 -0
  149. package/components/user/styles.css +20 -0
  150. package/components/user/template.njk +15 -0
  151. package/components/warning-text/macro.njk +3 -0
  152. package/components/warning-text/styles.css +15 -0
  153. package/components/warning-text/template.njk +8 -0
  154. package/components/widget/macro.njk +3 -0
  155. package/components/widget/styles.css +28 -0
  156. package/components/widget/template.njk +20 -0
  157. package/index.js +10 -0
  158. package/layouts/default.njk +122 -0
  159. package/layouts/document.njk +15 -0
  160. package/layouts/error.njk +19 -0
  161. package/layouts/form.njk +22 -0
  162. package/lib/esbuild.js +22 -0
  163. package/lib/filters/index.js +10 -0
  164. package/lib/filters/locale.js +17 -0
  165. package/lib/filters/string.js +29 -0
  166. package/lib/filters/url.js +69 -0
  167. package/lib/globals/attributes.js +23 -0
  168. package/lib/globals/classes.js +19 -0
  169. package/lib/globals/error-list.js +21 -0
  170. package/lib/globals/field-data.js +20 -0
  171. package/lib/globals/icon.js +80 -0
  172. package/lib/globals/index.js +12 -0
  173. package/lib/globals/item-id.js +17 -0
  174. package/lib/globals/summary-rows.js +39 -0
  175. package/lib/lightningcss.js +41 -0
  176. package/lib/markdown-it.js +27 -0
  177. package/lib/nunjucks.js +43 -0
  178. package/lib/serviceworker.js +240 -0
  179. package/lib/sharp.js +39 -0
  180. package/lib/utils/theme.js +115 -0
  181. package/lib/utils/wrap-element.js +11 -0
  182. package/locales/de.json +60 -0
  183. package/locales/en.json +60 -0
  184. package/locales/es-419.json +60 -0
  185. package/locales/es.json +60 -0
  186. package/locales/fr.json +60 -0
  187. package/locales/hi.json +60 -0
  188. package/locales/id.json +60 -0
  189. package/locales/it.json +60 -0
  190. package/locales/nl.json +60 -0
  191. package/locales/pl.json +60 -0
  192. package/locales/pt-BR.json +60 -0
  193. package/locales/pt.json +60 -0
  194. package/locales/sr.json +60 -0
  195. package/locales/sv.json +60 -0
  196. package/locales/zh-Hans-CN.json +60 -0
  197. package/package.json +64 -0
  198. package/scripts/app.js +23 -0
  199. package/styles/app.css +73 -0
  200. package/styles/base/embedded.css +29 -0
  201. package/styles/base/forms.css +55 -0
  202. package/styles/base/grouping.css +43 -0
  203. package/styles/base/interactive.css +19 -0
  204. package/styles/base/sections.css +59 -0
  205. package/styles/base/tables.css +30 -0
  206. package/styles/base/text.css +71 -0
  207. package/styles/config/custom-properties.css +211 -0
  208. package/styles/scopes/flow.css +114 -0
  209. package/styles/utilities/container.css +6 -0
  210. package/styles/utilities/visually-hidden.css +10 -0
  211. package/styles/vendor/codemirror.css +116 -0
  212. package/styles/vendor/easy-markdown-editor.css +219 -0
  213. package/styles/vendor/markdown-it-prism.css +79 -0
package/README.md ADDED
@@ -0,0 +1,10 @@
1
+ # @indiekit/frontend
2
+
3
+ Frontend components for Indiekit.
4
+
5
+ ## Installation
6
+
7
+ `npm install @indiekit/frontend`
8
+
9
+ > [!NOTE]
10
+ > This package is installed alongside `@indiekit/indiekit`
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
2
+ <path fill="#333" d="M0 0h512v512H0z"/>
3
+ <circle fill="#ccc" cx="156" cy="156" r="94"/>
4
+ <path fill="#ccc" d="M79.4 264h153.2c5.4 0 7.3.6 9.3 1.6 2 1 3.5 2.6 4.5 4.5 1 2 1.6 4 1.6 9.3v153.2c0 5.4-.6 7.3-1.6 9.3-1 2-2.6 3.5-4.5 4.5-2 1-4 1.6-9.3 1.6H79.4c-5.4 0-7.3-.6-9.3-1.6-2-1-3.5-2.6-4.5-4.5-1-2-1.6-4-1.6-9.3V279.4c0-5.4.6-7.3 1.6-9.3 1-2 2.6-3.5 4.5-4.5 2-1 4-1.6 9.3-1.6Zm191.1 0h162.1c5.4 0 7.3.6 9.3 1.6 2 1 3.5 2.6 4.5 4.5 1 2 1.6 4 1.6 9.3v162.1a6 6 0 0 1-10.2 4.3L266.2 274.2a6 6 0 0 1 4.3-10.2Zm3.2-16C379.3 248 448 174 448 73.7c0-6.5-3.2-9.7-9.7-9.7H276a12 12 0 0 0-12 12v162.3c0 6.5 3.2 9.7 9.7 9.7Z"/>
5
+ </svg>
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
2
+ <path fill="#333" d="M0 0h512v512H0z"/>
3
+ <circle fill="#ccc" cx="180" cy="180" r="72" />
4
+ <path fill="#ccc" d="M125.4 262h109.2c5.4 0 7.3.6 9.3 1.6 2 1 3.5 2.6 4.5 4.5 1 2 1.6 4 1.6 9.3v109.2c0 5.4-.6 7.3-1.6 9.3-1 2-2.6 3.5-4.5 4.5-2 1-4 1.6-9.3 1.6H125.4c-5.4 0-7.3-.6-9.3-1.6-2-1-3.5-2.6-4.5-4.5-1-2-1.6-4-1.6-9.3V277.4c0-5.4.6-7.3 1.6-9.3 1-2 2.6-3.5 4.5-4.5 2-1 4-1.6 9.3-1.6Zm145.1 0h116.1c5.4 0 7.3.6 9.3 1.6 2 1 3.5 2.6 4.5 4.5 1 2 1.6 4 1.6 9.3v116.1a6 6 0 0 1-10.2 4.3L266.2 272.2a6 6 0 0 1 4.3-10.2Zm-1.1-12c80.3 0 132.6-56.3 132.6-132.6 0-5-2.5-7.4-7.4-7.4H274a12 12 0 0 0-12 12v120.6c0 5 2.5 7.4 7.4 7.4Z"/>
5
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
2
+ <path d="M30 34v28H2V34h28zm32 0v28L34 34h28zM17 1c7 0 14 7 14 16 0 7-7 14-14 14-9 0-16-7-16-14C1 8 8 1 17 1zm45 1c0 15-13 28-28 28V2h28z"/>
3
+ </svg>
@@ -0,0 +1,7 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <path id="icon" fill="#AAA" d="m14 17 12 12 6-6 12 12v1a8 8 0 0 1-8 8H12a8 8 0 0 1-8-8v-9l10-10Zm0 5-6 6v8a4 4 0 0 0 3.8 4H36a4 4 0 0 0 4-3.8V36l-8-8-6 6-12-12ZM32.3 4c1 0 2.1.4 2.9 1.2l7.6 7.6a4 4 0 0 1 1.2 2.9V32l-4-4V16h-8V8H12c-2 0-4 2-4 4v8l-4 4V12a8 8 0 0 1 8-8h20.3Z" opacity=".7"/>
4
+ </defs>
5
+ <rect fill="#000" width="100%" height="100%" opacity="0.075"/>
6
+ <use href="#icon" x="50%" y="50%" transform="translate(-24 -24)"/>
7
+ </svg>
@@ -0,0 +1,7 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <path id="icon" fill="#AAA" d="M24 32a5 5 0 1 1 0 10 5 5 0 0 1 0-10Zm-6.9-11.9 4.1 4.1a17 17 0 0 0-9.7 5.3L8 26a22 22 0 0 1 9-6Zm22.5 5.4L36 29l-.8-.8L26 19a22 22 0 0 1 13.5 6.4ZM8.2 11.2l3.7 3.7a24.7 24.7 0 0 0-8.4 6.6l-3.6-3.6c2.4-2.7 5.2-5 8.3-6.7ZM24 7a32 32 0 0 1 23.4 10.2l-3.5 3.6a27 27 0 0 0-24.5-8.4l-4.2-4.2A32 32 0 0 1 24 7ZM2 5l3-3 41 41-3 3L2 5Z" opacity=".7"/>
4
+ </defs>
5
+ <rect fill="#000" width="100%" height="100%" opacity="0.075"/>
6
+ <use href="#icon" x="50%" y="50%" transform="translate(-24 -24)"/>
7
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96">
2
+ <path fill="#17181C" d="M0 0h96v96H0z"/>
3
+ <path fill="#FFF" d="M14 70V36a4 4 0 0 1 4-4h60a4 4 0 0 1 4 4v34a4 4 0 0 1-4 4H18a4 4 0 0 1-4-4Zm12-48h12a2 2 0 0 1 2 2v5H24v-5c0-1.1.9-2 2-2Zm32 0h12a2 2 0 0 1 2 2v5H56v-5c0-1.1.9-2 2-2Z"/>
4
+ </svg>
@@ -0,0 +1,3 @@
1
+ {% macro actions(opts) %}
2
+ {%- include "./template.njk" -%}
3
+ {% endmacro %}
@@ -0,0 +1,19 @@
1
+ .actions {
2
+ --anchor-decoration-color: transparent;
3
+ --icon-margin: var(--space-2xs);
4
+ display: flex;
5
+ flex-wrap: wrap;
6
+ font: var(--font-body);
7
+ gap: var(--space-2xs) var(--space-l);
8
+ }
9
+
10
+ .actions__link {
11
+ margin: calc(var(--space-s) * -1);
12
+ padding: var(--space-s);
13
+ white-space: nowrap;
14
+ }
15
+
16
+ .actions__link--warning {
17
+ --anchor-color: var(--color-error);
18
+ --anchor-color-hover: var(--color-error-variant);
19
+ }
@@ -0,0 +1,19 @@
1
+ {% macro _actionLink(action) %}
2
+ <a class="{{ classes("actions__link", action) }}" href="{{ action.href }}"{{ attributes(action.attributes) }}>
3
+ {{- icon(action.icon) if action.icon -}}
4
+ {{- action.text | safe -}}
5
+ </a>
6
+ {% endmacro %}
7
+ {%- if opts.items.length === 1 %}
8
+ <div class="{{ classes("actions", opts) }}">
9
+ {{ _actionLink(opts.items[0]) | trim }}
10
+ </div>
11
+ {%- else %}
12
+ <ul class="{{ classes("actions", opts) }}" role="list">
13
+ {% for item in opts.items %}{% if item.text %}
14
+ <li class="actions__list-item">
15
+ {{ _actionLink(item) | trim }}
16
+ </li>
17
+ {% endif %}{% endfor %}
18
+ </ul>
19
+ {%- endif %}
@@ -0,0 +1,170 @@
1
+ const focusableSelector = `button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"]`;
2
+
3
+ export const AddAnotherComponent = class extends HTMLElement {
4
+ connectedCallback() {
5
+ this.$addButtonTemplate = this.querySelector("#add-button");
6
+ this.$deleteButtonTemplate = this.querySelector("#delete-button");
7
+ this.$$fields = this.querySelectorAll(".field");
8
+ this.$list = this.querySelector(".add-another__list");
9
+
10
+ this.updateItems();
11
+ this.createAddButton();
12
+ }
13
+
14
+ /**
15
+ * Add item to list
16
+ * @param {Event} event - Add button event
17
+ */
18
+ add(event) {
19
+ event.preventDefault();
20
+ const $newItem = this.createItem();
21
+ this.$list.append($newItem);
22
+ this.updateItems();
23
+ $newItem.querySelector(focusableSelector).focus();
24
+ }
25
+
26
+ /**
27
+ * Delete item from list
28
+ * @param {Event} event - Delete button event
29
+ */
30
+ delete(event) {
31
+ event.preventDefault();
32
+ event.target.closest("li").remove();
33
+ this.updateItems();
34
+ this.focusHeading();
35
+ }
36
+
37
+ /**
38
+ * Get heading
39
+ * @returns {HTMLLegendElement} - Group legend
40
+ */
41
+ getHeading() {
42
+ return this.querySelector("legend");
43
+ }
44
+
45
+ /**
46
+ * Focus heading
47
+ */
48
+ focusHeading() {
49
+ const $heading = this.getHeading();
50
+
51
+ $heading.setAttribute("tabindex", "-1");
52
+ $heading.focus();
53
+ }
54
+
55
+ /**
56
+ * Create add button
57
+ */
58
+ createAddButton() {
59
+ let $addButton = this.$addButtonTemplate.content.cloneNode(true);
60
+
61
+ this.append($addButton);
62
+
63
+ $addButton = this.querySelector(".add-another__add");
64
+ $addButton.addEventListener("click", (event) => this.add(event));
65
+ }
66
+
67
+ /**
68
+ * Get delete button
69
+ * @param {HTMLElement} element - Containing element
70
+ * @returns {HTMLButtonElement} - Delete button
71
+ */
72
+ getDeleteButton(element) {
73
+ return element.querySelector(".add-another__delete");
74
+ }
75
+
76
+ /**
77
+ * Create delete button
78
+ * @param {HTMLElement} element - Containing element
79
+ */
80
+ createDeleteButton(element) {
81
+ const $deleteButton =
82
+ this.$deleteButtonTemplate.content.firstElementChild.cloneNode(true);
83
+
84
+ element.append($deleteButton);
85
+ }
86
+
87
+ /**
88
+ * Update delete button
89
+ * @param {HTMLElement} element - Containing element
90
+ */
91
+ updateDeleteButton(element) {
92
+ const $deleteButton = this.getDeleteButton(element);
93
+ $deleteButton.setAttribute("aria-labelledby", `delete-title ${element.id}`);
94
+ $deleteButton.addEventListener("click", (event) => this.delete(event));
95
+ }
96
+
97
+ /**
98
+ * Create new item by cloning first item in list and updating its attributes
99
+ * @returns {HTMLLIElement} - List item containing form field(s)
100
+ */
101
+ createItem() {
102
+ const $$items = this.querySelectorAll(".add-another__list-item");
103
+ const $item = $$items[0].cloneNode(true);
104
+ const uid = Date.now().toString();
105
+
106
+ const $$fields = $item.querySelectorAll(".field--error");
107
+ for (const $field of $$fields) {
108
+ $field.classList.remove("field--error");
109
+ }
110
+
111
+ const $$errorMessages = $item.querySelectorAll(".error-message");
112
+ for (const $errorMessage of $$errorMessages) {
113
+ $errorMessage.remove();
114
+ }
115
+
116
+ const $$inputs = $item.querySelectorAll("input, select, textarea");
117
+ for (const $input of $$inputs) {
118
+ $input.id = $input.id.replace("-0", `-${uid}`);
119
+ $input.name = $input.name.replace("[0]", `[${uid}]`);
120
+ $input.value = "";
121
+ $input.classList.remove(
122
+ "input--error",
123
+ "select--error",
124
+ "textarea--error",
125
+ );
126
+ }
127
+
128
+ const $$labels = $item.querySelectorAll("label");
129
+ for (const $label of $$labels) {
130
+ const forAttribute = $label.getAttribute("for");
131
+ $label.setAttribute("for", forAttribute.replace("-0", `-${uid}`));
132
+ }
133
+
134
+ $item.id = `${this.id}-${uid}`;
135
+
136
+ return $item;
137
+ }
138
+
139
+ /**
140
+ * Update all items
141
+ * - Update ID’s to use for labelling remove button
142
+ * - Update ARIA label to reference item’s position in list
143
+ * - Add remove buttons (or remove if only one item remaining in list)
144
+ */
145
+ updateItems() {
146
+ const $$items = this.querySelectorAll(".add-another__list-item");
147
+
148
+ for (const [index, $item] of $$items.entries()) {
149
+ $item.id = $item.id || `${this.id}-${index}`;
150
+ $item.setAttribute("aria-label", `Item ${index + 1}`);
151
+
152
+ // If no delete button, add one (if more than 1 item in list)
153
+ // Used when initializing
154
+ if (!this.getDeleteButton($item) && $$items.length > 1) {
155
+ this.createDeleteButton($item);
156
+ }
157
+
158
+ // If has delete button
159
+ if (this.getDeleteButton($item)) {
160
+ if ($$items.length === 1) {
161
+ // If only 1 item in list, remove button
162
+ this.getDeleteButton($item).remove();
163
+ } else {
164
+ // Else update button attributes
165
+ this.updateDeleteButton($item);
166
+ }
167
+ }
168
+ }
169
+ }
170
+ };
@@ -0,0 +1,3 @@
1
+ {% macro addAnother(opts) %}
2
+ {%- include "./template.njk" -%}
3
+ {% endmacro %}
@@ -0,0 +1,63 @@
1
+ add-another {
2
+ --counter-size: 1.66667em;
3
+ display: block;
4
+ }
5
+
6
+ .add-another__list {
7
+ counter-reset: items;
8
+ }
9
+
10
+ .add-another__list-item {
11
+ --label-font: var(--font-fieldset-label);
12
+ margin-block-end: var(--space-m);
13
+ padding-block: var(--space-xs);
14
+ padding-inline-start: calc(var(--counter-size) + var(--space-s));
15
+ position: relative;
16
+
17
+ & .fieldset--group {
18
+ margin-block-start: 0;
19
+ }
20
+
21
+ &::before {
22
+ align-items: center;
23
+ background-color: var(--color-offset);
24
+ block-size: var(--counter-size);
25
+ border-radius: var(--border-radius-small);
26
+ color: var(--color-on-offset);
27
+ content: counter(items);
28
+ counter-increment: items;
29
+ display: flex;
30
+ font: var(--font-label);
31
+ inline-size: var(--counter-size);
32
+ inset: 0;
33
+ justify-content: center;
34
+ position: absolute;
35
+ }
36
+
37
+ &:not([hidden]) {
38
+ display: flex;
39
+ }
40
+
41
+ & > :first-child {
42
+ flex: 1;
43
+ }
44
+ }
45
+
46
+ .add-another__add.button {
47
+ display: flex;
48
+ inline-size: calc(100% - var(--counter-size) - var(--space-s));
49
+ margin-block-start: 0;
50
+ margin-inline-start: calc(var(--counter-size) + var(--space-s));
51
+ }
52
+
53
+ .add-another__delete.button {
54
+ --button-padding: 0;
55
+ --icon-size: 0.875em;
56
+
57
+ block-size: var(--counter-size);
58
+ display: flex;
59
+ inline-size: var(--counter-size);
60
+ inset-block-start: var(--counter-size);
61
+ inset-inline-start: 0;
62
+ position: absolute;
63
+ }
@@ -0,0 +1,39 @@
1
+ {% from "../button/macro.njk" import button with context %}
2
+ {% from "../field/macro.njk" import field with context %}
3
+ {% from "../fieldset/macro.njk" import fieldset with context %}
4
+ {% set id = opts.id or opts.name | slugify({ decamelize: true }) %}
5
+ {# `fieldset` is false by default #}
6
+ {%- set hasFieldset = true if opts.fieldset else false %}
7
+ {# Capture the HTML so we can optionally nest it within a fieldset #}
8
+ {%- set innerHtml %}{{ caller() if caller }}{% endset %}
9
+ {% call field({
10
+ element: "add-another",
11
+ classes: opts.field.classes,
12
+ attributes: {
13
+ id: id
14
+ }
15
+ }) %}
16
+ {% if opts.fieldset %}
17
+ {% call fieldset({
18
+ describedBy: describedBy,
19
+ classes: opts.fieldset.classes,
20
+ attributes: opts.fieldset.attributes,
21
+ legend: opts.fieldset.legend
22
+ }) %}{{ innerHtml | trim | safe }}{% endcall %}
23
+ {% else %}
24
+ {{ innerHtml | trim | safe }}
25
+ {% endif %}
26
+ <template id="add-button">
27
+ {{ button({
28
+ classes: "add-another__add button--secondary",
29
+ text: __("addAnother.add", opts.name)
30
+ }) | indent(4) }}
31
+ </template>
32
+ <template id="delete-button">
33
+ {{ button({
34
+ classes: "add-another__delete button--warning",
35
+ icon: "delete",
36
+ iconText: __("addAnother.delete")
37
+ }) | indent(4) }}
38
+ </template>
39
+ {% endcall %}
@@ -0,0 +1,45 @@
1
+ .app {
2
+ background-color: var(--color-offset);
3
+ display: flex;
4
+ flex-direction: column;
5
+ font-family: var(--font-family-sans);
6
+ justify-content: space-between;
7
+ }
8
+
9
+ .app--minimalui {
10
+ --container-max-inline-size: 36rem;
11
+
12
+ & .header,
13
+ & .footer {
14
+ border: 0;
15
+ }
16
+
17
+ & .header__container,
18
+ & .footer__container {
19
+ align-items: center;
20
+ inline-size: auto;
21
+ }
22
+
23
+ & .main {
24
+ @media (width > 36rem) {
25
+ border-radius: var(--border-radius-large);
26
+ flex: 0;
27
+ margin: auto;
28
+ overflow: hidden;
29
+ }
30
+ }
31
+
32
+ & .main__container {
33
+ padding-block: var(--space-l);
34
+ }
35
+
36
+ & .notification {
37
+ border-start-end-radius: var(--border-radius-large);
38
+ border-start-start-radius: var(--border-radius-large);
39
+ }
40
+
41
+ & .notification + .main__container {
42
+ border-start-end-radius: 0;
43
+ border-start-start-radius: 0;
44
+ }
45
+ }
@@ -0,0 +1,3 @@
1
+ {% macro authorize(opts) %}
2
+ {%- include "./template.njk" -%}
3
+ {% endmacro %}
@@ -0,0 +1,23 @@
1
+ .authorize {
2
+ --authorize-client-icon-size: 4rem;
3
+ line-height: var(--line-height-tight);
4
+
5
+ &:has(.authorize__client-icon) {
6
+ min-block-size: var(--authorize-client-icon-size);
7
+ }
8
+
9
+ & a {
10
+ font-weight: 600;
11
+ }
12
+ }
13
+
14
+ .authorize__client-icon {
15
+ background-color: var(--color-neutral90); /* Ignore color-scheme */
16
+ block-size: var(--authorize-client-icon-size);
17
+ border-radius: var(--border-radius-small);
18
+ box-shadow: inset 0 0 0 1px var(--color-shadow);
19
+ float: inline-start;
20
+ inline-size: var(--authorize-client-icon-size);
21
+ margin-inline-end: var(--space-s);
22
+ padding: var(--space-2xs);
23
+ }
@@ -0,0 +1,14 @@
1
+ {% set clientLink = opts.client.name | friendlyUrl | linkTo(opts.client.url) %}
2
+ {% set meLink = opts.me | friendlyUrl | replace("/", "/<wbr>") | linkTo(opts.me) %}
3
+ <p class="{{ classes("authorize", opts) }} s-flow"
4
+ {{- attributes(opts.attributes) }}>
5
+ {% if opts.client.logo %}
6
+ <a class="authorize__client" href="{{ opts.client.url }}">
7
+ <img class="authorize__client-icon" src="{{ opts.client.logo }}" alt="" height="64" width="64">
8
+ </a>
9
+ {% endif %}
10
+ {{ __(opts.key, {
11
+ client: "__client__",
12
+ me: "__me__"
13
+ }) | replace("__client__", clientLink) | replace("__me__", meLink) | markdown("inline") | safe }}
14
+ </p>
@@ -0,0 +1,3 @@
1
+ {% macro avatar(opts) %}
2
+ {%- include "./template.njk" -%}
3
+ {% endmacro %}
@@ -0,0 +1,23 @@
1
+ .avatar {
2
+ background:
3
+ radial-gradient(
4
+ circle,
5
+ var(--color-offset-variant-darker) 50%,
6
+ transparent 50%
7
+ )
8
+ 50% 20%/75% 75% no-repeat,
9
+ radial-gradient(
10
+ circle,
11
+ var(--color-offset-variant-darker) 50%,
12
+ transparent 50%
13
+ )
14
+ 50% -50%/100% 160% no-repeat,
15
+ var(--color-offset);
16
+ block-size: var(--avatar-size, 3rem);
17
+ border-radius: var(--border-radius-small);
18
+ inline-size: var(--avatar-size, 3rem);
19
+ max-inline-size: none;
20
+ object-fit: cover;
21
+ outline: var(--border-width-thin) solid var(--color-shadow);
22
+ outline-offset: calc(var(--border-width-thin) * -1);
23
+ }
@@ -0,0 +1 @@
1
+ <img class="{{ classes("avatar", opts) }}" src="{{ opts.src }}" alt="{{ opts.alt }}">
@@ -0,0 +1,3 @@
1
+ {% macro backLink(opts) %}
2
+ {%- include "./template.njk" -%}
3
+ {% endmacro %}
@@ -0,0 +1,46 @@
1
+ .back-link {
2
+ --anchor-decoration-color: transparent;
3
+ --back-link-padding: var(--space-s);
4
+ --back-link-chevron-rotation: -45deg;
5
+ --back-link-chevron-size: 0.5em;
6
+ --back-link-chevron-thickness: var(--text-thickness);
7
+
8
+ display: inline-block;
9
+ font: var(--font-caption);
10
+ margin-inline: calc(var(--back-link-padding) * -1);
11
+ padding: var(--back-link-padding);
12
+ padding-block-start: var(--back-link-padding);
13
+ padding-inline-start: calc(var(--back-link-padding) * 2);
14
+ position: relative;
15
+
16
+ &::before {
17
+ block-size: var(--back-link-chevron-size);
18
+ border: 0 solid currentcolor;
19
+ border-block-start-width: var(--back-link-chevron-thickness);
20
+ border-inline-start-width: var(--back-link-chevron-thickness);
21
+ content: "";
22
+ display: block;
23
+ inline-size: var(--back-link-chevron-size);
24
+ inset-block-start: calc(
25
+ var(--back-link-padding) + var(--back-link-chevron-size)
26
+ );
27
+ inset-inline-start: var(--back-link-padding);
28
+ position: absolute;
29
+ transform: rotate(var(--back-link-chevron-rotation));
30
+ }
31
+
32
+ &:focus-visible::before,
33
+ &:hover::before {
34
+ --back-link-chevron-thickness: calc(var(--text-thickness) * 2);
35
+ }
36
+
37
+ &::after {
38
+ content: "";
39
+ inset: 0;
40
+ position: absolute;
41
+ }
42
+ }
43
+
44
+ :root[dir="rtl"] .back-link {
45
+ --back-link-chevron-rotation: 45deg;
46
+ }
@@ -0,0 +1,5 @@
1
+ <div class="-!-container">
2
+ <a class="{{ classes("back-link", opts) }}" href="{{ opts.href }}">
3
+ {{- opts.text | default(__("backLink.text")) | safe -}}
4
+ </a>
5
+ </div>
@@ -0,0 +1,3 @@
1
+ {% macro badge(opts) %}
2
+ {%- include "./template.njk" -%}
3
+ {% endmacro %}
@@ -0,0 +1,85 @@
1
+ .badge {
2
+ /*
3
+ * 1. When a user customises their colours, often the background is removed.
4
+ * Adding an outline ensures that badge still keeps it’s meaning.
5
+ *
6
+ * @link https://accessibility.blog.gov.uk/2017/03/27/how-users-change-colours-on-websites/
7
+ *
8
+ * 2. Adjust baseline to visually center text within pill shape.
9
+ */
10
+ --icon-margin: var(--space-xs);
11
+ align-items: center;
12
+ background-color: var(--color-primary);
13
+ border-radius: var(--space-l);
14
+ color: var(--color-on-primary);
15
+ display: inline flow-root;
16
+ font: var(--font-caption);
17
+ font-weight: 500;
18
+ outline: var(--border-width-thick) solid transparent; /* 1 */
19
+ outline-offset: calc(var(--border-width-thick) * -1); /* 1 */
20
+ padding-block-end: calc(var(--space-2xs) - 0.0625rem); /* 2 */
21
+ padding-block-start: calc(var(--space-2xs) + 0.0625rem); /* 2 */
22
+ padding-inline: var(--space-m);
23
+ white-space: nowrap;
24
+
25
+ & + .badge {
26
+ margin-inline-start: var(--space-2xs);
27
+ }
28
+
29
+ & .icon {
30
+ inset-block-start: -0.125em;
31
+ }
32
+ }
33
+
34
+ .badge--small {
35
+ font-size: 0.75rem;
36
+ padding-block-end: calc(var(--space-2xs) / 2 - 0.0625rem);
37
+ padding-block-start: calc(var(--space-2xs) / 2 + 0.0625rem);
38
+ padding-inline: var(--space-s);
39
+ }
40
+
41
+ .badge--green {
42
+ background: var(--color-green50);
43
+ color: var(--color-green10);
44
+ }
45
+
46
+ .badge--purple {
47
+ background: var(--color-purple45);
48
+ color: var(--color-neutral99);
49
+ }
50
+
51
+ .badge--red {
52
+ background: var(--color-red45);
53
+ color: var(--color-neutral99);
54
+ }
55
+
56
+ .badge--yellow {
57
+ background: var(--color-yellow50);
58
+ color: var(--color-neutral10);
59
+ }
60
+
61
+ .badge--offset {
62
+ background: var(--color-offset);
63
+ box-shadow: inset 0 0 0 1px var(--color-shadow);
64
+ color: var(--color-on-offset);
65
+ }
66
+
67
+ .badge--offset-green {
68
+ background: var(--color-green90);
69
+ color: var(--color-green10);
70
+ }
71
+
72
+ .badge--offset-purple {
73
+ background: var(--color-purple90);
74
+ color: var(--color-purple10);
75
+ }
76
+
77
+ .badge--offset-red {
78
+ background: var(--color-red90);
79
+ color: var(--color-red10);
80
+ }
81
+
82
+ .badge--offset-yellow {
83
+ background: var(--color-yellow90);
84
+ color: var(--color-yellow10);
85
+ }
@@ -0,0 +1,7 @@
1
+ <strong class="{{ classes("badge", opts) }}
2
+ {{- " badge--" + opts.size if opts.size }}
3
+ {{- " badge--" + opts.color if opts.color }}"
4
+ {{- attributes(opts.attributes) }}>
5
+ {{- icon(opts.icon) if opts.icon -}}
6
+ {{- opts.text | safe -}}
7
+ </strong>
@@ -0,0 +1,3 @@
1
+ {% macro bookmarklet(opts) %}
2
+ {%- include "./template.njk" -%}
3
+ {% endmacro %}