Skip to content

Commit

Permalink
PBI 2716 & 2758 Improve Testimonials Section on Home Page (#2756)
Browse files Browse the repository at this point in the history
* Setup Marquee component from Magic UI

* Implement Marquee into testimonials block

* Fix testimony card height

* add src as tailwind config folder

* changed testimonial card css

* update line clamp style

* Adjust the layout of Testimonials

* Keep the functionality of Testimonials unchanged

* fix the error in tailwind.config.js

* Updated some styles to make the gradient effect more natural

* Resolved the issues related to PBI2758 and optimized the corresponding component

* Update the comments

* Optimized the synchronization function

* Optimized the synchronization function

* Optimized the synchronization function

---------

Co-authored-by: Tino Liu [SSW] <[email protected]>
  • Loading branch information
ZenoWang1999 and tino-liu authored Jan 21, 2025
1 parent e743489 commit 1bc1c9b
Show file tree
Hide file tree
Showing 12 changed files with 579 additions and 262 deletions.
10 changes: 2 additions & 8 deletions app/docs/[...slug]/DocsPagesClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ import { TinaMarkdown } from 'tinacms/dist/rich-text';
import { useTocListener } from 'components/AppRouterMigrationComponents/Docs/toc_helper';

export default function DocsClient(props) {

const { PageTableOfContents, NavigationDocsData } = props.props;
const DocumentationData = props.tinaProps.data.doc;

const allData = [DocumentationData, PageTableOfContents, NavigationDocsData];

const allData = [DocumentationData, PageTableOfContents, NavigationDocsData];

const isScreenSmallerThan1200 = screenResizer().isScreenSmallerThan1200;
const isScreenSmallerThan840 = screenResizer().isScreenSmallerThan840;
Expand All @@ -32,8 +30,6 @@ export default function DocsClient(props) {
title: DocumentationData?.next?.title,
};



const lastEdited = DocumentationData?.last_edited;
const date = lastEdited === null ? null : new Date(lastEdited);
const formattedDate = date
Expand All @@ -49,9 +45,7 @@ export default function DocsClient(props) {
? 'grid-cols-[1.25fr_3fr]'
: 'grid-cols-[1.25fr_3fr_0.75fr]';



return (
return (
<div className="relative my-6 lg:my-16 flex justify-center items-start">
<div className={`lg:px-16 px-3 w-full max-w-[2000px] grid ${gridClass}`}>
{/* LEFT COLUMN */}
Expand Down
21 changes: 21 additions & 0 deletions components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "styles/tailwind.css",
"baseColor": "zinc",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}
192 changes: 103 additions & 89 deletions components/AppRouterMigrationComponents/Docs/toc/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
'use client';

import { useState, useEffect } from 'react';
import { useState, useEffect, useRef } from 'react';
import ReactMarkdown from 'react-markdown';
import styled, { css } from 'styled-components';
import RightArrowSvg from 'public/svg/right-arrow.svg';
import { getDocId } from 'utils/docs/getDocIds';

interface TocProps {
tocItems: Array<{ type: string; text: string }>;
activeIds: string[];
}

export const generateMarkdown = (tocItems: Array<{ type: string; text: string }>) => {
export const generateMarkdown = (
tocItems: Array<{ type: string; text: string }>
) => {
return tocItems
.map((item) => {
const anchor = getDocId(item.text);
Expand All @@ -23,55 +24,118 @@ export const generateMarkdown = (tocItems: Array<{ type: string; text: string }>

const ToC = ({ tocItems, activeIds }: TocProps) => {
const [isOpen, setIsOpen] = useState(false);
const tocWrapperRef = useRef<HTMLDivElement>(null);

useEffect(() => {
const close = () => setIsOpen(false);
const allLinks = document.querySelectorAll('a');
allLinks.forEach((a) => a.addEventListener('click', close));
return () => allLinks.forEach((a) => a.removeEventListener('click', close));

return () => {
allLinks.forEach((a) => a.removeEventListener('click', close));
};
}, []);

useEffect(() => {
if (tocWrapperRef.current && activeIds.length > 0) {
const tocList = tocWrapperRef.current;

const lastActiveId = activeIds[activeIds.length - 1];
const activeLink = tocList.querySelector(`a[href="#${lastActiveId}"]`);

if (activeLink) {
const activeTop = (activeLink as HTMLElement).offsetTop;
const activeHeight = (activeLink as HTMLElement).offsetHeight;
const listHeight = tocList.clientHeight;

tocList.scrollTo({
top: activeTop - listHeight / 2 + activeHeight / 2,
behavior: 'smooth',
});
}
}
}, [activeIds]);

if (!tocItems || tocItems.length === 0) {
return null;
}

const tocMarkdown = generateMarkdown(tocItems);



return (
<TocWrapper>
<TocContent activeIds={activeIds} isOpen={isOpen}>
<TocDesktopHeader>Table of Contents</TocDesktopHeader>
<ReactMarkdown
components={{
li: ({ children }) => (
<li className="hover:text-orange-500 transition-colors">{children}</li>
),
a: ({ children, ...props }) => {
const isActive = activeIds.includes(props.href?.slice(1)); // Match href with activeIds
return (
<a
{...props}
className={`${
isActive ? 'text-orange-500 font-bold no-underline' : 'hover:text-orange-500 underline transition-colors'
}`}
>
{children}
</a>
);
},
}}
>
{tocMarkdown}
</ReactMarkdown>
</TocContent>
</TocWrapper>
<>
<TocWrapper>
<TocContent activeIds={activeIds} isOpen={isOpen}>
<TocDesktopHeader>Table of Contents</TocDesktopHeader>
<TocTitleList
ref={tocWrapperRef}
className="max-h-[70vh] 2xl:max-h-[75vh] p-4 overflow-y-auto"
>
<ReactMarkdown
components={{
ul: ({ children }) => (
<ul className="space-y-1 pt-1">{children}</ul>
),
li: ({ children }) => (
<li className="leading-relaxed">{children}</li>
),
a: ({ children, ...props }) => {
const isActive = activeIds.includes(props.href?.slice(1)); // Match href with activeIds
return (
<a
{...props}
className={`
block py-1 px-2 rounded-md hover:bg-gray-50/75 transition-colors duration-150
${
isActive
? 'text-orange-500 font-medium no-underline'
: 'text-gray-600 hover:text-orange-500'
}`}
>
{children}
</a>
);
},
}}
>
{tocMarkdown}
</ReactMarkdown>
</TocTitleList>
</TocContent>
</TocWrapper>
</>
);
};

export default ToC;

const TocTitleList = styled.div<{ ref: React.RefObject<HTMLDivElement> }>`
scrollbar-width: none;
::-webkit-scrollbar {
display: none;
}
-ms-overflow-style: none;
word-wrap: break-word;
white-space: normal;
overflow-wrap: break-word;
-webkit-mask-image: linear-gradient(
to bottom,
transparent,
black 5%,
black 95%,
transparent
);
mask-image: linear-gradient(
to bottom,
transparent,
black 5%,
black 95%,
transparent
);
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
`;
const TocDesktopHeader = styled.span`
display: none;
font-size: 1rem;
Expand All @@ -89,67 +153,17 @@ const TocDesktopHeader = styled.span`
const TocWrapper = styled.div`
margin-bottom: -0.375rem;
flex: 0 0 auto;
width: 300px; /* fix width */
word-wrap: break-word; /* break the long word */
white-space: normal;
overflow-wrap: break-word; /* suppport Chrome */
@media (min-width: 1200px) {
position: sticky;
top: 8rem;
}
`;

const TocButton = styled.button<{ isOpen: boolean }>`
display: block;
padding: 0;
outline: none;
border: none;
color: var(--color-secondary);
opacity: 0.65;
background: transparent;
cursor: pointer;
transition: opacity 185ms ease-out;
display: flex;
align-items: center;
line-height: 1;
margin-bottom: 1.125rem;
span {
margin-right: 0.5rem;
}
svg {
position: relative;
width: 1.25rem;
height: auto;
fill: var(--color-grey);
transform-origin: 50% 50%;
transition: opacity 180ms ease-out, transform 180ms ease-out;
opacity: 0.5;
}
:hover,
:focus {
opacity: 1;
svg {
opacity: 1;
}
}
${(props) =>
props.isOpen &&
css`
color: var(--color-orange);
svg {
transform: rotate(90deg);
opacity: 1;
}
`}
@media (min-width: 1200px) {
display: none;
}
`;

const TocContent = styled.div<{ isOpen: boolean; activeIds: string[] }>`
display: block;
width: 100%;
Expand All @@ -176,14 +190,14 @@ const TocContent = styled.div<{ isOpen: boolean; activeIds: string[] }>`
margin: 0;
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
li {
margin: 0;
padding: 0.375rem 0;
}
ul ul {
padding-left: 0.75rem;
Expand Down
1 change: 0 additions & 1 deletion components/AppRouterMigrationComponents/Docs/toc_helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ export function useTocListener(data: any) {

React.useEffect(() => {
if (!contentRef.current) return;

const tocListener = createTocListener(contentRef, setActiveIds);
const handleScroll = () => tocListener(); // Define scroll handler

Expand Down
Loading

0 comments on commit 1bc1c9b

Please sign in to comment.