chore: show menu item only if section anchor provided
This commit is contained in:
@@ -9,6 +9,7 @@ export const homePageDocument = gql`
|
|||||||
id
|
id
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
|
anchor
|
||||||
badge
|
badge
|
||||||
stats {
|
stats {
|
||||||
id
|
id
|
||||||
@@ -20,6 +21,7 @@ export const homePageDocument = gql`
|
|||||||
id
|
id
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
|
anchor
|
||||||
cards {
|
cards {
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
@@ -39,6 +41,7 @@ export const homePageDocument = gql`
|
|||||||
id
|
id
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
|
anchor
|
||||||
cards {
|
cards {
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
@@ -56,6 +59,7 @@ export const homePageDocument = gql`
|
|||||||
id
|
id
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
|
anchor
|
||||||
cards {
|
cards {
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
@@ -75,6 +79,7 @@ export const homePageDocument = gql`
|
|||||||
id
|
id
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
|
anchor
|
||||||
partners(pagination: { pageSize: 100 }) {
|
partners(pagination: { pageSize: 100 }) {
|
||||||
id
|
id
|
||||||
value
|
value
|
||||||
|
|||||||
@@ -1611,11 +1611,11 @@ export type HomePageQueryVariables = Exact<{ [key: string]: never; }>;
|
|||||||
|
|
||||||
|
|
||||||
export type HomePageQuery = { __typename?: 'Query', homePage?: { __typename?: 'HomePage', sections?: Array<
|
export type HomePageQuery = { __typename?: 'Query', homePage?: { __typename?: 'HomePage', sections?: Array<
|
||||||
| { __typename: 'ComponentSectionsAbout', id: string, title?: string | null, description?: string | null, partners?: Array<{ __typename?: 'ComponentSharedString', id: string, value: string } | null> | null, cards?: Array<{ __typename?: 'ComponentCardsAdvantage', id: string, title?: string | null, description?: string | null, color?: { __typename?: 'ComponentSharedColor', value?: Enum_Componentsharedcolor_Value | null } | null, icon?: { __typename?: 'ComponentSharedIcon', value?: Enum_Componentsharedicon_Value | null } | null } | null> | null }
|
| { __typename: 'ComponentSectionsAbout', id: string, title?: string | null, description?: string | null, anchor?: string | null, partners?: Array<{ __typename?: 'ComponentSharedString', id: string, value: string } | null> | null, cards?: Array<{ __typename?: 'ComponentCardsAdvantage', id: string, title?: string | null, description?: string | null, color?: { __typename?: 'ComponentSharedColor', value?: Enum_Componentsharedcolor_Value | null } | null, icon?: { __typename?: 'ComponentSharedIcon', value?: Enum_Componentsharedicon_Value | null } | null } | null> | null }
|
||||||
| { __typename: 'ComponentSectionsCases', id: string, title?: string | null, description?: string | null, cards?: Array<{ __typename?: 'ComponentCardsCase', id: string, title?: string | null, description?: string | null, pretitle?: string | null, badge?: string | null, footnote?: string | null, color?: { __typename?: 'ComponentSharedColor', value?: Enum_Componentsharedcolor_Value | null } | null, icon?: { __typename?: 'ComponentSharedIcon', value?: Enum_Componentsharedicon_Value | null } | null } | null> | null }
|
| { __typename: 'ComponentSectionsCases', id: string, title?: string | null, description?: string | null, anchor?: string | null, cards?: Array<{ __typename?: 'ComponentCardsCase', id: string, title?: string | null, description?: string | null, pretitle?: string | null, badge?: string | null, footnote?: string | null, color?: { __typename?: 'ComponentSharedColor', value?: Enum_Componentsharedcolor_Value | null } | null, icon?: { __typename?: 'ComponentSharedIcon', value?: Enum_Componentsharedicon_Value | null } | null } | null> | null }
|
||||||
| { __typename: 'ComponentSectionsHomeHero', id: string, title?: string | null, description?: string | null, badge?: string | null, stats?: Array<{ __typename?: 'ComponentSharedAttribute', id: string, key?: string | null, value?: string | null } | null> | null }
|
| { __typename: 'ComponentSectionsHomeHero', id: string, title?: string | null, description?: string | null, anchor?: string | null, badge?: string | null, stats?: Array<{ __typename?: 'ComponentSharedAttribute', id: string, key?: string | null, value?: string | null } | null> | null }
|
||||||
| { __typename: 'ComponentSectionsServices', id: string, title?: string | null, description?: string | null, cards?: Array<{ __typename?: 'ComponentCardsService', id: string, title?: string | null, description?: string | null, icon?: { __typename?: 'ComponentSharedIcon', value?: Enum_Componentsharedicon_Value | null } | null, color?: { __typename?: 'ComponentSharedColor', value?: Enum_Componentsharedcolor_Value | null } | null, category?: { __typename?: 'Category', slug: string } | null } | null> | null }
|
| { __typename: 'ComponentSectionsServices', id: string, title?: string | null, description?: string | null, anchor?: string | null, cards?: Array<{ __typename?: 'ComponentCardsService', id: string, title?: string | null, description?: string | null, icon?: { __typename?: 'ComponentSharedIcon', value?: Enum_Componentsharedicon_Value | null } | null, color?: { __typename?: 'ComponentSharedColor', value?: Enum_Componentsharedcolor_Value | null } | null, category?: { __typename?: 'Category', slug: string } | null } | null> | null }
|
||||||
| { __typename: 'ComponentSectionsSolutions', id: string, title?: string | null, description?: string | null, cards?: Array<{ __typename?: 'ComponentCardsSolution', id: string, title?: string | null, description?: string | null, footnote?: string | null, icon?: { __typename?: 'ComponentSharedIcon', value?: Enum_Componentsharedicon_Value | null } | null, category?: { __typename?: 'Category', slug: string } | null } | null> | null }
|
| { __typename: 'ComponentSectionsSolutions', id: string, title?: string | null, description?: string | null, anchor?: string | null, cards?: Array<{ __typename?: 'ComponentCardsSolution', id: string, title?: string | null, description?: string | null, footnote?: string | null, icon?: { __typename?: 'ComponentSharedIcon', value?: Enum_Componentsharedicon_Value | null } | null, category?: { __typename?: 'Category', slug: string } | null } | null> | null }
|
||||||
| { __typename: 'Error' }
|
| { __typename: 'Error' }
|
||||||
| null> | null } | null };
|
| null> | null } | null };
|
||||||
|
|
||||||
@@ -1677,6 +1677,7 @@ export const HomePageDocument = new TypedDocumentString(`
|
|||||||
id
|
id
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
|
anchor
|
||||||
badge
|
badge
|
||||||
stats {
|
stats {
|
||||||
id
|
id
|
||||||
@@ -1688,6 +1689,7 @@ export const HomePageDocument = new TypedDocumentString(`
|
|||||||
id
|
id
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
|
anchor
|
||||||
cards {
|
cards {
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
@@ -1707,6 +1709,7 @@ export const HomePageDocument = new TypedDocumentString(`
|
|||||||
id
|
id
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
|
anchor
|
||||||
cards {
|
cards {
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
@@ -1724,6 +1727,7 @@ export const HomePageDocument = new TypedDocumentString(`
|
|||||||
id
|
id
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
|
anchor
|
||||||
cards {
|
cards {
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
@@ -1743,6 +1747,7 @@ export const HomePageDocument = new TypedDocumentString(`
|
|||||||
id
|
id
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
|
anchor
|
||||||
partners(pagination: {pageSize: 100}) {
|
partners(pagination: {pageSize: 100}) {
|
||||||
id
|
id
|
||||||
value
|
value
|
||||||
|
|||||||
46
src/lib/cms/sections/homeNav.ts
Normal file
46
src/lib/cms/sections/homeNav.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import type { HomePageQuery } from '../../../graphql/graphql'
|
||||||
|
import type { Maybe } from '../../types'
|
||||||
|
|
||||||
|
type HomePageData = NonNullable<HomePageQuery['homePage']>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anchors configured on each home-page section, keyed by section kind. A key is
|
||||||
|
* present only when its section exists and has a non-empty `anchor`, which is
|
||||||
|
* what gates the matching header menu item.
|
||||||
|
*/
|
||||||
|
export interface HomeSectionAnchors {
|
||||||
|
hero?: string
|
||||||
|
services?: string
|
||||||
|
solutions?: string
|
||||||
|
cases?: string
|
||||||
|
about?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getHomeSectionAnchors(home: Maybe<HomePageData>): HomeSectionAnchors {
|
||||||
|
const anchors: HomeSectionAnchors = {}
|
||||||
|
|
||||||
|
for (const section of home?.sections ?? []) {
|
||||||
|
if (!section || section.__typename === 'Error') continue
|
||||||
|
const anchor = section.anchor?.trim()
|
||||||
|
if (!anchor) continue
|
||||||
|
switch (section.__typename) {
|
||||||
|
case 'ComponentSectionsHomeHero':
|
||||||
|
anchors.hero = anchor
|
||||||
|
break
|
||||||
|
case 'ComponentSectionsServices':
|
||||||
|
anchors.services = anchor
|
||||||
|
break
|
||||||
|
case 'ComponentSectionsSolutions':
|
||||||
|
anchors.solutions = anchor
|
||||||
|
break
|
||||||
|
case 'ComponentSectionsCases':
|
||||||
|
anchors.cases = anchor
|
||||||
|
break
|
||||||
|
case 'ComponentSectionsAbout':
|
||||||
|
anchors.about = anchor
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return anchors
|
||||||
|
}
|
||||||
@@ -8,12 +8,22 @@ import { CategoryView } from '../views/CategoryView'
|
|||||||
import { siteConfigQuery } from '../graphql-documents/site-config.gql.generated'
|
import { siteConfigQuery } from '../graphql-documents/site-config.gql.generated'
|
||||||
import { menuItemsQuery } from '../graphql-documents/menu-items.gql.generated'
|
import { menuItemsQuery } from '../graphql-documents/menu-items.gql.generated'
|
||||||
import { categoryQuery } from '../graphql-documents/category.gql.generated'
|
import { categoryQuery } from '../graphql-documents/category.gql.generated'
|
||||||
|
import { homePageQuery } from '../graphql-documents/home-page.gql.generated'
|
||||||
import { resolveUploadUrl } from '../lib/cms/uploads/url'
|
import { resolveUploadUrl } from '../lib/cms/uploads/url'
|
||||||
|
import { getHomeSectionAnchors } from '../lib/cms/sections/homeNav'
|
||||||
|
|
||||||
const [siteResult, menuItemsResult] = await Promise.all([siteConfigQuery.execute(), menuItemsQuery.execute()])
|
const [siteResult, menuItemsResult, homeResult] = await Promise.all([
|
||||||
|
siteConfigQuery.execute(),
|
||||||
|
menuItemsQuery.execute(),
|
||||||
|
homePageQuery.execute(),
|
||||||
|
])
|
||||||
if (siteResult.errors?.length) {
|
if (siteResult.errors?.length) {
|
||||||
throw new Error(siteResult.errors.map(e => e.message).join(', '))
|
throw new Error(siteResult.errors.map(e => e.message).join(', '))
|
||||||
}
|
}
|
||||||
|
if (homeResult.errors?.length) {
|
||||||
|
throw new Error(homeResult.errors.map(e => e.message).join(', '))
|
||||||
|
}
|
||||||
|
const sectionAnchors = getHomeSectionAnchors(homeResult.data?.homePage ?? null)
|
||||||
const siteConfig = siteResult.data?.siteConfig
|
const siteConfig = siteResult.data?.siteConfig
|
||||||
const siteTitle = siteConfig?.title ?? ''
|
const siteTitle = siteConfig?.title ?? ''
|
||||||
const siteDescription = siteConfig?.description ?? ''
|
const siteDescription = siteConfig?.description ?? ''
|
||||||
@@ -62,7 +72,7 @@ const vendors = (category.vendors?.filter(v => v != null) ?? []).map(vendor => (
|
|||||||
description={description ?? siteDescription}
|
description={description ?? siteDescription}
|
||||||
>
|
>
|
||||||
<div class="min-h-screen bg-white w-full overflow-x-hidden">
|
<div class="min-h-screen bg-white w-full overflow-x-hidden">
|
||||||
<Header client:load siteTitle={siteTitle} contacts={contacts} solutions={solutionCategories} services={serviceCategories} />
|
<Header client:load siteTitle={siteTitle} contacts={contacts} solutions={solutionCategories} services={serviceCategories} sectionAnchors={sectionAnchors} />
|
||||||
<CategoryView client:load badge={badge} title={title} description={description} vendors={vendors} contacts={contacts} />
|
<CategoryView client:load badge={badge} title={title} description={description} vendors={vendors} contacts={contacts} />
|
||||||
<Footer
|
<Footer
|
||||||
client:load
|
client:load
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { menuItemsQuery } from '../graphql-documents/menu-items.gql.generated'
|
|||||||
import { homePageQuery } from '../graphql-documents/home-page.gql.generated'
|
import { homePageQuery } from '../graphql-documents/home-page.gql.generated'
|
||||||
import { siteConfigQuery } from '../graphql-documents/site-config.gql.generated'
|
import { siteConfigQuery } from '../graphql-documents/site-config.gql.generated'
|
||||||
import { resolveUploadUrl } from '../lib/cms/uploads/url'
|
import { resolveUploadUrl } from '../lib/cms/uploads/url'
|
||||||
|
import { getHomeSectionAnchors } from '../lib/cms/sections/homeNav'
|
||||||
|
|
||||||
const [homeResult, siteResult, menuItemsResult] = await Promise.all([
|
const [homeResult, siteResult, menuItemsResult] = await Promise.all([
|
||||||
homePageQuery.execute(),
|
homePageQuery.execute(),
|
||||||
@@ -39,11 +40,12 @@ const menuItems = (menuItemsResult.data?.categories?.filter(c => c != null) ?? [
|
|||||||
|
|
||||||
const solutionCategories = menuItems.filter(c => c.group === Enum_Category_Group.Solution)
|
const solutionCategories = menuItems.filter(c => c.group === Enum_Category_Group.Solution)
|
||||||
const serviceCategories = menuItems.filter(c => c.group === Enum_Category_Group.Service)
|
const serviceCategories = menuItems.filter(c => c.group === Enum_Category_Group.Service)
|
||||||
|
const sectionAnchors = getHomeSectionAnchors(homePage)
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title={siteTitle} description={siteDescription}>
|
<Layout title={siteTitle} description={siteDescription}>
|
||||||
<div class="min-h-screen bg-white w-full overflow-x-hidden">
|
<div class="min-h-screen bg-white w-full overflow-x-hidden">
|
||||||
<Header client:load siteTitle={siteTitle} contacts={contacts} solutions={solutionCategories} services={serviceCategories} />
|
<Header client:load siteTitle={siteTitle} contacts={contacts} solutions={solutionCategories} services={serviceCategories} sectionAnchors={sectionAnchors} />
|
||||||
<HomePage client:load homePage={homePage} contacts={contacts} />
|
<HomePage client:load homePage={homePage} contacts={contacts} />
|
||||||
<Footer
|
<Footer
|
||||||
client:load
|
client:load
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Menu, X, ChevronDown } from 'lucide-react'
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { ContactModal } from '../components/ContactModal'
|
import { ContactModal } from '../components/ContactModal'
|
||||||
import type { MenuItemsQuery } from '../graphql/graphql'
|
import type { MenuItemsQuery } from '../graphql/graphql'
|
||||||
|
import type { HomeSectionAnchors } from '../lib/cms/sections/homeNav'
|
||||||
import type { SiteConfigContact } from '../lib/cms/contact/types'
|
import type { SiteConfigContact } from '../lib/cms/contact/types'
|
||||||
import { navigateHomeSectionAnchor } from '../lib/scrollToHash'
|
import { navigateHomeSectionAnchor } from '../lib/scrollToHash'
|
||||||
|
|
||||||
@@ -12,9 +13,16 @@ export interface HeaderProps {
|
|||||||
contacts?: readonly SiteConfigContact[]
|
contacts?: readonly SiteConfigContact[]
|
||||||
solutions?: readonly CategoryNavItem[]
|
solutions?: readonly CategoryNavItem[]
|
||||||
services?: readonly CategoryNavItem[]
|
services?: readonly CategoryNavItem[]
|
||||||
|
sectionAnchors?: HomeSectionAnchors
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Header({ siteTitle = '', contacts = [], solutions = [], services = [] }: HeaderProps) {
|
export function Header({
|
||||||
|
siteTitle = '',
|
||||||
|
contacts = [],
|
||||||
|
solutions = [],
|
||||||
|
services = [],
|
||||||
|
sectionAnchors = {},
|
||||||
|
}: HeaderProps) {
|
||||||
const [isMenuOpen, setIsMenuOpen] = useState(false)
|
const [isMenuOpen, setIsMenuOpen] = useState(false)
|
||||||
const [isSolutionsOpen, setIsSolutionsOpen] = useState(false)
|
const [isSolutionsOpen, setIsSolutionsOpen] = useState(false)
|
||||||
const [isServicesOpen, setIsServicesOpen] = useState(false)
|
const [isServicesOpen, setIsServicesOpen] = useState(false)
|
||||||
@@ -86,20 +94,24 @@ export function Header({ siteTitle = '', contacts = [], solutions = [], services
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<a
|
{sectionAnchors.cases && (
|
||||||
href="/#cases"
|
<a
|
||||||
className="text-gray-700 hover:text-blue-600 transition-colors whitespace-nowrap"
|
href={`/#${sectionAnchors.cases}`}
|
||||||
onClick={e => navigateHomeSectionAnchor(e, 'cases')}
|
className="text-gray-700 hover:text-blue-600 transition-colors whitespace-nowrap"
|
||||||
>
|
onClick={e => navigateHomeSectionAnchor(e, sectionAnchors.cases!)}
|
||||||
Кейсы
|
>
|
||||||
</a>
|
Кейсы
|
||||||
<a
|
</a>
|
||||||
href="/#about"
|
)}
|
||||||
className="text-gray-700 hover:text-blue-600 transition-colors whitespace-nowrap"
|
{sectionAnchors.about && (
|
||||||
onClick={e => navigateHomeSectionAnchor(e, 'about')}
|
<a
|
||||||
>
|
href={`/#${sectionAnchors.about}`}
|
||||||
О компании
|
className="text-gray-700 hover:text-blue-600 transition-colors whitespace-nowrap"
|
||||||
</a>
|
onClick={e => navigateHomeSectionAnchor(e, sectionAnchors.about!)}
|
||||||
|
>
|
||||||
|
О компании
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
<a
|
<a
|
||||||
href="/#contact"
|
href="/#contact"
|
||||||
className="text-gray-700 hover:text-blue-600 transition-colors whitespace-nowrap"
|
className="text-gray-700 hover:text-blue-600 transition-colors whitespace-nowrap"
|
||||||
@@ -185,26 +197,30 @@ export function Header({ siteTitle = '', contacts = [], solutions = [], services
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<a
|
{sectionAnchors.cases && (
|
||||||
href="/#cases"
|
<a
|
||||||
onClick={e => {
|
href={`/#${sectionAnchors.cases}`}
|
||||||
navigateHomeSectionAnchor(e, 'cases')
|
onClick={e => {
|
||||||
setIsMenuOpen(false)
|
navigateHomeSectionAnchor(e, sectionAnchors.cases!)
|
||||||
}}
|
setIsMenuOpen(false)
|
||||||
className="text-gray-700 hover:text-blue-600"
|
}}
|
||||||
>
|
className="text-gray-700 hover:text-blue-600"
|
||||||
Кейсы
|
>
|
||||||
</a>
|
Кейсы
|
||||||
<a
|
</a>
|
||||||
href="/#about"
|
)}
|
||||||
onClick={e => {
|
{sectionAnchors.about && (
|
||||||
navigateHomeSectionAnchor(e, 'about')
|
<a
|
||||||
setIsMenuOpen(false)
|
href={`/#${sectionAnchors.about}`}
|
||||||
}}
|
onClick={e => {
|
||||||
className="text-gray-700 hover:text-blue-600"
|
navigateHomeSectionAnchor(e, sectionAnchors.about!)
|
||||||
>
|
setIsMenuOpen(false)
|
||||||
О компании
|
}}
|
||||||
</a>
|
className="text-gray-700 hover:text-blue-600"
|
||||||
|
>
|
||||||
|
О компании
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
<a
|
<a
|
||||||
href="/#contact"
|
href="/#contact"
|
||||||
onClick={e => {
|
onClick={e => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState, type ReactNode } from 'react'
|
||||||
import type { HomePageQuery } from '../graphql/graphql'
|
import type { HomePageQuery } from '../graphql/graphql'
|
||||||
import { Hero } from '../sections/Hero'
|
import { Hero } from '../sections/Hero'
|
||||||
import { Services } from '../sections/Services'
|
import { Services } from '../sections/Services'
|
||||||
@@ -56,6 +56,17 @@ function parseHomeSections(home: Maybe<HomePageData>) {
|
|||||||
return { hero, services, solutions, cases, about }
|
return { hero, services, solutions, cases, about }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Wraps a section in an anchor target (id + header-offset scroll margin) when it has an anchor. */
|
||||||
|
function SectionAnchor({ anchor, children }: { anchor?: Maybe<string>; children: ReactNode }) {
|
||||||
|
const id = anchor?.trim()
|
||||||
|
if (!id) return <>{children}</>
|
||||||
|
return (
|
||||||
|
<div id={id} style={{ scrollMarginTop: HEADER_OFFSET_PX }}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export interface HomePageProps {
|
export interface HomePageProps {
|
||||||
homePage?: Maybe<HomePageData>
|
homePage?: Maybe<HomePageData>
|
||||||
contacts?: readonly SiteConfigContact[]
|
contacts?: readonly SiteConfigContact[]
|
||||||
@@ -75,15 +86,21 @@ export function HomePage({ homePage, contacts = [] }: HomePageProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Hero onOpenContactModal={() => setContactOpen(true)} data={hero} />
|
<SectionAnchor anchor={hero?.anchor}>
|
||||||
<Services data={services} />
|
<Hero onOpenContactModal={() => setContactOpen(true)} data={hero} />
|
||||||
<Solutions data={solutions} />
|
</SectionAnchor>
|
||||||
<div id="cases" style={{ scrollMarginTop: HEADER_OFFSET_PX }}>
|
<SectionAnchor anchor={services?.anchor}>
|
||||||
|
<Services data={services} />
|
||||||
|
</SectionAnchor>
|
||||||
|
<SectionAnchor anchor={solutions?.anchor}>
|
||||||
|
<Solutions data={solutions} />
|
||||||
|
</SectionAnchor>
|
||||||
|
<SectionAnchor anchor={cases?.anchor}>
|
||||||
<Cases data={cases} />
|
<Cases data={cases} />
|
||||||
</div>
|
</SectionAnchor>
|
||||||
<div id="about" style={{ scrollMarginTop: HEADER_OFFSET_PX }}>
|
<SectionAnchor anchor={about?.anchor}>
|
||||||
<About data={about} />
|
<About data={about} />
|
||||||
</div>
|
</SectionAnchor>
|
||||||
<div id="contact" style={{ scrollMarginTop: HEADER_OFFSET_PX }}>
|
<div id="contact" style={{ scrollMarginTop: HEADER_OFFSET_PX }}>
|
||||||
<Contact contacts={contacts} submissionSource="home_contact_section" />
|
<Contact contacts={contacts} submissionSource="home_contact_section" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user