@treely/strapi-slices 7.9.0 → 7.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/SEOTags/SEOTags.d.ts +10 -0
- package/dist/strapi-slices.cjs.development.js +105 -2
- package/dist/strapi-slices.cjs.development.js.map +1 -1
- package/dist/strapi-slices.cjs.production.min.js +1 -1
- package/dist/strapi-slices.cjs.production.min.js.map +1 -1
- package/dist/strapi-slices.esm.js +105 -2
- package/dist/strapi-slices.esm.js.map +1 -1
- package/package.json +2 -1
- package/src/components/SEOTags/SEOTags.tsx +175 -0
- package/src/slices/ProjectsMap/ProjectsMap.tsx +1 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { Article, BlogPosting, Brand, BreadcrumbList, Event, FAQPage, HowTo, LocalBusiness, Offer, Organization, Person, Product, Service, WebPage, WithContext } from 'schema-dts';
|
|
3
|
+
type SupportedSchemaType = Article | BlogPosting | Brand | BreadcrumbList | Event | FAQPage | HowTo | LocalBusiness | Offer | Organization | Person | Product | Service | WebPage;
|
|
2
4
|
interface SEOTagsProps {
|
|
3
5
|
title: string;
|
|
4
6
|
description: string;
|
|
@@ -9,6 +11,14 @@ interface SEOTagsProps {
|
|
|
9
11
|
metaTitleSuffix?: string;
|
|
10
12
|
favicon?: string;
|
|
11
13
|
domain?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Structured data for SEO purposes, following the schema.org standard.
|
|
16
|
+
* This can be a single schema object or an array of schema objects.
|
|
17
|
+
* Each object must include an `@context` property set to "https://schema.org"
|
|
18
|
+
* and an `@type` property indicating the type of schema (e.g., Article, Product).
|
|
19
|
+
* The schema falls back to the default schema if it is invalid.
|
|
20
|
+
*/
|
|
21
|
+
schemaMarkup?: WithContext<SupportedSchemaType> | WithContext<SupportedSchemaType>[];
|
|
12
22
|
}
|
|
13
23
|
export declare const SEOTags: React.FC<SEOTagsProps>;
|
|
14
24
|
export {};
|
|
@@ -903,6 +903,86 @@ var PreviewAlert = function PreviewAlert() {
|
|
|
903
903
|
}));
|
|
904
904
|
};
|
|
905
905
|
|
|
906
|
+
// Helper function to convert SchemaValue to string
|
|
907
|
+
var getTextValue = function getTextValue(value) {
|
|
908
|
+
if (typeof value === 'string') return value;
|
|
909
|
+
if (typeof value === 'object' && value !== null && 'text' in value) {
|
|
910
|
+
return value.text;
|
|
911
|
+
}
|
|
912
|
+
return '';
|
|
913
|
+
};
|
|
914
|
+
// Helper function to safely access properties from a schema
|
|
915
|
+
var getSchemaProperty = function getSchemaProperty(schema, property) {
|
|
916
|
+
return getTextValue(schema[property]) || '';
|
|
917
|
+
};
|
|
918
|
+
// Helper function to get a unique identifier from a schema
|
|
919
|
+
var getSchemaIdentifier = function getSchemaIdentifier(schema) {
|
|
920
|
+
var _offer$price;
|
|
921
|
+
var type = schema['@type'];
|
|
922
|
+
switch (type) {
|
|
923
|
+
case 'Organization':
|
|
924
|
+
return getSchemaProperty(schema, 'name') || 'default';
|
|
925
|
+
case 'Article':
|
|
926
|
+
case 'BlogPosting':
|
|
927
|
+
return getSchemaProperty(schema, 'headline') || 'untitled-article';
|
|
928
|
+
case 'Product':
|
|
929
|
+
return getSchemaProperty(schema, 'name') || 'untitled-product';
|
|
930
|
+
case 'Person':
|
|
931
|
+
return getSchemaProperty(schema, 'name') || 'unnamed-person';
|
|
932
|
+
case 'Event':
|
|
933
|
+
return getSchemaProperty(schema, 'name') || 'untitled-event';
|
|
934
|
+
case 'LocalBusiness':
|
|
935
|
+
return getSchemaProperty(schema, 'name') || 'unnamed-business';
|
|
936
|
+
case 'Service':
|
|
937
|
+
return getSchemaProperty(schema, 'name') || 'unnamed-service';
|
|
938
|
+
case 'Brand':
|
|
939
|
+
return getSchemaProperty(schema, 'name') || 'unnamed-brand';
|
|
940
|
+
case 'FAQPage':
|
|
941
|
+
return 'faq-page';
|
|
942
|
+
case 'HowTo':
|
|
943
|
+
return getSchemaProperty(schema, 'name') || 'untitled-howto';
|
|
944
|
+
case 'BreadcrumbList':
|
|
945
|
+
return 'breadcrumbs';
|
|
946
|
+
case 'Offer':
|
|
947
|
+
var offer = schema;
|
|
948
|
+
return "offer-" + ((_offer$price = offer.price) != null ? _offer$price : 'unknown-price');
|
|
949
|
+
case 'WebPage':
|
|
950
|
+
return getSchemaProperty(schema, 'name') || 'untitled-page';
|
|
951
|
+
default:
|
|
952
|
+
return 'unknown-schema';
|
|
953
|
+
}
|
|
954
|
+
};
|
|
955
|
+
var validateSchema = function validateSchema(schema) {
|
|
956
|
+
if (Array.isArray(schema)) {
|
|
957
|
+
return schema.every(function (item) {
|
|
958
|
+
return item['@context'] === 'https://schema.org' && '@type' in item;
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
return schema['@context'] === 'https://schema.org' && '@type' in schema;
|
|
962
|
+
};
|
|
963
|
+
var DEFAULT_SCHEMA = {
|
|
964
|
+
'@context': 'https://schema.org',
|
|
965
|
+
'@type': 'Organization',
|
|
966
|
+
name: 'Tree.ly',
|
|
967
|
+
url: 'https://tree.ly',
|
|
968
|
+
logo: 'https://cdn.tree.ly/logo.png',
|
|
969
|
+
address: {
|
|
970
|
+
'@type': 'PostalAddress',
|
|
971
|
+
streetAddress: 'Littengasse 2b/c',
|
|
972
|
+
addressLocality: 'Dornbirn',
|
|
973
|
+
postalCode: '6850',
|
|
974
|
+
addressRegion: 'Vorarlberg',
|
|
975
|
+
addressCountry: 'AT'
|
|
976
|
+
},
|
|
977
|
+
contactPoint: {
|
|
978
|
+
'@type': 'ContactPoint',
|
|
979
|
+
telephone: '+43-5572-432015',
|
|
980
|
+
contactType: 'Customer Service',
|
|
981
|
+
areaServed: 'AT',
|
|
982
|
+
availableLanguage: ['English', 'German']
|
|
983
|
+
},
|
|
984
|
+
sameAs: ['https://www.linkedin.com/company/tree-ly', 'https://www.facebook.com/treely', 'https://www.instagram.com/treely']
|
|
985
|
+
};
|
|
906
986
|
var SEOTags = function SEOTags(_ref) {
|
|
907
987
|
var _shareImage$url, _shareImage$alt;
|
|
908
988
|
var title = _ref.title,
|
|
@@ -913,9 +993,24 @@ var SEOTags = function SEOTags(_ref) {
|
|
|
913
993
|
_ref$favicon = _ref.favicon,
|
|
914
994
|
favicon = _ref$favicon === void 0 ? 'https://cdn.tree.ly/favicon.ico' : _ref$favicon,
|
|
915
995
|
_ref$domain = _ref.domain,
|
|
916
|
-
domain = _ref$domain === void 0 ? 'tree.ly' : _ref$domain
|
|
996
|
+
domain = _ref$domain === void 0 ? 'tree.ly' : _ref$domain,
|
|
997
|
+
schemaMarkup = _ref.schemaMarkup;
|
|
917
998
|
var shareImageUrl = (_shareImage$url = shareImage == null ? void 0 : shareImage.url) != null ? _shareImage$url : DEFAULT_SHARE_IMAGE;
|
|
918
999
|
var shareImageAlt = (_shareImage$alt = shareImage == null ? void 0 : shareImage.alt) != null ? _shareImage$alt : DEFAULT_SHARE_ALT;
|
|
1000
|
+
var schemas = schemaMarkup || DEFAULT_SCHEMA;
|
|
1001
|
+
var isValidSchema = validateSchema(schemas);
|
|
1002
|
+
if (schemaMarkup && !isValidSchema) {
|
|
1003
|
+
console.warn('Invalid schema markup provided to SEOTags component. Falling back to default schema.', schemaMarkup);
|
|
1004
|
+
schemas = DEFAULT_SCHEMA;
|
|
1005
|
+
isValidSchema = true;
|
|
1006
|
+
}
|
|
1007
|
+
var schemaArray = Array.isArray(schemas) ? schemas : [schemas];
|
|
1008
|
+
var getSchemaKey = function getSchemaKey(schema, index) {
|
|
1009
|
+
var type = schema['@type'];
|
|
1010
|
+
var identifier = getSchemaIdentifier(schema);
|
|
1011
|
+
// Add index to ensure uniqueness, especially for fallback identifiers
|
|
1012
|
+
return type + "-" + identifier + "-" + index;
|
|
1013
|
+
};
|
|
919
1014
|
return React__default.default.createElement(Head__default.default, null, React__default.default.createElement("title", null, title + " - " + metaTitleSuffix), React__default.default.createElement("meta", {
|
|
920
1015
|
name: "description",
|
|
921
1016
|
content: description
|
|
@@ -961,6 +1056,14 @@ var SEOTags = function SEOTags(_ref) {
|
|
|
961
1056
|
}), React__default.default.createElement("meta", {
|
|
962
1057
|
name: "twitter:image:alt",
|
|
963
1058
|
content: shareImageAlt
|
|
1059
|
+
}), isValidSchema && schemaArray.map(function (schema, index) {
|
|
1060
|
+
return React__default.default.createElement("script", {
|
|
1061
|
+
key: getSchemaKey(schema, index),
|
|
1062
|
+
type: "application/ld+json",
|
|
1063
|
+
dangerouslySetInnerHTML: {
|
|
1064
|
+
__html: JSON.stringify(schema)
|
|
1065
|
+
}
|
|
1066
|
+
});
|
|
964
1067
|
}));
|
|
965
1068
|
};
|
|
966
1069
|
|
|
@@ -3681,7 +3784,7 @@ var ProjectsMap = function ProjectsMap(_ref) {
|
|
|
3681
3784
|
client.createRoot(ref.current).render(React__default.default.createElement(MinimalProviders, {
|
|
3682
3785
|
locale: locale
|
|
3683
3786
|
}, React__default.default.createElement(MapMarker, {
|
|
3684
|
-
title: project.title,
|
|
3787
|
+
title: project.friendlyName || project.title,
|
|
3685
3788
|
isPublic: project.isPublic,
|
|
3686
3789
|
portfolioHost: project.portfolioHost,
|
|
3687
3790
|
slug: project.slug,
|