From 589f69633145ac7436992618dbf057c026bea2fb Mon Sep 17 00:00:00 2001 From: Ted <406419317@qq.com> Date: Tue, 23 Jun 2026 03:53:41 +0800 Subject: [PATCH] =?UTF-8?q?refactor&fix:=20=E9=87=8D=E6=9E=84=E5=B8=83?= =?UTF-8?q?=E5=B1=80=E7=BA=A6=E6=9D=9F=EF=BC=9A=20-=20=E5=91=BD=E5=90=8D?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=E5=8C=96=EF=BC=8C=E6=9B=B4=E6=9C=89=E6=9D=A1?= =?UTF-8?q?=E7=90=86=EF=BC=9B=20-=20=E6=94=B9=E7=94=A8grid=E5=B8=83?= =?UTF-8?q?=E5=B1=80=EF=BC=9B=20-=20=E4=BF=AE=E5=A4=8D=E4=B9=8B=E5=89=8D?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=E7=9A=84=E5=AE=BD=E5=BA=A6=E4=B8=8D=E4=B8=80?= =?UTF-8?q?=E8=87=B4=E3=80=81=E8=AF=A5=E7=BC=A9=E4=B8=8D=E7=BC=A9=E7=AD=89?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MasonryLayout.tsx | 26 ---------- src/hooks/useDashboardLayout.ts | 29 ++++++----- src/pages/CardDashboard.tsx | 72 +++++++++++++--------------- src/pages/cards/cards.css | 15 +++++- src/pages/cards/emptyCard.css | 1 - src/pages/dashboard.css | 61 ++++++++++++----------- src/pages/header/HeaderView.tsx | 23 ++++----- src/pages/header/addnote.css | 3 +- src/pages/header/header.css | 41 +++++++++------- src/pages/sidebar/SideBarContent.tsx | 2 +- src/pages/sidebar/Sidebar.tsx | 13 ++++- src/pages/sidebar/sidebar.css | 8 ++-- 12 files changed, 150 insertions(+), 144 deletions(-) delete mode 100644 src/components/MasonryLayout.tsx diff --git a/src/components/MasonryLayout.tsx b/src/components/MasonryLayout.tsx deleted file mode 100644 index 53ddba2..0000000 --- a/src/components/MasonryLayout.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import * as React from "react"; - -interface MasonryLayoutProps { - children: React.ReactNode[]; - columns: number; -} - -export const MasonryLayout = ({ children, columns }: MasonryLayoutProps) => { - const getColumns = (items: React.ReactNode[], colCount: number) => { - const cols: React.ReactNode[][] = Array.from({ length: colCount }, () => []); - items.forEach((item, idx) => { - cols[idx % colCount].push(item); - }); - return cols; - }; - - const columnsData = getColumns(children, columns); - - return ( - <> - {columnsData.map((col, idx) => ( -
{col}
- ))} - - ); -}; diff --git a/src/hooks/useDashboardLayout.ts b/src/hooks/useDashboardLayout.ts index 3996e9c..d43ad0d 100644 --- a/src/hooks/useDashboardLayout.ts +++ b/src/hooks/useDashboardLayout.ts @@ -5,31 +5,38 @@ import { useCombineStore } from 'src/store'; export const useDashboardLayout = (containerRef: RefObject) => { const cardsColumns = useCombineStore((state) => state.settings.cardsColumns); const [showSidebar, setShowSidebar] = useState<'normal' | 'hide' | 'show'>(Platform.isMobile ? 'hide' : 'normal'); - const [colCount, setColCount] = useState(1); + const [colCount, setColCount] = useState<'small' | 'one' | 'two'>('one'); const updateLayout = useCallback((width?: number) => { if (Platform.isMobile) { setShowSidebar('hide'); - setColCount(1); + setColCount('small'); return; } - const containerWidth = width ?? containerRef.current?.clientWidth ?? 0; + let containerWidth = width ?? containerRef.current?.clientWidth ?? 0; if (containerWidth === 0) return; + + containerWidth -= 16; // both padding 8 + const siderbar = 296; + const padding = 6; + const card = 620; + const cardGap = 16; - const _showSidebar = containerWidth >= 920 ? 'normal' : 'hide'; // 920 是试验效果得来的 + const _showSidebar = containerWidth >= (siderbar + padding + card) ? 'normal' : 'hide'; setShowSidebar(_showSidebar); - if (cardsColumns == 1) { - setColCount(1); + if (containerWidth < card) { + setColCount('small'); return; } + + if (cardsColumns == 1) { + setColCount('one'); + return; + } - const mainWidth = containerWidth - (_showSidebar == 'normal' ? 400 : 0); - const cardWidth = 620; - const cardsPadding = 24; - const widthFor2Cols = cardWidth + cardsPadding + cardWidth; - const cnt = mainWidth >= widthFor2Cols ? 2 : 1; + const cnt = containerWidth >= (siderbar + padding + card + cardGap + card) ? 'two' : 'one'; setColCount(cnt); }, [cardsColumns, containerRef]); diff --git a/src/pages/CardDashboard.tsx b/src/pages/CardDashboard.tsx index ab82d8f..24a3cfe 100644 --- a/src/pages/CardDashboard.tsx +++ b/src/pages/CardDashboard.tsx @@ -7,24 +7,19 @@ import CardNote from "./cards/CardNote"; import { Icon } from "src/components/Icon"; import Sidebar from "./sidebar/Sidebar"; import { DefaultFilterSchemeID } from "src/models/FilterScheme"; -import { SidebarContent } from "./sidebar/SideBarContent"; import { HeaderView } from "./header/HeaderView"; import { ActiveFiltersView } from "./header/ActiveFiltersView"; import EmptyStateCard from "./cards/EmptyStateCard"; import { ViewSelectModal } from "./sidebar/viewScheme/ViewSelectModal"; - import { useDashboardLayout } from 'src/hooks/useDashboardLayout'; import { useInfiniteScroll } from 'src/hooks/useInfiniteScroll'; import AddNoteView from "./header/AddNoteView"; import { i18n } from "src/utils/i18n"; import { useCombineStore, createDashboardLocalStore, DashboardStoreContext, useDashboardLocalStore } from "src/store"; import { SortFilesButton } from "./header/SortFilesButton"; - -import { MasonryLayout } from "src/components/MasonryLayout"; import { FileInfo } from "src/models/FileInfo"; - export const CARD_DASHBOARD_VIEW_TYPE = "dashboard-view"; export class CardDashboard extends ItemView { @@ -168,55 +163,54 @@ const CardDashboardInner = ({ plugin }: { plugin: BanyanPlugin }) => { modal.open(); }; - const cardNodes = useMemo(() => displayFiles.map((f, index) => { + const cardNotes = useMemo(() => displayFiles.map((f, index) => { const isLastCard = index === displayFiles.length - 1; const isPinned = curScheme.pinned.includes(f.file.path); return ( -
+
); - }), [displayFiles, curScheme.pinned, lastCardElementRef, useCardNote2]); + }), [displayFiles, curScheme.pinned, lastCardElementRef, useCardNote2, colCount]); + const isNotEmpty = displayFiles.length > 0; return ( -
- {showSidebar != 'normal' && setShowSidebar('hide')}>} - {showSidebar == 'normal' && } -
- - {!Platform.isMobile &&
} -
-
-
- +
+ setShowSidebar('hide')} /> +
+
+ + {!Platform.isMobile &&
} +
+
+
+ +
+ {i18n.t('loaded_notes', { count: `${displayFiles.length}`, total: `${curSchemeNotesLength}` })} + {isNotEmpty && !randomBrowse && } +
+
+ {enableViewSchemes && curScheme.type != 'ViewScheme' && curScheme.id != DefaultFilterSchemeID && isNotEmpty && }
- {i18n.t('loaded_notes', { count: `${displayFiles.length}`, total: `${curSchemeNotesLength}` })} - {cardNodes.length > 0 && !randomBrowse && } -
-
- {enableViewSchemes && curScheme.type != 'ViewScheme' && curScheme.id != DefaultFilterSchemeID && cardNodes.length > 0 && }
+
- -
- {cardNodes.length === 0 ? ( +
+ {isNotEmpty ? + cardNotes : - ) : ( - - {cardNodes} - - )} + }
{/* Add loading and end-of-list indicators here */} -
+
{isLoading &&
{i18n.t('loading_text')}
} - {!isLoading && displayFiles.length >= curSchemeNotesLength && cardNodes.length > 0 &&
{i18n.t('reached_bottom')}
} + {!isLoading && displayFiles.length >= curSchemeNotesLength && isNotEmpty &&
{i18n.t('reached_bottom')}
}
{/* 手机端悬浮添加按钮 */} {Platform.isMobile && ( diff --git a/src/pages/cards/cards.css b/src/pages/cards/cards.css index ea6d55b..121833b 100644 --- a/src/pages/cards/cards.css +++ b/src/pages/cards/cards.css @@ -1,13 +1,24 @@ +.card-note { + display: flex; + width: 620px; +} + +.card-note.small { + width: 100%; +} + .card-note-container { background: var(--background-secondary); color: var(--text-normal); border-radius: 8px; padding: 16px; - margin-bottom: 16px; position: relative; box-shadow: 0 1px 6px 1px rgba(0, 0, 0, 0.16); + width: 620px; +} + +.card-note.small .card-note-container { width: 100%; - max-width: 620px; } .card-note-content { diff --git a/src/pages/cards/emptyCard.css b/src/pages/cards/emptyCard.css index b92846e..165ac27 100644 --- a/src/pages/cards/emptyCard.css +++ b/src/pages/cards/emptyCard.css @@ -8,7 +8,6 @@ border-radius: 16px; box-shadow: 0 1px 6px 1px rgba(0, 0, 0, 0.16); padding: 48px 24px; - max-width: 620px; width: 100%; } diff --git a/src/pages/dashboard.css b/src/pages/dashboard.css index 4fd4341..554d9db 100644 --- a/src/pages/dashboard.css +++ b/src/pages/dashboard.css @@ -1,42 +1,55 @@ /* --- 整个面板 --- */ -.dashboard-container { +.dashboard { display: flex; flex-direction: row; justify-content: center; height: 100%; overflow: hidden; + width: 100%; + max-width: 1590px; /* 16 + 296 + 6 + 620 + 16 + 620 + 16 */ + margin: 0 auto; } /* --- 主内容区 --- */ -.main-container { +.main { + width: fit-content; + display: flex; + flex-direction: column; height: 100%; overflow-y: auto; scrollbar-width: none; } -.main-container::-webkit-scrollbar { +.main::-webkit-scrollbar { display: none; } +/* 卡片内容区 */ + +.cards { + display: grid; + justify-content: start; + gap: 16px; + margin: 6px 4px 0 4px; +} + +.cards.small { + grid-template-columns: 1fr; +} + +.cards.one { + grid-template-columns: 620px; + max-width: 620px; +} + +.cards.two { + grid-template-columns: repeat(2, 620px); +} + /* 桌面设备 */ @media (min-width: 768px) { - .main-container { - max-width: 100%; - min-width: 620px; - } - .main-cards { - display: flex; - gap: 16px; - flex: 1; - margin: 6px 0 0 4px; - } - - .main-cards-column { - width: 100%; - min-width: 620px; - } } /* 移动设备 */ @@ -45,19 +58,9 @@ .workspace-leaf-content[data-type="dashboard-view"] .view-content { padding-bottom: 0 !important; } - - .main-container { - width: 100%; - } - - .main-cards-column { - width: 100%; - min-width: calc(100vw - 24px); - padding: 0 4px; - } } -.main-cards-loading { +.cards-loading { text-align: center; padding: 20px; color: var(--text-muted); diff --git a/src/pages/header/HeaderView.tsx b/src/pages/header/HeaderView.tsx index d708a09..6665ef4 100644 --- a/src/pages/header/HeaderView.tsx +++ b/src/pages/header/HeaderView.tsx @@ -1,15 +1,16 @@ import React from 'react'; import { Icon } from "src/components/Icon"; import { Searchbar } from "./searchbar/Searchbar"; -import { DefaultFilterSchemeID, getDefaultFilterScheme } from "src/models/FilterScheme"; +import { DefaultFilterSchemeID, FilterScheme, getDefaultFilterScheme } from "src/models/FilterScheme"; import { i18n } from "src/utils/i18n"; +import { ViewScheme } from 'src/models/ViewScheme'; interface HeaderViewProps { showSidebar: 'normal' | 'hide' | 'show'; setShowSidebar: (state: 'normal' | 'hide' | 'show') => void; - curScheme: any; - filterSchemes: any[]; - setCurScheme: (scheme: any) => void; + curScheme: FilterScheme | ViewScheme; + filterSchemes: FilterScheme[]; + setCurScheme: (scheme: FilterScheme | ViewScheme) => void; } export const HeaderView: React.FC = ({ @@ -20,8 +21,8 @@ export const HeaderView: React.FC = ({ setCurScheme }) => { return ( -
-
+
+
{curScheme.id === DefaultFilterSchemeID && ( -
{curScheme.name}
+
{curScheme.name}
)} {curScheme.id !== DefaultFilterSchemeID && ( -
+
{ setCurScheme(getDefaultFilterScheme(filterSchemes)); }} > {getDefaultFilterScheme(filterSchemes).name}
-
{'/'}
-
{curScheme.name}
+
{'/'}
+
{curScheme.name}
)}
diff --git a/src/pages/header/addnote.css b/src/pages/header/addnote.css index 77cafdd..d031066 100644 --- a/src/pages/header/addnote.css +++ b/src/pages/header/addnote.css @@ -9,7 +9,6 @@ position: relative; box-shadow: 0 1px 6px 1px rgba(0, 0, 0, 0.16); width: 100%; - max-width: 620px; border: 1px solid transparent; } @@ -90,6 +89,8 @@ .add-note-send-button { padding: 6px 15px; + width: 48px; + align-self: end; } .add-note-send-button:hover { diff --git a/src/pages/header/header.css b/src/pages/header/header.css index d26d98d..dbd36df 100644 --- a/src/pages/header/header.css +++ b/src/pages/header/header.css @@ -1,4 +1,10 @@ -.main-header-container { +.header { + display: flex; + flex-direction: column; + width: 100%; +} + +.header-main { display: flex; flex-direction: row; justify-content: space-between; @@ -14,62 +20,61 @@ } /* 主标题 */ -.main-header-title { +.header-main-title { display: flex; align-items: center; } -.main-header-title-container { +.header-main-title-container { display: flex; } -.main-header-add-note-container { - margin-top: 16px; - margin: 4px; +.header-main-add-note-container { + margin: 4px 4px 0 4px; } -.main-header-title-container { +.header-main-title-container { display: flex; } -.main-header-title-content { +.header-main-title-content { padding: 6px 8px; color: var(--text-normal); font-size: var(--font-text-size); font-weight: var(--font-ui-semibold); } -.main-header-title-separator { +.header-main-title-separator { padding: 6px 4px; color: var(--text-faint); font-size: var(--font-small); font-weight: var(--font-ui-semibold); } -.main-header-title-content-clickable { +.header-main-title-content-clickable { cursor: pointer; } -.main-header-title-content-clickable:hover { +.header-main-title-content-clickable:hover { background: var(--background-secondary); border-radius: 6px; } /* 副标题 */ -.main-subheader-container { +.header-sub-container { margin-top: 0; display: flex; align-items: baseline; justify-content: space-between; } -.main-subheader-info { +.header-sub-info { display: flex; align-items: center; } -.main-subheader-info .refresh-btn { +.header-sub-info .refresh-btn { background-color: transparent; padding: var(--size-2-2) var(--size-2-3); cursor: pointer; @@ -77,14 +82,14 @@ } @media (hover: hover) { - .main-subheader-info .refresh-btn:hover { + .header-sub-info .refresh-btn:hover { background-color: var(--theme-color-translucent-015); color: var(--icon-color-hover); } } @media (hover: none) { - .main-subheader-info .refresh-btn:active { + .header-sub-info .refresh-btn:active { background-color: var(--theme-color-translucent-015); color: var(--icon-color-hover); } @@ -92,13 +97,13 @@ -.main-subheader-loaded-notes { +.header-sub-loaded-notes { padding: 12px 6px; color: var(--text-muted); font-size: var(--font-smaller); } -.main-subheader-btn-section { +.header-sub-btn-section { display: flex; gap: 8px; } diff --git a/src/pages/sidebar/SideBarContent.tsx b/src/pages/sidebar/SideBarContent.tsx index d67934a..60b0018 100644 --- a/src/pages/sidebar/SideBarContent.tsx +++ b/src/pages/sidebar/SideBarContent.tsx @@ -20,7 +20,7 @@ export const SidebarContent = () => { } return ( -
+
diff --git a/src/pages/sidebar/Sidebar.tsx b/src/pages/sidebar/Sidebar.tsx index 3e866d4..842ea25 100644 --- a/src/pages/sidebar/Sidebar.tsx +++ b/src/pages/sidebar/Sidebar.tsx @@ -1,13 +1,24 @@ import { useEffect } from "react"; +import { SidebarContent } from "./SideBarContent"; interface SidebarProps { + showSidebar: 'normal' | 'hide' | 'show'; + onClose: () => void; +} + +const Sidebar: React.FC = ({ showSidebar, onClose }) => { + if (showSidebar == 'normal') return ; + return ; +} + +interface SidebarContainerProps { visible: boolean; onClose: () => void; children?: React.ReactNode; } // 侧边栏组件,支持响应式隐藏与展开 -const Sidebar: React.FC = ({ visible, onClose, children }) => { +const SidebarContainer: React.FC = ({ visible, onClose, children }) => { // 监听点击遮罩关闭 useEffect(() => { if (!visible) return; diff --git a/src/pages/sidebar/sidebar.css b/src/pages/sidebar/sidebar.css index e51981d..5716f28 100644 --- a/src/pages/sidebar/sidebar.css +++ b/src/pages/sidebar/sidebar.css @@ -12,8 +12,8 @@ .sidebar-container { position: absolute; height: 100%; - background: var(--background-secondary, #222); - color: var(--text-normal, #fff); + background: var(--background-secondary); + color: var(--text-normal); box-shadow: 2px 0 8px rgba(0, 0, 0, 0.08); z-index: 1001; transition: left 0.25s cubic-bezier(.4, 0, .2, 1); @@ -43,7 +43,7 @@ /* 侧边栏内容 */ -.sidebar-content-container { +.sidebar-content { display: flex; flex-direction: column; padding: 0 16px 50px 16px; @@ -55,7 +55,7 @@ scrollbar-width: none; } -.sidebar-content-container::-webkit-scrollbar { +.sidebar-content::-webkit-scrollbar { display: none; }