From c11f7854095eebf9b4c5e2b26f9335cf3698bfb3 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Sun, 9 Jun 2024 09:41:38 +0530 Subject: [PATCH] feat: add experience story support for mobile --- src/components/Exp/Story.tsx | 166 +++++++++++++++++++++++++++++++++++++------ src/components/Exp/Tags.tsx | 2 +- src/components/Exp/Unit.tsx | 37 +++++++--- src/pages/main/Exp.tsx | 6 +- 4 files changed, 176 insertions(+), 35 deletions(-) diff --git a/src/components/Exp/Story.tsx b/src/components/Exp/Story.tsx index 48a7b52..e094900 100644 --- a/src/components/Exp/Story.tsx +++ b/src/components/Exp/Story.tsx @@ -1,6 +1,8 @@ import React from "react"; import { css, cx } from "@emotion/css"; +import { ReactComponent as Close } from "../../assets/close.svg"; import { Experience } from "./types"; +import { offscreenWidth } from "../constants"; const story = css` position: absolute; @@ -9,43 +11,134 @@ const story = css` border-radius: 0.5rem; display: flex; - overflow: hidden; - - & .contents { - padding: 1.5rem; - line-height: 1.25rem; - display: flex; - flex-direction: row; - align-items: flex-start; - gap: 2rem; - margin-block-start: 1rem; - height: var(--story-height); + & * { + line-height: 140%; + } - & ul { + & .story-content { + & > div { max-height: 100%; margin: 0; column-count: 3; - column-gap: 2rem; + column-gap: 2.5rem; color: var(--text-subdued); font-weight: 400; - & li + li { - margin-block-start: 0.5rem; + & p { + font-size: 0.9rem; + } + + & > p + p { + margin-block-start: 0.5em; } + } + } + + /* desktop & tablet */ + @media screen and (min-width: ${offscreenWidth}) { + /* offset padding */ + transform: translateX(calc(var(--item-padding) * -1)); + + & .story-handle { + display: none; + } + + & .story-content { + padding: 1.5rem; + display: flex; + flex-direction: row; + align-items: flex-start; + gap: 3rem; + margin-block-start: 1rem; + height: var(--story-height); + } + } + + /* mobile */ + @media screen and (max-width: ${offscreenWidth}) { + position: fixed; + display: flex; + justify-content: center; + height: calc(100vh - 10rem); + width: 100vw; + left: 0; + z-index: 900; + font-size: 1.25rem; + background: var(--bg-colour); + border-inline: 1px solid var(--offscreen-handle); + overflow-y: auto; + overflow-x: hidden; + overscroll-behavior: contain; + + /* + Push this offscreen element out of screen; + Unit.ts will pull it up when .active + */ + top: 100vh; + + & .story-handle { + content: ""; + width: 100%; + height: 1rem; + background-color: var(--offscreen-handle); + position: absolute; + top: 0; + left: 0; - & li::marker { + &::before { content: ""; - font-weight: 800; - padding-top: 1rem; + position: absolute; + width: 2rem; + height: 0.2rem; + background-color: var(--offscreen-handle-tab); + z-index: 900; + inset: 0; + top: 0; + margin: auto; + } + } + + & .story-content { + display: flex; + flex-direction: column; + gap: 3rem; + /* height: 100%; */ + max-width: 40rem; + + margin-block: 4rem; + overflow-x: hidden; + overflow-y: auto; + overscroll-behavior: contain; + + & > img { + margin-inline: 4rem; + } + + & > div { + column-count: unset; + padding-inline: 4rem; + height: 100%; + overflow-y: auto; + + & p { + font-size: 1rem; + } + } + + & > .closer { + display: flex; } } } `; -export const Story = ({ description, logo }: Experience) => { +export const Story = ({ description, logo, active }: Experience) => { return ( -
-
+
+
+
{ `, )} /> -
    {description}
+ +
{description}
); diff --git a/src/components/Exp/Tags.tsx b/src/components/Exp/Tags.tsx index ce185a0..85ef90c 100644 --- a/src/components/Exp/Tags.tsx +++ b/src/components/Exp/Tags.tsx @@ -100,7 +100,7 @@ export const Clear = (props: { selected: Tags }) => { fill: var(--text-colour); `} /> - Clear + Clear filters ); }; diff --git a/src/components/Exp/Unit.tsx b/src/components/Exp/Unit.tsx index 0951406..151d88f 100644 --- a/src/components/Exp/Unit.tsx +++ b/src/components/Exp/Unit.tsx @@ -3,24 +3,25 @@ import { css, cx } from "@emotion/css"; import { Story } from "./Story"; import { Experience } from "./types"; import { Content } from "./Content"; +import { offscreenWidth } from "../constants"; const expUnit = css` --final-height: 20rem; --unit-height: 9rem; --story-height: calc(var(--final-height) - var(--unit-height)); - --transition-time: 300ms; + --transition-time: 200ms; & > * { line-height: 1em; font-size: 1rem; } - & button { + & > button { border: 1px solid transparent; transition: all calc(var(--transition-time) * 2); } - &.active button { + &.active > button { background-color: var(--card-active); border: 1px solid var(--card-active-border); box-shadow: 0 0 50rem 0 rgba(190, 190, 190, 0.5); @@ -41,19 +42,34 @@ const expUnit = css` & .story { opacity: 0; - transition: opacity var(--transition-time) ease-in-out; - transition-delay: 0; + transition: all calc(var(--transition-time)) ease-in-out; + transition-delay: 0ms; } &.active { - height: var(--final-height); - transition-delay: 0; - transition-delay: var(--transition-time); + transition-delay: 0ms; + + .timeline-circle { + background: #ffffff; + } .story { + transition-delay: var(--transition-time); opacity: 1; - transition: opacity calc(var(--transition-time) * 2) ease-in-out; + } + + @media screen and (min-width: ${offscreenWidth}) { transition-delay: var(--transition-time); + height: var(--final-height); + } + + @media screen and (max-width: ${offscreenWidth}) { + .story { + transition-delay: 0ms; + position: fixed; + inset: 0; + top: 10rem; + } } } @@ -61,8 +77,9 @@ const expUnit = css` `; export const ExpUnit = (props: Experience) => { + const { active } = props; return ( -
+
diff --git a/src/pages/main/Exp.tsx b/src/pages/main/Exp.tsx index e0b7304..c61bf31 100644 --- a/src/pages/main/Exp.tsx +++ b/src/pages/main/Exp.tsx @@ -19,7 +19,7 @@ const Exp: React.FC = () => { return null; } - const slug = location.replace("/experience/", "").replace("/", ""); + const slug = location.replace(/^\/experience\/?/, "").replace("/", ""); useEffect(() => { const handler = (e: KeyboardEvent) => { @@ -82,7 +82,9 @@ const Exp: React.FC = () => { {...unit} onClick={() => { if (slug === unit.slug) return navigate("/experience"); - navigate(`/experience/${unit.slug}`); + if (slug) + navigate(`/experience/${unit.slug}`, { replace: true }); + else navigate(`/experience/${unit.slug}`); }} /> ))}