aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Marek Knappe <marek.knappe@gmail.com>2023-12-23 04:59:03 +1000
committerLibravatar GitHub <noreply@github.com>2023-12-22 11:59:03 -0700
commitdf10736dc9da80e0b40006300ecdba70005a6804 (patch)
tree81527adccd127b32c74c60a8d868f05ccc84b977
parentfix: invalid volta versions in package.json (#481) (diff)
downloadferdium-recipes-df10736dc9da80e0b40006300ecdba70005a6804.tar.gz
ferdium-recipes-df10736dc9da80e0b40006300ecdba70005a6804.tar.zst
ferdium-recipes-df10736dc9da80e0b40006300ecdba70005a6804.zip
[feature] Added threads recipe (#484)
Co-authored-by: Marek Knappe <mknappe@perceptyx.com>
-rw-r--r--recipes/threads/darkmode.css421
-rw-r--r--recipes/threads/icon.svg1
-rw-r--r--recipes/threads/index.js8
-rw-r--r--recipes/threads/package.json10
-rw-r--r--recipes/threads/service.css0
-rw-r--r--recipes/threads/webview.js78
6 files changed, 518 insertions, 0 deletions
diff --git a/recipes/threads/darkmode.css b/recipes/threads/darkmode.css
new file mode 100644
index 0000000..c71469a
--- /dev/null
+++ b/recipes/threads/darkmode.css
@@ -0,0 +1,421 @@
1/* Copied from: https://github.com/ducfilan/Dark-mode-Franz-Ferdi */
2
3:root:not(#z) {
4 --bshadow: 0 2px 4px var(--shadow);
5 --t: transparent !important;
6 --avatar: a_radius;
7 --ui-font: "font_name", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
8 Helvetica, Arial, Ubuntu, Cantarell, "Noto Sans", var(--emoji-font),
9 sans-serif;
10 --emoji-font: "font_name", "joypixels", "Apple Color Emoji", "Segoe UI Emoji",
11 "Segoe UI Symbol", "Noto Color Emoji";
12 --white: #fff;
13 --dark: #1f232a;
14 --darken: #252a33;
15 --darker: #333943;
16 --light: #e9e9e9;
17 --lighter: #a1a1a1;
18 --accent: #7289da;
19 --shadow: rgba(0, 0, 0, 0.145);
20 --yellow: #e5c512;
21 --orange: #df4b16;
22 --red: #dc322f;
23 --magenta: #f33682;
24 --violet: #6c71c4;
25 --blue: #268bd2;
26 --cyan: #2aa198;
27 --green: #859900;
28 --dark-rgb: 31, 35, 42;
29 --darken-rgb: 37, 42, 51;
30 --darker-rgb: 51, 57, 67;
31 --light-rgb: 233, 233, 233;
32 --lighter-rgb: 161, 161, 161;
33 --accent-rgb: 114, 137, 218;
34 --shadow-rgb: 0, 0, 0;
35 --white-rgb: 255, 255, 255;
36 --b6a: var(--darker-rgb);
37 --b38: var(--darker-rgb);
38 --ce3: var(--darker-rgb);
39 --ca6: var(--darker-rgb);
40 --d87: var(--darken-rgb);
41 --f23: var(--darken-rgb);
42 --b3f: var(--dark-rgb);
43 --i1d: var(--light-rgb);
44 --f75: var(--light-rgb);
45 --f52: var(--lighter-rgb);
46 --bb2: var(--darken-rgb);
47 --f23: var(--dark-rgb);
48 --fe0: var(--accent-rgb);
49 --d69: var(--accent-rgb);
50 --c37: var(--accent-rgb);
51 --eca: var(--darken-rgb);
52 --jb7: var(--shadow-rgb);
53 --fa7: var(--darken-rgb);
54 --de5: var(--white-rgb);
55}
56::-webkit-scrollbar {
57 width: 0.5em;
58}
59* {
60 scrollbar-width: thin;
61}
62html {
63 scrollbar-color: var(--accent) rgba(136, 136, 136, 0.082);
64}
65::-webkit-scrollbar {
66 background-color: rgba(136, 136, 136, 0.082) !important;
67}
68::-webkit-scrollbar-thumb {
69 background-color: var(--accent) !important;
70}
71body {
72 color: var(--light) !important;
73 background-color: var(--dark) !important;
74}
75body ::placeholder {
76 color: var(--lighter) !important;
77}
78body ::-webkit-input-placeholder {
79 color: var(--lighter) !important;
80}
81body,
82body button,
83body input,
84body textarea {
85 font-family: var(--ui-font) !important;
86}
87body[style*="background: white"] {
88 background-color: var(--dark) !important;
89}
90body[style*="background: white"] svg {
91 fill: var(--lighter) !important;
92}
93body[class*="error"] .top-bar,
94body[class*="404"] .top-bar {
95 color: var(--light) !important;
96 border-color: var(--darker) !important;
97 background-color: var(--darken) !important;
98}
99body[class*="error"] .top-bar .logo,
100body[class*="404"] .top-bar .logo {
101 filter: invert(0.8) !important;
102}
103body[class*="error"] a,
104body[class*="404"] a,
105body[class*="error"] strong,
106body[class*="404"] strong {
107 color: var(--accent) !important;
108}
109body svg[fill="#262626"] {
110 fill: var(--light);
111}
112body svg[fill="#ffffff"] {
113 fill: var(--light);
114}
115body svg[fill="#8e8e8e"] {
116 fill: var(--lighter);
117}
118body svg[fill="#ed4956"] {
119 fill: var(--red);
120}
121body svg[fill="#0095f6"] {
122 fill: var(--blue);
123}
124body svg path {
125 transition: fill-opacity 0.2s ease;
126}
127body svg:hover path {
128 fill-opacity: 0.6;
129}
130body .coreSpriteLoggedOutWordmark,
131body .coreSpriteMobileNavDirect,
132body .coreSpriteTaggedNull {
133 filter: invert(0.8) !important;
134}
135[class*="SpriteDirect"],
136[class*="SpriteFacebook"],
137[class*="SpriteLink"],
138[class*="SpriteMail"],
139[class*="SpriteApp"],
140[class*="Spritez"],
141[class*="SpriteKeyhole"],
142[class*="SpriteFriend_"],
143[class*="SpriteAdd_friend_"],
144[class*="SpriteDropdownArrowGrey"],
145[class*="SpritePagingChevron"],
146[class*="SpriteCamera"],
147[class*="SpriteProfileChannelNullState"],
148[class*="SpriteLocation_"],
149[class*="SpriteInfo__filled__16__grey"],
150[class*="SpriteCircle_add"] {
151 filter: invert(0.8) !important;
152}
153img[src*="44884218_345707102882519_2446069589734326272"] {
154 filter: invert(0.8) !important;
155}
156body ._2Lks6 {
157 color: var(--accent) !important;
158}
159body nav a[href="/"] img,
160[src*="logo.png"] {
161 filter: invert(0.8);
162}
163body .HZ802,
164body .nHGTw {
165 color: var(--white) !important;
166 background-color: var(--accent) !important;
167}
168body .HZ802 .H9zXO::after,
169body .nHGTw .H9zXO::after {
170 background-color: var(--accent) !important;
171}
172.iMofo {
173 box-shadow: 0 4px 16px var(--shadow) !important;
174}
175body .HZ802 [class*="Sprite"] + div > div,
176body .nHGTw [class*="Sprite"] + div > div {
177 color: var(--white) !important;
178}
179body > [role="presentation"],
180body > [role="dialog"] {
181 background: rgba(var(--b3f), 0.8) !important;
182}
183.not-logged-in .N9d2H {
184 display: none !important;
185}
186.not-logged-in [style*="overflow: hidden"] {
187 overflow: unset !important;
188}
189.not-logged-in [style*="overflow: hidden"] > [role="presentation"] {
190 display: none !important;
191}
192body .LFGs8 {
193 color: var(--accent) !important;
194}
195body .yQ0j1 {
196 color: var(--lighter) !important;
197}
198body .M-jxE,
199body .M-jxE > button {
200 background-color: var(--darken) !important;
201}
202body ._4Kbb_ {
203 margin-top: 1rem;
204 color: var(--light) !important;
205 border-color: var(--darker) !important;
206 background-color: var(--darken) !important;
207}
208.hUQXy,
209.hUQXy:visited {
210 color: var(--accent) !important;
211}
212body .jju9v {
213 border: 1px solid var(--darker);
214 color: var(--light) !important;
215 background-color: var(--darken) !important;
216}
217body .hI7cq {
218 color: var(--light) !important;
219}
220body .isgrP > ul {
221 background-color: var(--t) !important;
222}
223body ._7LpC8 a,
224body .rin8p {
225 color: var(--accent) !important;
226}
227body .rb9ad,
228body .-wdIA,
229body .d-Vzv {
230 border-color: var(--darker) !important;
231}
232body .leaflet-container {
233 background-color: var(--darken) !important;
234 box-shadow: 0 1px var(--darker);
235}
236body .leaflet-tile {
237 filter: invert(0.9) hue-rotate(180deg) !important;
238}
239body .leaflet-popup-content-wrapper,
240body .leaflet-popup-tip {
241 background-color: var(--darken) !important;
242 box-shadow: 0 3px 14px var(--shadow);
243}
244body .Sux9m {
245 border-color: #aaa !important;
246 background-color: rgba(238, 238, 238, 0.067) !important;
247 --eca: var(--light-rgb);
248}
249body .Sux9m ::placeholder {
250 color: #eee !important;
251}
252body .Sux9m ::-webkit-input-placeholder {
253 color: #eee !important;
254}
255body .Sux9m + div [class*="glyphsSpriteDirect_"] {
256 filter: invert(0.3) !important;
257}
258body .tCibT {
259 border: 1px solid var(--darker) !important;
260 box-shadow: var(--bshadow) !important;
261}
262.R8iOs {
263 border: 1px solid var(--darker) !important;
264 color: var(--light) !important;
265 background-color: var(--dark) !important;
266}
267.R8iOs > * {
268 color: inherit;
269}
270[role="button"] + span[class=""] > div[class],
271.G_hoz {
272 background-color: var(--darker) !important;
273}
274body header + div + div.GZkEI li[style] > div > div > [role],
275body article + div + div.GZkEI li[style] > div > div > [role] {
276 --d87: var(--dark-rgb);
277}
278body .WidCF,
279body .HaS-3 {
280 border-right: 1px solid var(--darker);
281 background-size: 200% 200% !important;
282 background: linear-gradient(
283 115deg,
284 var(--dark) 40%,
285 var(--darken),
286 var(--dark) 60%
287 );
288 animation: Loader 2.5s ease infinite !important;
289 background-color: var(--darken) !important;
290}
291body > [role="dialog"] > [role="dialog"] > [role="dialog"] {
292 border: 1px solid var(--darker) !important;
293 box-shadow: 0 0px 16px var(--darken);
294}
295body [role="dialog"] > article > header {
296 overflow-x: hidden !important;
297}
298body [role="dialog"] > article > header + div {
299 --jb7: var(--darken-rgb);
300}
301body > [role="presentation"] > [role="dialog"] > div {
302 border: 1px solid var(--darker) !important;
303}
304body > [role="presentation"] button.aOOlW:not(.SRPMb):hover,
305body > [role="presentation"] button.aOOlW:not(.SRPMb):active {
306 background-color: var(--darken) !important;
307}
308body article > header ~ div .WXPwG .Yi5aA {
309 background-color: var(--white) !important;
310}
311body img + div[style="height: 100%;"],
312body video + div[style="height: 100%;"] {
313 position: unset !important;
314 display: none !important;
315}
316body ._9AhH0 {
317 position: unset !important;
318}
319body .PyenC,
320body .fXIG0 {
321 bottom: 40px !important;
322}
323body .GBPOY {
324 border-radius: 3px;
325 border-color: var(--darker) !important;
326 background-color: var(--darken) !important;
327}
328body .GBPOY a {
329 color: var(--light) !important;
330}
331body .uo5MA,
332body .uo5MA > div:nth-child(1) {
333 box-shadow: var(--bshadow) !important;
334 border: 1px solid var(--darker);
335 background-color: var(--dark) !important;
336}
337body .uo5MA > div:nth-child(2) {
338 background-color: var(--dark) !important;
339}
340body .uo5MA > div:nth-child(3) {
341 border-radius: 0 0 6px 6px;
342}
343body .uo5MA .DPiy6 {
344 background-color: var(--t) !important;
345}
346body .QOqBd {
347 background-color: var(--darker) !important;
348}
349.X3a-9 {
350 background-color: var(--dark) !important;
351}
352body .CMoMH:not(._6FEQj) {
353 background-color: var(--dark) !important;
354}
355body .CMoMH._6FEQj {
356 background-color: var(--darker) !important;
357}
358body .XjicZ {
359 border-top: 1px solid var(--darker);
360 background-color: var(--darken) !important;
361}
362body .XjicZ p {
363 color: var(--light) !important;
364}
365body footer {
366 width: 100% !important;
367 margin: 0 auto !important;
368 max-width: 935px !important;
369 border-top: 1px solid var(--darker) !important;
370}
371.XfvCs {
372 margin-bottom: 30px !important;
373}
374body footer > div::after {
375 content: var(--note);
376 text-align: center;
377 margin-top: 2rem;
378}
379@keyframes Loader {
380 0% {
381 background-position: 33% 0%;
382 }
383 50% {
384 background-position: 68% 100%;
385 }
386 100% {
387 background-position: 33% 0%;
388 }
389}
390
391:root:not(#z) {
392 scrollbar-color: var(--accent) transparent;
393}
394
395:root ::-webkit-scrollbar {
396 background-color: transparent !important;
397 width: 0 !important;
398}
399:root ::-webkit-scrollbar-thumb {
400 background-color: var(--accent) !important;
401}
402div.Igw0E.IwRSH.eGOV_._4EzTm._5VUwz.ZUqME ::-webkit-scrollbar,
403div.N9abW::-webkit-scrollbar,
404div.frMpI.-sxBV::-webkit-scrollbar {
405 background-color: transparent !important;
406 width: 0.5em !important;
407}
408div.N9abW::-webkit-scrollbar-thumb,
409div.Igw0E.IwRSH.eGOV_._4EzTm._5VUwz.ZUqME ::-webkit-scrollbar-thumb,
410div.frMpI.-sxBV::-webkit-scrollbar-thumb {
411 background-color: var(--accent) !important;
412}
413
414div.frMpI.-sxBV {
415 padding: 20px 30px 0 20px !important;
416}
417
418body footer nav + span::before,
419button.sXUSN:hover {
420 cursor: pointer !important;
421}
diff --git a/recipes/threads/icon.svg b/recipes/threads/icon.svg
new file mode 100644
index 0000000..ae0ec86
--- /dev/null
+++ b/recipes/threads/icon.svg
@@ -0,0 +1 @@
<svg aria-label="Threads" viewBox="0 0 192 192" xmlns="http://www.w3.org/2000/svg"><path class="x19hqcy" d="M141.537 88.9883C140.71 88.5919 139.87 88.2104 139.019 87.8451C137.537 60.5382 122.616 44.905 97.5619 44.745C97.4484 44.7443 97.3355 44.7443 97.222 44.7443C82.2364 44.7443 69.7731 51.1409 62.102 62.7807L75.881 72.2328C81.6116 63.5383 90.6052 61.6848 97.2286 61.6848C97.3051 61.6848 97.3819 61.6848 97.4576 61.6855C105.707 61.7381 111.932 64.1366 115.961 68.814C118.893 72.2193 120.854 76.925 121.825 82.8638C114.511 81.6207 106.601 81.2385 98.145 81.7233C74.3247 83.0954 59.0111 96.9879 60.0396 116.292C60.5615 126.084 65.4397 134.508 73.775 140.011C80.8224 144.663 89.899 146.938 99.3323 146.423C111.79 145.74 121.563 140.987 128.381 132.296C133.559 125.696 136.834 117.143 138.28 106.366C144.217 109.949 148.617 114.664 151.047 120.332C155.179 129.967 155.42 145.8 142.501 158.708C131.182 170.016 117.576 174.908 97.0135 175.059C74.2042 174.89 56.9538 167.575 45.7381 153.317C35.2355 139.966 29.8077 120.682 29.6052 96C29.8077 71.3178 35.2355 52.0336 45.7381 38.6827C56.9538 24.4249 74.2039 17.11 97.0132 16.9405C119.988 17.1113 137.539 24.4614 149.184 38.788C154.894 45.8136 159.199 54.6488 162.037 64.9503L178.184 60.6422C174.744 47.9622 169.331 37.0357 161.965 27.974C147.036 9.60668 125.202 0.195148 97.0695 0H96.9569C68.8816 0.19447 47.2921 9.6418 32.7883 28.0793C19.8819 44.4864 13.2244 67.3157 13.0007 95.9325L13 96L13.0007 96.0675C13.2244 124.684 19.8819 147.514 32.7883 163.921C47.2921 182.358 68.8816 191.806 96.9569 192H97.0695C122.03 191.827 139.624 185.292 154.118 170.811C173.081 151.866 172.51 128.119 166.26 113.541C161.776 103.087 153.227 94.5962 141.537 88.9883ZM98.4405 129.507C88.0005 130.095 77.1544 125.409 76.6196 115.372C76.2232 107.93 81.9158 99.626 99.0812 98.6368C101.047 98.5234 102.976 98.468 104.871 98.468C111.106 98.468 116.939 99.0737 122.242 100.233C120.264 124.935 108.662 128.946 98.4405 129.507Z"></path></svg>
diff --git a/recipes/threads/index.js b/recipes/threads/index.js
new file mode 100644
index 0000000..66df129
--- /dev/null
+++ b/recipes/threads/index.js
@@ -0,0 +1,8 @@
1module.exports = Ferdium =>
2 class Threads extends Ferdium {
3 overrideUserAgent() {
4 return window.navigator.userAgent
5 .replaceAll(/(Ferdium|Electron)\/\S+ \([^)]+\)/g, '')
6 .trim();
7 }
8 };
diff --git a/recipes/threads/package.json b/recipes/threads/package.json
new file mode 100644
index 0000000..9c8b6d1
--- /dev/null
+++ b/recipes/threads/package.json
@@ -0,0 +1,10 @@
1{
2 "id": "threads",
3 "name": "Threads",
4 "version": "1.0.0",
5 "license": "MIT",
6 "config": {
7 "serviceURL": "https://threads.net/",
8 "hasNotificationSound": true
9 }
10}
diff --git a/recipes/threads/service.css b/recipes/threads/service.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/recipes/threads/service.css
diff --git a/recipes/threads/webview.js b/recipes/threads/webview.js
new file mode 100644
index 0000000..3092d21
--- /dev/null
+++ b/recipes/threads/webview.js
@@ -0,0 +1,78 @@
1function _interopRequireDefault(obj) {
2 return obj && obj.__esModule ? obj : { default: obj };
3}
4
5const _path = _interopRequireDefault(require('path'));
6
7module.exports = (Ferdium, settings) => {
8 // adapted from the franz-custom-website recipe, for opening
9 // links according to the user's preference (Ferdium/ext.browser)
10 document.addEventListener(
11 'click',
12 event => {
13 const link = event.target.closest('a');
14 const button = event.target.closest('button');
15
16 if (link || button) {
17 const url = link
18 ? link.getAttribute('href')
19 : button.getAttribute('title');
20
21 // check if the URL is relative or absolute
22 if (url.startsWith('/')) {
23 return;
24 }
25
26 // check if we have a valid URL that is not a script nor an image:
27 if (url && url !== '#' && !Ferdium.isImage(link)) {
28 event.preventDefault();
29 event.stopPropagation();
30
31 if (settings.trapLinkClicks === true) {
32 window.location.href = url;
33 } else {
34 Ferdium.openNewWindow(url);
35 }
36 }
37 }
38 },
39 true,
40 );
41
42 const getMessages = () => {
43 const element = document.querySelector('a[href^="/direct/inbox"] span');
44 Ferdium.setBadge(
45 element && element.textContent
46 ? Ferdium.safeParseInt(element.textContent)
47 : 0,
48 );
49 };
50
51 Ferdium.loop(getMessages);
52
53 // https://github.com/ferdium/ferdium-recipes/blob/9d715597a600710c20f75412d3dcd8cdb7b3c39e/docs/frontend_api.md#usage-4
54 // Helper that activates DarkReader and injects your darkmode.css at the same time
55 Ferdium.handleDarkMode(isEnabled => {
56 const url = new URL(window.location.href);
57 const { searchParams } = url;
58 const isDarkModeParam = searchParams.get('theme');
59 let changedParams = false;
60
61 if (isEnabled) {
62 isDarkModeParam
63 ? null
64 : (searchParams.set('theme', 'dark'), (changedParams = true));
65 } else {
66 isDarkModeParam
67 ? (searchParams.delete('theme', 'dark'), (changedParams = true))
68 : null;
69 }
70
71 changedParams
72 ? ((url.search = searchParams.toString()),
73 (window.location.href = url.toString()))
74 : null;
75 });
76
77 Ferdium.injectCSS(_path.default.join(__dirname, 'service.css'));
78};