wpheadless-lib 1.0.0 → 1.0.2
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/app/globals.css +11 -1
- package/dist/components/Breadcrumbs/index.js +6 -1
- package/dist/components/PostCard/index.js +6 -2
- package/dist/components/PostCard/index.module.css +11 -2
- package/dist/components/layout/Header/HeaderClient.d.ts +19 -0
- package/dist/components/layout/Header/HeaderClient.js +27 -0
- package/dist/components/layout/Header/index.js +14 -3
- package/dist/components/layout/Header/index.module.css +127 -7
- package/dist/utils/i18n.js +4 -0
- package/dist/utils/seo.d.ts +1 -0
- package/dist/utils/seo.js +1 -0
- package/dist/views/CategoryListView/index.d.ts +2 -1
- package/dist/views/CategoryListView/index.js +2 -2
- package/dist/views/CategoryPaginationView/index.js +1 -1
- package/dist/views/HomeView/index.js +5 -1
- package/dist/views/HomeView/index.module.css +1 -1
- package/dist/views/PostView/index.js +5 -1
- package/dist/views/PostView/index.module.css +37 -12
- package/package.json +2 -2
package/dist/app/globals.css
CHANGED
|
@@ -223,12 +223,22 @@ a:hover {
|
|
|
223
223
|
display: inline-block;
|
|
224
224
|
padding: 0.25rem 0.75rem;
|
|
225
225
|
background: var(--primary);
|
|
226
|
-
color:
|
|
226
|
+
color: #ffffff;
|
|
227
227
|
font-size: 0.75rem;
|
|
228
228
|
font-weight: 600;
|
|
229
229
|
border-radius: 9999px;
|
|
230
230
|
text-transform: uppercase;
|
|
231
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);
|
|
232
242
|
}
|
|
233
243
|
|
|
234
244
|
/* Utilities */
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import Link from "next/link";
|
|
3
3
|
import styles from "./index.module.css";
|
|
4
|
+
function truncateLabel(label, max = 30) {
|
|
5
|
+
const trimmed = label.trim();
|
|
6
|
+
return trimmed.length > max ? `${trimmed.slice(0, max)}...` : trimmed;
|
|
7
|
+
}
|
|
4
8
|
export function Breadcrumbs({ items }) {
|
|
5
9
|
if (!items.length)
|
|
6
10
|
return null;
|
|
7
11
|
return (_jsx("nav", { "aria-label": "Breadcrumb", className: styles.nav, children: _jsx("ol", { className: styles.list, children: items.map((item, idx) => {
|
|
8
12
|
const isLast = idx === items.length - 1;
|
|
9
|
-
|
|
13
|
+
const display = truncateLabel(item.label, 30);
|
|
14
|
+
return (_jsxs("li", { className: styles.item, children: [item.href && !isLast ? (_jsx(Link, { href: item.href, className: styles.link, title: item.label, children: display })) : (_jsx("span", { className: styles.current, "aria-current": isLast ? "page" : undefined, title: item.label, children: display })), idx < items.length - 1 && (_jsx("span", { className: styles.separator, children: "/" }))] }, `${item.label}-${idx}`));
|
|
10
15
|
}) }) }));
|
|
11
16
|
}
|
|
@@ -4,6 +4,10 @@ import Link from "next/link";
|
|
|
4
4
|
import { getFeaturedMedia } from "../../utils";
|
|
5
5
|
import { buildCategoryUrl, buildPostUrl, formatPostDate, resolveCategorySlug, } from "./index.utils";
|
|
6
6
|
import styles from "./index.module.css";
|
|
7
|
+
function truncateText(text, max = 20) {
|
|
8
|
+
const normalized = text.trim();
|
|
9
|
+
return normalized.length > max ? `${normalized.slice(0, max)}...` : normalized;
|
|
10
|
+
}
|
|
7
11
|
export default function PostCard({ post, categorySlug, locale = "en", dateLocale = "en-US", }) {
|
|
8
12
|
const featuredMedia = getFeaturedMedia(post);
|
|
9
13
|
const imageUrl = featuredMedia?.source_url;
|
|
@@ -14,9 +18,9 @@ export default function PostCard({ post, categorySlug, locale = "en", dateLocale
|
|
|
14
18
|
categorySlug: resolvedCategory,
|
|
15
19
|
locale,
|
|
16
20
|
});
|
|
17
|
-
return (_jsxs("article", { className: `${styles.card} card`, children: [categories.length > 0 && (_jsx("div", { className: styles.badges, children: categories.map((cat) => (_jsx(Link, { href: buildCategoryUrl(cat.slug, locale), className: `badge ${styles.badge}`, children: cat.name }, cat.id ?? cat.slug))) })), _jsxs(Link, { href: postUrl, className: styles.postLink, children: [imageUrl && (_jsx("div", { className: styles.imageWrapper, children: _jsx(Image, { src: imageUrl, alt: featuredMedia?.alt_text || post.title.rendered, fill: true, style: { objectFit: "cover" }, sizes: "(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw" }) })), _jsxs("div", { className: styles.body, children: [_jsx("h2", { dangerouslySetInnerHTML: {
|
|
21
|
+
return (_jsxs("article", { className: `${styles.card} card`, children: [categories.length > 0 && (_jsx("div", { className: styles.badges, children: categories.map((cat) => (_jsx(Link, { href: buildCategoryUrl(cat.slug, locale), className: `badge ${styles.badge}`, title: cat.name, children: truncateText(cat.name, 20) }, cat.id ?? cat.slug))) })), _jsxs(Link, { href: postUrl, className: styles.postLink, children: [imageUrl && (_jsx("div", { className: styles.imageWrapper, children: _jsx(Image, { src: imageUrl, alt: featuredMedia?.alt_text || post.title.rendered, fill: true, style: { objectFit: "cover" }, sizes: "(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw" }) })), _jsxs("div", { className: styles.body, children: [_jsx("h2", { className: styles.title, dangerouslySetInnerHTML: {
|
|
18
22
|
__html: post.title.rendered,
|
|
19
|
-
}
|
|
23
|
+
} }), _jsx("div", { dangerouslySetInnerHTML: {
|
|
20
24
|
__html: post.excerpt.rendered,
|
|
21
25
|
}, className: styles.excerpt }), _jsx("time", { dateTime: post.date, className: styles.date, children: formatPostDate(post.date, dateLocale) })] })] })] }));
|
|
22
26
|
}
|
|
@@ -3,17 +3,23 @@
|
|
|
3
3
|
display: flex;
|
|
4
4
|
flex-direction: column;
|
|
5
5
|
height: 100%;
|
|
6
|
+
overflow: hidden;
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
.badges {
|
|
10
|
+
position: absolute;
|
|
11
|
+
top: 12px;
|
|
12
|
+
left: 12px;
|
|
13
|
+
right: 12px;
|
|
9
14
|
display: flex;
|
|
10
15
|
gap: 0.5rem;
|
|
11
16
|
flex-wrap: wrap;
|
|
12
|
-
|
|
17
|
+
z-index: 2;
|
|
13
18
|
}
|
|
14
19
|
|
|
15
20
|
.badge {
|
|
16
21
|
text-decoration: none;
|
|
22
|
+
box-shadow: 0 6px 16px var(--shadow);
|
|
17
23
|
}
|
|
18
24
|
|
|
19
25
|
.postLink {
|
|
@@ -21,6 +27,8 @@
|
|
|
21
27
|
color: inherit;
|
|
22
28
|
display: block;
|
|
23
29
|
height: 100%;
|
|
30
|
+
position: relative;
|
|
31
|
+
z-index: 1;
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
.imageWrapper {
|
|
@@ -33,7 +41,7 @@
|
|
|
33
41
|
padding: var(--spacing-sm) var(--spacing-md) var(--spacing-md);
|
|
34
42
|
display: flex;
|
|
35
43
|
flex-direction: column;
|
|
36
|
-
gap: var(--spacing-
|
|
44
|
+
gap: var(--spacing-xs);
|
|
37
45
|
align-items: flex-start;
|
|
38
46
|
}
|
|
39
47
|
|
|
@@ -42,6 +50,7 @@
|
|
|
42
50
|
font-weight: 700;
|
|
43
51
|
line-height: 1.3;
|
|
44
52
|
color: var(--foreground);
|
|
53
|
+
margin-top: 0;
|
|
45
54
|
}
|
|
46
55
|
|
|
47
56
|
.excerpt {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
type MenuLink = {
|
|
2
|
+
id: number;
|
|
3
|
+
href: string;
|
|
4
|
+
label: string;
|
|
5
|
+
target?: string;
|
|
6
|
+
};
|
|
7
|
+
type HeaderLabels = {
|
|
8
|
+
navAria: string;
|
|
9
|
+
openMenu: string;
|
|
10
|
+
closeMenu: string;
|
|
11
|
+
};
|
|
12
|
+
type HeaderClientProps = {
|
|
13
|
+
menuLinks: MenuLink[];
|
|
14
|
+
siteName: string;
|
|
15
|
+
homeHref: string;
|
|
16
|
+
labels: HeaderLabels;
|
|
17
|
+
};
|
|
18
|
+
export default function HeaderClient({ menuLinks, siteName, homeHref, labels, }: HeaderClientProps): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
import styles from "./index.module.css";
|
|
6
|
+
export default function HeaderClient({ menuLinks, siteName, homeHref, labels, }) {
|
|
7
|
+
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
|
8
|
+
const [isMobileView, setIsMobileView] = useState(false);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const handleResize = () => {
|
|
11
|
+
const isMobile = window.innerWidth < 900;
|
|
12
|
+
setIsMobileView(isMobile);
|
|
13
|
+
if (!isMobile) {
|
|
14
|
+
setIsMenuOpen(false);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
handleResize();
|
|
18
|
+
window.addEventListener("resize", handleResize);
|
|
19
|
+
return () => window.removeEventListener("resize", handleResize);
|
|
20
|
+
}, []);
|
|
21
|
+
const toggleMenu = () => setIsMenuOpen((prev) => !prev);
|
|
22
|
+
const handleLinkClick = () => setIsMenuOpen(false);
|
|
23
|
+
const menuLabel = isMenuOpen ? labels.closeMenu : labels.openMenu;
|
|
24
|
+
return (_jsxs("div", { className: styles.inner, children: [_jsx(Link, { href: homeHref, className: styles.logo, children: siteName }), menuLinks.length > 0 && (_jsxs("div", { className: styles.navWrapper, children: [_jsxs("button", { type: "button", className: styles.menuButton, "aria-expanded": isMenuOpen, "aria-controls": "primary-navigation", "aria-label": menuLabel, onClick: toggleMenu, children: [_jsxs("span", { className: styles.menuIcon, "aria-hidden": "true", children: [_jsx("span", {}), _jsx("span", {}), _jsx("span", {})] }), _jsx("span", { className: styles.menuText, children: menuLabel })] }), _jsx("nav", { id: "primary-navigation", "aria-label": labels.navAria, className: `${styles.nav} ${isMenuOpen ? styles.navOpen : ""}`, "aria-hidden": !isMenuOpen && isMobileView, hidden: !isMenuOpen && isMobileView, children: _jsx("ul", { className: styles.list, children: menuLinks.map((item) => (_jsx("li", { children: _jsx(Link, { href: item.href, className: "header-link", onClick: handleLinkClick, target: item.target || undefined, rel: item.target === "_blank"
|
|
25
|
+
? "noopener noreferrer"
|
|
26
|
+
: undefined, children: item.label }) }, item.id))) }) })] }))] }));
|
|
27
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import Link from "next/link";
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
2
|
import { createMenuEndpoints, createAuth } from "wpjsapi-lib";
|
|
4
3
|
import { convertWpUrl, getTranslator } from "../../../utils";
|
|
4
|
+
import HeaderClient from "./HeaderClient";
|
|
5
5
|
import styles from "./index.module.css";
|
|
6
6
|
export const dynamic = "force-static";
|
|
7
7
|
export const revalidate = 3600;
|
|
@@ -32,5 +32,16 @@ export default async function Header({ menuId, wpApiUrl, wpUsername, wpAppPasswo
|
|
|
32
32
|
catch (e) {
|
|
33
33
|
console.error("Error obteniendo menú:", e);
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
const menuLinks = menuItems.map((item) => ({
|
|
36
|
+
id: item.id,
|
|
37
|
+
href: convertWpUrl(item.url, wpApiUrl),
|
|
38
|
+
label: item.title.rendered,
|
|
39
|
+
target: item.target || undefined,
|
|
40
|
+
}));
|
|
41
|
+
const labels = {
|
|
42
|
+
navAria: t("header.navAria"),
|
|
43
|
+
openMenu: t("header.openMenu"),
|
|
44
|
+
closeMenu: t("header.closeMenu"),
|
|
45
|
+
};
|
|
46
|
+
return (_jsx("header", { className: styles.header, children: _jsx("div", { className: "container", children: _jsx(HeaderClient, { menuLinks: menuLinks, siteName: siteName, homeHref: homeHref, labels: labels }) }) }));
|
|
36
47
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
.header {
|
|
2
|
+
--header-height: 78px;
|
|
2
3
|
position: sticky;
|
|
3
4
|
top: 0;
|
|
4
5
|
z-index: 100;
|
|
@@ -14,6 +15,8 @@
|
|
|
14
15
|
justify-content: space-between;
|
|
15
16
|
padding: 1.25rem 0;
|
|
16
17
|
gap: 3rem;
|
|
18
|
+
position: relative;
|
|
19
|
+
min-height: var(--header-height);
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
.logo {
|
|
@@ -25,13 +28,6 @@
|
|
|
25
28
|
text-decoration: none;
|
|
26
29
|
}
|
|
27
30
|
|
|
28
|
-
.navWrapper {
|
|
29
|
-
display: flex;
|
|
30
|
-
align-items: center;
|
|
31
|
-
gap: 2rem;
|
|
32
|
-
flex: 1;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
31
|
.nav {
|
|
36
32
|
flex: 1;
|
|
37
33
|
display: flex;
|
|
@@ -46,3 +42,127 @@
|
|
|
46
42
|
margin: 0;
|
|
47
43
|
padding: 0;
|
|
48
44
|
}
|
|
45
|
+
|
|
46
|
+
.navWrapper {
|
|
47
|
+
display: flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
gap: 1.5rem;
|
|
50
|
+
flex: 1;
|
|
51
|
+
justify-content: flex-end;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.menuButton {
|
|
55
|
+
display: none;
|
|
56
|
+
align-items: center;
|
|
57
|
+
gap: 0.5rem;
|
|
58
|
+
padding: 0.6rem 0.75rem;
|
|
59
|
+
border-radius: 10px;
|
|
60
|
+
border: 1px solid var(--border);
|
|
61
|
+
background: var(--background);
|
|
62
|
+
color: var(--foreground);
|
|
63
|
+
font-weight: 600;
|
|
64
|
+
cursor: pointer;
|
|
65
|
+
transition: var(--transition);
|
|
66
|
+
position: relative;
|
|
67
|
+
z-index: 120;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.menuButton:hover {
|
|
71
|
+
border-color: var(--primary);
|
|
72
|
+
color: var(--primary);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.menuIcon {
|
|
76
|
+
position: relative;
|
|
77
|
+
width: 20px;
|
|
78
|
+
height: 14px;
|
|
79
|
+
display: inline-block;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.menuIcon span {
|
|
83
|
+
position: absolute;
|
|
84
|
+
left: 0;
|
|
85
|
+
width: 100%;
|
|
86
|
+
height: 2px;
|
|
87
|
+
background: currentColor;
|
|
88
|
+
border-radius: 999px;
|
|
89
|
+
transition: transform 0.3s ease, opacity 0.3s ease;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.menuIcon span:nth-child(1) {
|
|
93
|
+
top: 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.menuIcon span:nth-child(2) {
|
|
97
|
+
top: 6px;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.menuIcon span:nth-child(3) {
|
|
101
|
+
top: 12px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.menuButton[aria-expanded="true"] .menuIcon span:nth-child(1) {
|
|
105
|
+
transform: translateY(6px) rotate(45deg);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.menuButton[aria-expanded="true"] .menuIcon span:nth-child(2) {
|
|
109
|
+
opacity: 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.menuButton[aria-expanded="true"] .menuIcon span:nth-child(3) {
|
|
113
|
+
transform: translateY(-6px) rotate(-45deg);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.menuText {
|
|
117
|
+
position: absolute;
|
|
118
|
+
width: 1px;
|
|
119
|
+
height: 1px;
|
|
120
|
+
padding: 0;
|
|
121
|
+
margin: -1px;
|
|
122
|
+
overflow: hidden;
|
|
123
|
+
clip: rect(0, 0, 0, 0);
|
|
124
|
+
white-space: nowrap;
|
|
125
|
+
border: 0;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@media (max-width: 900px) {
|
|
129
|
+
.inner {
|
|
130
|
+
gap: 1.25rem;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.nav {
|
|
134
|
+
position: fixed;
|
|
135
|
+
top: var(--header-height);
|
|
136
|
+
left: 0;
|
|
137
|
+
right: 0;
|
|
138
|
+
bottom: 0;
|
|
139
|
+
height: calc(100vh - var(--header-height));
|
|
140
|
+
padding: 1.5rem 1.25rem 2.5rem;
|
|
141
|
+
background: var(--card-bg);
|
|
142
|
+
display: block;
|
|
143
|
+
overflow: hidden;
|
|
144
|
+
opacity: 0;
|
|
145
|
+
pointer-events: none;
|
|
146
|
+
transform: translateY(-8px);
|
|
147
|
+
transition: opacity 0.25s ease, transform 0.25s ease;
|
|
148
|
+
z-index: 90;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.navOpen {
|
|
152
|
+
opacity: 1;
|
|
153
|
+
pointer-events: auto;
|
|
154
|
+
overflow: auto;
|
|
155
|
+
transform: translateY(0);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.list {
|
|
159
|
+
flex-direction: column;
|
|
160
|
+
align-items: flex-start;
|
|
161
|
+
gap: 1rem;
|
|
162
|
+
padding: 1rem 0 1.25rem;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.menuButton {
|
|
166
|
+
display: inline-flex;
|
|
167
|
+
}
|
|
168
|
+
}
|
package/dist/utils/i18n.js
CHANGED
|
@@ -7,6 +7,8 @@ const defaultMessages = {
|
|
|
7
7
|
},
|
|
8
8
|
header: {
|
|
9
9
|
navAria: "Main navigation",
|
|
10
|
+
openMenu: "Open menu",
|
|
11
|
+
closeMenu: "Close menu",
|
|
10
12
|
},
|
|
11
13
|
site: {
|
|
12
14
|
title: "Site title",
|
|
@@ -61,6 +63,8 @@ const defaultMessages = {
|
|
|
61
63
|
},
|
|
62
64
|
header: {
|
|
63
65
|
navAria: "Navegación principal",
|
|
66
|
+
openMenu: "Abrir menú",
|
|
67
|
+
closeMenu: "Cerrar menú",
|
|
64
68
|
},
|
|
65
69
|
site: {
|
|
66
70
|
title: "Título del sitio",
|
package/dist/utils/seo.d.ts
CHANGED
package/dist/utils/seo.js
CHANGED
|
@@ -78,6 +78,7 @@ export function buildBreadcrumbSchema(items) {
|
|
|
78
78
|
return {
|
|
79
79
|
"@context": "https://schema.org",
|
|
80
80
|
"@type": "BreadcrumbList",
|
|
81
|
+
"@id": `${items[items.length - 1].item}#breadcrumb`,
|
|
81
82
|
itemListElement: items.map((it, idx) => ({
|
|
82
83
|
"@type": "ListItem",
|
|
83
84
|
position: idx + 1,
|
|
@@ -5,8 +5,9 @@ type CategoryListViewProps = {
|
|
|
5
5
|
posts: WPPost[];
|
|
6
6
|
totalPages: number;
|
|
7
7
|
baseUrl?: string;
|
|
8
|
+
homeHref?: string;
|
|
8
9
|
locale?: Locale;
|
|
9
10
|
dateLocale?: string;
|
|
10
11
|
};
|
|
11
|
-
export declare function CategoryListView({ category, posts, totalPages, baseUrl, locale, dateLocale, }: CategoryListViewProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare function CategoryListView({ category, posts, totalPages, baseUrl, homeHref, locale, dateLocale, }: CategoryListViewProps): import("react/jsx-runtime").JSX.Element;
|
|
12
13
|
export {};
|
|
@@ -5,13 +5,13 @@ import styles from "./index.module.css";
|
|
|
5
5
|
import { getCountLabel, getEmptyLabel, getPaginatorBase } from "./index.utils";
|
|
6
6
|
import { Breadcrumbs } from "../../components";
|
|
7
7
|
import { getTranslator } from "../../utils";
|
|
8
|
-
export function CategoryListView({ category, posts, totalPages, baseUrl, locale, dateLocale = "en-US", }) {
|
|
8
|
+
export function CategoryListView({ category, posts, totalPages, baseUrl, homeHref = "/", locale, dateLocale = "en-US", }) {
|
|
9
9
|
const paginatorBase = getPaginatorBase(category, baseUrl);
|
|
10
10
|
const countLabel = getCountLabel(category, locale);
|
|
11
11
|
const emptyLabel = getEmptyLabel(locale);
|
|
12
12
|
const t = getTranslator(locale);
|
|
13
13
|
return (_jsxs("div", { className: `container ${styles.container}`, children: [_jsxs("header", { className: styles.header, children: [_jsx(Breadcrumbs, { items: [
|
|
14
|
-
{ label: "Home", href:
|
|
14
|
+
{ label: "Home", href: homeHref },
|
|
15
15
|
{ label: category.name },
|
|
16
16
|
] }), _jsx("h1", { className: styles.title, children: category.name }), category.description && (_jsx("div", { className: styles.description, dangerouslySetInnerHTML: { __html: category.description } })), countLabel && _jsx("p", { className: styles.count, children: countLabel })] }), posts.length === 0 ? (_jsx("p", { className: styles.empty, children: emptyLabel })) : (_jsxs("section", { "aria-label": t("home.title"), className: styles.gridSection, children: [_jsx("div", { className: styles.grid, children: posts.map((post) => (_jsx(PostCard, { post: post, categorySlug: category.slug, locale: locale, dateLocale: dateLocale }, post.id))) }), _jsx(Paginator, { currentPage: 1, totalPages: totalPages, baseUrl: paginatorBase, locale: locale })] }))] }));
|
|
17
17
|
}
|
|
@@ -14,5 +14,5 @@ export function CategoryPaginationView({ category, posts, currentPage, totalPage
|
|
|
14
14
|
{ label: "Home", href: paginatorBase || "/" },
|
|
15
15
|
{ label: category.name },
|
|
16
16
|
{ label: pageLabel },
|
|
17
|
-
] }), _jsx("h1", { className: styles.title, children: category.name }),
|
|
17
|
+
] }), _jsx("h1", { className: styles.title, children: category.name }), _jsx("p", { className: styles.pageLabel, children: pageLabel })] }), posts.length === 0 ? (_jsx("p", { className: styles.empty, children: emptyLabel })) : (_jsxs("section", { "aria-label": t("category.pageLabel", { page: currentPage }), className: styles.gridSection, children: [_jsx("div", { className: styles.grid, children: posts.map((post) => (_jsx(PostCard, { post: post, categorySlug: category.slug, locale: locale, dateLocale: dateLocale }, post.id))) }), _jsx(Paginator, { currentPage: currentPage, totalPages: totalPages, baseUrl: paginatorBase, locale: locale })] }))] }));
|
|
18
18
|
}
|
|
@@ -5,6 +5,10 @@ import Paginator from "../../components/Paginator";
|
|
|
5
5
|
import PostCard from "../../components/PostCard";
|
|
6
6
|
import styles from "./index.module.css";
|
|
7
7
|
import { buildFeaturedViewModel, getHomeCopy } from "./index.utils";
|
|
8
|
+
function truncateLabel(label, max = 20) {
|
|
9
|
+
const trimmed = label.trim();
|
|
10
|
+
return trimmed.length > max ? `${trimmed.slice(0, max)}...` : trimmed;
|
|
11
|
+
}
|
|
8
12
|
export function HomeView({ featuredPost, regularPosts, error, totalPages, baseUrl = "", locale, dateLocale = "en-US", }) {
|
|
9
13
|
const copy = getHomeCopy(locale);
|
|
10
14
|
const featuredModel = featuredPost
|
|
@@ -13,7 +17,7 @@ export function HomeView({ featuredPost, regularPosts, error, totalPages, baseUr
|
|
|
13
17
|
return (_jsx("div", { className: `container ${styles.container}`, children: error ? (_jsxs("div", { className: styles.errorBox, children: [_jsxs("p", { children: [copy.errorTitle, ": ", error] }), _jsx("p", { className: styles.errorHint, children: copy.errorHint })] })) : !featuredModel && regularPosts.length === 0 ? (_jsx("p", { className: styles.empty, children: copy.empty })) : (_jsxs(_Fragment, { children: [featuredModel && (_jsxs("article", { className: `card ${styles.featured} ${featuredModel.image
|
|
14
18
|
? styles.featuredWithImage
|
|
15
19
|
: styles.featuredNoImage}`, children: [featuredModel.image && (_jsx(Link, { href: featuredModel.postUrl, className: styles.featuredImageLink, children: _jsx(Image, { src: featuredModel.image.src, alt: featuredModel.image.alt, fill: true, className: styles.featuredImage, priority: true, sizes: "(max-width: 768px) 100vw, 50vw" }) })), _jsxs("div", { className: styles.featuredBody, children: [featuredModel.badgeLabel &&
|
|
16
|
-
(featuredModel.badgeUrl ? (_jsx(Link, { href: featuredModel.badgeUrl, className: `${styles.featuredBadge} badge`, children: featuredModel.badgeLabel })) : (_jsx("span", { className: `${styles.featuredBadge} badge`, children: featuredModel.badgeLabel }))), _jsx(Link, { href: featuredModel.postUrl, children: _jsx("h2", { dangerouslySetInnerHTML: {
|
|
20
|
+
(featuredModel.badgeUrl ? (_jsx(Link, { href: featuredModel.badgeUrl, className: `${styles.featuredBadge} badge`, title: featuredModel.badgeLabel, children: truncateLabel(featuredModel.badgeLabel) })) : (_jsx("span", { className: `${styles.featuredBadge} badge`, title: featuredModel.badgeLabel, children: truncateLabel(featuredModel.badgeLabel) }))), _jsx(Link, { href: featuredModel.postUrl, children: _jsx("h2", { dangerouslySetInnerHTML: {
|
|
17
21
|
__html: featuredModel.titleHtml,
|
|
18
22
|
}, className: styles.featuredTitle }) }), _jsx("div", { dangerouslySetInnerHTML: {
|
|
19
23
|
__html: featuredModel.excerptHtml,
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
.featured {
|
|
25
25
|
margin-bottom: var(--spacing-lg);
|
|
26
26
|
display: grid;
|
|
27
|
-
gap: var(--spacing-lg);
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
.featuredWithImage {
|
|
@@ -60,6 +59,7 @@
|
|
|
60
59
|
.featuredTitle {
|
|
61
60
|
margin-bottom: var(--spacing-sm);
|
|
62
61
|
font-size: 2rem;
|
|
62
|
+
margin-top: 0;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
.featuredExcerpt {
|
|
@@ -5,6 +5,10 @@ import { getTranslator } from "../../utils";
|
|
|
5
5
|
import { Breadcrumbs } from "../../components";
|
|
6
6
|
import { buildCategoryUrl, formatPublishedDate, getAuthor, getFeaturedImage, getPrimaryCategory, } from "./index.utils";
|
|
7
7
|
import { stripTags } from "../../utils";
|
|
8
|
+
function truncateLabel(label, max = 20) {
|
|
9
|
+
const trimmed = label.trim();
|
|
10
|
+
return trimmed.length > max ? `${trimmed.slice(0, max)}...` : trimmed;
|
|
11
|
+
}
|
|
8
12
|
export function PostView({ post, dateLocale = "en-US", categoryBasePath = "/", locale, }) {
|
|
9
13
|
const t = getTranslator(locale);
|
|
10
14
|
const author = getAuthor(post);
|
|
@@ -22,5 +26,5 @@ export function PostView({ post, dateLocale = "en-US", categoryBasePath = "/", l
|
|
|
22
26
|
{ label: "Home", href: categoryBasePath },
|
|
23
27
|
{ label: stripTags(post.title.rendered) || post.title.rendered },
|
|
24
28
|
];
|
|
25
|
-
return (_jsx("div", { className: `container ${styles.container}`, children: _jsxs("article", { className: styles.article, children: [_jsx(Breadcrumbs, { items: breadcrumbs }),
|
|
29
|
+
return (_jsx("div", { className: `container ${styles.container}`, children: _jsxs("article", { className: styles.article, children: [_jsx(Breadcrumbs, { items: breadcrumbs }), _jsx("header", { className: styles.postHeader, children: _jsx("h1", { dangerouslySetInnerHTML: { __html: post.title.rendered }, className: styles.title }) }), featuredImage && (_jsxs("figure", { className: styles.figure, children: [primaryCategory && (_jsx("div", { className: styles.badgeOverlay, children: categoryUrl ? (_jsx("a", { href: categoryUrl, className: "badge", title: primaryCategory.name, children: truncateLabel(primaryCategory.name, 20) })) : (_jsx("span", { className: "badge", title: primaryCategory.name, children: truncateLabel(primaryCategory.name, 20) })) })), _jsx(Image, { src: featuredImage.src, alt: featuredImage.alt, width: featuredImage.width, height: featuredImage.height, className: styles.image, priority: true, sizes: "(max-width: 900px) 100vw, 900px" })] })), _jsxs("div", { className: styles.meta, children: [author && (_jsx("span", { className: styles.authorLabel, children: t("post.authorPrefix", { name: author.name }) })), _jsx("span", { children: "\u2022" }), _jsx("time", { dateTime: post.date, children: publishedDate })] }), _jsx("div", { dangerouslySetInnerHTML: { __html: post.content.rendered }, className: `post-content ${styles.content}` }), author && author.description && (_jsxs("aside", { className: `card ${styles.authorCard}`, children: [_jsx("h2", { className: styles.authorTitle, children: t("post.aboutAuthor") }), _jsxs("address", { className: styles.authorAddress, children: [_jsx("strong", { className: styles.authorName, children: author.name }), _jsx("p", { className: styles.authorBio, children: author.description })] })] }))] }) }));
|
|
26
30
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
.container {
|
|
2
|
-
padding-top: var(--spacing-
|
|
2
|
+
padding-top: var(--spacing-sm);
|
|
3
3
|
padding-bottom: var(--spacing-xl);
|
|
4
4
|
}
|
|
5
5
|
|
|
@@ -8,25 +8,36 @@
|
|
|
8
8
|
margin: 0 auto;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
.
|
|
12
|
-
|
|
11
|
+
.badgeOverlay {
|
|
12
|
+
position: absolute;
|
|
13
|
+
bottom: 25px;
|
|
14
|
+
left: 15px;
|
|
15
|
+
z-index: 2;
|
|
16
|
+
box-shadow: 0 6px 16px var(--shadow);
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
.title {
|
|
16
20
|
font-size: clamp(2rem, 5vw, 3rem);
|
|
17
21
|
font-weight: 800;
|
|
18
22
|
line-height: 1.2;
|
|
19
|
-
margin-bottom: var(--spacing-md);
|
|
20
23
|
color: var(--foreground);
|
|
24
|
+
margin-bottom: var(--spacing-sm);
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
.meta {
|
|
24
28
|
display: flex;
|
|
25
29
|
align-items: center;
|
|
26
30
|
gap: var(--spacing-sm);
|
|
27
|
-
margin
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
margin: 0 0 var(--spacing-sm);
|
|
32
|
+
padding: 0.7rem 0.9rem;
|
|
33
|
+
background: rgba(0, 0, 0, 0.06);
|
|
34
|
+
border: 1px solid var(--border);
|
|
35
|
+
border-radius: 10px;
|
|
36
|
+
color: var(--foreground);
|
|
37
|
+
font-size: 0.8rem;
|
|
38
|
+
width: fit-content;
|
|
39
|
+
max-width: 100%;
|
|
40
|
+
flex-wrap: wrap;
|
|
30
41
|
}
|
|
31
42
|
|
|
32
43
|
.authorLabel {
|
|
@@ -34,7 +45,8 @@
|
|
|
34
45
|
}
|
|
35
46
|
|
|
36
47
|
.figure {
|
|
37
|
-
margin-bottom: var(--spacing-
|
|
48
|
+
margin-bottom: var(--spacing-xs);
|
|
49
|
+
position: relative;
|
|
38
50
|
}
|
|
39
51
|
|
|
40
52
|
.image {
|
|
@@ -51,8 +63,20 @@
|
|
|
51
63
|
}
|
|
52
64
|
|
|
53
65
|
.authorCard {
|
|
54
|
-
margin-top: var(--spacing-
|
|
55
|
-
|
|
66
|
+
margin-top: var(--spacing-lg);
|
|
67
|
+
margin-left: auto;
|
|
68
|
+
margin-right: auto;
|
|
69
|
+
padding: var(--spacing-md) var(--spacing-lg);
|
|
70
|
+
max-width: 720px;
|
|
71
|
+
background: rgba(255, 255, 255, 0.03);
|
|
72
|
+
border: 1px solid var(--border);
|
|
73
|
+
box-shadow: 0 6px 18px var(--shadow);
|
|
74
|
+
transition: none;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.authorCard:hover {
|
|
78
|
+
box-shadow: 0 6px 18px var(--shadow);
|
|
79
|
+
transform: none;
|
|
56
80
|
}
|
|
57
81
|
|
|
58
82
|
.authorAddress {
|
|
@@ -60,7 +84,7 @@
|
|
|
60
84
|
}
|
|
61
85
|
|
|
62
86
|
.authorTitle {
|
|
63
|
-
font-size: 1.
|
|
87
|
+
font-size: 1.1rem;
|
|
64
88
|
font-weight: 700;
|
|
65
89
|
margin-top: 0;
|
|
66
90
|
margin-bottom: var(--spacing-md);
|
|
@@ -70,11 +94,12 @@
|
|
|
70
94
|
.authorName {
|
|
71
95
|
display: block;
|
|
72
96
|
margin-bottom: var(--spacing-xs);
|
|
73
|
-
font-size:
|
|
97
|
+
font-size: 1rem;
|
|
74
98
|
color: var(--foreground);
|
|
75
99
|
}
|
|
76
100
|
|
|
77
101
|
.authorBio {
|
|
78
102
|
color: var(--foreground-light);
|
|
79
103
|
line-height: 1.6;
|
|
104
|
+
font-size: 0.95rem;
|
|
80
105
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wpheadless-lib",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"wpjsapi-lib": "3.
|
|
28
|
+
"wpjsapi-lib": "3.1.1"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/node": "^20",
|