Skip to content

Commit

Permalink
Merge branch 'connect-more' into button-component-CSS
Browse files Browse the repository at this point in the history
  • Loading branch information
mruwnik committed Feb 13, 2024
2 parents 85664ad + f958b9f commit 6584587
Show file tree
Hide file tree
Showing 21 changed files with 268 additions and 23 deletions.
6 changes: 6 additions & 0 deletions app/assets/icons/arrow-up-right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions app/components/Article/KeepGoing/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Button from '~/components/Button'
import ListTable from '~/components/Table'
import {ArrowRight} from '~/components/icons-generated'
import useToC from '~/hooks/useToC'
import type {TOCItem} from '~/routes/questions.toc'
import type {Question} from '~/server-utils/stampy'
import './keepGoing.css'

const NextArticle = ({category, next}: {category?: string; next?: TOCItem}) =>
next && (
<>
<h2>Keep going! &#128073;</h2>
<span>Continue with the next article in {category}</span>
<div className="keepGoing-next">
<span className="keepGoing-next-title">{next.title}</span>
<Button action={`/${next.pageid}`} className="primary-alt">
Next
<ArrowRight />
</Button>
</div>
</>
)

export const KeepGoing = ({pageid, relatedQuestions}: Question) => {
const {findSection, getNext} = useToC()
const {category} = findSection(pageid) || {}
const next = getNext(pageid)
const hasRelated = relatedQuestions && relatedQuestions.length > 0

return (
<div className="keepGoing">
<NextArticle category={category} next={next} />

{next && hasRelated && <span>Or jump to a related question</span>}
{hasRelated && <ListTable elements={relatedQuestions.map((i) => ({...i, hasIcon: true}))} />}
</div>
)
}

export default KeepGoing
25 changes: 25 additions & 0 deletions app/components/Article/KeepGoing/keepGoing.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.keepGoing-next {
width: calc(99% - 32px);
position: relative;
border-radius: 6px;
background-color: var(--colors-teal-600);
display: flex;
justify-content: space-between;
padding: 32px;
margin-bottom: 56px;
}
.keepGoing span {
font-size: 18px;
}
.keepGoing-next-title {
position: relative;
font-size: 18px;
letter-spacing: -0.01em;
line-height: 170%;
font-weight: 600;
font-family: Poppins;
color: #fff;
color: #fff;
text-align: left;
display: inline-block;
}
3 changes: 3 additions & 0 deletions app/components/Article/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {useRef, useState, useEffect} from 'react'
import KeepGoing from '~/components/Article/KeepGoing'
import CopyIcon from '~/components/icons-generated/Copy'
import EditIcon from '~/components/icons-generated/Pencil'
import ThumbUpIcon from '~/components/icons-generated/ThumbUp'
Expand Down Expand Up @@ -244,6 +245,8 @@ export const Article = ({question, glossary}: ArticleProps) => {

<Contents pageid={pageid} html={text || ''} glossary={glossary || {}} />

<KeepGoing {...question} />

<ArticleFooter {...question} />
<hr />
<div className="article-tags">
Expand Down
4 changes: 3 additions & 1 deletion app/components/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ type ButtonProps = {
children?: ReactNode
className?: string
tooltip?: string
icon?: ReactNode
}
const Button = ({children, action, tooltip, className}: ButtonProps) => {
const Button = ({children, action, tooltip, icon, className}: ButtonProps) => {
const classes = ['button', className, tooltip && 'tooltip'].filter((i) => i).join(' ')
if (typeof action === 'string') {
return (
<Link to={action} className={classes} data-tooltip={tooltip}>
{children}
{icon && icon}
</Link>
)
}
Expand Down
2 changes: 1 addition & 1 deletion app/components/CategoriesNav/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const CategoriesNav = ({categories, activeCategoryId}: CategoriesNavProps
return (
<div className={styles.categoriesGroup}>
<h4>Categories</h4>
<SearchInput onChange={onSearch} />
<SearchInput onChange={onSearch} placeholderText="Filter by keyword" />
{categories
.filter((tag) => tag.name.toLowerCase().includes(search.toLowerCase()))
.map(({tagId, name, questions}) => (
Expand Down
8 changes: 6 additions & 2 deletions app/components/SearchInput/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ interface SearchInputProps {
* Custom styles
*/
expandable?: boolean
/**
* Custom placeholder
*/
placeholderText?: string
}
export const SearchInput = ({onChange, expandable}: SearchInputProps) => {
export const SearchInput = ({onChange, expandable, placeholderText}: SearchInputProps) => {
const [search, setSearch] = useState('')
const handleSearch = (search: string) => {
setSearch(search)
Expand All @@ -29,7 +33,7 @@ export const SearchInput = ({onChange, expandable}: SearchInputProps) => {
<input
type="search"
name="searchbar"
placeholder="Search articles"
placeholder={placeholderText ?? 'Search articles'}
className="search-input"
onChange={(e) => {
handleSearch(e.currentTarget.value)
Expand Down
11 changes: 9 additions & 2 deletions app/components/Table/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import {Link} from '@remix-run/react'
import {ArrowUpRight} from '~/components/icons-generated'
import './listTable.css'

export type ListItem = {
pageid: string
title: string
hasIcon?: boolean
}
export type ListTableProps = {
/**
* Browse by category
*/
elements: any[]
elements: ListItem[]
}

export const ListTable = ({elements}: ListTableProps) => (
<div className={'table-list'}>
{elements.map(({pageid, title}, i) => (
{elements.map(({pageid, title, hasIcon}, i) => (
<Link key={`entry-${i}`} className={'table-entry'} to={`/${pageid}`}>
{title}
{hasIcon && <ArrowUpRight />}
</Link>
))}
</div>
Expand Down
2 changes: 2 additions & 0 deletions app/components/Table/listTable.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
text-decoration: none;
padding: 32px;
border-bottom: 1px solid var(--colors-teal-200);
display: flex;
justify-content: space-between;
}
.table-entry:hover {
background-color: var(--colors-teal-50);
Expand Down
9 changes: 9 additions & 0 deletions app/components/icons-generated/ArrowUpRight.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type {SVGProps} from 'react'
const SvgArrowUpRight = (props: SVGProps<SVGSVGElement>) => (
<svg xmlns="http://www.w3.org/2000/svg" width={16} height={16} fill="none" {...props}>
<g stroke="#1D9089" strokeLinecap="round" strokeLinejoin="round">
<path d="M8 2.5h5.5V8M13 3 2.5 13.5" />
</g>
</svg>
)
export default SvgArrowUpRight
1 change: 1 addition & 0 deletions app/components/icons-generated/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export {default as Aisafety} from './Aisafety'
export {default as ArrowRight} from './ArrowRight'
export {default as ArrowUpRight} from './ArrowUpRight'
export {default as BottomEclipse} from './BottomEclipse'
export {default as Chatbot} from './Chatbot'
export {default as Code} from './Code'
Expand Down
4 changes: 2 additions & 2 deletions app/hooks/stateModifiers.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Question, QuestionState, RelatedQuestions, PageId} from '~/server-utils/stampy'
import {Question, QuestionState, RelatedQuestion, PageId} from '~/server-utils/stampy'

type StateEntry = [PageId, QuestionState]
type StateString = string
Expand Down Expand Up @@ -70,7 +70,7 @@ export const insertAfter = (state: StateString, pageId: PageId, to: PageId): Sta
export const insertInto = (
state: StateString,
pageid: PageId,
relatedQuestions: RelatedQuestions,
relatedQuestions: RelatedQuestion[],
options = {toggle: true}
): StateString =>
processStateEntries(state, (entries: StateEntry[]) =>
Expand Down
3 changes: 1 addition & 2 deletions app/hooks/useCachedObjects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type useCachedObjectsType = {
tags: useObjectsType<Tag[]>
toc: useObjectsType<TOCItem[]>
}
const CachedObjectsContext = createContext<useCachedObjectsType | null>(null)
export const CachedObjectsContext = createContext<useCachedObjectsType | null>(null)

const getGlossary = async () => (await fetchGlossary()).data
const getTags = async () => (await fetchTags()).tags
Expand All @@ -40,7 +40,6 @@ export const CachedObjectsProvider = ({children}: {children: ReactElement}) => {
const tags = useItemsFuncs<Tag[]>(getTags)
const toc = useItemsFuncs<TOCItem[]>(getToC)

console.log('caching')
return (
<CachedObjectsContext.Provider value={{tags, glossary, toc}}>
{children}
Expand Down
4 changes: 2 additions & 2 deletions app/hooks/useQuestionStateInUrl.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {useState, useRef, useEffect, useMemo, useCallback} from 'react'
import {useSearchParams, useNavigation} from '@remix-run/react'
import {Question, QuestionState, RelatedQuestions, PageId, Glossary} from '~/server-utils/stampy'
import {Question, QuestionState, RelatedQuestion, PageId, Glossary} from '~/server-utils/stampy'
import {fetchAllQuestionsOnSite} from '~/routes/questions.allQuestionsOnSite'
import {fetchGlossary} from '~/routes/questions.glossary'
import {
Expand Down Expand Up @@ -136,7 +136,7 @@ export default function useQuestionStateInUrl(minLogo: boolean, initialQuestions
const unshownRelatedQuestions = (
questions: Question[],
questionProps: Question
): RelatedQuestions => {
): RelatedQuestion[] => {
const {relatedQuestions} = questionProps

const onSiteQuestions = onSiteQuestionsRef.current
Expand Down
23 changes: 23 additions & 0 deletions app/hooks/useToC.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const identity = (i: any) => i

const useToC = () => {
const {items: toc} = useCachedToC()
console.log(toc)

const checkPath = (pageid: string) => (item: TOCItem) => {
if (item.pageid === pageid) return [pageid]
Expand All @@ -21,10 +22,32 @@ const useToC = () => {
return toc.map(checkPath(pageid)).filter(identity)[0]
}

const getNext = (pageid: string): TOCItem | undefined => {
type NextItem = {
current?: string
next?: TOCItem
}
const findNext = (prev: string | undefined, item: TOCItem): NextItem => {
if (pageid === prev) return {current: prev, next: item}

let previous: string | undefined = item.pageid
for (const child of item.children || []) {
const {next, current} = findNext(previous, child)
if (next) return {next, current}
previous = current
}
return {current: previous}
}

const all = {pageid: '', children: toc || []} as TOCItem
return toc && findNext('', all).next
}

return {
toc: toc || [],
findSection,
getPath,
getNext,
}
}

Expand Down
6 changes: 3 additions & 3 deletions app/routes/questions.add.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import {useState, useEffect} from 'react'
import type {ActionFunctionArgs} from '@remix-run/cloudflare'
import {Form} from '@remix-run/react'
import {redirect} from '@remix-run/cloudflare'
import {addQuestion, loadAllQuestions, fetchJsonList, RelatedQuestions} from '~/server-utils/stampy'
import {addQuestion, loadAllQuestions, fetchJsonList, RelatedQuestion} from '~/server-utils/stampy'

const getRelated = async (question: string): Promise<RelatedQuestions> => {
const getRelated = async (question: string): Promise<RelatedQuestion[]> => {
const url = `${NLP_SEARCH_ENDPOINT}/api/search?query=${question}?status=all`
try {
return await fetchJsonList(url)
Expand Down Expand Up @@ -41,7 +41,7 @@ export const action = async ({request}: ActionFunctionArgs) => {
} else {
relatedQuestions = formData
.getAll('relatedQuestion')
.map((question) => ({title: question})) as RelatedQuestions
.map((question) => ({title: question})) as RelatedQuestion[]
}

// Make sure the question is formatted as a question
Expand Down
4 changes: 3 additions & 1 deletion app/routes/tags.all.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ export const loader = async ({request, params}: Parameters<LoaderFunction>[0]) =
const {data: tags, timestamp} = await loadTags(request)

const tagId = params['*'] && params['*'].split('/')[0]
const currentTag = tagId ? tags.find(({tagId: checkedId, name}) => [checkedId.toString(), name].includes(tagId)) : tags[0]
const currentTag = tagId
? tags.find(({tagId: checkedId, name}) => [checkedId.toString(), name].includes(tagId))
: tags[0]

if (currentTag === undefined) {
throw new Response(null, {
Expand Down
4 changes: 2 additions & 2 deletions app/routes/tags.single.$tag.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {useState, useEffect, ReactNode} from 'react'
import {LoaderFunction} from '@remix-run/cloudflare'
import {reloadInBackgroundIfNeeded} from '~/server-utils/kv-cache'
import {Tag as TagType, QuestionState, RelatedQuestions, loadTag} from '~/server-utils/stampy'
import {Tag as TagType, QuestionState, RelatedQuestion, loadTag} from '~/server-utils/stampy'
import Dialog from '~/components/dialog'

type Props = {
Expand Down Expand Up @@ -47,7 +47,7 @@ export function Tag({
showCount,
}: {
name: string
questions?: RelatedQuestions
questions?: RelatedQuestion[]
showCount?: boolean
}) {
const [questions, setQuestions] = useState(tqs)
Expand Down
10 changes: 5 additions & 5 deletions app/server-utils/stampy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export enum QuestionState {
COLLAPSED = '-',
RELATED = 'r',
}
export type RelatedQuestions = {title: string; pageid: string}[]
export type RelatedQuestion = {title: string; pageid: string}
export enum QuestionStatus {
WITHDRAWN = 'Withdrawn',
SKETCH = 'Bulletpoint sketch',
Expand Down Expand Up @@ -59,15 +59,15 @@ export type Tag = {
name: string
url: string
internal: boolean
questions: RelatedQuestions
questions: RelatedQuestion[]
mainQuestion: string | null
}
export type Question = {
title: string
pageid: string
text: string | null
answerEditLink: string | null
relatedQuestions: RelatedQuestions
relatedQuestions: RelatedQuestion[]
questionState?: QuestionState
tags: string[]
banners: Banner[]
Expand All @@ -82,7 +82,7 @@ export type Question = {
export type PageId = Question['pageid']
export type NewQuestion = {
title: string
relatedQuestions: RelatedQuestions
relatedQuestions: RelatedQuestion[]
source?: string
}
type Entity = {
Expand Down Expand Up @@ -434,7 +434,7 @@ export const insertRows = async (table: string, rows: NewQuestion[]) => {
return await sendToCoda(url, payload, 'POST', `${CODA_INCOMING_TOKEN}`)
}

export const addQuestion = async (title: string, relatedQuestions: RelatedQuestions) => {
export const addQuestion = async (title: string, relatedQuestions: RelatedQuestion[]) => {
return await insertRows(INCOMING_QUESTIONS_TABLE, [{title, relatedQuestions}])
}

Expand Down
Loading

0 comments on commit 6584587

Please sign in to comment.