@prezly/theme-kit-nextjs 1.6.2 → 1.6.4-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 (95) hide show
  1. package/README.md +30 -0
  2. package/build/adapter-nextjs/processRequest.js +3 -1
  3. package/build/adapter-nextjs/processRequest.js.map +1 -1
  4. package/build/components-nextjs/PageSeo/PageSeo.d.ts +12 -0
  5. package/build/components-nextjs/PageSeo/PageSeo.js +89 -0
  6. package/build/components-nextjs/PageSeo/PageSeo.js.map +1 -0
  7. package/build/components-nextjs/PageSeo/index.d.ts +2 -0
  8. package/build/components-nextjs/PageSeo/index.js +17 -0
  9. package/build/components-nextjs/PageSeo/index.js.map +1 -0
  10. package/build/components-nextjs/PageSeo/lib/getAbsoluteUrl.d.ts +1 -0
  11. package/build/components-nextjs/PageSeo/lib/getAbsoluteUrl.js +11 -0
  12. package/build/components-nextjs/PageSeo/lib/getAbsoluteUrl.js.map +1 -0
  13. package/build/components-nextjs/PageSeo/lib/types.d.ts +4 -0
  14. package/build/components-nextjs/PageSeo/lib/types.js +3 -0
  15. package/build/components-nextjs/PageSeo/lib/types.js.map +1 -0
  16. package/build/components-nextjs/Sitemap/SitemapBuilder.d.ts +11 -0
  17. package/build/components-nextjs/Sitemap/SitemapBuilder.js +51 -0
  18. package/build/components-nextjs/Sitemap/SitemapBuilder.js.map +1 -0
  19. package/build/components-nextjs/Sitemap/createPaths.d.ts +2 -0
  20. package/build/components-nextjs/Sitemap/createPaths.js +50 -0
  21. package/build/components-nextjs/Sitemap/createPaths.js.map +1 -0
  22. package/build/components-nextjs/Sitemap/getInitialProps.d.ts +2 -0
  23. package/build/components-nextjs/Sitemap/getInitialProps.js +78 -0
  24. package/build/components-nextjs/Sitemap/getInitialProps.js.map +1 -0
  25. package/build/components-nextjs/Sitemap/index.d.ts +4 -0
  26. package/build/components-nextjs/Sitemap/index.js +21 -0
  27. package/build/components-nextjs/Sitemap/index.js.map +1 -0
  28. package/build/components-nextjs/Sitemap/types.d.ts +5 -0
  29. package/build/components-nextjs/Sitemap/types.js +3 -0
  30. package/build/components-nextjs/Sitemap/types.js.map +1 -0
  31. package/build/components-nextjs/StorySeo/StorySeo.d.ts +11 -0
  32. package/build/components-nextjs/StorySeo/StorySeo.js +47 -0
  33. package/build/components-nextjs/StorySeo/StorySeo.js.map +1 -0
  34. package/build/components-nextjs/StorySeo/index.d.ts +1 -0
  35. package/build/components-nextjs/StorySeo/index.js +6 -0
  36. package/build/components-nextjs/StorySeo/index.js.map +1 -0
  37. package/build/components-nextjs/index.d.ts +3 -0
  38. package/build/components-nextjs/index.js +19 -0
  39. package/build/components-nextjs/index.js.map +1 -0
  40. package/build/data-fetching/lib/getEnvVariables.d.ts +1 -1
  41. package/build/data-fetching/lib/getEnvVariables.js.map +1 -1
  42. package/build/index.d.ts +2 -0
  43. package/build/index.js +2 -0
  44. package/build/index.js.map +1 -1
  45. package/build/infinite-loading/apiHandlers/fetchGalleries.d.ts +2 -0
  46. package/build/infinite-loading/apiHandlers/fetchGalleries.js +73 -0
  47. package/build/infinite-loading/apiHandlers/fetchGalleries.js.map +1 -0
  48. package/build/infinite-loading/apiHandlers/fetchStories.d.ts +2 -0
  49. package/build/infinite-loading/apiHandlers/fetchStories.js +75 -0
  50. package/build/infinite-loading/apiHandlers/fetchStories.js.map +1 -0
  51. package/build/infinite-loading/apiHandlers/index.d.ts +2 -0
  52. package/build/infinite-loading/apiHandlers/index.js +8 -0
  53. package/build/infinite-loading/apiHandlers/index.js.map +1 -0
  54. package/build/infinite-loading/index.d.ts +5 -0
  55. package/build/infinite-loading/index.js +22 -0
  56. package/build/infinite-loading/index.js.map +1 -0
  57. package/build/infinite-loading/types.d.ts +5 -0
  58. package/build/infinite-loading/types.js +3 -0
  59. package/build/infinite-loading/types.js.map +1 -0
  60. package/build/infinite-loading/useInfiniteGalleriesLoading.d.ts +13 -0
  61. package/build/infinite-loading/useInfiniteGalleriesLoading.js +98 -0
  62. package/build/infinite-loading/useInfiniteGalleriesLoading.js.map +1 -0
  63. package/build/infinite-loading/useInfiniteLoading.d.ts +16 -0
  64. package/build/infinite-loading/useInfiniteLoading.js +115 -0
  65. package/build/infinite-loading/useInfiniteLoading.js.map +1 -0
  66. package/build/infinite-loading/useInfiniteStoriesLoading.d.ts +13 -0
  67. package/build/infinite-loading/useInfiniteStoriesLoading.js +116 -0
  68. package/build/infinite-loading/useInfiniteStoriesLoading.js.map +1 -0
  69. package/build/intl/locale.js +4 -3
  70. package/build/intl/locale.js.map +1 -1
  71. package/package.json +6 -3
  72. package/src/adapter-nextjs/processRequest.ts +3 -1
  73. package/src/components-nextjs/PageSeo/PageSeo.tsx +123 -0
  74. package/src/components-nextjs/PageSeo/index.ts +2 -0
  75. package/src/components-nextjs/PageSeo/lib/getAbsoluteUrl.ts +7 -0
  76. package/src/components-nextjs/PageSeo/lib/types.ts +4 -0
  77. package/src/components-nextjs/Sitemap/SitemapBuilder.ts +56 -0
  78. package/src/components-nextjs/Sitemap/createPaths.ts +21 -0
  79. package/src/components-nextjs/Sitemap/getInitialProps.ts +37 -0
  80. package/src/components-nextjs/Sitemap/index.ts +5 -0
  81. package/src/components-nextjs/Sitemap/types.ts +5 -0
  82. package/src/components-nextjs/StorySeo/StorySeo.tsx +68 -0
  83. package/src/components-nextjs/StorySeo/index.ts +1 -0
  84. package/src/components-nextjs/index.ts +3 -0
  85. package/src/data-fetching/lib/getEnvVariables.ts +5 -3
  86. package/src/index.ts +2 -0
  87. package/src/infinite-loading/apiHandlers/fetchGalleries.ts +24 -0
  88. package/src/infinite-loading/apiHandlers/fetchStories.ts +26 -0
  89. package/src/infinite-loading/apiHandlers/index.ts +2 -0
  90. package/src/infinite-loading/index.ts +5 -0
  91. package/src/infinite-loading/types.ts +5 -0
  92. package/src/infinite-loading/useInfiniteGalleriesLoading.ts +53 -0
  93. package/src/infinite-loading/useInfiniteLoading.ts +66 -0
  94. package/src/infinite-loading/useInfiniteStoriesLoading.ts +81 -0
  95. package/src/intl/locale.ts +5 -4
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (_) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.useInfiniteStoriesLoading = void 0;
51
+ var react_1 = require("react");
52
+ var newsroom_context_1 = require("../newsroom-context");
53
+ var useInfiniteLoading_1 = require("./useInfiniteLoading");
54
+ function fetchStories(page, pageSize, category, locale, include) {
55
+ return __awaiter(this, void 0, void 0, function () {
56
+ var result, message;
57
+ return __generator(this, function (_a) {
58
+ switch (_a.label) {
59
+ case 0: return [4 /*yield*/, fetch('/api/fetch-stories', {
60
+ method: 'POST',
61
+ headers: {
62
+ 'Content-Type': 'application/json',
63
+ },
64
+ body: JSON.stringify(__assign({ page: page, pageSize: pageSize, category: category, include: include }, (locale && {
65
+ localeCode: locale.toUnderscoreCode(),
66
+ }))),
67
+ })];
68
+ case 1:
69
+ result = _a.sent();
70
+ if (!!result.ok) return [3 /*break*/, 3];
71
+ return [4 /*yield*/, result.json()];
72
+ case 2:
73
+ message = (_a.sent()).message;
74
+ throw new Error(message);
75
+ case 3: return [2 /*return*/, result.json()];
76
+ }
77
+ });
78
+ });
79
+ }
80
+ /**
81
+ * NOTE: This hook depends on the presence of a Next API route (/api/fetch-stories)!
82
+ * The handler for this route is exported from `apiHandlers/fetchStories.ts` file.
83
+ * See https://github.com/prezly/theme-nextjs-bea/blob/d381e9878187ca98815d240d3ffdf10a75993c14/pages/index.tsx#L24 for usage example
84
+ */
85
+ function useInfiniteStoriesLoading(initialStories, pagination, category, include) {
86
+ var _this = this;
87
+ var currentLocale = (0, newsroom_context_1.useCurrentLocale)();
88
+ var _a = (0, useInfiniteLoading_1.useInfiniteLoading)({
89
+ fetchingFn: function (nextPage, pageSize) { return __awaiter(_this, void 0, void 0, function () {
90
+ var stories;
91
+ return __generator(this, function (_a) {
92
+ switch (_a.label) {
93
+ case 0: return [4 /*yield*/, fetchStories(nextPage, pageSize, category, currentLocale, include)];
94
+ case 1:
95
+ stories = (_a.sent()).stories;
96
+ return [2 /*return*/, stories];
97
+ }
98
+ });
99
+ }); },
100
+ initialData: initialStories,
101
+ pagination: pagination,
102
+ }), canLoadMore = _a.canLoadMore, data = _a.data, isLoading = _a.isLoading, loadMore = _a.loadMore, resetData = _a.resetData;
103
+ (0, react_1.useEffect)(function () {
104
+ if (category === null || category === void 0 ? void 0 : category.id) {
105
+ resetData();
106
+ }
107
+ }, [category === null || category === void 0 ? void 0 : category.id, resetData]);
108
+ return {
109
+ canLoadMore: canLoadMore,
110
+ isLoading: isLoading,
111
+ loadMoreStories: loadMore,
112
+ stories: data,
113
+ };
114
+ }
115
+ exports.useInfiniteStoriesLoading = useInfiniteStoriesLoading;
116
+ //# sourceMappingURL=useInfiniteStoriesLoading.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInfiniteStoriesLoading.js","sourceRoot":"","sources":["../../src/infinite-loading/useInfiniteStoriesLoading.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,+BAAkC;AAGlC,wDAAuD;AAGvD,2DAA0D;AAE1D,SAAe,YAAY,CACvB,IAAY,EACZ,QAAgB,EAChB,QAAmB,EACnB,MAAqB,EACrB,OAAoC;;;;;wBAErB,qBAAM,KAAK,CAAC,oBAAoB,EAAE;wBAC7C,MAAM,EAAE,MAAM;wBACd,OAAO,EAAE;4BACL,cAAc,EAAE,kBAAkB;yBACrC;wBACD,IAAI,EAAE,IAAI,CAAC,SAAS,YAChB,IAAI,MAAA,EACJ,QAAQ,UAAA,EACR,QAAQ,UAAA,EACR,OAAO,SAAA,IACJ,CAAC,MAAM,IAAI;4BACV,UAAU,EAAE,MAAM,CAAC,gBAAgB,EAAE;yBACxC,CAAC,EACJ;qBACL,CAAC,EAAA;;oBAdI,MAAM,GAAG,SAcb;yBAEE,CAAC,MAAM,CAAC,EAAE,EAAV,wBAAU;oBACU,qBAAM,MAAM,CAAC,IAAI,EAAE,EAAA;;oBAA/B,OAAO,GAAK,CAAA,SAAmB,CAAA,QAAxB;oBACf,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;wBAG7B,sBAAO,MAAM,CAAC,IAAI,EAAE,EAAC;;;;CACxB;AAED;;;;GAIG;AACH,SAAgB,yBAAyB,CACrC,cAAmB,EACnB,UAA2B,EAC3B,QAAmB,EACnB,OAAoC;IAJxC,iBAmCC;IA7BG,IAAM,aAAa,GAAG,IAAA,mCAAgB,GAAE,CAAC;IAEnC,IAAA,KAAwD,IAAA,uCAAkB,EAAI;QAChF,UAAU,EAAE,UAAO,QAAQ,EAAE,QAAQ;;;;4BACb,qBAAM,YAAY,CAClC,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,OAAO,CACV,EAAA;;wBANO,OAAO,GAAK,CAAA,SAMnB,CAAA,QANc;wBAOf,sBAAO,OAAO,EAAC;;;aAClB;QACD,WAAW,EAAE,cAAc;QAC3B,UAAU,YAAA;KACb,CAAC,EAbM,WAAW,iBAAA,EAAE,IAAI,UAAA,EAAE,SAAS,eAAA,EAAE,QAAQ,cAAA,EAAE,SAAS,eAavD,CAAC;IAEH,IAAA,iBAAS,EAAC;QACN,IAAI,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,EAAE,EAAE;YACd,SAAS,EAAE,CAAC;SACf;IACL,CAAC,EAAE,CAAC,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC;IAE9B,OAAO;QACH,WAAW,aAAA;QACX,SAAS,WAAA;QACT,eAAe,EAAE,QAAQ;QACzB,OAAO,EAAE,IAAI;KAChB,CAAC;AACN,CAAC;AAnCD,8DAmCC"}
@@ -84,12 +84,13 @@ function getSupportedLocaleIsoCode(locale) {
84
84
  }
85
85
  exports.getSupportedLocaleIsoCode = getSupportedLocaleIsoCode;
86
86
  function getRedirectToCanonicalLocale(shortestLocaleCode, nextLocaleIsoCode, redirectPath, query) {
87
+ // No need to redirect if no particular locale was requested by the application
88
+ if (!nextLocaleIsoCode || nextLocaleIsoCode === exports.DUMMY_DEFAULT_LOCALE) {
89
+ return undefined;
90
+ }
87
91
  var shortestLocaleSlug = shortestLocaleCode
88
92
  ? localeObject_1.LocaleObject.fromAnyCode(shortestLocaleCode).toUrlSlug()
89
93
  : shortestLocaleCode;
90
- if (nextLocaleIsoCode === exports.DUMMY_DEFAULT_LOCALE) {
91
- return undefined;
92
- }
93
94
  if (shortestLocaleSlug !== nextLocaleIsoCode) {
94
95
  var prefixedPath = redirectPath && !redirectPath.startsWith('/') ? "/".concat(redirectPath) : redirectPath;
95
96
  var urlQuery = query ? "?".concat((0, querystring_1.stringify)(query)) : '';
@@ -1 +1 @@
1
- {"version":3,"file":"locale.js","sourceRoot":"","sources":["../../src/intl/locale.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"locale.js","sourceRoot":"","sources":["../../src/intl/locale.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prezly/theme-kit-nextjs",
3
- "version": "1.6.2",
3
+ "version": "1.6.4-0",
4
4
  "description": "Data layer and utility library for developing Prezly themes with NextJS",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -48,8 +48,11 @@
48
48
  "react-dom": "^17.x"
49
49
  },
50
50
  "dependencies": {
51
- "@prezly/sdk": "^6.11.0",
52
- "parse-data-url": "^4.0.1"
51
+ "@prezly/sdk": "^6.21.0",
52
+ "@react-hookz/web": "^13.2.1",
53
+ "next-seo": "^5.4.0",
54
+ "parse-data-url": "^4.0.1",
55
+ "string-strip-html": "^9.1.9"
53
56
  },
54
57
  "devDependencies": {
55
58
  "@prezly/eslint-config": "^4.0.0",
@@ -22,7 +22,9 @@ export function processRequest<Props>(
22
22
 
23
23
  const { localeResolved, ...pageProps } = props;
24
24
 
25
- if (!localeResolved) {
25
+ // If no locale was provided by Next, it most likely means that the theme is not supporting multi-language.
26
+ // In that case we won't show 404 page.
27
+ if (!localeResolved && nextLocale) {
26
28
  return { notFound: true };
27
29
  }
28
30
 
@@ -0,0 +1,123 @@
1
+ import { NextSeo } from 'next-seo';
2
+ import type { NextSeoProps } from 'next-seo';
3
+ import { useRouter } from 'next/router';
4
+ import { useMemo } from 'react';
5
+ import { stripHtml } from 'string-strip-html';
6
+
7
+ import { getNewsroomLogoUrl, getUsedLanguages } from '../../data-fetching';
8
+ import { LocaleObject } from '../../intl';
9
+ import {
10
+ useCompanyInformation,
11
+ useCurrentLocale,
12
+ useCurrentStory,
13
+ useGetLinkLocaleSlug,
14
+ useGetTranslationUrl,
15
+ useLanguages,
16
+ useNewsroom,
17
+ } from '../../newsroom-context';
18
+
19
+ import { getAbsoluteUrl } from './lib/getAbsoluteUrl';
20
+ import type { AlternateLanguageLink } from './lib/types';
21
+
22
+ type Props = NextSeoProps & {
23
+ imageUrl?: string;
24
+ };
25
+
26
+ /**
27
+ * This component provides base page attributes for every Newsroom page.
28
+ * It depends on information from NewsroomContext, so the component should be placed inside the `NewsroomContextProvider`.
29
+ * You can pass additional props expected by NextSeo component to override any info that is provided by the NewsroomContext.
30
+ */
31
+ export function PageSeo({
32
+ title,
33
+ description,
34
+ imageUrl,
35
+ canonical,
36
+ openGraph,
37
+ twitter,
38
+ ...nextSeoProps
39
+ }: Props) {
40
+ const companyInformation = useCompanyInformation();
41
+ const newsroom = useNewsroom();
42
+ const currentLocale = useCurrentLocale();
43
+ const languages = useLanguages();
44
+ const getTranslationUrl = useGetTranslationUrl();
45
+ const getLinkLocaleSlug = useGetLinkLocaleSlug();
46
+ const currentStory = useCurrentStory();
47
+ const { asPath } = useRouter();
48
+
49
+ const pageTitle = title || companyInformation.name;
50
+ const pageDescription = description || stripHtml(companyInformation.about).result;
51
+ const canonicalUrl =
52
+ canonical || getAbsoluteUrl(asPath, newsroom.url, getLinkLocaleSlug(currentLocale));
53
+ const siteName = companyInformation.name;
54
+ const logoUrl = imageUrl || getNewsroomLogoUrl(newsroom);
55
+
56
+ const alternateLanguageLinks: AlternateLanguageLink[] = useMemo(() => {
57
+ if (!languages.length) {
58
+ return [];
59
+ }
60
+
61
+ const alternateLanguages = getUsedLanguages(languages).filter(
62
+ (language) => language.code !== currentLocale.toUnderscoreCode(),
63
+ );
64
+
65
+ return alternateLanguages
66
+ .map((language) => {
67
+ const locale = LocaleObject.fromAnyCode(language.code);
68
+
69
+ const translationLink = getTranslationUrl(locale, true);
70
+
71
+ if (!translationLink) {
72
+ return undefined;
73
+ }
74
+
75
+ return {
76
+ hrefLang: locale.toHyphenCode(),
77
+ href: getAbsoluteUrl(
78
+ translationLink,
79
+ newsroom.url,
80
+ currentStory && translationLink !== '/' ? false : getLinkLocaleSlug(locale),
81
+ ),
82
+ };
83
+ })
84
+ .filter<AlternateLanguageLink>(Boolean as any);
85
+ }, [
86
+ currentLocale,
87
+ getLinkLocaleSlug,
88
+ getTranslationUrl,
89
+ languages,
90
+ newsroom.url,
91
+ currentStory,
92
+ ]);
93
+
94
+ return (
95
+ <NextSeo
96
+ title={pageTitle}
97
+ description={pageDescription}
98
+ canonical={canonicalUrl}
99
+ openGraph={{
100
+ url: canonicalUrl,
101
+ title: pageTitle,
102
+ description: pageDescription,
103
+ locale: currentLocale.toUnderscoreCode(),
104
+ images: [
105
+ {
106
+ url: logoUrl,
107
+ alt: pageTitle,
108
+ },
109
+ ],
110
+ site_name: siteName,
111
+ ...openGraph,
112
+ }}
113
+ twitter={{
114
+ site: siteName,
115
+ cardType: 'summary',
116
+ ...twitter,
117
+ }}
118
+ additionalMetaTags={[{ name: 'twitter:image', content: logoUrl }]}
119
+ languageAlternates={alternateLanguageLinks}
120
+ {...nextSeoProps}
121
+ />
122
+ );
123
+ }
@@ -0,0 +1,2 @@
1
+ export { PageSeo } from './PageSeo';
2
+ export * from './lib/types';
@@ -0,0 +1,7 @@
1
+ // Returns absolute URL based on the path and without any query parameters
2
+ export function getAbsoluteUrl(path: string, origin: string, localeCode?: string | false): string {
3
+ const url = new URL(`${localeCode ? `/${localeCode}` : ''}${path || '/'}`, origin);
4
+ url.search = '';
5
+
6
+ return url.toString();
7
+ }
@@ -0,0 +1,4 @@
1
+ export type AlternateLanguageLink = {
2
+ href: string;
3
+ hrefLang: string;
4
+ };
@@ -0,0 +1,56 @@
1
+ import type { SitemapUrl } from './types';
2
+
3
+ export class SitemapBuilder {
4
+ private baseUrl: string;
5
+
6
+ private urls: SitemapUrl[] = [];
7
+
8
+ constructor(baseUrl: string) {
9
+ this.baseUrl = baseUrl;
10
+ }
11
+
12
+ public addUrl(location: string) {
13
+ this.urls.push({
14
+ location: this.baseUrl + location,
15
+ changeFrequency: SitemapBuilder.guessFrequency(location),
16
+ priority: SitemapBuilder.guessPriority(location),
17
+ });
18
+ }
19
+
20
+ private static guessFrequency(location: string) {
21
+ if (location === '/') return 'daily';
22
+
23
+ return 'weekly';
24
+ }
25
+
26
+ private static guessPriority(location: string) {
27
+ if (location === '/') return '0.9';
28
+
29
+ if (location.startsWith('/category/')) {
30
+ return '0.8';
31
+ }
32
+
33
+ return '0.7';
34
+ }
35
+
36
+ static serializeLocation(url: SitemapUrl) {
37
+ return [
38
+ '<url>',
39
+ url.location && `\t<loc>${url.location}</loc>`,
40
+ url.changeFrequency && `\t<changefreq>${url.changeFrequency}</changefreq>`,
41
+ url.priority && `\t<priority>${url.priority}</priority>`,
42
+ '</url>',
43
+ ]
44
+ .filter(Boolean)
45
+ .join('\n');
46
+ }
47
+
48
+ serialize() {
49
+ return [
50
+ '<?xml version="1.0" encoding="UTF-8" ?>',
51
+ '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">',
52
+ this.urls.map(SitemapBuilder.serializeLocation).join('\n'),
53
+ '</urlset>',
54
+ ].join('\n');
55
+ }
56
+ }
@@ -0,0 +1,21 @@
1
+ import type { Category, Story } from '@prezly/sdk';
2
+
3
+ export function createPaths(stories: Story[], categories: Category[]) {
4
+ const storiesUrls = stories.map(({ slug }) => `/${slug}`);
5
+ const categoriesUrls = categories
6
+ .map((category) => {
7
+ const translations = Object.values(category.i18n);
8
+ const allSlugs = translations
9
+ .map(({ slug }) => slug || '')
10
+ .filter(Boolean)
11
+ .reduce<string[]>(
12
+ (slugs, slug) => (slugs.includes(slug) ? [...slugs] : [...slugs, slug]),
13
+ [],
14
+ );
15
+
16
+ return allSlugs.map((slug) => `/category/${slug}`);
17
+ })
18
+ .flat();
19
+
20
+ return [...storiesUrls, ...categoriesUrls];
21
+ }
@@ -0,0 +1,37 @@
1
+ import type { NextPageContext } from 'next';
2
+
3
+ import { getPrezlyApi } from '../../data-fetching';
4
+
5
+ import { createPaths } from './createPaths';
6
+ import { SitemapBuilder } from './SitemapBuilder';
7
+
8
+ export async function getInitialProps(ctx: NextPageContext, additionalPaths?: string[]) {
9
+ const { res, req } = ctx;
10
+
11
+ if (!req || !res) {
12
+ // client side
13
+ return null;
14
+ }
15
+
16
+ const baseUrl = req.headers.host || '/';
17
+
18
+ const api = getPrezlyApi(req);
19
+ const stories = await api.getAllStories();
20
+ const categories = await api.getCategories();
21
+
22
+ const paths = createPaths(stories, categories);
23
+ const sitemapBuilder = new SitemapBuilder(baseUrl);
24
+
25
+ sitemapBuilder.addUrl('/');
26
+ paths.forEach((path) => sitemapBuilder.addUrl(path));
27
+
28
+ if (additionalPaths) {
29
+ additionalPaths.forEach((path) => sitemapBuilder.addUrl(path));
30
+ }
31
+
32
+ res.setHeader('Content-Type', 'text/xml');
33
+ res.write(sitemapBuilder.serialize());
34
+ res.end();
35
+
36
+ return null;
37
+ }
@@ -0,0 +1,5 @@
1
+ export { getInitialProps as getSitemapInitialProps } from './getInitialProps';
2
+
3
+ export { SitemapBuilder } from './SitemapBuilder';
4
+ export { createPaths } from './createPaths';
5
+ export * from './types';
@@ -0,0 +1,5 @@
1
+ export type SitemapUrl = {
2
+ location: string;
3
+ changeFrequency?: string;
4
+ priority?: string;
5
+ };
@@ -0,0 +1,68 @@
1
+ import type { ExtendedStory } from '@prezly/sdk';
2
+ import { ArticleJsonLd, NextSeo } from 'next-seo';
3
+
4
+ type Props = {
5
+ story: ExtendedStory;
6
+ };
7
+
8
+ /**
9
+ * This components provides additional page attributes for the Story page.
10
+ * It works in conjunction with `PageSeo` component, overidding some of its attributes.
11
+ */
12
+ export function StorySeo({ story }: Props) {
13
+ const { title, subtitle, published_at, updated_at, author, oembed, newsroom, summary } = story;
14
+
15
+ const authorName = author?.display_name || author?.email || 'Unknown';
16
+ const description = subtitle || summary;
17
+
18
+ return (
19
+ <>
20
+ <NextSeo
21
+ title={title}
22
+ description={description}
23
+ canonical={oembed.url}
24
+ openGraph={{
25
+ title,
26
+ description,
27
+ url: oembed.url,
28
+ site_name: newsroom.display_name,
29
+ type: 'article',
30
+ article: {
31
+ publishedTime: published_at || undefined,
32
+ modifiedTime: updated_at,
33
+ authors: [authorName],
34
+ },
35
+ ...(oembed.thumbnail_url && {
36
+ images: [
37
+ {
38
+ url: oembed.thumbnail_url,
39
+ alt: oembed.title,
40
+ width: oembed.thumbnail_width,
41
+ height: oembed.thumbnail_height,
42
+ },
43
+ ],
44
+ }),
45
+ }}
46
+ additionalMetaTags={
47
+ oembed.thumbnail_url
48
+ ? [
49
+ { name: 'twitter:card', content: 'summary_large_image' },
50
+ { name: 'twitter:image', content: oembed.thumbnail_url },
51
+ ]
52
+ : undefined
53
+ }
54
+ />
55
+ <ArticleJsonLd
56
+ url={oembed.url}
57
+ title={title}
58
+ images={oembed.thumbnail_url ? [oembed.thumbnail_url] : []}
59
+ datePublished={published_at || ''}
60
+ dateModified={updated_at}
61
+ authorName={[authorName]}
62
+ publisherName={newsroom.display_name}
63
+ publisherLogo={newsroom.thumbnail_url}
64
+ description={description}
65
+ />
66
+ </>
67
+ );
68
+ }
@@ -0,0 +1 @@
1
+ export { StorySeo } from './StorySeo';
@@ -0,0 +1,3 @@
1
+ export { PageSeo } from './PageSeo';
2
+ export * from './Sitemap';
3
+ export { StorySeo } from './StorySeo';
@@ -27,7 +27,9 @@ function decodeHttpEnv(header: string): Record<string, any> {
27
27
  return decodeJson(header);
28
28
  }
29
29
 
30
- export function getEnvVariables(req?: IncomingMessage): PrezlyEnv {
30
+ export function getEnvVariables<EnvType extends PrezlyEnv = PrezlyEnv>(
31
+ req?: IncomingMessage,
32
+ ): NodeJS.ProcessEnv & EnvType {
31
33
  if (typeof window !== 'undefined') {
32
34
  throw new Error('"getEnvVariables" should only be used on back-end side.');
33
35
  }
@@ -37,8 +39,8 @@ export function getEnvVariables(req?: IncomingMessage): PrezlyEnv {
37
39
  if (headerName && req) {
38
40
  const header = req.headers[headerName] as string | undefined;
39
41
  const httpEnv = decodeHttpEnv(header || '');
40
- return { ...process.env, ...httpEnv };
42
+ return { ...process.env, ...httpEnv } as NodeJS.ProcessEnv & EnvType;
41
43
  }
42
44
 
43
- return { ...process.env };
45
+ return { ...process.env } as NodeJS.ProcessEnv & EnvType;
44
46
  }
package/src/index.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  export * from './adapter-nextjs';
2
+ export * from './components-nextjs';
2
3
  export * from './data-fetching';
4
+ export * from './infinite-loading';
3
5
  export * from './intl';
4
6
  export * from './newsroom-context';
5
7
  export * from './types';
@@ -0,0 +1,24 @@
1
+ import type { NextApiRequest, NextApiResponse } from 'next';
2
+
3
+ import { getPrezlyApi } from '../../data-fetching';
4
+
5
+ export async function fetchGalleries(req: NextApiRequest, res: NextApiResponse) {
6
+ if (req.method !== 'POST') {
7
+ res.status(405);
8
+ return;
9
+ }
10
+
11
+ const { page, pageSize } = req.body;
12
+
13
+ try {
14
+ const api = getPrezlyApi(req);
15
+
16
+ const { galleries } = await api.getGalleries({ page, pageSize });
17
+
18
+ res.status(200).json({ galleries });
19
+ } catch (error) {
20
+ res.status(500).send({
21
+ message: (error as Error).message,
22
+ });
23
+ }
24
+ }
@@ -0,0 +1,26 @@
1
+ import type { NextApiRequest, NextApiResponse } from 'next';
2
+
3
+ import { getPrezlyApi } from '../../data-fetching';
4
+
5
+ export async function fetchStories(req: NextApiRequest, res: NextApiResponse) {
6
+ if (req.method !== 'POST') {
7
+ res.status(405);
8
+ return;
9
+ }
10
+
11
+ const { page, pageSize, category, include, localeCode } = req.body;
12
+
13
+ try {
14
+ const api = getPrezlyApi(req);
15
+
16
+ const { stories } = await (category
17
+ ? api.getStoriesFromCategory(category, { page, pageSize, include, localeCode })
18
+ : api.getStories({ page, pageSize, include, localeCode }));
19
+
20
+ res.status(200).json({ stories });
21
+ } catch (error) {
22
+ res.status(500).send({
23
+ message: (error as Error).message,
24
+ });
25
+ }
26
+ }
@@ -0,0 +1,2 @@
1
+ export { fetchGalleries } from './fetchGalleries';
2
+ export { fetchStories } from './fetchStories';
@@ -0,0 +1,5 @@
1
+ export { useInfiniteLoading } from './useInfiniteLoading';
2
+ export { useInfiniteStoriesLoading } from './useInfiniteStoriesLoading';
3
+ export { useInfiniteGalleriesLoading } from './useInfiniteGalleriesLoading';
4
+ export * from './apiHandlers';
5
+ export * from './types';
@@ -0,0 +1,5 @@
1
+ export interface PaginationProps {
2
+ itemsTotal: number;
3
+ currentPage: number;
4
+ pageSize: number;
5
+ }