Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
131 commits
Select commit Hold shift + click to select a range
a01db6c
Increase height in repos page
rajashekar Jul 18, 2025
c36a801
Adding github urls
rajashekar Jul 18, 2025
0173158
fix github issue
rajashekar Jul 19, 2025
32e4738
capability to change the image url
rajashekar Jul 19, 2025
fd41751
Add edit hints
rajashekar Jul 19, 2025
5bd9e16
Add edit hints
rajashekar Jul 19, 2025
063f0d6
Adding drag and drop, rearrange posts
rajashekar Jul 19, 2025
edb8316
Adding drag and drop, rearrange posts
rajashekar Jul 19, 2025
b58f6cd
Allow delete of the repo from portfolio
rajashekar Jul 19, 2025
2fb5bc8
t pull Merge branch 'main' of github.com:matmulai/foliolab
rajashekar Jul 20, 2025
ec9640d
Add demo video
rajashekar Jul 20, 2025
c91c42b
Add demo video
rajashekar Jul 20, 2025
06f6223
Add demo video
rajashekar Jul 20, 2025
41743c3
Add demo video
rajashekar Jul 21, 2025
5b909fa
Add comprehensive code review with 20 improvement recommendations
claude Nov 5, 2025
438793a
Fix critical security and stability issues
claude Nov 5, 2025
67d083f
Implement high priority code quality improvements
claude Nov 5, 2025
afa4de9
Implement remaining medium and low priority improvements
claude Nov 5, 2025
f48f1f0
Fix security issues
rajashekar Nov 5, 2025
893c262
Add multi-source portfolio data support
claude Nov 5, 2025
a86f548
Fix: Replace react-router-dom with wouter in data-sources page
claude Nov 6, 2025
165eb24
Fix TypeScript compilation errors in multi-source feature
claude Nov 7, 2025
c6e6a12
Merge pull request #2 from rajashekar/claude/expand-profile-sources-0…
rajashekar Nov 7, 2025
c30d310
Update home page to prominently feature multi-source portfolio options
claude Nov 7, 2025
a6ba1e9
Merge pull request #3 from rajashekar/claude/expand-profile-sources-0…
rajashekar Nov 7, 2025
1c1359f
Fix navigation context on data-sources page
claude Nov 7, 2025
3cbe496
Merge pull request #4 from rajashekar/claude/expand-profile-sources-0…
rajashekar Nov 8, 2025
4801082
Fix missing .js extensions in ES module imports for sources route
claude Nov 10, 2025
12ff1fb
Merge pull request #5 from rajashekar/claude/fix-missing-rss-module-0…
rajashekar Nov 10, 2025
d1a2fa8
Fix missing .js extension in medium.ts RSS import
claude Nov 10, 2025
3c098c1
Merge pull request #6 from rajashekar/claude/fix-missing-rss-module-0…
rajashekar Nov 10, 2025
d51faf3
Add documentation of portfolio selection flow analysis
claude Nov 10, 2025
0bd8682
Implement wizard-style portfolio creation flow
claude Nov 10, 2025
3dc5258
Merge pull request #7 from rajashekar/claude/fix-missing-rss-module-0…
rajashekar Nov 10, 2025
b3e9107
Refactor server logging to use structured logger in server/index.ts
google-labs-jules[bot] Feb 17, 2026
91950dd
Refactor server logging and fix client type errors
google-labs-jules[bot] Feb 17, 2026
eef5da9
Merge pull request #11 from rajashekar/refactor/server-logging-184433…
rajashekar Feb 17, 2026
c471802
feat(ui): add empty state to repo selection and improve accessibility
google-labs-jules[bot] Feb 17, 2026
912c824
perf: move regex patterns to module scope in removeBadges
google-labs-jules[bot] Feb 17, 2026
aa5a394
Fix: Prevent Stored XSS in portfolio generation
google-labs-jules[bot] Feb 17, 2026
02646b5
Merge pull request #15 from rajashekar/sentinel/fix-xss-portfolio-154…
rajashekar Feb 17, 2026
02faa99
Merge pull request #14 from rajashekar/perf/optimize-readme-cleaner-r…
rajashekar Feb 17, 2026
9e24cb3
feat(perf): lazy load repository details in getRepositories
google-labs-jules[bot] Feb 17, 2026
0e0ba9c
Merge pull request #12 from rajashekar/palette-micro-ux-empty-state-1…
rajashekar Feb 17, 2026
e6e58f2
Merge pull request #16 from rajashekar/bolt-perf-lazy-load-repos-1600…
rajashekar Feb 17, 2026
616cdfa
Fix Medium username extraction and improve test coverage
google-labs-jules[bot] Feb 17, 2026
a041ba4
Merge pull request #17 from rajashekar/fix-medium-username-extraction…
rajashekar Feb 17, 2026
83dcc22
Refactor duplicate Vercel header logic into helper function
google-labs-jules[bot] Feb 17, 2026
0fbb0ca
feat(tests): add test coverage for generateProjectSummary in project-…
google-labs-jules[bot] Feb 17, 2026
7be2bbd
Merge pull request #19 from rajashekar/test/project-analyzer-summary-…
rajashekar Feb 17, 2026
3f95d78
Merge pull request #18 from rajashekar/refactor-vercel-headers-799580…
rajashekar Feb 17, 2026
dd4edbd
test: add tests for error response factory and codes
google-labs-jules[bot] Feb 17, 2026
79d5375
Merge pull request #20 from rajashekar/test/error-responses-factory-t…
rajashekar Feb 17, 2026
8ef680d
Refactor isOctokitError to use safer type guards
google-labs-jules[bot] Feb 17, 2026
ba8e9c9
test: add unit tests for RSS to BlogPost conversion
google-labs-jules[bot] Feb 17, 2026
9fab382
chore: improve type safety for request ID
google-labs-jules[bot] Feb 17, 2026
fafeaef
Merge pull request #25 from rajashekar/chore/improve-request-id-typin…
rajashekar Feb 17, 2026
1f5e8ac
Merge pull request #24 from rajashekar/test-rss-conversion-2491327490…
rajashekar Feb 17, 2026
6799f87
Refactor FRAMEWORK_PATTERNS to separate config file
google-labs-jules[bot] Feb 17, 2026
88de3b8
Merge pull request #26 from rajashekar/refactor/framework-patterns-co…
rajashekar Feb 17, 2026
9adfcf0
Merge pull request #23 from rajashekar/refactor-isOctokitError-type-g…
rajashekar Feb 17, 2026
97bde56
chore: replace console logging with logger utility in github lib
google-labs-jules[bot] Feb 17, 2026
27a62d5
fix(security): Redact sensitive data from request logs
google-labs-jules[bot] Feb 17, 2026
6cb6bdd
fix(security): Redact sensitive data from request logs
google-labs-jules[bot] Feb 17, 2026
4c3c71c
🔒 security: fix stored XSS via repository URL and secure Vercel callback
google-labs-jules[bot] Feb 17, 2026
027dc06
🔒 security: fix stored XSS via repository URL and secure Vercel callback
google-labs-jules[bot] Feb 17, 2026
b285ea8
Optimize Octokit instantiation in getReadmeContent
google-labs-jules[bot] Feb 17, 2026
395e7fa
Merge pull request #13 from rajashekar/fix-sensitive-data-logging-863…
rajashekar Feb 17, 2026
5bc681b
Merge pull request #27 from rajashekar/fix-xss-vulnerability-46079285…
rajashekar Feb 17, 2026
e5099a7
Merge pull request #22 from rajashekar/fix-console-logging-github-lib…
rajashekar Feb 17, 2026
56020a1
Refactor portfolio HTML generation to separate module
google-labs-jules[bot] Feb 17, 2026
6e60053
Refactor portfolio HTML generation and merge conflicts
google-labs-jules[bot] Feb 17, 2026
6177fd3
Refactor portfolio HTML generation and merge conflicts
google-labs-jules[bot] Feb 17, 2026
d9b7efe
Refactor portfolio HTML generation and merge conflicts
google-labs-jules[bot] Feb 17, 2026
51e598e
Fix CI failures in portfolio preview and routes
google-labs-jules[bot] Feb 17, 2026
1aec0a8
Merge pull request #28 from rajashekar/perf/optimize-octokit-instanti…
rajashekar Feb 17, 2026
6e42cdf
Merge pull request #21 from rajashekar/refactor-portfolio-generator-1…
rajashekar Feb 17, 2026
70ae65b
perf: Optimize GitHub organization repo fetching with Promise.all
google-labs-jules[bot] Feb 17, 2026
54dd6a3
perf: optimize string concatenation in generateRepoSummary
google-labs-jules[bot] Feb 17, 2026
1de52cb
perf: optimize string concat & resolve merge conflicts
google-labs-jules[bot] Feb 17, 2026
c8b2014
perf: optimize string concat, resolve conflicts & improve type safety
google-labs-jules[bot] Feb 17, 2026
507a1cb
perf: optimize string concat & resolve all conflicts
google-labs-jules[bot] Feb 17, 2026
174d335
Merge pull request #10 from rajashekar/perf-optimize-github-org-fetch…
rajashekar Feb 17, 2026
e881f8e
perf: optimize string concatenation and fix CI build failures
google-labs-jules[bot] Feb 18, 2026
a43846e
Merge pull request #9 from rajashekar/perf-string-concat-169982945445…
rajashekar Feb 18, 2026
5dc91be
🧪 improve GitLab README title extraction and add tests
google-labs-jules[bot] Feb 18, 2026
4dafb0e
Merge pull request #29 from rajashekar/testing-improvement-gitlab-rea…
rajashekar Feb 18, 2026
fc09215
Merge branch 'main' of github.com:matmulai/foliolab
Feb 18, 2026
58b314e
fix(security): upgrade dependencies to fix vulnerabilities
Feb 18, 2026
b22a977
fix(ci): upgrade @types/node for vite 7.x compatibility
Feb 18, 2026
a12b7b7
fix(types): use const assertions for vite 7.x server options
Feb 18, 2026
1632a97
fix: address code review feedback from Copilot
Feb 18, 2026
04f9dbf
perf(github): reuse octokit instance when fetching readmes
google-labs-jules[bot] Feb 18, 2026
cbb843e
fix(security): prevent XSS in portfolio generation by sanitizing URLs
google-labs-jules[bot] Feb 18, 2026
0eeabb9
feat(ui): improve accessibility of item selection list
google-labs-jules[bot] Feb 18, 2026
1ed0ddf
Merge pull request #32 from rajashekar/palette-ux-item-selection-a11y…
rajashekar Feb 19, 2026
cc5439a
Merge pull request #31 from rajashekar/sentinel-fix-xss-portfolio-317…
rajashekar Feb 19, 2026
1b60d53
Merge pull request #30 from rajashekar/bolt-performance-octokit-reuse…
rajashekar Feb 19, 2026
a9b7dee
feat(ui): enhance accessibility of source selection page
google-labs-jules[bot] Feb 19, 2026
99697ec
Merge pull request #35 from rajashekar/palette-ux-improvements-100286…
rajashekar Feb 19, 2026
b6e1b56
feat(ui): enhance FAQ section with Accordion component
google-labs-jules[bot] Feb 20, 2026
a3b1da5
feat(security): fix XSS vulnerability in Vercel OAuth callback
google-labs-jules[bot] Feb 20, 2026
633d168
Merge pull request #38 from rajashekar/sentinel-fix-vercel-xss-388266…
rajashekar Feb 21, 2026
8bb7525
perf(client): optimize SelectItemsPage filtering and grouping
google-labs-jules[bot] Feb 25, 2026
4012042
⚡ Bolt: Optimize framework detection with O(1) file lookups
google-labs-jules[bot] Feb 26, 2026
db35fa2
feat(ux): improve accessibility and usability of repository selection
google-labs-jules[bot] Mar 3, 2026
d29a1d7
feat(ui): add aria-label to remove repository button
google-labs-jules[bot] Mar 11, 2026
7b37625
🛡️ Sentinel: [security improvement] Secure Request ID generation
google-labs-jules[bot] Mar 18, 2026
524f412
⚡ Bolt: Extract RegExps in readme-cleaner to reduce compilation overhead
google-labs-jules[bot] Apr 1, 2026
f94c98c
Add ARIA labels to icon-only buttons in DataSources page
google-labs-jules[bot] Apr 6, 2026
f1f11a3
🛡️ Sentinel: [MEDIUM] Fix sensitive data leak in request logging
google-labs-jules[bot] Apr 8, 2026
f8f01ac
🛡️ Sentinel: [CRITICAL] Fix SSRF vulnerability in rss-parser
google-labs-jules[bot] Apr 13, 2026
ebd8f7c
⚡ Bolt: Optimize project analyzer pattern matching
google-labs-jules[bot] Apr 13, 2026
fbc6e4d
🎨 Palette: Add ARIA labels to icon-only buttons in portfolio preview
google-labs-jules[bot] Apr 13, 2026
7cc2699
fix: resolve merge conflicts with origin/main, keeping local enhancem…
Apr 13, 2026
b81ae08
Merge pull request #175 from rajashekar/palette-aria-labels-505133617…
rajashekar Apr 13, 2026
2c07836
Merge pull request #174 from rajashekar/bolt-optimize-project-analyze…
rajashekar Apr 13, 2026
8abd0d5
Merge pull request #173 from rajashekar/sentinel-fix-rss-parser-ssrf-…
rajashekar Apr 13, 2026
672fc60
Merge pull request #162 from rajashekar/sentinel-fix-log-redaction-64…
rajashekar Apr 13, 2026
bd1e1f6
Merge pull request #156 from rajashekar/palette-add-aria-labels-10921…
rajashekar Apr 13, 2026
fc096fb
Merge pull request #142 from rajashekar/bolt/readme-cleaner-regex-opt…
rajashekar Apr 13, 2026
0824c20
Merge pull request #105 from rajashekar/sentinel-secure-request-id-13…
rajashekar Apr 13, 2026
7503214
Merge pull request #88 from rajashekar/palette-a11y-repo-select-aria-…
rajashekar Apr 13, 2026
c8d0c08
Merge pull request #65 from rajashekar/palette-repo-select-ux-1512932…
rajashekar Apr 13, 2026
65a423b
Merge pull request #55 from rajashekar/bolt-framework-detection-optim…
rajashekar Apr 13, 2026
68042a2
Merge pull request #52 from rajashekar/bolt-select-items-optimization…
rajashekar Apr 13, 2026
b33d553
Merge pull request #36 from rajashekar/palette-faq-accordion-51917671…
rajashekar Apr 13, 2026
65613b2
chore: remove unnecessary files and fix broken CONTRIBUTING.md
Apr 13, 2026
20770aa
fix: resolve merge conflicts with upstream/main
Apr 13, 2026
d30dc68
fix: address Copilot review comments
Apr 13, 2026
968b754
fix: make username required in getGitLabProjectsWithTitles to fix TS2345
Apr 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Dependencies
node_modules
pnpm-lock.yaml
yarn.lock

# Build outputs
dist
Expand Down
25 changes: 23 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,30 @@
# Contributing to FolioLab

Thank you for your interest in contributing!

## Getting Started

1. Install dependencies:
```bash
npm install
```

2. Set up environment variables:
Create a `.env` file with the required GitHub OAuth credentials.
Create a `.env` file with the required GitHub OAuth credentials (see `.env.example`).

3. Start the development server:
```bash
npm run dev
npm run dev
```

## Running Tests

```bash
npm run test:run
```

## Building

```bash
npm run build
```
2 changes: 2 additions & 0 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import DataSourcesPage from "@/pages/data-sources";
import { Switch, Route } from "wouter";
import { queryClient } from "./lib/queryClient";
import { QueryClientProvider } from "@tanstack/react-query";
Expand All @@ -24,6 +25,7 @@ function Router() {
<Route path="/wizard" component={DataWizard} />
<Route path="/select-items" component={SelectItems} />
<Route path="/preview" component={PortfolioPreview} />
<Route path="/data-sources" component={DataSourcesPage} />
<Route component={NotFound} />
</Switch>
</>
Expand Down
7 changes: 7 additions & 0 deletions client/src/pages/data-sources.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ export default function DataSourcesPage() {
<button
onClick={() => setLocation(hasGitHubToken ? '/repos' : '/')}
className="text-gray-600 hover:text-gray-900 mb-4 flex items-center gap-2"
aria-label={hasGitHubToken ? 'Back to GitHub Repos' : 'Back to Home'}
>
← {hasGitHubToken ? 'Back to GitHub Repos' : 'Back to Home'}
</button>
Expand Down Expand Up @@ -327,6 +328,7 @@ export default function DataSourcesPage() {
<button
onClick={() => setActiveSource(null)}
className="text-gray-500 hover:text-gray-700"
aria-label="Close form"
>
</button>
Expand Down Expand Up @@ -375,6 +377,7 @@ export default function DataSourcesPage() {
<button
onClick={() => setActiveSource(null)}
className="text-gray-500 hover:text-gray-700"
aria-label="Close form"
>
</button>
Expand Down Expand Up @@ -414,6 +417,7 @@ export default function DataSourcesPage() {
<button
onClick={() => setActiveSource(null)}
className="text-gray-500 hover:text-gray-700"
aria-label="Close form"
>
</button>
Expand Down Expand Up @@ -465,6 +469,7 @@ export default function DataSourcesPage() {
<button
onClick={() => setActiveSource(null)}
className="text-gray-500 hover:text-gray-700"
aria-label="Close form"
>
</button>
Expand Down Expand Up @@ -516,6 +521,7 @@ export default function DataSourcesPage() {
<button
onClick={() => setActiveSource(null)}
className="text-gray-500 hover:text-gray-700"
aria-label="Close form"
>
</button>
Expand Down Expand Up @@ -614,6 +620,7 @@ export default function DataSourcesPage() {
<button
onClick={() => setLocation('/repos')}
className="bg-white border-2 border-gray-300 text-gray-700 py-3 px-8 rounded-lg hover:bg-gray-50 transition-all shadow-lg"
aria-label="Back to GitHub Selection"
>
← Back to GitHub Selection
</button>
Expand Down
77 changes: 49 additions & 28 deletions client/src/pages/home.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { Link } from "wouter";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Github, Shield, Globe, FileQuestion, Mail, Info, Database } from "lucide-react";
import { clearAllData } from "@/lib/queryClient";
import { clearStorage } from "@/lib/storage";
Expand Down Expand Up @@ -103,34 +109,49 @@ export default function Home() {
<div className="mt-20">
<h2 className="text-3xl font-bold mb-8">Frequently Asked Questions</h2>
<div className="grid gap-6 text-left">
<div>
<h3 className="font-semibold mb-2">How does it work?</h3>
<p className="text-muted-foreground">
Import content from GitHub, GitLab, Bitbucket, Medium, your blog, or add custom content.
Select what you want to showcase, and we'll generate beautiful summaries using AI.
Deploy your portfolio with one click to GitHub Pages or Vercel.
</p>
</div>
<div>
<h3 className="font-semibold mb-2">What sources can I use?</h3>
<p className="text-muted-foreground">
You can import from GitHub (OAuth), GitLab (personal access token), Bitbucket (app password),
Medium (username), any blog RSS feed, or create custom free-form content. Mix and match
as many sources as you like!
</p>
</div>
<div>
<h3 className="font-semibold mb-2">Is it free to use?</h3>
<p className="text-muted-foreground">
FolioLab is open-source and free to use.
</p>
</div>
<div>
<h3 className="font-semibold mb-2">What data do you collect?</h3>
<p className="text-muted-foreground">
We don't store any of your data.
</p>
</div>
<Accordion type="single" collapsible className="w-full">
<AccordionItem value="item-1">
<AccordionTrigger className="text-lg font-semibold">
How does it work?
</AccordionTrigger>
<AccordionContent className="text-muted-foreground text-base">
Import content from GitHub, GitLab, Bitbucket, Medium, your
blog, or add custom content. Select what you want to showcase,
and we'll generate beautiful summaries using AI. Deploy your
portfolio with one click to GitHub Pages or Vercel.
</AccordionContent>
</AccordionItem>

<AccordionItem value="item-2">
<AccordionTrigger className="text-lg font-semibold">
What sources can I use?
</AccordionTrigger>
<AccordionContent className="text-muted-foreground text-base">
You can import from GitHub (OAuth), GitLab (personal access
token), Bitbucket (app password), Medium (username), any blog
RSS feed, or create custom free-form content. Mix and match as
many sources as you like!
</AccordionContent>
</AccordionItem>

<AccordionItem value="item-3">
<AccordionTrigger className="text-lg font-semibold">
Is it free to use?
</AccordionTrigger>
<AccordionContent className="text-muted-foreground text-base">
FolioLab is open-source and free to use.
</AccordionContent>
</AccordionItem>

<AccordionItem value="item-4">
<AccordionTrigger className="text-lg font-semibold">
What data do you collect?
</AccordionTrigger>
<AccordionContent className="text-muted-foreground text-base">
We don't store any of your data.
</AccordionContent>
</AccordionItem>
</Accordion>
</div>
</div>

Expand Down
14 changes: 12 additions & 2 deletions client/src/pages/portfolio-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@ export default function PortfolioPreview() {
variant="ghost"
className="absolute top-0 right-0 opacity-0 group-hover:opacity-100 transition-opacity"
onClick={() => startEditingItemTitle(item.id, getItemTitle(item))}
aria-label="Edit item title"
>
<Edit2 className="h-4 w-4" />
</Button>
Expand All @@ -539,7 +540,7 @@ export default function PortfolioPreview() {
</span>
)}
{item.url && (
<Button variant="outline" size="icon" asChild>
<Button variant="outline" size="icon" asChild aria-label="View item">
<a
href={item.url}
target="_blank"
Expand Down Expand Up @@ -594,6 +595,7 @@ export default function PortfolioPreview() {
size="sm"
variant="ghost"
onClick={() => startEditingItem(item.id, getItemSummary(item))}
aria-label="Edit item summary"
>
<Edit2 className="h-4 w-4" />
</Button>
Expand All @@ -603,6 +605,7 @@ export default function PortfolioPreview() {
onClick={() => deleteItem(item.id)}
className="text-red-500 hover:text-red-700"
title="Remove from portfolio"
aria-label="Remove from portfolio"
>
<Trash2 className="h-4 w-4" />
</Button>
Expand Down Expand Up @@ -761,6 +764,7 @@ export default function PortfolioPreview() {
variant="ghost"
className="absolute top-0 right-0 opacity-0 group-hover:opacity-100 transition-opacity"
onClick={startEditingTitle}
aria-label="Edit portfolio title"
>
<Edit2 className="h-4 w-4" />
</Button>
Expand Down Expand Up @@ -806,6 +810,7 @@ export default function PortfolioPreview() {
variant="ghost"
className="absolute top-0 right-0 opacity-0 group-hover:opacity-100 transition-opacity"
onClick={startEditingIntro}
aria-label="Edit introduction"
>
<Edit2 className="h-4 w-4" />
</Button>
Expand Down Expand Up @@ -882,6 +887,7 @@ export default function PortfolioPreview() {
variant="ghost"
className="absolute top-0 right-0 opacity-0 group-hover:opacity-100 transition-opacity"
onClick={startEditingSkills}
aria-label="Edit skills"
>
<Edit2 className="h-4 w-4" />
</Button>
Expand Down Expand Up @@ -941,6 +947,7 @@ export default function PortfolioPreview() {
variant="ghost"
className="absolute top-0 right-0 opacity-0 group-hover:opacity-100 transition-opacity"
onClick={startEditingInterests}
aria-label="Edit interests"
>
<Edit2 className="h-4 w-4" />
</Button>
Expand Down Expand Up @@ -1056,6 +1063,7 @@ export default function PortfolioPreview() {
variant="ghost"
className="absolute top-0 right-0 opacity-0 group-hover:opacity-100 transition-opacity"
onClick={() => startEditingItemTitle(item.id, getItemTitle(item))}
aria-label="Edit item title"
>
<Edit2 className="h-4 w-4" />
</Button>
Expand All @@ -1070,7 +1078,7 @@ export default function PortfolioPreview() {
</span>
)}
{item.url && (
<Button variant="outline" size="icon" asChild>
<Button variant="outline" size="icon" asChild aria-label="View item">
<a
href={item.url}
target="_blank"
Expand Down Expand Up @@ -1125,6 +1133,7 @@ export default function PortfolioPreview() {
size="sm"
variant="ghost"
onClick={() => startEditingItem(item.id, getItemSummary(item))}
aria-label="Edit item summary"
>
<Edit2 className="h-4 w-4" />
</Button>
Expand All @@ -1134,6 +1143,7 @@ export default function PortfolioPreview() {
onClick={() => deleteItem(item.id)}
className="text-red-500 hover:text-red-700"
title="Remove from portfolio"
aria-label="Remove from portfolio"
>
<Trash2 className="h-4 w-4" />
</Button>
Expand Down
20 changes: 17 additions & 3 deletions client/src/pages/repo-select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Skeleton } from "@/components/ui/skeleton";
import { Input } from "@/components/ui/input";
import { apiRequest, queryClient } from "@/lib/queryClient";
import { Repository } from "@shared/schema";
import { Search, ExternalLink } from "lucide-react";
import { Search, ExternalLink, X } from "lucide-react";
import { useToast } from "@/hooks/use-toast";
import { toggleRepositorySelection, saveRepositories, getRepositories, getGitHubToken } from "@/lib/storage";
import { AnalysisProgress } from "@/components/analysis-progress";
Expand Down Expand Up @@ -273,8 +273,21 @@ export default function RepoSelect() {
setSearchQuery(e.target.value);
setCurrentPage(1);
}}
className="pl-9"
className="pl-9 pr-9"
/>
{searchQuery && (
<button
type="button"
onClick={() => {
setSearchQuery("");
setCurrentPage(1);
}}
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-muted-foreground hover:text-foreground p-1 rounded-full focus:outline-none focus:ring-2 focus:ring-ring"
aria-label="Clear search"
>
<X className="h-4 w-4" />
</button>
)}
</div>
<div className="flex items-center gap-4">
<div className="flex items-center gap-2">
Expand Down Expand Up @@ -471,8 +484,9 @@ export default function RepoSelect() {
onClick={() => repo.id && toggleRepo({ id: repo.id, selected: false })}
className="ml-2 h-6 w-6 p-0 text-muted-foreground hover:text-destructive"
title="Remove from selection"
aria-label={`Remove ${repo.displayName || repo.name} from selection`}
>
×
<X className="h-4 w-4" />
</Button>
</div>
</CardHeader>
Expand Down
Loading
Loading