Skip to content

Commit

Permalink
Improve landing
Browse files Browse the repository at this point in the history
  • Loading branch information
cesalberca committed Aug 1, 2024
1 parent cdd870c commit b83200e
Show file tree
Hide file tree
Showing 16 changed files with 222 additions and 156 deletions.
Binary file added public/assets/images/archimedesjs.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/images/blog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@
h6 {
@apply text-lg;
}

.wrapper {
@apply mx-auto max-w-xl;
}
}

.full-width-section {
Expand All @@ -111,3 +115,13 @@
margin-left: -50vw;
margin-right: -50vw;
}

@screen lg {
.full-width-section {
@apply max-w-xl m-auto w-full relative left-0 right-0;
}
}

.bleed-width-section {
@apply max-w-screen-xl m-auto;
}
29 changes: 29 additions & 0 deletions src/components/ui/badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as React from 'react'
import { cva, type VariantProps } from 'class-variance-authority'

import { cn } from '@/lib/utils'

const badgeVariants = cva(
'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
{
variants: {
variant: {
default: 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
secondary: 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
destructive: 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
outline: 'text-foreground',
},
},
defaultVariants: {
variant: 'default',
},
},
)

export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {}

function Badge({ className, variant, ...props }: BadgeProps) {
return <div className={cn(badgeVariants({ variant }), className)} {...props} />
}

export { Badge, badgeVariants }
2 changes: 1 addition & 1 deletion src/core/components/hero/hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { cn } from '@/lib/utils'

export const Hero: FC<PropsWithChildren<{ image?: string; className?: string }>> = ({ image, className, children }) => {
return (
<div className={cn('full-width-section h-[80vh]', className)}>
<div className={cn('full-width-section h-[60vh]', className)}>
{image && (
<Image
className="w-full h-full object-cover overflow-hidden object-top md:object-contain"
Expand Down
12 changes: 11 additions & 1 deletion src/core/components/leet-card/leet-background.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const LeetBackground: FC<PropsWithChildren> = ({ children }) => {
}

const handleMouseLeave = () => {
controls.start({ opacity: 0, transition: { duration: 0.5, ease: 'easeInOut' } })
controls.start({ opacity: 0.25, transition: { duration: 0.5, ease: 'easeInOut' } })
}

return (
Expand All @@ -64,6 +64,16 @@ export const LeetBackground: FC<PropsWithChildren> = ({ children }) => {
<motion.div
ref={decoRef}
animate={controls}
onViewportEnter={() => {
if (decoRef.current && itemRef.current) {
controls.start({ opacity: 1, transition: { duration: 0.5, ease: 'easeInOut' } })
itemRef.current.style.setProperty('--x', `${0}px`)
itemRef.current.style.setProperty('--y', `${0}px`)
x.set(linearInterpolation(x.get(), 0, 0.1))
y.set(linearInterpolation(y.get(), 0, 0.1))
decoRef.current.innerHTML = getRandomString(2000)
}
}}
className={cn(
'absolute top-0 left-0 h-full w-full font-mono text-xs break-words leading-4 text-white opacity-0',
styles.mask,
Expand Down
8 changes: 6 additions & 2 deletions src/core/components/leet-card/leet-card.module.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
.radial-background {
transition: all 0.5s ease-in-out;
}

.radial-background::after {
background: radial-gradient(rgb(23, 24, 37) 40%, rgb(102, 51, 238) 50%, rgb(142, 100, 255), rgb(249, 38, 114));
mix-blend-mode: darken;
}

.mask {
-webkit-mask-image: radial-gradient(300px circle at var(--x) var(--y), black 20%, rgba(0, 0, 0, 0.25), transparent);
mask-image: radial-gradient(300px circle at var(--x) var(--y), black 20%, rgba(0, 0, 0, 0.25), transparent);
-webkit-mask-image: radial-gradient(350px circle at var(--x) var(--y), black 20%, rgba(0, 0, 0, 0.25), transparent);
mask-image: radial-gradient(350px circle at var(--x) var(--y), black 20%, rgba(0, 0, 0, 0.25), transparent);
}
4 changes: 2 additions & 2 deletions src/core/components/leet-card/leet-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import React, { type FC, type PropsWithChildren, type ReactNode } from 'react'
import { LeetBackground } from '@/core/components/leet-card/leet-background'

export const LeetCard: FC<PropsWithChildren<{ icon: ReactNode }>> = ({ children, icon }) => {
export const LeetCard: FC<PropsWithChildren<{ center: ReactNode }>> = ({ children, center }) => {
return (
<div className="grid grid-col-1 border bg-background">
<div className="grid p-m gap-4 bg-background">
<LeetBackground>{icon}</LeetBackground>
<LeetBackground>{center}</LeetBackground>
{children}
</div>
</div>
Expand Down
5 changes: 3 additions & 2 deletions src/core/components/markdown/markdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import type { FC } from 'react'
import { Prism as SyntaxHighlighter, type SyntaxHighlighterProps } from 'react-syntax-highlighter'
import dark from 'react-syntax-highlighter/dist/esm/styles/prism/synthwave84'
import ReactMarkdown from 'react-markdown'
import { cn } from '@/lib/utils'

export const Markdown: FC<{ value: string }> = async ({ value }) => {
export const Markdown: FC<{ value: string; className?: string }> = async ({ value, className }) => {
return (
<ReactMarkdown
className="prose prose-zinc dark:prose-invert"
className={cn('prose prose-zinc dark:prose-invert', className)}
components={{
code(props) {
const { children, className, node, ...rest } = props
Expand Down
2 changes: 1 addition & 1 deletion src/core/components/page/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const Page: FC<PropsWithChildren> = ({ children }) => {
return (
<div>
<Navbar className="w-full" />
<main className="mx-auto max-w-xl">{children}</main>
<main>{children}</main>
<Footer />
</div>
)
Expand Down
10 changes: 6 additions & 4 deletions src/core/components/tilt-card/tilt-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { MouseIcon } from 'lucide-react'
import { cn } from '@/lib/utils'

const RATIO = 32.5
const ROTATION_RANGE = RATIO
const ROTATION_RANGE = 20
const HALF_ROTATION_RANGE = RATIO / 2

export const TiltCard: FC<
Expand Down Expand Up @@ -60,12 +60,14 @@ export const TiltCard: FC<
}}
className={cn('relative rounded-xl bg-accent', className)}
>
<MouseIcon
<div
className="mx-auto drop-shadow absolute top-0 left-[50%]"
style={{
transform: 'translateZ(75px) translateY(40px)',
}}
className="mx-auto text-4xl"
/>
>
<MouseIcon className="text-4xl" />
</div>
<div
style={{
transform: 'translateZ(50px)',
Expand Down
18 changes: 12 additions & 6 deletions src/core/i18n/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,27 @@
"whoAmI": "**Senior Frontend Architect** & **Software Crafter** from Spain. Freelancer _obsessed_ with **best practices**, **architecture** and **testing**.\n\nAs an [international speaker](https://www.cesalberca.com/talks) and Digital Nomad, I share my tech adventures around the world.\n\n Active in the [Codemotion](https://www.codemotion.com/) community as a committee member and [ambassador](https://community-en.codemotion.it/community/ambassador-program).",
"projects": {
"title": "Projects",
"description": "I love to create projects to learn new technologies and to share knowledge. Here are some of the projects I've created.",
"code": "See the code",
"live": "Live version",
"katasTitle": "TypeScript Katas",
"katasDescription": "TDD and testing are very important to me. Whenever I was teaching a course about programming I needed to create the same exercises over and over again. So I decided to create this instead.\n\nIt's a project to practise TDD, testing and TypeScript through simple and useful Katas.",
"whoAmITitle": "Who Am I",
"whoAmIDescription": "Simple Who Am I game implemented using RxJs, React and Firebase.",
"frontendReformsTitle": "WordleJS",
"frontendReformsDescription": "Code for the talk Frontend Reforms where we build a Wordle for frontend frameworks"
"blog": "Personal blog",
"blogDescription": "I write about software architecture, testing and frontend development. I also write about my experiences as a Digital Nomad and my trips around the world.",
"archimedesJs": "ArchimedesJS",
"archimedesJsDescription": "Archimedes is a series of architectural concepts that are implemented in different languages. Using a given Archimedes implementation provides a set of solid and flexible architectural pieces."
},
"services": {
"title": "Services",
"description": "I offer a wide range of services, from consulting to training, and from architecture to development. I can help you with your project, no matter the size or the technology stack. I have experience in different industries and I can adapt to your needs. I'm a freelancer, so I can work with you in a flexible way."
"description": "After <leet>10 years</leet> of experience in Frontend Development and after having deployed to production projects using <leet>React</leet>, <leet>Angular</leet> and <leet>Vue</leet>, I can help you to improve your team's skills in best practices, testing and architecture.",
"consultancy": "Consultancy",
"consultancyDescription": "I can help you to improve your team's skills in best practices, testing and architecture. I can provide consultancy in different formats, from code reviews to architecture design.",
"training": "Training",
"trainingDescription": "I will help you to improve your team's skills in best practices, testing and architecture. I can provide training in different formats, from workshops to online courses.",
"mentoring": "Mentoring",
"mentoringDescription": "I can help you to improve your skills in frontend development, architecture and testing. I can provide mentoring in different formats, from pair programming to code reviews."
}
},

"article": {
"title": "Articles",
"shareArticle": "Share article",
Expand Down
13 changes: 10 additions & 3 deletions src/features/home/ui/home.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Services } from './services'
import { SocialMedia } from '@/core/components/social-media/social-media'
import { Hero } from '@/core/components/hero/hero'
import { ScrambleList } from '@/core/components/scramble-list/scramble-list'
import { ScrambleText } from '@/core/components/scramble-text/scramble-text'

export const Section: FC<
PropsWithChildren<{
Expand All @@ -19,7 +20,11 @@ export const Section: FC<
> = ({ children, title }) => {
return (
<section className="mt-xxl">
{title && <h2 className="mt-m">{title}</h2>}
{title && (
<h2 className="my-m wrapper">
<ScrambleText>{title}</ScrambleText>
</h2>
)}
{children}
</section>
)
Expand Down Expand Up @@ -51,7 +56,7 @@ export const HomePage: FC<{ articles: Article[] }> = ({ articles }) => {
</Hero>

<Section>
<Markdown value={t('home.whoAmI')} />
<Markdown className="wrapper" value={t('home.whoAmI')} />
</Section>

<Section title={t('home.services.title')}>
Expand All @@ -63,7 +68,9 @@ export const HomePage: FC<{ articles: Article[] }> = ({ articles }) => {
</Section>

<Section title={t('home.technologies')}>
<Technologies />
<div className="wrapper">
<Technologies />
</div>
</Section>

<Section title={t('home.latestArticles')}>
Expand Down
82 changes: 49 additions & 33 deletions src/features/home/ui/projects.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import type { FC } from 'react'
import { Card } from '../../../core/components/card/card'
import { Link } from '../../../core/components/link/link'
import { Url } from '../../../core/types/url'
import { useTranslations } from 'next-intl'
import Image from 'next/image'
import { cn } from '@/lib/utils'
import { TiltCard } from '@/core/components/tilt-card/tilt-card'
import { Markdown } from '@/core/components/markdown/markdown'
import { Technologies } from '@/features/home/ui/technologies'
import { Button } from '@/components/ui/button'
import Link from 'next/link'

interface Project {
title: string
description: string
link?: Url
code: Url
image: string
technologies: string[]
}

export const Projects: FC = () => {
Expand All @@ -26,45 +27,60 @@ export const Projects: FC = () => {
description: t('home.projects.katasDescription'),
code: Url.fromValue('https://github.com/cesalberca/katas'),
image: '/assets/images/katas.png',
technologies: ['React', 'TypeScript', 'Jest', 'TDD', 'Testing'],
},
{
title: t('home.projects.whoAmITitle'),
description: t('home.projects.whoAmIDescription'),
link: Url.fromValue('https://github.com/cesalberca/who-am-i'),
code: Url.fromValue('https://who-am-i-e6a66.web.app/'),
image: '/assets/images/katas.png',
title: t('home.projects.archimedesJs'),
description: t('home.projects.archimedesJsDescription'),
link: Url.fromValue('https://archimedesfw.io/'),
code: Url.fromValue('https://github.com/archimedes-projects/archimedes-js/'),
image: '/assets/images/archimedesjs.png',
technologies: ['TypeScript', 'Jest', 'Architecture', 'Isomorphic'],
},
{
title: t('home.projects.frontendReformsTitle'),
description: t('home.projects.frontendReformsDescription'),
link: Url.fromValue('https://cesalberca.github.io/reformas-de-frontaneria/'),
code: Url.fromValue('https://github.com/cesalberca/reformas-de-frontaneria'),
image: '/assets/images/katas.png',
title: t('home.projects.blog'),
description: t('home.projects.blogDescription'),
code: Url.fromValue('https://github.com/cesalberca/blog'),
image: '/assets/images/blog.png',
technologies: ['React', 'TypeScript', 'Jest', 'NextJS'],
},
]

return (
<div>
{projects.map((x, i) => (
<div key={x.title} className={cn('flex full-width-section gap-m', i % 2 !== 0 ? 'flex-row-reverse' : '')}>
<TiltCard className="flex-2" defaultTiltX={i % 2 !== 0 ? 5 : 5} defaultTiltY={i % 2 === 0 ? 30 : -30}>
<Image src={x.image} alt={x.title} width={600} height={400} />
<footer>
<Link to={x.code.value}>{t('home.projects.live')}</Link>
{x.link?.value && (
<Link key={x.title} to={x.code.value}>
{t('home.projects.code')}
</Link>
)}
</footer>
</TiltCard>
<aside className="flex-1">
<h3>{x.title}</h3>
<Markdown value={x.description}></Markdown>
<Technologies />
</aside>
</div>
))}
<div className="flex flex-col gap-20">
<p className="wrapper">{t('home.projects.description')}</p>
<section className="mt-xxl flex flex-col gap-20 bleed-width-section">
{projects.map((x, i) => (
<div key={x.title} className={cn('flex gap-m items-center', { 'flex-row-reverse': i % 2 !== 0 })}>
<TiltCard className="flex-2" defaultTiltX={i % 2 !== 0 ? 5 : 5} defaultTiltY={i % 2 === 0 ? 30 : -30}>
<Image src={x.image} alt={x.title} width={600} height={400} />
<footer
className="flex gap-4 justify-center"
style={{
transformStyle: 'preserve-3d',
transform: 'translateZ(100px) translateY(-10px)',
}}
>
<Button asChild className="drop-shadow">
<Link href={x.code.value}>{t('home.projects.live')}</Link>
</Button>
{x.link?.value && (
<Button asChild className="drop-shadow">
<Link href={x.code.value}>{t('home.projects.code')}</Link>
</Button>
)}
</footer>
</TiltCard>
<aside className="flex-1">
<h3>{x.title}</h3>
<Markdown value={x.description}></Markdown>
<div className="pt-m">
<Technologies technologies={x.technologies} />
</div>
</aside>
</div>
))}
</section>
</div>
)
}
Loading

0 comments on commit b83200e

Please sign in to comment.