@@ -2,7 +2,10 @@ import { useOf } from '@storybook/blocks';
2
2
import { ResetWrapper } from "@storybook/components" ;
3
3
import { styled } from "@storybook/theming" ;
4
4
import React , { useEffect , useState } from "react" ;
5
- import { Code } from "./Typography.jsx" ;
5
+ import AdobeSVG from "../assets/images/adobe_logo.svg?raw" ;
6
+ import GitHubSVG from "../assets/images/github_logo.svg?raw" ;
7
+ import NpmSVG from "../assets/images/npm_logo.svg?raw" ;
8
+ import { Body , Code , Heading } from "./Typography.jsx" ;
6
9
import { fetchToken } from "./utilities.js" ;
7
10
8
11
export const DList = styled . dl `
@@ -97,6 +100,45 @@ export const StatusLight = styled.span(({ variant = "positive", ...props }) => `
97
100
margin-block-end: 1px;
98
101
` ) ;
99
102
103
+ export const ResourceSection = styled . section `
104
+ display: flex;
105
+ flex-flow: row wrap;
106
+ align-items: center;
107
+ ` ;
108
+
109
+ export const ResourceLink = styled . a `
110
+ position: relative;
111
+ display: inline-flex;
112
+ flex-direction: row;
113
+ align-items: center;
114
+ margin-block-end: 16px;
115
+ margin-inline-end: 16px;
116
+ box-sizing: border-box;
117
+ text-decoration: none;
118
+ min-inline-size: 100px;
119
+ border: 1px solid transparent;
120
+ border-radius: 5px;
121
+ border-color: rgb(230, 230, 230);
122
+ overflow: hidden;
123
+ color: rgb(0, 0, 0);
124
+
125
+ &:hover {
126
+ border-color: rgb(213, 213, 213);
127
+ }
128
+ ` ;
129
+
130
+ export const ResourceIconWrapper = styled . div `
131
+ background-color: rgba(248, 248, 248);
132
+ padding: 12px;
133
+ display: flex;
134
+ inline-size: 40px;
135
+ block-size: 40px;
136
+ ` ;
137
+
138
+ export const ResourceTextWrapper = styled . div `
139
+ margin-inline: 16px;
140
+ ` ;
141
+
100
142
const VersionDetails = ( { tag, data = { } , isDeprecated = false , skipDate = false , skipLink = false } ) => {
101
143
let statusType = "notice" ;
102
144
let statusMessage = "Not yet available on the npm registry." ;
@@ -264,13 +306,104 @@ function fetchNpmData(packageName, setnpmData, setIsLoading) {
264
306
} , [ cache , setCache , packageName , setnpmData , setIsLoading ] ) ;
265
307
}
266
308
309
+ const fetchLogo = ( brand ) => {
310
+ switch ( brand ) {
311
+ case "npm" :
312
+ return NpmSVG ;
313
+ case "GitHub" :
314
+ return GitHubSVG ;
315
+ case "Adobe" :
316
+ return AdobeSVG ;
317
+ }
318
+
319
+ return ;
320
+ }
321
+
322
+ /**
323
+ * Displays a resource card containing text and an image that links to a particular resource.
324
+ *
325
+ * @param {string } heading - heading of the resource card
326
+ * @param {string } alt - additional description of the resource card
327
+ * @param {string } image - the SVG image
328
+ * @param {string } href - optional link to the resource, found in packageJson?.spectrum?.guidelines
329
+ * @returns {string }
330
+ */
331
+ export const ResourceLinkContent = ( { heading, alt, logo, href } ) => {
332
+ if ( ! href ) return ;
333
+
334
+ return (
335
+ < ResourceLink href = { href } className = "sb-unstyled" title = { alt } >
336
+ < ResourceIconWrapper dangerouslySetInnerHTML = { { __html : fetchLogo ( logo ) } } />
337
+ < ResourceTextWrapper >
338
+ { heading ? < Heading size = "xs" > { heading } </ Heading > : "" }
339
+ { alt ? < Body size = "s" > { alt } </ Body > : "" }
340
+ </ ResourceTextWrapper >
341
+ </ ResourceLink >
342
+ ) ;
343
+ } ;
344
+
345
+ /**
346
+ * Displays the list of relevant component links (to NPM, repo, guidelines, etc).
347
+ *
348
+ * The rootClassName is read from the story's default args, found in the story's metadata.
349
+ *
350
+ * The for loop is particularly helpful to match guidelines links for any nested components
351
+ * (i.e. meter, form). We need to check that the rootClassName matches the rootClass found
352
+ * in the packageJson.spectrum, to link to the correct guidelines page.
353
+ *
354
+ * Deprecated components should not show a GitHub resource card.
355
+ *
356
+ * @param {string } packageName - packageName sourced from packageJson?.name
357
+ * @param {string[] } spectrumData - an array of objects sourced from packageJson?.spectrum
358
+ * @param {string } rootClassName - a component's default rootClass arg
359
+ * @returns {string }
360
+ */
361
+ export const ResourceListDetails = ( { packageName, spectrumData = [ ] , rootClassName, isDeprecated } ) => {
362
+ if ( ! packageName ) return ;
363
+
364
+ let href ;
365
+
366
+ for ( let i = 0 ; i < spectrumData ?. length ; i ++ ) {
367
+ if ( spectrumData [ i ] ?. guidelines && spectrumData [ i ] ?. rootClass === rootClassName ) {
368
+ href = spectrumData [ i ] ?. guidelines ;
369
+ }
370
+ }
371
+
372
+ return (
373
+ < ResourceSection className = "sb-unstyled" >
374
+ { href ?
375
+ < ResourceLinkContent
376
+ className = "doc-block-resource-cards"
377
+ heading = "View guidelines"
378
+ alt = "Spectrum website"
379
+ logo = "Adobe"
380
+ href = { href } /> : "" }
381
+ < ResourceLinkContent
382
+ className = "doc-block-resource-cards"
383
+ heading = "View package"
384
+ alt = "npm"
385
+ logo = "npm"
386
+ href = { `https://npmjs.com/${ packageName } ` } />
387
+ { ! isDeprecated ?
388
+ < ResourceLinkContent
389
+ className = "doc-block-resource-cards"
390
+ heading = "View repository"
391
+ alt = "GitHub"
392
+ logo = "GitHub"
393
+ href = { `https://github.com/adobe/spectrum-css/tree/main/components/${ packageName . split ( '/' ) . pop ( ) } ` } /> : "" }
394
+ </ ResourceSection >
395
+ )
396
+ } ;
397
+
267
398
/**
268
399
* Displays the current version number of the component. The version is read from
269
400
* the component's parameters, where it was sourced from the package.json file.
270
401
*
271
- * Also displays a component status of "deprecated" if it is set in the story's
402
+ * Displays a component status of "deprecated" if it is set in the story's
272
403
* parameters.
273
404
*
405
+ * Displays the list of relevant component links (to NPM, repo, guidelines, etc).
406
+ *
274
407
* Usage of this doc block within MDX template(s):
275
408
* <ComponentDetails />
276
409
*/
@@ -279,8 +412,16 @@ export const ComponentDetails = () => {
279
412
280
413
const isDeprecated = storyMeta ?. csfFile ?. meta ?. parameters ?. status ?. type == "deprecated" ;
281
414
const packageJson = storyMeta ?. csfFile ?. meta ?. parameters ?. packageJson ?? { } ;
415
+ const rootClassName = storyMeta ?. csfFile ?. meta ?. args ?. rootClass ?? "" ;
416
+
417
+ const packageName = packageJson ?. name ;
418
+
419
+ if ( ! packageName ) return ;
282
420
283
- if ( ! packageJson ?. name ) return ;
421
+ let spectrumData = packageJson ?. spectrum ;
422
+ if ( typeof spectrumData === "string" ) {
423
+ spectrumData = [ spectrumData ] ;
424
+ }
284
425
285
426
const [ isLoading , setIsLoading ] = useState ( true ) ;
286
427
const [ npmData , setnpmData ] = useState ( { } ) ;
@@ -291,26 +432,28 @@ export const ComponentDetails = () => {
291
432
292
433
return (
293
434
< ResetWrapper >
294
- { ! isLoading ?
295
- < DList className = "docblock-metadata sb-unstyled" >
296
- { isDeprecated
297
- ? < >
298
- < DTerm key = { 'status' } > Status:</ DTerm >
299
- < DDefinition key = { 'status-data' } > Deprecated</ DDefinition >
300
- </ >
301
- : ""
302
- }
303
- { showLocalVersion
304
- ? < >
305
- < DTerm key = { 'version-label' } > Local version:</ DTerm >
306
- < DDefinition key = { 'version' } > < VersionDetails tag = { "local" } data = { allVersions && allVersions . find ( ( [ tag ] ) => tag === "local" ) ?. [ 1 ] } isDeprecated = { isDeprecated } /> </ DDefinition >
435
+ { ! isLoading ? < >
436
+ < DList className = "docblock-metadata sb-unstyled" >
437
+ { isDeprecated
438
+ ? < >
439
+ < DTerm key = { 'status' } > Status:</ DTerm >
440
+ < DDefinition key = { 'status-data' } > Deprecated</ DDefinition >
441
+ </ >
442
+ : ""
443
+ }
444
+ { showLocalVersion
445
+ ? < >
446
+ < DTerm key = { 'version-label' } > Local version:</ DTerm >
447
+ < DDefinition key = { 'version' } > < VersionDetails tag = { "local" } data = { allVersions && allVersions . find ( ( [ tag ] ) => tag === "local" ) ?. [ 1 ] } isDeprecated = { isDeprecated } /> </ DDefinition >
448
+ </ >
449
+ : < >
450
+ < DTerm key = { 'version-label' } > Latest version:</ DTerm >
451
+ < DDefinition key = { 'version' } > < VersionDetails tag = { "latest" } data = { allVersions && allVersions . find ( ( [ tag ] ) => tag === "latest" ) ?. [ 1 ] } isDeprecated = { isDeprecated } skipLink = { true } /> </ DDefinition >
307
452
</ >
308
- : < >
309
- < DTerm key = { 'version-label' } > Latest version:</ DTerm >
310
- < DDefinition key = { 'version' } > < VersionDetails tag = { "latest" } data = { allVersions && allVersions . find ( ( [ tag ] ) => tag === "latest" ) ?. [ 1 ] } isDeprecated = { isDeprecated } skipLink = { true } /> </ DDefinition >
311
- </ >
312
- }
313
- </ DList >
453
+ }
454
+ </ DList >
455
+ < ResourceListDetails packageName = { packageName } spectrumData = { spectrumData } rootClassName = { rootClassName } isDeprecated = { isDeprecated } />
456
+ </ >
314
457
: "" }
315
458
</ ResetWrapper >
316
459
) ;
0 commit comments