diff --git a/package-lock.json b/package-lock.json index 8ada3c0..b0c73ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@solid-primitives/i18n": "^1.1.0", "@solid-primitives/intersection-observer": "^1.3.0", + "normalize.css": "^8.0.1", "solid-js": "^1.3.13" }, "devDependencies": { @@ -1230,6 +1231,11 @@ "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", "dev": true }, + "node_modules/normalize.css": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz", + "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==" + }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -2237,6 +2243,11 @@ "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", "dev": true }, + "normalize.css": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz", + "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==" + }, "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", diff --git a/package.json b/package.json index 76ee4bc..2a9f89b 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "dependencies": { "@solid-primitives/i18n": "^1.1.0", "@solid-primitives/intersection-observer": "^1.3.0", + "normalize.css": "^8.0.1", "solid-js": "^1.3.13" } } diff --git a/src/.DS_Store b/src/.DS_Store index 6a48e8e..afc6386 100644 Binary files a/src/.DS_Store and b/src/.DS_Store differ diff --git a/src/assets/.DS_Store b/src/assets/.DS_Store index 6d10f64..ffa5ac5 100644 Binary files a/src/assets/.DS_Store and b/src/assets/.DS_Store differ diff --git a/src/assets/icons/globe.svg b/src/assets/icons/globe.svg new file mode 100644 index 0000000..9156a12 --- /dev/null +++ b/src/assets/icons/globe.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/mail.svg b/src/assets/icons/mail.svg new file mode 100644 index 0000000..a0c70c0 --- /dev/null +++ b/src/assets/icons/mail.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/projects/flexpatrolPreview.png b/src/assets/projects/flexpatrolPreview.png new file mode 100644 index 0000000..eef7a35 Binary files /dev/null and b/src/assets/projects/flexpatrolPreview.png differ diff --git a/src/assets/projects/gamesPreview.png b/src/assets/projects/gamesPreview.png new file mode 100644 index 0000000..54dd5ee Binary files /dev/null and b/src/assets/projects/gamesPreview.png differ diff --git a/src/assets/projects/studybuddyPreview.png b/src/assets/projects/studybuddyPreview.png new file mode 100644 index 0000000..a495f6e Binary files /dev/null and b/src/assets/projects/studybuddyPreview.png differ diff --git a/src/assets/projects/warframePreview.png b/src/assets/projects/warframePreview.png new file mode 100644 index 0000000..26899eb Binary files /dev/null and b/src/assets/projects/warframePreview.png differ diff --git a/src/assets/projects/worktimePreview.png b/src/assets/projects/worktimePreview.png new file mode 100644 index 0000000..565e634 Binary files /dev/null and b/src/assets/projects/worktimePreview.png differ diff --git a/src/components/Controls.module.css b/src/components/Controls.module.css index 15d5854..f4cba2f 100644 --- a/src/components/Controls.module.css +++ b/src/components/Controls.module.css @@ -5,13 +5,14 @@ top: 50%; transform: translateY(-50%); padding: var(--gap-sm); - border-radius: 12px; + border-radius: var(--radius-md); width: 64px; + z-index: 10; } .chapters { position: relative; - height: calc(64px * 3); + height: calc(70px * 3); width: 100%; margin-bottom: var(--gap-md); } @@ -53,18 +54,16 @@ background: var(--clr-bg); border-radius: 20px; aspect-ratio: 1/1; - transition: width .6s, height .6s; + transition: width .6s, height .6s, transform .6s; width: 0; height: 0; + transform: translate(-50%, 50%); } .selected { width: 64px; height: 64px; -} - -.control:nth-child(1), .blob:nth-child(1) { - + transform: translateX(-50%); } .control:nth-child(2), .blob:nth-child(2) { @@ -74,3 +73,42 @@ .control:nth-child(3), .blob:nth-child(3) { top: calc(70px * 2); } + +@media screen and (max-width: 1080px) { + .Controls { + top: unset; + bottom: 0; + left: 0; + width: calc(100% - var(--gap-md)); + height: 64px; + border-radius: 0; + transform: translateY(0); + } + + .chapters { + width: calc(70px * 3); + height: 64px; + margin: auto; + } + + .control, .blob { + top: 0; + left: 0; + transform: translateX(0); + } + + .control, .control > img { + width: auto; + height: 100%; + } + + .control:nth-child(2), .blob:nth-child(2) { + top: unset; + left: 70px; + } + + .control:nth-child(3), .blob:nth-child(3) { + top: unset; + left: calc(70px * 2); + } +} \ No newline at end of file diff --git a/src/components/Controls.tsx b/src/components/Controls.tsx index 975f3b2..ebdd214 100644 --- a/src/components/Controls.tsx +++ b/src/components/Controls.tsx @@ -6,6 +6,7 @@ import styles from './Controls.module.css'; import LanguageSelector from './LanguageSelector'; import homeIcon from '../assets/icons/home.svg' import gridIcon from '../assets/icons/grid.svg' +import mailIcon from '../assets/icons/mail.svg' export default () => { const [store, {setVisibleChapter}] = useStore() as Store; @@ -14,7 +15,7 @@ export default () => { const chapters = [ { name: 'home', icon: homeIcon }, { name: 'projects', icon: gridIcon }, - { name: 'whatever', icon: homeIcon }, + { name: 'whatever', icon: mailIcon }, ] const selectChapter = (chapterName: string) => { diff --git a/src/components/Hero.module.css b/src/components/Hero.module.css index 3d7d4a1..179dea9 100644 --- a/src/components/Hero.module.css +++ b/src/components/Hero.module.css @@ -7,7 +7,7 @@ } .gradientText { - font-size: 72px; + font-size: 86px; background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab); -webkit-background-clip: text; -webkit-text-fill-color: transparent; diff --git a/src/components/LanguageSelector.module.css b/src/components/LanguageSelector.module.css index f478a9b..15ef2e4 100644 --- a/src/components/LanguageSelector.module.css +++ b/src/components/LanguageSelector.module.css @@ -1,4 +1,22 @@ .LanguageSelector { cursor: pointer; user-select: none; + display: flex; + align-items: center; + justify-content: center; + width: max-content; + margin: auto; +} + +.LanguageSelector > img { + margin-right: 6px; +} + +@media screen and (max-width: 1080px) { + .LanguageSelector { + position: absolute; + right: var(--gap-lg); + top: 50%; + transform: translateY(-50%); + } } diff --git a/src/components/LanguageSelector.tsx b/src/components/LanguageSelector.tsx index a01abf4..67cf102 100644 --- a/src/components/LanguageSelector.tsx +++ b/src/components/LanguageSelector.tsx @@ -1,10 +1,20 @@ import { useI18n } from "@solid-primitives/i18n"; import styles from './LanguageSelector.module.css'; +import globeIcon from '../assets/icons/globe.svg'; export default () => { const [t, { locale }] = useI18n(); + const avaliableLocales = ['en', 'ru']; + const preferredLocales = navigator.languages.map((lang) => lang.substring(0, 2)); + for (const lang of preferredLocales) { + if (avaliableLocales.includes(lang)) { + locale(lang); + break; + } + } + return (
{ @@ -19,6 +29,7 @@ export default () => { }} class={styles.LanguageSelector} > + {t('lang')}
) diff --git a/src/components/Projects/Project.module.css b/src/components/Projects/Project.module.css index e69de29..1da6f2c 100644 --- a/src/components/Projects/Project.module.css +++ b/src/components/Projects/Project.module.css @@ -0,0 +1,30 @@ +.Project { + position: relative; + background: var(--clr-bg-trietary); + border-radius: var(--radius-md); + width: calc(33% - var(--gap-lg)); + min-width: 320px; +} + +.preview { + position: relative; + display: block; + border-radius: var(--radius-md) var(--radius-md) 0 0; + left: 0; + top: 0; + width: 100%; + height: 250px; + object-fit: cover; + object-position: top; +} + +.body { + padding: var(--gap-sm); + text-align: left; + height: 107px; +} + +.description { + padding-top: var(--gap-sm); + font: var(--font-sm); +} diff --git a/src/components/Projects/Project.tsx b/src/components/Projects/Project.tsx index 8f93d06..ae95e02 100644 --- a/src/components/Projects/Project.tsx +++ b/src/components/Projects/Project.tsx @@ -1,9 +1,30 @@ -import styles from './Project.module.css'; +import { useI18n } from "@solid-primitives/i18n"; + +import styles from './Project.module.css'; +import type { Project } from './projectList'; + +export default (props: {project: Project}) => { + const [t] = useI18n(); -export default () => { return (
- + +
+ +

{props.project.name}

+
+
+ {t(props.project.descriptionSlug)} +
+
) } \ No newline at end of file diff --git a/src/components/Projects/Projects.module.css b/src/components/Projects/Projects.module.css index 2482f36..83643c6 100644 --- a/src/components/Projects/Projects.module.css +++ b/src/components/Projects/Projects.module.css @@ -4,4 +4,7 @@ justify-content: center; align-items: center; flex-wrap: wrap; + gap: var(--gap-lg); + margin-left: 130px; + margin-right: 130px; } diff --git a/src/components/Projects/Projects.tsx b/src/components/Projects/Projects.tsx index bf98300..bed3ac7 100644 --- a/src/components/Projects/Projects.tsx +++ b/src/components/Projects/Projects.tsx @@ -1,13 +1,17 @@ +import { For } from 'solid-js'; import { createViewportObserver } from '@solid-primitives/intersection-observer'; import { useStore } from '../../store/index'; import type { Store } from '../../store/index'; import { scrollHereWhenSelected } from "../../utlis/scroll"; import styles from './Projects.module.css'; +import projects from './projectList'; +import Project from './Project'; +import type { Project as ProjectType } from './projectList'; export default () => { const [store, { setVisibleChapter }] = useStore() as Store; - const [observer] = createViewportObserver({threshold: 0.9}); + const [observer] = createViewportObserver({threshold: 0.5}); return (
{ ref={(element) => scrollHereWhenSelected(element, store, 'projects')} class={styles.Projects} > + {(project: ProjectType) => + + }
) diff --git a/src/components/Projects/projectList.ts b/src/components/Projects/projectList.ts new file mode 100644 index 0000000..f93c3f0 --- /dev/null +++ b/src/components/Projects/projectList.ts @@ -0,0 +1,52 @@ +import flexpatrolPreview from '../../assets/projects/flexpatrolPreview.png'; +import gamesPreview from '../../assets/projects/gamesPreview.png'; +import warframePreview from '../../assets/projects/warframePreview.png'; +import worktimePreview from '../../assets/projects/worktimePreview.png'; +import studybuddyPreview from '../../assets/projects/studybuddyPreview.png'; + +export class Project { + name: string; + preview: string; + link: string; + descriptionSlug: string; + + constructor(project: Project) { + this.name = project.name + this.preview = project.preview + this.link = project.link + this.descriptionSlug = project.descriptionSlug + } +} + +export default [ + new Project({ + name: 'flexpatrol.ru', + preview: flexpatrolPreview, + link: 'https://flexpatrol.ru', + descriptionSlug: 'flexpatrol_desc' + }), + new Project({ + name: 'My Games', + preview: gamesPreview, + link: 'https://games.anatolykopyl.ru', + descriptionSlug: 'games_desc' + }), + new Project({ + name: 'Warframe Center', + preview: warframePreview, + link: 'https://warframe.center', + descriptionSlug: 'warframe_desc' + }), + new Project({ + name: 'Worktime', + preview: worktimePreview, + link: 'https://anatolykopyl.github.io/worktime', + descriptionSlug: 'worktime_desc' + }), + new Project({ + name: 'Studybuddy', + preview: studybuddyPreview, + link: 'https://studybuddy.top', + descriptionSlug: 'studybuddy_desc' + }), +] diff --git a/src/index.css b/src/index.css index 52dfb64..9a43530 100644 --- a/src/index.css +++ b/src/index.css @@ -1,24 +1,42 @@ +@import 'normalize.css'; + :root { --clr-bg: rgb(7, 6, 9); --clr-bg-secondary: hsl(260, 20%, 16%); + --clr-bg-trietary: hsl(260, 20%, 10%); + --clr-text: white; + --gap-sm: 18px; --gap-md: 36px; --gap-lg: 72px; + + --radius-md: 12px; + + --ff-default: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + --font-sm: normal normal 300 16px var(--ff-default); + --font-md: normal normal 400 18px var(--ff-default); } body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - color: white; - font-size: 18px; + color: var(--clr-text); + font: var(--font-md); text-align: center; background: var(--clr-bg); } +h1, h2, h3, h4, h5, h6 { + margin: 0; +} + +a { + color: inherit; + text-decoration: none; +} + code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; diff --git a/src/localization/en.json b/src/localization/en.json index 4d4e5f6..de1679a 100644 --- a/src/localization/en.json +++ b/src/localization/en.json @@ -1,5 +1,10 @@ { "lang": "en", "my_name": "Anatoly Kopyl", - "tagline": "Professional fullstack developer with standards" + "tagline": "Professional fullstack developer with standards", + "flexpatrol_desc": "A landing page for a gaming squad with info on their servers and their status.", + "games_desc": "A page with thumbnails and links to my games.", + "warframe_desc": "A service that monitors prices of items on warframe.market and calculates profitable gaps between them.", + "worktime_desc": "A PWA that I use daily to track my time spent working. Full offline support.", + "studybuddy_desc": "A PWA for splitting into groups or taking topics for an assignment." } diff --git a/src/localization/ru.json b/src/localization/ru.json index b8799bb..27d7ed1 100644 --- a/src/localization/ru.json +++ b/src/localization/ru.json @@ -1,5 +1,6 @@ { "lang": "ru", "my_name": "Анатолий Копыл", - "tagline": "Профессиональный fullstack разработчик со стандартами" + "tagline": "Профессиональный fullstack разработчик со стандартами", + "flexpatrol_desc": "Лендинг для сквада геймеров, с информацией об их серверах и их статусе." }