Skip to content

Commit

Permalink
feat: added Suspense skeletons for news page
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbrusegard committed Jan 26, 2024
1 parent e5a61a9 commit 5f62df8
Show file tree
Hide file tree
Showing 13 changed files with 214 additions and 38 deletions.
9 changes: 9 additions & 0 deletions src/app/[locale]/(dashboard)/news/[article]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function generateMetadata() {
return {
title: 'Test',
};
}

export default function Article() {
return null;
}
33 changes: 9 additions & 24 deletions src/app/[locale]/(dashboard)/news/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { useTranslations } from 'next-intl';
import { getTranslations, unstable_setRequestLocale } from 'next-intl/server';

import { Link } from '@/lib/navigation';
import { cx } from '@/lib/utils';

import { NewsCard } from '@/components/news/NewsCard';
import { NewsItemGrid } from '@/components/news/NewsItemGrid';
import { NewsCardGridSuspense } from '@/components/news/NewsCardGridSuspense';
import { NewsItemGridSuspense } from '@/components/news/NewsItemGridSuspense';
import { Button } from '@/components/ui/Button';
import { Separator } from '@/components/ui/Separator';

Expand Down Expand Up @@ -205,28 +204,14 @@ export default function News({
</Link>
</Button>
</div>
<div className='grid h-192 grid-rows-4 gap-4 xs:h-96 xs:grid-cols-3 xs:grid-rows-2 md:grid-cols-4 lg:h-112'>
{mockData.slice(0, 4).map((data, index) => (
<NewsCard
className={cx(
index === 0 && 'row-span-1 xs:col-span-2 md:row-span-2',
index === 1 && 'col-span-1 row-span-1 md:col-span-2',
index === 3 && 'row-span-1 xs:col-span-2 md:col-span-1',
)}
key={data.id}
id={data.id}
internal={data.internal}
title={data.title}
date={data.date}
photoUrl={data.photoUrl}
t={{
internalArticle: t('internalArticle'),
}}
/>
))}
</div>
<NewsCardGridSuspense
newsData={mockData}
t={{
internalArticle: t('internalArticle'),
}}
/>
<Separator className='my-6' />
<NewsItemGrid
<NewsItemGridSuspense
newsData={mockData}
t={{
morePages: useTranslations('ui')('morePages'),
Expand Down
58 changes: 58 additions & 0 deletions src/components/layout/PaginationCarouselSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationNext,
PaginationPrevious,
} from '@/components/ui/Pagination';

type PaginationCarouselSkeletonProps = {
className?: string;
t: {
goToPreviousPage: string;
previous: string;
morePages: string;
goToNextPage: string;
next: string;
};
};

function PaginationCarouselSkeleton({
className,
t,
}: PaginationCarouselSkeletonProps) {
return (
<Pagination className={className}>
<PaginationContent>
<PaginationItem>
<PaginationPrevious
className='cursor-not-allowed opacity-50 hover:bg-transparent'
href='#'
goToPreviousPage={t.goToPreviousPage}
previous={t.previous}
aria-disabled={true}
tabIndex={-1}
/>
</PaginationItem>
{Array.from({ length: 4 }).map((_, index) => (
<PaginationItem className='cursor-not-allowed opacity-50' key={index}>
<PaginationEllipsis morePages='' />
</PaginationItem>
))}
<PaginationItem>
<PaginationNext
className='cursor-not-allowed opacity-50 hover:bg-transparent'
href='#'
goToNextPage={t.goToNextPage}
next={t.next}
aria-disabled={true}
tabIndex={-1}
/>
</PaginationItem>
</PaginationContent>
</Pagination>
);
}

export { PaginationCarouselSkeleton };
4 changes: 2 additions & 2 deletions src/components/news/NewsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ function NewsCard({
>
<Link
href={{
pathname: '/news/[articleId]',
params: { articleId: id },
pathname: '/news/[article]',
params: { article: id },
}}
>
<Card className='relative flex h-full min-h-32 w-full overflow-hidden'>
Expand Down
43 changes: 43 additions & 0 deletions src/components/news/NewsCardGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { cx } from '@/lib/utils';

import { NewsCard } from '@/components/news/NewsCard';

type NewsCardGridProps = {
newsData: {
id: number;
internal: boolean;
title: string;
date: string;
photoUrl: string;
}[];
t: {
internalArticle: string;
};
};

function NewsCardGrid({ newsData, t }: NewsCardGridProps) {
return (
<div className='grid h-192 grid-rows-4 gap-4 xs:h-96 xs:grid-cols-3 xs:grid-rows-2 md:grid-cols-4 lg:h-112'>
{newsData.slice(0, 4).map((data, index) => (
<NewsCard
className={cx(
index === 0 && 'row-span-1 xs:col-span-2 md:row-span-2',
index === 1 && 'col-span-1 row-span-1 md:col-span-2',
index === 3 && 'row-span-1 xs:col-span-2 md:col-span-1',
)}
key={data.id}
id={data.id}
internal={data.internal}
title={data.title}
date={data.date}
photoUrl={data.photoUrl}
t={{
internalArticle: t.internalArticle,
}}
/>
))}
</div>
);
}

export { NewsCardGrid, type NewsCardGridProps };
35 changes: 35 additions & 0 deletions src/components/news/NewsCardGridSuspense.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import * as React from 'react';

import { cx } from '@/lib/utils';

import {
NewsCardGrid,
type NewsCardGridProps,
} from '@/components/news/NewsCardGrid';
import { Skeleton } from '@/components/ui/Skeleton';

function NewsCardGridSuspense({ ...props }: NewsCardGridProps) {
return (
<React.Suspense
fallback={
<div className='grid h-192 grid-rows-4 gap-4 xs:h-96 xs:grid-cols-3 xs:grid-rows-2 md:grid-cols-4 lg:h-112'>
{Array.from({ length: 4 }).map((_, index) => (
<Skeleton
className={cx(
'h-full w-full',
index === 0 && 'row-span-1 xs:col-span-2 md:row-span-2',
index === 1 && 'col-span-1 row-span-1 md:col-span-2',
index === 3 && 'row-span-1 xs:col-span-2 md:col-span-1',
)}
key={index}
/>
))}
</div>
}
>
<NewsCardGrid {...props} />
</React.Suspense>
);
}

export { NewsCardGridSuspense };
4 changes: 2 additions & 2 deletions src/components/news/NewsItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ function NewsItem({
>
<Link
href={{
pathname: '/news/[articleId]',
params: { articleId: id },
pathname: '/news/[article]',
params: { article: id },
}}
>
<div className='flex gap-4 overflow-hidden rounded-lg transition-colors group-hover:bg-accent group-hover:dark:bg-card'>
Expand Down
2 changes: 1 addition & 1 deletion src/components/news/NewsItemGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,4 @@ function NewsItemGrid({ newsData, t }: NewsItemGridProps) {
);
}

export { NewsItemGrid };
export { NewsItemGrid, type NewsItemGridProps };
29 changes: 29 additions & 0 deletions src/components/news/NewsItemGridSuspense.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as React from 'react';

import { PaginationCarouselSkeleton } from '@/components/layout/PaginationCarouselSkeleton';
import {
NewsItemGrid,
type NewsItemGridProps,
} from '@/components/news/NewsItemGrid';
import { NewsItemSkeleton } from '@/components/news/NewsItemSkeleton';

function NewsItemGridSuspense({ ...props }: NewsItemGridProps) {
return (
<React.Suspense
fallback={
<>
<div className='grid min-h-[752px] grid-cols-1 gap-4 sm:min-h-[368px] sm:grid-cols-2 lg:min-h-[240px] lg:grid-cols-3'>
{Array.from({ length: 6 }).map((_, index) => (
<NewsItemSkeleton key={index} />
))}
</div>
<PaginationCarouselSkeleton className='my-6' t={props.t} />
</>
}
>
<NewsItemGrid {...props} />
</React.Suspense>
);
}

export { NewsItemGridSuspense };
17 changes: 17 additions & 0 deletions src/components/news/NewsItemSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Skeleton } from '@/components/ui/Skeleton';

function NewsItemSkeleton() {
return (
<div className='flex gap-4 overflow-hidden rounded-lg'>
<div className='relative h-28 w-28 flex-shrink-0'>
<Skeleton className='h-full w-full rounded-lg object-cover object-center' />
</div>
<div className='w-full py-2 pr-1'>
<Skeleton className='h-[18px] w-5/6 py-[5px]' />
<Skeleton className='h-[12px] w-2/3 py-[2px] sm:h-[14px] sm:py-[3px] [&:not(:first-child)]:mt-2' />
</div>
</div>
);
}

export { NewsItemSkeleton };
4 changes: 2 additions & 2 deletions src/design/Field.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Eye, EyeOff } from 'lucide-react';
import React, { useState } from 'react';
import * as React from 'react';

import { cx } from '@/lib/utils';

Expand Down Expand Up @@ -57,7 +57,7 @@ const Field: React.FC<FieldProps> = ({
id,
onClick,
}) => {
const [showPassword, setShowPassword] = useState(false);
const [showPassword, setShowPassword] = React.useState(false);

const _onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
if (onChange) {
Expand Down
8 changes: 4 additions & 4 deletions src/design/TypeWriter.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react';
import * as React from 'react';

// TypeWriter Interface
interface TypeWriterProps {
Expand All @@ -9,10 +9,10 @@ interface TypeWriterProps {

// TypeWriter Function: Renders text as if it is being written out.
const TypeWriter: React.FC<TypeWriterProps> = ({ className, text, delay }) => {
const [currentText, setCurrentText] = useState('');
const [currentIndex, setCurrentIndex] = useState(0);
const [currentText, setCurrentText] = React.useState('');
const [currentIndex, setCurrentIndex] = React.useState(0);

useEffect(() => {
React.useEffect(() => {
if (currentIndex < text.length) {
const timeout = setTimeout(() => {
setCurrentText((prevText) => prevText + text[currentIndex]);
Expand Down
6 changes: 3 additions & 3 deletions src/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ const pathnames = {
en: '/news/new',
no: '/nyheter/ny',
},
'/news/[articleId]': {
en: '/news/[articleId]',
no: '/nyheter/[articleId]',
'/news/[article]': {
en: '/news/[article]',
no: '/nyheter/[article]',
},
'/about': {
en: '/about',
Expand Down

0 comments on commit 5f62df8

Please sign in to comment.