Create skills section (#67)

This commit is contained in:
Szymon Kin 2022-10-30 10:29:01 +01:00 committed by GitHub
parent 222924fa4b
commit c76651e841
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 276 additions and 22 deletions

View file

@ -4,16 +4,14 @@ import type { IconName } from '@/types/icon';
import Icon from './icon';
export interface Props {
icon?: {
name: IconName;
name?: IconName;
color?: string;
};
}
const { icon } = Astro.props;
const { name, color } = Astro.props;
---
<div class="flex items-center w-fit h-6 px-2.5 rounded text-sm font-medium text-gray-700 bg-gray-100 gap-x-1.5">
{icon && <Icon client:load name={icon.name} color={icon.color} size={16} />}
<Icon client:load name={name} color={color} size={16} />
<slot />
</div>

View file

@ -0,0 +1,15 @@
---
import type { LevelledSkill } from '@/types/skills-section';
import Skill from './skill.astro';
export interface Props {
skills: LevelledSkill[];
}
const { skills } = Astro.props;
---
<div class:list={['flex', 'flex-wrap', 'gap-8']}>
{skills.map((skill) => <Skill {...skill} />)}
</div>

View file

@ -0,0 +1,33 @@
---
import Typography from '@/atoms/typography.astro';
import type { Tag } from '@/types/common';
import type { LevelledSkill, SkillSet } from '@/types/skills-section';
import LevelledSkillSubsection from './levelled-skill-subsection.astro';
import TagSkillSubsection from './tag-skill-subsection.astro';
export interface Props {
skillSet: SkillSet<Tag> | SkillSet<LevelledSkill>;
}
const {
skillSet: { skills, title },
} = Astro.props;
const isLevelledSkillSection = (skillsSectionData: Tag[] | LevelledSkill[]): skillsSectionData is LevelledSkill[] => {
if (!skillsSectionData[0]) return false;
return (skillsSectionData[0] as LevelledSkill).level !== undefined;
};
---
<div class:list={['flex', 'flex-col', 'gap-3']}>
<Typography variant="section-subtitle">{title}</Typography>
{
isLevelledSkillSection(skills) ? (
<LevelledSkillSubsection skills={skills} />
) : (
<TagSkillSubsection skills={skills} />
)
}
</div>

View file

@ -18,7 +18,9 @@ const IconWrapper = url ? 'a' : 'div';
{...(url && { href: url, target: "_blank", rel: "noopener noreferrer" })}
>
<Icon client:load name={icon} color={iconColor} size={20} />
<Typography variant="tile-subtitle" class="text-gray-700">{name}</Typography>
<Typography variant="tile-subtitle">
<span class="text-gray-700">{name}</span>
</Typography>
</IconWrapper>
<SkillLevel skillLevel={level} />
</div>

View file

@ -0,0 +1,28 @@
---
import Tag from '@/atoms/tag.astro';
import type { Tag as TagData } from '@/types/common';
export interface Props {
skills: TagData[];
}
const { skills } = Astro.props;
---
<div class:list={['flex', 'flex-wrap', 'gap-3', 'items-center']}>
{
skills.map(({ name, icon, iconColor, url }) =>
url ? (
<a href={url} target="_blank" rel="noopener noreferrer">
<Tag name={icon} color={iconColor}>
{name}
</Tag>
</a>
) : (
<Tag name={icon} color={iconColor}>
{name}
</Tag>
)
)
}
</div>

View file

@ -68,10 +68,14 @@ const {
tags.map(({ icon, iconColor, name, url: tagUrl }) =>
tagUrl ? (
<a href={tagUrl} target="_blank" rel="noopener noreferrer">
<Tag icon={icon ? { name: icon, color: iconColor } : undefined}>{name}</Tag>
<Tag name={icon} color={iconColor}>
{name}
</Tag>
</a>
) : (
<Tag icon={icon ? { name: icon, color: iconColor } : undefined}>{name}</Tag>
<Tag name={icon} color={iconColor}>
{name}
</Tag>
)
)
}

View file

@ -1,8 +1,20 @@
---
import SectionCard from '@/atoms/section-card.astro';
import Typography from '@/atoms/typography.astro';
import SkillSubsection from '@/organisms/skill-subsection.astro';
import type { SkillsSection } from '@/types/skills-section';
export interface Props extends SkillsSection {}
const {
config: { title },
skillSets,
} = Astro.props;
---
<SectionCard>Skills section</SectionCard>
<SectionCard>
<Typography variant="section-title">{title}</Typography>
<div class:list={['flex', 'flex-col', 'gap-10']}>
{skillSets.map((skillSet) => <SkillSubsection skillSet={skillSet} />)}
</div>
</SectionCard>

View file

@ -22,16 +22,9 @@ import data from '../data';
<meta name="description" content={data.seo.description} />
</head>
<body class="flex justify-center bg-gray-50">
<div class="flex gap-8 w-full max-w-6xl px-2 py-3 sm:px-8 sm:py-12 lg:px-16 lg:py-20 lg:ml-22">
<main class="w-full space-y-4 sm:space-y-6 lg:space-y-8">
<MainSection {...data.main} />
{data.skills && <SkillsSection {...data.skills} />}
{data.experience && <ExperienceSection {...data.experience} />}
{data.portfolio && <PortfolioSection {...data.portfolio} />}
{data.testimonials && <TestimonialsSection {...data.testimonials} />}
{data.favorites && <FavoritesSection {...data.favorites} />}
</main>
<Sidebar className="hidden lg:flex">
<div class="flex relative transform-none gap-8 w-full max-w-5xl px-2 py-3 sm:px-8 sm:py-12 lg:py-20">
<div class="absolute -right-2">
<Sidebar className="hidden xl:flex fixed">
<SidebarItem icon="fa6-solid:user" />
{data.skills && <SidebarItem icon="fa6-solid:bars-progress" />}
{data.experience && <SidebarItem icon="fa6-solid:suitcase" />}
@ -40,5 +33,14 @@ import data from '../data';
{data.favorites && <SidebarItem icon="fa6-solid:star" />}
</Sidebar>
</div>
<main class="w-full relative space-y-4 sm:space-y-6 lg:space-y-8">
<MainSection {...data.main} />
{data.skills && <SkillsSection {...data.skills} />}
{data.experience && <ExperienceSection {...data.experience} />}
{data.portfolio && <PortfolioSection {...data.portfolio} />}
{data.testimonials && <TestimonialsSection {...data.testimonials} />}
{data.favorites && <FavoritesSection {...data.favorites} />}
</main>
</div>
</body>
</html>

View file

@ -0,0 +1,160 @@
---
import SkillsSection from '@/sections/skills-section.astro';
import type { SkillsSection as SkillsSectionData } from '@/types/skills-section';
const skills: SkillsSectionData = {
config: {
title: 'Skills',
icon: 'fa6-solid:bars-progress',
},
skillSets: [
{
title: 'I already know',
skills: [
{
icon: 'simple-icons:react',
iconColor: '#61DAFB',
name: 'React.js',
level: 5,
url: 'https://reactjs.org/',
description:
'Proin ut erat sed massa tempus suscipit. Mauris efficitur nunc sem, nec scelerisque ligula bibendum ut.',
},
{
icon: 'simple-icons:typescript',
iconColor: '#3178C6',
name: 'TypeScript',
level: 4,
url: 'https://www.typescriptlang.org/',
description: 'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.',
},
{
icon: 'simple-icons:sass',
iconColor: '#CC6699',
name: 'SASS',
level: 4,
url: 'https://sass-lang.com/',
description: 'Nulla interdum pellentesque ultricies. Ut id eros commodo, ultrices ligula eu, elementum ante.',
},
{
icon: 'simple-icons:chakraui',
iconColor: '#319795',
name: 'Chakra UI',
level: 5,
url: 'https://chakra-ui.com/',
},
{
icon: 'simple-icons:tailwindcss',
iconColor: '#06B6D4',
name: 'Tailwind CSS',
level: 2,
url: 'https://tailwindcss.com/',
},
{
icon: 'simple-icons:prettier',
iconColor: '#F7B93E',
name: 'Prettier',
level: 5,
url: 'https://prettier.io/',
},
{
icon: 'simple-icons:eslint',
iconColor: '#4B32C3',
name: 'ESLint',
level: 4,
url: 'https://eslint.org/',
description:
'Nulla tempor turpis at vehicula pharetra. Vestibulum tellus tortor, commodo et suscipit id, lobortis id nunc.',
},
{
icon: 'simple-icons:nestjs',
iconColor: '#E0234E',
name: 'NestJS',
level: 2,
url: 'https://nestjs.com/',
description:
'Praesent feugiat ultricies iaculis. In posuere vehicula odio, sed consequat velit porta viverra.',
},
{
icon: 'simple-icons:postgresql',
iconColor: '#4169E1',
name: 'PostgreSQL',
level: 2,
url: 'https://www.postgresql.org/',
},
{
icon: 'simple-icons:mongodb',
iconColor: '#47A248',
name: 'MongoDB',
level: 1,
url: 'https://www.mongodb.com/',
},
{
icon: 'simple-icons:firebase',
iconColor: '#FFCA28',
name: 'Firebase',
level: 1,
url: 'https://firebase.google.com/',
},
{
icon: 'simple-icons:pnpm',
iconColor: '#F69220',
name: 'pnpm',
level: 3,
url: 'https://pnpm.io/',
},
],
},
{
title: 'I want to learn',
skills: [
{
icon: 'simple-icons:apollographql',
iconColor: '#311C87',
name: 'Apollo GraphQL',
},
{
icon: 'simple-icons:astro',
iconColor: '#FF5D01',
name: 'Astro',
},
{
icon: 'simple-icons:supabase',
iconColor: '#3ECF8E',
name: 'Supabase',
},
{
icon: 'simple-icons:cypress',
iconColor: '#17202C',
name: 'Cypress',
},
],
},
{
title: 'I speak',
skills: [
{
icon: 'circle-flags:pl',
name: 'Polish - native',
},
{
icon: 'circle-flags:us',
name: 'English - C1',
},
{
icon: 'circle-flags:es-variant',
name: 'Spanish - B1',
},
],
},
],
};
---
<body class="flex justify-center bg-gray-50">
<div class="flex gap-8 w-full max-w-6xl px-2 py-3 sm:px-8 sm:py-12 lg:px-16 lg:py-20 lg:ml-22">
<main class="w-full space-y-4 sm:space-y-6 lg:space-y-8">
<SkillsSection config={skills.config} skillSets={skills.skillSets} />
</main>
</div>
</body>

View file

@ -7,5 +7,5 @@ import Tag from '@/atoms/tag.astro';
</div>
<div class="p-5">
<Tag icon={{ name: 'simple-icons:react', color: '#61DAFB' }}>Tag text</Tag>
<Tag name="simple-icons:react" color="#61DAFB">Tag text</Tag>
</div>

View file

@ -4,7 +4,7 @@ export interface LevelledSkill extends Tag {
level: 1 | 2 | 3 | 4 | 5;
}
interface SkillSet<SkillType> {
export interface SkillSet<SkillType> {
title: string;
skills: SkillType[];
}