@ndla/ui 34.3.6 → 34.5.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.
Files changed (62) hide show
  1. package/es/Article/Article.js +6 -7
  2. package/es/ContentTypeBadge/ContentTypeBadge.js +3 -6
  3. package/es/MyNdla/Resource/Folder.js +38 -29
  4. package/es/Resource/BlockResource.js +21 -13
  5. package/es/Resource/ListResource.js +12 -21
  6. package/es/Resource/resourceComponents.js +18 -22
  7. package/es/SearchTypeResult/ResultNavigation.js +7 -5
  8. package/es/SearchTypeResult/SearchItem.js +51 -89
  9. package/es/SearchTypeResult/SearchItems.js +14 -10
  10. package/es/SearchTypeResult/SearchTypeHeader.js +14 -12
  11. package/es/SearchTypeResult/SearchTypeResult.js +6 -4
  12. package/es/SearchTypeResult/components/ItemContexts.js +12 -14
  13. package/es/SearchTypeResult/components/ItemResourceHeader.js +35 -33
  14. package/es/SearchTypeResult/components/ItemTopicHeader.js +6 -6
  15. package/es/locale/messages-en.js +3 -3
  16. package/es/locale/messages-nb.js +3 -3
  17. package/es/locale/messages-nn.js +3 -3
  18. package/es/locale/messages-sma.js +7 -7
  19. package/lib/Article/Article.js +6 -7
  20. package/lib/ContentTypeBadge/ContentTypeBadge.d.ts +3 -8
  21. package/lib/ContentTypeBadge/ContentTypeBadge.js +3 -6
  22. package/lib/MyNdla/Resource/Folder.js +38 -29
  23. package/lib/Resource/BlockResource.js +20 -12
  24. package/lib/Resource/ListResource.js +12 -21
  25. package/lib/Resource/resourceComponents.d.ts +0 -4
  26. package/lib/Resource/resourceComponents.js +19 -24
  27. package/lib/SearchTypeResult/ResultNavigation.d.ts +4 -1
  28. package/lib/SearchTypeResult/ResultNavigation.js +7 -5
  29. package/lib/SearchTypeResult/SearchItem.d.ts +4 -4
  30. package/lib/SearchTypeResult/SearchItem.js +62 -88
  31. package/lib/SearchTypeResult/SearchItems.d.ts +2 -2
  32. package/lib/SearchTypeResult/SearchItems.js +14 -10
  33. package/lib/SearchTypeResult/SearchTypeHeader.js +14 -12
  34. package/lib/SearchTypeResult/SearchTypeResult.js +6 -4
  35. package/lib/SearchTypeResult/components/ItemContexts.js +12 -14
  36. package/lib/SearchTypeResult/components/ItemResourceHeader.d.ts +2 -2
  37. package/lib/SearchTypeResult/components/ItemResourceHeader.js +35 -33
  38. package/lib/SearchTypeResult/components/ItemTopicHeader.d.ts +2 -2
  39. package/lib/SearchTypeResult/components/ItemTopicHeader.js +6 -6
  40. package/lib/locale/messages-en.js +3 -3
  41. package/lib/locale/messages-nb.js +3 -3
  42. package/lib/locale/messages-nn.js +3 -3
  43. package/lib/locale/messages-sma.js +7 -7
  44. package/package.json +14 -14
  45. package/src/Article/Article.tsx +4 -3
  46. package/src/ContentTypeBadge/ContentTypeBadge.tsx +4 -9
  47. package/src/MyNdla/Resource/Folder.tsx +8 -12
  48. package/src/Resource/BlockResource.tsx +8 -8
  49. package/src/Resource/ListResource.tsx +15 -13
  50. package/src/Resource/resourceComponents.tsx +5 -6
  51. package/src/SearchTypeResult/ResultNavigation.tsx +6 -2
  52. package/src/SearchTypeResult/SearchItem.tsx +61 -77
  53. package/src/SearchTypeResult/SearchItems.tsx +25 -16
  54. package/src/SearchTypeResult/SearchTypeHeader.tsx +9 -3
  55. package/src/SearchTypeResult/SearchTypeResult.tsx +2 -2
  56. package/src/SearchTypeResult/components/ItemContexts.tsx +9 -9
  57. package/src/SearchTypeResult/components/ItemResourceHeader.tsx +33 -31
  58. package/src/SearchTypeResult/components/ItemTopicHeader.tsx +9 -15
  59. package/src/locale/messages-en.ts +3 -3
  60. package/src/locale/messages-nb.ts +3 -3
  61. package/src/locale/messages-nn.ts +3 -3
  62. package/src/locale/messages-sma.ts +7 -7
@@ -6,7 +6,7 @@
6
6
  *
7
7
  */
8
8
 
9
- import React, { ReactNode } from 'react';
9
+ import React, { ReactNode, useRef } from 'react';
10
10
  import styled from '@emotion/styled';
11
11
  import parse from 'html-react-parser';
12
12
 
@@ -20,25 +20,19 @@ import ItemTopicHeader from './components/ItemTopicHeader';
20
20
  import ItemResourceHeader from './components/ItemResourceHeader';
21
21
  const { contentTypes } = constants;
22
22
 
23
- type ItemTypeProps = {
23
+ interface ItemTypeProps {
24
24
  contentType?: ContentType;
25
25
  isTopic?: boolean;
26
- };
26
+ }
27
27
 
28
- const Container = styled.div`
28
+ const Container = styled.article`
29
+ cursor: pointer;
30
+ position: relative;
29
31
  display: flex;
30
- height: 400px;
31
- align-items: center;
32
- justify-content: center;
33
- `;
34
-
35
- const ItemWrapper = styled.div`
36
32
  flex-direction: column;
37
- display: flex;
38
- width: 100%;
39
- height: 100%;
40
- border: 1px solid ${colors.brand.neutral7};
41
33
  border-radius: 5px;
34
+ border: 1px solid ${colors.brand.neutral7};
35
+
42
36
  img {
43
37
  transition: all ${animations.durations.fast} ease-in-out;
44
38
  }
@@ -49,43 +43,36 @@ const ItemWrapper = styled.div`
49
43
  }
50
44
  `;
51
45
 
52
- const ItemLink = styled(SafeLink)`
53
- box-shadow: none;
54
- color: unset;
55
- text-decoration: none;
56
- display: flex;
57
- flex-direction: column;
58
- position: relative;
59
- min-height: 0;
60
- flex: 1;
61
- `;
62
-
63
- const TextWrapper = styled.div`
64
- padding: 0 ${spacing.normal} ${spacing.small};
65
- `;
66
-
67
- const ItemTitleWrapper = styled.div<ItemTypeProps>`
68
- margin-top: ${spacing.small};
69
- `;
70
-
71
46
  const ItemTitle = styled.h3<ItemTypeProps>`
47
+ display: inline;
72
48
  ${fonts.sizes('24px', '28px')};
73
49
  color: ${colors.brand.primary};
74
- ${(props) => props.isTopic && `margin-bottom: ${spacing.small};`};
50
+ margin-bottom: ${(props) => props.isTopic && spacing.small};
75
51
  font-weight: ${fonts.weight.semibold};
76
- overflow-wrap: anywhere;
77
- display: inline;
78
- ${ItemWrapper}:hover & {
79
- box-shadow: inset 0 -1px;
80
- background-color: transparent;
52
+ overflow-wrap: break-word;
53
+ margin: 0;
54
+ ${Container}:hover & {
55
+ box-shadow: 0 -1px inset;
56
+ }
57
+ `;
58
+
59
+ const StyledLink = styled(SafeLink)`
60
+ box-shadow: none;
61
+ color: ${colors.brand.primary};
62
+
63
+ :after {
64
+ content: '';
65
+ position: absolute;
66
+ z-index: 1;
67
+ top: 0;
68
+ right: 0;
69
+ bottom: 0;
70
+ left: 0;
81
71
  }
82
72
  `;
73
+
83
74
  const ItemText = styled.div<ItemTypeProps>`
84
- overflow: hidden;
85
75
  ${fonts.sizes('16px', '24px')};
86
- word-break: break-word;
87
- overflow-wrap: anywhere;
88
- margin-top: ${spacing.small};
89
76
  ${(props) =>
90
77
  props.isTopic &&
91
78
  `
@@ -93,12 +80,14 @@ const ItemText = styled.div<ItemTypeProps>`
93
80
  `};
94
81
  `;
95
82
 
96
- const ContextWrapper = styled.div`
97
- background: white;
98
- padding: 0 ${spacing.normal} ${spacing.small};
83
+ const ContentWrapper = styled.main`
84
+ display: flex;
85
+ flex-direction: column;
86
+ gap: ${spacing.small};
87
+ padding: ${spacing.small} ${spacing.normal};
99
88
  `;
100
89
 
101
- export type SearchItemProps = {
90
+ export interface SearchItemProps {
102
91
  id: string | number;
103
92
  title: string;
104
93
  url: string;
@@ -108,44 +97,39 @@ export type SearchItemProps = {
108
97
  labels?: string[];
109
98
  type?: ContentType;
110
99
  children?: ReactNode;
111
- };
112
- export type SearchItemType = {
100
+ }
101
+
102
+ export interface SearchItemType {
113
103
  item: SearchItemProps;
114
104
  type?: ContentType;
115
- };
105
+ }
106
+
116
107
  const SearchItem = ({ item, type }: SearchItemType) => {
117
- const { title, url, ingress, contexts, img = null, labels = [], children } = item;
108
+ const { title, url, ingress, contexts = [], img = null, labels = [] } = item;
109
+ const linkRef = useRef<HTMLAnchorElement>(null);
118
110
 
119
111
  const isTopic = type === contentTypes.TOPIC || type === contentTypes.MULTIDISCIPLINARY_TOPIC;
120
112
 
121
113
  return (
122
114
  <Container>
123
- <ItemWrapper>
124
- <ItemLink to={url}>
125
- {isTopic ? (
126
- <ItemTopicHeader image={img} type={type}>
127
- <ItemTitleWrapper isTopic>
128
- <ItemTitle isTopic>{title}</ItemTitle>
129
- </ItemTitleWrapper>
130
- <ItemText isTopic>{parse(ingress)}</ItemText>
131
- </ItemTopicHeader>
132
- ) : (
133
- <>
134
- <ItemResourceHeader labels={labels} img={img} type={type} />
135
- <TextWrapper>
136
- <ItemTitleWrapper>
137
- <ItemTitle>{title}</ItemTitle>
138
- </ItemTitleWrapper>
139
- <ItemText>{parse(ingress)}</ItemText>
140
- </TextWrapper>
141
- </>
142
- )}
143
- <ContextWrapper>
144
- {contexts && contexts.length > 0 && <ItemContexts contexts={contexts} id={item.id} title={item.title} />}
145
- </ContextWrapper>
146
- </ItemLink>
147
- {children}
148
- </ItemWrapper>
115
+ {isTopic ? (
116
+ <ItemTopicHeader image={img} type={type}>
117
+ <StyledLink to={url} ref={linkRef}>
118
+ <ItemTitle>{title}</ItemTitle>
119
+ </StyledLink>
120
+ </ItemTopicHeader>
121
+ ) : (
122
+ <ItemResourceHeader labels={labels} img={img} type={type} />
123
+ )}
124
+ <ContentWrapper>
125
+ {!isTopic && (
126
+ <StyledLink to={url} ref={linkRef}>
127
+ <ItemTitle>{title}</ItemTitle>
128
+ </StyledLink>
129
+ )}
130
+ <ItemText isTopic={isTopic}>{parse(ingress)}</ItemText>
131
+ {contexts.length > 0 && <ItemContexts contexts={contexts} id={item.id} title={item.title} />}
132
+ </ContentWrapper>
149
133
  </Container>
150
134
  );
151
135
  };
@@ -8,6 +8,7 @@
8
8
 
9
9
  import React, { memo } from 'react';
10
10
  import styled from '@emotion/styled';
11
+ import { css } from '@emotion/react';
11
12
  import { breakpoints, mq, spacing } from '@ndla/core';
12
13
  import SearchItem, { SearchItemProps } from './SearchItem';
13
14
  import { ContentType } from './SearchTypeResult';
@@ -18,41 +19,49 @@ const Wrapper = styled.div`
18
19
  position: relative;
19
20
  `;
20
21
 
21
- type ContainerProps = {
22
+ interface ContainerProps {
22
23
  viewType: Props['viewType'];
23
- };
24
+ }
24
25
 
25
- const Container = styled.div<ContainerProps>`
26
+ const Container = styled.ul<ContainerProps>`
26
27
  display: grid;
28
+ align-items: flex-start;
29
+ list-style: none;
27
30
  row-gap: ${spacing.normal};
28
31
  grid-template-columns: repeat(1, 1fr);
29
32
 
30
33
  ${(props) =>
31
34
  props.viewType === 'grid' &&
32
- `
33
- ${mq.range({ from: breakpoints.tablet })} {
34
- column-gap: ${spacing.normal};
35
- grid-template-columns: repeat(2, 1fr);
36
- }
37
-
38
- ${mq.range({ from: breakpoints.desktop })} {
39
- grid-template-columns: repeat(3, 1fr);
40
- }`}
35
+ css`
36
+ ${mq.range({ from: breakpoints.tablet })} {
37
+ column-gap: ${spacing.normal};
38
+ grid-template-columns: repeat(2, 1fr);
39
+ }
40
+
41
+ ${mq.range({ from: breakpoints.desktop })} {
42
+ grid-template-columns: repeat(3, 1fr);
43
+ }
44
+ `}
41
45
  `;
42
46
 
43
- type Props = {
47
+ interface Props {
44
48
  items: SearchItemProps[];
45
49
  type?: ContentType;
46
50
  viewType?: 'grid' | 'list';
47
- };
51
+ }
52
+
48
53
  const SearchItems = ({ items, type, viewType = 'grid' }: Props) => {
49
54
  return (
50
55
  <Wrapper>
51
- <Container viewType={viewType}>
56
+ <Container aria-labelledby={`searchitem-header-${type}`} viewType={viewType}>
52
57
  {items.map((item) => {
53
58
  const contentType = type || item.type;
54
59
  const Component = viewType === 'list' ? SearchItemList : SearchItem;
55
- return <Component item={item} key={`${item.id}`} type={contentType} />;
60
+ return (
61
+ <li key={`${item.id}`}>
62
+ <Component item={item} type={contentType} />
63
+ </li>
64
+ );
56
65
  })}
57
66
  </Container>
58
67
  </Wrapper>
@@ -42,10 +42,13 @@ const BadgeWrapper = styled.span`
42
42
  margin-right: ${spacing.small};
43
43
  `;
44
44
 
45
- const SubjectName = styled.span`
45
+ const SubjectName = styled.div`
46
+ display: flex;
47
+ gap: ${spacing.small};
46
48
  ${fonts.sizes('18px', '24px')};
47
49
  margin: 2px 0;
48
- b {
50
+ h2 {
51
+ margin: 0;
49
52
  ${fonts.sizes('18px', '24px')};
50
53
  margin-right: 4px;
51
54
  }
@@ -97,7 +100,9 @@ const SearchTypeHeader = ({ filters = [], onFilterClick, totalCount, type }: Pro
97
100
  </BadgeWrapper>
98
101
  )}
99
102
  <SubjectName>
100
- <b>{type ? t(`contentTypes.${type}`) : t(`searchPage.resultType.allContentTypes`)}</b>{' '}
103
+ <h2 id={`searchitem-header-${type}`}>
104
+ {type ? t(`contentTypes.${type}`) : t(`searchPage.resultType.allContentTypes`)}
105
+ </h2>
101
106
  {totalCount && <Count>{t(`searchPage.resultType.hits`, { count: totalCount })}</Count>}
102
107
  </SubjectName>
103
108
  </TypeWrapper>
@@ -107,6 +112,7 @@ const SearchTypeHeader = ({ filters = [], onFilterClick, totalCount, type }: Pro
107
112
  {filters.map((option: FilterOptionsType) => (
108
113
  <CategoryTypeButtonWrapper key={option.id}>
109
114
  <Button
115
+ aria-current={option.active}
110
116
  size="xsmall"
111
117
  borderShape="rounded"
112
118
  greyLighter={!option.active}
@@ -16,7 +16,7 @@ import SearchItems from './SearchItems';
16
16
  import { SearchItemProps } from './SearchItem';
17
17
  import ResultNavigation, { PaginationType } from './ResultNavigation';
18
18
 
19
- const Wrapper = styled.div`
19
+ const Wrapper = styled.section`
20
20
  display: flex;
21
21
  flex-direction: column;
22
22
  flex: 1;
@@ -81,7 +81,7 @@ const SearchTypeResult = ({
81
81
  )}
82
82
  <SearchTypeHeader onFilterClick={onFilterClick} filters={filters} totalCount={totalCount} type={type} />
83
83
  <SearchItems items={items} type={type} viewType={viewType} />
84
- {pagination && <ResultNavigation {...pagination} />}
84
+ {pagination && <ResultNavigation {...pagination} type={type} />}
85
85
  {children}
86
86
  </Wrapper>
87
87
  );
@@ -11,8 +11,8 @@ import SafeLink from '@ndla/safelink';
11
11
  import { Additional, Core } from '@ndla/icons/common';
12
12
  import styled from '@emotion/styled';
13
13
  import { breakpoints, colors, fonts, mq, spacing } from '@ndla/core';
14
- import Button from '@ndla/button';
15
- import Modal, { ModalCloseButton } from '@ndla/modal';
14
+ import { ButtonV2 } from '@ndla/button';
15
+ import { ModalV2, ModalCloseButton } from '@ndla/modal';
16
16
  import { useTranslation } from 'react-i18next';
17
17
 
18
18
  const BreadcrumbPath = styled.div`
@@ -24,7 +24,9 @@ const BreadcrumbPath = styled.div`
24
24
  }
25
25
  `;
26
26
 
27
- const ModalButton = styled(Button)`
27
+ const ModalButton = styled(ButtonV2)`
28
+ z-index: 1;
29
+ position: relative;
28
30
  ${fonts.sizes('14px', '20px')};
29
31
  box-shadow: none;
30
32
  &:hover {
@@ -97,19 +99,17 @@ const ItemContexts = ({ contexts, id, title }: ItemContextsType) => {
97
99
  <Breadcrumb breadcrumb={mainContext.breadcrumb}>
98
100
  &nbsp;
99
101
  {contexts.length > 1 && (
100
- <Modal
102
+ <ModalV2
101
103
  label={t('searchPage.contextModal.ariaLabel')}
102
104
  activateButton={
103
- <ModalButton link>
105
+ <ModalButton variant="link">
104
106
  {t('searchPage.contextModal.button', {
105
107
  count: contexts.length - 1,
106
108
  })}
107
109
  </ModalButton>
108
110
  }
109
111
  animation="subtle"
110
- animationDuration={50}
111
- backgroundColor="white"
112
- size="medium">
112
+ animationDuration={50}>
113
113
  {(onClose: () => void) => (
114
114
  <>
115
115
  <ModalHeader>
@@ -130,7 +130,7 @@ const ItemContexts = ({ contexts, id, title }: ItemContextsType) => {
130
130
  </ModalContent>
131
131
  </>
132
132
  )}
133
- </Modal>
133
+ </ModalV2>
134
134
  )}
135
135
  </Breadcrumb>
136
136
  );
@@ -18,29 +18,20 @@ import { SearchItemType } from '../SearchItem';
18
18
  import resourceTypeColor from '../../utils/resourceTypeColor';
19
19
  import ContentTypeBadge from '../../ContentTypeBadge';
20
20
 
21
- type ItemTypeProps = {
21
+ interface ItemTypeProps {
22
22
  contentType?: ContentType;
23
- };
23
+ }
24
24
 
25
25
  const ImageElement = styled.img`
26
26
  width: 100%;
27
27
  height: 100%;
28
28
  object-fit: cover;
29
- `;
30
-
31
- const ImageWrapper = styled.div`
32
- flex: 1;
33
- border-top-left-radius: 5px;
34
- border-top-right-radius: 5px;
35
29
  overflow: hidden;
36
30
  `;
37
31
 
38
32
  const NoImageElement = styled.div<ItemTypeProps>`
39
- border-top-left-radius: 5px;
40
- border-top-right-radius: 5px;
41
33
  flex: 1;
42
34
  background: ${(props) => props.contentType && `${resourceTypeColor(props.contentType)}`};
43
- position: relative;
44
35
  display: flex;
45
36
  align-items: center;
46
37
  justify-content: center;
@@ -59,7 +50,6 @@ const NoImageElement = styled.div<ItemTypeProps>`
59
50
  const ContentTypeWrapper = styled.div<ItemTypeProps>`
60
51
  height: 48px;
61
52
  background: ${(props) => props.contentType && `${resourceTypeColor(props.contentType)}`};
62
- flex: 0 0 auto;
63
53
  position: relative;
64
54
  display: flex;
65
55
  align-items: center;
@@ -69,47 +59,59 @@ const ContentTypeWrapper = styled.div<ItemTypeProps>`
69
59
  `;
70
60
 
71
61
  const ContentTypeIcon = styled.span<ItemTypeProps>`
62
+ display: flex;
72
63
  position: absolute;
73
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='78' height='23' viewBox='17 0 78 23' fill='none'%3E%3Cpath d='M35.6874 10.8284C37.0999 8.9889 38.405 7.28934 40 6C44.8452 2.08335 48.9078 0 56 0C63.0922 0 67.6548 2.5833 72.5 6.49995C74.0499 7.75284 75.2937 9.39082 76.6385 11.1617C80.0028 15.5921 83.9988 20.8545 95 23H17C27.9865 20.8573 32.1701 15.409 35.6874 10.8284ZM352' fill='${(
74
- props,
75
- ) => props.contentType && `${encodeURIComponent(resourceTypeColor(props.contentType))}`}'/%3E%3C/svg%3E");
76
- background-position: top;
77
- background-repeat: no-repeat;
78
- left: 17px;
79
64
  top: -23px;
80
- height: 45px;
81
- width: 78px;
82
- display: flex;
65
+ margin-left: ${spacing.small};
83
66
  justify-content: center;
84
- align-items: center;
85
- z-index: 2;
67
+ ::before {
68
+ content: '';
69
+ position: absolute;
70
+ height: 23px;
71
+ width: 78px;
72
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='78' height='23' viewBox='17 0 78 23' fill='none'%3E%3Cpath d='M35.6874 10.8284C37.0999 8.9889 38.405 7.28934 40 6C44.8452 2.08335 48.9078 0 56 0C63.0922 0 67.6548 2.5833 72.5 6.49995C74.0499 7.75284 75.2937 9.39082 76.6385 11.1617C80.0028 15.5921 83.9988 20.8545 95 23H17C27.9865 20.8573 32.1701 15.409 35.6874 10.8284ZM352' fill='${(
73
+ props,
74
+ ) => props.contentType && `${encodeURIComponent(resourceTypeColor(props.contentType))}`}'/%3E%3C/svg%3E");
75
+ }
76
+ `;
77
+
78
+ const StyledContentTypeBadge = styled(ContentTypeBadge)`
79
+ z-index: 1;
80
+ margin-top: ${spacing.xxsmall};
81
+
86
82
  svg {
87
83
  width: 20px;
88
84
  height: 20px;
89
85
  }
90
86
  `;
91
87
 
92
- type Props = {
88
+ const Wrapper = styled.header`
89
+ display: grid;
90
+ grid-template-rows: 1fr auto;
91
+ overflow: hidden;
92
+ flex-direction: column;
93
+ height: 180px;
94
+ `;
95
+
96
+ interface Props {
93
97
  labels: SearchItemType['item']['labels'];
94
98
  img?: SearchItemType['item']['img'] | null;
95
99
  type?: ContentType;
96
- };
100
+ }
97
101
 
98
102
  const ItemResourceHeader = ({ labels = [], img, type }: Props) => {
99
103
  const { t } = useTranslation();
100
104
  return (
101
- <>
105
+ <Wrapper>
102
106
  {img ? (
103
- <ImageWrapper>
104
- <ImageElement src={img.url} alt={img.alt} />
105
- </ImageWrapper>
107
+ <ImageElement src={img.url} alt={img.alt} />
106
108
  ) : (
107
109
  <NoImageElement contentType={type}>{type && <ContentTypeBadge type={type} border={false} />}</NoImageElement>
108
110
  )}
109
111
  <ContentTypeWrapper className="resource-type-wrapper" contentType={type}>
110
112
  {img && type && (
111
113
  <ContentTypeIcon className="resource-icon-wrapper" contentType={type}>
112
- <ContentTypeBadge type={type} border={false} />
114
+ <StyledContentTypeBadge type={type} border={false} />
113
115
  </ContentTypeIcon>
114
116
  )}
115
117
  {type && t(`contentTypes.${type}`)}
@@ -124,7 +126,7 @@ const ItemResourceHeader = ({ labels = [], img, type }: Props) => {
124
126
  </>
125
127
  )}
126
128
  </ContentTypeWrapper>
127
- </>
129
+ </Wrapper>
128
130
  );
129
131
  };
130
132
 
@@ -15,11 +15,8 @@ import { SearchItemType } from '../SearchItem';
15
15
  import ContentTypeBadge from '../../ContentTypeBadge';
16
16
  import { ContentType } from '../SearchTypeResult';
17
17
 
18
- const Wrapper = styled.div`
19
- padding: ${spacing.small} ${spacing.normal};
20
- position: relative;
21
- min-height: 0;
22
- flex: 1;
18
+ const Wrapper = styled.header`
19
+ padding: ${spacing.small} ${spacing.normal} 0;
23
20
  `;
24
21
 
25
22
  const Label = styled.div`
@@ -28,7 +25,7 @@ const Label = styled.div`
28
25
  height: 26px;
29
26
  display: flex;
30
27
  align-items: center;
31
- margin-top: ${spacing.small};
28
+ margin: ${spacing.small} 0;
32
29
 
33
30
  .c-content-type-badge {
34
31
  width: 26px;
@@ -46,15 +43,11 @@ const Label = styled.div`
46
43
  const TopicHeaderVisualElementWrapper = styled.div`
47
44
  float: right;
48
45
  margin-left: ${spacing.small};
49
- position: relative;
50
- width: 112px;
51
- height: 112px;
46
+ width: 110px;
47
+ height: 110px;
52
48
  display: flex;
53
- justify-content: center;
54
- align-items: center;
55
49
  overflow: hidden;
56
50
  border-radius: 50%;
57
- -webkit-mask-image: -webkit-radial-gradient(white, black);
58
51
  `;
59
52
 
60
53
  const TopicHeaderImage = styled.img`
@@ -64,18 +57,19 @@ const TopicHeaderImage = styled.img`
64
57
  max-width: unset;
65
58
  `;
66
59
 
67
- type Props = {
60
+ interface Props {
68
61
  children: ReactNode;
69
62
  image?: SearchItemType['item']['img'] | null;
70
63
  type?: ContentType;
71
- };
64
+ }
65
+
72
66
  const ItemTopicHeader = ({ children, image, type }: Props) => {
73
67
  const { t } = useTranslation();
74
68
  return (
75
69
  <Wrapper>
76
70
  {image && (
77
71
  <TopicHeaderVisualElementWrapper>
78
- <TopicHeaderImage className="topic-header-image" src={image.url} alt={image.alt} />
72
+ <TopicHeaderImage className="topic-header-image" src={image.url} alt="" />
79
73
  </TopicHeaderVisualElementWrapper>
80
74
  )}
81
75
  <Label className="topic-label">
@@ -335,7 +335,7 @@ const messages = {
335
335
  multidisciplinarySubjects: 'Multidisciplinary subjects',
336
336
  toolboxStudents: 'Toolbox - for students',
337
337
  toolboxTeachers: 'Toolbox - for teachers',
338
- film: 'NDLA Film',
338
+ film: 'NDLA film',
339
339
  about: {
340
340
  title: 'About NDLA',
341
341
  numbers: 'Numbers and reports',
@@ -793,7 +793,7 @@ const messages = {
793
793
  loadingMovies: 'Loading movies..',
794
794
  subjectsInMovies: 'Subjects in film',
795
795
  about: {
796
- heading: 'About NDLA Film',
796
+ heading: 'About NDLA film',
797
797
  more: 'Read more about NDLA film',
798
798
  text: 'Ndla film er ei nettbasert filmtjeneste for elever og lærere i videregående skole. Her finn du spillefilmer, kortfilmer, dokumentarfilmer og TV-serier.',
799
799
  },
@@ -835,7 +835,7 @@ const messages = {
835
835
  },
836
836
  allMovieGroupTitleLabel: 'Movies starting with {{letter}}',
837
837
  moreAboutNdlaFilm: {
838
- header: 'NDLA Film',
838
+ header: 'NDLA film',
839
839
  firstParagraph:
840
840
  "The films in the film service are taken from Norwegian and international film heritage and are linked to curricula in several subjects. They have been selected by NDLA's editors in collaboration with Norgesfilm AS.",
841
841
  secondParagraph:
@@ -334,7 +334,7 @@ const messages = {
334
334
  multidisciplinarySubjects: 'Tverrfaglige tema',
335
335
  toolboxStudents: 'Verktøykassa - for elever',
336
336
  toolboxTeachers: 'Verktøykassa - for lærere',
337
- film: 'NDLA Film',
337
+ film: 'NDLA film',
338
338
  about: {
339
339
  title: 'Om NDLA',
340
340
  numbers: 'Tall og rapporter',
@@ -792,7 +792,7 @@ const messages = {
792
792
  loadingMovies: 'Henter filmer...',
793
793
  subjectsInMovies: 'Emner i film',
794
794
  about: {
795
- heading: 'Om NDLA Film',
795
+ heading: 'Om NDLA film',
796
796
  more: 'Les mer om NDLA film',
797
797
  text: 'Ndla film er en nettbasert filmtjeneste for elever og lærere i videregående skole. Her funner du spillefilmer, kortfilmer, dokumentarfilmer og TV-serier.',
798
798
  },
@@ -834,7 +834,7 @@ const messages = {
834
834
  },
835
835
  allMovieGroupTitleLabel: 'Filmer som starter på {{letter}}',
836
836
  moreAboutNdlaFilm: {
837
- header: 'NDLA Film',
837
+ header: 'NDLA film',
838
838
  firstParagraph:
839
839
  'Filmene i filmtjenesten er hentet fra norsk og internasjonal filmarv og kobles mot læreplaner i flere fag. De er valgt ut av NDLAs redaksjoner i samarbeid med Norgesfilm AS.',
840
840
  secondParagraph:
@@ -334,7 +334,7 @@ const messages = {
334
334
  multidisciplinarySubjects: 'Tverrfaglege tema',
335
335
  toolboxStudents: 'Verktøykassa - for elevar',
336
336
  toolboxTeachers: 'Verktøykassa - for lærarar',
337
- film: 'NDLA Film',
337
+ film: 'NDLA film',
338
338
  about: {
339
339
  title: 'Om NDLA',
340
340
  numbers: 'Tall og rapporter',
@@ -792,7 +792,7 @@ const messages = {
792
792
  loadingMovies: 'Hentar filmar...',
793
793
  subjectsInMovies: 'Emne i film',
794
794
  about: {
795
- heading: 'Om NDLA Film',
795
+ heading: 'Om NDLA film',
796
796
  more: 'Les meir om NDLA film',
797
797
  text: 'NDLA film er ei nettbasert filmteneste for elevar og lærarar i vidaregåande skule. Her finn du spelefilmar, kortfilmar, dokumentarfilmar og TV-seriar.',
798
798
  },
@@ -834,7 +834,7 @@ const messages = {
834
834
  },
835
835
  allMovieGroupTitleLabel: 'Filmar som startar på {{letter}}',
836
836
  moreAboutNdlaFilm: {
837
- header: 'NDLA Film',
837
+ header: 'NDLA film',
838
838
  firstParagraph:
839
839
  'Filmane i filmtenesta er henta frå norsk og internasjonal filmarv og er kopla mot læreplanar i fleire fag. Dei er valde av redaksjonane til NDLA i samarbeid med Norgesfilm AS.',
840
840
  secondParagraph: