Skip to content

Commit

Permalink
Merge pull request #203 from OXeu/dev
Browse files Browse the repository at this point in the history
fix: a few known bugs
  • Loading branch information
OXeu authored Jul 8, 2024
2 parents ccf1d6c + d90b390 commit 2aebc6c
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 83 deletions.
26 changes: 15 additions & 11 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from 'react'
import { useEffect, useMemo, useRef, useState } from 'react'
import { Helmet } from 'react-helmet'
import { getCookie } from 'typescript-cookie'
import { DefaultParams, PathPattern, Route, Switch } from 'wouter'
Expand All @@ -16,15 +16,15 @@ import { HashtagsPage } from './page/hashtags.tsx'
import { Settings } from "./page/settings.tsx"
import { TimelinePage } from './page/timeline'
import { WritingPage } from './page/writing'
import { ClientConfigContext, ConfigWrapper, defaultClientConfig, defaultClientConfigWrapper } from './state/config.tsx'
import { ClientConfigContext, ConfigWrapper, defaultClientConfig } from './state/config.tsx'
import { Profile, ProfileContext } from './state/profile'
import { headersWithAuth } from './utils/auth'
import { tryInt } from './utils/int'

function App() {
const ref = useRef(false)
const [profile, setProfile] = useState<Profile | undefined>()
const [config, setConfig] = useState<ConfigWrapper>(defaultClientConfigWrapper)
const [config, setConfig] = useState<ConfigWrapper>(new ConfigWrapper({}, new Map()))
useEffect(() => {
if (ref.current) return
if (getCookie('token')?.length ?? 0 > 0) {
Expand Down Expand Up @@ -57,12 +57,14 @@ function App() {
}
ref.current = true
}, [])
const favicon = useMemo(() => config.get<string>("favicon"), [config])
return (
<>
<ClientConfigContext.Provider value={config}>
<ProfileContext.Provider value={profile}>
<Helmet>
<link rel="icon" href={config.get("favicon")} />
{favicon &&
<link rel="icon" href={favicon} />}
</Helmet>
<Switch>
<RouteMe path="/">
Expand Down Expand Up @@ -111,15 +113,15 @@ function App() {
</RouteMe>

<RouteWithIndex path="/feed/:id">
{(params, TOC) => {
return (<FeedPage id={params.id || ""} TOC={TOC} />)
{(params, TOC, clean) => {
return (<FeedPage id={params.id || ""} TOC={TOC} clean={clean} />)
}}
</RouteWithIndex>

<RouteWithIndex path="/:alias">
{(params, TOC) => {
{(params, TOC, clean) => {
return (
<FeedPage id={params.alias || ""} TOC={TOC} />
<FeedPage id={params.alias || ""} TOC={TOC} clean={clean} />
)
}}
</RouteWithIndex>
Expand Down Expand Up @@ -154,10 +156,12 @@ function RouteMe({ path, children, headerComponent, paddingClassName }:


function RouteWithIndex({ path, children }:
{ path: PathPattern, children: (params: DefaultParams, TOC: () => JSX.Element) => React.ReactNode }) {
const TOC = useTableOfContents(".toc-content", "header");
{ path: PathPattern, children: (params: DefaultParams, TOC: () => JSX.Element, clean: (id: string) => void) => React.ReactNode }) {
const { TOC, cleanup } = useTableOfContents(".toc-content");
return (<RouteMe path={path} headerComponent={TOCHeader({ TOC: TOC })} paddingClassName='mx-4'>
{params => children(params, TOC)}
{params => {
return children(params, TOC, cleanup)
}}
</RouteMe>)
}

Expand Down
85 changes: 48 additions & 37 deletions client/src/components/markdown.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import React, { isValidElement, cloneElement, useEffect, useMemo } from "react";
import ReactMarkdown from "react-markdown";
import gfm from "remark-gfm";
import remarkMath from "remark-math";
import rehypeKatex from "rehype-katex";
import { remarkAlert } from "remark-github-blockquote-alert";
import "katex/dist/katex.min.css";
import React, { cloneElement, isValidElement, useEffect, useMemo, useRef } from "react";
import ReactMarkdown from "react-markdown";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import {
vscDarkPlus,
base16AteliersulphurpoolLight,
vscDarkPlus,
} from "react-syntax-highlighter/dist/esm/styles/prism";
import rehypeKatex from "rehype-katex";
import rehypeRaw from "rehype-raw";
import { useColorMode } from "../utils/darkModeUtils";
import gfm from "remark-gfm";
import { remarkAlert } from "remark-github-blockquote-alert";
import remarkMath from "remark-math";
import Lightbox, { SlideImage } from "yet-another-react-lightbox";
import Counter from "yet-another-react-lightbox/plugins/counter";
import "yet-another-react-lightbox/plugins/counter.css";
import Download from "yet-another-react-lightbox/plugins/download";
import Zoom from "yet-another-react-lightbox/plugins/zoom";
import Counter from "yet-another-react-lightbox/plugins/counter";
import "yet-another-react-lightbox/styles.css";
import "yet-another-react-lightbox/plugins/counter.css";
import { useColorMode } from "../utils/darkModeUtils";

const countNewlinesBeforeNode = (text: string, offset: number) => {
let newlinesBefore = 0;
Expand Down Expand Up @@ -48,34 +48,13 @@ const isMarkdownImageLinkAtEnd = (text: string) => {
export function Markdown({ content }: { content: string }) {
const colorMode = useColorMode();
const [index, setIndex] = React.useState(-1);
const [slides, setSlides] = React.useState<SlideImage[]>();
const slides = useRef<SlideImage[]>();

useEffect(() => {
const parent = document.getElementsByClassName("toc-content")[0];
if (!parent) return;
const images = parent.querySelectorAll("img");
const slides = Array.from(images)
.map((image) => {
const url = image.getAttribute("src") || "";
const filename = url.split("/").pop() || "";
const alt = image.getAttribute("alt") || "";
return {
src: url,
alt: alt,
imageFit: "contain" as const,
download: {
url: url,
filename: filename,
},
};
})
.filter((slide) => slide.src != "");
setSlides(slides);
slides.current = undefined;
}, [content]);

const show = (src: string | undefined) => {
const index = slides?.findIndex((slide) => slide.src === src) ?? -1;
setIndex(index);
};


const Content = useMemo(() => (
<ReactMarkdown
Expand All @@ -101,7 +80,9 @@ export function Markdown({ content }: { content: string }) {
<img
src={src}
{...props}
onClick={() => show(src)}
onClick={() => {
show(src)
}}
className={`mx-auto ${rounded ? "rounded-xl" : ""}`}
style={{ zoom: scale }}
/>
Expand Down Expand Up @@ -361,13 +342,43 @@ export function Markdown({ content }: { content: string }) {
}}
/>), [content])



const show = (src: string | undefined) => {
let slidesLocal = slides.current;
if (!slidesLocal) {
const parent = document.getElementsByClassName("toc-content")[0];
if (!parent) return;
const images = parent.querySelectorAll("img");
slidesLocal = Array.from(images)
.map((image) => {
const url = image.getAttribute("src") || "";
const filename = url.split("/").pop() || "";
const alt = image.getAttribute("alt") || "";
return {
src: url,
alt: alt,
imageFit: "contain" as const,
download: {
url: url,
filename: filename,
},
};
})
.filter((slide) => slide.src != "");
slides.current = (slidesLocal);
}
const index = slidesLocal?.findIndex((slide) => slide.src === src) ?? -1;
setIndex(index);
};

return (
<>
{Content}
<Lightbox
plugins={[Download, Zoom, Counter]}
index={index}
slides={slides}
slides={slides.current}
open={index >= 0}
close={() => setIndex(-1)}
/>
Expand Down
70 changes: 38 additions & 32 deletions client/src/hooks/useTableOfContents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,20 @@ export interface TableOfContent {
index: number
text: string
marginLeft: number
offsetTop: number
element: HTMLElement
}

const useTableOfContents = (selector: string, id: string) => {
const useTableOfContents = (selector: string) => {
const intersectingListRef = useRef<boolean[]>([]) // isIntersecting array
const [tableOfContents, setTableOfContents] = useState<TableOfContent[]>([])
const [activeIndex, setActiveIndex] = useState(0)
const { t } = useTranslation()
const io = useRef<IntersectionObserver | null>(null);

const ref = useRef(false)
const [ref, setRef] = useState("-1")
const lastRef = useRef("")

useEffect(() => {
console.log(id,ref.current)
if (ref.current) return
if (lastRef.current === ref) return
const content = document.querySelector(selector)
if (!content) return
const intersectingList = intersectingListRef.current
Expand All @@ -32,7 +31,7 @@ const useTableOfContents = (selector: string, id: string) => {
index: i,
text: header.textContent || '',
marginLeft: (Number(header.tagName.charAt(1)) - 1) * 10,
offsetTop: header.offsetTop + 2, // have to down little bit
element: header, // have to down little bit
}))
setTableOfContents(tocData)

Expand All @@ -46,7 +45,6 @@ const useTableOfContents = (selector: string, id: string) => {
intersectingList[idx] = isIntersecting
})
// get activeIndex
console.log(id, intersectingList)
const currentIndex = intersectingList.findIndex((item) => item)
let activeIndex = currentIndex - 1
if (currentIndex === -1) {
Expand All @@ -65,32 +63,40 @@ const useTableOfContents = (selector: string, id: string) => {
intersectingList.push(false) // increase array length
io.current!.observe(header) // register to observe
})
ref.current = true
console.log(id,ref.current)
})
lastRef.current = ref
return () => {
if (io.current) io.current.disconnect()
}
}, [ref])

const onClick = (offsetTop: number) => {
window.scrollTo({
behavior: 'smooth',
left: 0,
top: offsetTop,
})
const cleanup = (newId: string) => {
if (lastRef.current === newId) return
setRef(newId)
if (io.current) io.current.disconnect()
}

return {
TOC: () => (<div>
<h2 className="text-lg font-bold">{t("index.title")}</h2>
<ul>
{tableOfContents.length === 0 && <li>{t("index.empty.title")}</li>}
{tableOfContents.map((item) => (
<li
key={item.index}
className={activeIndex === item.index ? "text-theme" : ""}
style={{ marginLeft: item.marginLeft }}
onClick={() => {
item.element.scrollIntoView({
behavior: 'smooth'
});
}}
>
{item.text}
</li>
))}
</ul>
</div>), cleanup
}
return () => (<div>
<h2 className="text-lg font-bold">{t("index.title")}</h2>
<ul>
{tableOfContents.map((item) => (
<li
key={item.index}
className={activeIndex === item.index ? "text-theme" : ""}
style={{ marginLeft: item.marginLeft }}
onClick={() => onClick(item.offsetTop)}
>
{item.text}
</li>
))}
</ul>
</div>)
}

export default useTableOfContents
3 changes: 2 additions & 1 deletion client/src/page/feed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type Feed = {
uv: number;
};

export function FeedPage({ id, TOC }: { id: string, TOC: () => JSX.Element }) {
export function FeedPage({ id, TOC, clean }: { id: string, TOC: () => JSX.Element, clean: (id: string) => void }) {
const { t } = useTranslation();
const profile = useContext(ProfileContext);
const [feed, setFeed] = useState<Feed>();
Expand Down Expand Up @@ -91,6 +91,7 @@ export function FeedPage({ id, TOC }: { id: string, TOC: () => JSX.Element }) {
if (img_match) {
setHeadImage(img_match[1]);
}
clean(id);
}, 0);
}
});
Expand Down
5 changes: 3 additions & 2 deletions client/src/state/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ export class ConfigWrapper {
this.defaultConfig = defaultConfig;
}
get<T>(key: string) {
if (this.config[key] != undefined) {
return this.config[key] as T;
const value = this.config[key];
if (value != undefined && value != "") {
return value as T;
}
if (this.defaultConfig.has(key)) {
return this.defaultConfig.get(key) as T;
Expand Down

0 comments on commit 2aebc6c

Please sign in to comment.