@bbki.ng/site 2.0.29 → 2.0.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @bbki.ng/site
2
2
 
3
+ ## 2.0.31
4
+
5
+ ## 2.0.30
6
+
3
7
  ## 2.0.29
4
8
 
5
9
  ## 2.0.28
package/index.html CHANGED
@@ -2,7 +2,7 @@
2
2
  <html lang="en" class="h-full no-scrollbar">
3
3
  <head>
4
4
  <title>bbki.ng</title>
5
- <meta name='viewport' content='initial-scale=1, viewport-fit=cover'>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <meta name="description" content="baby king" />
7
7
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
8
8
  <link
@@ -41,7 +41,7 @@
41
41
  </head>
42
42
 
43
43
  <body class="h-full m-0 flex flex-col font-mono">
44
- <div id="blog" class="flex-grow noto-serif"></div>
44
+ <div id="blog" class="flex-grow noto-serif no-scrollbar"></div>
45
45
  <script type="module" src="/src/index.tsx"></script>
46
46
  <script type="module">
47
47
  // Import the functions you need from the SDKs you need
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbki.ng/site",
3
- "version": "2.0.29",
3
+ "version": "2.0.31",
4
4
  "description": "code behind bbki.ng",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -24,7 +24,7 @@
24
24
  "react-cusdis": "^2.1.3",
25
25
  "react-dom": "^18.0.0",
26
26
  "react-hotkeys-hook": "^3.4.3",
27
- "react-router-dom": "6",
27
+ "react-router-dom": "6.30.2",
28
28
  "sonner": "1.4.0",
29
29
  "swr": "^2.2.5",
30
30
  "vaul": "1.1.2"
@@ -59,7 +59,7 @@
59
59
  "tailwindcss": "^3.0.7",
60
60
  "ts-jest": "^27.1.1",
61
61
  "typescript": "^4.5.4",
62
- "vite": "5.0.0",
62
+ "vite": "7.2.4",
63
63
  "vite-plugin-cross-origin-isolation": "0.1.6",
64
64
  "vite-plugin-glsl": "1.2.1",
65
65
  "vite-plugin-mdx": "^3.5.8",
package/src/blog/app.tsx CHANGED
@@ -5,7 +5,6 @@ import { HotKeyNav } from "./components";
5
5
  import { threeColWrapper } from "@/components/with_wrapper";
6
6
  import { Cover } from "./pages";
7
7
 
8
- import Png from "@/pages/extensions/png";
9
8
  import ArticlePage from "@/pages/extensions/txt/article";
10
9
  import NowPage from "@/pages/now";
11
10
  import PhotoProjects from "@/pages/extensions/png/png_projects";
@@ -22,35 +21,32 @@ import { AppCtxMenu } from "@/components/app_ctx_menu";
22
21
  import { Pochacco, PochaccoPose } from "@/components/Pochacco/Pochacco";
23
22
  import { Role, useRole } from "@/hooks/use_role";
24
23
  import { BotRedirect } from "@/pages/bot";
25
- import { PluginInit } from "@/components/plugin/PluginInit";
26
24
  import { BBContext } from "@/context/bbcontext";
27
25
  import { PluginContentPage } from "@/components/plugin/PluginContentPage";
28
26
  import { PluginRoutes } from "@/components/plugin/PluginRoutes";
29
- import {useClipboardToPost} from "@/hooks/use_clipboard_to_post";
30
- import {useSharedStringToPost} from "@/hooks/use_shared_string_to_post";
27
+ import { useClipboardToPost } from "@/hooks/use_clipboard_to_post";
28
+ import { useSharedStringToPost } from "@/hooks/use_shared_string_to_post";
31
29
 
32
30
  const Layout = () => {
33
31
  const { isLoading, isFontLoading } = useContext(GlobalLoadingContext);
34
32
  const role = useRole();
35
33
  const isQueen = role === Role.QUEEN;
36
34
  return (
37
- <>
38
- <Page
39
- nav={
40
- <AppCtxMenu>
41
- <Nav
42
- paths={usePaths()}
43
- className="gradient-blur-cover select-none"
44
- loading={isLoading}
45
- customLogo={
46
- isQueen ? <Pochacco pose={PochaccoPose.Watching} /> : null
47
- }
48
- />
49
- </AppCtxMenu>
50
- }
51
- main={<Outlet />}
52
- />
53
- </>
35
+ <Page
36
+ nav={
37
+ <AppCtxMenu>
38
+ <Nav
39
+ paths={usePaths()}
40
+ className="gradient-blur-cover select-none"
41
+ loading={isLoading}
42
+ customLogo={
43
+ isQueen ? <Pochacco pose={PochaccoPose.Watching} /> : null
44
+ }
45
+ />
46
+ </AppCtxMenu>
47
+ }
48
+ main={<Outlet />}
49
+ />
54
50
  );
55
51
  };
56
52
 
@@ -63,43 +59,40 @@ const TagsResultInMidCol = threeColWrapper(TagsResult);
63
59
  const CoverInMidCol = threeColWrapper(Cover);
64
60
 
65
61
  export const App = () => {
62
+ useClipboardToPost();
66
63
 
67
- useClipboardToPost();
64
+ useSharedStringToPost();
68
65
 
69
- useSharedStringToPost();
70
-
71
- return (
66
+ return (
72
67
  <SWR>
73
- {/*<EffectContextProvider>*/}
74
68
  <HotKeyNav>
75
69
  <BBContext>
76
- {/*<PluginInit>*/}
77
- <Routes>
78
- <Route path="/" element={<Layout />}>
79
- <Route index element={<CoverInMidCol />} />
70
+ <Routes>
71
+ <Route path="/" element={<Layout />}>
72
+ <Route index element={<CoverInMidCol />} />
80
73
 
81
- <Route path="blog" element={<ContentInMidCol />} />
82
- <Route path="blog/:title" element={<ArticleInMidCol />} />
83
- <Route path="blog/:title/:id" element={<PhotoProjects />} />
84
- <Route path="tags" element={<TagsInMidCol />} />
85
- <Route path="tags/:tag" element={<TagsResultInMidCol />} />
86
-
87
- <Route path="bot" element={<BotRedirect />} />
88
- <Route path="now" element={<NowInMidCol />} />
89
- <Route path="login" element={<LoginInMidCol />} />
90
- <Route path="upload" element={<UploadPage />} />
91
- <Route path="/plugins" element={<PluginRoutes />} />
92
- <Route
93
- path="/plugins/:pluginRoute"
94
- element={<PluginContentPage />}
95
- />
74
+ <Route path="blog" element={<Outlet />}>
75
+ <Route path="" element={<ContentInMidCol />} index />
76
+ <Route path=":title" element={<ArticleInMidCol />} />
96
77
  </Route>
97
- <Route path="*" element={<NotFound />} />
98
- </Routes>
99
- {/*</PluginInit>*/}
78
+ <Route path="blog/:title/:id" element={<PhotoProjects />} />
79
+ <Route path="tags" element={<TagsInMidCol />} />
80
+ <Route path="tags/:tag" element={<TagsResultInMidCol />} />
81
+
82
+ <Route path="bot" element={<BotRedirect />} />
83
+ <Route path="now" element={<NowInMidCol />} />
84
+ <Route path="login" element={<LoginInMidCol />} />
85
+ <Route path="upload" element={<UploadPage />} />
86
+ <Route path="/plugins" element={<PluginRoutes />} />
87
+ <Route
88
+ path="/plugins/:pluginRoute"
89
+ element={<PluginContentPage />}
90
+ />
91
+ </Route>
92
+ <Route path="*" element={<NotFound />} />
93
+ </Routes>
100
94
  </BBContext>
101
95
  </HotKeyNav>
102
- {/*</EffectContextProvider>*/}
103
96
  </SWR>
104
97
  );
105
98
  };
@@ -0,0 +1,73 @@
1
+ import { useEffect, useRef } from "react";
2
+ import { useLocation } from "react-router-dom";
3
+
4
+ const SCROLL_STORAGE_KEY = "div-scroll-positions";
5
+
6
+ function getScrollPositions(): Record<string, number> {
7
+ const stored = sessionStorage.getItem(SCROLL_STORAGE_KEY);
8
+ return stored ? JSON.parse(stored) : {};
9
+ }
10
+
11
+ function saveScrollPosition(key: string, position: number) {
12
+ const positions = getScrollPositions();
13
+ positions[key] = position;
14
+ sessionStorage.setItem(SCROLL_STORAGE_KEY, JSON.stringify(positions));
15
+ }
16
+
17
+ export function useBlogScrollReset() {
18
+ useEffect(() => {
19
+ const element = document.getElementById("blog");
20
+ if (!element) return;
21
+
22
+ element.scrollTop = 0;
23
+ }, []);
24
+ }
25
+
26
+ export function useBlogScrollRestoration(debounceMs: number = 100) {
27
+ const location = useLocation();
28
+ const isFirstRender = useRef(true);
29
+ const scrollTimeoutRef = useRef<number>();
30
+ const element = document.getElementById("blog");
31
+ const scrollKey = `blog`;
32
+
33
+ // Restore scroll position on mount
34
+ useEffect(() => {
35
+ if (!isFirstRender.current || !element) return;
36
+
37
+ const positions = getScrollPositions();
38
+ const savedPosition = positions[scrollKey];
39
+ if (!savedPosition) {
40
+ return;
41
+ }
42
+
43
+ requestAnimationFrame(() => {
44
+ element.scrollTop = savedPosition;
45
+ });
46
+ isFirstRender.current = false;
47
+ }, []);
48
+
49
+ // Save scroll position with debouncing
50
+ useEffect(() => {
51
+ if (!element) return;
52
+
53
+ const handleScroll = () => {
54
+ // Clear previous timeout
55
+ if (scrollTimeoutRef.current) {
56
+ clearTimeout(scrollTimeoutRef.current);
57
+ }
58
+
59
+ // Debounce the save operation
60
+ scrollTimeoutRef.current = window.setTimeout(() => {
61
+ if (element) {
62
+ saveScrollPosition(scrollKey, element.scrollTop);
63
+ }
64
+ }, debounceMs);
65
+ };
66
+
67
+ element.addEventListener("scroll", handleScroll, { passive: true });
68
+
69
+ return () => {
70
+ element.removeEventListener("scroll", handleScroll);
71
+ };
72
+ }, []);
73
+ }
@@ -1,24 +1,23 @@
1
1
  import React from "react";
2
2
 
3
3
  export const useClipboardContent = () => {
4
- const [clipboardContent, setClipboardContent] = React.useState<string | null>(null);
4
+ const [clipboardContent, setClipboardContent] = React.useState<string | null>(
5
+ null
6
+ );
5
7
 
6
- React.useEffect(() => {
7
- const handlePaste = (event: ClipboardEvent) => {
8
+ React.useEffect(() => {
9
+ const handlePaste = (event: ClipboardEvent) => {
10
+ if (event.clipboardData) {
11
+ setClipboardContent(event.clipboardData.getData("text/plain"));
12
+ }
13
+ };
8
14
 
9
- if (event.clipboardData) {
10
- setClipboardContent(event.clipboardData.getData("text/plain"));
11
- }
12
- };
15
+ document.addEventListener("paste", handlePaste);
13
16
 
14
- document.addEventListener("paste", handlePaste);
17
+ return () => {
18
+ document.removeEventListener("paste", handlePaste);
19
+ };
20
+ }, []);
15
21
 
16
- return () => {
17
- document.removeEventListener("paste", handlePaste);
18
- };
19
- }, []);
20
-
21
- console.log(clipboardContent);
22
-
23
- return clipboardContent;
24
- }
22
+ return clipboardContent;
23
+ };
package/src/blog/main.css CHANGED
@@ -14,6 +14,12 @@ body {
14
14
 
15
15
  #blog {
16
16
  overflow: auto;
17
+ -ms-overflow-style: none; /* Internet Explorer 10+ */
18
+ scrollbar-width: none;
19
+ }
20
+
21
+ #blog::-webkit-scrollbar {
22
+ display: none;
17
23
  }
18
24
 
19
25
  .noto-serif {
@@ -3,13 +3,14 @@ import { MdxArticleList } from "@/articles";
3
3
  import { withArticleWrapper } from "@/components";
4
4
  import { MdxArticle } from "@/types/articles";
5
5
  import { NotFound, DropZone } from "@bbki.ng/components";
6
- import { useParams } from "react-router-dom";
6
+ import { useLocation, useParams } from "react-router-dom";
7
7
  import { usePosts } from "@/hooks/use_posts";
8
8
  import { ArticlePage } from "@/components/article";
9
9
  import { GlobalLoadingContext } from "@/context/global_loading_state_provider";
10
10
  import { useFile2Post } from "@/hooks/use_file_to_post";
11
11
  import { useAuthed } from "@/hooks/use_authed";
12
12
  import { ArticleCtxMenu } from "@/components/article_ctx_menu";
13
+ import { useBlogScrollReset } from "@/hooks/use_blog_scroll_pos_restoration";
13
14
 
14
15
  type TArticleMap = {
15
16
  [key: string]: ReactElement;
@@ -28,14 +29,11 @@ export default () => {
28
29
  const { posts, isError, isLoading } = usePosts(title);
29
30
  const { setIsLoading } = useContext(GlobalLoadingContext);
30
31
 
31
- useEffect(() => {
32
- // scroll to top
33
- window.scrollTo(0, 0);
34
- }, []);
35
-
36
32
  const reader = useFile2Post();
37
33
  const isKing = useAuthed();
38
34
 
35
+ useBlogScrollReset();
36
+
39
37
  if (!title) {
40
38
  return <NotFound />;
41
39
  }
@@ -6,7 +6,9 @@ import { CenterLinkList } from "@/components";
6
6
  import { useAuthed } from "@/hooks/use_authed";
7
7
  import { useFile2Post } from "@/hooks/use_file_to_post";
8
8
  import { useSafeArticleLoading } from "@/hooks/use_safe_loading";
9
- import {useClipboardToPost} from "@/hooks/use_clipboard_to_post";
9
+ import { useClipboardToPost } from "@/hooks/use_clipboard_to_post";
10
+ import { useLocation } from "react-router-dom";
11
+ import { useBlogScrollRestoration } from "@/hooks/use_blog_scroll_pos_restoration";
10
12
 
11
13
  type TxtProps = {
12
14
  title?: string;
@@ -18,6 +20,8 @@ const Posts = (props: TxtProps) => {
18
20
 
19
21
  const isGlobalLoading = useSafeArticleLoading(0.2, 5);
20
22
 
23
+ useBlogScrollRestoration();
24
+
21
25
  if (isLoading) {
22
26
  return null;
23
27
  }