v0.8.0 0fa6785

notifications.ts RawHistoryFolder

1import type { NotificationOptions } from '../types/app.js';
2
3interface TimerElement extends HTMLElement {
4  timeout?: ReturnType<typeof setTimeout>;
5}
6
7export class NotificationService {
8  private zoomNotification: HTMLElement | null = null;
9  private generalNotification: HTMLElement | null = null;
10
11  showZoom(message: string, duration = 2000): void {
12    // Create or update zoom notification
13    if (!this.zoomNotification) {
14      this.zoomNotification = this.createNotificationElement('zoom-notification', {
15        top: '20px',
16        right: '20px',
17        background: 'rgba(0, 0, 0, 0.8)',
18        color: 'white'
19      });
20    }
21
22    this.updateNotification(this.zoomNotification, message, duration);
23  }
24
25  show(message: string, type: NotificationOptions['type'] = 'info', duration = 3000): void {
26    // Create or update general notification
27    if (!this.generalNotification) {
28      this.generalNotification = this.createNotificationElement('general-notification', {
29        top: '60px',
30        right: '20px'
31      });
32    }
33
34    // Set colors based on type
35    const colors = this.getNotificationColors(type);
36    this.generalNotification.style.background = colors.background;
37    this.generalNotification.style.color = colors.color;
38
39    this.updateNotification(this.generalNotification, message, duration);
40  }
41
42  private createNotificationElement(id: string, baseStyles: Record<string, string>): HTMLElement {
43    const notification = document.createElement('div');
44    notification.id = id;
45    
46    const styles = {
47      position: 'fixed',
48      padding: '10px 15px',
49      borderRadius: '5px',
50      fontSize: '14px',
51      zIndex: '10000',
52      transition: 'opacity 0.3s',
53      opacity: '0',
54      ...baseStyles
55    };
56
57    notification.style.cssText = Object.entries(styles)
58      .map(([key, value]) => `${this.camelToKebab(key)}: ${value}`)
59      .join('; ');
60
61    document.body.appendChild(notification);
62    return notification;
63  }
64
65  private updateNotification(element: HTMLElement, message: string, duration: number): void {
66    element.textContent = message;
67    element.style.opacity = '1';
68
69    // Clear any existing timeout
70    const timerElement = element as TimerElement;
71    if (timerElement.timeout) {
72      clearTimeout(timerElement.timeout);
73    }
74
75    // Hide after duration
76    timerElement.timeout = setTimeout(() => {
77      element.style.opacity = '0';
78    }, duration);
79  }
80
81  private getNotificationColors(type: NotificationOptions['type']): { background: string; color: string } {
82    switch (type) {
83      case 'error':
84        return { background: 'rgba(220, 53, 69, 0.9)', color: 'white' };
85      case 'success':
86        return { background: 'rgba(25, 135, 84, 0.9)', color: 'white' };
87      default:
88        return { background: 'rgba(13, 110, 253, 0.9)', color: 'white' };
89    }
90  }
91
92  private camelToKebab(str: string): string {
93    return str.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`);
94  }
95}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close