global article container
Some checks failed
/ image_build (push) Failing after 10s

This commit is contained in:
tymur999
2026-03-16 19:42:43 -04:00
parent 2c34229cc0
commit e61d3525a0
9 changed files with 101 additions and 40 deletions

View File

@@ -1,7 +1,8 @@
import {createContext, lazy, LazyExoticComponent, PropsWithChildren, useContext, useState} from "react";
import {Path} from "../router/router";
import {MDXContent} from "mdx/types";
import {lazy, LazyExoticComponent} from "react";
import allBlack from "../img/IMG_3095.jpg";
import {Reader} from "./Reader";
export interface Article {
name: string,
@@ -21,4 +22,19 @@ export const ARTICLES: Article[] = [
published: new Date(Date.parse("3/15/2026")),
article: lazy(() => import("./mdx/high-school.mdx"))
}
];
]
const articleContext =
createContext<ReturnType<typeof useState<Article | undefined>>>([undefined, function(){}]);
export function useArticle() {
return useContext(articleContext);
}
export default function ArticleProvider({ children }: PropsWithChildren) {
const state = useState<Article | undefined>(undefined);
return <articleContext.Provider value={state}>
<Reader/>
{children}
</articleContext.Provider>;
}

View File

@@ -1,31 +1,28 @@
import {Article, ARTICLES} from "./articles";
import {useState} from "react";
import {Article, ARTICLES, useArticle} from "./ArticleContext";
import "./list.sass";
import {ReactComponent as BoxSvg} from "../img/blog-box.svg";
import {Reader} from "./Reader";
export function ArticlesList() {
const [reading, setReading] = useState<Article | null>(null);
return <main className="art-ctr">
<section className="spacer"/>
<section className="articles">
{
ARTICLES.map(a =>
<BlogBox key={a.name} article={a} setReading={setReading}/>
<BlogBox key={a.name} article={a}/>
)
}
</section>
<section className="spacer"/>
<Reader post={reading} setPost={setReading} />
<Reader/>
</main>
}
function BlogBox(props: { article: Article, setReading: (_: Article) => void}) {
const {article,
article: {name, description, thumbnail, published},
setReading} = props;
function BlogBox(props: { article: Article }) {
const {article, article: {name, description, thumbnail, published} } = props;
const [, setReading] = useArticle();
return (
<button className="link" onClick={() => setReading(article)}>

View File

@@ -1,6 +1,6 @@
import {Article} from "./articles";
import {useArticle} from "./ArticleContext";
import {motion} from "framer-motion";
import {useAnimate} from "motion/react";
import {useAnimate, animate as animateClass} from "motion/react";
import {TargetAndTransition} from "motion";
import {useEffect} from "react";
@@ -9,22 +9,40 @@ const READER : Record<Transition, TargetAndTransition> = {
closed : { opacity: 0 },
open : { opacity: 1 }
};
const ARTICLE : Record<Transition, TargetAndTransition> = {
closed : { top: "-100%" },
open : { top: "50%" }
};
type Props = { post: Article | null, setPost: (_: Article | null) => void };
export function Reader({ post, setPost }: Props) {
const [ scope, animate ]= useAnimate<HTMLElement>();
export function Reader() {
const [ scope, animate ] = useAnimate<HTMLElement>();
const [post, setPost] = useArticle();
useEffect(() => {
if(post && scope.current) {
animate(scope.current, READER.open);
animateClass(".read-box", ARTICLE.open);
}
}, [post, scope]);
useEffect(() => {
function pressEscape(e: KeyboardEvent) {
e.key === "Escape" && handleClose();
}
document.addEventListener("keydown", pressEscape);
return () => document.removeEventListener("keydown", pressEscape);
}, []);
function handleClose() {
animate(scope.current, READER.closed)
.then(() => setPost(null));
Promise.all([
animate(scope.current, READER.closed),
animateClass(".read-box", ARTICLE.closed)
]).then(() => setPost(undefined));
}
return post ? (
<motion.article
key="reader"
@@ -33,9 +51,9 @@ export function Reader({ post, setPost }: Props) {
animate={READER.open}
onClick={handleClose}
className="reader link">
<section onClick={e => e.stopPropagation()}>
<motion.section className="read-box" initial={{top: "-100%"}} animate={{top: "50%"}} onClick={e => e.stopPropagation()}>
<post.article/>
</section>
</motion.section>
</motion.article>
) : <></>;
}

View File

@@ -54,17 +54,21 @@ $entry-width: 400px
flex-wrap: wrap
.reader
font-family: Neuton, serif
border: 2px solid black
&, > section
position: absolute
position: fixed
top: 50%
left: 50%
transform: translate(-50%, -50%)
z-index: 9999
width: 100vw
height: 100vh
min-height: 100vh
background: rgba(0,0,0,0.5)
> section
margin-top: nav.$padding
background: white
color: black
width: 75vw
height: 75vh
width: 50vw
min-height: 75vh

View File

@@ -1 +1,9 @@
# My high school experience
import allBlack from "../../img/IMG_3095.jpg";
import "./high-school.sass";
# My high school experience
<img src={allBlack} width={500} alt="turtleneck thumbnail"/>
My coding journey started with Code Combat, a Python coding RPG game

View File

@@ -0,0 +1,3 @@
article
img
width: 500px

View File

@@ -5,6 +5,7 @@ import {RouterProvider} from "./router/RouterContext";
import "@fontsource/inter"; // Defaults to weight 400
import "@fontsource/neuton";
import {Routes} from "./router/Route";
import ArticleProvider from "./articles/ArticleContext";
const Nav = React.lazy(() => import("./nav/Nav"));
@@ -15,8 +16,10 @@ const root = ReactDOM.createRoot(
root.render(
<React.StrictMode>
<RouterProvider>
<Nav/>
<Routes/>
<ArticleProvider>
<Nav/>
<Routes/>
</ArticleProvider>
</RouterProvider>
</React.StrictMode>
);

View File

@@ -1,15 +1,13 @@
import "./menu.sass";
import {animate, motion} from "framer-motion";
import {useEffect} from "react";
import {ARTICLES, useArticle} from "../articles/ArticleContext";
const articles = [
"Test 123",
"Hello",
"Title of Album"
];
const hidden = -999;
export function Menu({active} : {active: boolean}) {
const [, setReading] = useArticle();
useEffect(() => {
if(active) {
animate(".menu", {left : 0})
@@ -20,11 +18,18 @@ export function Menu({active} : {active: boolean}) {
return (
<motion.section initial={{left: hidden}} className="menu">
{
articles.map(title => <div key={title}>
{title}
</div>)
}
<ul>
{
ARTICLES.map((article) =>
<li key={article.name}>
<button className="link" onClick={() => setReading(article)} >
{article.name}
</button>
</li>
)
}
</ul>
</motion.section>
)
}

View File

@@ -2,8 +2,15 @@
.menu
position: absolute
display: flex
flex-direction: column
z-index: 999
&, ul
display: flex
flex-direction: column
list-style: none
button
font-weight: bold
text-decoration: underline
font-size: 1rem
background: nav.$menu
color: white
width: 25%