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
|
@@ -8,11 +8,14 @@ import {
|
|
|
8
8
|
|
|
9
9
|
interface Props {
|
|
10
10
|
mediaId: string
|
|
11
|
+
minimumItems?: number
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
const
|
|
14
|
+
const { mediaId, minimumItems = 2 } = Astro.props
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
const item = await getMediaItem(mediaId)
|
|
17
|
+
|
|
18
|
+
if (item.data.content.length < minimumItems) {
|
|
16
19
|
return
|
|
17
20
|
}
|
|
18
21
|
|
|
@@ -17,7 +17,7 @@ const { direction, code: lang } = resolveLanguage(language)
|
|
|
17
17
|
description && (
|
|
18
18
|
<div
|
|
19
19
|
dir={direction}
|
|
20
|
-
class="prose prose-gray mx-auto mt-
|
|
20
|
+
class="prose prose-gray mx-auto mt-8 max-w-screen-md px-4 md:mt-12 md:px-8"
|
|
21
21
|
set:html={await markdownToHtml(description)}
|
|
22
22
|
lang={lang}
|
|
23
23
|
id="description"
|
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Authors from "./main-details/Authors.astro"
|
|
3
|
-
import
|
|
3
|
+
import ShareButton from "./main-details/ShareButton.astro"
|
|
4
|
+
import Thumbnail from "./main-details/Thumbnail.astro"
|
|
4
5
|
import Title from "./main-details/Title.astro"
|
|
5
6
|
|
|
6
7
|
export type Props = {
|
|
7
8
|
mediaId: string
|
|
8
|
-
|
|
9
|
+
thumbnailStyle?: "default" | "book"
|
|
10
|
+
thumbnailSize?: "md" | "lg"
|
|
9
11
|
}
|
|
10
12
|
|
|
11
|
-
const { mediaId,
|
|
13
|
+
const { mediaId, thumbnailStyle, thumbnailSize } = Astro.props
|
|
12
14
|
---
|
|
13
15
|
|
|
14
16
|
<div
|
|
15
17
|
class="mx-auto mt-10 flex max-w-screen-md flex-col items-center gap-8 px-4 sm:mt-20 sm:flex-row sm:items-start sm:gap-14 md:px-8"
|
|
16
18
|
>
|
|
17
|
-
<
|
|
19
|
+
<Thumbnail size={thumbnailSize} mediaId={mediaId} style={thumbnailStyle} />
|
|
18
20
|
<div class="flex w-full grow flex-col items-center sm:items-start">
|
|
19
21
|
<Title className="text-center sm:text-start" mediaId={mediaId} />
|
|
20
|
-
<Authors className="
|
|
22
|
+
<Authors className="mt-2" mediaId={mediaId} />
|
|
23
|
+
<ShareButton className="mt-3" />
|
|
21
24
|
<slot />
|
|
22
25
|
</div>
|
|
23
26
|
</div>
|
|
@@ -12,8 +12,8 @@ const authors = item.data.authors?.join(", ")
|
|
|
12
12
|
|
|
13
13
|
{
|
|
14
14
|
authors && (
|
|
15
|
-
<
|
|
15
|
+
<div class="text-xl sm:text-2xl" class:list={Astro.props.className}>
|
|
16
16
|
{authors}
|
|
17
|
-
</
|
|
17
|
+
</div>
|
|
18
18
|
)
|
|
19
19
|
}
|
|
@@ -6,8 +6,9 @@ import { createContentMetadata } from "../../utils/create-content-metadata"
|
|
|
6
6
|
interface Props {
|
|
7
7
|
mediaId: string
|
|
8
8
|
openActionLabel: string
|
|
9
|
+
className?: string
|
|
9
10
|
}
|
|
10
|
-
const { mediaId, openActionLabel } = Astro.props
|
|
11
|
+
const { mediaId, openActionLabel, className } = Astro.props
|
|
11
12
|
const item = await getMediaItem(mediaId)
|
|
12
13
|
const content = createContentMetadata(item.data.content[0])
|
|
13
14
|
---
|
|
@@ -17,6 +18,7 @@ const content = createContentMetadata(item.data.content[0])
|
|
|
17
18
|
href={content.url}
|
|
18
19
|
target={content.target}
|
|
19
20
|
hreflang={item.data.language}
|
|
21
|
+
class:list={[className]}
|
|
20
22
|
>
|
|
21
23
|
{
|
|
22
24
|
content.isExternal && (
|
|
@@ -7,7 +7,7 @@ interface Props {
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
<button
|
|
10
|
-
class="flex cursor-pointer items-center
|
|
10
|
+
class="flex cursor-pointer items-center gap-2 font-bold text-gray-700 underline"
|
|
11
11
|
class:list={[Astro.props.className]}
|
|
12
12
|
id="share-btn"
|
|
13
13
|
><Icon className="mdi--share" ariaLabel="" />
|
|
@@ -22,37 +22,25 @@ interface Props {
|
|
|
22
22
|
</div>
|
|
23
23
|
</div>
|
|
24
24
|
<script>
|
|
25
|
-
document.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
25
|
+
const btn = document.querySelector("#share-btn")
|
|
26
|
+
btn?.addEventListener("click", () => {
|
|
27
|
+
if (navigator.share) {
|
|
28
|
+
navigator
|
|
29
|
+
.share({
|
|
30
|
+
url: window.location.href,
|
|
31
|
+
})
|
|
32
|
+
.catch((e) => console.debug("Could not share", e))
|
|
33
|
+
} else {
|
|
34
|
+
navigator.clipboard
|
|
35
|
+
.writeText(window.location.href)
|
|
36
|
+
.then(() => {
|
|
37
|
+
const toast = document.querySelector<HTMLElement>("#share-success")!
|
|
38
|
+
toast.style.opacity = "100%"
|
|
39
|
+
setTimeout(() => {
|
|
40
|
+
toast.style.opacity = "0%"
|
|
41
|
+
}, 3000)
|
|
42
|
+
})
|
|
43
|
+
.catch((error) => console.log("Error copying URL to clipboard:", error))
|
|
34
44
|
}
|
|
35
|
-
|
|
36
|
-
if (navigator.share) {
|
|
37
|
-
navigator
|
|
38
|
-
.share({
|
|
39
|
-
url: window.location.href,
|
|
40
|
-
})
|
|
41
|
-
.catch((e) => console.debug("Could not share", e))
|
|
42
|
-
} else {
|
|
43
|
-
navigator.clipboard
|
|
44
|
-
.writeText(window.location.href)
|
|
45
|
-
.then(() => {
|
|
46
|
-
const toast = document.querySelector<HTMLElement>("#share-success")!
|
|
47
|
-
toast.style.opacity = "100%"
|
|
48
|
-
setTimeout(() => {
|
|
49
|
-
toast.style.opacity = "0%"
|
|
50
|
-
}, 3000)
|
|
51
|
-
})
|
|
52
|
-
.catch((error) =>
|
|
53
|
-
console.log("Error copying URL to clipboard:", error),
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
})
|
|
57
|
-
}
|
|
45
|
+
})
|
|
58
46
|
</script>
|
|
@@ -6,12 +6,23 @@ import { getMediaItem } from "../../../../content/get-media-items"
|
|
|
6
6
|
interface Props {
|
|
7
7
|
mediaId: string
|
|
8
8
|
style?: "default" | "book"
|
|
9
|
+
size?: "md" | "lg"
|
|
9
10
|
}
|
|
10
|
-
const { mediaId, style = "default" } = Astro.props
|
|
11
|
+
const { mediaId, style = "default", size = "lg" } = Astro.props
|
|
11
12
|
|
|
12
13
|
const item = await getMediaItem(mediaId)
|
|
13
14
|
const image = item.data.image
|
|
14
15
|
const isPortraitImage = image.height > image.width
|
|
16
|
+
const imageSizes = {
|
|
17
|
+
md: {
|
|
18
|
+
css: isPortraitImage ? "h-52 w-auto" : "h-auto w-52",
|
|
19
|
+
query: "13rem",
|
|
20
|
+
},
|
|
21
|
+
lg: {
|
|
22
|
+
css: isPortraitImage ? "h-52 w-auto sm:h-72" : "h-auto w-52 sm:w-72",
|
|
23
|
+
query: "(max-width: 640px) 13rem, 18rem",
|
|
24
|
+
},
|
|
25
|
+
}
|
|
15
26
|
---
|
|
16
27
|
|
|
17
28
|
<div
|
|
@@ -19,10 +30,10 @@ const isPortraitImage = image.height > image.width
|
|
|
19
30
|
class:list={style === "book" ? "rounded-sm" : "rounded-md"}
|
|
20
31
|
>
|
|
21
32
|
<Image
|
|
22
|
-
class:list={
|
|
33
|
+
class:list={imageSizes[size].css}
|
|
23
34
|
alt=""
|
|
24
35
|
widths={[256, 512, 768, 1024]}
|
|
25
|
-
sizes=
|
|
36
|
+
sizes={imageSizes[size].query}
|
|
26
37
|
src={image}
|
|
27
38
|
quality="high"
|
|
28
39
|
loading="eager"
|
|
@@ -4,29 +4,13 @@ import { useEffect, useMemo, useRef, useState } from "react"
|
|
|
4
4
|
import type { SearchItem, SearchResponse } from "../../api/search-response"
|
|
5
5
|
import { observeSearchQuery, type SearchQuery } from "../utils/search-query"
|
|
6
6
|
|
|
7
|
-
declare global {
|
|
8
|
-
interface Window {
|
|
9
|
-
lnSearchState?: {
|
|
10
|
-
fuse: Fuse<SearchItem>
|
|
11
|
-
items: SearchItem[]
|
|
12
|
-
locale?: string
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
7
|
interface Context {
|
|
18
8
|
categories: Record<string, string>
|
|
19
9
|
mediaTypes: Record<string, { name: string }>
|
|
20
10
|
languages: Record<string, { name: string }>
|
|
21
|
-
currentLocale?: string
|
|
22
11
|
}
|
|
23
12
|
|
|
24
|
-
export function useSearch({
|
|
25
|
-
currentLocale,
|
|
26
|
-
categories,
|
|
27
|
-
mediaTypes,
|
|
28
|
-
languages,
|
|
29
|
-
}: Context) {
|
|
13
|
+
export function useSearch({ categories, mediaTypes, languages }: Context) {
|
|
30
14
|
const fuse = useRef<Fuse<SearchItem>>(undefined)
|
|
31
15
|
const [allItems, setAllItems] = useState<SearchItem[]>([])
|
|
32
16
|
const [isLoading, setIsLoading] = useState(true)
|
|
@@ -83,27 +67,12 @@ export function useSearch({
|
|
|
83
67
|
ignoreLocation: true,
|
|
84
68
|
})
|
|
85
69
|
setAllItems(items)
|
|
86
|
-
window.lnSearchState = {
|
|
87
|
-
locale: currentLocale,
|
|
88
|
-
items,
|
|
89
|
-
fuse: fuse.current,
|
|
90
|
-
}
|
|
91
70
|
} catch (error) {
|
|
92
71
|
console.error(error)
|
|
93
72
|
}
|
|
94
73
|
setIsLoading(false)
|
|
95
74
|
}
|
|
96
|
-
|
|
97
|
-
// locale is still the same because we add translated values to the
|
|
98
|
-
// search index
|
|
99
|
-
const { lnSearchState } = window
|
|
100
|
-
if (lnSearchState && lnSearchState.locale === currentLocale) {
|
|
101
|
-
fuse.current = lnSearchState.fuse
|
|
102
|
-
setAllItems(lnSearchState.items)
|
|
103
|
-
setIsLoading(false)
|
|
104
|
-
} else {
|
|
105
|
-
fetchData()
|
|
106
|
-
}
|
|
75
|
+
fetchData()
|
|
107
76
|
return removeSearchQueryObserver
|
|
108
77
|
}, [])
|
|
109
78
|
|
package/src/utils/paths.ts
CHANGED
|
@@ -21,12 +21,26 @@ export function detailsPagePath(
|
|
|
21
21
|
*/
|
|
22
22
|
export function searchPagePath(
|
|
23
23
|
locale: string | undefined,
|
|
24
|
-
filter?: {
|
|
24
|
+
filter?: {
|
|
25
|
+
category?: string
|
|
26
|
+
language?: string
|
|
27
|
+
search?: string
|
|
28
|
+
type?: string
|
|
29
|
+
},
|
|
25
30
|
) {
|
|
26
31
|
const searchParams = new URLSearchParams()
|
|
27
32
|
if (filter?.category) {
|
|
28
33
|
searchParams.append("category", filter.category)
|
|
29
34
|
}
|
|
35
|
+
if (filter?.language) {
|
|
36
|
+
searchParams.append("language", filter.language)
|
|
37
|
+
}
|
|
38
|
+
if (filter?.search) {
|
|
39
|
+
searchParams.append("search", filter.search)
|
|
40
|
+
}
|
|
41
|
+
if (filter?.type) {
|
|
42
|
+
searchParams.append("type", filter.type)
|
|
43
|
+
}
|
|
30
44
|
const query = searchParams.size ? `?${searchParams.toString()}` : ""
|
|
31
45
|
return `/${locale}/media${query}`
|
|
32
46
|
}
|