Skip to content

Commit

Permalink
Merge pull request #115 from timlrx/v2
Browse files Browse the repository at this point in the history
Newsletter and search component changes
  • Loading branch information
timlrx authored Jul 17, 2023
2 parents 6c7cf77 + 70bafdd commit f6ba3d8
Show file tree
Hide file tree
Showing 13 changed files with 149 additions and 136 deletions.
2 changes: 2 additions & 0 deletions .changeset/pre.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
"neat-tables-occur",
"pretty-worms-help",
"proud-brooms-laugh",
"tall-rocks-hear",
"tricky-carpets-fly",
"unlucky-keys-join",
"weak-swans-heal"
]
Expand Down
7 changes: 7 additions & 0 deletions .changeset/tall-rocks-hear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'pliny': patch
---

Remove next/dynamic from search component
Remove redundant context components
load kbar data in advance and refactor code
5 changes: 5 additions & 0 deletions .changeset/tricky-carpets-fly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'pliny': patch
---

Fix newsletter typo
9 changes: 9 additions & 0 deletions packages/pliny/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# pliny

## 0.1.0-beta.7

### Patch Changes

- 33d15e3: Remove next/dynamic from search component
Remove redundant context components
load kbar data in advance and refactor code
- 7f71035: Fix newsletter typo

## 0.1.0-beta.6

### Patch Changes
Expand Down
5 changes: 4 additions & 1 deletion packages/pliny/add-use-client.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import globby from 'globby'
'comments/Disqus.js',
'comments/Giscus.js',
'comments/Utterances.js',
'search/*.js',
'search/Algolia.js',
'search/KBar.js',
'search/KBarModal.js',
'search/KBarPortal.js',
'ui/NewsletterForm.js',
'ui/Pre.js',
])
Expand Down
2 changes: 1 addition & 1 deletion packages/pliny/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "pliny",
"description": "Main entry point for pliny components",
"homepage": "https://github.com/timlrx/pliny",
"version": "0.1.0-beta.6",
"version": "0.1.0-beta.7",
"type": "module",
"exports": {
"./*": "./*",
Expand Down
14 changes: 6 additions & 8 deletions packages/pliny/src/newsletter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ async function NewsletterAPIHandler(
if (response.status >= 400) {
res.status(response.status).json({ error: `There was an error subscribing to the list.` })
}
res.status(201).json({ error: '' })
res.status(201).json({ message: 'Successfully subscribed to the newsletter' })
} catch (error) {
res.status(500).json({ error: error.message || error.toString() })
}
Expand Down Expand Up @@ -89,18 +89,16 @@ async function NewsletterRouteHandler(req: NextRequest, options: NewsletterConfi
default:
return NextResponse.json({ error: `${options.provider} not supported` }, { status: 500 })
}
if (response.status == 200) {
return NextResponse.json(
{ message: 'Successfully subscribed to the newsletter' },
{ status: response.status }
)
} else if (response.status >= 400) {
if (response.status >= 400) {
return NextResponse.json(
{ error: `There was an error subscribing to the list` },
{ status: response.status }
)
}
return NextResponse.json({ error: '' }, { status: 201 })
return NextResponse.json(
{ message: 'Successfully subscribed to the newsletter' },
{ status: 201 }
)
} catch (error) {
return NextResponse.json({ error: error.message || error.toString() }, { status: 500 })
}
Expand Down
9 changes: 9 additions & 0 deletions packages/pliny/src/search/Algolia.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ export const AlgoliaSearchContext = React.createContext<AlgoliaSearchContext>(
{} as AlgoliaSearchContext
)

/**
* Command palette like search component for algolia - `ctrl-k` to open the palette.
* To toggle the modal or search from child components, use the search context:
* ```
* import { AlgoliaSearchContext } from 'pliny/search/algolia'
* const { query } = useContext(AlgoliaSearchContext)
* ```
*
*/
export const AlgoliaSearchProvider: React.FC<React.PropsWithChildren<AlgoliaSearchProps>> = (
props
) => {
Expand Down
93 changes: 74 additions & 19 deletions packages/pliny/src/search/KBar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { useState, useEffect, useCallback, FC, ReactNode } from 'react'
import { useState, useEffect, useCallback, FC, ReactNode, useMemo } from 'react'
import type { Action } from 'kbar'
import { useRouter } from 'next/navigation.js'
import { KBarModal as KBarModalType } from './KBarModal'
import { CoreContent, MDXDocument } from '../utils/contentlayer'
import { formatDate } from '../utils/formatDate'

export interface KBarSearchProps {
searchDocumentsPath: string
Expand All @@ -15,13 +17,41 @@ export interface KBarConfig {

let KBarModal: typeof KBarModalType | null = null

/**
* Command palette like search component with kbar - `ctrl-k` to open the palette.
* To toggle the modal or search from child components, use the search context:
* ```
* import { useKBar } from 'kbar'
* const { query } = useKBar()
* ```
* See https://github.com/timc1/kbar/blob/main/src/types.ts#L98-L106 for typings.
*
* @param {*} { kbarConfig, children }
* @return {*}
*/
export const KBarSearchProvider: FC<{
children: ReactNode
kbarConfig: KBarSearchProps
}> = ({ kbarConfig, children }) => {
const router = useRouter()
const { searchDocumentsPath, defaultActions } = kbarConfig
const [loaded, setLoaded] = useState(false)
const [searchActions, setSearchActions] = useState<Action[]>([])
const [modalLoaded, setModalLoaded] = useState(false)
const [dataLoaded, setDataLoaded] = useState(false)

const startingActions = useMemo(() => {
return Array.isArray(defaultActions)
? defaultActions
: [
{
id: 'homepage',
name: 'Homepage',
keywords: '',
section: 'Home',
perform: () => router.push('/'),
},
]
}, [defaultActions, router])

const importDocSearchModalIfNeeded = useCallback(() => {
if (KBarModal) {
Expand All @@ -37,34 +67,59 @@ export const KBarSearchProvider: FC<{
if (event.ctrlKey && event.key === 'k') {
event.preventDefault()
importDocSearchModalIfNeeded().then(() => {
setLoaded(true)
setModalLoaded(true)
window.removeEventListener('keydown', handleKeyDown)
})
}
}
if (!loaded) window.addEventListener('keydown', handleKeyDown)
const mapPosts = (posts: CoreContent<MDXDocument>[]) => {
const actions: Action[] = []
for (const post of posts) {
actions.push({
id: post.path,
name: post.title,
keywords: post?.summary || '',
section: 'Content',
subtitle: formatDate(post.date, 'en-US'),
perform: () => router.push('/' + post.path),
})
}
return actions
}
async function fetchData() {
const res = await fetch(searchDocumentsPath)
const json = await res.json()
const actions = mapPosts(json)
setSearchActions(actions)
setDataLoaded(true)
}
if (!modalLoaded) {
window.addEventListener('keydown', handleKeyDown)
}
if (!dataLoaded) {
fetchData()
}
return () => {
/*removes event listener on cleanup*/
window.removeEventListener('keydown', handleKeyDown)
}
}, [importDocSearchModalIfNeeded, loaded])

const startingActions: Action[] = Array.isArray(defaultActions)
? defaultActions
: [
{
id: 'homepage',
name: 'Homepage',
keywords: '',
section: 'Home',
perform: () => router.push('/'),
},
]
}, [
importDocSearchModalIfNeeded,
modalLoaded,
dataLoaded,
startingActions,
router,
searchDocumentsPath,
])

return (
<>
{loaded && KBarModal ? (
<KBarModal startingActions={startingActions} searchDocumentsPath={searchDocumentsPath}>
{modalLoaded && KBarModal ? (
<KBarModal
actions={searchActions}
searchDocumentsPath={searchDocumentsPath}
isLoading={!dataLoaded}
>
{children}
</KBarModal>
) : (
Expand Down
9 changes: 5 additions & 4 deletions packages/pliny/src/search/KBarModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import { Portal } from './KBarPortal'

export const KBarModal: FC<{
children: ReactNode
startingActions: Action[]
actions: Action[]
searchDocumentsPath: string
}> = ({ startingActions, searchDocumentsPath, children }) => {
isLoading: boolean
}> = ({ actions, children, isLoading }) => {
return (
<KBarProvider actions={startingActions}>
<Portal searchDocumentsPath={searchDocumentsPath} />
<KBarProvider actions={actions}>
<Portal isLoading={isLoading} />
{children}
</KBarProvider>
)
Expand Down
59 changes: 11 additions & 48 deletions packages/pliny/src/search/KBarPortal.tsx
Original file line number Diff line number Diff line change
@@ -1,61 +1,27 @@
import React, { useState, useEffect } from 'react'
import { useRouter } from 'next/navigation.js'
import { CoreContent, MDXDocument } from '../utils/contentlayer'
import { formatDate } from '../utils/formatDate'
import { useEffect } from 'react'

import {
KBarPortal,
KBarSearch,
KBarAnimator,
KBarPositioner,
KBarResults,
useMatches,
useRegisterActions,
useKBar,
Action,
ActionImpl,
} from 'kbar'

let init = false

export const Portal = ({ searchDocumentsPath }: { searchDocumentsPath: string }) => {
const [searchActions, setSearchActions] = useState([])
export const Portal = ({ isLoading }: { isLoading: boolean }) => {
const { query } = useKBar()
const router = useRouter()

// Display on load as we already wait for crtl+k event to load it
useEffect(() => {
if (!init) {
init = true
query.toggle()
}
}, [])

useEffect(() => {
const mapPosts = (posts: CoreContent<MDXDocument>[]) => {
const actions: Action[] = []
for (const post of posts) {
actions.push({
id: post.path,
name: post.title,
keywords: post?.summary || '',
section: 'Content',
subtitle: formatDate(post.date, 'en-US'),
perform: () => router.push('/' + post.path),
})
}
return actions
}

async function fetchData() {
const res = await fetch(searchDocumentsPath)
const json = await res.json()
const actions = mapPosts(json)
setSearchActions(actions)
}
fetchData()
}, [searchDocumentsPath])

useRegisterActions(searchActions, [searchActions])
}, [query])

return (
<KBarPortal>
Expand Down Expand Up @@ -84,22 +50,19 @@ export const Portal = ({ searchDocumentsPath }: { searchDocumentsPath: string })
ESC
</span>
</div>
<RenderResults />
{!isLoading && <RenderResults />}
{isLoading && (
<div className="block border-t border-gray-100 px-4 py-8 text-center text-gray-400 dark:border-gray-800 dark:text-gray-600">
Loading...
</div>
)}
</div>
</KBarAnimator>
</KBarPositioner>
</KBarPortal>
)
}

interface RenderParams<T = ActionImpl | string> {
item: T
active: boolean
}

// The default Kbar results component has some issues with preact.
// https://github.com/timc1/kbar/issues/208
// Using custom, non-virtualized implementation in the meantime.
const RenderResults = () => {
const { results } = useMatches()

Expand All @@ -111,7 +74,7 @@ const RenderResults = () => {
<div>
{typeof item === 'string' ? (
<div className="pt-3">
<div className="text-primary-600 block border-t border-gray-100 px-4 pt-6 pb-2 text-xs font-semibold uppercase dark:border-gray-800">
<div className="block border-t border-gray-100 px-4 pb-2 pt-6 text-xs font-semibold uppercase text-primary-600 dark:border-gray-800">
{item}
</div>
</div>
Expand Down
Loading

0 comments on commit f6ba3d8

Please sign in to comment.