lightnet 3.6.1 → 3.8.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.
- package/CHANGELOG.md +59 -0
- package/README.md +23 -11
- package/__e2e__/fixtures/basics/node_modules/.bin/astro +7 -3
- package/__e2e__/fixtures/basics/node_modules/.bin/tailwind +5 -1
- package/__e2e__/fixtures/basics/node_modules/.bin/tailwindcss +5 -1
- package/__e2e__/fixtures/basics/node_modules/.bin/tsc +7 -3
- package/__e2e__/fixtures/basics/node_modules/.bin/tsserver +7 -3
- package/__e2e__/fixtures/basics/package.json +10 -7
- package/__tests__/utils/markdown.spec.ts +4 -0
- package/__tests__/utils/urls.spec.ts +27 -0
- package/exports/experimental-components.ts +1 -0
- package/package.json +19 -12
- package/src/astro-integration/integration.ts +6 -0
- package/src/components/CarouselSection.astro +182 -0
- package/src/components/CategoriesSection.astro +96 -47
- package/src/components/MediaGallery.astro +1 -1
- package/src/components/SearchInput.astro +1 -0
- package/src/components/SearchSection.astro +9 -4
- package/src/components/Section.astro +31 -17
- package/src/content/get-categories.ts +1 -1
- package/src/i18n/translations/README.md +1 -1
- package/src/i18n/translations/ar.yml +2 -0
- package/src/i18n/translations/bn.yml +2 -0
- package/src/i18n/translations/de.yml +2 -0
- package/src/i18n/translations/en.yml +12 -0
- package/src/i18n/translations/es.yml +2 -0
- package/src/i18n/translations/fi.yml +2 -0
- package/src/i18n/translations/fr.yml +2 -0
- package/src/i18n/translations/hi.yml +2 -0
- package/src/i18n/translations/pt.yml +2 -0
- package/src/i18n/translations/ru.yml +2 -0
- package/src/i18n/translations/uk.yml +2 -0
- package/src/i18n/translations/zh.yml +2 -0
- package/src/i18n/translations.ts +2 -0
- package/src/layouts/Page.astro +2 -3
- package/src/layouts/components/Header.astro +1 -4
- package/src/layouts/components/ViewTransition.astro +9 -0
- package/src/pages/api/versions.ts +7 -0
- package/src/pages/details-page/AudioDetailsPage.astro +4 -9
- package/src/pages/details-page/DefaultDetailsPage.astro +6 -6
- package/src/pages/details-page/components/AudioPanel.astro +64 -0
- package/src/pages/details-page/components/{main-details/AudioPlayer.astro → AudioPlayer.astro} +1 -1
- package/src/pages/details-page/components/ContentSection.astro +5 -2
- package/src/pages/details-page/components/DescriptionSection.astro +1 -1
- package/src/pages/details-page/components/MainDetailsSection.astro +8 -5
- package/src/pages/details-page/components/VideoDetailsSection.astro +1 -1
- package/src/pages/details-page/components/main-details/Authors.astro +2 -2
- package/src/pages/details-page/components/main-details/OpenButton.astro +3 -1
- package/src/pages/details-page/components/main-details/ShareButton.astro +21 -33
- package/src/pages/details-page/components/main-details/{Cover.astro → Thumbnail.astro} +14 -3
- package/src/pages/search-page/components/SearchList.tsx +0 -1
- package/src/pages/search-page/hooks/use-search.ts +2 -33
- package/src/utils/paths.ts +15 -1
|
@@ -4,15 +4,16 @@ import { Image } from "astro:assets"
|
|
|
4
4
|
|
|
5
5
|
import { getUsedCategories } from "../content/get-categories"
|
|
6
6
|
import { searchPagePath } from "../utils/paths"
|
|
7
|
-
import
|
|
7
|
+
import CarouselSection from "./CarouselSection.astro"
|
|
8
|
+
import Section, { type Props as SectionProps } from "./Section.astro"
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
layout?: "button-grid" | "image-grid"
|
|
10
|
+
type Props = SectionProps & {
|
|
11
|
+
layout?: "grid" | "carousel"
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
const { title, layout = "
|
|
14
|
+
const { title, layout = "carousel", ...props } = Astro.props
|
|
15
15
|
const { t, currentLocale } = Astro.locals.i18n
|
|
16
|
+
const resolvedTitle = title ?? t("ln.categories")
|
|
16
17
|
|
|
17
18
|
const categories = await getUsedCategories(currentLocale, t)
|
|
18
19
|
type Category = (typeof categories)[number]
|
|
@@ -20,8 +21,8 @@ type Category = (typeof categories)[number]
|
|
|
20
21
|
function getImage({ image, id }: Category) {
|
|
21
22
|
if (!image) {
|
|
22
23
|
throw new AstroError(
|
|
23
|
-
`
|
|
24
|
-
`To resolve this issue,
|
|
24
|
+
`Expected an image for category "${id}".`,
|
|
25
|
+
`To resolve this issue, provide a valid image path in /src/content/categories/${id}.json.`,
|
|
25
26
|
)
|
|
26
27
|
}
|
|
27
28
|
return image
|
|
@@ -29,40 +30,27 @@ function getImage({ image, id }: Category) {
|
|
|
29
30
|
---
|
|
30
31
|
|
|
31
32
|
{
|
|
32
|
-
categories.length && (
|
|
33
|
-
<Section title={
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
!!categories.length && layout === "grid" && (
|
|
34
|
+
<Section {...props} title={resolvedTitle}>
|
|
35
|
+
<ol class="grid grid-cols-2 items-end justify-between gap-4 sm:grid-cols-3 md:grid-cols-4 md:gap-8 lg:grid-cols-5">
|
|
36
|
+
{categories.map((category) => (
|
|
37
|
+
<li class="h-full">
|
|
38
|
+
<a
|
|
39
|
+
href={searchPagePath(currentLocale, { category: category.id })}
|
|
40
|
+
class="group flex h-full flex-col gap-3"
|
|
41
|
+
>
|
|
42
|
+
<div
|
|
43
|
+
class="relative overflow-hidden rounded-2xl shadow-md outline-2 outline-gray-400 transition-colors duration-75 ease-in-out sm:group-hover:outline"
|
|
44
|
+
class:list={[
|
|
45
|
+
!category.image && "h-full min-h-28 w-full bg-gray-300",
|
|
46
|
+
]}
|
|
43
47
|
>
|
|
44
|
-
|
|
45
|
-
{category.name}
|
|
46
|
-
</div>
|
|
47
|
-
</a>
|
|
48
|
-
</li>
|
|
49
|
-
))}
|
|
50
|
-
</ul>
|
|
51
|
-
)}
|
|
52
|
-
{layout === "image-grid" && (
|
|
53
|
-
<ol class="grid grid-cols-2 items-end justify-between gap-4 sm:grid-cols-3 md:grid-cols-4 md:gap-8 lg:grid-cols-5">
|
|
54
|
-
{categories.map((category) => (
|
|
55
|
-
<li>
|
|
56
|
-
<a
|
|
57
|
-
href={searchPagePath(currentLocale, { category: category.id })}
|
|
58
|
-
class="group flex flex-col gap-3"
|
|
59
|
-
>
|
|
60
|
-
<div class="relative overflow-hidden rounded-md shadow-md outline-2 outline-gray-400 transition-all duration-75 ease-in-out sm:group-hover:outline">
|
|
48
|
+
{category.image && (
|
|
61
49
|
<Image
|
|
62
|
-
class="h-full w-full object-contain"
|
|
50
|
+
class="h-full w-full bg-gray-500 object-contain"
|
|
63
51
|
src={getImage(category)}
|
|
64
52
|
alt=""
|
|
65
|
-
widths={[256, 512, 768
|
|
53
|
+
widths={[128, 256, 388, 512, 768]}
|
|
66
54
|
sizes={
|
|
67
55
|
"(max-width: 640px) calc(calc(100vw - 3.5rem ) / 2), " +
|
|
68
56
|
"(max-width: 768px) calc(calc(100vw - 5rem ) / 3), " +
|
|
@@ -71,17 +59,78 @@ function getImage({ image, id }: Category) {
|
|
|
71
59
|
"217px"
|
|
72
60
|
}
|
|
73
61
|
/>
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
62
|
+
)}
|
|
63
|
+
|
|
64
|
+
<div
|
|
65
|
+
class="absolute start-0 top-0 flex h-full w-full flex-col justify-end bg-gradient-to-t p-4 text-gray-50"
|
|
66
|
+
class:list={[
|
|
67
|
+
category.image
|
|
68
|
+
? "from-black/80 via-black/30 via-50% to-transparent"
|
|
69
|
+
: "from-black/35 to-transparent",
|
|
70
|
+
]}
|
|
71
|
+
>
|
|
72
|
+
<span class="line-clamp-3 select-none text-balance font-bold">
|
|
73
|
+
{category.name}
|
|
74
|
+
</span>
|
|
79
75
|
</div>
|
|
80
|
-
</
|
|
81
|
-
</
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
76
|
+
</div>
|
|
77
|
+
</a>
|
|
78
|
+
</li>
|
|
79
|
+
))}
|
|
80
|
+
</ol>
|
|
85
81
|
</Section>
|
|
86
82
|
)
|
|
87
83
|
}
|
|
84
|
+
{
|
|
85
|
+
!!categories.length && layout === "carousel" && (
|
|
86
|
+
<CarouselSection {...props} title={resolvedTitle}>
|
|
87
|
+
{categories.map((category) => (
|
|
88
|
+
<li
|
|
89
|
+
class="carousel-item--narrow h-full"
|
|
90
|
+
role="group"
|
|
91
|
+
aria-roledescription="slide"
|
|
92
|
+
>
|
|
93
|
+
<a
|
|
94
|
+
href={searchPagePath(currentLocale, { category: category.id })}
|
|
95
|
+
class="group flex h-full flex-col gap-3"
|
|
96
|
+
>
|
|
97
|
+
<div
|
|
98
|
+
class="relative overflow-hidden rounded-2xl shadow-md outline-2 outline-gray-400 transition-all duration-75 ease-in-out sm:group-hover:outline"
|
|
99
|
+
class:list={[
|
|
100
|
+
!category.image && "h-full min-h-28 w-full bg-gray-300",
|
|
101
|
+
]}
|
|
102
|
+
>
|
|
103
|
+
{category.image && (
|
|
104
|
+
<Image
|
|
105
|
+
class="h-full w-full bg-gray-300 object-contain"
|
|
106
|
+
src={getImage(category)}
|
|
107
|
+
alt=""
|
|
108
|
+
widths={[128, 256, 388, 512, 768]}
|
|
109
|
+
sizes={
|
|
110
|
+
"(max-width: 640px) calc(calc(100vw - 3rem ) / 2.3), " +
|
|
111
|
+
"(max-width: 768px) calc(calc(100vw - 5rem ) / 3), " +
|
|
112
|
+
"(max-width: 1024px) calc(calc(100vw - 10rem ) / 4), " +
|
|
113
|
+
"(max-width: 1280px) calc(calc(100vw - 12rem ) / 5), " +
|
|
114
|
+
"217px"
|
|
115
|
+
}
|
|
116
|
+
/>
|
|
117
|
+
)}
|
|
118
|
+
<div
|
|
119
|
+
class="absolute start-0 top-0 flex h-full w-full flex-col justify-end bg-gradient-to-t p-4 text-gray-50"
|
|
120
|
+
class:list={[
|
|
121
|
+
category.image
|
|
122
|
+
? "from-black/80 via-black/30 via-50% to-transparent"
|
|
123
|
+
: "from-black/35 to-transparent",
|
|
124
|
+
]}
|
|
125
|
+
>
|
|
126
|
+
<span class="line-clamp-3 select-none text-balance font-bold">
|
|
127
|
+
{category.name}
|
|
128
|
+
</span>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
</a>
|
|
132
|
+
</li>
|
|
133
|
+
))}
|
|
134
|
+
</CarouselSection>
|
|
135
|
+
)
|
|
136
|
+
}
|
|
@@ -81,7 +81,7 @@ const items = itemsInput.filter((item) => !!item)
|
|
|
81
81
|
{
|
|
82
82
|
(layout === "video" || layout === "landscape") && (
|
|
83
83
|
<ol
|
|
84
|
-
class="grid grid-cols-1 justify-between gap-x-7 gap-y-4 sm:grid-cols-2 md:grid-cols-3 md:gap-8 lg:grid-cols-4
|
|
84
|
+
class="grid grid-cols-1 justify-between gap-x-7 gap-y-4 sm:grid-cols-2 md:grid-cols-3 md:gap-8 lg:grid-cols-4"
|
|
85
85
|
class:list={[layout === "landscape" && "items-end"]}
|
|
86
86
|
>
|
|
87
87
|
{items.map((item) => (
|
|
@@ -11,6 +11,7 @@ const { t } = Astro.locals.i18n
|
|
|
11
11
|
<form
|
|
12
12
|
action={`/${Astro.currentLocale}/media`}
|
|
13
13
|
method="get"
|
|
14
|
+
role="search"
|
|
14
15
|
class="dy-join group w-full rounded-2xl shadow-md outline-2 outline-offset-2 outline-gray-400 group-focus-within:outline"
|
|
15
16
|
class:list={[Astro.props.className]}
|
|
16
17
|
>
|
|
@@ -3,12 +3,17 @@ import SearchFilter from "../pages/search-page/components/SearchFilter.astro"
|
|
|
3
3
|
import SearchList from "../pages/search-page/components/SearchList.astro"
|
|
4
4
|
import Section, { type Props as SectionProps } from "./Section.astro"
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
type Props = Omit<SectionProps, "maxWidth">
|
|
7
|
+
|
|
8
|
+
const { className = "", titleClass = "", ...props } = Astro.props
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
<Section
|
|
11
|
+
<Section
|
|
12
|
+
{...props}
|
|
13
|
+
className={"px-0 md:px-0 " + className}
|
|
14
|
+
titleClass={"px-4 md:px-8 " + titleClass}
|
|
15
|
+
maxWidth="narrow"
|
|
16
|
+
>
|
|
12
17
|
<div class="px-4 md:px-8">
|
|
13
18
|
<SearchFilter />
|
|
14
19
|
</div>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
+
import Icon from "./Icon"
|
|
3
|
+
|
|
2
4
|
export interface Props {
|
|
3
5
|
/**
|
|
4
6
|
* Id to set to the section element.
|
|
@@ -21,30 +23,35 @@ export interface Props {
|
|
|
21
23
|
* @default "lg"
|
|
22
24
|
*/
|
|
23
25
|
marginTop?: "sm" | "lg" | "none"
|
|
24
|
-
/**
|
|
25
|
-
* Remove padding from the left and right side of the content.
|
|
26
|
-
* This will not apply to the section title.
|
|
27
|
-
*
|
|
28
|
-
* @default false
|
|
29
|
-
*/
|
|
30
|
-
disableHorizontalPadding?: boolean
|
|
31
26
|
/**
|
|
32
27
|
* Title on top of the section.
|
|
33
28
|
*/
|
|
34
29
|
title?: string
|
|
30
|
+
/**
|
|
31
|
+
* A link to add to the section title. This link can be used to show
|
|
32
|
+
* more content related to the section.
|
|
33
|
+
*
|
|
34
|
+
* The link will not be transformed. You need to make sure to prepend the current locale.
|
|
35
|
+
*/
|
|
36
|
+
titleHref?: string
|
|
35
37
|
/**
|
|
36
38
|
* Css classes to set to the section element.
|
|
37
39
|
*/
|
|
38
40
|
className?: string
|
|
41
|
+
/**
|
|
42
|
+
* Css classes to set to the title element.
|
|
43
|
+
*/
|
|
44
|
+
titleClass?: string
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
const {
|
|
42
48
|
id,
|
|
43
49
|
maxWidth = "wide",
|
|
44
50
|
marginTop = "lg",
|
|
45
|
-
|
|
51
|
+
titleHref,
|
|
46
52
|
title,
|
|
47
53
|
className,
|
|
54
|
+
titleClass,
|
|
48
55
|
} = Astro.props
|
|
49
56
|
|
|
50
57
|
const maxWidths = {
|
|
@@ -60,22 +67,29 @@ const marginTopValues = {
|
|
|
60
67
|
---
|
|
61
68
|
|
|
62
69
|
<section
|
|
63
|
-
class="mx-auto"
|
|
64
|
-
class:list={[
|
|
65
|
-
maxWidths[maxWidth],
|
|
66
|
-
marginTopValues[marginTop],
|
|
67
|
-
!disableHorizontalPadding && "px-4 md:px-8",
|
|
68
|
-
className,
|
|
69
|
-
]}
|
|
70
|
+
class="mx-auto px-4 md:px-8"
|
|
71
|
+
class:list={[maxWidths[maxWidth], marginTopValues[marginTop], className]}
|
|
70
72
|
id={id}
|
|
73
|
+
aria-label={title}
|
|
71
74
|
>
|
|
72
75
|
{
|
|
73
76
|
title && (
|
|
74
77
|
<h2
|
|
75
78
|
class="mb-10 text-balance text-2xl font-bold text-gray-700 sm:mb-12 sm:text-3xl"
|
|
76
|
-
class:list={[
|
|
79
|
+
class:list={[titleClass]}
|
|
77
80
|
>
|
|
78
|
-
{
|
|
81
|
+
{titleHref ? (
|
|
82
|
+
<a href={titleHref} class="group flex items-center">
|
|
83
|
+
{title}
|
|
84
|
+
<Icon
|
|
85
|
+
className="mdi--chevron-right group-hover:text-primary transition-colors ease-in-out duration-75 text-4xl sm:text-5xl -ms-2"
|
|
86
|
+
ariaLabel=""
|
|
87
|
+
flipIcon={Astro.locals.i18n.direction === "rtl"}
|
|
88
|
+
/>
|
|
89
|
+
</a>
|
|
90
|
+
) : (
|
|
91
|
+
<>{title}</>
|
|
92
|
+
)}
|
|
79
93
|
</h2>
|
|
80
94
|
)
|
|
81
95
|
}
|
|
@@ -68,6 +68,6 @@ function parseCategory(item: unknown) {
|
|
|
68
68
|
categoryEntrySchema,
|
|
69
69
|
item,
|
|
70
70
|
(id) => `Invalid category: ${id}`,
|
|
71
|
-
(id) => `Fix these issues inside "src/content/
|
|
71
|
+
(id) => `Fix these issues inside "src/content/categories/${id}.json":`,
|
|
72
72
|
)
|
|
73
73
|
}
|
|
@@ -8,7 +8,7 @@ Check the [translation status](TRANSLATION-STATUS.md) for an overview of complet
|
|
|
8
8
|
Have you translated LightNet into a new language? Have you fixed a incorrect translation? Great! How about sharing
|
|
9
9
|
your work with others, by adding it to this folder?
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
These are the ways you can contribute your translations:
|
|
12
12
|
|
|
13
13
|
- [Open a GitHub pull-request](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project), if you are a git-native. 🤓
|
|
14
14
|
- [Use the translation-update form](https://github.com/LightNetDev/LightNet/issues/new?template=---03-translations-update.yml) to share your work. ⭐️
|
|
@@ -48,6 +48,18 @@ ln.languages: Languages
|
|
|
48
48
|
# Used on: https://sk8-ministries.pages.dev/en/media
|
|
49
49
|
ln.type: Type
|
|
50
50
|
|
|
51
|
+
# Accessibility label for buttons to show the previous items.
|
|
52
|
+
# This is used on the carousel arrow button.
|
|
53
|
+
#
|
|
54
|
+
# English: Previous
|
|
55
|
+
ln.previous: Previous
|
|
56
|
+
|
|
57
|
+
# Accessibility label for buttons to show the next items.
|
|
58
|
+
# This is used on the carousel arrow button.
|
|
59
|
+
#
|
|
60
|
+
# English: Next
|
|
61
|
+
ln.next: Next
|
|
62
|
+
|
|
51
63
|
# Accessibility label for an external link.
|
|
52
64
|
# This is only "visible" to a screen-reader.
|
|
53
65
|
#
|
package/src/i18n/translations.ts
CHANGED
package/src/layouts/Page.astro
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
---
|
|
2
|
-
import { ClientRouter } from "astro:transitions"
|
|
3
2
|
import CustomFooter from "virtual:lightnet/components/CustomFooter"
|
|
4
3
|
import CustomHead from "virtual:lightnet/components/CustomHead"
|
|
5
4
|
import config from "virtual:lightnet/config"
|
|
@@ -8,6 +7,7 @@ import { resolveLanguage } from "../i18n/resolve-language"
|
|
|
8
7
|
import Favicon from "./components/Favicon.astro"
|
|
9
8
|
import Header from "./components/Header.astro"
|
|
10
9
|
import PreloadReact from "./components/PreloadReact"
|
|
10
|
+
import ViewTransition from "./components/ViewTransition.astro"
|
|
11
11
|
|
|
12
12
|
interface Props {
|
|
13
13
|
title?: string
|
|
@@ -32,10 +32,9 @@ const language = resolveLanguage(currentLocale)
|
|
|
32
32
|
{config.manifest && <link rel="manifest" href={config.manifest} />}
|
|
33
33
|
<link rel="prefetch" href="/api/search.json" />
|
|
34
34
|
<Favicon />
|
|
35
|
-
<
|
|
35
|
+
<ViewTransition />
|
|
36
36
|
</head>
|
|
37
37
|
<body
|
|
38
|
-
transition:animate="none"
|
|
39
38
|
class="flex min-h-screen flex-col overflow-y-scroll bg-gray-50 text-gray-900"
|
|
40
39
|
>
|
|
41
40
|
<Header />
|
|
@@ -3,10 +3,7 @@ import PageNavigation from "./PageNavigation.astro"
|
|
|
3
3
|
import PageTitle from "./PageTitle.astro"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
<header
|
|
7
|
-
class="fixed top-0 z-50 h-14 w-full bg-white shadow-lg sm:h-20"
|
|
8
|
-
transition:animate="none"
|
|
9
|
-
>
|
|
6
|
+
<header class="fixed top-0 z-50 h-14 w-full bg-white shadow-lg sm:h-20">
|
|
10
7
|
<div class="mx-auto flex h-full max-w-screen-xl justify-between px-4 md:px-8">
|
|
11
8
|
<PageTitle />
|
|
12
9
|
<PageNavigation />
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
---
|
|
2
|
-
import
|
|
2
|
+
import AudioPanel from "./components/AudioPanel.astro"
|
|
3
3
|
import ContentSection from "./components/ContentSection.astro"
|
|
4
4
|
import DescriptionSection from "./components/DescriptionSection.astro"
|
|
5
5
|
import DetailsPage from "./components/DetailsPage.astro"
|
|
6
|
-
import AudioPlayer from "./components/main-details/AudioPlayer.astro"
|
|
7
|
-
import ShareButton from "./components/main-details/ShareButton.astro"
|
|
8
6
|
import MainDetailsSection from "./components/MainDetailsSection.astro"
|
|
9
7
|
import MediaCollectionsSection from "./components/MediaCollectionsSection.astro"
|
|
10
8
|
import MoreDetailsSection from "./components/MoreDetailsSection.astro"
|
|
@@ -14,16 +12,13 @@ export type Props = {
|
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
const { mediaId } = Astro.props
|
|
17
|
-
const audioSrc = (await getMediaItem(mediaId)).data.content[0].url
|
|
18
15
|
---
|
|
19
16
|
|
|
20
17
|
<DetailsPage mediaId={mediaId}>
|
|
21
|
-
<MainDetailsSection mediaId={mediaId}
|
|
22
|
-
|
|
23
|
-
<ShareButton className="mt-4 min-w-40" />
|
|
24
|
-
</MainDetailsSection>
|
|
18
|
+
<MainDetailsSection thumbnailSize="md" mediaId={mediaId} />
|
|
19
|
+
<AudioPanel mediaId={mediaId} className="mt-10" />
|
|
25
20
|
<DescriptionSection mediaId={mediaId} />
|
|
26
|
-
<ContentSection mediaId={mediaId} />
|
|
21
|
+
<ContentSection mediaId={mediaId} minimumItems={1} />
|
|
27
22
|
<MediaCollectionsSection mediaId={mediaId} />
|
|
28
23
|
<MoreDetailsSection mediaId={mediaId} />
|
|
29
24
|
</DetailsPage>
|
|
@@ -3,7 +3,6 @@ import ContentSection from "./components/ContentSection.astro"
|
|
|
3
3
|
import DescriptionSection from "./components/DescriptionSection.astro"
|
|
4
4
|
import DetailsPage from "./components/DetailsPage.astro"
|
|
5
5
|
import OpenButton from "./components/main-details/OpenButton.astro"
|
|
6
|
-
import ShareButton from "./components/main-details/ShareButton.astro"
|
|
7
6
|
import MainDetailsSection from "./components/MainDetailsSection.astro"
|
|
8
7
|
import MediaCollectionsSection from "./components/MediaCollectionsSection.astro"
|
|
9
8
|
import MoreDetailsSection from "./components/MoreDetailsSection.astro"
|
|
@@ -18,11 +17,12 @@ const { mediaId, coverStyle, openActionLabel = "ln.details.open" } = Astro.props
|
|
|
18
17
|
---
|
|
19
18
|
|
|
20
19
|
<DetailsPage mediaId={mediaId}>
|
|
21
|
-
<MainDetailsSection mediaId={mediaId}
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
<MainDetailsSection mediaId={mediaId} thumbnailStyle={coverStyle}>
|
|
21
|
+
<OpenButton
|
|
22
|
+
className="mt-8"
|
|
23
|
+
mediaId={mediaId}
|
|
24
|
+
openActionLabel={openActionLabel}
|
|
25
|
+
/>
|
|
26
26
|
</MainDetailsSection>
|
|
27
27
|
<DescriptionSection mediaId={mediaId} />
|
|
28
28
|
<ContentSection mediaId={mediaId} />
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { AstroError } from "astro/errors"
|
|
3
|
+
|
|
4
|
+
import { getMediaItem } from "../../../content/get-media-items"
|
|
5
|
+
import { createContentMetadata } from "../utils/create-content-metadata"
|
|
6
|
+
import AudioPlayer from "./AudioPlayer.astro"
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
mediaId: string
|
|
10
|
+
className?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const { mediaId, className } = Astro.props
|
|
14
|
+
const { t } = Astro.locals.i18n
|
|
15
|
+
|
|
16
|
+
const item = await getMediaItem(mediaId)
|
|
17
|
+
|
|
18
|
+
const content = item.data.content
|
|
19
|
+
.map((c) => createContentMetadata(c))
|
|
20
|
+
.filter((c) => c.extension === "mp3")
|
|
21
|
+
|
|
22
|
+
if (!content.length) {
|
|
23
|
+
throw new AstroError(
|
|
24
|
+
`Missing mp3 content for ${mediaId}`,
|
|
25
|
+
`Add at least one mp3 file to the content array of /src/media/${mediaId}.json`,
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
<ol
|
|
31
|
+
class="mx-auto mt-10 flex max-w-screen-md flex-col gap-10 px-4 md:px-8"
|
|
32
|
+
class:list={[className]}
|
|
33
|
+
id="audio-panel"
|
|
34
|
+
>
|
|
35
|
+
{
|
|
36
|
+
content.map((c) => (
|
|
37
|
+
<li>
|
|
38
|
+
{content.length > 1 && <div class="mb-3 font-bold">{t(c.label)}</div>}
|
|
39
|
+
<AudioPlayer className="w-full" src={c.url} />
|
|
40
|
+
</li>
|
|
41
|
+
))
|
|
42
|
+
}
|
|
43
|
+
</ol>
|
|
44
|
+
<script>
|
|
45
|
+
const audioPanel = document.getElementById("audio-panel")
|
|
46
|
+
const audios = Array.from(audioPanel?.querySelectorAll("audio") ?? [])
|
|
47
|
+
|
|
48
|
+
audios.forEach((audio, index) => {
|
|
49
|
+
audio.addEventListener("play", () => {
|
|
50
|
+
audios.forEach((otherAudio) => {
|
|
51
|
+
if (otherAudio !== audio) {
|
|
52
|
+
otherAudio.pause()
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
audio.addEventListener("ended", () => {
|
|
58
|
+
const nextAudio = audios[index + 1]
|
|
59
|
+
if (nextAudio) {
|
|
60
|
+
nextAudio.play()
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
</script>
|