Skip to content

Commit a86d611

Browse files
authored
feat: Tray sticker (#105)
1 parent 66a0485 commit a86d611

File tree

8 files changed

+131
-2
lines changed

8 files changed

+131
-2
lines changed

src/main/ipcs/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ import './ipcProjects';
44
import './ipcGit';
55
import './ipcLaunch';
66
import './ipcGitHub';
7+
import './ipcSticker';

src/main/ipcs/ipcSticker.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { ipcMain, Menu, Tray, nativeImage, BrowserWindow } from 'electron';
2+
import log from 'electron-log';
3+
4+
let tray: Tray | null = null;
5+
6+
ipcMain.handle('sticker:add', async (_, text: string): Promise<void> => {
7+
if (tray) tray.destroy();
8+
9+
const trayIcon = nativeImage.createEmpty();
10+
tray = new Tray(trayIcon);
11+
tray.setTitle(text, { fontType: 'monospaced' });
12+
tray.setToolTip('Devkitty. Click to remove sticker.');
13+
14+
tray.on('click', () => {
15+
if (tray) {
16+
tray.destroy();
17+
tray = null;
18+
}
19+
});
20+
});

src/main/ipcs/preload.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ const bridge = {
4242
ipcRenderer.on('settings:updated', callback),
4343
set: <K extends keyof Settings>(key: K, value: Partial<Settings[K]>, safe?: boolean) =>
4444
ipcRenderer.invoke('settings:set', key, value, safe)
45+
},
46+
sticker: {
47+
add: (text: string) => ipcRenderer.invoke('sticker:add', text)
4548
}
4649
};
4750

src/rendered/components/AppNavbar/AppNavbar.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,20 @@ import { useDarkMode } from 'rendered/hooks/useDarkMode';
77
import { useProjects } from 'rendered/hooks/useProjects';
88

99
import { LeftGroup, Logo, RightGroup, StyledNavbar, Shadow, ShadowContainer, Title } from './AppNavbar.styles';
10+
import { useModal } from 'rendered/hooks/useModal';
1011

1112
export const AppNavbar = () => {
1213
const { themeSource, toggleDarkMode } = useDarkMode();
1314
const { showLogo } = useAppSettings();
1415
const { addProject } = useProjects();
16+
const { openModal } = useModal();
17+
18+
const addSticker = () => {
19+
openModal({
20+
name: 'sticker:add',
21+
props: {}
22+
});
23+
};
1524

1625
const refresh = () => {
1726
window.location.reload();
@@ -59,6 +68,12 @@ export const AppNavbar = () => {
5968
/>
6069
)}
6170

71+
<Button
72+
minimal
73+
icon="pin"
74+
onClick={addSticker}
75+
/>
76+
6277
<NavLink
6378
className={({ isActive }) => clsx(Classes.BUTTON, Classes.MINIMAL, isActive && Classes.ACTIVE)}
6479
to="/settings"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { Colors, Dialog } from '@blueprintjs/core';
2+
import styled from 'styled-components';
3+
4+
export const StyledDialog = styled(Dialog)`
5+
max-width: 250px;
6+
`;
7+
8+
export const Actions = styled.div`
9+
display: flex;
10+
align-items: center;
11+
margin-top: 10px;
12+
justify-content: space-between;
13+
flex-direction: row-reverse;
14+
`;
15+
16+
export const Error = styled.div`
17+
color: ${Colors.RED3};
18+
font-size: 12px;
19+
`;
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { Button, Classes, DialogBody, InputGroup } from '@blueprintjs/core';
2+
import { ChangeEventHandler, FC, useState } from 'react';
3+
4+
import { appToaster } from 'rendered/utils/appToaster';
5+
import { ModalProps } from 'types/Modal';
6+
7+
import { Actions, Error, StyledDialog } from './TrayStickerModal.styles';
8+
9+
export const TrayStickerModal: FC<ModalProps> = ({ onClose, darkMode, isOpen }) => {
10+
const [text, setText] = useState<string>('');
11+
const [error, setError] = useState<string | undefined>();
12+
13+
const handleChange: ChangeEventHandler<HTMLInputElement> = ({ target: { value } }) => {
14+
setText(value);
15+
};
16+
17+
const handleSave = async () => {
18+
setError(undefined);
19+
20+
if (text.trim().length < 1) {
21+
setError('Sticker text is required');
22+
return;
23+
}
24+
25+
window.bridge.sticker.add(text);
26+
27+
(await appToaster).show({
28+
intent: 'success',
29+
message: `Sticker added!`
30+
});
31+
32+
onClose();
33+
};
34+
35+
return (
36+
<StyledDialog
37+
className={darkMode && Classes.DARK}
38+
icon="pin"
39+
isOpen={isOpen}
40+
title={'Add Tray Sticker'}
41+
onClose={onClose}
42+
>
43+
<DialogBody>
44+
<InputGroup
45+
autoFocus
46+
intent={error ? 'danger' : 'none'}
47+
placeholder="sticker text..."
48+
value={text}
49+
onChange={handleChange}
50+
/>
51+
52+
<Actions>
53+
<Button
54+
intent="warning"
55+
text={'Add'}
56+
onClick={handleSave}
57+
/>
58+
59+
{error && <Error>{error}</Error>}
60+
</Actions>
61+
</DialogBody>
62+
</StyledDialog>
63+
);
64+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { TrayStickerModal } from './TrayStickerModal';

src/rendered/hooks/useModal.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { GitMergeModal, GitMergeModalProps } from 'rendered/components/Modals/Gi
77
import { RemoveAlert } from 'rendered/components/Project/components/RemoveAlert';
88
import { RemoveAlertProps } from 'rendered/components/Project/components/RemoveAlert/RemoveAlert';
99
import { GroupModal, GroupModalProps } from 'rendered/components/Modals/GroupModal/GroupModal';
10+
import { TrayStickerModal } from 'rendered/components/Modals/TrayStickerModal';
1011
import {
1112
RemoveGroupAlert,
1213
RemoveGroupAlertProps
@@ -36,6 +37,10 @@ type ActiveModal = ModalProps &
3637
name: 'remove:group';
3738
props: RemoveGroupAlertProps;
3839
}
40+
| {
41+
name: 'sticker:add';
42+
props: ModalProps;
43+
}
3944
);
4045

4146
type State = {
@@ -47,9 +52,10 @@ type State = {
4752
const Modals: Record<ActiveModal['name'], FC<ActiveModal['props']>> = {
4853
'git:merge': GitMergeModal,
4954
'git:reset': GitResetModal,
50-
group: GroupModal,
5155
'remove:group': RemoveGroupAlert,
52-
'remove:project': RemoveAlert
56+
'remove:project': RemoveAlert,
57+
'sticker:add': TrayStickerModal,
58+
group: GroupModal
5359
};
5460

5561
export const useModal = create<State>()((set, get) => ({

0 commit comments

Comments
 (0)