diff --git a/next.config.js b/next.config.js index b97848d..074b341 100644 --- a/next.config.js +++ b/next.config.js @@ -39,6 +39,15 @@ const nextConfig = { }, staticPageGenerationTimeout: 600, + + async rewrites() { + return [ + { + source: '/downloads/cv.pdf', + destination: '/api/cv.pdf', + }, + ]; + }, }; module.exports = nextConfig; diff --git a/src/app/(public)/about/free-time/page.tsx b/src/app/(public)/about/page.tsx similarity index 98% rename from src/app/(public)/about/free-time/page.tsx rename to src/app/(public)/about/page.tsx index 43b02a1..383681e 100644 --- a/src/app/(public)/about/free-time/page.tsx +++ b/src/app/(public)/about/page.tsx @@ -109,7 +109,7 @@ const AboutFreeTimePage = async () => {
-

Free Time

+

About me

diff --git a/src/app/(public)/about/work/page.tsx b/src/app/(public)/about/work/page.tsx deleted file mode 100644 index 99a1ac6..0000000 --- a/src/app/(public)/about/work/page.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import Image from 'next/image'; -import * as React from 'react'; -import ReactMarkdown from 'react-markdown'; - -import Heading from '@/components/atoms/headings/Heading'; -import Education from '@/components/organisms/about-work/Education'; -import Intro from '@/components/organisms/about-work/Intro'; -import Languages from '@/components/organisms/about-work/Languages'; -import Publications from '@/components/organisms/about-work/Publications'; -import WorkExperience from '@/components/organisms/about-work/WorkExperience'; - -import { queryJobs } from '@/queries/jobs'; -import { queryLanguages } from '@/queries/languages'; -import { queryPublications } from '@/queries/publications'; -import { querySchools } from '@/queries/schools'; -import { queryIntro } from '@/queries/short-texts'; -import { querySkills } from '@/queries/skills'; - -import { Icon } from '@/types/Icon'; -import { Skill } from '@/types/Skill'; - -export const metadata = { - title: 'About my Work | MartaCodes.it', - description: 'About page', -}; - -const queryData = async () => { - const intro = await queryIntro(); - - const jobs = await queryJobs(); - const languages = await queryLanguages(); - const publications = await queryPublications(); - const schools = await querySchools(); - const skills = await querySkills(); - - return { - intro, - jobs, - languages, - publications, - schools, - skills, - }; -}; - -const AboutPage = async () => { - const { intro, jobs, languages, publications, schools, skills } = - await queryData(); - - const iconDimension = 36; - - return ( -

-
-
- - - - -
- {skills.map((skill: Skill) => ( -
-
- {skill.icons.map((icon: Icon) => ( - {icon.name} - ))} -
- -

{skill.title}

- - - {skill.description} - -
- ))} -
- -
- - - -
- - - -
- - - -
- - -
-
-
- ); -}; - -export default AboutPage; diff --git a/src/app/(public)/cv/page.tsx b/src/app/(public)/cv/page.tsx index c6f5f93..3bb8d65 100644 --- a/src/app/(public)/cv/page.tsx +++ b/src/app/(public)/cv/page.tsx @@ -1,18 +1,107 @@ +import Image from 'next/image'; import * as React from 'react'; +import ReactMarkdown from 'react-markdown'; +import Heading from '@/components/atoms/headings/Heading'; +import Education from '@/components/organisms/about-work/Education'; +import Intro from '@/components/organisms/about-work/Intro'; +import Languages from '@/components/organisms/about-work/Languages'; +import Publications from '@/components/organisms/about-work/Publications'; +import WorkExperience from '@/components/organisms/about-work/WorkExperience'; import CvCard from '@/components/organisms/cv/CvCard'; +import { queryJobs } from '@/queries/jobs'; +import { queryLanguages } from '@/queries/languages'; +import { queryPublications } from '@/queries/publications'; +import { querySchools } from '@/queries/schools'; +import { queryIntro } from '@/queries/short-texts'; +import { querySkills } from '@/queries/skills'; + +import { Icon } from '@/types/Icon'; +import { Skill } from '@/types/Skill'; + export const metadata = { - title: 'CV | MartaCodes.it', - description: 'CV page', + title: 'About my Work | MartaCodes.it', + description: 'About page', +}; + +const queryData = async () => { + const intro = await queryIntro(); + + const jobs = await queryJobs(); + const languages = await queryLanguages(); + const publications = await queryPublications(); + const schools = await querySchools(); + const skills = await querySkills(); + + return { + intro, + jobs, + languages, + publications, + schools, + skills, + }; }; -const CVPage = async () => { +const AboutPage = async () => { + const { intro, jobs, languages, publications, schools, skills } = + await queryData(); + + const iconDimension = 36; + return (
-
+
-

CV

+ + + + +
+ {skills.map((skill: Skill) => ( +
+
+ {skill.icons.map((icon: Icon) => ( + {icon.name} + ))} +
+ +

{skill.title}

+ + + {skill.description} + +
+ ))} +
+ +
+ + + +
+ + + +
+ + + +
+ + + +
@@ -21,4 +110,4 @@ const CVPage = async () => { ); }; -export default CVPage; +export default AboutPage; diff --git a/src/components/atoms/headings/SectionHeading.tsx b/src/components/atoms/headings/SectionHeading.tsx index 3d461cf..ab828b2 100644 --- a/src/components/atoms/headings/SectionHeading.tsx +++ b/src/components/atoms/headings/SectionHeading.tsx @@ -14,7 +14,7 @@ const SectionHeading = ({ titlePrefix }: SectionHeadingProps) => { const titleIconDimension = 36; return ( -
+
(null); - const open = Boolean(anchorEl); - const handleClick = (event: React.MouseEvent) => { - setAnchorEl(event.currentTarget); - }; - const handleClose = () => { - setAnchorEl(null); - }; - const pathname = usePathname(); useEffect(() => { @@ -76,40 +64,6 @@ export default function Header() {
    -
  • - - {t('headerMenu.about')} - {!open && } - {open && } - - - - - 👔 {t('headerMenu.aboutWork')} - - - - - 🪁 {t('headerMenu.aboutFreeTime')} - - - -
  • - {links.map(({ href, label }) => (
  • { const { t } = useTranslation(); - const mobileLinks = [ - { href: '/about/work', label: 'headerMenu.aboutWorkMobile' }, - { href: '/about/free-time', label: 'headerMenu.aboutFreeTimeMobile' }, - ...links, - ]; const navigationVariants = { hidden: { opacity: 0, x: -50 }, visible: (custom: number) => ({ @@ -49,7 +44,7 @@ export const MobileMenu = ({ isOpen }: MobileMenuProps) => { }} >
      - {mobileLinks.map(({ href, label }, i) => ( + {links.map(({ href, label }, i) => ( {
      - {intro.content.replace('8', noOfYears)} + + {intro.content.replace('8', noOfYears)} +
); diff --git a/src/components/organisms/about-work/Languages.tsx b/src/components/organisms/about-work/Languages.tsx index 960f90c..fd27356 100644 --- a/src/components/organisms/about-work/Languages.tsx +++ b/src/components/organisms/about-work/Languages.tsx @@ -16,11 +16,11 @@ const Languages = ({ languages }: LanguageProps) => {
-
+
{languages.map((language) => (
{
-
+
{publications.map((publication) => (
- {publication.title} + + {publication.title} +
diff --git a/src/components/organisms/cv/CvCard.tsx b/src/components/organisms/cv/CvCard.tsx index 7a2197e..1babe6d 100644 --- a/src/components/organisms/cv/CvCard.tsx +++ b/src/components/organisms/cv/CvCard.tsx @@ -1,6 +1,5 @@ 'use client'; -import Image from 'next/image'; import * as React from 'react'; import { useTranslation } from 'react-i18next'; import { FaDownload } from 'react-icons/fa'; @@ -10,38 +9,15 @@ import Button from '@/components/buttons/Button'; const CvCard = () => { const { t } = useTranslation(); - const width = 1200; - return ( - <> - - -
- CV Page 1 - CV Page 2 -
- + ); }; diff --git a/src/data/locales/en.json b/src/data/locales/en.json index bd7b456..0b191e1 100644 --- a/src/data/locales/en.json +++ b/src/data/locales/en.json @@ -5,6 +5,7 @@ "aboutWorkMobile": "About ~ Work & Career", "aboutFreeTime": "Free Time", "aboutFreeTimeMobile": "About ~ Free Time", + "experience": "Work", "projects": "Projects", "cv": "CV", "uses": "Uses", @@ -20,7 +21,7 @@ "feedback": "Feedback" }, "aboutWork": { - "title": "Work & Career", + "title": "My CV", "softwareDevelopment": { "title": "Software Development", "icon": "https://res.cloudinary.com/dwrurydlt/image/upload/v1692734473/laptop_4a3ba3b30c.svg" @@ -42,7 +43,9 @@ "icon": "https://res.cloudinary.com/dwrurydlt/image/upload/v1692894192/newspaper_e15ec94d21.svg" } }, - "aboutFreeTime": {}, + "about": { + "title": "Su di me" + }, "projects": { "readMore": "Read More" }, diff --git a/src/data/locales/it.json b/src/data/locales/it.json index 9a28906..cd347b2 100644 --- a/src/data/locales/it.json +++ b/src/data/locales/it.json @@ -1,6 +1,6 @@ { "headerMenu": { - "about": "About", + "about": "Su di me", "aboutWork": "Lavoro", "aboutWorkMobile": "About ~ Lavoro", "aboutFreeTime": "Tempo Libero", @@ -20,7 +20,7 @@ "feedback": "Feedback" }, "aboutWork": { - "title": "Carriera Lavorativa", + "title": "CV", "softwareDevelopment": { "title": "Sviluppo Software", "icon": "https://res.cloudinary.com/dwrurydlt/image/upload/v1692734473/laptop_4a3ba3b30c.svg" @@ -40,12 +40,15 @@ "publications": { "title": "Pubblicazioni", "icon": "https://res.cloudinary.com/dwrurydlt/image/upload/v1692894192/newspaper_e15ec94d21.svg" - }, - "projects": { - "readMore": "Leggi di più" - }, - "cv": { - "download": "Scarica PDF" } + }, + "about": { + "title": "About me" + }, + "projects": { + "readMore": "Leggi di più" + }, + "cv": { + "download": "Scarica PDF" } } diff --git a/src/pages/api/cv.pdf.ts b/src/pages/api/cv.pdf.ts new file mode 100644 index 0000000..dd90425 --- /dev/null +++ b/src/pages/api/cv.pdf.ts @@ -0,0 +1,32 @@ +/* eslint-disable no-console */ +import { NextApiRequest, NextApiResponse } from 'next'; +import fetch from 'node-fetch'; + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse, +) { + try { + const cloudinaryUrl = + 'https://res.cloudinary.com/dwrurydlt/image/upload/v1694634540/Pancaldi_CV_aug23_258811b6b1.pdf'; + + const cloudinaryResponse = await fetch(cloudinaryUrl); + + if (!cloudinaryResponse.ok) { + console.error( + 'Error fetching the PDF from Cloudinary:', + cloudinaryResponse.statusText, + ); + res.status(500).end('Internal Server Error'); + return; + } + + res.setHeader('Content-Type', 'application/pdf'); + res.setHeader('Content-Disposition', 'inline; filename=cv.pdf'); + + cloudinaryResponse.body.pipe(res); + } catch (error) { + console.error('Error:', error); + res.status(500).end('Internal Server Error'); + } +}