diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 33140ac..0000000 --- a/.babelrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "presets": ["next/babel"], - "plugins": [ - [ - "styled-components", - { - "ssr": true - } - ] - ] -} diff --git a/.env.example b/.env.example deleted file mode 100644 index 65a3cf3..0000000 --- a/.env.example +++ /dev/null @@ -1,2 +0,0 @@ -NEXT_PUBLIC_FORMSPREE_KEY=FORMSPREE_KEY -NEXT_PUBLIC_GOOGLE_ANALYTICS_KEY=GOOGLE_ANALYTICS_KEY \ No newline at end of file diff --git a/.github/workflows/hugo.yaml b/.github/workflows/hugo.yaml new file mode 100644 index 0000000..696f423 --- /dev/null +++ b/.github/workflows/hugo.yaml @@ -0,0 +1,76 @@ +# Sample workflow for building and deploying a Hugo site to GitHub Pages +name: Deploy to GitHub Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: + - rebuild + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: 'pages' + cancel-in-progress: false + +# Default to bash +defaults: + run: + shell: bash + +jobs: + # Build job + build: + runs-on: ubuntu-latest + env: + HUGO_VERSION: 0.120.2 + steps: + - name: Install Hugo CLI + run: | + wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \ + && sudo dpkg -i ${{ runner.temp }}/hugo.deb + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + - name: Setup Pages + id: pages + uses: actions/configure-pages@v3 + - name: Install Node.js dependencies + run: '[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true' + - name: Build with Hugo + env: + # For maximum backward compatibility with Hugo modules + HUGO_ENVIRONMENT: production + HUGO_ENV: production + run: | + hugo \ + --gc \ + --minify \ + --baseURL "${{ steps.pages.outputs.base_url }}/" + - name: Upload artifact + uses: actions/upload-pages-artifact@v2 + with: + path: ./public + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 diff --git a/.gitignore b/.gitignore index 1437c53..8a19fab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,34 +1,4 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. +public/ +resources/ -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env.local -.env.development.local -.env.test.local -.env.production.local - -# vercel -.vercel +.hugo_build.lock \ No newline at end of file diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 22c8bbc..0000000 --- a/.prettierignore +++ /dev/null @@ -1,32 +0,0 @@ -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env.local -.env.development.local -.env.test.local -.env.production.local - -# vercel -.vercel diff --git a/_projects/astrobuild.mdx b/_projects/astrobuild.mdx deleted file mode 100644 index a2911b2..0000000 --- a/_projects/astrobuild.mdx +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: 'Astrobuild' -description: 'Prototype of a collaboration tool between stakeholders for building software projects' -date: '2023-06-11' -demo: 'https://astrobuild.vercel.app' -code: 'https://github.com/hazemKrimi/astrobuild' -tags: ['react', 'typescript', 'graphql', 'styled-components', 'apollographql', 'vite', 'react-flow'] ---- - -# Introduction - -This was my final year of studies projects where my collegue and I worked on a prototype for a project building solution for the agency we had an internship in called [Astrolab](https://astrolab-agency.com). -As there were lockdowns in Tunisia in 2020/2021 because of covid software agencies and clients could not have in person meetings to discuss a client's software project. -So the idea of Astrobuild is to reduce meetings and make the client participate with other stakeholders in the process of creating a software project by tracking and communicating with their associated product owner. - -# Features - -### Client - - Account management - - Project creation from choosing the templates, features and deliverables (Specification, design, MVP or full build) - - Project tracking - - Chat with associated product owner for tracking and support - - Payment (WIP) - -### Product Owner - - Account management - - Management of templates - - Review of projects and transferring deliverables - - Chat with clients on their projects - -### Developer - - Account management - - Features, categories and wireframes management - -### Admin - - Identity and access management (WIP) - -# Technologies Used -The frontend project is a [React](https://react.dev) application with [TypeScript](https://www.typescriptlang.org) which consumes a set of [GraphQL](https://graphql.org) APIs using [Apollo GraphQL](https://www.apollographql.com) and a some REST APIs. - -A small components library with a custom theme was made for this project using [Styled Components](https://styled-components.com) which can be viewed at the components folder. - -The prototyping feature was done using [React Flow](https://reactflow.dev) which is a library for creating and interacting with diagrams. - -To view the full architecture of the application go [here](https://github.com/MedAmineFouzai/astrobuild-api/blob/main/README.md). - -# Screenshots - -### Project page for the client -![Project](https://github.com/hazemKrimi/astrobuild/blob/main/screenshots/project.png?raw=true) - -### Template page for the product owner -![Template](https://github.com/hazemKrimi/astrobuild/blob/main/screenshots/template.png?raw=true) - -### Prototype page for the developer -![Prototype](https://github.com/hazemKrimi/astrobuild/blob/main/screenshots/prototype.png?raw=true) - -### Support page for the product owner -![Support](https://github.com/hazemKrimi/astrobuild/blob/main/screenshots/support.png?raw=true) - -### User editing page for the admin -![Admin](https://github.com/hazemKrimi/astrobuild/blob/main/screenshots/admin.png?raw=true) - -# Credits - -- Mohamed Amine Fouzai: [GitHub](https://github.com/MedAmineFouzai), [LinkedIn](https://www.linkedin.com/in/amine-fouzai) \ No newline at end of file diff --git a/_projects/react-weather-app.mdx b/_projects/react-weather-app.mdx deleted file mode 100644 index 3ee0cb7..0000000 --- a/_projects/react-weather-app.mdx +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: 'React Weather App' -description: 'Weather app made with React, TypeScript and OpenWeatherMap API' -date: '2021-09-19' -demo: 'https://hazemkrimi.github.io/react-weather-app' -code: 'https://github.com/hazemKrimi/react-weather-app' -tags: ['react', 'typescript', 'openweathermap'] ---- - -# About the project - -This is a project that I made as a step in the interview process for my final year internship. - -# Technologies - -- React -- TypeScript -- Styled Components -- OpenWeatherMap API - -# Screenshots - -![Desktop](https://res.cloudinary.com/dun9hhyz1/image/upload/v1643548378/personal-website/portfolio/react-weather-app/screenshot_ueu2a4.png) diff --git a/archetypes/default.md b/archetypes/default.md new file mode 100644 index 0000000..00e77bd --- /dev/null +++ b/archetypes/default.md @@ -0,0 +1,6 @@ +--- +title: "{{ replace .Name "-" " " | title }}" +date: {{ .Date }} +draft: true +--- + diff --git a/assets/android-chrome-192x192.png b/assets/android-chrome-192x192.png new file mode 100644 index 0000000..f3952be Binary files /dev/null and b/assets/android-chrome-192x192.png differ diff --git a/assets/apple-touch-icon.png b/assets/apple-touch-icon.png new file mode 100644 index 0000000..c19973e Binary files /dev/null and b/assets/apple-touch-icon.png differ diff --git a/assets/css/about.css b/assets/css/about.css new file mode 100644 index 0000000..d71dd95 --- /dev/null +++ b/assets/css/about.css @@ -0,0 +1,9 @@ +section img { + float: right; +} + +@media only screen and (max-width: 1024px) { + section img { + display: none; + } +} diff --git a/assets/css/baseof.css b/assets/css/baseof.css new file mode 100644 index 0000000..215a908 --- /dev/null +++ b/assets/css/baseof.css @@ -0,0 +1,169 @@ +@font-face { + font-family: 'Open Sans'; + src: url('/fonts/OpenSans.ttf') format('ttf'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'Open Sans'; + src: url('/fonts/OpenSans-Italic.ttf') format('ttf'); + font-weight: normal; + font-style: italic; +} + +:root { + --black: #131314; + --white: white; + --crimson: #bd1839; + --light-gray: #e7e7e7; + --dark-background: #1d1b1b; + --light-background: #fbfbfb; + --partial-dark-background: var(--black); + --partial-light-background: #ececec; + --card-radius: 1.875rem; + --form-radius: 0.563rem; + --shadow: 0px 4px 8px rgba(0, 0, 0, 0.04); +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +* { + margin: 0; +} + +::-webkit-scrollbar { + width: 0; + height: 0; + background: transparent; +} + +::-webkit-scrollbar-thumb { + background: transparent; +} + +::selection { + background: var(--text); + color: var(--background); +} + +body { + font-family: 'Open Sans', sans-serif; + font-size: 16px; + line-height: 1.5; + -webkit-font-smoothing: antialiased; + + background-color: var(--background); + color: var(--text); + + isolation: isolate; + user-select: text; +} + +body::-webkit-scrollbar { + width: 0.5rem !important; +} + +body::-webkit-scrollbar-thumb { + background-color: var(--text) !important; +} + +#links .linkedin, +#links .github, +#links .cv-paper-flip, +#links .mail, +#nav-toggler svg path, +.arrow, +.eye, +.calendar, +.clock, +.share { + stroke: var(--text); +} + +#links .twitter, +#links .rss, +#links .cv, +#links .moon > path { + fill: var(--text); +} + +main { + width: 85%; + min-height: 70vh; + margin: auto; +} + +img, +picture, +video, +canvas, +svg { + max-width: 100%; +} + +input, +button, +textarea, +select { + font: inherit; +} + +p, +h1, +h2, +h3, +h4, +h5, +h6 { + overflow-wrap: break-word; +} + +main h1, +main h2, +main h3 { + margin-bottom: 1rem; +} + +main p { + margin-bottom: 2rem; +} + +main h1 { + font-size: 4rem; +} + +main h2 { + font-size: 3rem; +} + +main h3 { + font-size: 2rem; +} + +a { + color: var(--text); +} + +a, +button { + cursor: pointer; +} + +@media only screen and (max-width: 1024px) { + main h1 { + font-size: 2.5rem; + } + + main h2 { + font-size: 1.75rem; + } + + main h3 { + font-size: 1.25rem; + } +} diff --git a/assets/css/index.css b/assets/css/index.css new file mode 100644 index 0000000..acbad26 --- /dev/null +++ b/assets/css/index.css @@ -0,0 +1,75 @@ +:root { + --first-action-dark-background: #353535; + --first-action-light-background: var(--partial-dark-background); + --second-action-dark-background: #f3f3f3; + --second-action-light-background: var(--partial-light-background); +} + +main h1 { + text-transform: capitalize; +} + +main h1 span, +main h1 a { + color: var(--crimson); +} + +main h1 a { + text-decoration: none; +} + +main #intro { + display: flex; + column-gap: 1rem; +} + +main #intro img { + width: 19.6875rem; + height: 19.6875rem; +} + +main #intro #action-buttons { + display: flex; + column-gap: 1rem; +} + +main #intro #action-buttons a { + text-decoration: none; + border-radius: 0.5625rem; + padding: 1rem 2rem; +} + +main #intro #action-buttons a:first-of-type { + background-color: var(--first-action-background); + color: var(--white); +} + +main #intro #action-buttons a:last-of-type { + background-color: var(--second-action-background); + color: var(--black); +} + +main section { + margin-bottom: 5rem; +} + +main #projects > div:first-of-type, +main #blog > div:first-of-type { + display: flex; + align-items: center; + justify-content: space-between; +} + +@media only screen and (max-width: 1024px) { + main section { + margin-bottom: 2rem; + } + + main #intro #action-buttons { + margin-top: 1.5rem; + } + + main #intro img { + display: none; + } +} diff --git a/assets/css/list.css b/assets/css/list.css new file mode 100644 index 0000000..5898f86 --- /dev/null +++ b/assets/css/list.css @@ -0,0 +1,18 @@ +main #tags { + display: flex; + align-items: center; + column-gap: 1rem; + margin-bottom: 2rem; +} + +main #tags a { + border-radius: 0.5625rem; + background-color: #5a5a5a; + color: var(--white); + padding: 0.5rem 1rem; + text-decoration: none; +} + +main #tags .selected { + background-color: var(--crimson); +} diff --git a/assets/css/partials.css b/assets/css/partials.css new file mode 100644 index 0000000..d35a213 --- /dev/null +++ b/assets/css/partials.css @@ -0,0 +1,418 @@ +:root { + --about-card-light-background: var(--partial-light-background); + --about-card-dark-background: var(--partial-dark-background); + --button-light-background: var(--partial-dark-background); + --button-dark-background: #353535; + --card-light-background: var(--partial-light-background); + --card-dark-background: var(--partial-dark-background); + --input-light-background: var(--partial-light-background); + --input-dark-background: #2d2d2d; + --footer-light-background: var(--partial-light-background); + --footer-dark-background: var(--partial-dark-background); + --header-light-background: var(--partial-light-background); + --header-dark-background: #676666; + --nav-light-background: var(--partial-light-background); + --nav-dark-background: var(--partial-dark-background); + --toc-light-background: var(--partial-light-background); + --toc-dark-background: var(--partial-dark-background); +} + +#about-card { + background-color: var(--about-card-background); + color: var(--text); + border-radius: 1.875rem; + padding: 3.5rem 2.5rem; + margin-bottom: 2rem; + display: flex; + column-gap: 2rem; +} + +#about-card img { + width: 8.9375rem; + height: 8.9375rem; +} + +#about-card h3 { + margin-bottom: 1.75rem; + text-transform: capitalize; +} + +#about-card p { + margin-bottom: 4rem; +} + +#about-card #links { + display: flex; + align-items: center; + justify-content: space-between; +} + +.breadcrumb { + margin-bottom: 1.5rem; +} + +.breadcrumb ol { + padding-left: 0; +} + +.breadcrumb li { + display: inline; +} + +.breadcrumb li:not(:last-child)::after { + content: '›'; + margin: 0rem 0.5rem; +} + +.breadcrumb a { + text-transform: capitalize; +} + +.breadcrumb .tag { + text-transform: lowercase; +} + +.card { + background-color: var(--card-background); + color: var(--text); + border-radius: 1.875rem; + padding: 3.5rem 2.5rem; + margin-bottom: 2rem; +} + +.card h3 { + margin-bottom: 1.75rem; + text-transform: capitalize; +} + +.card .date { + font-weight: bold; +} + +.card p { + margin-top: 1rem; +} + +.card #links { + display: flex; + align-items: center; + justify-content: space-between; +} + +.card .read-more, +.card .demo { + display: inline-flex; + align-items: center; + column-gap: 0.25rem; +} + +.card .demo { + background-color: #353535; + color: var(--white); + border-radius: 0.4375rem; + text-decoration: none; + padding: 0.5rem 1rem; +} + +.card .demo .eye { + stroke: var(--white); +} + +input, +textarea, +button, +#submission-status { + border: none; + border-radius: 0.5625rem; + color: var(--text); +} + +input, +textarea { + padding: 1.2rem 1.9rem; + background-color: var(--input-background); +} + +textarea { + resize: none; +} + +form { + display: flex; + flex-direction: column; + align-items: start; + justify-content: center; + row-gap: 1.7rem; +} + +form input, +form textarea { + width: 100%; +} + +form div { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + row-gap: 1.7rem; +} + +form button, +form #submission-status { + padding: 1rem 2.8rem; + background-color: var(--button-background); + color: var(--white); +} + +form #submission-status { + width: auto; + display: none; +} + +footer #links, +header #links, +#mobile-navigation #links { + display: flex; + align-items: center; + column-gap: 1.5rem; +} + +footer #links a, +header #links a, +header #menus a, +#mobile-navigation #links a { + display: inline-flex; + align-items: center; + justify-content: center; +} + +footer { + width: 100%; + padding: 3rem 8rem; + margin-top: 2.5rem; + display: flex; + align-items: center; + flex-direction: column; + row-gap: 5rem; + background-color: var(--footer-background); + color: var(--text); +} + +footer #footer-face { + display: flex; + align-items: center; + column-gap: 0.625rem; +} + +footer #copyright { + font-size: 0.875rem; +} + +header, +#mobile-navigation { + width: 85%; + border-radius: 0.75rem; + text-transform: uppercase; + color: var(--text); +} + +header { + margin: 2.5rem auto; + padding: 0.938rem 2.188rem; + background-color: var(--header-background); + display: flex; + align-items: center; + justify-content: space-between; +} + +#mobile-navigation { + background-color: var(--nav-background); + display: none; + position: fixed; + flex-direction: column; +} + +header #header-face { + display: flex; + align-items: center; + column-gap: 0.625rem; +} + +header #header-face span, +footer #footer-face span { + font-size: 1.17rem; + font-weight: 600; +} + +header #menus a, +#mobile-navigation #menus a { + text-decoration: none; + font-weight: 600; + font-size: 15px; +} + +header #menus { + display: flex; + align-items: center; + column-gap: 1.563rem; +} + +#mobile-navigation #menus { + display: flex; + flex-direction: column; + align-items: end; + justify-content: center; + row-gap: 3.125rem; +} + +#mobile-navigation hr { + margin-top: 3.125rem; + margin-bottom: 1.25rem; +} + +#mobile-navigation #links { + display: flex; + justify-content: end; + column-gap: 1.5rem; +} + +#mobile-navigation #links .theme-toggler { + margin-right: auto; +} + +header #nav-toggler { + display: none; +} + +.theme-toggler, +#nav-toggler { + cursor: pointer; +} + +.pagination { + display: flex; + justify-content: end; + align-items: center; +} + +.pagination { + display: flex; + column-gap: 1rem; +} + +.pagination .pagination ul, +.pagination li { + list-style: none; +} + +.pagination a { + border-radius: 0.5625rem; + background-color: #8b8b8b; + color: var(--white); + padding: 0.25rem 0.75rem; + display: inline-flex; + justify-content: center; + align-items: center; + text-decoration: none; +} + +.pagination a.first, +.pagination a.last { + background-color: #606060; +} + +.pagination a.active { + background-color: #232323; +} + +#table-of-contents { + position: sticky; + top: 3rem; + margin-top: 3rem; + height: 25rem; + max-height: 25rem; + padding: 1.2rem 1.6rem; + border-radius: 0.75rem; + background-color: var(--toc-background); +} + +#table-of-contents span { + font-weight: bold; + font-size: 1.5rem; +} + +#table-of-contents nav { + margin-top: 0.5rem; +} + +#table-of-contents nav ul { + list-style-type: none; + padding-inline-start: 2rem; + margin-bottom: 0rem; +} + +#table-of-contents nav > ul:first-of-type { + padding: 0rem; +} + +.vertical-separator { + border-left: 1px solid var(--text); + height: 24px; + opacity: 0.25; +} + +hr { + color: var(--text); + opacity: 0.25; +} + +@media only screen and (max-width: 768px) { + .pagination { + justify-content: center; + } +} + +@media only screen and (max-width: 1024px) { + #about-card { + flex-direction: column; + row-gap: 2rem; + } + + #about-card img { + align-self: center; + } + + .card { + padding: 2.5rem 1.5rem; + } + + .card h3 { + margin-bottom: 1.25rem; + } + + .card p { + margin-bottom: 1.75rem; + } + + footer { + padding: 3rem 5rem; + row-gap: 3rem; + } + + header, + #mobile-navigation { + margin: 1.5rem auto; + padding: 0.938rem 1.25rem; + } + + header #menus, + header #links { + display: none; + } + + header #nav-toggler { + display: initial; + } +} diff --git a/assets/css/single.css b/assets/css/single.css new file mode 100644 index 0000000..c49bc92 --- /dev/null +++ b/assets/css/single.css @@ -0,0 +1,66 @@ +main #container { + display: grid; + grid-template-columns: auto minmax(15rem, 20rem); + column-gap: 2rem; +} + +main #metadata { + margin-bottom: 2rem; +} + +main #metadata div { + min-width: 100%; + display: flex; + column-gap: 2rem; +} + +main #metadata div span { + display: inline-flex; + align-items: center; + column-gap: 0.25rem; +} + +main #metadata div #share { + display: none; +} + +main #metadata #share { + cursor: pointer; +} + +main #content ul, +main #content ol, +main #content .highlight { + margin-bottom: 2rem; +} + +main #content .highlight pre, +main #content .highlight div { + border-radius: 0.75rem; +} + +main #content .highlight div { + padding: 2rem 1rem; +} + +main #content .highlight pre { + padding: 0rem; +} + +@media only screen and (max-width: 1024px) { + main #container { + display: block; + } + + main #container #table-of-contents { + display: none; + } + + main #metadata div { + column-gap: 0.75rem; + } + + main #metadata div #share { + display: inline-flex; + } +} diff --git a/public/resume.pdf b/assets/cv.pdf old mode 100644 new mode 100755 similarity index 100% rename from public/resume.pdf rename to assets/cv.pdf diff --git a/assets/favicon-16x16.png b/assets/favicon-16x16.png new file mode 100644 index 0000000..9873984 Binary files /dev/null and b/assets/favicon-16x16.png differ diff --git a/assets/favicon-32x32.png b/assets/favicon-32x32.png new file mode 100644 index 0000000..31aa9cd Binary files /dev/null and b/assets/favicon-32x32.png differ diff --git a/assets/favicon.ico b/assets/favicon.ico new file mode 100644 index 0000000..2659857 Binary files /dev/null and b/assets/favicon.ico differ diff --git a/assets/fonts/OpenSans-Italic.ttf b/assets/fonts/OpenSans-Italic.ttf new file mode 100644 index 0000000..5bda9cc Binary files /dev/null and b/assets/fonts/OpenSans-Italic.ttf differ diff --git a/assets/fonts/OpenSans.ttf b/assets/fonts/OpenSans.ttf new file mode 100644 index 0000000..e4142bf Binary files /dev/null and b/assets/fonts/OpenSans.ttf differ diff --git a/assets/icons/arrow.svg b/assets/icons/arrow.svg new file mode 100644 index 0000000..62cd45e --- /dev/null +++ b/assets/icons/arrow.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/burger.svg b/assets/icons/burger.svg new file mode 100644 index 0000000..05e4970 --- /dev/null +++ b/assets/icons/burger.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/icons/calendar.svg b/assets/icons/calendar.svg new file mode 100644 index 0000000..12334c5 --- /dev/null +++ b/assets/icons/calendar.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/assets/icons/clock.svg b/assets/icons/clock.svg new file mode 100644 index 0000000..fdb927f --- /dev/null +++ b/assets/icons/clock.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/assets/icons/close.svg b/assets/icons/close.svg new file mode 100644 index 0000000..b095f1e --- /dev/null +++ b/assets/icons/close.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/cv.svg b/assets/icons/cv.svg new file mode 100644 index 0000000..0182d16 --- /dev/null +++ b/assets/icons/cv.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/icons/double-chevrons.svg b/assets/icons/double-chevrons.svg new file mode 100644 index 0000000..74fdfc8 --- /dev/null +++ b/assets/icons/double-chevrons.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/eye.svg b/assets/icons/eye.svg new file mode 100644 index 0000000..45f8ec2 --- /dev/null +++ b/assets/icons/eye.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/github.svg b/assets/icons/github.svg new file mode 100644 index 0000000..6025fe2 --- /dev/null +++ b/assets/icons/github.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/icons/linkedin.svg b/assets/icons/linkedin.svg new file mode 100644 index 0000000..2b8f0af --- /dev/null +++ b/assets/icons/linkedin.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/icons/mail.svg b/assets/icons/mail.svg new file mode 100644 index 0000000..022b1a8 --- /dev/null +++ b/assets/icons/mail.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/moon.svg b/assets/icons/moon.svg new file mode 100644 index 0000000..160c5f0 --- /dev/null +++ b/assets/icons/moon.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/rss.svg b/assets/icons/rss.svg new file mode 100644 index 0000000..df767b4 --- /dev/null +++ b/assets/icons/rss.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/share.svg b/assets/icons/share.svg new file mode 100644 index 0000000..74e1bc7 --- /dev/null +++ b/assets/icons/share.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/assets/icons/sun.svg b/assets/icons/sun.svg new file mode 100644 index 0000000..bf5036b --- /dev/null +++ b/assets/icons/sun.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/icons/twitter.svg b/assets/icons/twitter.svg new file mode 100644 index 0000000..a7b06be --- /dev/null +++ b/assets/icons/twitter.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/images/big-face.webp b/assets/images/big-face.webp new file mode 100644 index 0000000..6fb3b40 Binary files /dev/null and b/assets/images/big-face.webp differ diff --git a/assets/images/borded-face.webp b/assets/images/borded-face.webp new file mode 100644 index 0000000..09e3d38 Binary files /dev/null and b/assets/images/borded-face.webp differ diff --git a/assets/images/small-face.webp b/assets/images/small-face.webp new file mode 100644 index 0000000..7085b91 Binary files /dev/null and b/assets/images/small-face.webp differ diff --git a/assets/js/baseof.js b/assets/js/baseof.js new file mode 100644 index 0000000..537558a --- /dev/null +++ b/assets/js/baseof.js @@ -0,0 +1,121 @@ +function initTheme() { + const persistedColorPreference = window.localStorage.getItem('theme'); + const hasPersistedPreference = typeof persistedColorPreference === 'string'; + + if (hasPersistedPreference) { + return persistedColorPreference; + } + + const mql = window.matchMedia('(prefers-color-scheme: dark)'); + const hasMediaQueryPreference = typeof mql.matches === 'boolean'; + + if (hasMediaQueryPreference) { + return mql.matches ? 'dark' : 'light'; + } + + return 'light'; +} + +function loadTheme() { + root.style.setProperty('--theme', theme); + root.style.setProperty( + '--background', + theme === 'light' ? 'var(--light-background)' : 'var(--dark-background)' + ); + root.style.setProperty( + '--header-background', + theme === 'light' + ? 'var(--header-light-background)' + : 'var(--header-dark-background)' + ); + root.style.setProperty( + '--nav-background', + theme === 'light' + ? 'var(--nav-light-background)' + : 'var(--nav-dark-background)' + ); + root.style.setProperty( + '--first-action-background', + theme === 'light' + ? 'var(--first-action-light-background)' + : 'var(--first-action-dark-background)' + ); + root.style.setProperty( + '--second-action-background', + theme === 'light' + ? 'var(--second-action-light-background)' + : 'var(--second-action-dark-background)' + ); + root.style.setProperty( + '--input-background', + theme === 'light' + ? 'var(--input-light-background)' + : 'var(--input-dark-background)' + ); + root.style.setProperty( + '--button-background', + theme === 'light' + ? 'var(--button-light-background)' + : 'var(--button-dark-background)' + ); + root.style.setProperty( + '--card-background', + theme === 'light' + ? 'var(--card-light-background)' + : 'var(--card-dark-background)' + ); + root.style.setProperty( + '--toc-background', + theme === 'light' + ? 'var(--toc-light-background)' + : 'var(--toc-dark-background)' + ); + root.style.setProperty( + '--about-card-background', + theme === 'light' + ? 'var(--about-card-light-background)' + : 'var(--about-card-dark-background)' + ); + root.style.setProperty( + '--footer-background', + theme === 'light' + ? 'var(--footer-light-background)' + : 'var(--footer-dark-background)' + ); + root.style.setProperty( + '--header-shadow', + theme === 'light' ? 'var(--shadow)' : 'none' + ); + root.style.setProperty('--text', theme === 'light' ? 'black' : 'white'); + root.style.setProperty('--color', theme === 'light' ? 'black' : 'white'); + + document.querySelector( + theme === 'light' ? 'header .moon' : 'header .sun' + ).style.display = 'none'; + document.querySelector( + theme === 'light' ? 'nav .moon' : 'nav .sun' + ).style.display = 'none'; + document.querySelector( + theme === 'light' ? 'header .sun' : 'header .moon' + ).style.display = 'block'; + document.querySelector( + theme === 'light' ? 'nav .sun' : 'nav .moon' + ).style.display = 'block'; +} + +function updateTheme() { + theme = theme === 'light' ? 'dark' : 'light'; + window.localStorage.setItem('theme', theme); + loadTheme(); +} + +const root = document.documentElement; +const themeTogglers = document.querySelectorAll('.theme-toggler'); + +let theme = initTheme(); + +document.addEventListener('DOMContentLoaded', loadTheme); + +themeTogglers.forEach((themerToggler) => + themerToggler.addEventListener('click', updateTheme) +); diff --git a/assets/js/contact-form.js b/assets/js/contact-form.js new file mode 100644 index 0000000..3abd7e7 --- /dev/null +++ b/assets/js/contact-form.js @@ -0,0 +1,32 @@ +const form = document.querySelector('form'); +const submissionStatus = form.querySelector('#submission-status'); + +form.addEventListener('submit', (event) => { + event.preventDefault(); + + fetch(event.target.action, { + method: event.target.method, + body: new FormData(event.target), + headers: { + Accept: 'application/json', + }, + }) + .then((response) => { + if (response.ok) { + submissionStatus.innerHTML = 'Message sent successfully!'; + submissionStatus.style.display = 'block'; + form.reset(); + } + }) + .catch((error) => { + submissionStatus.innerHTML = 'Error sending message!'; + submissionStatus.style.display = 'block'; + console.error(error); + }) + .finally(() => { + setTimeout(() => { + submissionStatus.innerHTML = ''; + submissionStatus.style.display = 'none'; + }, 5000); + }); +}); diff --git a/assets/js/mobile-navigation.js b/assets/js/mobile-navigation.js new file mode 100644 index 0000000..48c736d --- /dev/null +++ b/assets/js/mobile-navigation.js @@ -0,0 +1,64 @@ +function loadBurger() { + const headerInitialLeftPosition = header.getBoundingClientRect().x; + + navToggler.querySelector(burgerOpen ? '#burger' : '#close').style.display = + 'none'; + navToggler.querySelector(burgerOpen ? '#close' : '#burger').style.display = + 'block'; + header.style.position = burgerOpen ? 'fixed' : 'initial'; + header.style.top = burgerOpen ? '0px' : 'initial'; + header.style.left = burgerOpen ? `${headerInitialLeftPosition}px` : 'initial'; + mobileNavigation.style.display = burgerOpen ? 'flex' : 'none'; + mobileNavigation.style.top = burgerOpen + ? `calc(${header.getBoundingClientRect().y}px + ${ + header.getBoundingClientRect().height + }px)` + : 'initial'; + mobileNavigation.style.left = burgerOpen + ? `${headerInitialLeftPosition}px` + : 'initial'; + document.querySelector('main').style.marginTop = burgerOpen + ? `calc(${header.getBoundingClientRect().height}px + 3rem)` + : '0px'; +} + +function updateBurger() { + burgerOpen = !burgerOpen; + loadBurger(); +} + +function resetBurger() { + burgerOpen = false; + loadBurger(); +} + +function resetBurgerWhenWindowResized() { + if (window.innerWidth > 1024) { + resetBurger(); + } +} + +function resetBurgerWhenClickedOutside(event) { + if ( + mobileNavigation.style.display === 'flex' && + event.target !== header && + event.target !== mobileNavigation && + !mobileNavigation.contains(event.target) && + !navToggler.contains(event.target) + ) { + resetBurger(); + } +} + +const navToggler = document.querySelector('#nav-toggler'); +const header = document.querySelector('header'); +const mobileNavigation = document.querySelector('nav'); +let burgerOpen = false; + +window.addEventListener('resize', resetBurgerWhenWindowResized); + +document.addEventListener('DOMContentLoaded', resetBurger); + +document.addEventListener('click', resetBurgerWhenClickedOutside); + +navToggler.addEventListener('click', updateBurger); diff --git a/components/Button/index.tsx b/components/Button/index.tsx deleted file mode 100644 index 7c0ff53..0000000 --- a/components/Button/index.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { Props } from './types'; -import { StyledButton } from './styles'; - -const Button = ({ - variant = 'text', - href, - target, - onClick, - children, - className, -}: Props) => ( - - {children} - -); - -export default Button; diff --git a/components/Button/styles.tsx b/components/Button/styles.tsx deleted file mode 100644 index 640f9da..0000000 --- a/components/Button/styles.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import styled from 'styled-components'; -import Link from 'next/link'; -import { Props } from './types'; - -export const StyledButton = styled(Link)` - position: relative; - display: inline; - cursor: pointer; - background: none; - color: var(--text); - border: ${({ variant }) => - variant === 'outline' ? '2px solid var(--text)' : '2px solid transparent'}; - font-weight: bold; - text-transform: ${({ variant }) => - variant === 'outline' ? 'uppercase' : 'inherit'}; - padding: ${({ variant }) => (variant === 'outline' ? '.5rem 1rem' : '0rem')}; - text-align: left; - text-decoration: none; - transition: color 250ms ease-in-out, border 250ms ease-in-out; - z-index: 1; - - @media (max-width: 768px) { - padding: ${({ variant }) => - variant === 'outline' ? '.5rem .75rem' : '0rem'}; - } - - &::before { - content: ''; - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - z-index: -1; - background-color: ${({ variant }) => - variant === 'outline' ? 'var(--text)' : 'inherit'}; - transition: transform 250ms ease-in-out; - transform: scaleX(0); - transform-origin: left; - } - - &:hover { - color: ${({ variant }) => - variant === 'outline' ? 'var(--background)' : 'inherit'}; - border: 2px solid transparent; - } - - &:hover::before { - transform: scaleX(1); - } -`; diff --git a/components/Button/types.ts b/components/Button/types.ts deleted file mode 100644 index 30dc416..0000000 --- a/components/Button/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -export type Props = { - variant?: 'outline' | 'text'; - href: string; - target?: HTMLAnchorElement['target']; - onClick?: () => void; - children: React.ReactNode; - className?: string; -}; diff --git a/components/Card/index.tsx b/components/Card/index.tsx deleted file mode 100644 index bfeed71..0000000 --- a/components/Card/index.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import Image from 'next/image'; -import { StyledCard } from './styles'; -import { Props } from './types'; - -const Card = ({ - title, - description, - image, - tags, - href, - target, - onClick, -}: Props) => { - return ( - -
-

{title}

-

{description}

- {tags && ( -
- {tags.map((tag, index) => ( - #{tag}  - ))} -
- )} -
- {image && ( -
- {title} -
- )} -
- ); -}; - -export default Card; diff --git a/components/Card/styles.tsx b/components/Card/styles.tsx deleted file mode 100644 index bed96bc..0000000 --- a/components/Card/styles.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import styled from 'styled-components'; -import Link from 'next/link'; - -export const StyledCard = styled(Link)<{ image?: boolean }>` - cursor: pointer; - width: 100%; - display: grid; - grid-template-columns: ${({ image }) => (image ? 'auto 9.375rem' : 'auto')}; - align-items: stretch; - transition: color 0ms ease-in-out; - text-decoration: none; - color: var(--text); - - @media (max-width: 320px) { - grid-template-columns: ${({ image }) => (image ? 'auto 7.813rem' : 'auto')}; - } - - @media (min-width: 1440px) { - grid-template-columns: ${({ image }) => - image ? 'auto 15.625rem' : 'auto'}; - } - - &:hover { - & > div { - background: ${({ theme }) => theme.colors.blue}; - - * { - color: ${({ theme }) => theme.colors.dark.text} !important; - } - } - - img { - filter: ${({ image }) => (image ? 'grayscale(80%)' : 'none')}; - } - } - - .card-content { - padding: 1rem 0rem; - background: var(--secondary-background); - display: grid; - row-gap: 0.5rem; - - @media (max-width: 768px) { - padding: 0.75rem 0rem; - } - } - - .card-image { - position: relative; - width: 100%; - } - - h3, - p, - .tags-wrapper { - padding: 0rem 1rem; - - @media (max-width: 768px) { - padding: 0rem 0.5rem; - } - } - - h3 { - font-size: 1.3rem; - } - - .tags-wrapper { - display: flex; - flex-direction: row; - align-content: center; - flex-wrap: wrap; - } - - span { - font-size: 0.7rem; - } -`; diff --git a/components/Card/types.ts b/components/Card/types.ts deleted file mode 100644 index 2b8e27e..0000000 --- a/components/Card/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -export interface Props { - title: string; - description: string; - image?: string; - tags?: string[]; - href: string; - target?: HTMLAnchorElement['target']; - onClick?: () => void; -} diff --git a/components/CodeBlock/index.tsx b/components/CodeBlock/index.tsx deleted file mode 100644 index be5d7ed..0000000 --- a/components/CodeBlock/index.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import Highlight, { defaultProps, Language } from 'prism-react-renderer'; -import theme from 'prism-react-renderer/themes/vsDark'; -import { Props } from './types'; -import { Line, LineContent, LineNo, Pre } from './styles'; - -const CodeBlock = ({ children, className }: Props) => { - const language = className.replace(/language-/, '') as Language; - - return ( - - {({ className, style, tokens, getLineProps, getTokenProps }) => ( -
-          {tokens.map((line, i) => (
-            
-              {i + 1}
-              
-                {line.map((token, key) => (
-                  
-                ))}
-              
-            
-          ))}
-        
- )} -
- ); -}; - -export default CodeBlock; diff --git a/components/CodeBlock/styles.tsx b/components/CodeBlock/styles.tsx deleted file mode 100644 index 502a527..0000000 --- a/components/CodeBlock/styles.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import styled from 'styled-components'; - -export const Pre = styled.pre` - text-align: left; - margin: 1em 0; - padding: 0.5em; - overflow: scroll; -`; - -export const Line = styled.div` - display: table-row; -`; - -export const LineNo = styled.span` - display: table-cell; - text-align: right; - padding-right: 1em; - user-select: none; - opacity: 0.5; -`; - -export const LineContent = styled.span` - display: table-cell; -`; diff --git a/components/CodeBlock/types.ts b/components/CodeBlock/types.ts deleted file mode 100644 index eff76be..0000000 --- a/components/CodeBlock/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface Props { - className: string; - children: React.ReactNode; -} diff --git a/components/Container.tsx b/components/Container.tsx deleted file mode 100644 index 058450c..0000000 --- a/components/Container.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import styled from 'styled-components'; - -const Container = styled.div` - width: 85%; - margin: auto; - - @media (max-width: 768px) { - width: 95%; - } -`; - -export default Container; diff --git a/components/Footer/index.tsx b/components/Footer/index.tsx deleted file mode 100644 index 4462214..0000000 --- a/components/Footer/index.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { useContext } from 'react'; -import { ThemeContext } from '../../styles/theme'; -import { StyledFooter } from './styles'; -import IconButton from '../IconButton'; - -const Footer = () => { - const { mode } = useContext(ThemeContext); - - return ( - -
- - - -
-

Hazem Krimi © {new Date().getFullYear()}

-
- ); -}; - -export default Footer; diff --git a/components/Footer/styles.tsx b/components/Footer/styles.tsx deleted file mode 100644 index 735753c..0000000 --- a/components/Footer/styles.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import styled from 'styled-components'; - -export const StyledFooter = styled.footer` - position: absolute; - bottom: 0; - min-height: 100px; - width: 85%; - margin: auto; - display: grid; - grid-template-columns: repeat(2, 1fr); - column-gap: 2rem; - justify-content: flex-end; - align-content: center; - padding: 1rem 0rem; - - @media (max-width: 768px) { - width: 95%; - } - - .contact { - display: grid; - grid-template-columns: repeat(auto-fill, 16px); - column-gap: 1rem; - align-items: center; - justify-content: flex-start; - - * { - user-select: none; - } - - @media (max-width: 768px) { - column-gap: 0.5rem; - } - } - - p { - display: inline; - text-align: right; - font-weight: bold; - } -`; diff --git a/components/GlobalStyles.tsx b/components/GlobalStyles.tsx deleted file mode 100644 index dc0cb4d..0000000 --- a/components/GlobalStyles.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { createGlobalStyle } from 'styled-components'; - -const GlobalStyles = createGlobalStyle` - * { - margin: 0; - padding: 0; - box-sizing: border-box; - font-family: 'Source Code Pro', monospace; - font-size: 16px; - line-height: 1.5; - outline: none; - user-select: text; - -webkit-tap-highlight-color: rgba(255, 255, 255, 0); - - @media(max-width: 768px) { - overflow-x: scroll; - } - - &::-webkit-scrollbar { - width: 0; - height: 0; - background: transparent; - } - - &::-webkit-scrollbar-thumb { - background: transparent; - } - - &::selection { - background: var(--text); - color: var(--background); - } - } - - html { - position: relative; - min-height: 100%; - background: var(--background) !important; - } - - * { - color: var(--text); - } - - ul, ol { - margin-inline-start: 1.9rem; - } - - body { - margin: 0 0 100px; - transition: color 250ms ease-in-out, background 250ms ease-in-out; - scroll-behavior: smooth; - - #nprogress .bar { - background: var(--text) !important; - } - - #nprogress .peg { - box-shadow: 0 0 10px var(--text), 0 0 5px var(--text) !important; - } - } - - body::-webkit-scrollbar { - width: 0.5rem !important; - } - - body::-webkit-scrollbar-thumb { - background-color: var(--text) !important; - } -`; - -export default GlobalStyles; diff --git a/components/Hero/index.tsx b/components/Hero/index.tsx deleted file mode 100644 index ce2853f..0000000 --- a/components/Hero/index.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Wrapper } from './styles'; -import Image from 'next/image'; - -const Hero = () => ( - -
-

Hi, I am Hazem

-

I Like Building Software

-

Full Stack TypeScript Developer

-

Life Long Learner

-
-
- Hazem Krimi -
-
-); - -export default Hero; diff --git a/components/Hero/styles.tsx b/components/Hero/styles.tsx deleted file mode 100644 index a4183ff..0000000 --- a/components/Hero/styles.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import styled from 'styled-components'; - -export const Wrapper = styled.div` - min-height: 45vh; - display: grid; - grid-template-columns: 1fr 32.188rem; - align-items: center; - height: auto; - text-align: left; - - @media (max-width: 1024px) { - min-height: 35vh; - grid-template-columns: 1fr; - - .photo { - display: none; - } - } - - h2 { - font-size: 1.5rem; - - @media (min-width: 1440px) { - font-size: 2rem; - } - - @media (min-width: 2560px) { - font-size: 3.5rem; - } - } - - .blue { - color: ${({ theme }) => theme.colors.blue}; - } -`; diff --git a/components/IconButton/index.tsx b/components/IconButton/index.tsx deleted file mode 100644 index 390d037..0000000 --- a/components/IconButton/index.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import Image from 'next/image'; -import { Props } from './types'; -import { StyledButton, StyledLink } from './styles'; - -const IconButton = ({ - alt, - icon, - href, - target, - onClick, - className, - width = 24, - height = 24, -}: Props) => - href ? ( - - {alt} - - ) : ( - - {alt} - - ); - -export default IconButton; diff --git a/components/IconButton/styles.tsx b/components/IconButton/styles.tsx deleted file mode 100644 index f75a111..0000000 --- a/components/IconButton/styles.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import styled, { css } from 'styled-components'; -import Link from 'next/link'; - -const sharedStyles = css` - cursor: pointer; - background: none; - border: none; - display: inline-flex; - align-items: center; -`; - -export const StyledLink = styled(Link)` - ${sharedStyles} -`; - -export const StyledButton = styled.button` - ${sharedStyles} -`; diff --git a/components/IconButton/types.ts b/components/IconButton/types.ts deleted file mode 100644 index 9dc87cd..0000000 --- a/components/IconButton/types.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface Props { - alt: string; - icon: string; - width?: number; - height?: number; - href?: string; - target?: HTMLAnchorElement['target']; - onClick?: () => void; - className?: string; -} diff --git a/components/Input/index.tsx b/components/Input/index.tsx deleted file mode 100644 index c1b2287..0000000 --- a/components/Input/index.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { BigField, SmallField } from './styles'; -import { Props } from './types'; - -const Input = ({ - type = 'text', - variant = 'small', - name, - value, - required, - placeholder, - className, - onChange, -}: Props) => { - return variant === 'small' ? ( - - ) : ( - - ); -}; - -export default Input; diff --git a/components/Input/styles.tsx b/components/Input/styles.tsx deleted file mode 100644 index 08ec3e8..0000000 --- a/components/Input/styles.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import styled from 'styled-components'; - -export const SmallField = styled.input` - border: none; - padding: 1rem; - background: var(--secondary-background); - color: var(--text); -`; - -export const BigField = styled.textarea` - resize: none; - border: none; - padding: 1rem; - background: var(--secondary-background); - color: var(--text); -`; diff --git a/components/Input/types.ts b/components/Input/types.ts deleted file mode 100644 index 51fab22..0000000 --- a/components/Input/types.ts +++ /dev/null @@ -1,12 +0,0 @@ -export interface Props { - placeholder?: string; - type: 'text' | 'email'; - variant: 'small' | 'big'; - name: string; - value: string; - required?: boolean; - onChange?: ( - event: React.ChangeEvent - ) => void; - className?: string; -} diff --git a/components/MDXButton/index.tsx b/components/MDXButton/index.tsx deleted file mode 100644 index afaaffb..0000000 --- a/components/MDXButton/index.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { useContext } from 'react'; -import { ThemeContext } from '../../styles/theme'; -import { Props } from './types'; -import { StyledLink, StyledButton } from './styles'; - -const MDXButton = ({ - variant = 'text', - type = 'button', - link, - target, - children, - disabled, - className, -}: Props) => { - const { mode } = useContext(ThemeContext); - - return link ? ( - - {children} - - ) : ( - - {children} - - ); -}; - -export default MDXButton; diff --git a/components/MDXButton/styles.tsx b/components/MDXButton/styles.tsx deleted file mode 100644 index 6be80bf..0000000 --- a/components/MDXButton/styles.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import Link from 'next/link'; -import styled, { css } from 'styled-components'; -import { Props } from './types'; - -export const sharedStyles = css` - cursor: pointer; - display: ${({ variant }) => - ['action', 'outline'].includes(variant as string) ? 'block' : 'inline'}; - width: ${({ variant }) => - ['action', 'outline'].includes(variant as string) ? '100%' : 'auto'}; - background: ${({ variant }) => (variant === 'action' ? '#1573CA' : 'none')}; - color: ${({ variant, mode }) => - variant === 'action' ? 'white' : mode === 'dark' ? 'white' : 'black'}; - border: ${({ variant, mode }) => - variant === 'outline' - ? `2px solid ${mode === 'dark' ? 'white' : 'black'}` - : 'none'}; - font-weight: bold; - font-size: ${({ variant }) => - ['action', 'outline'].includes(variant as string) ? '1.05rem' : 'inherit'}; - text-transform: ${({ variant }) => - ['action', 'outline'].includes(variant as string) - ? 'uppercase' - : 'inherit'}; - padding: ${({ variant }) => - ['action', 'outline'].includes(variant as string) ? '.5rem 1rem' : '0rem'}; - text-align: ${({ variant }) => - ['action', 'outline'].includes(variant as string) ? 'center' : 'left'}; - text-decoration: none; - transition: color 250ms ease-in-out; - - ${({ disabled }) => - disabled && - ` - background: gray; - cursor: default; - `} - - @media (max-width: 768px) { - padding: ${({ variant }) => - ['action', 'outline'].includes(variant as string) - ? '.5rem .75rem' - : '0rem'}; - } -`; - -export const StyledLink = styled(Link)` - ${sharedStyles} -`; - -export const StyledButton = styled.button>` - ${sharedStyles} -`; diff --git a/components/MDXButton/types.ts b/components/MDXButton/types.ts deleted file mode 100644 index 5bc3947..0000000 --- a/components/MDXButton/types.ts +++ /dev/null @@ -1,10 +0,0 @@ -export type Props = { - variant?: 'outline' | 'text' | 'action'; - type?: 'button' | 'submit'; - link?: string; - target?: HTMLAnchorElement['target']; - mode?: string; - disabled?: boolean; - className?: string; - children: React.ReactNode; -}; diff --git a/components/MobileNav/index.tsx b/components/MobileNav/index.tsx deleted file mode 100644 index 6b7df81..0000000 --- a/components/MobileNav/index.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { useContext, useRef, useEffect } from 'react'; -import { ThemeContext } from '../../styles/theme'; -import { Props } from './types'; -import { Bar } from './styles'; -import IconButton from '../IconButton'; -import Button from '../Button'; - -const MobileNav = ({ open, close }: Props) => { - const { mode, toggle } = useContext(ThemeContext); - const ref = useRef(null); - - useEffect(() => { - document.addEventListener('mousedown', (event: MouseEvent) => { - if (ref.current && ref.current.contains(event.target as Node)) { - document.addEventListener('mouseup', (event) => { - if (ref.current && !ref.current.contains(event.target as Node)) - return; - }); - } else { - document.addEventListener('mouseup', (event) => { - if (ref.current && !ref.current.contains(event.target as Node)) - close(); - }); - } - }); - - return () => { - document.removeEventListener('mousedown', () => {}); - document.removeEventListener('mouseup', () => {}); - }; - }); - - return ( - -
- -
-
- -
-
- -
-
- -
-
- -
-
- ); -}; - -export default MobileNav; diff --git a/components/MobileNav/styles.tsx b/components/MobileNav/styles.tsx deleted file mode 100644 index 380ca0f..0000000 --- a/components/MobileNav/styles.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import styled from 'styled-components'; -import { StyledProps } from './types'; - -export const Bar = styled.nav` - position: fixed; - z-index: 2; - top: 0; - right: 0; - transform-origin: right; - transform: ${({ open }) => (open ? 'translateX(0%)' : 'translateX(100%)')}; - width: 80%; - height: 100vh; - background: var(--text); - transition: transform 250ms ease-in-out; - display: grid; - grid-template-rows: 30% repeat(4, 50px); - padding: 1rem 1rem 5rem 1rem; - - @media (orientation: landscape) { - grid-template-rows: auto; - } - - .close { - justify-self: flex-end; - align-self: flex-start; - margin-top: 0.5rem; - } - - .mobile-button-wrapper { - display: flex; - margin: 0rem 1rem; - - a { - color: var(--text-inverted) !important; - } - } -`; diff --git a/components/MobileNav/types.ts b/components/MobileNav/types.ts deleted file mode 100644 index d677fb7..0000000 --- a/components/MobileNav/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -export type Props = { - open: boolean; - close: () => void; -}; - -export type StyledProps = { - open: boolean; -}; diff --git a/components/Nav/index.tsx b/components/Nav/index.tsx deleted file mode 100644 index d20dfd2..0000000 --- a/components/Nav/index.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { useContext, useState } from 'react'; -import { ThemeContext } from '../../styles/theme'; -import { Bar } from './styles'; -import Link from 'next/link'; -import Image from 'next/image'; -import Button from '../Button'; -import IconButton from '../IconButton'; -import MobileNav from '../MobileNav'; - -const Nav = () => { - const [mobileNavOpen, setMobileNavOpen] = useState(false); - const { mode, toggle } = useContext(ThemeContext); - - return ( - - - Logo Image -

Hazem Krimi

- -
- - - - - -
-
- - setMobileNavOpen(true)} - /> -
- setMobileNavOpen(false)} /> -
- ); -}; - -export default Nav; diff --git a/components/Nav/styles.tsx b/components/Nav/styles.tsx deleted file mode 100644 index 16efd84..0000000 --- a/components/Nav/styles.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import styled from 'styled-components'; - -export const Bar = styled.nav` - width: 100%; - display: grid; - grid-template-columns: auto 1fr; - align-items: center; - padding: 1rem 0rem; - - * { - user-select: none; - } - - h1 { - font-size: 1.7rem; - - @media (max-width: 768px) { - font-size: 1rem; - } - } - - div, - a.logo { - display: grid; - align-items: center; - column-gap: 1rem; - - @media (max-width: 768px) { - column-gap: 0.5rem; - } - } - - a.logo { - text-decoration: none; - color: var(--text); - cursor: pointer; - grid-template-columns: repeat(2, auto); - justify-content: flex-start; - } - - .buttons { - grid-template-columns: repeat(5, auto); - justify-content: flex-end; - - @media (max-width: 768px) { - display: none; - } - } - - .mobile-buttons { - display: none; - - @media (max-width: 768px) { - display: grid; - grid-template-columns: repeat(2, auto); - justify-content: flex-end; - } - } -`; diff --git a/content/_index.md b/content/_index.md new file mode 100644 index 0000000..980e6db --- /dev/null +++ b/content/_index.md @@ -0,0 +1,4 @@ +--- +title: 'Home' +date: 2023-10-18T20:03:43+01:00 +--- diff --git a/content/about.md b/content/about.md new file mode 100644 index 0000000..e8b85a8 --- /dev/null +++ b/content/about.md @@ -0,0 +1,33 @@ +--- +layout: 'about' +title: 'About' +date: 2023-10-18T20:03:43+01:00 +--- + +## About + +Hi again! So, you want to know more about me! We'll go through how I got into tech, my education and my career and some other things you might find interesting. Hopefully you enjoy reading about me and I am looking forward to chat! + +### How I got into Computer Science and Software Engineering + +Similar to many other software engineers stories I was fascinated by video games since childhood with the Atari, Nintendo Gameboy, N64, Game Cube and PC gaming. Some games I played when I was a kid are: Duck Hunt, Prince of Persia, IGI, Super Mario Bros (Of cource!) and many more. + +### My Education + +I am from Tunisia, and there you get to specialize in Computer Science early on in high school and that is exactly what I did in 2014. My first programming language was Pascal which is a similar language to Delphi. I learned the fundamentals of algorithms and data structures using Pascal, Networking fundamentals and got a little bit into webdev by the last year of high school. On my spare time, tinkered a bit with some game engines like Unity and Unreal 4 with some of my friends. + +In the summer of 2018, I got more interested in web development especially with JavaScript. So, in university I went for a program that is focused on web development but I did learn other stuff like C, Java, Linux, a bit of Assembly and I got into the intecacies of Computer Architecture and Operating Systems. + +The university program was mostly packed with the fundamentals but none of the technologies of today's world. So, I did a lot of learning by myself through small practice projects and participating in hackathons. Most of the technologies I work with today I learned by myself including: React.js and React Native, Node.js, TypeScript, GraphQL, MongoDB... + +### My Career + +I started my career as a Front End developer in a software agency in Tunisia called [EMIKETIC](https://www.emiketic.com) building mostly e-commerce websites for small to medium businesses and sometimes on custom solutions for clients. There I got to learn Next.js, Strapi and especially how to work effectively in a team environment where I got to hone my communication and collaboration skills. + +Then I started working remotely in a company based in the UK called [Cielo Costa](https://cielocosta.com) which is all about providing custom solutions to improves internal business processes. + +Currently, I am working at [Finteum](https://finteum.com) which is creating a global financial market for intraday liquidity, enabling interbank lending for hours at a time. + +### My Hobbies + +Even though I didn't pursue Game Development, I am still a gamer but I don't play that much anymore. Currently, I am more into Cycling, reading Mangas, Personal Development books and Computer Science related books. I also play [Chess](https://www.chess.com/member/hazemkrimi) and card games. \ No newline at end of file diff --git a/content/blog/_index.md b/content/blog/_index.md new file mode 100644 index 0000000..f7d3816 --- /dev/null +++ b/content/blog/_index.md @@ -0,0 +1,8 @@ +--- +title: "Blog" +date: 2023-10-18T20:03:43+01:00 +--- + +## Blog + +These are articles about things I learned about software engineering. \ No newline at end of file diff --git a/content/contact.md b/content/contact.md new file mode 100644 index 0000000..194e93d --- /dev/null +++ b/content/contact.md @@ -0,0 +1,9 @@ +--- +layout: 'contact' +title: 'Contact' +date: 2023-10-18T20:03:43+01:00 +--- + +## Contact + +Here you can contact me personally for any questions or opportunities. diff --git a/content/projects/_index.md b/content/projects/_index.md new file mode 100644 index 0000000..cfb64a6 --- /dev/null +++ b/content/projects/_index.md @@ -0,0 +1,8 @@ +--- +title: "Projects" +date: 2023-10-18T20:03:43+01:00 +--- + +## Projects + +These are all the projects I worked on personally and professionally. \ No newline at end of file diff --git a/content/projects/react-weather-app/index.md b/content/projects/react-weather-app/index.md new file mode 100644 index 0000000..6958cee --- /dev/null +++ b/content/projects/react-weather-app/index.md @@ -0,0 +1,23 @@ +--- +title: 'React Weather App' +description: 'Weather app made with React, TypeScript and OpenWeatherMap API' +demo: "https://hazemkrimi.github.io/react-weather-app" +date: 2023-09-19 +--- + +## About the project + +This is a project that I made as a step in the interview process for my final year internship. Here you can find its [source code](https://github.com/hazemKrimi/react-weather-app) or you can view the [demo](https://hazemkrimi.github.io/react-weather-app). + +The features are fetching the weather depending on the device's location or by using the search bar on the top right of the app. The weather data it fetches are the daily forecast, weekly forcast and today's wind and humidity. + +## Technologies + +- React +- TypeScript +- Styled Components +- OpenWeatherMap API + +## Screenshots + +![Project screenshot](react-weather-app-screenshot.webp) \ No newline at end of file diff --git a/content/projects/react-weather-app/react-weather-app-screenshot.webp b/content/projects/react-weather-app/react-weather-app-screenshot.webp new file mode 100644 index 0000000..486884e Binary files /dev/null and b/content/projects/react-weather-app/react-weather-app-screenshot.webp differ diff --git a/hugo.toml b/hugo.toml new file mode 100644 index 0000000..68d7a9e --- /dev/null +++ b/hugo.toml @@ -0,0 +1,60 @@ +languageCode = 'en' +title = 'Hazem Krimi' +paginate = 5 +enableRobotsTXT = true +[outputs] + home = ['html', 'rss'] + section = ['html', 'rss'] +[sitemap] + changeFreq = '' + filename = 'sitemap.xml' + priority = -1 +[taxonomies] + tag = 'tags' +[params] + formSpreeURL = 'https://formspree.io/f/xoqpgyge' + dateFormat = '02 January 2006' + defaultDescription = 'Personal website of Hazem Krimi' + defaultKeywords = 'Hazem Krimi, Software Engineer, Software Developer, Full Stack Developer, JavaScript, TypeScript, React, Node.js, Scala, Kotlin, Corda, SQL, GraphQL, MongoDB' + [params.author] + email = 'me@hazemkrimi.tech' + name = 'Hazem Krimi' +[module] +[menu] + [[menu.main]] + name = 'Home' + url = '/' + weight = 1 + [[menu.main]] + name = 'About' + url = '/about' + weight = 2 + [[menu.main]] + name = 'Projects' + url = '/projects' + weight = 3 + [[menu.main]] + name = 'Blog' + url = '/blog' + weight = 4 + [[menu.main]] + name = 'Contact' + url = '/contact' + weight = 5 +[[deployment.matchers]] + # Cache static assets for 1 year. + pattern = "^.+\\.(js|css|svg|ttf)$" + cacheControl = "max-age=31536000, no-transform, public" + gzip = true +[[deployment.matchers]] + pattern = "^.+\\.(gif|png|jpg|webp)$" + cacheControl = "max-age=31536000, no-transform, public" + gzip = false +[[deployment.matchers]] + # Set custom content type for /sitemap.xml + pattern = "^sitemap\\.xml$" + contentType = "application/xml" + gzip = true +[[deployment.matchers]] + pattern = "^.+\\.(html|xml|json)$" + gzip = true diff --git a/layouts/404.html b/layouts/404.html new file mode 100644 index 0000000..ba52ac2 --- /dev/null +++ b/layouts/404.html @@ -0,0 +1,8 @@ +{{ define "styles" }} + {{ $styles := resources.Get "css/index.css" | toCSS | minify }} + + +{{ end }} +{{ define "main" }} +

Page Not Found

+{{ end }} diff --git a/layouts/_default/_markup/render-link.html b/layouts/_default/_markup/render-link.html new file mode 100644 index 0000000..bd906b9 --- /dev/null +++ b/layouts/_default/_markup/render-link.html @@ -0,0 +1 @@ +{{ .Text | safeHTML }} diff --git a/layouts/_default/about.html b/layouts/_default/about.html new file mode 100644 index 0000000..a22454c --- /dev/null +++ b/layouts/_default/about.html @@ -0,0 +1,19 @@ +{{ define "styles" }} + {{ $styles := resources.Get "css/about.css" | toCSS | minify }} + + +{{ end }} + +{{ define "main" }} + {{ partial "breadcrumb.html" . }} + + {{ $faceImage := resources.Get "images/big-face.webp" }} + +
+ Hazem Krimi's face + {{ .Content }} +
+ +

Contact

+ {{ partial "contact-form.html" . }} +{{ end }} diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html new file mode 100644 index 0000000..f0aaf75 --- /dev/null +++ b/layouts/_default/baseof.html @@ -0,0 +1,79 @@ +{{ $baseStyles := resources.Get "css/baseof.css" | toCSS | minify }} +{{ $partialsStyles := resources.Get "css/partials.css" | toCSS | minify }} +{{ $baseScripts := resources.Get "js/baseof.js" | js.Build | minify }} +{{ $mobileNavigationScripts := resources.Get "js/mobile-navigation.js" | js.Build | minify }} +{{ $contactFormScripts := resources.Get "js/contact-form.js" | js.Build | minify }} + +{{ $androidChromeIcon := resources.Get "android-chrome-192x192.png" }} +{{ $appleTouchIcon := resources.Get "apple-touch-icon.png" }} +{{ $favIcon32 := resources.Get "favicon-32x32.png" }} +{{ $favIcon16 := resources.Get "favicon-16x16.png" }} +{{ $favIcon := resources.Get "favicon.ico" }} + +{{ $faceImage := resources.Get "images/big-face.webp" }} + + + + + + + + + + + + + + + + {{ block "meta" . }}{{ end }} + + {{ with .OutputFormats.Get "rss" -}} + {{ printf `` .Rel .MediaType.Type .Permalink site.Title | safeHTML }} + {{ end }} + + + + + + + + + + + {{ block "styles" . }}{{ end }} + + + {{ block "title" . }} + {{ .Page.Title }} | Hazem Krimi + {{ end }} + + + + + + {{ block "scripts" . }}{{ end }} + + + {{ partial "header.html" . }} + {{ partial "mobile-navigation.html" . }} + +
+ {{ block "main" . }}{{ end }} +
+ + {{ partial "footer.html" . }} + + \ No newline at end of file diff --git a/layouts/_default/contact.html b/layouts/_default/contact.html new file mode 100644 index 0000000..0f56bb2 --- /dev/null +++ b/layouts/_default/contact.html @@ -0,0 +1,7 @@ +{{ define "main" }} + {{ partial "breadcrumb.html" . }} + + {{ .Content }} + + {{ partial "contact-form.html" . }} +{{ end }} diff --git a/layouts/_default/home.rss.xml b/layouts/_default/home.rss.xml new file mode 100644 index 0000000..71672dd --- /dev/null +++ b/layouts/_default/home.rss.xml @@ -0,0 +1,78 @@ +{{- /* Deprecate site.Author.email in favor of site.Params.author.email */}} +{{- $authorEmail := "" }} +{{- with site.Params.author }} + {{- if reflect.IsMap . }} + {{- with .email }} + {{- $authorEmail = . }} + {{- end }} + {{- end }} +{{- else }} + {{- with site.Author.email }} + {{- $authorEmail = . }} + {{- warnf "The author key in site configuration is deprecated. Use params.author.email instead." }} + {{- end }} +{{- end }} + +{{- /* Deprecate site.Author.name in favor of site.Params.author.name */}} +{{- $authorName := "" }} +{{- with site.Params.author }} + {{- if reflect.IsMap . }} + {{- with .name }} + {{- $authorName = . }} + {{- end }} + {{- else }} + {{- $authorName = . }} + {{- end }} +{{- else }} + {{- with site.Author.name }} + {{- $authorName = . }} + {{- warnf "The author key in site configuration is deprecated. Use params.author.name instead." }} + {{- end }} +{{- end }} + +{{- $projectsPages := where .Site.RegularPages "Section" "projects" }} +{{- $blogPages := where .Site.RegularPages "Section" "blog" }} + +{{- $limit := .Site.Config.Services.RSS.Limit }} +{{- if ge $limit 1 }} + {{- $projectsPages = $projectsPages | first $limit }} + {{- $blogPages = $blogPages | first $limit }} +{{- end }} + +{{- printf "" | safeHTML }} + + + Hazem Krimi's content + {{ .Permalink }} + Hazem Krimi's projects and blog + Hugo -- gohugo.io + {{ site.Language.LanguageCode }}{{ with $authorEmail }} + {{.}}{{ with $authorName }} ({{ . }}){{ end }}{{ end }}{{ with $authorEmail }} + {{ . }}{{ with $authorName }} ({{ . }}){{ end }}{{ end }}{{ with .Site.Copyright }} + {{ . }}{{ end }}{{ if not .Date.IsZero }} + {{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}{{ end }} + {{- with .OutputFormats.Get "RSS" }} + {{ printf "" .Permalink .MediaType | safeHTML }} + {{- end }} + {{- range $projectsPages }} + + {{ .Title }} + {{ .Permalink }} + {{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }} + {{- with $authorEmail }}{{ . }}{{ with $authorName }} ({{ . }}){{ end }}{{ end }} + {{ .Permalink }} + {{ .Params.description | html }} + + {{- end }} + {{- range $blogPages }} + + {{ .Title }} + {{ .Permalink }} + {{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }} + {{- with $authorEmail }}{{ . }}{{ with $authorName }} ({{ . }}){{ end }}{{ end }} + {{ .Permalink }} + {{ .Params.description | html }} + + {{- end }} + + \ No newline at end of file diff --git a/layouts/_default/list.html b/layouts/_default/list.html new file mode 100644 index 0000000..0350c66 --- /dev/null +++ b/layouts/_default/list.html @@ -0,0 +1,44 @@ +{{ define "styles" }} + {{ $styles := resources.Get "css/list.css" | toCSS | minify }} + + +{{ end }} + +{{ define "main" }} + {{ partial "breadcrumb.html" . }} + + {{ .Content }} + + {{ if or (.InSection ($.Site.GetPage "blog")) (findRESubmatch "tags" .RelPermalink) }} + {{ $currentTitle := .Page.Title }} + + {{ if (findRESubmatch "tags" .RelPermalink) }} +

Blog

+

These are articles about things I learned about software engineering.

+ {{ end }} + + {{ if gt (len .Site.Taxonomies.tags) 0 }} +
+ {{ range .Site.Taxonomies.tags }} + + {{ .Page.Title }} + + {{ end }} +
+ {{ end }} + {{ end }} + + {{ if gt .Paginator.TotalPages 0 }} +
+ {{ range .Paginator.Pages }} + {{ partial "card.html" . }} + {{ end }} +
+ {{ else }} +

Nothing for now

+ {{ end }} + + {{ partial "pagination.html" . }} +{{ end }} diff --git a/layouts/_default/single.html b/layouts/_default/single.html new file mode 100644 index 0000000..de03552 --- /dev/null +++ b/layouts/_default/single.html @@ -0,0 +1,52 @@ +{{ define "styles" }} + {{ $styles := resources.Get "css/single.css" | toCSS | minify }} + + +{{ end }} + +{{ define "main" }} +
+
+ {{ partial "breadcrumb.html" . }} + +
+

{{ .Title }}

+
+ {{ readFile "assets/icons/calendar.svg" | safeHTML }} {{ .Date.Format .Site.Params.dateFormat }} + {{ readFile "assets/icons/clock.svg" | safeHTML }} {{ printf "%d minute(s) read" .ReadingTime }} + + {{ readFile "assets/icons/share.svg" | safeHTML }} + Share + +
+
+ +
+
+ {{ .Content }} +
+ +

Contact

+ {{ partial "contact-form.html" }} +
+
+ + {{ partial "table-of-contents.html" . }} +
+ + + +{{ end }} diff --git a/layouts/index.html b/layouts/index.html new file mode 100644 index 0000000..7c1f00d --- /dev/null +++ b/layouts/index.html @@ -0,0 +1,67 @@ +{{ define "styles" }} + {{ $styles := resources.Get "css/index.css" | toCSS | minify }} + + +{{ end }} +{{ define "main" }} + {{ $faceImage := resources.Get "images/big-face.webp" }} + +
+
+

Hi! I am Hazem, a sofware engineer currently working at Finteum

+

I have over two years of experience mainly working on web and cross platform mobile applications in E-Commerce, Fintech, Auditing and Compliance.

+
+ Blog + Contact +
+
+ Hazem Krimi's face +
+ +
+

About

+

Tinkering is what got me to where I am now as a professional software engineer.

+ {{ partial "about-card.html" . }} +
+ + {{ if (gt (len (where .Site.RegularPages "Section" "projects")) 0) }} +
+ +

These are all the projects I worked on personally and professionally.

+ {{ range (where .Site.Pages "Section" "projects") }} + {{ range first 2 .Pages }} + {{ partial "card.html" . }} + {{ end }} + {{ end }} +
+ {{ end }} + + {{ if (gt (len (where .Site.RegularPages "Section" "blog")) 0) }} +
+ +

These are articles about things I learned about software engineering.

+ {{ range (where .Site.Pages "Section" "blog") }} + {{ range first 2 .Pages }} + {{ partial "card.html" . }} + {{ end }} + {{ end }} +
+ {{ end }} + +
+

Contact

+

Here you can contact me personally for any questions or opportunities.

+ + {{ partial "contact-form.html" . }} +
+{{ end }} diff --git a/layouts/partials/about-card.html b/layouts/partials/about-card.html new file mode 100644 index 0000000..1954cbb --- /dev/null +++ b/layouts/partials/about-card.html @@ -0,0 +1,24 @@ +{{ $cv := resources.Get "cv.pdf" }} +{{ $faceImage := resources.Get "images/borded-face.webp" }} + +
+ Hazem Krimi's face +
+

+ My programming experience is mostly non-professional but it was essential + for my development. Even though I am working professionally for over two + years now, I got into programming much longer than that. I got into web + development in the summer of 2018 as I started learning the basics: HTML, + CSS, JS and most importantly how the web works by building very small + projects. +

+ +
+
diff --git a/layouts/partials/breadcrumb.html b/layouts/partials/breadcrumb.html new file mode 100644 index 0000000..910482b --- /dev/null +++ b/layouts/partials/breadcrumb.html @@ -0,0 +1,24 @@ + diff --git a/layouts/partials/card.html b/layouts/partials/card.html new file mode 100644 index 0000000..a27ddec --- /dev/null +++ b/layouts/partials/card.html @@ -0,0 +1,23 @@ +
+
+

{{ .Title }}

+ {{ if .InSection ($.Site.GetPage "blog") }} + {{ .Date.Format .Site.Params.dateFormat }} + {{ end }} +

{{ .Params.description }}

+ +
+
diff --git a/layouts/partials/contact-form.html b/layouts/partials/contact-form.html new file mode 100644 index 0000000..4822170 --- /dev/null +++ b/layouts/partials/contact-form.html @@ -0,0 +1,18 @@ +
+ + + +
+ +
+
+
diff --git a/layouts/partials/footer.html b/layouts/partials/footer.html new file mode 100644 index 0000000..6f117f5 --- /dev/null +++ b/layouts/partials/footer.html @@ -0,0 +1,56 @@ +{{ $faceImage := resources.Get "images/small-face.webp" }} +{{ $cv :=resources.Get "cv.pdf" }} + + diff --git a/layouts/partials/header.html b/layouts/partials/header.html new file mode 100644 index 0000000..19ba377 --- /dev/null +++ b/layouts/partials/header.html @@ -0,0 +1,72 @@ +{{ $faceImage := resources.Get "images/small-face.webp" }} +{{ $cv := resources.Get "cv.pdf" }} + +
+
+ Hazem Krimi's face + Hazem Krimi +
+ + + + {{ readFile "assets/icons/burger.svg" | safeHTML }} + {{ readFile "assets/icons/close.svg" | safeHTML }} + +
diff --git a/layouts/partials/mobile-navigation.html b/layouts/partials/mobile-navigation.html new file mode 100644 index 0000000..7775ce6 --- /dev/null +++ b/layouts/partials/mobile-navigation.html @@ -0,0 +1,59 @@ +{{ $cv := resources.Get "cv.pdf" }} + + \ No newline at end of file diff --git a/layouts/partials/pagination.html b/layouts/partials/pagination.html new file mode 100644 index 0000000..ad8246e --- /dev/null +++ b/layouts/partials/pagination.html @@ -0,0 +1,29 @@ +{{ $paginator := .Paginator }} + +{{ if gt $paginator.TotalPages 1 }} + +{{ end }} \ No newline at end of file diff --git a/layouts/partials/table-of-contents.html b/layouts/partials/table-of-contents.html new file mode 100644 index 0000000..9cc2598 --- /dev/null +++ b/layouts/partials/table-of-contents.html @@ -0,0 +1,6 @@ +{{ with .TableOfContents }} + +{{ end }} \ No newline at end of file diff --git a/mdx.d.ts b/mdx.d.ts deleted file mode 100644 index aeb22ac..0000000 --- a/mdx.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -declare module '@mdx-js/react' { - import * as React from 'react'; - - export type Components = { - [key]?: React.ComponentType; - }; - - export interface MDXProviderProps { - children: React.ReactNode; - components?: Components; - } - - export class MDXProvider extends React.Component {} -} diff --git a/next-env.d.ts b/next-env.d.ts deleted file mode 100644 index 4f11a03..0000000 --- a/next-env.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -/// -/// - -// NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/next.config.js b/next.config.js deleted file mode 100644 index 911d3af..0000000 --- a/next.config.js +++ /dev/null @@ -1,13 +0,0 @@ -const withMDX = require('@next/mdx')({ - extension: /\.mdx?$/, - options: { - providerImportSource: '@mdx-js/react', - }, -}); - -module.exports = withMDX({ - pageExtensions: ['ts', 'tsx', 'md', 'mdx'], - images: { - domains: ['res.cloudinary.com'], - }, -}); diff --git a/package.json b/package.json deleted file mode 100644 index 6cd83f9..0000000 --- a/package.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "personal-website", - "version": "0.1.0", - "private": true, - "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start", - "format": "prettier --write ./**/*.{js,jsx,ts,tsx}" - }, - "dependencies": { - "@formspree/react": "^2.4.1", - "@mdx-js/loader": "^2.3.0", - "@next/mdx": "^13.2.4", - "gray-matter": "^4.0.3", - "next": "^13.2.4", - "next-mdx-remote": "^4.4.1", - "nprogress": "^0.2.0", - "prism-react-renderer": "^1.3.5", - "react": "18.2.0", - "react-dom": "18.2.0", - "reading-time": "^1.5.0", - "styled-components": "^5.3.9" - }, - "devDependencies": { - "@types/node": "^18.15.3", - "@types/nprogress": "^0.2.0", - "@types/react": "^18.0.28", - "@types/styled-components": "^5.1.26", - "babel-plugin-styled-components": "^2.0.7", - "babel-runtime": "^6.26.0", - "prettier": "^2.8.8", - "typescript": "^5.0.2" - }, - "engines": { - "node": ">=14.x" - } -} diff --git a/pages/404.tsx b/pages/404.tsx deleted file mode 100644 index 226905b..0000000 --- a/pages/404.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { useRouter } from 'next/router'; -import Head from 'next/head'; -import IconButton from '../components/IconButton'; -import { Wrapper } from '../styles/404'; - -const NotFound = () => { - const router = useRouter(); - - return ( - <> - - - - - - - - - - 404 Not Found | Hazem Krimi - - -

404: This page could not be found

-
router.push('/')}> - - Go Home -
-
- - ); -}; - -export default NotFound; diff --git a/pages/_app.tsx b/pages/_app.tsx deleted file mode 100644 index aed57d0..0000000 --- a/pages/_app.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useEffect } from 'react'; - -import type { AppProps } from 'next/app'; -import Script from 'next/script'; -import { useRouter } from 'next/router'; - -import Nav from '../components/Nav'; -import Theme from '../styles/theme'; -import Container from '../components/Container'; -import GlobalStyles from '../components/GlobalStyles'; -import SharedStyles from '../styles/shared'; -import Footer from '../components/Footer'; - -import NProgress from 'nprogress'; -import 'nprogress/nprogress.css'; - -import { pageview } from '../utils/gtag'; -import { initStyles } from '../utils/styles'; - -NProgress.configure({ showSpinner: false }); - -const App = ({ Component, pageProps }: AppProps) => { - const router = useRouter(); - - useEffect(() => { - router.events.on('routeChangeStart', () => { - NProgress.start(); - }); - - router.events.on('routeChangeComplete', (url) => { - NProgress.done(); - pageview(url); - }); - - router.events.on('routeChangeError', () => { - NProgress.done(); - }); - - return () => { - router.events.off('routeChangeComplete', (url) => { - pageview(url); - }); - }; - }, [router.events]); - - return ( - <> -