7 Commits

Author SHA1 Message Date
AmintaCCCP
8c5f71ea77 fix update path 2025-09-23 16:56:22 +08:00
AmintaCCCP
d78bcd75d6 fix workflow 2025-09-23 16:47:44 +08:00
AmintaCCCP
e0af19dd2e Revert "fix workflow"
This reverts commit 0678fe9b04.
2025-09-23 16:37:52 +08:00
AmintaCCCP
0678fe9b04 fix workflow 2025-09-23 16:10:43 +08:00
AmintaCCCP
69f4a0788c fix bug 2025-09-23 15:51:15 +08:00
tamina
b2c49460ab Merge pull request #25 from rootwhois/main
feat(repositories): switch to infinite scroll with consistent card widths
2025-09-23 15:36:52 +08:00
rootwhois
b7ad4558ef feat(repositories): switch to infinite scroll with consistent card widths
- Replace pagination with on-demand infinite scrolling (load 50 per batch)
- Use IntersectionObserver and a bottom sentinel to trigger loading
- Update stats to show current range “X–Y / N repositories”
- Switch from CSS columns to fixed grid to ensure consistent card widths
- Remove pagination state and controls
- Clean up unused variables and resolve lint warnings

UX: smoother scrolling, stable card widths, more natural loading behavior.
2025-09-16 21:40:42 +08:00
5 changed files with 66 additions and 13 deletions

View File

@@ -409,7 +409,8 @@ jobs:
icon: 'build/icon.png',
category: 'public.app-category.productivity',
hardenedRuntime: true,
gatekeeperAssess: false
gatekeeperAssess: false,
identity: null
};
packageJson.build.dmg = {
title: 'GitHub Stars Manager',

View File

@@ -1,7 +1,7 @@
{
"name": "github-stars-manager",
"private": true,
"version": "0.1.4",
"version": "0.1.5",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,4 +1,4 @@
import React, { useState, useRef } from 'react';
import React, { useState, useRef, useEffect } from 'react';
import { Bot, ChevronDown, Pause, Play } from 'lucide-react';
import { RepositoryCard } from './RepositoryCard';
@@ -32,7 +32,6 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
const [showAISummary, setShowAISummary] = useState(true);
const [showDropdown, setShowDropdown] = useState(false);
const [isPaused, setIsPaused] = useState(false);
const [searchTime, setSearchTime] = useState<number | undefined>(undefined);
// 使用 useRef 来管理停止状态,确保在异步操作中能正确访问最新值
const shouldStopRef = useRef(false);
@@ -76,6 +75,43 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
);
});
// Infinite scroll (瀑布流按需加载)
const LOAD_BATCH = 50;
const [visibleCount, setVisibleCount] = useState(LOAD_BATCH);
const sentinelRef = useRef<HTMLDivElement | null>(null);
const startIndex = filteredRepositories.length === 0 ? 0 : 1;
const endIndex = Math.min(visibleCount, filteredRepositories.length);
const visibleRepositories = filteredRepositories.slice(0, visibleCount);
// Reset visible count when filters or data change
useEffect(() => {
setVisibleCount(LOAD_BATCH);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedCategory, repositories, filteredRepositories.length]);
// IntersectionObserver to load more on demand
useEffect(() => {
const node = sentinelRef.current;
if (!node) return;
const observer = new IntersectionObserver(
(entries) => {
const entry = entries[0];
if (entry.isIntersecting) {
setVisibleCount((count) => {
if (count >= filteredRepositories.length) return count;
return Math.min(count + LOAD_BATCH, filteredRepositories.length);
});
}
},
{ root: null, rootMargin: '200px', threshold: 0 }
);
observer.observe(node);
return () => observer.disconnect();
}, [filteredRepositories.length]);
const handleAIAnalyze = async (analyzeUnanalyzedOnly: boolean = false, analyzeFailedOnly: boolean = false) => {
if (!githubToken) {
alert(language === 'zh' ? 'GitHub token 未找到,请重新登录。' : 'GitHub token not found. Please login again.');
@@ -136,7 +172,7 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
const concurrency = activeConfig.concurrency || 1;
// 并发分析函数
const analyzeRepository = async (repo: Repository, index: number) => {
const analyzeRepository = async (repo: Repository) => {
// 检查是否需要停止
if (shouldStopRef.current) {
return false;
@@ -201,9 +237,7 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
}
const batch = targetRepos.slice(i, i + concurrency);
const promises = batch.map((repo, batchIndex) =>
analyzeRepository(repo, i + batchIndex)
);
const promises = batch.map((repo) => analyzeRepository(repo));
await Promise.all(promises);
@@ -434,7 +468,10 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
<div className="text-sm text-gray-500 dark:text-gray-400">
<div className="flex items-center justify-between">
<div>
{t(`显示 ${filteredRepositories.length} 个仓库`, `Showing ${filteredRepositories.length} repositories`)}
{t(
`${startIndex}-${endIndex} / 共 ${filteredRepositories.length} 个仓库`,
`Showing ${startIndex}-${endIndex} of ${filteredRepositories.length} repositories`
)}
{repositories.length !== filteredRepositories.length && (
<span className="ml-2 text-blue-600 dark:text-blue-400">
{t(`(从 ${repositories.length} 个中筛选)`, `(filtered from ${repositories.length})`)}
@@ -462,9 +499,9 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
</div>
</div>
{/* Repository Grid */}
{/* Repository Grid with consistent card widths */}
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-6">
{filteredRepositories.map(repo => (
{visibleRepositories.map(repo => (
<RepositoryCard
key={repo.id}
repository={repo}
@@ -473,6 +510,11 @@ export const RepositoryList: React.FC<RepositoryListProps> = ({
/>
))}
</div>
{/* Sentinel for on-demand loading */}
{visibleCount < filteredRepositories.length && (
<div ref={sentinelRef} className="h-8" />
)}
</div>
);
};

View File

@@ -17,7 +17,7 @@ export class UpdateService {
private static getCurrentVersion(): string {
// 在实际应用中,这个版本号应该在构建时注入
// 这里暂时硬编码,你可以通过构建脚本或环境变量来动态设置
return '0.1.4';
return '0.1.5';
}
static async checkForUpdates(): Promise<UpdateCheckResult> {

View File

@@ -29,4 +29,14 @@
</changelog>
<downloadUrl>https://github.com/AmintaCCCP/GithubStarsManager/releases/tag/v0.1.4</downloadUrl>
</version>
<version>
<number>0.1.5</number>
<releaseDate>2025-09-23</releaseDate>
<changelog>
<item>fix: Fixed the issue where the analysis progress becomes 0 due to switching headers during AI analysis</item>
<item>Add drag and no-drag regions for desktop app</item>
<item>switch to infinite scroll with consistent card widths</item>
</changelog>
<downloadUrl>https://github.com/AmintaCCCP/GithubStarsManager/releases/tag/v0.1.5</downloadUrl>
</version>
</versions>