1- import type { ChangeEvent } from 'react' ;
21import React from 'react' ;
32
4- import { styled } from '@storybook/core/theming' ;
3+ import { TooltipLinkList } from '@storybook/core/components' ;
4+ import { styled , useTheme } from '@storybook/core/theming' ;
5+ import { ShareAltIcon } from '@storybook/icons' ;
56import type { Tag } from '@storybook/types' ;
67
7- import { transparentize } from 'polished ' ;
8+ import type { API } from '@storybook/core/manager-api ' ;
89
910const BUILT_IN_TAGS = new Set ( [
1011 'dev' ,
@@ -15,97 +16,59 @@ const BUILT_IN_TAGS = new Set([
1516 'play-fn' ,
1617] ) ;
1718
18- const CollapseButton = styled . button ( ( { theme } ) => ( {
19- all : 'unset' ,
20- display : 'flex' ,
21- padding : '0px 8px' ,
22- borderRadius : 4 ,
23- transition : 'color 150ms, box-shadow 150ms' ,
24- gap : 6 ,
25- alignItems : 'center' ,
26- cursor : 'pointer' ,
27- height : 28 ,
28-
29- '&:hover, &:focus' : {
30- outline : 'none' ,
31- background : transparentize ( 0.93 , theme . color . secondary ) ,
32- } ,
33- } ) ) ;
34-
35- const Text = styled . span ( {
36- '[aria-readonly=true] &' : {
37- opacity : 0.5 ,
38- } ,
39- } ) ;
40-
41- const Label = styled . label ( {
42- lineHeight : '20px' ,
43- alignItems : 'center' ,
44- marginBottom : 8 ,
45-
46- '&:last-child' : {
47- marginBottom : 0 ,
48- } ,
49-
50- input : {
51- margin : 0 ,
52- marginRight : 6 ,
53- } ,
19+ const Wrapper = styled . div ( {
20+ minWidth : 180 ,
21+ maxWidth : 220 ,
5422} ) ;
5523
5624interface TagsFilterPanelProps {
25+ api : API ;
5726 allTags : Tag [ ] ;
5827 selectedTags : Tag [ ] ;
5928 toggleTag : ( tag : Tag ) => void ;
6029}
6130
62- interface TagsListProps {
63- tags : Tag [ ] ;
64- selectedTags : Tag [ ] ;
65- toggleTag : ( tag : Tag ) => void ;
66- }
67-
68- const TagsList = ( { tags, selectedTags, toggleTag } : TagsListProps ) => {
69- return tags . map ( ( tag ) => {
70- const checked = selectedTags . includes ( tag ) ;
71- const id = `tag-${ tag } ` ;
72- return (
73- < Label key = { id } htmlFor = { id } >
74- < input
75- type = "checkbox"
76- id = { id }
77- name = { id }
78- value = { tag }
79- onChange = { ( e : ChangeEvent < HTMLInputElement > ) => {
80- toggleTag ( e . target . value ) ;
81- } }
82- checked = { checked }
83- />
84- < Text > { tag } </ Text >
85- </ Label >
86- ) ;
87- } ) ;
88- } ;
89-
90- const Wrapper = styled . div ( {
91- padding : 10 ,
92- label : {
93- display : 'flex' ,
94- } ,
95- } ) ;
96-
97- export const TagsFilterPanel = ( { allTags, selectedTags, toggleTag } : TagsFilterPanelProps ) => {
31+ export const TagsFilterPanel = ( {
32+ api,
33+ allTags,
34+ selectedTags,
35+ toggleTag,
36+ } : TagsFilterPanelProps ) => {
37+ const theme = useTheme ( ) ;
9838 const userTags = allTags . filter ( ( tag ) => tag === 'play-fn' || ! BUILT_IN_TAGS . has ( tag ) ) . toSorted ( ) ;
39+ const docsUrl = api . getDocsUrl ( { subpath : 'writing-stories/tags' } ) ;
40+ const items =
41+ userTags . length === 0
42+ ? [
43+ {
44+ id : 'no-tags' ,
45+ title : 'There are no tags. Use tags to organize and filter your Storybook.' ,
46+ isIndented : false ,
47+ style : {
48+ borderBottom : `4px solid ${ theme . appBorderColor } ` ,
49+ } ,
50+ } ,
51+ {
52+ id : 'tags-docs' ,
53+ title : 'Learn how to add tags' ,
54+ icon : < ShareAltIcon /> ,
55+ href : docsUrl ,
56+ } ,
57+ ]
58+ : userTags . map ( ( tag ) => {
59+ const checked = selectedTags . includes ( tag ) ;
60+ const id = `tag-${ tag } ` ;
61+ return {
62+ id,
63+ title : tag ,
64+ right : < input type = "checkbox" id = { id } name = { id } value = { tag } checked = { checked } /> ,
65+ onClick : ( ) => toggleTag ( tag ) ,
66+ } ;
67+ } ) ;
9968
10069 return (
101- < div >
102- { userTags . length === 0 ? (
103- < > There are no tags. Use tags to organize and filter your Storybook.</ >
104- ) : (
105- < Wrapper >
106- < TagsList tags = { userTags } selectedTags = { selectedTags } toggleTag = { toggleTag } />
107- </ Wrapper >
108- ) }
109- </ div >
70+ < Wrapper >
71+ < TooltipLinkList links = { items } />
72+ </ Wrapper >
11073 ) ;
11174} ;
0 commit comments