Reworked projects section
|
Before Width: | Height: | Size: 488 KiB After Width: | Height: | Size: 612 KiB |
BIN
src/assets/projects/mockupPreview.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
src/assets/projects/musanthropePreview.png
Normal file
|
After Width: | Height: | Size: 626 KiB |
|
Before Width: | Height: | Size: 343 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 180 KiB After Width: | Height: | Size: 487 KiB |
@@ -9,12 +9,12 @@ import styles from './ContactForm.module.css';
|
||||
export default () => {
|
||||
const [t] = useI18n();
|
||||
const [state, setters] = useStore() as Store;
|
||||
const [observer] = createViewportObserver({ threshold: 0.9 });
|
||||
const [intersectionObserver] = createViewportObserver({ threshold: 0.9 });
|
||||
const chapterName = 'mail';
|
||||
|
||||
return (
|
||||
<div
|
||||
use:observer={(event) => {
|
||||
use:intersectionObserver={(event) => {
|
||||
if (event.isIntersecting) {
|
||||
if (!state.scrolling()) {
|
||||
setters.setVisibleChapter(chapterName);
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
transform: translateY(-50%);
|
||||
padding: var(--gap-sm);
|
||||
border-radius: var(--radius-md);
|
||||
width: 64px;
|
||||
width: 100px;
|
||||
box-sizing: border-box;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
@@ -86,8 +87,8 @@
|
||||
top: unset;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: calc(100% - var(--gap-md));
|
||||
height: 64px;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
border-radius: 0;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
@@ -52,6 +52,10 @@
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1080px) {
|
||||
.Hero {
|
||||
height: calc(100vh - 100px);
|
||||
}
|
||||
|
||||
.gradientText {
|
||||
font-size: 72px;
|
||||
}
|
||||
|
||||
@@ -9,13 +9,13 @@ import styles from './Hero.module.css';
|
||||
|
||||
export default () => {
|
||||
const [t] = useI18n();
|
||||
const [observer] = createViewportObserver({ threshold: 0.8 });
|
||||
const [intersectionObserver] = createViewportObserver({ threshold: 0.8 });
|
||||
const [state, setters] = useStore() as Store;
|
||||
const chapterName = 'home'
|
||||
|
||||
return (
|
||||
<header
|
||||
use:observer={(event) => {
|
||||
use:intersectionObserver={(event) => {
|
||||
if (event.isIntersecting) {
|
||||
if (!state.scrolling()) {
|
||||
setters.setVisibleChapter(chapterName);
|
||||
|
||||
@@ -6,9 +6,3 @@
|
||||
.Links>a {
|
||||
margin: 0 var(--gap-sm);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1080px) {
|
||||
.Links {
|
||||
bottom: calc(64px + var(--gap-lg));
|
||||
}
|
||||
}
|
||||
@@ -2,26 +2,43 @@
|
||||
position: relative;
|
||||
background: var(--clr-bg-trietary);
|
||||
border-radius: var(--radius-md);
|
||||
width: calc(33% - var(--gap-lg));
|
||||
min-width: 320px;
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
padding: var(--gap-md);
|
||||
gap: var(--gap-md);
|
||||
}
|
||||
|
||||
.Project_odd {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.Project_halfWidth {
|
||||
width: calc(50% - var(--gap-lg) / 2);
|
||||
flex-direction: column-reverse;
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
.Project_halfWidth .preview {
|
||||
height: 40%;
|
||||
}
|
||||
|
||||
.preview {
|
||||
position: relative;
|
||||
max-height: 100%;
|
||||
max-width: 50%;
|
||||
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;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.body {
|
||||
padding: var(--gap-sm);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: left;
|
||||
height: 107px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
gap: var(--gap-sm);
|
||||
}
|
||||
|
||||
.name {
|
||||
@@ -29,12 +46,29 @@
|
||||
}
|
||||
|
||||
.description {
|
||||
padding-top: var(--gap-sm);
|
||||
font: var(--font-sm);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1464px) {
|
||||
@media screen and (max-width: 1080px) {
|
||||
.Project {
|
||||
width: calc(50% - var(--gap-lg));
|
||||
flex-direction: column-reverse;
|
||||
align-items: end;
|
||||
height: unset;
|
||||
gap: var(--gap-lg);
|
||||
}
|
||||
|
||||
.Project_halfWidth {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.Project_halfWidth .preview {
|
||||
height: 200px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.preview {
|
||||
height: 200px;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,21 @@ import { useI18n } from "@solid-primitives/i18n";
|
||||
import styles from './Project.module.css';
|
||||
import type { Project } from './projectList';
|
||||
|
||||
export default (props: { project: Project }) => {
|
||||
export default (props: { project: Project, odd: boolean }) => {
|
||||
const [t] = useI18n();
|
||||
|
||||
return (
|
||||
<div class={styles.Project}>
|
||||
<div
|
||||
class={styles.Project}
|
||||
classList={{
|
||||
[styles.Project_odd]: props.odd,
|
||||
[styles.Project_halfWidth]: props.project.halfWidth
|
||||
}}
|
||||
>
|
||||
<img
|
||||
class={styles.preview}
|
||||
src={props.project.preview}
|
||||
style={props.project.previewStyle}
|
||||
/>
|
||||
<div
|
||||
class={styles.body}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--gap-lg);
|
||||
margin-left: var(--gap-xl);
|
||||
margin-right: var(--gap-xl);
|
||||
margin: auto;
|
||||
max-width: 980px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1080px) {
|
||||
@@ -15,5 +15,6 @@
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
gap: var(--gap-sm);
|
||||
}
|
||||
}
|
||||
@@ -5,18 +5,19 @@ 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 normalProjects from './projectList';
|
||||
import Project from './Project';
|
||||
import type { Project as ProjectType } from './projectList';
|
||||
|
||||
export default () => {
|
||||
const [state, setters] = useStore() as Store;
|
||||
const [observer] = createViewportObserver({ threshold: 0.1 });
|
||||
const [intersectionObserver] = createViewportObserver({ threshold: 0.1 });
|
||||
const chapterName = 'projects'
|
||||
const projects = normalProjects
|
||||
|
||||
return (
|
||||
<div
|
||||
use:observer={(event) => {
|
||||
use:intersectionObserver={(event) => {
|
||||
if (event.isIntersecting) {
|
||||
if (!state.scrolling()) {
|
||||
setters.setVisibleChapter(chapterName);
|
||||
@@ -28,9 +29,10 @@ export default () => {
|
||||
ref={(element) => scrollHereWhenSelected(element, [state, setters], chapterName)}
|
||||
class={styles.Projects}
|
||||
>
|
||||
<For each={projects}>{(project: ProjectType) =>
|
||||
<For each={projects}>{(project: ProjectType, i) =>
|
||||
<Project
|
||||
project={project}
|
||||
odd={i() % 2 === 0}
|
||||
/>
|
||||
}</For>
|
||||
|
||||
|
||||
@@ -3,57 +3,78 @@ 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';
|
||||
import mockupPreview from '../../assets/projects/mockupPreview.png';
|
||||
import vkmutePreview from '../../assets/projects/vkmutePreview.png';
|
||||
import musanthropePreview from '../../assets/projects/musanthropePreview.png';
|
||||
|
||||
export class Project {
|
||||
name: string;
|
||||
preview: string;
|
||||
link: string;
|
||||
descriptionSlug: string;
|
||||
previewStyle?: string;
|
||||
halfWidth?: boolean;
|
||||
|
||||
constructor(project: Project) {
|
||||
this.name = project.name
|
||||
this.preview = project.preview
|
||||
this.link = project.link
|
||||
this.descriptionSlug = project.descriptionSlug
|
||||
this.previewStyle = project.previewStyle
|
||||
this.halfWidth = project.halfWidth
|
||||
}
|
||||
}
|
||||
|
||||
export default [
|
||||
new Project({
|
||||
name: 'Warframe Center',
|
||||
preview: warframePreview,
|
||||
link: 'https://warframe.center',
|
||||
descriptionSlug: 'warframe_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'
|
||||
}),
|
||||
new Project({
|
||||
name: 'VK Mute',
|
||||
preview: vkmutePreview,
|
||||
link: 'https://chrome.google.com/webstore/detail/vk-mute/mcnkfnjggkbenehgfelnnkklpkpjeibl',
|
||||
descriptionSlug: 'vkmute_desc'
|
||||
descriptionSlug: 'vkmute_desc',
|
||||
halfWidth: true
|
||||
}),
|
||||
new Project({
|
||||
name: 'flexpatrol.ru',
|
||||
preview: flexpatrolPreview,
|
||||
link: 'https://flexpatrol.ru',
|
||||
descriptionSlug: 'flexpatrol_desc'
|
||||
name: 'Vue 3D Mockup',
|
||||
preview: mockupPreview,
|
||||
link: 'https://anatolykopyl.github.io/vue-three-d-mockup/',
|
||||
descriptionSlug: 'mockup_desc',
|
||||
halfWidth: true,
|
||||
// previewStyle: 'position: absolute; height: 50%;'
|
||||
}),
|
||||
new Project({
|
||||
name: 'My Games',
|
||||
name: 'Musanthrope X PAYDAY 2',
|
||||
preview: musanthropePreview,
|
||||
link: 'https://musanthrope.kopyl.dev',
|
||||
descriptionSlug: 'musanthrope_desc'
|
||||
}),
|
||||
new Project({
|
||||
name: 'Kopyl Games',
|
||||
preview: gamesPreview,
|
||||
link: 'https://games.anatolykopyl.ru',
|
||||
descriptionSlug: 'games_desc'
|
||||
descriptionSlug: 'games_desc',
|
||||
}),
|
||||
// new Project({
|
||||
// name: 'Studybuddy',
|
||||
// preview: studybuddyPreview,
|
||||
// link: 'https://studybuddy.top',
|
||||
// descriptionSlug: 'studybuddy_desc'
|
||||
// }),
|
||||
// new Project({
|
||||
// name: 'flexpatrol.ru',
|
||||
// preview: flexpatrolPreview,
|
||||
// link: 'https://flexpatrol.ru',
|
||||
// descriptionSlug: 'flexpatrol_desc'
|
||||
// }),
|
||||
]
|
||||
|
||||
@@ -3,13 +3,15 @@
|
||||
"my_name": "Anatoly Kopyl",
|
||||
"tagline": "Fullstack developer",
|
||||
"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.",
|
||||
"games_desc": "A page with a list of my games avaliable to play.",
|
||||
"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.",
|
||||
"mockup_desc": "A npm component leveraging three.js to make interactive 3D phone mockups.",
|
||||
"vkmute_desc": "A Browser extension that allows you to mute people in group chats on VK.com.",
|
||||
"musanthrope_desc": "A landing page for a music pack mod for PAYDAY 2 made by Musanthrope.",
|
||||
"name": "Your name",
|
||||
"message": "Write about anything",
|
||||
"message": "Ask me to make your next highly custom experience",
|
||||
"email": "Your email",
|
||||
"submit": "Submit"
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
"warframe_desc": "Сервис, который считает разницу в цене между позициями на warframe.market.",
|
||||
"worktime_desc": "PWA, которую я использую ежедневно для подсчета времени. Полная поддержка оффлайн работы.",
|
||||
"studybuddy_desc": "PWA для деления на бригады или варианты.",
|
||||
"mockup_desc": "Пакет для npm, позволяющий сосздавать интерактивные 3D мокапы телефонов с помощью three.js.",
|
||||
"vkmute_desc": "Расширение, позволяющее скрывать сообщения от указанных пользователей в беседах.",
|
||||
"musanthrope_desc": "Лэндинг мода с музыкой для PAYDAY 2 от Musanthrope.",
|
||||
"name": "Ваше имя",
|
||||
"message": "Напишите о чем угодно",
|
||||
"email": "Ваш email",
|
||||
|
||||