Skip to content

Commit 1884ce0

Browse files
committed
feat: enhance changelog with sidebar scroll position fixes and improve spec directory handling
1 parent 7f7f628 commit 1884ce0

File tree

4 files changed

+28
-5
lines changed

4 files changed

+28
-5
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased]
99

1010
### Fixed
11+
- **Web sidebar scroll position drift** (spec 101) - Eliminated scroll position jumping during navigation
12+
- Fixed React 19 `useSyncExternalStore` infinite loop by stabilizing server snapshot references
13+
- Isolated scroll persistence to prevent global store re-renders on every scroll event
14+
- Implemented component-local scroll management with `useIsomorphicLayoutEffect` for flicker-free restoration
15+
- Added guarded auto-anchoring that centers active spec on page refresh without disrupting user scrolling
16+
- Validated smooth scrolling for 100+ spec lists with no drift during rapid navigation or filtering
1117
- **Web spec detail page sub-specs display** - Fixed missing sub-specs tabs and count indicator
1218
- Sub-specs tabs now correctly display when available
1319
- Sidebar shows sub-spec count (e.g., "+3") for specs with additional markdown files

packages/cli/src/commands/ui.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ function buildUiRunner(
269269
}
270270

271271
if (packageManager === 'pnpm') {
272-
const args = ['dlx', '--prefer-offline', ...uiArgs];
272+
const args = ['dlx', ...uiArgs];
273273
return { command: 'pnpm', args, preview: `pnpm ${args.join(' ')}` };
274274
}
275275

packages/web/src/app/api/__tests__/specs.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ describe('Spec API Routes', () => {
5858

5959
const json = await response.json();
6060
expect(json).toHaveProperty('spec');
61-
expect(json.spec.id).toBe('1');
61+
expect(json.spec.id).toBe(mockSpec.id);
6262

6363
// Verify cache headers are present
6464
const cacheControl = response.headers.get('Cache-Control');

packages/web/src/lib/db/service-queries.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { specsService } from '../specs/service';
77
import type { Spec } from './schema';
88
import { detectSubSpecs } from '../sub-specs';
9-
import { join } from 'path';
9+
import { join, resolve } from 'path';
1010
import { readFileSync } from 'node:fs';
1111
import matter from 'gray-matter';
1212

@@ -17,6 +17,23 @@ export type ParsedSpec = Omit<Spec, 'tags'> & {
1717
tags: string[] | null;
1818
};
1919

20+
const DEFAULT_SPECS_DIR = resolve(process.cwd(), '../../specs');
21+
22+
function getSpecsRootDir(): string {
23+
const envDir = process.env.SPECS_DIR;
24+
if (!envDir) {
25+
return DEFAULT_SPECS_DIR;
26+
}
27+
return envDir.startsWith('/') ? envDir : resolve(process.cwd(), envDir);
28+
}
29+
30+
function buildSpecDirPath(filePath: string): string {
31+
const normalized = filePath
32+
.replace(/^specs\//, '')
33+
.replace(/\/README\.md$/, '');
34+
return join(getSpecsRootDir(), normalized);
35+
}
36+
2037
interface SpecRelationships {
2138
dependsOn: string[];
2239
related: string[];
@@ -113,7 +130,7 @@ export async function getSpecsWithSubSpecCount(projectId?: string): Promise<(Par
113130
}
114131

115132
return specs.map(spec => {
116-
const specDirPath = join(process.cwd(), '../../specs', spec.filePath.replace('/README.md', '').replace('specs/', ''));
133+
const specDirPath = buildSpecDirPath(spec.filePath);
117134
const subSpecsCount = countSubSpecs(specDirPath);
118135
return { ...parseSpecTags(spec), subSpecsCount };
119136
});
@@ -131,7 +148,7 @@ export async function getSpecById(id: string, projectId?: string): Promise<(Pars
131148

132149
// Detect sub-specs from filesystem (only for filesystem mode)
133150
if (!projectId) {
134-
const specDirPath = join(process.cwd(), '../../specs', spec.filePath.replace('/README.md', '').replace('specs/', ''));
151+
const specDirPath = buildSpecDirPath(spec.filePath);
135152
const subSpecs = detectSubSpecs(specDirPath);
136153
const relationships = getFilesystemRelationships(specDirPath);
137154
return { ...parsedSpec, subSpecs, relationships };

0 commit comments

Comments
 (0)