Skip to content

Commit

Permalink
Pushing up WIP to support issue #25 & #26
Browse files Browse the repository at this point in the history
  • Loading branch information
manifestinteractive committed Nov 1, 2023
1 parent 49ca20b commit 7a0fb31
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 22 deletions.
1 change: 0 additions & 1 deletion next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ const nextConfig = {
trailingSlash: false,
skipTrailingSlashRedirect: true,
reactStrictMode: true,
output: 'export',
distDir: 'dist',
images: {
unoptimized: true,
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sfccdevops/sfcc-docs",
"version": "0.5.0",
"version": "0.6.0",
"description": "Unofficial community edition of the Salesforce Commerce Cloud developer documentation.",
"license": "MIT",
"author": "Peter Schmalfeldt <[email protected]>",
Expand Down
29 changes: 16 additions & 13 deletions src/components/Layout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ function Header({ navigation }) {
)
}

export function Layout({ children, title, tableOfContents, isMarkdoc = false }) {
export function Layout({ children, title, tableOfContents, isMarkdoc = false, isEmbedded = null }) {
let router = useRouter()
let isHomePage = router.pathname === '/'

Expand All @@ -121,7 +121,7 @@ export function Layout({ children, title, tableOfContents, isMarkdoc = false })
}

return (
<>
<main className={isEmbedded === null ? 'hidden' : 'ready'}>
<a
id="skip-to-content-link"
className="duration-350 absolute left-1/2 top-0 z-20 w-36 -translate-x-1/2 -translate-y-full transform rounded-b-md bg-slate-950 px-3 py-1 text-white transition focus:translate-y-0 dark:bg-slate-50 dark:text-black"
Expand All @@ -135,19 +135,22 @@ export function Layout({ children, title, tableOfContents, isMarkdoc = false })
Skip to Content
</a>

{navigation && <Header navigation={navigation} />}
{navigation && isEmbedded === false && <Header navigation={navigation} />}

{isHomePage && <Hero />}

<div className="relative mx-auto flex w-full max-w-8xl flex-auto scroll-mt-20 justify-center sm:px-2 lg:px-8 xl:px-12" id="main">
<div className="z-10 hidden lg:relative lg:block lg:flex-none">
<div className="absolute inset-y-0 right-0 w-[50vw] bg-slate-50 dark:hidden" />
<div className="absolute bottom-0 right-0 top-16 hidden h-12 w-px bg-gradient-to-t from-slate-800 dark:block" />
<div className="absolute bottom-0 right-0 top-28 hidden w-px bg-slate-800 dark:block" />
<div className="sticky inset-0 left-[max(0px,calc(50%-45rem))] right-auto top-[3.8125rem] z-20 -ml-0.5 hidden h-[calc(100vh-4.75rem)] w-64 overflow-y-auto overflow-x-hidden pb-10 pr-6 lg:block" id="main-menu">
{navigation && <Navigation navigation={navigation} />}
{isEmbedded === false && (
<div className="z-10 hidden lg:relative lg:block lg:flex-none">
<div className="absolute inset-y-0 right-0 w-[50vw] bg-slate-50 dark:hidden" />
<div className="absolute bottom-0 right-0 top-16 hidden h-12 w-px bg-gradient-to-t from-slate-800 dark:block" />
<div className="absolute bottom-0 right-0 top-28 hidden w-px bg-slate-800 dark:block" />
<div className="sticky inset-0 left-[max(0px,calc(50%-45rem))] right-auto top-[3.8125rem] z-20 -ml-0.5 hidden h-[calc(100vh-4.75rem)] w-64 overflow-y-auto overflow-x-hidden pb-10 pr-6 lg:block" id="main-menu">
{navigation && <Navigation navigation={navigation} />}
</div>
</div>
</div>
<div className="min-w-0 max-w-2xl flex-auto px-4 py-16 lg:max-w-none lg:pl-8 lg:pr-0 xl:px-16">
)}
<div className={clsx('min-w-0 max-w-2xl flex-auto px-4 py-16 lg:max-w-none lg:pr-0 xl:px-16', isEmbedded === false ? 'lg:pl-8' : 'lg:pl-0')}>
{isMarkdoc ? (
<article>
{/* Document Title */}
Expand Down Expand Up @@ -196,7 +199,7 @@ export function Layout({ children, title, tableOfContents, isMarkdoc = false })
) : (
children
)}
{(previousPage || nextPage) && (
{(previousPage || nextPage) && isEmbedded === false && (
<dl className="mt-12 flex border-t border-slate-200 pt-6 dark:border-slate-800">
{previousPage && (
<div>
Expand Down Expand Up @@ -277,6 +280,6 @@ export function Layout({ children, title, tableOfContents, isMarkdoc = false })
</div>
)}
</div>
</>
</main>
)
}
2 changes: 1 addition & 1 deletion src/components/Navigation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export function Navigation({ navigation, className }) {
window.removeEventListener('pageshow', handleLoad)
window.removeEventListener('popstate', handleLoad)
}
}, [router.asPath, scrollTimer, sectionOpen])
}, [scrollTimer, sectionOpen])

// Handle the panel open state
const shouldSectionOpen = (open, section, pathname, keyword) => {
Expand Down
18 changes: 17 additions & 1 deletion src/components/Search.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ function useAutocomplete() {
id: nextId,
title: item.title,
pageTitle: item.pageTitle,
snippet: item.snippet,
label: query,
})
router.push(itemUrl)
Expand Down Expand Up @@ -111,6 +112,7 @@ function SearchResult({ result, autocomplete, collection, query, recentResult =
const sectionTitle = meta?.nav && meta.nav.alt ? `${meta.nav.alt}` : null
const hierarchy = meta?.nav ? [meta.nav.parent, meta.nav.child, meta.nav.title].filter(Boolean) : [sectionTitle, result.pageTitle].filter(Boolean)
const description = meta?.description ? meta.description : null
const snippet = result?.snippet ? result.snippet : null

function onRemove(id) {
recentSearchesPlugin.data.removeItem(id)
Expand All @@ -125,6 +127,7 @@ function SearchResult({ result, autocomplete, collection, query, recentResult =
id: nextId,
title: result.title,
pageTitle: result.pageTitle,
snippet: result.snippet,
label: query,
})
router.push(goToUrl)
Expand All @@ -145,6 +148,8 @@ function SearchResult({ result, autocomplete, collection, query, recentResult =
<div id={`title-${result.id}`} aria-hidden="true" className="text-sm text-slate-700 group-aria-selected:text-sky-600 dark:text-slate-300 dark:group-aria-selected:text-sky-400">
<HighlightQuery text={result.title} query={query} />
</div>

{/* Breadcrumb Hierarchy */}
{hierarchy.length > 0 && (
<div id={`hierarchy-${result.id}`} aria-hidden="true" className="mt-0.5 truncate whitespace-nowrap text-xs text-slate-700 dark:text-slate-200">
{hierarchy.map((item, itemIndex, items) => (
Expand All @@ -155,11 +160,22 @@ function SearchResult({ result, autocomplete, collection, query, recentResult =
))}
</div>
)}

{/* Page Description */}
{description && (
<div aria-hidden="true" className="mt-0.5 truncate whitespace-nowrap text-xs text-slate-400 dark:text-slate-400">
{description}
<HighlightQuery text={description} query={query} />
</div>
)}

{/* Search Result Snippet */}
{snippet && !snippet.slice(0, 50).startsWith(description.slice(0, 50)) && (
<div aria-hidden="true" className="mt-0.5 truncate whitespace-nowrap text-xs text-slate-400 dark:text-slate-400">
<HighlightQuery text={snippet} query={query} />
</div>
)}

{/* Show Recent Results if we have them */}
{recentResult === true && result.url && (
<button
className="absolute right-1 top-1 inline-block h-12 w-12 p-3.5 text-slate-400 transition-colors duration-200 hover:text-red-500 focus:text-red-500 focus:outline-none dark:text-slate-500 dark:hover:text-red-500"
Expand Down
15 changes: 13 additions & 2 deletions src/markdoc/search.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ const search = function (nextConfig = {}) {
resolution: 3
}
}],
store: ['title', 'pageTitle'],
store: ['title', 'pageTitle', 'snippet'],
}
})
Expand All @@ -124,7 +124,8 @@ const search = function (nextConfig = {}) {
sectionIndex.add({
url: url + (hash ? ('#' + hash) : ''),
title,
content: [title, ...content].join('\\n'),
content: [title, ...content].join(' \\n'),
snippet: content.slice(0, 3).join(' \\n'),
pageTitle: hash ? sections[0][0] : undefined,
})
}
Expand Down Expand Up @@ -156,6 +157,7 @@ const search = function (nextConfig = {}) {
const getScore = (query, item) => {
const keywords = query.split(' ')
const title = item.doc.title ? cleanTitle(item.doc.title.toLowerCase()) : null
const snippet = item.doc.snippet ? item.doc.snippet : null
const pageTitle = item.doc.pageTitle ? cleanTitle(item.doc.pageTitle.toLowerCase()) : null
const id = item.id ? item.id.toLowerCase() : null
Expand Down Expand Up @@ -185,6 +187,14 @@ const search = function (nextConfig = {}) {
regX = new RegExp(\`\$\{keyword\}\`, 'i')
result = pageTitle.match(regX)[0];
score += result ? (result.length / id.length) : 0
}
if (snippet && snippet.includes(keyword)) {
score += 1
regX = new RegExp(\`\$\{keyword\}\`, 'i')
result = snippet.match(regX)[0];
score += result ? (result.length / id.length) : 0
}
})
Expand All @@ -196,6 +206,7 @@ const search = function (nextConfig = {}) {
url: item.id,
title: cleanTitle(item.doc.title),
pageTitle: cleanTitle(item.doc.pageTitle),
snippet: item.doc.snippet,
score: getScore(query, item)
}))
Expand Down
23 changes: 22 additions & 1 deletion src/pages/_app.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useRouter } from 'next/router'
import { slugifyWithCounter } from '@sindresorhus/slugify'

import { Layout } from '@/components/Layout'
import { useEffect, useState } from 'react'

import 'focus-visible'
import '@/styles/tailwind.css'
Expand Down Expand Up @@ -56,6 +57,26 @@ function collectHeadings(nodes, slugify = slugifyWithCounter()) {
export default function App({ Component, pageProps }) {
const router = useRouter()

let [isEmbedded, setIsEmbedded] = useState(null)

useEffect(() => {
if ((router.query.embed && router.query.embed === 'true') || window.localStorage.embed === 'true') {
setIsEmbedded(true)
} else {
setIsEmbedded(false)
}
}, [router.query.embed])

useEffect(() => {
let handler = () => {
setIsEmbedded(window.localStorage.embed === 'true')
}

window.addEventListener('storage', handler)

return () => window.removeEventListener('storage', handler)
}, [])

const baseURL = process.env.SITE_URL || 'https://sfccdocs.com'

const metaTitle = pageProps.markdoc?.frontmatter.metaTitle
Expand Down Expand Up @@ -133,7 +154,7 @@ export default function App({ Component, pageProps }) {
{/* PWA Manifest */}
<link rel="manifest" href="/manifest.webmanifest" />
</Head>
<Layout title={metaTitle} tableOfContents={tableOfContents} isMarkdoc={Boolean(pageProps.markdoc)}>
<Layout title={metaTitle} tableOfContents={tableOfContents} isMarkdoc={Boolean(pageProps.markdoc)} isEmbedded={isEmbedded}>
<Component {...pageProps} />
</Layout>
</>
Expand Down
8 changes: 8 additions & 0 deletions src/pages/_document.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ const headerScript = `
window.defaultVersion = '${defaultVersion.value}'
window.useVersion = window.location.pathname.split('/')[1] || window.defaultVersion
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString) || null;
const embed = urlParams ? urlParams.get('embed') : null;
if (embed) {
window.localStorage.setItem('embed', embed === 'true' ? 'true' : 'false')
}
let isDarkMode = window.matchMedia('(prefers-color-scheme: dark)')
function updateTheme(theme) {
theme = theme ?? window.localStorage.theme ?? 'system'
Expand Down
55 changes: 55 additions & 0 deletions src/pages/api/search.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { getMeta } from '@/data/meta'

export default function handler(req, res) {
// Load Search Function
import('@/markdoc/search.mjs').then(({ search }) => {
try {
// Perform Search
const baseURL = process.env.SITE_URL || 'https://sfccdocs.com'
const results = search(req.query.query, {
limit: req.query.limit ? parseInt(req.query.limit, 10) : 100,
offset: req.query.offset ? parseInt(req.query.offset, 10) : 0,
})

// Loop through results
results.map((result, index) => {
// Add additional properties
const parts = result.url.split('#')
const baseUri = parts[0]
const anchor = parts.length > 1 ? `#${parts[1]}` : ''
const deprecated = baseUri.startsWith('/deprecated/')
const meta = getMeta(baseUri, deprecated)

result.deprecated = deprecated
result.title = meta.title
result.description = meta.description
result.keywords = meta.nav.alt.split(' › ')
result.snippet = result.snippet.split('. ')[0]
result.url = `${baseURL}${result.url}`
result.embed = `${baseURL}${baseUri}?embed=true${anchor}`

// Remove unneeded properties
delete result.score

if (result.pageTitle) {
delete result.pageTitle
}

// Sort properties alphabetically for easier readability
results[index] = Object.keys(result)
.sort()
.reduce((accumulator, key) => {
accumulator[key] = result[key]

return accumulator
}, {})
})

// Return results
res.status(200).json({ total: results.length, results })
} catch (error) {
// Return error
res.status(400).json({ error: error.message })
}
})
}

0 comments on commit 7a0fb31

Please sign in to comment.