Skip to content

Commit 8a0194a

Browse files
authored
Clicking in the table should open the correct tab (#87)
2 parents b3b5d86 + 5169253 commit 8a0194a

File tree

11 files changed

+102
-61
lines changed

11 files changed

+102
-61
lines changed

src/components/Badge.tsx

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,39 @@ import { type JSX, useState } from 'react'
22
import { twMerge } from 'tailwind-merge'
33
import type { VariantProps } from 'tailwind-variants'
44
import { badgeCVA, typeColors, typeIcons } from '@/components/design'
5+
import type { CommentTableRow } from '@/entrypoints/background'
56

6-
import { CodePreview } from './BadgePreviews/CodePreview'
7-
import { ImagePreview } from './BadgePreviews/ImagePreview'
8-
import { LinkPreview } from './BadgePreviews/LinkPreview'
9-
import { TextPreview } from './BadgePreviews/TextPreview'
10-
import { TimePreview } from './BadgePreviews/TimePreview'
7+
import { CodePreview } from './BadgePopups/CodePreview'
8+
import { ImagePreview } from './BadgePopups/ImagePreview'
9+
import { LinkPreview } from './BadgePopups/LinkPreview'
10+
import { OpenTabPopup } from './BadgePopups/OpenTabPopup'
11+
import { TextPreview } from './BadgePopups/TextPreview'
12+
import { TimePreview } from './BadgePopups/TimePreview'
1113

12-
const typeTooltips = {
14+
const typePopups = {
1315
code: CodePreview,
1416
image: ImagePreview,
1517
link: LinkPreview,
18+
open: OpenTabPopup,
1619
text: TextPreview,
1720
time: TimePreview,
18-
} satisfies Partial<Record<keyof typeof typeIcons, () => JSX.Element>>
21+
} satisfies Partial<Record<keyof typeof typeIcons, (props: BadgePopupProps) => JSX.Element>>
22+
23+
export interface BadgePopupProps {
24+
row: CommentTableRow
25+
}
1926

2027
export type BadgeProps = VariantProps<typeof badgeCVA> & {
2128
type: keyof typeof typeIcons
2229
text?: number | string
30+
data?: CommentTableRow
2331
}
2432

25-
const Badge = ({ text, type }: BadgeProps) => {
33+
const Badge = ({ text, type, data }: BadgeProps) => {
2634
const Icon = typeIcons[type]
2735
const [showTooltip, setShowTooltip] = useState(false)
28-
const TooltipComponent =
29-
showTooltip && type in typeTooltips && typeTooltips[type as keyof typeof typeTooltips]
36+
const PopupComponent =
37+
showTooltip && type in typePopups && typePopups[type as keyof typeof typePopups]
3038
return (
3139
<button
3240
type='button'
@@ -37,22 +45,22 @@ const Badge = ({ text, type }: BadgeProps) => {
3745
<span
3846
className={twMerge(
3947
badgeCVA({
40-
clickable: type in typeTooltips,
48+
clickable: type in typePopups,
4149
type,
4250
}),
4351
)}
4452
>
4553
{type === 'blank' || <Icon className='h-3 w-3' />}
4654
{text || type}
4755
</span>
48-
{TooltipComponent && (
56+
{PopupComponent && data && (
4957
<div
5058
className={twMerge(
5159
'absolute top-full z-10 w-30 rounded border px-2 py-1 text-left text-xs shadow-lg',
5260
typeColors[type],
5361
)}
5462
>
55-
<TooltipComponent />
63+
<PopupComponent row={data} />
5664
</div>
5765
)}
5866
</button>

src/components/BadgePreviews/CodePreview.tsx renamed to src/components/BadgePopups/CodePreview.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
export function CodePreview() {
1+
import type { BadgePopupProps } from '@/components/Badge'
2+
3+
export function CodePreview({ row: _row }: BadgePopupProps) {
24
return (
35
<>
46
TODO{' '}

src/components/BadgePreviews/ImagePreview.tsx renamed to src/components/BadgePopups/ImagePreview.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
export function ImagePreview() {
1+
import type { BadgePopupProps } from '@/components/Badge'
2+
3+
export function ImagePreview({ row: _row }: BadgePopupProps) {
24
return (
35
<>
46
TODO{' '}

src/components/BadgePreviews/LinkPreview.tsx renamed to src/components/BadgePopups/LinkPreview.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
export function LinkPreview() {
1+
import type { BadgePopupProps } from '@/components/Badge'
2+
3+
export function LinkPreview({ row: _row }: BadgePopupProps) {
24
return (
35
<>
46
TODO{' '}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { BadgePopupProps } from '@/components/Badge'
2+
import { openOrFocusComment } from '@/entrypoints/popup/popup'
3+
4+
export function OpenTabPopup({ row }: BadgePopupProps) {
5+
const handleClick = () => {
6+
openOrFocusComment(row.spot.unique_key)
7+
}
8+
9+
return (
10+
<button
11+
onClick={handleClick}
12+
className='w-full cursor-pointer text-left hover:bg-opacity-80'
13+
type='button'
14+
>
15+
<p>Tab is already open.</p>
16+
<p>Click to activate.</p>
17+
</button>
18+
)
19+
}

src/components/BadgePreviews/TextPreview.tsx renamed to src/components/BadgePopups/TextPreview.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
export function TextPreview() {
1+
import type { BadgePopupProps } from '@/components/Badge'
2+
3+
export function TextPreview({ row: _row }: BadgePopupProps) {
24
return (
35
<>
46
TODO{' '}

src/components/BadgePreviews/TimePreview.tsx renamed to src/components/BadgePopups/TimePreview.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
export function TimePreview() {
1+
import type { BadgePopupProps } from '@/components/Badge'
2+
3+
export function TimePreview({ row: _row }: BadgePopupProps) {
24
return (
35
<>
46
TODO{' '}

src/components/CommentRow.tsx

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import Badge from '@/components/Badge'
22
import { timeAgo } from '@/components/misc'
33
import type { CommentTableRow } from '@/entrypoints/background'
4+
import { openOrFocusComment } from '@/entrypoints/popup/popup'
45
import { EnhancerRegistry } from '@/lib/registries'
56

67
const enhancers = new EnhancerRegistry()
@@ -15,6 +16,10 @@ type CommentRowProps = {
1516

1617
export function CommentRow({ row, selectedIds, toggleSelection }: CommentRowProps) {
1718
const enhancer = enhancers.enhancerFor(row.spot)
19+
20+
const handleTitleClick = () => {
21+
openOrFocusComment(row.spot.unique_key)
22+
}
1823
return (
1924
<tr className='hover:bg-gray-50'>
2025
<td className='px-3 py-3'>
@@ -34,25 +39,29 @@ export function CommentRow({ row, selectedIds, toggleSelection }: CommentRowProp
3439
</div>
3540
<div className='flex flex-shrink-0 items-center gap-1'>
3641
{row.latestDraft.stats.links.length > 0 && (
37-
<Badge type='link' text={row.latestDraft.stats.links.length} />
42+
<Badge type='link' text={row.latestDraft.stats.links.length} data={row} />
3843
)}
3944
{row.latestDraft.stats.images.length > 0 && (
40-
<Badge type='image' text={row.latestDraft.stats.images.length} />
45+
<Badge type='image' text={row.latestDraft.stats.images.length} data={row} />
4146
)}
4247
{row.latestDraft.stats.codeBlocks.length > 0 && (
43-
<Badge type='code' text={row.latestDraft.stats.codeBlocks.length} />
48+
<Badge type='code' text={row.latestDraft.stats.codeBlocks.length} data={row} />
4449
)}
45-
<Badge type='text' text={row.latestDraft.stats.charCount} />
46-
<Badge type='time' text={timeAgo(row.latestDraft.time)} />
47-
{row.isOpenTab && <Badge type='open' />}
50+
<Badge type='text' text={row.latestDraft.stats.charCount} data={row} />
51+
<Badge type='time' text={timeAgo(row.latestDraft.time)} data={row} />
52+
{row.isOpenTab && <Badge type='open' data={row} />}
4853
</div>
4954
</div>
5055

5156
{/* Title */}
5257
<div className='flex items-center gap-1'>
53-
<a href='TODO' className='truncate font-medium text-sm hover:underline'>
58+
<button
59+
type='button'
60+
onClick={handleTitleClick}
61+
className='cursor-pointer truncate text-left font-medium text-sm hover:underline'
62+
>
5463
{enhancer.tableTitle(row.spot)}
55-
</a>
64+
</button>
5665
<Badge type={row.isSent ? 'sent' : 'unsent'} />
5766
{row.isTrashed && <Badge type='trashed' />}
5867
</div>

src/entrypoints/background.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
CLOSE_MESSAGE_PORT,
77
isContentToBackgroundMessage,
88
isGetOpenSpotsMessage,
9-
isSwitchToTabMessage,
9+
isOpenOrFocusMessage,
1010
KEEP_PORT_OPEN,
1111
} from '@/lib/messages'
1212

@@ -106,16 +106,21 @@ export function handlePopupMessage(
106106
const response: GetTableRowsResponse = { rows }
107107
sendResponse(response)
108108
return KEEP_PORT_OPEN
109-
} else if (isSwitchToTabMessage(message)) {
109+
} else if (isOpenOrFocusMessage(message)) {
110110
logger.debug('received switch tab message', message)
111-
browser.windows
112-
.update(message.windowId, { focused: true })
113-
.then(() => {
114-
return browser.tabs.update(message.tabId, { active: true })
115-
})
116-
.catch((error) => {
117-
console.error('Error switching to tab:', error)
118-
})
111+
const storage = openSpots.get(message.uniqueKey)
112+
if (storage) {
113+
browser.windows
114+
.update(storage.tab.windowId, { focused: true })
115+
.then(() => {
116+
return browser.tabs.update(storage.tab.tabId, { active: true })
117+
})
118+
.catch((error) => {
119+
console.error('Error switching to tab:', error)
120+
})
121+
} else {
122+
console.error('TODO: implement opening a previous comment', message.uniqueKey)
123+
}
119124
return CLOSE_MESSAGE_PORT
120125
} else {
121126
logger.error('received unknown message', message)

src/entrypoints/popup/popup.tsx

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { createRoot } from 'react-dom/client'
33
import { PopupRoot } from '@/components/PopupRoot'
44
import type { CommentTableRow } from '@/entrypoints/background'
55
import { logger } from '@/lib/logger'
6-
import type { GetOpenSpotsMessage, GetTableRowsResponse } from '@/lib/messages'
6+
import type { GetOpenSpotsMessage, GetTableRowsResponse, OpenOrFocusMessage } from '@/lib/messages'
77

88
export interface FilterState {
99
sentFilter: 'both' | 'sent' | 'unsent'
@@ -24,20 +24,14 @@ async function getOpenSpots(): Promise<CommentTableRow[]> {
2424
}
2525
}
2626

27-
// function switchToTab(tabId: number, windowId: number): void {
28-
// const message: SwitchToTabMessage = {
29-
// tabId,
30-
// type: 'SWITCH_TO_TAB',
31-
// windowId,
32-
// }
33-
// browser.runtime.sendMessage(message)
34-
// window.close()
35-
// }
36-
37-
// const handleSpotClick = (spot: CommentTableRow) => {
38-
// console.log('TODO: switchToTab')
39-
// //switchToTab(spot.tab.tabId, spot.tab.windowId)
40-
// }
27+
export function openOrFocusComment(uniqueKey: string): void {
28+
const message: OpenOrFocusMessage = {
29+
type: 'OPEN_OR_FOCUS_COMMENT',
30+
uniqueKey,
31+
}
32+
browser.runtime.sendMessage(message)
33+
window.close()
34+
}
4135

4236
const app = document.getElementById('app')
4337
if (app) {

0 commit comments

Comments
 (0)