diff --git a/client/public/locales/en/translation.json b/client/public/locales/en/translation.json
index 96265fff..d7910763 100644
--- a/client/public/locales/en/translation.json
+++ b/client/public/locales/en/translation.json
@@ -120,7 +120,9 @@
}
},
"logout": "Logout",
+ "main_content": "Main content",
"next": "Next Page",
+ "no_more": "No More",
"preview": "Preview",
"previous": "Previous Page",
"publish": {
@@ -213,7 +215,6 @@
"title": "Top"
},
"unlisted": "Unlisted",
- "untitled": "Untitled",
"untop": {
"title": "Untop"
},
diff --git a/client/public/locales/ja/translation.json b/client/public/locales/ja/translation.json
index e909e777..de491513 100644
--- a/client/public/locales/ja/translation.json
+++ b/client/public/locales/ja/translation.json
@@ -120,7 +120,9 @@
}
},
"logout": "ログアウト",
+ "main_content": "本文",
"next": "次のページ",
+ "no_more": "もうない",
"preview": "プレビュー",
"previous": "前のページ",
"publish": {
@@ -213,7 +215,6 @@
"title": "キャッシュをクリア"
},
"unlisted": "リストされていない",
- "untitled": "無題",
"untop": {
"title": "トップ解除"
},
diff --git a/client/public/locales/zh-CN/translation.json b/client/public/locales/zh-CN/translation.json
index 628f441f..89ea98ea 100644
--- a/client/public/locales/zh-CN/translation.json
+++ b/client/public/locales/zh-CN/translation.json
@@ -120,7 +120,9 @@
}
},
"logout": "退出登录",
+ "main_content": "正文",
"next": "下一页",
+ "no_more": "没有更多了",
"preview": "预览",
"previous": "上一页",
"publish": {
@@ -213,7 +215,6 @@
"title": "置顶"
},
"unlisted": "未列出",
- "untitled": "未列出",
"untop": {
"title": "取消置顶"
},
diff --git a/client/public/locales/zh-TW/translation.json b/client/public/locales/zh-TW/translation.json
index fed5b878..c2e77f75 100644
--- a/client/public/locales/zh-TW/translation.json
+++ b/client/public/locales/zh-TW/translation.json
@@ -120,7 +120,9 @@
}
},
"logout": "登出",
+ "main_content": "正文",
"next": "下一頁",
+ "no_more": "沒有更多了",
"preview": "預覽",
"previous": "上一頁",
"publish": {
@@ -213,7 +215,6 @@
"title": "置頂"
},
"unlisted": "未列出",
- "untitled": "未列出",
"untop": {
"title": "取消置頂"
},
diff --git a/client/src/components/adjacent_feed.tsx b/client/src/components/adjacent_feed.tsx
new file mode 100644
index 00000000..57e68f8f
--- /dev/null
+++ b/client/src/components/adjacent_feed.tsx
@@ -0,0 +1,81 @@
+import {useEffect, useState} from "react";
+import {client} from "../main.tsx";
+import {timeago} from "../utils/timeago.ts";
+import {Link} from "wouter";
+import {useTranslation} from "react-i18next";
+
+export type AdjacentFeed = {
+ id: number;
+ title: string | null;
+ summary: string;
+ hashtags: {
+ id: number;
+ name: string;
+ }[];
+ createdAt: Date;
+ updatedAt: Date;
+};
+export type AdjacentFeeds = {
+ nextFeed: AdjacentFeed | null;
+ previousFeed: AdjacentFeed | null;
+};
+
+export function AdjacentSection({id, setError}: { id: string, setError: (error: string) => void }) {
+ const [adjacentFeeds, setAdjacentFeeds] = useState
+ {type === "previous" ? "Previous" : "Next"}
+
+ {type === "previous" ? "Previous" : "Next"}
+
+
+ {data.createdAt === data.updatedAt ? timeago(data.createdAt) : t('feed_card.published$time', {time: timeago(data.createdAt)})}
+
+ {data.createdAt !== data.updatedAt &&
+
+ {t('feed_card.updated$time', {time: timeago(data.updatedAt)})}
+
+ }
+
+ {t('no_more')}
+
+
+ {data.title}
+
+
- {draft === 1 && 草稿} - {listed === 0 && 未列出} + {draft === 1 && {t("draft")}} + {listed === 0 && {t("unlisted")}} {top === 1 && - 置顶 + {t('article.top.title')} }
diff --git a/client/src/page/callback.tsx b/client/src/page/callback.tsx
index 17b51500..e299ca68 100644
--- a/client/src/page/callback.tsx
+++ b/client/src/page/callback.tsx
@@ -1,10 +1,10 @@
-import { useEffect } from "react";
-import { setCookie } from "typescript-cookie";
-import { useLocation, useSearch } from "wouter";
+import {useEffect} from "react";
+import {setCookie} from "typescript-cookie";
+import {useLocation, useSearch} from "wouter";
export function CallbackPage() {
const searchParams = new URLSearchParams(useSearch());
- const [_, setLocation] = useLocation();
+ const [, setLocation] = useLocation();
useEffect(() => {
const token = searchParams.get('token');
if (token) {
diff --git a/client/src/page/feed.tsx b/client/src/page/feed.tsx
index e2fa6d9c..00e69f53 100644
--- a/client/src/page/feed.tsx
+++ b/client/src/page/feed.tsx
@@ -1,23 +1,24 @@
-import { useContext, useEffect, useRef, useState } from "react";
-import { Helmet } from "react-helmet";
-import { useTranslation } from "react-i18next";
+import {useContext, useEffect, useRef, useState} from "react";
+import {Helmet} from "react-helmet";
+import {useTranslation} from "react-i18next";
import ReactModal from "react-modal";
import Popup from "reactjs-popup";
-import { Link, useLocation } from "wouter";
-import { useAlert, useConfirm } from "../components/dialog";
-import { HashTag } from "../components/hashtag";
-import { Waiting } from "../components/loading";
-import { Markdown } from "../components/markdown";
-import { client } from "../main";
-import { ClientConfigContext } from "../state/config";
-import { ProfileContext } from "../state/profile";
-import { headersWithAuth } from "../utils/auth";
-import { siteName } from "../utils/constants";
-import { timeago } from "../utils/timeago";
-import { Button } from "../components/button";
-import { Tips } from "../components/tips";
-import { useLoginModal } from "../hooks/useLoginModal";
+import {Link, useLocation} from "wouter";
+import {useAlert, useConfirm} from "../components/dialog";
+import {HashTag} from "../components/hashtag";
+import {Waiting} from "../components/loading";
+import {Markdown} from "../components/markdown";
+import {client} from "../main";
+import {ClientConfigContext} from "../state/config";
+import {ProfileContext} from "../state/profile";
+import {headersWithAuth} from "../utils/auth";
+import {siteName} from "../utils/constants";
+import {timeago} from "../utils/timeago";
+import {Button} from "../components/button";
+import {Tips} from "../components/tips";
+import {useLoginModal} from "../hooks/useLoginModal";
import mermaid from "mermaid";
+import {AdjacentSection} from "../components/adjacent_feed.tsx";
type Feed = {
id: number;
@@ -39,6 +40,8 @@ type Feed = {
uv: number;
};
+
+
export function FeedPage({ id, TOC, clean }: { id: string, TOC: () => JSX.Element, clean: (id: string) => void }) {
const { t } = useTranslation();
const profile = useContext(ProfileContext);
@@ -46,7 +49,7 @@ export function FeedPage({ id, TOC, clean }: { id: string, TOC: () => JSX.Elemen
const [error, setError] = useState
{t('settings.title')}
diff --git a/client/src/page/timeline.tsx b/client/src/page/timeline.tsx
index 2820c906..828d3e71 100644
--- a/client/src/page/timeline.tsx
+++ b/client/src/page/timeline.tsx
@@ -1,11 +1,11 @@
-import { useEffect, useRef, useState } from "react"
-import { Helmet } from 'react-helmet'
-import { Link } from "wouter"
-import { Waiting } from "../components/loading"
-import { client } from "../main"
-import { headersWithAuth } from "../utils/auth"
-import { siteName } from "../utils/constants"
-import { useTranslation } from "react-i18next";
+import {useEffect, useRef, useState} from "react"
+import {Helmet} from 'react-helmet'
+import {Link} from "wouter"
+import {Waiting} from "../components/loading"
+import {client} from "../main"
+import {headersWithAuth} from "../utils/auth"
+import {siteName} from "../utils/constants"
+import {useTranslation} from "react-i18next";
export function TimelinePage() {
@@ -63,7 +63,8 @@ export function TimelinePage() {