diff --git a/components/Button.stories.tsx b/components/Button.stories.tsx deleted file mode 100644 index a24a18b..0000000 --- a/components/Button.stories.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { storiesOf } from "@storybook/react"; -import Button from "./Button"; - -storiesOf("Button", module).add("with text", () => { - return ; diff --git a/components/Footer.tsx b/components/Footer.tsx new file mode 100644 index 0000000..3e6b4ac --- /dev/null +++ b/components/Footer.tsx @@ -0,0 +1,14 @@ +import * as React from 'react'; + +type Props = {}; + +export default ({}: Props) => ( + +); diff --git a/components/atom/Button.stories.tsx b/components/atom/Button.stories.tsx new file mode 100644 index 0000000..d1956ae --- /dev/null +++ b/components/atom/Button.stories.tsx @@ -0,0 +1,10 @@ +import { storiesOf } from '@storybook/react'; +import Button from './Button'; + +storiesOf('Design System/Atoms/Button', module).add('with text', () => { + return +); diff --git a/components/personal-card/PersonalCard.stories.tsx b/components/personal-card/PersonalCard.stories.tsx new file mode 100644 index 0000000..42c5367 --- /dev/null +++ b/components/personal-card/PersonalCard.stories.tsx @@ -0,0 +1,6 @@ +import { storiesOf } from '@storybook/react'; +import PersonalCard from './PersonalCard'; + +storiesOf('Components/Personal Card', module).add('with emoji', () => { + return ; +}); diff --git a/components/personal-card/PersonalCard.tsx b/components/personal-card/PersonalCard.tsx new file mode 100644 index 0000000..2c4005c --- /dev/null +++ b/components/personal-card/PersonalCard.tsx @@ -0,0 +1,16 @@ +import * as React from 'react'; +import Avatar from './elements/Avatar'; +import Contacts from './elements/Contacts'; +import Description from './elements/Description'; +import Title from './elements/Title'; + +type Props = {}; + +export default ({}: Props) => ( +
+ + + <Description /> + <Contacts /> + </div> +); diff --git a/components/personal-card/elements/Avatar.tsx b/components/personal-card/elements/Avatar.tsx new file mode 100644 index 0000000..d8bea81 --- /dev/null +++ b/components/personal-card/elements/Avatar.tsx @@ -0,0 +1,9 @@ +import * as React from 'react'; + +type Props = { + imgUrl: string; +}; + +export default ({ imgUrl }: Props) => ( + <img src={imgUrl} className={'border rounded-full h-48 sm mx-auto'}></img> +); diff --git a/components/personal-card/elements/Contacts.tsx b/components/personal-card/elements/Contacts.tsx new file mode 100644 index 0000000..6b137f6 --- /dev/null +++ b/components/personal-card/elements/Contacts.tsx @@ -0,0 +1,30 @@ +import * as React from 'react'; +import { Contact, ContactType } from '../../../src/contacts/contacts'; + +import ContactsButtons from './ContactsButtons'; + +type Props = {}; +const contactMe: Contact[] = [ + { id: 'fido_node', type: 'tg' }, + { id: 'aleksandr.mihailov@pm.me', type: 'mail' } +]; + +const socialButtons: Contact[] = [ + { id: 'fido_node', type: 'twitter' }, + { id: 'michey', type: 'github' }, + { id: 'alex-mihailov-870448187', type: 'linkedin' }, + { id: 'fido_node', type: 'twitch' } +]; + +export default ({}: Props) => ( + <> + <div className={'flex flex-col flex-row-2 '}> + <span className={'text-2xl text-center py-4'}>Contact me via: </span> + <ContactsButtons contacts={contactMe} /> + </div> + <div className={'flex flex-col flex-row-2'}> + <span className={'text-2xl text-center py-4'}>Social buttons: </span> + <ContactsButtons contacts={socialButtons} /> + </div> + </> +); diff --git a/components/personal-card/elements/ContactsButtons.tsx b/components/personal-card/elements/ContactsButtons.tsx new file mode 100644 index 0000000..c4b5799 --- /dev/null +++ b/components/personal-card/elements/ContactsButtons.tsx @@ -0,0 +1,43 @@ +import * as React from 'react'; +import '@fortawesome/fontawesome-svg-core'; +import { faEnvelope } from '@fortawesome/free-solid-svg-icons'; +import { + faTelegram, + faTwitter, + faGithub, + faLinkedin, + faTwitch +} from '@fortawesome/free-brands-svg-icons'; + +import { IconDefinition, IconName, IconPrefix } from '@fortawesome/fontawesome-svg-core'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Contact, contactToLink, ContactType } from '../../../src/contacts/contacts'; + +type Props = { + contacts: Contact[]; +}; + +const typeToIcon: { [key in ContactType]: [IconDefinition, string?] } = { + tg: [faTelegram], + mail: [faEnvelope], + twitter: [faTwitter], + github: [faGithub], + linkedin: [faLinkedin], + twitch: [faTwitch] +}; + +const ContactComp = ({ id, type }: Contact) => { + const iconDescr = typeToIcon[type]; + return ( + <a + className={'text-5xl p-3 text-gray-600' + ' ' + iconDescr[1]} + href={contactToLink({ id, type })} + target="_blank"> + <FontAwesomeIcon key={type} icon={iconDescr[0]} /> + </a> + ); +}; + +export default ({ contacts }: Props) => ( + <div className={'text-center'}>{contacts.map((c) => ContactComp(c))}</div> +); diff --git a/components/personal-card/elements/Description.tsx b/components/personal-card/elements/Description.tsx new file mode 100644 index 0000000..8f77653 --- /dev/null +++ b/components/personal-card/elements/Description.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; +import Link from './Link'; + +type Props = {}; + +export default ({}: Props) => ( + <div className={'flex flex-col flex-row-2'}> + <span className={'text-2xl text-center'}>Full stack engineer</span> + <span className={'text-2xl text-center'}> + FP-curious | λ-affected Wanna be rustacean 🦀 and/or secops guy 🔒 + </span> + <span className={'text-lg text-center text-gray-500 font-light'}> + Now <Link href="https://www.samsungnext.com/">@SamsungNEXT</Link> ( + <Link href="https://whisk.com/">Whisk product team</Link>). Previously{' '} + <Link href="https://www.visualthreat.com/">@VisualThreat.</Link> + </span> + <span className={'text-lg text-center text-gray-500 font-light'}> + Work with: Scala, TypeScript, Java, MongoDB, MySQL, Thrift, gRPC + </span> + </div> +); diff --git a/components/personal-card/elements/Link.tsx b/components/personal-card/elements/Link.tsx new file mode 100644 index 0000000..774121b --- /dev/null +++ b/components/personal-card/elements/Link.tsx @@ -0,0 +1,12 @@ +import * as React from 'react'; + +type Props = { + href: string; + children: string; +}; + +export default ({ href, children }: Props) => ( + <a className={'underline'} href={href}> + {children} + </a> +); diff --git a/components/personal-card/elements/Title.tsx b/components/personal-card/elements/Title.tsx new file mode 100644 index 0000000..9f18cee --- /dev/null +++ b/components/personal-card/elements/Title.tsx @@ -0,0 +1,9 @@ +import * as React from 'react'; + +type Props = {}; + +export default ({}: Props) => ( + <div className={'sm mx-auto'}> + <span className={'text-5xl'}>{'Alex Mihailov'}</span> + </div> +); diff --git a/package.json b/package.json index fe66f9a..5f96af7 100644 --- a/package.json +++ b/package.json @@ -7,16 +7,21 @@ "export": "next build && next export", "build": "next build", "start": "next start", - "storybook": "start-storybook -p 6006", + "storybook": "start-storybook -s ./public -p 6006 ", "build-storybook": "build-storybook" }, "dependencies": { + "@fortawesome/fontawesome-svg-core": "^1.2.35", + "@fortawesome/free-brands-svg-icons": "^5.15.3", + "@fortawesome/free-solid-svg-icons": "^5.15.3", + "@fortawesome/react-fontawesome": "^0.1.14", "next": "^10.1.0", "react": "17.0.1", "react-dom": "17.0.1" }, "devDependencies": { "@babel/core": "^7.13.16", + "@fortawesome/fontawesome-free": "^5.15.3", "@storybook/addon-actions": "^6.2.0", "@storybook/addon-essentials": "^6.2.0", "@storybook/addon-links": "^6.2.0", diff --git a/pages/index.tsx b/pages/index.tsx index ce8ecd7..35cc3fa 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,7 +1,14 @@ -import * as React from "react"; +import * as React from 'react'; +import Footer from '../components/Footer'; +import PersonalCard from '../components/personal-card/PersonalCard'; const Home = () => { - return <h1>Welcome to My Next App!</h1>; + return ( + <div className="bg-gray-100 flex flex-col h-screen justify-between"> + <PersonalCard /> + <Footer /> + </div> + ); }; -export default Home; \ No newline at end of file +export default Home; diff --git a/public/avatar.jpg b/public/avatar.jpg new file mode 100644 index 0000000..b79976a Binary files /dev/null and b/public/avatar.jpg differ diff --git a/src/contacts/contacts.ts b/src/contacts/contacts.ts new file mode 100644 index 0000000..c02d046 --- /dev/null +++ b/src/contacts/contacts.ts @@ -0,0 +1,23 @@ +import Contacts from '../../components/personal-card/elements/Contacts'; + +export type ContactType = 'tg' | 'mail' | 'twitter' | 'github' | 'linkedin' | 'twitch'; + +export interface Contact { + id: string; + type: ContactType; +} + +type MapType = { [key in ContactType]: (id: string) => string }; + +const typeToFormer: MapType = { + tg: (id) => `https://t.me/${id}`, + mail: (id) => `mailto:${id}`, + twitter: (id) => `https://twitter.com/${id}`, + github: (id) => `https://github.com/${id}`, + linkedin: (id) => `https://linkedin.com/in/${id}`, + twitch: (id) => `https://www.twitch.tv/${id}` +}; + +export function contactToLink(contact: Contact): string { + return typeToFormer[contact.type](contact.id); +} diff --git a/tsconfig.json b/tsconfig.json index 26a5296..80e21be 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,7 @@ { "compilerOptions": { "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": false, @@ -18,13 +14,7 @@ "isolatedModules": true, "jsx": "preserve" }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx" - ], - "exclude": [ - "node_modules" - ], - "baseUrl": "./", -} \ No newline at end of file + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"], + "baseUrl": "./" +} diff --git a/yarn.lock b/yarn.lock index fb410aa..e46b1b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1212,6 +1212,44 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== +"@fortawesome/fontawesome-common-types@^0.2.35": + version "0.2.35" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.35.tgz#01dd3d054da07a00b764d78748df20daf2b317e9" + integrity sha512-IHUfxSEDS9dDGqYwIW7wTN6tn/O8E0n5PcAHz9cAaBoZw6UpG20IG/YM3NNLaGPwPqgjBAFjIURzqoQs3rrtuw== + +"@fortawesome/fontawesome-free@^5.15.3": + version "5.15.3" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.3.tgz#c36ffa64a2a239bf948541a97b6ae8d729e09a9a" + integrity sha512-rFnSUN/QOtnOAgqFRooTA3H57JLDm0QEG/jPdk+tLQNL/eWd+Aok8g3qCI+Q1xuDPWpGW/i9JySpJVsq8Q0s9w== + +"@fortawesome/fontawesome-svg-core@^1.2.35": + version "1.2.35" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.35.tgz#85aea8c25645fcec88d35f2eb1045c38d3e65cff" + integrity sha512-uLEXifXIL7hnh2sNZQrIJWNol7cTVIzwI+4qcBIq9QWaZqUblm0IDrtSqbNg+3SQf8SMGHkiSigD++rHmCHjBg== + dependencies: + "@fortawesome/fontawesome-common-types" "^0.2.35" + +"@fortawesome/free-brands-svg-icons@^5.15.3": + version "5.15.3" + resolved "https://registry.yarnpkg.com/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.15.3.tgz#bec2821d23b9c667be1d192a6c5bfb2667e588eb" + integrity sha512-1hirPcbjj72ZJtFvdnXGPbAbpn3Ox6mH3g5STbANFp3vGSiE5u5ingAKV06mK6ZVqNYxUPlh4DlTnaIvLtF2kw== + dependencies: + "@fortawesome/fontawesome-common-types" "^0.2.35" + +"@fortawesome/free-solid-svg-icons@^5.15.3": + version "5.15.3" + resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.3.tgz#52eebe354f60dc77e0bde934ffc5c75ffd04f9d8" + integrity sha512-XPeeu1IlGYqz4VWGRAT5ukNMd4VHUEEJ7ysZ7pSSgaEtNvSo+FLurybGJVmiqkQdK50OkSja2bfZXOeyMGRD8Q== + dependencies: + "@fortawesome/fontawesome-common-types" "^0.2.35" + +"@fortawesome/react-fontawesome@^0.1.14": + version "0.1.14" + resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.14.tgz#bf28875c3935b69ce2dc620e1060b217a47f64ca" + integrity sha512-4wqNb0gRLVaBm/h+lGe8UfPPivcbuJ6ecI4hIgW0LjI7kzpYB9FkN0L9apbVzg+lsBdcTf0AlBtODjcSX5mmKA== + dependencies: + prop-types "^15.7.2" + "@fullhuman/postcss-purgecss@^3.1.3": version "3.1.3" resolved "https://registry.yarnpkg.com/@fullhuman/postcss-purgecss/-/postcss-purgecss-3.1.3.tgz#47af7b87c9bfb3de4bc94a38f875b928fffdf339"