lightnet 3.4.6 → 3.6.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 (65) hide show
  1. package/CHANGELOG.md +67 -10
  2. package/__e2e__/fixtures/basics/node_modules/.bin/astro +2 -2
  3. package/__e2e__/fixtures/basics/package.json +2 -2
  4. package/exports/components.ts +2 -0
  5. package/exports/content.ts +13 -3
  6. package/package.json +8 -7
  7. package/src/astro-integration/config.ts +6 -3
  8. package/src/components/CategoriesSection.astro +69 -19
  9. package/src/components/HeroSection.astro +15 -7
  10. package/src/components/HighlightSection.astro +1 -1
  11. package/src/components/MediaGallery.astro +2 -2
  12. package/src/components/MediaList.astro +2 -2
  13. package/src/components/SearchInput.astro +30 -0
  14. package/src/components/SearchSection.astro +16 -0
  15. package/src/components/Section.astro +20 -4
  16. package/src/content/astro-image.ts +10 -0
  17. package/src/content/compare-media-collection-items.ts +1 -1
  18. package/src/content/content-schema.ts +38 -6
  19. package/src/content/get-categories.ts +64 -6
  20. package/src/content/get-media-items.ts +1 -1
  21. package/src/content/get-media-types.ts +1 -1
  22. package/src/content/query-media-items.ts +1 -1
  23. package/src/i18n/translations/TRANSLATION-STATUS.md +33 -1
  24. package/src/i18n/translations/ar.yml +22 -0
  25. package/src/i18n/translations/bn.yml +22 -0
  26. package/src/i18n/translations/de.yml +1 -2
  27. package/src/i18n/translations/en.yml +3 -8
  28. package/src/i18n/translations/es.yml +22 -0
  29. package/src/i18n/translations/fi.yml +22 -0
  30. package/src/i18n/translations/fr.yml +22 -0
  31. package/src/i18n/translations/hi.yml +22 -0
  32. package/src/i18n/translations/pt.yml +22 -0
  33. package/src/i18n/translations/ru.yml +1 -2
  34. package/src/i18n/translations/uk.yml +1 -2
  35. package/src/i18n/translations/zh.yml +22 -0
  36. package/src/i18n/translations.ts +10 -3
  37. package/src/layouts/MarkdownPage.astro +7 -1
  38. package/src/layouts/Page.astro +1 -0
  39. package/src/layouts/components/PageNavigation.astro +13 -7
  40. package/src/pages/api/search.ts +1 -1
  41. package/src/pages/details-page/components/main-details/AudioPlayer.astro +1 -1
  42. package/src/pages/details-page/components/main-details/Cover.astro +1 -0
  43. package/src/pages/details-page/components/main-details/Title.astro +1 -1
  44. package/src/pages/details-page/components/more-details/Categories.astro +11 -4
  45. package/src/pages/details-page/utils/get-collection-items.ts +1 -1
  46. package/src/pages/search-page/SearchPageRoute.astro +10 -40
  47. package/src/pages/search-page/components/LoadingSkeleton.tsx +19 -0
  48. package/src/pages/search-page/components/SearchFilter.astro +65 -0
  49. package/src/pages/search-page/components/SearchFilter.tsx +33 -84
  50. package/src/pages/search-page/components/SearchList.astro +50 -0
  51. package/src/pages/search-page/components/SearchList.tsx +117 -0
  52. package/src/pages/search-page/components/SearchListItem.tsx +105 -0
  53. package/src/pages/search-page/components/Select.tsx +5 -5
  54. package/src/pages/search-page/hooks/use-search-query-param.ts +31 -0
  55. package/src/pages/search-page/hooks/use-search.ts +103 -49
  56. package/src/pages/search-page/utils/search-filter-translations.ts +20 -0
  57. package/src/pages/search-page/utils/search-query.ts +76 -0
  58. package/src/pages/search-page/utils/search-translations.ts +1 -12
  59. package/src/content/content-schema-internal.ts +0 -52
  60. package/src/content/external-api.ts +0 -7
  61. package/src/content/resolve-category-label.ts +0 -20
  62. package/src/pages/search-page/Search.tsx +0 -71
  63. package/src/pages/search-page/components/ResultList.tsx +0 -135
  64. package/src/pages/search-page/types.ts +0 -11
  65. package/src/pages/search-page/utils/use-provided-translations.ts +0 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,72 @@
1
1
  # lightnet
2
2
 
3
+ ## 3.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#280](https://github.com/LightNetDev/LightNet/pull/280) [`b7a9fea`](https://github.com/LightNetDev/LightNet/commit/b7a9fea1b599458838ae96866ee0910f93b6f56e) Thanks [@smn-cds](https://github.com/smn-cds)! - Feature: Category Image Grid Enhancement
8
+ - Introduced an optional `image` property for categories, allowing for enhanced visual representation.
9
+ - Updated the `CategorySection` component to support the display of category images.
10
+ - To utilize this feature, set the `layout` attribute to `image-grid`, enabling a visually appealing grid layout for category images.
11
+
12
+ - [#275](https://github.com/LightNetDev/LightNet/pull/275) [`d4bc7d4`](https://github.com/LightNetDev/LightNet/commit/d4bc7d4888b1282d9809e2451f7d867961d2dc07) Thanks [@sayedtenkanen](https://github.com/sayedtenkanen)! - Add Finnish translation
13
+
14
+ - [#281](https://github.com/LightNetDev/LightNet/pull/281) [`ed115b6`](https://github.com/LightNetDev/LightNet/commit/ed115b6a515cb22dfbf644103025c5ceb06cef1d) Thanks [@ajjn](https://github.com/ajjn)! - Add translation files for Arabic, Chinese, French, Spanish, Hindi, Bengali, and Portuguese
15
+
16
+ - [#280](https://github.com/LightNetDev/LightNet/pull/280) [`b7a9fea`](https://github.com/LightNetDev/LightNet/commit/b7a9fea1b599458838ae96866ee0910f93b6f56e) Thanks [@smn-cds](https://github.com/smn-cds)! - Improve MarkdownPage
17
+ - add rounded corners for images for more consistency with other images on LightNet
18
+ - add `className` property to apply your own classes to the component
19
+
20
+ - [#280](https://github.com/LightNetDev/LightNet/pull/280) [`b7a9fea`](https://github.com/LightNetDev/LightNet/commit/b7a9fea1b599458838ae96866ee0910f93b6f56e) Thanks [@smn-cds](https://github.com/smn-cds)! - Add reusable SearchInput component
21
+
22
+ ### Patch Changes
23
+
24
+ - [#280](https://github.com/LightNetDev/LightNet/pull/280) [`b7a9fea`](https://github.com/LightNetDev/LightNet/commit/b7a9fea1b599458838ae96866ee0910f93b6f56e) Thanks [@smn-cds](https://github.com/smn-cds)! - Improve text wrap behavior for titles by setting `text-wrap:balance`
25
+
26
+ - [#280](https://github.com/LightNetDev/LightNet/pull/280) [`b7a9fea`](https://github.com/LightNetDev/LightNet/commit/b7a9fea1b599458838ae96866ee0910f93b6f56e) Thanks [@smn-cds](https://github.com/smn-cds)! - Update translations: Remove ellipsis from search placeholder
27
+
28
+ ## 3.5.0
29
+
30
+ ### Minor Changes
31
+
32
+ - [#273](https://github.com/LightNetDev/LightNet/pull/273) [`5b0b24f`](https://github.com/LightNetDev/LightNet/commit/5b0b24f58a6b8df8a3bc7dc66b751981f4e0498e) Thanks [@smn-cds](https://github.com/smn-cds)! - Add `disableHorizontalPadding` option to `Section` component.
33
+
34
+ - [#273](https://github.com/LightNetDev/LightNet/pull/273) [`5b0b24f`](https://github.com/LightNetDev/LightNet/commit/5b0b24f58a6b8df8a3bc7dc66b751981f4e0498e) Thanks [@smn-cds](https://github.com/smn-cds)! - Add lightnet config option `searchPage.hideHeaderSearchIcon`
35
+
36
+ Set to true, this will remove the search magnifier icon from the header bar. For example this option can
37
+ be useful if a site directly provides the search on the homepage.
38
+
39
+ - [#273](https://github.com/LightNetDev/LightNet/pull/273) [`5b0b24f`](https://github.com/LightNetDev/LightNet/commit/5b0b24f58a6b8df8a3bc7dc66b751981f4e0498e) Thanks [@smn-cds](https://github.com/smn-cds)! - Implement infinite scroll for search results.
40
+
41
+ - [#273](https://github.com/LightNetDev/LightNet/pull/273) [`5b0b24f`](https://github.com/LightNetDev/LightNet/commit/5b0b24f58a6b8df8a3bc7dc66b751981f4e0498e) Thanks [@smn-cds](https://github.com/smn-cds)! - Add `SearchSection` component.
42
+
43
+ Add the search to your homepage as simple as:
44
+
45
+ ```astro
46
+ ---
47
+ import { Page, SearchSection } from "lightnet/components"
48
+ ---
49
+
50
+ <Page>
51
+ <SearchSection />
52
+ </Page>
53
+ ```
54
+
55
+ - [#273](https://github.com/LightNetDev/LightNet/pull/273) [`5b0b24f`](https://github.com/LightNetDev/LightNet/commit/5b0b24f58a6b8df8a3bc7dc66b751981f4e0498e) Thanks [@smn-cds](https://github.com/smn-cds)! - Add optional search input to `HeroSection`.
56
+
57
+ Enable it by setting the HeroSection's `showSearch` property to `true`.
58
+ By default `showSearch` is set to `false`.
59
+
60
+ - [#273](https://github.com/LightNetDev/LightNet/pull/273) [`5b0b24f`](https://github.com/LightNetDev/LightNet/commit/5b0b24f58a6b8df8a3bc7dc66b751981f4e0498e) Thanks [@smn-cds](https://github.com/smn-cds)! - Add fields to search index
61
+
62
+ The search text input also searches language, type and categories of a media item in the current site language.
63
+
64
+ Pro tip: Search for "theology | book" to find theology books. The [extended search syntax](https://www.fusejs.io/examples.html#extended-search) can do even more...
65
+
66
+ - [#273](https://github.com/LightNetDev/LightNet/pull/273) [`5b0b24f`](https://github.com/LightNetDev/LightNet/commit/5b0b24f58a6b8df8a3bc7dc66b751981f4e0498e) Thanks [@smn-cds](https://github.com/smn-cds)! - Update Translations
67
+ - remove `ln.search.more-results`. Because search now uses infinite scroll there is no need for this button label anymore 🎉.
68
+ - change value of `ln.search.placeholder` from "Search by title, author or description..." to "Search media...". Search now also searches on categories, type, language and id of a media item.
69
+
3
70
  ## 3.4.6
4
71
 
5
72
  ### Patch Changes
@@ -37,7 +104,6 @@
37
104
  ### Patch Changes
38
105
 
39
106
  - [#254](https://github.com/LightNetDev/LightNet/pull/254) [`46c0f7c`](https://github.com/LightNetDev/LightNet/commit/46c0f7c693a46a7a2e06e72c4a333368aa8f7485) Thanks [@smn-cds](https://github.com/smn-cds)! - Improve responsive image variants:
40
-
41
107
  - Improve image quality on search result items
42
108
  - Limit the size of the media list image
43
109
  - Streamline details page cover image variants
@@ -120,7 +186,6 @@
120
186
  - [#234](https://github.com/LightNetDev/LightNet/pull/234) [`1cb0dc0`](https://github.com/LightNetDev/LightNet/commit/1cb0dc0ef2d7a3ecb5d2a37a36f2f2e8fa97a756) Thanks [@smn-cds](https://github.com/smn-cds)! - Renames custom details pages prop `slug` to `mediaId`.
121
187
 
122
188
  - [#234](https://github.com/LightNetDev/LightNet/pull/234) [`1cb0dc0`](https://github.com/LightNetDev/LightNet/commit/1cb0dc0ef2d7a3ecb5d2a37a36f2f2e8fa97a756) Thanks [@smn-cds](https://github.com/smn-cds)! - Streamline handling of components. Make sure all components including a section are suffixed with `Section`.
123
-
124
189
  - Removes `Gallery` export
125
190
  - Adds `MediaGallerySection` that includes the section component
126
191
  - Renames `Hero` to `HeroSection`
@@ -128,7 +193,6 @@
128
193
  - Renames `MediaItemList` to `MediaList`
129
194
 
130
195
  - [#234](https://github.com/LightNetDev/LightNet/pull/234) [`1cb0dc0`](https://github.com/LightNetDev/LightNet/commit/1cb0dc0ef2d7a3ecb5d2a37a36f2f2e8fa97a756) Thanks [@smn-cds](https://github.com/smn-cds)! - Improve Section
131
-
132
196
  - rename maxWidth values: `full` => `wide`, `prose` => `narrow`
133
197
  - add marginTop settings: `none`, `sm`, `lg`
134
198
 
@@ -159,7 +223,6 @@
159
223
  ### Minor Changes
160
224
 
161
225
  - [#228](https://github.com/LightNetDev/LightNet/pull/228) [`b3bb5cc`](https://github.com/LightNetDev/LightNet/commit/b3bb5cc97a4f14ccb46c68f9dcdbe73d74563452) Thanks [@smn-cds](https://github.com/smn-cds)! - Add builtin languages
162
-
163
226
  - Russian
164
227
  - Ukrainian
165
228
 
@@ -186,7 +249,6 @@
186
249
  ### Minor Changes
187
250
 
188
251
  - [#220](https://github.com/LightNetDev/LightNet/pull/220) [`e10c96f`](https://github.com/LightNetDev/LightNet/commit/e10c96fb850db6d043c9bc0c929170c271979492) Thanks [@smn-cds](https://github.com/smn-cds)! - Update Tailwind CSS to v4
189
-
190
252
  - updates `tailwindcss` dependency to version ^4.
191
253
  - `@astro/tailwindcss` dependency has been replaced with `@tailwindcss/vite`
192
254
  - removes the use of `tailwind.config.js` inside site projects
@@ -224,7 +286,6 @@
224
286
  This update introduces major changes on our translation system.
225
287
 
226
288
  Changes:
227
-
228
289
  - Translations are now stored inside `.yml` files.
229
290
  - Added i18next as our translation engine
230
291
  - Translations now support a flat i18next syntax including (pluralization, contextualization, interpolation)
@@ -292,7 +353,6 @@
292
353
  - [#183](https://github.com/LightNetDev/lightnet/pull/183) [`9c0bb8d`](https://github.com/LightNetDev/lightnet/commit/9c0bb8d2508f8bfbb18dd224a36e7f5d75f89268) Thanks [@smn-cds](https://github.com/si-fab)! - Makes logo config optional.
293
354
 
294
355
  - [#183](https://github.com/LightNetDev/lightnet/pull/183) [`9c0bb8d`](https://github.com/LightNetDev/lightnet/commit/9c0bb8d2508f8bfbb18dd224a36e7f5d75f89268) Thanks [@smn-cds](https://github.com/si-fab)! - Rename `Section` component properties
295
-
296
356
  - change property name `width` to `maxWidth`
297
357
  - change property value `content` to `prose`
298
358
 
@@ -305,7 +365,6 @@
305
365
  Prefixing custom translation strings with `custom.` is non mandatory but recommended as it improves validation.
306
366
 
307
367
  This is changed:
308
-
309
368
  - rename translate parameter `fallbackToKey` to `allowFixedStrings`.
310
369
  - change behavior of the translate function. If `allowFixedStrings` is set to `true`, return the translation key if no translation is found. But fail if the key starts with `custom.` or `ln.` prefix.
311
370
  - change example to reflect the new convention of prefixing custom translation keys with `custom.`.
@@ -375,7 +434,6 @@
375
434
  - [#176](https://github.com/LightNetDev/lightnet/pull/176) [`6b4a664`](https://github.com/LightNetDev/lightnet/commit/6b4a66490079b0688577e6052ab9d7f2d0686170) Thanks [@smn-cds](https://github.com/si-fab)! - Extend Astro.locals.i18n object
376
435
 
377
436
  Provide:
378
-
379
437
  - `defaultLocale`
380
438
  - `currentLocale`
381
439
  - `locales`
@@ -396,7 +454,6 @@
396
454
  - [#174](https://github.com/LightNetDev/lightnet/pull/174) [`bb011bf`](https://github.com/LightNetDev/lightnet/commit/bb011bfef8c2d7745e3c3417f7f6ef608867e184) Thanks [@smn-cds](https://github.com/si-fab)! - Update Astro to version 5.
397
455
 
398
456
  Fix your project by doing this:
399
-
400
457
  - move `/src/content/config.ts` to `/src/content.config.ts`.
401
458
  - update tsconfig.json to match the following:
402
459
 
@@ -6,9 +6,9 @@ case `uname` in
6
6
  esac
7
7
 
8
8
  if [ -z "$NODE_PATH" ]; then
9
- export NODE_PATH="/home/runner/work/LightNet/LightNet/node_modules/.pnpm/astro@5.8.1_@types+node@22.15.29_jiti@2.4.2_lightningcss@1.29.1_rollup@4.41.1_terser@5.39.0_typescript@5.8.3_yaml@2.8.0/node_modules/astro/node_modules:/home/runner/work/LightNet/LightNet/node_modules/.pnpm/astro@5.8.1_@types+node@22.15.29_jiti@2.4.2_lightningcss@1.29.1_rollup@4.41.1_terser@5.39.0_typescript@5.8.3_yaml@2.8.0/node_modules:/home/runner/work/LightNet/LightNet/node_modules/.pnpm/node_modules"
9
+ export NODE_PATH="/home/runner/work/LightNet/LightNet/node_modules/.pnpm/astro@5.11.0_@types+node@24.0.12_jiti@2.4.2_lightningcss@1.29.1_rollup@4.44.2_terser@5.39.0_typescript@5.8.3_yaml@2.8.0/node_modules/astro/node_modules:/home/runner/work/LightNet/LightNet/node_modules/.pnpm/astro@5.11.0_@types+node@24.0.12_jiti@2.4.2_lightningcss@1.29.1_rollup@4.44.2_terser@5.39.0_typescript@5.8.3_yaml@2.8.0/node_modules:/home/runner/work/LightNet/LightNet/node_modules/.pnpm/node_modules"
10
10
  else
11
- export NODE_PATH="/home/runner/work/LightNet/LightNet/node_modules/.pnpm/astro@5.8.1_@types+node@22.15.29_jiti@2.4.2_lightningcss@1.29.1_rollup@4.41.1_terser@5.39.0_typescript@5.8.3_yaml@2.8.0/node_modules/astro/node_modules:/home/runner/work/LightNet/LightNet/node_modules/.pnpm/astro@5.8.1_@types+node@22.15.29_jiti@2.4.2_lightningcss@1.29.1_rollup@4.41.1_terser@5.39.0_typescript@5.8.3_yaml@2.8.0/node_modules:/home/runner/work/LightNet/LightNet/node_modules/.pnpm/node_modules:$NODE_PATH"
11
+ export NODE_PATH="/home/runner/work/LightNet/LightNet/node_modules/.pnpm/astro@5.11.0_@types+node@24.0.12_jiti@2.4.2_lightningcss@1.29.1_rollup@4.44.2_terser@5.39.0_typescript@5.8.3_yaml@2.8.0/node_modules/astro/node_modules:/home/runner/work/LightNet/LightNet/node_modules/.pnpm/astro@5.11.0_@types+node@24.0.12_jiti@2.4.2_lightningcss@1.29.1_rollup@4.44.2_terser@5.39.0_typescript@5.8.3_yaml@2.8.0/node_modules:/home/runner/work/LightNet/LightNet/node_modules/.pnpm/node_modules:$NODE_PATH"
12
12
  fi
13
13
  if [ -x "$basedir/node" ]; then
14
14
  exec "$basedir/node" "$basedir/../astro/astro.js" "$@"
@@ -7,8 +7,8 @@
7
7
  "@astrojs/react": "^4.3.0",
8
8
  "@astrojs/tailwind": "^6.0.2",
9
9
  "@lightnet/decap-admin": "^3.1.1",
10
- "astro": "^5.8.1",
11
- "lightnet": "^3.4.4",
10
+ "astro": "^5.11.0",
11
+ "lightnet": "^3.6.0",
12
12
  "react": "^19.1.0",
13
13
  "react-dom": "^19.1.0",
14
14
  "sharp": "^0.33.5",
@@ -4,6 +4,8 @@ export { default as HighlightSection } from "../src/components/HighlightSection.
4
4
  export { default as Icon } from "../src/components/Icon"
5
5
  export { default as MediaGallerySection } from "../src/components/MediaGallerySection.astro"
6
6
  export { default as MediaList } from "../src/components/MediaList.astro"
7
+ export { default as SearchInput } from "../src/components/SearchInput.astro"
8
+ export { default as SearchSection } from "../src/components/SearchSection.astro"
7
9
  export { default as Section } from "../src/components/Section.astro"
8
10
  export { default as VideoPlayer } from "../src/components/VideoPlayer.astro"
9
11
  export { default as MarkdownPage } from "../src/layouts/MarkdownPage.astro"
@@ -1,8 +1,18 @@
1
1
  export {
2
- categorySchema,
2
+ createCategorySchema as categorySchema,
3
3
  LIGHTNET_COLLECTIONS,
4
4
  mediaCollectionSchema,
5
- mediaSchema,
5
+ createMediaItemSchema as mediaItemSchema,
6
6
  mediaTypeSchema,
7
7
  } from "../src/content/content-schema"
8
- export { getMediaItems } from "../src/content/external-api"
8
+
9
+ import { type CollectionEntry, getCollection } from "astro:content"
10
+
11
+ import {
12
+ type MediaItemQuery,
13
+ queryMediaItems,
14
+ } from "../src/content/query-media-items"
15
+
16
+ export const getMediaItems = (
17
+ query?: MediaItemQuery<CollectionEntry<"media">>,
18
+ ) => queryMediaItems(getCollection("media"), query ?? {})
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "lightnet",
3
3
  "type": "module",
4
4
  "license": "MIT",
5
- "version": "3.4.6",
5
+ "version": "3.6.0",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/LightNetDev/lightnet",
@@ -45,17 +45,18 @@
45
45
  "@iconify-json/mdi": "^1.2.3",
46
46
  "@iconify/tailwind": "^1.2.0",
47
47
  "@tailwindcss/typography": "^0.5.16",
48
- "@types/react": "^19.1.6",
48
+ "@tanstack/react-virtual": "^3.13.12",
49
+ "@types/react": "^19.1.8",
49
50
  "daisyui": "^4.12.24",
50
51
  "fuse.js": "^7.1.0",
51
- "i18next": "^25.2.1",
52
- "marked": "^15.0.12",
52
+ "i18next": "^25.3.2",
53
+ "marked": "^16.0.0",
53
54
  "yaml": "^2.8.0"
54
55
  },
55
56
  "devDependencies": {
56
- "@playwright/test": "^1.52.0",
57
- "@types/node": "^22.15.29",
58
- "vitest": "^3.1.4"
57
+ "@playwright/test": "^1.53.2",
58
+ "@types/node": "^22.16.2",
59
+ "vitest": "^3.2.4"
59
60
  },
60
61
  "scripts": {
61
62
  "test": "vitest",
@@ -203,11 +203,14 @@ export const configSchema = z.object({
203
203
  searchPage: z
204
204
  .object({
205
205
  /**
206
- * When this is set to true, search results will be initially
207
- * filtered by site language. The filter will only be set when there
208
- * is any media item in the site language.
206
+ * Set this to true, to initially filter search results by current site language.
207
+ * The filter will only be set when there is any media item in the site language.
209
208
  */
210
209
  filterByLocale: z.boolean().default(false),
210
+ /**
211
+ * Set this to true, to remove the search magnifier icon from the header bar.
212
+ */
213
+ hideHeaderSearchIcon: z.boolean().default(false),
211
214
  })
212
215
  .optional(),
213
216
  })
@@ -1,37 +1,87 @@
1
1
  ---
2
- import { getCategories } from "../content/get-categories"
2
+ import { AstroError } from "astro/errors"
3
+ import { Image } from "astro:assets"
4
+
5
+ import { getUsedCategories } from "../content/get-categories"
3
6
  import { searchPagePath } from "../utils/paths"
4
7
  import Section from "./Section.astro"
5
8
 
6
9
  interface Props {
7
10
  title?: string
11
+ layout?: "button-grid" | "image-grid"
8
12
  }
9
13
 
10
- const { title } = Astro.props
14
+ const { title, layout = "button-grid" } = Astro.props
11
15
  const { t, currentLocale } = Astro.locals.i18n
12
16
 
13
- const categories = await getCategories(currentLocale, t)
17
+ const categories = await getUsedCategories(currentLocale, t)
18
+ type Category = (typeof categories)[number]
19
+
20
+ function getImage({ image, id }: Category) {
21
+ if (!image) {
22
+ throw new AstroError(
23
+ `The CategorySection with layout="image-grid" requires an image for category "${id}".`,
24
+ `To resolve this issue, either change the layout to "button-grid" or provide an image path in /src/content/categories/${id}.json.`,
25
+ )
26
+ }
27
+ return image
28
+ }
14
29
  ---
15
30
 
16
31
  {
17
32
  categories.length && (
18
33
  <Section title={title ?? t("ln.categories")}>
19
- <ul class="flex w-full flex-wrap gap-2 sm:gap-3">
20
- {categories.map((category) => (
21
- <li class="flex max-w-56 grow">
22
- <a
23
- class="flex h-12 w-full items-center justify-center rounded-xl bg-gray-200 p-2 px-8 shadow-sm hover:bg-gray-300 sm:h-14"
24
- href={searchPagePath(currentLocale, {
25
- category: category.id,
26
- })}
27
- >
28
- <span class="line-clamp-2 block text-xs font-bold uppercase text-gray-600">
29
- {category.name}
30
- </span>
31
- </a>
32
- </li>
33
- ))}
34
- </ul>
34
+ {layout === "button-grid" && (
35
+ <ul class="grid w-full grid-cols-2 flex-wrap gap-4 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5">
36
+ {categories.map((category) => (
37
+ <li class="grow">
38
+ <a
39
+ class="flex h-20 w-full items-center justify-center rounded-2xl bg-gray-200 p-3 text-gray-600 shadow-sm transition-colors ease-in-out hover:bg-gray-300"
40
+ href={searchPagePath(currentLocale, {
41
+ category: category.id,
42
+ })}
43
+ >
44
+ <div class="line-clamp-3 overflow-hidden text-balance text-center text-xs font-bold">
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">
61
+ <Image
62
+ class="h-full w-full object-contain"
63
+ src={getImage(category)}
64
+ alt=""
65
+ widths={[256, 512, 768, 1024]}
66
+ sizes={
67
+ "(max-width: 640px) calc(calc(100vw - 3.5rem ) / 2), " +
68
+ "(max-width: 768px) calc(calc(100vw - 5rem ) / 3), " +
69
+ "(max-width: 1024px) calc(calc(100vw - 10rem ) / 4), " +
70
+ "(max-width: 1280px) calc(calc(100vw - 12rem ) / 5), " +
71
+ "217px"
72
+ }
73
+ />
74
+ <div class="absolute start-0 top-0 flex h-full w-full flex-col justify-end bg-gradient-to-t from-black/80 via-black/35 via-30% to-transparent to-65% p-4 text-gray-50">
75
+ <span class="line-clamp-3 text-balance font-bold">
76
+ {category.name}
77
+ </span>
78
+ </div>
79
+ </div>
80
+ </a>
81
+ </li>
82
+ ))}
83
+ </ol>
84
+ )}
35
85
  </Section>
36
86
  )
37
87
  }
@@ -2,6 +2,8 @@
2
2
  import type { ImageMetadata } from "astro"
3
3
  import { Image } from "astro:assets"
4
4
 
5
+ import SearchInput from "./SearchInput.astro"
6
+
5
7
  interface Props {
6
8
  image: ImageMetadata
7
9
  title?: string
@@ -11,6 +13,7 @@ interface Props {
11
13
  subtitleSize?: "sm" | "md" | "lg" | "xl"
12
14
  subtitleClass?: string
13
15
  className?: string
16
+ showSearch?: boolean
14
17
  }
15
18
  const {
16
19
  image,
@@ -21,6 +24,7 @@ const {
21
24
  titleClass,
22
25
  subtitleClass,
23
26
  className,
27
+ showSearch = false,
24
28
  } = Astro.props
25
29
 
26
30
  const titleSizes = {
@@ -41,21 +45,20 @@ const subtitleSizes = {
41
45
  <div class="w-full">
42
46
  <div class="group relative">
43
47
  <Image
44
- class="h-72 w-full object-cover object-center md:h-[20rem] lg:h-[24rem] xl:h-[30rem]"
48
+ class="h-[20rem] w-full object-cover object-center lg:h-[24rem] xl:h-[30rem]"
45
49
  src={image}
46
- widths={[320, 768, 1280, 2560, 3000]}
47
- sizes="100vw"
48
- loading="eager"
50
+ layout="full-width"
51
+ priority={true}
49
52
  alt=""
50
53
  />
51
54
  <div
52
- class="bg-gradient-radial absolute top-0 flex h-full w-full flex-col items-center justify-center gap-6 from-black/30 to-black/40 p-4 text-center text-gray-50"
55
+ class="bg-gradient-radial absolute top-0 flex h-full w-full flex-col items-center justify-center from-black/30 to-black/40 p-4 text-center text-gray-50"
53
56
  class:list={[className]}
54
57
  >
55
58
  {
56
59
  title && (
57
60
  <h1
58
- class="max-w-screen-md font-bold transition-transform duration-1000 group-hover:scale-[102%]"
61
+ class="max-w-screen-md text-balance font-bold tracking-tight transition-transform duration-1000 group-hover:scale-[102%]"
59
62
  class:list={[titleSizes[titleSize], titleClass]}
60
63
  >
61
64
  {title}
@@ -65,7 +68,7 @@ const subtitleSizes = {
65
68
  {
66
69
  subtitle && (
67
70
  <p
68
- class="max-w-screen-sm font-bold"
71
+ class="mt-1 max-w-screen-sm text-balance font-bold md:mt-2"
69
72
  class:list={[
70
73
  "sm:text-lg md:text-2xl",
71
74
  subtitleSizes[subtitleSize],
@@ -76,6 +79,11 @@ const subtitleSizes = {
76
79
  </p>
77
80
  )
78
81
  }
82
+ {
83
+ showSearch && (
84
+ <SearchInput className="mt-6 max-w-sm md:mt-10 md:max-w-md" />
85
+ )
86
+ }
79
87
  <slot />
80
88
  </div>
81
89
  </div>
@@ -36,7 +36,7 @@ const { image, id, title, text, link, className, titleClass, textClass } =
36
36
  {
37
37
  title && (
38
38
  <h2
39
- class="mb-4 text-2xl font-bold sm:mb-8 sm:text-3xl"
39
+ class="mb-4 text-balance text-2xl font-bold sm:mb-8 sm:text-3xl"
40
40
  class:list={titleClass}
41
41
  >
42
42
  {title}
@@ -65,7 +65,7 @@ const items = itemsInput.filter((item) => !!item)
65
65
  <span class="absolute start-[3px] top-0 h-full w-[4px] bg-gradient-to-r from-gray-500/20 to-transparent" />
66
66
  )}
67
67
  </div>
68
- <span class="line-clamp-2 h-12 text-sm font-bold text-gray-700">
68
+ <span class="line-clamp-2 h-12 text-balance text-sm font-bold text-gray-700">
69
69
  <Icon
70
70
  className={`${types[item.data.type.id].icon} me-2 align-bottom`}
71
71
  ariaLabel={types[item.data.type.id].name}
@@ -109,7 +109,7 @@ const items = itemsInput.filter((item) => !!item)
109
109
  }
110
110
  />
111
111
  </div>
112
- <span class="line-clamp-2 h-12 text-sm font-bold text-gray-700">
112
+ <span class="line-clamp-2 h-12 text-balance text-sm font-bold text-gray-700">
113
113
  <Icon
114
114
  className={`${types[item.data.type.id].icon} me-2 align-bottom`}
115
115
  ariaLabel={types[item.data.type.id].name}
@@ -71,14 +71,14 @@ const mediaTypes = Object.fromEntries(
71
71
  class="ms-5 flex grow flex-col justify-center sm:ms-8"
72
72
  lang={item.data.language}
73
73
  >
74
- <p class="mb-1 line-clamp-3 font-bold text-gray-700 md:mb-3">
74
+ <p class="mb-1 line-clamp-3 text-balance font-bold text-gray-700 md:mb-3">
75
75
  <Icon
76
76
  className={`${mediaTypes[item.data.type.id].icon} me-2 align-bottom text-2xl text-gray-700`}
77
77
  ariaLabel={mediaTypes[item.data.type.id].name}
78
78
  />
79
79
  <span>{item.data.title}</span>
80
80
  </p>
81
- <div class="mb-3 flex flex-col flex-wrap items-start gap-2 md:flex-row md:items-center md:gap-3">
81
+ <div class="mb-3 flex flex-col flex-wrap items-start gap-2 text-balance md:flex-row md:items-center md:gap-3">
82
82
  {!!item.data.authors?.length && (
83
83
  <p class="mb-1 md:mb-0 md:text-base">
84
84
  {item.data.authors.join(", ")}
@@ -0,0 +1,30 @@
1
+ ---
2
+ import Icon from "./Icon"
3
+
4
+ type Props = {
5
+ className?: string
6
+ }
7
+
8
+ const { t } = Astro.locals.i18n
9
+ ---
10
+
11
+ <form
12
+ action={`/${Astro.currentLocale}/media`}
13
+ method="get"
14
+ class="dy-join group w-full rounded-2xl shadow-md outline-2 outline-offset-2 outline-gray-400 group-focus-within:outline"
15
+ class:list={[Astro.props.className]}
16
+ >
17
+ <input
18
+ class="dy-input dy-join-item grow rounded-2xl bg-gray-100/95 text-gray-900 placeholder-gray-500 shadow-inner focus:outline-none"
19
+ enterkeyhint="search"
20
+ type="search"
21
+ name="search"
22
+ placeholder={t("ln.search.placeholder")}
23
+ />
24
+ <button
25
+ type="submit"
26
+ class="dy-btn dy-join-item rounded-2xl border-gray-100/95 bg-gray-800 text-gray-50 hover:bg-gray-950 hover:text-gray-300"
27
+ >
28
+ <Icon className="mdi--magnify" ariaLabel={t("ln.search.title")} />
29
+ </button>
30
+ </form>
@@ -0,0 +1,16 @@
1
+ ---
2
+ import SearchFilter from "../pages/search-page/components/SearchFilter.astro"
3
+ import SearchList from "../pages/search-page/components/SearchList.astro"
4
+ import Section, { type Props as SectionProps } from "./Section.astro"
5
+
6
+ // we need the semi-colon for the astro compiler :(
7
+ // prettier-ignore
8
+ type Props = Omit<SectionProps, "disableHorizontalPadding" | "maxWidth">;
9
+ ---
10
+
11
+ <Section {...Astro.props} disableHorizontalPadding={true} maxWidth="narrow">
12
+ <div class="px-4 md:px-8">
13
+ <SearchFilter />
14
+ </div>
15
+ <SearchList />
16
+ </Section>
@@ -1,5 +1,5 @@
1
1
  ---
2
- interface Props {
2
+ export interface Props {
3
3
  /**
4
4
  * Id to set to the section element.
5
5
  * For example this can be used to reference it inside anchors.
@@ -21,6 +21,13 @@ interface Props {
21
21
  * @default "lg"
22
22
  */
23
23
  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
24
31
  /**
25
32
  * Title on top of the section.
26
33
  */
@@ -35,6 +42,7 @@ const {
35
42
  id,
36
43
  maxWidth = "wide",
37
44
  marginTop = "lg",
45
+ disableHorizontalPadding = false,
38
46
  title,
39
47
  className,
40
48
  } = Astro.props
@@ -52,13 +60,21 @@ const marginTopValues = {
52
60
  ---
53
61
 
54
62
  <section
55
- class="mx-auto px-4 md:px-8"
56
- class:list={[maxWidths[maxWidth], marginTopValues[marginTop], className]}
63
+ class="mx-auto"
64
+ class:list={[
65
+ maxWidths[maxWidth],
66
+ marginTopValues[marginTop],
67
+ !disableHorizontalPadding && "px-4 md:px-8",
68
+ className,
69
+ ]}
57
70
  id={id}
58
71
  >
59
72
  {
60
73
  title && (
61
- <h2 class="mb-10 text-2xl font-bold text-gray-700 sm:mb-12 sm:text-3xl">
74
+ <h2
75
+ class="mb-10 text-balance text-2xl font-bold text-gray-700 sm:mb-12 sm:text-3xl"
76
+ class:list={[disableHorizontalPadding && "px-4 md:px-8"]}
77
+ >
62
78
  {title}
63
79
  </h2>
64
80
  )
@@ -12,3 +12,13 @@ export const astroImage = (image: ImageFunction) =>
12
12
  .string()
13
13
  .transform((path) => (path.startsWith("./") ? path : `./${path}`))
14
14
  .pipe(image())
15
+
16
+ /**
17
+ * The Astro image function resolves to this schema.
18
+ */
19
+ export const imageSchema = z.object({
20
+ src: z.string(),
21
+ width: z.number(),
22
+ height: z.number(),
23
+ format: z.enum(["png", "jpg", "jpeg", "tiff", "webp", "gif", "svg", "avif"]),
24
+ })
@@ -1,4 +1,4 @@
1
- import type { MediaItemEntry } from "./content-schema-internal"
1
+ import type { MediaItemEntry } from "./content-schema"
2
2
 
3
3
  export function compareMediaCollectionItems(
4
4
  item1: MediaItemEntry,