@pixelated-tech/components 3.13.14 → 3.13.16
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/dist/components/general/schema.functions.js +114 -0
- package/dist/components/general/schema.js +662 -0
- package/dist/components/general/sitemap.js +74 -31
- package/dist/components/general/utilities.js +38 -0
- package/dist/components/integrations/spotify.components.js +43 -0
- package/dist/components/integrations/spotify.functions.js +111 -0
- package/dist/components/integrations/wordpress.components.js +2 -2
- package/dist/config/pixelated.config.json.enc +1 -1
- package/dist/index.js +7 -13
- package/dist/index.server.js +3 -1
- package/dist/scripts/release.sh +9 -15
- package/dist/scripts/update.sh +45 -8
- package/dist/types/components/general/schema.d.ts +266 -0
- package/dist/types/components/general/schema.d.ts.map +1 -0
- package/dist/types/components/general/schema.functions.d.ts +77 -0
- package/dist/types/components/general/schema.functions.d.ts.map +1 -0
- package/dist/types/components/general/sitemap.d.ts +4 -4
- package/dist/types/components/general/sitemap.d.ts.map +1 -1
- package/dist/types/components/general/utilities.d.ts +2 -0
- package/dist/types/components/general/utilities.d.ts.map +1 -1
- package/dist/types/components/integrations/spotify.components.d.ts +27 -0
- package/dist/types/components/integrations/spotify.components.d.ts.map +1 -0
- package/dist/types/components/integrations/spotify.functions.d.ts +57 -0
- package/dist/types/components/integrations/spotify.functions.d.ts.map +1 -0
- package/dist/types/index.d.ts +7 -13
- package/dist/types/index.server.d.ts +3 -1
- package/dist/types/stories/general/schema.stories.d.ts +1 -1
- package/dist/types/stories/general/schema.stories.d.ts.map +1 -1
- package/dist/types/stories/integrations/loremipsum.stories.d.ts +1 -1
- package/dist/types/stories/integrations/schema-podcast.stories.d.ts +45 -0
- package/dist/types/stories/integrations/schema-podcast.stories.d.ts.map +1 -0
- package/dist/types/stories/integrations/spotify.stories.d.ts +19 -0
- package/dist/types/stories/integrations/spotify.stories.d.ts.map +1 -0
- package/dist/types/tests/schema-podcast.test.d.ts +2 -0
- package/dist/types/tests/schema-podcast.test.d.ts.map +1 -0
- package/dist/types/tests/spotify.test.d.ts +2 -0
- package/dist/types/tests/spotify.test.d.ts.map +1 -0
- package/package.json +46 -42
- package/dist/components/general/schema-blogposting.functions.js +0 -44
- package/dist/components/general/schema-blogposting.js +0 -18
- package/dist/components/general/schema-breadcrumb.js +0 -78
- package/dist/components/general/schema-faq.js +0 -38
- package/dist/components/general/schema-localbusiness.js +0 -125
- package/dist/components/general/schema-product.js +0 -51
- package/dist/components/general/schema-recipe.js +0 -58
- package/dist/components/general/schema-review.js +0 -47
- package/dist/components/general/schema-services.js +0 -79
- package/dist/components/general/schema-website.js +0 -148
- package/dist/types/components/general/schema-blogposting.d.ts +0 -10
- package/dist/types/components/general/schema-blogposting.d.ts.map +0 -1
- package/dist/types/components/general/schema-blogposting.functions.d.ts +0 -27
- package/dist/types/components/general/schema-blogposting.functions.d.ts.map +0 -1
- package/dist/types/components/general/schema-breadcrumb.d.ts +0 -14
- package/dist/types/components/general/schema-breadcrumb.d.ts.map +0 -1
- package/dist/types/components/general/schema-faq.d.ts +0 -10
- package/dist/types/components/general/schema-faq.d.ts.map +0 -1
- package/dist/types/components/general/schema-localbusiness.d.ts +0 -53
- package/dist/types/components/general/schema-localbusiness.d.ts.map +0 -1
- package/dist/types/components/general/schema-product.d.ts +0 -38
- package/dist/types/components/general/schema-product.d.ts.map +0 -1
- package/dist/types/components/general/schema-recipe.d.ts +0 -33
- package/dist/types/components/general/schema-recipe.d.ts.map +0 -1
- package/dist/types/components/general/schema-review.d.ts +0 -34
- package/dist/types/components/general/schema-review.d.ts.map +0 -1
- package/dist/types/components/general/schema-services.d.ts +0 -36
- package/dist/types/components/general/schema-services.d.ts.map +0 -1
- package/dist/types/components/general/schema-website.d.ts +0 -40
- package/dist/types/components/general/schema-website.d.ts.map +0 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import PropTypes from "prop-types";
|
|
2
|
+
import { encode } from 'html-entities';
|
|
2
3
|
import { getAllRoutes } from "./metadata.functions";
|
|
3
4
|
import { getWordPressItems, getWordPressItemImages } from "../integrations/wordpress.functions";
|
|
4
|
-
import { getContentfulFieldValues,
|
|
5
|
+
import { getContentfulFieldValues, getContentfulAssets } from "../integrations/contentful.delivery";
|
|
5
6
|
import { getEbayAppToken, getEbayItemsSearch } from "../shoppingcart/ebay.functions";
|
|
6
7
|
import { getFullPixelatedConfig } from '../config/config';
|
|
7
8
|
import { CacheManager } from '../general/cache-manager';
|
|
@@ -81,7 +82,7 @@ export async function generateSitemap(cfg = {}, originInput) {
|
|
|
81
82
|
const useWPImages = cfg.createWordPressImageURLs ?? false;
|
|
82
83
|
const useImageJSON = cfg.createImageURLsFromJSON ?? true;
|
|
83
84
|
const useContentful = cfg.createContentfulURLs ?? false;
|
|
84
|
-
const
|
|
85
|
+
const useContentfulAssets = cfg.createContentfulAssetURLs ?? false;
|
|
85
86
|
const usePageBuilder = cfg.createPageBuilderURLs ?? false;
|
|
86
87
|
const useEbay = cfg.createEbayItemURLs ?? false;
|
|
87
88
|
// Pages
|
|
@@ -103,9 +104,9 @@ export async function generateSitemap(cfg = {}, originInput) {
|
|
|
103
104
|
if (useContentful && cfg.contentful) {
|
|
104
105
|
sitemapEntries.push(...(await createContentfulURLs({ apiProps: cfg.contentful, origin })));
|
|
105
106
|
}
|
|
106
|
-
// Contentful images
|
|
107
|
-
if (
|
|
108
|
-
sitemapEntries.push(...(await
|
|
107
|
+
// Contentful assets (images and videos)
|
|
108
|
+
if (useContentfulAssets && cfg.contentful) {
|
|
109
|
+
sitemapEntries.push(...(await createContentfulAssetURLs({ apiProps: cfg.contentful, origin })));
|
|
109
110
|
}
|
|
110
111
|
// Page Builder (existing helper in package not always present)
|
|
111
112
|
if (usePageBuilder && cfg.contentful) {
|
|
@@ -300,17 +301,17 @@ export async function createContentfulPageBuilderURLs(props) {
|
|
|
300
301
|
return sitemap;
|
|
301
302
|
}
|
|
302
303
|
/**
|
|
303
|
-
*
|
|
304
|
+
* createContentfulAssetURLs — Fetch Contentful assets and generate absolute image and video URLs for the sitemap.
|
|
304
305
|
*
|
|
305
306
|
* @param {shape} [props.apiProps] - Contentful API props (proxyURL optional, base_url, space_id, environment, access_token).
|
|
306
|
-
* @param {string} [props.proxyURL] - Optional proxy base URL to route
|
|
307
|
+
* @param {string} [props.proxyURL] - Optional proxy base URL to route asset requests through.
|
|
307
308
|
* @param {string} [props.base_url] - Contentful base API URL.
|
|
308
309
|
* @param {string} [props.space_id] - Contentful space id.
|
|
309
310
|
* @param {string} [props.environment] - Contentful environment.
|
|
310
311
|
* @param {string} [props.access_token] - Access token to read assets from Contentful.
|
|
311
|
-
* @param {string} [props.origin] - Origin used to convert relative
|
|
312
|
+
* @param {string} [props.origin] - Origin used to convert relative asset paths to absolute URLs.
|
|
312
313
|
*/
|
|
313
|
-
|
|
314
|
+
createContentfulAssetURLs.propTypes = {
|
|
314
315
|
/** Contentful API properties */
|
|
315
316
|
apiProps: PropTypes.shape({
|
|
316
317
|
/** Optional proxy URL */
|
|
@@ -327,37 +328,79 @@ createContentfulImageURLs.propTypes = {
|
|
|
327
328
|
/** Origin used to convert relative URLs to absolute */
|
|
328
329
|
origin: PropTypes.string.isRequired,
|
|
329
330
|
};
|
|
330
|
-
export async function
|
|
331
|
+
export async function createContentfulAssetURLs(props) {
|
|
331
332
|
const sitemap = [];
|
|
332
333
|
const providerContentfulApiProps = getFullPixelatedConfig()?.contentful;
|
|
333
334
|
// Changed order: provider config overrides apiProps for security (tokens)
|
|
334
335
|
const mergedApiProps = { ...props.apiProps, ...providerContentfulApiProps };
|
|
335
|
-
// const mergedApiProps = { ...providerContentfulApiProps, ...props.apiProps }; // Old: apiProps overrode provider
|
|
336
336
|
try {
|
|
337
|
-
const
|
|
338
|
-
if (!Array.isArray(
|
|
337
|
+
const rawAssets = await getContentfulAssets({ apiProps: mergedApiProps });
|
|
338
|
+
if (!Array.isArray(rawAssets?.items) || rawAssets.items.length === 0) {
|
|
339
339
|
return sitemap;
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
340
|
+
}
|
|
341
|
+
// Process assets into images and videos by content type
|
|
342
|
+
const imageAssets = rawAssets.items.filter((a) => a.fields?.file?.contentType?.startsWith('image/'));
|
|
343
|
+
// Process image assets
|
|
344
|
+
if (imageAssets.length > 0) {
|
|
345
|
+
const imageURLs = imageAssets.map((a) => {
|
|
346
|
+
let url = a.fields?.file?.url || '';
|
|
347
|
+
if (!url)
|
|
348
|
+
return '';
|
|
349
|
+
if (url.startsWith('//'))
|
|
350
|
+
url = `https:${url}`;
|
|
351
|
+
else if (url.startsWith('/'))
|
|
352
|
+
url = `${props.origin}${url}`;
|
|
353
|
+
else if (!url.startsWith('http://') && !url.startsWith('https://'))
|
|
354
|
+
url = `${props.origin}/${url}`;
|
|
355
|
+
return encode(url);
|
|
356
|
+
}).filter(Boolean);
|
|
357
|
+
if (imageURLs.length > 0) {
|
|
358
|
+
sitemap.push({
|
|
359
|
+
url: `${props.origin}/images`,
|
|
360
|
+
lastModified: new Date(),
|
|
361
|
+
changeFrequency: 'always',
|
|
362
|
+
priority: 1.0,
|
|
363
|
+
images: imageURLs,
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
const videoAssets = rawAssets.items.filter((a) => a.fields?.file?.contentType?.startsWith('video/'));
|
|
368
|
+
// Process video assets
|
|
369
|
+
if (videoAssets.length > 0) {
|
|
370
|
+
console.log("Video Assets", videoAssets);
|
|
371
|
+
sitemap.push({
|
|
372
|
+
url: `${props.origin}/videos`,
|
|
373
|
+
lastModified: new Date(),
|
|
374
|
+
changeFrequency: 'always',
|
|
375
|
+
priority: 1.0,
|
|
376
|
+
// videos: videoURLs,
|
|
377
|
+
videos: videoAssets.map((a) => {
|
|
378
|
+
let url = a.fields?.file?.url || '';
|
|
379
|
+
if (!url)
|
|
380
|
+
return null;
|
|
381
|
+
if (url.startsWith('//'))
|
|
382
|
+
url = `https:${url}`;
|
|
383
|
+
else if (url.startsWith('/'))
|
|
384
|
+
url = `${props.origin}${url}`;
|
|
385
|
+
else if (!url.startsWith('http://') && !url.startsWith('https://'))
|
|
386
|
+
url = `${props.origin}/${url}`;
|
|
387
|
+
return {
|
|
388
|
+
title: a.fields?.title || 'Untitled Video',
|
|
389
|
+
thumbnail_loc: `${props.origin}/images/placeholder.png`,
|
|
390
|
+
description: a.fields?.description || 'No description available',
|
|
391
|
+
publication_date: a.sys?.createdAt || new Date().toISOString(),
|
|
392
|
+
content_loc: encode(url),
|
|
393
|
+
player_loc: encode(url),
|
|
394
|
+
family_friendly: 'yes',
|
|
395
|
+
// duration: 600,
|
|
396
|
+
};
|
|
397
|
+
})
|
|
398
|
+
});
|
|
399
|
+
}
|
|
357
400
|
}
|
|
358
401
|
catch (e) {
|
|
359
402
|
if (typeof console !== 'undefined')
|
|
360
|
-
console.warn('
|
|
403
|
+
console.warn('createContentfulAssetURLs failed', e);
|
|
361
404
|
}
|
|
362
405
|
return sitemap;
|
|
363
406
|
}
|
|
@@ -203,3 +203,41 @@ export const SERVER_ONLY_PATTERNS = [
|
|
|
203
203
|
// /\bNextRequest\b/,
|
|
204
204
|
// /\bNextResponse\b/
|
|
205
205
|
];
|
|
206
|
+
export function stringTo1337_v1(str) {
|
|
207
|
+
return str
|
|
208
|
+
.replace(/o/gi, '0')
|
|
209
|
+
// .replace(/i/gi, '1')
|
|
210
|
+
.replace(/l/gi, '1')
|
|
211
|
+
.replace(/r/gi, '2')
|
|
212
|
+
.replace(/e/gi, '3')
|
|
213
|
+
.replace(/a/gi, '4')
|
|
214
|
+
.replace(/s/gi, '5')
|
|
215
|
+
.replace(/g/gi, '6')
|
|
216
|
+
.replace(/t/gi, '7')
|
|
217
|
+
.replace(/b/gi, '8')
|
|
218
|
+
.replace(/g/gi, '9');
|
|
219
|
+
}
|
|
220
|
+
export function stringTo1337(str) {
|
|
221
|
+
//converts lowercase non consecutive, non number characters (and doublets) to leet speak numbers
|
|
222
|
+
const leetMap = {
|
|
223
|
+
'o': '0', 'l': '1', 'z': '2', 'e': '3',
|
|
224
|
+
'a': '4', 's': '5', 'b': '6', 't': '7',
|
|
225
|
+
'g': '9'
|
|
226
|
+
};
|
|
227
|
+
let result = '';
|
|
228
|
+
for (const char of str) {
|
|
229
|
+
const leet = leetMap[char];
|
|
230
|
+
const last = result.slice(-1);
|
|
231
|
+
const lastIsNumber = /[0-9]/.test(last);
|
|
232
|
+
// Convert if:
|
|
233
|
+
// 1. There is a mapping
|
|
234
|
+
// 2. AND (the last char isn't a leet number OR it's matches for a doublet)
|
|
235
|
+
if (leet && (!lastIsNumber || last === leet)) {
|
|
236
|
+
result += leet;
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
result += char;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return result;
|
|
243
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { PageGridItem } from '@pixelated-tech/components';
|
|
4
|
+
import { BlogPostSummary } from '@pixelated-tech/components';
|
|
5
|
+
function getFirstSentences(str, minLength = 300) {
|
|
6
|
+
if (!str)
|
|
7
|
+
return '';
|
|
8
|
+
const firstPeriodIndex = str.indexOf('.', minLength);
|
|
9
|
+
if (firstPeriodIndex !== -1) {
|
|
10
|
+
return str.slice(0, firstPeriodIndex + 1);
|
|
11
|
+
}
|
|
12
|
+
return str;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Component to display a list of podcast episodes.
|
|
16
|
+
* @param props - The properties for the component, including an array of podcast episodes.
|
|
17
|
+
* @returns A React component that renders a list of podcast episodes.
|
|
18
|
+
*/
|
|
19
|
+
PodcastEpisodeList.propTypes = {
|
|
20
|
+
episodes: PropTypes.arrayOf(PropTypes.shape({
|
|
21
|
+
title: PropTypes.string.isRequired,
|
|
22
|
+
description: PropTypes.string.isRequired,
|
|
23
|
+
link: PropTypes.string.isRequired,
|
|
24
|
+
guid: PropTypes.string.isRequired,
|
|
25
|
+
creator: PropTypes.string.isRequired,
|
|
26
|
+
pubDate: PropTypes.string.isRequired,
|
|
27
|
+
enclosure: PropTypes.shape({
|
|
28
|
+
url: PropTypes.string.isRequired,
|
|
29
|
+
type: PropTypes.string.isRequired,
|
|
30
|
+
length: PropTypes.string.isRequired,
|
|
31
|
+
}).isRequired,
|
|
32
|
+
summary: PropTypes.string.isRequired,
|
|
33
|
+
explicit: PropTypes.bool.isRequired,
|
|
34
|
+
duration: PropTypes.string.isRequired,
|
|
35
|
+
image: PropTypes.string.isRequired,
|
|
36
|
+
episode: PropTypes.string.isRequired,
|
|
37
|
+
episodeType: PropTypes.string.isRequired,
|
|
38
|
+
}).isRequired).isRequired
|
|
39
|
+
};
|
|
40
|
+
export function PodcastEpisodeList(props) {
|
|
41
|
+
const { episodes } = props;
|
|
42
|
+
return (_jsx(_Fragment, { children: episodes.map((episode) => (_jsx(PageGridItem, { children: _jsx(BlogPostSummary, { ID: episode.guid, title: episode.title, date: episode.pubDate, excerpt: getFirstSentences(episode.summary), URL: episode.link, featured_image: episode.image, showCategories: false }) }, episode.guid))) }));
|
|
43
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import PropTypes from "prop-types";
|
|
2
|
+
function SpotifyRSSSeriesToJson(data) {
|
|
3
|
+
const parser = new DOMParser();
|
|
4
|
+
const xml = parser.parseFromString(data, 'application/xml');
|
|
5
|
+
const channel = xml.querySelectorAll('channel');
|
|
6
|
+
if (channel.length > 0) {
|
|
7
|
+
const item = channel[0];
|
|
8
|
+
return {
|
|
9
|
+
title: item.querySelector('title')?.textContent,
|
|
10
|
+
description: item.querySelector('description')?.textContent,
|
|
11
|
+
link: item.querySelector('link')?.textContent,
|
|
12
|
+
generator: item.querySelector('generator')?.textContent,
|
|
13
|
+
lastBuildDate: item.querySelector('lastBuildDate')?.textContent,
|
|
14
|
+
author: item.querySelector('author')?.textContent,
|
|
15
|
+
copyright: item.querySelector('copyright')?.textContent,
|
|
16
|
+
language: item.querySelector('language')?.textContent,
|
|
17
|
+
iTunesAuthor: item.querySelector('author')?.textContent,
|
|
18
|
+
summary: item.querySelector('summary')?.textContent,
|
|
19
|
+
type: item.querySelector('type')?.textContent,
|
|
20
|
+
owner: {
|
|
21
|
+
name: item.querySelector('owner')?.querySelector('name')?.textContent,
|
|
22
|
+
email: item.querySelector('owner')?.querySelector('email')?.textContent,
|
|
23
|
+
},
|
|
24
|
+
explicit: item.querySelector('explicit')?.textContent,
|
|
25
|
+
category: item.querySelector('category')?.textContent,
|
|
26
|
+
image: item.querySelector('image')?.getAttribute('href') || '',
|
|
27
|
+
/*
|
|
28
|
+
<atom:link href="https://anchor.fm/s/10fc04b98/podcast/rss" rel="self" type="application/rss+xml"/>
|
|
29
|
+
<atom:link rel="hub" href="https://pubsubhubbub.appspot.com/"/>
|
|
30
|
+
*/
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* getSpotifySeries — Fetch series information from the Spotify API for a given podcast.
|
|
39
|
+
*
|
|
40
|
+
* @param {string} [props.rssURL] - RSS feed URL of the podcast.
|
|
41
|
+
*/
|
|
42
|
+
getSpotifySeries.propTypes = {
|
|
43
|
+
/** RSS feed URL of the podcast */
|
|
44
|
+
rssURL: PropTypes.string.isRequired,
|
|
45
|
+
};
|
|
46
|
+
export async function getSpotifySeries(props) {
|
|
47
|
+
const { rssURL } = props;
|
|
48
|
+
try {
|
|
49
|
+
const response = await fetch(rssURL);
|
|
50
|
+
const data = await response.text();
|
|
51
|
+
let rssJSON = SpotifyRSSSeriesToJson(data);
|
|
52
|
+
return rssJSON;
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
console.error("Error fetching Spotify series data via RSS:", error);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function SpotifyRSSItemsToJson(data) {
|
|
60
|
+
const parser = new DOMParser();
|
|
61
|
+
const xml = parser.parseFromString(data, 'application/xml');
|
|
62
|
+
let items;
|
|
63
|
+
if (xml.querySelectorAll('item').length > 0) {
|
|
64
|
+
items = Array.from(xml.querySelectorAll('item')).map(item => {
|
|
65
|
+
return {
|
|
66
|
+
title: item.querySelector('title')?.textContent,
|
|
67
|
+
description: item.querySelector('description')?.textContent,
|
|
68
|
+
link: item.querySelector('link')?.textContent,
|
|
69
|
+
guid: item.querySelector('guid')?.textContent,
|
|
70
|
+
creator: item.querySelector('creator')?.textContent,
|
|
71
|
+
pubDate: item.querySelector('pubDate')?.textContent,
|
|
72
|
+
enclosure: {
|
|
73
|
+
url: item.querySelector('enclosure')?.getAttribute('url') || '',
|
|
74
|
+
type: item.querySelector('enclosure')?.getAttribute('type') || '',
|
|
75
|
+
length: item.querySelector('enclosure')?.getAttribute('length') || '',
|
|
76
|
+
},
|
|
77
|
+
summary: item.querySelector('summary')?.textContent,
|
|
78
|
+
explicit: item.querySelector('explicit')?.textContent,
|
|
79
|
+
duration: item.querySelector('duration')?.textContent,
|
|
80
|
+
image: item.querySelector('image')?.getAttribute('href') || '',
|
|
81
|
+
episode: item.querySelector('episode')?.textContent,
|
|
82
|
+
episodeType: item.querySelector('episodeType')?.textContent,
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return (items);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* getSpotifyEpisodes — Fetch episodes from the Spotify API for a given podcast.
|
|
90
|
+
*
|
|
91
|
+
* @param {string} [props.rssURL] - RSS feed URL of the podcast.
|
|
92
|
+
*/
|
|
93
|
+
getSpotifyEpisodes.propTypes = {
|
|
94
|
+
/** RSS feed URL of the podcast */
|
|
95
|
+
rssURL: PropTypes.string.isRequired,
|
|
96
|
+
};
|
|
97
|
+
export async function getSpotifyEpisodes(props) {
|
|
98
|
+
const { rssURL } = props;
|
|
99
|
+
try {
|
|
100
|
+
const response = await fetch(rssURL);
|
|
101
|
+
const data = await response.text();
|
|
102
|
+
let rssJSON = SpotifyRSSItemsToJson(data);
|
|
103
|
+
if (rssJSON)
|
|
104
|
+
rssJSON = rssJSON.sort((a, b) => ((a.pubDate ?? '') < (b.pubDate ?? '')) ? 1 : -1);
|
|
105
|
+
return rssJSON;
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
console.error("Error fetching Spotify episodes via RSS:", error);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -9,8 +9,8 @@ import { getWordPressItems, getWordPressLastModified } from './wordpress.functio
|
|
|
9
9
|
import { Loading, ToggleLoading } from '../general/loading';
|
|
10
10
|
import { CacheManager } from "../general/cache-manager";
|
|
11
11
|
import "./wordpress.css";
|
|
12
|
-
import { SchemaBlogPosting } from '../general/schema
|
|
13
|
-
import { mapWordPressToBlogPosting } from '../general/schema
|
|
12
|
+
import { SchemaBlogPosting } from '../general/schema';
|
|
13
|
+
import { mapWordPressToBlogPosting } from '../general/schema.functions';
|
|
14
14
|
// https://microformats.org/wiki/h-entry
|
|
15
15
|
function decodeString(str) {
|
|
16
16
|
const textarea = document.createElement('textarea');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
pxl:v1:
|
|
1
|
+
pxl:v1:944e61c3a894b694470bac88:f6779781197b20e03d028b7ef7b9e0d1:7d4f34021a97d9ddc6abc9eafd6fc8ab3331521a2d2778d03e3fd73b7a43e7d876b4abe146b08a1f6434ad5eca758902efc9fdee70d2a714d03ceeca56ccc927882baf25169bcbec791f9d556c461e175c4fc7476b413a933a5b2456dc02cbe1844b628fee57147b9e323db61c157f3719e1b9dadfa8d0fbaf182b147f7fecab03490ddc56e244511d043d56222c51ef0978bd0e0f97a226c7f9e4e5db26d502a8409474646b8af27b6b3951b448881d456d650b1620cccfcf20b2d6291d929c1d0501fb2c7285d57f161d7b8ba6bdeed2a86f3e2973faa4a2ba7ee0acad5591c19421377cdc3db453566d8ee351957298bf5bbfe5e8b65f3b92bb87edb9f81867e682b7fb939750771abfb78554b8dae1835bf2601f0e853154bc8c1ad4dd13f1d8cd62aa51970e00a99793ad9e211110e1616513be5d767938cb6e25c779fa759fb00fbd420abe655f22639048abcc6a64971fd17045e4910d9970c5b1283df77ec3a791b334f73b969c0c11e042cf951912cbe75fe575ad89fa8aa07a5a5e8ddc82037791eec89cde965fcbb34ad942f6f6e83ad6b945c1b19d67f3552a11d5234b4d146bb6548ddcce1028cc403e3931bf2690edb6ca664b529f147546ba2472714e7da565cd65b605fa8c63670f8273d6cdccd6d68cd3aaed2b31537e68e03fa9a714e25abaa5495063791550473b0e302591249af671d34fca96bb570580341c4bbe354eac0d49c884d597b768e3dd0ac613eb4de1918043076423a0659467d6a27cbd1e9b36af0af4ebdf8ab66f0525b864cdecc7ffd051b14292399abff2ea947d43f67ea52f918c97f456cf551a772562ffdc3c1a69e51d47662add62b98f96c293deb611900e15cb4cd32c542b4dcd3fb74b86b860107461fc513292a862e1baf8d4d886cc8a38de5250ee0df338910086eda61ed71b20dbbc2ea2215f4de83cd0909b2018782c454165b61734d6a62097aa86c833ea83ddb0202201f8d3f6db442aa5b9fc8f511e33733cdc4105bac41a089f79f477b6d16eab14e2017214553bf024c8a12779ac8f2ab18a771c6fda2a32e4497cb9ad9aa85cd1d9d3d4d0904492cf15b9fce1fad21821976b996b1046a6c2a47af2f1b011fe7fe98f5c21fe16566405baa865a859416dd0fea83309acdfb48be864cddfb0567a4a04e6b921d88b23542fd0eca913ef5ea41448c743e033bb6c8bd7ee68cf610c8c118b2e62b06d74a8ebd84f494b3e18000260c087d7dba662862657d03115da55700c992163e8ac4ac0677ccd4ddb013910e64bb0ec26c4d0b10fc2fc0f32f54b7f98d9bf9f2df9778713cfae5a1af74380f5c089f42c2a76385f979fa899249e42e4552817e1333f10d2864a194e6069edd843077b607a9ae27e3b4ec6cd1a9d46905b3c82dbd15804f37629d5fc833f78f007b58f20561766c062a3e9f919560b6e385fa2a04014af8d576ebe020d6bf3909dde72174346bba7cad0f419289caf4b5a78ccb46b505c78c275ceac24c9288e290c3b78861525bd1c366f19dfd60b6dade33e1d89e2ccb8c0d4153939daea7deb0eb618f7d9080b9b92572fbf7989169248b96c9e8c796d197cbb33a29e277488c2d0f29003c30ceaceb4f18bdf7ce5af3841ba41d6a2387361ce318d944591429141ff1571f800065ca70a118384dd5ed7bdc1998e77f130e6f6962ed957baf8e842db91dbea612c444cb3e4de3c05c1cddfa4003a4415ec994390c02d07f4fb3759b3dccaa518e866293aeda8aafcf12257ab5fd04f32af299d07dfe94d8a9f2620cdfb7da421a91e4c19f072c3eb154f09d90631b3b7923f1a8b188ce76a11b6a9fcdc925bc4d13105c0e917c31ef33ce23092ceb95c3f675df2cff9ff1dc2ee011a096fbde4815135cc1a937266ab75f3e763e4d2f115de29ffa1bf613ae7d450719e1608f3f401bb7a613be93175893f7f6add200fb43e186b7e7946d02cc4472e408448ec89461711bacba747304c8d0b5836db2ac307f46d4f5b18c43f7188b2afcfaab16d2c55acf6209984745ac341b27ba2ee816f30ebbe1b6585deabc553e6368b8bb9e82952372385ce7e8198b76a750bd45b1371bbf7daa94c057e5c6d1855d6bdb404c1c56b0f2ceed9e9d90f80793b2b994d4d5ee1f8c330d93613f2ea8cbe5cf54065a3d8f990f61d0f366bacf02f8f14a45dc809c2fd07f7afdc9eda7e8dc4114491f303abccc22a352ef9ce6d3fe496c979757e2166da62535c71cf37b9dfe855c38dc4c7221c99c0863558dbff39793e9e5ec93a59d279b29c4b4361f22186cad0d70c7aee82b717eca7dbfeafbfae4ad88d8f1f3ff720974ad3fde16165b323557c901521cf36a7c177beab3fce4473aaf4b9f73276ff2ac9a8bce40419ad8d7657531ea593f7d50d459bd15dd8c180f4cdca9fcd255010386bbebadd07edf6598b2ba597d541ae8b822c2f37c296f42e651684c62b90beff18795eb0636102bdfb59b282f4596b9479c44dbaf4f6e3a5f3f97cf819c580d697317f78e4b97f1188879221e7bcdfebe98d6622304ed58067c8d3092d4b9fcc4e6c7ab511865054efaa2a3158995f6c9552bd9092d7a13b6df9ef0d1aba0458323a06fde15f0f0ace038620e017bc4d9f7b39a4d437b58cf09f96ba19b3238eec550e4ce3938a368b765ddf99c5188e06295611166db68057d9d40037c4951eb244e5ca44cea74a0961177056fb3daf789c7bd00ad4975f1aa5acfe0007216e7b89793891191cd2b269c334f8b03d6420f0f05741e43d3c1f73d79c2ba3665f7dee1940569747bddf7951071496164542bc4e4a06f1a5a524b52a20904dc5138959dbe9dfe80cd373dc85fc38ecfa01ae274dd7b237355773f852336b420a5c7014211762c9c3e0d8178fc3de2756387e601636af9abc1e502baeda567d863257461f8131d58f2b8c6dfc5e9dd4ef9c0311ae24e98ff7323905cdf5b0041396e25b00284a7335867ac8a3effcf1963a1f98d11445bc6529fa1ef790bb5654300a95a042eb912c8d3baee66af768bf5f168bf373fd535ea6b24aed2d8fb6e99be1fcf07dc03e2b065a2b2b63ec4164d33603f252b2500b1104f761387fa5768c9441cf96dc7ddcffa130480aba07b816a4123ef9e13e13c4c02d6418264d178a1f059d919703ced2d0e85046c649f249baf5cf69333f720168ab9015cfe2c8959ef5df19d982a22d58c97768d0519db911dbb62f1b7d0aea0035dd1618be2ba6a0c31d0f64bbe139fb3c847c28051bd10994db9f645dbec726858e1b93fdb351a1e7f826a2f336c76fac898023e6608792e9507cbbf8f5c700dac02faccf15cc76e4edfc6dbfb1a94a44006a7d75aca791fa60729191072ea6ddbfecf63ae1efc5b60c5172b6f358d97eb337dc0cfdb4749754b24c56760a59e63fcd1ffac6f067a593bb3fdd25981b40abfaf1349d486d5baa3469ba7723b9d5f795ccad47e8f742a3520cc27a27e410be3fadbd29a9aed21f38b8687c41e5b61f27c8720a44721942ccfe8115921746ebd3967d1959d6c318e79e3bf6242cbde0b2bcf6f9ee9bcc416f7f2de108950740c7a15353ab4f9beda7ffd34e835a3a96480f50753384303f72ec5086ee068e19a1b92f6f9a440b31df44574a25e1fb3d646941e3ffbc61efbdadbd60b0790f251fe76e3d4a4c36d56e573ca4ed9a3f273fecb5673fbef83bb0aeb4b84b06eea730bc70f8531400570ba1f5852710b5622b13691bce5b75bf52973b81d997f925f5947e1e3ff5dc8a1689f4914726ae5d8399c5e9bd4397cc2a538ad609a4db37ac1de7dfc729c9d68d5921bb1bcf4e26e46763d5184fee8cba8260c96d8c8e6919164ea6a5956010bb70a42975000e4a4310f57e5bcc9b5ae37d4379d0e429c7ca85b95af872dc53ff7c0051ccfa403a96ccea339ae7f93463d18a3e25fd4fa2431b0e42a1a7a8fd9fe0e16063d8bad5fe5ce6dd4d77f4273822f3d1701d5a2df96117739867277d987ca9acfc1cec6ac423c92577efc8ed64b59e19908b7b6516d2171e75f92ffac643a660c9462b66dcc5e495f0734d18c7ed551d60fbb94582c9854bf7f64be60552d50454587c474f55bef32dce91e32e438b652e4fe510ae64b9edc3aad012ce3a246fc660356b6d08f479114d767515b6287599257332af996a7f1e2d3f802899beded1b2ce4cef4fb82360905dccf7c36d5cdd81c2fc3ad9e2824ace66169aaaff65412b3a2b50e9268063a6224d4218b6a148429466223fdb6be4f9d4e0cb5af5d49d968db89f5978e2e3b36426652d7a21e5b37a46f706168a4d6efe7446cb479af9a77b67cc960917c03c5a8e9409608d73de415daad4f5cbc826795251502a3a2c5015f2e6432ff6e9a56fe357a027e354389ff5e94ba86400a509b374a504385dbed27be82eeee376b45226717c4731f77d2955cf9127dfa3e96676a4eea53f3feadc5dc72c8c6a44636d208eec756680a0b3e77fd68a67600761bb7fb40e32182b9540c4f166bc141cbc65e3d6d33895c1e5dddddbfe758fb574f851aa92fd24a5704cea302c5e250af273cd5ec567dc3de4101bbb20532881bf519b4d4f806cacc7b3b541d2c3b2a8e4707e175120d34d6f4bd9d25a9b7106abcf1fdad303081cbb9a19543b0e3d279fdc92c0fe9d6fdab1d6c031c85cb3c8ff58282c63bc629b03096aef20b62966ea977e93cdcf81a64c04e3a1bcbd7ed6c5c11a891a58d38ef11141d5c0bff17870e1196c9dfc6f996f3e092dfbf1d13b815731846033c6f0dc8f69f079c296b02dbf4fcbdea3a8d8b44569cd4861aa26903b7bbb83893125e3b67936c3e25978c2238a9adb7b7f560be5e946fe4f780efda5cc474f10854016fdeed26d22cae0d66dcf7c0a3271f6d3dff102700b46089cd151b169415482eabe33eea7c4e7be28a137503f51a22982c0673bcf3c990c4af558adcee7d6c4277d4266b90a1acc2d31fb48b8e6004af095507c4fe609ed96c5e215b7bd3f3faeb8240705e72bda4ce846b1a715c63ce9861b52cbae58e57488614ef6eb3f5b1e7eea3b6567d38fa2e7f70407a107e8d9a718197092943c46668e0110f14ba001dd47d3f1cbd3a7c928b47e8dde47467e0e7682dcd520bf747bb038acfc1a96cb6593af32bba76656167f7496e91fac8feb8c9f1293ec4853969d6197
|
package/dist/index.js
CHANGED
|
@@ -29,16 +29,8 @@ export * from './components/general/modal';
|
|
|
29
29
|
export * from './components/general/nerdjoke';
|
|
30
30
|
export * from './components/general/recipe';
|
|
31
31
|
export * from './components/general/resume';
|
|
32
|
-
export * from './components/general/schema
|
|
33
|
-
export * from './components/general/schema
|
|
34
|
-
export * from './components/general/schema-breadcrumb';
|
|
35
|
-
export * from './components/general/schema-faq';
|
|
36
|
-
export * from './components/general/schema-localbusiness';
|
|
37
|
-
export * from './components/general/schema-product';
|
|
38
|
-
export * from './components/general/schema-recipe';
|
|
39
|
-
export * from './components/general/schema-review';
|
|
40
|
-
export * from './components/general/schema-services';
|
|
41
|
-
export * from './components/general/schema-website';
|
|
32
|
+
export * from './components/general/schema';
|
|
33
|
+
export * from './components/general/schema.functions';
|
|
42
34
|
export * from './components/general/semantic';
|
|
43
35
|
export * from './components/general/sidepanel';
|
|
44
36
|
export * from './components/general/sitemap';
|
|
@@ -54,12 +46,11 @@ export * from './components/general/tiles';
|
|
|
54
46
|
export * from './components/general/timeline';
|
|
55
47
|
export * from './components/integrations/calendly';
|
|
56
48
|
export * from './components/integrations/cloudinary';
|
|
57
|
-
export * from './components/integrations/lipsum';
|
|
58
|
-
export * from './components/integrations/loremipsum';
|
|
59
49
|
export * from './components/integrations/contentful.delivery';
|
|
60
50
|
export * from './components/integrations/contentful.items.components';
|
|
61
51
|
export * from './components/integrations/contentful.management';
|
|
62
52
|
export * from './components/integrations/flickr';
|
|
53
|
+
export * from './components/integrations/gemini-api.client';
|
|
63
54
|
export * from './components/integrations/google.reviews.components';
|
|
64
55
|
export * from './components/integrations/google.reviews.functions';
|
|
65
56
|
export * from './components/integrations/googleanalytics';
|
|
@@ -70,8 +61,11 @@ export * from './components/integrations/gravatar.functions';
|
|
|
70
61
|
export * from './components/integrations/hubspot.components';
|
|
71
62
|
export * from './components/integrations/instagram.components';
|
|
72
63
|
export * from './components/integrations/instagram.functions';
|
|
64
|
+
export * from './components/integrations/lipsum';
|
|
65
|
+
export * from './components/integrations/loremipsum';
|
|
73
66
|
export * from './components/integrations/socialcard';
|
|
74
|
-
export * from './components/integrations/
|
|
67
|
+
export * from './components/integrations/spotify.components';
|
|
68
|
+
export * from './components/integrations/spotify.functions';
|
|
75
69
|
export * from './components/integrations/wordpress.components';
|
|
76
70
|
export * from './components/integrations/wordpress.functions';
|
|
77
71
|
export * from './components/integrations/yelp';
|
package/dist/index.server.js
CHANGED
|
@@ -12,7 +12,7 @@ export * from './components/general/manifest';
|
|
|
12
12
|
export * from './components/general/metadata.functions';
|
|
13
13
|
export * from './components/general/proxy-handler';
|
|
14
14
|
export * from './components/general/resume';
|
|
15
|
-
export * from './components/general/schema
|
|
15
|
+
export * from './components/general/schema.functions';
|
|
16
16
|
export * from './components/general/sitemap';
|
|
17
17
|
export * from './components/general/skeleton';
|
|
18
18
|
export * from './components/general/well-known';
|
|
@@ -26,6 +26,8 @@ export * from './components/integrations/google.reviews.functions';
|
|
|
26
26
|
export * from './components/integrations/gravatar.functions';
|
|
27
27
|
export * from './components/integrations/instagram.functions';
|
|
28
28
|
export * from './components/integrations/lipsum';
|
|
29
|
+
export * from './components/integrations/spotify.components';
|
|
30
|
+
export * from './components/integrations/spotify.functions';
|
|
29
31
|
export * from './components/integrations/wordpress.functions';
|
|
30
32
|
export * from './components/shoppingcart/ebay.functions';
|
|
31
33
|
export * from './components/sitebuilder/config/ConfigEngine';
|
package/dist/scripts/release.sh
CHANGED
|
@@ -164,21 +164,15 @@ fi
|
|
|
164
164
|
echo ""
|
|
165
165
|
echo "📦 Step $((STEP_COUNT++)): Updating dependencies (all sections)..."
|
|
166
166
|
echo "================================================="
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
echo "✅ No $scope updates needed"
|
|
177
|
-
fi
|
|
178
|
-
done
|
|
179
|
-
# report peer deps separately
|
|
180
|
-
peers=$(npm outdated --parseable --long --peer | awk -F: '{print $4}')
|
|
181
|
-
printf "peer deps (manual): %s\n" "$peers"
|
|
167
|
+
if [ -f "src/scripts/update.sh" ]; then
|
|
168
|
+
bash src/scripts/update.sh
|
|
169
|
+
elif [ -f "scripts/update.sh" ]; then
|
|
170
|
+
bash scripts/update.sh
|
|
171
|
+
elif command -v npm &> /dev/null; then
|
|
172
|
+
npm run update 2>/dev/null || echo "⚠️ No update script found; skipping dependency update"
|
|
173
|
+
else
|
|
174
|
+
echo "⚠️ Could not find update.sh; skipping dependency update"
|
|
175
|
+
fi
|
|
182
176
|
|
|
183
177
|
|
|
184
178
|
|
package/dist/scripts/update.sh
CHANGED
|
@@ -4,15 +4,25 @@ set -euo pipefail
|
|
|
4
4
|
# update.sh - refresh dependencies across all sections
|
|
5
5
|
# usage: bash src/scripts/update.sh
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
# Dynamically build skip list from packages with pinned versions (no ^, ~, or *)
|
|
8
|
+
if command -v jq &> /dev/null; then
|
|
9
|
+
SKIP_PACKAGES=$(jq -r '.devDependencies // {} | to_entries[] | select(.value | test("^[0-9]")) | .key' package.json 2>/dev/null | paste -sd '|' - || echo "")
|
|
10
|
+
else
|
|
11
|
+
SKIP_PACKAGES=""
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
for type in "" --dev --optional; do
|
|
8
15
|
case $type in
|
|
9
16
|
"") flag=""; installArgs="--save" ;;
|
|
10
|
-
--dev) flag
|
|
11
|
-
--optional) flag
|
|
12
|
-
--peer) flag=--peer; installArgs="" ;;
|
|
17
|
+
--dev) flag="--include=dev"; installArgs="--save-dev" ;;
|
|
18
|
+
--optional) flag="--include=optional"; installArgs="--save-optional" ;;
|
|
13
19
|
esac
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
if [ -n "$SKIP_PACKAGES" ]; then
|
|
22
|
+
UPDATES=$(npm outdated $flag | awk 'NR>1 {print $1"@"$4}' | grep -vE "^($SKIP_PACKAGES)@" || true)
|
|
23
|
+
else
|
|
24
|
+
UPDATES=$(npm outdated $flag | awk 'NR>1 {print $1"@"$4}' || true)
|
|
25
|
+
fi
|
|
16
26
|
if [ -n "$UPDATES" ]; then
|
|
17
27
|
echo "Updating $type packages: $UPDATES"
|
|
18
28
|
if [ "$type" = "--peer" ]; then
|
|
@@ -26,8 +36,35 @@ for type in "" --dev --optional --peer; do
|
|
|
26
36
|
fi
|
|
27
37
|
done
|
|
28
38
|
|
|
29
|
-
#
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
# Handle peer dependencies
|
|
40
|
+
echo ""
|
|
41
|
+
echo "Checking peer dependencies for updates..."
|
|
42
|
+
if command -v jq &> /dev/null; then
|
|
43
|
+
peers=$(jq -r '.peerDependencies // {} | to_entries[] | "\(.key)=\(.value)"' package.json 2>/dev/null)
|
|
44
|
+
if [ -n "$peers" ]; then
|
|
45
|
+
while IFS='=' read -r pkgname current_constraint; do
|
|
46
|
+
if [ -n "$pkgname" ]; then
|
|
47
|
+
# Extract installed version from node_modules
|
|
48
|
+
installed=$(npm ls "$pkgname" --depth=0 2>/dev/null | grep "$pkgname" | sed 's/.*@\([0-9.]*\).*/\1/' | head -1)
|
|
49
|
+
# Get latest version
|
|
50
|
+
latest=$(npm view "$pkgname" version 2>/dev/null)
|
|
51
|
+
if [ -n "$latest" ] && [ -n "$installed" ]; then
|
|
52
|
+
# Only update if installed version is different from latest
|
|
53
|
+
if [ "$latest" != "$installed" ]; then
|
|
54
|
+
echo "📦 Updating peer dependency: $pkgname from $installed to $latest"
|
|
55
|
+
npm install "$pkgname@$latest" --save-peer 2>/dev/null || npm install "$pkgname@$latest" --save-dev 2>/dev/null || true
|
|
56
|
+
else
|
|
57
|
+
echo "✅ $pkgname is up to date ($latest)"
|
|
58
|
+
fi
|
|
59
|
+
fi
|
|
60
|
+
fi
|
|
61
|
+
done <<< "$peers"
|
|
62
|
+
else
|
|
63
|
+
echo "✅ No peer dependencies to update"
|
|
64
|
+
fi
|
|
65
|
+
else
|
|
66
|
+
echo "⚠️ jq not found - skipping peer dependency updates"
|
|
67
|
+
echo " Run 'npm ls --peer' to check peer dependencies manually"
|
|
68
|
+
fi
|
|
32
69
|
|
|
33
70
|
npm audit fix 2>/dev/null || true
|