Skip to content

Commit c13f09a

Browse files
authored
feat: react devtools and twemoji plugin (#2662)
* feat: react devtools Signed-off-by: Adam Setch <adam.setch@outlook.com> * feat: react devtools Signed-off-by: Adam Setch <adam.setch@outlook.com> * Update package.json * feat: react devtools Signed-off-by: Adam Setch <adam.setch@outlook.com> --------- Signed-off-by: Adam Setch <adam.setch@outlook.com>
1 parent 98bd3dd commit c13f09a

7 files changed

Lines changed: 777 additions & 29 deletions

File tree

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"codegen": "graphql-codegen --config codegen.ts",
1212
"codegen:watch": "pnpm codegen --watch",
1313
"dev": "concurrently --names \"vite,codegen\" --prefix-colors \"blue,magenta\" \"vite dev\" \"pnpm codegen:watch\"",
14+
"devtools": "concurrently --names \"dev,devtools\" --prefix-colors \"cyan,green\" \"pnpm dev\" \"react-devtools\"",
1415
"start": "pnpm build && pnpm dev",
1516
"package:linux": "electron-builder --linux",
1617
"package:macos": "electron-builder --mac",
@@ -114,6 +115,7 @@
114115
"graphql": "16.13.0",
115116
"happy-dom": "20.7.0",
116117
"husky": "9.1.7",
118+
"react-devtools": "7.0.1",
117119
"rimraf": "6.1.3",
118120
"semver": "7.7.4",
119121
"tailwind-merge": "3.5.0",

pnpm-lock.yaml

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

src/renderer/components/AllRead.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ export const AllRead: FC<AllReadProps> = ({
1717

1818
const emoji = useMemo(
1919
() =>
20-
Constants.ALL_READ_EMOJIS[
21-
Math.floor(Math.random() * Constants.ALL_READ_EMOJIS.length)
20+
Constants.EMOJIS.ALL_READ[
21+
Math.floor(Math.random() * Constants.EMOJIS.ALL_READ.length)
2222
],
2323
[],
2424
);

src/renderer/constants.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,17 @@ export const Constants = {
2323
GITHUB_API_GRAPHQL_URL: 'https://api.github.com/graphql',
2424
GITHUB_API_MERGE_BATCH_SIZE: 100,
2525

26-
ALL_READ_EMOJIS: ['🎉', '🎊', '🥳', '👏', '🙌', '😎', '🏖️', '🚀', '✨', '🏆'],
26+
// Emojis for different states and events
27+
EMOJIS: {
28+
ALL_READ: ['🎉', '🎊', '🥳', '👏', '🙌', '😎', '🏖️', '🚀', '✨', '🏆'],
29+
ERRORS: {
30+
BAD_CREDENTIALS: ['🔓'],
31+
MISSING_SCOPES: ['🔭'],
32+
NETWORK: ['🛜'],
33+
RATE_LIMITED: ['😮‍💨'],
34+
UNKNOWN: ['🤔', '🥲', '😳', '🫠', '🙃', '🙈'],
35+
},
36+
},
2737

2838
DEFAULT_FETCH_NOTIFICATIONS_INTERVAL_MS: 60 * 1000, // 1 minute
2939
MIN_FETCH_NOTIFICATIONS_INTERVAL_MS: 60 * 1000, // 1 minute

src/renderer/utils/api/graphql/generated/graphql.ts

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

src/renderer/utils/errors.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,35 @@
1+
import { Constants } from '../constants';
2+
13
import type { AccountNotifications, ErrorType, GitifyError } from '../types';
24

35
export const Errors: Record<ErrorType, GitifyError> = {
46
BAD_CREDENTIALS: {
57
title: 'Bad Credentials',
68
descriptions: ['Your credentials are either invalid or expired.'],
7-
emojis: ['🔓'],
9+
emojis: Constants.EMOJIS.ERRORS.BAD_CREDENTIALS,
810
},
911
MISSING_SCOPES: {
1012
title: 'Missing Scopes',
1113
descriptions: ['Your credentials are missing a required API scope.'],
12-
emojis: ['🔭'],
14+
emojis: Constants.EMOJIS.ERRORS.MISSING_SCOPES,
1315
},
1416
NETWORK: {
1517
title: 'Network Error',
1618
descriptions: [
1719
'Unable to connect to one or more of your GitHub environments.',
1820
'Please check your network connection, including whether you require a VPN, and try again.',
1921
],
20-
emojis: ['🛜'],
22+
emojis: Constants.EMOJIS.ERRORS.NETWORK,
2123
},
2224
RATE_LIMITED: {
2325
title: 'Rate Limited',
2426
descriptions: ['Please wait a while before trying again.'],
25-
emojis: ['😮‍💨'],
27+
emojis: Constants.EMOJIS.ERRORS.RATE_LIMITED,
2628
},
2729
UNKNOWN: {
2830
title: 'Oops! Something went wrong',
2931
descriptions: ['Please try again later.'],
30-
emojis: ['🤔', '🥲', '😳', '🫠', '🙃', '🙈'],
32+
emojis: Constants.EMOJIS.ERRORS.UNKNOWN,
3133
},
3234
};
3335

vite.config.ts

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,61 @@ import { fileURLToPath } from 'node:url';
33
import twemoji from '@discordapp/twemoji';
44
import tailwindcss from '@tailwindcss/vite';
55
import react from '@vitejs/plugin-react-swc';
6+
import type { Plugin } from 'vite';
67
import { defineConfig } from 'vite';
78
import checker from 'vite-plugin-checker';
89
import electron from 'vite-plugin-electron/simple';
910
import { viteStaticCopy } from 'vite-plugin-static-copy';
1011

1112
import { Constants } from './src/renderer/constants';
1213

13-
import { Errors } from './src/renderer/utils/errors';
14+
/**
15+
* Helper to generate Twemoji static copy targets.
16+
* Extracts all emojis from Constants.EMOJIS and maps them to their SVG filenames.
17+
*/
18+
const getTwemojiCopyTargets = () => {
19+
const flatten = (obj: object): string[] =>
20+
Object.values(obj).flatMap((v) =>
21+
Array.isArray(v) ? v : flatten(v as object),
22+
);
1423

15-
const ALL_EMOJIS = [
16-
...Constants.ALL_READ_EMOJIS,
17-
...Errors.BAD_CREDENTIALS.emojis,
18-
...Errors.MISSING_SCOPES.emojis,
19-
...Errors.NETWORK.emojis,
20-
...Errors.RATE_LIMITED.emojis,
21-
...Errors.UNKNOWN.emojis,
22-
];
24+
const extractSvgFilename = (imgHtml: string) =>
25+
imgHtml
26+
.match(/src="(.*)"/)?.[1]
27+
.split('/')
28+
.pop();
2329

24-
const extractSvgFilename = (imgHtml: string) =>
25-
imgHtml
26-
.match(/src="(.*)"/)?.[1]
27-
.split('/')
28-
.pop();
30+
const allEmojis = flatten(Constants.EMOJIS);
31+
const emojiFilenames = allEmojis.map((emoji) =>
32+
extractSvgFilename(twemoji.parse(emoji, { folder: 'svg', ext: '.svg' })),
33+
);
2934

30-
const ALL_EMOJI_SVG_FILENAMES = ALL_EMOJIS.map((emoji) =>
31-
extractSvgFilename(twemoji.parse(emoji, { folder: 'svg', ext: '.svg' })),
32-
);
35+
return emojiFilenames.map((filename) => ({
36+
src: `../../node_modules/@discordapp/twemoji/dist/svg/${filename}`,
37+
dest: 'assets/images/twemoji',
38+
}));
39+
};
40+
41+
/**
42+
* Vite plugin that injects React DevTools connection script in dev mode only.
43+
* This script connects the renderer process to the standalone react-devtools instance.
44+
*/
45+
const reactDevToolsPlugin = (): Plugin => ({
46+
name: 'react-devtools',
47+
apply: 'serve', // Only apply in dev mode (vite dev)
48+
transformIndexHtml(html) {
49+
// Inject devtools connection script and update CSP to allow localhost:8097
50+
return html
51+
.replace(
52+
'<meta http-equiv="Content-Security-Policy" content="script-src \'self\';',
53+
'<meta http-equiv="Content-Security-Policy" content="script-src \'self\' http://localhost:8097;',
54+
)
55+
.replace(
56+
'</head>',
57+
' <script src="http://localhost:8097"></script>\n </head>',
58+
);
59+
},
60+
});
3361

3462
export default defineConfig(({ command }) => {
3563
const isBuild = command === 'build';
@@ -45,6 +73,7 @@ export default defineConfig(({ command }) => {
4573
biome: { dev: { logLevel: ['error'] } },
4674
}),
4775
]),
76+
reactDevToolsPlugin(),
4877
react({
4978
plugins: [
5079
[
@@ -91,10 +120,7 @@ export default defineConfig(({ command }) => {
91120
}),
92121
viteStaticCopy({
93122
targets: [
94-
...ALL_EMOJI_SVG_FILENAMES.map((filename) => ({
95-
src: `../../node_modules/@discordapp/twemoji/dist/svg/${filename}`,
96-
dest: 'assets/images/twemoji',
97-
})),
123+
...getTwemojiCopyTargets(),
98124
{
99125
src: '../../assets',
100126
dest: '.',

0 commit comments

Comments
 (0)