@ndla/ui 37.1.4 → 39.0.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 (121) hide show
  1. package/es/Article/Article.js +2 -2
  2. package/es/Article/ArticleHeaderWrapper.js +4 -7
  3. package/es/Article/ArticleNotions.js +16 -17
  4. package/es/Article/ArticleSideBar.js +4 -5
  5. package/es/AudioPlayer/Controls.js +187 -237
  6. package/es/BlogPost/BlogPost.js +4 -4
  7. package/es/CompetenceGoals/CompetenceGoalsDialog.js +12 -25
  8. package/es/Filter/FilterButtons.js +12 -14
  9. package/es/Filter/FilterListPhone.js +2 -4
  10. package/es/Footer/index.js +1 -2
  11. package/es/Grid/Grid.js +41 -0
  12. package/es/Grid/index.js +9 -0
  13. package/es/LearningPaths/LearningPathMenuModalWrapper.js +10 -6
  14. package/es/Masthead/MastheadSearchModal.js +56 -47
  15. package/es/MyNdla/SettingsMenu.js +6 -6
  16. package/es/NDLAFilm/AboutNdlaFilm.js +3 -3
  17. package/es/ResourcesWrapper/ResourcesTopicTitle.js +19 -23
  18. package/es/SearchTypeResult/PopupFilter.js +14 -20
  19. package/es/SearchTypeResult/components/ItemContexts.js +10 -21
  20. package/es/Topic/Topic.js +23 -23
  21. package/es/User/index.js +1 -3
  22. package/es/index.js +2 -3
  23. package/es/locale/messages-en.js +1 -0
  24. package/es/locale/messages-nb.js +1 -0
  25. package/es/locale/messages-nn.js +1 -0
  26. package/es/locale/messages-se.js +1 -0
  27. package/es/locale/messages-sma.js +1 -0
  28. package/lib/Article/Article.d.ts +2 -2
  29. package/lib/Article/Article.js +2 -2
  30. package/lib/Article/ArticleHeaderWrapper.d.ts +3 -2
  31. package/lib/Article/ArticleHeaderWrapper.js +4 -7
  32. package/lib/Article/ArticleNotions.js +17 -21
  33. package/lib/Article/ArticleSideBar.js +5 -9
  34. package/lib/AudioPlayer/Controls.d.ts +2 -2
  35. package/lib/AudioPlayer/Controls.js +187 -237
  36. package/lib/BlogPost/BlogPost.d.ts +1 -1
  37. package/lib/BlogPost/BlogPost.js +4 -4
  38. package/lib/CompetenceGoals/CompetenceGoalsDialog.d.ts +3 -14
  39. package/lib/CompetenceGoals/CompetenceGoalsDialog.js +11 -26
  40. package/lib/Filter/FilterButtons.js +13 -15
  41. package/lib/Filter/FilterListPhone.js +3 -5
  42. package/lib/Footer/index.d.ts +1 -2
  43. package/lib/Footer/index.js +0 -7
  44. package/lib/Grid/Grid.d.ts +15 -0
  45. package/lib/Grid/Grid.js +48 -0
  46. package/lib/Grid/index.d.ts +9 -0
  47. package/lib/Grid/index.js +13 -0
  48. package/lib/LearningPaths/LearningPathMenuModalWrapper.js +9 -8
  49. package/lib/Masthead/MastheadSearchModal.d.ts +1 -1
  50. package/lib/Masthead/MastheadSearchModal.js +58 -46
  51. package/lib/MyNdla/SettingsMenu.js +5 -5
  52. package/lib/NDLAFilm/AboutNdlaFilm.js +2 -2
  53. package/lib/ResourcesWrapper/ResourcesTopicTitle.js +20 -27
  54. package/lib/SearchTypeResult/PopupFilter.js +14 -20
  55. package/lib/SearchTypeResult/components/ItemContexts.js +10 -21
  56. package/lib/Topic/Topic.js +22 -22
  57. package/lib/User/index.d.ts +0 -2
  58. package/lib/User/index.js +1 -13
  59. package/lib/index.d.ts +3 -3
  60. package/lib/index.js +8 -20
  61. package/lib/locale/messages-en.d.ts +1 -0
  62. package/lib/locale/messages-en.js +1 -0
  63. package/lib/locale/messages-nb.d.ts +1 -0
  64. package/lib/locale/messages-nb.js +1 -0
  65. package/lib/locale/messages-nn.d.ts +1 -0
  66. package/lib/locale/messages-nn.js +1 -0
  67. package/lib/locale/messages-se.d.ts +1 -0
  68. package/lib/locale/messages-se.js +1 -0
  69. package/lib/locale/messages-sma.d.ts +1 -0
  70. package/lib/locale/messages-sma.js +1 -0
  71. package/package.json +20 -22
  72. package/src/Article/Article.tsx +4 -4
  73. package/src/Article/ArticleHeaderWrapper.tsx +12 -18
  74. package/src/Article/ArticleNotions.tsx +7 -8
  75. package/src/Article/ArticleSideBar.tsx +3 -3
  76. package/src/AudioPlayer/Controls.tsx +150 -289
  77. package/src/BlogPost/BlogPost.stories.tsx +15 -12
  78. package/src/BlogPost/BlogPost.tsx +1 -1
  79. package/src/CompetenceGoals/CompetenceGoalsDialog.tsx +13 -38
  80. package/src/Filter/FilterButtons.tsx +4 -5
  81. package/src/Filter/FilterListPhone.tsx +3 -4
  82. package/src/Footer/index.ts +1 -2
  83. package/src/Grid/Grid.stories.tsx +68 -0
  84. package/src/Grid/Grid.tsx +63 -0
  85. package/src/Grid/index.ts +10 -0
  86. package/src/KeyFigure/KeyFigure.stories.tsx +10 -8
  87. package/src/LearningPaths/LearningPathMenuModalWrapper.tsx +10 -6
  88. package/src/Masthead/MastheadSearchModal.tsx +48 -74
  89. package/src/MyNdla/SettingsMenu.tsx +3 -3
  90. package/src/NDLAFilm/AboutNdlaFilm.tsx +3 -3
  91. package/src/ResourcesWrapper/ResourcesTopicTitle.tsx +4 -8
  92. package/src/SearchTypeResult/PopupFilter.tsx +6 -11
  93. package/src/SearchTypeResult/components/ItemContexts.tsx +4 -21
  94. package/src/Topic/Topic.tsx +7 -7
  95. package/src/User/index.ts +0 -2
  96. package/src/index.ts +3 -3
  97. package/src/locale/messages-en.ts +1 -0
  98. package/src/locale/messages-nb.ts +1 -0
  99. package/src/locale/messages-nn.ts +1 -0
  100. package/src/locale/messages-se.ts +1 -0
  101. package/src/locale/messages-sma.ts +1 -0
  102. package/es/Figure/FigureLicenseDialogContent.js +0 -75
  103. package/es/Footer/FooterAuth.js +0 -110
  104. package/es/Masthead/MastheadAuthModal.js +0 -50
  105. package/es/SearchTypeResult/SearchNotionItem.js +0 -208
  106. package/es/User/AuthModal.js +0 -116
  107. package/lib/Figure/FigureLicenseDialogContent.d.ts +0 -22
  108. package/lib/Figure/FigureLicenseDialogContent.js +0 -80
  109. package/lib/Footer/FooterAuth.d.ts +0 -10
  110. package/lib/Footer/FooterAuth.js +0 -114
  111. package/lib/Masthead/MastheadAuthModal.d.ts +0 -13
  112. package/lib/Masthead/MastheadAuthModal.js +0 -56
  113. package/lib/SearchTypeResult/SearchNotionItem.d.ts +0 -29
  114. package/lib/SearchTypeResult/SearchNotionItem.js +0 -215
  115. package/lib/User/AuthModal.d.ts +0 -22
  116. package/lib/User/AuthModal.js +0 -124
  117. package/src/Figure/FigureLicenseDialogContent.tsx +0 -80
  118. package/src/Footer/FooterAuth.tsx +0 -104
  119. package/src/Masthead/MastheadAuthModal.tsx +0 -62
  120. package/src/SearchTypeResult/SearchNotionItem.tsx +0 -228
  121. package/src/User/AuthModal.tsx +0 -123
@@ -8,179 +8,85 @@
8
8
 
9
9
  import React, { useEffect, useRef, useState } from 'react';
10
10
  import styled from '@emotion/styled';
11
- import { Menu, MenuButton, MenuItem, MenuPopover, MenuItems, MenuItemProps } from '@reach/menu-button';
12
- import { SliderInput, SliderTrack, SliderRange, SliderHandle, SliderOrientation } from '@reach/slider';
13
- import { Popover } from '@headlessui/react';
11
+ import { Root, Trigger, Item, Content, DropdownMenuPortal } from '@radix-ui/react-dropdown-menu';
12
+ import { Root as SliderRoot, Track, Range, SliderThumb } from '@radix-ui/react-slider';
13
+ import { Root as PopoverRoot, PopoverContent, PopoverTrigger, PopoverPortal } from '@radix-ui/react-popover';
14
14
  import { Play, Pause, VolumeUp } from '@ndla/icons/common';
15
15
  import { breakpoints, colors, fonts, misc, mq, spacing } from '@ndla/core';
16
16
  import { useTranslation } from 'react-i18next';
17
17
  import { Back15, Forward15 } from '@ndla/icons/action';
18
+ import { ButtonV2, IconButtonV2 } from '@ndla/button';
18
19
 
19
20
  const ControlsWrapper = styled.div`
20
21
  border: 1px solid ${colors.brand.lighter};
21
22
  display: flex;
22
23
  align-items: center;
23
24
  justify-content: center;
24
- background: #ffffff;
25
+ background: ${colors.white};
25
26
  font-family: ${fonts.sans};
27
+ gap: ${spacing.xsmall};
28
+ padding: ${spacing.small} ${spacing.normal};
26
29
  ${mq.range({ until: breakpoints.tabletWide })} {
27
- flex-wrap: wrap;
28
- }
29
- padding: ${spacing.small};
30
- ${mq.range({ from: breakpoints.tabletWide })} {
31
- padding: ${spacing.small} ${spacing.normal};
30
+ display: grid;
31
+ padding: ${spacing.small};
32
+ grid-template-columns: 1fr repeat(5, auto) 1fr;
33
+ grid-template-areas:
34
+ 'track track track track track track track'
35
+ '. speed backwards play forwards volume .';
32
36
  }
33
37
  `;
34
38
 
35
- const PlayButton = styled.button`
36
- background: ${colors.brand.lighter};
37
- border: none;
38
- display: flex;
39
- align-items: center;
40
- justify-content: center;
41
- padding: 0;
42
- cursor: pointer;
43
- color: ${colors.brand.primary};
44
- width: 55px;
45
- height: 55px;
46
- border-radius: 50%;
47
- transition: ${misc.transition.default};
48
- margin-right: ${spacing.small};
39
+ const PlayButton = styled(IconButtonV2)`
49
40
  ${mq.range({ until: breakpoints.tabletWide })} {
50
- order: 4;
51
- margin-left: ${spacing.small};
52
- }
53
-
54
- &:hover,
55
- &:active,
56
- &:focus {
57
- background: ${colors.brand.primary};
58
- color: #ffffff;
59
- }
60
-
61
- .c-icon {
62
- width: 24px;
63
- height: 24px;
41
+ grid-area: play;
64
42
  }
65
43
  `;
66
44
 
67
- const ForwardRewindButton = styled.button`
68
- background-color: inherit;
69
- background-position: center;
70
- background-repeat: no-repeat;
71
- width: 42px;
72
- height: 42px;
73
- border: 0;
74
- border-radius: 50%;
75
- cursor: pointer;
76
- font-weight: bold;
77
- font-size: 9px;
78
- line-height: 23px;
79
- color: ${colors.brand.dark};
80
- font-family: ${fonts.sans};
81
- transition: ${misc.transition.default};
82
-
83
- &:hover {
84
- background-color: ${colors.brand.greyLighter};
85
- }
86
- `;
87
-
88
- const Forward15SecButton = styled(ForwardRewindButton)`
89
- svg {
90
- fill: ${colors.brand.primary};
91
- width: 24px;
92
- height: 24px;
93
- }
45
+ const Forward15SecButton = styled(IconButtonV2)`
94
46
  ${mq.range({ until: breakpoints.tabletWide })} {
95
- order: 3;
47
+ grid-area: forwards;
96
48
  }
97
49
  `;
98
- const Back15SecButton = styled(ForwardRewindButton)`
99
- svg {
100
- fill: ${colors.brand.primary};
101
- width: 24px;
102
- height: 24px;
103
- }
50
+ const Back15SecButton = styled(IconButtonV2)`
104
51
  ${mq.range({ until: breakpoints.tabletWide })} {
105
- order: 5;
52
+ grid-area: backwards;
106
53
  }
107
54
  `;
108
55
 
109
- const SpeedWrapper = styled.div`
110
- position: relative;
111
- display: flex;
112
- justify-content: center;
56
+ const SpeedButton = styled(ButtonV2)`
113
57
  ${mq.range({ until: breakpoints.tabletWide })} {
114
- order: 2;
115
- }
116
- `;
117
- const SpeedButton = styled(MenuButton)`
118
- height: 32px;
119
- border: 0;
120
- background: none;
121
- cursor: pointer;
122
- font-weight: 600;
123
- font-size: 12px;
124
- text-align: center;
125
- width: 52px;
126
- &:hover,
127
- &:active,
128
- &:focus,
129
- &[aria-expanded='true'] {
130
- background: ${colors.brand.greyLighter};
131
- border-radius: 27px;
132
- color: ${colors.text.primary};
58
+ grid-area: speed;
133
59
  }
134
60
  `;
135
61
 
136
- const SpeedMenu = styled(MenuPopover)`
137
- position: absolute;
138
- bottom: 36px;
139
- z-index: 99;
140
- `;
141
-
142
- const SpeedList = styled(MenuItems)`
143
- background: #ffffff;
62
+ const SpeedList = styled(Content)`
63
+ background: ${colors.white};
144
64
  border: 1px solid ${colors.brand.lighter};
145
- border-radius: 5px;
65
+ border-radius: ${misc.borderRadius};
146
66
  padding: 5px 10px;
147
67
  display: flex;
148
68
  flex-direction: column;
149
69
  justify-content: center;
150
- align-items: stretch;
151
70
  `;
152
71
 
153
- interface SpeedValueButtonProps extends MenuItemProps {
154
- selected?: boolean;
155
- }
156
-
157
- const SpeedValueButton = styled(MenuItem)<SpeedValueButtonProps>`
72
+ const SpeedValueButton = styled(Item)`
158
73
  height: 28px;
159
- position: relative;
160
- background: none;
161
- border: 0;
162
74
  padding: 0 14px;
163
75
  cursor: pointer;
164
- font-weight: 600;
165
- font-size: 14px;
76
+ font-weight: ${fonts.weight.semibold};
77
+ ${fonts.sizes('14px')};
166
78
  color: ${colors.text.light};
167
79
  display: flex;
168
80
  justify-content: center;
169
- align-items: center;
170
81
  &:hover,
171
82
  &:active,
172
83
  &:focus,
173
- &[data-selected] {
84
+ &[data-highlighted] {
174
85
  background: ${colors.brand.greyLighter};
175
86
  border-radius: 5px;
87
+ outline: none;
176
88
  color: ${colors.text.primary};
177
89
  }
178
- ${(props) =>
179
- props.selected &&
180
- `
181
- color: ${colors.text.primary};
182
-
183
- `}
184
90
  `;
185
91
 
186
92
  const SpeedSelectedMark = styled.span`
@@ -188,142 +94,108 @@ const SpeedSelectedMark = styled.span`
188
94
  background: #d1372e;
189
95
  width: 6px;
190
96
  height: 6px;
191
- display: inline-block;
192
- align-self: flex-start;
193
97
  margin: 6px 0 0 2px;
194
98
  `;
195
99
 
196
100
  const Time = styled.div`
197
- font-size: 16px;
101
+ ${fonts.sizes('16px')};
198
102
  `;
199
103
 
200
104
  const ProgressWrapper = styled.div`
201
- flex: 1 1 auto;
105
+ flex: 1;
202
106
  display: flex;
203
107
  align-items: center;
204
- margin: 0 ${spacing.small};
108
+ gap: ${spacing.small};
205
109
  ${mq.range({ until: breakpoints.tabletWide })} {
206
- order: 1;
207
- width: 100%;
208
- margin: 0;
209
- margin-bottom: ${spacing.normal};
110
+ grid-area: track;
210
111
  }
211
112
  `;
212
- const SliderWrapper = styled.div`
113
+
114
+ const SliderWrapper = styled(SliderRoot)`
213
115
  cursor: pointer;
214
- flex: 1 1 auto;
215
- margin: 0 ${spacing.small};
116
+ flex: 1;
117
+ position: relative;
118
+ display: flex;
119
+ align-items: center;
120
+ user-select: none;
121
+ touch-action: none;
216
122
  `;
217
123
 
218
- const ProgressBackground = styled(SliderTrack)`
124
+ const StyledTrack = styled(Track)`
219
125
  height: 4px;
220
126
  width: 100%;
221
127
  background: ${colors.brand.lighter};
222
128
  border-radius: 7px;
223
129
  `;
224
130
 
225
- const ProgressPlayed = styled(SliderRange)`
131
+ const StyledRange = styled(Range)`
132
+ position: absolute;
226
133
  height: 4px;
227
134
  background: #5cbc80;
228
135
  border-radius: 7px;
229
136
  `;
230
137
 
231
- const ProgressHandle = styled(SliderHandle)`
138
+ const StyledThumb = styled(SliderThumb)`
139
+ display: block;
232
140
  width: 20px;
233
141
  height: 20px;
234
142
  background: #5cbc80;
235
143
  border-radius: 50%;
236
- top: -8px;
144
+ outline: none;
237
145
  `;
238
146
 
239
- const VolumeWrapper = styled(Popover)`
147
+ const VolumeWrapper = styled(PopoverRoot)`
240
148
  position: relative;
241
149
  display: flex;
242
150
  justify-content: center;
243
- ${mq.range({ until: breakpoints.tabletWide })} {
244
- order: 6;
245
- }
246
- `;
247
-
248
- const WardButtonWrapper = styled.div<{ order: number }>`
249
- position: relative;
250
- display: flex;
251
- justify-content: center;
252
- ${mq.range({ until: breakpoints.tabletWide })} {
253
- ${(props) =>
254
- `
255
- order: ${props.order};
256
- `}
257
- }
258
- `;
259
-
260
- const VolumeButton = styled(Popover.Button)`
261
- background-color: inherit;
262
- width: 48px;
263
- height: 48px;
264
- border-radius: 50%;
265
- border: 0;
266
- background-position: center;
267
- background-repeat: no-repeat;
268
- cursor: pointer;
269
-
270
- svg {
271
- fill: ${colors.brand.primary};
272
- width: 32px;
273
- height: 32px;
274
- }
275
-
276
- &:hover,
277
- &:active,
278
- &:focus,
279
- &[aria-expanded='true'] {
280
- background-color: ${colors.brand.greyLighter};
281
- }
282
151
  `;
283
152
 
284
- const VolumeList = styled(Popover.Panel)`
285
- position: absolute;
286
- bottom: 52px;
287
- z-index: 99;
153
+ const VolumeList = styled(PopoverContent)`
288
154
  box-shadow: 0 14px 20px -5px rgba(32, 88, 143, 0.17);
289
155
  border-radius: 60px;
290
- background: #ffffff;
156
+ background: ${colors.white};
157
+ padding: ${spacing.small};
291
158
  border: 1px solid ${colors.brand.lighter};
292
- display: flex;
293
- flex-direction: column;
294
- justify-content: center;
295
- width: 32px;
296
159
  height: 128px;
297
160
  `;
298
161
 
299
- const VolumeSliderWrapper = styled.div`
162
+ const VolumeSliderWrapper = styled(SliderRoot)`
300
163
  cursor: pointer;
301
- flex: 1 1 auto;
164
+ height: 100%;
165
+ position: relative;
302
166
  display: flex;
303
- justify-content: center;
304
- padding: 16px 0;
167
+ flex-direction: column;
168
+ align-items: center;
169
+ user-select: none;
170
+ touch-action: none;
171
+ `;
172
+
173
+ const VolumeButton = styled(IconButtonV2)`
174
+ ${mq.range({ until: breakpoints.tabletWide })} {
175
+ grid-area: volume;
176
+ }
305
177
  `;
306
178
 
307
- const VolumeSliderBackground = styled(SliderTrack)`
179
+ const VolumeSliderBackground = styled(Track)`
308
180
  height: 100%;
309
181
  width: 5px;
310
182
  background: ${colors.brand.lighter};
311
183
  border-radius: 7px;
312
184
  `;
313
185
 
314
- const VolumeSliderSelected = styled(SliderRange)`
186
+ const VolumeSliderSelected = styled(Range)`
187
+ position: absolute;
315
188
  width: 5px;
316
189
  background: ${colors.brand.secondary};
317
190
  border-radius: 7px;
318
- bottom: 0;
319
191
  `;
320
192
 
321
- const VolumeSliderHandle = styled(SliderHandle)`
193
+ const VolumeSliderHandle = styled(SliderThumb)`
194
+ display: block;
322
195
  width: 20px;
323
196
  height: 20px;
324
197
  background: ${colors.brand.primary};
325
198
  border-radius: 50%;
326
- left: -8px;
327
199
  `;
328
200
 
329
201
  const formatTime = (seconds: number) => {
@@ -336,16 +208,15 @@ const formatTime = (seconds: number) => {
336
208
 
337
209
  const speedValues = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
338
210
 
339
- type Props = {
211
+ interface Props {
340
212
  src: string;
341
213
  title: string;
342
- };
214
+ }
343
215
 
344
216
  const Controls = ({ src, title }: Props) => {
345
217
  const { t } = useTranslation();
346
218
  const [speedValue, setSpeedValue] = useState(1);
347
219
  const [volumeValue, setVolumeValue] = useState(100);
348
- const [sliderValue, setSliderValue] = useState(0);
349
220
  const [currentTime, setCurrentTime] = useState(0);
350
221
  const [remainingTime, setRemainingTime] = useState(0);
351
222
  const [playing, setPlaying] = useState(false);
@@ -362,8 +233,6 @@ const Controls = ({ src, title }: Props) => {
362
233
  const audioElement = audioRef.current;
363
234
  const handleTimeUpdate = () => {
364
235
  const { currentTime, duration } = audioElement;
365
- const percent = Math.round((currentTime / duration) * 100);
366
- setSliderValue(percent);
367
236
  setCurrentTime(Math.round(currentTime));
368
237
  setRemainingTime(Math.round(duration - currentTime));
369
238
  };
@@ -372,7 +241,6 @@ const Controls = ({ src, title }: Props) => {
372
241
  const { currentTime, duration } = audioElement;
373
242
  setCurrentTime(Math.round(currentTime));
374
243
  setRemainingTime(Math.round(duration - currentTime));
375
- setRemainingTime(Math.round(duration - currentTime));
376
244
  };
377
245
 
378
246
  const handleTimeEnded = () => {
@@ -408,16 +276,16 @@ const Controls = ({ src, title }: Props) => {
408
276
  }
409
277
  };
410
278
 
411
- const handleSliderChange = (value: number) => {
279
+ const handleSliderChange = (value: number[]) => {
412
280
  if (audioRef.current) {
413
- audioRef.current.currentTime = (value / 100) * audioRef.current.duration;
281
+ audioRef.current.currentTime = value[0];
414
282
  }
415
283
  };
416
284
 
417
- const handleVolumeSliderChange = (value: number) => {
285
+ const handleVolumeSliderChange = (values: number[]) => {
418
286
  if (audioRef.current) {
419
- audioRef.current.volume = value / 100;
420
- setVolumeValue(value);
287
+ audioRef.current.volume = values[0] / 100;
288
+ setVolumeValue(values[0]);
421
289
  }
422
290
  };
423
291
 
@@ -426,102 +294,95 @@ const Controls = ({ src, title }: Props) => {
426
294
  {/* eslint-disable-next-line jsx-a11y/media-has-caption */}
427
295
  <audio ref={audioRef} src={src} title={title} preload="metadata" />
428
296
  <ControlsWrapper>
429
- <PlayButton type="button" onClick={togglePlay} title="play" aria-label="play">
430
- <span aria-hidden>
431
- {playing ? (
432
- <Pause role="img" aria-label="Pause" title="Pause" />
433
- ) : (
434
- <Play role="img" aria-label="Play" title="Play" />
435
- )}
436
- </span>
297
+ <PlayButton
298
+ aria-label={t(playing ? t('audio.pause') : t('audio.play'))}
299
+ colorTheme="lighter"
300
+ size="normal"
301
+ onClick={togglePlay}
302
+ >
303
+ {playing ? <Pause /> : <Play />}
437
304
  </PlayButton>
438
- <WardButtonWrapper order={3}>
439
- <Back15SecButton
440
- type="button"
441
- title={t('audio.controls.rewind15sec')}
442
- aria-label={t('audio.controls.rewind15sec')}
443
- onClick={() => {
444
- onSeekSeconds(-15);
445
- }}
446
- >
447
- <Back15 />
448
- </Back15SecButton>
449
- </WardButtonWrapper>
450
-
451
- <SpeedWrapper>
452
- <Menu>
305
+ <Back15SecButton
306
+ variant="ghost"
307
+ colorTheme="greyLighter"
308
+ title={t('audio.controls.rewind15sec')}
309
+ aria-label={t('audio.controls.rewind15sec')}
310
+ onClick={() => onSeekSeconds(-15)}
311
+ >
312
+ <Back15 />
313
+ </Back15SecButton>
314
+
315
+ <Root>
316
+ <Trigger asChild>
453
317
  <SpeedButton
454
- type="button"
455
- as="button"
318
+ shape="pill"
319
+ variant="ghost"
320
+ size="normal"
321
+ colorTheme="greyLighter"
456
322
  title={t('audio.controls.selectSpeed')}
457
323
  aria-label={t('audio.controls.selectSpeed')}
458
324
  >
459
325
  {speedValue}x
460
326
  </SpeedButton>
461
- <SpeedMenu as="div" portal={false}>
462
- <div>
463
- <SpeedList as="div">
464
- {speedValues.map((speed) => (
465
- <SpeedValueButton
466
- type="button"
467
- //@ts-ignore
468
- as="button"
469
- key={speed}
470
- selected={speed === speedValue}
471
- onSelect={() => {
472
- setSpeedValue(speed);
473
- }}
474
- >
475
- {speed}x{speed === speedValue && <SpeedSelectedMark />}
476
- </SpeedValueButton>
477
- ))}
478
- </SpeedList>
479
- </div>
480
- </SpeedMenu>
481
- </Menu>
482
- </SpeedWrapper>
483
- <WardButtonWrapper order={5}>
484
- <Forward15SecButton
485
- type="button"
486
- title={t('audio.controls.forward15sec')}
487
- aria-label={t('audio.controls.forward15sec')}
488
- onClick={() => {
489
- onSeekSeconds(15);
490
- }}
491
- >
492
- <Forward15 />
493
- </Forward15SecButton>
494
- </WardButtonWrapper>
327
+ </Trigger>
328
+ <DropdownMenuPortal>
329
+ <SpeedList side="top">
330
+ {speedValues.map((speed) => (
331
+ <SpeedValueButton key={speed} onSelect={() => setSpeedValue(speed)}>
332
+ {speed}x{speed === speedValue && <SpeedSelectedMark />}
333
+ </SpeedValueButton>
334
+ ))}
335
+ </SpeedList>
336
+ </DropdownMenuPortal>
337
+ </Root>
338
+ <Forward15SecButton
339
+ colorTheme="greyLighter"
340
+ variant="ghost"
341
+ title={t('audio.controls.forward15sec')}
342
+ aria-label={t('audio.controls.forward15sec')}
343
+ onClick={() => onSeekSeconds(15)}
344
+ >
345
+ <Forward15 />
346
+ </Forward15SecButton>
495
347
  <ProgressWrapper>
496
348
  <Time>{formatTime(currentTime)}</Time>
497
- <SliderWrapper>
498
- <SliderInput onChange={handleSliderChange} value={sliderValue}>
499
- <ProgressBackground as="div">
500
- <ProgressPlayed as="div" />
501
- <ProgressHandle as="div" />
502
- </ProgressBackground>
503
- </SliderInput>
349
+ <SliderWrapper
350
+ value={[audioRef.current?.currentTime ?? 0]}
351
+ defaultValue={[0]}
352
+ step={1}
353
+ max={audioRef.current?.duration ?? 0}
354
+ onValueChange={handleSliderChange}
355
+ >
356
+ <StyledTrack>
357
+ <StyledRange />
358
+ </StyledTrack>
359
+ <StyledThumb />
504
360
  </SliderWrapper>
505
361
  <Time>-{formatTime(remainingTime)}</Time>
506
362
  </ProgressWrapper>
507
363
  <VolumeWrapper>
508
- <VolumeButton aria-label={t('audio.controls.adjustVolume')}>
509
- <VolumeUp />
510
- </VolumeButton>
511
- <VolumeList>
512
- <VolumeSliderWrapper>
513
- <SliderInput
514
- orientation={SliderOrientation.Vertical}
515
- onChange={handleVolumeSliderChange}
516
- value={volumeValue}
364
+ <PopoverTrigger asChild>
365
+ <VolumeButton variant="ghost" colorTheme="greyLighter" aria-label={t('audio.controls.adjustVolume')}>
366
+ <VolumeUp />
367
+ </VolumeButton>
368
+ </PopoverTrigger>
369
+ <PopoverPortal>
370
+ <VolumeList side="top">
371
+ <VolumeSliderWrapper
372
+ orientation="vertical"
373
+ value={[volumeValue]}
374
+ min={0}
375
+ defaultValue={[100]}
376
+ step={1}
377
+ onValueChange={handleVolumeSliderChange}
517
378
  >
518
- <VolumeSliderBackground as="div">
519
- <VolumeSliderSelected as="div" />
520
- <VolumeSliderHandle as="div" />
379
+ <VolumeSliderBackground>
380
+ <VolumeSliderSelected />
521
381
  </VolumeSliderBackground>
522
- </SliderInput>
523
- </VolumeSliderWrapper>
524
- </VolumeList>
382
+ <VolumeSliderHandle />
383
+ </VolumeSliderWrapper>
384
+ </VolumeList>
385
+ </PopoverPortal>
525
386
  </VolumeWrapper>
526
387
  </ControlsWrapper>
527
388
  </div>
@@ -8,9 +8,21 @@
8
8
 
9
9
  import React from 'react';
10
10
  import { Meta, StoryFn } from '@storybook/react';
11
- import BlogPost from './BlogPost';
11
+ import BlogPost, { Props } from './BlogPost';
12
12
  import { defaultParameters } from '../../../../stories/defaults';
13
13
 
14
+ const args: Props = {
15
+ title: { title: 'Min bloggpost', language: 'nb-no' },
16
+ author: 'Ola Nordmann',
17
+ url: '#',
18
+ headingLevel: 'h3',
19
+ size: 'large',
20
+ metaImage: {
21
+ alt: 'Yonghetempelet i Beijing. Foto.',
22
+ url: 'https://api.test.ndla.no/image-api/raw/id//62870',
23
+ },
24
+ };
25
+
14
26
  export default {
15
27
  title: 'Enkle komponenter/Blog Post',
16
28
  component: BlogPost,
@@ -18,21 +30,12 @@ export default {
18
30
  parameters: {
19
31
  ...defaultParameters,
20
32
  },
21
- args: {
22
- title: { title: 'Min bloggpost', language: 'nb-no' },
23
- author: 'Ola Nordmann',
24
- url: '#',
25
- headingLevel: 'h3',
26
- size: 'large',
27
- metaImage: {
28
- alt: 'Yonghetempelet i Beijing. Foto.',
29
- url: 'https://api.test.ndla.no/image-api/raw/20080101-032119-ag.jpg',
30
- },
31
- },
33
+ args: args,
32
34
  } as Meta<typeof BlogPost>;
33
35
 
34
36
  export const BlogPostStory: StoryFn<typeof BlogPost> = ({ ...args }) => {
35
37
  return <BlogPost {...args} />;
36
38
  };
37
39
 
40
+ BlogPostStory.args = args;
38
41
  BlogPostStory.storyName = 'BlogPost';
@@ -13,7 +13,7 @@ import { colors, fonts, misc, spacing } from '@ndla/core';
13
13
  import { Quote } from '@ndla/icons/editor';
14
14
  import { HeadingLevel } from '../types';
15
15
 
16
- interface Props {
16
+ export interface Props {
17
17
  title: {
18
18
  title: string;
19
19
  language: string;