dn-react-router-toolkit 0.1.6 → 0.1.8

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.
@@ -1,249 +1,257 @@
1
1
  // src/seo-kit/seo.tsx
2
2
  import React from "react";
3
+ import { useMatches } from "react-router";
3
4
  function configSEO(config) {
4
- return {
5
- config,
6
- async init(props = {}) {
7
- const canonicalPath = props.canonicalPath;
8
- const url = canonicalPath ? `${config.origin}${canonicalPath}` : `${config.origin}${props.path || ""}`;
9
- const pageTitle = props.title ? `${props.title} | ${config.siteName}` : config.siteName;
10
- const description = props.description || config.description;
11
- const keywords = props.keywords || config.keywords;
12
- const websiteSchemaId = `${config.origin}/#website`;
13
- const websiteSchema = {
14
- "@type": "WebSite",
15
- "@id": websiteSchemaId,
16
- url: config.origin,
17
- name: config.siteName,
18
- alternateName: config.siteName,
19
- description: config.description,
20
- inLanguage: "ko"
5
+ function init(props) {
6
+ const canonicalPath = props.canonicalPath;
7
+ const url = canonicalPath ? `${config.origin}${canonicalPath === "/" ? "" : canonicalPath}` : `${config.origin}${props.path || ""}`;
8
+ const pageTitle = props.title ? `${props.title} | ${config.siteName}` : config.siteName;
9
+ const description = props.description || config.description;
10
+ const keywords = props.keywords || config.keywords;
11
+ const thumbnail = props.thumbnail || (typeof config.thumbnail === "function" ? config.thumbnail() : config.thumbnail);
12
+ return {
13
+ pageTitle,
14
+ type: props.type,
15
+ description,
16
+ keywords,
17
+ url,
18
+ thumbnail
19
+ };
20
+ }
21
+ const meta = ({ loaderData }) => {
22
+ const props = loaderData?.seo || {};
23
+ const { pageTitle, type, description, keywords, url, thumbnail } = props;
24
+ const socialImage = thumbnail ? [
25
+ typeof thumbnail === "string" ? {
26
+ url: thumbnail,
27
+ alt: `${props.title} \uB300\uD45C \uC774\uBBF8\uC9C0`
28
+ } : thumbnail
29
+ ] : [];
30
+ return [
31
+ pageTitle && { title: pageTitle },
32
+ description && { name: "description", content: description },
33
+ keywords && { name: "keywords", content: keywords.join(", ") },
34
+ url && {
35
+ tagName: "link",
36
+ rel: "canonical",
37
+ href: url
38
+ },
39
+ { property: "og:type", content: type || "website" },
40
+ pageTitle && { property: "og:title", content: pageTitle },
41
+ description && { property: "og:description", content: description },
42
+ url && { property: "og:url", content: url },
43
+ { property: "og:site_name", content: config.siteName },
44
+ ...socialImage?.map((file) => ({
45
+ property: "og:image",
46
+ content: file.url
47
+ })),
48
+ {
49
+ property: "twitter:card",
50
+ content: socialImage.length > 0 ? "summary_large_image" : "summary"
51
+ },
52
+ pageTitle && { property: "twitter:title", content: pageTitle },
53
+ description && { property: "twitter:description", content: description },
54
+ ...socialImage?.map((file) => ({
55
+ property: "twitter:image",
56
+ content: file.url
57
+ }))
58
+ ];
59
+ };
60
+ function StructedData() {
61
+ const matches = useMatches();
62
+ const data = matches.reduce((acc, match) => {
63
+ return {
64
+ ...acc,
65
+ ...match.loaderData?.seo || {}
21
66
  };
22
- const thumbnailSchemaId = `${url}/#thumbnail`;
23
- const thumbnail = props.thumbnail || (typeof config.thumbnail === "function" ? await config.thumbnail() : config.thumbnail);
24
- const thumbnailUrl = thumbnail?.url;
25
- const socialImage = thumbnail ? [
26
- typeof thumbnail === "string" ? {
27
- url: thumbnail,
67
+ }, {});
68
+ const { pageTitle, description, keywords, url, thumbnail } = data;
69
+ const thumbnailUrl = thumbnail?.url;
70
+ const props = data?.seo || {};
71
+ const websiteSchemaId = `${config.origin}/#website`;
72
+ const websiteSchema = {
73
+ "@type": "WebSite",
74
+ "@id": websiteSchemaId,
75
+ url: config.origin,
76
+ name: config.siteName,
77
+ alternateName: config.siteName,
78
+ description: config.description,
79
+ inLanguage: "ko"
80
+ };
81
+ const thumbnailSchemaId = `${url}/#thumbnail`;
82
+ const images = [
83
+ ...thumbnailUrl ? [
84
+ {
85
+ id: thumbnailSchemaId,
86
+ url: thumbnailUrl,
28
87
  alt: `${props.title} \uB300\uD45C \uC774\uBBF8\uC9C0`
29
- } : thumbnail
30
- ] : [];
31
- const images = [
32
- ...thumbnailUrl ? [
33
- {
34
- id: thumbnailSchemaId,
35
- url: thumbnailUrl,
36
- alt: `${props.title} \uB300\uD45C \uC774\uBBF8\uC9C0`
37
- }
38
- ] : [],
39
- ...props.images || [],
40
- ...props.collection?.map((portfolio) => portfolio.thumbnail) || []
41
- ].filter(Boolean);
42
- const image = images.filter((file) => file.id).map((file) => ({
43
- "@type": "ImageObject",
44
- "@id": `${url}/#${file.id}`
45
- }));
46
- const breadcrumbSchemaId = `${url}#breadcrumb`;
47
- const updatedAt = props.updatedAt;
48
- const createdAt = props.createdAt;
49
- const meta = () => {
50
- return [
51
- { title: pageTitle },
52
- { name: "description", content: description },
53
- { name: "keywords", content: keywords?.join(", ") || "" },
54
- {
55
- tagName: "link",
56
- rel: "canonical",
57
- href: url
88
+ }
89
+ ] : [],
90
+ ...props.images || [],
91
+ ...props.collection?.map((portfolio) => portfolio.thumbnail) || []
92
+ ].filter(Boolean);
93
+ const image = images.filter((file) => file.id).map((file) => ({
94
+ "@type": "ImageObject",
95
+ "@id": `${url}/#${file.id}`
96
+ }));
97
+ const breadcrumbSchemaId = `${url}#breadcrumb`;
98
+ const updatedAt = props.updatedAt;
99
+ const createdAt = props.createdAt;
100
+ const additionalStructedData = [
101
+ ...typeof props.structedData === "function" ? props.structedData() : props.structedData || [],
102
+ ...typeof config.structedData === "function" ? config.structedData() : config.structedData || []
103
+ ];
104
+ const collectionMainEntity = props.collection ? {
105
+ "@type": "ItemList",
106
+ numberOfItems: props.collection.length,
107
+ itemListElement: props.collection.map((item, index) => ({
108
+ "@type": "ListItem",
109
+ position: index + 1,
110
+ url: item.url,
111
+ item: {
112
+ "@type": "WebPage",
113
+ "@id": `${item.url}#webpage`,
114
+ url: item.url,
115
+ name: item.title,
116
+ thumbnailUrl: item.thumbnail?.url,
117
+ dateModified: item.updatedAt?.toISOString(),
118
+ dateCreated: item.createdAt?.toISOString(),
119
+ datePublished: item.createdAt?.toISOString()
120
+ }
121
+ }))
122
+ } : void 0;
123
+ const structuredData = {
124
+ "@context": "https://schema.org",
125
+ "@graph": [
126
+ {
127
+ "@type": "WebPage",
128
+ "@id": `${url}#webpage`,
129
+ url,
130
+ name: pageTitle,
131
+ description,
132
+ keywords,
133
+ dateModified: updatedAt?.toISOString(),
134
+ datePublished: createdAt?.toISOString(),
135
+ dateCreated: createdAt?.toISOString(),
136
+ primaryImageOfPage: thumbnail ? {
137
+ "@id": thumbnailSchemaId
138
+ } : void 0,
139
+ isPartOf: {
140
+ "@id": websiteSchemaId
58
141
  },
59
- { property: "og:type", content: props.type || "website" },
60
- { property: "og:title", content: pageTitle },
61
- { property: "og:description", content: description },
62
- { property: "og:url", content: url },
63
- { property: "og:site_name", content: config.siteName },
64
- ...socialImage.map((file) => ({
65
- property: "og:image",
66
- content: file.url
67
- })),
68
- {
69
- property: "twitter:card",
70
- content: socialImage.length > 0 ? "summary_large_image" : "summary"
142
+ inLanguage: "ko",
143
+ breadcrumb: props.breadcrumbs && props.breadcrumbs.length > 0 ? {
144
+ "@id": breadcrumbSchemaId
145
+ } : void 0,
146
+ image,
147
+ mainEntity: collectionMainEntity
148
+ },
149
+ props.article && {
150
+ "@type": "Article",
151
+ "@id": `${url}#article`,
152
+ url,
153
+ name: pageTitle,
154
+ description,
155
+ keywords,
156
+ headline: pageTitle,
157
+ dateModified: updatedAt?.toISOString(),
158
+ datePublished: createdAt?.toISOString(),
159
+ dateCreated: createdAt?.toISOString(),
160
+ isPartOf: {
161
+ "@id": websiteSchemaId
71
162
  },
72
- { property: "twitter:title", content: pageTitle },
73
- { property: "twitter:description", content: description },
74
- ...socialImage.map((file) => ({
75
- property: "twitter:image",
76
- content: file.url
77
- }))
78
- ];
79
- };
80
- const additionalStructedData = [
81
- ...typeof props.structedData === "function" ? await props.structedData() : props.structedData || [],
82
- ...typeof config.structedData === "function" ? await config.structedData() : config.structedData || []
83
- ];
84
- function getStructedData() {
85
- const collectionMainEntity = props.collection ? {
86
- "@type": "ItemList",
87
- numberOfItems: props.collection.length,
88
- itemListElement: props.collection.map((item, index) => ({
89
- "@type": "ListItem",
90
- position: index + 1,
91
- url: item.url,
92
- item: {
93
- "@type": "WebPage",
94
- "@id": `${item.url}#webpage`,
95
- url: item.url,
96
- name: item.title,
97
- thumbnailUrl: item.thumbnail?.url,
98
- dateModified: item.updatedAt?.toISOString(),
99
- dateCreated: item.createdAt?.toISOString(),
100
- datePublished: item.createdAt?.toISOString()
101
- }
102
- }))
103
- } : void 0;
104
- return {
105
- "@context": "https://schema.org",
106
- "@graph": [
107
- {
108
- "@type": "WebPage",
109
- "@id": `${url}#webpage`,
110
- url,
111
- name: pageTitle,
112
- description,
113
- keywords,
114
- dateModified: updatedAt?.toISOString(),
115
- datePublished: createdAt?.toISOString(),
116
- dateCreated: createdAt?.toISOString(),
117
- primaryImageOfPage: thumbnail ? {
118
- "@id": thumbnailSchemaId
119
- } : void 0,
120
- isPartOf: {
121
- "@id": websiteSchemaId
122
- },
123
- inLanguage: "ko",
124
- breadcrumb: props.breadcrumbs && props.breadcrumbs.length > 0 ? {
125
- "@id": breadcrumbSchemaId
126
- } : void 0,
127
- image,
128
- mainEntity: collectionMainEntity
129
- },
130
- props.article && {
131
- "@type": "Article",
132
- "@id": `${url}#article`,
133
- url,
134
- name: pageTitle,
135
- description,
136
- keywords,
137
- headline: pageTitle,
138
- dateModified: updatedAt?.toISOString(),
139
- datePublished: createdAt?.toISOString(),
140
- dateCreated: createdAt?.toISOString(),
141
- isPartOf: {
142
- "@id": websiteSchemaId
143
- },
144
- inLanguage: "ko",
145
- image
146
- },
147
- props.blogPosting && {
148
- "@type": "BlogPosting",
149
- "@id": `${url}/#blogposting`,
150
- url,
151
- headline: pageTitle,
152
- description,
153
- thumbnailUrl,
154
- datePublished: createdAt?.toISOString(),
155
- dateModified: updatedAt?.toISOString(),
156
- isPartOf: { "@id": websiteSchemaId },
157
- image
158
- },
159
- props.creativeWork && {
160
- "@type": "CreativeWork",
161
- "@id": `${url}/#creativework`,
162
- url,
163
- name: pageTitle,
164
- description,
165
- datePublished: createdAt?.toISOString(),
166
- dateModified: updatedAt?.toISOString(),
167
- isPartOf: { "@id": websiteSchemaId },
168
- thumbnailUrl,
169
- image
170
- },
171
- props.visualArtwork && {
172
- "@type": "VisualArtwork",
173
- "@id": `${url}/#visualartwork`,
174
- url,
175
- name: pageTitle,
176
- description,
177
- datePublished: createdAt?.toISOString(),
178
- dateModified: updatedAt?.toISOString(),
179
- isPartOf: { "@id": websiteSchemaId },
180
- thumbnailUrl,
181
- image
182
- },
183
- props.collection && {
184
- "@type": "CollectionPage",
185
- "@id": `${url}/#collectionpage`,
186
- url,
187
- name: pageTitle,
188
- description,
189
- isPartOf: { "@id": websiteSchemaId },
190
- image,
191
- inLanguage: "ko-KR",
192
- breadcrumb: props.breadcrumbs && props.breadcrumbs.length > 0 ? {
193
- "@id": `${url}/#breadcrumb`
194
- } : void 0,
195
- mainEntity: collectionMainEntity
196
- },
197
- websiteSchema,
198
- props.breadcrumbs && props.breadcrumbs.length > 0 && {
199
- "@id": breadcrumbSchemaId,
200
- "@type": "BreadcrumbList",
201
- itemListElement: props.breadcrumbs.map((breadcrumb, index) => ({
202
- "@type": "ListItem",
203
- position: index + 1,
204
- name: breadcrumb.label,
205
- item: `${config.origin}${breadcrumb.href}`
206
- }))
207
- },
208
- ...additionalStructedData,
209
- ...images.map((file) => {
210
- return {
211
- "@type": "ImageObject",
212
- "@id": `${url}/#${file.id}`,
213
- url: file.url,
214
- contentUrl: file.url,
215
- name: file.alt,
216
- description: file.alt,
217
- width: file?.width?.toString(),
218
- height: file?.height?.toString(),
219
- creditText: config.copyright,
220
- license: `${config.origin}/terms`,
221
- copyrightNotice: config.copyright,
222
- acquireLicensePage: `${config.origin}/terms`
223
- };
163
+ inLanguage: "ko",
164
+ image
165
+ },
166
+ props.blogPosting && {
167
+ "@type": "BlogPosting",
168
+ "@id": `${url}/#blogposting`,
169
+ url,
170
+ headline: pageTitle,
171
+ description,
172
+ thumbnailUrl,
173
+ datePublished: createdAt?.toISOString(),
174
+ dateModified: updatedAt?.toISOString(),
175
+ isPartOf: { "@id": websiteSchemaId },
176
+ image
177
+ },
178
+ props.creativeWork && {
179
+ "@type": "CreativeWork",
180
+ "@id": `${url}/#creativework`,
181
+ url,
182
+ name: pageTitle,
183
+ description,
184
+ datePublished: createdAt?.toISOString(),
185
+ dateModified: updatedAt?.toISOString(),
186
+ isPartOf: { "@id": websiteSchemaId },
187
+ thumbnailUrl,
188
+ image
189
+ },
190
+ props.visualArtwork && {
191
+ "@type": "VisualArtwork",
192
+ "@id": `${url}/#visualartwork`,
193
+ url,
194
+ name: pageTitle,
195
+ description,
196
+ datePublished: createdAt?.toISOString(),
197
+ dateModified: updatedAt?.toISOString(),
198
+ isPartOf: { "@id": websiteSchemaId },
199
+ thumbnailUrl,
200
+ image
201
+ },
202
+ props.collection && {
203
+ "@type": "CollectionPage",
204
+ "@id": `${url}/#collectionpage`,
205
+ url,
206
+ name: pageTitle,
207
+ description,
208
+ isPartOf: { "@id": websiteSchemaId },
209
+ image,
210
+ inLanguage: "ko-KR",
211
+ breadcrumb: props.breadcrumbs && props.breadcrumbs.length > 0 ? {
212
+ "@id": `${url}/#breadcrumb`
213
+ } : void 0,
214
+ mainEntity: collectionMainEntity
215
+ },
216
+ websiteSchema,
217
+ props.breadcrumbs && props.breadcrumbs.length > 0 && {
218
+ "@id": breadcrumbSchemaId,
219
+ "@type": "BreadcrumbList",
220
+ itemListElement: props.breadcrumbs.map(
221
+ (breadcrumb, index) => ({
222
+ "@type": "ListItem",
223
+ position: index + 1,
224
+ name: breadcrumb.title,
225
+ item: `${config.origin}${breadcrumb.href}`
224
226
  })
225
- ].filter(Boolean)
226
- };
227
- }
228
- function generateJSONLD() {
229
- const structedData = getStructedData();
230
- return /* @__PURE__ */ React.createElement(
231
- "script",
232
- {
233
- type: "application/ld+json",
234
- dangerouslySetInnerHTML: {
235
- __html: JSON.stringify(structedData).replace(/</g, "\\u003c")
236
- }
237
- }
238
- );
239
- }
240
- return {
241
- config,
242
- props,
243
- meta,
244
- generateJSONLD
245
- };
246
- }
227
+ )
228
+ },
229
+ ...additionalStructedData,
230
+ ...images.map((file) => {
231
+ return {
232
+ "@type": "ImageObject",
233
+ "@id": `${url}/#${file.id}`,
234
+ url: file.url,
235
+ contentUrl: file.url,
236
+ name: file.alt,
237
+ description: file.alt,
238
+ width: file?.width?.toString(),
239
+ height: file?.height?.toString(),
240
+ creditText: config.copyright,
241
+ license: `${config.origin}/terms`,
242
+ copyrightNotice: config.copyright,
243
+ acquireLicensePage: `${config.origin}/terms`
244
+ };
245
+ })
246
+ ].filter(Boolean)
247
+ };
248
+ return /* @__PURE__ */ React.createElement("script", { type: "application/ld+json" }, JSON.stringify(structuredData));
249
+ }
250
+ return {
251
+ config,
252
+ init,
253
+ meta,
254
+ StructedData
247
255
  };
248
256
  }
249
257
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dn-react-router-toolkit",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "types": "./dist/index.d.ts",
5
5
  "main": "./dist/index.mjs",
6
6
  "module": "./dist/index.js",
@@ -1,6 +0,0 @@
1
- export { LoaderFn, createLoader } from './loader.mjs';
2
- export { createSEOLoader } from './seo_loader.mjs';
3
- export { SEO, SEOImage, configSEO } from './seo.mjs';
4
- import 'react-router';
5
- import 'react';
6
- import 'schema-dts';
@@ -1,6 +0,0 @@
1
- export { LoaderFn, createLoader } from './loader.js';
2
- export { createSEOLoader } from './seo_loader.js';
3
- export { SEO, SEOImage, configSEO } from './seo.js';
4
- import 'react-router';
5
- import 'react';
6
- import 'schema-dts';