diff --git a/src/App.tsx b/src/App.tsx index 486a861..72280e4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,14 +3,16 @@ import type { Component } from 'solid-js'; import Controls from './components/Controls'; import Hero from './components/Hero' import Projects from './components/Projects/Projects' +import ContactForm from './components/ContactForm' const App: Component = () => { return ( - <> +
- + +
); }; diff --git a/src/components/ContactForm.module.css b/src/components/ContactForm.module.css new file mode 100644 index 0000000..a7b7d96 --- /dev/null +++ b/src/components/ContactForm.module.css @@ -0,0 +1,24 @@ +.ContactForm { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + padding: var(--gap-md); + margin-left: var(--gap-xl); + margin-right: var(--gap-xl); +} + +.ContactForm > * { + width: 100%; + max-width: 600px; + box-sizing: border-box; + margin-bottom: var(--gap-sm); +} + +@media screen and (max-width: 1080px) { + .ContactForm { + margin: 0; + width: 100%; + box-sizing: border-box; + } +} diff --git a/src/components/ContactForm.tsx b/src/components/ContactForm.tsx new file mode 100644 index 0000000..970b2b1 --- /dev/null +++ b/src/components/ContactForm.tsx @@ -0,0 +1,51 @@ +import { useI18n } from "@solid-primitives/i18n"; +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 './ContactForm.module.css'; + +export default () => { + const [t] = useI18n(); + const [state, setters] = useStore() as Store; + const [observer] = createViewportObserver({threshold: 0.9}); + const chapterName = 'mail'; + + return ( +
{ + if (event.isIntersecting) { + if (!state.scrolling()) { + setters.setVisibleChapter(chapterName); + } else if (state.visibleChapter() === chapterName) { + setters.setScrolling(false) + } + // Сраный костыль + } else if (state.visibleChapter() === chapterName) { + setters.setVisibleChapter('projects'); + } + }} + ref={(element) => scrollHereWhenSelected(element, [state, setters], chapterName)} + class={styles.ContactForm} + action="https://send.pageclip.co/ipMETNW8CCV8ka21myU6D22bvnOAV0Ag" + method="post" + > + + + + + +
+ ) +} \ No newline at end of file diff --git a/src/components/Controls.module.css b/src/components/Controls.module.css index f4cba2f..db4fe6b 100644 --- a/src/components/Controls.module.css +++ b/src/components/Controls.module.css @@ -57,7 +57,6 @@ transition: width .6s, height .6s, transform .6s; width: 0; height: 0; - transform: translate(-50%, 50%); } .selected { diff --git a/src/components/Controls.tsx b/src/components/Controls.tsx index ebdd214..b5a4cee 100644 --- a/src/components/Controls.tsx +++ b/src/components/Controls.tsx @@ -9,31 +9,31 @@ import gridIcon from '../assets/icons/grid.svg' import mailIcon from '../assets/icons/mail.svg' export default () => { - const [store, {setVisibleChapter}] = useStore() as Store; + const [state, {setVisibleChapter, setScrolling}] = useStore() as Store; const [selected, setSelected] = createSignal('home'); const [blobby, setBlobby] = createSignal(['home']); const chapters = [ { name: 'home', icon: homeIcon }, { name: 'projects', icon: gridIcon }, - { name: 'whatever', icon: mailIcon }, + { name: 'mail', icon: mailIcon }, ] const selectChapter = (chapterName: string) => { if (chapterName !== selected()) { - setSelected(chapterName) - setVisibleChapter(chapterName) - setBlobby(b => [chapterName, ...b]) + setSelected(chapterName); + setVisibleChapter(chapterName); + setBlobby(b => [chapterName, ...b]); setTimeout(() => { - setBlobby(b => [chapterName]) - }, 500) + setBlobby(b => [chapterName]); + }, 500); } } createEffect((prev) => { - if (prev !== store.visibleChapter()) { - selectChapter(store.visibleChapter()); + if (prev !== state.visibleChapter()) { + selectChapter(state.visibleChapter()); } - return store.visibleChapter(); + return state.visibleChapter(); }); return ( @@ -54,6 +54,7 @@ export default () => { {(chapter) =>
{ + setScrolling(true); selectChapter(chapter.name) }} class={styles.control} diff --git a/src/components/Hero.module.css b/src/components/Hero.module.css index 2a747ae..2d1f6f5 100644 --- a/src/components/Hero.module.css +++ b/src/components/Hero.module.css @@ -1,4 +1,5 @@ .Hero { + position: relative; height: 100vh; display: flex; flex-direction: column; @@ -23,6 +24,19 @@ word-break: break-word; } +.blur { + pointer-events: none; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + backdrop-filter: blur(50px); + opacity: 1; + transition: opacity 2.5s; + transition-delay: .5s; +} + @keyframes gradient { 0% { background-position: 0% 50%; diff --git a/src/components/Hero.tsx b/src/components/Hero.tsx index 30a1d9a..52f686b 100644 --- a/src/components/Hero.tsx +++ b/src/components/Hero.tsx @@ -9,17 +9,22 @@ import styles from './Hero.module.css'; export default () => { const [t] = useI18n(); - const [observer] = createViewportObserver({threshold: 0.9}); - const [store, { setVisibleChapter }] = useStore() as Store; + const [observer] = createViewportObserver({threshold: 0.8}); + const [state, setters] = useStore() as Store; + const chapterName = 'home' return (
{ if (event.isIntersecting) { - setVisibleChapter('home'); - }} - } - ref={(element) => scrollHereWhenSelected(element, store, 'home')} + if (!state.scrolling()) { + setters.setVisibleChapter(chapterName); + } else if (state.visibleChapter() === chapterName) { + setters.setScrolling(false) + } + } + }} + ref={(element) => scrollHereWhenSelected(element, [state, setters], chapterName)} class={styles.Hero} >

@@ -30,6 +35,13 @@ export default () => {

+ +
{ + setTimeout(() => element.style.opacity = '0') + }} + /> ) }; diff --git a/src/components/Projects/Projects.module.css b/src/components/Projects/Projects.module.css index 83643c6..9595cb7 100644 --- a/src/components/Projects/Projects.module.css +++ b/src/components/Projects/Projects.module.css @@ -1,10 +1,19 @@ .Projects { padding: var(--gap-md); display: flex; - justify-content: center; + justify-content: space-between; align-items: center; flex-wrap: wrap; gap: var(--gap-lg); - margin-left: 130px; - margin-right: 130px; + margin-left: var(--gap-xl); + margin-right: var(--gap-xl); +} + +@media screen and (max-width: 1080px) { + .Projects { + margin: 0; + width: 100%; + box-sizing: border-box; + flex-direction: column; + } } diff --git a/src/components/Projects/Projects.tsx b/src/components/Projects/Projects.tsx index bed3ac7..e2330c2 100644 --- a/src/components/Projects/Projects.tsx +++ b/src/components/Projects/Projects.tsx @@ -10,17 +10,23 @@ import Project from './Project'; import type { Project as ProjectType } from './projectList'; export default () => { - const [store, { setVisibleChapter }] = useStore() as Store; - const [observer] = createViewportObserver({threshold: 0.5}); + const [state, setters] = useStore() as Store; + const [observer] = createViewportObserver({threshold: 0.1}); + const chapterName = 'projects' return (
{ if (event.isIntersecting) { - setVisibleChapter('projects'); - }} - } - ref={(element) => scrollHereWhenSelected(element, store, 'projects')} + console.log(chapterName); + if (!state.scrolling()) { + setters.setVisibleChapter(chapterName); + } else if (state.visibleChapter() === chapterName) { + setters.setScrolling(false) + } + } + }} + ref={(element) => scrollHereWhenSelected(element, [state, setters], chapterName)} class={styles.Projects} > {(project: ProjectType) => diff --git a/src/index.css b/src/index.css index fd3df5f..b0939f9 100644 --- a/src/index.css +++ b/src/index.css @@ -9,6 +9,7 @@ --gap-sm: 18px; --gap-md: 36px; --gap-lg: 72px; + --gap-xl: 144px; --radius-md: 12px; @@ -19,6 +20,10 @@ --font-md: normal normal 400 18px var(--ff-default); } +.App { + padding-bottom: var(--gap-xl); +} + body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; @@ -41,3 +46,12 @@ code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } + +input, textarea { + background: var(--clr-bg-secondary); + border: none; + padding: var(--gap-sm); + border-radius: var(--radius-md); + display: inline-block; + color: var(--clr-text); +} diff --git a/src/localization/en.json b/src/localization/en.json index f7d0ee8..b426380 100644 --- a/src/localization/en.json +++ b/src/localization/en.json @@ -7,5 +7,6 @@ "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.", - "vkmute_desc": "A Browser extension that allows you to mute people in group chats on VK.com." + "vkmute_desc": "A Browser extension that allows you to mute people in group chats on VK.com.", + "name": "Your name" } diff --git a/src/store/index.tsx b/src/store/index.tsx index 2d7a82c..080169d 100644 --- a/src/store/index.tsx +++ b/src/store/index.tsx @@ -2,20 +2,30 @@ import { createSignal, createContext, useContext } from "solid-js"; import type { Accessor, Setter } from 'solid-js'; export type Store = [ - { visibleChapter: Accessor }, - { setVisibleChapter: Setter } + { + visibleChapter: Accessor, + scrolling: Accessor, + }, + { + setVisibleChapter: Setter, + setScrolling: Setter, + } ] const StoreContext = createContext(); export function StoreProvider(props: any) { const [visibleChapter, setVisibleChapter] = createSignal('home'); + const [scrolling, setScrolling] = createSignal(false); + const store: Store = [ { - visibleChapter + visibleChapter, + scrolling, }, { - setVisibleChapter + setVisibleChapter, + setScrolling } ]; diff --git a/src/utlis/scroll.ts b/src/utlis/scroll.ts index a8fd152..0b6b995 100644 --- a/src/utlis/scroll.ts +++ b/src/utlis/scroll.ts @@ -1,10 +1,14 @@ import { createEffect } from "solid-js"; -export const scrollHereWhenSelected = (element: HTMLElement, store, chapter) => { +import type { Store } from '../store/index'; + +export const scrollHereWhenSelected = (element: HTMLElement, store: Store, chapter: string) => { + const [state, setters] = store; return createEffect((prev) => { - if (prev !== store.visibleChapter() && store.visibleChapter() === chapter) { - element.scrollIntoView({behavior: "smooth"}) + if (prev !== state.visibleChapter() && state.visibleChapter() === chapter && state.scrolling()) { + element.scrollIntoView({behavior: "smooth"}); + setters.setScrolling(true); } - return store.visibleChapter(); + return state.visibleChapter(); }); }