wpheadless-lib 1.1.10 → 1.1.12

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 (120) hide show
  1. package/dist/api/categories.d.ts +1 -1
  2. package/dist/api/categories.js +18 -2
  3. package/dist/api/index.d.ts +7 -6
  4. package/dist/api/index.js +7 -6
  5. package/dist/api/mappers.d.ts +1 -1
  6. package/dist/api/mappers.js +1 -1
  7. package/dist/api/menus.d.ts +18 -0
  8. package/dist/api/menus.js +39 -0
  9. package/dist/api/posts.js +30 -2
  10. package/dist/api/translations.js +7 -1
  11. package/dist/api/wpClient.d.ts +5 -8
  12. package/dist/api/wpClient.js +14 -0
  13. package/dist/app/config.d.ts +2 -1
  14. package/dist/app/config.js +4 -0
  15. package/dist/app/globals.css +35 -124
  16. package/dist/base/category/index.d.ts +3 -3
  17. package/dist/base/category/index.js +9 -8
  18. package/dist/base/category/pagination.d.ts +2 -2
  19. package/dist/base/category/pagination.js +12 -10
  20. package/dist/base/home/index.js +1 -1
  21. package/dist/base/home/pagination.js +3 -3
  22. package/dist/base/index.d.ts +7 -7
  23. package/dist/base/index.js +7 -7
  24. package/dist/base/layout/RootLayoutBase.d.ts +7 -8
  25. package/dist/base/layout/RootLayoutBase.js +4 -4
  26. package/dist/base/layout/RootLayoutBase.module.css +10 -0
  27. package/dist/base/legal/index.d.ts +4 -4
  28. package/dist/base/legal/index.js +36 -24
  29. package/dist/base/post/index.d.ts +1 -1
  30. package/dist/base/post/index.js +15 -12
  31. package/dist/components/Breadcrumbs/index.d.ts +1 -1
  32. package/dist/components/Breadcrumbs/index.js +4 -4
  33. package/dist/components/JsonLd.d.ts +5 -0
  34. package/dist/components/JsonLd.js +9 -0
  35. package/dist/components/Paginator/index.d.ts +2 -2
  36. package/dist/components/Paginator/index.js +5 -5
  37. package/dist/components/PostCard/index.d.ts +3 -2
  38. package/dist/components/PostCard/index.js +8 -6
  39. package/dist/components/PostCard/index.module.css +7 -7
  40. package/dist/components/PostCard/index.types.d.ts +2 -1
  41. package/dist/components/PostCard/index.utils.d.ts +5 -5
  42. package/dist/components/PostCard/index.utils.js +8 -6
  43. package/dist/components/index.d.ts +6 -5
  44. package/dist/components/index.js +6 -5
  45. package/dist/components/layout/Footer/index.d.ts +6 -6
  46. package/dist/components/layout/Footer/index.js +11 -22
  47. package/dist/components/layout/Footer/index.module.css +59 -9
  48. package/dist/components/layout/Header/HeaderClient.d.ts +2 -2
  49. package/dist/components/layout/Header/HeaderClient.js +22 -2
  50. package/dist/components/layout/Header/index.d.ts +6 -6
  51. package/dist/components/layout/Header/index.js +10 -29
  52. package/dist/components/layout/Header/index.module.css +77 -16
  53. package/dist/components/ui/alert.d.ts +8 -0
  54. package/dist/components/ui/alert.js +12 -0
  55. package/dist/components/ui/alert.module.css +26 -0
  56. package/dist/components/ui/badge.d.ts +3 -0
  57. package/dist/components/ui/badge.js +9 -0
  58. package/dist/components/ui/badge.module.css +23 -0
  59. package/dist/components/ui/breadcrumb.d.ts +8 -0
  60. package/dist/components/ui/breadcrumb.js +22 -0
  61. package/dist/components/ui/breadcrumb.module.css +37 -0
  62. package/dist/components/ui/button.d.ts +7 -0
  63. package/dist/components/ui/button.js +16 -0
  64. package/dist/components/ui/button.module.css +72 -0
  65. package/dist/components/ui/card.d.ts +11 -0
  66. package/dist/components/ui/card.js +16 -0
  67. package/dist/components/ui/card.module.css +37 -0
  68. package/dist/components/ui/cn.d.ts +1 -0
  69. package/dist/components/ui/cn.js +3 -0
  70. package/dist/components/ui/index.d.ts +6 -0
  71. package/dist/components/ui/index.js +6 -0
  72. package/dist/components/ui/pagination.d.ts +14 -0
  73. package/dist/components/ui/pagination.js +25 -0
  74. package/dist/components/ui/pagination.module.css +62 -0
  75. package/dist/index.d.ts +6 -6
  76. package/dist/index.js +6 -6
  77. package/dist/plugins/index.d.ts +1 -1
  78. package/dist/plugins/index.js +1 -1
  79. package/dist/plugins/yoast/index.js +10 -7
  80. package/dist/utils/hreflang.d.ts +5 -7
  81. package/dist/utils/hreflang.js +19 -8
  82. package/dist/utils/html.d.ts +2 -0
  83. package/dist/utils/html.js +25 -0
  84. package/dist/utils/index.d.ts +7 -6
  85. package/dist/utils/index.js +7 -6
  86. package/dist/utils/language.d.ts +37 -0
  87. package/dist/utils/language.js +75 -0
  88. package/dist/utils/seo.d.ts +1 -6
  89. package/dist/utils/seo.js +9 -5
  90. package/dist/utils/sitemap.d.ts +1 -1
  91. package/dist/utils/sitemap.js +181 -63
  92. package/dist/views/CategoryListView/index.d.ts +2 -2
  93. package/dist/views/CategoryListView/index.js +6 -6
  94. package/dist/views/CategoryListView/index.utils.d.ts +1 -1
  95. package/dist/views/CategoryListView/index.utils.js +1 -1
  96. package/dist/views/CategoryPaginationView/index.d.ts +2 -2
  97. package/dist/views/CategoryPaginationView/index.js +6 -6
  98. package/dist/views/CategoryPaginationView/index.utils.d.ts +1 -1
  99. package/dist/views/CategoryPaginationView/index.utils.js +1 -1
  100. package/dist/views/HomePaginationView/index.d.ts +2 -2
  101. package/dist/views/HomePaginationView/index.js +5 -4
  102. package/dist/views/HomePaginationView/index.utils.d.ts +1 -1
  103. package/dist/views/HomePaginationView/index.utils.js +1 -1
  104. package/dist/views/HomeView/index.d.ts +2 -2
  105. package/dist/views/HomeView/index.js +13 -12
  106. package/dist/views/HomeView/index.module.css +51 -8
  107. package/dist/views/HomeView/index.utils.d.ts +1 -1
  108. package/dist/views/HomeView/index.utils.js +2 -2
  109. package/dist/views/LegalPageView/index.d.ts +2 -1
  110. package/dist/views/LegalPageView/index.js +5 -5
  111. package/dist/views/LegalPageView/index.module.css +3 -3
  112. package/dist/views/LegalPageView/index.utils.js +1 -1
  113. package/dist/views/PostView/index.d.ts +3 -2
  114. package/dist/views/PostView/index.js +9 -7
  115. package/dist/views/PostView/index.module.css +46 -13
  116. package/dist/views/PostView/index.utils.d.ts +3 -3
  117. package/dist/views/PostView/index.utils.js +2 -2
  118. package/dist/views/index.d.ts +6 -6
  119. package/dist/views/index.js +6 -6
  120. package/package.json +47 -10
@@ -1,5 +1,5 @@
1
1
  import type { WPCategory, WPPost } from "wpjsapi-lib";
2
- import type { ApiResult } from "./posts";
2
+ import type { ApiResult } from "./posts.js";
3
3
  export type CategoryClientConfig = {
4
4
  baseApiUrl: string;
5
5
  username?: string;
@@ -1,6 +1,9 @@
1
- import { createWpClient } from "./wpClient";
2
- import { fetchCategoriesByTranslationKey } from "./translations";
1
+ import { createWpClient, isValidWpApiUrl } from "./wpClient.js";
2
+ import { fetchCategoriesByTranslationKey } from "./translations.js";
3
3
  export async function listCategoryStaticParams({ baseApiUrl, lang, }) {
4
+ if (!isValidWpApiUrl(baseApiUrl)) {
5
+ return { ok: true, data: [], error: null };
6
+ }
4
7
  try {
5
8
  const { categoriesApi } = createWpClient({
6
9
  baseUrl: baseApiUrl,
@@ -21,6 +24,9 @@ export async function listCategoryStaticParams({ baseApiUrl, lang, }) {
21
24
  }
22
25
  }
23
26
  export async function getCategoryBySlug({ baseApiUrl, slug, lang, }) {
27
+ if (!isValidWpApiUrl(baseApiUrl)) {
28
+ return { ok: true, data: null, error: null };
29
+ }
24
30
  try {
25
31
  const { categoriesApi } = createWpClient({
26
32
  baseUrl: baseApiUrl,
@@ -42,6 +48,13 @@ export async function getCategoryBySlug({ baseApiUrl, slug, lang, }) {
42
48
  }
43
49
  }
44
50
  export async function listCategoryPosts({ baseApiUrl, categoryId, perPage, langId, }) {
51
+ if (!isValidWpApiUrl(baseApiUrl)) {
52
+ return {
53
+ ok: true,
54
+ data: { posts: [], totalPages: 0 },
55
+ error: null,
56
+ };
57
+ }
45
58
  try {
46
59
  const { postsApi } = createWpClient({
47
60
  baseUrl: baseApiUrl,
@@ -75,6 +88,9 @@ export async function listCategoryPosts({ baseApiUrl, categoryId, perPage, langI
75
88
  }
76
89
  }
77
90
  export async function getCategoryByTranslationKey({ baseApiUrl, translationKey, lang, perPage = 1, }) {
91
+ if (!isValidWpApiUrl(baseApiUrl)) {
92
+ return { ok: true, data: null, error: null };
93
+ }
78
94
  try {
79
95
  const categories = await fetchCategoriesByTranslationKey({
80
96
  baseApiUrl,
@@ -1,6 +1,7 @@
1
- export * from "./types";
2
- export * from "./posts";
3
- export * from "./categories";
4
- export * from "./translations";
5
- export * from "./mappers";
6
- export * from "./wpClient";
1
+ export * from "./types.js";
2
+ export * from "./posts.js";
3
+ export * from "./categories.js";
4
+ export * from "./translations.js";
5
+ export * from "./mappers.js";
6
+ export * from "./wpClient.js";
7
+ export * from "./menus.js";
package/dist/api/index.js CHANGED
@@ -1,6 +1,7 @@
1
- export * from "./types";
2
- export * from "./posts";
3
- export * from "./categories";
4
- export * from "./translations";
5
- export * from "./mappers";
6
- export * from "./wpClient";
1
+ export * from "./types.js";
2
+ export * from "./posts.js";
3
+ export * from "./categories.js";
4
+ export * from "./translations.js";
5
+ export * from "./mappers.js";
6
+ export * from "./wpClient.js";
7
+ export * from "./menus.js";
@@ -1,5 +1,5 @@
1
1
  import type { WPCategory, WPPost, WPPage } from "wpjsapi-lib";
2
- import { type CategoryEntity, type PostEntity, type PageEntity } from "./types";
2
+ import { type CategoryEntity, type PostEntity, type PageEntity } from "./types.js";
3
3
  export declare function mapPostEntity(post: WPPost): PostEntity;
4
4
  export declare function mapCategoryEntity(category: WPCategory): CategoryEntity;
5
5
  export declare function mapPageEntity(page: WPPage): PageEntity<WPPage>;
@@ -1,4 +1,4 @@
1
- import { getEntityLanguageId, getTranslationKey } from "../utils/hreflang";
1
+ import { getEntityLanguageId, getTranslationKey } from "../utils/hreflang.js";
2
2
  const getEmbeddedCategories = (post) => (post._embedded?.["wp:term"]?.[0] || []).filter(Boolean);
3
3
  export function mapPostEntity(post) {
4
4
  return {
@@ -0,0 +1,18 @@
1
+ import { type WPMenuItem } from "wpjsapi-lib";
2
+ export type MenuClientConfig = {
3
+ baseApiUrl: string;
4
+ username?: string;
5
+ appPassword?: string;
6
+ };
7
+ export type MenuLink = {
8
+ id: number;
9
+ href: string;
10
+ label: string;
11
+ target?: string;
12
+ };
13
+ export declare function fetchMenuItems({ baseApiUrl, menuId, username, appPassword, }: MenuClientConfig & {
14
+ menuId?: string | number;
15
+ }): Promise<WPMenuItem[]>;
16
+ export declare function fetchMenuLinks(params: MenuClientConfig & {
17
+ menuId?: string | number;
18
+ }): Promise<MenuLink[]>;
@@ -0,0 +1,39 @@
1
+ import { createAuth, createMenuEndpoints } from "wpjsapi-lib";
2
+ import { convertWpUrl } from "../utils/routing.js";
3
+ import { isValidWpApiUrl } from "./wpClient.js";
4
+ export async function fetchMenuItems({ baseApiUrl, menuId, username, appPassword, }) {
5
+ if (!isValidWpApiUrl(baseApiUrl) || !menuId)
6
+ return [];
7
+ const parsedMenuId = typeof menuId === "number" ? menuId : Number.parseInt(menuId, 10);
8
+ if (Number.isNaN(parsedMenuId))
9
+ return [];
10
+ const auth = username && appPassword
11
+ ? createAuth({
12
+ method: "basic",
13
+ credentials: {
14
+ username,
15
+ password: appPassword,
16
+ },
17
+ })
18
+ : undefined;
19
+ const menusApi = createMenuEndpoints({
20
+ baseUrl: baseApiUrl,
21
+ ...(auth ? { auth } : {}),
22
+ });
23
+ const itemsResponse = await menusApi.items.list({
24
+ menus: [parsedMenuId],
25
+ per_page: 100,
26
+ orderby: "menu_order",
27
+ order: "asc",
28
+ });
29
+ return itemsResponse.items;
30
+ }
31
+ export async function fetchMenuLinks(params) {
32
+ const items = await fetchMenuItems(params);
33
+ return items.map((item) => ({
34
+ id: item.id,
35
+ href: convertWpUrl(item.url, params.baseApiUrl),
36
+ label: item.title.rendered,
37
+ target: item.target || undefined,
38
+ }));
39
+ }
package/dist/api/posts.js CHANGED
@@ -1,7 +1,22 @@
1
- import { createWpClient } from "./wpClient";
2
- import { fetchPostsByTranslationKey } from "./translations";
1
+ import { createWpClient, isValidWpApiUrl } from "./wpClient.js";
2
+ import { fetchPostsByTranslationKey } from "./translations.js";
3
3
  const toMessage = (err) => err instanceof Error ? err.message : "Unknown error";
4
+ function emptyPaginatedPosts(page = 1, perPage = 0) {
5
+ return {
6
+ items: [],
7
+ pagination: {
8
+ total: 0,
9
+ totalPages: 0,
10
+ currentPage: page,
11
+ perPage,
12
+ hasMore: false,
13
+ },
14
+ };
15
+ }
4
16
  export async function getPostBySlug({ baseApiUrl, slug, langId, username, appPassword, }) {
17
+ if (!isValidWpApiUrl(baseApiUrl)) {
18
+ return { ok: true, data: null, error: null };
19
+ }
5
20
  try {
6
21
  const { postsApi } = createWpClient({
7
22
  baseUrl: baseApiUrl,
@@ -24,6 +39,9 @@ export async function getPostBySlug({ baseApiUrl, slug, langId, username, appPas
24
39
  }
25
40
  }
26
41
  export async function listPostStaticParams({ baseApiUrl, lang, langId, }) {
42
+ if (!isValidWpApiUrl(baseApiUrl)) {
43
+ return { ok: true, data: [], error: null };
44
+ }
27
45
  try {
28
46
  const { postsApi, categoriesApi } = createWpClient({ baseUrl: baseApiUrl });
29
47
  const categories = await categoriesApi.listAll(lang ? { lang } : undefined);
@@ -54,6 +72,9 @@ export async function listPostStaticParams({ baseApiUrl, lang, langId, }) {
54
72
  }
55
73
  }
56
74
  export async function listPostsByTranslationKey({ baseApiUrl, translationKey, username, appPassword, perPage = 20, }) {
75
+ if (!isValidWpApiUrl(baseApiUrl)) {
76
+ return { ok: true, data: [], error: null };
77
+ }
57
78
  try {
58
79
  const posts = await fetchPostsByTranslationKey({
59
80
  baseApiUrl,
@@ -69,6 +90,13 @@ export async function listPostsByTranslationKey({ baseApiUrl, translationKey, us
69
90
  }
70
91
  }
71
92
  export async function listPosts({ baseApiUrl, perPage, page, langId, categories, embed = false, fields, order, orderby, }) {
93
+ if (!isValidWpApiUrl(baseApiUrl)) {
94
+ return {
95
+ ok: true,
96
+ data: emptyPaginatedPosts(page ?? 1, perPage),
97
+ error: null,
98
+ };
99
+ }
72
100
  try {
73
101
  const { postsApi } = createWpClient({
74
102
  baseUrl: baseApiUrl,
@@ -1,5 +1,8 @@
1
- import { createWpClient } from "./wpClient";
1
+ import { createWpClient, isValidWpApiUrl } from "./wpClient.js";
2
2
  export async function fetchPostsByTranslationKey({ baseApiUrl, translationKey, username, appPassword, perPage = 20, }) {
3
+ if (!isValidWpApiUrl(baseApiUrl)) {
4
+ return [];
5
+ }
3
6
  const { postsApi } = createWpClient({
4
7
  baseUrl: baseApiUrl,
5
8
  username,
@@ -13,6 +16,9 @@ export async function fetchPostsByTranslationKey({ baseApiUrl, translationKey, u
13
16
  return response.items;
14
17
  }
15
18
  export async function fetchCategoriesByTranslationKey({ baseApiUrl, translationKey, lang, username, appPassword, perPage = 20, }) {
19
+ if (!isValidWpApiUrl(baseApiUrl)) {
20
+ return [];
21
+ }
16
22
  const { categoriesApi } = createWpClient({
17
23
  baseUrl: baseApiUrl,
18
24
  username,
@@ -3,13 +3,12 @@ type WpClientOptions = {
3
3
  username?: string;
4
4
  appPassword?: string;
5
5
  };
6
+ export declare function isValidWpApiUrl(baseUrl?: string): baseUrl is string;
6
7
  export declare function createWpClient({ baseUrl, username, appPassword, }: WpClientOptions): {
7
8
  postsApi: {
9
+ listAll: (params?: Omit<import("wpjsapi-lib").WPPostParameters, "page" | "per_page"> | undefined, options?: import("wpjsapi-lib").RequestOptions) => Promise<import("wpjsapi-lib").WPPost[]>;
10
+ pages: (params?: import("wpjsapi-lib").WPPostParameters | undefined, options?: import("wpjsapi-lib").RequestOptions) => AsyncGenerator<import("wpjsapi-lib").WPPaginatedResponse<import("wpjsapi-lib").WPPost>, void, unknown>;
8
11
  list: (params?: import("wpjsapi-lib").WPPostParameters, options?: import("wpjsapi-lib").RequestOptions) => Promise<import("wpjsapi-lib").WPPaginatedResponse<import("wpjsapi-lib").WPPost>>;
9
- listAll: (params?: Omit<import("wpjsapi-lib").WPPostParameters, "page" | "per_page">, options?: import("wpjsapi-lib").RequestOptions) => Promise<import("wpjsapi-lib").WPPost[]>;
10
- pages: (params?: import("wpjsapi-lib").WPPostParameters, options?: import("wpjsapi-lib").RequestOptions) => {
11
- [Symbol.asyncIterator](): AsyncGenerator<import("wpjsapi-lib").WPPaginatedResponse<import("wpjsapi-lib").WPPost>, void, unknown>;
12
- };
13
12
  get: (id: number, context?: "view" | "embed" | "edit", embed?: boolean, options?: import("wpjsapi-lib").RequestOptions) => Promise<import("wpjsapi-lib").WPPost>;
14
13
  create: (data: import("wpjsapi-lib").WPPostCreate, options?: import("wpjsapi-lib").RequestOptions) => Promise<import("wpjsapi-lib").WPPost>;
15
14
  update: (id: number, data: import("wpjsapi-lib").WPPostUpdate, options?: import("wpjsapi-lib").RequestOptions) => Promise<import("wpjsapi-lib").WPPost>;
@@ -17,11 +16,9 @@ export declare function createWpClient({ baseUrl, username, appPassword, }: WpCl
17
16
  getRevisions: (id: number, options?: import("wpjsapi-lib").RequestOptions) => Promise<import("wpjsapi-lib").WPPost[]>;
18
17
  };
19
18
  categoriesApi: {
19
+ listAll: (params?: Omit<import("wpjsapi-lib").WPCategoryParameters, "page" | "per_page"> | undefined, options?: import("wpjsapi-lib").RequestOptions) => Promise<import("wpjsapi-lib").WPCategory[]>;
20
+ pages: (params?: import("wpjsapi-lib").WPCategoryParameters | undefined, options?: import("wpjsapi-lib").RequestOptions) => AsyncGenerator<import("wpjsapi-lib").WPPaginatedResponse<import("wpjsapi-lib").WPCategory>, void, unknown>;
20
21
  list: (params?: import("wpjsapi-lib").WPCategoryParameters, options?: import("wpjsapi-lib").RequestOptions) => Promise<import("wpjsapi-lib").WPPaginatedResponse<import("wpjsapi-lib").WPCategory>>;
21
- listAll: (params?: Omit<import("wpjsapi-lib").WPCategoryParameters, "page" | "per_page">, options?: import("wpjsapi-lib").RequestOptions) => Promise<import("wpjsapi-lib").WPCategory[]>;
22
- pages: (params?: import("wpjsapi-lib").WPCategoryParameters, options?: import("wpjsapi-lib").RequestOptions) => {
23
- [Symbol.asyncIterator](): AsyncGenerator<import("wpjsapi-lib").WPPaginatedResponse<import("wpjsapi-lib").WPCategory>, void, unknown>;
24
- };
25
22
  get: (id: number, context?: "view" | "embed" | "edit", embed?: boolean, options?: import("wpjsapi-lib").RequestOptions) => Promise<import("wpjsapi-lib").WPCategory>;
26
23
  create: (data: import("wpjsapi-lib").WPCategoryCreate, options?: import("wpjsapi-lib").RequestOptions) => Promise<import("wpjsapi-lib").WPCategory>;
27
24
  update: (id: number, data: import("wpjsapi-lib").WPCategoryUpdate, options?: import("wpjsapi-lib").RequestOptions) => Promise<import("wpjsapi-lib").WPCategory>;
@@ -1,5 +1,19 @@
1
1
  import { createAuth, createCategoryEndpoints, createPostsEndpoints, } from "wpjsapi-lib";
2
+ export function isValidWpApiUrl(baseUrl) {
3
+ if (!baseUrl)
4
+ return false;
5
+ try {
6
+ const url = new URL(baseUrl);
7
+ return url.protocol === "http:" || url.protocol === "https:";
8
+ }
9
+ catch {
10
+ return false;
11
+ }
12
+ }
2
13
  export function createWpClient({ baseUrl, username, appPassword, }) {
14
+ if (!isValidWpApiUrl(baseUrl)) {
15
+ throw new Error("WP API URL must be an absolute http(s) URL. Set WP_API_URL to your WordPress REST API root.");
16
+ }
3
17
  const hasAuth = username && appPassword;
4
18
  const auth = hasAuth
5
19
  ? createAuth({
@@ -1,5 +1,6 @@
1
- import type { LanguageConfig } from "../utils/hreflang";
1
+ import type { LanguageConfig } from "../utils/hreflang.js";
2
2
  export declare const languages: LanguageConfig[];
3
+ export declare const normalizedLanguages: import("../index.js").SiteLanguage[];
3
4
  export declare const runtimeConfig: {
4
5
  postsPerPagePagination: number;
5
6
  };
@@ -1,3 +1,4 @@
1
+ import { normalizeLanguages } from "../utils/language.js";
1
2
  const parseLanguagesFromEnv = () => {
2
3
  const raw = process.env.WP_LANGUAGES;
3
4
  if (!raw)
@@ -23,6 +24,9 @@ const parseLanguagesFromEnv = () => {
23
24
  }
24
25
  };
25
26
  export const languages = parseLanguagesFromEnv();
27
+ export const normalizedLanguages = normalizeLanguages(languages, {
28
+ defaultCode: process.env.WP_DEFAULT_LANGUAGE || process.env.NEXT_PUBLIC_DEFAULT_LANGUAGE,
29
+ });
26
30
  export const runtimeConfig = {
27
31
  postsPerPagePagination: Number.parseInt(process.env.WP_POSTS_PER_PAGE_PAGINATION ?? "", 10) || 10,
28
32
  };
@@ -8,16 +8,19 @@
8
8
  --spacing-xl: 3rem;
9
9
 
10
10
  /* Typography */
11
- --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "Inter", "Roboto",
12
- "Helvetica Neue", Arial, sans-serif;
13
- --font-display: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
11
+ --font-sans: Arial, sans-serif;
12
+ --font-display: Arial, sans-serif;
14
13
 
15
14
  /* Transitions */
16
- --transition: all 0.2s ease;
15
+ --transition: color 0.2s ease, background-color 0.2s ease,
16
+ border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
17
+ --focus-ring: 0 0 0 3px rgba(37, 99, 235, 0.28);
17
18
 
18
19
  /* Colors - Light theme (default) */
19
20
  --primary: #2563eb;
20
21
  --primary-hover: #1d4ed8;
22
+ --primary-foreground: #ffffff;
23
+ --destructive: #dc2626;
21
24
  --secondary: #64748b;
22
25
  --background: #ffffff;
23
26
  --background-alt: #f8fafc;
@@ -65,6 +68,21 @@ html {
65
68
  scroll-behavior: smooth;
66
69
  }
67
70
 
71
+ @media (prefers-reduced-motion: reduce) {
72
+ html {
73
+ scroll-behavior: auto;
74
+ }
75
+
76
+ *,
77
+ *::before,
78
+ *::after {
79
+ animation-duration: 0.01ms !important;
80
+ animation-iteration-count: 1 !important;
81
+ scroll-behavior: auto !important;
82
+ transition-duration: 0.01ms !important;
83
+ }
84
+ }
85
+
68
86
  html,
69
87
  body {
70
88
  max-width: 100vw;
@@ -78,6 +96,7 @@ body {
78
96
  -webkit-font-smoothing: antialiased;
79
97
  -moz-osx-font-smoothing: grayscale;
80
98
  line-height: 1.6;
99
+ touch-action: manipulation;
81
100
  }
82
101
 
83
102
  /* Typography */
@@ -92,6 +111,7 @@ h6 {
92
111
  line-height: 1.2;
93
112
  color: var(--foreground);
94
113
  margin-bottom: 0.75rem;
114
+ text-wrap: balance;
95
115
  }
96
116
 
97
117
  h1 {
@@ -122,6 +142,17 @@ a:hover {
122
142
  color: var(--primary-hover);
123
143
  }
124
144
 
145
+ a:focus-visible,
146
+ button:focus-visible,
147
+ [role="button"]:focus-visible,
148
+ input:focus-visible,
149
+ select:focus-visible,
150
+ textarea:focus-visible {
151
+ outline: 2px solid var(--primary);
152
+ outline-offset: 3px;
153
+ box-shadow: var(--focus-ring);
154
+ }
155
+
125
156
  /* Post content styling */
126
157
  .post-content h2 {
127
158
  margin-top: 2.5rem;
@@ -196,51 +227,6 @@ a:hover {
196
227
  overflow-x: auto;
197
228
  }
198
229
 
199
- /* Container */
200
- .container {
201
- width: 100%;
202
- max-width: var(--container-width);
203
- margin: 0 auto;
204
- padding: 0 var(--spacing-md);
205
- }
206
-
207
- /* Card styling */
208
- .card {
209
- background: var(--card-bg);
210
- border-radius: 12px;
211
- overflow: hidden;
212
- box-shadow: 0 1px 3px var(--shadow);
213
- transition: var(--transition);
214
- }
215
-
216
- .card:hover {
217
- box-shadow: 0 10px 25px var(--shadow-hover);
218
- transform: translateY(-2px);
219
- }
220
-
221
- /* Badge */
222
- .badge {
223
- display: inline-block;
224
- padding: 0.25rem 0.75rem;
225
- background: var(--primary);
226
- color: #ffffff;
227
- font-size: 0.75rem;
228
- font-weight: 600;
229
- border-radius: 9999px;
230
- text-transform: uppercase;
231
- letter-spacing: 0.05em;
232
- transition: var(--transition);
233
- }
234
-
235
- .badge:hover,
236
- .badge:focus-visible,
237
- a.badge,
238
- a.badge:hover,
239
- a.badge:focus-visible {
240
- color: #ffffff !important;
241
- background: var(--primary-hover);
242
- }
243
-
244
230
  /* Utilities */
245
231
  .text-muted {
246
232
  color: var(--foreground-light);
@@ -250,45 +236,6 @@ a {
250
236
  text-decoration: none;
251
237
  }
252
238
 
253
- a.header-link {
254
- color: var(--foreground);
255
- font-weight: 600;
256
- font-size: 0.9375rem;
257
- transition: var(--transition);
258
- position: relative;
259
- display: inline-block;
260
- }
261
-
262
- a.header-link::after {
263
- content: "";
264
- position: absolute;
265
- bottom: -4px;
266
- left: 0;
267
- width: 0;
268
- height: 2px;
269
- background: var(--primary);
270
- transition: width 0.3s ease;
271
- }
272
-
273
- a.header-link:hover {
274
- color: var(--primary);
275
- }
276
-
277
- a.header-link:hover::after {
278
- width: 100%;
279
- }
280
-
281
- a.footer-link {
282
- color: var(--foreground-light);
283
- font-size: 0.875rem;
284
- transition: var(--transition);
285
- display: inline-block;
286
- }
287
-
288
- a.footer-link:hover {
289
- color: var(--primary);
290
- }
291
-
292
239
  @media (prefers-color-scheme: dark) {
293
240
  :root:not([data-theme]) {
294
241
  color-scheme: dark;
@@ -298,39 +245,3 @@ a.footer-link:hover {
298
245
  :root[data-theme="dark"] {
299
246
  color-scheme: dark;
300
247
  }
301
-
302
- /* Paginator styles */
303
- .paginator-nav,
304
- .paginator-page {
305
- padding: 0.625rem 1.25rem;
306
- border: 1px solid var(--border);
307
- border-radius: 8px;
308
- background: var(--card-bg);
309
- color: var(--foreground);
310
- font-weight: 500;
311
- font-size: 0.9375rem;
312
- transition: var(--transition);
313
- display: inline-flex;
314
- align-items: center;
315
- justify-content: center;
316
- min-width: 44px;
317
- }
318
-
319
- .paginator-nav:hover,
320
- .paginator-page:hover {
321
- border-color: var(--primary);
322
- background: var(--background-alt);
323
- color: var(--primary);
324
- }
325
-
326
- .paginator-page.paginator-active {
327
- background: var(--primary);
328
- color: white;
329
- border-color: var(--primary);
330
- font-weight: 600;
331
- }
332
-
333
- .paginator-page.paginator-active:hover {
334
- background: var(--primary-hover);
335
- color: white;
336
- }
@@ -2,7 +2,7 @@ import { type WPCategory, type WPPost } from "wpjsapi-lib";
2
2
  import type { Metadata } from "next";
3
3
  type CategoryStaticParamsInput = {
4
4
  baseApiUrl: string;
5
- lang: string;
5
+ lang?: string;
6
6
  };
7
7
  export declare function getCategoryStaticParams({ baseApiUrl, lang, }: CategoryStaticParamsInput): Promise<Array<{
8
8
  category: string;
@@ -10,7 +10,7 @@ export declare function getCategoryStaticParams({ baseApiUrl, lang, }: CategoryS
10
10
  export declare function fetchCategory({ baseApiUrl, slug, lang, }: {
11
11
  baseApiUrl: string;
12
12
  slug: string;
13
- lang: string;
13
+ lang?: string;
14
14
  }): Promise<WPCategory | null>;
15
15
  export declare function fetchCategoryPosts({ baseApiUrl, categoryId, perPage, langId, }: {
16
16
  baseApiUrl: string;
@@ -24,7 +24,7 @@ export declare function fetchCategoryPosts({ baseApiUrl, categoryId, perPage, la
24
24
  export declare function fetchCategoryByTranslationKey({ baseApiUrl, translationKey, lang, }: {
25
25
  baseApiUrl: string;
26
26
  translationKey: string;
27
- lang: string;
27
+ lang?: string;
28
28
  }): Promise<WPCategory | null>;
29
29
  export declare function buildCategoryMetadata({ category, canonical, useYoast, siteName, languages, siteUrl, wpApiUrl, }: {
30
30
  category: WPCategory;
@@ -1,7 +1,7 @@
1
- import { getPlainTextExcerpt } from "../../utils";
2
- import { withXDefault } from "../../utils/hreflang";
3
- import { extractYoastMetadata } from "../../plugins/yoast";
4
- import { getCategoryByTranslationKey, getCategoryBySlug, listCategoryPosts, listCategoryStaticParams, } from "../../api/categories";
1
+ import { getPlainTextExcerpt, toPlainText } from "../../utils/index.js";
2
+ import { withXDefault } from "../../utils/hreflang.js";
3
+ import { extractYoastMetadata } from "../../plugins/yoast/index.js";
4
+ import { getCategoryByTranslationKey, getCategoryBySlug, listCategoryPosts, listCategoryStaticParams, } from "../../api/categories.js";
5
5
  export async function getCategoryStaticParams({ baseApiUrl, lang, }) {
6
6
  const result = await listCategoryStaticParams({
7
7
  baseApiUrl,
@@ -57,16 +57,17 @@ export async function fetchCategoryByTranslationKey({ baseApiUrl, translationKey
57
57
  }
58
58
  export function buildCategoryMetadata({ category, canonical, useYoast = true, siteName, languages, siteUrl, wpApiUrl, }) {
59
59
  const fallbackDescription = getPlainTextExcerpt(category.description, 160);
60
+ const fallbackTitle = toPlainText(category.name) || category.name;
60
61
  const languageAlternates = withXDefault(languages);
61
62
  const fallbackMetadata = {
62
- title: category.name,
63
+ title: fallbackTitle,
63
64
  description: fallbackDescription,
64
65
  alternates: {
65
66
  canonical,
66
67
  ...(languageAlternates ? { languages: languageAlternates } : {}),
67
68
  },
68
69
  openGraph: {
69
- title: category.name,
70
+ title: fallbackTitle,
70
71
  description: fallbackDescription,
71
72
  url: canonical,
72
73
  siteName,
@@ -74,7 +75,7 @@ export function buildCategoryMetadata({ category, canonical, useYoast = true, si
74
75
  },
75
76
  twitter: {
76
77
  card: "summary_large_image",
77
- title: category.name,
78
+ title: fallbackTitle,
78
79
  description: fallbackDescription,
79
80
  },
80
81
  };
@@ -82,7 +83,7 @@ export function buildCategoryMetadata({ category, canonical, useYoast = true, si
82
83
  return fallbackMetadata;
83
84
  const meta = extractYoastMetadata(category, {
84
85
  url: canonical,
85
- title: category.name,
86
+ title: fallbackTitle,
86
87
  description: fallbackDescription,
87
88
  siteName,
88
89
  }, { siteUrl, wpApiUrl });
@@ -3,7 +3,7 @@ import type { Metadata } from "next";
3
3
  type CategoryStaticParamsInput = {
4
4
  baseApiUrl: string;
5
5
  perPage: number;
6
- lang: string;
6
+ lang?: string;
7
7
  langId?: string;
8
8
  };
9
9
  type CategoryStaticParam = {
@@ -14,7 +14,7 @@ export declare function getCategoryPaginationStaticParams({ baseApiUrl, perPage,
14
14
  export declare function fetchCategoryBySlug({ baseApiUrl, slug, lang, }: {
15
15
  baseApiUrl: string;
16
16
  slug: string;
17
- lang: string;
17
+ lang?: string;
18
18
  }): Promise<WPCategory | null>;
19
19
  export declare function fetchCategoryPaginatedPosts({ baseApiUrl, categoryId, page, perPage, langId, }: {
20
20
  baseApiUrl: string;
@@ -1,15 +1,17 @@
1
- import { buildCategoryMetadata } from "./index";
2
- import { createWpClient } from "../../api/wpClient";
3
- import { getPostsTotalPages, listPostsWithEmbeds } from "../../api/posts";
4
- import { mapCategoryEntity } from "../../api/mappers";
5
- import { getCategoryBySlug as getCategoryBySlugApi } from "../../api/categories";
6
- import { ensureTrailingSlash } from "../../utils";
1
+ import { buildCategoryMetadata } from "./index.js";
2
+ import { createWpClient, isValidWpApiUrl } from "../../api/wpClient.js";
3
+ import { getPostsTotalPages, listPostsWithEmbeds } from "../../api/posts.js";
4
+ import { mapCategoryEntity } from "../../api/mappers.js";
5
+ import { getCategoryBySlug as getCategoryBySlugApi } from "../../api/categories.js";
6
+ import { ensureTrailingSlash } from "../../utils/index.js";
7
7
  export async function getCategoryPaginationStaticParams({ baseApiUrl, perPage, lang, langId, }) {
8
- const { categoriesApi } = createWpClient({
9
- baseUrl: baseApiUrl,
10
- });
8
+ if (!isValidWpApiUrl(baseApiUrl))
9
+ return [];
11
10
  try {
12
- const categories = await categoriesApi.listAll({ lang });
11
+ const { categoriesApi } = createWpClient({
12
+ baseUrl: baseApiUrl,
13
+ });
14
+ const categories = await categoriesApi.listAll(lang ? { lang } : undefined);
13
15
  const paths = [];
14
16
  for (const category of categories) {
15
17
  const totalPagesResult = await getPostsTotalPages({
@@ -1,4 +1,4 @@
1
- import { listPostsWithEmbeds } from "../../api/posts";
1
+ import { listPostsWithEmbeds } from "../../api/posts.js";
2
2
  export async function fetchHomePosts({ baseApiUrl, perPage, langId, }) {
3
3
  const postsResponse = await listPostsWithEmbeds({
4
4
  perPage,
@@ -1,6 +1,6 @@
1
- import { getPlainTextExcerpt, getOgImageUrl, getFeaturedMedia, } from "../../utils";
2
- import { withXDefault } from "../../utils/hreflang";
3
- import { listPostsWithEmbeds, getPostsTotalPages } from "../../api/posts";
1
+ import { getPlainTextExcerpt, getOgImageUrl, getFeaturedMedia, } from "../../utils/index.js";
2
+ import { withXDefault } from "../../utils/hreflang.js";
3
+ import { listPostsWithEmbeds, getPostsTotalPages } from "../../api/posts.js";
4
4
  export async function getHomePaginationStaticParams({ baseApiUrl, perPage, langId, }) {
5
5
  const totalPagesResult = await getPostsTotalPages({
6
6
  baseApiUrl,