@vicacha-devs/strapi-plugin-seo 0.0.0-stage → 2.1.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 (81) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +84 -2
  3. package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/AlternativeTextCheck/index.d.ts +9 -0
  4. package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/CanonicalUrlCheck/index.d.ts +7 -0
  5. package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/KeywordDensityCheck/index.d.ts +7 -0
  6. package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/LastUpdatedAtCheck/index.d.ts +7 -0
  7. package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/MetaDescriptionCheck/index.d.ts +7 -0
  8. package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/MetaRobotCheck/index.d.ts +7 -0
  9. package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/MetaTitleCheck/index.d.ts +7 -0
  10. package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/OpenGraphCheck/index.d.ts +7 -0
  11. package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/SEOAccordion/index.d.ts +10 -0
  12. package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/StructuredDataCheck/index.d.ts +7 -0
  13. package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/WordCountCheck/index.d.ts +7 -0
  14. package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/index.d.ts +10 -0
  15. package/dist/admin/components/CMEditView/RightLinksCompo/Summary/BrowserPreview/KeywordCheck/index.d.ts +7 -0
  16. package/dist/admin/components/CMEditView/RightLinksCompo/Summary/BrowserPreview/MetaChecks/index.d.ts +8 -0
  17. package/dist/admin/components/CMEditView/RightLinksCompo/Summary/BrowserPreview/Serp/index.d.ts +6 -0
  18. package/dist/admin/components/CMEditView/RightLinksCompo/Summary/BrowserPreview/index.d.ts +6 -0
  19. package/dist/admin/components/CMEditView/RightLinksCompo/Summary/OpenGraphPreview/Facebook/index.d.ts +8 -0
  20. package/dist/admin/components/CMEditView/RightLinksCompo/Summary/OpenGraphPreview/LinkedIn/index.d.ts +8 -0
  21. package/dist/admin/components/CMEditView/RightLinksCompo/Summary/OpenGraphPreview/X/index.d.ts +8 -0
  22. package/dist/admin/components/CMEditView/RightLinksCompo/Summary/OpenGraphPreview/index.d.ts +6 -0
  23. package/dist/admin/components/CMEditView/RightLinksCompo/Summary/PreviewChecks/index.d.ts +6 -0
  24. package/dist/admin/components/CMEditView/RightLinksCompo/Summary/index.d.ts +4 -0
  25. package/dist/admin/components/CMEditView/RightLinksCompo/Summary/reducer.d.ts +2 -0
  26. package/dist/admin/components/CMEditView/RightLinksCompo/index.d.ts +1 -0
  27. package/dist/admin/components/CMEditView/utils/checks.d.ts +14 -0
  28. package/dist/admin/components/CMEditView/utils/getRegularImageAltTexts.d.ts +5 -0
  29. package/dist/admin/components/CMEditView/utils/getRichTextAndBlocksFields.d.ts +10 -0
  30. package/dist/admin/components/CMEditView/utils/getRichTextData.d.ts +2 -0
  31. package/dist/admin/components/HomePage/Header/index.d.ts +5 -0
  32. package/dist/admin/components/HomePage/Main/EmptyComponentLayout/illo.d.ts +1 -0
  33. package/dist/admin/components/HomePage/Main/SettingsModal/index.d.ts +8 -0
  34. package/dist/admin/components/HomePage/Main/index.d.ts +6 -0
  35. package/dist/admin/components/Initializer.d.ts +5 -0
  36. package/dist/admin/hooks/useSettingsApi.d.ts +5 -0
  37. package/dist/admin/index-C8tiCtgn.cjs +3490 -0
  38. package/dist/admin/index-CJ64dp6B.js +3473 -0
  39. package/dist/admin/index-CZ4VBOGS.cjs +589 -0
  40. package/dist/admin/index-DgvE6ytW.js +571 -0
  41. package/dist/admin/index.cjs +5 -0
  42. package/dist/admin/index.d.ts +18 -0
  43. package/dist/admin/index.js +5 -0
  44. package/dist/admin/index.mjs +5 -0
  45. package/dist/admin/pages/App/index.d.ts +2 -0
  46. package/dist/admin/pages/HomePage/index.d.ts +2 -0
  47. package/dist/admin/permissions.d.ts +10 -0
  48. package/dist/admin/pluginId.d.ts +1 -0
  49. package/dist/admin/translations/ar.json.d.ts +133 -0
  50. package/dist/admin/translations/en.json.d.ts +133 -0
  51. package/dist/admin/translations/es.json.d.ts +133 -0
  52. package/dist/admin/translations/fr.json.d.ts +133 -0
  53. package/dist/admin/translations/pt-BR.json.d.ts +133 -0
  54. package/dist/admin/translations/tr.json.d.ts +133 -0
  55. package/dist/admin/utils/getTrad.d.ts +1 -0
  56. package/dist/admin/utils/prefixPluginTranslations.d.ts +1 -0
  57. package/dist/package.json +3 -0
  58. package/dist/server/bootstrap.d.ts +5 -0
  59. package/dist/server/components/open-graph.json.d.ts +36 -0
  60. package/dist/server/components/seo.json.d.ts +52 -0
  61. package/dist/server/config/index.d.ts +5 -0
  62. package/dist/server/controllers/index.d.ts +16 -0
  63. package/dist/server/controllers/seo.d.ts +13 -0
  64. package/dist/server/controllers/settings.d.ts +16 -0
  65. package/dist/server/destroy.d.ts +5 -0
  66. package/dist/server/index.cjs +416 -0
  67. package/dist/server/index.d.ts +83 -0
  68. package/dist/server/index.js +416 -0
  69. package/dist/server/index.mjs +416 -0
  70. package/dist/server/register.d.ts +5 -0
  71. package/dist/server/routes/index.d.ts +35 -0
  72. package/dist/server/routes/seo.d.ts +16 -0
  73. package/dist/server/routes/settings.d.ts +16 -0
  74. package/dist/server/services/index.d.ts +19 -0
  75. package/dist/server/services/seo.d.ts +12 -0
  76. package/dist/server/services/settings.d.ts +10 -0
  77. package/dist/shared/index.cjs +17 -0
  78. package/dist/shared/index.d.ts +1 -0
  79. package/dist/shared/index.js +17 -0
  80. package/dist/shared/index.mjs +17 -0
  81. package/package.json +100 -3
@@ -0,0 +1,571 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Layouts, useNotification, ContentBox, useFetchClient, private_useAutoReloadOverlayBlocker, Page, private_AutoReloadOverlayBlockerProvider } from "@strapi/strapi/admin";
3
+ import { NavLink, Routes, Route } from "react-router-dom";
4
+ import { g as getTrad, u as useSettingsApi, I as Illo, p as pluginId, a as pluginPermissions } from "./index-CJ64dp6B.js";
5
+ import { Box, Flex, LinkButton, Modal, Button, Typography, Grid, Switch, Tabs, Table, Thead, Tr, Th, Tbody, Td, EmptyStateLayout } from "@strapi/design-system";
6
+ import { Pencil, ArrowLeft, Cog, Information, Plus } from "@strapi/icons";
7
+ import * as React from "react";
8
+ import { useIntl } from "react-intl";
9
+ const SEO_COMPONENT_PATH = "/plugins/content-type-builder/component-categories/shared/shared.seo";
10
+ const Header = ({ seoComponent }) => {
11
+ const { formatMessage } = useIntl();
12
+ return /* @__PURE__ */ jsx(Box, { background: "neutral100", children: /* @__PURE__ */ jsx(
13
+ Layouts.Header,
14
+ {
15
+ primaryAction: /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
16
+ seoComponent ? /* @__PURE__ */ jsx(
17
+ LinkButton,
18
+ {
19
+ variant: "secondary",
20
+ tag: NavLink,
21
+ to: SEO_COMPONENT_PATH,
22
+ startIcon: /* @__PURE__ */ jsx(Pencil, {}),
23
+ children: formatMessage({
24
+ id: getTrad("SEOPage.header.button.edit-component"),
25
+ defaultMessage: "Edit SEO component"
26
+ })
27
+ }
28
+ ) : null,
29
+ /* @__PURE__ */ jsx(
30
+ LinkButton,
31
+ {
32
+ tag: NavLink,
33
+ variant: "tertiary",
34
+ to: "/",
35
+ startIcon: /* @__PURE__ */ jsx(ArrowLeft, {}),
36
+ children: formatMessage({
37
+ id: getTrad("SEOPage.header.button.back"),
38
+ defaultMessage: "Back"
39
+ })
40
+ }
41
+ )
42
+ ] }),
43
+ title: formatMessage({
44
+ id: getTrad("SEOPage.header.title"),
45
+ defaultMessage: "SEO"
46
+ }),
47
+ subtitle: formatMessage({
48
+ id: getTrad("SEOPage.header.subtitle"),
49
+ defaultMessage: "Optimize your content to be SEO friendly"
50
+ }),
51
+ as: "h2"
52
+ }
53
+ ) });
54
+ };
55
+ const SettingsModal = ({
56
+ item,
57
+ defaultSettings: sharedSettings = null,
58
+ onSettingsUpdated
59
+ }) => {
60
+ const { toggleNotification } = useNotification();
61
+ const { formatMessage } = useIntl();
62
+ const { getSettings, setSettings } = useSettingsApi();
63
+ const [isOpen, setIsOpen] = React.useState(false);
64
+ const [metaTitle, setMetaTitle] = React.useState(true);
65
+ const [metaDescription, setMetaDescription] = React.useState(true);
66
+ const [metaRobots, setMetaRobots] = React.useState(true);
67
+ const [openGraph, setOpenGraph] = React.useState(true);
68
+ const [wordCount, setWordCount] = React.useState(true);
69
+ const [canonicalUrl, setCanonicalUrl] = React.useState(true);
70
+ const [keywordDensity, setKeywordDensity] = React.useState(true);
71
+ const [structuredData, setStructuredData] = React.useState(true);
72
+ const [alternativeText, setAlternativeText] = React.useState(true);
73
+ const [lastUpdatedAt, setLastUpdatedAt] = React.useState(true);
74
+ const [localSettings, setLocalSettings] = React.useState(sharedSettings);
75
+ const activeSettings = sharedSettings ?? localSettings;
76
+ const applyChecksToState = (settingsMap) => {
77
+ const seoChecks = settingsMap?.[item?.uid]?.seoChecks;
78
+ if (!seoChecks) {
79
+ return;
80
+ }
81
+ setMetaTitle(seoChecks.metaTitle);
82
+ setMetaDescription(seoChecks.metaDescription);
83
+ setMetaRobots(seoChecks.metaRobots);
84
+ setOpenGraph(seoChecks.openGraph);
85
+ setWordCount(seoChecks.wordCount);
86
+ setCanonicalUrl(seoChecks.canonicalUrl);
87
+ setKeywordDensity(seoChecks.keywordDensity);
88
+ setStructuredData(seoChecks.structuredData);
89
+ setAlternativeText(seoChecks.alternativeText);
90
+ setLastUpdatedAt(seoChecks.lastUpdatedAt);
91
+ };
92
+ const setupModalSettings = async () => {
93
+ if (activeSettings) {
94
+ applyChecksToState(activeSettings);
95
+ return;
96
+ }
97
+ try {
98
+ const { data } = await getSettings();
99
+ setLocalSettings(data);
100
+ onSettingsUpdated?.(data);
101
+ applyChecksToState(data);
102
+ } catch {
103
+ }
104
+ };
105
+ const handleSavingSettingsModal = async () => {
106
+ const baseSettings = activeSettings ?? {};
107
+ const collectionName = baseSettings?.[item?.uid]?.collectionName ?? item?.globalId ?? item?.uid;
108
+ const newSettings = {
109
+ ...baseSettings,
110
+ [item?.uid]: {
111
+ collectionName,
112
+ seoChecks: {
113
+ metaTitle,
114
+ metaDescription,
115
+ metaRobots,
116
+ openGraph,
117
+ wordCount,
118
+ canonicalUrl,
119
+ keywordDensity,
120
+ structuredData,
121
+ alternativeText,
122
+ lastUpdatedAt
123
+ }
124
+ }
125
+ };
126
+ try {
127
+ const { data: savedSettings } = await setSettings(newSettings);
128
+ const resolvedSettings = savedSettings ?? newSettings;
129
+ setLocalSettings(resolvedSettings);
130
+ onSettingsUpdated?.(resolvedSettings);
131
+ setIsOpen(false);
132
+ toggleNotification({
133
+ type: "success",
134
+ message: formatMessage(
135
+ {
136
+ id: getTrad("notification.success.settings"),
137
+ defaultMessage: "Settings saved for {collectionName} content-type."
138
+ },
139
+ { collectionName }
140
+ )
141
+ });
142
+ } catch {
143
+ toggleNotification({
144
+ type: "danger",
145
+ message: formatMessage({
146
+ id: getTrad("notification.error.settings"),
147
+ defaultMessage: "Failed to save SEO settings."
148
+ })
149
+ });
150
+ }
151
+ };
152
+ return /* @__PURE__ */ jsxs(Modal.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
153
+ /* @__PURE__ */ jsx(Modal.Trigger, { children: /* @__PURE__ */ jsx(
154
+ Button,
155
+ {
156
+ variant: "tertiary",
157
+ startIcon: /* @__PURE__ */ jsx(Cog, {}),
158
+ onClick: () => void setupModalSettings(),
159
+ children: formatMessage({
160
+ id: getTrad("SEOPage.info.settings"),
161
+ defaultMessage: "Settings"
162
+ })
163
+ }
164
+ ) }),
165
+ /* @__PURE__ */ jsxs(Modal.Content, { labelledBy: "title", children: [
166
+ /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(
167
+ Typography,
168
+ {
169
+ fontWeight: "bold",
170
+ textColor: "neutral800",
171
+ tag: "h2",
172
+ id: "title",
173
+ children: formatMessage({
174
+ id: getTrad("SEOPage.info.settings"),
175
+ defaultMessage: "Settings"
176
+ })
177
+ }
178
+ ) }),
179
+ /* @__PURE__ */ jsxs(
180
+ "form",
181
+ {
182
+ onSubmit: (event) => {
183
+ event.preventDefault();
184
+ void handleSavingSettingsModal();
185
+ },
186
+ children: [
187
+ /* @__PURE__ */ jsxs(Modal.Body, { children: [
188
+ /* @__PURE__ */ jsx(Box, { paddingBottom: 4, children: /* @__PURE__ */ jsx(
189
+ ContentBox,
190
+ {
191
+ title: formatMessage({
192
+ id: getTrad("Information"),
193
+ defaultMessage: "Information"
194
+ }),
195
+ subtitle: formatMessage({
196
+ id: getTrad("SEOPage.info.settings.information"),
197
+ defaultMessage: "Disable SEO checks for this specific content-type."
198
+ }),
199
+ icon: /* @__PURE__ */ jsx(Information, {}),
200
+ iconBackground: "primary100"
201
+ }
202
+ ) }),
203
+ /* @__PURE__ */ jsx(Grid.Root, { gap: 4, children: [
204
+ {
205
+ state: metaTitle,
206
+ stateSetter: setMetaTitle,
207
+ id: "SEOPage.info.settings.meta-title-check",
208
+ defaultMessage: "Meta Title"
209
+ },
210
+ {
211
+ state: metaDescription,
212
+ stateSetter: setMetaDescription,
213
+ id: "SEOPage.info.settings.meta-description-check",
214
+ defaultMessage: "Meta Description"
215
+ },
216
+ {
217
+ state: metaRobots,
218
+ stateSetter: setMetaRobots,
219
+ id: "SEOPage.info.settings.meta-robots-check",
220
+ defaultMessage: "Meta Robots"
221
+ },
222
+ {
223
+ state: openGraph,
224
+ stateSetter: setOpenGraph,
225
+ id: "SEOPage.info.settings.open-graph-check",
226
+ defaultMessage: "Open Graph"
227
+ },
228
+ {
229
+ state: wordCount,
230
+ stateSetter: setWordCount,
231
+ id: "SEOPage.info.settings.word-count-check",
232
+ defaultMessage: "Word Count"
233
+ },
234
+ {
235
+ state: canonicalUrl,
236
+ stateSetter: setCanonicalUrl,
237
+ id: "SEOPage.info.settings.canonical-url-check",
238
+ defaultMessage: "Canonical URL"
239
+ },
240
+ {
241
+ state: keywordDensity,
242
+ stateSetter: setKeywordDensity,
243
+ id: "SEOPage.info.settings.keyword-density-check",
244
+ defaultMessage: "Keyword Density"
245
+ },
246
+ {
247
+ state: structuredData,
248
+ stateSetter: setStructuredData,
249
+ id: "SEOPage.info.settings.structured-data-check",
250
+ defaultMessage: "Structured Data"
251
+ },
252
+ {
253
+ state: alternativeText,
254
+ stateSetter: setAlternativeText,
255
+ id: "SEOPage.info.settings.alternative-text-check",
256
+ defaultMessage: "Alt Text"
257
+ },
258
+ {
259
+ state: lastUpdatedAt,
260
+ stateSetter: setLastUpdatedAt,
261
+ id: "SEOPage.info.settings.last-updated-at-check",
262
+ defaultMessage: "Last Updated At"
263
+ }
264
+ ].map(({ state, stateSetter, id, defaultMessage }) => {
265
+ return /* @__PURE__ */ jsxs(
266
+ Grid.Item,
267
+ {
268
+ col: 6,
269
+ s: 6,
270
+ gap: 2,
271
+ padding: 4,
272
+ background: "neutral0",
273
+ borderWidth: "2px",
274
+ shadow: "filterShadow",
275
+ children: [
276
+ /* @__PURE__ */ jsx(
277
+ Switch,
278
+ {
279
+ checked: state,
280
+ onCheckedChange: () => stateSetter((isChecked) => !isChecked)
281
+ }
282
+ ),
283
+ /* @__PURE__ */ jsx(Typography, { variant: "delta", children: formatMessage({
284
+ id: getTrad(id),
285
+ defaultMessage
286
+ }) })
287
+ ]
288
+ },
289
+ id
290
+ );
291
+ }) })
292
+ ] }),
293
+ /* @__PURE__ */ jsxs(Modal.Footer, { children: [
294
+ /* @__PURE__ */ jsx(Modal.Close, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
295
+ id: getTrad("SEOPage.info.settings.cancel.button"),
296
+ defaultMessage: "Cancel"
297
+ }) }) }),
298
+ /* @__PURE__ */ jsx(Button, { type: "submit", children: formatMessage({
299
+ id: getTrad("SEOPage.info.settings.save.button"),
300
+ defaultMessage: "Save"
301
+ }) })
302
+ ] })
303
+ ]
304
+ }
305
+ )
306
+ ] })
307
+ ] });
308
+ };
309
+ const ContentTypeRow = ({
310
+ item,
311
+ defaultSettings,
312
+ onSettingsUpdated
313
+ }) => {
314
+ const { formatMessage } = useIntl();
315
+ return /* @__PURE__ */ jsxs(Tr, { children: [
316
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", children: item.globalId }) }),
317
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Flex, { justifyContent: "flex-end", alignItems: "center", children: item.seo ? /* @__PURE__ */ jsx(
318
+ SettingsModal,
319
+ {
320
+ item,
321
+ defaultSettings,
322
+ onSettingsUpdated
323
+ }
324
+ ) : /* @__PURE__ */ jsx(
325
+ LinkButton,
326
+ {
327
+ startIcon: /* @__PURE__ */ jsx(Plus, {}),
328
+ variant: "secondary",
329
+ tag: NavLink,
330
+ to: `/plugins/content-type-builder/content-types/${item.uid}`,
331
+ children: formatMessage({
332
+ id: getTrad("SEOPage.info.add"),
333
+ defaultMessage: "Add component"
334
+ })
335
+ }
336
+ ) }) })
337
+ ] }, item.uid);
338
+ };
339
+ const ContentTypeTabTable = ({
340
+ items,
341
+ emptyMessageId,
342
+ emptyDefaultMessage,
343
+ createLinkTo,
344
+ createButtonId,
345
+ createButtonDefaultMessage,
346
+ defaultSettings,
347
+ onSettingsUpdated
348
+ }) => {
349
+ const { formatMessage } = useIntl();
350
+ const safeItems = Array.isArray(items) ? items : [];
351
+ const createAction = createLinkTo && createButtonId ? /* @__PURE__ */ jsx(
352
+ LinkButton,
353
+ {
354
+ tag: NavLink,
355
+ to: createLinkTo,
356
+ variant: "secondary",
357
+ startIcon: /* @__PURE__ */ jsx(Plus, {}),
358
+ children: formatMessage({
359
+ id: getTrad(createButtonId),
360
+ defaultMessage: createButtonDefaultMessage
361
+ })
362
+ }
363
+ ) : void 0;
364
+ return /* @__PURE__ */ jsxs(Table, { colCount: 2, rowCount: Math.max(safeItems.length, 1), children: [
365
+ /* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [
366
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", children: formatMessage({
367
+ id: getTrad("SEOPage.tab-panel.column-name"),
368
+ defaultMessage: "Name"
369
+ }) }) }),
370
+ /* @__PURE__ */ jsx(Th, {})
371
+ ] }) }),
372
+ /* @__PURE__ */ jsx(Tbody, { children: safeItems.length > 0 ? safeItems.map((item) => /* @__PURE__ */ jsx(
373
+ ContentTypeRow,
374
+ {
375
+ item,
376
+ defaultSettings,
377
+ onSettingsUpdated
378
+ },
379
+ item.uid
380
+ )) : /* @__PURE__ */ jsx(Tr, { children: /* @__PURE__ */ jsx(Td, { colSpan: 2, children: /* @__PURE__ */ jsx(Box, { padding: 8, background: "neutral0", children: /* @__PURE__ */ jsx(
381
+ EmptyStateLayout,
382
+ {
383
+ icon: /* @__PURE__ */ jsx(Illo, {}),
384
+ content: formatMessage({
385
+ id: getTrad(emptyMessageId),
386
+ defaultMessage: emptyDefaultMessage
387
+ }),
388
+ action: createAction
389
+ }
390
+ ) }) }) }) })
391
+ ] });
392
+ };
393
+ const Main = ({ contentTypes }) => {
394
+ const { formatMessage } = useIntl();
395
+ const { getSettings } = useSettingsApi();
396
+ const [defaultSettings, setDefaultSettings] = React.useState(null);
397
+ React.useEffect(() => {
398
+ let isMounted = true;
399
+ void getSettings().then(({ data }) => {
400
+ if (isMounted && data) {
401
+ setDefaultSettings(data);
402
+ }
403
+ }).catch(() => {
404
+ });
405
+ return () => {
406
+ isMounted = false;
407
+ };
408
+ }, []);
409
+ const TabValues = {
410
+ collectionTypes: "collection-types",
411
+ singleTypes: "single-types",
412
+ plugins: "plugins"
413
+ };
414
+ return /* @__PURE__ */ jsx(Box, { padding: 8, children: /* @__PURE__ */ jsxs(
415
+ Tabs.Root,
416
+ {
417
+ id: "tabs",
418
+ variant: "simple",
419
+ defaultValue: TabValues.collectionTypes,
420
+ children: [
421
+ /* @__PURE__ */ jsxs(Tabs.List, { children: [
422
+ /* @__PURE__ */ jsx(Tabs.Trigger, { value: TabValues.collectionTypes, children: /* @__PURE__ */ jsx(Typography, { children: formatMessage({
423
+ id: getTrad("SEOPage.tab.collection-type-title"),
424
+ defaultMessage: "Collection Types"
425
+ }) }) }),
426
+ /* @__PURE__ */ jsx(Tabs.Trigger, { value: TabValues.singleTypes, children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
427
+ id: getTrad("SEOPage.tab.single-type-title"),
428
+ defaultMessage: "Single Types"
429
+ }) }) }),
430
+ /* @__PURE__ */ jsx(Tabs.Trigger, { value: TabValues.plugins, children: /* @__PURE__ */ jsx(Typography, { variant: "omega", children: formatMessage({
431
+ id: getTrad("SEOPage.tab.plugin-title"),
432
+ defaultMessage: "Plugins"
433
+ }) }) })
434
+ ] }),
435
+ /* @__PURE__ */ jsx(Tabs.Content, { value: TabValues.collectionTypes, children: /* @__PURE__ */ jsx(
436
+ ContentTypeTabTable,
437
+ {
438
+ items: contentTypes?.collectionTypes,
439
+ emptyMessageId: "SEOPage.info.no-collection-types",
440
+ emptyDefaultMessage: "You don't have any collection-types yet...",
441
+ createLinkTo: "/plugins/content-type-builder",
442
+ createButtonId: "SEOPage.info.create-collection-type",
443
+ createButtonDefaultMessage: "Create your first collection-type",
444
+ defaultSettings,
445
+ onSettingsUpdated: setDefaultSettings
446
+ }
447
+ ) }),
448
+ /* @__PURE__ */ jsx(Tabs.Content, { value: TabValues.singleTypes, children: /* @__PURE__ */ jsx(
449
+ ContentTypeTabTable,
450
+ {
451
+ items: contentTypes?.singleTypes,
452
+ emptyMessageId: "SEOPage.info.no-single-types",
453
+ emptyDefaultMessage: "You don't have any single-types yet...",
454
+ createLinkTo: "/plugins/content-type-builder",
455
+ createButtonId: "SEOPage.info.create-single-type",
456
+ createButtonDefaultMessage: "Create your first single-type",
457
+ defaultSettings,
458
+ onSettingsUpdated: setDefaultSettings
459
+ }
460
+ ) }),
461
+ /* @__PURE__ */ jsx(Tabs.Content, { value: TabValues.plugins, children: /* @__PURE__ */ jsx(
462
+ ContentTypeTabTable,
463
+ {
464
+ items: contentTypes?.plugins,
465
+ emptyMessageId: "SEOPage.info.no-plugin-content-type",
466
+ emptyDefaultMessage: "You don't have any plugin content-type yet...",
467
+ defaultSettings,
468
+ onSettingsUpdated: setDefaultSettings
469
+ }
470
+ ) })
471
+ ]
472
+ }
473
+ ) });
474
+ };
475
+ const HomePage = React.memo(() => {
476
+ const { get, post } = useFetchClient();
477
+ const { lockAppWithAutoreload, unlockAppWithAutoreload } = private_useAutoReloadOverlayBlocker();
478
+ const { formatMessage } = useIntl();
479
+ const [isLoading, setIsLoading] = React.useState(true);
480
+ const [seoComponent, setSeoComponent] = React.useState(null);
481
+ const [contentTypes, setContentTypes] = React.useState(null);
482
+ React.useEffect(() => {
483
+ let isMounted = true;
484
+ const fetchSeoComponent = async () => {
485
+ try {
486
+ const { data } = await get(
487
+ `/${pluginId}/component`
488
+ );
489
+ return data;
490
+ } catch {
491
+ return null;
492
+ }
493
+ };
494
+ const fetchContentTypes = async () => {
495
+ try {
496
+ const { data } = await get(
497
+ `/${pluginId}/content-types`
498
+ );
499
+ return data;
500
+ } catch {
501
+ return null;
502
+ }
503
+ };
504
+ const createSeoComponent = async () => {
505
+ try {
506
+ const { data } = await post(
507
+ `/${pluginId}/component`
508
+ );
509
+ return data;
510
+ } catch {
511
+ return null;
512
+ }
513
+ };
514
+ const fetchData = async () => {
515
+ let currentComponent = await fetchSeoComponent();
516
+ let currentContentTypes = await fetchContentTypes();
517
+ const hasNoSeoComponent = !currentComponent || Object.keys(currentComponent).length === 0;
518
+ if (hasNoSeoComponent) {
519
+ try {
520
+ lockAppWithAutoreload();
521
+ await createSeoComponent();
522
+ } catch {
523
+ } finally {
524
+ unlockAppWithAutoreload();
525
+ }
526
+ currentComponent = await fetchSeoComponent();
527
+ currentContentTypes = await fetchContentTypes();
528
+ }
529
+ if (isMounted) {
530
+ setSeoComponent(currentComponent);
531
+ setContentTypes(currentContentTypes);
532
+ setIsLoading(false);
533
+ }
534
+ };
535
+ void fetchData();
536
+ return () => {
537
+ isMounted = false;
538
+ };
539
+ }, []);
540
+ if (isLoading) {
541
+ return /* @__PURE__ */ jsx(Page.Loading, {});
542
+ }
543
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
544
+ /* @__PURE__ */ jsx(Header, { seoComponent }),
545
+ /* @__PURE__ */ jsx(Box, { paddingLeft: 8, paddingRight: 8, children: /* @__PURE__ */ jsx(
546
+ ContentBox,
547
+ {
548
+ title: formatMessage({
549
+ id: getTrad("Information"),
550
+ defaultMessage: "Information"
551
+ }),
552
+ subtitle: formatMessage({
553
+ id: getTrad("SEOPage.info.information"),
554
+ defaultMessage: "When adding your SEO component, make sure to name it 'seo' and to include it in the root of your Content-Type."
555
+ }),
556
+ icon: /* @__PURE__ */ jsx(Information, {}),
557
+ iconBackground: "primary100"
558
+ }
559
+ ) }),
560
+ /* @__PURE__ */ jsx(Main, { contentTypes })
561
+ ] });
562
+ });
563
+ const App = () => {
564
+ return /* @__PURE__ */ jsx(private_AutoReloadOverlayBlockerProvider, { children: /* @__PURE__ */ jsx(Page.Protect, { permissions: pluginPermissions.main, children: /* @__PURE__ */ jsxs(Routes, { children: [
565
+ /* @__PURE__ */ jsx(Route, { index: true, element: /* @__PURE__ */ jsx(HomePage, {}) }),
566
+ /* @__PURE__ */ jsx(Route, { path: "*", element: /* @__PURE__ */ jsx(Page.Error, {}) })
567
+ ] }) }) });
568
+ };
569
+ export {
570
+ App as default
571
+ };
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ require("@strapi/icons");
4
+ const index = require("./index-C8tiCtgn.cjs");
5
+ exports.default = index.index;
@@ -0,0 +1,18 @@
1
+ interface StrapiAdminApp {
2
+ addMenuLink: (link: Record<string, unknown>) => void;
3
+ registerPlugin: (plugin: Record<string, unknown>) => void;
4
+ getPlugin: (name: string) => {
5
+ injectComponent: (containerName: string, blockName: string, component: Record<string, unknown>) => void;
6
+ };
7
+ }
8
+ declare const _default: {
9
+ register(app: StrapiAdminApp): void;
10
+ bootstrap(app: StrapiAdminApp): void;
11
+ registerTrads: ({ locales, }?: {
12
+ locales?: string[];
13
+ }) => Promise<Array<{
14
+ data: Record<string, string>;
15
+ locale: string;
16
+ }>>;
17
+ };
18
+ export default _default;
@@ -0,0 +1,5 @@
1
+ import "@strapi/icons";
2
+ import { i } from "./index-CJ64dp6B.js";
3
+ export {
4
+ i as default
5
+ };
@@ -0,0 +1,5 @@
1
+ import "@strapi/icons";
2
+ import { i } from "./index-CJ64dp6B.js";
3
+ export {
4
+ i as default
5
+ };
@@ -0,0 +1,2 @@
1
+ declare const App: () => import("react/jsx-runtime").JSX.Element;
2
+ export default App;
@@ -0,0 +1,2 @@
1
+ import * as React from "react";
2
+ export declare const HomePage: React.FC<{}>;
@@ -0,0 +1,10 @@
1
+ export declare const pluginPermissions: {
2
+ main: {
3
+ action: string;
4
+ subject: null;
5
+ }[];
6
+ settings: {
7
+ action: string;
8
+ subject: null;
9
+ }[];
10
+ };
@@ -0,0 +1 @@
1
+ export declare const pluginId: string;