-
-
Notifications
You must be signed in to change notification settings - Fork 225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Web release 3 #655
Web release 3 #655
Changes from all commits
7c5c331
3c3c5f6
46a922b
ee6bfdf
023a3c0
8cb617e
8a32db3
3647457
2cda0bc
f45b548
a22a799
abbcc0a
fb98b60
3958b6d
c8599e0
373f64e
f7e6fd5
7995844
c04d577
886ee85
ee91a74
69a1eae
989ded0
290e4de
515f95c
d8ef58c
3991da0
15a1ca8
2927056
56a54d3
52c7c5a
d66d2d5
0b7946c
6caf9c0
2ad9a42
3de5ecb
71a8630
7049fc7
c400a71
f155ea9
e8dc9bc
2954b0c
a00c819
7b13f8e
c3f2a06
5c4acaa
0898f7b
3af14b5
647d52c
ae04e43
46e4dcd
1f56a4a
73aec68
b1e68ad
4a53960
0b0fb2d
6b51f02
0662ac9
c3478f4
02f07a8
dd3afee
69f2863
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import React, { useState, useEffect } from 'react'; | ||
import { useRouter } from 'next/router'; | ||
|
||
interface AccordionItem { | ||
question: string; | ||
answer: string; | ||
id: number; | ||
} | ||
|
||
interface AccordionProps { | ||
items: AccordionItem[]; | ||
} | ||
|
||
const Accordion: React.FC<AccordionProps> = ({ items }) => { | ||
const [activeIndex, setActiveIndex] = useState<number | null>(null); | ||
const router = useRouter(); | ||
|
||
const handleToggle = (index: number) => { | ||
setActiveIndex((prevIndex) => (prevIndex === index ? null : index)); | ||
}; | ||
|
||
useEffect(() => { | ||
const hash = router.asPath.split('#')[1]; | ||
if (hash) { | ||
const id = parseInt(hash, 10); | ||
const index = items.findIndex((item) => item.id === id); | ||
if (index !== -1) { | ||
setActiveIndex(index); | ||
|
||
setTimeout(() => { | ||
const element = document.getElementById(hash); | ||
if (element) { | ||
const navbarHeight = 150; | ||
const offset = element.offsetTop - navbarHeight; | ||
window.scrollTo({ top: offset, behavior: 'smooth' }); | ||
} | ||
}, 0); | ||
} | ||
} | ||
}, [items, router.asPath]); | ||
|
||
const handleLinkClick = (id: number) => { | ||
const index = items.findIndex((item) => item.id === id); | ||
setActiveIndex(index); | ||
|
||
const newUrl = `#${id}`; | ||
router.push(newUrl, undefined, { shallow: true }); | ||
}; | ||
|
||
return ( | ||
<div> | ||
{items.map((item, index) => ( | ||
<div | ||
key={item.id || index} | ||
className={`overflow-hidden transition-max-height border-t-2 ${ | ||
activeIndex === index ? 'max-h-96' : 'max-h-20' | ||
} ${index === items.length - 1 ? 'border-b-2' : ''}`} | ||
> | ||
<div className='flex justify-between p-4 pl-2 cursor-pointer'> | ||
<div className='text-[20px]'> | ||
<a | ||
href={`#${item.id}`} | ||
onClick={(e) => { | ||
e.preventDefault(); | ||
handleLinkClick(item.id); | ||
}} | ||
> | ||
{item.question} | ||
</a> | ||
</div> | ||
<div | ||
className={`transform transition-transform duration-200 max-h-7 text-[20px] ${ | ||
activeIndex === index ? 'rotate-45' : '' | ||
}`} | ||
onClick={() => handleToggle(index)} | ||
> | ||
+ | ||
</div> | ||
</div> | ||
{activeIndex === index && ( | ||
<div | ||
id={`${item.id}`} | ||
className='p-2 text-gray-500 dark:text-slate-200 pb-4' | ||
> | ||
{item.answer} | ||
</div> | ||
)} | ||
</div> | ||
))} | ||
</div> | ||
); | ||
}; | ||
|
||
export default Accordion; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import React from 'react'; | ||
import Link from 'next/link'; | ||
import TextTruncate from 'react-text-truncate'; | ||
interface CardProps { | ||
title: string; | ||
body: string; | ||
icon?: string; | ||
link?: string; | ||
image?: string; | ||
extended?: boolean; | ||
headerSize?: 'small' | 'medium' | 'large'; | ||
bodyTextSize?: 'small' | 'medium' | 'large'; | ||
} | ||
|
||
const CardBody = ({ | ||
title, | ||
body, | ||
icon, | ||
link, | ||
image, | ||
extended, | ||
headerSize, | ||
bodyTextSize, | ||
}: CardProps) => { | ||
const headerSizeClasses: Record<string, string> = { | ||
small: 'text-[0.9rem]', | ||
medium: 'text-[1.3rem]', | ||
large: 'text-[2rem]', | ||
}; | ||
const bodyTextSizeClasses: Record<string, string> = { | ||
small: 'text-[0.85rem]', | ||
medium: 'text-[1rem]', | ||
large: 'text-[1.5rem]', | ||
}; | ||
return ( | ||
<div className='group relative h-full w-full rounded-lg border border-gray-200 bg-white p-6 px-12 shadow-3xl dark:shadow-2xl dark:shadow-slate-900 transition-colors ease-in-out hover:bg-slate-100 dark:bg-slate-800 hover:dark:bg-slate-900/30'> | ||
<div className='flex justify-center '> | ||
{image && <img src={image} className='h-32 p-2' />} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it is better to use Next.js prebuilt https://nextjs.org/learn-pages-router/seo/improve/images |
||
</div> | ||
<div className='flex flex-row items-start mb-6'> | ||
{icon && ( | ||
<span className='mr-6 flex h-14 w-14 flex-shrink-0 items-center justify-center rounded-lg border bg-blue-200 px-3 text-gray-900 dark:text-white'> | ||
<img src={icon} alt={title} className='h-full w-full' /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Better to use Next.js prebuilt Image Component. |
||
</span> | ||
)} | ||
<p | ||
className={`mb-1 mt-1 items-center font-bold text-gray-900 dark:text-white ${headerSizeClasses[headerSize || 'medium']}`} | ||
> | ||
{title} | ||
</p> | ||
</div> | ||
<hr className='mb-4 mt-3.5 h-px border-0 bg-gray-400' /> | ||
<p | ||
className={`mb-8 text-black mt-5 dark:text-white ${bodyTextSizeClasses[bodyTextSize || 'medium']} `} | ||
> | ||
{extended && <span dangerouslySetInnerHTML={{ __html: body }} />} | ||
{!extended && <TextTruncate element='span' line={3} text={body} />} | ||
</p> | ||
{link && ( | ||
<p className='absolute bottom-3 right-5 font-medium opacity-0 transition-opacity delay-150 ease-in-out group-hover:opacity-100 text-black dark:text-white '> | ||
Read More | ||
</p> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
const Card: React.FC<CardProps> = ({ | ||
title, | ||
body, | ||
icon, | ||
link, | ||
image, | ||
extended, | ||
headerSize, | ||
bodyTextSize, | ||
}) => { | ||
return ( | ||
<> | ||
{link ? ( | ||
<Link href={link}> | ||
<CardBody | ||
{...{ | ||
title, | ||
body, | ||
icon, | ||
link, | ||
image, | ||
extended, | ||
headerSize, | ||
bodyTextSize, | ||
}} | ||
/> | ||
</Link> | ||
) : ( | ||
<CardBody | ||
{...{ | ||
title, | ||
body, | ||
icon, | ||
link, | ||
image, | ||
extended, | ||
headerSize, | ||
bodyTextSize, | ||
}} | ||
/> | ||
)} | ||
</> | ||
); | ||
}; | ||
|
||
export default Card; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import React from 'react'; | ||
import faqData from '../data/faq.json'; | ||
import Accordion from '~/components/Accordion'; | ||
|
||
export default function Faq({ category }: { category: string }) { | ||
const filteredFAQs = faqData.filter((item) => item.category === category); | ||
|
||
return ( | ||
<section> | ||
<div className='max-w-screen-md mx-auto p-8 px-0 ml-0'> | ||
<h2 className='text-2xl font-bold text-[24px] mb-4'> | ||
{category.toUpperCase()} | ||
</h2> | ||
<Accordion items={filteredFAQs} /> | ||
</div> | ||
</section> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
[ | ||
{ | ||
"title": "How JSON Schema Was an Obvious Choice at GitHub", | ||
"summary": "At GitHub's Docs Engineering team, while shipping releases to production 20 times per day or more, JSON Schema is critical in increasing confidence in changes to data, content and APIs.", | ||
"logo": "/img/logos/github-logo.png", | ||
"links": { | ||
"lang": "URL1", | ||
"url": "/blog/posts/github-case-study" | ||
} | ||
}, | ||
{ | ||
"title": "How 6 River Systems saves time and boosts collaboration with JSON Schema", | ||
"summary": "Explore the powerful impact of JSON Schema on 6 River Systems' fulfillment operations. Discover how they enabled enhanced collaboration, time savings, and data quality assurance, propelling their successful scaling journey.", | ||
"logo": "/img/logos/6river-logo.svg", | ||
"links": { | ||
"lang": "URL1", | ||
"url": "/blog/posts/6-river-systems-case-study" | ||
} | ||
}, | ||
{ | ||
"title": "Transforming the technical recruiting industry with JSON Schema", | ||
"summary": "Learn how Manfred used JSON Schema to transform the technical recruiting industry.", | ||
"logo": "/img/logos/manfred-color.svg", | ||
"links": { | ||
"lang": "URL1", | ||
"url": "/blog/posts/manfred-case-study" | ||
} | ||
}, | ||
{ | ||
"title": "How Postman uses JSON Schema", | ||
"summary": "Learn how JSON Schema continues to be a crucial component of the Postman API Platform and the API ecosystem.", | ||
"logo": "/img/logos/sponsors/postman_logo-orange.svg", | ||
"links": { | ||
"lang": "URL1", | ||
"url": "/blog/posts/postman-case-study" | ||
} | ||
}, | ||
{ | ||
"title": "Using JSON Schema at Remote to scale forms and data validations", | ||
"summary": "Using JSON Schema at Remote was the first step to solving data validation and form generation problems across all levels at Remote.", | ||
"logo": "/img/logos/remote-logo.png", | ||
"links": { | ||
"lang": "URL1", | ||
"url": "/blog/posts/remote-case-study" | ||
} | ||
}, | ||
{ | ||
"title": "How Tyler Technologies reduced its client feedback loop with JSON Schema", | ||
"summary": "Using JSON Schema at Tyler Technologies meant showing added value to clients could take minutes rather than days or in some cases weeks.", | ||
"logo": "/img/logos/tyler-tech-logo.svg", | ||
"links": { | ||
"lang": "URL1", | ||
"url": "/blog/posts/tyler-technologies-case-study" | ||
} | ||
}, | ||
{ | ||
"title": "How the W3C Web of Things brings JSON Schema to the Internet of Things", | ||
"summary": "Using JSON Schema at the W3C Web of Things to create an interoperability layer so that different IoT platforms, protocols and standards can operate together.", | ||
"logo": "/img/logos/wot-logo.png", | ||
"links": { | ||
"lang": "URL1", | ||
"url": "/blog/posts/w3c-wot-case-study" | ||
} | ||
} | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cards are the Call to Action in many cases. Having "read more" hidden until hover is not good. Users need to know it's clickable.
In many cases, we want to make the CTA more prominent, such as on the case studies page.
Consider a comparison with that of CNCF. Their case study CTAs are clear and strong.
We don't need to copy them with the layout, but our design should cause people to be drawn to the CTA.