Add top navigation similar to dynamic product pages:
- SVC.plus/blog breadcrumb (clickable, returns to homepage)
- Search component on the right
- Sticky positioning with blur background
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Hide navbar by default on /blog and its subpaths
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
### Changes:
1. **Added fallback data files**:
- `public/_build/artifacts-manifest.json` - Local fallback for downloads page
- `public/_build/offline-package.json` - Local fallback for offline-package
2. **Updated data fetching logic**:
- `dl-index-data-artifacts.ts` - Now uses local fallback when network fetch fails
- `dl-index-data-offline-package.ts` - Now uses local fallback when network fetch fails
### Problem:
In static development mode (`yarn start -p 3000`), the dashboard's docs and downloads pages
could not fetch data from external URLs, resulting in empty content.
### Solution:
Added local fallback data files that are imported directly into the components.
When network requests fail (e.g., in offline mode or behind firewall), the app now
falls back to local static data, ensuring pages work in development mode.
### Data Flow:
1. Try fetching from `https://dl.svc.plus/dl-index/*.json`
2. If that fails, try fallback URL
3. If that also fails, use local `public/_build/*.json` data
4. Display content to user
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
### Changes:
1. **scripts/gen_docs_manifest.py**
- Added --include parameter with default "docs"
- Filters documentation files to only include specified directories
- Can be provided multiple times for multiple directories
- Updated docstring to document the new parameter
2. **scripts/gen_mirror_manifest.py**
- Added generation of offline-package.json file
- Filters listings to only include offline-package directory entries
- Writes to the same output directory alongside manifest.json
### Usage:
For gen_docs_manifest.py:
python3 scripts/gen_docs_manifest.py \
--root /data/update-server/docs \
--base-url-prefix https://dl.svc.plus/docs \
--include docs
For gen_mirror_manifest.py:
python3 scripts/gen_mirror_manifest.py \
--root /data/update-server \
--include offline-package \
--output dl-index/
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
### Changes:
1. **scripts/gen_docs_manifest.py**
- Added --include parameter with default "docs"
- Filters documentation files to only include specified directories
- Can be provided multiple times for multiple directories
- Updated docstring to document the new parameter
2. **scripts/gen_mirror_manifest.py**
- Added generation of offline-package.json file
- Filters listings to only include offline-package directory entries
- Writes to the same output directory alongside manifest.json
### Usage:
For gen_docs_manifest.py:
python3 scripts/gen_docs_manifest.py \
--root /data/update-server/docs \
--base-url-prefix https://dl.svc.plus/docs \
--include docs
For gen_mirror_manifest.py:
python3 scripts/gen_mirror_manifest.py \
--root /data/update-server \
--include offline-package \
--output dl-index/
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
### Changes:
1. **scripts/gen_mirror_manifest.py**
- Added generation of offline-package.json file
- Filters listings to only include offline-package directory
- Writes to the same output directory (dl-index/)
2. **src/lib/download/dl-index-data-offline-package.ts**
- New module to fetch offline-package data from CDN
- Fetches from: https://dl.svc.plus/dl-index/offline-package.json
- Provides helper functions:
- fetchOfflinePackageListings()
- getOfflinePackageListings()
- getOfflinePackageSections()
- getOfflinePackageFileCount()
- Includes simple in-memory caching
3. **src/app/download/page.tsx**
- Updated to use offline-package data
- Merges offline-package sections with existing data
- Added offline-package file count to totals
- Made component async to support data fetching
### Result:
Download page now fetches and displays offline-package data from the CDN endpoint, providing real-time updates without rebuilding the application.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
### Changes:
- Changed --base-url-prefix default from "/" to "https://dl.svc.plus/offline-package"
- Updated docstring usage example to reflect the new default
### Reason:
Sets a more specific default URL prefix for offline package downloads
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
### Changes:
1. Set ROOT default to `/data/update-server/`
- Changed --root from required to optional with default value
2. Add --include [dirlist] parameter
- Default: offline-package
- Can be provided multiple times
- Filters which directories to include in manifest
- Only processes directories matching the include list
3. Add --output parameter
- Default: dl-index/
- Specifies where to write manifest.json
- Creates directory if it doesn't exist
### Usage:
python3 scripts/gen_mirror_manifest.py \
--root /data/update-server \
--base-url-prefix / \
--include offline-package \
--output dl-index/ \
[--exclude docs --exclude xray-core]
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
### Issue:
Next.js App Router expects params to be a Promise that must be awaited before accessing properties.
### Error:
```
Route "/download/[...segments]" used `params.segments`.
`params` is a Promise and must be unwrapped with `await`
or `React.use()` before accessing its properties.
```
### Solution:
- Made component async: `export default async function DownloadListing`
- Updated params type: `Promise<{ segments: string[] }>`
- Unwrapped with await: `const { segments: rawSegments } = await params`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
### Changes:
- Moved types from legacy 'types/download.ts' to '@lib/download/types'
- Updated all imports to use the new location:
- src/components/download/DownloadListingContent.tsx
- src/components/download/FileTable.tsx
- src/lib/download-data.ts
- src/lib/download-manifest.ts
- src/app/download/[...segments]/page.tsx
### Why:
- Resolved TS6137 error: Cannot import type declaration files
- Aligns with codebase pattern: types co-located with modules (@lib/iac/types, @lib/mail/types)
- Uses consistent @ alias import pattern throughout codebase
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
### Errors Fixed:
1. **Cloud IaC Index JSON Import** (src/app/cloud_iac/*/page.tsx)
- Fixed incorrect relative import paths for cloud_iac_index.json
- Updated to correct number of `../` to reach public directory
- Both provider and service pages now import correctly
2. **Products Registry Import** (src/app/[slug]/Client.tsx)
- Changed from non-existent `@src/products/registry` to `@modules/products/registry`
- Uses existing path alias configured in tsconfig.json
3. **Download Type Import** (src/app/download/*/page.tsx)
- Fixed import path from `../../../types/download` to `@types/download`
- Added proper type annotation for filter callbacks to resolve TypeScript errors
4. **Docs Manifest Import** (src/app/docs/resources.server.ts)
- Temporarily disabled invalid docs-manifest.json import (malformed JSON)
- Falls back to docs_index.json
- Build now passes without JSON parsing errors
### Result:
- Build errors reduced from 7 to 0
- All module imports resolved correctly
- TypeScript compilation passes
- Ready for production build
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
### Issue:
PostCSS config file was using ES module syntax (export default) in a .js file without "type": "module" in package.json.
**Warning Message:**
"Module type of file is not specified and it doesn't parse as CommonJS. Reparsing as ES module because module syntax is detected. This incurs a performance overhead."
### Solution:
Renamed `postcss.config.js` to `postcss.config.mjs`:
- .mjs extension is automatically recognized as ES module
- No need to modify package.json
- Eliminates performance overhead warning
- Cleaner, explicit ES module indication
### Changes:
- **File renamed**: `postcss.config.js` → `postcss.config.mjs`
- **Content unchanged**: Still uses ES module export syntax
- **No package.json changes needed**
### Result:
- ✅ PostCSS module parsing warning eliminated
- ✅ Build still works correctly
- ✅ Performance improved (no re-parsing)
- ✅ Clear ES module indication
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
### Task Completed:
1. ✅ **Language Component Already Extracted**
- LanguageToggle component is already in `src/components/LanguageToggle.tsx`
- Uses global `useLanguage` hook from LanguageProvider
- Already a shared component that can be reused anywhere
2. ✅ **Updated Navbar to Hide on Dynamic Routes**
- Modified `src/components/Navbar.tsx` to hide on `/xstream`, `/xcloudflow`, `/xscopehub`
- Updated `isHiddenRoute` check to include these dynamic routes
- Navbar automatically hides when visiting these product pages
### Changes:
**File: src/components/Navbar.tsx**
- Extended the hidden route list to include:
- `/xstream` - XStream product page
- `/xcloudflow` - XCloudFlow product page
- `/xscopehub` - XScopeHub product page
- Existing hidden routes: `/login`, `/register`
### Result:
- ✅ Navbar is hidden on all product landing pages
- ✅ Language component remains globally accessible and shared
- ✅ No code duplication - LanguageToggle is reusable
- ✅ Clean separation of concerns
### Usage:
Any component can import and use the shared Language component:
```typescript
import LanguageToggle from '@/components/LanguageToggle'
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>