Create favorites section (#84)

This commit is contained in:
Szymon Kin 2022-11-17 19:32:29 +01:00 committed by GitHub
parent 89f1dcc0d0
commit d6139f2c43
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 108 additions and 35 deletions

28
package-lock.json generated
View file

@ -8648,9 +8648,9 @@
}
},
"node_modules/sharp": {
"version": "0.31.1",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.31.1.tgz",
"integrity": "sha512-GR8M1wBwOiFKLkm9JPun27OQnNRZdHfSf9VwcdZX6UrRmM1/XnOrLFTF0GAil+y/YK4E6qcM/ugxs80QirsHxg==",
"version": "0.31.2",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.31.2.tgz",
"integrity": "sha512-DUdNVEXgS5A97cTagSLIIp8dUZ/lZtk78iNVZgHdHbx1qnQR7JAHY0BnXnwwH39Iw+VKhO08CTYhIg0p98vQ5Q==",
"hasInstallScript": true,
"optional": true,
"peer": true,
@ -8659,7 +8659,7 @@
"detect-libc": "^2.0.1",
"node-addon-api": "^5.0.0",
"prebuild-install": "^7.1.1",
"semver": "^7.3.7",
"semver": "^7.3.8",
"simple-get": "^4.0.1",
"tar-fs": "^2.1.1",
"tunnel-agent": "^0.6.0"
@ -8672,9 +8672,9 @@
}
},
"node_modules/sharp/node_modules/semver": {
"version": "7.3.7",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
"version": "7.3.8",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
"optional": true,
"peer": true,
"dependencies": {
@ -16642,9 +16642,9 @@
"integrity": "sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g=="
},
"sharp": {
"version": "0.31.1",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.31.1.tgz",
"integrity": "sha512-GR8M1wBwOiFKLkm9JPun27OQnNRZdHfSf9VwcdZX6UrRmM1/XnOrLFTF0GAil+y/YK4E6qcM/ugxs80QirsHxg==",
"version": "0.31.2",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.31.2.tgz",
"integrity": "sha512-DUdNVEXgS5A97cTagSLIIp8dUZ/lZtk78iNVZgHdHbx1qnQR7JAHY0BnXnwwH39Iw+VKhO08CTYhIg0p98vQ5Q==",
"optional": true,
"peer": true,
"requires": {
@ -16652,16 +16652,16 @@
"detect-libc": "^2.0.1",
"node-addon-api": "^5.0.0",
"prebuild-install": "^7.1.1",
"semver": "^7.3.7",
"semver": "^7.3.8",
"simple-get": "^4.0.1",
"tar-fs": "^2.1.1",
"tunnel-agent": "^0.6.0"
},
"dependencies": {
"semver": {
"version": "7.3.7",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
"version": "7.3.8",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
"optional": true,
"peer": true,
"requires": {

View file

@ -14,16 +14,17 @@ const BookTile = 'a';
<BookTile
href={value.url}
class:list={['flex', 'flex-col', 'gap-3', 'transition', 'duration-300', 'hover:translate-y-2', props.class]}
class:list={['flex', 'flex-col', 'gap-3', 'transition', 'duration-300', 'hover:translate-y-2', 'w-full', props.class]}
>
<Image
class:list={['rounded-lg', 'shadow-md', 'object-cover']}
class:list={['rounded-lg', 'shadow-md', 'aspect-[3/4]', 'object-cover']}
src={value.cover}
aspectRatio="1.3"
aspectRatio={3 / 4}
width="auto"
alt={value.title}
format="webp"
/>
<div class:list={['tile-content', 'gap-1']}>
<div class:list={['tile-content', 'gap-1', 'w-full']}>
<Typography class:list={['leading-5', 'hover:text-gray-900']} variant="tile-title">
{value.title}
</Typography>

View file

@ -6,7 +6,7 @@ type Props = IconProps & Omit<TooltipProps, 'children'>;
const IconWithTooltip = ({ name, color, size, ...tooltipProps }: Props) => (
<Tooltip {...tooltipProps}>
<div>
<div className="cursor-pointer">
<Icon name={name} color={color} size={size} />
</div>
</Tooltip>

View file

@ -14,13 +14,14 @@ const MediaTile = 'a';
<MediaTile
href={value.url}
class:list={['flex', 'flex-col', 'gap-3', 'transition', 'duration-300', 'hover:translate-y-2', props.class]}
class:list={['flex', 'flex-col', 'gap-3', 'transition', 'duration-300', 'hover:translate-y-2', 'w-full', props.class]}
>
<Image
class:list={['rounded-lg', 'shadow-md', 'object-cover']}
class:list={['rounded-lg', 'shadow-md', 'aspect-square', 'object-cover']}
src={value.image}
width="auto"
aspectRatio={1 / 1}
alt={value.title}
aspectRatio="1.1"
format="webp"
/>
<div class:list={['tile-content', 'gap-1']}>

View file

@ -14,21 +14,19 @@ const PersonTile = 'a';
<PersonTile
href={value.url}
class:list={['flex', 'flex-col', 'gap-3', 'transition', 'duration-300', 'hover:translate-y-2', props.class]}
class:list={['flex', 'flex-col', 'gap-3', 'transition', 'duration-300', 'hover:translate-y-2', 'w-full', props.class]}
>
<Image
class:list={['rounded-lg', 'shadow-md', 'object-cover', 'transition', 'duration-300']}
class:list={['rounded-lg', 'shadow-md', 'transition', 'duration-300', 'aspect-square', 'object-cover']}
width="auto"
aspectRatio={1 / 1}
src={value.image}
alt={value.name}
aspectRatio="1/1"
format="webp"
/>
<div class:list={['tile-content', 'gap-1']}>
<Typography class:list={['leading-5', 'hover:text-gray-900']} variant="tile-title">
{value.name}
</Typography>
<Typography variant="tile-subtitle">
{value.name}
</Typography>
</div>
</PersonTile>

View file

@ -18,13 +18,13 @@ const getVideoThumbnail = (url: string) => {
<VideoTile
href={value.url}
class:list={['flex', 'flex-col', 'gap-3', 'transition', 'duration-300', 'hover:translate-y-2', props.class]}
class:list={['flex', 'flex-col', 'gap-3', 'transition', 'duration-300', 'hover:translate-y-2', 'w-full', props.class]}
>
<Image
class:list={['rounded-lg', 'shadow-md', 'object-cover']}
class:list={['rounded-lg', 'shadow-md', 'aspect-video', 'object-cover']}
src={getVideoThumbnail(value.url)}
width="auto"
aspectRatio="1.67"
aspectRatio={16 / 9}
alt={value.title}
format="webp"
/>

View file

@ -1,18 +1,87 @@
---
import type { ComponentInstance } from 'astro';
import BookTile from '@/atoms/book-tile.astro';
import MediaTile from '@/atoms/media-tile.astro';
import PersonTile from '@/atoms/person-tile.astro';
import SectionCard from '@/atoms/section-card.astro';
import Typography from '@/atoms/typography.astro';
import VideoTile from '@/atoms/video-tile.astro';
import type { Section } from '@/types/data';
import type { FavoritesSection } from '@/types/favorites-section';
import type { Book, FavoritesSection, Media, Person, Video } from '@/types/favorites-section';
export interface Props extends FavoritesSection {}
const {
config: { title },
books,
medias,
people,
videos,
} = Astro.props;
type Subsection = 'books' | 'medias' | 'people' | 'videos';
type SubsectionData = Book | Media | Person | Video;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- required to avoid type casting
type SubsectionComponent = (_props: { value: any }) => ComponentInstance;
interface FavoritesSubsection<T extends SubsectionData> {
name: Subsection;
data: T[];
title: string;
columnsLayout: string;
Component: SubsectionComponent;
}
const booksSubsection: FavoritesSubsection<Book> = {
name: 'books',
columnsLayout: 'grid-cols-4',
Component: BookTile,
...books,
};
const mediasSubsection: FavoritesSubsection<Media> = {
name: 'medias',
columnsLayout: 'grid-cols-6',
Component: MediaTile,
...medias,
};
const peopleSubsection: FavoritesSubsection<Person> = {
name: 'people',
columnsLayout: 'grid-cols-6',
Component: PersonTile,
...people,
};
const videosSubsection: FavoritesSubsection<Video> = {
name: 'videos',
columnsLayout: 'grid-cols-3',
Component: VideoTile,
...videos,
};
const subsections = [booksSubsection, peopleSubsection, videosSubsection, mediasSubsection];
const section: Section = 'favorites';
---
<SectionCard section={section}
><Typography variant="section-title" id={`${section}-heading`}>{title}</Typography>
<SectionCard section={section}>
<Typography variant="section-title" id={`${section}-heading`}>{title}</Typography>
<div class:list={['flex', 'flex-col', 'gap-16']}>
{
subsections.map(({ Component, data, name, columnsLayout, title: subsectionTitle }) => (
<div class:list={['flex', 'flex-col', 'gap-6']}>
<Typography variant="section-subtitle" id={`${section}-${name}-heading`}>
{subsectionTitle}
</Typography>
<div class:list={['grid', 'gap-8', columnsLayout]}>
{data.map((value) => (
<Component value={value} />
))}
</div>
</div>
))
}
</div>
</SectionCard>

View file

@ -34,7 +34,7 @@ const { seo, ...dataWithoutSeo } = data;
return (
sectionData && (
<SidebarItem
client:load
client:only="react"
title={sectionData.config.title}
icon={sectionData.config.icon}
section={key}

View file

@ -3,6 +3,10 @@ import MainSection from '@/sections/main-section.astro';
import type { MainSection as MainSectionData } from '@/types/main-section';
const mainSectionData: MainSectionData = {
config: {
title: 'Main Section',
icon: 'fa6-solid:user',
},
image: import('@/assets/my-image.jpeg'),
fullName: 'Mark Freeman',
role: 'Senior React Developer',