pauloj commited on
Commit
1098188
·
1 Parent(s): afb82e2

feat: Improve DiffView theme and color consistency

Browse files

- Added dark/light theme support for syntax highlighting
- Enhanced color styles for added/removed lines and characters
- Integrated theme store to dynamically adjust syntax highlighter theme
- Refined color contrast for better readability across themes

Files changed (1) hide show
  1. app/components/workbench/DiffView.tsx +31 -24
app/components/workbench/DiffView.tsx CHANGED
@@ -10,6 +10,7 @@ import { diffFiles, extractRelativePath } from '~/utils/diff';
10
  import { ActionRunner } from '~/lib/runtime/action-runner';
11
  import type { FileHistory } from '~/types/actions';
12
  import { getLanguageFromExtension } from '~/utils/getLanguageFromExtension';
 
13
 
14
  interface CodeComparisonProps {
15
  beforeCode: string;
@@ -302,12 +303,20 @@ const processChanges = (beforeCode: string, afterCode: string) => {
302
  const lineNumberStyles = "w-9 shrink-0 pl-2 py-1 text-left font-mono text-bolt-elements-textTertiary border-r border-bolt-elements-borderColor bg-bolt-elements-background-depth-1";
303
  const lineContentStyles = "px-1 py-1 font-mono whitespace-pre flex-1 group-hover:bg-bolt-elements-background-depth-2 text-bolt-elements-textPrimary";
304
  const diffPanelStyles = "h-full overflow-auto diff-panel-content";
 
 
305
  const diffLineStyles = {
306
- added: 'bg-green-500/20 border-l-4 border-green-500',
307
- removed: 'bg-red-500/20 border-l-4 border-red-500',
308
  unchanged: ''
309
  };
310
 
 
 
 
 
 
 
311
  const renderContentWarning = (type: 'binary' | 'error') => (
312
  <div className="h-full flex items-center justify-center p-4">
313
  <div className="text-center text-bolt-elements-textTertiary">
@@ -324,10 +333,11 @@ const renderContentWarning = (type: 'binary' | 'error') => (
324
  </div>
325
  );
326
 
327
- const NoChangesView = memo(({ beforeCode, language, highlighter }: {
328
  beforeCode: string;
329
  language: string;
330
  highlighter: any;
 
331
  }) => (
332
  <div className="h-full flex flex-col items-center justify-center p-4">
333
  <div className="text-center text-bolt-elements-textTertiary">
@@ -347,7 +357,7 @@ const NoChangesView = memo(({ beforeCode, language, highlighter }: {
347
  <span className="mr-2"> </span>
348
  <span dangerouslySetInnerHTML={{
349
  __html: highlighter ?
350
- highlighter.codeToHtml(line, { lang: language, theme: 'github-dark' })
351
  .replace(/<\/?pre[^>]*>/g, '')
352
  .replace(/<\/?code[^>]*>/g, '')
353
  : line
@@ -372,7 +382,8 @@ const CodeLine = memo(({
372
  type,
373
  highlighter,
374
  language,
375
- block
 
376
  }: {
377
  lineNumber: number;
378
  content: string;
@@ -380,17 +391,14 @@ const CodeLine = memo(({
380
  highlighter: any;
381
  language: string;
382
  block: DiffBlock;
 
383
  }) => {
384
- const bgColor = {
385
- added: 'bg-green-500/20 border-l-4 border-green-500',
386
- removed: 'bg-red-500/20 border-l-4 border-red-500',
387
- unchanged: ''
388
- }[type];
389
 
390
  const renderContent = () => {
391
  if (type === 'unchanged' || !block.charChanges) {
392
  const highlightedCode = highlighter ?
393
- highlighter.codeToHtml(content, { lang: language, theme: 'github-dark' })
394
  .replace(/<\/?pre[^>]*>/g, '')
395
  .replace(/<\/?code[^>]*>/g, '')
396
  : content;
@@ -400,14 +408,10 @@ const CodeLine = memo(({
400
  return (
401
  <>
402
  {block.charChanges.map((change, index) => {
403
- const changeClass = {
404
- added: 'text-green-500 bg-green-500/20',
405
- removed: 'text-red-500 bg-red-500/20',
406
- unchanged: ''
407
- }[change.type];
408
 
409
  const highlightedCode = highlighter ?
410
- highlighter.codeToHtml(change.value, { lang: language, theme: 'github-dark' })
411
  .replace(/<\/?pre[^>]*>/g, '')
412
  .replace(/<\/?code[^>]*>/g, '')
413
  : change.value;
@@ -429,8 +433,8 @@ const CodeLine = memo(({
429
  <div className={lineNumberStyles}>{lineNumber + 1}</div>
430
  <div className={`${lineContentStyles} ${bgColor}`}>
431
  <span className="mr-2 text-bolt-elements-textTertiary">
432
- {type === 'added' && '+'}
433
- {type === 'removed' && '-'}
434
  {type === 'unchanged' && ' '}
435
  </span>
436
  {renderContent()}
@@ -488,20 +492,20 @@ const FileInfo = memo(({
488
  {showStats && (
489
  <div className="flex items-center gap-1 text-xs">
490
  {additions > 0 && (
491
- <span className="text-green-500">+{additions}</span>
492
  )}
493
  {deletions > 0 && (
494
- <span className="text-red-500">-{deletions}</span>
495
  )}
496
  </div>
497
  )}
498
- <span className="text-yellow-400">Modified</span>
499
  <span className="text-bolt-elements-textTertiary text-xs">
500
  {new Date().toLocaleTimeString()}
501
  </span>
502
  </>
503
  ) : (
504
- <span className="text-green-400">No Changes</span>
505
  )}
506
  <FullscreenButton onClick={onToggleFullscreen} isFullscreen={isFullscreen} />
507
  </span>
@@ -512,6 +516,7 @@ const FileInfo = memo(({
512
  const InlineDiffComparison = memo(({ beforeCode, afterCode, filename, language, lightTheme, darkTheme }: CodeComparisonProps) => {
513
  const [isFullscreen, setIsFullscreen] = useState(false);
514
  const [highlighter, setHighlighter] = useState<any>(null);
 
515
 
516
  const toggleFullscreen = useCallback(() => {
517
  setIsFullscreen(prev => !prev);
@@ -521,7 +526,7 @@ const InlineDiffComparison = memo(({ beforeCode, afterCode, filename, language,
521
 
522
  useEffect(() => {
523
  getHighlighter({
524
- themes: ['github-dark'],
525
  langs: ['typescript', 'javascript', 'json', 'html', 'css', 'jsx', 'tsx']
526
  }).then(setHighlighter);
527
  }, []);
@@ -551,6 +556,7 @@ const InlineDiffComparison = memo(({ beforeCode, afterCode, filename, language,
551
  highlighter={highlighter}
552
  language={language}
553
  block={block}
 
554
  />
555
  ))}
556
  </div>
@@ -559,6 +565,7 @@ const InlineDiffComparison = memo(({ beforeCode, afterCode, filename, language,
559
  beforeCode={beforeCode}
560
  language={language}
561
  highlighter={highlighter}
 
562
  />
563
  )}
564
  </div>
 
10
  import { ActionRunner } from '~/lib/runtime/action-runner';
11
  import type { FileHistory } from '~/types/actions';
12
  import { getLanguageFromExtension } from '~/utils/getLanguageFromExtension';
13
+ import { themeStore } from '~/lib/stores/theme';
14
 
15
  interface CodeComparisonProps {
16
  beforeCode: string;
 
303
  const lineNumberStyles = "w-9 shrink-0 pl-2 py-1 text-left font-mono text-bolt-elements-textTertiary border-r border-bolt-elements-borderColor bg-bolt-elements-background-depth-1";
304
  const lineContentStyles = "px-1 py-1 font-mono whitespace-pre flex-1 group-hover:bg-bolt-elements-background-depth-2 text-bolt-elements-textPrimary";
305
  const diffPanelStyles = "h-full overflow-auto diff-panel-content";
306
+
307
+ // Updated color styles for better consistency
308
  const diffLineStyles = {
309
+ added: 'bg-green-500/10 dark:bg-green-500/20 border-l-4 border-green-500',
310
+ removed: 'bg-red-500/10 dark:bg-red-500/20 border-l-4 border-red-500',
311
  unchanged: ''
312
  };
313
 
314
+ const changeColorStyles = {
315
+ added: 'text-green-700 dark:text-green-500 bg-green-500/10 dark:bg-green-500/20',
316
+ removed: 'text-red-700 dark:text-red-500 bg-red-500/10 dark:bg-red-500/20',
317
+ unchanged: 'text-bolt-elements-textPrimary'
318
+ };
319
+
320
  const renderContentWarning = (type: 'binary' | 'error') => (
321
  <div className="h-full flex items-center justify-center p-4">
322
  <div className="text-center text-bolt-elements-textTertiary">
 
333
  </div>
334
  );
335
 
336
+ const NoChangesView = memo(({ beforeCode, language, highlighter, theme }: {
337
  beforeCode: string;
338
  language: string;
339
  highlighter: any;
340
+ theme: string;
341
  }) => (
342
  <div className="h-full flex flex-col items-center justify-center p-4">
343
  <div className="text-center text-bolt-elements-textTertiary">
 
357
  <span className="mr-2"> </span>
358
  <span dangerouslySetInnerHTML={{
359
  __html: highlighter ?
360
+ highlighter.codeToHtml(line, { lang: language, theme: theme === 'dark' ? 'github-dark' : 'github-light' })
361
  .replace(/<\/?pre[^>]*>/g, '')
362
  .replace(/<\/?code[^>]*>/g, '')
363
  : line
 
382
  type,
383
  highlighter,
384
  language,
385
+ block,
386
+ theme
387
  }: {
388
  lineNumber: number;
389
  content: string;
 
391
  highlighter: any;
392
  language: string;
393
  block: DiffBlock;
394
+ theme: string;
395
  }) => {
396
+ const bgColor = diffLineStyles[type];
 
 
 
 
397
 
398
  const renderContent = () => {
399
  if (type === 'unchanged' || !block.charChanges) {
400
  const highlightedCode = highlighter ?
401
+ highlighter.codeToHtml(content, { lang: language, theme: theme === 'dark' ? 'github-dark' : 'github-light' })
402
  .replace(/<\/?pre[^>]*>/g, '')
403
  .replace(/<\/?code[^>]*>/g, '')
404
  : content;
 
408
  return (
409
  <>
410
  {block.charChanges.map((change, index) => {
411
+ const changeClass = changeColorStyles[change.type];
 
 
 
 
412
 
413
  const highlightedCode = highlighter ?
414
+ highlighter.codeToHtml(change.value, { lang: language, theme: theme === 'dark' ? 'github-dark' : 'github-light' })
415
  .replace(/<\/?pre[^>]*>/g, '')
416
  .replace(/<\/?code[^>]*>/g, '')
417
  : change.value;
 
433
  <div className={lineNumberStyles}>{lineNumber + 1}</div>
434
  <div className={`${lineContentStyles} ${bgColor}`}>
435
  <span className="mr-2 text-bolt-elements-textTertiary">
436
+ {type === 'added' && <span className="text-green-700 dark:text-green-500">+</span>}
437
+ {type === 'removed' && <span className="text-red-700 dark:text-red-500">-</span>}
438
  {type === 'unchanged' && ' '}
439
  </span>
440
  {renderContent()}
 
492
  {showStats && (
493
  <div className="flex items-center gap-1 text-xs">
494
  {additions > 0 && (
495
+ <span className="text-green-700 dark:text-green-500">+{additions}</span>
496
  )}
497
  {deletions > 0 && (
498
+ <span className="text-red-700 dark:text-red-500">-{deletions}</span>
499
  )}
500
  </div>
501
  )}
502
+ <span className="text-yellow-600 dark:text-yellow-400">Modified</span>
503
  <span className="text-bolt-elements-textTertiary text-xs">
504
  {new Date().toLocaleTimeString()}
505
  </span>
506
  </>
507
  ) : (
508
+ <span className="text-green-700 dark:text-green-400">No Changes</span>
509
  )}
510
  <FullscreenButton onClick={onToggleFullscreen} isFullscreen={isFullscreen} />
511
  </span>
 
516
  const InlineDiffComparison = memo(({ beforeCode, afterCode, filename, language, lightTheme, darkTheme }: CodeComparisonProps) => {
517
  const [isFullscreen, setIsFullscreen] = useState(false);
518
  const [highlighter, setHighlighter] = useState<any>(null);
519
+ const theme = useStore(themeStore);
520
 
521
  const toggleFullscreen = useCallback(() => {
522
  setIsFullscreen(prev => !prev);
 
526
 
527
  useEffect(() => {
528
  getHighlighter({
529
+ themes: ['github-dark', 'github-light'],
530
  langs: ['typescript', 'javascript', 'json', 'html', 'css', 'jsx', 'tsx']
531
  }).then(setHighlighter);
532
  }, []);
 
556
  highlighter={highlighter}
557
  language={language}
558
  block={block}
559
+ theme={theme}
560
  />
561
  ))}
562
  </div>
 
565
  beforeCode={beforeCode}
566
  language={language}
567
  highlighter={highlighter}
568
+ theme={theme}
569
  />
570
  )}
571
  </div>