0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-30 20:33:54 -05:00

refactor(console): add missing section title and adjust card layout in get-started page (#4428)

This commit is contained in:
Charles Zhao 2023-09-06 10:10:35 +08:00 committed by GitHub
parent 5e8b1bd598
commit 54321d93a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 67 additions and 28 deletions

View file

@ -0,0 +1,27 @@
import { useEffect, useLayoutEffect, useRef } from 'react';
type Callback = (event?: UIEvent) => void;
const useWindowResize = (callback: Callback) => {
const callbackRef = useRef<Callback>(callback);
useEffect(() => {
// eslint-disable-next-line @silverhand/fp/no-mutation
callbackRef.current = callback;
}, [callback]);
useLayoutEffect(() => {
const handler: Callback = (event) => {
callbackRef.current(event);
};
handler();
window.addEventListener('resize', handler);
return () => {
window.removeEventListener('resize', handler);
};
}, []);
};
export default useWindowResize;

View file

@ -1,4 +1,5 @@
import classNames from 'classnames';
import { type Ref, forwardRef } from 'react';
import { type Guide } from '@/assets/docs/guides/types';
@ -15,20 +16,16 @@ type GuideGroupProps = {
onClickGuide: (data: SelectedGuide) => void;
};
function GuideGroup({
className,
categoryName,
guides,
hasCardBorder,
isCompact,
onClickGuide,
}: GuideGroupProps) {
function GuideGroup(
{ className, categoryName, guides, hasCardBorder, isCompact, onClickGuide }: GuideGroupProps,
ref: Ref<HTMLDivElement>
) {
if (!guides?.length) {
return null;
}
return (
<div className={classNames(styles.guideGroup, className)}>
<div ref={ref} className={classNames(styles.guideGroup, className)}>
{categoryName && <label>{categoryName}</label>}
<div className={styles.grid}>
{guides.map((guide) => (
@ -45,4 +42,4 @@ function GuideGroup({
);
}
export default GuideGroup;
export default forwardRef<HTMLDivElement, GuideGroupProps>(GuideGroup);

View file

@ -1,7 +1,7 @@
import { withAppInsights } from '@logto/app-insights/react';
import { Theme, type Application } from '@logto/schemas';
import classNames from 'classnames';
import { useCallback, useContext, useMemo, useState } from 'react';
import { useCallback, useContext, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import CheckPreviewDark from '@/assets/icons/check-demo-dark.svg';
@ -19,9 +19,11 @@ import Spacer from '@/ds-components/Spacer';
import TextLink from '@/ds-components/TextLink';
import useTenantPathname from '@/hooks/use-tenant-pathname';
import useTheme from '@/hooks/use-theme';
import useWindowResize from '@/hooks/use-window-resize';
import CreateForm from '../Applications/components/CreateForm';
import GuideCard, { type SelectedGuide } from '../Applications/components/GuideCard';
import { type SelectedGuide } from '../Applications/components/GuideCard';
import GuideGroup from '../Applications/components/GuideGroup';
import useAppGuideMetadata from '../Applications/components/GuideLibrary/hook';
import FreePlanNotification from './FreePlanNotification';
@ -39,16 +41,26 @@ function GetStarted() {
const [selectedGuide, setSelectedGuide] = useState<SelectedGuide>();
const [_, getStructuredMetadata] = useAppGuideMetadata();
const [showCreateForm, setShowCreateForm] = useState<boolean>(false);
// The number of visible guide cards to show in one row per the current screen width
const [visibleCardCount, setVisibleCardCount] = useState(4);
const containerRef = useRef<HTMLDivElement>(null);
const theme = useTheme();
const { PreviewIcon, SocialIcon, RbacIcon } = icons[theme];
useWindowResize(() => {
const containerWidth = containerRef.current?.clientWidth ?? 0;
// Responsive breakpoints (1080, 680px) are defined in `GuideGroup` component SCSS,
// and we need to keep them consistent.
setVisibleCardCount(containerWidth > 1080 ? 4 : containerWidth > 680 ? 3 : 2);
});
/**
* Only need 4 featured guides at most, since by design in get-started page we need to show
* a few most popular SDK guides, and 4 makes it easy to have a 4 x 1 or 2 x 2 card layout.
* Slice the guide metadata as we only need to show 1 row of guide cards in get-started page
*/
const featuredAppGuides = useMemo(
() => getStructuredMetadata().featured.slice(0, 4),
[getStructuredMetadata]
() => getStructuredMetadata().featured.slice(0, visibleCardCount),
[visibleCardCount, getStructuredMetadata]
);
const onClickGuide = useCallback((data: SelectedGuide) => {
@ -78,10 +90,12 @@ function GetStarted() {
<FreePlanNotification />
<Card className={styles.card}>
<div className={styles.title}>{t('get_started.develop.title')}</div>
<div className={styles.grid}>
{featuredAppGuides.map((guide) => (
<GuideCard key={guide.id} hasBorder data={guide} onClick={onClickGuide} />
))}
<GuideGroup
ref={containerRef}
hasCardBorder
guides={featuredAppGuides}
onClickGuide={onClickGuide}
/>
{selectedGuide?.target !== 'API' && showCreateForm && (
<CreateForm
defaultCreateType={selectedGuide?.target}
@ -89,10 +103,10 @@ function GetStarted() {
onClose={onCloseCreateForm}
/>
)}
</div>
<TextLink to="/applications/create">{t('get_started.view_all')}</TextLink>
</Card>
<Card className={styles.card}>
<div className={styles.title}>{t('get_started.customize.title')}</div>
<div className={styles.borderBox}>
<div className={styles.rowWrapper}>
<div className={styles.icon}>
@ -134,6 +148,7 @@ function GetStarted() {
</div>
</Card>
<Card className={styles.card}>
<div className={styles.title}>{t('get_started.manage.title')}</div>
<div className={styles.borderBox}>
<div className={styles.rowWrapper}>
<div className={styles.icon}>