wpheadless-lib 1.1.2 → 1.1.3

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,5 +1,6 @@
1
1
  import type { ReactNode } from "react";
2
2
  import "../../app/globals.css";
3
+ import type { LogoProps } from "../../components/layout/types";
3
4
  export declare const fontClassName = "";
4
5
  export declare const viewport: {
5
6
  width: string;
@@ -17,6 +18,8 @@ type RootLayoutBaseProps = {
17
18
  wpAppPassword: string;
18
19
  homeHref?: string;
19
20
  locale?: string;
21
+ headerLogo?: LogoProps;
22
+ footerLogo?: LogoProps;
20
23
  };
21
- export declare function RootLayoutBase({ children, menuHeaderId, menuFooterId, siteName, wpApiUrl, wpUsername, wpAppPassword, homeHref, locale, }: RootLayoutBaseProps): import("react/jsx-runtime").JSX.Element;
24
+ export declare function RootLayoutBase({ children, menuHeaderId, menuFooterId, siteName, wpApiUrl, wpUsername, wpAppPassword, homeHref, locale, headerLogo, footerLogo, }: RootLayoutBaseProps): import("react/jsx-runtime").JSX.Element;
22
25
  export {};
@@ -10,6 +10,6 @@ export const viewport = {
10
10
  maximumScale: 5,
11
11
  themeColor: "#333333",
12
12
  };
13
- export function RootLayoutBase({ children, menuHeaderId, menuFooterId, siteName, wpApiUrl, wpUsername, wpAppPassword, homeHref, locale, }) {
14
- return (_jsxs(_Fragment, { children: [_jsx(Header, { menuId: menuHeaderId, wpApiUrl: wpApiUrl, wpUsername: wpUsername, wpAppPassword: wpAppPassword, siteName: siteName, homeHref: homeHref, locale: locale }), _jsx("main", { id: "main-content", style: { minHeight: "calc(100vh - 200px)" }, children: children }), _jsx(Footer, { menuId: menuFooterId, wpApiUrl: wpApiUrl, wpUsername: wpUsername, wpAppPassword: wpAppPassword, siteName: siteName, locale: locale })] }));
13
+ export function RootLayoutBase({ children, menuHeaderId, menuFooterId, siteName, wpApiUrl, wpUsername, wpAppPassword, homeHref, locale, headerLogo, footerLogo, }) {
14
+ return (_jsxs(_Fragment, { children: [_jsx(Header, { menuId: menuHeaderId, wpApiUrl: wpApiUrl, wpUsername: wpUsername, wpAppPassword: wpAppPassword, siteName: siteName, homeHref: homeHref, locale: locale, logo: headerLogo }), _jsx("main", { id: "main-content", style: { minHeight: "calc(100vh - 200px)" }, children: children }), _jsx(Footer, { menuId: menuFooterId, wpApiUrl: wpApiUrl, wpUsername: wpUsername, wpAppPassword: wpAppPassword, siteName: siteName, locale: locale, logo: footerLogo })] }));
15
15
  }
@@ -1,3 +1,4 @@
1
+ import type { LogoProps } from "../types";
1
2
  export declare const dynamic = "force-static";
2
3
  export declare const revalidate = 3600;
3
4
  type FooterProps = {
@@ -7,6 +8,7 @@ type FooterProps = {
7
8
  wpAppPassword: string;
8
9
  siteName: string;
9
10
  locale?: string;
11
+ logo?: LogoProps;
10
12
  };
11
- export default function Footer({ menuId, wpApiUrl, wpUsername, wpAppPassword, siteName, locale, }: FooterProps): Promise<import("react/jsx-runtime").JSX.Element>;
13
+ export default function Footer({ menuId, wpApiUrl, wpUsername, wpAppPassword, siteName, locale, logo, }: FooterProps): Promise<import("react/jsx-runtime").JSX.Element>;
12
14
  export {};
@@ -5,7 +5,7 @@ import { convertWpUrl, getTranslator } from "../../../utils";
5
5
  import styles from "./index.module.css";
6
6
  export const dynamic = "force-static";
7
7
  export const revalidate = 3600;
8
- export default async function Footer({ menuId, wpApiUrl, wpUsername, wpAppPassword, siteName, locale, }) {
8
+ export default async function Footer({ menuId, wpApiUrl, wpUsername, wpAppPassword, siteName, locale, logo, }) {
9
9
  const auth = createAuth({
10
10
  method: "basic",
11
11
  credentials: {
@@ -19,6 +19,8 @@ export default async function Footer({ menuId, wpApiUrl, wpUsername, wpAppPasswo
19
19
  });
20
20
  let menuItems = [];
21
21
  const t = getTranslator(locale);
22
+ const logoData = logo?.src ? logo : null;
23
+ const logoAlt = logoData?.alt || siteName;
22
24
  try {
23
25
  const parsedMenuId = parseInt(menuId);
24
26
  const itemsResponse = await menusApi.items.list({
@@ -32,5 +34,5 @@ export default async function Footer({ menuId, wpApiUrl, wpUsername, wpAppPasswo
32
34
  catch (e) {
33
35
  console.error("Error obteniendo menú footer:", e);
34
36
  }
35
- return (_jsx("footer", { className: styles.footer, children: _jsx("div", { className: "container", children: _jsxs("div", { className: styles.wrapper, children: [_jsxs("div", { className: styles.grid, children: [_jsxs("div", { children: [_jsx("h3", { className: styles.siteName, children: siteName }), _jsx("p", { className: `${styles.muted} text-muted`, children: t("footer.tagline") })] }), menuItems.length > 0 && (_jsxs("nav", { "aria-label": t("footer.navAria"), className: styles.nav, children: [_jsx("h4", { className: styles.navTitle, children: t("footer.navTitle") }), _jsx("ul", { className: styles.list, children: menuItems.map((item) => (_jsx("li", { children: _jsx(Link, { href: convertWpUrl(item.url, wpApiUrl), className: "footer-link", children: item.title.rendered }) }, item.id))) })] }))] }), _jsxs("div", { className: styles.bottomBar, children: [_jsxs("span", { children: ["\u00A9 ", new Date().getFullYear(), " ", siteName] }), _jsx("span", { children: t("footer.noCookies") })] })] }) }) }));
37
+ return (_jsx("footer", { className: styles.footer, children: _jsx("div", { className: "container", children: _jsxs("div", { className: styles.wrapper, children: [_jsxs("div", { className: styles.grid, children: [_jsxs("div", { children: [_jsx("h3", { className: styles.siteName, children: logoData ? (_jsx("img", { src: logoData.src, alt: logoAlt, className: styles.logoImage, width: logoData.width, height: logoData.height })) : (siteName) }), _jsx("p", { className: `${styles.muted} text-muted`, children: t("footer.tagline") })] }), menuItems.length > 0 && (_jsxs("nav", { "aria-label": t("footer.navAria"), className: styles.nav, children: [_jsx("h4", { className: styles.navTitle, children: t("footer.navTitle") }), _jsx("ul", { className: styles.list, children: menuItems.map((item) => (_jsx("li", { children: _jsx(Link, { href: convertWpUrl(item.url, wpApiUrl), className: "footer-link", children: item.title.rendered }) }, item.id))) })] }))] }), _jsxs("div", { className: styles.bottomBar, children: [_jsxs("span", { children: ["\u00A9 ", new Date().getFullYear(), " ", siteName] }), _jsx("span", { children: t("footer.noCookies") })] })] }) }) }));
36
38
  }
@@ -16,12 +16,21 @@
16
16
  }
17
17
 
18
18
  .siteName {
19
+ display: inline-flex;
20
+ align-items: center;
19
21
  font-size: 1.25rem;
20
22
  font-weight: bold;
21
23
  margin-bottom: 1rem;
22
24
  color: var(--foreground);
23
25
  }
24
26
 
27
+ .logoImage {
28
+ height: 44px;
29
+ width: auto;
30
+ display: block;
31
+ object-fit: contain;
32
+ }
33
+
25
34
  .muted {
26
35
  font-size: 0.875rem;
27
36
  }
@@ -1,3 +1,4 @@
1
+ import type { LogoProps } from "../types";
1
2
  type MenuLink = {
2
3
  id: number;
3
4
  href: string;
@@ -14,6 +15,7 @@ type HeaderClientProps = {
14
15
  siteName: string;
15
16
  homeHref: string;
16
17
  labels: HeaderLabels;
18
+ logo?: LogoProps;
17
19
  };
18
- export default function HeaderClient({ menuLinks, siteName, homeHref, labels, }: HeaderClientProps): import("react/jsx-runtime").JSX.Element;
20
+ export default function HeaderClient({ menuLinks, siteName, homeHref, labels, logo, }: HeaderClientProps): import("react/jsx-runtime").JSX.Element;
19
21
  export {};
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import Link from "next/link";
4
4
  import { useEffect, useState } from "react";
5
5
  import styles from "./index.module.css";
6
- export default function HeaderClient({ menuLinks, siteName, homeHref, labels, }) {
6
+ export default function HeaderClient({ menuLinks, siteName, homeHref, labels, logo, }) {
7
7
  const [isMenuOpen, setIsMenuOpen] = useState(false);
8
8
  const [isMobileView, setIsMobileView] = useState(false);
9
9
  useEffect(() => {
@@ -21,7 +21,9 @@ export default function HeaderClient({ menuLinks, siteName, homeHref, labels, })
21
21
  const toggleMenu = () => setIsMenuOpen((prev) => !prev);
22
22
  const handleLinkClick = () => setIsMenuOpen(false);
23
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"
24
+ const logoData = logo?.src ? logo : null;
25
+ const logoAlt = logoData?.alt || siteName;
26
+ return (_jsxs("div", { className: styles.inner, children: [_jsx(Link, { href: homeHref, className: styles.logo, children: logoData ? (_jsx("img", { src: logoData.src, alt: logoAlt, className: styles.logoImage, width: logoData.width, height: logoData.height })) : (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
27
  ? "noopener noreferrer"
26
28
  : undefined, children: item.label }) }, item.id))) }) })] }))] }));
27
29
  }
@@ -1,3 +1,4 @@
1
+ import type { LogoProps } from "../types";
1
2
  export declare const dynamic = "force-static";
2
3
  export declare const revalidate = 3600;
3
4
  type HeaderProps = {
@@ -8,6 +9,7 @@ type HeaderProps = {
8
9
  siteName: string;
9
10
  homeHref?: string;
10
11
  locale?: string;
12
+ logo?: LogoProps;
11
13
  };
12
- export default function Header({ menuId, wpApiUrl, wpUsername, wpAppPassword, siteName, homeHref, locale, }: HeaderProps): Promise<import("react/jsx-runtime").JSX.Element>;
14
+ export default function Header({ menuId, wpApiUrl, wpUsername, wpAppPassword, siteName, homeHref, locale, logo, }: HeaderProps): Promise<import("react/jsx-runtime").JSX.Element>;
13
15
  export {};
@@ -5,7 +5,7 @@ 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;
8
- export default async function Header({ menuId, wpApiUrl, wpUsername, wpAppPassword, siteName, homeHref = "/", locale, }) {
8
+ export default async function Header({ menuId, wpApiUrl, wpUsername, wpAppPassword, siteName, homeHref = "/", locale, logo, }) {
9
9
  const t = getTranslator(locale);
10
10
  const auth = createAuth({
11
11
  method: "basic",
@@ -43,5 +43,5 @@ export default async function Header({ menuId, wpApiUrl, wpUsername, wpAppPasswo
43
43
  openMenu: t("header.openMenu"),
44
44
  closeMenu: t("header.closeMenu"),
45
45
  };
46
- return (_jsx("header", { className: styles.header, children: _jsx("div", { className: "container", children: _jsx(HeaderClient, { menuLinks: menuLinks, siteName: siteName, homeHref: homeHref, labels: labels }) }) }));
46
+ return (_jsx("header", { className: styles.header, children: _jsx("div", { className: "container", children: _jsx(HeaderClient, { menuLinks: menuLinks, siteName: siteName, homeHref: homeHref, labels: labels, logo: logo }) }) }));
47
47
  }
@@ -20,6 +20,9 @@
20
20
  }
21
21
 
22
22
  .logo {
23
+ display: inline-flex;
24
+ align-items: center;
25
+ gap: 0.5rem;
23
26
  font-size: 1.75rem;
24
27
  font-weight: 700;
25
28
  color: var(--primary);
@@ -28,6 +31,13 @@
28
31
  text-decoration: none;
29
32
  }
30
33
 
34
+ .logoImage {
35
+ height: 40px;
36
+ width: auto;
37
+ display: block;
38
+ object-fit: contain;
39
+ }
40
+
31
41
  .nav {
32
42
  flex: 1;
33
43
  display: flex;
@@ -0,0 +1,6 @@
1
+ export type LogoProps = {
2
+ src: string;
3
+ alt?: string;
4
+ width?: number;
5
+ height?: number;
6
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -76,3 +76,21 @@
76
76
  gap: var(--spacing-md);
77
77
  margin-bottom: var(--spacing-lg);
78
78
  }
79
+
80
+ @media (max-width: 900px) {
81
+ .featuredWithImage {
82
+ grid-template-columns: 1fr;
83
+ }
84
+
85
+ .featuredImageLink {
86
+ min-height: 220px;
87
+ }
88
+
89
+ .featuredBody {
90
+ padding: var(--spacing-md);
91
+ }
92
+
93
+ .featuredTitle {
94
+ font-size: 1.5rem;
95
+ }
96
+ }
@@ -5,6 +5,7 @@ type PostViewProps = {
5
5
  dateLocale?: string;
6
6
  categoryBasePath?: string;
7
7
  locale?: Locale;
8
+ authorDescription?: string | null;
8
9
  };
9
- export declare function PostView({ post, dateLocale, categoryBasePath, locale, }: PostViewProps): import("react/jsx-runtime").JSX.Element;
10
+ export declare function PostView({ post, dateLocale, categoryBasePath, locale, authorDescription, }: PostViewProps): import("react/jsx-runtime").JSX.Element;
10
11
  export {};
@@ -9,9 +9,10 @@ function truncateLabel(label, max = 20) {
9
9
  const trimmed = label.trim();
10
10
  return trimmed.length > max ? `${trimmed.slice(0, max)}...` : trimmed;
11
11
  }
12
- export function PostView({ post, dateLocale = "en-US", categoryBasePath = "/", locale, }) {
12
+ export function PostView({ post, dateLocale = "en-US", categoryBasePath = "/", locale, authorDescription, }) {
13
13
  const t = getTranslator(locale);
14
14
  const author = getAuthor(post);
15
+ const authorBio = authorDescription ?? author?.description;
15
16
  const primaryCategory = getPrimaryCategory(post);
16
17
  const categoryUrl = buildCategoryUrl(categoryBasePath, primaryCategory?.slug);
17
18
  const featuredImage = getFeaturedImage(post, locale);
@@ -26,5 +27,5 @@ export function PostView({ post, dateLocale = "en-US", categoryBasePath = "/", l
26
27
  { label: "Home", href: categoryBasePath },
27
28
  { label: stripTags(post.title.rendered) || post.title.rendered },
28
29
  ];
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 })] })] }))] }) }));
30
+ 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 && (_jsx("aside", { className: `card ${styles.authorCard}`, children: _jsxs("address", { className: styles.authorAddress, children: [_jsx("strong", { className: styles.authorName, children: author.name }), authorBio && (_jsx("p", { className: styles.authorBio, children: authorBio }))] }) }))] }) }));
30
31
  }
@@ -1,8 +1,10 @@
1
- import { getFeaturedMedia, getTranslator, stripTags, } from "../../utils";
1
+ import { ensureTrailingSlash, getFeaturedMedia, getTranslator, stripTags, } from "../../utils";
2
2
  import { formatPostDate } from "../../components/PostCard/index.utils";
3
3
  export const getCategories = (post) => (post._embedded?.["wp:term"]?.[0] || []).filter(Boolean);
4
4
  export const getPrimaryCategory = (post) => getCategories(post)[0];
5
- export const buildCategoryUrl = (basePath, slug) => (slug ? `${basePath}${slug}`.replace(/\/+/g, "/") : null);
5
+ export const buildCategoryUrl = (basePath, slug) => slug
6
+ ? ensureTrailingSlash(`${basePath}${slug}`.replace(/\/+/g, "/"))
7
+ : null;
6
8
  export const getAuthor = (post) => post._embedded?.author?.[0];
7
9
  export const getFeaturedImage = (post, locale) => {
8
10
  const t = getTranslator(locale);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wpheadless-lib",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",