Browse Source

feat: add experience story support for mobile

pull/2/head
Muthu Kumar 3 months ago
parent
commit
c11f785409
Failed to extract signature
  1. 164
      src/components/Exp/Story.tsx
  2. 2
      src/components/Exp/Tags.tsx
  3. 37
      src/components/Exp/Unit.tsx
  4. 6
      src/pages/main/Exp.tsx

164
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;
& * {
line-height: 140%;
}
& .story-content {
& > div {
max-height: 100%;
margin: 0;
column-count: 3;
column-gap: 2.5rem;
color: var(--text-subdued);
font-weight: 400;
& 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));
& .contents {
& .story-handle {
display: none;
}
& .story-content {
padding: 1.5rem;
line-height: 1.25rem;
display: flex;
flex-direction: row;
align-items: flex-start;
gap: 2rem;
gap: 3rem;
margin-block-start: 1rem;
height: var(--story-height);
}
}
& ul {
max-height: 100%;
margin: 0;
column-count: 3;
column-gap: 2rem;
color: var(--text-subdued);
font-weight: 400;
/* 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;
& li + li {
margin-block-start: 0.5rem;
}
/*
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 (
<div className={cx(story, "story")}>
<div className="contents">
<div
className={cx(story, "story")}
id={active ? "active-story" : undefined}>
<div aria-hidden className="story-handle" />
<div className="story-content">
<img
src={`/assets/logos/` + logo}
className={cx(
@ -59,7 +152,36 @@ export const Story = ({ description, logo }: Experience) => {
`,
)}
/>
<ul>{description}</ul>
<button
className={cx(
"closer",
css`
display: none;
appearance: none;
border: none;
background: var(--card-active);
color: var(--text-subdued);
width: 3rem;
height: 3rem;
border-radius: 3rem;
/* set in mobile mode */
/* display: flex; */
justify-content: center;
align-items: center;
position: absolute;
top: 4rem;
right: 4rem;
cursor: pointer;
transform: rotate(90deg);
`,
)}
onClick={() => window.history.back()}>
<Close />
</button>
<div>{description}</div>
</div>
</div>
);

2
src/components/Exp/Tags.tsx

@ -100,7 +100,7 @@ export const Clear = (props: { selected: Tags }) => {
fill: var(--text-colour);
`}
/>
Clear
Clear filters
</button>
);
};

37
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 (
<div className={cx(expUnit, { active: props.active })}>
<div className={cx(expUnit, { active })}>
<Content {...props} />
<Story {...props} />
</div>

6
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}`);
}}
/>
))}

Loading…
Cancel
Save