dev #16

Merged
RizqiSyahrendra merged 15 commits from dev into main 2025-03-12 09:09:23 +00:00
28 changed files with 1499 additions and 884 deletions

70
package-lock.json generated
View File

@ -18,10 +18,12 @@
"animejs": "^3.2.2", "animejs": "^3.2.2",
"bootstrap": "^5.1.3", "bootstrap": "^5.1.3",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"framer-motion": "^12.4.13",
"graphql": "^16.10.0", "graphql": "^16.10.0",
"imagesloaded": "^5.0.0", "imagesloaded": "^5.0.0",
"isotope-layout": "^3.0.6", "isotope-layout": "^3.0.6",
"jarallax": "^2.2.1", "jarallax": "^2.2.1",
"motion": "^12.4.13",
"next": "15.2.0-canary.30", "next": "15.2.0-canary.30",
"payload": "^3.20.0", "payload": "^3.20.0",
"photoswipe": "^5.4.4", "photoswipe": "^5.4.4",
@ -8092,6 +8094,33 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/framer-motion": {
"version": "12.4.13",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.4.13.tgz",
"integrity": "sha512-JHSXIdL7WOTCSEb2UUurHURV85pWTn6UIg+iWLBhH5SFndbjni8CEQcxwsBwOs3RHZ83TkE4xoxb9cHsFPY9yQ==",
"license": "MIT",
"dependencies": {
"motion-dom": "^12.4.11",
"motion-utils": "^12.4.10",
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/fsevents": { "node_modules/fsevents": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@ -10289,6 +10318,47 @@
"license": "MIT", "license": "MIT",
"peer": true "peer": true
}, },
"node_modules/motion": {
"version": "12.4.13",
"resolved": "https://registry.npmjs.org/motion/-/motion-12.4.13.tgz",
"integrity": "sha512-8ehpE6Sd8ack6jLLzweW6RwCBQoASf+yVu8aUPFNKHsJIVejJaBPGsMiswcpfzHeCusZ/ztNIKbgoEn7ruJaOw==",
"license": "MIT",
"dependencies": {
"framer-motion": "^12.4.13",
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/motion-dom": {
"version": "12.4.11",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.4.11.tgz",
"integrity": "sha512-wstlyV3pktgFjqsjbXMo1NX9hQD9XTVqxQNvfc+FREAgxr3GVzgWIEKvbyyNlki3J1jmmh+et9X3aCKeqFPcxA==",
"license": "MIT",
"dependencies": {
"motion-utils": "^12.4.10"
}
},
"node_modules/motion-utils": {
"version": "12.4.10",
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.4.10.tgz",
"integrity": "sha512-NPwZd94V013SwRf++jMrk2+HEBgPkeIE2RiOzhAuuQlqxMJPkKt/LXVh6Upl+iN8oarSGD2dlY5/bqgsYXDABA==",
"license": "MIT"
},
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",

View File

@ -14,6 +14,7 @@
"tsc": "tsc" "tsc": "tsc"
}, },
"dependencies": { "dependencies": {
"@next/third-parties": "^15.2.2",
"@payloadcms/db-postgres": "^3.20.0", "@payloadcms/db-postgres": "^3.20.0",
"@payloadcms/next": "^3.20.0", "@payloadcms/next": "^3.20.0",
"@payloadcms/payload-cloud": "^3.20.0", "@payloadcms/payload-cloud": "^3.20.0",
@ -24,10 +25,12 @@
"animejs": "^3.2.2", "animejs": "^3.2.2",
"bootstrap": "^5.1.3", "bootstrap": "^5.1.3",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"framer-motion": "^12.4.13",
"graphql": "^16.10.0", "graphql": "^16.10.0",
"imagesloaded": "^5.0.0", "imagesloaded": "^5.0.0",
"isotope-layout": "^3.0.6", "isotope-layout": "^3.0.6",
"jarallax": "^2.2.1", "jarallax": "^2.2.1",
"motion": "^12.4.13",
"next": "15.2.0-canary.30", "next": "15.2.0-canary.30",
"payload": "^3.20.0", "payload": "^3.20.0",
"photoswipe": "^5.4.4", "photoswipe": "^5.4.4",

View File

@ -47,8 +47,9 @@
--bs-black-rgb: 0, 0, 0; --bs-black-rgb: 0, 0, 0;
--bs-body-color-rgb: 33, 37, 41; --bs-body-color-rgb: 33, 37, 41;
--bs-body-bg-rgb: 255, 255, 255; --bs-body-bg-rgb: 255, 255, 255;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", --bs-font-sans-serif:
"Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif); --bs-body-font-family: var(--bs-font-sans-serif);
@ -70,7 +71,6 @@
} }
body { body {
margin: 0; margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size); font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight); font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height); line-height: var(--bs-body-line-height);
@ -172,10 +172,7 @@ address {
font-style: normal; font-style: normal;
line-height: inherit; line-height: inherit;
} }
ol,
ul {
padding-left: 2rem;
}
dl, dl,
ol, ol,
ul { ul {
@ -2535,7 +2532,8 @@ textarea.form-control.is-valid {
.was-validated .form-select:valid:not([multiple]):not([size]), .was-validated .form-select:valid:not([multiple]):not([size]),
.was-validated .form-select:valid:not([multiple])[size="1"] { .was-validated .form-select:valid:not([multiple])[size="1"] {
padding-right: 4.125rem; padding-right: 4.125rem;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"), background-image:
url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),
url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
background-position: background-position:
right 0.75rem center, right 0.75rem center,
@ -2634,7 +2632,8 @@ textarea.form-control.is-invalid {
.was-validated .form-select:invalid:not([multiple]):not([size]), .was-validated .form-select:invalid:not([multiple]):not([size]),
.was-validated .form-select:invalid:not([multiple])[size="1"] { .was-validated .form-select:invalid:not([multiple])[size="1"] {
padding-right: 4.125rem; padding-right: 4.125rem;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"), background-image:
url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),
url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e"); url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
background-position: background-position:
right 0.75rem center, right 0.75rem center,

View File

@ -20,13 +20,12 @@
.dark .light-mode-logo { .dark .light-mode-logo {
display: none; display: none;
} }
@media (min-width: 1025px) { /* @media (min-width: 1025px) {
.mn-has-sub:hover + *, .mn-has-sub:hover + *,
.mn-has-sub + *:hover { .mn-has-sub + *:hover {
display: block !important;
z-index: 1; z-index: 1;
} }
} } */
.fadeInText { .fadeInText {
animation: animationFadeText 0.5s linear 0s 1; animation: animationFadeText 0.5s linear 0s 1;
@ -87,7 +86,7 @@ a {
} }
.mn-sub { .mn-sub {
transition: max-height 0.3s ease-in-out; transition: max-height;
} }
.mn-sub.open { .mn-sub.open {

View File

@ -1,6 +1,4 @@
.theme-slick { .theme-slick {
--font-global: "Plus Jakarta Sans", sans-serif;
--font-alt: "Plus Jakarta Sans", sans-serif;
--section-padding-y: 50px; --section-padding-y: 50px;
--color-teal-1: #64b3b4; --color-teal-1: #64b3b4;
--color-dark-1: #1e2432; --color-dark-1: #1e2432;
@ -66,14 +64,15 @@
--gradient-gray-light-1: linear-gradient(0deg, #f7f9fc 0%, #fff 100%); --gradient-gray-light-1: linear-gradient(0deg, #f7f9fc 0%, #fff 100%);
--gradient-gray-light-2: linear-gradient(0deg, #fff 0%, #f7f9fc 100%); --gradient-gray-light-2: linear-gradient(0deg, #fff 0%, #f7f9fc 100%);
--border-radius-default: 10px; --border-radius-default: 10px;
--box-shadow: 0px 5px 10px 0px rgba(30, 36, 50, 0.05), 0px 1px 1px 0px rgba(30, 36, 50, 0.03), --box-shadow:
0px 5px 10px 0px rgba(30, 36, 50, 0.05), 0px 1px 1px 0px rgba(30, 36, 50, 0.03),
0px 3px 5px 0px rgba(30, 36, 50, 0.03); 0px 3px 5px 0px rgba(30, 36, 50, 0.03);
--box-shadow-strong: 0px 5px 10px 0px rgba(30, 36, 50, 0.08), 0px 1px 1px 0px rgba(30, 36, 50, 0.06), --box-shadow-strong:
0px 5px 10px 0px rgba(30, 36, 50, 0.08), 0px 1px 1px 0px rgba(30, 36, 50, 0.06),
0px 3px 5px 0px rgba(30, 36, 50, 0.06); 0px 3px 5px 0px rgba(30, 36, 50, 0.06);
--box-shadow-block: 0px 10px 30px 0px rgba(30, 36, 50, 0.07), 0px 0px 1px 0px rgba(30, 36, 50, 0.1); --box-shadow-block: 0px 10px 30px 0px rgba(30, 36, 50, 0.07), 0px 0px 1px 0px rgba(30, 36, 50, 0.1);
--box-shadow-block-strong: 0px 15px 50px 0px rgba(30, 36, 50, 0.14), 0px 0px 1px 0px rgba(30, 36, 50, 0.15); --box-shadow-block-strong: 0px 15px 50px 0px rgba(30, 36, 50, 0.14), 0px 0px 1px 0px rgba(30, 36, 50, 0.15);
color: var(--color-dark-1); color: var(--color-dark-1);
font-family: var(--font-global);
font-size: 17px; font-size: 17px;
font-weight: 400; font-weight: 400;
line-height: 1.725; line-height: 1.725;
@ -201,9 +200,6 @@
.theme-slick .inner-nav ul li { .theme-slick .inner-nav ul li {
margin: 0 18px; margin: 0 18px;
} }
.theme-slick .inner-nav > ul > li > a {
opacity: 0.7;
}
.theme-slick .inner-nav ul li a { .theme-slick .inner-nav ul li a {
position: relative; position: relative;
} }
@ -233,11 +229,7 @@
.theme-slick .mobile-on .desktop-nav ul { .theme-slick .mobile-on .desktop-nav ul {
background: rgba(30, 36, 50, 0.99); background: rgba(30, 36, 50, 0.99);
} }
.theme-slick .mobile-on .desktop-nav ul li a,
.theme-slick .inner-nav ul li .mn-sub li a,
.theme-slick .mn-group-title {
color: rgba(255, 255, 255, 0.9) !important;
}
.theme-slick .form label { .theme-slick .form label {
margin-bottom: 15px; margin-bottom: 15px;
font-size: 18px; font-size: 18px;

View File

@ -238,10 +238,10 @@ Primary use: Multipurpose Template
--gradient-primary-alpha-2: linear-gradient(90deg, transparent 13%, var(--color-primary-1) 60%); --gradient-primary-alpha-2: linear-gradient(90deg, transparent 13%, var(--color-primary-1) 60%);
--border-radius-default: 4px; --border-radius-default: 4px;
--border-radius-large: 30px; --border-radius-large: 30px;
--box-shadow: 0px 5px 10px 0px rgba(0, 0, 0, 0.05), 0px 1px 1px 0px rgba(0, 0, 0, 0.03), --box-shadow:
0px 3px 5px 0px rgba(0, 0, 0, 0.03); 0px 5px 10px 0px rgba(0, 0, 0, 0.05), 0px 1px 1px 0px rgba(0, 0, 0, 0.03), 0px 3px 5px 0px rgba(0, 0, 0, 0.03);
--box-shadow-strong: 0px 5px 10px 0px rgba(0, 0, 0, 0.08), 0px 1px 1px 0px rgba(0, 0, 0, 0.06), --box-shadow-strong:
0px 3px 5px 0px rgba(0, 0, 0, 0.06); 0px 5px 10px 0px rgba(0, 0, 0, 0.08), 0px 1px 1px 0px rgba(0, 0, 0, 0.06), 0px 3px 5px 0px rgba(0, 0, 0, 0.06);
--box-shadow-block: 0px 3px 50px 0px rgba(0, 0, 0, 0.05); --box-shadow-block: 0px 3px 50px 0px rgba(0, 0, 0, 0.05);
--box-shadow-block-strong: 0px 3px 50px 0px rgba(0, 0, 0, 0.15); --box-shadow-block-strong: 0px 3px 50px 0px rgba(0, 0, 0, 0.15);
--transition-default: all 0.27s cubic-bezier(0, 0, 0.58, 1); --transition-default: all 0.27s cubic-bezier(0, 0, 0.58, 1);
@ -746,7 +746,6 @@ video {
body { body {
color: var(--color-dark-1); color: var(--color-dark-1);
font-family: var(--font-global);
font-size: 18px; font-size: 18px;
font-weight: 400; font-weight: 400;
letter-spacing: normal; letter-spacing: normal;
@ -3835,7 +3834,6 @@ a.logo:hover {
.inner-nav ul { .inner-nav ul {
margin: auto; margin: auto;
font-size: 17px; font-size: 17px;
font-weight: 500;
text-align: center; text-align: center;
letter-spacing: 0; letter-spacing: 0;
line-height: 1.3; line-height: 1.3;
@ -3880,7 +3878,6 @@ a.logo:hover {
display: table-cell; display: table-cell;
vertical-align: middle; vertical-align: middle;
height: var(--menu-bar-height); height: var(--menu-bar-height);
opacity: 0.65;
} }
.main-nav:not(.mobile-on).small-height .inner-nav > ul > li > a { .main-nav:not(.mobile-on).small-height .inner-nav > ul > li > a {
height: var(--menu-bar-height-scrolled) !important; height: var(--menu-bar-height-scrolled) !important;
@ -3925,7 +3922,7 @@ a.logo:hover {
transition: var(--transition-default); transition: var(--transition-default);
} }
.mn-sub { .mn-sub {
display: none; /* opacity: 0; */
width: 220px; width: 220px;
position: absolute; position: absolute;
top: 100%; top: 100%;
@ -3979,7 +3976,6 @@ a.logo:hover {
border-left: none; border-left: none;
border-right: none; border-right: none;
letter-spacing: 0; letter-spacing: 0;
color: var(--color-gray-light-5) !important;
outline-offset: -2px !important; outline-offset: -2px !important;
transition: var(--transition-default); transition: var(--transition-default);
} }
@ -3990,7 +3986,6 @@ a.logo:hover {
.inner-nav ul li .mn-sub li a:hover, .inner-nav ul li .mn-sub li a:hover,
.mn-sub li a.active { .mn-sub li a.active {
background: rgba(255, 255, 255, 0.09); background: rgba(255, 255, 255, 0.09);
color: var(--color-gray-light-1) !important;
} }
.mn-sub:not(.mn-has-multi) li ul { .mn-sub:not(.mn-has-multi) li ul {
left: 100%; left: 100%;
@ -4324,20 +4319,11 @@ a.logo:hover {
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
} }
.main-nav.dark .inner-nav ul > li > a { .main-nav.dark .inner-nav ul > li > a {
font-size: 18px; font-weight: 500;
color: #fff; line-height: 1.2em;
opacity: 0.78;
padding: 10px; padding: 10px;
} }
.main-nav.dark .inner-nav ul > li > a:hover,
.main-nav.dark .inner-nav ul > li > a.active {
color: #fff;
opacity: 1 !important;
}
.main-nav.dark .inner-nav ul li .mn-sub li a {
opacity: 1;
}
.main-nav.dark .main-nav-icon-cart { .main-nav.dark .main-nav-icon-cart {
opacity: 1; opacity: 1;
} }
@ -4361,13 +4347,13 @@ a.logo:hover {
font-size: 18px; font-size: 18px;
font-weight: 700; font-weight: 700;
text-decoration: none; text-decoration: none;
color: rgba(255, 255, 255, 0.9); /* color: rgba(255, 255, 255, 0.9); */
} }
.main-nav.dark .mn-sub { /* .main-nav.dark .mn-sub {
-webkit-box-shadow: none; -webkit-box-shadow: none;
-moz-box-shadow: none; -moz-box-shadow: none;
box-shadow: none; box-shadow: none;
} } */
.main-nav.dark .mi-chevron-down, .main-nav.dark .mi-chevron-down,
.main-nav.dark.body-scrolled .inner-nav ul > li > a:hover .mi-chevron-down, .main-nav.dark.body-scrolled .inner-nav ul > li > a:hover .mi-chevron-down,
.main-nav.dark.body-scrolled .inner-nav ul > li > a.active .mi-chevron-down { .main-nav.dark.body-scrolled .inner-nav ul > li > a.active .mi-chevron-down {

View File

@ -2,22 +2,106 @@ import { BeforeFooterBlock } from "@/components/Blocks/BeforeFooter";
import { BlogCardItemSkeleton } from "@/components/Blogs/BlogCardItem"; import { BlogCardItemSkeleton } from "@/components/Blogs/BlogCardItem";
import Blogs from "@/components/Blogs/Blogs"; import Blogs from "@/components/Blogs/Blogs";
import HeroOther from "@/components/HeroOther"; import HeroOther from "@/components/HeroOther";
import { getDefaultMetadata } from "@/utils/metadata";
import { sanitizePageNumber } from "@/utils/sanitize"; import { sanitizePageNumber } from "@/utils/sanitize";
import { Metadata } from "next";
import { headers } from "next/headers";
import { Suspense } from "react"; import { Suspense } from "react";
export const metadata = { const metaDesc =
title: "Blog - Cochise Oncology", "Explore the latest insights, news, and patient resources on the Cochise Oncology blog. Stay informed about cancer treatments, patient support services, and wellness tips. Read our expert articles today.";
description: "Blog - Cochise Oncology",
}; export async function generateMetadata(): Promise<Metadata> {
const metadata = await getDefaultMetadata();
metadata.title = `Blog - ${metadata.openGraph?.siteName}`;
metadata.description = metaDesc;
return metadata;
}
export default async function BlogPage({ searchParams }: { searchParams?: Promise<{ page?: string; s?: string }> }) { export default async function BlogPage({ searchParams }: { searchParams?: Promise<{ page?: string; s?: string }> }) {
const params = await searchParams; const params = await searchParams;
const paramsPage = params?.page; const paramsPage = params?.page;
const paramsSearch = params?.s; const paramsSearch = params?.s;
const page = sanitizePageNumber(paramsPage); const page = sanitizePageNumber(paramsPage);
const headersList = await headers();
const mainUrl = headersList.get("x-main-url");
const fullUrl = headersList.get("x-full-url");
const siteName = headersList.get("x-site-name");
const jsonLd = {
"@context": "https://schema.org",
"@graph": [
{
"@type": "WebPage",
"@id": fullUrl,
url: fullUrl,
name: `Blog - ${siteName}`,
isPartOf: {
"@id": `${mainUrl}/#website`,
},
datePublished: "2024-07-18T16:42:14+00:00",
dateModified: "2025-02-27T01:20:38+00:00",
description: metaDesc,
breadcrumb: {
"@id": `${fullUrl}#breadcrumb`,
},
inLanguage: "en-US",
potentialAction: [
{
"@type": "ReadAction",
target: [fullUrl],
},
],
},
{
"@type": "WebSite",
"@id": `${mainUrl}/#website`,
url: `${mainUrl}/`,
name: siteName,
description: "",
publisher: {
"@id": `${mainUrl}/#organization`,
},
potentialAction: [
{
"@type": "SearchAction",
target: {
"@type": "EntryPoint",
urlTemplate: `${mainUrl}/?s={search_term_string}`,
},
"query-input": {
"@type": "PropertyValueSpecification",
valueRequired: true,
valueName: "search_term_string",
},
},
],
inLanguage: "en-US",
},
{
"@type": "Organization",
"@id": `${mainUrl}/#organization`,
name: siteName,
url: `${mainUrl}/`,
logo: {
"@type": "ImageObject",
inLanguage: "en-US",
"@id": `${mainUrl}/#/schema/logo/image/`,
url: `${mainUrl}/assets/images/logo-dark.webp`,
contentUrl: `${mainUrl}/assets/images/logo-dark.webp`,
caption: siteName,
},
image: {
"@id": `${mainUrl}/#/schema/logo/image/`,
},
},
],
};
return ( return (
<> <>
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />
<HeroOther title="Blog" /> <HeroOther title="Blog" />
<section className="page-section" id="blog"> <section className="page-section" id="blog">

View File

@ -2,14 +2,24 @@ import { BeforeFooterBlock } from "@/components/Blocks/BeforeFooter";
import { BlogCardItemSkeleton } from "@/components/Blogs/BlogCardItem"; import { BlogCardItemSkeleton } from "@/components/Blogs/BlogCardItem";
import Blogs from "@/components/Blogs/Blogs"; import Blogs from "@/components/Blogs/Blogs";
import HeroOther from "@/components/HeroOther"; import HeroOther from "@/components/HeroOther";
import { fetchBlogCategoryBySlug } from "@/services/payload/blog";
import { getDefaultMetadata } from "@/utils/metadata"; import { getDefaultMetadata } from "@/utils/metadata";
import { sanitizePageNumber } from "@/utils/sanitize"; import { sanitizePageNumber } from "@/utils/sanitize";
import { Metadata } from "next"; import { Metadata } from "next";
// import { headers } from "next/headers"; import { headers } from "next/headers";
import { notFound } from "next/navigation";
import { Suspense } from "react"; import { Suspense } from "react";
export async function generateMetadata(): Promise<Metadata> { export async function generateMetadata({ params }: { params: Promise<{ path: string[0] }> }): Promise<Metadata> {
const path = (await params)?.path;
const paramsCategory = path?.[0] ?? "";
const metadata = await getDefaultMetadata(); const metadata = await getDefaultMetadata();
const category = await fetchBlogCategoryBySlug(paramsCategory);
if (!!category?.data) {
metadata.title = `${category.data.name} Archives - ${metadata.openGraph?.siteName}`;
}
return metadata; return metadata;
} }
@ -21,19 +31,92 @@ export default async function CategoryPage({
searchParams?: Promise<{ page?: string; s?: string }>; searchParams?: Promise<{ page?: string; s?: string }>;
}) { }) {
const path = (await params)?.path; const path = (await params)?.path;
// const headersList = await headers(); const paramsCategory = path?.[0] ?? "";
// const paramsCategory = path?.[0] ?? "";
const paramsPage = path?.[2] ?? ""; const paramsPage = path?.[2] ?? "";
const paramsSearch = (await searchParams)?.s; const paramsSearch = (await searchParams)?.s;
const page = sanitizePageNumber(paramsPage); const page = sanitizePageNumber(paramsPage);
const headersList = await headers();
const mainUrl = headersList.get("x-main-url");
const fullUrl = headersList.get("x-full-url");
const siteName = headersList.get("x-site-name");
const category = await fetchBlogCategoryBySlug(paramsCategory);
if (!category) {
notFound();
}
const jsonLd = {
"@context": "https://schema.org",
"@graph": [
{
"@type": "CollectionPage",
"@id": fullUrl,
url: fullUrl,
name: `${category.data.name} - ${siteName}`,
isPartOf: {
"@id": `${mainUrl}/#website`,
},
primaryImageOfPage: {
"@id": `${fullUrl}#primaryimage`,
},
image: {
"@id": `${fullUrl}#primaryimage`,
},
inLanguage: "en-US",
},
{
"@type": "WebSite",
"@id": `${mainUrl}/#website`,
url: `${mainUrl}/`,
name: siteName,
description: "",
publisher: {
"@id": `${mainUrl}/#organization`,
},
potentialAction: [
{
"@type": "SearchAction",
target: {
"@type": "EntryPoint",
urlTemplate: `${mainUrl}/?s={search_term_string}`,
},
"query-input": {
"@type": "PropertyValueSpecification",
valueRequired: true,
valueName: "search_term_string",
},
},
],
inLanguage: "en-US",
},
{
"@type": "Organization",
"@id": `${mainUrl}/#organization`,
name: siteName,
url: `${mainUrl}/`,
logo: {
"@type": "ImageObject",
inLanguage: "en-US",
"@id": `${mainUrl}/#/schema/logo/image/`,
url: `${mainUrl}/assets/images/logo-dark.webp`,
contentUrl: `${mainUrl}/assets/images/logo-dark.webp`,
caption: siteName,
},
image: {
"@id": `${mainUrl}/#/schema/logo/image/`,
},
},
],
};
return ( return (
<> <>
<HeroOther title="Blog" /> <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />
<HeroOther title={`Category: ${category.data.name}`} />
<section className="page-section" id="blog"> <section className="page-section" id="blog">
<div className="w-full max-w-7xl mx-auto px-4 md:px-8"> <div className="w-full max-w-7xl mx-auto px-4 md:px-8">
<form action={`category/chemotherapy/page/1`} method="GET"> <form action={`/category/${paramsCategory}`} method="GET">
<div className="input-group"> <div className="input-group">
<input <input
type="text" type="text"
@ -52,7 +135,7 @@ export default async function CategoryPage({
</div> </div>
<Suspense fallback={<Loading />}> <Suspense fallback={<Loading />}>
<Blogs preset="categories" page={page} search={paramsSearch} /> <Blogs preset="categories" categoryId={category.data.id} page={page} search={paramsSearch} />
</Suspense> </Suspense>
</section> </section>

View File

@ -8,14 +8,27 @@ import { getDefaultMetadata } from "@/utils/metadata";
import "@public/assets/css/styles.css"; import "@public/assets/css/styles.css";
import "jarallax/dist/jarallax.min.css"; import "jarallax/dist/jarallax.min.css";
import { Metadata } from "next"; import { Metadata } from "next";
import { Roboto } from "next/font/google"; import { Roboto, Noto_Sans } from "next/font/google";
import "photoswipe/dist/photoswipe.css"; import "photoswipe/dist/photoswipe.css";
import "react-modal-video/css/modal-video.css"; import "react-modal-video/css/modal-video.css";
import "swiper/css"; import "swiper/css";
import "swiper/css/effect-fade"; import "swiper/css/effect-fade";
import "tippy.js/dist/tippy.css"; import "tippy.js/dist/tippy.css";
const roboto = Roboto({ subsets: ["latin"] }); const roboto = Roboto({
weight: ["400", "500", "600", "700", "800"],
style: ["normal", "italic"],
subsets: ["latin"],
display: "swap",
variable: "--font-roboto",
});
const notoSans = Noto_Sans({
weight: ["400", "500", "600"],
style: ["normal", "italic"],
subsets: ["latin"],
display: "swap",
variable: "--font-noto-sans",
});
export async function generateMetadata(): Promise<Metadata> { export async function generateMetadata(): Promise<Metadata> {
const metadata = await getDefaultMetadata(); const metadata = await getDefaultMetadata();
@ -28,9 +41,9 @@ export default function MainLayout({
children: React.ReactNode; children: React.ReactNode;
}>) { }>) {
return ( return (
<html lang="en" className={`no-mobile no-touch ${roboto.className}`}> <html lang="en" className={`no-mobile no-touch ${roboto.variable} ${notoSans.variable}`}>
<InitialScript /> <InitialScript />
<body className="appear-animate body"> <body className="appear-animate body font-fontMain">
<div className="theme-slick"> <div className="theme-slick">
<div className="page" id="top"> <div className="page" id="top">
<Header links={navMenuData} /> <Header links={navMenuData} />

View File

@ -111,7 +111,7 @@ export default async function Home() {
{ {
"@type": "Organization", "@type": "Organization",
"@id": `${fullUrl}#organization`, "@id": `${fullUrl}#organization`,
name: "Cochise Oncology", name: siteName,
url: fullUrl, url: fullUrl,
logo: { logo: {
"@type": "ImageObject", "@type": "ImageObject",

View File

@ -0,0 +1,157 @@
import { BeforeFooterBlock } from "@/components/Blocks/BeforeFooter";
import { BlogCardItemSkeleton } from "@/components/Blogs/BlogCardItem";
import Blogs from "@/components/Blogs/Blogs";
import HeroOther from "@/components/HeroOther";
import { fetchBlogTagBySlug } from "@/services/payload/blog";
import { getDefaultMetadata } from "@/utils/metadata";
import { sanitizePageNumber } from "@/utils/sanitize";
import { Metadata } from "next";
import { headers } from "next/headers";
import { notFound } from "next/navigation";
import { Suspense } from "react";
export async function generateMetadata({ params }: { params: Promise<{ path: string[0] }> }): Promise<Metadata> {
const path = (await params)?.path;
const paramsTag = path?.[0] ?? "";
const metadata = await getDefaultMetadata();
const tag = await fetchBlogTagBySlug(paramsTag);
if (!!tag?.data) {
metadata.title = `${tag.data.name} Archives - ${metadata.openGraph?.siteName}`;
}
return metadata;
}
export default async function TagPage({
params,
searchParams,
}: {
params?: Promise<{ path: string[] }>;
searchParams?: Promise<{ page?: string; s?: string }>;
}) {
const path = (await params)?.path;
const paramsTag = path?.[0] ?? "";
const paramsPage = path?.[2] ?? "";
const paramsSearch = (await searchParams)?.s;
const page = sanitizePageNumber(paramsPage);
const headersList = await headers();
const mainUrl = headersList.get("x-main-url");
const fullUrl = headersList.get("x-full-url");
const siteName = headersList.get("x-site-name");
const tag = await fetchBlogTagBySlug(paramsTag);
if (!tag) {
notFound();
}
const jsonLd = {
"@context": "https://schema.org",
"@graph": [
{
"@type": "CollectionPage",
"@id": fullUrl,
url: fullUrl,
name: `${tag.data.name} - ${siteName}`,
isPartOf: {
"@id": `${mainUrl}/#website`,
},
primaryImageOfPage: {
"@id": `${fullUrl}#primaryimage`,
},
image: {
"@id": `${fullUrl}#primaryimage`,
},
inLanguage: "en-US",
},
{
"@type": "WebSite",
"@id": `${mainUrl}/#website`,
url: `${mainUrl}/`,
name: siteName,
description: "",
publisher: {
"@id": `${mainUrl}/#organization`,
},
potentialAction: [
{
"@type": "SearchAction",
target: {
"@type": "EntryPoint",
urlTemplate: `${mainUrl}/?s={search_term_string}`,
},
"query-input": {
"@type": "PropertyValueSpecification",
valueRequired: true,
valueName: "search_term_string",
},
},
],
inLanguage: "en-US",
},
{
"@type": "Organization",
"@id": `${mainUrl}/#organization`,
name: siteName,
url: `${mainUrl}/`,
logo: {
"@type": "ImageObject",
inLanguage: "en-US",
"@id": `${mainUrl}/#/schema/logo/image/`,
url: `${mainUrl}/assets/images/logo-dark.webp`,
contentUrl: `${mainUrl}/assets/images/logo-dark.webp`,
caption: siteName,
},
image: {
"@id": `${mainUrl}/#/schema/logo/image/`,
},
},
],
};
return (
<>
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />
<HeroOther title={`Tag: ${tag.data.name}`} />
<section className="page-section" id="blog">
<div className="w-full max-w-7xl mx-auto px-4 md:px-8">
<form action={`/tag/${paramsTag}`} method="GET">
<div className="input-group">
<input
type="text"
name="s"
defaultValue={paramsSearch ?? ""}
placeholder="Search blog..."
className="input-lg input-circle form-control h-12"
/>
<div className="input-group-append px-2">
<button className="btn btn-info text-white h-12 px-5" type="submit">
Search
</button>
</div>
</div>
</form>
</div>
<Suspense fallback={<Loading />}>
<Blogs preset="tags" tagId={tag.data.id} page={page} search={paramsSearch} />
</Suspense>
</section>
<BeforeFooterBlock />
</>
);
}
function Loading() {
return (
<div className="container position-relative">
<div className="row">
<BlogCardItemSkeleton />
<BlogCardItemSkeleton />
<BlogCardItemSkeleton />
</div>
</div>
);
}

View File

@ -33,7 +33,6 @@
body { body {
color: var(--foreground); color: var(--foreground);
background: var(--background); background: var(--background);
font-family: Arial, Helvetica, sans-serif;
} }
@layer components { @layer components {
@ -63,6 +62,10 @@ body {
.ext-btn-shadow-sm-primary8 { .ext-btn-shadow-sm-primary8 {
@apply bg-extColorPrimary8 text-white hover:text-white hover:bg-extColorPrimary6 transition-colors; @apply bg-extColorPrimary8 text-white hover:text-white hover:bg-extColorPrimary6 transition-colors;
} }
.shadow-nav {
@apply !shadow-[0px_0px_10px_0px_rgba(0,0,0,0.24)];
}
} }
.bg-gradient { .bg-gradient {

View File

@ -47,8 +47,8 @@ export function BeforeFooterBlock({ title, description, buttonText, showLinier =
)} )}
<div className="max-w-4xl mx-auto mt-12"> <div className="max-w-4xl mx-auto mt-12">
<h2 className="text-4xl font-semibold mb-4">{title ?? placeholderTitle}</h2> <h4 className="text-4xl font-medium mb-3">{title ?? placeholderTitle}</h4>
<p className="text-lg leading-relaxed mb-6">{description ?? placeholderDescription}</p> <span className="text-lg leading-relaxed mb-6">{description ?? placeholderDescription}</span>
<div className="pt-5"> <div className="pt-5">
<Link <Link
href="/contact" href="/contact"

View File

@ -7,7 +7,7 @@ export function ContentBlock(props: any) {
<div className="container relative"> <div className="container relative">
<div className="row"> <div className="row">
{/* Content */} {/* Content */}
<div className="col-md-10 offset-md-1 col-lg-8 offset-lg-2"> <div className="col-md-10 offset-md-1 col-lg-10 offset-lg-1">
{/* Post */} {/* Post */}
<div className="blog-item mb-10"> <div className="blog-item mb-10">
<div className="blog-item-body"> <div className="blog-item-body">

View File

@ -100,7 +100,7 @@ export default async function BlogDetail({ slug }: BlogDetailProps) {
<div className="container relative"> <div className="container relative">
<div className="row"> <div className="row">
{/* Content */} {/* Content */}
<div className="col-md-10 offset-md-1 col-lg-8 offset-lg-2"> <div className="col-md-10 offset-md-1 col-lg-10 offset-lg-1">
{/* Post */} {/* Post */}
<div className="blog-item mb-80 mb-xs-40"> <div className="blog-item mb-80 mb-xs-40">
<div className="blog-item-body"> <div className="blog-item-body">
@ -133,7 +133,7 @@ export function BlogDetailContentSkeleton() {
<div className="container relative"> <div className="container relative">
<div className="row"> <div className="row">
{/* Content */} {/* Content */}
<div className="col-md-10 offset-md-1 col-lg-8 offset-lg-2"> <div className="col-md-10 offset-md-1 col-lg-10 offset-lg-1">
{/* Post */} {/* Post */}
<div className="blog-item mb-80 mb-xs-40"> <div className="blog-item mb-80 mb-xs-40">
<div className="blog-item-body"> <div className="blog-item-body">

View File

@ -3,14 +3,37 @@ import { fetchBlog } from "@/services/payload/blog";
import { BlogCardItem } from "./BlogCardItem"; import { BlogCardItem } from "./BlogCardItem";
import { sanitizeBlogContentIntoStringPreview } from "@/utils/sanitize"; import { sanitizeBlogContentIntoStringPreview } from "@/utils/sanitize";
export interface BlogsProps { export type BlogsProps = {
preset?: "blogs" | "categories";
page: number; page: number;
search?: string; search?: string;
} } & (
| {
preset?: "blogs";
}
| {
preset?: "categories";
categoryId: number;
}
| {
preset?: "tags";
tagId: number;
}
);
export default async function Blogs({ page, search, preset = "blogs" }: BlogsProps) { export default async function Blogs({ page, search, ...params }: BlogsProps) {
const data = await fetchBlog({ page, search }); const fetchBlogParams: Parameters<typeof fetchBlog>[0] = {
page,
search,
};
if (params.preset === "categories") {
fetchBlogParams.categoryId = params.categoryId;
}
if (params.preset === "tags") {
fetchBlogParams.tagId = params.tagId;
}
const data = await fetchBlog(fetchBlogParams);
if (!data?.totalDocs) return <></>; if (!data?.totalDocs) return <></>;
@ -42,7 +65,7 @@ export default async function Blogs({ page, search, preset = "blogs" }: BlogsPro
hasNextPage={data.hasNextPage} hasNextPage={data.hasNextPage}
hasPreviousPage={data.hasPrevPage} hasPreviousPage={data.hasPrevPage}
totalPages={data.totalPages} totalPages={data.totalPages}
usePathParams={preset === "blogs" ? false : true} usePathParams={params.preset === "blogs" ? false : true}
/> />
</div> </div>
)} )}

View File

@ -1,4 +1,6 @@
import { fetchContact } from "@/services/payload/contact"; import { fetchContact } from "@/services/payload/contact";
import { FaClock, FaFax, FaMapMarkerAlt } from "react-icons/fa";
import { GiRotaryPhone } from "react-icons/gi";
import { Suspense } from "react"; import { Suspense } from "react";
export default function Contact() { export default function Contact() {
@ -32,21 +34,7 @@ async function ContactWithData() {
{/* Contact Item */} {/* Contact Item */}
<div className="col-sm-6 mb-xs-30 d-flex align-items-stretch"> <div className="col-sm-6 mb-xs-30 d-flex align-items-stretch">
<div className="alt-features-item border-left mt-0 wow fadeScaleIn" data-wow-delay=".3s"> <div className="alt-features-item border-left mt-0 wow fadeScaleIn" data-wow-delay=".3s">
<div className="alt-features-icon"> <FaMapMarkerAlt className="text-4xl m-5" />
<svg
width={24}
height={24}
viewBox="0 0 24 24"
fill="currentColor"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fillRule="evenodd"
clipRule="evenodd"
>
<path d="M12 2C8.134 2 5 5.134 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.866-3.134-7-7-7zm0 9.5c-1.381 0-2.5-1.119-2.5-2.5s1.119-2.5 2.5-2.5 2.5 1.119 2.5 2.5-1.119 2.5-2.5 2.5z" />
</svg>
</div>
<h4 className="alt-features-title">Location</h4> <h4 className="alt-features-title">Location</h4>
<div className="alt-features-descr clearlinks"> <div className="alt-features-descr clearlinks">
<div> <div>
@ -61,20 +49,7 @@ async function ContactWithData() {
{/* Contact Item */} {/* Contact Item */}
<div className="col-sm-6 d-flex align-items-stretch"> <div className="col-sm-6 d-flex align-items-stretch">
<div className="alt-features-item border-left mt-0 wow fadeScaleIn" data-wow-delay=".5s"> <div className="alt-features-item border-left mt-0 wow fadeScaleIn" data-wow-delay=".5s">
<div className="alt-features-icon"> <GiRotaryPhone className="text-4xl m-5" />
<svg
width={24}
height={24}
viewBox="0 0 24 24"
fill="currentColor"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fillRule="evenodd"
clipRule="evenodd"
>
<path d="M17 2H7C5.9 2 5 2.9 5 4v16c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 17H7V5h10v14zM12 16c.55 0 1-.45 1-1s-.45-1-1-1-1 .45-1 1 .45 1 1 1z" />
</svg>
</div>
<h4 className="alt-features-title">Phone</h4> <h4 className="alt-features-title">Phone</h4>
<div className="alt-features-descr clearlinks"> <div className="alt-features-descr clearlinks">
<div> <div>
@ -89,20 +64,7 @@ async function ContactWithData() {
{/* Contact Item */} {/* Contact Item */}
<div className="col-sm-6 mb-xs-30 d-flex align-items-stretch"> <div className="col-sm-6 mb-xs-30 d-flex align-items-stretch">
<div className="alt-features-item border-left mt-0 wow fadeScaleIn" data-wow-delay=".3s"> <div className="alt-features-item border-left mt-0 wow fadeScaleIn" data-wow-delay=".3s">
<div className="alt-features-icon"> <FaClock className="text-4xl m-5" />
<svg
width={24}
height={24}
viewBox="0 0 24 24"
fill="currentColor"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fillRule="evenodd"
clipRule="evenodd"
>
<path d="M12 2C6.486 2 2 6.486 2 12s4.486 10 10 10 10-4.486 10-10S17.514 2 12 2zm0 18c-4.411 0-8-3.589-8-8s3.589-8 8-8 8 3.589 8 8-3.589 8-8 8zm1-8h4v2h-6V7h2v5z" />
</svg>
</div>
<h4 className="alt-features-title">Hours</h4> <h4 className="alt-features-title">Hours</h4>
<div className="alt-features-descr clearlinks"> <div className="alt-features-descr clearlinks">
{Array.isArray(contact?.hours) && {Array.isArray(contact?.hours) &&
@ -118,20 +80,7 @@ async function ContactWithData() {
{/* Contact Item */} {/* Contact Item */}
<div className="col-sm-6 mb-xs-30 d-flex align-items-stretch"> <div className="col-sm-6 mb-xs-30 d-flex align-items-stretch">
<div className="alt-features-item border-left mt-0 wow fadeScaleIn" data-wow-delay=".3s"> <div className="alt-features-item border-left mt-0 wow fadeScaleIn" data-wow-delay=".3s">
<div className="alt-features-icon"> <FaFax className="text-4xl m-5" />
<svg
width={24}
height={24}
viewBox="0 0 24 24"
fill="currentColor"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fillRule="evenodd"
clipRule="evenodd"
>
<path d="M12 2C6.486 2 2 6.486 2 12s4.486 10 10 10 10-4.486 10-10S17.514 2 12 2zm0 18c-4.411 0-8-3.589-8-8s3.589-8 8-8 8 3.589 8 8-3.589 8-8 8zm1-12h-2v2h2V8zm0 4h-2v6h2v-6zm-4-2H7v2h2v-2zm6 0h-2v2h2v-2z" />
</svg>
</div>
<h4 className="alt-features-title">Fax</h4> <h4 className="alt-features-title">Fax</h4>
<div className="alt-features-descr clearlinks"> <div className="alt-features-descr clearlinks">
<div> <div>

View File

@ -11,8 +11,8 @@ const shareIcons: Record<string, any> = {
phone: { phone: {
link: "tel:+15208036644", link: "tel:+15208036644",
dom: ( dom: (
<span className="social-nav flex gap-1 text-2xl lg:text-white"> <span className="social-nav flex text-2xl text-white space-x-3 lg:space-x-1">
<Image src="/assets/icons/phone.png" alt="Image Description" width={25} height={22} /> <Image src="/assets/icons/phone.png" alt="Phone" width={30} height={25} />
<b className="text-[17px]">(520) 803-6644</b> <b className="text-[17px]">(520) 803-6644</b>
</span> </span>
), ),
@ -20,7 +20,7 @@ const shareIcons: Record<string, any> = {
facebook: { facebook: {
link: "https://www.facebook.com/p/Cochise-Oncology-61556262839823", link: "https://www.facebook.com/p/Cochise-Oncology-61556262839823",
dom: ( dom: (
<span className="social-nav flex gap-3 text-2xl lg:text-white"> <span className="social-nav flex text-2xl text-white space-x-3 lg:space-x-1">
<FaFacebook size={25} /> <FaFacebook size={25} />
<b className="text-[17px] lg:hidden">Facebook</b> <b className="text-[17px] lg:hidden">Facebook</b>
</span> </span>
@ -29,7 +29,7 @@ const shareIcons: Record<string, any> = {
linkedin: { linkedin: {
link: "https://linkedin.com/company/cochise-oncology", link: "https://linkedin.com/company/cochise-oncology",
dom: ( dom: (
<span className="social-nav flex gap-3 text-2xl lg:text-white"> <span className="social-nav flex text-2xl text-white space-x-3 lg:space-x-1">
<FaLinkedin size={25} /> <FaLinkedin size={25} />
<b className="text-[17px] lg:hidden">Linkedin</b> <b className="text-[17px] lg:hidden">Linkedin</b>
</span> </span>
@ -41,23 +41,13 @@ export default function Header({ links }: { links: typeof navMenuData }) {
return ( return (
<nav className="main-nav dark stick-fixed wow-menubar wch-unset relative"> <nav className="main-nav dark stick-fixed wow-menubar wch-unset relative">
<div className="main-nav-sub full-wrapper"> <div className="main-nav-sub full-wrapper">
{/* Logo (* Add your text or image to the link tag. Use SVG or PNG image format. <div className="nav-logo-wrap local-scroll lg:hidden">
If you use a PNG logo image, the image resolution must be equal 200% of the visible logo
image size for support of retina screens. See details in the template documentation. *) */}
<div className="nav-logo-wrap local-scroll">
<Link href={`/`} className="logo"> <Link href={`/`} className="logo">
<Image <Image
src="/assets/images/demo-slick/logo-dark.webp" src="/assets/images/demo-slick/logo-dark.webp"
alt="Your Company Logo" alt="Company Logo"
width={105} width={250}
height={34} height={150}
className="light-mode-logo"
/>
<Image
src="/assets/images/demo-slick/logo-dark.webp"
alt="Your Company Logo"
width={405}
height={34}
className="dark-mode-logo" className="dark-mode-logo"
/> />
</Link> </Link>
@ -70,30 +60,41 @@ export default function Header({ links }: { links: typeof navMenuData }) {
{/* Main Menu */} {/* Main Menu */}
<div className="inner-nav desktop-nav"> <div className="inner-nav desktop-nav">
<ul className="clearlist local-scroll"> <ul className="clearlist local-scroll">
{/* Item With Sub */} <li className="!hidden lg:!block">
<Link href={`/`} className="logo">
<Image
src="/assets/images/demo-slick/logo-dark.webp"
alt="Company Logo"
width={165}
height={100}
className="dark-mode-logo"
/>
</Link>
</li>
<HeaderNav links={links} /> <HeaderNav links={links} />
{/* End Item With Sub */} <li>
</ul>
<ul className="items-end clearlist flex flex-col justify-center h-full">
<div className="flex flex-col items-center h-full w-full content-center justify-center gap-2"> <div className="flex flex-col items-center h-full w-full content-center justify-center gap-2">
<div className="flex justify-center">
<a <a
href="/contact" href="/contact"
className="bg-extColorPrimary6 hover:bg-extColorPrimary8 px-3 py-2 rounded-full text-white font-semibold hover:cursor-pointer hover:scale-[1.15] mt-3 lg:mt-0 transition-all duration-300" className="bg-extColorPrimary6 hover:bg-extColorPrimary8 px-4 py-2 rounded-full text-white font-semibold hover:cursor-pointer hover:scale-[1.15] mt-3 lg:mt-0 transition-all duration-300"
> >
REQUEST CONSULTATION REQUEST CONSULTATION
</a> </a>
</div>
<div className="flex justify-between w-full flex-col lg:flex-row"> <div className="flex justify-between w-full flex-col lg:flex-row">
{Object.keys(shareIcons).map((k, idx) => { {Object.keys(shareIcons).map((k, idx) => {
return ( return (
<li key={idx} className="!p-0 !m-0"> <div key={idx} className="!p-0 !m-0">
<a className="cursor-pointer text-white" href={shareIcons[k].link} target="_blank"> <a className="cursor-pointer text-white" href={shareIcons[k].link} target="_blank">
{shareIcons[k].dom} {shareIcons[k].dom}
</a> </a>
</li> </div>
); );
})} })}
</div> </div>
</div> </div>
</li>
</ul> </ul>
</div> </div>

View File

@ -7,9 +7,13 @@ import { scrollToElement } from "@/utils/scrollToElement";
import { toggleMobileMenu } from "@/utils/toggleMobileMenu"; import { toggleMobileMenu } from "@/utils/toggleMobileMenu";
import Link from "next/link"; import Link from "next/link";
import { Fragment, useEffect, useRef, useState } from "react"; import { Fragment, useEffect, useRef, useState } from "react";
import { FaCaretDown, FaCaretRight } from "react-icons/fa";
export default function HeaderNav({ links, animateY = false }: { links: typeof navMenuData; animateY?: boolean }) { export default function HeaderNav({ links, animateY = false }: { links: typeof navMenuData; animateY?: boolean }) {
const [hoveredNavItem, setHoveredNavItem] = useState("");
const [hoveredSubNavItem, setHoveredSubNavItem] = useState("");
const [isDropdownOpen, setIsDropdownOpen] = useState([""]); const [isDropdownOpen, setIsDropdownOpen] = useState([""]);
const [isSubDropdownOpen, setIsSubDropdownOpen] = useState("");
const dropdownRef = useRef(null); const dropdownRef = useRef(null);
const toggleDropdown = (section: string[]) => { const toggleDropdown = (section: string[]) => {
@ -40,7 +44,10 @@ export default function HeaderNav({ links, animateY = false }: { links: typeof n
<Fragment key={index}> <Fragment key={index}>
<li> <li>
{!Array.isArray(link?.child) && ( {!Array.isArray(link?.child) && (
<Link href={link.href}> <Link
href={link.href}
className="!text-white hover:!text-extColorPrimary3 !text-[20px] !transition-all !duration-500"
>
{animateY ? ( {animateY ? (
<span className="btn-animate-y"> <span className="btn-animate-y">
<span className="btn-animate-y-1">{link.text}</span> <span className="btn-animate-y-1">{link.text}</span>
@ -55,35 +62,54 @@ export default function HeaderNav({ links, animateY = false }: { links: typeof n
)} )}
{Array.isArray(link?.child) && ( {Array.isArray(link?.child) && (
<> <div onMouseOver={() => setHoveredNavItem(`${index}`)} onMouseLeave={() => setHoveredNavItem("")}>
<Link href={link?.href ?? "#"} className="mn-has-sub flex justify-between"> <Link
{link.text} <i className="mi-chevron-down" onClick={() => toggleDropdown([link.text])} /> href={link?.href ?? "#"}
className="mn-has-sub !flex justify-between items-center !text-white hover:!text-extColorPrimary3 !text-[20px] !transition-all !duration-500"
onClick={() => toggleDropdown([link.text])}
>
{link.text} <FaCaretDown className="ml-2" />
</Link> </Link>
<ul <ul
className={`mn-sub to-right ${isDropdownOpen.includes(link.text) && "open"} !bg-extColorPrimary8`} className={`font-fontSecondary mn-sub to-right mt-2 ${isDropdownOpen.includes(link.text) && "open"} !bg-extColorPrimary8 ${hoveredNavItem.includes(`${index}`) ? "lg:visible lg:opacity-100 lg:z-10" : "lg:invisible lg:opacity-0"} !transition-all !duration-300 lg:shadow-nav`}
ref={dropdownRef} ref={dropdownRef}
> >
{link.child.map((subLink: any, subLinkIdx: number) => ( {link.child.map((subLink: any, subLinkIdx: number) => (
<li key={subLinkIdx}> <li
key={subLinkIdx}
onMouseOver={() => setHoveredSubNavItem(`${index}-${subLinkIdx}`)}
onMouseLeave={() => setHoveredSubNavItem("")}
>
{!Array.isArray(subLink?.child) && ( {!Array.isArray(subLink?.child) && (
<Link href={subLink?.href} onClick={() => toggleMobileMenu()}> <Link
href={subLink?.href}
onClick={() => toggleMobileMenu()}
className="!text-[14px] !text-white hover:!bg-extColorPrimary5 hover:!text-extColorPrimary3 !transition-all !duration-500"
>
{subLink?.text} {subLink?.text}
</Link> </Link>
)} )}
{Array.isArray(subLink?.child) && ( {Array.isArray(subLink?.child) && (
<> <>
<Link href={subLink?.href ?? "#"} className="mn-has-sub !flex !justify-between"> <Link
<span>{subLink.text}</span> href={subLink?.href ?? "#"}
<i className="mi-chevron-down" onClick={() => toggleDropdown([link.text, subLink.text])} /> className="mn-has-sub !flex !justify-between !items-center !text-white hover:!bg-extColorPrimary5 hover:!text-extColorPrimary3 transition-all duration-500"
onClick={() => setIsSubDropdownOpen(`${index}-${subLinkIdx}`)}
>
<span className="!text-[14px]">{subLink.text}</span>
<FaCaretRight className="ml-2" />
</Link> </Link>
<ul <ul
className={`mn-sub to-right ${isDropdownOpen.includes(subLink.text) && "open"} !bg-extColorPrimary8`} className={`mn-sub to-right ${isSubDropdownOpen.includes(`${index}-${subLinkIdx}`) && "open"} ${hoveredSubNavItem.includes(`${index}-${subLinkIdx}`) ? "lg:visible lg:opacity-100 lg:z-10" : "lg:invisible lg:opacity-0"} !bg-extColorPrimary8 !transition-all !duration-300 lg:shadow-nav`}
> >
{subLink.child.map((subLink2: any, subLinkIdx2: number) => ( {subLink.child.map((subLink2: any, subLinkIdx2: number) => (
<li key={subLinkIdx2}> <li key={subLinkIdx2}>
<Link href={subLink2?.href} onClick={() => toggleMobileMenu()}> <Link
href={subLink2?.href}
className="!text-[14px] !items-center !text-white hover:!bg-extColorPrimary5 hover:!text-extColorPrimary3 transition-all duration-500"
onClick={() => toggleMobileMenu()}
>
{subLink2?.text} {subLink2?.text}
</Link> </Link>
</li> </li>
@ -94,12 +120,12 @@ export default function HeaderNav({ links, animateY = false }: { links: typeof n
</li> </li>
))} ))}
</ul> </ul>
</> </div>
)} )}
</li> </li>
{index != links.length - 1 && ( {index != links.length - 1 && (
<div <div
className="text-white bg-white h-[1px] md:h-[25px] mx-2 opacity-[0.3]" className="text-white bg-white h-[1px] lg:h-[25px] mx-2 opacity-[0.3]"
style={{ border: "1px solid white" }} style={{ border: "1px solid white" }}
/> />
)} )}

View File

@ -16,14 +16,14 @@ const shareIcons: Record<string, any> = {
export default function HeroOther({ title, img, createdAt, shareUrl }: HeroOtherProps) { export default function HeroOther({ title, img, createdAt, shareUrl }: HeroOtherProps) {
return ( return (
<section className="page-section bg-dark-1 bg-gradient-gray-dark-1 light-content bg-scroll overflow-hidden !py-20 md:!pt-52 md:!pb-28 relative min-h-[48vh]"> <section className="page-section bg-dark-1 bg-gradient-gray-dark-1 light-content bg-scroll overflow-hidden !py-20 !pt-52 md:!pb-28 relative min-h-[48vh]">
{/* <!-- Background Shape --> */} {/* <!-- Background Shape --> */}
<div className="bg-shape-1 w-full h-full opacity-50 bg-contain"> <div className="bg-shape-1 w-full h-full opacity-50 bg-contain">
<Image src={img || "/assets/images/hero-default.webp"} alt="" fill className="object-cover" /> <Image src={img || "/assets/images/hero-default.webp"} alt="" fill className="object-cover" />
</div> </div>
{/* <!-- End Background Shape --> */} {/* <!-- End Background Shape --> */}
<div className="container position-relative pt-sm-40 text-center"> <div className="container position-relative text-center">
<div className="row"> <div className="row">
<div className="col-md-10 offset-md-1 col-lg-8 offset-lg-2"> <div className="col-md-10 offset-md-1 col-lg-8 offset-lg-2">
<h1 className="text-5xl !font-medium mb-10 leading-[1.5]">{title ?? ""}</h1> <h1 className="text-5xl !font-medium mb-10 leading-[1.5]">{title ?? ""}</h1>

View File

@ -5,6 +5,7 @@ import { init_wow } from "@/utils/initWow";
import { parallaxMouseMovement, parallaxScroll } from "@/utils/parallax"; import { parallaxMouseMovement, parallaxScroll } from "@/utils/parallax";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
import { useEffect } from "react"; import { useEffect } from "react";
import { GoogleTagManager } from "@next/third-parties/google";
export default function InitialScript() { export default function InitialScript() {
const path = usePathname(); const path = usePathname();
@ -36,5 +37,9 @@ export default function InitialScript() {
} }
}, []); }, []);
return <></>; return (
<>
<GoogleTagManager gtmId="GTM-XYZ" />
</>
);
} }

View File

@ -28,8 +28,13 @@ export default function Pagination({
const searchParams = new URLSearchParams(url.search); const searchParams = new URLSearchParams(url.search);
if (usePathParams) { if (usePathParams) {
searchParams.set("page", `${page}`); let updatedPath = "";
window.location.href = `${pathName}/page/${page}/?${searchParams}`; if (pathName.includes("/page")) {
updatedPath = pathName.replace(/\/page\/\d+/, `/page/${page}`);
} else {
updatedPath = `${pathName}/page/${page}`;
}
window.location.href = `${updatedPath}?${searchParams}`;
} else { } else {
searchParams.set("page", `${page}`); searchParams.set("page", `${page}`);
window.location.href = `${pathName}/?${searchParams}`; window.location.href = `${pathName}/?${searchParams}`;

View File

@ -6,10 +6,65 @@
* and re-run `payload generate:types` to regenerate this file. * and re-run `payload generate:types` to regenerate this file.
*/ */
/**
* Supported timezones in IANA format.
*
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "supportedTimezones".
*/
export type SupportedTimezones =
| 'Pacific/Midway'
| 'Pacific/Niue'
| 'Pacific/Honolulu'
| 'Pacific/Rarotonga'
| 'America/Anchorage'
| 'Pacific/Gambier'
| 'America/Los_Angeles'
| 'America/Tijuana'
| 'America/Denver'
| 'America/Phoenix'
| 'America/Chicago'
| 'America/Guatemala'
| 'America/New_York'
| 'America/Bogota'
| 'America/Caracas'
| 'America/Santiago'
| 'America/Buenos_Aires'
| 'America/Sao_Paulo'
| 'Atlantic/South_Georgia'
| 'Atlantic/Azores'
| 'Atlantic/Cape_Verde'
| 'Europe/London'
| 'Europe/Berlin'
| 'Africa/Lagos'
| 'Europe/Athens'
| 'Africa/Cairo'
| 'Europe/Moscow'
| 'Asia/Riyadh'
| 'Asia/Dubai'
| 'Asia/Baku'
| 'Asia/Karachi'
| 'Asia/Tashkent'
| 'Asia/Calcutta'
| 'Asia/Dhaka'
| 'Asia/Almaty'
| 'Asia/Jakarta'
| 'Asia/Bangkok'
| 'Asia/Shanghai'
| 'Asia/Singapore'
| 'Asia/Tokyo'
| 'Asia/Seoul'
| 'Australia/Sydney'
| 'Pacific/Guam'
| 'Pacific/Noumea'
| 'Pacific/Auckland'
| 'Pacific/Fiji';
export interface Config { export interface Config {
auth: { auth: {
users: UserAuthOperations; users: UserAuthOperations;
}; };
blocks: {};
collections: { collections: {
users: User; users: User;
media: Media; media: Media;

View File

@ -5,10 +5,11 @@ import { getPayload, Where } from "payload";
type FetchBlogParams = { type FetchBlogParams = {
page?: number; page?: number;
search?: string; search?: string;
categorySlug?: string; categoryId?: number;
tagId?: number;
}; };
export async function fetchBlog({ page, search = "", categorySlug = "" }: FetchBlogParams = {}) { export async function fetchBlog({ page, search = "", categoryId, tagId }: FetchBlogParams = {}) {
const payload = await getPayload({ config: payloadConfig }); const payload = await getPayload({ config: payloadConfig });
const queryCondition: Where = {}; const queryCondition: Where = {};
@ -17,9 +18,14 @@ export async function fetchBlog({ page, search = "", categorySlug = "" }: FetchB
contains: search, contains: search,
}; };
} }
if (!!categorySlug) { if (!!categoryId) {
queryCondition["categories"] = { queryCondition["categories"] = {
equals: 9, equals: categoryId,
};
}
if (!!tagId) {
queryCondition["tags"] = {
equals: tagId,
}; };
} }
@ -70,3 +76,35 @@ export async function fetchBlogDetail(slug: string | undefined) {
imgUrl, imgUrl,
}; };
} }
export async function fetchBlogCategoryBySlug(slug: string) {
const payload = await getPayload({ config: payloadConfig });
const category = await payload.find({
collection: "blogCategories",
where: {
slug: { equals: slug },
},
});
if (!category?.docs?.[0]) return null;
return {
data: category.docs[0],
};
}
export async function fetchBlogTagBySlug(slug: string) {
const payload = await getPayload({ config: payloadConfig });
const tag = await payload.find({
collection: "blogTags",
where: {
slug: { equals: slug },
},
});
if (!tag?.docs?.[0]) return null;
return {
data: tag.docs[0],
};
}

View File

@ -21,7 +21,6 @@ export async function getDefaultMetadata(): Promise<Metadata> {
}, },
openGraph: { openGraph: {
siteName, siteName,
title: siteName,
description: metaDesc, description: metaDesc,
type: "website", type: "website",
locale: "en_US", locale: "en_US",

View File

@ -4,7 +4,7 @@ export const toggleMobileMenu = () => {
const desktop_nav = document.querySelector(".desktop-nav"); const desktop_nav = document.querySelector(".desktop-nav");
if (desktop_nav.classList.contains("js-opened")) { if (desktop_nav.classList.contains("js-opened")) {
desktop_nav.style.maxHeight = "0px"; desktop_nav.style.maxHeight = "";
desktop_nav.classList.remove("js-opened"); desktop_nav.classList.remove("js-opened");
mobile_nav.classList.remove("active"); mobile_nav.classList.remove("active");
} else { } else {
@ -18,7 +18,7 @@ export const closeMobileMenu = () => {
const desktop_nav = document.querySelector(".desktop-nav"); const desktop_nav = document.querySelector(".desktop-nav");
if (desktop_nav.classList.contains("js-opened")) { if (desktop_nav.classList.contains("js-opened")) {
desktop_nav.style.maxHeight = "0px"; desktop_nav.style.maxHeight = "";
desktop_nav.classList.remove("js-opened"); desktop_nav.classList.remove("js-opened");
mobile_nav.classList.remove("active"); mobile_nav.classList.remove("active");
} }

View File

@ -8,6 +8,10 @@ export default {
], ],
theme: { theme: {
extend: { extend: {
fontFamily: {
fontMain: ["var(--font-noto-sans)"],
fontSecondary: ["var(--font-roboto)"],
},
colors: { colors: {
background: "var(--background)", background: "var(--background)",
foreground: "var(--foreground)", foreground: "var(--foreground)",

1485
yarn.lock

File diff suppressed because it is too large Load Diff