aboutsummaryrefslogtreecommitdiffstats
path: root/src/webview/screenshare.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/webview/screenshare.ts')
-rw-r--r--src/webview/screenshare.ts143
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 @@
1import { desktopCapturer } from 'electron';
2
3const CANCEL_ID = 'desktop-capturer-selection__cancel';
4
5export 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
32export 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
104export const screenShareJs = `
105window.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`;