@ndla/ui 42.1.1 → 42.1.2

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 (36) hide show
  1. package/es/AudioPlayer/AudioPlayer.js +27 -33
  2. package/es/CampaignBlock/CampaignBlock.js +32 -18
  3. package/es/LicenseByline/EmbedByline.js +5 -5
  4. package/es/MyNdla/Resource/Folder.js +27 -66
  5. package/es/Resource/BlockResource.js +13 -22
  6. package/es/Resource/ListResource.js +12 -14
  7. package/es/Resource/resourceComponents.js +59 -29
  8. package/es/TreeStructure/ComboboxButton.js +17 -20
  9. package/es/TreeStructure/FolderItem.js +42 -65
  10. package/es/TreeStructure/FolderItems.js +25 -19
  11. package/es/TreeStructure/TreeStructure.js +19 -26
  12. package/lib/AudioPlayer/AudioPlayer.js +27 -33
  13. package/lib/CampaignBlock/CampaignBlock.js +32 -18
  14. package/lib/LicenseByline/EmbedByline.js +5 -5
  15. package/lib/MyNdla/Resource/Folder.js +27 -66
  16. package/lib/Resource/BlockResource.d.ts +1 -1
  17. package/lib/Resource/BlockResource.js +12 -21
  18. package/lib/Resource/ListResource.js +11 -13
  19. package/lib/Resource/resourceComponents.d.ts +5 -10
  20. package/lib/Resource/resourceComponents.js +63 -31
  21. package/lib/TreeStructure/ComboboxButton.js +17 -20
  22. package/lib/TreeStructure/FolderItem.js +40 -63
  23. package/lib/TreeStructure/FolderItems.js +31 -26
  24. package/lib/TreeStructure/TreeStructure.js +19 -26
  25. package/package.json +14 -14
  26. package/src/AudioPlayer/AudioPlayer.tsx +24 -34
  27. package/src/CampaignBlock/CampaignBlock.tsx +10 -10
  28. package/src/LicenseByline/EmbedByline.tsx +1 -1
  29. package/src/MyNdla/Resource/Folder.tsx +28 -35
  30. package/src/Resource/BlockResource.tsx +21 -18
  31. package/src/Resource/ListResource.tsx +17 -12
  32. package/src/Resource/resourceComponents.tsx +34 -15
  33. package/src/TreeStructure/ComboboxButton.tsx +5 -7
  34. package/src/TreeStructure/FolderItem.tsx +49 -32
  35. package/src/TreeStructure/FolderItems.tsx +6 -8
  36. package/src/TreeStructure/TreeStructure.tsx +16 -25
@@ -53,22 +53,17 @@ const ImageWrapper = styled.div`
53
53
  }
54
54
  `;
55
55
 
56
- type TextWrapperProps = {
57
- hasImage?: boolean;
58
- };
59
-
60
- const TextWrapper = styled.div<TextWrapperProps>`
56
+ const TextWrapper = styled.div`
61
57
  padding: ${spacing.small};
62
58
  width: 100%;
63
-
64
- ${(props) =>
65
- props.hasImage &&
66
- `${mq.range({ from: breakpoints.tablet })} {
67
- padding: ${spacing.small} ${spacing.normal};
59
+ &[data-has-image='true'] {
60
+ ${mq.range({ from: breakpoints.tablet })} {
61
+ padding: ${spacing.small} ${spacing.normal};
62
+ }
63
+ ${mq.range({ from: breakpoints.tabletWide })} {
64
+ padding: ${spacing.small} ${spacing.medium};
65
+ }
68
66
  }
69
- ${mq.range({ from: breakpoints.tabletWide })} {
70
- padding: ${spacing.small} ${spacing.medium};
71
- }`}
72
67
  `;
73
68
 
74
69
  const TitleWrapper = styled.div`
@@ -78,13 +73,12 @@ const TitleWrapper = styled.div`
78
73
  }
79
74
  `;
80
75
 
81
- type TitleProps = {
82
- hasDescription?: boolean;
83
- };
84
-
85
- const Title = styled.h2<TitleProps>`
76
+ const Title = styled.h2`
86
77
  ${fonts.sizes('22px', '30px')};
87
- margin: 0 0 ${(props) => props.hasDescription && `${spacing.small}`};
78
+ margin: 0px;
79
+ &[data-has-desc='true'] {
80
+ margin: 0 0 ${spacing.small};
81
+ }
88
82
  `;
89
83
 
90
84
  const Subtitle = styled.h3`
@@ -99,14 +93,10 @@ const StyledDescription = styled.div`
99
93
  margin: 0;
100
94
  `;
101
95
 
102
- type LinkToTextVersionWrapperProps = {
103
- noMargin?: boolean;
104
- };
105
- const LinkToTextVersionWrapper = styled.div<LinkToTextVersionWrapperProps>`
106
- ${(props) =>
107
- !props.noMargin &&
108
- `margin-top: ${spacing.normal};
109
- `}
96
+ const LinkToTextVersionWrapper = styled.div`
97
+ &[data-margin='true'] {
98
+ margin-top: ${spacing.small};
99
+ }
110
100
  ${mq.range({ until: breakpoints.tabletWide })} {
111
101
  margin: ${spacing.small} 0;
112
102
  }
@@ -201,10 +191,10 @@ const AudioPlayer = ({ src, title, subtitle, speech, description, img, textVersi
201
191
  };
202
192
 
203
193
  type TextVersionComponentProps = {
204
- noMargin?: boolean;
194
+ margin?: boolean;
205
195
  };
206
- const TextVersionComponent = ({ noMargin }: TextVersionComponentProps) => (
207
- <LinkToTextVersionWrapper noMargin={noMargin}>
196
+ const TextVersionComponent = ({ margin }: TextVersionComponentProps) => (
197
+ <LinkToTextVersionWrapper data-margin={margin}>
208
198
  <ButtonV2 size="normal" shape="pill" onClick={toggleTextVersion} data-audio-text-button-id={staticRenderId}>
209
199
  {t('audio.textVersion.heading')}
210
200
  </ButtonV2>
@@ -219,7 +209,7 @@ const AudioPlayer = ({ src, title, subtitle, speech, description, img, textVersi
219
209
  <img src={img.url} alt={img.alt} />
220
210
  </ImageWrapper>
221
211
  )}
222
- <TextWrapper hasImage={!!img}>
212
+ <TextWrapper data-has-image={!!img}>
223
213
  <TitleWrapper>
224
214
  <div>
225
215
  {subtitle && (
@@ -227,9 +217,9 @@ const AudioPlayer = ({ src, title, subtitle, speech, description, img, textVersi
227
217
  {subtitle.url ? <SafeLink to={subtitle.url}>{subtitle.title}</SafeLink> : subtitle.title}
228
218
  </Subtitle>
229
219
  )}
230
- <Title hasDescription={!!description}>{title}</Title>
220
+ <Title data-has-desc={!!description}>{title}</Title>
231
221
  </div>
232
- {textVersion && !img && <TextVersionComponent noMargin />}
222
+ {textVersion && !img && <TextVersionComponent />}
233
223
  </TitleWrapper>
234
224
  {description && (
235
225
  <StyledDescription>
@@ -241,7 +231,7 @@ const AudioPlayer = ({ src, title, subtitle, speech, description, img, textVersi
241
231
  </ButtonV2>
242
232
  </StyledDescription>
243
233
  )}
244
- {textVersion && img && <TextVersionComponent />}
234
+ {textVersion && img && <TextVersionComponent margin />}
245
235
  </TextWrapper>
246
236
  </InfoWrapper>
247
237
  <div data-audio-player={1} data-src={src} data-title={title}>
@@ -18,6 +18,7 @@ interface Image {
18
18
  src: string;
19
19
  alt: string;
20
20
  }
21
+
21
22
  interface Props {
22
23
  title: {
23
24
  title: string;
@@ -62,12 +63,7 @@ const StyledDescription = styled.p`
62
63
 
63
64
  const StyledImg = styled.img`
64
65
  max-height: 200px;
65
- ${mq.range({ until: breakpoints.tabletWide })} {
66
- align-self: center;
67
- }
68
- ${mq.range({ from: breakpoints.tabletWide })} {
69
- align-self: center;
70
- }
66
+ align-self: center;
71
67
  `;
72
68
 
73
69
  const StyledLink = styled(SafeLink)`
@@ -84,6 +80,10 @@ const StyledLink = styled(SafeLink)`
84
80
  }
85
81
  `;
86
82
 
83
+ const TextWrapper = styled.div`
84
+ flex-grow: 1;
85
+ `;
86
+
87
87
  const CampaignBlock = ({
88
88
  title,
89
89
  imageBefore,
@@ -95,16 +95,16 @@ const CampaignBlock = ({
95
95
  }: Props) => {
96
96
  return (
97
97
  <Container className={className}>
98
- {imageBefore && <StyledImg src={imageBefore.src} data-left={true} />}
99
- <div>
98
+ {imageBefore && <StyledImg src={imageBefore.src} />}
99
+ <TextWrapper>
100
100
  <Heading css={headingStyle}>{title.title}</Heading>
101
101
  <StyledDescription>{description.text}</StyledDescription>
102
102
  <StyledLink to={url.url}>
103
103
  {url.text}
104
104
  <Forward />
105
105
  </StyledLink>
106
- </div>
107
- {imageAfter && <StyledImg src={imageAfter.src} data-right={true} />}
106
+ </TextWrapper>
107
+ {imageAfter && <StyledImg src={imageAfter.src} />}
108
108
  </Container>
109
109
  );
110
110
  };
@@ -124,7 +124,7 @@ const StyledSpan = styled.span`
124
124
 
125
125
  const LicenseInformationWrapper = styled.div`
126
126
  flex: 1;
127
- padding-right: ${spacing.xsmall}}
127
+ padding-right: ${spacing.xsmall};
128
128
  `;
129
129
 
130
130
  const EmbedByline = ({
@@ -11,38 +11,30 @@ import React from 'react';
11
11
  import { FolderOutlined, FolderShared } from '@ndla/icons/contentType';
12
12
  import { FileDocumentOutline, Share } from '@ndla/icons/common';
13
13
  import { fonts, spacing, colors, mq, breakpoints } from '@ndla/core';
14
- import { css } from '@emotion/react';
15
14
  import { useTranslation } from 'react-i18next';
16
15
  import { MenuItemProps } from '@ndla/button';
17
16
  import { ResourceTitleLink } from '../../Resource/resourceComponents';
18
17
  import FolderMenu from './FolderMenu';
19
18
 
20
19
  export type LayoutType = 'list' | 'listLarger' | 'block';
21
- interface LayoutProps {
22
- type: LayoutType;
23
- }
24
20
 
25
- const FolderWrapper = styled.div<LayoutProps>`
21
+ const FolderWrapper = styled.div`
26
22
  display: flex;
27
23
  position: relative;
28
24
  align-items: center;
29
25
  justify-content: space-between;
30
26
 
31
27
  ${mq.range({ until: breakpoints.mobileWide })} {
32
- ${({ type }) =>
33
- type !== 'list' &&
34
- css`
35
- flex-direction: column;
36
- align-items: unset;
37
- `}
38
- }
39
-
40
- ${({ type }) =>
41
- type === 'block' &&
42
- css`
28
+ &:not([data-type='list']) {
43
29
  flex-direction: column;
44
30
  align-items: unset;
45
- `}
31
+ }
32
+ }
33
+
34
+ &[data-type='block'] {
35
+ flex-direction: column;
36
+ align-items: unset;
37
+ }
46
38
 
47
39
  border: 1px solid ${colors.brand.neutral7};
48
40
  cursor: pointer;
@@ -52,17 +44,23 @@ const FolderWrapper = styled.div<LayoutProps>`
52
44
  &:hover {
53
45
  box-shadow: 1px 1px 6px 2px rgba(9, 55, 101, 0.08);
54
46
  transition-duration: 0.2s;
47
+ [data-title] {
48
+ color: ${colors.brand.primary};
49
+ text-decoration: underline;
50
+ }
55
51
  }
56
52
  `;
57
53
 
58
- const TitleWrapper = styled.div<LayoutProps>`
54
+ const TitleWrapper = styled.div`
59
55
  display: flex;
60
56
  margin: ${spacing.nsmall};
61
- margin-bottom: ${({ type }) => type === 'block' && 0};
62
57
  flex-direction: row;
63
58
  align-items: center;
64
59
  gap: ${spacing.xsmall};
65
60
  justify-content: space-between;
61
+ &[data-type='block'] {
62
+ margin-bottom: 0;
63
+ }
66
64
  `;
67
65
 
68
66
  const IconWrapper = styled.div`
@@ -88,11 +86,6 @@ const FolderTitle = styled.h2`
88
86
  -webkit-line-clamp: 1;
89
87
  line-clamp: 1;
90
88
  -webkit-box-orient: vertical;
91
-
92
- ${FolderWrapper}:hover & {
93
- color: ${colors.brand.primary};
94
- text-decoration: underline;
95
- }
96
89
  `;
97
90
 
98
91
  const MenuWrapper = styled.div`
@@ -113,7 +106,7 @@ const CountContainer = styled.div`
113
106
  margin: 0 ${spacing.small} 0 ${spacing.nsmall};
114
107
  `;
115
108
 
116
- const IconTextWrapper = styled.div<LayoutProps>`
109
+ const IconTextWrapper = styled.div`
117
110
  display: flex;
118
111
  align-items: center;
119
112
  gap: ${spacing.xxsmall};
@@ -125,11 +118,9 @@ const IconTextWrapper = styled.div<LayoutProps>`
125
118
  }
126
119
  ${fonts.sizes(16)};
127
120
  ${mq.range({ until: breakpoints.mobileWide })} {
128
- ${({ type }) =>
129
- type === 'list' &&
130
- css`
131
- display: none;
132
- `}
121
+ &[data-type='list'] {
122
+ display: none;
123
+ }
133
124
  }
134
125
  `;
135
126
 
@@ -145,7 +136,7 @@ const Count = ({ type, count, layoutType }: IconCountProps) => {
145
136
  if (!count) return null;
146
137
 
147
138
  return (
148
- <IconTextWrapper type={layoutType}>
139
+ <IconTextWrapper data-type={layoutType}>
149
140
  <Icon />
150
141
  <span>{t(`myNdla.${type}s`, { count })}</span>
151
142
  </IconTextWrapper>
@@ -180,22 +171,24 @@ const Folder = ({
180
171
  const Icon = isShared ? FolderShared : FolderOutlined;
181
172
 
182
173
  return (
183
- <FolderWrapper type={type} id={id}>
184
- <TitleWrapper type={type}>
174
+ <FolderWrapper data-type={type} id={id}>
175
+ <TitleWrapper data-type={type}>
185
176
  <IconWrapper
186
177
  aria-label={`${isShared ? `${t('myNdla.folder.sharing.shared')} ` : ''}${t('myNdla.folder.folder')}`}
187
178
  >
188
179
  <Icon />
189
180
  </IconWrapper>
190
181
  <ResourceTitleLink to={link}>
191
- <FolderTitle title={title}>{title}</FolderTitle>
182
+ <FolderTitle data-title="" title={title}>
183
+ {title}
184
+ </FolderTitle>
192
185
  </ResourceTitleLink>
193
186
  </TitleWrapper>
194
187
  <MenuWrapper>
195
188
  <CountContainer>
196
189
  {isShared && (
197
190
  // Information regarding the shared status of a folder is read previously, ignore this
198
- <IconTextWrapper type={type} aria-hidden>
191
+ <IconTextWrapper data-type={type} aria-hidden>
199
192
  <Share />
200
193
  <span>{t('myNdla.folder.sharing.shared')}</span>
201
194
  </IconTextWrapper>
@@ -15,11 +15,11 @@ import Image from '../Image';
15
15
  import {
16
16
  CompressedTagList,
17
17
  ResourceImageProps,
18
- ResourceTitle,
19
18
  ResourceTypeList,
20
19
  ResourceTitleLink,
21
20
  LoaderProps,
22
- StyledContentIconWrapper,
21
+ ContentIconWrapper,
22
+ resourceHeadingStyle,
23
23
  } from './resourceComponents';
24
24
  import ContentLoader from '../ContentLoader';
25
25
  import { contentTypeMapping, resourceEmbedTypeMapping } from '../model/ContentType';
@@ -41,11 +41,23 @@ const BlockElementWrapper = styled.div`
41
41
  &:hover {
42
42
  box-shadow: 1px 1px 6px 2px rgba(9, 55, 101, 0.08);
43
43
  transition-duration: 0.2s;
44
- ${() => ResourceTitleLink} {
44
+ [data-link] {
45
45
  color: ${colors.brand.primary};
46
46
  text-decoration: underline;
47
47
  }
48
48
  }
49
+
50
+ &:hover,
51
+ &:focus,
52
+ &:focus-within {
53
+ [data-description] {
54
+ /* Unfortunate css needed for multi-line text overflow ellipsis. */
55
+ height: 3.1em;
56
+ -webkit-line-clamp: 2;
57
+ line-clamp: 2;
58
+ -webkit-box-orient: vertical;
59
+ }
60
+ }
49
61
  `;
50
62
 
51
63
  const BlockDescription = styled.p`
@@ -57,14 +69,6 @@ const BlockDescription = styled.p`
57
69
  overflow: hidden;
58
70
  text-overflow: ellipsis;
59
71
  transition: height 0.2s ease-out;
60
- ${() => BlockElementWrapper}:hover &, ${() => BlockElementWrapper}:focus & , ${() =>
61
- BlockElementWrapper}:focus-within & {
62
- // Unfortunate css needed for multi-line text overflow ellipsis.
63
- height: 3.1em;
64
- -webkit-line-clamp: 2;
65
- line-clamp: 2;
66
- -webkit-box-orient: vertical;
67
- }
68
72
  `;
69
73
 
70
74
  const TagsAndActionMenu = styled.div`
@@ -114,9 +118,9 @@ const BlockImage = ({ image, loading, contentType }: BlockImageProps) => {
114
118
  }
115
119
  if (image.src === '') {
116
120
  return (
117
- <StyledContentIconWrapper contentType={contentType}>
121
+ <ContentIconWrapper contentType={contentType}>
118
122
  <ContentTypeBadge type={contentType} size="large" />
119
- </StyledContentIconWrapper>
123
+ </ContentIconWrapper>
120
124
  );
121
125
  } else {
122
126
  return <Image alt={image.alt} src={image.src} fallbackWidth={300} />;
@@ -161,12 +165,11 @@ const BlockResource = ({
161
165
  description,
162
166
  menuItems,
163
167
  isLoading,
164
- headingLevel = 'h2',
168
+ headingLevel: Heading = 'h2',
165
169
  targetBlank,
166
170
  resourceTypes,
167
171
  }: Props) => {
168
172
  const firstResourceType = resourceTypes?.[0]?.id ?? '';
169
- const Title = ResourceTitle.withComponent(headingLevel);
170
173
 
171
174
  return (
172
175
  <BlockElementWrapper id={id}>
@@ -184,12 +187,12 @@ const BlockResource = ({
184
187
  <BlockInfoWrapper>
185
188
  <ContentWrapper>
186
189
  <ResourceTypeAndTitleLoader loading={isLoading}>
187
- <ResourceTitleLink title={title} target={targetBlank ? '_blank' : undefined} to={link}>
188
- <Title>{title}</Title>
190
+ <ResourceTitleLink data-link="" title={title} target={targetBlank ? '_blank' : undefined} to={link}>
191
+ <Heading css={resourceHeadingStyle}>{title}</Heading>
189
192
  </ResourceTitleLink>
190
193
  </ResourceTypeAndTitleLoader>
191
194
  <ResourceTypeList resourceTypes={resourceTypes} />
192
- <BlockDescription>{description}</BlockDescription>
195
+ <BlockDescription data-description="">{description}</BlockDescription>
193
196
  </ContentWrapper>
194
197
  <TagsAndActionMenu>
195
198
  {tags && tags.length > 0 && <CompressedTagList tagLinkPrefix={tagLinkPrefix} tags={tags} />}
@@ -14,11 +14,11 @@ import Image from '../Image';
14
14
  import {
15
15
  CompressedTagList,
16
16
  ResourceImageProps,
17
- ResourceTitle,
17
+ resourceHeadingStyle,
18
18
  ResourceTitleLink as StyledLink,
19
19
  ResourceTypeList,
20
- StyledContentIconWrapper,
21
20
  LoaderProps,
21
+ ContentIconWrapper,
22
22
  } from './resourceComponents';
23
23
  import ContentLoader from '../ContentLoader';
24
24
  import ContentTypeBadge from '../ContentTypeBadge';
@@ -48,7 +48,7 @@ const ListResourceWrapper = styled.div`
48
48
  &:hover {
49
49
  box-shadow: 1px 1px 6px 2px rgba(9, 55, 101, 0.08);
50
50
  transition-duration: 0.2s;
51
- ${() => StyledLink} {
51
+ [data-link] {
52
52
  color: ${colors.brand.primary};
53
53
  text-decoration: underline;
54
54
  }
@@ -61,11 +61,7 @@ interface StyledImageProps {
61
61
 
62
62
  const ImageWrapper = styled.div<StyledImageProps>`
63
63
  grid-area: image;
64
- width: ${(p) => (p.imageSize === 'normal' ? '136px' : '56px')};
65
- ${mq.range({ until: breakpoints.mobileWide })} {
66
- width: 56px;
67
- margin-bottom: 0;
68
- }
64
+ width: 56px;
69
65
  overflow: hidden;
70
66
  border-radius: 2px;
71
67
  display: flex;
@@ -73,6 +69,13 @@ const ImageWrapper = styled.div<StyledImageProps>`
73
69
  align-items: center;
74
70
  justify-content: center;
75
71
  aspect-ratio: 4/3;
72
+ &[data-image-size='normal'] {
73
+ width: 136px;
74
+ }
75
+ ${mq.range({ until: breakpoints.mobileWide })} {
76
+ width: 56px;
77
+ margin-bottom: 0;
78
+ }
76
79
  `;
77
80
 
78
81
  const StyledImage = styled(Image)`
@@ -138,9 +141,9 @@ const ListResourceImage = ({ resourceImage, loading, type, contentType, backgrou
138
141
  if (!loading) {
139
142
  if (resourceImage.src === '') {
140
143
  return (
141
- <StyledContentIconWrapper contentType={contentType}>
144
+ <ContentIconWrapper contentType={contentType}>
142
145
  <ContentTypeBadge type={contentType} background={background} size="x-small" />
143
- </StyledContentIconWrapper>
146
+ </ContentIconWrapper>
144
147
  );
145
148
  } else {
146
149
  return (
@@ -237,8 +240,10 @@ const ListResource = ({
237
240
  </ImageWrapper>
238
241
  <TopicAndTitleWrapper>
239
242
  <TypeAndTitleLoader loading={isLoading}>
240
- <StyledLink to={link} target={targetBlank ? '_blank' : undefined}>
241
- <ResourceTitle title={title}>{title}</ResourceTitle>
243
+ <StyledLink to={link} data-link="" target={targetBlank ? '_blank' : undefined}>
244
+ <h1 css={resourceHeadingStyle} title={title}>
245
+ {title}
246
+ </h1>
242
247
  </StyledLink>
243
248
  <ResourceTypeList resourceTypes={resourceTypes} />
244
249
  </TypeAndTitleLoader>
@@ -8,12 +8,13 @@
8
8
 
9
9
  import styled from '@emotion/styled';
10
10
  import { colors, fonts, spacing } from '@ndla/core';
11
- import React, { ReactNode } from 'react';
11
+ import React, { CSSProperties, HTMLAttributes, ReactNode, useMemo } from 'react';
12
12
  import { useTranslation } from 'react-i18next';
13
13
  import { MenuButton } from '@ndla/button';
14
14
  import SafeLink from '@ndla/safelink';
15
15
  import { useNavigate } from 'react-router-dom';
16
16
  import { HashTag } from '@ndla/icons/common';
17
+ import { css } from '@emotion/react';
17
18
  import resourceTypeColor from '../utils/resourceTypeColor';
18
19
  import { resourceEmbedTypeMapping } from '../model/ContentType';
19
20
 
@@ -37,7 +38,7 @@ export const ResourceTitleLink = styled(SafeLink)`
37
38
  }
38
39
  `;
39
40
 
40
- export const ResourceTitle = styled.span`
41
+ export const resourceHeadingStyle = css`
41
42
  margin: 0;
42
43
  overflow: hidden;
43
44
  text-overflow: ellipsis;
@@ -113,19 +114,32 @@ const TagCounterWrapper = styled.span`
113
114
  ${fonts.sizes('14px', '14px')};
114
115
  `;
115
116
 
116
- export interface ContentIconProps {
117
+ interface ContentIconProps extends HTMLAttributes<HTMLSpanElement> {
117
118
  contentType: string;
119
+ children?: ReactNode;
118
120
  }
119
121
 
120
- export const StyledContentIconWrapper = styled.span<ContentIconProps>`
122
+ const StyledContentIconWrapper = styled.span`
121
123
  width: 100%;
122
124
  aspect-ratio: 4/3;
123
125
  display: flex;
124
126
  align-items: center;
125
127
  justify-content: center;
126
- background-color: ${({ contentType }) => resourceTypeColor(contentType)};
128
+ background-color: var(--content-background-color);
127
129
  `;
128
130
 
131
+ export const ContentIconWrapper = ({ contentType, children, ...props }: ContentIconProps) => {
132
+ const contentIconWrapperVars = useMemo(
133
+ () => ({ '--content-background-color': resourceTypeColor(contentType) } as unknown as CSSProperties),
134
+ [contentType],
135
+ );
136
+ return (
137
+ <StyledContentIconWrapper {...props} style={contentIconWrapperVars}>
138
+ {children}
139
+ </StyledContentIconWrapper>
140
+ );
141
+ };
142
+
129
143
  interface TagListProps {
130
144
  tags?: string[];
131
145
  tagLinkPrefix?: string;
@@ -161,16 +175,21 @@ interface CompressedTagListProps {
161
175
  export const CompressedTagList = ({ tags, tagLinkPrefix }: CompressedTagListProps) => {
162
176
  const navigate = useNavigate();
163
177
  const { t } = useTranslation();
164
- const visibleTags = tags.slice(0, 3);
165
- const remainingTags = tags.slice(3, tags.length).map((tag) => {
166
- return {
167
- icon: <HashTag />,
168
- text: tag,
169
- onClick: () => {
170
- navigate(`${tagLinkPrefix ? tagLinkPrefix : ''}/${encodeURIComponent(tag)}`);
171
- },
172
- };
173
- });
178
+ const visibleTags = useMemo(() => tags.slice(0, 3), [tags]);
179
+ const remainingTags = useMemo(
180
+ () =>
181
+ tags.slice(3, tags.length).map((tag) => {
182
+ return {
183
+ icon: <HashTag />,
184
+ text: tag,
185
+ onClick: () => {
186
+ navigate(`${tagLinkPrefix ? tagLinkPrefix : ''}/${encodeURIComponent(tag)}`);
187
+ },
188
+ };
189
+ }),
190
+ [navigate, tagLinkPrefix, tags],
191
+ );
192
+
174
193
  return (
175
194
  <>
176
195
  <TagList tagLinkPrefix={tagLinkPrefix} tags={visibleTags} />
@@ -18,15 +18,13 @@ import { TreeStructureType } from './types';
18
18
  import { arrowNavigation } from './arrowNavigation';
19
19
  import ContentLoader from '../ContentLoader';
20
20
 
21
- interface StyledRowProps {
22
- isOpen: boolean;
23
- }
24
-
25
- const StyledRow = styled.div<StyledRowProps>`
21
+ const StyledRow = styled.div`
26
22
  display: flex;
27
23
  padding: ${spacing.xxsmall};
28
24
  align-items: center;
29
- border-bottom: ${({ isOpen }) => isOpen && `1px solid ${colors.brand.tertiary}`};
25
+ &[data-open='true'] {
26
+ border-bottom: 1px solid ${colors.brand.tertiary};
27
+ }
30
28
  `;
31
29
  const StyledSelectedFolder = styled(Button)`
32
30
  flex: 1;
@@ -110,7 +108,7 @@ const ComboboxButton = forwardRef<HTMLButtonElement, Props>(
110
108
 
111
109
  return (
112
110
  <StyledRow
113
- isOpen={showTree}
111
+ data-open={showTree}
114
112
  onMouseDown={(e) => {
115
113
  if (!e.defaultPrevented) {
116
114
  e.preventDefault();