@ndla/ui 49.0.0 → 49.0.3

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 (45) hide show
  1. package/es/ContactBlock/ContactBlock.js +29 -20
  2. package/es/Embed/BrightcoveEmbed.js +8 -6
  3. package/es/Embed/ImageEmbed.js +7 -5
  4. package/es/Gloss/Gloss.js +10 -8
  5. package/es/LanguageSelector/LanguageSelector.js +8 -6
  6. package/es/locale/messages-en.js +15 -2
  7. package/es/locale/messages-nb.js +17 -4
  8. package/es/locale/messages-nn.js +19 -6
  9. package/es/locale/messages-se.js +13 -0
  10. package/es/locale/messages-sma.js +16 -3
  11. package/lib/ContactBlock/ContactBlock.js +28 -19
  12. package/lib/Embed/BrightcoveEmbed.d.ts +3 -2
  13. package/lib/Embed/BrightcoveEmbed.js +8 -6
  14. package/lib/Embed/ImageEmbed.d.ts +3 -2
  15. package/lib/Embed/ImageEmbed.js +7 -5
  16. package/lib/Embed/index.d.ts +1 -1
  17. package/lib/Embed/types.d.ts +1 -0
  18. package/lib/Gloss/Gloss.js +10 -8
  19. package/lib/LanguageSelector/LanguageSelector.d.ts +2 -1
  20. package/lib/LanguageSelector/LanguageSelector.js +8 -6
  21. package/lib/index.d.ts +1 -1
  22. package/lib/locale/messages-en.d.ts +13 -0
  23. package/lib/locale/messages-en.js +15 -2
  24. package/lib/locale/messages-nb.d.ts +13 -0
  25. package/lib/locale/messages-nb.js +17 -4
  26. package/lib/locale/messages-nn.d.ts +13 -0
  27. package/lib/locale/messages-nn.js +19 -6
  28. package/lib/locale/messages-se.d.ts +13 -0
  29. package/lib/locale/messages-se.js +13 -0
  30. package/lib/locale/messages-sma.d.ts +13 -0
  31. package/lib/locale/messages-sma.js +16 -3
  32. package/package.json +17 -17
  33. package/src/ContactBlock/ContactBlock.tsx +12 -6
  34. package/src/Embed/BrightcoveEmbed.tsx +6 -5
  35. package/src/Embed/ImageEmbed.tsx +14 -5
  36. package/src/Embed/index.ts +1 -1
  37. package/src/Embed/types.ts +2 -0
  38. package/src/Gloss/Gloss.tsx +4 -2
  39. package/src/LanguageSelector/LanguageSelector.tsx +9 -2
  40. package/src/index.ts +1 -1
  41. package/src/locale/messages-en.ts +15 -2
  42. package/src/locale/messages-nb.ts +17 -4
  43. package/src/locale/messages-nn.ts +19 -6
  44. package/src/locale/messages-se.ts +14 -0
  45. package/src/locale/messages-sma.ts +16 -3
@@ -18,12 +18,13 @@ import { ButtonV2 } from '@ndla/button';
18
18
  import { Figure } from '../Figure';
19
19
  import { EmbedByline } from '../LicenseByline';
20
20
  import EmbedErrorPlaceholder from './EmbedErrorPlaceholder';
21
- import { HeartButtonType } from './types';
21
+ import { HeartButtonType, RenderContext } from './types';
22
22
 
23
23
  interface Props {
24
24
  embed: BrightcoveMetaData;
25
25
  isConcept?: boolean;
26
26
  heartButton?: HeartButtonType;
27
+ renderContext?: RenderContext;
27
28
  }
28
29
 
29
30
  const LinkedVideoButton = styled(ButtonV2)`
@@ -57,19 +58,19 @@ const getIframeProps = (data: BrightcoveEmbedData, sources: BrightcoveVideoSourc
57
58
  width: source?.width ?? '640',
58
59
  };
59
60
  };
60
- const BrightcoveEmbed = ({ embed, isConcept, heartButton: HeartButton }: Props) => {
61
+ const BrightcoveEmbed = ({ embed, isConcept, heartButton: HeartButton, renderContext = 'article' }: Props) => {
61
62
  const [showOriginalVideo, setShowOriginalVideo] = useState(true);
62
63
  const { t } = useTranslation();
63
64
  const iframeRef = useRef<HTMLIFrameElement>(null);
64
65
  const { embedData } = embed;
65
66
  const fallbackTitle = `${t('embed.type.video')}: ${embedData.videoid}`;
66
67
  const parsedDescription = useMemo(() => {
67
- if (embed.embedData.caption) {
68
- return parse(embed.embedData.caption);
68
+ if (embed.embedData.caption || renderContext === 'article') {
69
+ return embed.embedData.caption ? parse(embed.embedData.caption) : undefined;
69
70
  } else if (embed.status === 'success' && embed.data.description) {
70
71
  return parse(embed.data.description);
71
72
  }
72
- }, [embed]);
73
+ }, [embed, renderContext]);
73
74
 
74
75
  useEffect(() => {
75
76
  const iframe = iframeRef.current;
@@ -19,7 +19,7 @@ import { Figure, FigureType } from '../Figure';
19
19
  import Image, { ImageLink } from '../Image';
20
20
  import { EmbedByline } from '../LicenseByline';
21
21
  import EmbedErrorPlaceholder from './EmbedErrorPlaceholder';
22
- import { HeartButtonType } from './types';
22
+ import { HeartButtonType, RenderContext } from './types';
23
23
 
24
24
  interface Props {
25
25
  embed: ImageMetaData;
@@ -28,6 +28,7 @@ interface Props {
28
28
  heartButton?: HeartButtonType;
29
29
  inGrid?: boolean;
30
30
  lang?: string;
31
+ renderContext?: RenderContext;
31
32
  }
32
33
 
33
34
  export interface Author {
@@ -105,17 +106,25 @@ export const getCrop = (data: ImageEmbedData) => {
105
106
 
106
107
  const expandedSizes = '(min-width: 1024px) 1024px, 100vw';
107
108
 
108
- const ImageEmbed = ({ embed, previewAlt, heartButton: HeartButton, inGrid, path, lang }: Props) => {
109
+ const ImageEmbed = ({
110
+ embed,
111
+ previewAlt,
112
+ heartButton: HeartButton,
113
+ inGrid,
114
+ path,
115
+ lang,
116
+ renderContext = 'article',
117
+ }: Props) => {
109
118
  const [isBylineHidden, setIsBylineHidden] = useState(hideByline(embed.embedData.size));
110
119
  const [imageSizes, setImageSizes] = useState<string | undefined>(undefined);
111
120
 
112
121
  const parsedDescription = useMemo(() => {
113
- if (embed.embedData.caption) {
114
- return parse(embed.embedData.caption);
122
+ if (embed.embedData.caption || renderContext === 'article') {
123
+ return embed.embedData.caption ? parse(embed.embedData.caption) : undefined;
115
124
  } else if (embed.status === 'success' && embed.data.caption.caption) {
116
125
  return parse(embed.data.caption.caption);
117
126
  }
118
- }, [embed]);
127
+ }, [embed, renderContext]);
119
128
 
120
129
  if (embed.status === 'error') {
121
130
  const { align, size } = embed.embedData;
@@ -20,4 +20,4 @@ export { ConceptNotionV2 } from './conceptComponents';
20
20
  export { default as ConceptListEmbed } from './ConceptListEmbed';
21
21
  export { default as UnknownEmbed } from './UnknownEmbed';
22
22
  export { InlineConcept, BlockConcept } from './ConceptEmbed';
23
- export type { HeartButtonType } from './types';
23
+ export type { HeartButtonType, RenderContext } from './types';
@@ -10,3 +10,5 @@ import { ElementType } from 'react';
10
10
  import { EmbedMetaData } from '@ndla/types-embed';
11
11
 
12
12
  export type HeartButtonType = ElementType<{ embed: Extract<EmbedMetaData, { status: 'success' }> }>;
13
+
14
+ export type RenderContext = 'article' | 'embed';
@@ -129,7 +129,7 @@ const Gloss = ({ title, glossData, audio }: Props) => {
129
129
  </GlossContainer>
130
130
  {audio?.src && <SpeechControl src={audio.src} title={audio.title}></SpeechControl>}
131
131
  </Wrapper>
132
- <span>{title.title}</span>
132
+ <span lang={title.language}>{title.title}</span>
133
133
  </Container>
134
134
  {glossData.examples && glossData.examples.length > 0 && (
135
135
  <AccordionRoot type="single" collapsible>
@@ -140,7 +140,9 @@ const Gloss = ({ title, glossData, audio }: Props) => {
140
140
  <div key={index}>
141
141
  {example.map((translation, innerIndex) => (
142
142
  <div key={`${index}_${innerIndex}`}>
143
- <TranslatedText data-first={innerIndex === 0}>{translation.example}</TranslatedText>
143
+ <TranslatedText data-first={innerIndex === 0} lang={translation.language}>
144
+ {translation.example}
145
+ </TranslatedText>
144
146
  {translation.transcriptions.pinyin && (
145
147
  <TranslatedText key={t('gloss.transcriptions.pinyin')} lang={glossData.originalLanguage}>
146
148
  {translation.transcriptions?.pinyin}
@@ -17,6 +17,7 @@ interface Props<T extends string> {
17
17
  locales: T[];
18
18
  onSelect: (locale: T) => void;
19
19
  inverted?: boolean;
20
+ triggerId?: string;
20
21
  }
21
22
 
22
23
  const StyledDropdownContent = styled(DropdownContent)`
@@ -60,12 +61,18 @@ const Text = styled.span`
60
61
  font-weight: ${fonts.weight.semibold};
61
62
  `;
62
63
 
63
- const LanguageSelector = <T extends string>({ locales, onSelect, inverted }: Props<T>) => {
64
+ const LanguageSelector = <T extends string>({ locales, onSelect, inverted, triggerId }: Props<T>) => {
64
65
  const { t, i18n } = useTranslation();
65
66
  return (
66
67
  <DropdownMenu>
67
68
  <DropdownTrigger>
68
- <ButtonV2 variant="outline" shape="pill" inverted={inverted} aria-label={t('footer.selectLanguage')}>
69
+ <ButtonV2
70
+ variant="outline"
71
+ shape="pill"
72
+ inverted={inverted}
73
+ aria-label={t('footer.selectLanguage')}
74
+ id={triggerId}
75
+ >
69
76
  {t(`languages.prefixChangeLanguage`)} <ChevronDown />
70
77
  </ButtonV2>
71
78
  </DropdownTrigger>
package/src/index.ts CHANGED
@@ -213,7 +213,7 @@ export { BlogPostV2 } from './BlogPost';
213
213
  export { ProgrammeCard } from './ProgrammeCard';
214
214
  export { KeyFigure } from './KeyFigure';
215
215
  export { default as ContactBlock } from './ContactBlock';
216
- export type { HeartButtonType } from './Embed';
216
+ export type { HeartButtonType, RenderContext } from './Embed';
217
217
  export { CampaignBlock } from './CampaignBlock';
218
218
  export { Grid, GridParallaxItem } from './Grid';
219
219
  export type { GridType } from './Grid';
@@ -537,6 +537,7 @@ const messages = {
537
537
  files: 'Files',
538
538
  embedlink: 'Embedded link',
539
539
  concept: 'Concepts',
540
+ gloss: 'Glosses',
540
541
  podcast: 'Podcast',
541
542
  other: 'Other content',
542
543
  },
@@ -611,6 +612,18 @@ const messages = {
611
612
  hasCopiedTitle: 'Embed link copied',
612
613
  },
613
614
  },
615
+ gloss: {
616
+ heading: 'How to reuse gloss content',
617
+ description: 'Remember that built-in content might have a different license than the gloss text',
618
+ rules: 'Rules for use of gloss:',
619
+ title: 'Title',
620
+ embedlink: {
621
+ heading: 'How to show the gloss in other content',
622
+ description: 'This url shows the gloss without menu and footer',
623
+ copyTitle: 'Copy embed link',
624
+ hasCopiedTitle: 'Embed link copied',
625
+ },
626
+ },
614
627
  files: {
615
628
  heading: 'How to reuse files',
616
629
  description: 'Remember to copy the text to be attached to the file where you use it.',
@@ -1023,8 +1036,8 @@ const messages = {
1023
1036
  heading: 'Text version',
1024
1037
  close: 'Close text version',
1025
1038
  },
1026
- readMoreDescriptionLabel: 'show more',
1027
- readLessDescriptionLabel: 'show less',
1039
+ readMoreDescriptionLabel: 'Show more',
1040
+ readLessDescriptionLabel: 'Show less',
1028
1041
  },
1029
1042
  h5p: {
1030
1043
  reuse: 'Use H5P',
@@ -551,6 +551,7 @@ const messages = {
551
551
  files: 'Filer',
552
552
  embedlink: 'Innbyggingslenke',
553
553
  concept: 'Forklaringer',
554
+ gloss: 'Gloser',
554
555
  podcast: 'Podkast',
555
556
  other: 'Annet innhold',
556
557
  },
@@ -625,6 +626,18 @@ const messages = {
625
626
  hasCopiedTitle: 'Innbyggingslenke kopiert',
626
627
  },
627
628
  },
629
+ gloss: {
630
+ heading: 'Slik gjenbruker du gloser',
631
+ description: 'Husk at innebygd innhold i en glose kan ha en annen lisens enn selve gloseteksten',
632
+ rules: 'Regler for bruk av glose:',
633
+ title: 'Tittel',
634
+ embedlink: {
635
+ heading: 'Slik viser du glosen i annet innhold',
636
+ description: 'Denne lenken viser glosen uten kontekst (meny og bunntekst)',
637
+ copyTitle: 'Kopier innbyggingslenke',
638
+ hasCopiedTitle: 'Innbyggingslenke kopiert',
639
+ },
640
+ },
628
641
  files: {
629
642
  heading: 'Slik gjenbruker du filer',
630
643
  description: 'Husk å kopier teksten som skal legges ved filen der du bruker den.',
@@ -1009,11 +1022,11 @@ const messages = {
1009
1022
  download: 'Last ned lydfil',
1010
1023
  reuse: 'Bruk lydfil',
1011
1024
  error: {
1012
- url: 'Feil ved lasting av lydfila.',
1025
+ url: 'Feil ved lasting av lydfil.',
1013
1026
  caption: 'Beklager, en feil oppstod ved lasting av lydfil.',
1014
1027
  },
1015
1028
  controls: {
1016
- forward15sec: 'Spol 15 sekunder frem',
1029
+ forward15sec: 'Spol 15 sekunder fram',
1017
1030
  rewind15sec: 'Spol 15 sekunder tilbake',
1018
1031
  selectSpeed: 'Velg avspillingshastighet',
1019
1032
  adjustVolume: 'Endre volum',
@@ -1022,8 +1035,8 @@ const messages = {
1022
1035
  heading: 'Tekstversjon',
1023
1036
  close: 'Lukk tekstversjon',
1024
1037
  },
1025
- readMoreDescriptionLabel: 'vis mer',
1026
- readLessDescriptionLabel: 'vis mindre',
1038
+ readMoreDescriptionLabel: 'Vis mer',
1039
+ readLessDescriptionLabel: 'Vis mindre',
1027
1040
  },
1028
1041
  h5p: {
1029
1042
  reuse: 'Bruk H5P',
@@ -551,6 +551,7 @@ const messages = {
551
551
  files: 'Filer',
552
552
  embedlink: 'Innbyggingslenke',
553
553
  concept: 'Forklaringar',
554
+ gloss: 'Glosar',
554
555
  podcast: 'Podkast',
555
556
  other: 'Anna innhald',
556
557
  },
@@ -625,6 +626,18 @@ const messages = {
625
626
  rules: 'Reglar for bruk av forklaring:',
626
627
  title: 'Tittel',
627
628
  },
629
+ gloss: {
630
+ embedlink: {
631
+ heading: 'Slik viser du glosen i anna innhald',
632
+ description: 'Denne lenka viser glosen utan kontekst (meny og botntekst)',
633
+ copyTitle: 'Kopier innbyggingslenke',
634
+ hasCopiedTitle: 'Innbyggingslenke kopiert',
635
+ },
636
+ heading: 'Slik gjenbruker du gloser',
637
+ description: 'Husk at innebygd innhald i ei glose kan ha ein anna lisens enn sjølve gloseteksten',
638
+ rules: 'Regler for bruk av glose:',
639
+ title: 'Tittel',
640
+ },
628
641
  files: {
629
642
  heading: 'Slik gjenbruker du filer',
630
643
  description: 'Hugs å kopiere teksten som skal leggjast ved fila der du bruker ho.',
@@ -1004,17 +1017,17 @@ const messages = {
1004
1017
  },
1005
1018
  },
1006
1019
  audio: {
1007
- play: 'Spill av',
1020
+ play: 'Spel av',
1008
1021
  pause: 'Pause',
1009
1022
  download: 'Last ned lydfil',
1010
1023
  reuse: 'Bruk lydfil',
1011
1024
  error: {
1012
- url: 'Feil ved lasting av lydfila.',
1025
+ url: 'Feil ved lasting av lydfil.',
1013
1026
  caption: 'Orsak, ein feil oppstod ved lasting av lydfil.',
1014
1027
  },
1015
1028
  controls: {
1016
- forward15sec: 'Spol 15 sekundar fram',
1017
- rewind15sec: 'Spol 15 sekundar tilbake',
1029
+ forward15sec: 'Spol 15 sekund fram',
1030
+ rewind15sec: 'Spol 15 sekund tilbake',
1018
1031
  selectSpeed: 'Velg avspelingshastigheit',
1019
1032
  adjustVolume: 'Endre volum',
1020
1033
  },
@@ -1022,8 +1035,8 @@ const messages = {
1022
1035
  heading: 'Tekstversjon',
1023
1036
  close: 'Lukk tekstversjon',
1024
1037
  },
1025
- readMoreDescriptionLabel: 'vis meir',
1026
- readLessDescriptionLabel: 'vis mindre',
1038
+ readMoreDescriptionLabel: 'Vis meir',
1039
+ readLessDescriptionLabel: 'Vis mindre',
1027
1040
  },
1028
1041
  h5p: {
1029
1042
  reuse: 'Bruk H5P',
@@ -552,6 +552,7 @@ const messages = {
552
552
  files: 'Fiillat',
553
553
  embedlink: 'Sisahuksenliŋka',
554
554
  concept: 'Čilgehusat',
555
+ gloss: 'Gloser',
555
556
  podcast: 'Podkásta',
556
557
  other: 'Eará sisdoallu',
557
558
  },
@@ -626,6 +627,19 @@ const messages = {
626
627
  hasCopiedTitle: 'Sisahuksenliŋka máŋgejuvvon',
627
628
  },
628
629
  },
630
+ gloss: {
631
+ heading: 'Movt geavahit ođđasit dajaldagaid',
632
+ description:
633
+ 'Muitte ahte sisdoalus mii lea vuojuhuvvon ovtta gihppagii sáhttá leat eará liseansa go dušše jietnadat.',
634
+ rules: 'Glossa geavaheami njuolggadusat:',
635
+ title: 'Namahus',
636
+ embedlink: {
637
+ heading: 'Čájet jietnadaga eará sisdoaluin',
638
+ description: 'Dát liŋka čájeha teavstta konteavstta haga (fállu ja juolgeteaksta)',
639
+ copyTitle: 'Máŋge sisačálihanliŋkka',
640
+ hasCopiedTitle: 'Sajáiduhttinliŋka mángejuvvon',
641
+ },
642
+ },
629
643
  files: {
630
644
  heading: 'Ná geavahat fiillaid ođđasit',
631
645
  description: 'Muitte máŋget teavsttaid mat galget čuovvut fiillaid doppe gos dat geavahuvvet.',
@@ -552,6 +552,7 @@ const messages = {
552
552
  files: 'Fijlh',
553
553
  embedlink: 'Sïjsebïejemesvaalhtese',
554
554
  concept: 'Buerkiestimmieh',
555
+ gloss: 'Glosa',
555
556
  podcast: 'Podkast',
556
557
  other: 'Jeatjah sisvege',
557
558
  },
@@ -628,6 +629,18 @@ const messages = {
628
629
  hasCopiedTitle: 'Innbyggingslenke kopiert',
629
630
  },
630
631
  },
632
+ gloss: {
633
+ heading: 'Naemhtie gïelem ikth vielie nåhtadidh',
634
+ description: 'Mujhtieh sisvege aktene raajesisnie maahta jeatjah lisensem utnedh enn jïjtjehke raajesisnie',
635
+ rules: 'Njoelkedassh guktie diejvesem nåhtadidh:',
636
+ title: 'Tihtele',
637
+ embedlink: {
638
+ heading: 'Naemhtie gïelem jeatjah sisvegisnie vuesehte',
639
+ description: 'Daate lïenghke vuesehte tjoejh konteksten namhtah (meny jïh nueliekapihtele)',
640
+ copyTitle: 'Kopijerh svaalhtesem sïjse loggedh',
641
+ hasCopiedTitle: 'Bigkeme svaalhtese kopijeradamme',
642
+ },
643
+ },
631
644
  files: {
632
645
  heading: 'Slik gjenbruker du filer',
633
646
  description:
@@ -1026,8 +1039,8 @@ const messages = {
1026
1039
  heading: 'Teeksteversjovne',
1027
1040
  close: 'Dahph teeksteversjovnem',
1028
1041
  },
1029
- readMoreDescriptionLabel: 'vis mer',
1030
- readLessDescriptionLabel: 'vis mindre',
1042
+ readMoreDescriptionLabel: 'Vis mer',
1043
+ readLessDescriptionLabel: 'Vis mindre',
1031
1044
  },
1032
1045
  h5p: {
1033
1046
  reuse: 'Bruk H5P',
@@ -1370,7 +1383,7 @@ const messages = {
1370
1383
  concept: 'Forklaring',
1371
1384
  h5p: 'H5P',
1372
1385
  external: 'Ekstern ressurs',
1373
- gloss: 'Glose',
1386
+ gloss: 'Glosa',
1374
1387
  },
1375
1388
  },
1376
1389
  gloss: {