Controls turn into tapbar

This commit is contained in:
2022-05-20 23:50:47 +03:00
parent 49ae4b0dec
commit 7c076a040c
24 changed files with 246 additions and 21 deletions

11
package-lock.json generated
View File

@@ -11,6 +11,7 @@
"dependencies": { "dependencies": {
"@solid-primitives/i18n": "^1.1.0", "@solid-primitives/i18n": "^1.1.0",
"@solid-primitives/intersection-observer": "^1.3.0", "@solid-primitives/intersection-observer": "^1.3.0",
"normalize.css": "^8.0.1",
"solid-js": "^1.3.13" "solid-js": "^1.3.13"
}, },
"devDependencies": { "devDependencies": {
@@ -1230,6 +1231,11 @@
"integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==",
"dev": true "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": { "node_modules/path-parse": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
@@ -2237,6 +2243,11 @@
"integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==",
"dev": true "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": { "path-parse": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",

View File

@@ -17,6 +17,7 @@
"dependencies": { "dependencies": {
"@solid-primitives/i18n": "^1.1.0", "@solid-primitives/i18n": "^1.1.0",
"@solid-primitives/intersection-observer": "^1.3.0", "@solid-primitives/intersection-observer": "^1.3.0",
"normalize.css": "^8.0.1",
"solid-js": "^1.3.13" "solid-js": "^1.3.13"
} }
} }

BIN
src/.DS_Store vendored

Binary file not shown.

BIN
src/assets/.DS_Store vendored

Binary file not shown.

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="white" class="bi bi-globe" viewBox="0 0 16 16">
<path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855A7.97 7.97 0 0 0 5.145 4H7.5V1.077zM4.09 4a9.267 9.267 0 0 1 .64-1.539 6.7 6.7 0 0 1 .597-.933A7.025 7.025 0 0 0 2.255 4H4.09zm-.582 3.5c.03-.877.138-1.718.312-2.5H1.674a6.958 6.958 0 0 0-.656 2.5h2.49zM4.847 5a12.5 12.5 0 0 0-.338 2.5H7.5V5H4.847zM8.5 5v2.5h2.99a12.495 12.495 0 0 0-.337-2.5H8.5zM4.51 8.5a12.5 12.5 0 0 0 .337 2.5H7.5V8.5H4.51zm3.99 0V11h2.653c.187-.765.306-1.608.338-2.5H8.5zM5.145 12c.138.386.295.744.468 1.068.552 1.035 1.218 1.65 1.887 1.855V12H5.145zm.182 2.472a6.696 6.696 0 0 1-.597-.933A9.268 9.268 0 0 1 4.09 12H2.255a7.024 7.024 0 0 0 3.072 2.472zM3.82 11a13.652 13.652 0 0 1-.312-2.5h-2.49c.062.89.291 1.733.656 2.5H3.82zm6.853 3.472A7.024 7.024 0 0 0 13.745 12H11.91a9.27 9.27 0 0 1-.64 1.539 6.688 6.688 0 0 1-.597.933zM8.5 12v2.923c.67-.204 1.335-.82 1.887-1.855.173-.324.33-.682.468-1.068H8.5zm3.68-1h2.146c.365-.767.594-1.61.656-2.5h-2.49a13.65 13.65 0 0 1-.312 2.5zm2.802-3.5a6.959 6.959 0 0 0-.656-2.5H12.18c.174.782.282 1.623.312 2.5h2.49zM11.27 2.461c.247.464.462.98.64 1.539h1.835a7.024 7.024 0 0 0-3.072-2.472c.218.284.418.598.597.933zM10.855 4a7.966 7.966 0 0 0-.468-1.068C9.835 1.897 9.17 1.282 8.5 1.077V4h2.355z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="white" class="bi bi-envelope" viewBox="0 0 16 16">
<path d="M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V4Zm2-1a1 1 0 0 0-1 1v.217l7 4.2 7-4.2V4a1 1 0 0 0-1-1H2Zm13 2.383-4.708 2.825L15 11.105V5.383Zm-.034 6.876-5.64-3.471L8 9.583l-1.326-.795-5.64 3.47A1 1 0 0 0 2 13h12a1 1 0 0 0 .966-.741ZM1 11.105l4.708-2.897L1 5.383v5.722Z"/>
</svg>

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

View File

@@ -5,13 +5,14 @@
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
padding: var(--gap-sm); padding: var(--gap-sm);
border-radius: 12px; border-radius: var(--radius-md);
width: 64px; width: 64px;
z-index: 10;
} }
.chapters { .chapters {
position: relative; position: relative;
height: calc(64px * 3); height: calc(70px * 3);
width: 100%; width: 100%;
margin-bottom: var(--gap-md); margin-bottom: var(--gap-md);
} }
@@ -53,18 +54,16 @@
background: var(--clr-bg); background: var(--clr-bg);
border-radius: 20px; border-radius: 20px;
aspect-ratio: 1/1; aspect-ratio: 1/1;
transition: width .6s, height .6s; transition: width .6s, height .6s, transform .6s;
width: 0; width: 0;
height: 0; height: 0;
transform: translate(-50%, 50%);
} }
.selected { .selected {
width: 64px; width: 64px;
height: 64px; height: 64px;
} transform: translateX(-50%);
.control:nth-child(1), .blob:nth-child(1) {
} }
.control:nth-child(2), .blob:nth-child(2) { .control:nth-child(2), .blob:nth-child(2) {
@@ -74,3 +73,42 @@
.control:nth-child(3), .blob:nth-child(3) { .control:nth-child(3), .blob:nth-child(3) {
top: calc(70px * 2); 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);
}
}

View File

@@ -6,6 +6,7 @@ import styles from './Controls.module.css';
import LanguageSelector from './LanguageSelector'; import LanguageSelector from './LanguageSelector';
import homeIcon from '../assets/icons/home.svg' import homeIcon from '../assets/icons/home.svg'
import gridIcon from '../assets/icons/grid.svg' import gridIcon from '../assets/icons/grid.svg'
import mailIcon from '../assets/icons/mail.svg'
export default () => { export default () => {
const [store, {setVisibleChapter}] = useStore() as Store; const [store, {setVisibleChapter}] = useStore() as Store;
@@ -14,7 +15,7 @@ export default () => {
const chapters = [ const chapters = [
{ name: 'home', icon: homeIcon }, { name: 'home', icon: homeIcon },
{ name: 'projects', icon: gridIcon }, { name: 'projects', icon: gridIcon },
{ name: 'whatever', icon: homeIcon }, { name: 'whatever', icon: mailIcon },
] ]
const selectChapter = (chapterName: string) => { const selectChapter = (chapterName: string) => {

View File

@@ -7,7 +7,7 @@
} }
.gradientText { .gradientText {
font-size: 72px; font-size: 86px;
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab); background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
-webkit-background-clip: text; -webkit-background-clip: text;
-webkit-text-fill-color: transparent; -webkit-text-fill-color: transparent;

View File

@@ -1,4 +1,22 @@
.LanguageSelector { .LanguageSelector {
cursor: pointer; cursor: pointer;
user-select: none; 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%);
}
} }

View File

@@ -1,10 +1,20 @@
import { useI18n } from "@solid-primitives/i18n"; import { useI18n } from "@solid-primitives/i18n";
import styles from './LanguageSelector.module.css'; import styles from './LanguageSelector.module.css';
import globeIcon from '../assets/icons/globe.svg';
export default () => { export default () => {
const [t, { locale }] = useI18n(); 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 ( return (
<div <div
onClick={() => { onClick={() => {
@@ -19,6 +29,7 @@ export default () => {
}} }}
class={styles.LanguageSelector} class={styles.LanguageSelector}
> >
<img src={globeIcon}/>
{t('lang')} {t('lang')}
</div> </div>
) )

View File

@@ -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);
}

View File

@@ -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 ( return (
<div class={styles.Project}> <div class={styles.Project}>
<img
class={styles.preview}
src={props.project.preview}
/>
<div
class={styles.body}
>
<a
href={props.project.link}
target="_blank"
>
<h2>{props.project.name}</h2>
</a>
<div class={styles.description}>
{t(props.project.descriptionSlug)}
</div>
</div>
</div> </div>
) )
} }

View File

@@ -4,4 +4,7 @@
justify-content: center; justify-content: center;
align-items: center; align-items: center;
flex-wrap: wrap; flex-wrap: wrap;
gap: var(--gap-lg);
margin-left: 130px;
margin-right: 130px;
} }

View File

@@ -1,13 +1,17 @@
import { For } from 'solid-js';
import { createViewportObserver } from '@solid-primitives/intersection-observer'; import { createViewportObserver } from '@solid-primitives/intersection-observer';
import { useStore } from '../../store/index'; import { useStore } from '../../store/index';
import type { Store } from '../../store/index'; import type { Store } from '../../store/index';
import { scrollHereWhenSelected } from "../../utlis/scroll"; import { scrollHereWhenSelected } from "../../utlis/scroll";
import styles from './Projects.module.css'; import styles from './Projects.module.css';
import projects from './projectList';
import Project from './Project';
import type { Project as ProjectType } from './projectList';
export default () => { export default () => {
const [store, { setVisibleChapter }] = useStore() as Store; const [store, { setVisibleChapter }] = useStore() as Store;
const [observer] = createViewportObserver({threshold: 0.9}); const [observer] = createViewportObserver({threshold: 0.5});
return ( return (
<div <div
@@ -19,6 +23,11 @@ export default () => {
ref={(element) => scrollHereWhenSelected(element, store, 'projects')} ref={(element) => scrollHereWhenSelected(element, store, 'projects')}
class={styles.Projects} class={styles.Projects}
> >
<For each={projects}>{(project: ProjectType) =>
<Project
project={project}
/>
}</For>
</div> </div>
) )

View File

@@ -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'
}),
]

View File

@@ -1,24 +1,42 @@
@import 'normalize.css';
:root { :root {
--clr-bg: rgb(7, 6, 9); --clr-bg: rgb(7, 6, 9);
--clr-bg-secondary: hsl(260, 20%, 16%); --clr-bg-secondary: hsl(260, 20%, 16%);
--clr-bg-trietary: hsl(260, 20%, 10%);
--clr-text: white;
--gap-sm: 18px; --gap-sm: 18px;
--gap-md: 36px; --gap-md: 36px;
--gap-lg: 72px; --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 { 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; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
color: white; color: var(--clr-text);
font-size: 18px; font: var(--font-md);
text-align: center; text-align: center;
background: var(--clr-bg); background: var(--clr-bg);
} }
h1, h2, h3, h4, h5, h6 {
margin: 0;
}
a {
color: inherit;
text-decoration: none;
}
code { code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace; monospace;

View File

@@ -1,5 +1,10 @@
{ {
"lang": "en", "lang": "en",
"my_name": "Anatoly Kopyl", "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."
} }

View File

@@ -1,5 +1,6 @@
{ {
"lang": "ru", "lang": "ru",
"my_name": "Анатолий Копыл", "my_name": "Анатолий Копыл",
"tagline": "Профессиональный fullstack разработчик со стандартами" "tagline": "Профессиональный fullstack разработчик со стандартами",
"flexpatrol_desc": "Лендинг для сквада геймеров, с информацией об их серверах и их статусе."
} }