diff options
Diffstat (limited to 'src/webview/screenshare.ts')
-rw-r--r-- | src/webview/screenshare.ts | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/src/webview/screenshare.ts b/src/webview/screenshare.ts new file mode 100644 index 000000000..91a1623bb --- /dev/null +++ b/src/webview/screenshare.ts | |||
@@ -0,0 +1,143 @@ | |||
1 | import { desktopCapturer } from 'electron'; | ||
2 | |||
3 | const CANCEL_ID = 'desktop-capturer-selection__cancel'; | ||
4 | |||
5 | export async function getDisplayMediaSelector() { | ||
6 | const sources = await desktopCapturer.getSources({ | ||
7 | types: ['screen', 'window'], | ||
8 | }); | ||
9 | return `<div class="desktop-capturer-selection__scroller"> | ||
10 | <ul class="desktop-capturer-selection__list"> | ||
11 | ${sources | ||
12 | .map( | ||
13 | ({ id, name, thumbnail }) => ` | ||
14 | <li class="desktop-capturer-selection__item"> | ||
15 | <button class="desktop-capturer-selection__btn" data-id="${id}" title="${name}"> | ||
16 | <img class="desktop-capturer-selection__thumbnail" src="${thumbnail.toDataURL()}" /> | ||
17 | <span class="desktop-capturer-selection__name">${name}</span> | ||
18 | </button> | ||
19 | </li> | ||
20 | `, | ||
21 | ) | ||
22 | .join('')} | ||
23 | <li class="desktop-capturer-selection__item"> | ||
24 | <button class="desktop-capturer-selection__btn" data-id="${CANCEL_ID}" title="Cancel"> | ||
25 | <span class="desktop-capturer-selection__name desktop-capturer-selection__name--cancel">Cancel</span> | ||
26 | </button> | ||
27 | </li> | ||
28 | </ul> | ||
29 | </div>`; | ||
30 | } | ||
31 | |||
32 | export const screenShareCss = ` | ||
33 | .desktop-capturer-selection { | ||
34 | position: fixed; | ||
35 | top: 0; | ||
36 | left: 0; | ||
37 | width: 100%; | ||
38 | height: 100vh; | ||
39 | background: rgba(30,30,30,.75); | ||
40 | color: #fff; | ||
41 | z-index: 10000000; | ||
42 | display: flex; | ||
43 | align-items: center; | ||
44 | justify-content: center; | ||
45 | } | ||
46 | .desktop-capturer-selection__scroller { | ||
47 | width: 100%; | ||
48 | max-height: 100vh; | ||
49 | overflow-y: auto; | ||
50 | } | ||
51 | .desktop-capturer-selection__list { | ||
52 | max-width: calc(100% - 100px); | ||
53 | margin: 50px; | ||
54 | padding: 0; | ||
55 | display: flex; | ||
56 | flex-wrap: wrap; | ||
57 | list-style: none; | ||
58 | overflow: hidden; | ||
59 | justify-content: center; | ||
60 | } | ||
61 | .desktop-capturer-selection__item { | ||
62 | display: flex; | ||
63 | margin: 4px; | ||
64 | } | ||
65 | .desktop-capturer-selection__btn { | ||
66 | display: flex; | ||
67 | flex-direction: column; | ||
68 | align-items: stretch; | ||
69 | width: 145px; | ||
70 | margin: 0; | ||
71 | border: 0; | ||
72 | border-radius: 3px; | ||
73 | padding: 4px; | ||
74 | background: #252626; | ||
75 | text-align: left; | ||
76 | @media (prefers-reduced-motion: no-preference) { | ||
77 | transition: background-color .15s, box-shadow .15s, color .15s; | ||
78 | } | ||
79 | color: #dedede; | ||
80 | } | ||
81 | .desktop-capturer-selection__btn:hover, | ||
82 | .desktop-capturer-selection__btn:focus { | ||
83 | background: rgba(98,100,167,.8); | ||
84 | box-shadow: 0 0 4px rgba(0,0,0,0.45), 0 0 2px rgba(0,0,0,0.25); | ||
85 | color: #fff; | ||
86 | } | ||
87 | .desktop-capturer-selection__thumbnail { | ||
88 | width: 100%; | ||
89 | height: 81px; | ||
90 | object-fit: cover; | ||
91 | } | ||
92 | .desktop-capturer-selection__name { | ||
93 | margin: 6px 0; | ||
94 | white-space: nowrap; | ||
95 | text-overflow: ellipsis; | ||
96 | text-align: center; | ||
97 | overflow: hidden; | ||
98 | } | ||
99 | .desktop-capturer-selection__name--cancel { | ||
100 | margin: auto 0; | ||
101 | } | ||
102 | `; | ||
103 | |||
104 | export const screenShareJs = ` | ||
105 | window.navigator.mediaDevices.getDisplayMedia = () => new Promise(async (resolve, reject) => { | ||
106 | try { | ||
107 | const selectionElem = document.createElement('div'); | ||
108 | selectionElem.classList = ['desktop-capturer-selection']; | ||
109 | selectionElem.innerHTML = await window.ferdi.getDisplayMediaSelector(); | ||
110 | document.body.appendChild(selectionElem); | ||
111 | |||
112 | document | ||
113 | .querySelectorAll('.desktop-capturer-selection__btn') | ||
114 | .forEach((button) => { | ||
115 | button.addEventListener('click', async () => { | ||
116 | try { | ||
117 | const id = button.getAttribute('data-id'); | ||
118 | if (id === '${CANCEL_ID}') { | ||
119 | reject(new Error('Cancelled by user')); | ||
120 | } else { | ||
121 | const stream = await window.navigator.mediaDevices.getUserMedia({ | ||
122 | audio: false, | ||
123 | video: { | ||
124 | mandatory: { | ||
125 | chromeMediaSource: 'desktop', | ||
126 | chromeMediaSourceId: id, | ||
127 | }, | ||
128 | }, | ||
129 | }); | ||
130 | resolve(stream); | ||
131 | } | ||
132 | } catch (err) { | ||
133 | reject(err); | ||
134 | } finally { | ||
135 | selectionElem.remove(); | ||
136 | } | ||
137 | }); | ||
138 | }); | ||
139 | } catch (err) { | ||
140 | reject(err); | ||
141 | } | ||
142 | }); | ||
143 | `; | ||