Skip to content

Commit

Permalink
Merge pull request #4 from kettei-sproutty/feature/blog-section
Browse files Browse the repository at this point in the history
feat(blog): create blog page
  • Loading branch information
kettei-sproutty authored Jun 12, 2024
2 parents 2de51c4 + 0dbfbe1 commit 70b9454
Show file tree
Hide file tree
Showing 32 changed files with 773 additions and 46 deletions.
4 changes: 4 additions & 0 deletions lefthook.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ run = "pnpm biome check --apply --no-errors-on-unmatched --files-ignore-unknown=
# glob = "*.svelte"
# run = "pnpm svelte-check -- {staged_files} && git update-index --again"

# [pre-commit.commands.update-mdx]
# glob = "*.mdx"
# run = "pnpm scripts/update-mdx {staged_files} && git update-index --again"

[pre-commit.commands.check-toml]
glob = "*.toml"
run = "pnpm taplo format {staged_files} && git update-index --again"
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
},
"type": "module",
"dependencies": {
"@vercel/analytics": "^1.3.1",
"autoprefixer": "^10.4.19",
"highlight.js": "^11.9.0",
"postcss": "^8.4.38",
Expand Down
22 changes: 22 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ kbd {
--a4-height: 297mm;
--a4-aspect-ratio: calc(var(--a4-height) / var(--a4-width));

--page-min-height: calc(100dvh - var(--header-weight) - var(--footer-height));
--page-min-height: calc(100dvh - var(--header-height) - var(--footer-height));

--primary-100: #e8e9e9;
--primary-200: #cdcecf;
Expand Down
32 changes: 32 additions & 0 deletions src/components/blog/blog-link.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script lang="ts">
import { page } from '$app/stores'
import { cn } from '$lib'
import type { BlogPost } from '$lib/blog/post'
type BlogLinkProps = {
article: BlogPost
}
let { article }: BlogLinkProps = $props()
</script>

<a
aria-current={$page.params.slug === article.slug ? "page" : undefined}
href="/blog/{article.slug}"
class={cn(
"flex justify-between hover:bg-primary-600 transition-colors duration-200 ease-in-out px-2",
"focus:bg-primary-500",
{
"bg-primary-700": $page.params.slug === article.slug,
},
)}
>
<span>{article.metadata.title}</span>
<span class="text-primary-400">
{Intl.DateTimeFormat("en", {
year: "2-digit",
month: "short",
day: "numeric",
}).format(new Date(article.metadata.date))}
</span>
</a>
103 changes: 103 additions & 0 deletions src/components/blog/blog-modal.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<script lang="ts">
import Button from '$components/ui/button.svelte'
import Input from '$components/ui/input.svelte'
import { cn } from '$lib'
import BlogSection from './blog-section.svelte'
type BlogModalProps = {
showModal: boolean
handleFilter: (value: string) => void
closeModal: () => void
search: string
}
let { showModal, handleFilter, closeModal, search }: BlogModalProps = $props()
let value = $state(search)
const handleClose = (event: MouseEvent | KeyboardEvent) => {
if (!showModal) return
if (event instanceof KeyboardEvent) {
if (event.key === ' ' || event.key === 'Escape') {
event.preventDefault()
closeModal()
}
return
}
event.preventDefault()
closeModal()
}
const handleSearch = (event: MouseEvent | KeyboardEvent) => {
if (!showModal) return
if (event instanceof KeyboardEvent) {
if (event.key === ' ' || event.key === 'Enter') {
handleFilter(value)
closeModal()
}
return
}
handleFilter(value)
closeModal()
}
$effect(() => {
const handleKeyUp = (event: KeyboardEvent) => {
switch (event.key) {
case 'Escape':
handleClose(event)
break
case 'Enter':
handleSearch(event)
break
}
}
window.addEventListener('keyup', handleKeyUp)
return () => window.removeEventListener('keyup', handleKeyUp)
})
</script>

<dialog open={showModal}>
<div
class={cn(
"fixed inset-0 bg-black bg-opacity-50 z-50 w-full h-full",
showModal ? "flex" : "hidden",
)}
></div>
{#if showModal}
<div
class={cn(
"fixed inset-0 flex justify-center items-center z-50",
showModal ? "flex" : "hidden",
)}
>
<BlogSection class="text-primary-300 bg-primary-900 p-4 w-80" label="Search" id="search">
<Input
autofocus
showLabel={false}
label="search"
value={value}
oninput={(e) => e.target instanceof HTMLInputElement && (value = e.target.value)}
error={null}
placeholder={"Search for an article"}
/>
<div class="flex gap-2">
<Button onkeypress={closeModal} onclick={closeModal} class="w-1/2 flex items-center justify-center bg-primary-900" type="button">
<span class="text-center text-sm">Close</span>
<kbd class="text-primary-300 font-thin text-xs">(Esc)</kbd>
</Button>
<Button onkeypress={handleSearch} onclick={handleSearch} class="w-1/2 flex items-center justify-center bg-primary-900" type="button">
<span class="text-center text-sm">Search</span>
<kbd class="text-primary-300 font-thin text-xs">(Enter)</kbd>
</Button>
</div></BlogSection
>
</div>
{/if}
</dialog>
36 changes: 36 additions & 0 deletions src/components/blog/blog-section.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script lang="ts">
import { cn } from '$lib'
import type { HTMLAttributes } from 'svelte/elements'
type BlogSectionProps = HTMLAttributes<HTMLDivElement> & {
label: string
isAside?: boolean
id: string
}
const { label, isAside = false, id, ...props }: BlogSectionProps = $props()
</script>

{#if isAside}
<aside id={id} class={cn("blog-section", props.class)}>
<h2 class="blog-section__title">{label}</h2>
<div class="h-2"></div>
{@render props.children?.()}
</aside>
{:else}
<section id={id} class={cn("blog-section", props.class)}>
<h2 class="blog-section__title">{label}</h2>
<div class="h-2"></div>
{@render props.children?.()}
</section>
{/if}

<style lang="postcss">
.blog-section {
@apply border border-primary-500 rounded-md relative;
}
.blog-section__title {
@apply text-sm font-sans bg-primary-900 inline-block -top-3 absolute left-2 px-2 font-bold;
}
</style>
3 changes: 3 additions & 0 deletions src/components/blog/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { default as BlogLink } from './blog-link.svelte'
export { default as BlogModal } from './blog-modal.svelte'
export { default as BlogSection } from './blog-section.svelte'
39 changes: 25 additions & 14 deletions src/components/resume/resume.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts" context="module">
import GlobeIcon from '$icons/globe-icon.svelte'
import PhoneIcon from '$icons/phone-icon.svelte'
import SocialEmailIcon from '$icons/social-email-icon.svelte'
import SocialGithubIcon from '$icons/social-github-icon.svelte'
import SocialLinkedinIcon from '$icons/social-linkedin-icon.svelte'
Expand All @@ -23,11 +24,11 @@ export const resume = {
name: 'Alessio Marchi',
role: 'Senior Software Developer',
about: [
"I'm a 26 years old Senior Software Developer based in Rome, Italy. I love Rust, Typescript, open-source community/projects and the tech community in general.",
'I love sharing knowledge, discuss and collaborate with people from all over the world, trying to improving myself day by day, learning new things and experimenting with new technologies.',
'I am a 26-year-old Senior Software Developer located in Rome, Italy, specializing in Rust, TypeScript, and contributing to open-source community projects. My passion extends to the broader tech community, where I actively engage.',
'I am dedicated to sharing knowledge, engaging in discussions, and collaborating globally. My commitment to personal growth drives me to continuously learn, experiment with new technologies, and refine my skills.',
],
contacts: [
{ name: 'email', value: 'mailto:about@alessiomarchi.dev', Icon: SocialEmailIcon },
{ name: 'email', value: 'mailto:alessiomarchi.dev@gmail.com', Icon: SocialEmailIcon },
{ name: 'GitHub', value: 'https://github.com/kettei-sproutty', Icon: SocialGithubIcon },
{ name: 'Twitter', value: 'https://x.com/alessiom97', Icon: SocialXIcon },
{
Expand All @@ -45,25 +46,34 @@ export const resume = {
projects: [
{
description:
'Team of 3, build a Fullstack application for analyzing website a11y (WCAG 2.2) issues, and a stream-based AI chatbot for suggesting fixes.',
'Team of 3, developed a full-stack application for analyzing website accessibility (WCAG 2.2) issues and a stream-based AI chatbot for suggesting fixes.',
stack: ['NextJS', 'Node (Hono)', 'MongoDB', 'IA', 'TailwindCSS', 'GitHub', 'Figma'],
},
{
description:
'Team of 3, build a WYSIWYG editor, similar to Docs/Word, with pagination, normalization, and custom blocks.',
'Team of 3, built a WYSIWYG editor, similar to Docs/Word, featuring pagination, normalization, and custom blocks.',
stack: [
'React with Vite',
'SlateJS/PlateJS',
'SlateJS',
'TailwindCSS',
'Jotai',
'Turborepo',
'Azure',
'Figma',
],
},
{
description:
'Team of 2, build an interactive 2D application, using sprites and animations, and a Rust script that generates the sprites.',
stack: ['NextJS (SSG)', 'ThreeJS (R3F)', 'Rust', 'Framer Motion', 'Azure', 'Figma'],
'Team of 2, built an interactive 2D application using sprites and animations, along with a Rust script that generates the sprites atlas.',
stack: [
'NextJS (SSG)',
'ThreeJS (R3F)',
'Valtio',
'Rust',
'Framer Motion',
'Azure',
'Figma',
],
},
],
},
Expand All @@ -73,13 +83,13 @@ export const resume = {
projects: [
{
description:
'Team of 6, build a graph-based web application, for handling connections between nodes rappresenting a power plant. After the delivery it was studied a refactor using react-flow instead of mxgraph.',
stack: ['React', 'mxGraph', 'SASS', 'Azure', 'Figma'],
'Team of 6, built a graph-based web application for handling connections between nodes in a power plant. After delivery, we studied a refactor using React Flow instead of mxGraph.',
stack: ['React', 'mxGraph', 'Redux', 'SASS', 'Azure', 'Figma'],
},
{
description:
'Team of 8, progressive rewrite of a web application, from VanillaJS to Vue, with a new design and new features, handling the integration with payment services.',
stack: ['Vue', 'Nuxt', 'Adobe IO', 'Adobe AEM', 'Miro'],
'Team of 8, progressively rewrote a web application from VanillaJS to Vue, incorporating a new design and new features, and managing the integration with payment services.',
stack: ['Vue', 'Nuxt', 'Vuex', 'Adobe IO', 'Adobe AEM', 'Miro'],
},
],
period: '2021 - 2022',
Expand All @@ -91,7 +101,7 @@ export const resume = {
projects: [
{
description:
'Team of 4, developed an application for reserving sport fields in Rome. The application was built using a microservices architecture, with a federated GraphQL gateway.',
'Team of 4, developed an application for reserving sports fields in Rome. The application was built using a microservices architecture with a federated GraphQL gateway.',
stack: ['React', 'GraphQL (Apollo Server/Client)', 'Apollo Federation', 'MongoDB'],
},
],
Expand All @@ -103,7 +113,7 @@ export const resume = {
projects: [
{
description:
'Solo project, developed a portal for creating and managing insurance policies, where customers can track their policies and make payments.',
'Solo project, developed a portal for creating and managing insurance policies, enabling customers to track their policies and make payments.',
stack: ['NextJS (SSR)', 'Hasura', 'PostgreSQL', 'GraphQL'],
},
],
Expand All @@ -120,6 +130,7 @@ export const resume = {
'Apollo GraphQL',
'Tauri',
'Leptos',
'Valtio/Jotai/Redux',
'Axum/Rocket',
'Redis',
'SlateJS',
Expand Down
28 changes: 28 additions & 0 deletions src/components/ui/button.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script lang="ts">
import { cn } from '$lib'
import type { HTMLAttributes, HTMLButtonAttributes } from 'svelte/elements'
type ButtonProps = Omit<HTMLButtonAttributes, 'type'> & {
hasIcon?: boolean
fullWidth?: boolean
type: Exclude<HTMLButtonAttributes['type'], undefined | null>
}
const { children, type, fullWidth = false, class: className, ...props }: ButtonProps = $props()
</script>

<button
type={type}
class={cn(
"border border-primary-700 bg-primary-700 transition-colors duration-200 ease-in-out text-primary-200 px-2 py-1 rounded-md flex items-center gap-2",
"hover:bg-primary-600 focus:bg-primary-700 focus:outline-none active:bg-primary-800 active:text-primary-100",
{
"flex gap-2 items-center": props.hasIcon,
"w-full flex items-center justify-center": fullWidth,
},
className,
)}
{...props}
>
{@render children?.()}
</button>
Loading

0 comments on commit 70b9454

Please sign in to comment.