@stackoverflow/stacks 2.2.0 → 2.3.0

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.
@@ -2,82 +2,76 @@
2
2
  // CONTEXTUAL STYLES
3
3
  #stacks-internals #screen-sm({
4
4
  .s-btn {
5
+ --_bu-px: 0.4em;
6
+
5
7
  &.s-btn__dropdown {
6
8
  padding-right: 1.2em;
7
9
 
8
10
  &:after {
9
- right: 0.4em;
11
+ right: var(--_bu-px);
10
12
  }
11
13
  }
12
-
13
- padding-left: 0.4em;
14
- padding-right: 0.4em;
15
14
  }
16
15
  }, @force-selector: true);
17
16
 
18
- // VARIANTS
19
- &:not(&--radio) .s-btn:not(:first-child):not(:last-child),
20
- &&--radio .s-btn:not(:first-of-type):not(:last-of-type) {
21
- border-radius: 0;
22
- }
23
-
24
- &:not(&--radio) .s-btn:first-child:not(:only-child),
25
- &&--radio .s-btn:first-of-type:not(:last-of-type) {
26
- border-top-right-radius: 0;
27
- border-bottom-right-radius: 0;
28
- }
29
-
30
- &:not(&--radio) .s-btn:last-child:not(:only-child),
31
- &&--radio .s-btn:last-of-type:not(:first-of-type) {
32
- border-top-left-radius: 0;
33
- border-bottom-left-radius: 0;
17
+ // CHILD ELEMENTS
18
+ form {
19
+ display: flex;
20
+ margin-right: calc(var(--su-static1) * -1); // -1px
34
21
  }
35
22
 
36
- &:not(&--radio) .s-btn:not(:last-child),
37
- &&--radio .s-btn:not(:last-of-type) {
38
- margin-right: calc(var(--su-static1) * -1);
39
- }
23
+ .s-btn {
24
+ --_bu-br: var(--br-sm);
25
+ --_bu-bc-hover: transparent;
40
26
 
41
- // CHILD ELEMENTS
42
- form {
43
- &:not(:first-child):not(:last-child) {
44
- .s-btn {
45
- border-radius: 0;
46
- }
27
+ &,
28
+ &.s-btn__md {
29
+ --_bu-px: var(--su12);
30
+ --_bu-py: var(--su8);
47
31
  }
48
32
 
49
- &:last-child:not(:only-child) {
50
- .s-btn:not(:last-child) {
51
- border-radius: 0;
52
- }
33
+ &.s-btn___xs {
34
+ --_bu-px: var(--su8);
35
+ --_bu-py: var(--su4);
53
36
  }
54
37
 
55
- &:first-child:not(:only-child) {
56
- .s-btn:not(:first-child) {
57
- border-radius: 0;
58
- }
38
+ &.s-btn___sm {
39
+ --_bu-px: calc(var(--su8) + var(--su2));
40
+ --_bu-py: var(--su6);
59
41
  }
60
42
 
61
- display: flex;
62
- margin-right: calc(var(--su-static1) * -1); // -1px
63
- }
43
+ &.is-selected,
44
+ &--radio:checked + .s-btn {
45
+ font-weight: bold;
46
+ }
64
47
 
65
- .s-btn {
66
- &:active {
67
- z-index: var(--zi-active);
48
+ .s-btn--badge {
49
+ font-weight: normal;
68
50
  }
69
51
 
70
- &.is-selected,
71
- &--radio:checked + .s-btn {
72
- z-index: var(--zi-selected); // When the button is active or selected, it should pop above its siblings
52
+ & .s-btn--text {
53
+ &:before {
54
+ content: attr(data-text);
55
+ content: attr(data-text) / "";
56
+ font-weight: bold;
57
+ height: 0;
58
+ pointer-events: none;
59
+ user-select: none;
60
+ visibility: hidden;
61
+ }
62
+
63
+ display: inline-flex;
64
+ flex-direction: column;
73
65
  }
74
66
 
75
- margin-bottom: calc(var(--su-static1) * -1); // When wrapping we need to account for the border
76
67
  white-space: nowrap; // When the buttons wrap, they get super tall and mess up the whole layout
77
68
  }
78
69
 
79
70
  // STATIC COMPONENT STYLES
80
- display: flex;
71
+ border: var(--su-static1) solid var(--black-300);
72
+ border-radius: var(--br-md);
73
+ display: inline-flex; // TODO investigate if changing from flex to inline-flex will be an issue
81
74
  flex-wrap: wrap;
82
75
  margin-bottom: var(--su-static1); // Compensate for buttons having a margin bottom of -1px to account for row wrapping
76
+ padding: calc(var(--su-static4) - var(--su-static1));
83
77
  }
@@ -0,0 +1,77 @@
1
+ import { html } from "@open-wc/testing";
2
+ import type { TestVariationArgs } from "../../test/test-utils";
3
+
4
+ const btns = [
5
+ { name: "Newest", isSelected: true },
6
+ { name: "Frequent" },
7
+ { name: "Active" },
8
+ ];
9
+
10
+ const getBtn = ({
11
+ name = "",
12
+ isRadio,
13
+ isSelected,
14
+ hasBadge,
15
+ }: {
16
+ name: string;
17
+ isRadio?: boolean;
18
+ isSelected?: boolean;
19
+ hasBadge?: boolean;
20
+ }): string => {
21
+ const baseClasses = "s-btn s-btn__muted";
22
+ const btnChildren = `
23
+ <span class="s-btn--text" data-text="${name}">${name}</span>
24
+ ${
25
+ hasBadge
26
+ ? `<span class="s-btn--badge"><span class="s-btn--number">123</span></span>`
27
+ : ""
28
+ }
29
+ `;
30
+
31
+ return isRadio
32
+ ? `<input
33
+ class="s-btn--radio"
34
+ type="radio"
35
+ name="test-btn-radio-group"
36
+ id="btn-${name}"
37
+ ${isSelected ? "checked" : ""}/>
38
+ <label class="${baseClasses}" for="btn-${name}">
39
+ ${btnChildren}
40
+ </label>`
41
+ : `<button
42
+ class="${baseClasses}${isSelected ? " is-selected" : ""}"
43
+ ${isSelected ? `aria-current="true"` : ""}
44
+ type="button">
45
+ ${btnChildren}
46
+ </button>`;
47
+ };
48
+
49
+ const getBtns = (ids: number[]): string => {
50
+ return ids.map((id) => getBtn(btns[id])).join("");
51
+ };
52
+
53
+ const testArgs: TestVariationArgs = {
54
+ baseClass: "s-btn-group",
55
+ children: {
56
+ default: getBtns([0, 1, 2]),
57
+ single: getBtns([0]),
58
+ form: `
59
+ ${getBtns([0])}
60
+ <form class="mb0 p0">
61
+ ${getBtn(btns[1])}
62
+ </form>
63
+ ${getBtns([2])}
64
+ `,
65
+ badge: btns.map((btn) => getBtn({ ...btn, hasBadge: true })).join(""),
66
+ radio: btns.map((btn) => getBtn({ ...btn, isRadio: true })).join(""),
67
+ },
68
+ template: ({ component, testid }) =>
69
+ html`<div
70
+ class="d-inline-flex ai-center jc-center p8"
71
+ data-testid="${testid}"
72
+ >
73
+ ${component}
74
+ </div>`,
75
+ };
76
+
77
+ export { testArgs };
@@ -0,0 +1,7 @@
1
+ import { testArgs } from "./button-group.test.setup";
2
+ import { runVisualTests } from "../../test/visual-test-utils";
3
+ import "../../index";
4
+
5
+ describe("button group", () => {
6
+ runVisualTests(testArgs);
7
+ });
@@ -102,7 +102,9 @@
102
102
  }
103
103
 
104
104
  // INTERACTION
105
- &:focus {
105
+ // Note: We're applying the focus styles both on `:focus` and `:focus-within` since this component can sometimes be used on the parent of an input such as in our tag selector in Core.
106
+ &:focus,
107
+ &:focus-within {
106
108
  .focus-styles();
107
109
  }
108
110
 
@@ -0,0 +1,25 @@
1
+ import { runA11yTests } from "../../test/a11y-test-utils";
2
+ import testArgs from "./post-summary.test.setup";
3
+ import "../../index";
4
+
5
+ describe("post-summary", () => {
6
+ // Base, sparce
7
+ runA11yTests({
8
+ ...testArgs.base,
9
+ // TODO resolve test failures
10
+ skippedTestids: [
11
+ /-deleted/,
12
+ /-ignored/,
13
+ /-highcontrast-(light|dark)-watched/,
14
+ ],
15
+ });
16
+
17
+ // Truncated description sizes
18
+ runA11yTests(testArgs.sizes);
19
+
20
+ // Stats - answers, view hotness
21
+ runA11yTests(testArgs.stats);
22
+
23
+ // Badges
24
+ runA11yTests(testArgs.badges);
25
+ });
@@ -0,0 +1,435 @@
1
+ import { html } from "@open-wc/testing";
2
+ import {
3
+ IconArchiveSm,
4
+ IconCheckmarkSm,
5
+ IconEllipsisVertical,
6
+ IconEyeSm,
7
+ IconNotInterested,
8
+ IconPencilSm,
9
+ IconTackSm,
10
+ IconTrashSm,
11
+ } from "@stackoverflow/stacks-icons/icons";
12
+ import type { TestVariationArgs } from "../../test/test-utils";
13
+ import "../../index";
14
+
15
+ type BadgeType =
16
+ | "danger"
17
+ | "danger-filled"
18
+ | "info"
19
+ | "muted"
20
+ | "muted-filled"
21
+ | "warning";
22
+
23
+ type Stats = {
24
+ votes: number;
25
+ views: number;
26
+ answers: number;
27
+ accepted?: boolean;
28
+ bounty?: number;
29
+ badge?: BadgeType;
30
+ };
31
+
32
+ type Tags = { text: string; type?: "required" | "moderator" }[];
33
+
34
+ type TruncationSizes = "sm" | "md" | "lg" | "";
35
+
36
+ const formatNumber = (num: number) => {
37
+ switch (true) {
38
+ case num > 10000090:
39
+ return (num / 1000000).toFixed(0) + "m";
40
+ case num > 1000000:
41
+ return (num / 1000000).toFixed(1) + "m";
42
+ case num > 10000:
43
+ return (num / 1000).toFixed(0) + "k";
44
+ case num > 1000:
45
+ return (num / 1000).toFixed(1) + "k";
46
+ default:
47
+ return num.toString();
48
+ }
49
+ };
50
+
51
+ const getBadge = (type: BadgeType) => {
52
+ const badgeClasses = type
53
+ .split("-")
54
+ .map((modifier) => `s-badge__${modifier}`)
55
+ .join(" ");
56
+ const getIcon = () => {
57
+ switch (type) {
58
+ case "danger":
59
+ return IconNotInterested;
60
+ case "danger-filled":
61
+ return IconTrashSm;
62
+ case "info":
63
+ return IconPencilSm;
64
+ case "muted":
65
+ return IconArchiveSm;
66
+ case "muted-filled":
67
+ return IconTackSm;
68
+ case "warning":
69
+ return IconEyeSm;
70
+ default:
71
+ return "";
72
+ }
73
+ };
74
+
75
+ const getText = () => {
76
+ switch (type) {
77
+ case "danger":
78
+ return "Closed";
79
+ case "danger-filled":
80
+ return "Deleted";
81
+ case "info":
82
+ return "Draft";
83
+ case "muted":
84
+ return "Archived";
85
+ case "muted-filled":
86
+ return "Pinned";
87
+ case "warning":
88
+ return "Review";
89
+ default:
90
+ return "";
91
+ }
92
+ };
93
+
94
+ return `
95
+ <div
96
+ class="s-post-summary--stats-item s-badge s-badge__icon ${badgeClasses}"
97
+ >
98
+ ${getIcon()}
99
+ ${getText()}
100
+ </div>`;
101
+ };
102
+
103
+ const getDescription = (truncation?: TruncationSizes, text?: string) => `
104
+ <p class="s-post-summary--content-excerpt
105
+ ${truncation ? `s-post-summary--content-excerpt__${truncation}` : ""}
106
+ ">
107
+ ${text ? text : "In the spirit of type safety associated with the CriteriaQuery JPA 2.0 also has an API to support Metamodel representation of entities. Is anyone aware of a fully functional implementation of this API (to generate the Metamodel as opposed to creating the metamodel classes manually)? It would be awesome if someone also knows the steps for setting this up in Eclipse (I assume it's as simple as setting up an annotation processor, but you never know)."}
108
+ </p>
109
+ `;
110
+
111
+ const getHotnessClass = (num: number) => {
112
+ switch (true) {
113
+ case num > 100000:
114
+ return "is-supernova";
115
+ case num > 10000:
116
+ return "is-hot";
117
+ case num > 1000:
118
+ return "is-warm";
119
+ default:
120
+ return "";
121
+ }
122
+ };
123
+
124
+ const getStats = ({
125
+ votes,
126
+ views,
127
+ answers,
128
+ accepted,
129
+ bounty,
130
+ badge,
131
+ }: Stats) => `
132
+ <div class="s-post-summary--stats">
133
+ ${badge ? getBadge(badge) : ""}
134
+ <div class="s-post-summary--stats-item s-post-summary--stats-item__emphasized">
135
+ <span class="s-post-summary--stats-item-number">${formatNumber(votes)}</span>
136
+ <span class="s-post-summary--stats-item-unit">${votes === 1 ? "vote" : "votes"}</span>
137
+ </div>
138
+ <div class="s-post-summary--stats-item ${accepted ? "has-accepted-answer" : ""} ${answers > 0 ? "has-answers" : ""}">
139
+ ${accepted ? IconCheckmarkSm : ""}
140
+ <span class="s-post-summary--stats-item-number">${formatNumber(answers)}</span>
141
+ <span class="s-post-summary--stats-item-unit">${answers === 1 ? "answer" : "answers"}</span>
142
+ </div>
143
+ <div class="s-post-summary--stats-item ${getHotnessClass(views)}">
144
+ <span class="s-post-summary--stats-item-number">${formatNumber(views)}</span>
145
+ <span class="s-post-summary--stats-item-unit">${views === 1 ? "view" : "views"}</span>
146
+ </div>
147
+ ${
148
+ bounty
149
+ ? `
150
+ <div class="s-post-summary--stats-item s-badge s-badge__bounty">
151
+ +${bounty}
152
+ </div>
153
+ `
154
+ : ""
155
+ }
156
+ </div>
157
+ `;
158
+
159
+ const getTags = (tags?: Tags) => {
160
+ const tagsArr = tags ?? [
161
+ {
162
+ text: "feature-request",
163
+ type: "required",
164
+ },
165
+ {
166
+ text: "status-complete",
167
+ type: "moderator",
168
+ },
169
+ {
170
+ text: "design",
171
+ },
172
+ ];
173
+
174
+ const tagsHTML = tagsArr
175
+ .map(
176
+ ({ text, type }) => `
177
+ <a class="s-tag ${type ? `s-tag__${type}` : ""}" href="/">${text}</a>
178
+ `
179
+ )
180
+ .join("");
181
+
182
+ return `<div class="s-post-summary--meta-tags">${tagsHTML}</div>`;
183
+ };
184
+
185
+ const getUser = () => `
186
+ <div class="s-user-card s-user-card__minimal">
187
+ <a href="#" class="s-avatar s-user-card--avatar">
188
+ <img class="s-avatar--image" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAATwAAAE8CAMAAABq2/00AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABhQTFRF/3IA/////44y/8OS/+fU//Xs/6tn/9e2EhvbMQAABH9JREFUeNrs3e1y2ygAhWELJHH/d7zuJpN1XAnxoe408Ly/6xnnHXEOIEwfDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/gbAGEhrZl2VloY20PIk8tAzZbfkXA7eeuHyysVfdFMsXiY66ptiWF8Re05BdxF7HkBV7PUNW7FVx4E7sVSwrDjBw2+pC7NWwHtkTe3ULM7En9v6O2ONF7Ik9sSf2IPbEntgTexB7t8feTsynniD2Oh6tXex1hFoUe02kaxVi72JMZs+Rib0LLdkXFGLvaECWjkOxdxVmUex1rB6S2Kss2lcytSH2LnVkakPsXQ7E8xwTe5fuMrUh9vKj8CP4xN7lNOXc3mnwib1M2X7Z28VeS93mg0/sFZTG6WCMVSE51fqsYL4s9jpqQ+yV1caxErHXUxtir6c2xF5HbYRF7LXXhtjrqQ2x11MbYu9tLG4VtSH2empD7BUNxpPaSGKvPPh2sdcxX45i78baEHs18+X32hB7NfPl99oQex21MVHsxViaR8W1MU3s/XpMSvWF0tqYJfY+BmMq01dcG+scP6/6enTK9BW+1J0j9l5aYN0rP5BzM0XsbSUnAlpqY4LYezexFeRSbpslH3uDXdF64OG6est258PohXE8BK+7o6g29rJTQsPt1F3qK9qdTwMP2Wz2X1Vv0UvdbeQ53nl2Xesr2Z0Pww7Zs5lsafWW1MY+6JDNxv5/+kLb5/fXfzLirRdhKSGnr6A2tkGvJoxLGZnqva6NkAbdgA+pUN9a+QuWYYPu+98ee/W1/PJgoMG7lek7nW3UHiEdbKpcqu+kO2L9b4aG0rcWjt5jfWf2Z7kCeE891XtSG/O86A5d+tbZj1h0VW+c/ja90FG9uxMCFdWb/+SkZ1Oaq/d1vjzvXfvF+tLp+aiZT5S1Vm90lrFj02B3bW1d9X7T92u+7Aq9qk2D+Fob/v/Myu7YostC76xe9K966evfr5+7ekuXHVy1V6+R275pEMd3kPbGB+Syeod/8D7Sf41NBvPdMf7a4uXpaTGY0zd+4r0vDlKtwdPqHf/BOzzf8zQYqvRtcz54mXfUNUVyUL0T7AhcrBbKY/C36p1geVEy1y00+F3fBA9eKFxnlRXJa/XOcKxnqeF6Pv1VvTPc7RuXai6K5LN6Z9hQSUsb2Rh86pviUultaScTg/sMD15YeqmcT8/bFx1Foi/umk9P3hcMfqTenrabBT5j8DGTwHivwelOCTwNrnfJm/Ol2U0GZ74WdE+dBn9+Z/z2J9UZ7IjB7dZv8gPl9RRJIq89BiN57QZ38trn04G8k62E6xjcHuQ1D+JEXrvBnbz2+XQgr30+/SCveT69ktceg4m8doOBvDG/CXnkkTezvOXPQB555JFHHnnkkUceeeSRRx555JFHHnnkkWcnmTzyyCOPPPLII4888sgjjzzfhDzyyCOPPPL+9Ff+eyCPPPLII4888sgjjzzyyCOPPPLII4888sgDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPy//CPAAPiZOI3BPDFQAAAAAElFTkSuQmCC" alt="placeholder avatar">
189
+ <span class="v-visible-sr">Tracy Smith</span>
190
+ </a>
191
+ <a href="#" class="s-user-card--link">Tracy Smith</a>
192
+ <ul class="s-user-card--awards">
193
+ <li class="s-user-card--rep">1350</li>
194
+ </ul>
195
+ <time class="s-user-card--time">asked just now</time>
196
+ </div>
197
+ `;
198
+
199
+ const getChildren = ({
200
+ show = {
201
+ description: false,
202
+ menuBtn: false,
203
+ stats: false,
204
+ tags: false,
205
+ title: false,
206
+ user: false,
207
+ },
208
+ description = {
209
+ truncation: "",
210
+ text: "",
211
+ },
212
+ stats,
213
+ tags,
214
+ title,
215
+ }: {
216
+ show?: {
217
+ description?: boolean;
218
+ menuBtn?: boolean;
219
+ stats?: boolean;
220
+ tags?: boolean;
221
+ title?: boolean;
222
+ user?: boolean;
223
+ };
224
+ description?: {
225
+ truncation?: TruncationSizes;
226
+ text?: string;
227
+ };
228
+ stats?: Stats;
229
+ tags?: Tags;
230
+ title?: string;
231
+ }) => {
232
+ const titleEl =
233
+ show.title || title
234
+ ? `
235
+ <h3 class="s-post-summary--content-title">
236
+ ${title ? title : "How to generate the JPA entity Metamodel?"}
237
+ </h3>
238
+ `
239
+ : "";
240
+ const descriptionEl =
241
+ show.description || description.truncation || description.text
242
+ ? description
243
+ ? getDescription(description.truncation, description.text)
244
+ : getDescription()
245
+ : "";
246
+ const tagsEl = show.tags || tags ? getTags(tags) : "";
247
+ const userEl = show.user ? getUser() : "";
248
+ const menuBtnEl = show.menuBtn
249
+ ? `
250
+ <a href="#" class="s-btn s-btn__muted s-post-summary--content-menu-button">
251
+ ${IconEllipsisVertical}
252
+ <span class="v-visible-sr">menu</span>
253
+ </a>
254
+ `
255
+ : "";
256
+
257
+ return `
258
+ ${
259
+ show.stats || stats
260
+ ? getStats(
261
+ stats
262
+ ? stats
263
+ : {
264
+ votes: 95,
265
+ views: 104123,
266
+ answers: 5,
267
+ accepted: true,
268
+ bounty: 50,
269
+ }
270
+ )
271
+ : ""
272
+ }
273
+ ${
274
+ titleEl || descriptionEl || tagsEl || userEl || menuBtnEl
275
+ ? `
276
+ <div class="s-post-summary--content">
277
+ ${titleEl}
278
+ ${descriptionEl}
279
+ <div class="s-post-summary--meta">
280
+ ${tagsEl}
281
+ ${userEl}
282
+ </div>
283
+ ${menuBtnEl}
284
+ </div>`
285
+ : ""
286
+ }
287
+ `;
288
+ };
289
+
290
+ const getBadgeChildren = (badge: BadgeType) => {
291
+ return getChildren({
292
+ show: {
293
+ stats: true,
294
+ },
295
+ stats: {
296
+ badge: badge as BadgeType,
297
+ answers: 0,
298
+ votes: 1,
299
+ views: 20,
300
+ },
301
+ });
302
+ };
303
+
304
+ const getSizeChildren = (size: string) => {
305
+ return getChildren({
306
+ show: {
307
+ description: true,
308
+ menuBtn: true,
309
+ stats: true,
310
+ tags: true,
311
+ title: true,
312
+ user: true,
313
+ },
314
+ description: {
315
+ truncation: size as TruncationSizes,
316
+ },
317
+ });
318
+ };
319
+
320
+ const getStatsChildren = ({
321
+ accepted = false,
322
+ answers = 1,
323
+ views = 20,
324
+ }: {
325
+ accepted?: boolean;
326
+ answers?: number;
327
+ views?: number;
328
+ }) =>
329
+ getChildren({
330
+ show: {
331
+ stats: true,
332
+ },
333
+ stats: {
334
+ votes: 1,
335
+ answers,
336
+ accepted,
337
+ views,
338
+ },
339
+ });
340
+
341
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
342
+ const template = ({ component, testid }: any) => html`
343
+ <div class="d-flex ai-center jc-center p8 ws6" data-testid="${testid}">
344
+ ${component}
345
+ </div>
346
+ `;
347
+
348
+ const testArgs: {
349
+ [key: string]: TestVariationArgs;
350
+ } = {
351
+ base: {
352
+ baseClass: "s-post-summary",
353
+ modifiers: {
354
+ primary: ["deleted", "ignored", "watched"], // variants described as modifiers to test colliding modifiers
355
+ secondary: ["minimal"],
356
+ global: ["w100"],
357
+ },
358
+ children: {
359
+ default: getChildren({
360
+ show: {
361
+ description: true,
362
+ menuBtn: true,
363
+ stats: true,
364
+ tags: true,
365
+ title: true,
366
+ user: true,
367
+ },
368
+ }),
369
+ sparce: getChildren({
370
+ show: {
371
+ stats: true,
372
+ tags: true,
373
+ title: true,
374
+ user: true,
375
+ },
376
+ tags: [
377
+ {
378
+ text: "featured-request",
379
+ type: "required",
380
+ },
381
+ ],
382
+ title: "Short title",
383
+ }),
384
+ },
385
+ options: {
386
+ includeNullModifier: false,
387
+ },
388
+ template,
389
+ },
390
+ badges: {
391
+ baseClass: "s-post-summary",
392
+ children: {
393
+ "badge-danger": getBadgeChildren("danger"),
394
+ "badge-danger-filled": getBadgeChildren("danger-filled"),
395
+ "badge-info": getBadgeChildren("info"),
396
+ "badge-muted": getBadgeChildren("muted"),
397
+ "badge-muted-filled": getBadgeChildren("muted-filled"),
398
+ "badge-warning": getBadgeChildren("warning"),
399
+ },
400
+ template,
401
+ },
402
+ sizes: {
403
+ baseClass: "s-post-summary",
404
+ modifiers: {
405
+ global: ["w100"],
406
+ },
407
+ children: {
408
+ "description-sm": getSizeChildren("sm"),
409
+ "description-md": getSizeChildren("md"),
410
+ "description-lg": getSizeChildren("lg"),
411
+ },
412
+ options: {
413
+ includeNullModifier: false,
414
+ },
415
+ template,
416
+ },
417
+ stats: {
418
+ baseClass: "s-post-summary",
419
+ children: {
420
+ "stats-unanswered": getStatsChildren({ answers: 0 }),
421
+ "stats-answered": getStatsChildren({ answers: 1 }),
422
+ "stats-answered-accepted": getStatsChildren({
423
+ answers: 10,
424
+ accepted: true,
425
+ }),
426
+ "stats-views": getStatsChildren({ views: 1 }),
427
+ "stats-views-warm": getStatsChildren({ views: 1001 }),
428
+ "stats-views-hot": getStatsChildren({ views: 10001 }),
429
+ "stats-views-supernova": getStatsChildren({ views: 100001 }),
430
+ },
431
+ template,
432
+ },
433
+ };
434
+
435
+ export default testArgs;