Skip to content

Commit

Permalink
Merge pull request #50 from NekoAria/main
Browse files Browse the repository at this point in the history
修复计数和历史请求问题,增强文章切换功能和移动端体验,优化配置和状态管理
  • Loading branch information
electh authored Mar 28, 2024
2 parents 4c7a943 + cd7bca0 commit 3b5cec1
Show file tree
Hide file tree
Showing 38 changed files with 718 additions and 365 deletions.
2 changes: 1 addition & 1 deletion src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import useStore from "./Store";
import Header from "./components/Header/Header";
import Main from "./components/Main/Main";
import Sidebar from "./components/Sidebar/Sidebar";
import { applyColor } from "./utils/Colors";
import { applyColor } from "./utils/colors";

const App = () => {
const initData = useStore((state) => state.initData);
Expand Down
58 changes: 35 additions & 23 deletions src/Store.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
getTodayEntries,
getUnreadInfo,
} from "./apis";
import { getConfig, setConfig } from "./utils/Config";
import { getConfig } from "./utils/config";

const calculateUnreadCount = (currentCount, status) => {
if (status === "read") {
Expand Down Expand Up @@ -44,12 +44,17 @@ const useStore = create((set, get) => ({
unreadToday: 0,
starredCount: 0,
readCount: 0,
hiddenFeedIds: [],
hiddenGroupIds: [],
entriesOrder: getConfig("entriesOrder") || "desc",
entriesPerPage: getConfig("entriesPerPage") || 100,
showAllFeeds: getConfig("showAllFeeds") || false,
loading: true,
visible: {
settings: false,
addFeed: false,
},
theme: getConfig("theme") || "system",
theme: getConfig("theme") || "light",
layout: getConfig("layout") || "large",
fontSize: getConfig("fontSize") || 1.05,
showFeedIcon: getConfig("showFeedIcon") || true,
Expand All @@ -66,6 +71,10 @@ const useStore = create((set, get) => ({
set((state) => ({ starredCount: updater(state.starredCount) })),
setReadCount: (updater) =>
set((state) => ({ readCount: updater(state.readCount) })),
setEntriesOrder: (value) => set({ entriesOrder: value }),
setEntriesPerPage: (value) => set({ entriesPerPage: value }),
toggleShowAllFeeds: () =>
set((state) => ({ showAllFeeds: !state.showAllFeeds })),
setActiveContent: (activeContent) => {
set({ activeContent: activeContent });
},
Expand Down Expand Up @@ -103,11 +112,27 @@ const useStore = create((set, get) => ({
starredResponse &&
todayUnreadResponse
) {
const hiddenFeedIds = feedResponse.data
.filter((feed) => feed.hide_globally || feed.category.hide_globally)
.map((feed) => feed.id);
const hiddenGroupIds = groupResponse.data
.filter((group) => group.hide_globally)
.map((group) => group.id);

set({ hiddenFeedIds });
set({ hiddenGroupIds });

const unreadInfo = unreadResponse.data.unreads;
const unreadTotal = Object.values(unreadInfo).reduce(
(acc, cur) => acc + cur,
0,
);

const unreadTotal = Object.keys(unreadInfo).reduce((acc, id) => {
if (
get().showAllFeeds ||
!hiddenFeedIds.includes(Number.parseInt(id))
) {
return acc + unreadInfo[id];
}
return acc;
}, 0);

set({ unreadTotal });

Expand Down Expand Up @@ -165,34 +190,21 @@ const useStore = create((set, get) => ({
}));
},

toggleTheme: (value) => {
set({ theme: value });
setConfig("theme", value);
},

toggleLayout: () => {
const newLayout = get().layout === "large" ? "small" : "large";
set({ layout: newLayout });
setConfig("layout", newLayout);
},

setFontSize: (sizeStr) => {
set({ fontSize: sizeStr });
setConfig("fontSize", sizeStr);
},
setFontSize: (sizeStr) => set({ fontSize: sizeStr }),

setShowFeedIcon: (showFeedIcon) => {
set({ showFeedIcon: showFeedIcon });
setConfig("showFeedIcon", showFeedIcon);
},
toggleShowFeedIcon: () =>
set((state) => ({ showFeedIcon: !state.showFeedIcon })),

setVisible: (modalName, visible) => {
set((state) => ({ visible: { ...state.visible, [modalName]: visible } }));
},

setCollapsed: (collapsed) => {
set({ collapsed: collapsed });
},
toggleCollapsed: () => set((state) => ({ collapsed: !state.collapsed })),
}));

export default useStore;
2 changes: 1 addition & 1 deletion src/apis/axios.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Message } from "@arco-design/web-react";
import axios from "axios";

import router from "../routes";
import { getAuth } from "../utils/Auth";
import { getAuth } from "../utils/auth";

const apiClient = axios.create({
timeout: 5000,
Expand Down
82 changes: 69 additions & 13 deletions src/apis/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { get24HoursAgoTimestamp } from "../utils/Date";
import { getConfig } from "../utils/config.js";
import { get24HoursAgoTimestamp } from "../utils/date";
import { apiClient } from "./axios";

export const updateEntriesStatus = async (entryIds, newStatus) =>
Expand Down Expand Up @@ -54,20 +55,69 @@ export const addFeed = async (feedUrl, groupId, isFullText) =>
crawler: isFullText,
});

export const buildEntriesUrl = (baseParams, extraParams = {}) => {
const { baseUrl, orderField, direction, offset, limit, status } = baseParams;
const queryParams = new URLSearchParams({
...extraParams,
order: orderField,
direction,
offset,
limit,
});

if (status) {
queryParams.append("status", status);
}

return `${baseUrl}?${queryParams.toString()}`;
};

export const getAllEntries = async (offset = 0, status = null) => {
const base_url = `/v1/entries?order=published_at&direction=desc&offset=${offset}`;
const url = status ? `${base_url}&status=${status}` : base_url;
const entriesOrder = getConfig("entriesOrder");
const entriesPerPage = getConfig("entriesPerPage");
const baseParams = {
baseUrl: "/v1/entries",
orderField: "created_at",
direction: entriesOrder,
offset,
limit: entriesPerPage,
status,
};

const url = buildEntriesUrl(baseParams);
return apiClient.get(url);
};

export const getHistoryEntries = async (offset = 0) => {
const url = `/v1/entries?order=changed_at&direction=desc&status=read&offset=${offset}`;
const entriesOrder = getConfig("entriesOrder");
const entriesPerPage = getConfig("entriesPerPage");
const baseParams = {
baseUrl: "/v1/entries",
orderField: "changed_at",
direction: entriesOrder,
offset,
limit: entriesPerPage,
status: "read",
};

const url = buildEntriesUrl(baseParams);
return apiClient.get(url);
};

export const getStarredEntries = async (offset = 0, status = null) => {
const baseUrl = `/v1/entries?order=published_at&direction=desc&starred=true&offset=${offset}`;
const url = status ? `${baseUrl}&status=${status}` : baseUrl;
const entriesOrder = getConfig("entriesOrder");
const entriesPerPage = getConfig("entriesPerPage");
const baseParams = {
baseUrl: "/v1/entries",
orderField: "published_at",
direction: entriesOrder,
offset,
limit: entriesPerPage,
status,
};
const extraParams = { starred: "true" };

const url = buildEntriesUrl(baseParams, extraParams);
return apiClient.get(url);
};

Expand All @@ -76,13 +126,19 @@ export const getTodayEntries = async (
status = null,
limit = null,
) => {
const entriesOrder = getConfig("entriesOrder");
const entriesPerPage = limit || getConfig("entriesPerPage");
const timestamp = get24HoursAgoTimestamp();
let url = `/v1/entries?order=published_at&direction=desc&published_after=${timestamp}&offset=${offset}`;
if (status) {
url += `&status=${status}`;
}
if (limit) {
url += `&limit=${limit}`;
}
const baseParams = {
baseUrl: "/v1/entries",
orderField: "published_at",
direction: entriesOrder,
offset,
limit: entriesPerPage,
status,
};
const extraParams = { published_after: timestamp };

const url = buildEntriesUrl(baseParams, extraParams);
return apiClient.get(url);
};
12 changes: 10 additions & 2 deletions src/components/Article/ActionButtons.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,19 @@ import useStore from "../../Store";
import useEntryActions from "../../hooks/useEntryActions";
import useKeyHandlers from "../../hooks/useKeyHandlers";

const ActionButtons = ({ handleEntryClick }) => {
const ActionButtons = ({
handleEntryClick,
getEntries,
isFilteredEntriesUpdated,
}) => {
const activeContent = useStore((state) => state.activeContent);
const { handleFetchContent, toggleEntryStarred, toggleEntryStatus } =
useEntryActions();
const { handleLeftKey, handleRightKey } = useKeyHandlers();
const { handleLeftKey, handleRightKey } = useKeyHandlers(
handleEntryClick,
getEntries,
isFilteredEntriesUpdated,
);

if (!activeContent) {
return null;
Expand Down
12 changes: 10 additions & 2 deletions src/components/Article/ActionButtonsMobile.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,19 @@ import useStore from "../../Store";
import useEntryActions from "../../hooks/useEntryActions";
import useKeyHandlers from "../../hooks/useKeyHandlers";

const ActionButtonsMobile = ({ handleEntryClick }) => {
const ActionButtonsMobile = ({
handleEntryClick,
getEntries,
isFilteredEntriesUpdated,
}) => {
const activeContent = useStore((state) => state.activeContent);
const { handleFetchContent, toggleEntryStarred, toggleEntryStatus } =
useEntryActions();
const { handleLeftKey, handleRightKey, handleEscapeKey } = useKeyHandlers();
const { handleLeftKey, handleRightKey, handleEscapeKey } = useKeyHandlers(
handleEntryClick,
getEntries,
isFilteredEntriesUpdated,
);

if (!activeContent) {
return null;
Expand Down
2 changes: 1 addition & 1 deletion src/components/Article/ArticleCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import classNames from "classnames";
import React from "react";

import useStore from "../../Store";
import { generateRelativeTime } from "../../utils/Date";
import { generateRelativeTime } from "../../utils/date";
import "./ArticleCard.css";
import ImageWithLazyLoading from "./ImageWithLazyLoading";

Expand Down
2 changes: 1 addition & 1 deletion src/components/Article/ArticleCardMini.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import classNames from "classnames";
import React from "react";

import useStore from "../../Store";
import { generateRelativeTime } from "../../utils/Date";
import { generateRelativeTime } from "../../utils/date";
import "./ArticleCard.css";
import ImageWithLazyLoading from "./ImageWithLazyLoading";

Expand Down
5 changes: 3 additions & 2 deletions src/components/Article/ArticleDetail.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,9 @@ const ArticleDetail = forwardRef((_, ref) => {
<Typography.Text
style={{ color: "var(--color-text-3)", fontSize: "0.75 rem" }}
>
{dayjs(activeContent.published_at).format("MMMM D, YYYY")} AT{" "}
{dayjs(activeContent.published_at).format("hh:mm")}
{dayjs(activeContent.published_at).format(
"dddd, MMMM D, YYYY [at] h:mm A",
)}
</Typography.Text>
<Divider />
</div>
Expand Down
41 changes: 24 additions & 17 deletions src/components/Article/ArticleList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import isURL from "validator/es/lib/isURL";

import useStore from "../../Store";
import useLoadMore from "../../hooks/useLoadMore";
import { extractProtocolAndHostname } from "../../utils/URL";
import { extractProtocolAndHostname } from "../../utils/url";
import ContentContext from "../Content/ContentContext";
import ArticleCard from "./ArticleCard";
import ArticleCardMini from "./ArticleCardMini";
Expand All @@ -23,6 +23,8 @@ const ArticleList = forwardRef(

const { loadingMore, handleLoadMore } = useLoadMore();
const layout = useStore((state) => state.layout);
const hiddenFeedIds = useStore((state) => state.hiddenFeedIds);
const showAllFeeds = useStore((state) => state.showAllFeeds);

return (
<div
Expand All @@ -40,23 +42,28 @@ const ArticleList = forwardRef(
<LoadingCards loading={loading} />
{loading ? null : (
<div ref={cardsRef}>
{filteredEntries.map((entry) => {
if (!isURL(entry.feed.site_url)) {
entry.feed.site_url = extractProtocolAndHostname(
entry.feed.feed_url,
);
}
{filteredEntries
.filter(
(entry) =>
showAllFeeds || !hiddenFeedIds.includes(entry.feed.id),
)
.map((entry) => {
if (!isURL(entry.feed.site_url)) {
entry.feed.site_url = extractProtocolAndHostname(
entry.feed.feed_url,
);
}

const ArticleComponent =
layout === "small" ? ArticleCardMini : ArticleCard;
return (
<ArticleComponent
key={entry.id}
entry={entry}
handleEntryClick={handleEntryClick}
/>
);
})}
const ArticleComponent =
layout === "small" ? ArticleCardMini : ArticleCard;
return (
<ArticleComponent
key={entry.id}
entry={entry}
handleEntryClick={handleEntryClick}
/>
);
})}
</div>
)}
{!loading &&
Expand Down
7 changes: 4 additions & 3 deletions src/components/Content/Content.css
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,13 @@ p {

/*code 相关样式 */
.article-content code {
font-family: "JetBrains Mono", Consolas, Monaco, "Andale Mono", monospace;
font-size: 0.8em;
background-color: var(--color-neutral-3);
border-radius: 2px;
color: var(--color-text-2);
font-family: "JetBrains Mono", Consolas, Monaco, "Andale Mono", monospace;
font-size: 0.8em;
margin: 2px;
padding: 2px;
border-radius: 2px;
}

/*code 相关样式 */
Expand Down
Loading

0 comments on commit 3b5cec1

Please sign in to comment.