Skip to content

Commit a7f4ea4

Browse files
authored
GH_PR_ADD_COMMENT works for reloads and turbolinks (#8)
2 parents 0358c6e + 4e4a25f commit a7f4ea4

File tree

11 files changed

+111
-164
lines changed

11 files changed

+111
-164
lines changed

browser-extension/biome.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"recommended": true,
5151
"style": {
5252
"noDefaultExport": "off",
53-
"noNonNullAssertion": "warn",
53+
"noNonNullAssertion": "off",
5454
"noParameterAssign": {
5555
"options": {
5656
"propertyAssignment": "deny"

browser-extension/package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

browser-extension/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"dependencies": {
44
"@wxt-dev/webextension-polyfill": "^1.0.0",
55
"highlight.js": "^11.11.1",
6+
"markdown-actions": "^1.1.2",
67
"webextension-polyfill": "^0.12.0"
78
},
89
"description": "Syntax highlighting and autosave for comments on GitHub (and other other markdown-friendly websites).",

browser-extension/src/entrypoints/content.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CONFIG } from '../lib/config'
1+
import { CONFIG, type ModeType } from '../lib/config'
22
import { logger } from '../lib/logger'
33
import { EnhancerRegistry, TextareaRegistry } from '../lib/registries'
44
import { githubPrNewCommentContentScript } from '../playgrounds/github-playground'
@@ -8,7 +8,7 @@ const enhancedTextareas = new TextareaRegistry()
88

99
export default defineContentScript({
1010
main() {
11-
if (CONFIG.MODE === 'PLAYGROUNDS_PR') {
11+
if ((CONFIG.MODE as ModeType) === 'PLAYGROUNDS_PR') {
1212
githubPrNewCommentContentScript()
1313
return
1414
}

browser-extension/src/lib/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ export const CONFIG = {
66
ADDED_OVERTYPE_CLASS: 'gitcasso-overtype',
77
DEBUG: true, // enabled debug logging
88
EXTENSION_NAME: 'gitcasso', // decorates logs
9-
MODE: 'PLAYGROUNDS_PR' satisfies ModeType,
9+
MODE: 'PROD' satisfies ModeType,
1010
} as const

browser-extension/src/lib/enhancer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { OverType } from '../overtype/mock-overtype'
1+
import type { OverTypeInstance } from '../overtype/overtype'
22

33
/**
44
* stores enough info about the location of a draft to:
@@ -18,7 +18,7 @@ export interface CommentEnhancer<Spot extends CommentSpot = CommentSpot> {
1818
* whenever a new `textarea` is added to any webpage, this method is called.
1919
* if we return non-null, then we become the handler for that text area.
2020
*/
21-
tryToEnhance(textarea: HTMLTextAreaElement): [OverType, Spot] | null
21+
tryToEnhance(textarea: HTMLTextAreaElement): [OverTypeInstance, Spot] | null
2222

2323
tableIcon(spot: Spot): string
2424
tableTitle(spot: Spot): string
Lines changed: 66 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
import { OverType } from '../../overtype/mock-overtype'
1+
import hljs from 'highlight.js'
2+
import { logger } from '../../lib/logger'
3+
import OverType, { type OverTypeInstance } from '../../overtype/overtype'
24
import type { CommentEnhancer, CommentSpot } from '../enhancer'
35

46
const GITHUB_SPOT_TYPES = [
7+
'GH_PR_ADD_COMMENT',
8+
/* TODO
59
'GH_ISSUE_NEW',
610
'GH_PR_NEW',
711
'GH_ISSUE_ADD_COMMENT',
8-
'GH_PR_ADD_COMMENT',
9-
/* TODO
1012
'GH_ISSUE_EDIT_COMMENT',
1113
'GH_PR_EDIT_COMMENT',
1214
'GH_PR_CODE_COMMENT',
@@ -15,95 +17,95 @@ const GITHUB_SPOT_TYPES = [
1517

1618
export type GitHubSpotType = (typeof GITHUB_SPOT_TYPES)[number]
1719

18-
export interface GitHubSpot extends CommentSpot {
20+
export interface GitHubAddCommentSpot extends CommentSpot {
1921
type: GitHubSpotType // Override to narrow from string to specific union
2022
domain: string
2123
slug: string // owner/repo
22-
number?: number | undefined // issue/PR number, undefined for new issues and PRs
24+
number: number // issue/PR number, undefined for new issues and PRs
2325
}
2426

25-
export class GitHubEnhancer implements CommentEnhancer<GitHubSpot> {
27+
export class GitHubAddCommentEnhancer implements CommentEnhancer<GitHubAddCommentSpot> {
2628
forSpotTypes(): string[] {
2729
return [...GITHUB_SPOT_TYPES]
2830
}
2931

30-
tryToEnhance(textarea: HTMLTextAreaElement): [OverType, GitHubSpot] | null {
31-
// Only handle GitHub domains
32-
if (!window.location.hostname.includes('github')) {
32+
tryToEnhance(textarea: HTMLTextAreaElement): [OverTypeInstance, GitHubAddCommentSpot] | null {
33+
// Only handle github.com domains TODO: identify GitHub Enterprise somehow
34+
if (window.location.hostname !== 'github.com') {
3335
return null
3436
}
3537

36-
const pathname = window.location.pathname
37-
3838
// Parse GitHub URL structure: /owner/repo/issues/123 or /owner/repo/pull/456
39-
const match = pathname.match(/^\/([^/]+)\/([^/]+)(?:\/(issues|pull)\/(\d+))?/)
40-
if (!match) return null
39+
logger.debug(`${this.constructor.name} examing url`, window.location.pathname)
4140

42-
const [, owner, repo, urlType, numberStr] = match
41+
const match = window.location.pathname.match(/^\/([^/]+)\/([^/]+)(?:\/pull\/(\d+))/)
42+
logger.debug(`${this.constructor.name} found match`, window.location.pathname)
43+
if (!match) return null
44+
const [, owner, repo, numberStr] = match
4345
const slug = `${owner}/${repo}`
44-
const number = numberStr ? parseInt(numberStr, 10) : undefined
45-
46-
// Determine comment type
47-
let type: GitHubSpotType
48-
49-
if (pathname.includes('/issues/new')) {
50-
type = 'GH_ISSUE_NEW'
51-
} else if (pathname.includes('/compare/') || pathname.endsWith('/compare')) {
52-
type = 'GH_PR_NEW'
53-
} else if (urlType && number) {
54-
if (urlType === 'issues') {
55-
type = 'GH_ISSUE_ADD_COMMENT'
56-
} else {
57-
type = 'GH_PR_ADD_COMMENT'
58-
}
59-
} else {
60-
return null
61-
}
46+
const number = parseInt(numberStr!, 10)
6247

63-
// Generate unique key based on context
64-
let unique_key = `github:${slug}`
65-
if (number) {
66-
unique_key += `:${urlType}:${number}`
67-
} else {
68-
unique_key += ':new'
69-
}
48+
const unique_key = `github.com:${slug}:${number}`
7049

71-
const spot: GitHubSpot = {
72-
domain: window.location.hostname,
50+
const spot: GitHubAddCommentSpot = {
51+
domain: 'github.com',
7352
number,
7453
slug,
75-
type,
54+
type: 'GH_PR_ADD_COMMENT',
7655
unique_key,
7756
}
78-
const overtype = new OverType(textarea)
79-
return [overtype, spot]
57+
return [this.createOvertypeFor(textarea), spot]
58+
}
59+
60+
private createOvertypeFor(ghCommentBox: HTMLTextAreaElement): OverTypeInstance {
61+
OverType.setCodeHighlighter(hljsHighlighter)
62+
const overtypeContainer = this.modifyDOM(ghCommentBox)
63+
return new OverType(overtypeContainer, {
64+
autoResize: true,
65+
minHeight: '102px',
66+
padding: 'var(--base-size-8)',
67+
placeholder: 'Add your comment here...',
68+
})[0]!
69+
}
70+
71+
private modifyDOM(overtypeInput: HTMLTextAreaElement): HTMLElement {
72+
overtypeInput.classList.add('overtype-input')
73+
const overtypePreview = document.createElement('div')
74+
overtypePreview.classList.add('overtype-preview')
75+
overtypeInput.insertAdjacentElement('afterend', overtypePreview)
76+
const overtypeWrapper = overtypeInput.parentElement!.closest('div')!
77+
overtypeWrapper.classList.add('overtype-wrapper')
78+
overtypeInput.placeholder = 'Add your comment here...'
79+
const overtypeContainer = overtypeWrapper.parentElement!.closest('div')!
80+
overtypeContainer.classList.add('overtype-container')
81+
return overtypeContainer.parentElement!.closest('div')!
8082
}
8183

82-
tableTitle(spot: GitHubSpot): string {
84+
tableTitle(spot: GitHubAddCommentSpot): string {
8385
const { slug, number } = spot
84-
if (number) {
85-
return `Comment on ${slug} #${number}`
86-
}
87-
return `New ${window.location.pathname.includes('/issues/') ? 'issue' : 'PR'} in ${slug}`
86+
return `${slug} PR #${number}`
8887
}
8988

90-
tableIcon(spot: GitHubSpot): string {
91-
switch (spot.type) {
92-
case 'GH_ISSUE_NEW':
93-
case 'GH_ISSUE_ADD_COMMENT':
94-
return '🐛' // Issue icon
95-
case 'GH_PR_NEW':
96-
case 'GH_PR_ADD_COMMENT':
97-
return '🔄' // PR icon
98-
}
89+
tableIcon(_: GitHubAddCommentSpot): string {
90+
return '🔄' // PR icon TODO: icon urls in /public
91+
}
92+
93+
buildUrl(spot: GitHubAddCommentSpot): string {
94+
return `https://${spot.domain}/${spot.slug}/pull/${spot.number}`
9995
}
96+
}
10097

101-
buildUrl(spot: GitHubSpot): string {
102-
const baseUrl = `https://${spot.domain}/${spot.slug}`
103-
if (spot.number) {
104-
const type = spot.type.indexOf('ISSUE') ? 'issues' : 'pull'
105-
return `${baseUrl}/${type}/${spot.number}`
98+
function hljsHighlighter(code: string, language: string) {
99+
try {
100+
if (language && hljs.getLanguage(language)) {
101+
const result = hljs.highlight(code, { language })
102+
return result.value
103+
} else {
104+
const result = hljs.highlightAuto(code)
105+
return result.value
106106
}
107-
return baseUrl
107+
} catch (error) {
108+
console.warn('highlight.js highlighting failed:', error)
109+
return code
108110
}
109111
}

browser-extension/src/lib/registries.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
1-
import type { OverType } from '../overtype/mock-overtype'
1+
import type { OverTypeInstance } from '../overtype/overtype'
22
import type { CommentEnhancer, CommentSpot } from './enhancer'
3-
import { GitHubEnhancer } from './enhancers/github'
3+
import { GitHubAddCommentEnhancer } from './enhancers/github'
44

55
export interface EnhancedTextarea<T extends CommentSpot = CommentSpot> {
66
textarea: HTMLTextAreaElement
77
spot: T
8-
handler: CommentEnhancer<T>
9-
overtype: OverType
8+
enhancer: CommentEnhancer<T>
9+
overtype: OverTypeInstance
1010
}
1111

1212
export class EnhancerRegistry {
1313
private enhancers = new Set<CommentEnhancer<any>>()
1414

1515
constructor() {
1616
// Register all available handlers
17-
this.register(new GitHubEnhancer())
17+
this.register(new GitHubAddCommentEnhancer())
1818
}
1919

2020
private register<T extends CommentSpot>(handler: CommentEnhancer<T>): void {
2121
this.enhancers.add(handler)
2222
}
2323

2424
tryToEnhance(textarea: HTMLTextAreaElement): EnhancedTextarea<any> | null {
25-
for (const handler of this.enhancers) {
25+
for (const enhancer of this.enhancers) {
2626
try {
27-
const result = handler.tryToEnhance(textarea)
27+
const result = enhancer.tryToEnhance(textarea)
2828
if (result) {
2929
const [overtype, spot] = result
30-
return { handler, overtype, spot, textarea }
30+
return { enhancer, overtype, spot, textarea }
3131
}
3232
} catch (error) {
3333
console.warn('Handler failed to identify textarea:', error)

browser-extension/src/overtype/mock-overtype.ts

Lines changed: 0 additions & 44 deletions
This file was deleted.

browser-extension/tests/lib/enhancers/__snapshots__/github.test.ts.snap

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)