Skip to content

Commit 423a7bc

Browse files
committed
Working straight from claude, refinement needed.
1 parent b92a4a5 commit 423a7bc

File tree

15 files changed

+1112
-168
lines changed

15 files changed

+1112
-168
lines changed

browser-extension/package.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,36 @@
11
{
22
"author": "DiffPlug",
33
"dependencies": {
4+
"@types/react": "^19.1.12",
5+
"@types/react-dom": "^19.1.9",
46
"@wxt-dev/webextension-polyfill": "^1.0.0",
7+
"class-variance-authority": "^0.7.1",
8+
"clsx": "^2.1.1",
59
"highlight.js": "^11.11.1",
10+
"lucide-react": "^0.543.0",
611
"overtype": "workspace:*",
12+
"react": "^19.1.1",
13+
"react-dom": "^19.1.1",
14+
"tailwind-merge": "^3.3.1",
715
"webextension-polyfill": "^0.12.0"
816
},
917
"description": "Syntax highlighting and autosave for comments on GitHub (and other other markdown-friendly websites).",
1018
"devDependencies": {
1119
"@biomejs/biome": "^2.1.2",
1220
"@playwright/test": "^1.46.0",
21+
"@tailwindcss/postcss": "^4.1.13",
1322
"@testing-library/jest-dom": "^6.6.4",
1423
"@types/express": "^4.17.21",
1524
"@types/har-format": "^1.2.16",
1625
"@types/node": "^22.16.5",
26+
"@vitejs/plugin-react": "^5.0.2",
1727
"@vitest/coverage-v8": "^3.2.4",
1828
"@vitest/ui": "^3.2.4",
29+
"autoprefixer": "^10.4.21",
1930
"express": "^4.19.2",
2031
"linkedom": "^0.18.12",
32+
"postcss": "^8.5.6",
33+
"tailwindcss": "^4.1.13",
2134
"tsx": "^4.19.1",
2235
"typescript": "^5.8.3",
2336
"vitest": "^3.2.4",
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
plugins: {
3+
'@tailwindcss/postcss': {},
4+
autoprefixer: {},
5+
},
6+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import * as React from 'react'
2+
3+
import { cn } from '@/lib/utils'
4+
5+
const Table = React.forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(
6+
({ className, ...props }, ref) => (
7+
<div className='relative w-full overflow-auto'>
8+
<table ref={ref} className={cn('w-full caption-bottom text-sm', className)} {...props} />
9+
</div>
10+
),
11+
)
12+
Table.displayName = 'Table'
13+
14+
const TableHeader = React.forwardRef<
15+
HTMLTableSectionElement,
16+
React.HTMLAttributes<HTMLTableSectionElement>
17+
>(({ className, ...props }, ref) => (
18+
<thead ref={ref} className={cn('[&_tr]:border-b', className)} {...props} />
19+
))
20+
TableHeader.displayName = 'TableHeader'
21+
22+
const TableBody = React.forwardRef<
23+
HTMLTableSectionElement,
24+
React.HTMLAttributes<HTMLTableSectionElement>
25+
>(({ className, ...props }, ref) => (
26+
<tbody ref={ref} className={cn('[&_tr:last-child]:border-0', className)} {...props} />
27+
))
28+
TableBody.displayName = 'TableBody'
29+
30+
const TableFooter = React.forwardRef<
31+
HTMLTableSectionElement,
32+
React.HTMLAttributes<HTMLTableSectionElement>
33+
>(({ className, ...props }, ref) => (
34+
<tfoot
35+
ref={ref}
36+
className={cn('border-t bg-muted/50 font-medium [&>tr]:last:border-b-0', className)}
37+
{...props}
38+
/>
39+
))
40+
TableFooter.displayName = 'TableFooter'
41+
42+
const TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTMLTableRowElement>>(
43+
({ className, ...props }, ref) => (
44+
<tr
45+
ref={ref}
46+
className={cn(
47+
'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
48+
className,
49+
)}
50+
{...props}
51+
/>
52+
),
53+
)
54+
TableRow.displayName = 'TableRow'
55+
56+
const TableHead = React.forwardRef<
57+
HTMLTableCellElement,
58+
React.ThHTMLAttributes<HTMLTableCellElement>
59+
>(({ className, ...props }, ref) => (
60+
<th
61+
ref={ref}
62+
className={cn(
63+
'h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0',
64+
className,
65+
)}
66+
{...props}
67+
/>
68+
))
69+
TableHead.displayName = 'TableHead'
70+
71+
const TableCell = React.forwardRef<
72+
HTMLTableCellElement,
73+
React.TdHTMLAttributes<HTMLTableCellElement>
74+
>(({ className, ...props }, ref) => (
75+
<td
76+
ref={ref}
77+
className={cn('p-4 align-middle [&:has([role=checkbox])]:pr-0', className)}
78+
{...props}
79+
/>
80+
))
81+
TableCell.displayName = 'TableCell'
82+
83+
const TableCaption = React.forwardRef<
84+
HTMLTableCaptionElement,
85+
React.HTMLAttributes<HTMLTableCaptionElement>
86+
>(({ className, ...props }, ref) => (
87+
<caption ref={ref} className={cn('mt-4 text-sm text-muted-foreground', className)} {...props} />
88+
))
89+
TableCaption.displayName = 'TableCaption'
90+
91+
export { Table, TableHeader, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableRow }

browser-extension/src/entrypoints/popup/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
<body>
99
<div id="app">
1010
</div>
11-
<script type="module" src="main.ts"></script>
11+
<script type="module" src="main.tsx"></script>
1212
</body>
1313
</html>

browser-extension/src/entrypoints/popup/main.ts

Lines changed: 0 additions & 97 deletions
This file was deleted.
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import './style.css'
2+
import React from 'react'
3+
import { createRoot } from 'react-dom/client'
4+
import {
5+
Table,
6+
TableBody,
7+
TableCell,
8+
TableHead,
9+
TableHeader,
10+
TableRow,
11+
} from '@/components/ui/table'
12+
import { cn } from '@/lib/utils'
13+
import { logger } from '../../lib/logger'
14+
import type {
15+
GetOpenSpotsMessage,
16+
GetOpenSpotsResponse,
17+
SwitchToTabMessage,
18+
} from '../../lib/messages'
19+
import { EnhancerRegistry } from '../../lib/registries'
20+
import type { CommentState } from '../background'
21+
22+
const enhancers = new EnhancerRegistry()
23+
24+
async function getOpenSpots(): Promise<CommentState[]> {
25+
logger.debug('Sending message to background script...')
26+
try {
27+
const message: GetOpenSpotsMessage = { type: 'GET_OPEN_SPOTS' }
28+
const response = (await browser.runtime.sendMessage(message)) as GetOpenSpotsResponse
29+
logger.debug('Received response:', response)
30+
return response.spots || []
31+
} catch (error) {
32+
logger.error('Error sending message to background:', error)
33+
return []
34+
}
35+
}
36+
37+
function switchToTab(tabId: number, windowId: number): void {
38+
const message: SwitchToTabMessage = {
39+
tabId,
40+
type: 'SWITCH_TO_TAB',
41+
windowId,
42+
}
43+
browser.runtime.sendMessage(message)
44+
window.close()
45+
}
46+
47+
interface SpotRowProps {
48+
commentState: CommentState
49+
onClick: () => void
50+
}
51+
52+
function SpotRow({ commentState, onClick }: SpotRowProps) {
53+
const enhancer = enhancers.enhancerFor(commentState.spot)
54+
55+
if (!enhancer) {
56+
logger.error('No enhancer found for:', commentState.spot)
57+
logger.error('Only have enhancers for:', enhancers.byType)
58+
return null
59+
}
60+
61+
return (
62+
<TableRow
63+
className={cn(
64+
'cursor-pointer transition-colors hover:bg-muted/50',
65+
'border-b border-border/40',
66+
)}
67+
onClick={onClick}
68+
>
69+
<TableCell className='p-3'>
70+
<div className='flex items-center gap-2'>
71+
<span className='text-lg'>{enhancer.tableIcon(commentState.spot)}</span>
72+
<div className='font-medium text-sm text-foreground overflow-hidden text-ellipsis whitespace-nowrap'>
73+
{enhancer.tableTitle(commentState.spot)}
74+
</div>
75+
</div>
76+
</TableCell>
77+
</TableRow>
78+
)
79+
}
80+
81+
function PopupApp() {
82+
const [spots, setSpots] = React.useState<CommentState[]>([])
83+
const [isLoading, setIsLoading] = React.useState(true)
84+
85+
React.useEffect(() => {
86+
const loadSpots = async () => {
87+
try {
88+
const openSpots = await getOpenSpots()
89+
setSpots(openSpots)
90+
} catch (error) {
91+
logger.error('Error loading spots:', error)
92+
} finally {
93+
setIsLoading(false)
94+
}
95+
}
96+
97+
loadSpots()
98+
}, [])
99+
100+
if (isLoading) {
101+
return <div className='p-4 text-center text-muted-foreground'>Loading...</div>
102+
}
103+
104+
if (spots.length === 0) {
105+
return (
106+
<div className='p-10 text-center text-muted-foreground italic'>No open comment spots</div>
107+
)
108+
}
109+
110+
return (
111+
<div className='w-full'>
112+
<h2 className='mb-4 text-lg font-semibold text-foreground'>Open Comment Spots</h2>
113+
114+
<div className='border rounded-md'>
115+
<Table>
116+
<TableHeader>
117+
<TableRow>
118+
<TableHead className='p-3 font-medium text-muted-foreground'>Comment Spots</TableHead>
119+
</TableRow>
120+
</TableHeader>
121+
<TableBody>
122+
{spots.map((spot) => (
123+
<SpotRow
124+
key={spot.spot.unique_key}
125+
commentState={spot}
126+
onClick={() => switchToTab(spot.tab.tabId, spot.tab.windowId)}
127+
/>
128+
))}
129+
</TableBody>
130+
</Table>
131+
</div>
132+
</div>
133+
)
134+
}
135+
136+
// Initialize React app
137+
const app = document.getElementById('app')
138+
if (app) {
139+
const root = createRoot(app)
140+
root.render(<PopupApp />)
141+
} else {
142+
logger.error('App element not found')
143+
}

0 commit comments

Comments
 (0)