@ndla/ui 56.0.185-alpha.0 → 56.0.187-alpha.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 (113) hide show
  1. package/dist/panda.buildinfo.json +20 -27
  2. package/dist/styles.css +61 -140
  3. package/es/Article/ArticleByline.mjs +2 -1
  4. package/es/Article/ArticleByline.mjs.map +1 -1
  5. package/es/AudioPlayer/AudioElement.mjs +12 -0
  6. package/es/AudioPlayer/AudioElement.mjs.map +1 -0
  7. package/es/AudioPlayer/AudioPlayer.mjs +7 -2
  8. package/es/AudioPlayer/AudioPlayer.mjs.map +1 -1
  9. package/es/AudioPlayer/AudioProgress.mjs +54 -0
  10. package/es/AudioPlayer/AudioProgress.mjs.map +1 -0
  11. package/es/AudioPlayer/CompactAudioPlayer.mjs +111 -0
  12. package/es/AudioPlayer/CompactAudioPlayer.mjs.map +1 -0
  13. package/es/AudioPlayer/Controls.mjs +25 -110
  14. package/es/AudioPlayer/Controls.mjs.map +1 -1
  15. package/es/AudioPlayer/PlayButton.mjs +24 -0
  16. package/es/AudioPlayer/PlayButton.mjs.map +1 -0
  17. package/es/AudioPlayer/SpeechControl.mjs +5 -16
  18. package/es/AudioPlayer/SpeechControl.mjs.map +1 -1
  19. package/es/AudioPlayer/VolumeSlider.mjs +31 -0
  20. package/es/AudioPlayer/VolumeSlider.mjs.map +1 -0
  21. package/es/AudioPlayer/audioUtils.mjs +17 -0
  22. package/es/AudioPlayer/audioUtils.mjs.map +1 -0
  23. package/es/AudioPlayer/useAudioControls.mjs +55 -0
  24. package/es/AudioPlayer/useAudioControls.mjs.map +1 -0
  25. package/es/Breadcrumb/BreadcrumbItem.mjs +1 -2
  26. package/es/Breadcrumb/BreadcrumbItem.mjs.map +1 -1
  27. package/es/Embed/AudioEmbed.mjs +3 -7
  28. package/es/Embed/AudioEmbed.mjs.map +1 -1
  29. package/es/Embed/ExternalEmbed.mjs +13 -16
  30. package/es/Embed/ExternalEmbed.mjs.map +1 -1
  31. package/es/Embed/IframeEmbed.mjs +4 -5
  32. package/es/Embed/IframeEmbed.mjs.map +1 -1
  33. package/es/FactBox/FactBox.mjs +14 -38
  34. package/es/FactBox/FactBox.mjs.map +1 -1
  35. package/es/Gloss/Gloss.mjs +1 -2
  36. package/es/Gloss/Gloss.mjs.map +1 -1
  37. package/es/Grid/Grid.mjs +1 -2
  38. package/es/Grid/Grid.mjs.map +1 -1
  39. package/es/LinkBlock/LinkBlock.mjs +9 -2
  40. package/es/LinkBlock/LinkBlock.mjs.map +1 -1
  41. package/es/Pitch/Pitch.mjs +1 -2
  42. package/es/Pitch/Pitch.mjs.map +1 -1
  43. package/es/index.mjs +2 -1
  44. package/lib/Article/ArticleByline.js +2 -1
  45. package/lib/Article/ArticleByline.js.map +1 -1
  46. package/lib/AudioPlayer/AudioElement.d.ts +14 -0
  47. package/lib/AudioPlayer/AudioElement.js +13 -0
  48. package/lib/AudioPlayer/AudioElement.js.map +1 -0
  49. package/lib/AudioPlayer/AudioPlayer.d.ts +5 -4
  50. package/lib/AudioPlayer/AudioPlayer.js +7 -2
  51. package/lib/AudioPlayer/AudioPlayer.js.map +1 -1
  52. package/lib/AudioPlayer/AudioProgress.d.ts +16 -0
  53. package/lib/AudioPlayer/AudioProgress.js +55 -0
  54. package/lib/AudioPlayer/AudioProgress.js.map +1 -0
  55. package/lib/AudioPlayer/CompactAudioPlayer.d.ts +13 -0
  56. package/lib/AudioPlayer/CompactAudioPlayer.js +112 -0
  57. package/lib/AudioPlayer/CompactAudioPlayer.js.map +1 -0
  58. package/lib/AudioPlayer/Controls.d.ts +1 -0
  59. package/lib/AudioPlayer/Controls.js +25 -110
  60. package/lib/AudioPlayer/Controls.js.map +1 -1
  61. package/lib/AudioPlayer/PlayButton.d.ts +13 -0
  62. package/lib/AudioPlayer/PlayButton.js +25 -0
  63. package/lib/AudioPlayer/PlayButton.js.map +1 -0
  64. package/lib/AudioPlayer/SpeechControl.d.ts +1 -2
  65. package/lib/AudioPlayer/SpeechControl.js +5 -16
  66. package/lib/AudioPlayer/SpeechControl.js.map +1 -1
  67. package/lib/AudioPlayer/VolumeSlider.d.ts +14 -0
  68. package/lib/AudioPlayer/VolumeSlider.js +32 -0
  69. package/lib/AudioPlayer/VolumeSlider.js.map +1 -0
  70. package/lib/AudioPlayer/audioUtils.d.ts +8 -0
  71. package/lib/AudioPlayer/audioUtils.js +17 -0
  72. package/lib/AudioPlayer/audioUtils.js.map +1 -0
  73. package/lib/AudioPlayer/useAudioControls.d.ts +24 -0
  74. package/lib/AudioPlayer/useAudioControls.js +56 -0
  75. package/lib/AudioPlayer/useAudioControls.js.map +1 -0
  76. package/lib/Breadcrumb/BreadcrumbItem.js +1 -2
  77. package/lib/Breadcrumb/BreadcrumbItem.js.map +1 -1
  78. package/lib/Embed/AudioEmbed.js +3 -7
  79. package/lib/Embed/AudioEmbed.js.map +1 -1
  80. package/lib/Embed/ExternalEmbed.js +13 -16
  81. package/lib/Embed/ExternalEmbed.js.map +1 -1
  82. package/lib/Embed/IframeEmbed.js +4 -5
  83. package/lib/Embed/IframeEmbed.js.map +1 -1
  84. package/lib/FactBox/FactBox.js +13 -37
  85. package/lib/FactBox/FactBox.js.map +1 -1
  86. package/lib/Gloss/Gloss.js +1 -2
  87. package/lib/Gloss/Gloss.js.map +1 -1
  88. package/lib/Grid/Grid.js +1 -2
  89. package/lib/Grid/Grid.js.map +1 -1
  90. package/lib/LinkBlock/LinkBlock.js +9 -2
  91. package/lib/LinkBlock/LinkBlock.js.map +1 -1
  92. package/lib/Pitch/Pitch.js +1 -2
  93. package/lib/Pitch/Pitch.js.map +1 -1
  94. package/lib/index.d.ts +2 -0
  95. package/lib/index.js +2 -0
  96. package/package.json +10 -10
  97. package/src/Article/ArticleByline.tsx +5 -1
  98. package/src/AudioPlayer/AudioElement.tsx +20 -0
  99. package/src/AudioPlayer/{AudiPlayer.stories.tsx → AudioPlayer.stories.tsx} +10 -1
  100. package/src/AudioPlayer/AudioPlayer.tsx +12 -5
  101. package/src/AudioPlayer/AudioProgress.tsx +92 -0
  102. package/src/AudioPlayer/CompactAudioPlayer.tsx +124 -0
  103. package/src/AudioPlayer/Controls.tsx +36 -149
  104. package/src/AudioPlayer/PlayButton.tsx +24 -0
  105. package/src/AudioPlayer/SpeechControl.tsx +6 -19
  106. package/src/AudioPlayer/VolumeSlider.tsx +56 -0
  107. package/src/AudioPlayer/audioUtils.ts +15 -0
  108. package/src/AudioPlayer/useAudioControls.ts +80 -0
  109. package/src/Embed/AudioEmbed.tsx +3 -4
  110. package/src/FactBox/FactBox.tsx +13 -43
  111. package/src/Gloss/Gloss.tsx +1 -1
  112. package/src/LinkBlock/LinkBlock.tsx +5 -2
  113. package/src/index.ts +2 -0
@@ -1 +1 @@
1
- {"version":3,"file":"Gloss.js","names":["AccordionItemContent","AccordionItem","AccordionRoot","Text","SpeechControl","AccordionItemTrigger","IconButton","AccordionItemIndicator","ArrowDownShortLine","GlossExample"],"sources":["../../src/Gloss/Gloss.tsx"],"sourcesContent":["/**\n * Copyright (c) 2023-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { AccordionItemTrigger } from \"@ark-ui/react\";\nimport { ArrowDownShortLine } from \"@ndla/icons\";\nimport {\n AccordionItem,\n AccordionItemContent,\n AccordionItemIndicator,\n AccordionRoot,\n IconButton,\n Text,\n} from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { StyledVariantProps } from \"@ndla/styled-system/types\";\nimport type { ConceptTitleDTO, GlossDataDTO, GlossExampleDTO } from \"@ndla/types-backend/concept-api\";\nimport parse from \"html-react-parser\";\nimport { useMemo } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { SpeechControl } from \"../AudioPlayer/SpeechControl\";\nimport { GlossExample } from \"./GlossExample\";\n\n// TODO: Figure out padding between bordered and simple variant.\n// The design says that the content above the accordion content should have enough padding to align with the accordion content.\n// When a gloss is bordered there's way too much padding.\n\nconst getFilteredExamples = (\n glossData: GlossDataDTO | undefined,\n exampleIds: string | undefined,\n exampleLangs: string | undefined,\n): GlossExampleDTO[][] => {\n if (exampleIds !== undefined || exampleLangs !== undefined) {\n const exampleIdsList = exampleIds?.toString()?.split(\",\") ?? [];\n const exampleLangsList = exampleLangs?.split(\",\") ?? [];\n\n const filteredExamples =\n glossData?.examples?.map((examples, i) => {\n if (exampleIdsList.includes(i.toString())) {\n return examples.filter((e) => exampleLangsList.includes(e.language));\n }\n return [];\n }) ?? [];\n const examplesWithoutEmpty = filteredExamples.filter((el) => !!el.length);\n return examplesWithoutEmpty;\n }\n return glossData?.examples ?? [];\n};\n\nconst Container = styled(\"div\", {\n base: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n },\n});\n\nconst TextWrapper = styled(\"div\", {\n base: {\n display: \"flex\",\n gap: \"small\",\n },\n});\n\nconst StyledAccordionItemContent = styled(AccordionItemContent, {\n base: {\n paddingInline: \"0\",\n },\n});\n\nconst StyledContainer = styled(Container, {\n base: {\n marginBlockStart: \"3xsmall\",\n },\n});\n\nconst StyledAccordionItem = styled(AccordionItem, {\n base: {\n paddingBlock: \"small\",\n paddingInline: \"medium\",\n },\n defaultVariants: {\n variant: \"simple\",\n },\n variants: {\n variant: {\n simple: {},\n bordered: {\n border: \"1px solid\",\n borderColor: \"stroke.subtle\",\n borderRadius: \"xsmall\",\n },\n },\n },\n});\n\ntype GlossVariantProps = StyledVariantProps<typeof StyledAccordionItem>;\n\nexport interface Props {\n title: ConceptTitleDTO;\n glossData?: GlossDataDTO;\n audio?: {\n title: string;\n src?: string;\n };\n exampleIds?: string;\n exampleLangs?: string;\n}\n\nexport const Gloss = ({ title, glossData, audio, exampleIds, exampleLangs, variant }: Props & GlossVariantProps) => {\n const { t } = useTranslation();\n\n const parsedTitle = useMemo(() => parse(title.htmlTitle), [title.htmlTitle]);\n\n const filteredExamples = useMemo(\n () => getFilteredExamples(glossData, exampleIds, exampleLangs),\n [exampleIds, exampleLangs, glossData],\n );\n\n if (!glossData) return null;\n\n return (\n <AccordionRoot multiple variant=\"clean\">\n <StyledAccordionItem value=\"gloss\" variant={variant}>\n <Container>\n <TextWrapper>\n <Text textStyle=\"label.medium\" fontWeight=\"bold\" asChild consumeCss lang={glossData.originalLanguage}>\n <span>{glossData.gloss}</span>\n </Text>\n {!!glossData.transcriptions.traditional && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span\n key={t(\"gloss.transcriptions.traditional\")}\n aria-label={t(\"gloss.transcriptions.traditional\")}\n lang={glossData.originalLanguage}\n >\n {glossData.transcriptions.traditional}\n </span>\n </Text>\n )}\n {!!glossData.transcriptions.pinyin && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span\n data-pinyin=\"\"\n key={t(\"gloss.transcriptions.pinyin\")}\n aria-label={t(\"gloss.transcriptions.pinyin\")}\n lang={glossData.originalLanguage}\n >\n {glossData.transcriptions.pinyin}\n </span>\n </Text>\n )}\n {!!glossData.wordClass && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span aria-label={t(\"gloss.wordClass\")}>\n {glossData.wordClass.map((wc) => t(`wordClass.${wc}`).toLowerCase()).join(\" / \")}\n </span>\n </Text>\n )}\n </TextWrapper>\n {!!audio?.src && <SpeechControl src={audio.src} title={audio.title} type=\"gloss\" />}\n </Container>\n <StyledContainer>\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span lang={title.language}>{parsedTitle}</span>\n </Text>\n {!!filteredExamples.length && (\n <AccordionItemTrigger asChild>\n <IconButton variant=\"tertiary\" aria-label={t(\"gloss.showExamples\")} title={t(\"gloss.showExamples\")}>\n <AccordionItemIndicator asChild>\n <ArrowDownShortLine size=\"medium\" />\n </AccordionItemIndicator>\n </IconButton>\n </AccordionItemTrigger>\n )}\n </StyledContainer>\n <StyledAccordionItemContent>\n {filteredExamples.map((examples, index) => (\n <GlossExample\n key={`gloss-example-${index}`}\n examples={examples}\n originalLanguage={glossData.originalLanguage}\n />\n ))}\n </StyledAccordionItemContent>\n </StyledAccordionItem>\n </AccordionRoot>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"Gloss.js","names":["AccordionItemContent","AccordionItem","AccordionRoot","Text","SpeechControl","AccordionItemTrigger","IconButton","AccordionItemIndicator","ArrowDownShortLine","GlossExample"],"sources":["../../src/Gloss/Gloss.tsx"],"sourcesContent":["/**\n * Copyright (c) 2023-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { AccordionItemTrigger } from \"@ark-ui/react\";\nimport { ArrowDownShortLine } from \"@ndla/icons\";\nimport {\n AccordionItem,\n AccordionItemContent,\n AccordionItemIndicator,\n AccordionRoot,\n IconButton,\n Text,\n} from \"@ndla/primitives\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { StyledVariantProps } from \"@ndla/styled-system/types\";\nimport type { ConceptTitleDTO, GlossDataDTO, GlossExampleDTO } from \"@ndla/types-backend/concept-api\";\nimport parse from \"html-react-parser\";\nimport { useMemo } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { SpeechControl } from \"../AudioPlayer/SpeechControl\";\nimport { GlossExample } from \"./GlossExample\";\n\n// TODO: Figure out padding between bordered and simple variant.\n// The design says that the content above the accordion content should have enough padding to align with the accordion content.\n// When a gloss is bordered there's way too much padding.\n\nconst getFilteredExamples = (\n glossData: GlossDataDTO | undefined,\n exampleIds: string | undefined,\n exampleLangs: string | undefined,\n): GlossExampleDTO[][] => {\n if (exampleIds !== undefined || exampleLangs !== undefined) {\n const exampleIdsList = exampleIds?.toString()?.split(\",\") ?? [];\n const exampleLangsList = exampleLangs?.split(\",\") ?? [];\n\n const filteredExamples =\n glossData?.examples?.map((examples, i) => {\n if (exampleIdsList.includes(i.toString())) {\n return examples.filter((e) => exampleLangsList.includes(e.language));\n }\n return [];\n }) ?? [];\n const examplesWithoutEmpty = filteredExamples.filter((el) => !!el.length);\n return examplesWithoutEmpty;\n }\n return glossData?.examples ?? [];\n};\n\nconst Container = styled(\"div\", {\n base: {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n },\n});\n\nconst TextWrapper = styled(\"div\", {\n base: {\n display: \"flex\",\n gap: \"small\",\n },\n});\n\nconst StyledAccordionItemContent = styled(AccordionItemContent, {\n base: {\n paddingInline: \"0\",\n },\n});\n\nconst StyledContainer = styled(Container, {\n base: {\n marginBlockStart: \"3xsmall\",\n },\n});\n\nconst StyledAccordionItem = styled(AccordionItem, {\n base: {\n paddingBlock: \"small\",\n paddingInline: \"medium\",\n },\n defaultVariants: {\n variant: \"simple\",\n },\n variants: {\n variant: {\n simple: {},\n bordered: {\n border: \"1px solid\",\n borderColor: \"stroke.subtle\",\n borderRadius: \"xsmall\",\n },\n },\n },\n});\n\ntype GlossVariantProps = StyledVariantProps<typeof StyledAccordionItem>;\n\nexport interface Props {\n title: ConceptTitleDTO;\n glossData?: GlossDataDTO;\n audio?: {\n title: string;\n src?: string;\n };\n exampleIds?: string;\n exampleLangs?: string;\n}\n\nexport const Gloss = ({ title, glossData, audio, exampleIds, exampleLangs, variant }: Props & GlossVariantProps) => {\n const { t } = useTranslation();\n\n const parsedTitle = useMemo(() => parse(title.htmlTitle), [title.htmlTitle]);\n\n const filteredExamples = useMemo(\n () => getFilteredExamples(glossData, exampleIds, exampleLangs),\n [exampleIds, exampleLangs, glossData],\n );\n\n if (!glossData) return null;\n\n return (\n <AccordionRoot multiple variant=\"clean\">\n <StyledAccordionItem value=\"gloss\" variant={variant}>\n <Container>\n <TextWrapper>\n <Text textStyle=\"label.medium\" fontWeight=\"bold\" asChild consumeCss lang={glossData.originalLanguage}>\n <span>{glossData.gloss}</span>\n </Text>\n {!!glossData.transcriptions.traditional && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span\n key={t(\"gloss.transcriptions.traditional\")}\n aria-label={t(\"gloss.transcriptions.traditional\")}\n lang={glossData.originalLanguage}\n >\n {glossData.transcriptions.traditional}\n </span>\n </Text>\n )}\n {!!glossData.transcriptions.pinyin && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span\n data-pinyin=\"\"\n key={t(\"gloss.transcriptions.pinyin\")}\n aria-label={t(\"gloss.transcriptions.pinyin\")}\n lang={glossData.originalLanguage}\n >\n {glossData.transcriptions.pinyin}\n </span>\n </Text>\n )}\n {!!glossData.wordClass && (\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span aria-label={t(\"gloss.wordClass\")}>\n {glossData.wordClass.map((wc) => t(`wordClass.${wc}`).toLowerCase()).join(\" / \")}\n </span>\n </Text>\n )}\n </TextWrapper>\n {!!audio?.src && <SpeechControl src={audio.src} title={audio.title} />}\n </Container>\n <StyledContainer>\n <Text textStyle=\"label.medium\" asChild consumeCss>\n <span lang={title.language}>{parsedTitle}</span>\n </Text>\n {!!filteredExamples.length && (\n <AccordionItemTrigger asChild>\n <IconButton variant=\"tertiary\" aria-label={t(\"gloss.showExamples\")} title={t(\"gloss.showExamples\")}>\n <AccordionItemIndicator asChild>\n <ArrowDownShortLine size=\"medium\" />\n </AccordionItemIndicator>\n </IconButton>\n </AccordionItemTrigger>\n )}\n </StyledContainer>\n <StyledAccordionItemContent>\n {filteredExamples.map((examples, index) => (\n <GlossExample\n key={`gloss-example-${index}`}\n examples={examples}\n originalLanguage={glossData.originalLanguage}\n />\n ))}\n </StyledAccordionItemContent>\n </StyledAccordionItem>\n </AccordionRoot>\n );\n};\n"],"mappings":"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"}
package/lib/Grid/Grid.js CHANGED
@@ -58,11 +58,10 @@ const StyledGridItem = (0, _ndla_styled_system_jsx.styled)("div", {
58
58
  } } }
59
59
  });
60
60
  const Grid = ({ columns, border, children, ...rest }) => {
61
- const amountOfColumns = children?.length === 3 ? "3" : columns;
62
61
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GridContainer, {
63
62
  "data-embed-type": "grid",
64
63
  border,
65
- columns: amountOfColumns,
64
+ columns: children?.length === 3 ? "3" : columns,
66
65
  ...rest,
67
66
  children
68
67
  });
@@ -1 +1 @@
1
- {"version":3,"file":"Grid.js","names":[],"sources":["../../src/Grid/Grid.tsx"],"sourcesContent":["/**\n * Copyright (c) 2023-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { StyledVariantProps } from \"@ndla/styled-system/types\";\nimport { type ComponentProps, type ReactNode } from \"react\";\n\nconst GridContainer = styled(\"div\", {\n base: {\n display: \"grid\",\n justifyContent: \"center\",\n borderRadius: \"xsmall\",\n gridRowGap: \"large\",\n gridColumnGap: \"medium\",\n width: \"100%\",\n minWidth: \"surface.xxsmall\",\n gridTemplateColumns: \"repeat(2, minmax(0, 1fr))\",\n\n \"& div[data-embed-type='pitch']\": {\n height: \"100%\",\n \"& > :last-child\": {\n marginTop: \"auto\",\n },\n },\n tabletDown: {\n gridTemplateColumns: \"repeat(1, minmax(0, 1fr))\",\n },\n tabletToDesktop: {\n gridTemplateColumns: \"repeat(2, minmax(0, 1fr))\",\n \"& > div:nth-child(3):last-child\": {\n display: \"flex\",\n flexFlow: \"column\",\n justifyContent: \"center\",\n alignItems: \"center\",\n gridColumn: \"span 2\",\n },\n },\n },\n variants: {\n columns: {\n \"2\": {},\n \"2x2\": {},\n \"3\": { desktop: { gridTemplateColumns: \"repeat(3, minmax(0, 1fr))\" } },\n \"4\": { desktop: { gridTemplateColumns: \"repeat(4, minmax(0, 1fr))\" } },\n },\n border: {\n lightBlue: {\n padding: \"xsmall\",\n border: \"1px solid\",\n borderColor: \"stroke.subtle\",\n },\n },\n },\n});\n\nconst StyledGridItem = styled(\"div\", {\n base: {\n padding: \"medium\",\n },\n variants: {\n border: {\n true: {\n outline: \"1px solid\",\n outlineColor: \"stroke.subtle\",\n },\n },\n },\n});\n\ntype GridVariantProps = NonNullable<StyledVariantProps<typeof GridContainer>>;\n\nexport interface GridProps extends ComponentProps<\"div\">, GridVariantProps {\n children?: ReactNode[];\n columns: NonNullable<GridVariantProps[\"columns\"]>;\n}\n\ntype GridItemVariantProps = NonNullable<StyledVariantProps<typeof StyledGridItem>>;\n\nexport interface GridItemProps extends ComponentProps<\"div\">, GridItemVariantProps {}\n\nexport const Grid = ({ columns, border, children, ...rest }: GridProps) => {\n const amountOfColumns = children?.length === 3 ? \"3\" : columns;\n\n return (\n <GridContainer data-embed-type=\"grid\" border={border} columns={amountOfColumns} {...rest}>\n {children}\n </GridContainer>\n );\n};\n\nexport const GridItem = ({ border, children, ...rest }: GridItemProps) => {\n return (\n <StyledGridItem data-embed-type=\"grid-cell\" border={border} {...rest}>\n {children}\n </StyledGridItem>\n );\n};\n"],"mappings":";;;;;;;;;;;;AAYA,MAAM,iBAAA,GAAA,wBAAA,QAAuB,OAAO;CAClC,MAAM;EACJ,SAAS;EACT,gBAAgB;EAChB,cAAc;EACd,YAAY;EACZ,eAAe;EACf,OAAO;EACP,UAAU;EACV,qBAAqB;EAErB,kCAAkC;GAChC,QAAQ;GACR,mBAAmB,EACjB,WAAW,QACZ;GACF;EACD,YAAY,EACV,qBAAqB,6BACtB;EACD,iBAAiB;GACf,qBAAqB;GACrB,mCAAmC;IACjC,SAAS;IACT,UAAU;IACV,gBAAgB;IAChB,YAAY;IACZ,YAAY;IACb;GACF;EACF;CACD,UAAU;EACR,SAAS;GACP,KAAK,EAAE;GACP,OAAO,EAAE;GACT,KAAK,EAAE,SAAS,EAAE,qBAAqB,6BAA6B,EAAE;GACtE,KAAK,EAAE,SAAS,EAAE,qBAAqB,6BAA6B,EAAE;GACvE;EACD,QAAQ,EACN,WAAW;GACT,SAAS;GACT,QAAQ;GACR,aAAa;GACd,EACF;EACF;CACF,CAAC;AAEF,MAAM,kBAAA,GAAA,wBAAA,QAAwB,OAAO;CACnC,MAAM,EACJ,SAAS,UACV;CACD,UAAU,EACR,QAAQ,EACN,MAAM;EACJ,SAAS;EACT,cAAc;EACf,EACF,EACF;CACF,CAAC;AAaF,MAAa,QAAQ,EAAE,SAAS,QAAQ,UAAU,GAAG,WAAsB;CACzE,MAAM,kBAAkB,UAAU,WAAW,IAAI,MAAM;AAEvD,QACE,iBAAA,GAAA,kBAAA,KAAC,eAAD;EAAe,mBAAgB;EAAe;EAAQ,SAAS;EAAiB,GAAI;EACjF;EACa,CAAA;;AAIpB,MAAa,YAAY,EAAE,QAAQ,UAAU,GAAG,WAA0B;AACxE,QACE,iBAAA,GAAA,kBAAA,KAAC,gBAAD;EAAgB,mBAAgB;EAAoB;EAAQ,GAAI;EAC7D;EACc,CAAA"}
1
+ {"version":3,"file":"Grid.js","names":[],"sources":["../../src/Grid/Grid.tsx"],"sourcesContent":["/**\n * Copyright (c) 2023-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { StyledVariantProps } from \"@ndla/styled-system/types\";\nimport { type ComponentProps, type ReactNode } from \"react\";\n\nconst GridContainer = styled(\"div\", {\n base: {\n display: \"grid\",\n justifyContent: \"center\",\n borderRadius: \"xsmall\",\n gridRowGap: \"large\",\n gridColumnGap: \"medium\",\n width: \"100%\",\n minWidth: \"surface.xxsmall\",\n gridTemplateColumns: \"repeat(2, minmax(0, 1fr))\",\n\n \"& div[data-embed-type='pitch']\": {\n height: \"100%\",\n \"& > :last-child\": {\n marginTop: \"auto\",\n },\n },\n tabletDown: {\n gridTemplateColumns: \"repeat(1, minmax(0, 1fr))\",\n },\n tabletToDesktop: {\n gridTemplateColumns: \"repeat(2, minmax(0, 1fr))\",\n \"& > div:nth-child(3):last-child\": {\n display: \"flex\",\n flexFlow: \"column\",\n justifyContent: \"center\",\n alignItems: \"center\",\n gridColumn: \"span 2\",\n },\n },\n },\n variants: {\n columns: {\n \"2\": {},\n \"2x2\": {},\n \"3\": { desktop: { gridTemplateColumns: \"repeat(3, minmax(0, 1fr))\" } },\n \"4\": { desktop: { gridTemplateColumns: \"repeat(4, minmax(0, 1fr))\" } },\n },\n border: {\n lightBlue: {\n padding: \"xsmall\",\n border: \"1px solid\",\n borderColor: \"stroke.subtle\",\n },\n },\n },\n});\n\nconst StyledGridItem = styled(\"div\", {\n base: {\n padding: \"medium\",\n },\n variants: {\n border: {\n true: {\n outline: \"1px solid\",\n outlineColor: \"stroke.subtle\",\n },\n },\n },\n});\n\ntype GridVariantProps = NonNullable<StyledVariantProps<typeof GridContainer>>;\n\nexport interface GridProps extends ComponentProps<\"div\">, GridVariantProps {\n children?: ReactNode[];\n columns: NonNullable<GridVariantProps[\"columns\"]>;\n}\n\ntype GridItemVariantProps = NonNullable<StyledVariantProps<typeof StyledGridItem>>;\n\nexport interface GridItemProps extends ComponentProps<\"div\">, GridItemVariantProps {}\n\nexport const Grid = ({ columns, border, children, ...rest }: GridProps) => {\n const amountOfColumns = children?.length === 3 ? \"3\" : columns;\n\n return (\n <GridContainer data-embed-type=\"grid\" border={border} columns={amountOfColumns} {...rest}>\n {children}\n </GridContainer>\n );\n};\n\nexport const GridItem = ({ border, children, ...rest }: GridItemProps) => {\n return (\n <StyledGridItem data-embed-type=\"grid-cell\" border={border} {...rest}>\n {children}\n </StyledGridItem>\n );\n};\n"],"mappings":";;;;;;;;;;;;AAYA,MAAM,iBAAA,GAAA,wBAAA,QAAuB,OAAO;CAClC,MAAM;EACJ,SAAS;EACT,gBAAgB;EAChB,cAAc;EACd,YAAY;EACZ,eAAe;EACf,OAAO;EACP,UAAU;EACV,qBAAqB;EAErB,kCAAkC;GAChC,QAAQ;GACR,mBAAmB,EACjB,WAAW,QACZ;GACF;EACD,YAAY,EACV,qBAAqB,6BACtB;EACD,iBAAiB;GACf,qBAAqB;GACrB,mCAAmC;IACjC,SAAS;IACT,UAAU;IACV,gBAAgB;IAChB,YAAY;IACZ,YAAY;IACb;GACF;EACF;CACD,UAAU;EACR,SAAS;GACP,KAAK,EAAE;GACP,OAAO,EAAE;GACT,KAAK,EAAE,SAAS,EAAE,qBAAqB,6BAA6B,EAAE;GACtE,KAAK,EAAE,SAAS,EAAE,qBAAqB,6BAA6B,EAAE;GACvE;EACD,QAAQ,EACN,WAAW;GACT,SAAS;GACT,QAAQ;GACR,aAAa;GACd,EACF;EACF;CACF,CAAC;AAEF,MAAM,kBAAA,GAAA,wBAAA,QAAwB,OAAO;CACnC,MAAM,EACJ,SAAS,UACV;CACD,UAAU,EACR,QAAQ,EACN,MAAM;EACJ,SAAS;EACT,cAAc;EACf,EACF,EACF;CACF,CAAC;AAaF,MAAa,QAAQ,EAAE,SAAS,QAAQ,UAAU,GAAG,WAAsB;AAGzE,QACE,iBAAA,GAAA,kBAAA,KAAC,eAAD;EAAe,mBAAgB;EAAe;EAAQ,SAHhC,UAAU,WAAW,IAAI,MAAM;EAG2B,GAAI;EACjF;EACa,CAAA;;AAIpB,MAAa,YAAY,EAAE,QAAQ,UAAU,GAAG,WAA0B;AACxE,QACE,iBAAA,GAAA,kBAAA,KAAC,gBAAD;EAAgB,mBAAgB;EAAoB;EAAQ,GAAI;EAC7D;EACc,CAAA"}
@@ -5,9 +5,11 @@ let _ndla_styled_system_jsx = require("@ndla/styled-system/jsx");
5
5
  let react = require("react");
6
6
  let html_react_parser = require("html-react-parser");
7
7
  html_react_parser = require_runtime.__toESM(html_react_parser);
8
+ let react_i18next = require("react-i18next");
8
9
  let _ndla_icons = require("@ndla/icons");
9
10
  let _ndla_safelink = require("@ndla/safelink");
10
11
  let react_jsx_runtime = require("react/jsx-runtime");
12
+ let _ndla_util = require("@ndla/util");
11
13
  //#region src/LinkBlock/LinkBlock.tsx
12
14
  /**
13
15
  * Copyright (c) 2023-present, NDLA.
@@ -51,16 +53,21 @@ const StyledDateContainer = (0, _ndla_styled_system_jsx.styled)("div", { base: {
51
53
  } });
52
54
  const StyledCalendarEd = (0, _ndla_styled_system_jsx.styled)(_ndla_icons.CalendarLine, { base: { color: "icon.strong" } });
53
55
  const LinkBlock = ({ title, articleLanguage, date, url, path }) => {
56
+ const { i18n } = (0, react_i18next.useTranslation)();
54
57
  const href = require_relativeUrl.getPossiblyRelativeUrl(url, path);
55
58
  const formattedDate = (0, react.useMemo)(() => {
56
59
  if (!date) return null;
57
- return new Intl.DateTimeFormat(articleLanguage, {
60
+ return new Intl.DateTimeFormat((0, _ndla_util.toIntlLanguage)(articleLanguage ?? i18n.language), {
58
61
  timeZone: "CET",
59
62
  day: "2-digit",
60
63
  month: "long",
61
64
  year: "numeric"
62
65
  }).format(new Date(date));
63
- }, [date, articleLanguage]);
66
+ }, [
67
+ date,
68
+ articleLanguage,
69
+ i18n.language
70
+ ]);
64
71
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(StyledSafeLink, {
65
72
  to: href,
66
73
  "data-embed-type": "link-block",
@@ -1 +1 @@
1
- {"version":3,"file":"LinkBlock.js","names":["SafeLink","CalendarLine","getPossiblyRelativeUrl","Heading","ArrowRightLine"],"sources":["../../src/LinkBlock/LinkBlock.tsx"],"sourcesContent":["/**\n * Copyright (c) 2023-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { ArrowRightLine, CalendarLine } from \"@ndla/icons\";\nimport { Heading } from \"@ndla/primitives\";\nimport { SafeLink } from \"@ndla/safelink\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { LinkBlockEmbedData } from \"@ndla/types-embed\";\nimport parse from \"html-react-parser\";\nimport { useMemo } from \"react\";\nimport { getPossiblyRelativeUrl } from \"../utils/relativeUrl\";\n\nconst InfoWrapper = styled(\"div\", {\n base: {\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"xsmall\",\n },\n});\n\nconst StyledSafeLink = styled(SafeLink, {\n base: {\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n background: \"surface.default\",\n padding: \"medium\",\n border: \"1px solid\",\n borderColor: \"stroke.subtle\",\n borderRadius: \"xsmall\",\n \"& h3\": {\n textDecoration: \"underline\",\n },\n \"& [data-forward]\": {\n transitionProperty: \"width, height\",\n transitionTimingFunction: \"ease-in-out\",\n transitionDuration: \"fast\",\n },\n _hover: {\n \"& h3\": {\n textDecoration: \"none\",\n },\n \"& [data-forward]\": {\n width: \"large\",\n height: \"large\",\n },\n },\n },\n});\n\nconst StyledDateContainer = styled(\"div\", {\n base: {\n display: \"flex\",\n alignItems: \"center\",\n gap: \"xxsmall\",\n },\n});\n\nconst StyledCalendarEd = styled(CalendarLine, {\n base: {\n color: \"icon.strong\",\n },\n});\n\ninterface Props extends Omit<LinkBlockEmbedData, \"resource\"> {\n path?: string;\n articleLanguage?: string;\n}\n\nexport const LinkBlock = ({ title, articleLanguage, date, url, path }: Props) => {\n const href = getPossiblyRelativeUrl(url, path);\n const formattedDate = useMemo(() => {\n if (!date) return null;\n return new Intl.DateTimeFormat(articleLanguage, {\n timeZone: \"CET\",\n day: \"2-digit\",\n month: \"long\",\n year: \"numeric\",\n }).format(new Date(date));\n }, [date, articleLanguage]);\n return (\n <StyledSafeLink to={href} data-embed-type=\"link-block\">\n <InfoWrapper>\n <Heading asChild consumeCss textStyle=\"title.medium\">\n <h3 data-heading>{parse(title)}</h3>\n </Heading>\n {!!date && (\n <StyledDateContainer>\n <StyledCalendarEd />\n {formattedDate}\n </StyledDateContainer>\n )}\n </InfoWrapper>\n <ArrowRightLine data-forward />\n </StyledSafeLink>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiBA,MAAM,eAAA,GAAA,wBAAA,QAAqB,OAAO,EAChC,MAAM;CACJ,SAAS;CACT,eAAe;CACf,KAAK;CACN,EACF,CAAC;AAEF,MAAM,kBAAA,GAAA,wBAAA,QAAwBA,eAAAA,UAAU,EACtC,MAAM;CACJ,SAAS;CACT,gBAAgB;CAChB,YAAY;CACZ,YAAY;CACZ,SAAS;CACT,QAAQ;CACR,aAAa;CACb,cAAc;CACd,QAAQ,EACN,gBAAgB,aACjB;CACD,oBAAoB;EAClB,oBAAoB;EACpB,0BAA0B;EAC1B,oBAAoB;EACrB;CACD,QAAQ;EACN,QAAQ,EACN,gBAAgB,QACjB;EACD,oBAAoB;GAClB,OAAO;GACP,QAAQ;GACT;EACF;CACF,EACF,CAAC;AAEF,MAAM,uBAAA,GAAA,wBAAA,QAA6B,OAAO,EACxC,MAAM;CACJ,SAAS;CACT,YAAY;CACZ,KAAK;CACN,EACF,CAAC;AAEF,MAAM,oBAAA,GAAA,wBAAA,QAA0BC,YAAAA,cAAc,EAC5C,MAAM,EACJ,OAAO,eACR,EACF,CAAC;AAOF,MAAa,aAAa,EAAE,OAAO,iBAAiB,MAAM,KAAK,WAAkB;CAC/E,MAAM,OAAOC,oBAAAA,uBAAuB,KAAK,KAAK;CAC9C,MAAM,iBAAA,GAAA,MAAA,eAA8B;AAClC,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,IAAI,KAAK,eAAe,iBAAiB;GAC9C,UAAU;GACV,KAAK;GACL,OAAO;GACP,MAAM;GACP,CAAC,CAAC,OAAO,IAAI,KAAK,KAAK,CAAC;IACxB,CAAC,MAAM,gBAAgB,CAAC;AAC3B,QACE,iBAAA,GAAA,kBAAA,MAAC,gBAAD;EAAgB,IAAI;EAAM,mBAAgB;YAA1C,CACE,iBAAA,GAAA,kBAAA,MAAC,aAAD,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,KAACC,iBAAAA,SAAD;GAAS,SAAA;GAAQ,YAAA;GAAW,WAAU;aACpC,iBAAA,GAAA,kBAAA,KAAC,MAAD;IAAI,gBAAA;6CAAoB,MAAM;IAAM,CAAA;GAC5B,CAAA,EACT,CAAC,CAAC,QACD,iBAAA,GAAA,kBAAA,MAAC,qBAAD,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAC,kBAAD,EAAoB,CAAA,EACnB,cACmB,EAAA,CAAA,CAEZ,EAAA,CAAA,EACd,iBAAA,GAAA,kBAAA,KAACC,YAAAA,gBAAD,EAAgB,gBAAA,MAAe,CAAA,CAChB"}
1
+ {"version":3,"file":"LinkBlock.js","names":["SafeLink","CalendarLine","getPossiblyRelativeUrl","Heading","ArrowRightLine"],"sources":["../../src/LinkBlock/LinkBlock.tsx"],"sourcesContent":["/**\n * Copyright (c) 2023-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { ArrowRightLine, CalendarLine } from \"@ndla/icons\";\nimport { Heading } from \"@ndla/primitives\";\nimport { SafeLink } from \"@ndla/safelink\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport type { LinkBlockEmbedData } from \"@ndla/types-embed\";\nimport { toIntlLanguage } from \"@ndla/util\";\nimport parse from \"html-react-parser\";\nimport { useMemo } from \"react\";\nimport { useTranslation } from \"react-i18next\";\nimport { getPossiblyRelativeUrl } from \"../utils/relativeUrl\";\n\nconst InfoWrapper = styled(\"div\", {\n base: {\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"xsmall\",\n },\n});\n\nconst StyledSafeLink = styled(SafeLink, {\n base: {\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n background: \"surface.default\",\n padding: \"medium\",\n border: \"1px solid\",\n borderColor: \"stroke.subtle\",\n borderRadius: \"xsmall\",\n \"& h3\": {\n textDecoration: \"underline\",\n },\n \"& [data-forward]\": {\n transitionProperty: \"width, height\",\n transitionTimingFunction: \"ease-in-out\",\n transitionDuration: \"fast\",\n },\n _hover: {\n \"& h3\": {\n textDecoration: \"none\",\n },\n \"& [data-forward]\": {\n width: \"large\",\n height: \"large\",\n },\n },\n },\n});\n\nconst StyledDateContainer = styled(\"div\", {\n base: {\n display: \"flex\",\n alignItems: \"center\",\n gap: \"xxsmall\",\n },\n});\n\nconst StyledCalendarEd = styled(CalendarLine, {\n base: {\n color: \"icon.strong\",\n },\n});\n\ninterface Props extends Omit<LinkBlockEmbedData, \"resource\"> {\n path?: string;\n articleLanguage?: string;\n}\n\nexport const LinkBlock = ({ title, articleLanguage, date, url, path }: Props) => {\n const { i18n } = useTranslation();\n const href = getPossiblyRelativeUrl(url, path);\n const formattedDate = useMemo(() => {\n if (!date) return null;\n return new Intl.DateTimeFormat(toIntlLanguage(articleLanguage ?? i18n.language), {\n timeZone: \"CET\",\n day: \"2-digit\",\n month: \"long\",\n year: \"numeric\",\n }).format(new Date(date));\n }, [date, articleLanguage, i18n.language]);\n return (\n <StyledSafeLink to={href} data-embed-type=\"link-block\">\n <InfoWrapper>\n <Heading asChild consumeCss textStyle=\"title.medium\">\n <h3 data-heading>{parse(title)}</h3>\n </Heading>\n {!!date && (\n <StyledDateContainer>\n <StyledCalendarEd />\n {formattedDate}\n </StyledDateContainer>\n )}\n </InfoWrapper>\n <ArrowRightLine data-forward />\n </StyledSafeLink>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAmBA,MAAM,eAAA,GAAA,wBAAA,QAAqB,OAAO,EAChC,MAAM;CACJ,SAAS;CACT,eAAe;CACf,KAAK;CACN,EACF,CAAC;AAEF,MAAM,kBAAA,GAAA,wBAAA,QAAwBA,eAAAA,UAAU,EACtC,MAAM;CACJ,SAAS;CACT,gBAAgB;CAChB,YAAY;CACZ,YAAY;CACZ,SAAS;CACT,QAAQ;CACR,aAAa;CACb,cAAc;CACd,QAAQ,EACN,gBAAgB,aACjB;CACD,oBAAoB;EAClB,oBAAoB;EACpB,0BAA0B;EAC1B,oBAAoB;EACrB;CACD,QAAQ;EACN,QAAQ,EACN,gBAAgB,QACjB;EACD,oBAAoB;GAClB,OAAO;GACP,QAAQ;GACT;EACF;CACF,EACF,CAAC;AAEF,MAAM,uBAAA,GAAA,wBAAA,QAA6B,OAAO,EACxC,MAAM;CACJ,SAAS;CACT,YAAY;CACZ,KAAK;CACN,EACF,CAAC;AAEF,MAAM,oBAAA,GAAA,wBAAA,QAA0BC,YAAAA,cAAc,EAC5C,MAAM,EACJ,OAAO,eACR,EACF,CAAC;AAOF,MAAa,aAAa,EAAE,OAAO,iBAAiB,MAAM,KAAK,WAAkB;CAC/E,MAAM,EAAE,UAAA,GAAA,cAAA,iBAAyB;CACjC,MAAM,OAAOC,oBAAAA,uBAAuB,KAAK,KAAK;CAC9C,MAAM,iBAAA,GAAA,MAAA,eAA8B;AAClC,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,IAAI,KAAK,gBAAA,GAAA,WAAA,gBAA8B,mBAAmB,KAAK,SAAS,EAAE;GAC/E,UAAU;GACV,KAAK;GACL,OAAO;GACP,MAAM;GACP,CAAC,CAAC,OAAO,IAAI,KAAK,KAAK,CAAC;IACxB;EAAC;EAAM;EAAiB,KAAK;EAAS,CAAC;AAC1C,QACE,iBAAA,GAAA,kBAAA,MAAC,gBAAD;EAAgB,IAAI;EAAM,mBAAgB;YAA1C,CACE,iBAAA,GAAA,kBAAA,MAAC,aAAD,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,KAACC,iBAAAA,SAAD;GAAS,SAAA;GAAQ,YAAA;GAAW,WAAU;aACpC,iBAAA,GAAA,kBAAA,KAAC,MAAD;IAAI,gBAAA;6CAAoB,MAAM;IAAM,CAAA;GAC5B,CAAA,EACT,CAAC,CAAC,QACD,iBAAA,GAAA,kBAAA,MAAC,qBAAD,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAC,kBAAD,EAAoB,CAAA,EACnB,cACmB,EAAA,CAAA,CAEZ,EAAA,CAAA,EACd,iBAAA,GAAA,kBAAA,KAACC,YAAAA,gBAAD,EAAgB,gBAAA,MAAe,CAAA,CAChB"}
@@ -29,7 +29,6 @@ const StyledCardImage = (0, _ndla_styled_system_jsx.styled)(_ndla_primitives.Car
29
29
  height: "unset"
30
30
  } });
31
31
  const Pitch = ({ title, url, metaImage, path, description }) => {
32
- const href = require_relativeUrl.getPossiblyRelativeUrl(url, path);
33
32
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StyledCardRoot, {
34
33
  nonInteractive: true,
35
34
  "data-embed-type": "pitch",
@@ -41,7 +40,7 @@ const Pitch = ({ title, url, metaImage, path, description }) => {
41
40
  asChild: true,
42
41
  consumeCss: true,
43
42
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_ndla_safelink.SafeLink, {
44
- to: href,
43
+ to: require_relativeUrl.getPossiblyRelativeUrl(url, path),
45
44
  unstyled: true,
46
45
  css: _ndla_styled_system_patterns.linkOverlay.raw(),
47
46
  children: (0, html_react_parser.default)(title)
@@ -1 +1 @@
1
- {"version":3,"file":"Pitch.js","names":["CardHeading","Text","CardRoot","CardImage","getPossiblyRelativeUrl","SafeLink","linkOverlay"],"sources":["../../src/Pitch/Pitch.tsx"],"sourcesContent":["/**\n * Copyright (c) 2024-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { CardHeading, CardImage, CardRoot, Text } from \"@ndla/primitives\";\nimport { SafeLink } from \"@ndla/safelink\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport { linkOverlay } from \"@ndla/styled-system/patterns\";\nimport parse from \"html-react-parser\";\nimport { getPossiblyRelativeUrl } from \"../utils/relativeUrl\";\n\nexport interface Props {\n title: string;\n url: string;\n description?: string;\n metaImage: {\n url: string;\n alt: string;\n };\n path?: string;\n}\n\nconst StyledCardHeading = styled(CardHeading, {\n base: {\n paddingBlockStart: \"medium\",\n },\n});\n\nconst StyledText = styled(Text, {\n base: {\n paddingBlockEnd: \"medium\",\n },\n});\n\nconst StyledCardRoot = styled(CardRoot, {\n base: {\n outline: \"0px\",\n boxShadow: \"none\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"small\",\n },\n});\n\nconst StyledCardImage = styled(CardImage, {\n base: {\n aspectRatio: \"16/9\",\n height: \"unset\",\n },\n});\n\nexport const Pitch = ({ title, url, metaImage, path, description }: Props) => {\n const href = getPossiblyRelativeUrl(url, path);\n\n return (\n <StyledCardRoot nonInteractive data-embed-type=\"pitch\" asChild consumeCss>\n <div>\n <StyledCardHeading textStyle=\"heading.small\" asChild consumeCss>\n <SafeLink to={href} unstyled css={linkOverlay.raw()}>\n {parse(title)}\n </SafeLink>\n </StyledCardHeading>\n {!!description && (\n <StyledText textStyle=\"body.xlarge\" asChild consumeCss>\n <div>{parse(description)}</div>\n </StyledText>\n )}\n <StyledCardImage\n variant=\"rounded\"\n src={metaImage.url}\n alt={metaImage.alt}\n sizes=\"480px\"\n fallbackWidth={300}\n width={550}\n height={310}\n />\n </div>\n </StyledCardRoot>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AA0BA,MAAM,qBAAA,GAAA,wBAAA,QAA2BA,iBAAAA,aAAa,EAC5C,MAAM,EACJ,mBAAmB,UACpB,EACF,CAAC;AAEF,MAAM,cAAA,GAAA,wBAAA,QAAoBC,iBAAAA,MAAM,EAC9B,MAAM,EACJ,iBAAiB,UAClB,EACF,CAAC;AAEF,MAAM,kBAAA,GAAA,wBAAA,QAAwBC,iBAAAA,UAAU,EACtC,MAAM;CACJ,SAAS;CACT,WAAW;CACX,SAAS;CACT,eAAe;CACf,KAAK;CACN,EACF,CAAC;AAEF,MAAM,mBAAA,GAAA,wBAAA,QAAyBC,iBAAAA,WAAW,EACxC,MAAM;CACJ,aAAa;CACb,QAAQ;CACT,EACF,CAAC;AAEF,MAAa,SAAS,EAAE,OAAO,KAAK,WAAW,MAAM,kBAAyB;CAC5E,MAAM,OAAOC,oBAAAA,uBAAuB,KAAK,KAAK;AAE9C,QACE,iBAAA,GAAA,kBAAA,KAAC,gBAAD;EAAgB,gBAAA;EAAe,mBAAgB;EAAQ,SAAA;EAAQ,YAAA;YAC7D,iBAAA,GAAA,kBAAA,MAAC,OAAD,EAAA,UAAA;GACE,iBAAA,GAAA,kBAAA,KAAC,mBAAD;IAAmB,WAAU;IAAgB,SAAA;IAAQ,YAAA;cACnD,iBAAA,GAAA,kBAAA,KAACC,eAAAA,UAAD;KAAU,IAAI;KAAM,UAAA;KAAS,KAAKC,6BAAAA,YAAY,KAAK;8CAC1C,MAAM;KACJ,CAAA;IACO,CAAA;GACnB,CAAC,CAAC,eACD,iBAAA,GAAA,kBAAA,KAAC,YAAD;IAAY,WAAU;IAAc,SAAA;IAAQ,YAAA;cAC1C,iBAAA,GAAA,kBAAA,KAAC,OAAD,EAAA,WAAA,GAAA,kBAAA,SAAY,YAAY,EAAO,CAAA;IACpB,CAAA;GAEf,iBAAA,GAAA,kBAAA,KAAC,iBAAD;IACE,SAAQ;IACR,KAAK,UAAU;IACf,KAAK,UAAU;IACf,OAAM;IACN,eAAe;IACf,OAAO;IACP,QAAQ;IACR,CAAA;GACE,EAAA,CAAA;EACS,CAAA"}
1
+ {"version":3,"file":"Pitch.js","names":["CardHeading","Text","CardRoot","CardImage","SafeLink","getPossiblyRelativeUrl","linkOverlay"],"sources":["../../src/Pitch/Pitch.tsx"],"sourcesContent":["/**\n * Copyright (c) 2024-present, NDLA.\n *\n * This source code is licensed under the GPLv3 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n\nimport { CardHeading, CardImage, CardRoot, Text } from \"@ndla/primitives\";\nimport { SafeLink } from \"@ndla/safelink\";\nimport { styled } from \"@ndla/styled-system/jsx\";\nimport { linkOverlay } from \"@ndla/styled-system/patterns\";\nimport parse from \"html-react-parser\";\nimport { getPossiblyRelativeUrl } from \"../utils/relativeUrl\";\n\nexport interface Props {\n title: string;\n url: string;\n description?: string;\n metaImage: {\n url: string;\n alt: string;\n };\n path?: string;\n}\n\nconst StyledCardHeading = styled(CardHeading, {\n base: {\n paddingBlockStart: \"medium\",\n },\n});\n\nconst StyledText = styled(Text, {\n base: {\n paddingBlockEnd: \"medium\",\n },\n});\n\nconst StyledCardRoot = styled(CardRoot, {\n base: {\n outline: \"0px\",\n boxShadow: \"none\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"small\",\n },\n});\n\nconst StyledCardImage = styled(CardImage, {\n base: {\n aspectRatio: \"16/9\",\n height: \"unset\",\n },\n});\n\nexport const Pitch = ({ title, url, metaImage, path, description }: Props) => {\n const href = getPossiblyRelativeUrl(url, path);\n\n return (\n <StyledCardRoot nonInteractive data-embed-type=\"pitch\" asChild consumeCss>\n <div>\n <StyledCardHeading textStyle=\"heading.small\" asChild consumeCss>\n <SafeLink to={href} unstyled css={linkOverlay.raw()}>\n {parse(title)}\n </SafeLink>\n </StyledCardHeading>\n {!!description && (\n <StyledText textStyle=\"body.xlarge\" asChild consumeCss>\n <div>{parse(description)}</div>\n </StyledText>\n )}\n <StyledCardImage\n variant=\"rounded\"\n src={metaImage.url}\n alt={metaImage.alt}\n sizes=\"480px\"\n fallbackWidth={300}\n width={550}\n height={310}\n />\n </div>\n </StyledCardRoot>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AA0BA,MAAM,qBAAA,GAAA,wBAAA,QAA2BA,iBAAAA,aAAa,EAC5C,MAAM,EACJ,mBAAmB,UACpB,EACF,CAAC;AAEF,MAAM,cAAA,GAAA,wBAAA,QAAoBC,iBAAAA,MAAM,EAC9B,MAAM,EACJ,iBAAiB,UAClB,EACF,CAAC;AAEF,MAAM,kBAAA,GAAA,wBAAA,QAAwBC,iBAAAA,UAAU,EACtC,MAAM;CACJ,SAAS;CACT,WAAW;CACX,SAAS;CACT,eAAe;CACf,KAAK;CACN,EACF,CAAC;AAEF,MAAM,mBAAA,GAAA,wBAAA,QAAyBC,iBAAAA,WAAW,EACxC,MAAM;CACJ,aAAa;CACb,QAAQ;CACT,EACF,CAAC;AAEF,MAAa,SAAS,EAAE,OAAO,KAAK,WAAW,MAAM,kBAAyB;AAG5E,QACE,iBAAA,GAAA,kBAAA,KAAC,gBAAD;EAAgB,gBAAA;EAAe,mBAAgB;EAAQ,SAAA;EAAQ,YAAA;YAC7D,iBAAA,GAAA,kBAAA,MAAC,OAAD,EAAA,UAAA;GACE,iBAAA,GAAA,kBAAA,KAAC,mBAAD;IAAmB,WAAU;IAAgB,SAAA;IAAQ,YAAA;cACnD,iBAAA,GAAA,kBAAA,KAACC,eAAAA,UAAD;KAAU,IANLC,oBAAAA,uBAAuB,KAAK,KAAK;KAMlB,UAAA;KAAS,KAAKC,6BAAAA,YAAY,KAAK;8CAC1C,MAAM;KACJ,CAAA;IACO,CAAA;GACnB,CAAC,CAAC,eACD,iBAAA,GAAA,kBAAA,KAAC,YAAD;IAAY,WAAU;IAAc,SAAA;IAAQ,YAAA;cAC1C,iBAAA,GAAA,kBAAA,KAAC,OAAD,EAAA,WAAA,GAAA,kBAAA,SAAY,YAAY,EAAO,CAAA;IACpB,CAAA;GAEf,iBAAA,GAAA,kBAAA,KAAC,iBAAD;IACE,SAAQ;IACR,KAAK,UAAU;IACf,KAAK,UAAU;IACf,OAAM;IACN,eAAe;IACf,OAAO;IACP,QAAQ;IACR,CAAA;GACE,EAAA,CAAA;EACS,CAAA"}
package/lib/index.d.ts CHANGED
@@ -39,6 +39,8 @@ export { PdfFile } from "./FileList/PdfFile";
39
39
  export { FactBox } from "./FactBox/FactBox";
40
40
  export { ResourceBox } from "./ResourceBox/ResourceBox";
41
41
  export { AudioPlayer } from "./AudioPlayer/AudioPlayer";
42
+ export type { AudioPlayerVariant } from "./AudioPlayer/AudioPlayer";
43
+ export { CompactAudioPlayer } from "./AudioPlayer/CompactAudioPlayer";
42
44
  export { constants } from "./model";
43
45
  export { contentTypes, contentTypeMapping, resourceEmbedTypeMapping } from "./model/ContentType";
44
46
  export { subjectTypes } from "./model/SubjectTypes";
package/lib/index.js CHANGED
@@ -11,6 +11,7 @@ const require_IframeEmbed = require("./Embed/IframeEmbed.js");
11
11
  const require_ImageEmbed = require("./Embed/ImageEmbed.js");
12
12
  const require_Concept = require("./Concept/Concept.js");
13
13
  const require_InlineTriggerButton = require("./Embed/InlineTriggerButton.js");
14
+ const require_CompactAudioPlayer = require("./AudioPlayer/CompactAudioPlayer.js");
14
15
  const require_AudioPlayer = require("./AudioPlayer/AudioPlayer.js");
15
16
  const require_AudioEmbed = require("./Embed/AudioEmbed.js");
16
17
  const require_FootnoteEmbed = require("./Embed/FootnoteEmbed.js");
@@ -75,6 +76,7 @@ exports.BrightcoveEmbed = require_BrightcoveEmbed.BrightcoveEmbed;
75
76
  exports.CampaignBlock = require_CampaignBlock.CampaignBlock;
76
77
  exports.CodeBlock = require_CodeBlock.CodeBlock;
77
78
  exports.CodeEmbed = require_CodeEmbed.CodeEmbed;
79
+ exports.CompactAudioPlayer = require_CompactAudioPlayer.CompactAudioPlayer;
78
80
  exports.Concept = require_Concept.Concept;
79
81
  exports.ConceptEmbed = require_ConceptEmbed.ConceptEmbed;
80
82
  exports.ConceptInlineTriggerButton = require_ConceptInlineTriggerButton.ConceptInlineTriggerButton;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ndla/ui",
3
3
  "type": "module",
4
- "version": "56.0.185-alpha.0",
4
+ "version": "56.0.187-alpha.0",
5
5
  "description": "UI component library for NDLA",
6
6
  "license": "GPL-3.0",
7
7
  "exports": {
@@ -38,13 +38,13 @@
38
38
  "dependencies": {
39
39
  "@ark-ui/react": "^5.34.1",
40
40
  "@ndla/core": "^6.0.7-alpha.0",
41
- "@ndla/icons": "^8.0.88-alpha.0",
41
+ "@ndla/icons": "^8.0.89-alpha.0",
42
42
  "@ndla/licenses": "^10.0.11-alpha.0",
43
- "@ndla/locales": "^0.0.2",
44
- "@ndla/primitives": "^1.0.127-alpha.0",
45
- "@ndla/safelink": "^7.0.130-alpha.0",
46
- "@ndla/styled-system": "^0.0.48",
47
- "@ndla/util": "^5.0.20-alpha.0",
43
+ "@ndla/locales": "^0.0.3",
44
+ "@ndla/primitives": "^1.0.128-alpha.0",
45
+ "@ndla/safelink": "^7.0.131-alpha.0",
46
+ "@ndla/styled-system": "^0.0.49",
47
+ "@ndla/util": "^5.0.21-alpha.0",
48
48
  "html-react-parser": "^6.0.0"
49
49
  },
50
50
  "peerDependencies": {
@@ -55,13 +55,13 @@
55
55
  "react-router": ">= 7.0.0"
56
56
  },
57
57
  "devDependencies": {
58
- "@ndla/preset-panda": "^0.0.75",
58
+ "@ndla/preset-panda": "^0.0.76",
59
59
  "@ndla/types-backend": "^1.0.89",
60
60
  "@ndla/types-embed": "^5.0.21-alpha.0",
61
- "@pandacss/dev": "^1.7.0"
61
+ "@pandacss/dev": "^1.10.0"
62
62
  },
63
63
  "publishConfig": {
64
64
  "access": "public"
65
65
  },
66
- "gitHead": "61d37fa44c4b9bd0517468c99cb9ee16d8c045bf"
66
+ "gitHead": "6e0fe3687125dd1a02010543128cf67ad50dc986"
67
67
  }
@@ -19,6 +19,7 @@ import {
19
19
  } from "@ndla/primitives";
20
20
  import { SafeLink } from "@ndla/safelink";
21
21
  import { styled } from "@ndla/styled-system/jsx";
22
+ import { toIntlLanguage } from "@ndla/util";
22
23
  import { type ReactNode, forwardRef, useCallback, useEffect, useRef } from "react";
23
24
  import { useTranslation } from "react-i18next";
24
25
  import type { FootNote } from "../types";
@@ -112,7 +113,10 @@ export const ArticleByline = ({
112
113
  const { t, i18n } = useTranslation();
113
114
 
114
115
  const showPrimaryContributors = suppliers.length > 0 || authors.length > 0;
115
- const listFormatter = new Intl.ListFormat(lang ?? i18n.language, { style: "long", type: "conjunction" });
116
+ const listFormatter = new Intl.ListFormat(toIntlLanguage(lang ?? i18n.language), {
117
+ style: "long",
118
+ type: "conjunction",
119
+ });
116
120
 
117
121
  return (
118
122
  <Wrapper>
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Copyright (c) 2026-present, NDLA.
3
+ *
4
+ * This source code is licensed under the GPLv3 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ import type { ComponentProps } from "react";
10
+
11
+ interface Props extends ComponentProps<"audio"> {
12
+ src: string;
13
+ title: string;
14
+ }
15
+
16
+ export const AudioElement = (props: Props) => {
17
+ // TODO: We should tie this up to the textual description somehow
18
+ // oxlint-disable-next-line jsx-a11y/media-has-caption
19
+ return <audio preload="metadata" {...props} />;
20
+ };
@@ -52,12 +52,21 @@ export const AudioPlayerStory: StoryObj<typeof AudioPlayer> = {
52
52
 
53
53
  AudioPlayerStory.storyName = "AudioPlayer";
54
54
 
55
+ export const SpeechVariant: StoryObj<typeof AudioPlayer> = {
56
+ args: {
57
+ src: "https://api.staging.ndla.no/audio/files/Alltid_Nyheter_nrk128kps.mp3",
58
+ title: "Den gode lydhistoria",
59
+ textVersion: TextVersion,
60
+ variant: "minimal",
61
+ },
62
+ };
63
+
55
64
  export const SimpleVariant: StoryObj<typeof AudioPlayer> = {
56
65
  args: {
57
66
  src: "https://api.staging.ndla.no/audio/files/Alltid_Nyheter_nrk128kps.mp3",
58
67
  title: "Den gode lydhistoria",
59
68
  textVersion: TextVersion,
60
- speech: true,
69
+ variant: "compact",
61
70
  },
62
71
  };
63
72
 
@@ -11,6 +11,7 @@ import { SafeLink } from "@ndla/safelink";
11
11
  import { styled } from "@ndla/styled-system/jsx";
12
12
  import { type ReactNode, useId, useMemo, useState } from "react";
13
13
  import { useTranslation } from "react-i18next";
14
+ import { CompactAudioPlayer } from "./CompactAudioPlayer";
14
15
  import { Controls } from "./Controls";
15
16
  import { SpeechControl } from "./SpeechControl";
16
17
 
@@ -140,33 +141,39 @@ const ShowMoreButton = styled(Button, {
140
141
 
141
142
  const DESCRIPTION_MAX_LENGTH = 200;
142
143
 
143
- type Props = {
144
+ export type AudioPlayerVariant = "standard" | "minimal" | "compact";
145
+
146
+ interface Props {
144
147
  src: string;
145
148
  title: string;
146
149
  subtitle?: {
147
150
  title: string;
148
151
  url?: string;
149
152
  };
150
- speech?: boolean;
153
+ variant?: AudioPlayerVariant;
151
154
  description?: string;
152
155
  textVersion?: ReactNode;
153
156
  img?: {
154
157
  url: string;
155
158
  alt: string;
156
159
  };
157
- };
160
+ }
158
161
 
159
- export const AudioPlayer = ({ src, title, subtitle, speech, description, img, textVersion }: Props) => {
162
+ export const AudioPlayer = ({ src, title, subtitle, variant = "standard", description, img, textVersion }: Props) => {
160
163
  const { t } = useTranslation();
161
164
  const [showTextVersion, setShowTextVersion] = useState(false);
162
165
  const [showFullDescription, setShowFullDescription] = useState(false);
163
166
  const truncatedDescription = useMemo(() => description?.slice(0, DESCRIPTION_MAX_LENGTH), [description]);
164
167
  const textDescriptionId = useId();
165
168
 
166
- if (speech) {
169
+ if (variant === "minimal") {
167
170
  return <SpeechControl src={src} title={title} />;
168
171
  }
169
172
 
173
+ if (variant === "compact") {
174
+ return <CompactAudioPlayer src={src} title={title} />;
175
+ }
176
+
170
177
  const toggleTextVersion = () => {
171
178
  setShowTextVersion((curr) => !curr);
172
179
  };
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Copyright (c) 2026-present, NDLA.
3
+ *
4
+ * This source code is licensed under the GPLv3 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ import type { SliderValueChangeDetails } from "@ark-ui/react";
10
+ import {
11
+ SliderRoot,
12
+ SliderLabel,
13
+ SliderControl,
14
+ SliderTrack,
15
+ SliderRange,
16
+ SliderThumb,
17
+ SliderHiddenInput,
18
+ } from "@ndla/primitives";
19
+ import { styled } from "@ndla/styled-system/jsx";
20
+ import { useTranslation } from "react-i18next";
21
+ import { formatTime } from "./audioUtils";
22
+
23
+ interface Props {
24
+ currentTime: number;
25
+ duration: number;
26
+ onValueChange: (details: SliderValueChangeDetails) => void;
27
+ variant?: "simple" | "standard";
28
+ }
29
+
30
+ const StyledSliderThumb = styled(SliderThumb, {
31
+ variants: {
32
+ variant: {
33
+ standard: {},
34
+ simple: {
35
+ borderRadius: "0",
36
+ width: "4xsmall",
37
+ height: "4xsmall",
38
+ },
39
+ },
40
+ },
41
+ });
42
+
43
+ const StyledSliderTrack = styled(SliderTrack, {
44
+ variants: {
45
+ variant: {
46
+ standard: {},
47
+ simple: {
48
+ background: "unset",
49
+ },
50
+ },
51
+ },
52
+ });
53
+
54
+ const StyledSliderControl = styled(SliderControl, {
55
+ variants: {
56
+ variant: {
57
+ standard: {},
58
+ simple: {
59
+ height: "unset",
60
+ },
61
+ },
62
+ },
63
+ });
64
+
65
+ export const AudioProgress = ({ currentTime, duration, onValueChange, variant }: Props) => {
66
+ const { t } = useTranslation();
67
+ return (
68
+ <SliderRoot
69
+ value={[currentTime]}
70
+ defaultValue={[0]}
71
+ step={1}
72
+ max={duration}
73
+ onValueChange={onValueChange}
74
+ getAriaValueText={(value) =>
75
+ t("audio.valueText", {
76
+ start: formatTime(Math.round(value.value)),
77
+ end: formatTime(Math.round(duration)),
78
+ })
79
+ }
80
+ >
81
+ <SliderLabel srOnly>{t("audio.progressBar")}</SliderLabel>
82
+ <StyledSliderControl variant={variant}>
83
+ <StyledSliderTrack variant={variant}>
84
+ <SliderRange />
85
+ </StyledSliderTrack>
86
+ <StyledSliderThumb index={0} variant={variant}>
87
+ <SliderHiddenInput />
88
+ </StyledSliderThumb>
89
+ </StyledSliderControl>
90
+ </SliderRoot>
91
+ );
92
+ };
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Copyright (c) 2026-present, NDLA.
3
+ *
4
+ * This source code is licensed under the GPLv3 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ import { VolumeUpFill } from "@ndla/icons";
10
+ import { PopoverRoot, PopoverTrigger, IconButton, PopoverContent, Text, PopoverTitle } from "@ndla/primitives";
11
+ import { styled } from "@ndla/styled-system/jsx";
12
+ import { useTranslation } from "react-i18next";
13
+ import { AudioElement } from "./AudioElement";
14
+ import { AudioProgress } from "./AudioProgress";
15
+ import { formatTime } from "./audioUtils";
16
+ import { PlayButton } from "./PlayButton";
17
+ import { useAudioControls } from "./useAudioControls";
18
+ import { VolumeSlider } from "./VolumeSlider";
19
+
20
+ const AudioContainer = styled("div", {
21
+ base: {
22
+ display: "flex",
23
+ gap: "xxsmall",
24
+ flexDirection: "column",
25
+ padding: "xsmall",
26
+ paddingBlockEnd: "0",
27
+ borderRadius: "xsmall",
28
+ boxShadow: "xsmall",
29
+ background: "surface.brand.1.subtle",
30
+ },
31
+ });
32
+
33
+ const ControlsContainer = styled("div", {
34
+ base: {
35
+ display: "flex",
36
+ gap: "xsmall",
37
+ alignItems: "center",
38
+ },
39
+ });
40
+
41
+ interface Props {
42
+ src: string;
43
+ title: string;
44
+ }
45
+
46
+ const StyledText = styled(Text, {
47
+ base: {
48
+ minWidth: "4xlarge",
49
+ flexShrink: "0",
50
+ textAlign: "center",
51
+ },
52
+ });
53
+
54
+ const StyledIconButton = styled(IconButton, {
55
+ base: {
56
+ marginInlineStart: "auto",
57
+ },
58
+ });
59
+
60
+ const EllipsedText = styled(Text, {
61
+ base: {
62
+ overflow: "hidden",
63
+ textOverflow: "ellipsis",
64
+ whiteSpace: "nowrap",
65
+ },
66
+ });
67
+
68
+ export const CompactAudioPlayer = ({ src, title }: Props) => {
69
+ const { t } = useTranslation();
70
+ const {
71
+ audioRef,
72
+ playing,
73
+ togglePlay,
74
+ currentTime,
75
+ duration,
76
+ handleSliderChange,
77
+ volumeValue,
78
+ handleVolumeSliderChange,
79
+ onEnded,
80
+ onHandleTime,
81
+ } = useAudioControls();
82
+ return (
83
+ <AudioContainer>
84
+ <AudioElement
85
+ ref={audioRef}
86
+ src={src}
87
+ title={title}
88
+ onEnded={onEnded}
89
+ onLoadedMetadata={onHandleTime}
90
+ onTimeUpdate={onHandleTime}
91
+ />
92
+ <ControlsContainer>
93
+ <PlayButton playing={playing} onClick={togglePlay} />
94
+ <StyledText>
95
+ <Text textStyle="label.medium" asChild consumeCss>
96
+ <span>{formatTime(currentTime)}</span>
97
+ </Text>
98
+ {"/ "}
99
+ <Text textStyle="label.medium" color="text.subtle" asChild consumeCss>
100
+ <span>{formatTime(duration)}</span>
101
+ </Text>
102
+ </StyledText>
103
+ <EllipsedText textStyle="title.medium">{title}</EllipsedText>
104
+ <PopoverRoot positioning={{ placement: "top" }}>
105
+ <PopoverTrigger asChild>
106
+ <StyledIconButton variant="tertiary">
107
+ <VolumeUpFill />
108
+ </StyledIconButton>
109
+ </PopoverTrigger>
110
+ <PopoverContent>
111
+ <PopoverTitle srOnly>{t("audio.controls.adjustVolume")}</PopoverTitle>
112
+ <VolumeSlider value={volumeValue} onValueChange={handleVolumeSliderChange} />
113
+ </PopoverContent>
114
+ </PopoverRoot>
115
+ </ControlsContainer>
116
+ <AudioProgress
117
+ currentTime={currentTime}
118
+ duration={duration}
119
+ onValueChange={handleSliderChange}
120
+ variant="simple"
121
+ />
122
+ </AudioContainer>
123
+ );
124
+ };