├── .gitignore ├── public ├── robots.txt ├── favicon.ico ├── security.txt ├── assets │ └── icons │ │ ├── circleEmpty.svg │ │ ├── circleFill.svg │ │ ├── expand.svg │ │ ├── close.svg │ │ ├── menu.svg │ │ ├── linkedin.svg │ │ ├── github.svg │ │ └── twitter.svg └── etc │ └── passwd ├── .prettierrc ├── next-env.d.ts ├── assets └── doodles │ ├── bulb.png │ ├── hero.png │ └── confetti.svg ├── .todo ├── postcss.config.js ├── components ├── SkillsTable │ ├── DomainContext.ts │ ├── DomainsNavigator.tsx │ ├── index.tsx │ └── DomainSkills.tsx ├── Icon.tsx ├── Hello.tsx ├── Layout.tsx ├── ProjectCard.tsx ├── SocialLinks.tsx ├── Navigation │ ├── MenuToggle.tsx │ ├── index.tsx │ ├── NavLinks.tsx │ └── MenuLinks.tsx └── Logo.tsx ├── next.config.js ├── pages ├── api │ ├── projects.ts │ └── skills.ts ├── stuff.tsx ├── _document.tsx ├── _app.tsx ├── projects.tsx └── index.tsx ├── .stylelintrc ├── styles ├── index.css └── nprogress.css ├── interfaces └── index.ts ├── tailwind.config.js ├── .eslintrc ├── tsconfig.json ├── data ├── skills.json └── projects.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .next 3 | .env 4 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "tabWidth": 2, 4 | "useTabs": false 5 | } 6 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alaadotsol/portfolio/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /assets/doodles/bulb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alaadotsol/portfolio/HEAD/assets/doodles/bulb.png -------------------------------------------------------------------------------- /assets/doodles/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alaadotsol/portfolio/HEAD/assets/doodles/hero.png -------------------------------------------------------------------------------- /.todo: -------------------------------------------------------------------------------- 1 | - Optimize images for fast loading 2 | - Animate projects page, maybe style it differently, the cards look weird 3 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | module.exports = { 4 | plugins: ["tailwindcss", "postcss-preset-env"], 5 | }; 6 | -------------------------------------------------------------------------------- /public/security.txt: -------------------------------------------------------------------------------- 1 | Contact: mailto:alaazorkane@gmail.com 2 | Preferred-Languages: en, fr, ar 3 | Canonical: https://alaazorkane.me/security.txt 4 | -------------------------------------------------------------------------------- /public/assets/icons/circleEmpty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/icons/circleFill.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/icons/expand.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /components/SkillsTable/DomainContext.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | import { NormalizedData, Domain } from "@/interfaces"; 3 | 4 | const DomainContext = createContext>({ 5 | allIds: [], 6 | byId: {}, 7 | }); 8 | 9 | export default DomainContext; 10 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | const withOptimizedImages = require("next-optimized-images"); 3 | const path = require("path"); 4 | module.exports = withOptimizedImages({ 5 | webpack(config) { 6 | config.resolve.alias.images = path.join(__dirname, "images"); 7 | return config; 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /public/assets/icons/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /public/assets/icons/menu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /pages/api/projects.ts: -------------------------------------------------------------------------------- 1 | import { NextApiRequest, NextApiResponse } from "next"; 2 | import { NormalizedData, Project } from "@/interfaces"; 3 | import projects from "@/data/projects.json"; 4 | 5 | export default ( 6 | _req: NextApiRequest, 7 | res: NextApiResponse> 8 | ): void => { 9 | res.status(200).json(projects); 10 | }; 11 | -------------------------------------------------------------------------------- /pages/api/skills.ts: -------------------------------------------------------------------------------- 1 | import { NextApiRequest, NextApiResponse } from "next"; 2 | import { NormalizedData, Domain } from "@/interfaces"; 3 | import skills from "@/data/skills.json"; 4 | 5 | export default async ( 6 | _req: NextApiRequest, 7 | res: NextApiResponse> 8 | ): Promise => { 9 | res.status(200).json(skills); 10 | }; 11 | -------------------------------------------------------------------------------- /pages/stuff.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { NextSeo } from "next-seo"; 3 | 4 | const MiscPage: FC = () => { 5 | return ( 6 | <> 7 | 8 |

9 | Here goes everything else... 10 |

11 | 12 | ); 13 | }; 14 | 15 | export default MiscPage; 16 | -------------------------------------------------------------------------------- /components/Icon.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | 3 | type Props = { 4 | icon: string; 5 | size: string; 6 | className?: string; 7 | }; 8 | 9 | const Icon: FC = ({ icon, size, className }) => { 10 | return ( 11 | {icon} 17 | ); 18 | }; 19 | 20 | export default Icon; 21 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-recommended", 3 | "rules": { 4 | "at-rule-no-unknown": [ 5 | true, 6 | { 7 | "ignoreAtRules": [ 8 | "extends", 9 | "tailwind" 10 | ] 11 | } 12 | ], 13 | "block-no-empty": null, 14 | "unit-whitelist": [ 15 | "em", 16 | "rem", 17 | "s", 18 | "px", 19 | "%", 20 | "ms", 21 | "deg" 22 | ] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /components/Hello.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | 3 | const Hello: FC = () => ( 4 |
5 |

Hello 👋🏼, my name is

6 |

Alaa Zorkane

7 |

8 | I make applications, libraries, servers, and everything in between! 9 |
I also love keyboards (very much). 10 |

11 |
12 | ); 13 | 14 | export default Hello; 15 | -------------------------------------------------------------------------------- /styles/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | 4 | *::selection { 5 | background-color: #222; 6 | color: white; 7 | } 8 | 9 | /* body { 10 | background: #f8f8f8; 11 | } */ 12 | 13 | .external::after { 14 | content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAQElEQVR42qXKwQkAIAxDUUdxtO6/RBQkQZvSi8I/pL4BoGw/XPkh4XigPmsUgh0626AjRsgxHTkUThsG2T/sIlzdTsp52kSS1wAAAABJRU5ErkJggg==); 15 | margin: 0 3px 0 5px; 16 | } 17 | 18 | @tailwind utilities; 19 | -------------------------------------------------------------------------------- /interfaces/index.ts: -------------------------------------------------------------------------------- 1 | export interface Skill { 2 | name: string; 3 | stars: number; 4 | } 5 | 6 | export interface Domain { 7 | title: string; 8 | skills: Skill[]; 9 | } 10 | 11 | export interface Project { 12 | title: string; 13 | description: string; 14 | techs: string[]; 15 | } 16 | 17 | export interface NormalizedData { 18 | byId: { [id: string]: T }; 19 | allIds: string[]; 20 | } 21 | 22 | export interface NavLink { 23 | title: string; 24 | location: string; 25 | external: boolean; 26 | } 27 | -------------------------------------------------------------------------------- /public/assets/icons/linkedin.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | module.exports = { 4 | purge: ["./components/**/*.tsx", "./pages/**/*.tsx"], 5 | theme: { 6 | fontFamily: { 7 | sans: 8 | '"Roboto Condensed", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"', 9 | serif: 'Arvo, Georgia, Cambria, "Times New Roman", Times, serif', 10 | }, 11 | extend: { 12 | boxShadow: { 13 | table: "5px 6px 0px #010b1b", 14 | }, 15 | }, 16 | }, 17 | variants: {}, 18 | plugins: [], 19 | }; 20 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaFeatures": { "jsx": true } 6 | }, 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:@typescript-eslint/eslint-recommended", 10 | "plugin:@typescript-eslint/recommended", 11 | "plugin:react/recommended", 12 | "prettier/@typescript-eslint", 13 | "plugin:prettier/recommended" 14 | ], 15 | "rules": { 16 | "prettier/prettier": ["warn", {}, { "usePrettierrc": true }], 17 | "react/prop-types": "off" // Use FC, Ill turn this on again after they fix this issue https://github.com/yannickcr/eslint-plugin-react/issues/2353 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /components/Layout.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC, ReactNode } from "react"; 2 | import { NextSeo } from "next-seo"; 3 | import Navigation from "./Navigation"; 4 | 5 | type Props = { 6 | children: ReactNode; 7 | }; 8 | 9 | const Layout: FC = ({ children }) => { 10 | return ( 11 | <> 12 | 16 |
17 | 18 | {children} 19 |
20 | 21 | ); 22 | }; 23 | 24 | export default Layout; 25 | -------------------------------------------------------------------------------- /pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Document, { 3 | Html, 4 | Head, 5 | Main, 6 | NextScript, 7 | DocumentInitialProps, 8 | DocumentContext, 9 | } from "next/document"; 10 | 11 | class MyDocument extends Document { 12 | static async getInitialProps( 13 | ctx: DocumentContext 14 | ): Promise { 15 | const initialProps = await Document.getInitialProps(ctx); 16 | return { ...initialProps }; 17 | } 18 | 19 | render(): JSX.Element { 20 | return ( 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | ); 29 | } 30 | } 31 | 32 | export default MyDocument; 33 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "alwaysStrict": true, 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "isolatedModules": true, 8 | "jsx": "preserve", 9 | "lib": ["dom", "es2017"], 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "noEmit": true, 13 | "noFallthroughCasesInSwitch": true, 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "resolveJsonModule": true, 17 | "skipLibCheck": true, 18 | "strict": true, 19 | "target": "esnext", 20 | "baseUrl": ".", 21 | "paths": { 22 | "@/*": ["./*"] 23 | } 24 | }, 25 | "exclude": ["node_modules"], 26 | "include": ["**/*.ts", "**/*.tsx"] 27 | } 28 | -------------------------------------------------------------------------------- /components/ProjectCard.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { Project } from "@/interfaces"; 3 | 4 | const ProjectCard: FC = ({ title, description, techs }) => { 5 | return ( 6 |
7 |
8 |

{title}

9 |

{description}

10 |
11 |
12 | {techs.map((tech) => ( 13 |
17 | {tech} 18 |
19 | ))} 20 |
21 |
22 | ); 23 | }; 24 | 25 | export default ProjectCard; 26 | -------------------------------------------------------------------------------- /public/assets/icons/github.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /components/SkillsTable/DomainsNavigator.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC, useContext } from "react"; 2 | import DomainContext from "./DomainContext"; 3 | 4 | type Props = { 5 | onChange: (newDomain: string) => void; 6 | active: string; 7 | }; 8 | 9 | const DomainsNavigator: FC = ({ onChange, active }) => { 10 | const domains = useContext(DomainContext).allIds; 11 | return ( 12 |
13 |
14 | {domains.map((domain) => ( 15 |
onChange(domain)} 17 | className={`p-3 cursor-pointer font-bold tracking-wider ${ 18 | active === domain ? "bg-black text-white" : "hover:bg-gray-200" 19 | }`} 20 | key={domain} 21 | > 22 | {domain} 23 |
24 | ))} 25 |
26 |
27 | ); 28 | }; 29 | 30 | export default DomainsNavigator; 31 | -------------------------------------------------------------------------------- /components/SkillsTable/index.tsx: -------------------------------------------------------------------------------- 1 | import useSWR from "swr"; 2 | import React, { FC, useState } from "react"; 3 | import DomainsNavigator from "./DomainsNavigator"; 4 | import { NormalizedData, Domain } from "@/interfaces"; 5 | import DomainSkills from "./DomainSkills"; 6 | import DomainContext from "./DomainContext"; 7 | 8 | const fetcher = (url: string) => fetch(url).then((r) => r.json()); 9 | 10 | const SkillsTable: FC = () => { 11 | const [domain, setDomain] = useState("langs"); 12 | const { data } = useSWR>("/api/skills", fetcher); 13 | // TODO: Some fancy loading skeleton 14 | if (!data) return

Loading...

; 15 | const handleDomainChange = (newDomain: string) => { 16 | //mutate(); 17 | setDomain(newDomain); 18 | }; 19 | return ( 20 | 21 |
22 | 23 | 24 |
25 |
26 | ); 27 | }; 28 | 29 | export default SkillsTable; 30 | -------------------------------------------------------------------------------- /components/SocialLinks.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import Icon from "./Icon"; 3 | import { motion, Variants } from "framer-motion"; 4 | 5 | type Props = { 6 | className?: string; 7 | }; 8 | 9 | const item: Variants = { 10 | hidden: { y: -10, opacity: 0 }, 11 | show: { y: 0, opacity: 1, transition: { default: { duration: 1 } } }, 12 | }; 13 | 14 | const SocialLinks: FC = ({ className }) => { 15 | const socialLinks = [ 16 | { title: "linkedin", link: "https://www.linkedin.com/in/AlaaZorkane" }, 17 | { title: "github", link: "https://www.github.com/AlaaZorkane" }, 18 | { title: "twitter", link: "https://www.twitter.com/AlaaZork" }, 19 | ]; 20 | return ( 21 |
22 | {socialLinks.map((social) => ( 23 | 32 | 33 | 34 | ))} 35 |
36 | ); 37 | }; 38 | 39 | export default SocialLinks; 40 | -------------------------------------------------------------------------------- /data/skills.json: -------------------------------------------------------------------------------- 1 | { 2 | "byId": { 3 | "langs": { 4 | "title": "langs", 5 | "skills": [ 6 | { "name": "js/ts", "stars": 5 }, 7 | { "name": "c/c++", "stars": 3 }, 8 | { "name": "python", "stars": 3 }, 9 | { "name": "bash", "stars": 2 } 10 | ] 11 | }, 12 | "frontend": { 13 | "title": "frontend", 14 | "skills": [ 15 | { "name": "react/next", "stars": 5 }, 16 | { "name": "chakra", "stars": 4 }, 17 | { "name": "emotion", "stars": 3 }, 18 | { "name": "tailwind", "stars": 4 } 19 | ] 20 | }, 21 | "backend": { 22 | "title": "backend", 23 | "skills": [ 24 | { "name": "express", "stars": 4 }, 25 | { "name": "graphql", "stars": 4 }, 26 | { "name": "mongodb", "stars": 3 }, 27 | { "name": "postgre", "stars": 3 } 28 | ] 29 | }, 30 | "tools": { 31 | "title": "tools", 32 | "skills": [ 33 | { "name": "git", "stars": 4 }, 34 | { "name": "docker", "stars": 3 }, 35 | { "name": "cypress", "stars": 3 }, 36 | { "name": "figma", "stars": 4 } 37 | ] 38 | } 39 | }, 40 | "allIds": ["langs", "frontend", "backend", "tools"] 41 | } 42 | -------------------------------------------------------------------------------- /components/Navigation/MenuToggle.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { motion } from "framer-motion"; 3 | 4 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 5 | const Path = (props: any) => ( 6 | 13 | ); 14 | 15 | type Props = { 16 | toggle: () => void; 17 | }; 18 | 19 | /** 20 | * Inspired from https://codesandbox.io/s/framer-motion-side-menu-mx2rw (framer docs) 21 | */ 22 | const MenuToggle: FC = ({ toggle }) => ( 23 | 30 | 31 | 37 | 43 | 44 | 45 | ); 46 | 47 | export default MenuToggle; 48 | -------------------------------------------------------------------------------- /pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { AppProps } from "next/app"; 3 | import Head from "next/head"; 4 | import Router from "next/router"; 5 | import NProgress from "nprogress"; 6 | import Layout from "@/components/Layout"; 7 | import "@/styles/index.css"; 8 | import "@/styles/nprogress.css"; 9 | import { motion } from "framer-motion"; 10 | 11 | NProgress.configure({ showSpinner: true }); 12 | Router.events.on("routeChangeStart", () => NProgress.start()); 13 | Router.events.on("routeChangeComplete", () => NProgress.done()); 14 | Router.events.on("routeChangeError", () => NProgress.done()); 15 | const App: FC = ({ Component, pageProps }) => ( 16 | <> 17 | 18 | 22 | 23 | 24 | 25 | 34 | 35 | 36 | ); 37 | 38 | export default App; 39 | -------------------------------------------------------------------------------- /data/projects.json: -------------------------------------------------------------------------------- 1 | { 2 | "byId": { 3 | "Cub3D": { 4 | "title": "Cub3D", 5 | "description": "A project where I recreated some of the aspects of the famous game Wolfenstein3D entirely from scratch, where I learned about techniques like raycasting and drawing algorthims.", 6 | "techs": ["minilibx", "C lang"] 7 | }, 8 | "Difys": { 9 | "title": "Difys", 10 | "description": "A headless botting framework made to help run user scripts to automate actions on a famous online mmorpg game", 11 | "techs": ["websocket", "javascript"] 12 | }, 13 | "Time": { 14 | "title": "Time", 15 | "description": "A time machine that walks you through the history of mankind, with facts, images and videos, from homo sapiens to modern history.", 16 | "techs": ["React", "Redux", "Firebase"] 17 | }, 18 | "Output2Hash": { 19 | "title": "Output2Hash", 20 | "description": "A tool to help competitors of OpenSource days competitive programing contest hash their results via a user interface.", 21 | "techs": ["Vue"] 22 | }, 23 | "Ft_server": { 24 | "title": "Ft_server", 25 | "description": "A dockerfile that automises the whole setup of an ssl nginx wordpress phpmyadmin container under debian.", 26 | "techs": ["Docker", "Linux"] 27 | } 28 | }, 29 | "allIds": ["Cub3D", "Difys", "Time", "Output2Hash", "Ft_server"] 30 | } 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alaazorkane", 3 | "version": "1.0.0", 4 | "author": "Alaa Zorkane ", 5 | "scripts": { 6 | "dev": "next", 7 | "build": "next build", 8 | "start": "next start", 9 | "type-check": "tsc" 10 | }, 11 | "dependencies": { 12 | "framer-motion": "^2.9.4", 13 | "imagemin-mozjpeg": "^9.0.0", 14 | "imagemin-optipng": "^8.0.0", 15 | "imagemin-svgo": "^8.0.0", 16 | "next": "latest", 17 | "next-optimized-images": "^2.6.1", 18 | "next-seo": "^4.5.0", 19 | "nprogress": "^0.2.0", 20 | "react": "^17.0.1", 21 | "react-dom": "^17.0.1", 22 | "swr": "^0.3.9" 23 | }, 24 | "devDependencies": { 25 | "@types/node": "^12.12.21", 26 | "@types/nprogress": "^0.2.0", 27 | "@types/react": "^16.9.16", 28 | "@types/react-dom": "^16.9.4", 29 | "@typescript-eslint/eslint-plugin": "^4.8.1", 30 | "@typescript-eslint/parser": "^4.8.1", 31 | "autoprefixer": "^10.0.2", 32 | "eslint": "^7.1.0", 33 | "eslint-config-prettier": "^6.11.0", 34 | "eslint-plugin-prettier": "^3.1.3", 35 | "eslint-plugin-react": "^7.20.0", 36 | "eslint-plugin-react-hooks": "^4.0.2", 37 | "postcss": "^8.0.9", 38 | "postcss-preset-env": "^6.7.0", 39 | "prettier": "^2.0.5", 40 | "stylelint": "^13.5.0", 41 | "stylelint-config-recommended": "^3.0.0", 42 | "tailwindcss": "^2.0.1", 43 | "typescript": "4.0.5" 44 | }, 45 | "license": "MIT" 46 | } 47 | -------------------------------------------------------------------------------- /components/Navigation/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import Logo from "../Logo"; 3 | import { NavLink } from "@/interfaces"; 4 | import NavLinks from "./NavLinks"; 5 | import MenuToggle from "./MenuToggle"; 6 | import { motion, useCycle, AnimatePresence } from "framer-motion"; 7 | import MenuLinks from "./MenuLinks"; 8 | import SocialLinks from "../SocialLinks"; 9 | 10 | const links: NavLink[] = [ 11 | { title: "whoami", location: "/", external: false }, 12 | { title: "projects", location: "/projects", external: false }, 13 | { title: "blog", location: "https://dev.to/alaazorkane", external: true }, 14 | { title: "stuff", location: "/stuff", external: false }, 15 | ]; 16 | 17 | const Navigation: FC = () => { 18 | const [isOpen, toggleOpen] = useCycle(false, true); 19 | return ( 20 | <> 21 | 37 | 38 | {isOpen && ( 39 | toggleOpen()} key={"menu"} /> 40 | )} 41 | 42 | 43 | ); 44 | }; 45 | 46 | export default Navigation; 47 | -------------------------------------------------------------------------------- /public/assets/icons/twitter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /pages/projects.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { NextSeo } from "next-seo"; 3 | import ProjectCard from "@/components/ProjectCard"; 4 | import { NormalizedData, Project } from "@/interfaces"; 5 | import useSWR from "swr"; 6 | 7 | const fetcher = (url: string) => fetch(url).then((r) => r.json()); 8 | 9 | const ProjectsPage: FC = () => { 10 | const { data } = useSWR>("/api/projects", fetcher); 11 | if (!data) return

Loading...

; 12 | const projects = data.allIds; 13 | return ( 14 | <> 15 | 16 |
17 | {projects.map((projectId) => { 18 | const { title, description, techs } = data.byId[projectId]; 19 | return ( 20 |
24 | 29 |
30 | ); 31 | })} 32 |
33 | 39 | More on my Github! 40 | 41 | bulb-doodle 47 | 48 | ); 49 | }; 50 | 51 | export default ProjectsPage; 52 | -------------------------------------------------------------------------------- /styles/nprogress.css: -------------------------------------------------------------------------------- 1 | #nprogress { 2 | pointer-events: none; 3 | } 4 | 5 | #nprogress .bar { 6 | background: rgb(0, 0, 0); 7 | 8 | position: fixed; 9 | z-index: 1031; 10 | top: 0; 11 | left: 0; 12 | 13 | width: 100%; 14 | height: 2px; 15 | } 16 | 17 | /* Fancy blur effect */ 18 | #nprogress .peg { 19 | display: block; 20 | position: absolute; 21 | right: 0px; 22 | width: 100px; 23 | height: 100%; 24 | box-shadow: 0 0 10px rgb(0, 0, 0), 0 0 5px rgb(0, 0, 0); 25 | opacity: 1; 26 | 27 | -webkit-transform: rotate(3deg) translate(0px, -4px); 28 | -ms-transform: rotate(3deg) translate(0px, -4px); 29 | transform: rotate(3deg) translate(0px, -4px); 30 | } 31 | 32 | /* Remove these to get rid of the spinner */ 33 | #nprogress .spinner { 34 | display: block; 35 | position: fixed; 36 | z-index: 1031; 37 | top: 15px; 38 | right: 15px; 39 | } 40 | 41 | #nprogress .spinner-icon { 42 | width: 18px; 43 | height: 18px; 44 | box-sizing: border-box; 45 | 46 | border: solid 2px transparent; 47 | border-top-color: rgb(0, 0, 0); 48 | border-left-color: rgb(0, 0, 0); 49 | border-radius: 50%; 50 | 51 | -webkit-animation: nprogress-spinner 400ms linear infinite; 52 | animation: nprogress-spinner 400ms linear infinite; 53 | } 54 | 55 | .nprogress-custom-parent { 56 | overflow: hidden; 57 | position: relative; 58 | } 59 | 60 | .nprogress-custom-parent #nprogress .spinner, 61 | .nprogress-custom-parent #nprogress .bar { 62 | position: absolute; 63 | } 64 | 65 | @-webkit-keyframes nprogress-spinner { 66 | 0% { 67 | -webkit-transform: rotate(0deg); 68 | } 69 | 100% { 70 | -webkit-transform: rotate(360deg); 71 | } 72 | } 73 | @keyframes nprogress-spinner { 74 | 0% { 75 | transform: rotate(0deg); 76 | } 77 | 100% { 78 | transform: rotate(360deg); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /pages/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { NextSeo } from "next-seo"; 3 | import Hello from "@/components/Hello"; 4 | import SkillsTable from "@/components/SkillsTable"; 5 | import { motion } from "framer-motion"; 6 | 7 | const IndexPage: FC = () => { 8 | return ( 9 | <> 10 | 11 |
12 |
13 | 19 | 20 | 21 |
22 |

23 | Want us to work together? 24 |

25 | 31 | get in touch 32 | 33 |
34 |
35 | 44 |
45 |
46 | 47 | ); 48 | }; 49 | 50 | export default IndexPage; 51 | -------------------------------------------------------------------------------- /components/Navigation/NavLinks.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { NavLink } from "@/interfaces"; 3 | import Link from "next/link"; 4 | import SocialLinks from "../SocialLinks"; 5 | import { motion, Variants } from "framer-motion"; 6 | import { useRouter } from "next/router"; 7 | 8 | type Props = { 9 | links: NavLink[]; 10 | }; 11 | 12 | const container: Variants = { 13 | hidden: {}, 14 | show: { 15 | transition: { 16 | staggerChildren: 0.1, 17 | }, 18 | }, 19 | }; 20 | 21 | const item: Variants = { 22 | hidden: { y: -10, opacity: 0 }, 23 | show: { y: 0, opacity: 1, transition: { default: { duration: 1 } } }, 24 | }; 25 | 26 | const NavLinks: FC = ({ links }) => { 27 | const router = useRouter(); 28 | const linkBaseStyle = "mr-4 cursor-pointer border-b-2 hover:border-black"; 29 | const linkProps = { 30 | whileHover: { y: -3 }, 31 | variants: item, 32 | }; 33 | return ( 34 | 40 | {links.map((link) => { 41 | if (!link.external) 42 | return ( 43 | 44 | 51 | {link.title} 52 | 53 | 54 | ); 55 | return ( 56 | 65 | {link.title} 66 | 67 | ); 68 | })} 69 | 70 | 71 | ); 72 | }; 73 | 74 | export default NavLinks; 75 | -------------------------------------------------------------------------------- /components/Navigation/MenuLinks.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { NavLink } from "@/interfaces"; 3 | import { motion, Variants } from "framer-motion"; 4 | import Link from "next/link"; 5 | import { useRouter } from "next/router"; 6 | 7 | type Props = { 8 | links: NavLink[]; 9 | toggle: () => void; 10 | }; 11 | 12 | const container: Variants = { 13 | closed: {}, 14 | open: { 15 | transition: { 16 | staggerChildren: 0.1, 17 | }, 18 | }, 19 | exit: { 20 | transition: { 21 | staggerChildren: 0.1, 22 | }, 23 | }, 24 | }; 25 | 26 | const item: Variants = { 27 | closed: { 28 | opacity: 0, 29 | x: -15, 30 | }, 31 | open: { 32 | opacity: 1, 33 | x: 0, 34 | }, 35 | exit: { 36 | x: -3, 37 | opacity: 0, 38 | transition: { duration: 0.2, ease: [0.48, 0.15, 0.25, 0.96] }, 39 | }, 40 | }; 41 | 42 | const MenuLinks: FC = ({ links, toggle }) => { 43 | const router = useRouter(); 44 | const linkBaseStyle = "p-2 cursor-pointer border-b-2 hover:border-black"; 45 | const linkProps = { 46 | onClick: () => toggle(), 47 | variants: item, 48 | exit: "exit", 49 | }; 50 | return ( 51 | 58 | {links.map((link) => { 59 | if (!link.external) 60 | return ( 61 | 62 | 68 | {link.title} 69 | 70 | 71 | ); 72 | return ( 73 | 80 | {link.title} 81 | 82 | ); 83 | })} 84 | 85 | ); 86 | }; 87 | 88 | export default MenuLinks; 89 | -------------------------------------------------------------------------------- /public/etc/passwd: -------------------------------------------------------------------------------- 1 | root:x:0:0::/root:/bin/bash 2 | nobody:x:65534:65534:Nobody:/:/usr/bin/nologin 3 | dbus:x:81:81:System Message Bus:/:/usr/bin/nologin 4 | bin:x:1:1::/:/usr/bin/nologin 5 | daemon:x:2:2::/:/usr/bin/nologin 6 | mail:x:8:12::/var/spool/mail:/usr/bin/nologin 7 | ftp:x:14:11::/srv/ftp:/usr/bin/nologin 8 | http:x:33:33::/srv/http:/usr/bin/nologin 9 | systemd-journal-remote:x:982:982:systemd Journal Remote:/:/usr/bin/nologin 10 | systemd-network:x:981:981:systemd Network Management:/:/usr/bin/nologin 11 | systemd-resolve:x:980:980:systemd Resolver:/:/usr/bin/nologin 12 | systemd-timesync:x:979:979:systemd Time Synchronization:/:/usr/bin/nologin 13 | systemd-coredump:x:978:978:systemd Core Dumper:/:/usr/bin/nologin 14 | uuidd:x:68:68::/:/usr/bin/nologin 15 | avahi:x:977:977:Avahi mDNS/DNS-SD daemon:/:/usr/bin/nologin 16 | colord:x:976:976:Color management daemon:/var/lib/colord:/usr/bin/nologin 17 | dnsmasq:x:975:975:dnsmasq daemon:/:/usr/bin/nologin 18 | git:x:974:974:git daemon user:/:/usr/bin/git-shell 19 | lightdm:x:973:973:Light Display Manager:/var/lib/lightdm:/usr/bin/nologin 20 | nm-openconnect:x:972:972:NetworkManager OpenConnect:/:/usr/bin/nologin 21 | nm-openvpn:x:971:971:NetworkManager OpenVPN:/:/usr/bin/nologin 22 | ntp:x:87:87:Network Time Protocol:/var/lib/ntp:/bin/false 23 | polkitd:x:102:102:PolicyKit daemon:/:/usr/bin/nologin 24 | rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/usr/bin/nologin 25 | usbmux:x:140:140:usbmux user:/:/usr/bin/nologin 26 | nvidia-persistenced:x:143:143:NVIDIA Persistence Daemon:/:/usr/bin/nologin 27 | alaa:x:1000:1000::/home/alaa:/usr/bin/zsh 28 | rtkit:x:133:133:RealtimeKit:/proc:/usr/bin/nologin 29 | flatpak:x:970:970:Flatpak system helper:/:/usr/bin/nologin 30 | geoclue:x:969:969:Geoinformation service:/var/lib/geoclue:/usr/bin/nologin 31 | stunnel:x:16:16::/var/run/stunnel:/usr/bin/nologin 32 | unbound:x:968:968:unbound:/etc/unbound:/usr/bin/nologin 33 | torguard:x:967:967:TorGuard VPN Software:/:/usr/bin/nologin 34 | salam:x:923:923:Layhdik al akh:/usr/bin/nologin 35 | dhcpcd:x:966:966:dhcpcd privilege separation:/var/lib/dhcpcd:/usr/bin/nologin 36 | mpd:x:45:45::/var/lib/mpd:/usr/bin/nologin 37 | gdm:x:120:120:Gnome Display Manager:/var/lib/gdm:/usr/bin/nologin 38 | cups:x:209:209:cups helper user:/:/usr/bin/nologin 39 | mongodb:x:965:965::/var/lib/mongodb:/usr/bin/nologin 40 | -------------------------------------------------------------------------------- /components/Logo.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { motion, useCycle, AnimatePresence } from "framer-motion"; 3 | 4 | const Logo: FC = () => { 5 | const [name, toggleName] = useCycle(false, true); 6 | const [easter, toggleEaster] = useCycle(false, true); 7 | return ( 8 |
9 | toggleEaster()} 19 | onMouseUp={() => toggleEaster()} 20 | onMouseEnter={() => toggleName()} 21 | onMouseLeave={() => toggleName()} 22 | > 23 | 24 | 25 | 26 | {name && ( 27 | 34 | {easter ? "laaaaaaa" : "laa Zorkane"} 35 | 36 | )} 37 | 38 |
39 | ); 40 | }; 41 | 42 | export default Logo; 43 | -------------------------------------------------------------------------------- /components/SkillsTable/DomainSkills.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC, useContext } from "react"; 2 | import DomainContext from "./DomainContext"; 3 | import Icon from "../Icon"; 4 | import { motion, Variants, AnimatePresence } from "framer-motion"; 5 | 6 | type Props = { 7 | selected: string; 8 | }; 9 | 10 | const container: Variants = { 11 | hidden: {}, 12 | show: { 13 | transition: { 14 | staggerChildren: 0.1, 15 | }, 16 | }, 17 | }; 18 | 19 | const item: Variants = { 20 | hidden: { y: -10, opacity: 0 }, 21 | show: { y: 0, opacity: 1, transition: { default: { duration: 1 } } }, 22 | }; 23 | 24 | const skillsContainer = { 25 | initial: { scale: 0.96, y: 30, opacity: 0 }, 26 | enter: { 27 | scale: 1, 28 | y: 0, 29 | opacity: 1, 30 | transition: { duration: 0.5, ease: [0.48, 0.15, 0.25, 0.96] }, 31 | }, 32 | exit: { 33 | scale: 0.8, 34 | opacity: 0, 35 | transition: { duration: 0.2, ease: [0.48, 0.15, 0.25, 0.96] }, 36 | }, 37 | }; 38 | 39 | const DomainSkills: FC = ({ selected }) => { 40 | const { skills } = useContext(DomainContext).byId[selected]; 41 | return ( 42 | 43 | 44 | 51 | {skills.map((skill) => ( 52 | 59 |

{skill.name}

60 | 61 | {[...Array(5)].map((_, key) => ( 62 | 63 | 70 | 71 | ))} 72 | 73 |
74 | ))} 75 |
76 |
77 |
78 | ); 79 | }; 80 | 81 | export default DomainSkills; 82 | -------------------------------------------------------------------------------- /assets/doodles/confetti.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | --------------------------------------------------------------------------------